summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--.mailmap218
-rw-r--r--Documentation/CodingGuidelines14
-rw-r--r--Documentation/Makefile44
-rw-r--r--Documentation/RelNotes/1.7.10.1.txt2
-rw-r--r--Documentation/RelNotes/1.7.5.4.txt2
-rw-r--r--Documentation/RelNotes/1.7.8.2.txt4
-rw-r--r--Documentation/RelNotes/1.7.8.txt4
-rw-r--r--Documentation/RelNotes/1.8.2.1.txt2
-rw-r--r--Documentation/RelNotes/1.8.2.2.txt2
-rw-r--r--Documentation/RelNotes/1.8.3.1.txt14
-rw-r--r--Documentation/RelNotes/1.8.3.2.txt59
-rw-r--r--Documentation/RelNotes/1.8.3.3.txt47
-rw-r--r--Documentation/RelNotes/1.8.3.4.txt20
-rw-r--r--Documentation/RelNotes/1.8.3.txt436
-rw-r--r--Documentation/RelNotes/1.8.4.txt486
-rw-r--r--Documentation/RelNotes/1.8.5.txt221
-rw-r--r--Documentation/SubmittingPatches15
-rw-r--r--Documentation/blame-options.txt25
-rw-r--r--Documentation/config.txt284
-rw-r--r--Documentation/diff-options.txt48
-rw-r--r--Documentation/fetch-options.txt2
-rw-r--r--Documentation/git-add.txt20
-rw-r--r--Documentation/git-am.txt11
-rw-r--r--Documentation/git-archive.txt2
-rw-r--r--Documentation/git-bisect-lk2009.txt2
-rw-r--r--Documentation/git-blame.txt14
-rw-r--r--Documentation/git-cat-file.txt79
-rw-r--r--Documentation/git-check-attr.txt14
-rw-r--r--Documentation/git-check-ignore.txt22
-rw-r--r--Documentation/git-check-mailmap.txt47
-rw-r--r--Documentation/git-check-ref-format.txt3
-rw-r--r--Documentation/git-checkout.txt12
-rw-r--r--Documentation/git-clean.txt71
-rw-r--r--Documentation/git-clone.txt23
-rw-r--r--Documentation/git-commit-tree.txt7
-rw-r--r--Documentation/git-commit.txt2
-rw-r--r--Documentation/git-config.txt90
-rw-r--r--Documentation/git-count-objects.txt30
-rw-r--r--Documentation/git-daemon.txt9
-rw-r--r--Documentation/git-describe.txt9
-rw-r--r--Documentation/git-diff-index.txt12
-rw-r--r--Documentation/git-diff.txt14
-rw-r--r--Documentation/git-difftool.txt11
-rw-r--r--Documentation/git-fast-export.txt24
-rw-r--r--Documentation/git-fetch-pack.txt10
-rw-r--r--Documentation/git-fmt-merge-msg.txt3
-rw-r--r--Documentation/git-format-patch.txt21
-rw-r--r--Documentation/git-fsck.txt6
-rw-r--r--Documentation/git-gc.txt11
-rw-r--r--Documentation/git-grep.txt2
-rw-r--r--Documentation/git-help.txt28
-rw-r--r--Documentation/git-index-pack.txt3
-rw-r--r--Documentation/git-log.txt51
-rw-r--r--Documentation/git-ls-remote.txt11
-rw-r--r--Documentation/git-mailinfo.txt2
-rw-r--r--Documentation/git-merge-file.txt5
-rw-r--r--Documentation/git-merge.txt11
-rw-r--r--Documentation/git-mergetool.txt2
-rw-r--r--Documentation/git-mv.txt10
-rw-r--r--Documentation/git-name-rev.txt9
-rw-r--r--Documentation/git-p4.txt17
-rw-r--r--Documentation/git-pack-refs.txt4
-rw-r--r--Documentation/git-prune.txt2
-rw-r--r--Documentation/git-pull.txt20
-rw-r--r--Documentation/git-push.txt86
-rw-r--r--Documentation/git-rebase.txt14
-rw-r--r--Documentation/git-reflog.txt9
-rw-r--r--Documentation/git-remote.txt27
-rw-r--r--Documentation/git-reset.txt2
-rw-r--r--Documentation/git-rev-list.txt2
-rw-r--r--Documentation/git-rev-parse.txt139
-rw-r--r--Documentation/git-revert.txt2
-rw-r--r--Documentation/git-rm.txt12
-rw-r--r--Documentation/git-send-email.txt15
-rw-r--r--Documentation/git-sh-setup.txt6
-rw-r--r--Documentation/git-shell.txt82
-rw-r--r--Documentation/git-shortlog.txt23
-rw-r--r--Documentation/git-show-ref.txt10
-rw-r--r--Documentation/git-show.txt9
-rw-r--r--Documentation/git-stash.txt13
-rw-r--r--Documentation/git-submodule.txt42
-rw-r--r--Documentation/git-svn.txt50
-rw-r--r--Documentation/git-tag.txt11
-rw-r--r--Documentation/git-update-index.txt10
-rw-r--r--Documentation/git-web--browse.txt1
-rw-r--r--Documentation/git-whatchanged.txt40
-rw-r--r--Documentation/git.txt73
-rw-r--r--Documentation/gitcore-tutorial.txt39
-rw-r--r--Documentation/gitdiffcore.txt45
-rw-r--r--Documentation/gitremote-helpers.txt27
-rw-r--r--Documentation/gitrepository-layout.txt7
-rw-r--r--Documentation/gitweb.conf.txt22
-rw-r--r--Documentation/gitweb.txt2
-rw-r--r--Documentation/glossary-content.txt69
-rw-r--r--Documentation/howto/new-command.txt2
-rw-r--r--Documentation/howto/revert-branch-rebase.txt2
-rw-r--r--Documentation/line-range-format.txt29
-rw-r--r--Documentation/merge-options.txt8
-rw-r--r--Documentation/pretty-formats.txt38
-rw-r--r--Documentation/pretty-options.txt2
-rw-r--r--Documentation/pull-fetch-param.txt11
-rw-r--r--Documentation/rev-list-options.txt51
-rw-r--r--Documentation/revisions.txt11
-rw-r--r--Documentation/technical/api-builtin.txt2
-rw-r--r--Documentation/technical/api-directory-listing.txt25
-rw-r--r--Documentation/technical/api-parse-options.txt18
-rw-r--r--Documentation/technical/api-revision-walking.txt2
-rw-r--r--Documentation/technical/api-setup.txt38
-rw-r--r--Documentation/technical/api-strbuf.txt5
-rw-r--r--Documentation/technical/http-protocol.txt503
-rw-r--r--Documentation/technical/index-format.txt2
-rw-r--r--Documentation/technical/pack-protocol.txt3
-rw-r--r--Documentation/technical/protocol-capabilities.txt40
-rw-r--r--Documentation/technical/racy-git.txt8
-rw-r--r--Documentation/urls.txt11
-rw-r--r--Documentation/user-manual.txt59
-rwxr-xr-xGIT-VERSION-GEN4
-rw-r--r--Makefile171
l---------RelNotes2
-rw-r--r--abspath.c2
-rw-r--r--advice.c6
-rw-r--r--advice.h4
-rw-r--r--archive-zip.c37
-rw-r--r--archive.c18
-rw-r--r--archive.h4
-rw-r--r--argv-array.h1
-rw-r--r--attr.c35
-rw-r--r--bisect.c5
-rw-r--r--branch.c100
-rw-r--r--builtin.h20
-rw-r--r--builtin/add.c386
-rw-r--r--builtin/apply.c47
-rw-r--r--builtin/archive.c17
-rw-r--r--builtin/bisect--helper.c8
-rw-r--r--builtin/blame.c214
-rw-r--r--builtin/branch.c79
-rw-r--r--builtin/cat-file.c231
-rw-r--r--builtin/check-attr.c26
-rw-r--r--builtin/check-ignore.c140
-rw-r--r--builtin/check-mailmap.c66
-rw-r--r--builtin/checkout-index.c8
-rw-r--r--builtin/checkout.c170
-rw-r--r--builtin/clean.c830
-rw-r--r--builtin/clone.c119
-rw-r--r--builtin/commit-tree.c2
-rw-r--r--builtin/commit.c213
-rw-r--r--builtin/config.c193
-rw-r--r--builtin/count-objects.c72
-rw-r--r--builtin/describe.c60
-rw-r--r--builtin/diff-files.c2
-rw-r--r--builtin/diff-index.c2
-rw-r--r--builtin/diff.c75
-rw-r--r--builtin/fast-export.c73
-rw-r--r--builtin/fetch-pack.c60
-rw-r--r--builtin/fetch.c244
-rw-r--r--builtin/for-each-ref.c13
-rw-r--r--builtin/fsck.c18
-rw-r--r--builtin/gc.c71
-rw-r--r--builtin/grep.c55
-rw-r--r--builtin/hash-object.c8
-rw-r--r--builtin/help.c48
-rw-r--r--builtin/index-pack.c38
-rw-r--r--builtin/log.c250
-rw-r--r--builtin/ls-files.c160
-rw-r--r--builtin/ls-tree.c19
-rw-r--r--builtin/merge-base.c12
-rw-r--r--builtin/merge-file.c2
-rw-r--r--builtin/merge-index.c4
-rw-r--r--builtin/merge-tree.c32
-rw-r--r--builtin/merge.c113
-rw-r--r--builtin/mv.c141
-rw-r--r--builtin/name-rev.c163
-rw-r--r--builtin/notes.c150
-rw-r--r--builtin/pack-objects.c2
-rw-r--r--builtin/pack-refs.c2
-rw-r--r--builtin/prune-packed.c15
-rw-r--r--builtin/prune.c6
-rw-r--r--builtin/push.c96
-rw-r--r--builtin/read-tree.c5
-rw-r--r--builtin/receive-pack.c19
-rw-r--r--builtin/reflog.c14
-rw-r--r--builtin/remote.c28
-rw-r--r--builtin/replace.c8
-rw-r--r--builtin/rerere.c8
-rw-r--r--builtin/reset.c40
-rw-r--r--builtin/rev-list.c1
-rw-r--r--builtin/rev-parse.c56
-rw-r--r--builtin/revert.c62
-rw-r--r--builtin/rm.c160
-rw-r--r--builtin/send-pack.c30
-rw-r--r--builtin/shortlog.c17
-rw-r--r--builtin/show-branch.c44
-rw-r--r--builtin/show-ref.c21
-rw-r--r--builtin/tag.c31
-rw-r--r--builtin/tar-tree.c11
-rw-r--r--builtin/update-index.c20
-rw-r--r--builtin/update-ref.c4
-rw-r--r--builtin/upload-archive.c45
-rw-r--r--bulk-checkin.c2
-rw-r--r--bundle.c2
-rw-r--r--cache-tree.c19
-rw-r--r--cache-tree.h2
-rw-r--r--cache.h195
-rw-r--r--color.c2
-rw-r--r--combine-diff.c268
-rw-r--r--command-list.txt1
-rw-r--r--commit-slab.h97
-rw-r--r--commit.c346
-rw-r--r--commit.h58
-rw-r--r--compat/apple-common-crypto.h86
-rw-r--r--compat/cygwin.c149
-rw-r--r--compat/cygwin.h9
-rw-r--r--compat/fnmatch/fnmatch.c3
-rw-r--r--compat/mingw.c16
-rw-r--r--compat/mingw.h11
-rw-r--r--compat/msvc.h2
-rw-r--r--compat/nedmalloc/Readme.txt2
-rw-r--r--compat/nedmalloc/malloc.c.h10
-rw-r--r--compat/nedmalloc/nedmalloc.c4
-rw-r--r--compat/poll/poll.c2
-rw-r--r--compat/precompose_utf8.c2
-rw-r--r--compat/regex/regcomp.c16
-rw-r--r--compat/regex/regexec.c12
-rw-r--r--compat/terminal.c4
-rw-r--r--compat/unsetenv.c2
-rw-r--r--compat/vcbuild/include/sys/poll.h1
-rw-r--r--compat/vcbuild/include/unistd.h3
-rw-r--r--compat/win32.h2
-rw-r--r--compat/win32/pthread.c2
-rw-r--r--compat/win32mmap.c4
-rw-r--r--config.c329
-rw-r--r--config.mak.in6
-rw-r--r--config.mak.uname26
-rw-r--r--configure.ac2
-rw-r--r--connect.c21
-rw-r--r--connect.h13
-rw-r--r--connected.c34
-rw-r--r--connected.h5
-rw-r--r--contrib/blameview/README9
-rwxr-xr-xcontrib/blameview/blameview.perl155
-rwxr-xr-xcontrib/ciabot/ciabot.py2
-rwxr-xr-xcontrib/ciabot/ciabot.sh4
-rw-r--r--contrib/completion/git-completion.bash285
-rw-r--r--contrib/completion/git-completion.zsh27
-rw-r--r--contrib/completion/git-prompt.sh338
-rwxr-xr-xcontrib/contacts/git-contacts201
-rw-r--r--contrib/contacts/git-contacts.txt94
-rw-r--r--contrib/continuous/cidaemon503
-rw-r--r--contrib/continuous/post-receive-cinotify104
-rw-r--r--contrib/credential/netrc/Makefile5
-rwxr-xr-xcontrib/credential/netrc/git-credential-netrc421
-rw-r--r--contrib/credential/netrc/test.netrc13
-rwxr-xr-xcontrib/credential/netrc/test.pl106
-rw-r--r--contrib/credential/osxkeychain/git-credential-osxkeychain.c12
-rwxr-xr-xcontrib/examples/git-log.sh15
-rwxr-xr-xcontrib/examples/git-whatchanged.sh28
-rwxr-xr-xcontrib/hg-to-git/hg-to-git.py2
-rw-r--r--contrib/hooks/multimail/README486
-rw-r--r--contrib/hooks/multimail/README.Git15
-rw-r--r--contrib/hooks/multimail/README.migrate-from-post-receive-email145
-rwxr-xr-xcontrib/hooks/multimail/git_multimail.py2393
-rwxr-xr-xcontrib/hooks/multimail/migrate-mailhook-config269
-rwxr-xr-xcontrib/hooks/multimail/post-receive90
-rwxr-xr-xcontrib/hooks/post-receive-email32
-rw-r--r--contrib/mw-to-git/.gitignore1
-rw-r--r--contrib/mw-to-git/.perlcriticrc28
-rw-r--r--contrib/mw-to-git/Git/Mediawiki.pm100
-rw-r--r--contrib/mw-to-git/Makefile43
-rwxr-xr-xcontrib/mw-to-git/bin-wrapper/git14
-rwxr-xr-xcontrib/mw-to-git/git-mw.perl368
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki.perl669
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw-lib.sh27
-rw-r--r--contrib/mw-to-git/t/test.config4
-rw-r--r--contrib/patches/docbook-xsl-manpages-charmap.patch21
-rw-r--r--contrib/remote-helpers/Makefile1
-rwxr-xr-xcontrib/remote-helpers/git-remote-bzr466
-rwxr-xr-xcontrib/remote-helpers/git-remote-hg675
-rwxr-xr-xcontrib/remote-helpers/test-bzr.sh394
-rwxr-xr-xcontrib/remote-helpers/test-hg-bidi.sh40
-rwxr-xr-xcontrib/remote-helpers/test-hg-hg-git.sh67
-rwxr-xr-xcontrib/remote-helpers/test-hg.sh701
-rw-r--r--contrib/subtree/Makefile1
-rwxr-xr-xcontrib/subtree/git-subtree.sh7
-rw-r--r--contrib/subtree/git-subtree.txt2
-rwxr-xr-xcontrib/subtree/t/t7900-subtree.sh8
-rw-r--r--convert.c29
-rw-r--r--convert.h2
-rw-r--r--credential-store.c4
-rw-r--r--daemon.c18
-rw-r--r--date.c34
-rw-r--r--decorate.c2
-rw-r--r--diff-delta.c2
-rw-r--r--diff-lib.c37
-rw-r--r--diff-no-index.c9
-rw-r--r--diff.c182
-rw-r--r--diff.h10
-rw-r--r--diffcore-pickaxe.c15
-rw-r--r--diffcore-rename.c1
-rw-r--r--dir.c879
-rw-r--r--dir.h44
-rw-r--r--editor.c2
-rw-r--r--entry.c32
-rw-r--r--environment.c2
-rw-r--r--exec_cmd.h1
-rw-r--r--fast-import.c64
-rw-r--r--fetch-pack.c222
-rw-r--r--fetch-pack.h16
-rwxr-xr-xfixup-builtins16
-rwxr-xr-xgit-add--interactive.perl5
-rwxr-xr-xgit-am.sh52
-rwxr-xr-xgit-bisect.sh18
-rw-r--r--git-compat-util.h32
-rwxr-xr-xgit-difftool.perl101
-rwxr-xr-xgit-gui/GIT-VERSION-GEN2
-rw-r--r--git-gui/Makefile6
-rwxr-xr-xgit-gui/git-gui.sh27
-rw-r--r--git-gui/lib/choose_repository.tcl4
-rw-r--r--git-gui/lib/diff.tcl11
-rw-r--r--git-gui/lib/mergetool.tcl4
-rw-r--r--git-gui/lib/remote.tcl6
-rw-r--r--git-gui/po/fr.po2
-rwxr-xr-xgit-merge-one-file.sh61
-rw-r--r--git-mergetool--lib.sh84
-rwxr-xr-xgit-p4.py41
-rwxr-xr-xgit-pull.sh54
-rw-r--r--git-rebase--am.sh12
-rw-r--r--git-rebase--interactive.sh101
-rw-r--r--git-rebase--merge.sh5
-rwxr-xr-xgit-rebase.sh63
-rwxr-xr-xgit-remote-testgit.sh (renamed from git-remote-testgit)52
-rwxr-xr-xgit-request-pull.sh14
-rwxr-xr-xgit-send-email.perl168
-rw-r--r--git-sh-setup.sh26
-rwxr-xr-xgit-stash.sh52
-rwxr-xr-xgit-submodule.sh239
-rwxr-xr-xgit-svn.perl40
-rwxr-xr-xgit-web--browse.sh15
-rw-r--r--git.c34
-rw-r--r--git.rc22
-rwxr-xr-xgitk-git/gitk254
-rw-r--r--gitk-git/po/sv.po633
-rwxr-xr-xgitweb/gitweb.perl15
-rw-r--r--gitweb/static/gitweb.css6
-rw-r--r--gpg-interface.h12
-rw-r--r--hash.h7
-rw-r--r--help.c55
-rw-r--r--help.h5
-rw-r--r--http-backend.c46
-rw-r--r--http-push.c4
-rw-r--r--http.c97
-rw-r--r--http.h16
-rw-r--r--imap-send.c4
-rw-r--r--kwset.c10
-rw-r--r--line-log.c1286
-rw-r--r--line-log.h65
-rw-r--r--line-range.c290
-rw-r--r--line-range.h39
-rw-r--r--lockfile.c10
-rw-r--r--log-tree.c152
-rw-r--r--log-tree.h1
-rw-r--r--mailmap.c91
-rw-r--r--match-trees.c44
-rw-r--r--merge-recursive.c9
-rw-r--r--mergetools/p4merge8
-rw-r--r--name-hash.c2
-rw-r--r--notes-merge.c31
-rw-r--r--notes-merge.h14
-rw-r--r--notes-utils.c157
-rw-r--r--notes-utils.h37
-rw-r--r--notes.c10
-rw-r--r--notes.h2
-rw-r--r--object.c91
-rw-r--r--object.h25
-rw-r--r--pack-refs.c148
-rw-r--r--pack-refs.h18
-rw-r--r--pack-revindex.c108
-rw-r--r--parse-options-cb.c6
-rw-r--r--parse-options.c58
-rw-r--r--parse-options.h14
-rw-r--r--path.c195
-rw-r--r--pathspec.c453
-rw-r--r--pathspec.h88
-rw-r--r--perl/Git.pm231
-rw-r--r--perl/Git/SVN/Editor.pm2
-rw-r--r--perl/Git/SVN/Fetcher.pm24
-rw-r--r--perl/Git/SVN/Prompt.pm2
-rw-r--r--perl/Git/SVN/Ra.pm4
-rw-r--r--pkt-line.c125
-rw-r--r--pkt-line.h72
-rw-r--r--po/TEAMS5
-rw-r--r--po/de.po5798
-rw-r--r--po/fr.po9823
-rw-r--r--po/git.pot3722
-rw-r--r--po/sv.po4116
-rw-r--r--po/vi.po4169
-rw-r--r--po/zh_CN.po4059
-rw-r--r--preload-index.c21
-rw-r--r--pretty.c548
-rw-r--r--prio-queue.c84
-rw-r--r--prio-queue.h48
-rw-r--r--progress.c43
-rw-r--r--quote.c126
-rw-r--r--quote.h15
-rw-r--r--read-cache.c285
-rw-r--r--refs.c1247
-rw-r--r--refs.h85
-rw-r--r--remote-curl.c288
-rw-r--r--remote-testsvn.c2
-rw-r--r--remote.c415
-rw-r--r--remote.h89
-rw-r--r--rerere.c19
-rw-r--r--rerere.h4
-rw-r--r--resolve-undo.c27
-rw-r--r--resolve-undo.h3
-rw-r--r--revision.c738
-rw-r--r--revision.h82
-rw-r--r--run-command.c15
-rw-r--r--run-command.h1
-rw-r--r--send-pack.c24
-rw-r--r--sequencer.c246
-rw-r--r--sequencer.h4
-rw-r--r--setup.c190
-rw-r--r--sha1_file.c776
-rw-r--r--sha1_name.c209
-rw-r--r--shallow.c59
-rw-r--r--shell.c25
-rw-r--r--sideband.c11
-rw-r--r--sideband.h3
-rw-r--r--strbuf.c19
-rw-r--r--strbuf.h1
-rw-r--r--streaming.c12
-rw-r--r--submodule.c182
-rw-r--r--submodule.h6
-rw-r--r--t/.gitattributes1
-rw-r--r--t/Makefile13
-rw-r--r--t/README48
-rw-r--r--t/annotate-tests.sh609
-rwxr-xr-xt/check-non-portable-shell.pl1
-rw-r--r--t/gitweb-lib.sh2
-rw-r--r--t/lib-gpg/pubring.gpgbin1164 -> 2359 bytes
-rw-r--r--t/lib-gpg/random_seedbin600 -> 600 bytes
-rw-r--r--t/lib-gpg/secring.gpgbin1237 -> 3734 bytes
-rw-r--r--t/lib-gpg/trustdb.gpgbin1280 -> 1360 bytes
-rw-r--r--t/lib-httpd.sh19
-rw-r--r--t/lib-httpd/apache.conf33
-rw-r--r--t/lib-rebase.sh123
-rw-r--r--t/lib-t6000.sh106
-rw-r--r--t/perf/README2
-rwxr-xr-xt/perf/p0002-read-cache.sh14
-rwxr-xr-xt/perf/p4211-line-log.sh34
-rw-r--r--t/perf/perf-lib.sh7
-rwxr-xr-xt/t0000-basic.sh101
-rwxr-xr-xt/t0005-signals.sh7
-rwxr-xr-xt/t0008-ignores.sh178
-rwxr-xr-xt/t0009-prio-queue.sh50
-rwxr-xr-xt/t0020-crlf.sh8
-rwxr-xr-xt/t0021-conversion.sh14
-rwxr-xr-xt/t0040-parse-options.sh46
-rwxr-xr-xt/t0060-path-utils.sh72
-rwxr-xr-xt/t0070-fundamental.sh4
-rwxr-xr-xt/t0100-previous.sh15
-rwxr-xr-xt/t0110-urlmatch-normalization.sh177
-rw-r--r--t/t0110/README9
-rw-r--r--t/t0110/url-11
-rw-r--r--t/t0110/url-101
-rw-r--r--t/t0110/url-111
-rw-r--r--t/t0110/url-21
-rw-r--r--t/t0110/url-31
-rw-r--r--t/t0110/url-41
-rw-r--r--t/t0110/url-51
-rw-r--r--t/t0110/url-61
-rw-r--r--t/t0110/url-71
-rw-r--r--t/t0110/url-81
-rw-r--r--t/t0110/url-91
-rwxr-xr-xt/t1004-read-tree-m-u-wf.sh7
-rwxr-xr-xt/t1006-cat-file.sh82
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh24
-rwxr-xr-xt/t1060-object-corruption.sh104
-rwxr-xr-xt/t1300-repo-config.sh73
-rwxr-xr-xt/t1307-config-blob.sh70
-rwxr-xr-xt/t1403-show-ref.sh167
-rwxr-xr-xt/t1411-reflog-show.sh22
-rwxr-xr-xt/t1507-rev-parse-upstream.sh15
-rwxr-xr-xt/t1508-at-combinations.sh66
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh50
-rwxr-xr-xt/t1513-rev-parse-prefix.sh96
-rwxr-xr-xt/t2001-checkout-cache-clash.sh7
-rwxr-xr-xt/t2004-checkout-cache-temp.sh5
-rwxr-xr-xt/t2007-checkout-symlink.sh12
-rwxr-xr-xt/t2012-checkout-last.sh34
-rwxr-xr-xt/t2021-checkout-overwrite.sh12
-rwxr-xr-xt/t2022-checkout-paths.sh22
-rwxr-xr-xt/t2024-checkout-dwim.sh167
-rwxr-xr-xt/t2200-add-update.sh27
-rwxr-xr-xt/t2202-add-addremove.sh10
-rwxr-xr-xt/t3001-ls-files-others-exclude.sh69
-rwxr-xr-xt/t3010-ls-files-killed-modified.sh160
-rwxr-xr-xt/t3030-merge-recursive.sh62
-rwxr-xr-xt/t3032-merge-recursive-options.sh2
-rwxr-xr-xt/t3070-wildmatch.sh55
-rwxr-xr-xt/t3100-ls-tree-restrict.sh42
-rwxr-xr-xt/t3200-branch.sh22
-rwxr-xr-xt/t3203-branch-output.sh6
-rwxr-xr-xt/t3210-pack-refs.sh33
-rwxr-xr-xt/t3211-peel-ref.sh9
-rwxr-xr-xt/t3400-rebase.sh64
-rwxr-xr-xt/t3401-rebase-partial.sh69
-rwxr-xr-xt/t3403-rebase-skip.sh7
-rwxr-xr-xt/t3404-rebase-interactive.sh154
-rwxr-xr-xt/t3406-rebase-message.sh50
-rwxr-xr-xt/t3409-rebase-preserve-merges.sh62
-rwxr-xr-xt/t3415-rebase-autosquash.sh57
-rwxr-xr-xt/t3420-rebase-autostash.sh170
-rwxr-xr-xt/t3421-rebase-topology-linear.sh350
-rwxr-xr-xt/t3425-rebase-topology-merges.sh258
-rwxr-xr-xt/t3501-revert-cherry-pick.sh2
-rwxr-xr-xt/t3505-cherry-pick-empty.sh18
-rwxr-xr-xt/t3506-cherry-pick-ff.sh2
-rwxr-xr-xt/t3508-cherry-pick-many-commits.sh6
-rwxr-xr-xt/t3509-cherry-pick-merge-df.sh14
-rwxr-xr-xt/t3511-cherry-pick-x.sh219
-rwxr-xr-xt/t3600-rm.sh259
-rwxr-xr-xt/t3700-add.sh15
-rwxr-xr-xt/t3900-i18n-commit.sh40
-rw-r--r--t/t3900/UTF-16.txtbin0 -> 146 bytes
-rwxr-xr-xt/t3903-stash.sh68
-rwxr-xr-xt/t4000-diff-format.sh48
-rwxr-xr-xt/t4008-diff-break-rewrite.sh12
-rwxr-xr-xt/t4011-diff-symlink.sh35
-rwxr-xr-xt/t4014-format-patch.sh338
-rwxr-xr-xt/t4015-diff-whitespace.sh345
-rwxr-xr-xt/t4023-diff-rename-typechange.sh28
-rwxr-xr-xt/t4030-diff-textconv.sh8
-rwxr-xr-xt/t4034-diff-words.sh7
-rwxr-xr-xt/t4038-diff-combined.sh177
-rwxr-xr-xt/t4041-diff-submodule-option.sh25
-rwxr-xr-xt/t4055-diff-context.sh2
-rwxr-xr-xt/t4111-apply-subdir.sh14
-rwxr-xr-xt/t4114-apply-typechange.sh29
-rwxr-xr-xt/t4115-apply-symlink.sh10
-rwxr-xr-xt/t4122-apply-symlink-inside.sh8
-rwxr-xr-xt/t4150-am.sh40
-rwxr-xr-xt/t4202-log.sh42
-rwxr-xr-xt/t4203-mailmap.sh77
-rwxr-xr-xt/t4205-log-pretty-formats.sh223
-rwxr-xr-xt/t4207-log-decoration-colors.sh8
-rwxr-xr-xt/t4211-line-log.sh97
-rw-r--r--t/t4211/expect.beginning-of-file43
-rw-r--r--t/t4211/expect.end-of-file62
-rw-r--r--t/t4211/expect.move-support-f80
-rw-r--r--t/t4211/expect.multiple104
-rw-r--r--t/t4211/expect.multiple-overlapping187
-rw-r--r--t/t4211/expect.multiple-superset187
-rw-r--r--t/t4211/expect.parallel-change-f-to-main160
-rw-r--r--t/t4211/expect.simple-f59
-rw-r--r--t/t4211/expect.simple-f-to-main100
-rw-r--r--t/t4211/expect.simple-main68
-rw-r--r--t/t4211/expect.simple-main-to-end70
-rw-r--r--t/t4211/expect.two-ranges102
-rw-r--r--t/t4211/expect.vanishes-early39
-rw-r--r--t/t4211/history.export406
-rwxr-xr-xt/t4300-merge-tree.sh74
-rwxr-xr-xt/t5000-tar-tree.sh168
-rw-r--r--t/t5000/pax.tarbin0 -> 10240 bytes
-rwxr-xr-xt/t5003-archive-zip.sh2
-rwxr-xr-xt/t5004-archive-corner-cases.sh15
-rw-r--r--t/t5004/empty-with-pax-header.tarbin0 -> 10240 bytes
-rwxr-xr-xt/t5150-request-pull.sh2
-rwxr-xr-xt/t5303-pack-corruption-resilience.sh29
-rwxr-xr-xt/t5304-prune.sh26
-rwxr-xr-xt/t5404-tracking-branches.sh2
-rwxr-xr-xt/t5407-post-rewrite-hook.sh4
-rwxr-xr-xt/t5500-fetch-pack.sh37
-rwxr-xr-xt/t5503-tagfollow.sh64
-rwxr-xr-xt/t5505-remote.sh850
-rwxr-xr-xt/t5510-fetch.sh116
-rwxr-xr-xt/t5516-fetch-push.sh600
-rwxr-xr-xt/t5517-push-mirror.sh2
-rwxr-xr-xt/t5519-push-alternates.sh12
-rwxr-xr-xt/t5520-pull.sh136
-rwxr-xr-xt/t5521-pull-options.sh26
-rwxr-xr-xt/t5528-push-default.sh65
-rwxr-xr-xt/t5531-deep-submodule-push.sh1
-rwxr-xr-xt/t5533-push-cas.sh189
-rwxr-xr-xt/t5541-http-push.sh5
-rwxr-xr-xt/t5550-http-fetch.sh1
-rwxr-xr-xt/t5551-http-fetch.sh49
-rwxr-xr-xt/t5560-http-backend-noserver.sh2
-rwxr-xr-xt/t5570-git-daemon.sh1
-rwxr-xr-xt/t5601-clone.sh5
-rwxr-xr-xt/t5700-clone-reference.sh31
-rwxr-xr-xt/t5702-clone-options.sh2
-rwxr-xr-xt/t5710-info-alternate.sh2
-rwxr-xr-xt/t5801-remote-helpers.sh123
-rwxr-xr-xt/t5802-connect-helper.sh72
-rwxr-xr-xt/t6002-rev-list-bisect.sh84
-rwxr-xr-xt/t6003-rev-list-topo-order.sh101
-rwxr-xr-xt/t6006-rev-list-format.sh206
-rwxr-xr-xt/t6012-rev-list-simplify.sh71
-rwxr-xr-xt/t6019-rev-list-ancestry-path.sh48
-rwxr-xr-xt/t6021-merge-criss-cross.sh2
-rwxr-xr-xt/t6022-merge-rename.sh14
-rwxr-xr-xt/t6030-bisect-porcelain.sh40
-rwxr-xr-xt/t6035-merge-dir-to-symlink.sh73
-rwxr-xr-xt/t6111-rev-list-treesame.sh196
-rwxr-xr-xt/t6120-describe.sh27
-rwxr-xr-xt/t6130-pathspec-noglob.sh87
-rwxr-xr-xt/t6131-pathspec-icase.sh103
-rwxr-xr-xt/t7001-mv.sh146
-rwxr-xr-xt/t7011-skip-worktree-reading.sh4
-rwxr-xr-xt/t7061-wtstatus-ignore.sh125
-rwxr-xr-xt/t7102-reset.sh41
-rwxr-xr-xt/t7201-co.sh1
-rwxr-xr-xt/t7300-clean.sh34
-rwxr-xr-xt/t7301-clean-interactive.sh475
-rwxr-xr-xt/t7400-submodule-basic.sh252
-rwxr-xr-xt/t7401-submodule-summary.sh116
-rwxr-xr-xt/t7403-submodule-sync.sh388
-rwxr-xr-xt/t7406-submodule-update.sh78
-rwxr-xr-xt/t7407-submodule-foreach.sh18
-rwxr-xr-xt/t7500-commit.sh12
-rwxr-xr-xt/t7501-commit.sh13
-rwxr-xr-xt/t7502-commit.sh93
-rwxr-xr-xt/t7508-status.sh108
-rwxr-xr-xt/t7512-status-help.sh127
-rwxr-xr-xt/t7600-merge.sh74
-rwxr-xr-xt/t7601-merge-pull-config.sh2
-rwxr-xr-xt/t7607-merge-overwrite.sh5
-rwxr-xr-xt/t7610-mergetool.sh6
-rwxr-xr-xt/t7612-merge-verify-signatures.sh61
-rwxr-xr-xt/t7800-difftool.sh473
-rwxr-xr-xt/t8001-annotate.sh6
-rwxr-xr-xt/t8002-blame.sh12
-rwxr-xr-xt/t8003-blame-corner-cases.sh6
-rwxr-xr-xt/t8006-blame-textconv.sh14
-rwxr-xr-xt/t8007-cat-file-textconv.sh10
-rwxr-xr-xt/t9001-send-email.sh138
-rwxr-xr-xt/t9020-remote-svn.sh2
-rwxr-xr-xt/t9112-git-svn-md5less-file.sh2
-rwxr-xr-xt/t9114-git-svn-dcommit-merge.sh2
-rwxr-xr-xt/t9147-git-svn-include-paths.sh149
-rwxr-xr-xt/t9161-git-svn-mergeinfo-push.sh1
-rwxr-xr-xt/t9167-git-svn-cmd-branch-subproject.sh48
-rwxr-xr-xt/t9300-fast-import.sh65
-rwxr-xr-xt/t9350-fast-export.sh11
-rwxr-xr-xt/t9400-git-cvsserver-server.sh1
-rwxr-xr-xt/t9401-git-cvsserver-crlf.sh1
-rwxr-xr-xt/t9402-git-cvsserver-refs.sh12
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh18
-rwxr-xr-xt/t9801-git-p4-branch.sh23
-rwxr-xr-xt/t9802-git-p4-filetype.sh6
-rwxr-xr-xt/t9808-git-p4-chdir.sh41
-rwxr-xr-xt/t9902-completion.sh277
-rwxr-xr-xt/t9903-bash-prompt.sh471
-rw-r--r--t/test-lib-functions.sh46
-rw-r--r--t/test-lib.sh270
-rwxr-xr-xt/valgrind/analyze.sh8
-rwxr-xr-xt/valgrind/valgrind.sh30
-rwxr-xr-xtemplates/hooks--pre-commit.sample27
-rwxr-xr-xtemplates/hooks--pre-push.sample1
-rw-r--r--test-chmtime.c12
-rw-r--r--test-dump-cache-tree.c4
-rw-r--r--test-index-version.c2
-rw-r--r--test-mergesort.c2
-rw-r--r--test-parse-options.c4
-rw-r--r--test-path-utils.c32
-rw-r--r--test-prio-queue.c39
-rw-r--r--test-read-cache.c13
-rw-r--r--test-subprocess.c4
-rw-r--r--test-svn-fe.c2
-rw-r--r--test-urlmatch-normalization.c50
-rw-r--r--thread-utils.c2
-rw-r--r--trace.c1
-rw-r--r--transport-helper.c115
-rw-r--r--transport.c38
-rw-r--r--transport.h16
-rw-r--r--tree-diff.c48
-rw-r--r--tree-walk.c89
-rw-r--r--tree-walk.h2
-rw-r--r--tree.c6
-rw-r--r--tree.h2
-rw-r--r--unpack-trees.c194
-rw-r--r--unpack-trees.h15
-rw-r--r--upload-pack.c68
-rw-r--r--urlmatch.c535
-rw-r--r--urlmatch.h54
-rw-r--r--utf8.c104
-rw-r--r--utf8.h24
-rw-r--r--wildmatch.c7
-rw-r--r--wrap-for-bin.sh2
-rw-r--r--wrapper.c28
-rw-r--r--write_or_die.c19
-rw-r--r--wt-status.c302
-rw-r--r--wt-status.h19
-rw-r--r--xdiff/xdiff.h2
-rw-r--r--xdiff/xdiffi.c29
-rw-r--r--xdiff/xdiffi.h1
-rw-r--r--xdiff/xemit.c49
-rw-r--r--xdiff/xemit.h2
-rw-r--r--xdiff/xutils.c13
-rw-r--r--xdiff/xutils.h1
-rw-r--r--zlib.c25
703 files changed, 64319 insertions, 21247 deletions
diff --git a/.gitignore b/.gitignore
index 6669bf0..66199ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@
/git-cat-file
/git-check-attr
/git-check-ignore
+/git-check-mailmap
/git-check-ref-format
/git-checkout
/git-checkout-index
@@ -125,6 +126,7 @@
/git-remote-ftps
/git-remote-fd
/git-remote-ext
+/git-remote-testgit
/git-remote-testpy
/git-remote-testsvn
/git-repack
@@ -190,6 +192,8 @@
/test-mktemp
/test-parse-options
/test-path-utils
+/test-prio-queue
+/test-read-cache
/test-regex
/test-revision-walking
/test-run-command
@@ -198,6 +202,7 @@
/test-string-list
/test-subprocess
/test-svn-fe
+/test-urlmatch-normalization
/test-wildmatch
/common-cmds.h
*.tar.gz
@@ -228,6 +233,7 @@
/cscope*
*.obj
*.lib
+*.res
*.sln
*.suo
*.ncb
diff --git a/.mailmap b/.mailmap
index 48d7acf..1c1f5ec 100644
--- a/.mailmap
+++ b/.mailmap
@@ -5,98 +5,242 @@
# same person appearing not to be so.
#
+<nico@fluxnic.net> <nico@cam.org>
+Alejandro R. Sedeño <asedeno@MIT.EDU> <asedeno@mit.edu>
Alex Bennée <kernel-hacker@bennee.com>
+Alex Riesen <raa.lkml@gmail.com> <fork0@t-online.de>
+Alex Riesen <raa.lkml@gmail.com> <raa@limbo.localdomain>
+Alex Riesen <raa.lkml@gmail.com> <raa@steel.home>
+Alex Vandiver <alex@chmrr.net> <alexmv@MIT.EDU>
Alexander Gavrilov <angavrilov@gmail.com>
+Alexey Shumkin <alex.crezoff@gmail.com> <zapped@mail.ru>
+Alexey Shumkin <alex.crezoff@gmail.com> <Alex.Crezoff@gmail.com>
+Anders Kaseorg <andersk@MIT.EDU> <andersk@ksplice.com>
+Anders Kaseorg <andersk@MIT.EDU> <andersk@mit.edu>
Aneesh Kumar K.V <aneesh.kumar@gmail.com>
-Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
+Amos Waterland <apw@debian.org> <apw@rossby.metr.ou.edu>
+Amos Waterland <apw@debian.org> <apw@us.ibm.com>
+Ben Walton <bdwalton@gmail.com> <bwalton@artsci.utoronto.ca>
+Benoit Sigoure <tsunanet@gmail.com> <tsuna@lrde.epita.fr>
+Bernt Hansen <bernt@norang.ca> <bernt@alumni.uwaterloo.ca>
+Brandon Casey <drafnel@gmail.com> <casey@nrlssc.navy.mil>
+brian m. carlson <sandals@crustytoothpaste.ath.cx> Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
+brian m. carlson <sandals@crustytoothpaste.ath.cx> <sandals@crustytoothpaste.net>
+Bryan Larsen <bryan@larsen.st> <bryan.larsen@gmail.com>
+Bryan Larsen <bryan@larsen.st> <bryanlarsen@yahoo.com>
Cheng Renquan <crquan@gmail.com>
Chris Shoemaker <c.shoemaker@cox.net>
+Chris Wright <chrisw@sous-sol.org> <chrisw@osdl.org>
+Cord Seele <cowose@gmail.com> <cowose@googlemail.com>
+Christian Stimming <stimming@tuhh.de> <chs@ckiste.goetheallee>
+Csaba Henk <csaba@gluster.com> <csaba@lowlife.hu>
Dan Johnson <computerdruid@gmail.com>
-Dana L. How <danahow@gmail.com>
-Dana L. How <how@deathvalley.cswitch.com>
+Dana L. How <danahow@gmail.com> <how@deathvalley.cswitch.com>
+Dana L. How <danahow@gmail.com> Dana How
Daniel Barkalow <barkalow@iabervon.org>
+Daniel Trstenjak <daniel.trstenjak@gmail.com> <daniel.trstenjak@online.de>
+Daniel Trstenjak <daniel.trstenjak@gmail.com> <trsten@science-computing.de>
+David Brown <git@davidb.org> <davidb@quicinc.com>
David D. Kilzer <ddkilzer@kilzer.net>
David KÃ¥gedal <davidk@lysator.liu.se>
+David Reiss <dreiss@facebook.com> <dreiss@dreiss-vmware.(none)>
David S. Miller <davem@davemloft.net>
Deskin Miller <deskinm@umich.edu>
Dirk Süsserott <newsletter@dirk.my1.cc>
+Eric Blake <eblake@redhat.com> <ebb9@byu.net>
+Eric Hanchrow <eric.hanchrow@gmail.com> <offby1@blarg.net>
Eric S. Raymond <esr@thyrsus.com>
Erik Faye-Lund <kusmabite@gmail.com> <kusmabite@googlemail.com>
-Fredrik Kuivinen <freku045@student.liu.se>
+Eyvind Bernhardsen <eyvind.bernhardsen@gmail.com> <eyvind-git@orakel.ntnu.no>
+Florian Achleitner <florian.achleitner.2.6.31@gmail.com> <florian.achleitner2.6.31@gmail.com>
+Franck Bui-Huu <vagabon.xyz@gmail.com> <fbuihuu@gmail.com>
+Frank Lichtenheld <frank@lichtenheld.de> <djpig@debian.org>
+Frank Lichtenheld <frank@lichtenheld.de> <flichtenheld@astaro.com>
+Fredrik Kuivinen <frekui@gmail.com> <freku045@student.liu.se>
Frédéric Heitzmann <frederic.heitzmann@gmail.com>
-H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
-H. Peter Anvin <hpa@tazenda.sc.orionmulti.com>
-H. Peter Anvin <hpa@trantor.hos.anvin.org>
+Garry Dolley <gdolley@ucla.edu> <gdolley@arpnetworks.com>
+Greg Price <price@mit.edu> <price@MIT.EDU>
+Greg Price <price@mit.edu> <price@ksplice.com>
+Heiko Voigt <hvoigt@hvoigt.net> <git-list@hvoigt.net>
+H. Merijn Brand <h.m.brand@xs4all.nl> H.Merijn Brand <h.m.brand@xs4all.nl>
+H. Peter Anvin <hpa@zytor.com> <hpa@bonde.sc.orionmulti.com>
+H. Peter Anvin <hpa@zytor.com> <hpa@smyrno.hos.anvin.org>
+H. Peter Anvin <hpa@zytor.com> <hpa@tazenda.sc.orionmulti.com>
+H. Peter Anvin <hpa@zytor.com> <hpa@trantor.hos.anvin.org>
+Han-Wen Nienhuys <hanwen@google.com> Han-Wen Nienhuys <hanwen@xs4all.nl>
Horst H. von Brand <vonbrand@inf.utfsm.cl>
-İsmail Dönmez <ismail@pardus.org.tr>
+J. Bruce Fields <bfields@citi.umich.edu> <bfields@fieldses.org>
+J. Bruce Fields <bfields@citi.umich.edu> <bfields@pig.linuxdev.us.dell.com>
+J. Bruce Fields <bfields@citi.umich.edu> <bfields@puzzle.fieldses.org>
Jakub Narębski <jnareb@gmail.com>
-Jay Soffian <jaysoffian+git@gmail.com>
+James Y Knight <jknight@itasoftware.com> <foom@fuhm.net>
+# The 2 following authors are probably the same person,
+# but both emails bounce.
+Jason McMullan <jason.mcmullan@timesys.com>
+Jason McMullan <mcmullan@netapp.com>
+Jason Riedy <ejr@eecs.berkeley.edu> <ejr@EECS.Berkeley.EDU>
+Jason Riedy <ejr@eecs.berkeley.edu> <ejr@cs.berkeley.edu>
+Jay Soffian <jaysoffian@gmail.com> <jaysoffian+git@gmail.com>
Jeff King <peff@peff.net> <peff@github.com>
+Jeff Muizelaar <jmuizelaar@mozilla.com> <jeff@infidigm.net>
+Jens Axboe <axboe@kernel.dk> <axboe@suse.de>
+Jens Axboe <axboe@kernel.dk> <jens.axboe@oracle.com>
+Jim Meyering <jim@meyering.net> <meyering@redhat.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 Schindelin <Johannes.Schindelin@gmx.de> <johannes.schindelin@gmx.de>
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>
+Johannes Sixt <j6t@kdbg.org> <j.sixt@viscovery.net>
+Johannes Sixt <j6t@kdbg.org> <johannes.sixt@telecom.at>
+John 'Warthog9' Hawley <warthog9@kernel.org> <warthog9@eaglescrag.net>
+Jon Loeliger <jdl@jdl.com> <jdl@freescale.com>
+Jon Loeliger <jdl@jdl.com> <jdl@freescale.org>
+Jon Seymour <jon.seymour@gmail.com> <jon@blackcubes.dyndns.org>
+Jonathan Nieder <jrnieder@gmail.com> <jrnieder@uchicago.edu>
+Jonathan del Strother <jon.delStrother@bestbefore.tv> <maillist@steelskies.com>
+Josh Triplett <josh@joshtriplett.org> <josh@freedesktop.org>
+Josh Triplett <josh@joshtriplett.org> <josht@us.ibm.com>
+Julian Phillips <julian@quantumfyre.co.uk> <jp3@quantumfyre.co.uk>
Junio C Hamano <gitster@pobox.com> <gitster@pobox.com>
-Junio C Hamano <gitster@pobox.com> <junio@pobox.com>
-Junio C Hamano <gitster@pobox.com> <junio@twinsun.com>
-Junio C Hamano <gitster@pobox.com> <junkio@twinsun.com>
Junio C Hamano <gitster@pobox.com> <junio@hera.kernel.org>
Junio C Hamano <gitster@pobox.com> <junio@kernel.org>
+Junio C Hamano <gitster@pobox.com> <junio@pobox.com>
+Junio C Hamano <gitster@pobox.com> <junio@twinsun.com>
Junio C Hamano <gitster@pobox.com> <junkio@cox.net>
-Karl Hasselström <kha@treskal.com>
-Kevin Leung <kevinlsk@gmail.com>
+Junio C Hamano <gitster@pobox.com> <junkio@twinsun.com>
+Karl Wiberg <kha@treskal.com> Karl Hasselström
+Karl Wiberg <kha@treskal.com> <kha@yoghurt.hemma.treskal.com>
+Karsten Blees <blees@dcon.de> <karsten.blees@dcon.de>
+Karsten Blees <blees@dcon.de> <karsten.blees@gmail.com>
+Kay Sievers <kay.sievers@vrfy.org> <kay.sievers@suse.de>
+Kay Sievers <kay.sievers@vrfy.org> <kay@mam.(none)>
+Keith Cascio <keith@CS.UCLA.EDU> <keith@cs.ucla.edu>
Kent Engstrom <kent@lysator.liu.se>
+Kevin Leung <kevinlsk@gmail.com>
+Kirill Smelkov <kirr@navytux.spb.ru> <kirr@landau.phys.spbu.ru>
+Kirill Smelkov <kirr@navytux.spb.ru> <kirr@mns.spb.ru>
+Knut Franke <Knut.Franke@gmx.de> <k.franke@science-computing.de>
Lars Doelle <lars.doelle@on-line ! de>
Lars Doelle <lars.doelle@on-line.de>
+Lars Noschinski <lars@public.noschinski.de> <lars.noschinski@rwth-aachen.de>
Li Hong <leehong@pku.edu.cn>
-Linus Torvalds <torvalds@linux-foundation.org> <torvalds@woody.linux-foundation.org>
-Linus Torvalds <torvalds@linux-foundation.org> <torvalds@osdl.org>
-Linus Torvalds <torvalds@linux-foundation.org> <torvalds@g5.osdl.org>
Linus Torvalds <torvalds@linux-foundation.org> <torvalds@evo.osdl.org>
-Linus Torvalds <torvalds@linux-foundation.org> <torvalds@ppc970.osdl.org>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@g5.osdl.org>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@osdl.org>
Linus Torvalds <torvalds@linux-foundation.org> <torvalds@ppc970.osdl.org.(none)>
-Lukas Sandström <lukass@etek.chalmers.se>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@ppc970.osdl.org>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@woody.linux-foundation.org>
+Lukas Sandström <luksan@gmail.com> <lukass@etek.chalmers.se>
+Marc Khouzam <marc.khouzam@ericsson.com> <marc.khouzam@gmail.com>
Marc-André Lureau <marcandre.lureau@gmail.com>
+Marco Costalba <mcostalba@gmail.com> <mcostalba@yahoo.it>
+Mark Levedahl <mdl123@verizon.net> <mlevedahl@gmail.com>
Mark Rada <marada@uwaterloo.ca>
Martin Langhoff <martin@laptop.org> <martin@catalyst.net.nz>
Martin von Zweigbergk <martinvonz@gmail.com> <martin.von.zweigbergk@gmail.com>
+Matt Draisey <matt@draisey.ca> <mattdraisey@sympatico.ca>
+Matt Kraai <kraai@ftbfs.org> <matt.kraai@amo.abbott.com>
+Matt McCutchen <matt@mattmccutchen.net> <hashproduct@gmail.com>
+Matthias Kestenholz <matthias@spinlock.ch> <mk@spinlock.ch>
+Matthias Urlichs <matthias@urlichs.de> <smurf@kiste.(none)>
+Matthias Urlichs <matthias@urlichs.de> <smurf@smurf.noris.de>
Michael Coleman <tutufan@gmail.com>
Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm>
+Michael S. Tsirkin <mst@kernel.org> <mst@redhat.com>
+Michael S. Tsirkin <mst@kernel.org> <mst@mellanox.co.il>
+Michael S. Tsirkin <mst@kernel.org> <mst@dev.mellanox.co.il>
Michael W. Olson <mwolson@gnu.org>
+Michael Witten <mfwitten@gmail.com> <mfwitten@MIT.EDU>
+Michael Witten <mfwitten@gmail.com> <mfwitten@mit.edu>
+Michal Rokos <michal.rokos@nextsoft.cz> <rokos@nextsoft.cz>
Michele Ballabio <barra_cuda@katamail.com>
-Nanako Shiraishi <nanako3@bluebottle.com>
+Miklos Vajna <vmiklos@frugalware.org> <vmiklos@suse.cz>
+Namhyung Kim <namhyung@gmail.com> <namhyung.kim@lge.com>
+Namhyung Kim <namhyung@gmail.com> <namhyung@kernel.org>
+Nanako Shiraishi <nanako3@lavabit.com> <nanako3@bluebottle.com>
Nanako Shiraishi <nanako3@lavabit.com>
+Nelson Elhage <nelhage@mit.edu> <nelhage@MIT.EDU>
+Nelson Elhage <nelhage@mit.edu> <nelhage@ksplice.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>
+Nick Stokoe <nick@noodlefactory.co.uk> Nick Woolley <nick@noodlefactory.co.uk>
+Nick Stokoe <nick@noodlefactory.co.uk> Nick Woolley <nickwoolley@yahoo.co.uk>
+Nicolas Morey-Chaisemartin <devel-git@morey-chaisemartin.com> <nicolas.morey@free.fr>
+Nicolas Morey-Chaisemartin <devel-git@morey-chaisemartin.com> <nmorey@kalray.eu>
+Nicolas Sebrecht <nicolas.s.dev@gmx.fr> <ni.s@laposte.net>
+Paolo Bonzini <bonzini@gnu.org> <paolo.bonzini@lu.unisi.ch>
+Pascal Obry <pascal@obry.net> <pascal.obry@gmail.com>
+Pascal Obry <pascal@obry.net> <pascal.obry@wanadoo.fr>
+Pat Notz <patnotz@gmail.com> <pknotz@sandia.gov>
+Paul Mackerras <paulus@samba.org> <paulus@dorrigo.(none)>
+Paul Mackerras <paulus@samba.org> <paulus@pogo.(none)>
+Peter Baumann <waste.manager@gmx.de> <Peter.B.Baumann@stud.informatik.uni-erlangen.de>
+Peter Baumann <waste.manager@gmx.de> <siprbaum@stud.informatik.uni-erlangen.de>
Peter Krefting <peter@softwolves.pp.se> <peter@softwolves.pp.se>
+Peter Krefting <peter@softwolves.pp.se> <peter@svarten.intern.softwolves.pp.se>
Petr Baudis <pasky@ucw.cz> <pasky@suse.cz>
+Petr Baudis <pasky@ucw.cz> <xpasky@machine>
+Phil Hord <hordp@cisco.com> <phil.hord@gmail.com>
+Philip Jägenstedt <philip@foolip.org> <philip.jagenstedt@gmail.com>
+Philipp A. Hartmann <pah@qo.cx> <ph@sorgh.de>
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>
+René Scharfe <l.s.r@web.de> <rene.scharfe@lsrfire.ath.cx>
Robert Fitzsimons <robfitz@273k.net>
+Robert Shearman <robertshearman@gmail.com> <rob@codeweavers.com>
Robert Zeh <robert.a.zeh@gmail.com>
-Sam Vilain <sam@vilain.net>
-Santi Béjar <sbejar@gmail.com>
+Robin Rosenberg <robin.rosenberg@dewire.com> <robin.rosenberg.lists@dewire.com>
+Rutger Nijlunsing <rutger.nijlunsing@gmail.com> <rutger@nospam.com>
+Rutger Nijlunsing <rutger.nijlunsing@gmail.com> <git@tux.tmfweb.nl>
+Ryan Anderson <ryan@michonline.com> <rda@google.com>
+Salikh Zakirov <salikh.zakirov@gmail.com> <Salikh.Zakirov@Intel.com>
+Sam Vilain <sam@vilain.net> <sam.vilain@catalyst.net.nz>
+Sam Vilain <sam@vilain.net> sam@vilain.net
+Santi Béjar <santi@agolina.net> <sbejar@gmail.com>
Sean Estabrooks <seanlkml@sympatico.ca>
+Sebastian Schuberth <sschuberth@gmail.com> <sschuberth@visageimaging.com>
+Seth Falcon <seth@userprimary.net> <sfalcon@fhcrc.org>
Shawn O. Pearce <spearce@spearce.org>
-Steven Grimm <koreth@midwinter.com>
+Simon Hausmann <hausmann@kde.org> <simon@lst.de>
+Simon Hausmann <hausmann@kde.org> <shausman@trolltech.com>
+Stefan Naewe <stefan.naewe@gmail.com> <stefan.naewe@atlas-elektronik.com>
+Stefan Naewe <stefan.naewe@gmail.com> <stefan.naewe@googlemail.com>
+Stefan Sperling <stsp@elego.de> <stsp@stsp.name>
+Štěpán Němec <stepnem@gmail.com> <stepan.nemec@gmail.com>
+Stephen Boyd <bebarino@gmail.com> <sboyd@codeaurora.org>
+Steven Drake <sdrake@xnet.co.nz> <sdrake@ihug.co.nz>
+Steven Grimm <koreth@midwinter.com> <sgrimm@sgrimm-mbp.local>
+Steven Grimm <koreth@midwinter.com> koreth@midwinter.com
+Steven Walter <stevenrwalter@gmail.com> <swalter@lexmark.com>
+Steven Walter <stevenrwalter@gmail.com> <swalter@lpdev.prtdev.lexmark.com>
+Sven Verdoolaege <skimo@kotnet.org> <Sven.Verdoolaege@cs.kuleuven.ac.be>
+Sven Verdoolaege <skimo@kotnet.org> <skimo@liacs.nl>
Tay Ray Chuan <rctay89@gmail.com>
+Ted Percival <ted@midg3t.net> <ted.percival@quest.com>
Theodore Ts'o <tytso@mit.edu>
+Thomas Ackermann <th.acker@arcor.de> <th.acker66@arcor.de>
Thomas Rast <trast@inf.ethz.ch> <trast@student.ethz.ch>
+Timo Hirvonen <tihirvon@gmail.com> <tihirvon@ee.oulu.fi>
+Toby Allsopp <Toby.Allsopp@navman.co.nz> <toby.allsopp@navman.co.nz>
+Tom Grennan <tmgrennan@gmail.com> <tgrennan@redback.com>
+Tommi Virtanen <tv@debian.org> <tv@eagain.net>
+Tommi Virtanen <tv@debian.org> <tv@inoi.fi>
+Tommy Thorn <tommy-git@thorn.ws> <tt1729@yahoo.com>
Tony Luck <tony.luck@intel.com>
-Uwe Kleine-König <Uwe_Zeisberger@digi.com>
-Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
-Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
-Uwe Kleine-König <uzeisberger@io.fsforth.de>
-Uwe Kleine-König <zeisberg@informatik.uni-freiburg.de>
-Ville Skyttä <scop@xemacs.org>
+Tor Arne Vestbø <torarnv@gmail.com> <tavestbo@trolltech.com>
+Trent Piepho <tpiepho@gmail.com> <tpiepho@freescale.com>
+Trent Piepho <tpiepho@gmail.com> <xyzzy@speakeasy.org>
+Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <Uwe.Kleine-Koenig@digi.com>
+Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <ukleinek@informatik.uni-freiburg.de>
+Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <uzeisberger@io.fsforth.de>
+Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <zeisberg@informatik.uni-freiburg.de>
+Ville Skyttä <ville.skytta@iki.fi> <scop@xemacs.org>
Vitaly "_Vi" Shukela <public_vi@tut.by>
+W. Trevor King <wking@tremily.us> <wking@drexel.edu>
William Pursell <bill.pursell@gmail.com>
+YONETANI Tomokazu <y0n3t4n1@gmail.com> <qhwt+git@les.ath.cx>
+YONETANI Tomokazu <y0n3t4n1@gmail.com> <y0netan1@dragonflybsd.org>
YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+# the two anonymous contributors are different persons:
anonymous <linux@horizon.com>
anonymous <linux@horizon.net>
+İsmail Dönmez <ismail@pardus.org.tr>
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 7e4d571..e5ca3b7 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -237,8 +237,18 @@ For Python scripts:
Writing Documentation:
- Most (if not all) of the documentation pages are written in AsciiDoc
- and processed into HTML output and manpages.
+ Most (if not all) of the documentation pages are written in the
+ AsciiDoc format in *.txt files (e.g. Documentation/git.txt), and
+ processed into HTML and manpages (e.g. git.html and git.1 in the
+ same directory).
+
+ The documentation liberally mixes US and UK English (en_US/UK)
+ norms for spelling and grammar, which is somewhat unfortunate.
+ In an ideal world, it would have been better if it consistently
+ used only one and not the other, and we would have picked en_US
+ (if you wish to correct the English of some of the existing
+ documentation, please see the documentation-related advice in the
+ Documentation/SubmittingPatches file).
Every user-visible change should be reflected in the documentation.
The same general rule as for code applies -- imitate the existing
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 62dbd9a..0cfdc36 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -31,11 +31,11 @@ MAN7_TXT += gittutorial.txt
MAN7_TXT += gitworkflows.txt
MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
-MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
-MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
+MAN_XML = $(patsubst %.txt,%.xml,$(MAN_TXT))
+MAN_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
OBSOLETE_HTML = git-remote-helpers.html
-DOC_HTML=$(MAN_HTML) $(OBSOLETE_HTML)
+DOC_HTML = $(MAN_HTML) $(OBSOLETE_HTML)
ARTICLES = howto-index
ARTICLES += everyday
@@ -74,35 +74,35 @@ SP_ARTICLES += technical/api-index
DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
-DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
-DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
-DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
-
-prefix?=$(HOME)
-bindir?=$(prefix)/bin
-htmldir?=$(prefix)/share/doc/git-doc
-pdfdir?=$(prefix)/share/doc/git-doc
-mandir?=$(prefix)/share/man
-man1dir=$(mandir)/man1
-man5dir=$(mandir)/man5
-man7dir=$(mandir)/man7
-# DESTDIR=
+DOC_MAN1 = $(patsubst %.txt,%.1,$(MAN1_TXT))
+DOC_MAN5 = $(patsubst %.txt,%.5,$(MAN5_TXT))
+DOC_MAN7 = $(patsubst %.txt,%.7,$(MAN7_TXT))
+
+prefix ?= $(HOME)
+bindir ?= $(prefix)/bin
+htmldir ?= $(prefix)/share/doc/git-doc
+infodir ?= $(prefix)/share/info
+pdfdir ?= $(prefix)/share/doc/git-doc
+mandir ?= $(prefix)/share/man
+man1dir = $(mandir)/man1
+man5dir = $(mandir)/man5
+man7dir = $(mandir)/man7
+# DESTDIR =
ASCIIDOC = asciidoc
ASCIIDOC_EXTRA =
MANPAGE_XSL = manpage-normal.xsl
XMLTO = xmlto
XMLTO_EXTRA =
-INSTALL?=install
+INSTALL ?= install
RM ?= rm -f
MAN_REPO = ../../git-manpages
HTML_REPO = ../../git-htmldocs
-infodir?=$(prefix)/share/info
-MAKEINFO=makeinfo
-INSTALL_INFO=install-info
-DOCBOOK2X_TEXI=docbook2x-texi
-DBLATEX=dblatex
+MAKEINFO = makeinfo
+INSTALL_INFO = install-info
+DOCBOOK2X_TEXI = docbook2x-texi
+DBLATEX = dblatex
ifndef PERL_PATH
PERL_PATH = /usr/bin/perl
endif
diff --git a/Documentation/RelNotes/1.7.10.1.txt b/Documentation/RelNotes/1.7.10.1.txt
index 806a965..be68524 100644
--- a/Documentation/RelNotes/1.7.10.1.txt
+++ b/Documentation/RelNotes/1.7.10.1.txt
@@ -14,7 +14,7 @@ Fixes since v1.7.10
not exclude them and tried to apply funny patches only to fail.
* "git blame" started missing quite a few changes from the origin
- since we stopped using the diff minimalization by default in v1.7.2
+ since we stopped using the diff minimization by default in v1.7.2
era.
* When PATH contains an unreadable directory, alias expansion code
diff --git a/Documentation/RelNotes/1.7.5.4.txt b/Documentation/RelNotes/1.7.5.4.txt
index cf3f455..7796df3 100644
--- a/Documentation/RelNotes/1.7.5.4.txt
+++ b/Documentation/RelNotes/1.7.5.4.txt
@@ -5,7 +5,7 @@ Fixes since v1.7.5.3
--------------------
* The single-key mode of "git add -p" was easily fooled into thinking
- that it was told to add everthing ('a') when up-arrow was pressed by
+ that it was told to add everything ('a') when up-arrow was pressed by
mistake.
* Setting a git command that uses custom configuration via "-c var=val"
diff --git a/Documentation/RelNotes/1.7.8.2.txt b/Documentation/RelNotes/1.7.8.2.txt
index e74f4ef..b9c66aa 100644
--- a/Documentation/RelNotes/1.7.8.2.txt
+++ b/Documentation/RelNotes/1.7.8.2.txt
@@ -12,11 +12,11 @@ Fixes since v1.7.8.1
* The configuration file parser used for sizes (e.g. bigFileThreshold)
did not correctly interpret 'g' suffix.
- * The replacement implemention for snprintf used on platforms with
+ * The replacement implementation for snprintf used on platforms with
native snprintf that is broken did not use va_copy correctly.
* LF-to-CRLF streaming filter replaced all LF with CRLF, which might
- be techinically correct but not friendly to people who are trying
+ be technically correct but not friendly to people who are trying
to recover from earlier mistakes of using CRLF in the repository
data in the first place. It now refrains from doing so for LF that
follows a CR.
diff --git a/Documentation/RelNotes/1.7.8.txt b/Documentation/RelNotes/1.7.8.txt
index b4d90bb..2493113 100644
--- a/Documentation/RelNotes/1.7.8.txt
+++ b/Documentation/RelNotes/1.7.8.txt
@@ -9,7 +9,7 @@ Updates since v1.7.7
* Updates to bash completion scripts.
* The build procedure has been taught to take advantage of computed
- dependency automatically when the complier supports it.
+ dependency automatically when the compiler supports it.
* The date parser now accepts timezone designators that lack minutes
part and also has a colon between "hh:mm".
@@ -31,7 +31,7 @@ Updates since v1.7.7
* Variants of "git cherry-pick" and "git revert" that take multiple
commits learned to "--continue" and "--abort".
- * "git daemon" gives more human readble error messages to clients
+ * "git daemon" gives more human readable error messages to clients
using ERR packets when appropriate.
* Errors at the network layer is logged by "git daemon".
diff --git a/Documentation/RelNotes/1.8.2.1.txt b/Documentation/RelNotes/1.8.2.1.txt
index 1354ad0..769a6fc 100644
--- a/Documentation/RelNotes/1.8.2.1.txt
+++ b/Documentation/RelNotes/1.8.2.1.txt
@@ -49,7 +49,7 @@ Fixes since v1.8.2
common prefix and suffix between the two filenames overlapped.
* "git submodule update", when recursed into sub-submodules, did not
- acccumulate the prefix paths.
+ accumulate the prefix paths.
* "git am $maildir/" applied messages in an unexpected order; sort
filenames read from the maildir/ in a way that is more likely to
diff --git a/Documentation/RelNotes/1.8.2.2.txt b/Documentation/RelNotes/1.8.2.2.txt
index dab4831..708df1a 100644
--- a/Documentation/RelNotes/1.8.2.2.txt
+++ b/Documentation/RelNotes/1.8.2.2.txt
@@ -58,4 +58,4 @@ Fixes since v1.8.2.1
conflicts have been applied.
* "git bundle" did not like a bundle created using a commit without
- any message as its one of the prerequistes.
+ any message as its one of the prerequisites.
diff --git a/Documentation/RelNotes/1.8.3.1.txt b/Documentation/RelNotes/1.8.3.1.txt
new file mode 100644
index 0000000..fc3ea18
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.1.txt
@@ -0,0 +1,14 @@
+Git v1.8.3.1 Release Notes
+========================
+
+Fixes since v1.8.3
+------------------
+
+ * When $HOME is misconfigured to point at an unreadable directory, we
+ used to complain and die. The check has been loosened.
+
+ * Handling of negative exclude pattern for directories "!dir" was
+ broken in the update to v1.8.3.
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
diff --git a/Documentation/RelNotes/1.8.3.2.txt b/Documentation/RelNotes/1.8.3.2.txt
new file mode 100644
index 0000000..26ae142
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.2.txt
@@ -0,0 +1,59 @@
+Git v1.8.3.2 Release Notes
+==========================
+
+Fixes since v1.8.3.1
+--------------------
+
+ * Cloning with "git clone --depth N" while fetch.fsckobjects (or
+ transfer.fsckobjects) is set to true did not tell the cut-off
+ points of the shallow history to the process that validates the
+ objects and the history received, causing the validation to fail.
+
+ * "git checkout foo" DWIMs the intended "upstream" and turns it into
+ "git checkout -t -b foo remotes/origin/foo". This codepath has been
+ updated to correctly take existing remote definitions into account.
+
+ * "git fetch" into a shallow repository from a repository that does
+ not know about the shallow boundary commits (e.g. a different fork
+ from the repository the current shallow repository was cloned from)
+ did not work correctly.
+
+ * "git subtree" (in contrib/) had one codepath with loose error
+ checks to lose data at the remote side.
+
+ * "git log --ancestry-path A...B" did not work as expected, as it did
+ not pay attention to the fact that the merge base between A and B
+ was the bottom of the range being specified.
+
+ * "git diff -c -p" was not showing a deleted line from a hunk when
+ another hunk immediately begins where the earlier one ends.
+
+ * "git merge @{-1}~22" was rewritten to "git merge frotz@{1}~22"
+ incorrectly when your previous branch was "frotz" (it should be
+ rewritten to "git merge frotz~22" instead).
+
+ * "git commit --allow-empty-message -m ''" should not start an
+ editor.
+
+ * "git push --[no-]verify" was not documented.
+
+ * An entry for "file://" scheme in the enumeration of URL types Git
+ can take in the HTML documentation was made into a clickable link
+ by mistake.
+
+ * zsh prompt script that borrowed from bash prompt script did not
+ work due to slight differences in array variable notation between
+ these two shells.
+
+ * The bash prompt code (in contrib/) displayed the name of the branch
+ being rebased when "rebase -i/-m/-p" modes are in use, but not the
+ plain vanilla "rebase".
+
+ * "git push $there HEAD:branch" did not resolve HEAD early enough, so
+ it was easy to flip it around while push is still going on and push
+ out a branch that the user did not originally intended when the
+ command was started.
+
+ * "difftool --dir-diff" did not copy back changes made by the
+ end-user in the diff tool backend to the working tree in some
+ cases.
diff --git a/Documentation/RelNotes/1.8.3.3.txt b/Documentation/RelNotes/1.8.3.3.txt
new file mode 100644
index 0000000..9ba4f4d
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.3.txt
@@ -0,0 +1,47 @@
+Git v1.8.3.3 Release Notes
+==========================
+
+Fixes since v1.8.3.2
+--------------------
+
+ * "git apply" parsed patches that add new files, generated by programs
+ other than Git, incorrectly. This is an old breakage in v1.7.11.
+
+ * Older cURL wanted piece of memory we call it with to be stable, but
+ we updated the auth material after handing it to a call.
+
+ * "git pull" into nothing trashed "local changes" that were in the
+ index.
+
+ * Many "git submodule" operations did not work on a submodule at a
+ path whose name is not in ASCII.
+
+ * "cherry-pick" had a small leak in its error codepath.
+
+ * Logic used by git-send-email to suppress cc mishandled names like
+ "A U. Thor" <author@example.xz>, where the human readable part
+ needs to be quoted (the user input may not have the double quotes
+ around the name, and comparison was done between quoted and
+ unquoted strings). It also mishandled names that need RFC2047
+ quoting.
+
+ * "gitweb" forgot to clear a global variable $search_regexp upon each
+ request, mistakenly carrying over the previous search to a new one
+ when used as a persistent CGI.
+
+ * The wildmatch engine did not honor WM_CASEFOLD option correctly.
+
+ * "git log -c --follow $path" segfaulted upon hitting the commit that
+ renamed the $path being followed.
+
+ * When a reflog notation is used for implicit "current branch",
+ e.g. "git log @{u}", we did not say which branch and worse said
+ "branch ''" in the error messages.
+
+ * Mac OS X does not like to write(2) more than INT_MAX number of
+ bytes; work it around by chopping write(2) into smaller pieces.
+
+ * Newer MacOS X encourages the programs to compile and link with
+ their CommonCrypto, not with OpenSSL.
+
+Also contains various minor documentation updates.
diff --git a/Documentation/RelNotes/1.8.3.4.txt b/Documentation/RelNotes/1.8.3.4.txt
new file mode 100644
index 0000000..56f106e
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.4.txt
@@ -0,0 +1,20 @@
+Git v1.8.3.4 Release Notes
+==========================
+
+This update is mostly to propagate documentation fixes and test
+updates from the master front back to the maintenance track.
+
+Fixes since v1.8.3.3
+--------------------
+
+ * The bisect log listed incorrect commits when bisection ends with
+ only skipped ones.
+
+ * The test coverage framework was left broken for some time.
+
+ * The test suite for HTTP transport did not run with Apache 2.4.
+
+ * "git diff" used to fail when core.safecrlf is set and the working
+ tree contents had mixed CRLF/LF line endings. Committing such a
+ content must be prohibited, but "git diff" should help the user to
+ locate and fix such problems without failing.
diff --git a/Documentation/RelNotes/1.8.3.txt b/Documentation/RelNotes/1.8.3.txt
new file mode 100644
index 0000000..ead568e
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.txt
@@ -0,0 +1,436 @@
+Git v1.8.3 Release Notes
+========================
+
+Backward compatibility notes (for Git 2.0)
+------------------------------------------
+
+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). In Git 2.0, the default will change to the "simple"
+semantics that pushes only the current branch to the branch with the same
+name, and only when the current branch is set to integrate with that
+remote branch. Use the user preference configuration variable
+"push.default" to change this. If you are an old-timer who is used
+to the "matching" semantics, you can set the variable to "matching"
+to keep the traditional behaviour. If you want to live in the future
+early, you can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" (and "git add -A") is run inside a subdirectory and
+does not specify which paths to add on the command line, it
+will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands. There will be no
+mechanism to make plain "git add -u" behave like "git add -u .".
+Current users of "git add -u" (without a pathspec) should start
+training their fingers to explicitly say "git add -u ."
+before Git 2.0 comes. A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
+
+In Git 2.0, "git add <path>" will behave as "git add -A <path>", so
+that "git add dir/" will notice paths you removed from the directory
+and record the removal. Versions before Git 2.0, including this
+release, will keep ignoring removals, but the users who rely on this
+behaviour are encouraged to start using "git add --ignore-removal <path>"
+now before 2.0 is released.
+
+
+Updates since v1.8.2
+--------------------
+
+Foreign interface
+
+ * remote-hg and remote-bzr helpers (in contrib/ since v1.8.2) have
+ been updated; especially, the latter has been done in an
+ accelerated schedule (read: we may not have merged to this release
+ if we were following the usual "cook sufficiently in next before
+ unleashing it to the world" workflow) in order to help Emacs folks,
+ whose primary SCM seems to be stagnating.
+
+
+UI, Workflows & Features
+
+ * A handful of updates applied to gitk, including an addition of
+ "revert" action, showing dates in tags in a nicer way, making
+ colors configurable, and support for -G'pickaxe' search.
+
+ * The prompt string generator (in contrib/completion/) learned to
+ show how many changes there are in total and how many have been
+ replayed during a "git rebase" session.
+
+ * "git branch --vv" learned to paint the name of the branch it
+ integrates with in a different color (color.branch.upstream,
+ which defaults to blue).
+
+ * In a sparsely populated working tree, "git checkout <pathspec>" no
+ longer unmarks paths that match the given pathspec that were
+ originally ignored with "--sparse" (use --ignore-skip-worktree-bits
+ option to resurrect these paths out of the index if you really want
+ to).
+
+ * "git log --format" specifier learned %C(auto) token that tells Git
+ to use color when interpolating %d (decoration), %h (short commit
+ object name), etc. for terminal output.
+
+ * "git bisect" leaves the final outcome as a comment in its bisect
+ log file.
+
+ * "git clone --reference" can now refer to a gitfile "textual symlink"
+ that points at the real location of the repository.
+
+ * "git count-objects" learned "--human-readable" aka "-H" option to
+ show various large numbers in Ki/Mi/GiB scaled as necessary.
+
+ * "git cherry-pick $blob" and "git cherry-pick $tree" are nonsense,
+ and a more readable error message e.g. "can't cherry-pick a tree"
+ is given (we used to say "expected exactly one commit").
+
+ * The "--annotate" option to "git send-email" can be turned on (or
+ off) by default with sendemail.annotate configuration variable (you
+ can use --no-annotate from the command line to override it).
+
+ * The "--cover-letter" option to "git format-patch" can be turned on
+ (or off) by default with format.coverLetter configuration
+ variable. By setting it to 'auto', you can turn it on only for a
+ series with two or more patches.
+
+ * The bash completion support (in contrib/) learned that cherry-pick
+ takes a few more options than it already knew about.
+
+ * "git help" learned "-g" option to show the list of guides just like
+ list of commands are given with "-a".
+
+ * A triangular "pull from one place, push to another place" workflow
+ is supported better by new remote.pushdefault (overrides the
+ "origin" thing) and branch.*.pushremote (overrides the
+ branch.*.remote) configuration variables.
+
+ * "git status" learned to report that you are in the middle of a
+ revert session, just like it does for a cherry-pick and a bisect
+ session.
+
+ * The handling by "git branch --set-upstream-to" against various forms
+ of erroneous inputs was suboptimal and has been improved.
+
+ * When the interactive access to git-shell is not enabled, it issues
+ a message meant to help the system administrator to enable it. An
+ explicit way has been added to issue custom messages to refuse an
+ access over the network to help the end users who connect to the
+ service expecting an interactive shell.
+
+ * In addition to the case where the user edits the log message with
+ the "e)dit" option of "am -i", replace the "Applying: this patch"
+ message with the final log message contents after applymsg hook
+ munges it.
+
+ * "git status" suggests users to look into using --untracked=no option
+ when it takes too long.
+
+ * "git status" shows a bit more information during a rebase/bisect
+ session.
+
+ * "git fetch" learned to fetch a commit at the tip of an unadvertised
+ ref by specifying a raw object name from the command line when the
+ server side supports this feature.
+
+ * Output from "git log --graph" works better with submodule log
+ output now.
+
+ * "git count-objects -v" learned to report leftover temporary
+ packfiles and other garbage in the object store.
+
+ * A new read-only credential helper (in contrib/) to interact with
+ the .netrc/.authinfo files has been added.
+
+ * "git send-email" can be used with the credential helper system.
+
+ * There was no Porcelain way to say "I no longer am interested in
+ this submodule", once you express your interest in a submodule with
+ "submodule init". "submodule deinit" is the way to do so.
+
+ * "git pull --rebase" learned to pass "-v/-q" options to underlying
+ "git rebase".
+
+ * The new "--follow-tags" option tells "git push" to push relevant
+ annotated tags when pushing branches out.
+
+ * "git merge" and "git pull" can optionally be told to inspect and
+ reject when merging a commit that does not carry a trusted GPG
+ signature.
+
+ * "git mergetool" now feeds files to the "p4merge" backend in the
+ order that matches the p4 convention, where "theirs" is usually
+ shown on the left side, which is the opposite from what other backends
+ expect.
+
+ * "show/log" now honors gpg.program configuration just like other
+ parts of the code that use GnuPG.
+
+ * "git log" that shows the difference between the parent and the
+ child has been optimized somewhat.
+
+ * "git difftool" allows the user to write into the temporary files
+ being shown; if the user makes changes to the working tree at the
+ same time, it now refrains from overwriting the copy in the working
+ tree and leaves the temporary file so that changes can be merged
+ manually.
+
+ * There was no good way to ask "I have a random string that came from
+ outside world. I want to turn it into a 40-hex object name while
+ making sure such an object exists". A new peeling suffix ^{object}
+ can be used for that purpose, together with "rev-parse --verify".
+
+
+Performance, Internal Implementation, etc.
+
+ * Updates for building under msvc.
+
+ * A handful of issues in the code that traverses the working tree to find
+ untracked and/or ignored files have been fixed, and the general
+ codepath involved in "status -u" and "clean" have been cleaned up
+ and optimized.
+
+ * The stack footprint of some codepaths that access an object from a
+ pack has been shrunk.
+
+ * The logic to coalesce the same lines removed from the parents in
+ the output from "diff -c/--cc" has been updated, but with O(n^2)
+ complexity, so this might turn out to be undesirable.
+
+ * The code to enforce permission bits on files in $GIT_DIR/ for
+ shared repositories has been simplified.
+
+ * A few codepaths know how much data they need to put in the
+ hashtables they use when they start, but still began with small tables
+ and repeatedly grew and rehashed them.
+
+ * The API to walk reflog entries from the latest to older, which was
+ necessary for operations such as "git checkout -", was cumbersome
+ to use correctly and also inefficient.
+
+ * Codepaths that inspect log-message-to-be and decide when to add a
+ new Signed-off-by line in various commands have been consolidated.
+
+ * The pkt-line API, implementation and its callers have been cleaned
+ up to make them more robust.
+
+ * The Cygwin port has a faster-but-lying lstat(2) emulation whose
+ incorrectness does not matter in practice except for a few
+ codepaths, and setting permission bits on directories is a codepath
+ that needs to use a more correct one.
+
+ * "git checkout" had repeated pathspec matches on the same paths,
+ which have been consolidated. Also a bug in "git checkout dir/"
+ that is started from an unmerged index has been fixed.
+
+ * A few bugfixes to "git rerere" working on corner case merge
+ conflicts have been applied.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.2
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.2 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * Recent versions of File::Temp (used by "git svn") started blowing
+ up when its tempfile sub is called as a class method; updated the
+ callsite to call it as a plain vanilla function to fix it.
+ (merge eafc2dd hb/git-pm-tempfile later to maint).
+
+ * Various subcommands of "git remote" simply ignored extraneous
+ command line arguments instead of diagnosing them as errors.
+
+ * When receive-pack detects an error in the pack header it received in
+ order to decide which of unpack-objects or index-pack to run, it
+ returned without closing the error stream, which led to a hung
+ sideband thread.
+
+ * Zsh completion forgot that the '%' character used to signal untracked
+ files needs to be escaped with another '%'.
+
+ * A commit object whose author or committer ident are malformed
+ crashed some code that trusted that a name, an email and a
+ timestamp can always be found in it.
+
+ * When "upload-pack" fails while generating a pack in response to
+ "git fetch" (or "git clone"), the receiving side had
+ a programming error that triggered the die handler
+ recursively.
+
+ * "rev-list --stdin" and friends kept bogus pointers into the input
+ buffer around as human readable object names. This was not a huge
+ problem but was exposed by a new change that uses these names in
+ error output.
+
+ * Smart-capable HTTP servers were not restricted via the
+ GIT_NAMESPACE mechanism when talking with commit-walking clients,
+ like they are when talking with smart HTTP clients.
+ (merge 6130f86 jk/http-dumb-namespaces later to maint).
+
+ * "git merge-tree" did not omit a merge result that is identical to
+ the "our" side in certain cases.
+ (merge aacecc3 jk/merge-tree-added-identically later to maint).
+
+ * Perl scripts like "git-svn" closed (instead of redirecting to /dev/null)
+ the standard error stream, which is not a very smart thing to do.
+ A later open may return file descriptor #2 for an unrelated purpose, and
+ error reporting code may write into it.
+
+ * "git show-branch" was not prepared to show a very long run of
+ ancestor operators e.g. foobar^2~2^2^2^2...^2~4 correctly.
+
+ * "git diff --diff-algorithm algo" is also understood as "git diff
+ --diff-algorithm=algo".
+
+ * The new core.commentchar configuration was not applied in a few
+ places.
+
+ * "git bundle" erroneously bailed out when parsing a valid bundle
+ containing a prerequisite commit without a commit message.
+
+ * "git log -S/-G" started paying attention to textconv filter, but
+ there was no way to disable this. Make it honor the --no-textconv
+ option.
+
+ * When used with the "-d temporary-directory" option, "git filter-branch"
+ failed to come back to the original working tree to perform the
+ final clean-up procedure.
+
+ * "git merge $(git rev-parse v1.8.2)" behaved quite differently from
+ "git merge v1.8.2", as if v1.8.2 were written as v1.8.2^0 and did
+ not pay much attention to the annotated tag payload. Make the code
+ notice the type of the tag object, in addition to the dwim_ref()
+ based classification the current code uses (i.e. the name appears
+ in refs/tags/) to decide when to special-case tag merging.
+
+ * Fix a 1.8.1.x regression that stopped matching "dir" (without a
+ trailing slash) to a directory "dir".
+
+ * "git apply --whitespace=fix" was not prepared to see a line getting
+ longer after fixing whitespaces (e.g. tab-in-indent aka Python).
+
+ * The prompt string generator (in contrib/completion/) did not notice
+ when we are in a middle of a "git revert" session.
+
+ * "submodule summary --summary-limit" option did not support the
+ "--option=value" form.
+
+ * "index-pack --fix-thin" used an uninitialized value to compute
+ the delta depths of objects it appends to the resulting pack.
+
+ * "index-pack --verify-stat" used a few counters outside the protection
+ of a mutex, possibly showing incorrect numbers.
+
+ * The code to keep track of what directory names are known to Git on
+ platforms with case insensitive filesystems could get confused upon a
+ hash collision between these pathnames and would loop forever.
+
+ * Annotated tags outside the refs/tags/ hierarchy were not advertised
+ correctly to ls-remote and fetch with recent versions of Git.
+
+ * Recent optimizations broke shallow clones.
+
+ * "git cmd -- ':(top'" was not diagnosed as an invalid syntax, and
+ instead the parser kept reading beyond the end of the string.
+
+ * "git tag -f <tag>" always said "Updated tag '<tag>'" even when
+ creating a new tag (i.e. neither overwriting nor updating).
+
+ * "git p4" did not behave well when the path to the root of the P4
+ client was not its real path.
+ (merge bbd8486 pw/p4-symlinked-root later to maint).
+
+ * "git archive" reported a failure when asked to create an archive out
+ of an empty tree. It is more intuitive to give an empty
+ archive back in such a case.
+
+ * When "format-patch" quoted a non-ascii string in header files,
+ it incorrectly applied rfc2047 and chopped a single character in
+ the middle of the string.
+
+ * An aliased command spawned from a bare repository that does not say
+ it is bare with "core.bare = yes" was treated as non-bare by mistake.
+
+ * In "git reflog expire", the REACHABLE bit was not cleared from the
+ correct objects.
+
+ * The logic used by "git diff -M --stat" to shorten the names of
+ files before and after a rename did not work correctly when the
+ common prefix and suffix between the two filenames overlapped.
+
+ * The "--match=<pattern>" option of "git describe", when used with
+ "--all" to allow refs that are not annotated tags to be a
+ base of description, did not restrict the output from the command
+ to those refs that match the given pattern.
+
+ * Clarify in the documentation "what" gets pushed to "where" when the
+ command line to "git push" does not say these explicitly.
+
+ * The "--color=<when>" argument to the commands in the diff family
+ was described poorly.
+
+ * The arguments given to the pre-rebase hook were not documented.
+
+ * The v4 index format was not documented.
+
+ * The "--match=<pattern>" argument "git describe" takes uses glob
+ pattern but it wasn't obvious from the documentation.
+
+ * Some sources failed to compile on systems that lack NI_MAXHOST in
+ their system header (e.g. z/OS).
+
+ * Add an example use of "--env-filter" in "filter-branch"
+ documentation.
+
+ * "git bundle verify" did not say "records a complete history" for a
+ bundle that does not have any prerequisites.
+
+ * In the v1.8.0 era, we changed symbols that do not have to be global
+ to file scope static, but a few functions in graph.c were used by
+ CGit sideways, bypassing the entry points of the API the
+ in-tree users use.
+
+ * "git update-index -h" did not do the usual "-h(elp)" thing.
+
+ * "git index-pack" had a buffer-overflow while preparing an
+ informational message when the translated version of it was too
+ long.
+
+ * 'git commit -m "$msg"' used to add an extra newline even when
+ $msg already ended with one.
+
+ * The SSL peer verification done by "git imap-send" did not ask for
+ Server Name Indication (RFC 4366), failing to connect to SSL/TLS
+ sites that serve multiple hostnames on a single IP.
+
+ * perl/Git.pm::cat_blob slurped everything in core only to write it
+ out to a file descriptor, which was not a very smart thing to do.
+
+ * "git branch" did not bother to check nonsense command line
+ parameters. It now issues errors in many cases.
+
+ * Verification of signed tags was not done correctly when not in C
+ or en/US locale.
+
+ * Some platforms and users spell UTF-8 differently; retry with the
+ most official "UTF-8" when the system does not understand the
+ user-supplied encoding name that is a common alternative
+ spelling of UTF-8.
+
+ * When export-subst is used, "zip" output recorded an incorrect
+ size of the file.
+
+ * "git am $maildir/" applied messages in an unexpected order; sort
+ filenames read from the maildir/ in a way that is more likely to
+ sort the messages in the order the writing MUA meant to, by sorting
+ numeric segments in numeric order and non-numeric segments in
+ alphabetical order.
+
+ * "git submodule update", when recursed into sub-submodules, did not
+ accumulate the prefix paths.
diff --git a/Documentation/RelNotes/1.8.4.txt b/Documentation/RelNotes/1.8.4.txt
new file mode 100644
index 0000000..02f681b
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.txt
@@ -0,0 +1,486 @@
+Git v1.8.4 Release Notes
+========================
+
+Backward compatibility notes (for Git 2.0)
+------------------------------------------
+
+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). In Git 2.0, the default will change to the "simple"
+semantics that pushes:
+
+ - only the current branch to the branch with the same name, and only
+ when the current branch is set to integrate with that remote
+ branch, if you are pushing to the same remote as you fetch from; or
+
+ - only the current branch to the branch with the same name, if you
+ are pushing to a remote that is not where you usually fetch from.
+
+Use the user preference configuration variable "push.default" to
+change this. If you are an old-timer who is used to the "matching"
+semantics, you can set the variable to "matching" to keep the
+traditional behaviour. If you want to live in the future early, you
+can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" (and "git add -A") is run inside a subdirectory and
+does not specify which paths to add on the command line, it
+will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands. There will be no
+mechanism to make plain "git add -u" behave like "git add -u .".
+Current users of "git add -u" (without a pathspec) should start
+training their fingers to explicitly say "git add -u ."
+before Git 2.0 comes. A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
+
+In Git 2.0, "git add <path>" will behave as "git add -A <path>", so
+that "git add dir/" will notice paths you removed from the directory
+and record the removal. Versions before Git 2.0, including this
+release, will keep ignoring removals, but the users who rely on this
+behaviour are encouraged to start using "git add --ignore-removal <path>"
+now before 2.0 is released.
+
+
+Updates since v1.8.3
+--------------------
+
+Foreign interfaces, subsystems and ports.
+
+ * Cygwin port has been updated for more recent Cygwin 1.7.
+
+ * "git rebase -i" now honors --strategy and -X options.
+
+ * Git-gui has been updated to its 0.18.0 version.
+
+ * MediaWiki remote helper (in contrib/) has been updated to use the
+ credential helper interface from Git.pm.
+
+ * Update build for Cygwin 1.[57]. Torsten Bögershausen reports that
+ this is fine with Cygwin 1.7 ($gmane/225824) so let's try moving it
+ ahead.
+
+ * The credential helper to talk to keychain on OS X (in contrib/) has
+ been updated to kick in not just when talking http/https but also
+ imap(s) and smtp.
+
+ * Remote transport helper has been updated to report errors and
+ maintain ref hierarchy used to keep track of its own state better.
+
+ * With "export" remote-helper protocol, (1) a push that tries to
+ update a remote ref whose name is different from the pushing side
+ does not work yet, and (2) the helper may not know how to do
+ --dry-run; these problematic cases are disabled for now.
+
+ * git-remote-hg/bzr (in contrib/) updates.
+
+ * git-remote-mw (in contrib/) hints users to check the certificate,
+ when https:// connection failed.
+
+ * git-remote-mw (in contrib/) adds a command to allow previewing the
+ contents locally before pushing it out, when working with a
+ MediaWiki remote.
+
+
+UI, Workflows & Features
+
+ * Sample "post-receive-email" hook script got an enhanced replacement
+ "multimail" (in contrib/).
+
+ * Also in contrib/ is a new "contacts" script that runs "git blame"
+ to find out the people who may be interested in a set of changes.
+
+ * "git clean" command learned an interactive mode.
+
+ * The "--head" option to "git show-ref" was only to add "HEAD" to the
+ list of candidate refs to be filtered by the usual rules
+ (e.g. "--heads" that only show refs under refs/heads). The meaning
+ of the option has been changed to always show "HEAD" regardless of
+ what filtering will be applied to any other ref.
+
+ This is a backward incompatible change and might cause breakages to
+ people's existing scripts.
+
+ * "git show -s" was less discoverable than it should have been. It
+ now has a natural synonym "git show --no-patch".
+
+ * "git check-mailmap" is a new command that lets you map usernames
+ and e-mail addresses through the mailmap mechanism, just like many
+ built-in commands do.
+
+ * "git name-rev" learned to name an annotated tag object back to its
+ tagname; "git name-rev $(git rev-parse v1.0.0)" gives "tags/v1.0.0",
+ for example.
+
+ * "git cat-file --batch-check=<format>" is added, primarily to allow
+ on-disk footprint of objects in packfiles (often they are a lot
+ smaller than their true size, when expressed as deltas) to be
+ reported.
+
+ * "git rebase [-i]" used to leave just "rebase" as its reflog messages
+ for some operations. They have been reworded to be more informative.
+
+ * In addition to the choice from "rebase, merge, or checkout-detach",
+ "submodule update" can allow a custom command to be used in to
+ update the working tree of submodules via the "submodule.*.update"
+ configuration variable.
+
+ * "git submodule update" can optionally clone the submodule
+ repositories shallowly.
+
+ * "git format-patch" learned "--from[=whom]" option, which sets the
+ "From: " header to the specified person (or the person who runs the
+ command, if "=whom" part is missing) and move the original author
+ information to an in-body From: header as necessary.
+
+ * The configuration variable "merge.ff" was cleary a tri-state to
+ choose one from "favor fast-forward when possible", "always create
+ a merge even when the history could fast-forward" and "do not
+ create any merge, only update when the history fast-forwards", but
+ the command line parser did not implement the usual convention of
+ "last one wins, and command line overrides the configuration"
+ correctly.
+
+ * "gitweb" learned to optionally place extra links that point at the
+ levels higher than the Gitweb pages themselves in the breadcrumbs,
+ so that it can be used as part of a larger installation.
+
+ * "git log --format=" now honors i18n.logoutputencoding configuration
+ variable.
+
+ * The "push.default=simple" mode of "git push" has been updated to
+ behave like "current" without requiring a remote tracking
+ information, when you push to a remote that is different from where
+ you fetch from (i.e. a triangular workflow).
+
+ * Having multiple "fixup!" on a line in the rebase instruction sheet
+ did not work very well with "git rebase -i --autosquash".
+
+ * "git log" learned the "--author-date-order" option, with which the
+ output is topologically sorted and commits in parallel histories
+ are shown intermixed together based on the author timestamp.
+
+ * Various subcommands of "git submodule" refused to run from anywhere
+ other than the top of the working tree of the superproject, but
+ they have been taught to let you run from a subdirectory.
+
+ * "git diff" learned a mode that ignores hunks whose change consists
+ only of additions and removals of blank lines, which is the same as
+ "diff -B" (ignore blank lines) of GNU diff.
+
+ * "git rm" gives a single message followed by list of paths to report
+ multiple paths that cannot be removed.
+
+ * "git rebase" can be told with ":/look for this string" syntax commits
+ to replay the changes onto and where the work to be replayed begins.
+
+ * Many tutorials teach users to set "color.ui" to "auto" as the first
+ thing after you set "user.name/email" to introduce yourselves to
+ Git. Now the variable defaults to "auto".
+
+ * On Cygwin, "cygstart" is now recognised as a possible way to start
+ a web browser (used in "help -w" and "instaweb" among others).
+
+ * "git status" learned status.branch and status.short configuration
+ variables to use --branch and --short options by default (override
+ with --no-branch and --no-short options from the command line).
+
+ * "git cmd <name>", when <name> happens to be a 40-hex string,
+ directly uses the 40-hex string as an object name, even if a ref
+ "refs/<some hierarchy>/<name>" exists. This disambiguation order
+ is unlikely to change, but we should warn about the ambiguity just
+ like we warn when more than one refs/ hierarchies share the same
+ name.
+
+ * "git rebase" learned "--[no-]autostash" option to save local
+ changes instead of refusing to run (to which people's normal
+ response was to stash them and re-run). This introduced a corner
+ case breakage to "git am --abort" but it has been fixed.
+
+ * "check-ignore" (new feature since 1.8.2) has been updated to work
+ more like "check-attr" over bidi-pipes.
+
+ * "git describe" learned "--first-parent" option to limit its closest
+ tagged commit search to the first-parent chain.
+
+ * "git merge foo" that might have meant "git merge origin/foo" is
+ diagnosed with a more informative error message.
+
+ * "git log -L<line>,<range>:<filename>" has been added. This may
+ still have leaks and rough edges, though.
+
+ * We used the approxidate() parser for "--expire=<timestamp>" options
+ of various commands, but it is better to treat --expire=all and
+ --expire=now a bit more specially than using the current timestamp.
+ "git gc" and "git reflog" have been updated with a new parsing
+ function for expiry dates.
+
+ * Updates to completion (both bash and zsh) helpers.
+
+ * The behaviour of the "--chain-reply-to" option of "git send-email"
+ have changed at 1.7.0, and we added a warning/advice message to
+ help users adjust to the new behaviour back then, but we kept it
+ around for too long. The message has finally been removed.
+
+ * "git fetch origin master" unlike "git fetch origin" or "git fetch"
+ did not update "refs/remotes/origin/master"; this was an early
+ design decision to keep the update of remote tracking branches
+ predictable, but in practice it turns out that people find it more
+ convenient to opportunistically update them whenever we have a
+ chance, and we have been updating them when we run "git push" which
+ already breaks the original "predictability" anyway.
+
+ * The configuration variable core.checkstat was advertised in the
+ documentation but the code expected core.statinfo instead.
+ For now, we accept both core.checkstat and core.statinfo, but the
+ latter will be removed in the longer term.
+
+
+Performance, Internal Implementation, etc.
+
+ * On Cygwin, we used to use our own lstat(2) emulation that is
+ allegedly faster than the platform one in codepaths where some of
+ the information it returns did not matter, but it started to bite
+ us in a few codepaths where the trick it uses to cheat does show
+ breakages. This emulation has been removed and we use the native
+ lstat(2) emulation supplied by Cygwin now.
+
+ * The function attributes extensions are used to catch mistakes in
+ use of our own variadic functions that use NULL sentinel at the end
+ (i.e. like execl(3)) and format strings (i.e. like printf(3)).
+
+ * The code to allow configuration data to be read from in-tree blob
+ objects is in. This may help working in a bare repository and
+ submodule updates.
+
+ * Fetching between repositories with many refs employed O(n^2)
+ algorithm to match up the common objects, which has been corrected.
+
+ * The original way to specify remote repository using .git/branches/
+ used to have a nifty feature. The code to support the feature was
+ still in a function but the caller was changed not to call it 5
+ years ago, breaking that feature and leaving the supporting code
+ unreachable. The dead code has been removed.
+
+ * "git pack-refs" that races with new ref creation or deletion have
+ been susceptible to lossage of refs under right conditions, which
+ has been tightened up.
+
+ * We read loose and packed references in two steps, but after
+ deciding to read a loose ref but before actually opening it to read
+ it, another process racing with us can unlink it, which would cause
+ us to barf. The codepath has been updated to retry when such a
+ race is detected, instead of outright failing.
+
+ * Uses of the platform fnmatch(3) function (many places in the code,
+ matching pathspec, .gitignore and .gitattributes to name a few)
+ have been replaced with wildmatch, allowing "foo/**/bar" that would
+ match foo/bar, foo/a/bar, foo/a/b/bar, etc.
+
+ * Memory ownership and lifetime rules for what for-each-ref feeds to
+ its callbacks have been clarified (in short, "you do not own it, so
+ make a copy if you want to keep it").
+
+ * The revision traversal logic to improve culling of irrelevant
+ parents while traversing a mergy history has been updated.
+
+ * Some leaks in unpack-trees (used in merge, cherry-pick and other
+ codepaths) have been plugged.
+
+ * The codepath to read from marks files in fast-import/export did not
+ have to accept anything but 40-hex representation of the object
+ name. Further, fast-export did not need full in-core object
+ representation to have parsed wen reading from them. These
+ codepaths have been optimized by taking advantage of these access
+ patterns.
+
+ * Object lookup logic, when the object hashtable starts to become
+ crowded, has been optimized.
+
+ * When TEST_OUTPUT_DIRECTORY setting is used, it was handled somewhat
+ inconsistently between the test framework and t/Makefile, and logic
+ to summarize the results looked at a wrong place.
+
+ * "git clone" uses a lighter-weight implementation when making sure
+ that the history behind refs are complete.
+
+ * Many warnings from sparse source checker in compat/ area has been
+ squelched.
+
+ * The code to reading and updating packed-refs file has been updated,
+ correcting corner case bugs.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.3
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.3 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * Newer Net::SMTP::SSL module does not want the user programs to use
+ the default behaviour to let server certificate go without
+ verification, so by default enable the verification with a
+ mechanism to turn it off if needed.
+ (merge 35035bb rr/send-email-ssl-verify later to maint).
+
+ * When "git" is spawned in such a way that any of the low 3 file
+ descriptors is closed, our first open() may yield file descriptor 2,
+ and writing error message to it would screw things up in a big way.
+ (merge a11c396 tr/protect-low-3-fds later to maint).
+
+ * The mailmap mechanism unnecessarily downcased the e-mail addresses
+ in the output, and also ignored the human name when it is a single
+ character name.
+ (merge bd23794 jc/mailmap-case-insensitivity later to maint).
+
+ * In two places we did not check return value (expected to be a file
+ descriptor) correctly.
+ (merge a77f106 tr/fd-gotcha-fixes later to maint).
+
+ * Logic to auto-detect character encodings in the commit log message
+ did not reject overlong and invalid UTF-8 characters.
+ (merge 81050ac bc/commit-invalid-utf8 later to maint).
+
+ * Pass port number as a separate argument when "send-email" initializes
+ Net::SMTP, instead of as a part of the hostname, i.e. host:port.
+ This allows GSSAPI codepath to match with the hostname given.
+ (merge 1a741bf bc/send-email-use-port-as-separate-param later to maint).
+
+ * "git diff" refused to even show difference when core.safecrlf is
+ set to true (i.e. error out) and there are offending lines in the
+ working tree files.
+ (merge 5430bb2 jc/maint-diff-core-safecrlf later to maint).
+
+ * A test that should have failed but didn't revealed a bug that needs
+ to be corrected.
+ (merge 94d75d1 jc/t1512-fix later to maint).
+
+ * An overlong path to a .git directory may have overflown the
+ temporary path buffer used to create a name for lockfiles.
+ (merge 2fbd4f9 mh/maint-lockfile-overflow later to maint).
+
+ * Invocations of "git checkout" used internally by "git rebase" were
+ counted as "checkout", and affected later "git checkout -" to the
+ the user to an unexpected place.
+ (merge 3bed291 rr/rebase-checkout-reflog later to maint).
+
+ * The configuration variable column.ui was poorly documented.
+ (merge 5e62cc1 rr/column-doc later to maint).
+
+ * "git name-rev --refs=tags/v*" were forbidden, which was a bit
+ inconvenient (you had to give a pattern to match refs fully, like
+ --refs=refs/tags/v*).
+ (merge 98c5c4a nk/name-rev-abbreviated-refs later to maint).
+
+ * "git apply" parsed patches that add new files, generated by
+ programs other than Git, incorrectly. This is an old breakage in
+ v1.7.11 and will need to be merged down to the maintenance tracks.
+
+ * Older cURL wanted piece of memory we call it with to be stable, but
+ we updated the auth material after handing it to a call.
+
+ * "git pull" into nothing trashed "local changes" that were in the
+ index, and this avoids it.
+
+ * Many "git submodule" operations do not work on a submodule at a
+ path whose name is not in ASCII.
+
+ * "cherry-pick" had a small leak in an error codepath.
+
+ * Logic used by git-send-email to suppress cc mishandled names like
+ "A U. Thor" <author@example.xz>, where the human readable part
+ needs to be quoted (the user input may not have the double quotes
+ around the name, and comparison was done between quoted and
+ unquoted strings). It also mishandled names that need RFC2047
+ quoting.
+
+ * Call to discard_cache/discard_index (used when we use different
+ contents of the index in-core, in many operations like commit,
+ apply, and merge) used to leak memory that held the array of index
+ entries, which has been plugged.
+ (merge a0fc4db rs/discard-index-discard-array later to maint).
+
+ * "gitweb" forgot to clear a global variable $search_regexp upon each
+ request, mistakenly carrying over the previous search to a new one
+ when used as a persistent CGI.
+
+ * The wildmatch engine did not honor WM_CASEFOLD option correctly.
+
+ * "git log -c --follow $path" segfaulted upon hitting the commit that
+ renamed the $path being followed.
+
+ * When a reflog notation is used for implicit "current branch", we
+ did not say which branch and worse said "branch ''".
+
+ * "difftool --dir-diff" did not copy back changes made by the
+ end-user in the diff tool backend to the working tree in some
+ cases.
+
+ * "git push $there HEAD:branch" did not resolve HEAD early enough, so
+ it was easy to flip it around while push is still going on and push
+ out a branch that the user did not originally intended when the
+ command was started.
+
+ * The bash prompt code (in contrib/) displayed the name of the branch
+ being rebased when "rebase -i/-m/-p" modes are in use, but not the
+ plain vanilla "rebase".
+
+ * Handling of negative exclude pattern for directories "!dir" was
+ broken in the update to v1.8.3.
+
+ * zsh prompt script that borrowed from bash prompt script did not
+ work due to slight differences in array variable notation between
+ these two shells.
+
+ * An entry for "file://" scheme in the enumeration of URL types Git
+ can take in the HTML documentation was made into a clickable link
+ by mistake.
+
+ * "git push --[no-]verify" was not documented.
+
+ * Stop installing the git-remote-testpy script that is only used for
+ testing.
+
+ * "git commit --allow-empty-message -m ''" should not start an
+ editor.
+
+ * "git merge @{-1}~22" was rewritten to "git merge frotz@{1}~22"
+ incorrectly when your previous branch was "frotz" (it should be
+ rewritten to "git merge frotz~22" instead).
+
+ * "git diff -c -p" was not showing a deleted line from a hunk when
+ another hunk immediately begins where the earlier one ends.
+
+ * "git log --ancestry-path A...B" did not work as expected, as it did
+ not pay attention to the fact that the merge base between A and B
+ was the bottom of the range being specified.
+
+ * Mac OS X does not like to write(2) more than INT_MAX number of
+ bytes; work it around by chopping write(2) into smaller pieces.
+
+ * Newer MacOS X encourages the programs to compile and link with
+ their CommonCrypto, not with OpenSSL.
+
+ * "git clone foo/bar:baz" cannot be a request to clone from a remote
+ over git-over-ssh specified in the scp style. This case is now
+ detected and clones from a local repository at "foo/bar:baz".
+
+ * When $HOME is misconfigured to point at an unreadable directory, we
+ used to complain and die. Loosen the check.
+
+ * "git subtree" (in contrib/) had one codepath with loose error
+ checks to lose data at the remote side.
+
+ * "git fetch" into a shallow repository from a repository that does
+ not know about the shallow boundary commits (e.g. a different fork
+ from the repository the current shallow repository was cloned from)
+ did not work correctly.
+
+ * "git checkout foo" DWIMs the intended "upstream" and turns it into
+ "git checkout -t -b foo remotes/origin/foo". This codepath has been
+ updated to correctly take existing remote definitions into account.
diff --git a/Documentation/RelNotes/1.8.5.txt b/Documentation/RelNotes/1.8.5.txt
new file mode 100644
index 0000000..a142eee
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.txt
@@ -0,0 +1,221 @@
+Git v1.8.5 Release Notes
+========================
+
+Backward compatibility notes (for Git 2.0)
+------------------------------------------
+
+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). In Git 2.0, the default will change to the "simple"
+semantics that pushes:
+
+ - only the current branch to the branch with the same name, and only
+ when the current branch is set to integrate with that remote
+ branch, if you are pushing to the same remote as you fetch from; or
+
+ - only the current branch to the branch with the same name, if you
+ are pushing to a remote that is not where you usually fetch from.
+
+Use the user preference configuration variable "push.default" to
+change this. If you are an old-timer who is used to the "matching"
+semantics, you can set the variable to "matching" to keep the
+traditional behaviour. If you want to live in the future early, you
+can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" (and "git add -A") is run inside a subdirectory and
+does not specify which paths to add on the command line, it
+will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands. There will be no
+mechanism to make plain "git add -u" behave like "git add -u .".
+Current users of "git add -u" (without a pathspec) should start
+training their fingers to explicitly say "git add -u ."
+before Git 2.0 comes. A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
+
+In Git 2.0, "git add <path>" will behave as "git add -A <path>", so
+that "git add dir/" will notice paths you removed from the directory
+and record the removal. Versions before Git 2.0, including this
+release, will keep ignoring removals, but the users who rely on this
+behaviour are encouraged to start using "git add --ignore-removal <path>"
+now before 2.0 is released.
+
+
+Updates since v1.8.4
+--------------------
+
+Foreign interfaces, subsystems and ports.
+
+ * remote-hg remote helper misbehaved when interacting with a local Hg
+ repository relative to the home directory, e.g. "clone hg::~/there".
+
+ * imap-send ported to OS X uses Apple's security framework instead of
+ OpenSSL one.
+
+ * Subversion 1.8.0 that was recently released breaks older subversion
+ clients coming over http/https in various ways.
+
+ * "git fast-import" treats an empty path given to "ls" as the root of
+ the tree.
+
+
+UI, Workflows & Features
+
+ * "git pull --rebase" always chose to do the bog-standard flattening
+ rebase. You can tell it to run "rebase --preserve-merges" by
+ setting "pull.rebase" configuration to "preserve".
+
+ * "git push --no-thin" actually disables the "thin pack transfer"
+ optimization.
+
+ * Magic pathspecs like ":(icase)makefile" that matches both
+ Makefile and makefile can be used in more places.
+
+ * The "http.*" variables can now be specified per URL that the
+ configuration applies. For example,
+
+ [http]
+ sslVerify = true
+ [http "https://weak.example.com/"]
+ sslVerify = false
+
+ would flip http.sslVerify off only when talking to that specified
+ site.
+
+ * "git mv A B" when moving a submodule A has been taught to
+ relocate its working tree and to adjust the paths in the
+ .gitmodules file.
+
+ * "git blame" can now take more than one -L option to discover the
+ origin of multiple blocks of the lines.
+
+ * The http transport clients can optionally ask to save cookies
+ with http.savecookies configuration variable.
+
+ * "git push" learned a more fine grained control over a blunt
+ "--force" when requesting a non-fast-forward update with the
+ "--force-with-lease=<refname>:<expected object name>" option.
+
+ * "git diff --diff-filter=<classes of changes>" can now take
+ lowercase letters (e.g. "--diff-filter=d") to mean "show
+ everything but these classes". "git diff-files -q" is now a
+ deprecated synonym for "git diff-files --diff-filter=d".
+
+ * "git fetch" (hence "git pull" as well) learned to check
+ "fetch.prune" and "remote.*.prune" configuration variables and
+ to behave as if the "--prune" command line option was given.
+
+ * "git check-ignore -z" applied the NUL termination to both its input
+ (with --stdin) and its output, but "git check-attr -z" ignored the
+ option on the output side. Make both honor -z on the input and
+ output side the same way.
+
+ * "git whatchanged" may still be used by old timers, but mention of
+ it in documents meant for new users will only waste readers' time
+ wonderig what the difference is between it and "git log". Make it
+ less prominent in the general part of the documentation and explain
+ that it is merely a "git log" with different default behaviour in
+ its own document.
+
+
+Performance, Internal Implementation, etc.
+
+ * Many commands use --dashed-option as a operation mode selector
+ (e.g. "git tag --delete") that the user can use at most one
+ (e.g. "git tag --delete --verify" is a nonsense) and you cannot
+ negate (e.g. "git tag --no-delete" is a nonsense). parse-options
+ API learned a new OPT_CMDMODE macro to make it easier to implement
+ such a set of options.
+
+ * OPT_BOOLEAN() in parse-options API was misdesigned to be "counting
+ up" but many subcommands expect it to behave as "on/off". Update
+ them to use OPT_BOOL() which is a proper boolean.
+
+ * "git gc" exits early without doing a double-work when it detects
+ that another instance of itself is already running.
+
+ * Under memory pressure and/or file descriptor pressure, we used to
+ close pack windows that are not used and also closed filehandle to
+ an open but unused packfiles. These are now controlled separately
+ to better cope with the load.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.4
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.4 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * "git ls-files -k" needs to crawl only the part of the working tree
+ that may overlap the paths in the index to find killed files, but
+ shared code with the logic to find all the untracked files, which
+ made it unnecessarily inefficient.
+ (merge 680be04 jc/ls-files-killed-optim later to maint).
+
+ * The commit object names in the insn sheet that was prepared at the
+ beginning of "rebase -i" session can become ambiguous as the
+ rebasing progresses and the repository gains more commits. Make
+ sure the internal record is kept with full 40-hex object names.
+ (merge 75c6976 es/rebase-i-no-abbrev later to maint).
+
+ * "git rebase --preserve-merges" internally used the merge machinery
+ and as a side effect, left merge summary message in the log, but
+ when rebasing, there should not be a need for merge summary.
+ (merge a9f739c rt/rebase-p-no-merge-summary later to maint).
+
+ * A call to xread() was used without a loop around to cope with short
+ read in the codepath to stream new contents to a pack.
+ (merge e92527c js/xread-in-full later to maint).
+
+ * "git rebase -i" forgot that the comment character can be
+ configurable while reading its insn sheet.
+ (merge 7bca7af es/rebase-i-respect-core-commentchar later to maint).
+
+ * The mailmap support code read past the allocated buffer when the
+ mailmap file ended with an incomplete line.
+ (merge f972a16 jk/mailmap-incomplete-line later to maint).
+
+ * We used to send a large request to read(2)/write(2) as a single
+ system call, which was bad from the latency point of view when
+ the operation needs to be killed, and also triggered an error on
+ broken 64-bit systems that refuse to take more than 2GB read or
+ write in one go.
+ (merge a487916 sp/clip-read-write-to-8mb later to maint).
+
+ * "git fetch" that auto-followed tags incorrectly reused the
+ connection with Git-aware transport helper (like the sample "ext::"
+ helper shipped with Git).
+ (merge 0f73f8b jc/transport-do-not-use-connect-twice-in-fetch later to maint).
+
+ * "git log --full-diff -- <pathspec>" showed a huge diff for paths
+ outside the given <pathspec> for each commit, instead of showing
+ the change relative to the parent of the commit. "git reflog -p"
+ had a similar problem.
+ (merge 838f9a1 tr/log-full-diff-keep-true-parents later to maint).
+
+ * Setting submodule.*.path configuration variable to true (without
+ giving "= value") caused Git to segfault.
+ (merge 4b05440 jl/some-submodule-config-are-not-boolean later to maint).
+
+ * "git rebase -i" (there could be others, as the root cause is pretty
+ generic) fed a random, data dependeant string to 'echo' and
+ expects it to come out literally, corrupting its error message.
+ (merge 89b0230 mm/no-shell-escape-in-die-message later to maint).
+
+ * Some people still use rather old versions of bash, which cannot
+ grok some constructs like 'printf -v varname' the prompt and
+ completion code started to use recently.
+ (merge a44aa69 bc/completion-for-bash-3.0 later to maint).
+
+ * Code to read configuration from a blob object did not compile on
+ platforms with fgetc() etc. implemented as macros.
+ (merge 49d6cfa hv/config-from-blob later to maint-1.8.3).
+
+ * The recent "short-cut clone connectivity check" topic broke a
+ shallow repository when a fetch operation tries to auto-follow tags.
+ (merge 6da8bdc nd/fetch-pack-shallow-fix later to maint-1.8.3).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index d0a4733..7055576 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -65,7 +65,20 @@ feature does not trigger when it shouldn't. Also make sure that the
test suite passes after your commit. Do not forget to update the
documentation to describe the updated behaviour.
-Oh, another thing. I am picky about whitespaces. Make sure your
+Speaking of the documentation, it is currently a liberal mixture of US
+and UK English norms for spelling and grammar, which is somewhat
+unfortunate. A huge patch that touches the files all over the place
+only to correct the inconsistency is not welcome, though. Potential
+clashes with other changes that can result from such a patch are not
+worth it. We prefer to gradually reconcile the inconsistencies in
+favor of US English, with small and easily digestible patches, as a
+side effect of doing some other real work in the vicinity (e.g.
+rewriting a paragraph for clarity, while turning en_UK spelling to
+en_US). Obvious typographical fixes are much more welcomed ("teh ->
+"the"), preferably submitted as independent patches separate from
+other documentation changes.
+
+Oh, another thing. We are picky about whitespaces. Make sure your
changes do not trigger errors with the sample pre-commit hook shipped
in templates/hooks--pre-commit. To help ensure this does not happen,
run git diff --check on your changes before you commit.
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index b0d31df..0cebc4f 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -10,27 +10,14 @@
Include additional statistics at the end of blame output.
-L <start>,<end>::
- Annotate only the given line range. <start> and <end> can take
- one of these forms:
-
- - number
-+
-If <start> or <end> is a number, it specifies an
-absolute line number (lines count from 1).
-+
-
-- /regex/
-+
-This form will use the first line matching the given
-POSIX regex. If <end> is a regex, it will search
-starting at the line given by <start>.
-+
-
-- +offset or -offset
+-L :<regex>::
+ Annotate only the given line range. May be specified multiple times.
+ Overlapping ranges are allowed.
+
-This is only valid for <end> and will specify a number
-of lines before or after the line given by <start>.
+<start> and <end> are optional. ``-L <start>'' or ``-L <start>,'' spans from
+<start> to end of file. ``-L ,<end>'' spans from start of file to <end>.
+
+include::line-range-format.txt[]
-l::
Show long rev (Default: off).
diff --git a/Documentation/config.txt b/Documentation/config.txt
index e97facc..9d101a9 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -199,6 +199,9 @@ advice.*::
amWorkDir::
Advice that shows the location of the patch file when
linkgit:git-am[1] fails to apply it.
+ rmHints::
+ In case of failure in the output of linkgit:git-rm[1],
+ show directions on how to proceed from the current state.
--
core.fileMode::
@@ -210,17 +213,6 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
will probe and set core.fileMode false if appropriate when the
repository is created.
-core.ignoreCygwinFSTricks::
- This option is only used by Cygwin implementation of Git. If false,
- the Cygwin stat() and lstat() functions are used. This may be useful
- if your repository consists of a few separate directories joined in
- one hierarchy using Cygwin mount. If true, Git uses native Win32 API
- whenever it is possible and falls back to Cygwin functions only to
- handle symbol links. The native mode is more than twice faster than
- normal Cygwin l/stat() functions. True by default, unless core.filemode
- is true, in which case ignoreCygwinFSTricks is ignored as Cygwin's
- POSIX emulation is required to support core.filemode.
-
core.ignorecase::
If true, this option enables various workarounds to enable
Git to work better on filesystems that are not case sensitive,
@@ -727,9 +719,22 @@ branch.autosetuprebase::
This option defaults to never.
branch.<name>.remote::
- When in branch <name>, it tells 'git fetch' and 'git push' which
- remote to fetch from/push to. It defaults to `origin` if no remote is
- configured. `origin` is also used if you are not on any branch.
+ When on branch <name>, it tells 'git fetch' and 'git push'
+ which remote to fetch from/push to. The remote to push to
+ may be overridden with `remote.pushdefault` (for all branches).
+ The remote to push to, for the current branch, may be further
+ overridden by `branch.<name>.pushremote`. If no remote is
+ configured, or if you are not on any branch, it defaults to
+ `origin` for fetching and `remote.pushdefault` for pushing.
+
+branch.<name>.pushremote::
+ When on branch <name>, it overrides `branch.<name>.remote` for
+ pushing. It also overrides `remote.pushdefault` for pushing
+ from branch <name>. When you pull from one place (e.g. your
+ upstream) and push to another place (e.g. your own publishing
+ repository), you would want to set `remote.pushdefault` to
+ specify the remote to push to for all branches, and use this
+ option to override it for a specific branch.
branch.<name>.merge::
Defines, together with branch.<name>.remote, the upstream branch
@@ -761,6 +766,10 @@ branch.<name>.rebase::
"git pull" is run. See "pull.rebase" for doing this in a non
branch-specific manner.
+
+ When preserve, also pass `--preserve-merges` along to 'git rebase'
+ so that locally committed merge commits will not be flattened
+ by running 'git pull'.
++
*NOTE*: this is a possibly dangerous operation; do *not* use
it unless you understand the implications (see linkgit:git-rebase[1]
for details).
@@ -794,7 +803,8 @@ color.branch::
color.branch.<slot>::
Use customized color for branch coloration. `<slot>` is one of
`current` (the current branch), `local` (a local branch),
- `remote` (a remote-tracking branch in refs/remotes/), `plain` (other
+ `remote` (a remote-tracking branch in refs/remotes/),
+ `upstream` (upstream tracking branch), `plain` (other
refs).
+
The value for these configuration variables is a list of colors (at most
@@ -862,16 +872,17 @@ The values of these variables may be specified as in color.branch.<slot>.
color.interactive::
When set to `always`, always use colors for interactive prompts
- and displays (such as those used by "git-add --interactive").
- When false (or `never`), never. When set to `true` or `auto`, use
- colors only when the output is to the terminal. Defaults to false.
+ and displays (such as those used by "git-add --interactive" and
+ "git-clean --interactive"). When false (or `never`), never.
+ When set to `true` or `auto`, use colors only when the output is
+ to the terminal. Defaults to false.
color.interactive.<slot>::
- Use customized color for 'git add --interactive'
- output. `<slot>` may be `prompt`, `header`, `help` or `error`, for
- four distinct types of normal output from interactive
- commands. The values of these variables may be specified as
- in color.branch.<slot>.
+ Use customized color for 'git add --interactive' and 'git clean
+ --interactive' output. `<slot>` may be `prompt`, `header`, `help`
+ or `error`, for four distinct types of normal output from
+ interactive commands. The values of these variables may be
+ specified as in color.branch.<slot>.
color.pager::
A boolean to enable/disable colored output when the pager is in
@@ -905,17 +916,21 @@ color.ui::
as `color.diff` and `color.grep` that control the use of color
per command family. Its scope will expand as more commands learn
configuration to set a default for the `--color` option. Set it
- to `always` if you want all output not intended for machine
- consumption to use color, to `true` or `auto` if you want such
- output to use color when written to the terminal, or to `false` or
- `never` if you prefer Git commands not to use color unless enabled
- explicitly with some other configuration or the `--color` option.
+ to `false` or `never` if you prefer Git commands not to use
+ color unless enabled explicitly with some other configuration
+ or the `--color` option. Set it to `always` if you want all
+ output not intended for machine consumption to use color, to
+ `true` or `auto` (this is the default since Git 1.8.4) if you
+ want such output to use color when written to the terminal.
column.ui::
Specify whether supported commands should output in columns.
This variable consists of a list of tokens separated by spaces
or commas:
+
+These options control when the feature should be enabled
+(defaults to 'never'):
++
--
`always`;;
always show in columns
@@ -923,24 +938,39 @@ column.ui::
never show in columns
`auto`;;
show in columns if the output is to the terminal
+--
++
+These options control layout (defaults to 'column'). Setting any
+of these implies 'always' if none of 'always', 'never', or 'auto' are
+specified.
++
+--
`column`;;
- fill columns before rows (default)
+ fill columns before rows
`row`;;
fill rows before columns
`plain`;;
show in one column
+--
++
+Finally, these options can be combined with a layout option (defaults
+to 'nodense'):
++
+--
`dense`;;
make unequal size columns to utilize more space
`nodense`;;
make equal size columns
--
-+
-This option defaults to 'never'.
column.branch::
Specify whether to output branch listing in `git branch` in columns.
See `column.ui` for details.
+column.clean::
+ Specify the layout when list items in `git clean -i`, which always
+ shows files and directories in columns. See `column.ui` for details.
+
column.status::
Specify whether to output untracked files in `git status` in columns.
See `column.ui` for details.
@@ -1035,6 +1065,10 @@ fetch.unpackLimit::
especially on slow filesystems. If not set, the value of
`transfer.unpackLimit` is used instead.
+fetch.prune::
+ If true, fetch will automatically behave as if the `--prune`
+ option was given on the command line. See also `remote.<name>.prune`.
+
format.attach::
Enable multipart/mixed attachments as the default for
'format-patch'. The value can also be a double quoted string
@@ -1096,6 +1130,11 @@ format.signoff::
the rights to submit this work under the same open source license.
Please see the 'SubmittingPatches' document for further discussion.
+format.coverLetter::
+ A boolean that controls whether to generate a cover-letter when
+ format-patch is invoked, but in addition can be set to "auto", to
+ generate a cover-letter only when there's more than one patch.
+
filter.<driver>.clean::
The command which is used to convert the content of a worktree
file to a blob upon checkin. See linkgit:gitattributes[5] for
@@ -1414,7 +1453,11 @@ http.cookiefile::
of the file to read cookies from should be plain HTTP headers or
the Netscape/Mozilla cookie file format (see linkgit:curl[1]).
NOTE that the file specified with http.cookiefile is only used as
- input. No cookies will be stored in the file.
+ input unless http.saveCookies is set.
+
+http.savecookies::
+ If set, store cookies received during requests to the file specified by
+ http.cookiefile. Has no effect if http.cookiefile is unset.
http.sslVerify::
Whether to verify the SSL certificate when fetching or pushing
@@ -1447,6 +1490,14 @@ http.sslCAPath::
with when fetching or pushing over HTTPS. Can be overridden
by the 'GIT_SSL_CAPATH' environment variable.
+http.sslTry::
+ Attempt to use AUTH SSL/TLS and encrypted data transfers
+ when connecting via regular FTP protocol. This might be needed
+ if the FTP server requires it for security reasons or you wish
+ to connect securely whenever remote FTP server supports it.
+ Default is false since it might trigger certificate verification
+ errors on misconfigured servers.
+
http.maxRequests::
How many HTTP requests to launch in parallel. Can be overridden
by the 'GIT_HTTP_MAX_REQUESTS' environment variable. Default is 5.
@@ -1486,6 +1537,51 @@ http.useragent::
of common USER_AGENT strings (but not including those like git/1.7.1).
Can be overridden by the 'GIT_HTTP_USER_AGENT' environment variable.
+http.<url>.*::
+ Any of the http.* options above can be applied selectively to some urls.
+ For a config key to match a URL, each element of the config key is
+ compared to that of the URL, in the following order:
++
+--
+. Scheme (e.g., `https` in `https://example.com/`). This field
+ must match exactly between the config key and the URL.
+
+. Host/domain name (e.g., `example.com` in `https://example.com/`).
+ This field must match exactly between the config key and the URL.
+
+. Port number (e.g., `8080` in `http://example.com:8080/`).
+ This field must match exactly between the config key and the URL.
+ Omitted port numbers are automatically converted to the correct
+ default for the scheme before matching.
+
+. Path (e.g., `repo.git` in `https://example.com/repo.git`). The
+ path field of the config key must match the path field of the URL
+ either exactly or as a prefix of slash-delimited path elements. This means
+ a config key with path `foo/` matches URL path `foo/bar`. A prefix can only
+ match on a slash (`/`) boundary. Longer matches take precedence (so a config
+ key with path `foo/bar` is a better match to URL path `foo/bar` than a config
+ key with just path `foo/`).
+
+. User name (e.g., `user` in `https://user@example.com/repo.git`). If
+ the config key has a user name it must match the user name in the
+ URL exactly. If the config key does not have a user name, that
+ config key will match a URL with any user name (including none),
+ but at a lower precedence than a config key with a user name.
+--
++
+The list above is ordered by decreasing precedence; a URL that matches
+a config key's path is preferred to one that matches its user name. For example,
+if the URL is `https://user@example.com/foo/bar` a config key match of
+`https://example.com/foo` will be preferred over a config key match of
+`https://user@example.com`.
++
+All URLs are normalized before attempting any matching (the password part,
+if embedded in the URL, is always ignored for matching purposes) so that
+equivalent urls that are simply spelled differently will match properly.
+Environment variable settings always override any matches. The urls that are
+matched against are those given directly to Git commands. This means any URLs
+visited as a result of a redirection do not participate in matching.
+
i18n.commitEncoding::
Character encoding the commit messages are stored in; Git itself
does not care per se, but this information is necessary e.g. when
@@ -1787,6 +1883,10 @@ pull.rebase::
pull" is run. See "branch.<name>.rebase" for setting this on a
per-branch basis.
+
+ When preserve, also pass `--preserve-merges` along to 'git rebase'
+ so that locally committed merge commits will not be flattened
+ by running 'git pull'.
++
*NOTE*: this is a possibly dangerous operation; do *not* use
it unless you understand the implications (see linkgit:git-rebase[1]
for details).
@@ -1799,39 +1899,59 @@ pull.twohead::
The default merge strategy to use when pulling a single branch.
push.default::
- Defines the action `git push` should take if no refspec is given
- on the command line, no refspec is configured in the remote, and
- no refspec is implied by any of the options given on the command
- line. Possible values are:
+ Defines the action `git push` should take if no refspec is
+ explicitly given. Different values are well-suited for
+ specific workflows; for instance, in a purely central workflow
+ (i.e. the fetch source is equal to the push destination),
+ `upstream` is probably what you want. 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
- shape and then push them out with a single command. It is not
- appropriate for pushing into a repository shared by multiple users,
- since locally stalled branches will attempt a non-fast forward push
- if other users updated the branch.
- +
- This is currently the default, but Git 2.0 will change the default
- to `simple`.
-* `upstream` - push the current branch to its upstream branch
- (`tracking` is a deprecated synonym for this).
- With this, `git push` will update the same remote ref as the one which
- is merged by `git pull`, making `push` and `pull` symmetrical.
- See "branch.<name>.merge" for how to configure the upstream branch.
-* `simple` - like `upstream`, but refuses to push if the upstream
- branch's name is different from the local one. This is the safest
- 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.
---
+
+* `nothing` - do not push anything (error out) unless a refspec is
+ explicitly given. This is primarily meant for people who want to
+ avoid mistakes by always being explicit.
+
+* `current` - push the current branch to update a branch with the same
+ name on the receiving end. Works in both central and non-central
+ workflows.
+
+* `upstream` - push the current branch back to the branch whose
+ changes are usually integrated into the current branch (which is
+ called `@{upstream}`). This mode only makes sense if you are
+ pushing to the same repository you would normally pull from
+ (i.e. central workflow).
+
+* `simple` - in centralized workflow, work like `upstream` with an
+ added safety to refuse to push if the upstream branch's name is
+ different from the local one.
++
+When pushing to a remote that is different from the remote you normally
+pull from, work as `current`. This is the safest option and is suited
+for beginners.
++
+This mode will become the default in Git 2.0.
+
+* `matching` - push all branches having the same name on both ends.
+ This makes the repository you are pushing to remember the set of
+ branches that will be pushed out (e.g. if you always push 'maint'
+ and 'master' there and no other branches, the repository you push
+ to will have these two branches, and your local 'maint' and
+ 'master' will be pushed there).
++
+To use this mode effectively, you have to make sure _all_ the
+branches you would push out are ready to be pushed out before
+running 'git push', as the whole point of this mode is to allow you
+to push all of the branches in one go. If you usually finish work
+on only one branch and push out the result, while other branches are
+unfinished, this mode is not for you. Also this mode is not
+suitable for pushing into a shared central repository, as other
+people may add new branches there, or update the tip of existing
+branches outside your control.
+
-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.
+This is currently the default, but Git 2.0 will change the default
+to `simple`.
+
+--
rebase.stat::
Whether to show a diffstat of what changed upstream since the last
@@ -1840,6 +1960,14 @@ rebase.stat::
rebase.autosquash::
If set to true enable '--autosquash' option by default.
+rebase.autostash::
+ When set to true, automatically create a temporary stash
+ before the operation begins, and apply it after the operation
+ ends. This means that you can run rebase on a dirty worktree.
+ However, use with care: the final stash application after a
+ successful rebase might result in non-trivial conflicts.
+ Defaults to false.
+
receive.autogc::
By default, git-receive-pack will run "git-gc --auto" after
receiving data from git-push and updating refs. You can stop
@@ -1898,6 +2026,11 @@ receive.updateserverinfo::
If set to true, git-receive-pack will run git-update-server-info
after receiving data from git-push and updating refs.
+remote.pushdefault::
+ The remote to push to by default. Overrides
+ `branch.<name>.remote` for all branches, and is overridden by
+ `branch.<name>.pushremote` for specific branches.
+
remote.<name>.url::
The URL of a remote repository. See linkgit:git-fetch[1] or
linkgit:git-push[1].
@@ -1952,6 +2085,12 @@ remote.<name>.vcs::
Setting this to a value <vcs> will cause Git to interact with
the remote with the git-remote-<vcs> helper.
+remote.<name>.prune::
+ When set to true, fetching from this remote by default will also
+ remove any remote-tracking branches which no longer exist on the
+ remote (as if the `--prune` option was give on the command line).
+ Overrides `fetch.prune` settings, if any.
+
remotes.<group>::
The list of remotes which are fetched by "git remote update
<group>". See linkgit:git-remote[1].
@@ -1990,6 +2129,10 @@ sendemail.smtpencryption::
sendemail.smtpssl::
Deprecated alias for 'sendemail.smtpencryption = ssl'.
+sendemail.smtpsslcertpath::
+ Path to ca-certificates (either a directory or a single file).
+ Set it to an empty string to disable certificate verification.
+
sendemail.<identity>.*::
Identity-specific versions of the 'sendemail.*' parameters
found below, taking precedence over those when the this
@@ -1998,6 +2141,7 @@ sendemail.<identity>.*::
sendemail.aliasesfile::
sendemail.aliasfiletype::
+sendemail.annotate::
sendemail.bcc::
sendemail.cc::
sendemail.cccmd::
@@ -2033,6 +2177,14 @@ status.relativePaths::
relative to the repository root (this was the default for Git
prior to v1.5.4).
+status.short::
+ Set to true to enable --short by default in linkgit:git-status[1].
+ The option --no-short takes precedence over this variable.
+
+status.branch::
+ Set to true to enable --branch by default in linkgit:git-status[1].
+ The option --no-branch takes precedence over this variable.
+
status.showUntrackedFiles::
By default, linkgit:git-status[1] and linkgit:git-commit[1] show
files which are not currently tracked by Git. Directories which
@@ -2123,7 +2275,13 @@ uploadpack.hiderefs::
are under the hierarchies listed on the value of this
variable is excluded, and is hidden from `git ls-remote`,
`git fetch`, etc. An attempt to fetch a hidden ref by `git
- fetch` will fail.
+ fetch` will fail. See also `uploadpack.allowtipsha1inwant`.
+
+uploadpack.allowtipsha1inwant::
+ When `uploadpack.hiderefs` is in effect, allow `upload-pack`
+ to accept a fetch request that asks for an object at the tip
+ of a hidden ref (by default, such a request is rejected).
+ see also `uploadpack.hiderefs`.
url.<base>.insteadOf::
Any URL that starts with this value will be rewritten to
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index b8a9b86..bbed2cd 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -26,6 +26,11 @@ ifndef::git-format-patch[]
{git-diff? This is the default.}
endif::git-format-patch[]
+-s::
+--no-patch::
+ Suppress diff output. Useful for commands like `git show` that
+ show the patch by default, or to cancel the effect of `--patch`.
+
-U<n>::
--unified=<n>::
Generate diffs with <n> lines of context instead of
@@ -333,7 +338,7 @@ endif::git-log[]
a fraction, with a decimal point before it. I.e., `-M5` becomes
0.5, and is thus the same as `-M50%`. Similarly, `-M05` is
the same as `-M5%`. To limit detection to exact renames, use
- `-M100%`.
+ `-M100%`. The default similarity index is 50%.
-C[<n>]::
--find-copies[=<n>]::
@@ -383,14 +388,36 @@ ifndef::git-format-patch[]
that matches other criteria, nothing is selected.
-S<string>::
- Look for differences that introduce or remove an instance of
- <string>. Note that this is different than the string simply
- appearing in diff output; see the 'pickaxe' entry in
- linkgit:gitdiffcore[7] for more details.
+ Look for differences that change the number of occurrences of
+ the specified string (i.e. addition/deletion) in a file.
+ Intended for the scripter's use.
++
+It is useful when you're looking for an exact block of code (like a
+struct), and want to know the history of that block since it first
+came into being: use the feature iteratively to feed the interesting
+block in the preimage back into `-S`, and keep going until you get the
+very first version of the block.
-G<regex>::
- Look for differences whose added or removed line matches
- the given <regex>.
+ Look for differences whose patch text contains added/removed
+ lines that match <regex>.
++
+To illustrate the difference between `-S<regex> --pickaxe-regex` and
+`-G<regex>`, consider a commit with the following diff in the same
+file:
++
+----
++ return !regexec(regexp, two->ptr, 1, &regmatch, 0);
+...
+- hit = !regexec(regexp, mf2.ptr, 1, &regmatch, 0);
+----
++
+While `git log -G"regexec\(regexp"` will show this commit, `git log
+-S"regexec\(regexp" --pickaxe-regex` will not (because the number of
+occurrences of that string did not change).
++
+See the 'pickaxe' entry in linkgit:gitdiffcore[7] for more
+information.
--pickaxe-all::
When `-S` or `-G` finds a change, show all the changes in that
@@ -398,8 +425,8 @@ ifndef::git-format-patch[]
in <string>.
--pickaxe-regex::
- Make the <string> not a plain string but an extended POSIX
- regex to match.
+ Treat the <string> given to `-S` as an extended POSIX regular
+ expression to match.
endif::git-format-patch[]
-O<orderfile>::
@@ -439,6 +466,9 @@ endif::git-format-patch[]
differences even if one line has whitespace where the other
line has none.
+--ignore-blank-lines::
+ Ignore changes whose lines are all blank.
+
--inter-hunk-context=<lines>::
Show the context between diff hunks, up to the specified number
of lines, thereby fusing hunks that are close to each other.
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 9cb6496..ba1fe49 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -61,7 +61,7 @@ endif::git-pull[]
ifndef::git-pull[]
-t::
--tags::
- This is a short-hand for giving "refs/tags/*:refs/tags/*"
+ This is a short-hand for giving `refs/tags/*:refs/tags/*`
refspec from the command line, to ask all tags to be fetched
and stored locally. Because this acts as an explicit
refspec, the default refspecs (configured with the
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index b0944e5..48754cb 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -9,9 +9,9 @@ SYNOPSIS
--------
[verse]
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
- [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
- [--refresh] [--ignore-errors] [--ignore-missing] [--]
- [<pathspec>...]
+ [--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]]
+ [--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing]
+ [--] [<pathspec>...]
DESCRIPTION
-----------
@@ -111,6 +111,7 @@ of Git, hence the form without <pathspec> should not be used.
-A::
--all::
+--no-ignore-removal::
Update the index not only where the working tree has a file
matching <pathspec> but also where the index already has an
entry. This adds, modifies, and removes index entries to
@@ -121,6 +122,19 @@ If no <pathspec> is given, the current version of Git defaults to
and its subdirectories. This default will change in a future version
of Git, hence the form without <pathspec> should not be used.
+--no-all::
+--ignore-removal::
+ Update the index by adding new files that are unknown to the
+ index and files modified in the working tree, but ignore
+ files that have been removed from the working tree. This
+ option is a no-op when no <pathspec> is used.
++
+This option is primarily to help the current users of Git, whose
+"git add <pathspec>..." ignores removed files. In future versions
+of Git, "git add <pathspec>..." will be a synonym to "git add -A
+<pathspec>..." and "git add --ignore-removal <pathspec>..." will behave like
+today's "git add <pathspec>...", ignoring removed files.
+
-N::
--intent-to-add::
Record only the fact that the path will be added later. An entry
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 19d57a8..54d8461 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -9,12 +9,12 @@ git-am - Apply a series of patches from a mailbox
SYNOPSIS
--------
[verse]
-'git am' [--signoff] [--keep] [--keep-cr | --no-keep-cr] [--utf8 | --no-utf8]
+'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8]
[--3way] [--interactive] [--committer-date-is-author-date]
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
[--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
- [--scissors | --no-scissors]
+ [--[no-]scissors]
[(<mbox> | <Maildir>)...]
'git am' (--continue | --skip | --abort)
@@ -43,8 +43,7 @@ OPTIONS
--keep-non-patch::
Pass `-b` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
---keep-cr::
---no-keep-cr::
+--[no-]keep-cr::
With `--keep-cr`, call 'git mailsplit' (see linkgit:git-mailsplit[1])
with the same option, to prevent it from stripping CR at the end of
lines. `am.keepcr` configuration variable can be used to specify the
@@ -133,7 +132,7 @@ default. You can use `--no-utf8` to override this.
--resolvemsg=<msg>::
When a patch failure occurs, <msg> will be printed
to the screen before exiting. This overrides the
- standard message informing you to use `--resolved`
+ standard message informing you to use `--continue`
or `--skip` to handle the failure. This is solely
for internal use between 'git rebase' and 'git am'.
@@ -177,7 +176,7 @@ aborts in the middle. You can recover from this in one of two ways:
. hand resolve the conflict in the working directory, and update
the index file to bring it into a state that the patch should
- have produced. Then run the command with the '--resolved' option.
+ have produced. Then run the command with the '--continue' option.
The command refuses to process new mailboxes until the current
operation is finished, so if you decide to start over from scratch,
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 250e522..b97aaab 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git archive' [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>]
- [-o | --output=<file>] [--worktree-attributes]
+ [-o <file> | --output=<file>] [--worktree-attributes]
[--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
[<path>...]
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt
index 0eed3e3..afeb86c 100644
--- a/Documentation/git-bisect-lk2009.txt
+++ b/Documentation/git-bisect-lk2009.txt
@@ -1320,7 +1320,7 @@ So git bisect is unconditional goodness - and feel free to quote that
;-)
_____________
-Acknowledgements
+Acknowledgments
----------------
Many thanks to Junio Hamano for his help in reviewing this paper, for
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 9a05c2b..f2c85cc 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -8,9 +8,9 @@ git-blame - Show what revision and author last modified each line of a file
SYNOPSIS
--------
[verse]
-'git blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental] [-L n,m]
- [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>] [--abbrev=<n>]
- [<rev> | --contents <file> | --reverse <rev>] [--] <file>
+'git blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental]
+ [-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
+ [--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>] [--] <file>
DESCRIPTION
-----------
@@ -18,7 +18,8 @@ DESCRIPTION
Annotates each line in the given file with information from the revision which
last modified the line. Optionally, start annotating from the given revision.
-The command can also limit the range of lines annotated.
+When specified one or more times, `-L` restricts annotation to the requested
+lines.
The origin of lines is automatically followed across whole-file
renames (currently there is no option to turn the rename-following
@@ -130,7 +131,10 @@ SPECIFYING RANGES
Unlike 'git blame' and 'git annotate' in older versions of git, the extent
of the annotation can be limited to both line ranges and revision
-ranges. When you are interested in finding the origin for
+ranges. The `-L` option, which limits annotation to a range of lines, may be
+specified multiple times.
+
+When you are interested in finding the origin for
lines 40-60 for file `foo`, you can use the `-L` option like so
(they mean the same thing -- both ask for 21 lines starting at
line 40):
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 30d585a..21cffe2 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -58,12 +58,16 @@ OPTIONS
to apply the filter to the content recorded in the index at <path>.
--batch::
- Print the SHA-1, type, size, and contents of each object provided on
- stdin. May not be combined with any other options or arguments.
+--batch=<format>::
+ Print object information and contents for each object provided
+ on stdin. May not be combined with any other options or arguments.
+ See the section `BATCH OUTPUT` below for details.
--batch-check::
- Print the SHA-1, type, and size of each object provided on stdin. May not
- be combined with any other options or arguments.
+--batch-check=<format>::
+ Print object information for each object provided on stdin. May
+ not be combined with any other options or arguments. See the
+ section `BATCH OUTPUT` below for details.
OUTPUT
------
@@ -78,28 +82,81 @@ If '-p' is specified, the contents of <object> are pretty-printed.
If <type> is specified, the raw (though uncompressed) contents of the <object>
will be returned.
-If '--batch' is specified, output of the following form is printed for each
-object specified on stdin:
+BATCH OUTPUT
+------------
+
+If `--batch` or `--batch-check` is given, `cat-file` will read objects
+from stdin, one per line, and print information about them. By default,
+the whole line is considered as an object, as if it were fed to
+linkgit:git-rev-parse[1].
+
+You can specify the information shown for each object by using a custom
+`<format>`. The `<format>` is copied literally to stdout for each
+object, with placeholders of the form `%(atom)` expanded, followed by a
+newline. The available atoms are:
+
+`objectname`::
+ The 40-hex object name of the object.
+
+`objecttype`::
+ The type of of the object (the same as `cat-file -t` reports).
+
+`objectsize`::
+ The size, in bytes, of the object (the same as `cat-file -s`
+ reports).
+
+`objectsize:disk`::
+ The size, in bytes, that the object takes up on disk. See the
+ note about on-disk sizes in the `CAVEATS` section below.
+
+`rest`::
+ If this atom is used in the output string, input lines are split
+ at the first whitespace boundary. All characters before that
+ whitespace are considered to be the object name; characters
+ after that first run of whitespace (i.e., the "rest" of the
+ line) are output in place of the `%(rest)` atom.
+
+If no format is specified, the default format is `%(objectname)
+%(objecttype) %(objectsize)`.
+
+If `--batch` is specified, the object information is followed by the
+object contents (consisting of `%(objectsize)` bytes), followed by a
+newline.
+
+For example, `--batch` without a custom format would produce:
------------
<sha1> SP <type> SP <size> LF
<contents> LF
------------
-If '--batch-check' is specified, output of the following form is printed for
-each object specified on stdin:
+Whereas `--batch-check='%(objectname) %(objecttype)'` would produce:
------------
-<sha1> SP <type> SP <size> LF
+<sha1> SP <type> LF
------------
-For both '--batch' and '--batch-check', output of the following form is printed
-for each object specified on stdin that does not exist in the repository:
+If a name is specified on stdin that cannot be resolved to an object in
+the repository, then `cat-file` will ignore any custom format and print:
------------
<object> SP missing LF
------------
+
+CAVEATS
+-------
+
+Note that the sizes of objects on disk are reported accurately, but care
+should be taken in drawing conclusions about which refs or objects are
+responsible for disk usage. The size of a packed non-delta object may be
+much larger than the size of objects which delta against it, but the
+choice of which object is the base and which is the delta is arbitrary
+and is subject to change during a repack. Note also that multiple copies
+of an object may be present in the object database; in this case, it is
+undefined which copy's size will be reported.
+
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 5abdbaa..00e2aa2 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -31,8 +31,9 @@ OPTIONS
Read file names from stdin instead of from the command-line.
-z::
- Only meaningful with `--stdin`; paths are separated with a
- NUL character instead of a linefeed character.
+ The output format is modified to be machine-parseable.
+ If `--stdin` is also given, input paths are separated
+ with a NUL character instead of a linefeed character.
\--::
Interpret all preceding arguments as attributes and all following
@@ -48,6 +49,10 @@ OUTPUT
The output is of the form:
<path> COLON SP <attribute> COLON SP <info> LF
+unless `-z` is in effect, in which case NUL is used as delimiter:
+<path> NUL <attribute> NUL <info> NUL
+
+
<path> is the path of a file being queried, <attribute> is an attribute
being queried and <info> can be either:
@@ -56,6 +61,11 @@ being queried and <info> can be either:
'set';; when the attribute is defined as true.
<value>;; when a value has been assigned to the attribute.
+Buffering happens as documented under the `GIT_FLUSH` option in
+linkgit:git[1]. The caller is responsible for avoiding deadlocks
+caused by overfilling an input buffer or reading from an empty output
+buffer.
+
EXAMPLES
--------
diff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.txt
index 854e4d0..d2df487 100644
--- a/Documentation/git-check-ignore.txt
+++ b/Documentation/git-check-ignore.txt
@@ -39,6 +39,12 @@ OPTIONS
below). If `--stdin` is also given, input paths are separated
with a NUL character instead of a linefeed character.
+-n, --non-matching::
+ Show given paths which don't match any pattern. This only
+ makes sense when `--verbose` is enabled, otherwise it would
+ not be possible to distinguish between paths which match a
+ pattern and those which don't.
+
OUTPUT
------
@@ -65,6 +71,20 @@ are also used instead of colons and hard tabs:
<source> <NULL> <linenum> <NULL> <pattern> <NULL> <pathname> <NULL>
+If `-n` or `--non-matching` are specified, non-matching pathnames will
+also be output, in which case all fields in each output record except
+for <pathname> will be empty. This can be useful when running
+non-interactively, so that files can be incrementally streamed to
+STDIN of a long-running check-ignore process, and for each of these
+files, STDOUT will indicate whether that file matched a pattern or
+not. (Without this option, it would be impossible to tell whether the
+absence of output for a given file meant that it didn't match any
+pattern, or that the output hadn't been generated yet.)
+
+Buffering happens as documented under the `GIT_FLUSH` option in
+linkgit:git[1]. The caller is responsible for avoiding deadlocks
+caused by overfilling an input buffer or reading from an empty output
+buffer.
EXIT STATUS
-----------
@@ -82,7 +102,7 @@ SEE ALSO
--------
linkgit:gitignore[5]
linkgit:gitconfig[5]
-linkgit:git-ls-files[5]
+linkgit:git-ls-files[1]
GIT
---
diff --git a/Documentation/git-check-mailmap.txt b/Documentation/git-check-mailmap.txt
new file mode 100644
index 0000000..39028ee
--- /dev/null
+++ b/Documentation/git-check-mailmap.txt
@@ -0,0 +1,47 @@
+git-check-mailmap(1)
+====================
+
+NAME
+----
+git-check-mailmap - Show canonical names and email addresses of contacts
+
+
+SYNOPSIS
+--------
+[verse]
+'git check-mailmap' [options] <contact>...
+
+
+DESCRIPTION
+-----------
+
+For each ``Name $$<user@host>$$'' or ``$$<user@host>$$'' from the command-line
+or standard input (when using `--stdin`), look up the person's canonical name
+and email address (see "Mapping Authors" below). If found, print them;
+otherwise print the input as-is.
+
+
+OPTIONS
+-------
+--stdin::
+ Read contacts, one per line, from the standard input after exhausting
+ contacts provided on the command-line.
+
+
+OUTPUT
+------
+
+For each contact, a single line is output, terminated by a newline. If the
+name is provided or known to the 'mailmap', ``Name $$<user@host>$$'' is
+printed; otherwise only ``$$<user@host>$$'' is printed.
+
+
+MAPPING AUTHORS
+---------------
+
+include::mailmap.txt[]
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index ec1739a..a49be1b 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -83,8 +83,7 @@ typed the branch name.
OPTIONS
-------
---allow-onelevel::
---no-allow-onelevel::
+--[no-]allow-onelevel::
Controls whether one-level refnames are accepted (i.e.,
refnames that do not contain multiple `/`-separated
components). The default is `--no-allow-onelevel`.
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 8edcdca..ca118ac 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -131,9 +131,9 @@ entries; instead, unmerged entries are ignored.
"--track" in linkgit:git-branch[1] for details.
+
If no '-b' option is given, the name of the new branch will be
-derived from the remote-tracking branch. If "remotes/" or "refs/remotes/"
-is prefixed it is stripped away, and then the part up to the
-next slash (which would be the nickname of the remote) is removed.
+derived from the remote-tracking branch, by looking at the local part of
+the refspec configured for the corresponding remote, and then stripping
+the initial part up to the "*".
This would tell us to use "hack" as the local branch when branching
off of "origin/hack" (or "remotes/origin/hack", or even
"refs/remotes/origin/hack"). If the given name has no slash, or the above
@@ -180,6 +180,12 @@ branch by running "git rm -rf ." from the top level of the working tree.
Afterwards you will be ready to prepare your new files, repopulating the
working tree, by copying them from elsewhere, extracting a tarball, etc.
+--ignore-skip-worktree-bits::
+ In sparse checkout mode, `git checkout -- <paths>` would
+ update only entries matched by <paths> and sparse patterns
+ in $GIT_DIR/info/sparse-checkout. This option ignores
+ the sparse patterns and adds back any files in <paths>.
+
-m::
--merge::
When switching branches,
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index bdc3ab8..8997922 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -8,7 +8,7 @@ git-clean - Remove untracked files from the working tree
SYNOPSIS
--------
[verse]
-'git clean' [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>...
+'git clean' [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>...
DESCRIPTION
-----------
@@ -34,7 +34,13 @@ OPTIONS
-f::
--force::
If the Git configuration variable clean.requireForce is not set
- to false, 'git clean' will refuse to run unless given -f or -n.
+ to false, 'git clean' will refuse to run unless given -f, -n or
+ -i.
+
+-i::
+--interactive::
+ Show what would be done and clean files interactively. See
+ ``Interactive mode'' for details.
-n::
--dry-run::
@@ -63,6 +69,67 @@ OPTIONS
Remove only files ignored by Git. This may be useful to rebuild
everything from scratch, but keep manually created files.
+Interactive mode
+----------------
+When the command enters the interactive mode, it shows the
+files and directories to be cleaned, and goes into its
+interactive command loop.
+
+The command loop shows the list of subcommands available, and
+gives a prompt "What now> ". In general, when the prompt ends
+with a single '>', you can pick only one of the choices given
+and type return, like this:
+
+------------
+ *** Commands ***
+ 1: clean 2: filter by pattern 3: select by numbers
+ 4: ask each 5: quit 6: help
+ What now> 1
+------------
+
+You also could say `c` or `clean` above as long as the choice is unique.
+
+The main command loop has 6 subcommands.
+
+clean::
+
+ Start cleaning files and directories, and then quit.
+
+filter by pattern::
+
+ This shows the files and directories to be deleted and issues an
+ "Input ignore patterns>>" prompt. You can input space-seperated
+ patterns to exclude files and directories from deletion.
+ E.g. "*.c *.h" will excludes files end with ".c" and ".h" from
+ deletion. When you are satisfied with the filtered result, press
+ ENTER (empty) back to the main menu.
+
+select by numbers::
+
+ This shows the files and directories to be deleted and issues an
+ "Select items to delete>>" prompt. When the prompt ends with double
+ '>>' like this, you can make more than one selection, concatenated
+ with whitespace or comma. Also you can say ranges. E.g. "2-5 7,9"
+ to choose 2,3,4,5,7,9 from the list. If the second number in a
+ range is omitted, all remaining items are selected. E.g. "7-" to
+ choose 7,8,9 from the list. You can say '*' to choose everything.
+ Also when you are satisfied with the filtered result, press ENTER
+ (empty) back to the main menu.
+
+ask each::
+
+ This will start to clean, and you must confirm one by one in order
+ to delete items. Please note that this action is not as efficient
+ as the above two actions.
+
+quit::
+
+ This lets you quit without do cleaning.
+
+help::
+
+ Show brief usage of interactive git-clean.
+
SEE ALSO
--------
linkgit:gitignore[5]
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 5c16e31..450f158 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -14,7 +14,7 @@ SYNOPSIS
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
[--separate-git-dir <git dir>]
[--depth <depth>] [--[no-]single-branch]
- [--recursive|--recurse-submodules] [--] <repository>
+ [--recursive | --recurse-submodules] [--] <repository>
[<directory>]
DESCRIPTION
@@ -188,7 +188,7 @@ objects from the source repository into a pack in the cloned repository.
with a long history, and would want to send in fixes
as patches.
---single-branch::
+--[no-]single-branch::
Clone only the history leading to the tip of a single branch,
either specified by the `--branch` option or the primary
branch remote's `HEAD` points at. When creating a shallow
@@ -239,8 +239,8 @@ Examples
* Clone from upstream:
+
------------
-$ git clone git://git.kernel.org/pub/scm/.../linux-2.6 my2.6
-$ cd my2.6
+$ git clone git://git.kernel.org/pub/scm/.../linux.git my-linux
+$ cd my-linux
$ make
------------
@@ -257,10 +257,10 @@ $ git show-branch
* Clone from upstream while borrowing from an existing local directory:
+
------------
-$ git clone --reference my2.6 \
- git://git.kernel.org/pub/scm/.../linux-2.7 \
- my2.7
-$ cd my2.7
+$ git clone --reference /git/linux.git \
+ git://git.kernel.org/pub/scm/.../linux.git \
+ my-linux
+$ cd my-linux
------------
@@ -271,13 +271,6 @@ $ git clone --bare -l /home/proj/.git /pub/scm/proj.git
------------
-* Create a repository on the kernel.org machine that borrows from Linus:
-+
-------------
-$ git clone --bare -l -s /pub/scm/.../torvalds/linux-2.6.git \
- /pub/scm/.../me/subsys-2.6.git
-------------
-
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index 86ef56e..cafdc96 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -10,7 +10,9 @@ SYNOPSIS
--------
[verse]
'git commit-tree' <tree> [(-p <parent>)...] < changelog
-'git commit-tree' [(-p <parent>)...] [(-m <message>)...] [(-F <file>)...] <tree>
+'git commit-tree' [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]
+ [(-F <file>)...] <tree>
+
DESCRIPTION
-----------
@@ -52,6 +54,9 @@ OPTIONS
Read the commit log message from the given file. Use `-` to read
from the standard input.
+-S[<keyid>]::
+ GPG-sign commit.
+
Commit Information
------------------
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 8172938..1a7616c 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -12,7 +12,7 @@ SYNOPSIS
[--dry-run] [(-c | -C | --fixup | --squash) <commit>]
[-F <file> | -m <msg>] [--reset-author] [--allow-empty]
[--allow-empty-message] [--no-verify] [-e] [--author=<author>]
- [--date=<date>] [--cleanup=<mode>] [--status | --no-status]
+ [--date=<date>] [--cleanup=<mode>] [--[no-]status]
[-i | -o] [-S[<keyid>]] [--] [<file>...]
DESCRIPTION
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 772ae2a..e9917b8 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -15,6 +15,7 @@ SYNOPSIS
'git config' [<file-option>] [type] [-z|--null] --get name [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [type] [-z|--null] --get-urlmatch name URL
'git config' [<file-option>] --unset name [value_regex]
'git config' [<file-option>] --unset-all name [value_regex]
'git config' [<file-option>] --rename-section old_name new_name
@@ -95,29 +96,55 @@ OPTIONS
in which section and variable names are lowercased, but subsection
names are not.
+--get-urlmatch name URL::
+ When given a two-part name section.key, the value for
+ section.<url>.key whose <url> part matches the best to the
+ given URL is returned (if no such key exists, the value for
+ section.key is used as a fallback). When given just the
+ section as name, do so for all the keys in the section and
+ list them.
+
--global::
- For writing options: write to global ~/.gitconfig file rather than
- the repository .git/config, write to $XDG_CONFIG_HOME/git/config file
- if this file exists and the ~/.gitconfig file doesn't.
+ For writing options: write to global `~/.gitconfig` file
+ rather than 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 and from
-$XDG_CONFIG_HOME/git/config 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>>.
--system::
- For writing options: write to system-wide $(prefix)/etc/gitconfig
- rather than the repository .git/config.
+ For writing options: write to system-wide
+ `$(prefix)/etc/gitconfig` rather than the repository
+ `.git/config`.
+
-For reading options: read only from system-wide $(prefix)/etc/gitconfig
+For reading options: read only from system-wide `$(prefix)/etc/gitconfig`
rather than from all available files.
+
See also <<FILES>>.
+--local::
+ For writing options: write to the repository `.git/config` file.
+ This is the default behavior.
++
+For reading options: read only from the repository `.git/config` rather than
+from all available files.
++
+See also <<FILES>>.
+
-f config-file::
--file config-file::
Use the given config file instead of the one specified by GIT_CONFIG.
+--blob blob::
+ Similar to '--file' but use the given blob instead of a file. E.g.
+ you can use 'master:.gitmodules' to read values from the file
+ '.gitmodules' in the master branch. See "SPECIFYING REVISIONS"
+ section in linkgit:gitrevisions[7] for a more complete list of
+ ways to spell blob names.
+
--remove-section::
Remove the given section from the configuration file.
@@ -186,8 +213,7 @@ See also <<FILES>>.
Opens an editor to modify the specified config file; either
'--system', '--global', or repository (default).
---includes::
---no-includes::
+--[no-]includes::
Respect `include.*` directives in config files when looking up
values. Defaults to on.
@@ -198,23 +224,23 @@ FILES
If not set explicitly with '--file', there are four files where
'git config' will search for configuration options:
-$GIT_DIR/config::
- Repository specific configuration file.
-
-~/.gitconfig::
- User-specific configuration file. Also called "global"
- configuration file.
+$(prefix)/etc/gitconfig::
+ System-wide 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
+ 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
+ `~/.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.
+~/.gitconfig::
+ User-specific configuration file. Also called "global"
+ configuration file.
+
+$GIT_DIR/config::
+ Repository specific configuration file.
If no further options are given, all reading options will read all of these
files that are available. If the global or the system-wide configuration
@@ -222,6 +248,10 @@ file are not available they will be ignored. If the repository configuration
file is not available or readable, 'git config' will exit with a non-zero
error code. However, in neither case will an error message be issued.
+The files are read in the order given above, with last value found taking
+precedence over values read earlier. When multiple values are taken then all
+values of a key from all files will be used.
+
All writing options will per default write to the repository specific
configuration file. Note that this also affects options like '--replace-all'
and '--unset'. *'git config' will only ever change one file at a time*.
@@ -274,6 +304,13 @@ Given a .git/config like this:
gitproxy=proxy-command for kernel.org
gitproxy=default-proxy ; for all the rest
+ ; HTTP
+ [http]
+ sslVerify
+ [http "https://weak.example.com"]
+ sslVerify = false
+ cookieFile = /tmp/cookie.txt
+
you can set the filemode to true with
------------
@@ -359,6 +396,19 @@ RESET=$(git config --get-color "" "reset")
echo "${WS}your whitespace color or blue reverse${RESET}"
------------
+For URLs in `https://weak.example.com`, `http.sslVerify` is set to
+false, while it is set to `true` for all others:
+
+------------
+% git config --bool --get-urlmatch http.sslverify https://good.example.com
+true
+% git config --bool --get-urlmatch http.sslverify https://weak.example.com
+false
+% git config --get-urlmatch http https://weak.example.com
+http.cookiefile /tmp/cookie.txt
+http.sslverify false
+------------
+
include::config.txt[]
GIT
diff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt
index 23c80ce..b300e84 100644
--- a/Documentation/git-count-objects.txt
+++ b/Documentation/git-count-objects.txt
@@ -8,7 +8,7 @@ git-count-objects - Count unpacked number of objects and their disk consumption
SYNOPSIS
--------
[verse]
-'git count-objects' [-v]
+'git count-objects' [-v] [-H | --human-readable]
DESCRIPTION
-----------
@@ -20,11 +20,29 @@ OPTIONS
-------
-v::
--verbose::
- In addition to the number of loose objects and disk
- space consumed, it reports the number of in-pack
- objects, number of packs, disk space consumed by those packs,
- and number of objects that can be removed by running
- `git prune-packed`.
+ Report in more detail:
++
+count: the number of loose objects
++
+size: disk space consumed by loose objects, in KiB (unless -H is specified)
++
+in-pack: the number of in-pack objects
++
+size-pack: disk space consumed by the packs, in KiB (unless -H is specified)
++
+prune-packable: the number of loose objects that are also present in
+the packs. These objects could be pruned using `git prune-packed`.
++
+garbage: the number of files in object database that are not valid
+loose objects nor valid packs
++
+size-garbage: disk space consumed by garbage files, in KiB (unless -H is
+specified)
+
+-H::
+--human-readable::
+
+Print sizes in human readable format
GIT
---
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index bfb106c..223f731 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -16,8 +16,10 @@ 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>]]
+ [--access-hook=<path>] [--[no-]informative-errors]
+ [--inetd |
+ [--listen=<host_or_ipaddr>] [--port=<n>]
+ [--user=<user> [--group=<group>]]]
[<directory>...]
DESCRIPTION
@@ -169,8 +171,7 @@ Git configuration files in that directory are readable by `<user>`.
repository configuration. By default, all the services
are overridable.
---informative-errors::
---no-informative-errors::
+--[no-]informative-errors::
When informative errors are turned on, git-daemon will report
more verbose errors to the client, differentiating conditions
like "no such repository" from "repository not exported". This
diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index 28e5ec0..9439cd6 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -88,6 +88,11 @@ OPTIONS
--always::
Show uniquely abbreviated commit object as fallback.
+--first-parent::
+ Follow only the first parent commit upon seeing a merge commit.
+ This is useful when you wish to not match tags on branches merged
+ in the history of the target commit.
+
EXAMPLES
--------
@@ -149,7 +154,9 @@ is found, its name will be output and searching will stop.
If an exact match was not found, 'git describe' will walk back
through the commit history to locate an ancestor commit which
has been tagged. The ancestor's tag will be output along with an
-abbreviation of the input committish's SHA-1.
+abbreviation of the input committish's SHA-1. If '--first-parent' was
+specified then the walk will only consider the first parent of each
+commit.
If multiple tags were found during the walk then the tag which
has the fewest commits different from the input committish will be
diff --git a/Documentation/git-diff-index.txt b/Documentation/git-diff-index.txt
index c0b7c58..a86cf62 100644
--- a/Documentation/git-diff-index.txt
+++ b/Documentation/git-diff-index.txt
@@ -3,7 +3,7 @@ git-diff-index(1)
NAME
----
-git-diff-index - Compares content and mode of blobs between the index and repository
+git-diff-index - Compare a tree to the working tree or index
SYNOPSIS
@@ -13,11 +13,11 @@ SYNOPSIS
DESCRIPTION
-----------
-Compares the content and mode of the blobs found via a tree
-object with the content of the current index and, optionally
-ignoring the stat state of the file on disk. When paths are
-specified, compares only those named paths. Otherwise all
-entries in the index are compared.
+Compares the content and mode of the blobs found in a tree object
+with the corresponding tracked files in the working tree, or with the
+corresponding paths in the index. When <path> arguments are present,
+compares only paths matching those patterns. Otherwise all tracked
+files are compared.
OPTIONS
-------
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index a7b4620..78d6d50 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -18,8 +18,8 @@ SYNOPSIS
DESCRIPTION
-----------
Show changes between the working tree and the index or a tree, changes
-between the index and a tree, changes between two trees, or changes
-between two files on disk.
+between the index and a tree, changes between two trees, changes between
+two blob objects, or changes between two files on disk.
'git diff' [--options] [--] [<path>...]::
@@ -56,11 +56,6 @@ directories. This behavior can be forced by --no-index.
This is to view the changes between two arbitrary
<commit>.
-'git diff' [options] <blob> <blob>::
-
- This form is to view the differences between the raw
- contents of two blob objects.
-
'git diff' [--options] <commit>..<commit> [--] [<path>...]::
This is synonymous to the previous form. If <commit> on
@@ -87,6 +82,11 @@ and the range notations ("<commit>..<commit>" and
"<commit>\...<commit>") do not mean a range as defined in the
"SPECIFYING RANGES" section in linkgit:gitrevisions[7].
+'git diff' [options] <blob> <blob>::
+
+ This form is to view the differences between the raw
+ contents of two blob objects.
+
OPTIONS
-------
:git-diff: 1
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index e0e12e9..11887e6 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -69,13 +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::
+--[no-]symlinks::
'git difftool''s default behavior is create symlinks to the
- working tree when run in `--dir-diff` mode.
+ working tree when run in `--dir-diff` mode and the right-hand
+ side of the comparison yields the same content as the file in
+ the working tree.
+
- Specifying `--no-symlinks` instructs 'git difftool' to create
- copies instead. `--no-symlinks` is the default on Windows.
+Specifying `--no-symlinks` instructs 'git difftool' to create copies
+instead. `--no-symlinks` is the default on Windows.
-x <command>::
--extcmd=<command>::
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index d6487e1..85f1f30 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -27,15 +27,17 @@ OPTIONS
Insert 'progress' statements every <n> objects, to be shown by
'git fast-import' during import.
---signed-tags=(verbatim|warn|strip|abort)::
+--signed-tags=(verbatim|warn|warn-strip|strip|abort)::
Specify how to handle signed tags. Since any transformation
after the export can change the tag names (which can also happen
when excluding revisions) the signatures will not match.
+
When asking to 'abort' (which is the default), this program will die
-when encountering a signed tag. With 'strip', the tags will be made
-unsigned, with 'verbatim', they will be silently exported
-and with 'warn', they will be exported, but you will see a warning.
+when encountering a signed tag. With 'strip', the tags will silently
+be made unsigned, with 'warn-strip' they will be made unsigned but a
+warning will be displayed, with 'verbatim', they will be silently
+exported and with 'warn', they will be exported, but you will see a
+warning.
--tag-of-filtered-object=(abort|drop|rewrite)::
Specify how to handle tags whose tagged object is filtered out.
@@ -66,6 +68,8 @@ produced incorrect results if you gave these options.
incremental runs. As <file> is only opened and truncated
at completion, the same path can also be safely given to
\--import-marks.
+ The file will not be written if no new object has been
+ marked/exported.
--import-marks=<file>::
Before processing any input, load the marks specified in
@@ -102,11 +106,11 @@ marks the same across runs.
different from the commit's first parent).
[<git-rev-list-args>...]::
- A list of arguments, acceptable to 'git rev-parse' and
- 'git rev-list', that specifies the specific objects and references
- to export. For example, `master~10..master` causes the
- current master reference to be exported along with all objects
- added since its 10th ancestor commit.
+ A list of arguments, acceptable to 'git rev-parse' and
+ 'git rev-list', that specifies the specific objects and references
+ to export. For example, `master~10..master` causes the
+ current master reference to be exported along with all objects
+ added since its 10th ancestor commit.
EXAMPLES
--------
@@ -137,7 +141,7 @@ Limitations
-----------
Since 'git fast-import' cannot tag trees, you will not be
-able to export the linux-2.6.git repository completely, as it contains
+able to export the linux.git repository completely, as it contains
a tag referencing a tree instead of a commit.
GIT
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index b81e90d..444b805 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -10,9 +10,9 @@ SYNOPSIS
--------
[verse]
'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag]
- [--upload-pack=<git-upload-pack>]
- [--depth=<n>] [--no-progress]
- [-v] [<host>:]<directory> [<refs>...]
+ [--upload-pack=<git-upload-pack>]
+ [--depth=<n>] [--no-progress]
+ [-v] [<host>:]<directory> [<refs>...]
DESCRIPTION
-----------
@@ -90,6 +90,10 @@ be in a separate packet, and the list must end with a flush packet.
--no-progress::
Do not show the progress.
+--check-self-contained-and-connected::
+ Output "connectivity-ok" if the received pack is
+ self-contained and connected.
+
-v::
Run verbosely.
diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt
index 3a0f55e..bb1232a 100644
--- a/Documentation/git-fmt-merge-msg.txt
+++ b/Documentation/git-fmt-merge-msg.txt
@@ -35,8 +35,7 @@ OPTIONS
Do not list one-line descriptions from the actual commits being
merged.
---summary::
---no-summary::
+--[no-]summary::
Synonyms to --log and --no-log; these are deprecated and will be
removed in the future.
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 3a62f50..9e0ef0e 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -20,7 +20,7 @@ SYNOPSIS
[--ignore-if-in-upstream]
[--subject-prefix=Subject-Prefix] [(--reroll-count|-v) <n>]
[--to=<email>] [--cc=<email>]
- [--cover-letter] [--quiet] [--notes[=<ref>]]
+ [--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
[<common diff options>]
[ <since> | <revision range> ]
@@ -187,6 +187,21 @@ will want to ensure that threading is disabled for `git send-email`.
The negated form `--no-cc` discards all `Cc:` headers added so
far (from config or command line).
+--from::
+--from=<ident>::
+ Use `ident` in the `From:` header of each commit email. If the
+ author ident of the commit is not textually identical to the
+ provided `ident`, place a `From:` header in the body of the
+ message with the original author. If no `ident` is given, use
+ the committer ident.
++
+Note that this option is only useful if you are actually sending the
+emails and want to identify yourself as the sender, but retain the
+original author (and `git am` will correctly pick up the in-body
+header). Note also that `git send-email` already handles this
+transformation for you, and this option should not be used if you are
+feeding the result to `git send-email`.
+
--add-header=<header>::
Add an arbitrary header to the email headers. This is in addition
to any configured headers, and may be used multiple times.
@@ -195,7 +210,7 @@ will want to ensure that threading is disabled for `git send-email`.
`Cc:`, and custom) headers added so far from config or command
line.
---cover-letter::
+--[no-]cover-letter::
In addition to the patches, generate a cover letter file
containing the shortlog and the overall diffstat. You can
fill in a description in the file before sending it out.
@@ -227,6 +242,7 @@ configuration options in linkgit:git-notes[1] to use this workflow).
Note that the leading character does not have to be a dot; for example,
you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
+-q::
--quiet::
Do not print the names of the generated files to standard output.
@@ -260,6 +276,7 @@ attachments, and sign off patches with configuration variables.
cc = <email>
attach [ = mime-boundary-string ]
signoff = true
+ coverletter = auto
------------
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt
index e5878bd..25c431d 100644
--- a/Documentation/git-fsck.txt
+++ b/Documentation/git-fsck.txt
@@ -30,8 +30,7 @@ index file, all SHA-1 references in `refs` namespace, and all reflogs
Print out objects that exist but that aren't reachable from any
of the reference nodes.
---dangling::
---no-dangling::
+--[no-]dangling::
Print objects that exist but that are never 'directly' used (default).
`--no-dangling` can be used to omit this information from the output.
@@ -78,8 +77,7 @@ index file, all SHA-1 references in `refs` namespace, and all reflogs
a blob, the contents are written into the file, rather than
its object name.
---progress::
---no-progress::
+--[no-]progress::
Progress status is reported on the standard error stream by
default when it is attached to a terminal, unless
--no-progress or --verbose is specified. --progress forces
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index b370b02..e158a3b 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -9,7 +9,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository
SYNOPSIS
--------
[verse]
-'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune]
+'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] [--force]
DESCRIPTION
-----------
@@ -62,8 +62,9 @@ automatic consolidation of packs.
--prune=<date>::
Prune loose objects older than date (default is 2 weeks ago,
- overridable by the config variable `gc.pruneExpire`). This
- option is on by default.
+ overridable by the config variable `gc.pruneExpire`).
+ --prune=all prunes loose objects regardless of their age.
+ --prune is on by default.
--no-prune::
Do not prune any loose objects.
@@ -71,6 +72,10 @@ automatic consolidation of packs.
--quiet::
Suppress all progress reports.
+--force::
+ Force `git gc` to run even if there may be another `git gc`
+ instance running on this repository.
+
Configuration
-------------
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 50d46e1..8497aa4 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -25,7 +25,7 @@ SYNOPSIS
[-W | --function-context]
[-f <file>] [-e] <pattern>
[--and|--or|--not|(|)|-e <pattern>...]
- [ [--exclude-standard] [--cached | --no-index | --untracked] | <tree>...]
+ [ [--[no-]exclude-standard] [--cached | --no-index | --untracked] | <tree>...]
[--] [<pathspec>...]
DESCRIPTION
diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt
index e07b6dc..b21e9d7 100644
--- a/Documentation/git-help.txt
+++ b/Documentation/git-help.txt
@@ -8,31 +8,45 @@ git-help - Display help information about Git
SYNOPSIS
--------
[verse]
-'git help' [-a|--all|-i|--info|-m|--man|-w|--web] [COMMAND]
+'git help' [-a|--all] [-g|--guide]
+ [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]
DESCRIPTION
-----------
-With no options and no COMMAND given, the synopsis of the 'git'
+With no options and no COMMAND or GUIDE given, the synopsis of the 'git'
command and a list of the most commonly used Git commands are printed
on the standard output.
-If the option '--all' or '-a' is given, then all available commands are
+If the option '--all' or '-a' is given, all available commands are
printed on the standard output.
-If a Git subcommand is named, a manual page for that subcommand is brought
-up. The 'man' program is used by default for this purpose, but this
-can be overridden by other options or configuration variables.
+If the option '--guide' or '-g' is given, a list of the useful
+Git guides is also printed on the standard output.
+
+If a command, or a guide, is given, a manual page for that command or
+guide is brought up. The 'man' program is used by default for this
+purpose, but this can be overridden by other options or configuration
+variables.
Note that `git --help ...` is identical to `git help ...` because the
former is internally converted into the latter.
+To display the linkgit:git[1] man page, use `git help git`.
+
+This page can be displayed with 'git help help' or `git help --help`
+
OPTIONS
-------
-a::
--all::
Prints all the available commands on the standard output. This
- option supersedes any other option.
+ option overrides any given command or guide name.
+
+-g::
+--guides::
+ Prints a list of useful guides on the standard output. This
+ option overrides any given command or guide name.
-i::
--info::
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index bde8eec..7a4e055 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -74,6 +74,9 @@ OPTIONS
--strict::
Die, if the pack contains broken objects or links.
+--check-self-contained-and-connected::
+ Die if the pack contains broken links. For internal use only.
+
--threads=<n>::
Specifies the number of threads to spawn when resolving
deltas. This requires that index-pack be compiled with
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 69db578..34097ef 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -9,7 +9,7 @@ git-log - Show commit logs
SYNOPSIS
--------
[verse]
-'git log' [<options>] [<since>..<until>] [[\--] <path>...]
+'git log' [<options>] [<revision range>] [[\--] <path>...]
DESCRIPTION
-----------
@@ -24,13 +24,6 @@ each commit introduces are shown.
OPTIONS
-------
-<since>..<until>::
- Show only commits between the named two commits. When
- either <since> or <until> is omitted, it defaults to
- `HEAD`, i.e. the tip of the current branch.
- For a more complete list of ways to spell <since>
- and <until>, see linkgit:gitrevisions[7].
-
--follow::
Continue listing the history of a file beyond renames
(works only for a single file).
@@ -69,20 +62,41 @@ produced by --stat etc.
Note that only message is considered, if also a diff is shown
its size is not included.
+-L <start>,<end>:<file>::
+-L :<regex>:<file>::
+
+ Trace the evolution of the line range given by "<start>,<end>"
+ (or the funcname regex <regex>) within the <file>. You may
+ not give any pathspec limiters. This is currently limited to
+ a walk starting from a single revision, i.e., you may only
+ give zero or one positive revision arguments.
+ You can specify this option more than once.
++
+include::line-range-format.txt[]
+
+<revision range>::
+ Show only commits in the specified revision range. When no
+ <revision range> is specified, it defaults to `HEAD` (i.e. the
+ whole history leading to the current commit). `origin..HEAD`
+ specifies all the commits reachable from the current commit
+ (i.e. `HEAD`), but not from `origin`. For a complete list of
+ ways to spell <revision range>, see the "Specifying Ranges"
+ section of linkgit:gitrevisions[7].
+
[\--] <path>...::
Show only commits that are enough to explain how the files
that match the specified paths came to be. See "History
Simplification" below for details and other simplification
modes.
+
-To prevent confusion with options and branch names, paths may need to
-be prefixed with "\-- " to separate them from options or refnames.
+Paths may need to be prefixed with "\-- " to separate them from
+options or the revision range, when confusion arises.
include::rev-list-options.txt[]
include::pretty-formats.txt[]
-Common diff options
+COMMON DIFF OPTIONS
-------------------
:git-log: 1
@@ -90,7 +104,7 @@ include::diff-options.txt[]
include::diff-generate-patch.txt[]
-Examples
+EXAMPLES
--------
`git log --no-merges`::
@@ -113,9 +127,9 @@ Examples
in the "release" branch, along with the list of paths
each commit modifies.
-`git log --follow builtin-rev-list.c`::
+`git log --follow builtin/rev-list.c`::
- Shows the commits that changed builtin-rev-list.c, including
+ Shows the commits that changed builtin/rev-list.c, including
those commits that occurred before the file was given its
present name.
@@ -138,15 +152,20 @@ Examples
This makes sense only when following a strict policy of merging all
topic branches when staying on a single integration branch.
+`git log -L '/int main/',/^}/:main.c`::
+
+ Shows how the function `main()` in the file 'main.c' evolved
+ over time.
+
`git log -3`::
Limits the number of commits to show to 3.
-Discussion
+DISCUSSION
----------
include::i18n.txt[]
-Configuration
+CONFIGURATION
-------------
See linkgit:git-config[1] for core variables and linkgit:git-diff[1]
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index 774de5e..2e22915 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -48,9 +48,9 @@ OPTIONS
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
- the local repository.
+ The "remote" repository to query. This parameter can be
+ either a URL or the name of a remote (see the GIT URLS and
+ REMOTES sections of linkgit:git-fetch[1]).
<refs>...::
When unspecified, all references, after filtering done
@@ -70,9 +70,8 @@ EXAMPLES
$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master pu rc
5fe978a5381f1fbad26a80e682ddd2a401966740 refs/heads/master
c781a84b5204fb294c9ccc79f8b3baceeb32c061 refs/heads/pu
- b1d096f2926c4e37c9c0b6a7bf2119bedaa277cb refs/heads/rc
- $ echo http://www.kernel.org/pub/scm/git/git.git >.git/branches/public
- $ git ls-remote --tags public v\*
+ $ git remote add korg http://www.kernel.org/pub/scm/git/git.git
+ $ git ls-remote --tags korg v\*
d6602ec5194c87b0fc87103ca4d67251c76f233a refs/tags/v0.99
f25a265a342aed6041ab0cc484224d9ca54b6f41 refs/tags/v0.99.1
c5db5456ae3b0873fc659c19fafdde22313cc441 refs/tags/v0.99.2
diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.txt
index 97e7a8e..164a3c6 100644
--- a/Documentation/git-mailinfo.txt
+++ b/Documentation/git-mailinfo.txt
@@ -9,7 +9,7 @@ git-mailinfo - Extracts patch and authorship from a single e-mail message
SYNOPSIS
--------
[verse]
-'git mailinfo' [-k|-b] [-u | --encoding=<encoding> | -n] [--scissors] <msg> <patch>
+'git mailinfo' [-k|-b] [-u | --encoding=<encoding> | -n] [--[no-]scissors] <msg> <patch>
DESCRIPTION
diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt
index d7db2a3..d2fc12e 100644
--- a/Documentation/git-merge-file.txt
+++ b/Documentation/git-merge-file.txt
@@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git merge-file' [-L <current-name> [-L <base-name> [-L <other-name>]]]
[--ours|--theirs|--union] [-p|--stdout] [-q|--quiet] [--marker-size=<n>]
- <current-file> <base-file> <other-file>
+ [--[no-]diff3] <current-file> <base-file> <other-file>
DESCRIPTION
@@ -66,6 +66,9 @@ OPTIONS
-q::
Quiet; do not warn about conflicts.
+--diff3::
+ Show conflicts in "diff3" style.
+
--ours::
--theirs::
--union::
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 42391f2..a74c371 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -56,8 +56,8 @@ especially if those changes were further modified after the merge
was started), 'git merge --abort' will in some cases be unable to
reconstruct the original (pre-merge) changes. Therefore:
-*Warning*: Running 'git merge' with uncommitted changes is
-discouraged: while possible, it leaves you in a state that is hard to
+*Warning*: Running 'git merge' with non-trivial uncommitted changes is
+discouraged: while possible, it may leave you in a state that is hard to
back out of in the case of a conflict.
@@ -76,8 +76,7 @@ The 'git fmt-merge-msg' command can be
used to give a good default for automated 'git merge'
invocations.
---rerere-autoupdate::
---no-rerere-autoupdate::
+--[no-]rerere-autoupdate::
Allow the rerere mechanism to update the index with the
result of auto-conflict resolution if possible.
@@ -187,11 +186,11 @@ In such a case, you can "unwrap" the tag yourself before feeding it
to `git merge`, or pass `--ff-only` when you do not have any work on
your own. e.g.
----
+----
git fetch origin
git merge v1.2.3^0
git merge --ff-only v1.2.3
----
+----
HOW CONFLICTS ARE PRESENTED
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
index 6b563c5..07137f2 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.txt
@@ -8,7 +8,7 @@ git-mergetool - Run merge conflict resolution tools to resolve merge conflicts
SYNOPSIS
--------
[verse]
-'git mergetool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<file>...]
+'git mergetool' [--tool=<tool>] [-y | --[no-]prompt] [<file>...]
DESCRIPTION
-----------
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index e93fcb4..b1f7988 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -13,7 +13,7 @@ SYNOPSIS
DESCRIPTION
-----------
-This script is used to move or rename a file, directory or symlink.
+Move or rename a file, directory or symlink.
git mv [-v] [-f] [-n] [-k] <source> <destination>
git mv [-v] [-f] [-n] [-k] <source> ... <destination directory>
@@ -44,6 +44,14 @@ OPTIONS
--verbose::
Report the names of files as they are moved.
+SUBMODULES
+----------
+Moving a submodule using a gitfile (which means they were cloned
+with a Git version 1.7.8 or newer) will update the gitfile and
+core.worktree setting to make the submodule work in the new location.
+It also will attempt to update the submodule.<name>.path setting in
+the linkgit:gitmodules[5] file and stage that file (unless -n is used).
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index ad1d146..15b00e0 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -25,14 +25,17 @@ OPTIONS
Do not use branch names, but only tags to name the commits
--refs=<pattern>::
- Only use refs whose names match a given shell pattern.
+ Only use refs whose names match a given shell pattern. The pattern
+ can be one of branch name, tag name or fully qualified ref name.
--all::
List all commits reachable from all refs
--stdin::
- Read from stdin, append "(<rev_name>)" to all sha1's of nameable
- commits, and pass to stdout
+ Transform stdin by substituting all the 40-character SHA-1
+ hexes (say $hex) with "$hex ($rev_name)". When used with
+ --name-only, substitute with "$rev_name", omitting $hex
+ altogether. Intended for the scripter's use.
--name-only::
Instead of printing both the SHA-1 and the name, print only
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index c579fbc..8cba16d 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -176,13 +176,16 @@ Sync options
These options can be used in the initial 'clone' as well as in
subsequent 'sync' operations.
---branch <branch>::
- Import changes into given branch. If the branch starts with
- 'refs/', it will be used as is. Otherwise if it does not start
- with 'p4/', that prefix is added. The branch is assumed to
- name a remote tracking, but this can be modified using
- '--import-local', or by giving a full ref name. The default
- branch is 'master'.
+--branch <ref>::
+ Import changes into <ref> instead of refs/remotes/p4/master.
+ If <ref> starts with refs/, it is used as is. Otherwise, if
+ it does not start with p4/, that prefix is added.
++
+By default a <ref> not starting with refs/ is treated as the
+name of a remote-tracking branch (under refs/remotes/). This
+behavior can be modified using the --import-local option.
++
+The default <ref> is "master".
+
This example imports a new remote "p4/proj2" into an existing
Git repository:
diff --git a/Documentation/git-pack-refs.txt b/Documentation/git-pack-refs.txt
index f131677..154081f 100644
--- a/Documentation/git-pack-refs.txt
+++ b/Documentation/git-pack-refs.txt
@@ -33,8 +33,8 @@ Subsequent updates to branches always create new files under
`$GIT_DIR/refs` directory hierarchy.
A recommended practice to deal with a repository with too many
-refs is to pack its refs with `--all --prune` once, and
-occasionally run `git pack-refs --prune`. Tags are by
+refs is to pack its refs with `--all` once, and
+occasionally run `git pack-refs`. Tags are by
definition stationary and are not expected to change. Branch
heads will be packed with the initial `pack-refs --all`, but
only the currently active branch heads will become unpacked,
diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt
index 80d01b0..bf82410 100644
--- a/Documentation/git-prune.txt
+++ b/Documentation/git-prune.txt
@@ -59,7 +59,7 @@ borrows from your repository via its
`.git/objects/info/alternates`:
------------
-$ git prune $(cd ../another && $(git rev-parse --all))
+$ git prune $(cd ../another && git rev-parse --all)
------------
Notes
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 24ab07a..beea10b 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -3,7 +3,7 @@ git-pull(1)
NAME
----
-git-pull - Fetch from and merge with another repository or a local branch
+git-pull - Fetch from and integrate with another repository or a local branch
SYNOPSIS
@@ -102,12 +102,18 @@ include::merge-options.txt[]
:git-pull: 1
-r::
---rebase::
- Rebase the current branch on top of the upstream branch after
- fetching. If there is a remote-tracking branch corresponding to
- the upstream branch and the upstream branch was rebased since last
- fetched, the rebase uses that information to avoid rebasing
- non-local changes.
+--rebase[=false|true|preserve]::
+ When true, rebase the current branch on top of the upstream
+ branch after fetching. If there is a remote-tracking branch
+ corresponding to the upstream branch and the upstream branch
+ was rebased since last fetched, the rebase uses that information
+ to avoid rebasing non-local changes.
++
+When preserve, also rebase the current branch on top of the upstream
+branch, but pass `--preserve-merges` along to `git rebase` so that
+locally created merge commits will not be flattened.
++
+When false, merge the current branch into the upstream branch.
+
See `pull.rebase`, `branch.<name>.rebase` and `branch.autosetuprebase` in
linkgit:git-config[1] if you want to make `git pull` always use
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 577d201..e2992f1 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -9,9 +9,10 @@ git-push - Update remote refs along with associated objects
SYNOPSIS
--------
[verse]
-'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
+'git push' [--all | --mirror | --tags] [--follow-tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [--prune] [-v | --verbose] [-u | --set-upstream]
- [<repository> [<refspec>...]]
+ [--force-with-lease[=<refname>[:<expect>]]]
+ [--no-verify] [<repository> [<refspec>...]]
DESCRIPTION
-----------
@@ -117,6 +118,12 @@ already exists on the remote side.
addition to refspecs explicitly listed on the command
line.
+--follow-tags::
+ Push all the refs that would be pushed without this option,
+ and also push annotated tags in `refs/tags` that are missing
+ from the remote but are pointing at committish that are
+ reachable from the refs being pushed.
+
--receive-pack=<git-receive-pack>::
--exec=<git-receive-pack>::
Path to the 'git-receive-pack' program on the remote
@@ -124,12 +131,75 @@ already exists on the remote side.
repository over ssh, and you do not have the program in
a directory on the default $PATH.
+--[no-]force-with-lease::
+--force-with-lease=<refname>::
+--force-with-lease=<refname>:<expect>::
+ Usually, "git push" refuses to update a remote ref that is
+ not an ancestor of the local ref used to overwrite it.
++
+This option bypasses the check, but instead requires that the
+current value of the ref to be the expected value. "git push"
+fails otherwise.
++
+Imagine that you have to rebase what you have already published.
+You will have to bypass the "must fast-forward" rule in order to
+replace the history you originally published with the rebased history.
+If somebody else built on top of your original history while you are
+rebasing, the tip of the branch at the remote may advance with her
+commit, and blindly pushing with `--force` will lose her work.
++
+This option allows you to say that you expect the history you are
+updating is what you rebased and want to replace. If the remote ref
+still points at the commit you specified, you can be sure that no
+other people did anything to the ref (it is like taking a "lease" on
+the ref without explicitly locking it, and you update the ref while
+making sure that your earlier "lease" is still valid).
++
+`--force-with-lease` alone, without specifying the details, will protect
+all remote refs that are going to be updated by requiring their
+current value to be the same as the remote-tracking branch we have
+for them, unless specified with a `--force-with-lease=<refname>:<expect>`
+option that explicitly states what the expected value is.
++
+`--force-with-lease=<refname>`, without specifying the expected value, will
+protect the named ref (alone), if it is going to be updated, by
+requiring its current value to be the same as the remote-tracking
+branch we have for it.
++
+`--force-with-lease=<refname>:<expect>` will protect the named ref (alone),
+if it is going to be updated, by requiring its current value to be
+the same as the specified value <expect> (which is allowed to be
+different from the remote-tracking branch we have for the refname,
+or we do not even have to have such a remote-tracking branch when
+this form is used).
++
+Note that all forms other than `--force-with-lease=<refname>:<expect>`
+that specifies the expected current value of the ref explicitly are
+still experimental and their semantics may change as we gain experience
+with this feature.
++
+"--no-force-with-lease" will cancel all the previous --force-with-lease on the
+command line.
+
-f::
--force::
Usually, the command refuses to update a remote ref that is
not an ancestor of the local ref used to overwrite it.
- This flag disables the check. This can cause the
- remote repository to lose commits; use it with care.
+ Also, when `--force-with-lease` option is used, the command refuses
+ to update a remote ref whose current value does not match
+ what is expected.
++
+This flag disables these checks, and can cause the remote repository
+to lose commits; use it with care.
++
+Note that `--force` applies to all the refs that are pushed, hence
+using it with `push.default` set to `matching` or with multiple push
+destinations configured with `remote.*.push` may overwrite refs
+other than the current branch (including local refs that are
+strictly behind their remote counterpart). To force a push to only
+one branch, use a `+` in front of the refspec to push (e.g `git push
+origin +master` to force a push to the `master` branch). See the
+`<refspec>...` section above for details.
--repo=<repository>::
This option is only relevant if no <repository> argument is
@@ -156,8 +226,7 @@ useful if you write an alias or script around 'git push'.
linkgit:git-pull[1] and other commands. For more information,
see 'branch.<name>.merge' in linkgit:git-config[1].
---thin::
---no-thin::
+--[no-]thin::
These options are passed to linkgit:git-send-pack[1]. A thin transfer
significantly reduces the amount of sent data when the sender and
receiver share many of the same objects in common. The default is
@@ -190,6 +259,11 @@ useful if you write an alias or script around 'git push'.
be pushed. If on-demand was not able to push all necessary
revisions it will also be aborted and exit with non-zero status.
+--[no-]verify::
+ Toggle the pre-push hook (see linkgit:githooks[5]). The
+ default is \--verify, giving the hook a chance to prevent the
+ push. With \--no-verify, the hook is bypassed completely.
+
include::urls-remotes.txt[]
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index aca8405..6b2e1c8 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -208,6 +208,9 @@ rebase.stat::
rebase.autosquash::
If set to true enable '--autosquash' option by default.
+rebase.autostash::
+ If set to true enable '--autostash' option by default.
+
OPTIONS
-------
--onto <newbase>::
@@ -386,7 +389,9 @@ squash/fixup series.
the same ..., automatically modify the todo list of rebase -i
so that the commit marked for squashing comes right after the
commit to be modified, and change the action of the moved
- commit from `pick` to `squash` (or `fixup`).
+ commit from `pick` to `squash` (or `fixup`). Ignores subsequent
+ "fixup! " or "squash! " after the first, in case you referred to an
+ earlier fixup/squash with `git commit --fixup/--squash`.
+
This option is only valid when the '--interactive' option is used.
+
@@ -394,6 +399,13 @@ If the '--autosquash' option is enabled by default using the
configuration variable `rebase.autosquash`, this option can be
used to override and disable this setting.
+--[no-]autostash::
+ Automatically create a temporary stash before the operation
+ begins, and apply it after the operation ends. This means
+ that you can run rebase on a dirty worktree. However, use
+ with care: the final stash application after a successful
+ rebase might result in non-trivial conflicts.
+
--no-ff::
With --interactive, cherry-pick all rebased commits instead of
fast-forwarding over the unchanged ones. This ensures that the
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index fb8697e..70791b9 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -67,14 +67,19 @@ them.
--expire=<time>::
Entries older than this time are pruned. Without the
option it is taken from configuration `gc.reflogExpire`,
- which in turn defaults to 90 days.
+ which in turn defaults to 90 days. --expire=all prunes
+ entries regardless of their age; --expire=never turns off
+ pruning of reachable entries (but see --expire-unreachable).
--expire-unreachable=<time>::
Entries older than this time and not reachable from
the current tip of the branch are pruned. Without the
option it is taken from configuration
`gc.reflogExpireUnreachable`, which in turn defaults to
- 30 days.
+ 30 days. --expire-unreachable=all prunes unreachable
+ entries regardless of their age; --expire-unreachable=never
+ turns off early pruning of unreachable entries (but see
+ --expire).
--all::
Instead of listing <refs> explicitly, prune all refs.
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 7a6f354..9c3e3bf 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git remote' [-v | --verbose]
-'git remote add' [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>
+'git remote add' [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=<fetch|push>] <name> <url>
'git remote rename' <old> <new>
'git remote remove' <name>
'git remote set-head' <name> (-a | -d | <branch>)
@@ -187,18 +187,25 @@ Examples
$ git remote
origin
$ git branch -r
-origin/master
-$ git remote add linux-nfs git://linux-nfs.org/pub/linux/nfs-2.6.git
+ origin/HEAD -> origin/master
+ origin/master
+$ git remote add staging git://git.kernel.org/.../gregkh/staging.git
$ git remote
-linux-nfs
origin
-$ git fetch
-* refs/remotes/linux-nfs/master: storing branch 'master' ...
- commit: bf81b46
+staging
+$ git fetch staging
+...
+From git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
+ * [new branch] master -> staging/master
+ * [new branch] staging-linus -> staging/staging-linus
+ * [new branch] staging-next -> staging/staging-next
$ git branch -r
-origin/master
-linux-nfs/master
-$ git checkout -b nfs linux-nfs/master
+ origin/HEAD -> origin/master
+ origin/master
+ staging/master
+ staging/staging-linus
+ staging/staging-next
+$ git checkout -b staging staging/master
...
------------
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index a404b47..f445cb3 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git reset' [-q] [<tree-ish>] [--] <paths>...
-'git reset' (--patch | -p) [<tree-sh>] [--] [<paths>...]
+'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]
'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
DESCRIPTION
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 65ac27e..045b37b 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -40,7 +40,7 @@ SYNOPSIS
[ \--right-only ]
[ \--cherry-mark ]
[ \--cherry-pick ]
- [ \--encoding[=<encoding>] ]
+ [ \--encoding=<encoding> ]
[ \--(author|committer|grep)=<pattern> ]
[ \--regexp-ignore-case | -i ]
[ \--extended-regexp | -E ]
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index f2537bb..d068a65 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -24,9 +24,23 @@ distinguish between them.
OPTIONS
-------
+
+Operation Modes
+~~~~~~~~~~~~~~~
+
+Each of these options must appear first on the command line.
+
--parseopt::
Use 'git rev-parse' in option parsing mode (see PARSEOPT section below).
+--sq-quote::
+ Use 'git rev-parse' in shell quoting mode (see SQ-QUOTE
+ section below). In contrast to the `--sq` option below, this
+ mode does only quoting. Nothing else is done to command input.
+
+Options for --parseopt
+~~~~~~~~~~~~~~~~~~~~~~
+
--keep-dashdash::
Only meaningful in `--parseopt` mode. Tells the option parser to echo
out the first `--` met instead of skipping it.
@@ -36,10 +50,8 @@ OPTIONS
the first non-option argument. This can be used to parse sub-commands
that take options themselves.
---sq-quote::
- Use 'git rev-parse' in shell quoting mode (see SQ-QUOTE
- section below). In contrast to the `--sq` option below, this
- mode does only quoting. Nothing else is done to command input.
+Options for Filtering
+~~~~~~~~~~~~~~~~~~~~~
--revs-only::
Do not output flags and parameters not meant for
@@ -55,13 +67,43 @@ OPTIONS
--no-flags::
Do not output flag parameters.
+Options for Output
+~~~~~~~~~~~~~~~~~~
+
--default <arg>::
If there is no parameter given by the user, use `<arg>`
instead.
+--prefix <arg>::
+ Behave as if 'git rev-parse' was invoked from the `<arg>`
+ subdirectory of the working tree. Any relative filenames are
+ resolved as if they are prefixed by `<arg>` and will be printed
+ in that form.
++
+This can be used to convert arguments to a command run in a subdirectory
+so that they can still be used after moving to the top-level of the
+repository. For example:
++
+----
+prefix=$(git rev-parse --show-prefix)
+cd "$(git rev-parse --show-toplevel)"
+eval "set -- $(git rev-parse --sq --prefix "$prefix" "$@")"
+----
+
--verify::
- The parameter given must be usable as a single, valid
- object name. Otherwise barf and abort.
+ Verify that exactly one parameter is provided, and that it
+ can be turned into a raw 20-byte SHA-1 that can be used to
+ access the object database. If so, emit it to the standard
+ output; otherwise, error out.
++
+If you want to make sure that the output actually names an object in
+your object database and/or can be used as a specific type of object
+you require, you can add "^{type}" peeling operator to the parameter.
+For example, `git rev-parse "$VAR^{commit}"` will make sure `$VAR`
+names an existing object that is a commit-ish (i.e. a commit, or an
+annotated tag that points at a commit). To make sure that `$VAR`
+names an existing object of any type, `git rev-parse "$VAR^{object}"`
+can be used.
-q::
--quiet::
@@ -83,6 +125,17 @@ OPTIONS
strip '{caret}' prefix from the object names that already have
one.
+--abbrev-ref[=(strict|loose)]::
+ A non-ambiguous short name of the objects name.
+ The option core.warnAmbiguousRefs is used to select the strict
+ abbreviation mode.
+
+--short::
+--short=number::
+ Instead of outputting the full SHA-1 values of object names try to
+ abbreviate them to a shorter unique name. When no length is specified
+ 7 is used. The minimum length is 4.
+
--symbolic::
Usually the object names are output in SHA-1 form (with
possible '{caret}' prefix); this option makes them output in a
@@ -96,16 +149,8 @@ OPTIONS
unfortunately named tag "master"), and show them as full
refnames (e.g. "refs/heads/master").
---abbrev-ref[=(strict|loose)]::
- A non-ambiguous short name of the objects name.
- 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.
+Options for Objects
+~~~~~~~~~~~~~~~~~~~
--all::
Show all refs found in `refs/`.
@@ -128,18 +173,20 @@ shown. If the pattern does not contain a globbing character (`?`,
character (`?`, `*`, or `[`), it is turned into a prefix
match by appending `/*`.
---show-toplevel::
- Show the absolute path of the top-level directory.
+--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.
---show-prefix::
- When the command is invoked from a subdirectory, show the
- path of the current directory relative to the top-level
- directory.
+Options for Files
+~~~~~~~~~~~~~~~~~
---show-cdup::
- When the command is invoked from a subdirectory, show the
- path of the top-level directory relative to the current
- directory (typically a sequence of "../", or an empty string).
+--local-env-vars::
+ List the GIT_* environment variables that are local to the
+ repository (e.g. GIT_DIR or GIT_WORK_TREE, but not GIT_EDITOR).
+ Only the names of the variables are listed, not their value,
+ even if they are set.
--git-dir::
Show `$GIT_DIR` if defined. Otherwise show the path to
@@ -161,17 +208,27 @@ print a message to stderr and exit with nonzero status.
--is-bare-repository::
When the repository is bare print "true", otherwise "false".
---local-env-vars::
- List the GIT_* environment variables that are local to the
- repository (e.g. GIT_DIR or GIT_WORK_TREE, but not GIT_EDITOR).
- Only the names of the variables are listed, not their value,
- even if they are set.
+--resolve-git-dir <path>::
+ Check if <path> is a valid repository or a gitfile that
+ points at a valid repository, and print the location of the
+ repository. If <path> is a gitfile then the resolved path
+ to the real repository is printed.
---short::
---short=number::
- Instead of outputting the full SHA-1 values of object names try to
- abbreviate them to a shorter unique name. When no length is specified
- 7 is used. The minimum length is 4.
+--show-cdup::
+ When the command is invoked from a subdirectory, show the
+ path of the top-level directory relative to the current
+ directory (typically a sequence of "../", or an empty string).
+
+--show-prefix::
+ When the command is invoked from a subdirectory, show the
+ path of the current directory relative to the top-level
+ directory.
+
+--show-toplevel::
+ Show the absolute path of the top-level directory.
+
+Other Options
+~~~~~~~~~~~~~
--since=datestring::
--after=datestring::
@@ -186,12 +243,6 @@ print a message to stderr and exit with nonzero status.
<args>...::
Flags and parameters to be parsed.
---resolve-git-dir <path>::
- Check if <path> is a valid repository or a gitfile that
- points at a valid repository, and print the location of the
- repository. If <path> is a gitfile then the resolved path
- to the real repository is printed.
-
include::revisions.txt[]
@@ -308,12 +359,12 @@ $ git rev-parse --verify HEAD
* Print the commit object name from the revision in the $REV shell variable:
+
------------
-$ git rev-parse --verify $REV
+$ git rev-parse --verify $REV^{commit}
------------
+
This will error out if $REV is empty or not a valid revision.
-* Same as above:
+* Similar to above:
+
------------
$ git rev-parse --default master --verify $REV
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 70152e8..f79c9d8 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -8,7 +8,7 @@ git-revert - Revert some existing commits
SYNOPSIS
--------
[verse]
-'git revert' [--edit | --no-edit] [-n] [-m parent-number] [-s] <commit>...
+'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] <commit>...
'git revert' --continue
'git revert' --quit
'git revert' --abort
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index 92bac27..9d731b4 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -134,14 +134,16 @@ use the following command:
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached
----------------
-Submodules
-~~~~~~~~~~
+SUBMODULES
+----------
Only submodules using a gitfile (which means they were cloned
with a Git version 1.7.8 or newer) will be removed from the work
tree, as their repository lives inside the .git directory of the
superproject. If a submodule (or one of those nested inside it)
still uses a .git directory, `git rm` will fail - no matter if forced
-or not - to protect the submodule's history.
+or not - to protect the submodule's history. If it exists the
+submodule.<name> section in the linkgit:gitmodules[5] file will also
+be removed and that file will be staged (unless --cached or -n are used).
A submodule is considered up-to-date when the HEAD is the same as
recorded in the index, no tracked files are modified and no untracked
@@ -149,6 +151,10 @@ files that aren't ignored are present in the submodules work tree.
Ignored files are deemed expendable and won't stop a submodule's work
tree from being removed.
+If you only want to remove the local checkout of a submodule from your
+work tree without committing the removal,
+use linkgit:git-submodule[1] `deinit` instead.
+
EXAMPLES
--------
`git rm Documentation/\*.txt`::
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 44a1f7c..f0e57a5 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -45,8 +45,9 @@ Composing
~~~~~~~~~
--annotate::
- Review and edit each patch you're about to send. See the
- CONFIGURATION section for 'sendemail.multiedit'.
+ Review and edit each patch you're about to send. Default is the value
+ of 'sendemail.annotate'. See the CONFIGURATION section for
+ 'sendemail.multiedit'.
--bcc=<address>::
Specify a "Bcc:" value for each email. Default is the value of
@@ -164,8 +165,8 @@ Sending
Furthermore, passwords need not be specified in configuration files
or on the command line. If a username has been specified (with
'--smtp-user' or a 'sendemail.smtpuser'), but no password has been
-specified (with '--smtp-pass' or 'sendemail.smtppass'), then the
-user is prompted for a password while the input is masked for privacy.
+specified (with '--smtp-pass' or 'sendemail.smtppass'), then
+a password is obtained using 'git-credential'.
--smtp-server=<host>::
If set, specifies the outgoing SMTP server to use (e.g.
@@ -197,6 +198,12 @@ must be used for each option.
--smtp-ssl::
Legacy alias for '--smtp-encryption ssl'.
+--smtp-ssl-cert-path::
+ Path to ca-certificates (either a directory or a single file).
+ Set it to an empty string to disable certificate verification.
+ Defaults to the value set to the 'sendemail.smtpsslcertpath'
+ configuration variable, if set, or `/etc/ssl/certs` otherwise.
+
--smtp-user=<user>::
Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
diff --git a/Documentation/git-sh-setup.txt b/Documentation/git-sh-setup.txt
index 6a9f66d..5d709d0 100644
--- a/Documentation/git-sh-setup.txt
+++ b/Documentation/git-sh-setup.txt
@@ -82,6 +82,12 @@ get_author_ident_from_commit::
outputs code for use with eval to set the GIT_AUTHOR_NAME,
GIT_AUTHOR_EMAIL and GIT_AUTHOR_DATE variables for a given commit.
+create_virtual_base::
+ modifies the first file so only lines in common with the
+ second file remain. If there is insufficient common material,
+ then the first file is left empty. The result is suitable
+ as a virtual base input for a 3-way merge.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.txt
index 9b92506..c35051b 100644
--- a/Documentation/git-shell.txt
+++ b/Documentation/git-shell.txt
@@ -9,25 +9,81 @@ git-shell - Restricted login shell for Git-only SSH access
SYNOPSIS
--------
[verse]
-'git shell' [-c <command> <argument>]
+'chsh' -s $(command -v git-shell) <user>
+'git clone' <user>`@localhost:/path/to/repo.git`
+'ssh' <user>`@localhost`
DESCRIPTION
-----------
-A login shell for SSH accounts to provide restricted Git access. When
-'-c' is given, the program executes <command> non-interactively;
-<command> can be one of 'git receive-pack', 'git upload-pack', 'git
-upload-archive', 'cvs server', or a command in COMMAND_DIR. The shell
-is started in interactive mode when no arguments are given; in this
-case, COMMAND_DIR must exist, and any of the executables in it can be
-invoked.
+This is a login shell for SSH accounts to provide restricted Git access.
+It permits execution only of server-side Git commands implementing the
+pull/push functionality, plus custom commands present in a subdirectory
+named `git-shell-commands` in the user's home directory.
-'cvs server' is a special command which executes git-cvsserver.
+COMMANDS
+--------
+
+'git shell' accepts the following commands after the '-c' option:
+
+'git receive-pack <argument>'::
+'git upload-pack <argument>'::
+'git upload-archive <argument>'::
+ Call the corresponding server-side command to support
+ the client's 'git push', 'git fetch', or 'git archive --remote'
+ request.
+'cvs server'::
+ Imitate a CVS server. See linkgit:git-cvsserver[1].
+
+If a `~/git-shell-commands` directory is present, 'git shell' will
+also handle other, custom commands by running
+"`git-shell-commands/<command> <arguments>`" from the user's home
+directory.
+
+INTERACTIVE USE
+---------------
+
+By default, the commands above can be executed only with the '-c'
+option; the shell is not interactive.
-COMMAND_DIR is the path "$HOME/git-shell-commands". The user must have
-read and execute permissions to the directory in order to execute the
-programs in it. The programs are executed with a cwd of $HOME, and
-<argument> is parsed as a command-line string.
+If a `~/git-shell-commands` directory is present, 'git shell'
+can also be run interactively (with no arguments). If a `help`
+command is present in the `git-shell-commands` directory, it is
+run to provide the user with an overview of allowed actions. Then a
+"git> " prompt is presented at which one can enter any of the
+commands from the `git-shell-commands` directory, or `exit` to close
+the connection.
+
+Generally this mode is used as an administrative interface to allow
+users to list repositories they have access to, create, delete, or
+rename repositories, or change repository descriptions and
+permissions.
+
+If a `no-interactive-login` command exists, then it is run and the
+interactive shell is aborted.
+
+EXAMPLE
+-------
+
+To disable interactive logins, displaying a greeting instead:
++
+----------------
+$ chsh -s /usr/bin/git-shell
+$ mkdir $HOME/git-shell-commands
+$ cat >$HOME/git-shell-commands/no-interactive-login <<\EOF
+#!/bin/sh
+printf '%s\n' "Hi $USER! You've successfully authenticated, but I do not"
+printf '%s\n' "provide interactive shell access."
+exit 128
+EOF
+$ chmod +x $HOME/git-shell-commands/no-interactive-login
+----------------
+
+SEE ALSO
+--------
+ssh(1),
+linkgit:git-daemon[1],
+contrib/git-shell-commands/README
GIT
---
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index c308e91..31af7f2 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -8,8 +8,8 @@ git-shortlog - Summarize 'git log' output
SYNOPSIS
--------
[verse]
-git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w]
-'git shortlog' [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] <commit>...
+git log --pretty=short | 'git shortlog' [<options>]
+'git shortlog' [<options>] [<revision range>] [[\--] <path>...]
DESCRIPTION
-----------
@@ -26,10 +26,6 @@ reference to the current repository.
OPTIONS
-------
--h::
---help::
- Print a short usage message and exit.
-
-n::
--numbered::
Sort output according to the number of commits per author instead
@@ -60,6 +56,21 @@ OPTIONS
If width is `0` (zero) then indent the lines of the output without wrapping
them.
+<revision range>::
+ Show only commits in the specified revision range. When no
+ <revision range> is specified, it defaults to `HEAD` (i.e. the
+ whole history leading to the current commit). `origin..HEAD`
+ specifies all the commits reachable from the current commit
+ (i.e. `HEAD`), but not from `origin`. For a complete list of
+ ways to spell <revision range>, see the "Specifying Ranges"
+ section of linkgit:gitrevisions[7].
+
+[\--] <path>...::
+ Consider only commits that are enough to explain how the files
+ that match the specified paths came to be.
++
+Paths may need to be prefixed with "\-- " to separate them from
+options or the revision range, when confusion arises.
MAPPING AUTHORS
---------------
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index de4d352..b0a309b 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -21,6 +21,8 @@ commit IDs. Results can be filtered using a pattern and tags can be
dereferenced into object IDs. Additionally, it can be used to test whether a
particular ref exists.
+By default, shows the tags, heads, and remote refs.
+
The --exclude-existing form is a filter that does the inverse, it shows the
refs from stdin that don't exist in the local repository.
@@ -32,14 +34,14 @@ OPTIONS
--head::
- Show the HEAD reference.
+ Show the HEAD reference, even if it would normally be filtered out.
--tags::
--heads::
- Limit to only "refs/heads" and "refs/tags", respectively. These
- options are not mutually exclusive; when given both, references stored
- in "refs/heads" and "refs/tags" are displayed.
+ Limit to "refs/heads" and "refs/tags", respectively. These options
+ are not mutually exclusive; when given both, references stored in
+ "refs/heads" and "refs/tags" are displayed.
-d::
--dereference::
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index ae4edcc..4e617e6 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -45,6 +45,15 @@ include::pretty-options.txt[]
include::pretty-formats.txt[]
+COMMON DIFF OPTIONS
+-------------------
+
+:git-log: 1
+include::diff-options.txt[]
+
+include::diff-generate-patch.txt[]
+
+
EXAMPLES
--------
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 711ffe1..db7e803 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -13,10 +13,11 @@ SYNOPSIS
'git stash' drop [-q|--quiet] [<stash>]
'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
'git stash' branch <branchname> [<stash>]
-'git stash' [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
+'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [<message>]]
'git stash' clear
-'git stash' create
+'git stash' create [<message>]
+'git stash' store [-m|--message <message>] [-q|--quiet] <commit>
DESCRIPTION
-----------
@@ -151,7 +152,15 @@ create::
Create a stash (which is a regular commit object) and return its
object name, without storing it anywhere in the ref namespace.
+ This is intended to be useful for scripts. It is probably not
+ the command you want to use; see "save" above.
+store::
+
+ Store a given stash created via 'git stash create' (which is a
+ dangling merge commit) in the stash ref, updating the stash
+ reflog. This is intended to be useful for scripts. It is
+ probably not the command you want to use; see "save" above.
DISCUSSION
----------
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index c99d795..bfef8a0 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -10,11 +10,12 @@ SYNOPSIS
--------
[verse]
'git submodule' [--quiet] add [-b <branch>] [-f|--force] [--name <name>]
- [--reference <repository>] [--] <repository> [<path>]
+ [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]
'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
'git submodule' [--quiet] init [--] [<path>...]
+'git submodule' [--quiet] deinit [-f|--force] [--] <path>...
'git submodule' [--quiet] update [--init] [--remote] [-N|--no-fetch]
- [-f|--force] [--rebase] [--reference <repository>]
+ [-f|--force] [--rebase] [--reference <repository>] [--depth <depth>]
[--merge] [--recursive] [--] [<path>...]
'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
[commit] [--] [<path>...]
@@ -76,6 +77,8 @@ argument <path> is the relative location for the cloned submodule
to exist in the superproject. If <path> is not given, the
"humanish" part of the source repository is used ("repo" for
"/path/to/repo.git" and "foo" for "host.xz:foo/.git").
+The <path> is also used as the submodule's logical name in its
+configuration entries unless `--name` is used to specify a logical name.
+
<repository> is the URL of the new submodule's origin repository.
This may be either an absolute URL, or (if it begins with ./
@@ -123,8 +126,10 @@ linkgit:git-status[1] and linkgit:git-diff[1] will provide that information
too (and can also report changes to a submodule's work tree).
init::
- Initialize the submodules, i.e. register each submodule name
- and url found in .gitmodules into .git/config.
+ Initialize the submodules recorded in the index (which were
+ added and committed elsewhere) by copying submodule
+ names and urls from .gitmodules to .git/config.
+ Optional <path> arguments limit which submodules will be initialized.
It will also copy the value of `submodule.$name.update` into
.git/config.
The key used in .git/config is `submodule.$name.url`.
@@ -135,13 +140,28 @@ init::
the explicit 'init' step if you do not intend to customize
any submodule locations.
+deinit::
+ Unregister the given submodules, i.e. remove the whole
+ `submodule.$name` section from .git/config together with their work
+ tree. Further calls to `git submodule update`, `git submodule foreach`
+ and `git submodule sync` will skip any unregistered submodules until
+ they are initialized again, so use this command if you don't want to
+ have a local checkout of the submodule in your work tree anymore. If
+ you really want to remove a submodule from the repository and commit
+ that use linkgit:git-rm[1] instead.
++
+If `--force` is specified, the submodule's work tree will be removed even if
+it contains local modifications.
+
update::
Update the registered submodules, i.e. clone missing submodules and
checkout the commit specified in the index of the containing repository.
This will make the submodules HEAD be detached unless `--rebase` or
`--merge` is specified or the key `submodule.$name.update` is set to
`rebase`, `merge` or `none`. `none` can be overridden by specifying
- `--checkout`.
+ `--checkout`. Setting the key `submodule.$name.update` to `!command`
+ will cause `command` to be run. `command` can be any arbitrary shell
+ command that takes a single argument, namely the sha1 to update to.
+
If the submodule is not yet initialized, and you just want to use the
setting as stored in .gitmodules, you can automatically initialize the
@@ -214,8 +234,10 @@ OPTIONS
-f::
--force::
- This option is only valid for add and update commands.
+ This option is only valid for add, deinit and update commands.
When running add, allow adding an otherwise ignored submodule path.
+ When running deinit the submodule work trees will be removed even if
+ they contain local changes.
When running update, throw away local changes in submodules when
switching to a different commit; and always run a checkout operation
in the submodule, even if the commit listed in the index of the
@@ -242,7 +264,7 @@ OPTIONS
--remote::
This option is only valid for the update command. Instead of using
the superproject's recorded SHA-1 to update the submodule, use the
- status of the submodule's remote tracking branch. The remote used
+ status of the submodule's remote-tracking branch. The remote used
is branch's remote (`branch.<name>.remote`), defaulting to `origin`.
The remote branch used defaults to `master`, but the branch name may
be overridden by setting the `submodule.<name>.branch` option in
@@ -308,6 +330,12 @@ for linkgit:git-clone[1]'s `--reference` and `--shared` options carefully.
only in the submodules of the current repo, but also
in any nested submodules inside those submodules (and so on).
+--depth::
+ This option is valid for add and update commands. Create a 'shallow'
+ clone with a history truncated to the specified number of revisions.
+ See linkgit:git-clone[1]
+
+
<path>...::
Paths to submodule(s). When specified this will restrict the command
to only operate on the submodules found at the specified paths.
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 7706d41..4dd3bcb 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -85,6 +85,10 @@ COMMANDS
When passed to 'init' or 'clone' this regular expression will
be preserved as a config key. See 'fetch' for a description
of '--ignore-paths'.
+--include-paths=<regex>;;
+ When passed to 'init' or 'clone' this regular expression will
+ be preserved as a config key. See 'fetch' for a description
+ of '--include-paths'.
--no-minimize-url;;
When tracking multiple directories (using --stdlayout,
--branches, or --tags options), git svn will attempt to connect
@@ -146,6 +150,14 @@ Skip "branches" and "tags" of first level directories;;
------------------------------------------------------------------------
--
+--include-paths=<regex>;;
+ This allows one to specify a Perl regular expression that will
+ cause the inclusion of only matching paths from checkout from SVN.
+ The '--include-paths' option should match for every 'fetch'
+ (including automatic fetches due to 'clone', 'dcommit',
+ 'rebase', etc) on a given repository. '--ignore-paths' takes
+ precedence over '--include-paths'.
+
--log-window-size=<n>;;
Fetch <n> log entries per request when scanning Subversion history.
The default is 100. For very large Subversion repositories, larger
@@ -244,7 +256,7 @@ first have already been pushed into SVN.
For each patch, one may answer "yes" (accept this patch), "no" (discard this
patch), "all" (accept all patches), or "quit".
+
- 'git svn dcommit' returns immediately if answer if "no" or "quit", without
+ 'git svn dcommit' returns immediately if answer is "no" or "quit", without
committing anything to SVN.
'branch'::
@@ -259,13 +271,15 @@ first have already been pushed into SVN.
Create a tag by using the tags_subdir instead of the branches_subdir
specified during git svn init.
--d;;
---destination;;
+-d<path>;;
+--destination=<path>;;
+
If more than one --branches (or --tags) option was given to the 'init'
or 'clone' command, you must provide the location of the branch (or
- tag) you wish to create in the SVN repository. The value of this
- option must match one of the paths specified by a --branches (or
- --tags) option. You can see these paths with the commands
+ tag) you wish to create in the SVN repository. <path> specifies which
+ path to use to create the branch or tag and should match the pattern
+ on the left-hand side of one of the configured branches or tags
+ refspecs. You can see these refspecs with the commands
+
git config --get-all svn-remote.<name>.branches
git config --get-all svn-remote.<name>.tags
@@ -286,6 +300,11 @@ where <name> is the name of the SVN repository as specified by the -R option to
git config --get-all svn-remote.<name>.commiturl
+
+--parents;;
+ Create parent folders. This parameter is equivalent to the parameter
+ --parents on svn cp commands and is useful for non-standard repository
+ layouts.
+
'tag'::
Create a tag in the SVN repository. This is a shorthand for
'branch -t'.
@@ -1020,6 +1039,25 @@ comma-separated list of names within braces. For example:
tags = tags/{1.0,2.0}/src:refs/remotes/tags/*
------------------------------------------------------------------------
+Multiple fetch, branches, and tags keys are supported:
+
+------------------------------------------------------------------------
+[svn-remote "messy-repo"]
+ url = http://server.org/svn
+ fetch = trunk/project-a:refs/remotes/project-a/trunk
+ fetch = branches/demos/june-project-a-demo:refs/remotes/project-a/demos/june-demo
+ branches = branches/server/*:refs/remotes/project-a/branches/*
+ branches = branches/demos/2011/*:refs/remotes/project-a/2011-demos/*
+ tags = tags/server/*:refs/remotes/project-a/tags/*
+------------------------------------------------------------------------
+
+Creating a branch in such a configuration requires disambiguating which
+location to use using the -d or --destination flag:
+
+------------------------------------------------------------------------
+$ git svn branch -d branches/server release-2-3-0
+------------------------------------------------------------------------
+
Note that git-svn keeps track of the highest revision in which a branch
or tag has appeared. If the subset of branches or tags is changed after
fetching, then .git/svn/.metadata must be manually edited to remove (or
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 22894cb..c418c44 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -42,6 +42,17 @@ committer identity for the current user is used to find the
GnuPG key for signing. The configuration variable `gpg.program`
is used to specify custom GnuPG binary.
+Tag objects (created with `-a`, `s`, or `-u`) are called "annotated"
+tags; they contain a creation date, the tagger name and e-mail, a
+tagging message, and an optional GnuPG signature. Whereas a
+"lightweight" tag is simply a name for an object (usually a commit
+object).
+
+Annotated tags are meant for release while lightweight tags are meant
+for private or temporary object labels. For this reason, some git
+commands for naming objects (like `git describe`) will ignore
+lightweight tags by default.
+
OPTIONS
-------
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 670e9fb..e0a8702 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -14,8 +14,8 @@ SYNOPSIS
[--refresh] [-q] [--unmerged] [--ignore-missing]
[(--cacheinfo <mode> <object> <file>)...]
[--chmod=(+|-)x]
- [--assume-unchanged | --no-assume-unchanged]
- [--skip-worktree | --no-skip-worktree]
+ [--[no-]assume-unchanged]
+ [--[no-]skip-worktree]
[--ignore-submodules]
[--really-refresh] [--unresolve] [--again | -g]
[--info-only] [--index-info]
@@ -77,8 +77,7 @@ OPTIONS
--chmod=(+|-)x::
Set the execute permissions on the updated files.
---assume-unchanged::
---no-assume-unchanged::
+--[no-]assume-unchanged::
When these flags are specified, the object names recorded
for the paths are not updated. Instead, these options
set and unset the "assume unchanged" bit for the
@@ -102,8 +101,7 @@ you will need to handle the situation manually.
Like '--refresh', but checks stat information unconditionally,
without regard to the "assume unchanged" setting.
---skip-worktree::
---no-skip-worktree::
+--[no-]skip-worktree::
When one of these flags is specified, the object name recorded
for the paths are not updated. Instead, these options
set and unset the "skip-worktree" bit for the paths. See
diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt
index ba79cb4..5aec4ec 100644
--- a/Documentation/git-web--browse.txt
+++ b/Documentation/git-web--browse.txt
@@ -34,6 +34,7 @@ The following browsers (or commands) are currently supported:
* dillo
* open (this is the default under Mac OS X GUI)
* start (this is the default under MinGW)
+* cygstart (this is the default under Cygwin)
Custom commands may also be specified.
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt
index c600b61..8b63ceb 100644
--- a/Documentation/git-whatchanged.txt
+++ b/Documentation/git-whatchanged.txt
@@ -13,43 +13,17 @@ SYNOPSIS
DESCRIPTION
-----------
-Shows commit logs and diff output each commit introduces. The
-command internally invokes 'git rev-list' piped to
-'git diff-tree', and takes command line options for both of
-these commands.
-This manual page describes only the most frequently used options.
+Shows commit logs and diff output each commit introduces.
+New users are encouraged to use linkgit:git-log[1] instead. The
+`whatchanged` command is essentially the same as linkgit:git-log[1]
+but defaults to show the raw format diff output and to skip merges.
-OPTIONS
--------
--p::
- Show textual diffs, instead of the Git internal diff
- output format that is useful only to tell the changed
- paths and their nature of changes.
+The command is kept primarily for historical reasons; fingers of
+many people who learned Git long before `git log` was invented by
+reading Linux kernel mailing list are trained to type it.
--<n>::
- Limit output to <n> commits.
-
-<since>..<until>::
- Limit output to between the two named commits (bottom
- exclusive, top inclusive).
-
--r::
- Show Git internal diff output, but for the whole tree,
- not just the top level.
-
--m::
- By default, differences for merge commits are not shown.
- With this flag, show differences to that commit from all
- of its parents.
-+
-However, it is not very useful in general, although it
-*is* useful on a file-by-file basis.
-
-include::pretty-options.txt[]
-
-include::pretty-formats.txt[]
Examples
--------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 9e302b0..c4f0ed5 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,12 +43,26 @@ unreleased) version of Git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
+* link:v1.8.4/git.html[documentation for release 1.8.4]
+
+* release notes for
+ link:RelNotes/1.8.4.txt[1.8.4].
+
+* link:v1.8.3.4/git.html[documentation for release 1.8.3.4]
+
+* release notes for
+ link:RelNotes/1.8.3.4.txt[1.8.3.4],
+ link:RelNotes/1.8.3.3.txt[1.8.3.3],
+ link:RelNotes/1.8.3.2.txt[1.8.3.2],
+ link:RelNotes/1.8.3.1.txt[1.8.3.1],
+ link:RelNotes/1.8.3.txt[1.8.3].
+
* link:v1.8.2.3/git.html[documentation for release 1.8.2.3]
* release notes for
- link:RelNotes/1.8.2.3.txt[1.8.2.3].
- link:RelNotes/1.8.2.2.txt[1.8.2.2].
- link:RelNotes/1.8.2.1.txt[1.8.2.1].
+ link:RelNotes/1.8.2.3.txt[1.8.2.3],
+ link:RelNotes/1.8.2.2.txt[1.8.2.2],
+ link:RelNotes/1.8.2.1.txt[1.8.2.1],
link:RelNotes/1.8.2.txt[1.8.2].
* link:v1.8.1.6/git.html[documentation for release 1.8.1.6]
@@ -443,10 +457,25 @@ help ...`.
linkgit:git-replace[1] for more information.
--literal-pathspecs::
- Treat pathspecs literally, rather than as glob patterns. This is
- equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
+ Treat pathspecs literally (i.e. no globbing, no pathspec magic).
+ This is equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
variable to `1`.
+--glob-pathspecs:
+ Add "glob" magic to all pathspec. This is equivalent to setting
+ the `GIT_GLOB_PATHSPECS` environment variable to `1`. Disabling
+ globbing on individual pathspecs can be done using pathspec
+ magic ":(literal)"
+
+--noglob-pathspecs:
+ Add "literal" magic to all pathspec. This is equivalent to setting
+ the `GIT_NOGLOB_PATHSPECS` environment variable to `1`. Enabling
+ globbing on individual pathspecs can be done using pathspec
+ magic ":(glob)"
+
+--icase-pathspecs:
+ Add "icase" magic to all pathspec. This is equivalent to setting
+ the `GIT_ICASE_PATHSPECS` environment variable to `1`.
GIT COMMANDS
------------
@@ -677,9 +706,7 @@ Git so take care if using Cogito etc.
The '--git-dir' command-line option also sets this value.
'GIT_WORK_TREE'::
- Set the path to the working tree. The value will not be
- used in combination with repositories found automatically in
- a .git directory (i.e. $GIT_DIR is not set).
+ Set the path to the root of the working tree.
This can also be controlled by the '--work-tree' command line
option and the core.worktree configuration variable.
@@ -811,8 +838,9 @@ for further details.
'GIT_FLUSH'::
If this environment variable is set to "1", then commands such
as 'git blame' (in incremental mode), 'git rev-list', 'git log',
- and 'git whatchanged' will force a flush of the output stream
- after each commit-oriented record have been flushed. If this
+ 'git check-attr' and 'git check-ignore' will
+ force a flush of the output stream after each record have been
+ flushed. If this
variable is set to "0", the output of these commands will be done
using completely buffered I/O. If this environment variable is
not set, Git will choose buffered or record-oriented flushing
@@ -832,6 +860,19 @@ for further details.
as a file path and will try to write the trace messages
into it.
+'GIT_TRACE_PACK_ACCESS'::
+ If this variable is set to a path, a file will be created at
+ the given path logging all accesses to any packs. For each
+ access, the pack file name and an offset in the pack is
+ recorded. This may be helpful for troubleshooting some
+ pack-related performance problems.
+
+'GIT_TRACE_PACKET'::
+ If this variable is set, it shows a trace of all packets
+ coming in or out of a given program. This can help with
+ debugging object negotiation or other protocol issues. Tracing
+ is turned off at a packet starting with "PACK".
+
GIT_LITERAL_PATHSPECS::
Setting this variable to `1` will cause Git to treat all
pathspecs literally, rather than as glob patterns. For example,
@@ -841,6 +882,18 @@ GIT_LITERAL_PATHSPECS::
literal paths to Git (e.g., paths previously given to you by
`git ls-tree`, `--raw` diff output, etc).
+GIT_GLOB_PATHSPECS::
+ Setting this variable to `1` will cause Git to treat all
+ pathspecs as glob patterns (aka "glob" magic).
+
+GIT_NOGLOB_PATHSPECS::
+ Setting this variable to `1` will cause Git to treat all
+ pathspecs as literal (aka "literal" magic).
+
+GIT_ICASE_PATHSPECS::
+ Setting this variable to `1` will cause Git to treat all
+ pathspecs as case-insensitive.
+
Discussion[[Discussion]]
------------------------
diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt
index f538a87..058a352 100644
--- a/Documentation/gitcore-tutorial.txt
+++ b/Documentation/gitcore-tutorial.txt
@@ -534,42 +534,9 @@ all, but just show the actual commit message.
In fact, together with the 'git rev-list' program (which generates a
list of revisions), 'git diff-tree' ends up being a veritable fount of
-changes. A trivial (but very useful) script called 'git whatchanged' is
-included with Git which does exactly this, and shows a log of recent
-activities.
-
-To see the whole history of our pitiful little git-tutorial project, you
-can do
-
-----------------
-$ git log
-----------------
-
-which shows just the log messages, or if we want to see the log together
-with the associated patches use the more complex (and much more
-powerful)
-
-----------------
-$ git whatchanged -p
-----------------
-
-and you will see exactly what has changed in the repository over its
-short history.
-
-[NOTE]
-When using the above two commands, the initial commit will be shown.
-If this is a problem because it is huge, you can hide it by setting
-the log.showroot configuration variable to false. Having this, you
-can still show it for each command just adding the `--root` option,
-which is a flag for 'git diff-tree' accepted by both commands.
-
-With that, you should now be having some inkling of what Git does, and
-can explore on your own.
-
-[NOTE]
-Most likely, you are not directly using the core
-Git Plumbing commands, but using Porcelain such as 'git add', `git-rm'
-and `git-commit'.
+changes. You can emulate `git log`, `git log -p`, etc. with a trivial
+script that pipes the output of `git rev-list` to `git diff-tree --stdin`,
+which was exactly how early versions of `git log` were implemented.
Tagging a version
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index 568d757..c8b3e51 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -222,26 +222,35 @@ version prefixed with '+'.
diffcore-pickaxe: For Detecting Addition/Deletion of Specified String
---------------------------------------------------------------------
-This transformation is used to find filepairs that represent
-changes that touch a specified string, and is controlled by the
--S option and the `--pickaxe-all` option to the 'git diff-*'
-commands.
-
-When diffcore-pickaxe is in use, it checks if there are
-filepairs whose "result" side and whose "origin" side have
-different number of specified string. Such a filepair represents
-"the string appeared in this changeset". It also checks for the
-opposite case that loses the specified string.
-
-When `--pickaxe-all` is not in effect, diffcore-pickaxe leaves
-only such filepairs that touch the specified string in its
-output. When `--pickaxe-all` is used, diffcore-pickaxe leaves all
-filepairs intact if there is such a filepair, or makes the
-output empty otherwise. The latter behaviour is designed to
-make reviewing of the changes in the context of the whole
+This transformation limits the set of filepairs to those that change
+specified strings between the preimage and the postimage in a certain
+way. -S<block of text> and -G<regular expression> options are used to
+specify different ways these strings are sought.
+
+"-S<block of text>" detects filepairs whose preimage and postimage
+have different number of occurrences of the specified block of text.
+By definition, it will not detect in-file moves. Also, when a
+changeset moves a file wholesale without affecting the interesting
+string, diffcore-rename kicks in as usual, and `-S` omits the filepair
+(since the number of occurrences of that string didn't change in that
+rename-detected filepair). When used with `--pickaxe-regex`, treat
+the <block of text> as an extended POSIX regular expression to match,
+instead of a literal string.
+
+"-G<regular expression>" (mnemonic: grep) detects filepairs whose
+textual diff has an added or a deleted line that matches the given
+regular expression. This means that it will detect in-file (or what
+rename-detection considers the same file) moves, which is noise. The
+implementation runs diff twice and greps, and this can be quite
+expensive.
+
+When `-S` or `-G` are used without `--pickaxe-all`, only filepairs
+that match their respective criterion are kept in the output. When
+`--pickaxe-all` is used, if even one filepair matches their respective
+criterion in a changeset, the entire changeset is kept. This behavior
+is designed to make reviewing changes in the context of the whole
changeset easier.
-
diffcore-order: For Sorting the Output Based on Filenames
---------------------------------------------------------
diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt
index 0c91aba..be7e224 100644
--- a/Documentation/gitremote-helpers.txt
+++ b/Documentation/gitremote-helpers.txt
@@ -120,6 +120,11 @@ connecting (see the 'connect' command under COMMANDS).
When choosing between 'push' and 'export', Git prefers 'push'.
Other frontends may have some other order of preference.
+'no-private-update'::
+ When using the 'refspec' capability, git normally updates the
+ private ref on successful push. This update is disabled when
+ the remote-helper declares the capability 'no-private-update'.
+
Capabilities for Fetching
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -143,6 +148,10 @@ Supported commands: 'list', 'fetch'.
+
Supported commands: 'list', 'import'.
+'check-connectivity'::
+ Can guarantee that when a clone is requested, the received
+ pack is self contained and is connected.
+
If a helper advertises 'connect', Git will use it if possible and
fall back to another capability if the helper requests so when
connecting (see the 'connect' command under COMMANDS).
@@ -159,11 +168,11 @@ Miscellaneous capabilities
carried out.
'refspec' <refspec>::
- This modifies the 'import' capability, allowing the produced
- fast-import stream to modify refs in a private namespace
- instead of writing to refs/heads or refs/remotes directly.
+ For remote helpers that implement 'import' or 'export', this capability
+ allows the refs to be constrained to a private namespace, instead of
+ writing to refs/heads or refs/remotes directly.
It is recommended that all importers providing the 'import'
- capability use this.
+ capability use this. It's mandatory for 'export'.
+
A helper advertising the capability
`refspec refs/heads/*:refs/svn/origin/branches/*`
@@ -202,6 +211,10 @@ there is an implied `refspec *:*`.
marks specified in <file> before processing any input. For details,
read up on '--import-marks=<file>' in linkgit:git-fast-export[1].
+'signed-tags'::
+ This modifies the 'export' capability, instructing Git to pass
+ '--signed-tags=verbatim' to linkgit:git-fast-export[1]. In the
+ absence of this capability, Git will use '--signed-tags=warn-strip'.
@@ -266,6 +279,9 @@ Optionally may output a 'lock <file>' line indicating a file under
GIT_DIR/objects/pack which is keeping a pack until refs can be
suitably updated.
+
+If option 'check-connectivity' is requested, the helper must output
+'connectivity-ok' if the clone is self-contained and connected.
++
Supported if the helper has the "fetch" capability.
'push' +<src>:<dst>::
@@ -412,6 +428,9 @@ set by Git if the remote helper has the 'option' capability.
must not rely on this option being set before
connect request occurs.
+'option check-connectivity' \{'true'|'false'\}::
+ Request the helper to check connectivity of a clone.
+
SEE ALSO
--------
linkgit:git-remote[1]
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 2ad09f4..aa03882 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -184,6 +184,10 @@ info/exclude::
'git clean' look at it but the core Git commands do not look
at it. See also: linkgit:gitignore[5].
+info/sparse-checkout::
+ This file stores sparse checkout patterns.
+ See also: linkgit:git-read-tree[1].
+
remotes::
Stores shorthands for URL and default refnames for use
when interacting with remote repositories via 'git fetch',
@@ -207,6 +211,9 @@ shallow::
and maintained by shallow clone mechanism. See `--depth`
option to linkgit:git-clone[1] and linkgit:git-fetch[1].
+modules::
+ Contains the git-repositories of the submodules.
+
SEE ALSO
--------
linkgit:git-init[1],
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index ea0526e..305db63 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -336,8 +336,26 @@ $home_link_str::
used as the first component of gitweb's "breadcrumb trail":
`<home link> / <project> / <action>`. Can be set at build time using
the `GITWEB_HOME_LINK_STR` variable. By default it is set to "projects",
- as this link leads to the list of projects. Other popular choice it to
- set it to the name of site.
+ as this link leads to the list of projects. Another popular choice is to
+ set it to the name of site. Note that it is treated as raw HTML so it
+ should not be set from untrusted sources.
+
+@extra_breadcrumbs::
+ Additional links to be added to the start of the breadcrumb trail before
+ the home link, to pages that are logically "above" the gitweb projects
+ list, such as the organization and department which host the gitweb
+ server. Each element of the list is a reference to an array, in which
+ element 0 is the link text (equivalent to `$home_link_str`) and element
+ 1 is the target URL (equivalent to `$home_link`).
++
+For example, the following setting produces a breadcrumb trail like
+"home / dev / projects / ..." where "projects" is the home link.
+----------------------------------------------------------------------------
+ our @extra_breadcrumbs = (
+ [ 'home' => 'https://www.example.org/' ],
+ [ 'dev' => 'https://dev.example.org/' ],
+ );
+----------------------------------------------------------------------------
$logo_url::
$logo_label::
diff --git a/Documentation/gitweb.txt b/Documentation/gitweb.txt
index 40969f1..cca14b8 100644
--- a/Documentation/gitweb.txt
+++ b/Documentation/gitweb.txt
@@ -504,7 +504,7 @@ repositories, you can configure Apache like this:
The above configuration expects your public repositories to live under
'/pub/git' and will serve them as `http://git.domain.org/dir-under-pub-git`,
-both as cloneable Git URL and as browseable gitweb interface. If you then
+both as clonable Git URL and as browseable gitweb interface. If you then
start your linkgit:git-daemon[1] with `--base-path=/pub/git --export-all`
then you can even use the `git://` URL with exactly the same path.
diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt
index 68a18e1..13a64d3 100644
--- a/Documentation/glossary-content.txt
+++ b/Documentation/glossary-content.txt
@@ -113,7 +113,7 @@ Note that commands that operate on the history of the current branch
while the HEAD is detached. They update the HEAD to point at the tip
of the updated history without affecting any branch. Commands that
update or inquire information _about_ the current branch (e.g. `git
-branch --set-upstream-to` that sets what remote tracking branch the
+branch --set-upstream-to` that sets what remote-tracking branch the
current branch integrates with) obviously do not work, as there is no
(real) current branch to ask about in this state.
@@ -267,7 +267,7 @@ This commit is referred to as a "merge commit", or sometimes just a
The default upstream <<def_repository,repository>>. Most projects have
at least one upstream project which they track. By default
'origin' is used for that purpose. New upstream updates
- will be fetched into remote <<def_remote_tracking_branch,remote-tracking branches>> named
+ will be fetched into <<def_remote_tracking_branch,remote-tracking branches>> named
origin/name-of-upstream-branch, which you can see using
`git branch -r`.
@@ -322,10 +322,54 @@ and a close parentheses `)`, and the remainder is the pattern to match
against the path.
+
The "magic signature" consists of an ASCII symbol that is not
-alphanumeric. Currently only the slash `/` is recognized as a
-"magic signature": it makes the pattern match from the root of
-the working tree, even when you are running the command from
-inside a subdirectory.
+alphanumeric.
++
+--
+top `/`;;
+ The magic word `top` (mnemonic: `/`) makes the pattern match
+ from the root of the working tree, even when you are running
+ the command from inside a subdirectory.
+
+literal;;
+ Wildcards in the pattern such as `*` or `?` are treated
+ as literal characters.
+
+icase;;
+ Case insensitive match.
+
+glob;;
+ Git treats the pattern as a shell glob suitable for
+ consumption by fnmatch(3) with the FNM_PATHNAME flag:
+ wildcards in the pattern will not match a / in the pathname.
+ For example, "Documentation/{asterisk}.html" matches
+ "Documentation/git.html" but not "Documentation/ppc/ppc.html"
+ or "tools/perf/Documentation/perf.html".
++
+Two consecutive asterisks ("`**`") in patterns matched against
+full pathname may have special meaning:
+
+ - A leading "`**`" followed by a slash means match in all
+ directories. For example, "`**/foo`" matches file or directory
+ "`foo`" anywhere, the same as pattern "`foo`". "**/foo/bar"
+ matches file or directory "`bar`" anywhere that is directly
+ under directory "`foo`".
+
+ - A trailing "/**" matches everything inside. For example,
+ "abc/**" matches all files inside directory "abc", relative
+ to the location of the `.gitignore` file, with infinite depth.
+
+ - A slash followed by two consecutive asterisks then a slash
+ matches zero or more directories. For example, "`a/**/b`"
+ matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
+
+ - Other consecutive asterisks are considered invalid.
++
+Glob magic is incompatible with literal magic.
+--
++
+Currently only the slash `/` is recognized as the "magic signature",
+but it is envisioned that we will support more types of magic in later
+versions of Git.
+
A pathspec with only a colon means "there is no pathspec". This form
should not be combined with other pathspec.
@@ -400,12 +444,13 @@ should not be combined with other pathspec.
<<def_ref,ref>> and local ref.
[[def_remote_tracking_branch]]remote-tracking branch::
- A regular Git <<def_branch,branch>> that is used to follow changes from
- another <<def_repository,repository>>. A remote-tracking
- branch should not contain direct modifications or have local commits
- made to it. A remote-tracking branch can usually be
- identified as the right-hand-side <<def_ref,ref>> in a Pull:
- <<def_refspec,refspec>>.
+ A <<def_ref,ref>> that is used to follow changes from another
+ <<def_repository,repository>>. It typically looks like
+ 'refs/remotes/foo/bar' (indicating that it tracks a branch named
+ 'bar' in a remote named 'foo'), and matches the right-hand-side of
+ a configured fetch <<def_refspec,refspec>>. A remote-tracking
+ branch should not contain direct modifications or have local
+ commits made to it.
[[def_repository]]repository::
A collection of <<def_ref,refs>> together with an
diff --git a/Documentation/howto/new-command.txt b/Documentation/howto/new-command.txt
index 2abc3a0..d7de5a3 100644
--- a/Documentation/howto/new-command.txt
+++ b/Documentation/howto/new-command.txt
@@ -94,7 +94,7 @@ your language, document it in the INSTALL file.
6. There is a file command-list.txt in the distribution main directory
that categorizes commands by type, so they can be listed in appropriate
subsections in the documentation's summary command list. Add an entry
-for yours. To understand the categories, look at git-cmmands.txt
+for yours. To understand the categories, look at git-commands.txt
in the main directory.
7. Give the maintainer one paragraph to include in the RelNotes file
diff --git a/Documentation/howto/revert-branch-rebase.txt b/Documentation/howto/revert-branch-rebase.txt
index 84dd839..0d5419e 100644
--- a/Documentation/howto/revert-branch-rebase.txt
+++ b/Documentation/howto/revert-branch-rebase.txt
@@ -12,7 +12,7 @@ How to revert an existing commit
================================
One of the changes I pulled into the 'master' branch turns out to
-break building Git with GCC 2.95. While they were well intentioned
+break building Git with GCC 2.95. While they were well-intentioned
portability fixes, keeping things working with gcc-2.95 was also
important. Here is what I did to revert the change in the 'master'
branch and to adjust the 'pu' branch, using core Git tools and
diff --git a/Documentation/line-range-format.txt b/Documentation/line-range-format.txt
new file mode 100644
index 0000000..d7f2603
--- /dev/null
+++ b/Documentation/line-range-format.txt
@@ -0,0 +1,29 @@
+<start> and <end> can take one of these forms:
+
+- number
++
+If <start> or <end> is a number, it specifies an
+absolute line number (lines count from 1).
++
+
+- /regex/
++
+This form will use the first line matching the given
+POSIX regex. If <start> is a regex, it will search from the end of
+the previous `-L` range, if any, otherwise from the start of file.
+If <start> is ``^/regex/'', it will search from the start of file.
+If <end> is a regex, it will search
+starting at the line given by <start>.
++
+
+- +offset or -offset
++
+This is only valid for <end> and will specify a number
+of lines before or after the line given by <start>.
+
++
+If ``:<regex>'' is given in place of <start> and <end>, it denotes the range
+from the first funcname line that matches <regex>, up to the next
+funcname line. ``:<regex>'' searches from the end of the previous `-L` range,
+if any, otherwise from the start of file.
+``^:<regex>'' searches from the start of file.
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 34a8445..afba8d4 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -8,12 +8,13 @@ failed and do not autocommit, to give the user a chance to
inspect and further tweak the merge result before committing.
--edit::
+-e::
--no-edit::
Invoke an editor before committing successful mechanical merge to
further edit the auto-generated merge message, so that the user
can explain and justify the merge. The `--no-edit` option can be
used to accept the auto-generated message (this is generally
- discouraged). The `--edit` option is still useful if you are
+ discouraged). The `--edit` (or `-e`) option is still useful if you are
giving a draft message with the `-m` option from the command line
and want to edit it in the editor.
+
@@ -84,6 +85,11 @@ option can be used to override --squash.
Pass merge strategy specific option through to the merge
strategy.
+--verify-signatures::
+--no-verify-signatures::
+ Verify that the commits being merged have good and trusted GPG signatures
+ and abort the merge in case they do not.
+
--summary::
--no-summary::
Synonyms to --stat and --no-stat; these are deprecated and will be
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 342965d..1d174fd 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -106,18 +106,22 @@ The placeholders are:
- '%P': parent hashes
- '%p': abbreviated parent hashes
- '%an': author name
-- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1]
+ or linkgit:git-blame[1])
- '%ae': author email
-- '%aE': author email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aE': author email (respecting .mailmap, see
+ linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ad': author date (format respects --date= option)
- '%aD': author date, RFC2822 style
- '%ar': author date, relative
- '%at': author date, UNIX timestamp
- '%ai': author date, ISO 8601 format
- '%cn': committer name
-- '%cN': committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cN': committer name (respecting .mailmap, see
+ linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ce': committer email
-- '%cE': committer email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cE': committer email (respecting .mailmap, see
+ linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%cd': committer date
- '%cD': committer date, RFC2822 style
- '%cr': committer date, relative
@@ -131,15 +135,18 @@ The placeholders are:
- '%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
+- '%G?': show "G" for a Good signature, "B" for a Bad signature, "U" for a good,
+ untrusted signature and "N" for no signature
- '%GS': show the name of the signer for a signed commit
- '%GK': show the key used to sign a signed commit
- '%gD': reflog selector, e.g., `refs/stash@{1}`
- '%gd': shortened reflog selector, e.g., `stash@{1}`
- '%gn': reflog identity name
-- '%gN': reflog identity name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gN': reflog identity name (respecting .mailmap, see
+ linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ge': reflog identity email
-- '%gE': reflog identity email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gE': reflog identity email (respecting .mailmap, see
+ linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%gs': reflog subject
- '%Cred': switch color to red
- '%Cgreen': switch color to green
@@ -149,13 +156,28 @@ The placeholders are:
adding `auto,` at the beginning will emit color only when colors are
enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
respecting the `auto` settings of the former if we are going to a
- terminal)
+ terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
+ on the next placeholders until the color is switched again.
- '%m': left, right or boundary mark
- '%n': newline
- '%%': a raw '%'
- '%x00': print a byte from a hex code
- '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
linkgit:git-shortlog[1].
+- '%<(<N>[,trunc|ltrunc|mtrunc])': make the next placeholder take at
+ least N columns, padding spaces on the right if necessary.
+ Optionally truncate at the beginning (ltrunc), the middle (mtrunc)
+ or the end (trunc) if the output is longer than N columns.
+ Note that truncating only works correctly with N >= 2.
+- '%<|(<N>)': make the next placeholder take at least until Nth
+ columns, padding spaces on the right if necessary
+- '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+ respectively, but padding spaces on the left
+- '%>>(<N>)', '%>>|(<N>)': similar to '%>(<N>)', '%>|(<N>)'
+ respectively, except that if the next placeholder takes more spaces
+ than given and there are spaces on its left, use those spaces
+- '%><(<N>)', '%><|(<N>)': similar to '% <(<N>)', '%<|(<N>)'
+ respectively, but padding both sides (i.e. the text is centered)
NOTE: Some placeholders may depend on other options given to the
revision traversal engine. For example, the `%g*` reflog options will
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 5e49942..eea0e30 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -28,7 +28,7 @@ people using 80-column terminals.
This is a shorthand for "--pretty=oneline --abbrev-commit"
used together.
---encoding[=<encoding>]::
+--encoding=<encoding>::
The commit objects record the encoding used for the log message
in their encoding header; this option can be used to tell the
command to re-code the commit log message in the encoding
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt
index 94a9d32..18cffc2 100644
--- a/Documentation/pull-fetch-param.txt
+++ b/Documentation/pull-fetch-param.txt
@@ -68,6 +68,11 @@ Some short-cut notations are also supported.
+
* `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`;
it requests fetching everything up to the given tag.
-* A parameter <ref> without a colon is equivalent to
- <ref>: when pulling/fetching, so it merges <ref> into the current
- branch without storing the remote branch anywhere locally
+ifndef::git-pull[]
+* A parameter <ref> without a colon fetches that ref into FETCH_HEAD,
+endif::git-pull[]
+ifdef::git-pull[]
+* A parameter <ref> without a colon merges <ref> into the current
+ branch,
+endif::git-pull[]
+ and updates the remote-tracking branches (if any).
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 3bdbf5e..5bdfb42 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -119,7 +119,7 @@ if it is part of the log message.
--no-min-parents::
--no-max-parents::
- Show only commits which have at least (or at most) that many
+ Show only commits which have at least (or at most) that many parent
commits. In particular, `--max-parents=1` is the same as `--no-merges`,
`--min-parents=2` is the same as `--merges`. `--max-parents=0`
gives all root commits and `--min-parents=3` all octopus merges.
@@ -271,8 +271,8 @@ See also linkgit:git-reflog[1].
--boundary::
- Output uninteresting commits at the boundary, which are usually
- not shown.
+ Output excluded boundary commits. Boundary commits are
+ prefixed with `-`.
--
@@ -342,13 +342,13 @@ In the following, we will always refer to the same example history to
illustrate the differences between simplification settings. We assume
that you are filtering for a file `foo` in this commit graph:
-----------------------------------------------------------------------
- .-A---M---N---O---P
- / / / / /
- I B C D E
- \ / / / /
- `-------------'
+ .-A---M---N---O---P---Q
+ / / / / / /
+ I B C D E Y
+ \ / / / / /
+ `-------------' X
-----------------------------------------------------------------------
-The horizontal line of history A---P is taken to be the first parent of
+The horizontal line of history A---Q is taken to be the first parent of
each merge. The commits are:
* `I` is the initial commit, in which `foo` exists with contents
@@ -367,8 +367,11 @@ each merge. The commits are:
`N` and `D` to "foobarbaz"; i.e., it is not TREESAME to any parent.
* `E` changes `quux` to "xyzzy", and its merge `P` combines the
- strings to "quux xyzzy". Despite appearing interesting, `P` is
- TREESAME to all parents.
+ strings to "quux xyzzy". `P` is TREESAME to `O`, but not to `E`.
+
+* `X` is an independent root commit that added a new file `side`, and `Y`
+ modified it. `Y` is TREESAME to `X`. Its merge `Q` added `side` to `P`, and
+ `Q` is TREESAME to `P`, but not to `Y`.
'rev-list' walks backwards through history, including or excluding
commits based on whether '\--full-history' and/or parent rewriting
@@ -410,10 +413,10 @@ parent lines.
the example, we get
+
-----------------------------------------------------------------------
- I A B N D O
+ I A B N D O P Q
-----------------------------------------------------------------------
+
-`P` and `M` were excluded because they are TREESAME to a parent. `E`,
+`M` was excluded because it is TREESAME to both parents. `E`,
`C` and `B` were all walked, but only `B` was !TREESAME, so the others
do not appear.
+
@@ -431,7 +434,7 @@ Along each parent, prune away commits that are not included
themselves. This results in
+
-----------------------------------------------------------------------
- .-A---M---N---O---P
+ .-A---M---N---O---P---Q
/ / / / /
I B / D /
\ / / / /
@@ -441,7 +444,7 @@ themselves. This results in
Compare to '\--full-history' without rewriting above. Note that `E`
was pruned away because it is TREESAME, but the parent list of P was
rewritten to contain `E`'s parent `I`. The same happened for `C` and
-`N`. Note also that `P` was included despite being TREESAME.
+`N`, and `X`, `Y` and `Q`.
In addition to the above settings, you can change whether TREESAME
affects inclusion:
@@ -471,8 +474,9 @@ history according to the following rules:
* Set `C'` to `C`.
+
* Replace each parent `P` of `C'` with its simplification `P'`. In
- the process, drop parents that are ancestors of other parents, and
- remove duplicates.
+ the process, drop parents that are ancestors of other parents or that are
+ root commits TREESAME to an empty tree, and remove duplicates, but take care
+ to never drop all parents that we are TREESAME to.
+
* If after this parent rewriting, `C'` is a root or merge commit (has
zero or >1 parents), a boundary commit, or !TREESAME, it remains.
@@ -490,7 +494,7 @@ The effect of this is best shown by way of comparing to
`---------'
-----------------------------------------------------------------------
+
-Note the major differences in `N` and `P` over '--full-history':
+Note the major differences in `N`, `P` and `Q` over '--full-history':
+
--
* `N`'s parent list had `I` removed, because it is an ancestor of the
@@ -498,6 +502,10 @@ Note the major differences in `N` and `P` over '--full-history':
+
* `P`'s parent list similarly had `I` removed. `P` was then
removed completely, because it had one parent and is TREESAME.
++
+* `Q`'s parent list had `Y` simplified to `X`. `X` was then removed, because it
+ was a TREESAME root. `Q` was then removed completely, because it had one
+ parent and is TREESAME.
--
Finally, there is a fifth simplification mode available:
@@ -617,6 +625,10 @@ By default, the commits are shown in reverse chronological order.
Show no parents before all of its children are shown, but
otherwise show commits in the commit timestamp order.
+--author-date-order::
+ Show no parents before all of its children are shown, but
+ otherwise show commits in the author timestamp order.
+
--topo-order::
Show no parents before all of its children are shown, and
avoid showing commits on multiple lines of history
@@ -837,7 +849,4 @@ options may be given. See linkgit:git-diff-files[1] for more options.
-t::
Show the tree objects in the diff output. This implies '-r'.
-
--s::
- Suppress diff output.
endif::git-rev-list[]
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index c582263..d477b3f 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -116,6 +116,11 @@ some output processing may assume ref names in UTF-8.
object of that type is found or the object cannot be
dereferenced anymore (in which case, barf). '<rev>{caret}0'
is a short-hand for '<rev>{caret}\{commit\}'.
++
+'rev{caret}\{object\}' can be used to make sure 'rev' names an
+object that exists, without requiring 'rev' to be a tag, and
+without dereferencing 'rev'; because a tag is already an object,
+it does not have to be dereferenced even once to get to an object.
'<rev>{caret}\{\}', e.g. 'v0.99.8{caret}\{\}'::
A suffix '{caret}' followed by an empty brace pair
@@ -239,11 +244,13 @@ To summarize:
'<rev1>..<rev2>'::
Include commits that are reachable from <rev2> but exclude
- those that are reachable from <rev1>.
+ those that are reachable from <rev1>. When either <rev1> or
+ <rev2> is omitted, it defaults to 'HEAD'.
'<rev1>\...<rev2>'::
Include commits that are reachable from either <rev1> or
- <rev2> but exclude those that are reachable from both.
+ <rev2> but exclude those that are reachable from both. When
+ either <rev1> or <rev2> is omitted, it defaults to 'HEAD'.
'<rev>{caret}@', e.g. 'HEAD{caret}@'::
A suffix '{caret}' followed by an at sign is the same as listing
diff --git a/Documentation/technical/api-builtin.txt b/Documentation/technical/api-builtin.txt
index 4a4228b..f3c1357 100644
--- a/Documentation/technical/api-builtin.txt
+++ b/Documentation/technical/api-builtin.txt
@@ -39,7 +39,7 @@ where options is the bitwise-or of:
on bare repositories.
This only makes sense when `RUN_SETUP` is also set.
-. Add `builtin-foo.o` to `BUILTIN_OBJS` in `Makefile`.
+. Add `builtin/foo.o` to `BUILTIN_OBJS` in `Makefile`.
Additionally, if `foo` is a new command, there are 3 more things to do:
diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt
index 1f349b2..7f8e78d 100644
--- a/Documentation/technical/api-directory-listing.txt
+++ b/Documentation/technical/api-directory-listing.txt
@@ -22,12 +22,23 @@ The notable options are:
`flags`::
- A bit-field of options:
+ A bit-field of options (the `*IGNORED*` flags are mutually exclusive):
`DIR_SHOW_IGNORED`:::
- The traversal is for finding just ignored files, not unignored
- files.
+ Return just ignored files in `entries[]`, not untracked files.
+
+`DIR_SHOW_IGNORED_TOO`:::
+
+ Similar to `DIR_SHOW_IGNORED`, but return ignored files in `ignored[]`
+ in addition to untracked files in `entries[]`.
+
+`DIR_COLLECT_IGNORED`:::
+
+ Special mode for git-add. Return ignored files in `ignored[]` and
+ untracked files in `entries[]`. Only returns ignored files that match
+ pathspec exactly (no wildcards). Does not recurse into ignored
+ directories.
`DIR_SHOW_OTHER_DIRECTORIES`:::
@@ -57,6 +68,14 @@ The result of the enumeration is left in these fields:
Internal use; keeps track of allocation of `entries[]` array.
+`ignored[]`::
+
+ An array of `struct dir_entry`, used for ignored paths with the
+ `DIR_SHOW_IGNORED_TOO` and `DIR_COLLECT_IGNORED` flags.
+
+`ignored_nr`::
+
+ The number of members in `ignored[]` array.
Calling sequence
----------------
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 32ddc1c..0be2b51 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -41,6 +41,8 @@ The parse-options API allows:
* Boolean long options can be 'negated' (or 'unset') by prepending
`no-`, e.g. `--no-abbrev` instead of `--abbrev`. Conversely,
options that begin with `no-` can be 'negated' by removing it.
+ Other long options can be unset (e.g., set string to NULL, set
+ integer to 0) by prepending `no-`.
* Options and non-option arguments can clearly be separated using the `--`
option, e.g. `-a -b --option -- --this-is-a-file` indicates that
@@ -174,6 +176,10 @@ There are some macros to easily define options:
Introduce an option with date argument, see `approxidate()`.
The timestamp is put into `int_var`.
+`OPT_EXPIRY_DATE(short, long, &int_var, description)`::
+ Introduce an option with expiry date argument, see `parse_expiry_date()`.
+ The timestamp is put into `int_var`.
+
`OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::
Introduce an option with argument.
The argument will be fed into the function given by `func_ptr`
@@ -269,10 +275,10 @@ Examples
--------
See `test-parse-options.c` and
-`builtin-add.c`,
-`builtin-clone.c`,
-`builtin-commit.c`,
-`builtin-fetch.c`,
-`builtin-fsck.c`,
-`builtin-rm.c`
+`builtin/add.c`,
+`builtin/clone.c`,
+`builtin/commit.c`,
+`builtin/fetch.c`,
+`builtin/fsck.c`,
+`builtin/rm.c`
for real-world examples.
diff --git a/Documentation/technical/api-revision-walking.txt b/Documentation/technical/api-revision-walking.txt
index b7d0d9a..55b878a 100644
--- a/Documentation/technical/api-revision-walking.txt
+++ b/Documentation/technical/api-revision-walking.txt
@@ -59,7 +59,7 @@ function.
`reset_revision_walk`::
Reset the flags used by the revision walking api. You can use
- this to do multiple sequencial revision walks.
+ this to do multiple sequential revision walks.
Data structures
---------------
diff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt
index 4f63a04..540e455 100644
--- a/Documentation/technical/api-setup.txt
+++ b/Documentation/technical/api-setup.txt
@@ -8,6 +8,42 @@ Talk about
* is_inside_git_dir()
* is_inside_work_tree()
* setup_work_tree()
-* get_pathspec()
(Dscho)
+
+Pathspec
+--------
+
+See glossary-context.txt for the syntax of pathspec. In memory, a
+pathspec set is represented by "struct pathspec" and is prepared by
+parse_pathspec(). This function takes several arguments:
+
+- magic_mask specifies what features that are NOT supported by the
+ following code. If a user attempts to use such a feature,
+ parse_pathspec() can reject it early.
+
+- flags specifies other things that the caller wants parse_pathspec to
+ perform.
+
+- prefix and args come from cmd_* functions
+
+get_pathspec() is obsolete and should never be used in new code.
+
+parse_pathspec() helps catch unsupported features and reject them
+politely. At a lower level, different pathspec-related functions may
+not support the same set of features. Such pathspec-sensitive
+functions are guarded with GUARD_PATHSPEC(), which will die in an
+unfriendly way when an unsupported feature is requested.
+
+The command designers are supposed to make sure that GUARD_PATHSPEC()
+never dies. They have to make sure all unsupported features are caught
+by parse_pathspec(), not by GUARD_PATHSPEC. grepping GUARD_PATHSPEC()
+should give the designers all pathspec-sensitive codepaths and what
+features they support.
+
+A similar process is applied when a new pathspec magic is added. The
+designer lifts the GUARD_PATHSPEC restriction in the functions that
+support the new magic. At the same time (s)he has to make sure this
+new feature will be caught at parse_pathspec() in commands that cannot
+handle the new magic in some cases. grepping parse_pathspec() should
+help.
diff --git a/Documentation/technical/api-strbuf.txt b/Documentation/technical/api-strbuf.txt
index 2c59cb2..3350d97 100644
--- a/Documentation/technical/api-strbuf.txt
+++ b/Documentation/technical/api-strbuf.txt
@@ -230,6 +230,11 @@ which can be used by the programmer of the callback as she sees fit.
destination. This is useful for literal data to be fed to either
strbuf_expand or to the *printf family of functions.
+`strbuf_humanise_bytes`::
+
+ Append the given byte size as a human-readable string (i.e. 12.23 KiB,
+ 3.50 MiB).
+
`strbuf_addf`::
Add a formatted string to the buffer.
diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt
new file mode 100644
index 0000000..a1173ee
--- /dev/null
+++ b/Documentation/technical/http-protocol.txt
@@ -0,0 +1,503 @@
+HTTP transfer protocols
+=======================
+
+Git supports two HTTP based transfer protocols. A "dumb" protocol
+which requires only a standard HTTP server on the server end of the
+connection, and a "smart" protocol which requires a Git aware CGI
+(or server module). This document describes both protocols.
+
+As a design feature smart clients can automatically upgrade "dumb"
+protocol URLs to smart URLs. This permits all users to have the
+same published URL, and the peers automatically select the most
+efficient transport available to them.
+
+
+URL Format
+----------
+
+URLs for Git repositories accessed by HTTP use the standard HTTP
+URL syntax documented by RFC 1738, so they are of the form:
+
+ http://<host>:<port>/<path>?<searchpart>
+
+Within this documentation the placeholder $GIT_URL will stand for
+the http:// repository URL entered by the end-user.
+
+Servers SHOULD handle all requests to locations matching $GIT_URL, as
+both the "smart" and "dumb" HTTP protocols used by Git operate
+by appending additional path components onto the end of the user
+supplied $GIT_URL string.
+
+An example of a dumb client requesting for a loose object:
+
+ $GIT_URL: http://example.com:8080/git/repo.git
+ URL request: http://example.com:8080/git/repo.git/objects/d0/49f6c27a2244e12041955e262a404c7faba355
+
+An example of a smart request to a catch-all gateway:
+
+ $GIT_URL: http://example.com/daemon.cgi?svc=git&q=
+ URL request: http://example.com/daemon.cgi?svc=git&q=/info/refs&service=git-receive-pack
+
+An example of a request to a submodule:
+
+ $GIT_URL: http://example.com/git/repo.git/path/submodule.git
+ URL request: http://example.com/git/repo.git/path/submodule.git/info/refs
+
+Clients MUST strip a trailing '/', if present, from the user supplied
+$GIT_URL string to prevent empty path tokens ('//') from appearing
+in any URL sent to a server. Compatible clients MUST expand
+'$GIT_URL/info/refs' as 'foo/info/refs' and not 'foo//info/refs'.
+
+
+Authentication
+--------------
+
+Standard HTTP authentication is used if authentication is required
+to access a repository, and MAY be configured and enforced by the
+HTTP server software.
+
+Because Git repositories are accessed by standard path components
+server administrators MAY use directory based permissions within
+their HTTP server to control repository access.
+
+Clients SHOULD support Basic authentication as described by RFC 2616.
+Servers SHOULD support Basic authentication by relying upon the
+HTTP server placed in front of the Git server software.
+
+Servers SHOULD NOT require HTTP cookies for the purposes of
+authentication or access control.
+
+Clients and servers MAY support other common forms of HTTP based
+authentication, such as Digest authentication.
+
+
+SSL
+---
+
+Clients and servers SHOULD support SSL, particularly to protect
+passwords when relying on Basic HTTP authentication.
+
+
+Session State
+-------------
+
+The Git over HTTP protocol (much like HTTP itself) is stateless
+from the perspective of the HTTP server side. All state MUST be
+retained and managed by the client process. This permits simple
+round-robin load-balancing on the server side, without needing to
+worry about state management.
+
+Clients MUST NOT require state management on the server side in
+order to function correctly.
+
+Servers MUST NOT require HTTP cookies in order to function correctly.
+Clients MAY store and forward HTTP cookies during request processing
+as described by RFC 2616 (HTTP/1.1). Servers SHOULD ignore any
+cookies sent by a client.
+
+
+General Request Processing
+--------------------------
+
+Except where noted, all standard HTTP behavior SHOULD be assumed
+by both client and server. This includes (but is not necessarily
+limited to):
+
+If there is no repository at $GIT_URL, or the resource pointed to by a
+location matching $GIT_URL does not exist, the server MUST NOT respond
+with '200 OK' response. A server SHOULD respond with
+'404 Not Found', '410 Gone', or any other suitable HTTP status code
+which does not imply the resource exists as requested.
+
+If there is a repository at $GIT_URL, but access is not currently
+permitted, the server MUST respond with the '403 Forbidden' HTTP
+status code.
+
+Servers SHOULD support both HTTP 1.0 and HTTP 1.1.
+Servers SHOULD support chunked encoding for both request and response
+bodies.
+
+Clients SHOULD support both HTTP 1.0 and HTTP 1.1.
+Clients SHOULD support chunked encoding for both request and response
+bodies.
+
+Servers MAY return ETag and/or Last-Modified headers.
+
+Clients MAY revalidate cached entities by including If-Modified-Since
+and/or If-None-Match request headers.
+
+Servers MAY return '304 Not Modified' if the relevant headers appear
+in the request and the entity has not changed. Clients MUST treat
+'304 Not Modified' identical to '200 OK' by reusing the cached entity.
+
+Clients MAY reuse a cached entity without revalidation if the
+Cache-Control and/or Expires header permits caching. Clients and
+servers MUST follow RFC 2616 for cache controls.
+
+
+Discovering References
+----------------------
+
+All HTTP clients MUST begin either a fetch or a push exchange by
+discovering the references available on the remote repository.
+
+Dumb Clients
+~~~~~~~~~~~~
+
+HTTP clients that only support the "dumb" protocol MUST discover
+references by making a request for the special info/refs file of
+the repository.
+
+Dumb HTTP clients MUST make a GET request to $GIT_URL/info/refs,
+without any search/query parameters.
+
+ C: GET $GIT_URL/info/refs HTTP/1.0
+
+ S: 200 OK
+ S:
+ S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint
+ S: d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master
+ S: 2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0
+ S: a3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}
+
+The Content-Type of the returned info/refs entity SHOULD be
+"text/plain; charset=utf-8", but MAY be any content type.
+Clients MUST NOT attempt to validate the returned Content-Type.
+Dumb servers MUST NOT return a return type starting with
+"application/x-git-".
+
+Cache-Control headers MAY be returned to disable caching of the
+returned entity.
+
+When examining the response clients SHOULD only examine the HTTP
+status code. Valid responses are '200 OK', or '304 Not Modified'.
+
+The returned content is a UNIX formatted text file describing
+each ref and its known value. The file SHOULD be sorted by name
+according to the C locale ordering. The file SHOULD NOT include
+the default ref named 'HEAD'.
+
+ info_refs = *( ref_record )
+ ref_record = any_ref / peeled_ref
+
+ any_ref = obj-id HTAB refname LF
+ peeled_ref = obj-id HTAB refname LF
+ obj-id HTAB refname "^{}" LF
+
+Smart Clients
+~~~~~~~~~~~~~
+
+HTTP clients that support the "smart" protocol (or both the
+"smart" and "dumb" protocols) MUST discover references by making
+a parameterized request for the info/refs file of the repository.
+
+The request MUST contain exactly one query parameter,
+'service=$servicename', where $servicename MUST be the service
+name the client wishes to contact to complete the operation.
+The request MUST NOT contain additional query parameters.
+
+ C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0
+
+ dumb server reply:
+ S: 200 OK
+ S:
+ S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint
+ S: d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master
+ S: 2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0
+ S: a3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}
+
+ smart server reply:
+ S: 200 OK
+ S: Content-Type: application/x-git-upload-pack-advertisement
+ S: Cache-Control: no-cache
+ S:
+ S: 001e# service=git-upload-pack\n
+ S: 004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint\0multi_ack\n
+ S: 0042d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
+ S: 003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0\n
+ S: 003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}\n
+
+Dumb Server Response
+^^^^^^^^^^^^^^^^^^^^
+Dumb servers MUST respond with the dumb server reply format.
+
+See the prior section under dumb clients for a more detailed
+description of the dumb server response.
+
+Smart Server Response
+^^^^^^^^^^^^^^^^^^^^^
+If the server does not recognize the requested service name, or the
+requested service name has been disabled by the server administrator,
+the server MUST respond with the '403 Forbidden' HTTP status code.
+
+Otherwise, smart servers MUST respond with the smart server reply
+format for the requested service name.
+
+Cache-Control headers SHOULD be used to disable caching of the
+returned entity.
+
+The Content-Type MUST be 'application/x-$servicename-advertisement'.
+Clients SHOULD fall back to the dumb protocol if another content
+type is returned. When falling back to the dumb protocol clients
+SHOULD NOT make an additional request to $GIT_URL/info/refs, but
+instead SHOULD use the response already in hand. Clients MUST NOT
+continue if they do not support the dumb protocol.
+
+Clients MUST validate the status code is either '200 OK' or
+'304 Not Modified'.
+
+Clients MUST validate the first five bytes of the response entity
+matches the regex "^[0-9a-f]{4}#". If this test fails, clients
+MUST NOT continue.
+
+Clients MUST parse the entire response as a sequence of pkt-line
+records.
+
+Clients MUST verify the first pkt-line is "# service=$servicename".
+Servers MUST set $servicename to be the request parameter value.
+Servers SHOULD include an LF at the end of this line.
+Clients MUST ignore an LF at the end of the line.
+
+Servers MUST terminate the response with the magic "0000" end
+pkt-line marker.
+
+The returned response is a pkt-line stream describing each ref and
+its known value. The stream SHOULD be sorted by name according to
+the C locale ordering. The stream SHOULD include the default ref
+named 'HEAD' as the first ref. The stream MUST include capability
+declarations behind a NUL on the first ref.
+
+ smart_reply = PKT-LINE("# service=$servicename" LF)
+ ref_list
+ "0000"
+ ref_list = empty_list / non_empty_list
+
+ empty_list = PKT-LINE(zero-id SP "capabilities^{}" NUL cap-list LF)
+
+ non_empty_list = PKT-LINE(obj-id SP name NUL cap_list LF)
+ *ref_record
+
+ cap-list = capability *(SP capability)
+ capability = 1*(LC_ALPHA / DIGIT / "-" / "_")
+ LC_ALPHA = %x61-7A
+
+ ref_record = any_ref / peeled_ref
+ any_ref = PKT-LINE(obj-id SP name LF)
+ peeled_ref = PKT-LINE(obj-id SP name LF)
+ PKT-LINE(obj-id SP name "^{}" LF
+
+Smart Service git-upload-pack
+------------------------------
+This service reads from the repository pointed to by $GIT_URL.
+
+Clients MUST first perform ref discovery with
+'$GIT_URL/info/refs?service=git-upload-pack'.
+
+ C: POST $GIT_URL/git-upload-pack HTTP/1.0
+ C: Content-Type: application/x-git-upload-pack-request
+ C:
+ C: 0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7\n
+ C: 0032have 441b40d833fdfa93eb2908e52742248faf0ee993\n
+ C: 0000
+
+ S: 200 OK
+ S: Content-Type: application/x-git-upload-pack-result
+ S: Cache-Control: no-cache
+ S:
+ S: ....ACK %s, continue
+ S: ....NAK
+
+Clients MUST NOT reuse or revalidate a cached reponse.
+Servers MUST include sufficient Cache-Control headers
+to prevent caching of the response.
+
+Servers SHOULD support all capabilities defined here.
+
+Clients MUST send at least one 'want' command in the request body.
+Clients MUST NOT reference an id in a 'want' command which did not
+appear in the response obtained through ref discovery unless the
+server advertises capability "allow-tip-sha1-in-want".
+
+ compute_request = want_list
+ have_list
+ request_end
+ request_end = "0000" / "done"
+
+ want_list = PKT-LINE(want NUL cap_list LF)
+ *(want_pkt)
+ want_pkt = PKT-LINE(want LF)
+ want = "want" SP id
+ cap_list = *(SP capability) SP
+
+ have_list = *PKT-LINE("have" SP id LF)
+
+TODO: Document this further.
+TODO: Don't use uppercase for variable names below.
+
+The Negotiation Algorithm
+~~~~~~~~~~~~~~~~~~~~~~~~~
+The computation to select the minimal pack proceeds as follows
+(c = client, s = server):
+
+ init step:
+ (c) Use ref discovery to obtain the advertised refs.
+ (c) Place any object seen into set ADVERTISED.
+
+ (c) Build an empty set, COMMON, to hold the objects that are later
+ determined to be on both ends.
+ (c) Build a set, WANT, of the objects from ADVERTISED the client
+ wants to fetch, based on what it saw during ref discovery.
+
+ (c) Start a queue, C_PENDING, ordered by commit time (popping newest
+ first). Add all client refs. When a commit is popped from
+ the queue its parents SHOULD be automatically inserted back.
+ Commits MUST only enter the queue once.
+
+ one compute step:
+ (c) Send one $GIT_URL/git-upload-pack request:
+
+ C: 0032want <WANT #1>...............................
+ C: 0032want <WANT #2>...............................
+ ....
+ C: 0032have <COMMON #1>.............................
+ C: 0032have <COMMON #2>.............................
+ ....
+ C: 0032have <HAVE #1>...............................
+ C: 0032have <HAVE #2>...............................
+ ....
+ C: 0000
+
+ The stream is organized into "commands", with each command
+ appearing by itself in a pkt-line. Within a command line
+ the text leading up to the first space is the command name,
+ and the remainder of the line to the first LF is the value.
+ Command lines are terminated with an LF as the last byte of
+ the pkt-line value.
+
+ Commands MUST appear in the following order, if they appear
+ at all in the request stream:
+
+ * want
+ * have
+
+ The stream is terminated by a pkt-line flush ("0000").
+
+ A single "want" or "have" command MUST have one hex formatted
+ SHA-1 as its value. Multiple SHA-1s MUST be sent by sending
+ multiple commands.
+
+ The HAVE list is created by popping the first 32 commits
+ from C_PENDING. Less can be supplied if C_PENDING empties.
+
+ If the client has sent 256 HAVE commits and has not yet
+ received one of those back from S_COMMON, or the client has
+ emptied C_PENDING it SHOULD include a "done" command to let
+ the server know it won't proceed:
+
+ C: 0009done
+
+ (s) Parse the git-upload-pack request:
+
+ Verify all objects in WANT are directly reachable from refs.
+
+ The server MAY walk backwards through history or through
+ the reflog to permit slightly stale requests.
+
+ If no WANT objects are received, send an error:
+
+TODO: Define error if no want lines are requested.
+
+ If any WANT object is not reachable, send an error:
+
+TODO: Define error if an invalid want is requested.
+
+ Create an empty list, S_COMMON.
+
+ If 'have' was sent:
+
+ Loop through the objects in the order supplied by the client.
+ For each object, if the server has the object reachable from
+ a ref, add it to S_COMMON. If a commit is added to S_COMMON,
+ do not add any ancestors, even if they also appear in HAVE.
+
+ (s) Send the git-upload-pack response:
+
+ If the server has found a closed set of objects to pack or the
+ request ends with "done", it replies with the pack.
+
+TODO: Document the pack based response
+ S: PACK...
+
+ The returned stream is the side-band-64k protocol supported
+ by the git-upload-pack service, and the pack is embedded into
+ stream 1. Progress messages from the server side MAY appear
+ in stream 2.
+
+ Here a "closed set of objects" is defined to have at least
+ one path from every WANT to at least one COMMON object.
+
+ If the server needs more information, it replies with a
+ status continue response:
+
+TODO: Document the non-pack response
+
+ (c) Parse the upload-pack response:
+
+TODO: Document parsing response
+
+ Do another compute step.
+
+
+Smart Service git-receive-pack
+------------------------------
+This service reads from the repository pointed to by $GIT_URL.
+
+Clients MUST first perform ref discovery with
+'$GIT_URL/info/refs?service=git-receive-pack'.
+
+ C: POST $GIT_URL/git-receive-pack HTTP/1.0
+ C: Content-Type: application/x-git-receive-pack-request
+ C:
+ C: ....0a53e9ddeaddad63ad106860237bbf53411d11a7 441b40d833fdfa93eb2908e52742248faf0ee993 refs/heads/maint\0 report-status
+ C: 0000
+ C: PACK....
+
+ S: 200 OK
+ S: Content-Type: application/x-git-receive-pack-result
+ S: Cache-Control: no-cache
+ S:
+ S: ....
+
+Clients MUST NOT reuse or revalidate a cached reponse.
+Servers MUST include sufficient Cache-Control headers
+to prevent caching of the response.
+
+Servers SHOULD support all capabilities defined here.
+
+Clients MUST send at least one command in the request body.
+Within the command portion of the request body clients SHOULD send
+the id obtained through ref discovery as old_id.
+
+ update_request = command_list
+ "PACK" <binary data>
+
+ command_list = PKT-LINE(command NUL cap_list LF)
+ *(command_pkt)
+ command_pkt = PKT-LINE(command LF)
+ cap_list = *(SP capability) SP
+
+ command = create / delete / update
+ create = zero-id SP new_id SP name
+ delete = old_id SP zero-id SP name
+ update = old_id SP new_id SP name
+
+TODO: Document this further.
+
+
+References
+----------
+
+link:http://www.ietf.org/rfc/rfc1738.txt[RFC 1738: Uniform Resource Locators (URL)]
+link:http://www.ietf.org/rfc/rfc2616.txt[RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1]
+link:technical/pack-protocol.txt
+link:technical/protocol-capabilities.txt
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index 0810251..f352a9b 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -175,7 +175,7 @@ Git index format
A conflict is represented in the index as a set of higher stage entries.
When a conflict is resolved (e.g. with "git add path"), these higher
- stage entries will be removed and a stage-0 entry with proper resoluton
+ stage entries will be removed and a stage-0 entry with proper resolution
is added.
When these higher stage entries are removed, they are saved in the
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index f1a51ed..b898e97 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -228,8 +228,7 @@ obtained through ref discovery.
The client MUST write all obj-ids which it only has shallow copies
of (meaning that it does not have the parents of a commit) as
'shallow' lines so that the server is aware of the limitations of
-the client's history. Clients MUST NOT mention an obj-id which
-it does not know exists on the server.
+the client's history.
The client now sends the maximum commit history depth it wants for
this transaction, which is the number of commits it wants from the
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index b15517f..fd8ffa5 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -18,11 +18,12 @@ was sent. Server MUST NOT ignore capabilities that client requested
and server advertised. As a consequence of these rules, server MUST
NOT advertise capabilities it does not understand.
-The 'report-status' and 'delete-refs' capabilities are sent and
+The 'report-status', 'delete-refs', and 'quiet' capabilities are sent and
recognized by the receive-pack (push to server) process.
-The 'ofs-delta' capability is sent and recognized by both upload-pack
-and receive-pack protocols.
+The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized
+by both upload-pack and receive-pack protocols. The 'agent' capability
+may optionally be sent in both protocols.
All other capabilities are only recognized by the upload-pack (fetch
from server) process.
@@ -123,6 +124,20 @@ Server can send, and client understand PACKv2 with delta referring to
its base by position in pack rather than by an obj-id. That is, they can
send/read OBJ_OFS_DELTA (aka type 6) in a packfile.
+agent
+-----
+
+The server may optionally send a capability of the form `agent=X` to
+notify the client that the server is running version `X`. The client may
+optionally return its own agent string by responding with an `agent=Y`
+capability (but it MUST NOT do so if the server did not mention the
+agent capability). The `X` and `Y` strings may contain any printable
+ASCII characters except space (i.e., the byte range 32 < x < 127), and
+are typically of the form "package/version" (e.g., "git/1.8.3.1"). The
+agent strings are purely informative for statistics and debugging
+purposes, and MUST NOT be used to programatically assume the presence
+or absence of particular features.
+
shallow
-------
@@ -168,7 +183,7 @@ of whether or not there are tags available.
report-status
-------------
-The upload-pack process can receive a 'report-status' capability,
+The receive-pack process can receive a 'report-status' capability,
which tells it that the client wants a report of what happened after
a packfile upload and reference update. If the pushing client requests
this capability, after unpacking and updating references the server
@@ -185,3 +200,20 @@ it is capable of accepting a zero-id value as the target
value of a reference update. It is not sent back by the client, it
simply informs the client that it can be sent zero-id values
to delete references.
+
+quiet
+-----
+
+If the receive-pack server advertises the 'quiet' capability, it is
+capable of silencing human-readable progress output which otherwise may
+be shown when processing the received pack. A send-pack client should
+respond with the 'quiet' capability to suppress server-side progress
+reporting if the local progress reporting is also being suppressed
+(e.g., via `push -q`, or if stderr does not go to a tty).
+
+allow-tip-sha1-in-want
+----------------------
+
+If the upload-pack server advertises this capability, fetch-pack may
+send "want" lines with SHA-1s that exist at the server but are not
+advertised by upload-pack.
diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.txt
index 6dc82ca..242a044 100644
--- a/Documentation/technical/racy-git.txt
+++ b/Documentation/technical/racy-git.txt
@@ -46,7 +46,7 @@ because in-core timestamps can have finer granularity than
on-disk timestamps, resulting in meaningless changes when an
inode is evicted from the inode cache. See commit 8ce13b0
of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
-([PATCH] Sync in core time granuality with filesystems,
+([PATCH] Sync in core time granularity with filesystems,
2005-01-04).
Racy Git
@@ -135,9 +135,9 @@ them, and give the same timestamp to the index file:
$ git ls-files | git update-index --stdin
$ touch -r .datestamp .git/index
-This will make all index entries racily clean. The linux-2.6
-project, for example, there are over 20,000 files in the working
-tree. On my Athlon 64 X2 3800+, after the above:
+This will make all index entries racily clean. The linux project, for
+example, there are over 20,000 files in the working tree. On my
+Athlon 64 X2 3800+, after the above:
$ /usr/bin/time git diff-files
1.68user 0.54system 0:02.22elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
diff --git a/Documentation/urls.txt b/Documentation/urls.txt
index 3ca122f..9ccb246 100644
--- a/Documentation/urls.txt
+++ b/Documentation/urls.txt
@@ -11,6 +11,9 @@ and ftps can be used for fetching and rsync can be used for fetching
and pushing, but these are inefficient and deprecated; do not use
them).
+The native transport (i.e. git:// URL) does no authentication and
+should be used with caution on unsecured networks.
+
The following syntaxes may be used with them:
- ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/path/to/repo.git/
@@ -23,6 +26,12 @@ An alternative scp-like syntax may also be used with the ssh protocol:
- {startsb}user@{endsb}host.xz:path/to/repo.git/
+This syntax is only recognized if there are no slashes before the
+first colon. This helps differentiate a local path that contains a
+colon. For example the local path `foo:bar` could be specified as an
+absolute path or `./foo:bar` to avoid being misinterpreted as an ssh
+url.
+
The ssh and git protocols additionally support ~username expansion:
- ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/~{startsb}user{endsb}/path/to/repo.git/
@@ -33,7 +42,7 @@ For local repositories, also supported by Git natively, the following
syntaxes may be used:
- /path/to/repo.git/
-- file:///path/to/repo.git/
+- \file:///path/to/repo.git/
ifndef::git-clone[]
These two syntaxes are mostly equivalent, except when cloning, when
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index e831cc2..fe723e4 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -57,17 +57,17 @@ download a copy of an existing repository. If you don't already have a
project in mind, here are some interesting examples:
------------------------------------------------
- # Git itself (approx. 10MB download):
+ # Git itself (approx. 40MB download):
$ git clone git://git.kernel.org/pub/scm/git/git.git
- # the Linux kernel (approx. 150MB download):
-$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+ # the Linux kernel (approx. 640MB download):
+$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
------------------------------------------------
The initial clone may be time-consuming for a large project, but you
will only need to clone once.
-The clone command creates a new directory named after the project (`git`
-or `linux-2.6` in the examples above). After you cd into this
+The clone command creates a new directory named after the project
+(`git` or `linux` in the examples above). After you cd into this
directory, you will see that it contains a copy of the project files,
called the <<def_working_tree,working tree>>, together with a special
top-level directory named `.git`, which contains all the information
@@ -431,19 +431,25 @@ You can also track branches from repositories other than the one you
cloned from, using linkgit:git-remote[1]:
-------------------------------------------------
-$ git remote add linux-nfs git://linux-nfs.org/pub/nfs-2.6.git
-$ git fetch linux-nfs
-* refs/remotes/linux-nfs/master: storing branch 'master' ...
- commit: bf81b46
+$ git remote add staging git://git.kernel.org/.../gregkh/staging.git
+$ git fetch staging
+...
+From git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
+ * [new branch] master -> staging/master
+ * [new branch] staging-linus -> staging/staging-linus
+ * [new branch] staging-next -> staging/staging-next
-------------------------------------------------
New remote-tracking branches will be stored under the shorthand name
-that you gave `git remote add`, in this case `linux-nfs`:
+that you gave `git remote add`, in this case `staging`:
-------------------------------------------------
$ git branch -r
-linux-nfs/master
-origin/master
+ origin/HEAD -> origin/master
+ origin/master
+ staging/master
+ staging/staging-linus
+ staging/staging-next
-------------------------------------------------
If you run `git fetch <remote>` later, the remote-tracking branches
@@ -455,9 +461,9 @@ a new stanza:
-------------------------------------------------
$ cat .git/config
...
-[remote "linux-nfs"]
- url = git://linux-nfs.org/pub/nfs-2.6.git
- fetch = +refs/heads/*:refs/remotes/linux-nfs/*
+[remote "staging"]
+ url = git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
+ fetch = +refs/heads/*:refs/remotes/staging/*
...
-------------------------------------------------
@@ -1835,7 +1841,7 @@ Once the index is updated with the results of the conflict
resolution, instead of creating a new commit, just run
-------------------------------------------------
-$ git am --resolved
+$ git am --continue
-------------------------------------------------
and Git will create the commit for you and continue applying the
@@ -2156,7 +2162,7 @@ To set this up, first create your work tree by cloning Linus's public
tree:
-------------------------------------------------
-$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
+$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git work
$ cd work
-------------------------------------------------
@@ -2198,7 +2204,7 @@ make it easy to push both branches to your public tree. (See
-------------------------------------------------
$ cat >> .git/config <<EOF
[remote "mytree"]
- url = master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
+ url = master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux.git
push = release
push = test
EOF
@@ -4256,15 +4262,16 @@ no longer need to call `setup_pager()` directly).
Nowadays, `git log` is a builtin, which means that it is _contained_ in the
command `git`. The source side of a builtin is
-- a function called `cmd_<bla>`, typically defined in `builtin-<bla>.c`,
- and declared in `builtin.h`,
+- a function called `cmd_<bla>`, typically defined in `builtin/<bla.c>`
+ (note that older versions of Git used to have it in `builtin-<bla>.c`
+ instead), and declared in `builtin.h`.
- an entry in the `commands[]` array in `git.c`, and
- an entry in `BUILTIN_OBJECTS` in the `Makefile`.
Sometimes, more than one builtin is contained in one source file. For
-example, `cmd_whatchanged()` and `cmd_log()` both reside in `builtin-log.c`,
+example, `cmd_whatchanged()` and `cmd_log()` both reside in `builtin/log.c`,
since they share quite a bit of code. In that case, the commands which are
_not_ named like the `.c` file in which they live have to be listed in
`BUILT_INS` in the `Makefile`.
@@ -4287,10 +4294,10 @@ For the sake of clarity, let's stay with `git cat-file`, because it
- is plumbing, and
- was around even in the initial commit (it literally went only through
- some 20 revisions as `cat-file.c`, was renamed to `builtin-cat-file.c`
+ some 20 revisions as `cat-file.c`, was renamed to `builtin/cat-file.c`
when made a builtin, and then saw less than 10 versions).
-So, look into `builtin-cat-file.c`, search for `cmd_cat_file()` and look what
+So, look into `builtin/cat-file.c`, search for `cmd_cat_file()` and look what
it does.
------------------------------------------------------------------
@@ -4366,7 +4373,7 @@ Another example: Find out what to do in order to make some script a
builtin:
-------------------------------------------------
-$ git log --no-merges --diff-filter=A builtin-*.c
+$ git log --no-merges --diff-filter=A builtin/*.c
-------------------------------------------------
You see, Git is actually the best tool to find out about the source of Git
@@ -4668,5 +4675,5 @@ Write a chapter on using plumbing and writing scripts.
Alternates, clone -reference, etc.
More on recovery from repository corruption. See:
- http://marc.theaimsgroup.com/?l=git&m=117263864820799&w=2
- http://marc.theaimsgroup.com/?l=git&m=117147855503798&w=2
+ http://marc.info/?l=git&m=117263864820799&w=2
+ http://marc.info/?l=git&m=117147855503798&w=2
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index f7ec14a..b444c18 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.2.3
+DEF_VER=v1.8.4.GIT
LF='
'
@@ -11,7 +11,7 @@ LF='
if test -f version
then
VN=$(cat version) || VN="$DEF_VER"
-elif test -d .git -o -f .git &&
+elif test -d ${GIT_DIR:-.git} -o -f .git &&
VN=$(git describe --match "v[0-9]*" --abbrev=7 HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
diff --git a/Makefile b/Makefile
index 598d631..e2abb7b 100644
--- a/Makefile
+++ b/Makefile
@@ -106,7 +106,7 @@ all::
# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the
# FNM_CASEFOLD GNU extension.
#
-# Define USE_WILDMATCH if you want to use Git's wildmatch
+# Define NO_WILDMATCH if you do not want to use Git's wildmatch
# implementation as fnmatch
#
# Define NO_GECOS_IN_PWENT if you don't have pw_gecos in struct passwd
@@ -137,6 +137,10 @@ all::
# specify your own (or DarwinPort's) include directories and
# library directories by defining CFLAGS and LDFLAGS appropriately.
#
+# Define NO_APPLE_COMMON_CRYPTO if you are building on Darwin/Mac OS X
+# and do not want to use Apple's CommonCrypto library. This allows you
+# to provide your own OpenSSL library, for example from MacPorts.
+#
# Define BLK_SHA1 environment variable to make use of the bundled
# optimized C SHA1 routine.
#
@@ -290,10 +294,6 @@ all::
#
# Define NO_REGEX if you have no or inferior regex support in your C library.
#
-# Define CYGWIN_V15_WIN32API if you are using Cygwin v1.7.x but are not
-# using the current w32api packages. The recommended approach, however,
-# is to update your installation if compilation errors occur.
-#
# Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the
# user.
#
@@ -358,33 +358,39 @@ STRIP ?= strip
# Among the variables below, these:
# gitexecdir
# template_dir
-# mandir
-# infodir
-# htmldir
# sysconfdir
# can be specified as a relative path some/where/else;
# this is interpreted as relative to $(prefix) and "git" at
# runtime figures out where they are based on the path to the executable.
+# Additionally, the following will be treated as relative by "git" if they
+# begin with "$(prefix)/":
+# mandir
+# infodir
+# htmldir
# This can help installing the suite in a relocatable way.
prefix = $(HOME)
bindir_relative = bin
bindir = $(prefix)/$(bindir_relative)
-mandir = share/man
-infodir = share/info
+mandir = $(prefix)/share/man
+infodir = $(prefix)/share/info
gitexecdir = libexec/git-core
mergetoolsdir = $(gitexecdir)/mergetools
sharedir = $(prefix)/share
gitwebdir = $(sharedir)/gitweb
localedir = $(sharedir)/locale
template_dir = share/git-core/templates
-htmldir = share/doc/git-doc
+htmldir = $(prefix)/share/doc/git-doc
ETC_GITCONFIG = $(sysconfdir)/gitconfig
ETC_GITATTRIBUTES = $(sysconfdir)/gitattributes
lib = lib
# DESTDIR =
pathsep = :
+mandir_relative = $(patsubst $(prefix)/%,%,$(mandir))
+infodir_relative = $(patsubst $(prefix)/%,%,$(infodir))
+htmldir_relative = $(patsubst $(prefix)/%,%,$(htmldir))
+
export prefix bindir sharedir sysconfdir gitwebdir localedir
CC = cc
@@ -454,6 +460,7 @@ SCRIPT_SH += git-mergetool.sh
SCRIPT_SH += git-pull.sh
SCRIPT_SH += git-quiltimport.sh
SCRIPT_SH += git-rebase.sh
+SCRIPT_SH += git-remote-testgit.sh
SCRIPT_SH += git-repack.sh
SCRIPT_SH += git-request-pull.sh
SCRIPT_SH += git-stash.sh
@@ -481,11 +488,18 @@ SCRIPT_PERL += git-svn.perl
SCRIPT_PYTHON += git-remote-testpy.py
SCRIPT_PYTHON += git-p4.py
+NO_INSTALL += git-remote-testgit
+NO_INSTALL += git-remote-testpy
+
# Generated files for scripts
SCRIPT_SH_GEN = $(patsubst %.sh,%,$(SCRIPT_SH))
SCRIPT_PERL_GEN = $(patsubst %.perl,%,$(SCRIPT_PERL))
SCRIPT_PYTHON_GEN = $(patsubst %.py,%,$(SCRIPT_PYTHON))
+SCRIPT_SH_INS = $(filter-out $(NO_INSTALL),$(SCRIPT_SH_GEN))
+SCRIPT_PERL_INS = $(filter-out $(NO_INSTALL),$(SCRIPT_PERL_GEN))
+SCRIPT_PYTHON_INS = $(filter-out $(NO_INSTALL),$(SCRIPT_PYTHON_GEN))
+
# Individual rules to allow e.g.
# "make -C ../.. SCRIPT_PERL=contrib/foo/bar.perl build-perl-script"
# from subdirectories like contrib/*/
@@ -495,12 +509,12 @@ build-sh-script: $(SCRIPT_SH_GEN)
build-python-script: $(SCRIPT_PYTHON_GEN)
.PHONY: install-perl-script install-sh-script install-python-script
-install-sh-script: $(SCRIPT_SH_GEN)
- $(INSTALL) $(SCRIPT_SH_GEN) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
-install-perl-script: $(SCRIPT_PERL_GEN)
- $(INSTALL) $(SCRIPT_PERL_GEN) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
-install-python-script: $(SCRIPT_PYTHON_GEN)
- $(INSTALL) $(SCRIPT_PYTHON_GEN) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+install-sh-script: $(SCRIPT_SH_INS)
+ $(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+install-perl-script: $(SCRIPT_PERL_INS)
+ $(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+install-python-script: $(SCRIPT_PYTHON_INS)
+ $(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
.PHONY: clean-perl-script clean-sh-script clean-python-script
clean-sh-script:
@@ -510,9 +524,9 @@ clean-perl-script:
clean-python-script:
$(RM) $(SCRIPT_PYTHON_GEN)
-SCRIPTS = $(SCRIPT_SH_GEN) \
- $(SCRIPT_PERL_GEN) \
- $(SCRIPT_PYTHON_GEN) \
+SCRIPTS = $(SCRIPT_SH_INS) \
+ $(SCRIPT_PERL_INS) \
+ $(SCRIPT_PYTHON_INS) \
git-instaweb
ETAGS_TARGET = TAGS
@@ -552,6 +566,8 @@ TEST_PROGRAMS_NEED_X += test-mergesort
TEST_PROGRAMS_NEED_X += test-mktemp
TEST_PROGRAMS_NEED_X += test-parse-options
TEST_PROGRAMS_NEED_X += test-path-utils
+TEST_PROGRAMS_NEED_X += test-prio-queue
+TEST_PROGRAMS_NEED_X += test-read-cache
TEST_PROGRAMS_NEED_X += test-regex
TEST_PROGRAMS_NEED_X += test-revision-walking
TEST_PROGRAMS_NEED_X += test-run-command
@@ -561,6 +577,7 @@ 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
+TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
TEST_PROGRAMS_NEED_X += test-wildmatch
TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
@@ -635,7 +652,6 @@ 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
@@ -667,6 +683,8 @@ LIB_H += help.h
LIB_H += http.h
LIB_H += kwset.h
LIB_H += levenshtein.h
+LIB_H += line-log.h
+LIB_H += line-range.h
LIB_H += list-objects.h
LIB_H += ll-merge.h
LIB_H += log-tree.h
@@ -676,15 +694,16 @@ LIB_H += merge-recursive.h
LIB_H += mergesort.h
LIB_H += notes-cache.h
LIB_H += notes-merge.h
+LIB_H += notes-utils.h
LIB_H += notes.h
LIB_H += object.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 += pathspec.h
LIB_H += pkt-line.h
+LIB_H += prio-queue.h
LIB_H += progress.h
LIB_H += prompt.h
LIB_H += quote.h
@@ -715,6 +734,7 @@ LIB_H += tree-walk.h
LIB_H += tree.h
LIB_H += unpack-trees.h
LIB_H += url.h
+LIB_H += urlmatch.h
LIB_H += userdiff.h
LIB_H += utf8.h
LIB_H += varint.h
@@ -795,6 +815,8 @@ LIB_OBJS += hex.o
LIB_OBJS += ident.o
LIB_OBJS += kwset.o
LIB_OBJS += levenshtein.o
+LIB_OBJS += line-log.o
+LIB_OBJS += line-range.o
LIB_OBJS += list-objects.o
LIB_OBJS += ll-merge.o
LIB_OBJS += lockfile.o
@@ -809,9 +831,9 @@ LIB_OBJS += name-hash.o
LIB_OBJS += notes.o
LIB_OBJS += notes-cache.o
LIB_OBJS += notes-merge.o
+LIB_OBJS += notes-utils.o
LIB_OBJS += object.o
LIB_OBJS += pack-check.o
-LIB_OBJS += pack-refs.o
LIB_OBJS += pack-revindex.o
LIB_OBJS += pack-write.o
LIB_OBJS += pager.o
@@ -824,6 +846,7 @@ LIB_OBJS += pathspec.o
LIB_OBJS += pkt-line.o
LIB_OBJS += preload-index.o
LIB_OBJS += pretty.o
+LIB_OBJS += prio-queue.o
LIB_OBJS += progress.o
LIB_OBJS += prompt.o
LIB_OBJS += quote.o
@@ -862,6 +885,7 @@ LIB_OBJS += tree.o
LIB_OBJS += tree-walk.o
LIB_OBJS += unpack-trees.o
LIB_OBJS += url.o
+LIB_OBJS += urlmatch.o
LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
@@ -887,6 +911,7 @@ BUILTIN_OBJS += builtin/bundle.o
BUILTIN_OBJS += builtin/cat-file.o
BUILTIN_OBJS += builtin/check-attr.o
BUILTIN_OBJS += builtin/check-ignore.o
+BUILTIN_OBJS += builtin/check-mailmap.o
BUILTIN_OBJS += builtin/check-ref-format.o
BUILTIN_OBJS += builtin/checkout-index.o
BUILTIN_OBJS += builtin/checkout.o
@@ -1048,6 +1073,11 @@ ifeq ($(uname_S),Darwin)
BASIC_LDFLAGS += -L/opt/local/lib
endif
endif
+ ifndef NO_APPLE_COMMON_CRYPTO
+ APPLE_COMMON_CRYPTO = YesPlease
+ COMPAT_CFLAGS += -DAPPLE_COMMON_CRYPTO
+ endif
+ NO_REGEX = YesPlease
PTHREAD_LIBS =
endif
@@ -1152,6 +1182,9 @@ ifdef NEEDS_SSL_WITH_CRYPTO
else
LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto
endif
+ifdef APPLE_COMMON_CRYPTO
+ LIB_4_CRYPTO += -framework Security -framework CoreFoundation
+endif
endif
ifdef NEEDS_LIBICONV
ifdef ICONVDIR
@@ -1255,7 +1288,7 @@ ifdef NO_FNMATCH_CASEFOLD
COMPAT_OBJS += compat/fnmatch/fnmatch.o
endif
endif
-ifdef USE_WILDMATCH
+ifndef NO_WILDMATCH
COMPAT_CFLAGS += -DUSE_WILDMATCH
endif
ifdef NO_SETENV
@@ -1382,10 +1415,16 @@ ifdef PPC_SHA1
LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
LIB_H += ppc/sha1.h
else
+ifdef APPLE_COMMON_CRYPTO
+ COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
+ SHA1_HEADER = <CommonCrypto/CommonDigest.h>
+else
SHA1_HEADER = <openssl/sha.h>
EXTLIBS += $(LIB_4_CRYPTO)
endif
endif
+endif
+
ifdef NO_PERL_MAKEMAKER
export NO_PERL_MAKEMAKER
endif
@@ -1443,9 +1482,6 @@ ifdef NO_REGEX
COMPAT_CFLAGS += -Icompat/regex
COMPAT_OBJS += compat/regex/regex.o
endif
-ifdef CYGWIN_V15_WIN32API
- COMPAT_CFLAGS += -DCYGWIN_V15_WIN32API
-endif
ifdef USE_NED_ALLOCATOR
COMPAT_CFLAGS += -Icompat/nedmalloc
@@ -1497,6 +1533,7 @@ ifndef V
QUIET_MSGFMT = @echo ' ' MSGFMT $@;
QUIET_GCOV = @echo ' ' GCOV $@;
QUIET_SP = @echo ' ' SP $<;
+ QUIET_RC = @echo ' ' RC $@;
QUIET_SUBDIR0 = +@subdir=
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
$(MAKE) $(PRINT_DIR) -C $$subdir
@@ -1539,12 +1576,12 @@ ETC_GITATTRIBUTES_SQ = $(subst ','\'',$(ETC_GITATTRIBUTES))
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
bindir_SQ = $(subst ','\'',$(bindir))
bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
-mandir_SQ = $(subst ','\'',$(mandir))
-infodir_SQ = $(subst ','\'',$(infodir))
+mandir_relative_SQ = $(subst ','\'',$(mandir_relative))
+infodir_relative_SQ = $(subst ','\'',$(infodir_relative))
localedir_SQ = $(subst ','\'',$(localedir))
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
template_dir_SQ = $(subst ','\'',$(template_dir))
-htmldir_SQ = $(subst ','\'',$(htmldir))
+htmldir_relative_SQ = $(subst ','\'',$(htmldir_relative))
prefix_SQ = $(subst ','\'',$(prefix))
gitwebdir_SQ = $(subst ','\'',$(gitwebdir))
@@ -1639,7 +1676,7 @@ please_set_SHELL_PATH_to_a_more_modern_shell:
shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
strip: $(PROGRAMS) git$X
- $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
+ $(STRIP) $(STRIP_OPTS) $^
### Target-specific flags and dependencies
@@ -1676,9 +1713,9 @@ strip: $(PROGRAMS) git$X
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)"'
+ '-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
+ '-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
+ '-DGIT_INFO_PATH="$(infodir_relative_SQ)"'
git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
@@ -1688,9 +1725,9 @@ help.sp help.s 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)"'
+ '-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
+ '-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
+ '-DGIT_INFO_PATH="$(infodir_relative_SQ)"'
version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT
version.sp version.s version.o: EXTRA_CPPFLAGS = \
@@ -1699,9 +1736,9 @@ version.sp version.s version.o: EXTRA_CPPFLAGS = \
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && \
- ln git$X $@ 2>/dev/null || \
- ln -s git$X $@ 2>/dev/null || \
- cp git$X $@
+ ln $< $@ 2>/dev/null || \
+ ln -s $< $@ 2>/dev/null || \
+ cp $< $@
common-cmds.h: ./generate-cmdlist.sh command-list.txt
@@ -1742,6 +1779,11 @@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
$(QUIET_GEN)$(cmd_munge_script) && \
mv $@+ $@
+git.res: git.rc GIT-VERSION-FILE
+ $(QUIET_RC)$(RC) \
+ $(join -DMAJOR= -DMINOR= -DPATCH=, $(wordlist 1,3,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \
+ -DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" $< -o $@
+
ifndef NO_PERL
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
@@ -1766,7 +1808,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
-e ' x' \
-e '}' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
- $@.perl >$@+ && \
+ $< >$@+ && \
chmod +x $@+ && \
mv $@+ $@
@@ -1790,8 +1832,8 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
endif # NO_PERL
ifndef NO_PYTHON
-$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
-$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
+$(SCRIPT_PYTHON_GEN): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
+$(SCRIPT_PYTHON_GEN): % : %.py
$(QUIET_GEN)$(RM) $@ $@+ && \
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
--no-print-directory prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' \
@@ -1799,11 +1841,11 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
sed -e '1s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
-e 's|\(os\.getenv("GITPYTHONLIB"\)[^)]*)|\1,"@@INSTLIBDIR@@")|' \
-e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
- $@.py >$@+ && \
+ $< >$@+ && \
chmod +x $@+ && \
mv $@+ $@
else # NO_PYTHON
-$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : unimplemented.sh
+$(SCRIPT_PYTHON_GEN): % : unimplemented.sh
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@@REASON@@|NO_PYTHON=$(NO_PYTHON)|g' \
@@ -1998,6 +2040,7 @@ endif
ifdef USE_NED_ALLOCATOR
compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
-DNDEBUG -DOVERRIDE_STRDUP -DREPLACE_SYSTEM_ALLOCATOR
+compat/nedmalloc/nedmalloc.sp: SPARSE_FLAGS += -Wno-non-pointer-null
endif
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
@@ -2029,13 +2072,13 @@ $(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS $(GITLIBS
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
$(LIB_FILE): $(LIB_OBJS)
- $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
+ $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $^
$(XDIFF_LIB): $(XDIFF_OBJS)
- $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(XDIFF_OBJS)
+ $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $^
$(VCSSVN_LIB): $(VCSSVN_OBJS)
- $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(VCSSVN_OBJS)
+ $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $^
export DEFAULT_EDITOR DEFAULT_PAGER
@@ -2153,6 +2196,9 @@ GIT-BUILD-OPTIONS: FORCE
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
@echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@
@echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@
+ifdef TEST_OUTPUT_DIRECTORY
+ @echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@
+endif
ifdef GIT_TEST_OPTS
@echo GIT_TEST_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_OPTS)))'\' >>$@
endif
@@ -2192,6 +2238,7 @@ endif
test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
all:: $(TEST_PROGRAMS) $(test_bindir_programs)
+all:: $(NO_INSTALL)
bin-wrappers/%: wrap-for-bin.sh
@mkdir -p bin-wrappers
@@ -2256,9 +2303,6 @@ check: common-cmds.h
exit 1; \
fi
-remove-dashes:
- ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
-
### Installation rules
ifneq ($(filter /%,$(firstword $(template_dir))),)
@@ -2437,11 +2481,11 @@ profile-clean:
$(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
$(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
-clean: profile-clean
- $(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \
+clean: profile-clean coverage-clean
+ $(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \
builtin/*.o $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
- $(RM) $(TEST_PROGRAMS)
+ $(RM) $(TEST_PROGRAMS) $(NO_INSTALL)
$(RM) -r bin-wrappers $(dep_dirs)
$(RM) -r po/build/
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*
@@ -2518,29 +2562,34 @@ check-builtins::
### Test suite coverage testing
#
-.PHONY: coverage coverage-clean coverage-build coverage-report
+.PHONY: coverage coverage-clean coverage-compile coverage-test coverage-report
+.PHONY: coverage-clean-results
coverage:
- $(MAKE) coverage-build
- $(MAKE) coverage-report
+ $(MAKE) coverage-test
+ $(MAKE) coverage-untested-functions
object_dirs := $(sort $(dir $(OBJECTS)))
-coverage-clean:
+coverage-clean-results:
$(RM) $(addsuffix *.gcov,$(object_dirs))
$(RM) $(addsuffix *.gcda,$(object_dirs))
- $(RM) $(addsuffix *.gcno,$(object_dirs))
$(RM) coverage-untested-functions
$(RM) -r cover_db/
$(RM) -r cover_db_html/
+coverage-clean: coverage-clean-results
+ $(RM) $(addsuffix *.gcno,$(object_dirs))
+
COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
GCOVFLAGS = --preserve-paths --branch-probabilities --all-blocks
-coverage-build: coverage-clean
+coverage-compile:
$(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
+
+coverage-test: coverage-clean-results coverage-compile
$(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
- -j1 test
+ DEFAULT_TEST_TARGET=test -j1 test
coverage-report:
$(QUIET_GCOV)for dir in $(object_dirs); do \
diff --git a/RelNotes b/RelNotes
index 155555e..61c3b54 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.2.3.txt \ No newline at end of file
+Documentation/RelNotes/1.8.5.txt \ No newline at end of file
diff --git a/abspath.c b/abspath.c
index 40cdc46..64adbe2 100644
--- a/abspath.c
+++ b/abspath.c
@@ -216,7 +216,7 @@ const char *absolute_path(const char *path)
const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
{
static char path[PATH_MAX];
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
if (!pfx_len || is_absolute_path(arg))
return arg;
memcpy(path, pfx, pfx_len);
diff --git a/advice.c b/advice.c
index 3bc8626..3eca9f5 100644
--- a/advice.c
+++ b/advice.c
@@ -13,6 +13,9 @@ int advice_commit_before_merge = 1;
int advice_resolve_conflict = 1;
int advice_implicit_identity = 1;
int advice_detached_head = 1;
+int advice_set_upstream_failure = 1;
+int advice_object_name_warning = 1;
+int advice_rm_hints = 1;
static struct {
const char *name;
@@ -31,6 +34,9 @@ static struct {
{ "resolveconflict", &advice_resolve_conflict },
{ "implicitidentity", &advice_implicit_identity },
{ "detachedhead", &advice_detached_head },
+ { "setupstreamfailure", &advice_set_upstream_failure },
+ { "objectnamewarning", &advice_object_name_warning },
+ { "rmhints", &advice_rm_hints },
/* make this an alias for backward compatibility */
{ "pushnonfastforward", &advice_push_update_rejected }
diff --git a/advice.h b/advice.h
index af0c983..08fbc8e 100644
--- a/advice.h
+++ b/advice.h
@@ -16,8 +16,12 @@ extern int advice_commit_before_merge;
extern int advice_resolve_conflict;
extern int advice_implicit_identity;
extern int advice_detached_head;
+extern int advice_set_upstream_failure;
+extern int advice_object_name_warning;
+extern int advice_rm_hints;
int git_default_advice_config(const char *var, const char *value);
+__attribute__((format (printf, 1, 2)))
void advise(const char *advice, ...);
int error_resolve_conflict(const char *me);
extern void NORETURN die_resolve_conflict(const char *me);
diff --git a/archive-zip.c b/archive-zip.c
index a8d1193..4bde019 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -111,8 +111,9 @@ static void copy_le32(unsigned char *dest, unsigned int n)
dest[3] = 0xff & (n >> 030);
}
-static void *zlib_deflate(void *data, unsigned long size,
- int compression_level, unsigned long *compressed_size)
+static void *zlib_deflate_raw(void *data, unsigned long size,
+ int compression_level,
+ unsigned long *compressed_size)
{
git_zstream stream;
unsigned long maxsize;
@@ -120,7 +121,7 @@ static void *zlib_deflate(void *data, unsigned long size,
int result;
memset(&stream, 0, sizeof(stream));
- git_deflate_init(&stream, compression_level);
+ git_deflate_init_raw(&stream, compression_level);
maxsize = git_deflate_bound(&stream, size);
buffer = xmalloc(maxsize);
@@ -231,7 +232,6 @@ static int write_zip_entry(struct archiver_args *args,
size = 0;
compressed_size = 0;
buffer = NULL;
- size = 0;
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
enum object_type type = sha1_object_info(sha1, &size);
@@ -265,14 +265,11 @@ static int write_zip_entry(struct archiver_args *args,
}
if (buffer && method == 8) {
- deflated = zlib_deflate(buffer, size, args->compression_level,
- &compressed_size);
- if (deflated && compressed_size - 6 < size) {
- /* ZLIB --> raw compressed data (see RFC 1950) */
- /* CMF and FLG ... */
- out = (unsigned char *)deflated + 2;
- compressed_size -= 6; /* ... and ADLER32 */
- } else {
+ out = deflated = zlib_deflate_raw(buffer, size,
+ args->compression_level,
+ &compressed_size);
+ if (!out || compressed_size >= size) {
+ out = buffer;
method = 0;
compressed_size = size;
}
@@ -353,7 +350,7 @@ static int write_zip_entry(struct archiver_args *args,
unsigned char compressed[STREAM_BUFFER_SIZE * 2];
memset(&zstream, 0, sizeof(zstream));
- git_deflate_init(&zstream, args->compression_level);
+ git_deflate_init_raw(&zstream, args->compression_level);
compressed_size = 0;
zstream.next_out = compressed;
@@ -370,13 +367,10 @@ static int write_zip_entry(struct archiver_args *args,
result = git_deflate(&zstream, 0);
if (result != Z_OK)
die("deflate error (%d)", result);
- out = compressed;
- if (!compressed_size)
- out += 2;
- out_len = zstream.next_out - out;
+ out_len = zstream.next_out - compressed;
if (out_len > 0) {
- write_or_die(1, out, out_len);
+ write_or_die(1, compressed, out_len);
compressed_size += out_len;
zstream.next_out = compressed;
zstream.avail_out = sizeof(compressed);
@@ -394,11 +388,8 @@ static int write_zip_entry(struct archiver_args *args,
die("deflate error (%d)", result);
git_deflate_end(&zstream);
- out = compressed;
- if (!compressed_size)
- out += 2;
- out_len = zstream.next_out - out - 4;
- write_or_die(1, out, out_len);
+ out_len = zstream.next_out - compressed;
+ write_or_die(1, compressed, out_len);
compressed_size += out_len;
zip_offset += compressed_size;
diff --git a/archive.c b/archive.c
index d254fa5..99fadc8 100644
--- a/archive.c
+++ b/archive.c
@@ -151,7 +151,6 @@ int write_archive_entries(struct archiver_args *args,
struct archiver_context context;
struct unpack_trees_options opts;
struct tree_desc t;
- struct pathspec pathspec;
int err;
if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
@@ -186,10 +185,8 @@ int write_archive_entries(struct archiver_args *args,
git_attr_set_direction(GIT_ATTR_INDEX, &the_index);
}
- init_pathspec(&pathspec, args->pathspec);
- err = read_tree_recursive(args->tree, "", 0, 0, &pathspec,
+ err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
write_archive_entry, &context);
- free_pathspec(&pathspec);
if (err == READ_TREE_RECURSIVE)
err = 0;
return err;
@@ -222,7 +219,7 @@ static int path_exists(struct tree *tree, const char *path)
struct pathspec pathspec;
int ret;
- init_pathspec(&pathspec, paths);
+ parse_pathspec(&pathspec, 0, 0, "", paths);
ret = read_tree_recursive(tree, "", 0, 0, &pathspec, reject_entry, NULL);
free_pathspec(&pathspec);
return ret != 0;
@@ -231,11 +228,18 @@ static int path_exists(struct tree *tree, const char *path)
static void parse_pathspec_arg(const char **pathspec,
struct archiver_args *ar_args)
{
- ar_args->pathspec = pathspec = get_pathspec("", pathspec);
+ /*
+ * must be consistent with parse_pathspec in path_exists()
+ * Also if pathspec patterns are dependent, we're in big
+ * trouble as we test each one separately
+ */
+ parse_pathspec(&ar_args->pathspec, 0,
+ PATHSPEC_PREFER_FULL,
+ "", pathspec);
if (pathspec) {
while (*pathspec) {
if (**pathspec && !path_exists(ar_args->tree, *pathspec))
- die("path not found: %s", *pathspec);
+ die(_("pathspec '%s' did not match any files"), *pathspec);
pathspec++;
}
}
diff --git a/archive.h b/archive.h
index 895afcd..4a791e1 100644
--- a/archive.h
+++ b/archive.h
@@ -1,6 +1,8 @@
#ifndef ARCHIVE_H
#define ARCHIVE_H
+#include "pathspec.h"
+
struct archiver_args {
const char *base;
size_t baselen;
@@ -8,7 +10,7 @@ struct archiver_args {
const unsigned char *commit_sha1;
const struct commit *commit;
time_t time;
- const char **pathspec;
+ struct pathspec pathspec;
unsigned int verbose : 1;
unsigned int worktree_attributes : 1;
unsigned int convert : 1;
diff --git a/argv-array.h b/argv-array.h
index 40248d4..85ba438 100644
--- a/argv-array.h
+++ b/argv-array.h
@@ -15,6 +15,7 @@ void argv_array_init(struct argv_array *);
void argv_array_push(struct argv_array *, const char *);
__attribute__((format (printf,2,3)))
void argv_array_pushf(struct argv_array *, const char *fmt, ...);
+LAST_ARG_MUST_BE_NULL
void argv_array_pushl(struct argv_array *, ...);
void argv_array_pop(struct argv_array *);
void argv_array_clear(struct argv_array *);
diff --git a/attr.c b/attr.c
index 689bc2a..0e774c6 100644
--- a/attr.c
+++ b/attr.c
@@ -381,46 +381,13 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
return res;
}
-static void *read_index_data(const char *path)
-{
- int pos, len;
- unsigned long sz;
- enum object_type type;
- void *data;
- struct index_state *istate = use_index ? use_index : &the_index;
-
- len = strlen(path);
- pos = index_name_pos(istate, path, len);
- if (pos < 0) {
- /*
- * We might be in the middle of a merge, in which
- * case we would read stage #2 (ours).
- */
- int i;
- for (i = -pos - 1;
- (pos < 0 && i < istate->cache_nr &&
- !strcmp(istate->cache[i]->name, path));
- i++)
- if (ce_stage(istate->cache[i]) == 2)
- pos = i;
- }
- if (pos < 0)
- return NULL;
- data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
- if (!data || type != OBJ_BLOB) {
- free(data);
- return NULL;
- }
- return data;
-}
-
static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)
{
struct attr_stack *res;
char *buf, *sp;
int lineno = 0;
- buf = read_index_data(path);
+ buf = read_blob_data_from_index(use_index ? use_index : &the_index, path, NULL);
if (!buf)
return NULL;
diff --git a/bisect.c b/bisect.c
index 374d9e2..71c1958 100644
--- a/bisect.c
+++ b/bisect.c
@@ -15,7 +15,7 @@
static struct sha1_array good_revs;
static struct sha1_array skipped_revs;
-static const unsigned char *current_bad_sha1;
+static unsigned char *current_bad_sha1;
static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
@@ -404,7 +404,8 @@ static int register_ref(const char *refname, const unsigned char *sha1,
int flags, void *cb_data)
{
if (!strcmp(refname, "bad")) {
- current_bad_sha1 = sha1;
+ current_bad_sha1 = xmalloc(20);
+ hashcpy(current_bad_sha1, sha1);
} else if (!prefixcmp(refname, "good-")) {
sha1_array_append(&good_revs, sha1);
} else if (!prefixcmp(refname, "skip-")) {
diff --git a/branch.c b/branch.c
index 2bef1e7..c5c6984 100644
--- a/branch.c
+++ b/branch.c
@@ -57,7 +57,7 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
if (remote_is_branch
&& !strcmp(local, shortname)
&& !origin) {
- warning("Not setting branch %s as its own upstream.",
+ warning(_("Not setting branch %s as its own upstream."),
local);
return;
}
@@ -78,25 +78,25 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
if (flag & BRANCH_CONFIG_VERBOSE) {
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);
+ printf_ln(rebasing ?
+ _("Branch %s set up to track remote branch %s from %s by rebasing.") :
+ _("Branch %s set up to track remote branch %s from %s."),
+ 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);
+ printf_ln(rebasing ?
+ _("Branch %s set up to track local branch %s by rebasing.") :
+ _("Branch %s set up to track local branch %s."),
+ 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);
+ printf_ln(rebasing ?
+ _("Branch %s set up to track remote ref %s by rebasing.") :
+ _("Branch %s set up to track remote ref %s."),
+ 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);
+ printf_ln(rebasing ?
+ _("Branch %s set up to track local ref %s by rebasing.") :
+ _("Branch %s set up to track local ref %s."),
+ local, remote);
else
die("BUG: impossible combination of %d and %p",
remote_is_branch, origin);
@@ -115,7 +115,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
if (strlen(new_ref) > 1024 - 7 - 7 - 1)
- return error("Tracking not set up: name too long: %s",
+ return error(_("Tracking not set up: name too long: %s"),
new_ref);
memset(&tracking, 0, sizeof(tracking));
@@ -134,7 +134,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
}
if (tracking.matches > 1)
- return error("Not tracking: ambiguous information for ref %s",
+ return error(_("Not tracking: ambiguous information for ref %s"),
orig_ref);
install_branch_config(config_flags, new_ref, tracking.remote,
@@ -179,12 +179,12 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
int force, int attr_only)
{
if (strbuf_check_branch_ref(ref, name))
- die("'%s' is not a valid branch name.", name);
+ die(_("'%s' is not a valid branch name."), name);
if (!ref_exists(ref->buf))
return 0;
else if (!force && !attr_only)
- die("A branch named '%s' already exists.", ref->buf + strlen("refs/heads/"));
+ die(_("A branch named '%s' already exists."), ref->buf + strlen("refs/heads/"));
if (!attr_only) {
const char *head;
@@ -192,11 +192,40 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
head = resolve_ref_unsafe("HEAD", sha1, 0, NULL);
if (!is_bare_repository() && head && !strcmp(head, ref->buf))
- die("Cannot force update the current branch.");
+ die(_("Cannot force update the current branch."));
}
return 1;
}
+static int check_tracking_branch(struct remote *remote, void *cb_data)
+{
+ char *tracking_branch = cb_data;
+ struct refspec query;
+ memset(&query, 0, sizeof(struct refspec));
+ query.dst = tracking_branch;
+ return !(remote_find_tracking(remote, &query) ||
+ prefixcmp(query.src, "refs/heads/"));
+}
+
+static int validate_remote_tracking_branch(char *ref)
+{
+ return !for_each_remote(check_tracking_branch, ref);
+}
+
+static const char upstream_not_branch[] =
+N_("Cannot setup tracking information; starting point '%s' is not a branch.");
+static const char upstream_missing[] =
+N_("the requested upstream branch '%s' does not exist");
+static const char upstream_advice[] =
+N_("\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push.");
+
void create_branch(const char *head,
const char *name, const char *start_name,
int force, int reflog, int clobber_head,
@@ -224,38 +253,47 @@ void create_branch(const char *head,
}
real_ref = NULL;
- if (get_sha1(start_name, sha1))
- die("Not a valid object name: '%s'.", start_name);
+ if (get_sha1(start_name, sha1)) {
+ if (explicit_tracking) {
+ if (advice_set_upstream_failure) {
+ error(_(upstream_missing), start_name);
+ advise(_(upstream_advice));
+ exit(1);
+ }
+ die(_(upstream_missing), start_name);
+ }
+ die(_("Not a valid object name: '%s'."), start_name);
+ }
switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
case 0:
/* Not branching from any existing branch */
if (explicit_tracking)
- die("Cannot setup tracking information; starting point is not a branch.");
+ die(_(upstream_not_branch), start_name);
break;
case 1:
/* Unique completion -- good, only if it is a real branch */
if (prefixcmp(real_ref, "refs/heads/") &&
- prefixcmp(real_ref, "refs/remotes/")) {
+ validate_remote_tracking_branch(real_ref)) {
if (explicit_tracking)
- die("Cannot setup tracking information; starting point is not a branch.");
+ die(_(upstream_not_branch), start_name);
else
real_ref = NULL;
}
break;
default:
- die("Ambiguous object name: '%s'.", start_name);
+ die(_("Ambiguous object name: '%s'."), start_name);
break;
}
if ((commit = lookup_commit_reference(sha1)) == NULL)
- die("Not a valid branch point: '%s'.", start_name);
+ die(_("Not a valid branch point: '%s'."), start_name);
hashcpy(sha1, commit->object.sha1);
if (!dont_change_ref) {
lock = lock_any_ref_for_update(ref.buf, NULL, 0);
if (!lock)
- die_errno("Failed to lock ref for update");
+ die_errno(_("Failed to lock ref for update"));
}
if (reflog)
@@ -273,7 +311,7 @@ void create_branch(const char *head,
if (!dont_change_ref)
if (write_ref_sha1(lock, sha1, msg) < 0)
- die_errno("Failed to write ref");
+ die_errno(_("Failed to write ref"));
strbuf_release(&ref);
free(real_ref);
diff --git a/builtin.h b/builtin.h
index faef559..8afa2de 100644
--- a/builtin.h
+++ b/builtin.h
@@ -5,13 +5,15 @@
#include "strbuf.h"
#include "cache.h"
#include "commit.h"
-#include "notes.h"
#define DEFAULT_MERGE_LOG_LEN 20
extern const char git_usage_string[];
extern const char git_more_info_string[];
+#define PRUNE_PACKED_DRY_RUN 01
+#define PRUNE_PACKED_VERBOSE 02
+
extern void prune_packed_objects(int);
struct fmt_merge_msg_opts {
@@ -23,21 +25,6 @@ struct fmt_merge_msg_opts {
extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
struct fmt_merge_msg_opts *);
-struct notes_rewrite_cfg {
- struct notes_tree **trees;
- const char *cmd;
- int enabled;
- combine_notes_fn combine;
- struct string_list *refs;
- int refs_from_env;
- int mode_from_env;
-};
-
-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);
-void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);
-
extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);
extern int cmd_add(int argc, const char **argv, const char *prefix);
@@ -53,6 +40,7 @@ extern int cmd_checkout(int argc, const char **argv, const char *prefix);
extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
extern int cmd_check_ignore(int argc, const char **argv, const char *prefix);
+extern int cmd_check_mailmap(int argc, const char **argv, const char *prefix);
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
extern int cmd_cherry(int argc, const char **argv, const char *prefix);
extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index ab1c9e8..31ddabd 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -26,8 +26,55 @@ static int take_worktree_changes;
struct update_callback_data {
int flags;
int add_errors;
+ const char *implicit_dot;
+ size_t implicit_dot_len;
+
+ /* only needed for 2.0 transition preparation */
+ int warn_add_would_remove;
};
+static const char *option_with_implicit_dot;
+static const char *short_option_with_implicit_dot;
+
+static void warn_pathless_add(void)
+{
+ static int shown;
+ assert(option_with_implicit_dot && short_option_with_implicit_dot);
+
+ if (shown)
+ return;
+ shown = 1;
+
+ /*
+ * To be consistent with "git add -p" and most Git
+ * commands, we should default to being tree-wide, but
+ * this is not the original behavior and can't be
+ * changed until users trained themselves not to type
+ * "git add -u" or "git add -A". For now, we warn and
+ * keep the old behavior. Later, the behavior can be changed
+ * to tree-wide, keeping the warning for a while, and
+ * eventually we can drop the warning.
+ */
+ warning(_("The behavior of 'git add %s (or %s)' with no path argument from a\n"
+ "subdirectory of the tree will change in Git 2.0 and should not be used anymore.\n"
+ "To add content for the whole tree, run:\n"
+ "\n"
+ " git add %s :/\n"
+ " (or git add %s :/)\n"
+ "\n"
+ "To restrict the command to the current directory, run:\n"
+ "\n"
+ " git add %s .\n"
+ " (or git add %s .)\n"
+ "\n"
+ "With the current Git version, the command is restricted to "
+ "the current directory.\n"
+ ""),
+ option_with_implicit_dot, short_option_with_implicit_dot,
+ option_with_implicit_dot, short_option_with_implicit_dot,
+ option_with_implicit_dot, short_option_with_implicit_dot);
+}
+
static int fix_unmerged_status(struct diff_filepair *p,
struct update_callback_data *data)
{
@@ -49,15 +96,49 @@ static int fix_unmerged_status(struct diff_filepair *p,
return DIFF_STATUS_MODIFIED;
}
+static const char *add_would_remove_warning = N_(
+ "You ran 'git add' with neither '-A (--all)' or '--ignore-removal',\n"
+"whose behaviour will change in Git 2.0 with respect to paths you removed.\n"
+"Paths like '%s' that are\n"
+"removed from your working tree are ignored with this version of Git.\n"
+"\n"
+"* 'git add --ignore-removal <pathspec>', which is the current default,\n"
+" ignores paths you removed from your working tree.\n"
+"\n"
+"* 'git add --all <pathspec>' will let you also record the removals.\n"
+"\n"
+"Run 'git status' to check the paths you removed from your working tree.\n");
+
+static void warn_add_would_remove(const char *path)
+{
+ warning(_(add_would_remove_warning), path);
+}
+
static void update_callback(struct diff_queue_struct *q,
struct diff_options *opt, void *cbdata)
{
int i;
struct update_callback_data *data = cbdata;
+ const char *implicit_dot = data->implicit_dot;
+ size_t implicit_dot_len = data->implicit_dot_len;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
const char *path = p->one->path;
+ /*
+ * Check if "git add -A" or "git add -u" was run from a
+ * subdirectory with a modified file outside that directory,
+ * and warn if so.
+ *
+ * "git add -u" will behave like "git add -u :/" instead of
+ * "git add -u ." in the future. This warning prepares for
+ * that change.
+ */
+ if (implicit_dot &&
+ strncmp_icase(path, implicit_dot, implicit_dot_len)) {
+ warn_pathless_add();
+ continue;
+ }
switch (fix_unmerged_status(p, data)) {
default:
die(_("unexpected diff status %c"), p->status);
@@ -70,6 +151,10 @@ static void update_callback(struct diff_queue_struct *q,
}
break;
case DIFF_STATUS_DELETED:
+ if (data->warn_add_would_remove) {
+ warn_add_would_remove(path);
+ data->warn_add_would_remove = 0;
+ }
if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
break;
if (!(data->flags & ADD_CACHE_PRETEND))
@@ -81,108 +166,90 @@ static void update_callback(struct diff_queue_struct *q,
}
}
-int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
+static void update_files_in_cache(const char *prefix,
+ const struct pathspec *pathspec,
+ struct update_callback_data *data)
{
- struct update_callback_data data;
struct rev_info rev;
+
init_revisions(&rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
- init_pathspec(&rev.prune_data, pathspec);
+ if (pathspec)
+ copy_pathspec(&rev.prune_data, pathspec);
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = update_callback;
- data.flags = flags;
- data.add_errors = 0;
- rev.diffopt.format_callback_data = &data;
+ rev.diffopt.format_callback_data = data;
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
+}
+
+int add_files_to_cache(const char *prefix,
+ const struct pathspec *pathspec, int flags)
+{
+ struct update_callback_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.flags = flags;
+ update_files_in_cache(prefix, pathspec, &data);
return !!data.add_errors;
}
-static char *prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
+#define WARN_IMPLICIT_DOT (1u << 0)
+static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,
+ int prefix, unsigned flag)
{
char *seen;
- int i, specs;
+ int i;
struct dir_entry **src, **dst;
- for (specs = 0; pathspec[specs]; specs++)
- /* nothing */;
- seen = xcalloc(specs, 1);
+ seen = xcalloc(pathspec->nr, 1);
src = dst = dir->entries;
i = dir->nr;
while (--i >= 0) {
struct dir_entry *entry = *src++;
- if (match_pathspec(pathspec, entry->name, entry->len,
- prefix, seen))
+ if (match_pathspec_depth(pathspec, entry->name, entry->len,
+ prefix, seen))
*dst++ = entry;
+ else if (flag & WARN_IMPLICIT_DOT)
+ /*
+ * "git add -A" was run from a subdirectory with a
+ * new file outside that directory.
+ *
+ * "git add -A" will behave like "git add -A :/"
+ * instead of "git add -A ." in the future.
+ * Warn about the coming behavior change.
+ */
+ warn_pathless_add();
}
dir->nr = dst - dir->entries;
- add_pathspec_matches_against_index(pathspec, seen, specs);
+ add_pathspec_matches_against_index(pathspec, seen);
return seen;
}
-/*
- * Checks the index to see whether any path in pathspec refers to
- * something inside a submodule. If so, dies with an error message.
- */
-static void treat_gitlinks(const char **pathspec)
-{
- int i;
-
- if (!pathspec || !*pathspec)
- return;
-
- for (i = 0; pathspec[i]; i++)
- pathspec[i] = check_path_for_gitlink(pathspec[i]);
-}
-
-static void refresh(int verbose, const char **pathspec)
+static void refresh(int verbose, const struct pathspec *pathspec)
{
char *seen;
- int i, specs;
+ int i;
- for (specs = 0; pathspec[specs]; specs++)
- /* nothing */;
- seen = xcalloc(specs, 1);
+ seen = xcalloc(pathspec->nr, 1);
refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
pathspec, seen, _("Unstaged changes after refreshing the index:"));
- for (i = 0; i < specs; i++) {
+ for (i = 0; i < pathspec->nr; i++) {
if (!seen[i])
- die(_("pathspec '%s' did not match any files"), pathspec[i]);
+ die(_("pathspec '%s' did not match any files"),
+ pathspec->items[i].match);
}
free(seen);
}
-/*
- * Normalizes argv relative to prefix, via get_pathspec(), and then
- * runs die_if_path_beyond_symlink() on each path in the normalized
- * list.
- */
-static const char **validate_pathspec(const char **argv, const char *prefix)
-{
- const char **pathspec = get_pathspec(prefix, argv);
-
- if (pathspec) {
- const char **p;
- for (p = pathspec; *p; p++) {
- die_if_path_beyond_symlink(*p, prefix);
- }
- }
-
- return pathspec;
-}
-
int run_add_interactive(const char *revision, const char *patch_mode,
- const char **pathspec)
+ const struct pathspec *pathspec)
{
- int status, ac, pc = 0;
+ int status, ac, i;
const char **args;
- if (pathspec)
- while (pathspec[pc])
- pc++;
-
- args = xcalloc(sizeof(const char *), (pc + 5));
+ args = xcalloc(sizeof(const char *), (pathspec->nr + 6));
ac = 0;
args[ac++] = "add--interactive";
if (patch_mode)
@@ -190,11 +257,9 @@ int run_add_interactive(const char *revision, const char *patch_mode,
if (revision)
args[ac++] = revision;
args[ac++] = "--";
- if (pc) {
- memcpy(&(args[ac]), pathspec, sizeof(const char *) * pc);
- ac += pc;
- }
- args[ac] = NULL;
+ for (i = 0; i < pathspec->nr; i++)
+ /* pass original pathspec, to be re-parsed */
+ args[ac++] = pathspec->items[i].original;
status = run_command_v_opt(args, RUN_GIT_CMD);
free(args);
@@ -203,17 +268,17 @@ int run_add_interactive(const char *revision, const char *patch_mode,
int interactive_add(int argc, const char **argv, const char *prefix, int patch)
{
- const char **pathspec = NULL;
+ struct pathspec pathspec;
- if (argc) {
- pathspec = validate_pathspec(argv, prefix);
- if (!pathspec)
- return -1;
- }
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_FULL |
+ PATHSPEC_SYMLINK_LEADING_PATH |
+ PATHSPEC_PREFIX_ORIGIN,
+ prefix, argv);
return run_add_interactive(NULL,
patch ? "--patch" : NULL,
- pathspec);
+ &pathspec);
}
static int edit_patch(int argc, const char **argv, const char *prefix)
@@ -238,6 +303,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
argc = setup_revisions(argc, argv, &rev, NULL);
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+ rev.diffopt.use_color = 0;
DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
out = open(file, O_CREAT | O_WRONLY, 0666);
if (out < 0)
@@ -270,23 +336,38 @@ static struct lock_file lock_file;
static const char ignore_error[] =
N_("The following paths are ignored by one of your .gitignore files:\n");
-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 int verbose, show_only, ignored_too, refresh_only;
+static int ignore_add_errors, intent_to_add, ignore_missing;
+
+#define ADDREMOVE_DEFAULT 0 /* Change to 1 in Git 2.0 */
+static int addremove = ADDREMOVE_DEFAULT;
+static int addremove_explicit = -1; /* unspecified */
+
+static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
+{
+ /* if we are told to ignore, we are not adding removals */
+ *(int *)opt->value = !unset ? 0 : 1;
+ return 0;
+}
static struct option builtin_add_options[] = {
OPT__DRY_RUN(&show_only, N_("dry run")),
OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_GROUP(""),
- 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_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
+ OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
+ OPT_BOOL('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_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
+ OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
+ OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
+ { OPTION_CALLBACK, 0, "ignore-removal", &addremove_explicit,
+ NULL /* takes no arguments */,
+ N_("ignore paths removed in the working tree (same as --no-all)"),
+ PARSE_OPT_NOARG, ignore_removal_cb },
+ OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
+ OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
+ OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
OPT_END(),
};
@@ -321,47 +402,18 @@ static int add_files(struct dir_struct *dir, int flags)
return exit_status;
}
-static void warn_pathless_add(const char *option_name, const char *short_name) {
- /*
- * To be consistent with "git add -p" and most Git
- * commands, we should default to being tree-wide, but
- * this is not the original behavior and can't be
- * changed until users trained themselves not to type
- * "git add -u" or "git add -A". For now, we warn and
- * keep the old behavior. Later, the behavior can be changed
- * to tree-wide, keeping the warning for a while, and
- * eventually we can drop the warning.
- */
- warning(_("The behavior of 'git add %s (or %s)' with no path argument from a\n"
- "subdirectory of the tree will change in Git 2.0 and should not be used anymore.\n"
- "To add content for the whole tree, run:\n"
- "\n"
- " git add %s :/\n"
- " (or git add %s :/)\n"
- "\n"
- "To restrict the command to the current directory, run:\n"
- "\n"
- " git add %s .\n"
- " (or git add %s .)\n"
- "\n"
- "With the current Git version, the command is restricted to the current directory."),
- option_name, short_name,
- option_name, short_name,
- option_name, short_name);
-}
-
int cmd_add(int argc, const char **argv, const char *prefix)
{
int exit_status = 0;
int newfd;
- const char **pathspec;
+ struct pathspec pathspec;
struct dir_struct dir;
int flags;
int add_new_files;
int require_pathspec;
char *seen = NULL;
- const char *option_with_implicit_dot = NULL;
- const char *short_option_with_implicit_dot = NULL;
+ int implicit_dot = 0;
+ struct update_callback_data update_data;
git_config(add_config, NULL);
@@ -377,8 +429,29 @@ int cmd_add(int argc, const char **argv, const char *prefix)
argc--;
argv++;
+ if (0 <= addremove_explicit)
+ addremove = addremove_explicit;
+ else if (take_worktree_changes && ADDREMOVE_DEFAULT)
+ addremove = 0; /* "-u" was given but not "-A" */
+
if (addremove && take_worktree_changes)
die(_("-A and -u are mutually incompatible"));
+
+ /*
+ * Warn when "git add pathspec..." was given without "-u" or "-A"
+ * and pathspec... covers a removed path.
+ */
+ memset(&update_data, 0, sizeof(update_data));
+ if (!take_worktree_changes && addremove_explicit < 0)
+ update_data.warn_add_would_remove = 1;
+
+ if (!take_worktree_changes && addremove_explicit < 0 && argc)
+ /*
+ * Turn "git add pathspec..." to "git add -A pathspec..."
+ * in Git 2.0 but not yet
+ */
+ ; /* addremove = 1; */
+
if (!show_only && ignore_missing)
die(_("Option --ignore-missing can only be used together with --dry-run"));
if (addremove) {
@@ -391,11 +464,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
}
if (option_with_implicit_dot && !argc) {
static const char *here[2] = { ".", NULL };
- if (prefix)
- warn_pathless_add(option_with_implicit_dot,
- short_option_with_implicit_dot);
argc = 1;
argv = here;
+ implicit_dot = 1;
}
add_new_files = !take_worktree_changes && !refresh_only;
@@ -408,21 +479,31 @@ int cmd_add(int argc, const char **argv, const char *prefix)
(intent_to_add ? ADD_CACHE_INTENT : 0) |
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
(!(addremove || take_worktree_changes)
- ? ADD_CACHE_IGNORE_REMOVAL : 0));
+ ? ADD_CACHE_IGNORE_REMOVAL : 0)) |
+ (implicit_dot ? ADD_CACHE_IMPLICIT_DOT : 0);
if (require_pathspec && argc == 0) {
fprintf(stderr, _("Nothing specified, nothing added.\n"));
fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
return 0;
}
- pathspec = validate_pathspec(argv, prefix);
if (read_cache() < 0)
die(_("index file corrupt"));
- treat_gitlinks(pathspec);
+
+ /*
+ * Check the "pathspec '%s' did not match any files" block
+ * below before enabling new magic.
+ */
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_FULL |
+ PATHSPEC_SYMLINK_LEADING_PATH |
+ PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE,
+ prefix, argv);
if (add_new_files) {
int baselen;
+ struct pathspec empty_pathspec;
/* Set up the default git porcelain excludes */
memset(&dir, 0, sizeof(dir));
@@ -431,44 +512,71 @@ int cmd_add(int argc, const char **argv, const char *prefix)
setup_standard_excludes(&dir);
}
+ memset(&empty_pathspec, 0, sizeof(empty_pathspec));
/* This picks up the paths that are not tracked */
- baselen = fill_directory(&dir, pathspec);
- if (pathspec)
- seen = prune_directory(&dir, pathspec, baselen);
+ baselen = fill_directory(&dir, implicit_dot ? &empty_pathspec : &pathspec);
+ if (pathspec.nr)
+ seen = prune_directory(&dir, &pathspec, baselen,
+ implicit_dot ? WARN_IMPLICIT_DOT : 0);
}
if (refresh_only) {
- refresh(verbose, pathspec);
+ refresh(verbose, &pathspec);
goto finish;
}
+ if (implicit_dot && prefix)
+ refresh_cache(REFRESH_QUIET);
- if (pathspec) {
+ if (pathspec.nr) {
int i;
- struct path_exclude_check check;
- path_exclude_check_init(&check, &dir);
if (!seen)
- seen = find_pathspecs_matching_against_index(pathspec);
- for (i = 0; pathspec[i]; i++) {
- if (!seen[i] && pathspec[i][0]
- && !file_exists(pathspec[i])) {
+ seen = find_pathspecs_matching_against_index(&pathspec);
+
+ /*
+ * file_exists() assumes exact match
+ */
+ GUARD_PATHSPEC(&pathspec,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
+ for (i = 0; i < pathspec.nr; i++) {
+ const char *path = pathspec.items[i].match;
+ if (!seen[i] &&
+ ((pathspec.items[i].magic &
+ (PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
+ !file_exists(path))) {
if (ignore_missing) {
int dtype = DT_UNKNOWN;
- if (is_path_excluded(&check, pathspec[i], -1, &dtype))
- dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
+ if (is_excluded(&dir, path, &dtype))
+ dir_add_ignored(&dir, path, pathspec.items[i].len);
} else
die(_("pathspec '%s' did not match any files"),
- pathspec[i]);
+ pathspec.items[i].original);
}
}
free(seen);
- path_exclude_check_clear(&check);
}
plug_bulk_checkin();
- exit_status |= add_files_to_cache(prefix, pathspec, flags);
+ if ((flags & ADD_CACHE_IMPLICIT_DOT) && prefix) {
+ /*
+ * Check for modified files throughout the worktree so
+ * update_callback has a chance to warn about changes
+ * outside the cwd.
+ */
+ update_data.implicit_dot = prefix;
+ update_data.implicit_dot_len = strlen(prefix);
+ free_pathspec(&pathspec);
+ memset(&pathspec, 0, sizeof(pathspec));
+ }
+ update_data.flags = flags & ~ADD_CACHE_IMPLICIT_DOT;
+ update_files_in_cache(prefix, &pathspec, &update_data);
+ exit_status |= !!update_data.add_errors;
if (add_new_files)
exit_status |= add_files(&dir, flags);
diff --git a/builtin/apply.c b/builtin/apply.c
index 30eefc3..ef32e4f 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -473,7 +473,7 @@ static char *find_name_gnu(const char *line, const char *def, int p_value)
/*
* Proposed "new-style" GNU patch/diff format; see
- * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
+ * http://marc.info/?l=git&m=112927316408690&w=2
*/
if (unquote_c_style(&name, line, NULL)) {
strbuf_release(&name);
@@ -722,7 +722,7 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
static char *find_name_traditional(const char *line, char *def, int p_value)
{
- size_t len = strlen(line);
+ size_t len;
size_t date_len;
if (*line == '"') {
@@ -906,7 +906,7 @@ static void parse_traditional_patch(const char *first, const char *second, struc
patch->old_name = name;
} else {
patch->old_name = name;
- patch->new_name = xstrdup(name);
+ patch->new_name = null_strdup(name);
}
}
if (!name)
@@ -2999,7 +2999,7 @@ static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsig
return 0;
}
-static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+static int read_file_or_gitlink(const struct cache_entry *ce, struct strbuf *buf)
{
if (!ce)
return 0;
@@ -3117,7 +3117,7 @@ static struct patch *previous_patch(struct patch *patch, int *gone)
return previous;
}
-static int verify_index_match(struct cache_entry *ce, struct stat *st)
+static int verify_index_match(const struct cache_entry *ce, struct stat *st)
{
if (S_ISGITLINK(ce->ce_mode)) {
if (!S_ISDIR(st->st_mode))
@@ -3130,7 +3130,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
#define SUBMODULE_PATCH_WITHOUT_INDEX 1
static int load_patch_target(struct strbuf *buf,
- struct cache_entry *ce,
+ const struct cache_entry *ce,
struct stat *st,
const char *name,
unsigned expected_mode)
@@ -3160,7 +3160,8 @@ static int load_patch_target(struct strbuf *buf,
* 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 patch *patch, struct stat *st,
+ const struct cache_entry *ce)
{
struct strbuf buf = STRBUF_INIT;
size_t len;
@@ -3273,7 +3274,7 @@ static int load_current(struct image *image, struct patch *patch)
}
static int try_threeway(struct image *image, struct patch *patch,
- struct stat *st, struct cache_entry *ce)
+ struct stat *st, const struct cache_entry *ce)
{
unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
struct strbuf buf = STRBUF_INIT;
@@ -3343,7 +3344,7 @@ static int try_threeway(struct image *image, struct patch *patch,
return 0;
}
-static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
+static int apply_data(struct patch *patch, struct stat *st, const struct cache_entry *ce)
{
struct image image;
@@ -3525,7 +3526,7 @@ static int check_patch(struct patch *patch)
ok_if_exists = 0;
if (new_name &&
- ((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {
+ ((0 < patch->is_new) || patch->is_rename || patch->is_copy)) {
int err = check_to_create(new_name, ok_if_exists);
if (err && threeway) {
@@ -3847,7 +3848,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
const char *s = buf;
if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1))
- die(_("corrupt patch for subproject %s"), path);
+ die(_("corrupt patch for submodule %s"), path);
} else {
if (!cached) {
if (lstat(path, &st) < 0)
@@ -4362,23 +4363,23 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
{ OPTION_CALLBACK, 'p', NULL, NULL, N_("num"),
N_("remove <num> leading slashes from traditional diff paths"),
0, option_parse_p },
- OPT_BOOLEAN(0, "no-add", &no_add,
+ OPT_BOOL(0, "no-add", &no_add,
N_("ignore additions made by the patch")),
- OPT_BOOLEAN(0, "stat", &diffstat,
+ OPT_BOOL(0, "stat", &diffstat,
N_("instead of applying the patch, output diffstat for the input")),
OPT_NOOP_NOARG(0, "allow-binary-replacement"),
OPT_NOOP_NOARG(0, "binary"),
- OPT_BOOLEAN(0, "numstat", &numstat,
+ OPT_BOOL(0, "numstat", &numstat,
N_("show number of added and deleted lines in decimal notation")),
- OPT_BOOLEAN(0, "summary", &summary,
+ OPT_BOOL(0, "summary", &summary,
N_("instead of applying the patch, output a summary for the input")),
- OPT_BOOLEAN(0, "check", &check,
+ OPT_BOOL(0, "check", &check,
N_("instead of applying the patch, see if the patch is applicable")),
- OPT_BOOLEAN(0, "index", &check_index,
+ OPT_BOOL(0, "index", &check_index,
N_("make sure the patch is applicable to the current index")),
- OPT_BOOLEAN(0, "cached", &cached,
+ OPT_BOOL(0, "cached", &cached,
N_("apply a patch without touching the working tree")),
- OPT_BOOLEAN(0, "apply", &force_apply,
+ OPT_BOOL(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")),
@@ -4398,13 +4399,13 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
{ OPTION_CALLBACK, 0, "ignore-whitespace", NULL, NULL,
N_("ignore changes in whitespace when finding context"),
PARSE_OPT_NOARG, option_parse_space_change },
- OPT_BOOLEAN('R', "reverse", &apply_in_reverse,
+ OPT_BOOL('R', "reverse", &apply_in_reverse,
N_("apply the patch in reverse")),
- OPT_BOOLEAN(0, "unidiff-zero", &unidiff_zero,
+ OPT_BOOL(0, "unidiff-zero", &unidiff_zero,
N_("don't expect at least one line of context")),
- OPT_BOOLEAN(0, "reject", &apply_with_reject,
+ OPT_BOOL(0, "reject", &apply_with_reject,
N_("leave the rejected hunks in corresponding *.rej files")),
- OPT_BOOLEAN(0, "allow-overlap", &allow_overlap,
+ OPT_BOOL(0, "allow-overlap", &allow_overlap,
N_("allow overlapping hunks")),
OPT__VERBOSE(&apply_verbosely, N_("be verbose")),
OPT_BIT(0, "inaccurate-eof", &options,
diff --git a/builtin/archive.c b/builtin/archive.c
index 9a1cfd3..49178f1 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -27,8 +27,8 @@ static int run_remote_archiver(int argc, const char **argv,
const char *remote, const char *exec,
const char *name_hint)
{
- char buf[LARGE_PACKET_MAX];
- int fd[2], i, len, rv;
+ char *buf;
+ int fd[2], i, rv;
struct transport *transport;
struct remote *_remote;
@@ -53,21 +53,18 @@ static int run_remote_archiver(int argc, const char **argv,
packet_write(fd[1], "argument %s\n", argv[i]);
packet_flush(fd[1]);
- len = packet_read_line(fd[0], buf, sizeof(buf));
- if (!len)
+ buf = packet_read_line(fd[0], NULL);
+ if (!buf)
die(_("git archive: expected ACK/NAK, got EOF"));
- if (buf[len-1] == '\n')
- buf[--len] = 0;
if (strcmp(buf, "ACK")) {
- if (len > 5 && !prefixcmp(buf, "NACK "))
+ if (!prefixcmp(buf, "NACK "))
die(_("git archive: NACK %s"), buf + 5);
- if (len > 4 && !prefixcmp(buf, "ERR "))
+ if (!prefixcmp(buf, "ERR "))
die(_("remote error: %s"), buf + 4);
die(_("git archive: protocol error"));
}
- len = packet_read_line(fd[0], buf, sizeof(buf));
- if (len)
+ if (packet_read_line(fd[0], NULL))
die(_("git archive: expected a flush"));
/* Now, start reading from fd[0] and spit it out to stdout */
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index e3884e3..3324229 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -13,10 +13,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
int next_all = 0;
int no_checkout = 0;
struct option options[] = {
- OPT_BOOLEAN(0, "next-all", &next_all,
- N_("perform 'git bisect next'")),
- OPT_BOOLEAN(0, "no-checkout", &no_checkout,
- N_("update BISECT_HEAD instead of checking out the current commit")),
+ OPT_BOOL(0, "next-all", &next_all,
+ N_("perform 'git bisect next'")),
+ OPT_BOOL(0, "no-checkout", &no_checkout,
+ N_("update BISECT_HEAD instead of checking out the current commit")),
OPT_END()
};
diff --git a/builtin/blame.c b/builtin/blame.c
index 7770781..6da7233 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -21,6 +21,8 @@
#include "parse-options.h"
#include "utf8.h"
#include "userdiff.h"
+#include "line-range.h"
+#include "line-log.h"
static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file");
@@ -407,7 +409,7 @@ static struct origin *find_origin(struct scoreboard *sb,
paths[0] = origin->path;
paths[1] = NULL;
- diff_tree_setup_paths(paths, &diff_opts);
+ parse_pathspec(&diff_opts.pathspec, PATHSPEC_ALL_MAGIC, 0, "", paths);
diff_setup_done(&diff_opts);
if (is_null_sha1(origin->commit->object.sha1))
@@ -457,7 +459,7 @@ static struct origin *find_origin(struct scoreboard *sb,
}
}
diff_flush(&diff_opts);
- diff_tree_release_paths(&diff_opts);
+ free_pathspec(&diff_opts.pathspec);
if (porigin) {
/*
* Create a freestanding copy that is not part of
@@ -485,15 +487,12 @@ static struct origin *find_rename(struct scoreboard *sb,
struct origin *porigin = NULL;
struct diff_options diff_opts;
int i;
- const char *paths[2];
diff_setup(&diff_opts);
DIFF_OPT_SET(&diff_opts, RECURSIVE);
diff_opts.detect_rename = DIFF_DETECT_RENAME;
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_opts.single_follow = origin->path;
- paths[0] = NULL;
- diff_tree_setup_paths(paths, &diff_opts);
diff_setup_done(&diff_opts);
if (is_null_sha1(origin->commit->object.sha1))
@@ -515,7 +514,7 @@ static struct origin *find_rename(struct scoreboard *sb,
}
}
diff_flush(&diff_opts);
- diff_tree_release_paths(&diff_opts);
+ free_pathspec(&diff_opts.pathspec);
return porigin;
}
@@ -566,11 +565,16 @@ static void dup_entry(struct blame_entry *dst, struct blame_entry *src)
dst->score = 0;
}
-static const char *nth_line(struct scoreboard *sb, int lno)
+static const char *nth_line(struct scoreboard *sb, long lno)
{
return sb->final_buf + sb->lineno[lno];
}
+static const char *nth_line_cb(void *data, long lno)
+{
+ return nth_line((struct scoreboard *)data, lno);
+}
+
/*
* It is known that lines between tlno to same came from parent, and e
* has an overlap with that range. it also is known that parent's
@@ -1058,7 +1062,6 @@ static int find_copy_in_parent(struct scoreboard *sb,
int opt)
{
struct diff_options diff_opts;
- const char *paths[1];
int i, j;
int retval;
struct blame_list *blame_list;
@@ -1072,8 +1075,6 @@ static int find_copy_in_parent(struct scoreboard *sb,
DIFF_OPT_SET(&diff_opts, RECURSIVE);
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
- paths[0] = NULL;
- diff_tree_setup_paths(paths, &diff_opts);
diff_setup_done(&diff_opts);
/* Try "find copies harder" on new path if requested;
@@ -1156,7 +1157,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
}
reset_scanned_flag(sb);
diff_flush(&diff_opts);
- diff_tree_release_paths(&diff_opts);
+ free_pathspec(&diff_opts.pathspec);
return retval;
}
@@ -1430,7 +1431,7 @@ static void get_commit_info(struct commit *commit,
commit_info_init(ret);
encoding = get_log_output_encoding();
- message = logmsg_reencode(commit, encoding);
+ message = logmsg_reencode(commit, NULL, encoding);
get_ac_line(message, "\nauthor ",
&ret->author, &ret->author_mail,
&ret->author_time, &ret->author_tz);
@@ -1931,103 +1932,6 @@ static const char *add_prefix(const char *prefix, const char *path)
return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
}
-/*
- * Parsing of (comma separated) one item in the -L option
- */
-static const char *parse_loc(const char *spec,
- struct scoreboard *sb, long lno,
- long begin, long *ret)
-{
- char *term;
- const char *line;
- long num;
- int reg_error;
- regex_t regexp;
- regmatch_t match[1];
-
- /* Allow "-L <something>,+20" to mean starting at <something>
- * for 20 lines, or "-L <something>,-5" for 5 lines ending at
- * <something>.
- */
- if (1 < begin && (spec[0] == '+' || spec[0] == '-')) {
- num = strtol(spec + 1, &term, 10);
- if (term != spec + 1) {
- if (spec[0] == '-')
- num = 0 - num;
- if (0 < num)
- *ret = begin + num - 2;
- else if (!num)
- *ret = begin;
- else
- *ret = begin + num;
- return term;
- }
- return spec;
- }
- num = strtol(spec, &term, 10);
- if (term != spec) {
- *ret = num;
- return term;
- }
- if (spec[0] != '/')
- return spec;
-
- /* it could be a regexp of form /.../ */
- for (term = (char *) spec + 1; *term && *term != '/'; term++) {
- if (*term == '\\')
- term++;
- }
- if (*term != '/')
- return spec;
-
- /* try [spec+1 .. term-1] as regexp */
- *term = 0;
- begin--; /* input is in human terms */
- line = nth_line(sb, begin);
-
- if (!(reg_error = regcomp(&regexp, spec + 1, REG_NEWLINE)) &&
- !(reg_error = regexec(&regexp, line, 1, match, 0))) {
- const char *cp = line + match[0].rm_so;
- const char *nline;
-
- while (begin++ < lno) {
- nline = nth_line(sb, begin);
- if (line <= cp && cp < nline)
- break;
- line = nline;
- }
- *ret = begin;
- regfree(&regexp);
- *term++ = '/';
- return term;
- }
- else {
- char errbuf[1024];
- regerror(reg_error, &regexp, errbuf, 1024);
- die("-L parameter '%s': %s", spec + 1, errbuf);
- }
-}
-
-/*
- * Parsing of -L option
- */
-static void prepare_blame_range(struct scoreboard *sb,
- const char *bottomtop,
- long lno,
- long *bottom, long *top)
-{
- const char *term;
-
- term = parse_loc(bottomtop, sb, lno, 1, bottom);
- if (*term == ',') {
- term = parse_loc(term + 1, sb, lno, *bottom + 1, top);
- if (*term)
- usage(blame_usage);
- }
- if (*term)
- usage(blame_usage);
-}
-
static int git_blame_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "blame.showroot")) {
@@ -2324,38 +2228,27 @@ static int blame_move_callback(const struct option *option, const char *arg, int
return 0;
}
-static int blame_bottomtop_callback(const struct option *option, const char *arg, int unset)
-{
- const char **bottomtop = option->value;
- if (!arg)
- return -1;
- if (*bottomtop)
- die("More than one '-L n,m' option given");
- *bottomtop = arg;
- return 0;
-}
-
int cmd_blame(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
const char *path;
struct scoreboard sb;
struct origin *o;
- struct blame_entry *ent;
- long dashdash_pos, bottom, top, lno;
+ struct blame_entry *ent = NULL;
+ long dashdash_pos, lno;
const char *final_commit_name = NULL;
enum object_type type;
- static const char *bottomtop = NULL;
+ static struct string_list range_list;
static int output_option = 0, opt = 0;
static int show_stats = 0;
static const char *revs_file = NULL;
static const char *contents_from = NULL;
static const struct option options[] = {
- 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_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
+ OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
+ OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
+ OPT_BOOL(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),
@@ -2372,13 +2265,16 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
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_STRING_LIST('L', NULL, &range_list, N_("n,m"), N_("Process only line range n,m, counting from 1")),
OPT__ABBREV(&abbrev),
OPT_END()
};
struct parse_opt_ctx_t ctx;
int cmd_is_annotate = !strcmp(argv[0], "annotate");
+ struct range_set ranges;
+ unsigned int range_i;
+ long anchor;
git_config(git_blame_config, NULL);
init_revisions(&revs, NULL);
@@ -2571,26 +2467,48 @@ parse_done:
num_read_blob++;
lno = prepare_lines(&sb);
- bottom = top = 0;
- if (bottomtop)
- prepare_blame_range(&sb, bottomtop, lno, &bottom, &top);
- if (bottom && top && top < bottom) {
- long tmp;
- tmp = top; top = bottom; bottom = tmp;
- }
- if (bottom < 1)
- bottom = 1;
- if (top < 1)
- top = lno;
- bottom--;
- if (lno < top || lno < bottom)
- die("file %s has only %lu lines", path, lno);
-
- ent = xcalloc(1, sizeof(*ent));
- ent->lno = bottom;
- ent->num_lines = top - bottom;
- ent->suspect = o;
- ent->s_lno = bottom;
+ if (lno && !range_list.nr)
+ string_list_append(&range_list, xstrdup("1"));
+
+ anchor = 1;
+ range_set_init(&ranges, range_list.nr);
+ for (range_i = 0; range_i < range_list.nr; ++range_i) {
+ long bottom, top;
+ if (parse_range_arg(range_list.items[range_i].string,
+ nth_line_cb, &sb, lno, anchor,
+ &bottom, &top, sb.path))
+ usage(blame_usage);
+ if (lno < top || ((lno || bottom) && lno < bottom))
+ die("file %s has only %lu lines", path, lno);
+ if (bottom < 1)
+ bottom = 1;
+ if (top < 1)
+ top = lno;
+ bottom--;
+ range_set_append_unsafe(&ranges, bottom, top);
+ anchor = top + 1;
+ }
+ sort_and_merge_range_set(&ranges);
+
+ for (range_i = ranges.nr; range_i > 0; --range_i) {
+ const struct range *r = &ranges.ranges[range_i - 1];
+ long bottom = r->start;
+ long top = r->end;
+ struct blame_entry *next = ent;
+ ent = xcalloc(1, sizeof(*ent));
+ ent->lno = bottom;
+ ent->num_lines = top - bottom;
+ ent->suspect = o;
+ ent->s_lno = bottom;
+ ent->next = next;
+ if (next)
+ next->prev = ent;
+ origin_incref(o);
+ }
+ origin_decref(o);
+
+ range_set_release(&ranges);
+ string_list_clear(&range_list, 0);
sb.ent = ent;
sb.path = path;
diff --git a/builtin/branch.c b/builtin/branch.c
index 00d17d2..0903763 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -18,6 +18,7 @@
#include "string-list.h"
#include "column.h"
#include "utf8.h"
+#include "wt-status.h"
static const char * const builtin_branch_usage[] = {
N_("git branch [options] [-r | -a] [--merged | --no-merged]"),
@@ -40,13 +41,15 @@ static char branch_colors[][COLOR_MAXLEN] = {
GIT_COLOR_RED, /* REMOTE */
GIT_COLOR_NORMAL, /* LOCAL */
GIT_COLOR_GREEN, /* CURRENT */
+ GIT_COLOR_BLUE, /* UPSTREAM */
};
enum color_branch {
BRANCH_COLOR_RESET = 0,
BRANCH_COLOR_PLAIN = 1,
BRANCH_COLOR_REMOTE = 2,
BRANCH_COLOR_LOCAL = 3,
- BRANCH_COLOR_CURRENT = 4
+ BRANCH_COLOR_CURRENT = 4,
+ BRANCH_COLOR_UPSTREAM = 5
};
static enum merge_filter {
@@ -71,6 +74,8 @@ static int parse_branch_color_slot(const char *var, int ofs)
return BRANCH_COLOR_LOCAL;
if (!strcasecmp(var+ofs, "current"))
return BRANCH_COLOR_CURRENT;
+ if (!strcasecmp(var+ofs, "upstream"))
+ return BRANCH_COLOR_UPSTREAM;
return -1;
}
@@ -417,36 +422,52 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
int ours, theirs;
char *ref = NULL;
struct branch *branch = branch_get(branch_name);
+ struct strbuf fancy = STRBUF_INIT;
if (!stat_tracking_info(branch, &ours, &theirs)) {
if (branch && branch->merge && branch->merge[0]->dst &&
- show_upstream_ref)
- strbuf_addf(stat, "[%s] ",
- shorten_unambiguous_ref(branch->merge[0]->dst, 0));
+ show_upstream_ref) {
+ ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
+ if (want_color(branch_use_color))
+ strbuf_addf(stat, "[%s%s%s] ",
+ branch_get_color(BRANCH_COLOR_UPSTREAM),
+ ref, branch_get_color(BRANCH_COLOR_RESET));
+ else
+ strbuf_addf(stat, "[%s] ", ref);
+ }
return;
}
- if (show_upstream_ref)
+ if (show_upstream_ref) {
ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
+ if (want_color(branch_use_color))
+ strbuf_addf(&fancy, "%s%s%s",
+ branch_get_color(BRANCH_COLOR_UPSTREAM),
+ ref, branch_get_color(BRANCH_COLOR_RESET));
+ else
+ strbuf_addstr(&fancy, ref);
+ }
+
if (!ours) {
if (ref)
- strbuf_addf(stat, _("[%s: behind %d]"), ref, theirs);
+ strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
else
strbuf_addf(stat, _("[behind %d]"), theirs);
} else if (!theirs) {
if (ref)
- strbuf_addf(stat, _("[%s: ahead %d]"), ref, ours);
+ strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
else
strbuf_addf(stat, _("[ahead %d]"), ours);
} else {
if (ref)
strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
- ref, ours, theirs);
+ fancy.buf, ours, theirs);
else
strbuf_addf(stat, _("[ahead %d, behind %d]"),
ours, theirs);
}
+ strbuf_release(&fancy);
strbuf_addch(stat, ' ');
free(ref);
}
@@ -550,6 +571,29 @@ static int calc_maxwidth(struct ref_list *refs)
return w;
}
+static char *get_head_description(void)
+{
+ struct strbuf desc = STRBUF_INIT;
+ struct wt_status_state state;
+ memset(&state, 0, sizeof(state));
+ wt_status_get_state(&state, 1);
+ if (state.rebase_in_progress ||
+ state.rebase_interactive_in_progress)
+ strbuf_addf(&desc, _("(no branch, rebasing %s)"),
+ state.branch);
+ else if (state.bisect_in_progress)
+ strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
+ state.branch);
+ else if (state.detached_from)
+ strbuf_addf(&desc, _("(detached from %s)"),
+ state.detached_from);
+ else
+ strbuf_addstr(&desc, _("(no branch)"));
+ free(state.branch);
+ free(state.onto);
+ free(state.detached_from);
+ return strbuf_detach(&desc, NULL);
+}
static void show_detached(struct ref_list *ref_list)
{
@@ -557,7 +601,7 @@ 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.name = get_head_description();
item.width = utf8_strwidth(item.name);
item.kind = REF_LOCAL_BRANCH;
item.dest = NULL;
@@ -753,7 +797,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_SET_INT( 0, "set-upstream", &track, N_("change upstream info"),
BRANCH_TRACK_OVERRIDE),
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_BOOL(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),
@@ -778,10 +822,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
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,
- N_("edit the description for the branch")),
+ OPT_BOOL(0, "list", &list, N_("list branch names")),
+ OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
+ OPT_BOOL(0, "edit-description", &edit_description,
+ 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,
@@ -828,7 +872,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (with_commit || merge_filter != NO_FILTER)
list = 1;
- if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)
+ if (!!delete + !!rename + !!force_create + !!new_upstream +
+ list + unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
if (abbrev == -1)
@@ -880,7 +925,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (edit_branch_description(branch_name))
return 1;
} else if (rename) {
- if (argc == 1)
+ if (!argc)
+ die(_("branch name required"));
+ else if (argc == 1)
rename_branch(head, argv[0], rename > 1);
else if (argc == 2)
rename_branch(argv[0], argv[1], rename > 1);
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 045cee7..41afaa5 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -13,9 +13,6 @@
#include "userdiff.h"
#include "streaming.h"
-#define BATCH 1
-#define BATCH_CHECK 2
-
static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
{
unsigned char sha1[20];
@@ -117,54 +114,195 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
return 0;
}
-static int batch_one_object(const char *obj_name, int print_contents)
-{
+struct expand_data {
unsigned char sha1[20];
- enum object_type type = 0;
+ enum object_type type;
unsigned long size;
- void *contents = NULL;
+ unsigned long disk_size;
+ const char *rest;
+
+ /*
+ * If mark_query is true, we do not expand anything, but rather
+ * just mark the object_info with items we wish to query.
+ */
+ int mark_query;
+
+ /*
+ * Whether to split the input on whitespace before feeding it to
+ * get_sha1; this is decided during the mark_query phase based on
+ * whether we have a %(rest) token in our format.
+ */
+ int split_on_whitespace;
+
+ /*
+ * After a mark_query run, this object_info is set up to be
+ * passed to sha1_object_info_extended. It will point to the data
+ * elements above, so you can retrieve the response from there.
+ */
+ struct object_info info;
+};
+
+static int is_atom(const char *atom, const char *s, int slen)
+{
+ int alen = strlen(atom);
+ return alen == slen && !memcmp(atom, s, alen);
+}
+
+static void expand_atom(struct strbuf *sb, const char *atom, int len,
+ void *vdata)
+{
+ struct expand_data *data = vdata;
+
+ if (is_atom("objectname", atom, len)) {
+ if (!data->mark_query)
+ strbuf_addstr(sb, sha1_to_hex(data->sha1));
+ } else if (is_atom("objecttype", atom, len)) {
+ if (data->mark_query)
+ data->info.typep = &data->type;
+ else
+ strbuf_addstr(sb, typename(data->type));
+ } else if (is_atom("objectsize", atom, len)) {
+ if (data->mark_query)
+ data->info.sizep = &data->size;
+ else
+ strbuf_addf(sb, "%lu", data->size);
+ } else if (is_atom("objectsize:disk", atom, len)) {
+ if (data->mark_query)
+ data->info.disk_sizep = &data->disk_size;
+ else
+ strbuf_addf(sb, "%lu", data->disk_size);
+ } else if (is_atom("rest", atom, len)) {
+ if (data->mark_query)
+ data->split_on_whitespace = 1;
+ else if (data->rest)
+ strbuf_addstr(sb, data->rest);
+ } else
+ die("unknown format element: %.*s", len, atom);
+}
+
+static size_t expand_format(struct strbuf *sb, const char *start, void *data)
+{
+ const char *end;
+
+ if (*start != '(')
+ return 0;
+ end = strchr(start + 1, ')');
+ if (!end)
+ die("format element '%s' does not end in ')'", start);
+
+ expand_atom(sb, start + 1, end - start - 1, data);
+
+ return end - start + 1;
+}
+
+static void print_object_or_die(int fd, const unsigned char *sha1,
+ enum object_type type, unsigned long size)
+{
+ if (type == OBJ_BLOB) {
+ if (stream_blob_to_fd(fd, sha1, NULL, 0) < 0)
+ die("unable to stream %s to stdout", sha1_to_hex(sha1));
+ }
+ else {
+ enum object_type rtype;
+ unsigned long rsize;
+ void *contents;
+
+ contents = read_sha1_file(sha1, &rtype, &rsize);
+ if (!contents)
+ die("object %s disappeared", sha1_to_hex(sha1));
+ if (rtype != type)
+ die("object %s changed type!?", sha1_to_hex(sha1));
+ if (rsize != size)
+ die("object %s change size!?", sha1_to_hex(sha1));
+
+ write_or_die(fd, contents, size);
+ free(contents);
+ }
+}
+
+struct batch_options {
+ int enabled;
+ int print_contents;
+ const char *format;
+};
+
+static int batch_one_object(const char *obj_name, struct batch_options *opt,
+ struct expand_data *data)
+{
+ struct strbuf buf = STRBUF_INIT;
if (!obj_name)
return 1;
- if (get_sha1(obj_name, sha1)) {
+ if (get_sha1(obj_name, data->sha1)) {
printf("%s missing\n", obj_name);
fflush(stdout);
return 0;
}
- if (print_contents == BATCH)
- contents = read_sha1_file(sha1, &type, &size);
- else
- type = sha1_object_info(sha1, &size);
-
- if (type <= 0) {
+ if (sha1_object_info_extended(data->sha1, &data->info) < 0) {
printf("%s missing\n", obj_name);
fflush(stdout);
- if (print_contents == BATCH)
- free(contents);
return 0;
}
- printf("%s %s %lu\n", sha1_to_hex(sha1), typename(type), size);
- fflush(stdout);
+ strbuf_expand(&buf, opt->format, expand_format, data);
+ strbuf_addch(&buf, '\n');
+ write_or_die(1, buf.buf, buf.len);
+ strbuf_release(&buf);
- if (print_contents == BATCH) {
- write_or_die(1, contents, size);
- printf("\n");
- fflush(stdout);
- free(contents);
+ if (opt->print_contents) {
+ print_object_or_die(1, data->sha1, data->type, data->size);
+ write_or_die(1, "\n", 1);
}
-
return 0;
}
-static int batch_objects(int print_contents)
+static int batch_objects(struct batch_options *opt)
{
struct strbuf buf = STRBUF_INIT;
+ struct expand_data data;
+
+ if (!opt->format)
+ opt->format = "%(objectname) %(objecttype) %(objectsize)";
+
+ /*
+ * Expand once with our special mark_query flag, which will prime the
+ * object_info to be handed to sha1_object_info_extended for each
+ * object.
+ */
+ memset(&data, 0, sizeof(data));
+ data.mark_query = 1;
+ strbuf_expand(&buf, opt->format, expand_format, &data);
+ data.mark_query = 0;
+
+ /*
+ * We are going to call get_sha1 on a potentially very large number of
+ * objects. In most large cases, these will be actual object sha1s. The
+ * cost to double-check that each one is not also a ref (just so we can
+ * warn) ends up dwarfing the actual cost of the object lookups
+ * themselves. We can work around it by just turning off the warning.
+ */
+ warn_on_object_refname_ambiguity = 0;
while (strbuf_getline(&buf, stdin, '\n') != EOF) {
- int error = batch_one_object(buf.buf, print_contents);
+ int error;
+
+ if (data.split_on_whitespace) {
+ /*
+ * Split at first whitespace, tying off the beginning
+ * of the string and saving the remainder (or NULL) in
+ * data.rest.
+ */
+ char *p = strpbrk(buf.buf, " \t");
+ if (p) {
+ while (*p && strchr(" \t", *p))
+ *p++ = '\0';
+ }
+ data.rest = p;
+ }
+
+ error = batch_one_object(buf.buf, opt, &data);
if (error)
return error;
}
@@ -186,10 +324,29 @@ static int git_cat_file_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
+static int batch_option_callback(const struct option *opt,
+ const char *arg,
+ int unset)
+{
+ struct batch_options *bo = opt->value;
+
+ if (unset) {
+ memset(bo, 0, sizeof(*bo));
+ return 0;
+ }
+
+ bo->enabled = 1;
+ bo->print_contents = !strcmp(opt->long_name, "batch");
+ bo->format = arg;
+
+ return 0;
+}
+
int cmd_cat_file(int argc, const char **argv, const char *prefix)
{
- int opt = 0, batch = 0;
+ int opt = 0;
const char *exp_type = NULL, *obj_name = NULL;
+ struct batch_options batch = {0};
const struct option options[] = {
OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")),
@@ -200,12 +357,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'),
OPT_SET_INT(0, "textconv", &opt,
N_("for blob objects, run textconv on object's content"), 'c'),
- OPT_SET_INT(0, "batch", &batch,
- N_("show info and content of objects fed from the standard input"),
- BATCH),
- OPT_SET_INT(0, "batch-check", &batch,
- N_("show info about objects fed from the standard input"),
- BATCH_CHECK),
+ { OPTION_CALLBACK, 0, "batch", &batch, "format",
+ N_("show info and content of objects fed from the standard input"),
+ PARSE_OPT_OPTARG, batch_option_callback },
+ { OPTION_CALLBACK, 0, "batch-check", &batch, "format",
+ N_("show info about objects fed from the standard input"),
+ PARSE_OPT_OPTARG, batch_option_callback },
OPT_END()
};
@@ -222,19 +379,19 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
else
usage_with_options(cat_file_usage, options);
}
- if (!opt && !batch) {
+ if (!opt && !batch.enabled) {
if (argc == 2) {
exp_type = argv[0];
obj_name = argv[1];
} else
usage_with_options(cat_file_usage, options);
}
- if (batch && (opt || argc)) {
+ if (batch.enabled && (opt || argc)) {
usage_with_options(cat_file_usage, options);
}
- if (batch)
- return batch_objects(batch);
+ if (batch.enabled)
+ return batch_objects(&batch);
return cat_one_file(opt, exp_type, obj_name);
}
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 075d01d..e9af7b2 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -13,14 +13,14 @@ N_("git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"),
NULL
};
-static int null_term_line;
+static int nul_term_line;
static const struct option check_attr_options[] = {
- 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,
- N_("input paths are terminated by a null character")),
+ OPT_BOOL('a', "all", &all_attrs, N_("report all attributes set on file")),
+ OPT_BOOL(0, "cached", &cached_attrs, N_("use .gitattributes only from the index")),
+ OPT_BOOL(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
+ OPT_BOOL('z', NULL, &nul_term_line,
+ N_("terminate input and output records by a NUL character")),
OPT_END()
};
@@ -38,8 +38,16 @@ static void output_attr(int cnt, struct git_attr_check *check,
else if (ATTR_UNSET(value))
value = "unspecified";
- quote_c_style(file, NULL, stdout, 0);
- printf(": %s: %s\n", git_attr_name(check[j].attr), value);
+ if (nul_term_line) {
+ printf("%s%c" /* path */
+ "%s%c" /* attrname */
+ "%s%c" /* attrvalue */,
+ file, 0, git_attr_name(check[j].attr), 0, value, 0);
+ } else {
+ quote_c_style(file, NULL, stdout, 0);
+ printf(": %s: %s\n", git_attr_name(check[j].attr), value);
+ }
+
}
}
@@ -65,7 +73,7 @@ static void check_attr_stdin_paths(const char *prefix, int cnt,
struct git_attr_check *check)
{
struct strbuf buf, nbuf;
- int line_termination = null_term_line ? 0 : '\n';
+ int line_termination = nul_term_line ? 0 : '\n';
strbuf_init(&buf, 0);
strbuf_init(&nbuf, 0);
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 0240f99..e2a1cef 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -5,38 +5,45 @@
#include "pathspec.h"
#include "parse-options.h"
-static int quiet, verbose, stdin_paths;
+static int quiet, verbose, stdin_paths, show_non_matching;
static const char * const check_ignore_usage[] = {
"git check-ignore [options] pathname...",
"git check-ignore [options] --stdin < <list-of-paths>",
NULL
};
-static int null_term_line;
+static int nul_term_line;
static const struct option check_ignore_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")),
OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_GROUP(""),
- OPT_BOOLEAN(0, "stdin", &stdin_paths,
- N_("read file names from stdin")),
- OPT_BOOLEAN('z', NULL, &null_term_line,
- N_("input paths are terminated by a null character")),
+ OPT_BOOL(0, "stdin", &stdin_paths,
+ N_("read file names from stdin")),
+ OPT_BOOL('z', NULL, &nul_term_line,
+ N_("terminate input and output records by a NUL character")),
+ OPT_BOOL('n', "non-matching", &show_non_matching,
+ N_("show non-matching input paths")),
OPT_END()
};
static void output_exclude(const char *path, struct exclude *exclude)
{
- char *bang = exclude->flags & EXC_FLAG_NEGATIVE ? "!" : "";
- char *slash = exclude->flags & EXC_FLAG_MUSTBEDIR ? "/" : "";
- if (!null_term_line) {
+ char *bang = (exclude && exclude->flags & EXC_FLAG_NEGATIVE) ? "!" : "";
+ char *slash = (exclude && exclude->flags & EXC_FLAG_MUSTBEDIR) ? "/" : "";
+ if (!nul_term_line) {
if (!verbose) {
write_name_quoted(path, stdout, '\n');
} else {
- quote_c_style(exclude->el->src, NULL, stdout, 0);
- printf(":%d:%s%s%s\t",
- exclude->srcpos,
- bang, exclude->pattern, slash);
+ if (exclude) {
+ quote_c_style(exclude->el->src, NULL, stdout, 0);
+ printf(":%d:%s%s%s\t",
+ exclude->srcpos,
+ bang, exclude->pattern, slash);
+ }
+ else {
+ printf("::\t");
+ }
quote_c_style(path, NULL, stdout, 0);
fputc('\n', stdout);
}
@@ -44,75 +51,72 @@ static void output_exclude(const char *path, struct exclude *exclude)
if (!verbose) {
printf("%s%c", path, '\0');
} else {
- printf("%s%c%d%c%s%s%s%c%s%c",
- exclude->el->src, '\0',
- exclude->srcpos, '\0',
- bang, exclude->pattern, slash, '\0',
- path, '\0');
+ if (exclude)
+ printf("%s%c%d%c%s%s%s%c%s%c",
+ exclude->el->src, '\0',
+ exclude->srcpos, '\0',
+ bang, exclude->pattern, slash, '\0',
+ path, '\0');
+ else
+ printf("%c%c%c%s%c", '\0', '\0', '\0', path, '\0');
}
}
}
-static int check_ignore(const char *prefix, const char **pathspec)
+static int check_ignore(struct dir_struct *dir,
+ const char *prefix, int argc, const char **argv)
{
- struct dir_struct dir;
- const char *path, *full_path;
+ const char *full_path;
char *seen;
int num_ignored = 0, dtype = DT_UNKNOWN, i;
- struct path_exclude_check check;
struct exclude *exclude;
+ struct pathspec pathspec;
- /* read_cache() is only necessary so we can watch out for submodules. */
- if (read_cache() < 0)
- die(_("index file corrupt"));
-
- memset(&dir, 0, sizeof(dir));
- dir.flags |= DIR_COLLECT_IGNORED;
- setup_standard_excludes(&dir);
-
- if (!pathspec || !*pathspec) {
+ if (!argc) {
if (!quiet)
fprintf(stderr, "no pathspec given.\n");
return 0;
}
- path_exclude_check_init(&check, &dir);
+ /*
+ * check-ignore just needs paths. Magic beyond :/ is really
+ * irrelevant.
+ */
+ parse_pathspec(&pathspec,
+ PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
+ PATHSPEC_SYMLINK_LEADING_PATH |
+ PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE |
+ PATHSPEC_KEEP_ORDER,
+ prefix, argv);
+
/*
* look for pathspecs matching entries in the index, since these
* should not be ignored, in order to be consistent with
* 'git status', 'git add' etc.
*/
- seen = find_pathspecs_matching_against_index(pathspec);
- for (i = 0; pathspec[i]; i++) {
- path = pathspec[i];
- full_path = prefix_path(prefix, prefix
- ? strlen(prefix) : 0, path);
- full_path = check_path_for_gitlink(full_path);
- die_if_path_beyond_symlink(full_path, prefix);
+ seen = find_pathspecs_matching_against_index(&pathspec);
+ for (i = 0; i < pathspec.nr; i++) {
+ full_path = pathspec.items[i].match;
+ exclude = NULL;
if (!seen[i]) {
- exclude = last_exclude_matching_path(&check, full_path,
- -1, &dtype);
- if (exclude) {
- if (!quiet)
- output_exclude(path, exclude);
- num_ignored++;
- }
+ exclude = last_exclude_matching(dir, full_path, &dtype);
}
+ if (!quiet && (exclude || show_non_matching))
+ output_exclude(pathspec.items[i].original, exclude);
+ if (exclude)
+ num_ignored++;
}
free(seen);
- clear_directory(&dir);
- path_exclude_check_clear(&check);
return num_ignored;
}
-static int check_ignore_stdin_paths(const char *prefix)
+static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)
{
struct strbuf buf, nbuf;
- char **pathspec = NULL;
- size_t nr = 0, alloc = 0;
- int line_termination = null_term_line ? 0 : '\n';
- int num_ignored;
+ char *pathspec[2] = { NULL, NULL };
+ int line_termination = nul_term_line ? 0 : '\n';
+ int num_ignored = 0;
strbuf_init(&buf, 0);
strbuf_init(&nbuf, 0);
@@ -123,23 +127,20 @@ static int check_ignore_stdin_paths(const char *prefix)
die("line is badly quoted");
strbuf_swap(&buf, &nbuf);
}
- ALLOC_GROW(pathspec, nr + 1, alloc);
- pathspec[nr] = xcalloc(strlen(buf.buf) + 1, sizeof(*buf.buf));
- strcpy(pathspec[nr++], buf.buf);
+ pathspec[0] = buf.buf;
+ num_ignored += check_ignore(dir, prefix,
+ 1, (const char **)pathspec);
+ maybe_flush_or_die(stdout, "check-ignore to stdout");
}
- ALLOC_GROW(pathspec, nr + 1, alloc);
- pathspec[nr] = NULL;
- num_ignored = check_ignore(prefix, (const char **)pathspec);
- maybe_flush_or_die(stdout, "attribute to stdout");
strbuf_release(&buf);
strbuf_release(&nbuf);
- free(pathspec);
return num_ignored;
}
int cmd_check_ignore(int argc, const char **argv, const char *prefix)
{
int num_ignored;
+ struct dir_struct dir;
git_config(git_default_config, NULL);
@@ -150,7 +151,7 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
if (argc > 0)
die(_("cannot specify pathnames with --stdin"));
} else {
- if (null_term_line)
+ if (nul_term_line)
die(_("-z only makes sense with --stdin"));
if (argc == 0)
die(_("no path specified"));
@@ -161,13 +162,24 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
if (verbose)
die(_("cannot have both --quiet and --verbose"));
}
+ if (show_non_matching && !verbose)
+ die(_("--non-matching is only valid with --verbose"));
+
+ /* read_cache() is only necessary so we can watch out for submodules. */
+ if (read_cache() < 0)
+ die(_("index file corrupt"));
+
+ memset(&dir, 0, sizeof(dir));
+ setup_standard_excludes(&dir);
if (stdin_paths) {
- num_ignored = check_ignore_stdin_paths(prefix);
+ num_ignored = check_ignore_stdin_paths(&dir, prefix);
} else {
- num_ignored = check_ignore(prefix, argv);
+ num_ignored = check_ignore(&dir, prefix, argc, argv);
maybe_flush_or_die(stdout, "ignore to stdout");
}
+ clear_directory(&dir);
+
return !num_ignored;
}
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
new file mode 100644
index 0000000..8f4d809
--- /dev/null
+++ b/builtin/check-mailmap.c
@@ -0,0 +1,66 @@
+#include "builtin.h"
+#include "mailmap.h"
+#include "parse-options.h"
+#include "string-list.h"
+
+static int use_stdin;
+static const char * const check_mailmap_usage[] = {
+N_("git check-mailmap [options] <contact>..."),
+NULL
+};
+
+static const struct option check_mailmap_options[] = {
+ OPT_BOOL(0, "stdin", &use_stdin, N_("also read contacts from stdin")),
+ OPT_END()
+};
+
+static void check_mailmap(struct string_list *mailmap, const char *contact)
+{
+ const char *name, *mail;
+ size_t namelen, maillen;
+ struct ident_split ident;
+
+ if (split_ident_line(&ident, contact, strlen(contact)))
+ die(_("unable to parse contact: %s"), contact);
+
+ name = ident.name_begin;
+ namelen = ident.name_end - ident.name_begin;
+ mail = ident.mail_begin;
+ maillen = ident.mail_end - ident.mail_begin;
+
+ map_user(mailmap, &mail, &maillen, &name, &namelen);
+
+ if (namelen)
+ printf("%.*s ", (int)namelen, name);
+ printf("<%.*s>\n", (int)maillen, mail);
+}
+
+int cmd_check_mailmap(int argc, const char **argv, const char *prefix)
+{
+ int i;
+ struct string_list mailmap = STRING_LIST_INIT_NODUP;
+
+ git_config(git_default_config, NULL);
+ argc = parse_options(argc, argv, prefix, check_mailmap_options,
+ check_mailmap_usage, 0);
+ if (argc == 0 && !use_stdin)
+ die(_("no contacts specified"));
+
+ read_mailmap(&mailmap, NULL);
+
+ for (i = 0; i < argc; ++i)
+ check_mailmap(&mailmap, argv[i]);
+ maybe_flush_or_die(stdout, "stdout");
+
+ if (use_stdin) {
+ struct strbuf buf = STRBUF_INIT;
+ while (strbuf_getline(&buf, stdin, '\n') != EOF) {
+ check_mailmap(&mailmap, buf.buf);
+ maybe_flush_or_die(stdout, "stdout");
+ }
+ strbuf_release(&buf);
+ }
+
+ clear_mailmap(&mailmap);
+ return 0;
+}
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index b1feda7..69e167b 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -183,12 +183,12 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
int prefix_length;
int force = 0, quiet = 0, not_new = 0;
struct option builtin_checkout_index_options[] = {
- OPT_BOOLEAN('a', "all", &all,
+ OPT_BOOL('a', "all", &all,
N_("check out all files in the index")),
OPT__FORCE(&force, N_("force overwrite of existing files")),
OPT__QUIET(&quiet,
N_("no warning for existing files and files not in index")),
- OPT_BOOLEAN('n', "no-create", &not_new,
+ OPT_BOOL('n', "no-create", &not_new,
N_("don't checkout new files")),
{ OPTION_CALLBACK, 'u', "index", &newfd, NULL,
N_("update stat information in the index file"),
@@ -196,9 +196,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
N_("paths are separated with NUL character"),
PARSE_OPT_NOARG, option_parse_z },
- OPT_BOOLEAN(0, "stdin", &read_from_stdin,
+ OPT_BOOL(0, "stdin", &read_from_stdin,
N_("read list of paths from the standard input")),
- OPT_BOOLEAN(0, "temp", &to_tempfile,
+ OPT_BOOL(0, "temp", &to_tempfile,
N_("write the content to temporary files")),
OPT_CALLBACK(0, "prefix", NULL, N_("string"),
N_("when creating files, prepend <string>"),
diff --git a/builtin/checkout.c b/builtin/checkout.c
index a9c1b5a..0f57397 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -35,6 +35,7 @@ struct checkout_opts {
int force_detach;
int writeout_stage;
int overwrite_ignore;
+ int ignore_skipworktree;
const char *new_branch;
const char *new_branch_force;
@@ -45,7 +46,7 @@ struct checkout_opts {
int branch_exists;
const char *prefix;
- const char **pathspec;
+ struct pathspec pathspec;
struct tree *source_tree;
};
@@ -82,12 +83,9 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
return 0;
}
-static int read_tree_some(struct tree *tree, const char **pathspec)
+static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
{
- struct pathspec ps;
- init_pathspec(&ps, pathspec);
- read_tree_recursive(tree, "", 0, 0, &ps, update_some, NULL);
- free_pathspec(&ps);
+ read_tree_recursive(tree, "", 0, 0, pathspec, update_some, NULL);
/* update the index with the given tree's info
* for all args, expanding wildcards, and exit
@@ -96,7 +94,7 @@ static int read_tree_some(struct tree *tree, const char **pathspec)
return 0;
}
-static int skip_same_name(struct cache_entry *ce, int pos)
+static int skip_same_name(const struct cache_entry *ce, int pos)
{
while (++pos < active_nr &&
!strcmp(active_cache[pos]->name, ce->name))
@@ -104,7 +102,7 @@ static int skip_same_name(struct cache_entry *ce, int pos)
return pos;
}
-static int check_stage(int stage, struct cache_entry *ce, int pos)
+static int check_stage(int stage, const struct cache_entry *ce, int pos)
{
while (pos < active_nr &&
!strcmp(active_cache[pos]->name, ce->name)) {
@@ -118,7 +116,7 @@ static int check_stage(int stage, struct cache_entry *ce, int pos)
return error(_("path '%s' does not have their version"), ce->name);
}
-static int check_stages(unsigned stages, struct cache_entry *ce, int pos)
+static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)
{
unsigned seen = 0;
const char *name = ce->name;
@@ -227,8 +225,6 @@ static int checkout_paths(const struct checkout_opts *opts,
int flag;
struct commit *head;
int errs = 0;
- int stage = opts->writeout_stage;
- int merge = opts->merge;
int newfd;
struct lock_file *lock_file;
@@ -256,45 +252,76 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->patch_mode)
return run_add_interactive(revision, "--patch=checkout",
- opts->pathspec);
+ &opts->pathspec);
lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_locked_index(lock_file, 1);
- if (read_cache_preload(opts->pathspec) < 0)
+ if (read_cache_preload(&opts->pathspec) < 0)
return error(_("corrupt index file"));
if (opts->source_tree)
- read_tree_some(opts->source_tree, opts->pathspec);
+ read_tree_some(opts->source_tree, &opts->pathspec);
- for (pos = 0; opts->pathspec[pos]; pos++)
- ;
- ps_matched = xcalloc(1, pos);
+ ps_matched = xcalloc(1, opts->pathspec.nr);
+ /*
+ * Make sure all pathspecs participated in locating the paths
+ * to be checked out.
+ */
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
+ ce->ce_flags &= ~CE_MATCHED;
+ if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
+ continue;
if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
+ /*
+ * "git checkout tree-ish -- path", but this entry
+ * is in the original index; it will not be checked
+ * out to the working tree and it does not matter
+ * if pathspec matched this entry. We will not do
+ * anything to this entry at all.
+ */
continue;
- match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
+ /*
+ * Either this entry came from the tree-ish we are
+ * checking the paths out of, or we are checking out
+ * of the index.
+ *
+ * If it comes from the tree-ish, we already know it
+ * matches the pathspec and could just stamp
+ * CE_MATCHED to it from update_some(). But we still
+ * need ps_matched and read_tree_recursive (and
+ * eventually tree_entry_interesting) cannot fill
+ * ps_matched yet. Once it can, we can avoid calling
+ * match_pathspec() for _all_ entries when
+ * opts->source_tree != NULL.
+ */
+ if (match_pathspec_depth(&opts->pathspec, ce->name, ce_namelen(ce),
+ 0, ps_matched))
+ ce->ce_flags |= CE_MATCHED;
}
- if (report_path_error(ps_matched, opts->pathspec, opts->prefix))
+ if (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {
+ free(ps_matched);
return 1;
+ }
+ free(ps_matched);
/* "checkout -m path" to recreate conflicted state */
if (opts->merge)
- unmerge_cache(opts->pathspec);
+ unmerge_marked_index(&the_index);
/* Any unmerged paths? */
for (pos = 0; pos < active_nr; pos++) {
- struct cache_entry *ce = active_cache[pos];
- if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+ const struct cache_entry *ce = active_cache[pos];
+ if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce))
continue;
if (opts->force) {
warning(_("path '%s' is unmerged"), ce->name);
- } else if (stage) {
- errs |= check_stage(stage, ce, pos);
+ } else if (opts->writeout_stage) {
+ errs |= check_stage(opts->writeout_stage, ce, pos);
} else if (opts->merge) {
errs |= check_stages((1<<2) | (1<<3), ce, pos);
} else {
@@ -313,16 +340,14 @@ static int checkout_paths(const struct checkout_opts *opts,
state.refresh_cache = 1;
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
- if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
- continue;
- if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+ if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce)) {
errs |= checkout_entry(ce, &state, NULL);
continue;
}
- if (stage)
- errs |= checkout_stage(stage, ce, pos, &state);
- else if (merge)
+ if (opts->writeout_stage)
+ errs |= checkout_stage(opts->writeout_stage, ce, pos, &state);
+ else if (opts->merge)
errs |= checkout_merged(pos, &state);
pos = skip_same_name(ce, pos) - 1;
}
@@ -555,7 +580,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
struct branch_info *new)
{
struct strbuf msg = STRBUF_INIT;
- const char *old_desc;
+ const char *old_desc, *reflog_msg;
if (opts->new_branch) {
if (opts->new_orphan_branch) {
if (opts->new_branch_log && !log_all_ref_updates) {
@@ -588,8 +613,13 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
old_desc = old->name;
if (!old_desc && old->commit)
old_desc = sha1_to_hex(old->commit->object.sha1);
- strbuf_addf(&msg, "checkout: moving from %s to %s",
- old_desc ? old_desc : "(invalid)", new->name);
+
+ reflog_msg = getenv("GIT_REFLOG_ACTION");
+ if (!reflog_msg)
+ strbuf_addf(&msg, "checkout: moving from %s to %s",
+ old_desc ? old_desc : "(invalid)", new->name);
+ else
+ strbuf_insert(&msg, 0, reflog_msg, strlen(reflog_msg));
if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
/* Nothing to do. */
@@ -700,7 +730,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
"If you want to keep them by creating a new branch, "
"this may be a good time\nto do so with:\n\n"
" git branch new_branch_name %s\n\n"),
- sha1_to_hex(commit->object.sha1));
+ find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
}
/*
@@ -793,38 +823,43 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
}
struct tracking_name_data {
- const char *name;
- char *remote;
+ /* const */ char *src_ref;
+ char *dst_ref;
+ unsigned char *dst_sha1;
int unique;
};
-static int check_tracking_name(const char *refname, const unsigned char *sha1,
- int flags, void *cb_data)
+static int check_tracking_name(struct remote *remote, void *cb_data)
{
struct tracking_name_data *cb = cb_data;
- const char *slash;
-
- if (prefixcmp(refname, "refs/remotes/"))
+ struct refspec query;
+ memset(&query, 0, sizeof(struct refspec));
+ query.src = cb->src_ref;
+ if (remote_find_tracking(remote, &query) ||
+ get_sha1(query.dst, cb->dst_sha1)) {
+ free(query.dst);
return 0;
- slash = strchr(refname + 13, '/');
- if (!slash || strcmp(slash + 1, cb->name))
- return 0;
- if (cb->remote) {
+ }
+ if (cb->dst_ref) {
+ free(query.dst);
cb->unique = 0;
return 0;
}
- cb->remote = xstrdup(refname);
+ cb->dst_ref = query.dst;
return 0;
}
-static const char *unique_tracking_name(const char *name)
+static const char *unique_tracking_name(const char *name, unsigned char *sha1)
{
- struct tracking_name_data cb_data = { NULL, NULL, 1 };
- cb_data.name = name;
- for_each_ref(check_tracking_name, &cb_data);
+ struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
+ char src_ref[PATH_MAX];
+ snprintf(src_ref, PATH_MAX, "refs/heads/%s", name);
+ cb_data.src_ref = src_ref;
+ cb_data.dst_sha1 = sha1;
+ for_each_remote(check_tracking_name, &cb_data);
if (cb_data.unique)
- return cb_data.remote;
- free(cb_data.remote);
+ return cb_data.dst_ref;
+ free(cb_data.dst_ref);
return NULL;
}
@@ -887,8 +922,8 @@ static int parse_branchname_arg(int argc, const char **argv,
if (dwim_new_local_branch_ok &&
!check_filename(NULL, arg) &&
argc == 1) {
- const char *remote = unique_tracking_name(arg);
- if (!remote || get_sha1(remote, rev))
+ const char *remote = unique_tracking_name(arg, rev);
+ if (!remote)
return argcount;
*new_branch = arg;
arg = remote;
@@ -960,7 +995,7 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
static int checkout_branch(struct checkout_opts *opts,
struct branch_info *new)
{
- if (opts->pathspec)
+ if (opts->pathspec.nr)
die(_("paths cannot be used with switching branches"));
if (opts->patch_mode)
@@ -1014,8 +1049,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
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_BOOL('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
+ OPT_BOOL(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, N_("new branch"), N_("new unparented branch")),
@@ -1024,14 +1059,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
3),
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_BOOL('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")),
+ OPT_BOOL(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,
- N_("second guess 'git checkout no-such-branch'"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+ OPT_BOOL('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
+ OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
+ N_("do not limit pathspecs to sparse entries only")),
+ OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
+ N_("second guess 'git checkout no-such-branch'")),
OPT_END(),
};
@@ -1110,9 +1146,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
}
if (argc) {
- opts.pathspec = get_pathspec(prefix, argv);
+ parse_pathspec(&opts.pathspec, 0,
+ opts.patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,
+ prefix, argv);
- if (!opts.pathspec)
+ if (!opts.pathspec.nr)
die(_("invalid path specification"));
/*
@@ -1144,7 +1182,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
strbuf_release(&buf);
}
- if (opts.patch_mode || opts.pathspec)
+ if (opts.patch_mode || opts.pathspec.nr)
return checkout_paths(&opts, new.name);
else
return checkout_branch(&opts, &new);
diff --git a/builtin/clean.c b/builtin/clean.c
index 04e396b..615cd57 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -13,11 +13,17 @@
#include "refs.h"
#include "string-list.h"
#include "quote.h"
+#include "column.h"
+#include "color.h"
+#include "pathspec.h"
static int force = -1; /* unset */
+static int interactive;
+static struct string_list del_list = STRING_LIST_INIT_DUP;
+static unsigned int colopts;
static const char *const builtin_clean_usage[] = {
- N_("git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
+ N_("git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
NULL
};
@@ -27,11 +33,112 @@ static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
static const char *msg_warn_remove_failed = N_("failed to remove %s");
+static int clean_use_color = -1;
+static char clean_colors[][COLOR_MAXLEN] = {
+ GIT_COLOR_RESET,
+ GIT_COLOR_NORMAL, /* PLAIN */
+ GIT_COLOR_BOLD_BLUE, /* PROMPT */
+ GIT_COLOR_BOLD, /* HEADER */
+ GIT_COLOR_BOLD_RED, /* HELP */
+ GIT_COLOR_BOLD_RED, /* ERROR */
+};
+enum color_clean {
+ CLEAN_COLOR_RESET = 0,
+ CLEAN_COLOR_PLAIN = 1,
+ CLEAN_COLOR_PROMPT = 2,
+ CLEAN_COLOR_HEADER = 3,
+ CLEAN_COLOR_HELP = 4,
+ CLEAN_COLOR_ERROR = 5,
+};
+
+#define MENU_OPTS_SINGLETON 01
+#define MENU_OPTS_IMMEDIATE 02
+#define MENU_OPTS_LIST_ONLY 04
+
+struct menu_opts {
+ const char *header;
+ const char *prompt;
+ int flags;
+};
+
+#define MENU_RETURN_NO_LOOP 10
+
+struct menu_item {
+ char hotkey;
+ const char *title;
+ int selected;
+ int (*fn)();
+};
+
+enum menu_stuff_type {
+ MENU_STUFF_TYPE_STRING_LIST = 1,
+ MENU_STUFF_TYPE_MENU_ITEM
+};
+
+struct menu_stuff {
+ enum menu_stuff_type type;
+ int nr;
+ void *stuff;
+};
+
+static int parse_clean_color_slot(const char *var)
+{
+ if (!strcasecmp(var, "reset"))
+ return CLEAN_COLOR_RESET;
+ if (!strcasecmp(var, "plain"))
+ return CLEAN_COLOR_PLAIN;
+ if (!strcasecmp(var, "prompt"))
+ return CLEAN_COLOR_PROMPT;
+ if (!strcasecmp(var, "header"))
+ return CLEAN_COLOR_HEADER;
+ if (!strcasecmp(var, "help"))
+ return CLEAN_COLOR_HELP;
+ if (!strcasecmp(var, "error"))
+ return CLEAN_COLOR_ERROR;
+ return -1;
+}
+
static int git_clean_config(const char *var, const char *value, void *cb)
{
- if (!strcmp(var, "clean.requireforce"))
+ if (!prefixcmp(var, "column."))
+ return git_column_config(var, value, "clean", &colopts);
+
+ /* honors the color.interactive* config variables which also
+ applied in git-add--interactive and git-stash */
+ if (!strcmp(var, "color.interactive")) {
+ clean_use_color = git_config_colorbool(var, value);
+ return 0;
+ }
+ if (!prefixcmp(var, "color.interactive.")) {
+ int slot = parse_clean_color_slot(var +
+ strlen("color.interactive."));
+ if (slot < 0)
+ return 0;
+ if (!value)
+ return config_error_nonbool(var);
+ color_parse(value, var, clean_colors[slot]);
+ return 0;
+ }
+
+ if (!strcmp(var, "clean.requireforce")) {
force = !git_config_bool(var, value);
- return git_default_config(var, value, cb);
+ return 0;
+ }
+
+ /* inspect the color.ui config variable and others */
+ return git_color_default_config(var, value, cb);
+}
+
+static const char *clean_get_color(enum color_clean ix)
+{
+ if (want_color(clean_use_color))
+ return clean_colors[ix];
+ return "";
+}
+
+static void clean_print_color(enum color_clean ix)
+{
+ printf("%s", clean_get_color(ix));
}
static int exclude_cb(const struct option *opt, const char *arg, int unset)
@@ -56,7 +163,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
!resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
if (!quiet) {
- quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ quote_path_relative(path->buf, prefix, &quoted);
printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
quoted.buf);
}
@@ -70,7 +177,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
/* an empty dir could be removed even if it is unreadble */
res = dry_run ? 0 : rmdir(path->buf);
if (res) {
- quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ quote_path_relative(path->buf, prefix, &quoted);
warning(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
}
@@ -94,7 +201,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
ret = 1;
if (gone) {
- quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ quote_path_relative(path->buf, prefix, &quoted);
string_list_append(&dels, quoted.buf);
} else
*dir_gone = 0;
@@ -102,10 +209,10 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
} else {
res = dry_run ? 0 : unlink(path->buf);
if (!res) {
- quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ quote_path_relative(path->buf, prefix, &quoted);
string_list_append(&dels, quoted.buf);
} else {
- quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ quote_path_relative(path->buf, prefix, &quoted);
warning(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
ret = 1;
@@ -127,7 +234,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
if (!res)
*dir_gone = 1;
else {
- quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ quote_path_relative(path->buf, prefix, &quoted);
warning(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
ret = 1;
@@ -142,30 +249,638 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
return ret;
}
+static void pretty_print_dels(void)
+{
+ struct string_list list = STRING_LIST_INIT_DUP;
+ struct string_list_item *item;
+ struct strbuf buf = STRBUF_INIT;
+ const char *qname;
+ struct column_options copts;
+
+ for_each_string_list_item(item, &del_list) {
+ qname = quote_path_relative(item->string, NULL, &buf);
+ string_list_append(&list, qname);
+ }
+
+ /*
+ * always enable column display, we only consult column.*
+ * about layout strategy and stuff
+ */
+ colopts = (colopts & ~COL_ENABLE_MASK) | COL_ENABLED;
+ memset(&copts, 0, sizeof(copts));
+ copts.indent = " ";
+ copts.padding = 2;
+ print_columns(&list, colopts, &copts);
+ strbuf_release(&buf);
+ string_list_clear(&list, 0);
+}
+
+static void pretty_print_menus(struct string_list *menu_list)
+{
+ unsigned int local_colopts = 0;
+ struct column_options copts;
+
+ local_colopts = COL_ENABLED | COL_ROW;
+ memset(&copts, 0, sizeof(copts));
+ copts.indent = " ";
+ copts.padding = 2;
+ print_columns(menu_list, local_colopts, &copts);
+}
+
+static void prompt_help_cmd(int singleton)
+{
+ clean_print_color(CLEAN_COLOR_HELP);
+ printf_ln(singleton ?
+ _("Prompt help:\n"
+ "1 - select a numbered item\n"
+ "foo - select item based on unique prefix\n"
+ " - (empty) select nothing") :
+ _("Prompt help:\n"
+ "1 - select a single item\n"
+ "3-5 - select a range of items\n"
+ "2-3,6-9 - select multiple ranges\n"
+ "foo - select item based on unique prefix\n"
+ "-... - unselect specified items\n"
+ "* - choose all items\n"
+ " - (empty) finish selecting"));
+ clean_print_color(CLEAN_COLOR_RESET);
+}
+
+/*
+ * display menu stuff with number prefix and hotkey highlight
+ */
+static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen)
+{
+ struct string_list menu_list = STRING_LIST_INIT_DUP;
+ struct strbuf menu = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT;
+ struct menu_item *menu_item;
+ struct string_list_item *string_list_item;
+ int i;
+
+ switch (stuff->type) {
+ default:
+ die("Bad type of menu_staff when print menu");
+ case MENU_STUFF_TYPE_MENU_ITEM:
+ menu_item = (struct menu_item *)stuff->stuff;
+ for (i = 0; i < stuff->nr; i++, menu_item++) {
+ const char *p;
+ int highlighted = 0;
+
+ p = menu_item->title;
+ if ((*chosen)[i] < 0)
+ (*chosen)[i] = menu_item->selected ? 1 : 0;
+ strbuf_addf(&menu, "%s%2d: ", (*chosen)[i] ? "*" : " ", i+1);
+ for (; *p; p++) {
+ if (!highlighted && *p == menu_item->hotkey) {
+ strbuf_addstr(&menu, clean_get_color(CLEAN_COLOR_PROMPT));
+ strbuf_addch(&menu, *p);
+ strbuf_addstr(&menu, clean_get_color(CLEAN_COLOR_RESET));
+ highlighted = 1;
+ } else {
+ strbuf_addch(&menu, *p);
+ }
+ }
+ string_list_append(&menu_list, menu.buf);
+ strbuf_reset(&menu);
+ }
+ break;
+ case MENU_STUFF_TYPE_STRING_LIST:
+ i = 0;
+ for_each_string_list_item(string_list_item, (struct string_list *)stuff->stuff) {
+ if ((*chosen)[i] < 0)
+ (*chosen)[i] = 0;
+ strbuf_addf(&menu, "%s%2d: %s",
+ (*chosen)[i] ? "*" : " ", i+1, string_list_item->string);
+ string_list_append(&menu_list, menu.buf);
+ strbuf_reset(&menu);
+ i++;
+ }
+ break;
+ }
+
+ pretty_print_menus(&menu_list);
+
+ strbuf_release(&menu);
+ strbuf_release(&buf);
+ string_list_clear(&menu_list, 0);
+}
+
+static int find_unique(const char *choice, struct menu_stuff *menu_stuff)
+{
+ struct menu_item *menu_item;
+ struct string_list_item *string_list_item;
+ int i, len, found = 0;
+
+ len = strlen(choice);
+ switch (menu_stuff->type) {
+ default:
+ die("Bad type of menu_stuff when parse choice");
+ case MENU_STUFF_TYPE_MENU_ITEM:
+
+ menu_item = (struct menu_item *)menu_stuff->stuff;
+ for (i = 0; i < menu_stuff->nr; i++, menu_item++) {
+ if (len == 1 && *choice == menu_item->hotkey) {
+ found = i + 1;
+ break;
+ }
+ if (!strncasecmp(choice, menu_item->title, len)) {
+ if (found) {
+ if (len == 1) {
+ /* continue for hotkey matching */
+ found = -1;
+ } else {
+ found = 0;
+ break;
+ }
+ } else {
+ found = i + 1;
+ }
+ }
+ }
+ break;
+ case MENU_STUFF_TYPE_STRING_LIST:
+ string_list_item = ((struct string_list *)menu_stuff->stuff)->items;
+ for (i = 0; i < menu_stuff->nr; i++, string_list_item++) {
+ if (!strncasecmp(choice, string_list_item->string, len)) {
+ if (found) {
+ found = 0;
+ break;
+ }
+ found = i + 1;
+ }
+ }
+ break;
+ }
+ return found;
+}
+
+
+/*
+ * Parse user input, and return choice(s) for menu (menu_stuff).
+ *
+ * Input
+ * (for single choice)
+ * 1 - select a numbered item
+ * foo - select item based on menu title
+ * - (empty) select nothing
+ *
+ * (for multiple choice)
+ * 1 - select a single item
+ * 3-5 - select a range of items
+ * 2-3,6-9 - select multiple ranges
+ * foo - select item based on menu title
+ * -... - unselect specified items
+ * * - choose all items
+ * - (empty) finish selecting
+ *
+ * The parse result will be saved in array **chosen, and
+ * return number of total selections.
+ */
+static int parse_choice(struct menu_stuff *menu_stuff,
+ int is_single,
+ struct strbuf input,
+ int **chosen)
+{
+ struct strbuf **choice_list, **ptr;
+ int nr = 0;
+ int i;
+
+ if (is_single) {
+ choice_list = strbuf_split_max(&input, '\n', 0);
+ } else {
+ char *p = input.buf;
+ do {
+ if (*p == ',')
+ *p = ' ';
+ } while (*p++);
+ choice_list = strbuf_split_max(&input, ' ', 0);
+ }
+
+ for (ptr = choice_list; *ptr; ptr++) {
+ char *p;
+ int choose = 1;
+ int bottom = 0, top = 0;
+ int is_range, is_number;
+
+ strbuf_trim(*ptr);
+ if (!(*ptr)->len)
+ continue;
+
+ /* Input that begins with '-'; unchoose */
+ if (*(*ptr)->buf == '-') {
+ choose = 0;
+ strbuf_remove((*ptr), 0, 1);
+ }
+
+ is_range = 0;
+ is_number = 1;
+ for (p = (*ptr)->buf; *p; p++) {
+ if ('-' == *p) {
+ if (!is_range) {
+ is_range = 1;
+ is_number = 0;
+ } else {
+ is_number = 0;
+ is_range = 0;
+ break;
+ }
+ } else if (!isdigit(*p)) {
+ is_number = 0;
+ is_range = 0;
+ break;
+ }
+ }
+
+ if (is_number) {
+ bottom = atoi((*ptr)->buf);
+ top = bottom;
+ } else if (is_range) {
+ bottom = atoi((*ptr)->buf);
+ /* a range can be specified like 5-7 or 5- */
+ if (!*(strchr((*ptr)->buf, '-') + 1))
+ top = menu_stuff->nr;
+ else
+ top = atoi(strchr((*ptr)->buf, '-') + 1);
+ } else if (!strcmp((*ptr)->buf, "*")) {
+ bottom = 1;
+ top = menu_stuff->nr;
+ } else {
+ bottom = find_unique((*ptr)->buf, menu_stuff);
+ top = bottom;
+ }
+
+ if (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top ||
+ (is_single && bottom != top)) {
+ clean_print_color(CLEAN_COLOR_ERROR);
+ printf_ln(_("Huh (%s)?"), (*ptr)->buf);
+ clean_print_color(CLEAN_COLOR_RESET);
+ continue;
+ }
+
+ for (i = bottom; i <= top; i++)
+ (*chosen)[i-1] = choose;
+ }
+
+ strbuf_list_free(choice_list);
+
+ for (i = 0; i < menu_stuff->nr; i++)
+ nr += (*chosen)[i];
+ return nr;
+}
+
+/*
+ * Implement a git-add-interactive compatible UI, which is borrowed
+ * from git-add--interactive.perl.
+ *
+ * Return value:
+ *
+ * - Return an array of integers
+ * - , and it is up to you to free the allocated memory.
+ * - The array ends with EOF.
+ * - If user pressed CTRL-D (i.e. EOF), no selection returned.
+ */
+static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)
+{
+ struct strbuf choice = STRBUF_INIT;
+ int *chosen, *result;
+ int nr = 0;
+ int eof = 0;
+ int i;
+
+ chosen = xmalloc(sizeof(int) * stuff->nr);
+ /* set chosen as uninitialized */
+ for (i = 0; i < stuff->nr; i++)
+ chosen[i] = -1;
+
+ for (;;) {
+ if (opts->header) {
+ printf_ln("%s%s%s",
+ clean_get_color(CLEAN_COLOR_HEADER),
+ _(opts->header),
+ clean_get_color(CLEAN_COLOR_RESET));
+ }
+
+ /* chosen will be initialized by print_highlight_menu_stuff */
+ print_highlight_menu_stuff(stuff, &chosen);
+
+ if (opts->flags & MENU_OPTS_LIST_ONLY)
+ break;
+
+ if (opts->prompt) {
+ printf("%s%s%s%s",
+ clean_get_color(CLEAN_COLOR_PROMPT),
+ _(opts->prompt),
+ opts->flags & MENU_OPTS_SINGLETON ? "> " : ">> ",
+ clean_get_color(CLEAN_COLOR_RESET));
+ }
+
+ if (strbuf_getline(&choice, stdin, '\n') != EOF) {
+ strbuf_trim(&choice);
+ } else {
+ eof = 1;
+ break;
+ }
+
+ /* help for prompt */
+ if (!strcmp(choice.buf, "?")) {
+ prompt_help_cmd(opts->flags & MENU_OPTS_SINGLETON);
+ continue;
+ }
+
+ /* for a multiple-choice menu, press ENTER (empty) will return back */
+ if (!(opts->flags & MENU_OPTS_SINGLETON) && !choice.len)
+ break;
+
+ nr = parse_choice(stuff,
+ opts->flags & MENU_OPTS_SINGLETON,
+ choice,
+ &chosen);
+
+ if (opts->flags & MENU_OPTS_SINGLETON) {
+ if (nr)
+ break;
+ } else if (opts->flags & MENU_OPTS_IMMEDIATE) {
+ break;
+ }
+ }
+
+ if (eof) {
+ result = xmalloc(sizeof(int));
+ *result = EOF;
+ } else {
+ int j = 0;
+
+ /*
+ * recalculate nr, if return back from menu directly with
+ * default selections.
+ */
+ if (!nr) {
+ for (i = 0; i < stuff->nr; i++)
+ nr += chosen[i];
+ }
+
+ result = xmalloc(sizeof(int) * (nr + 1));
+ memset(result, 0, sizeof(int) * (nr + 1));
+ for (i = 0; i < stuff->nr && j < nr; i++) {
+ if (chosen[i])
+ result[j++] = i;
+ }
+ result[j] = EOF;
+ }
+
+ free(chosen);
+ strbuf_release(&choice);
+ return result;
+}
+
+static int clean_cmd(void)
+{
+ return MENU_RETURN_NO_LOOP;
+}
+
+static int filter_by_patterns_cmd(void)
+{
+ struct dir_struct dir;
+ struct strbuf confirm = STRBUF_INIT;
+ struct strbuf **ignore_list;
+ struct string_list_item *item;
+ struct exclude_list *el;
+ int changed = -1, i;
+
+ for (;;) {
+ if (!del_list.nr)
+ break;
+
+ if (changed)
+ pretty_print_dels();
+
+ clean_print_color(CLEAN_COLOR_PROMPT);
+ printf(_("Input ignore patterns>> "));
+ clean_print_color(CLEAN_COLOR_RESET);
+ if (strbuf_getline(&confirm, stdin, '\n') != EOF)
+ strbuf_trim(&confirm);
+ else
+ putchar('\n');
+
+ /* quit filter_by_pattern mode if press ENTER or Ctrl-D */
+ if (!confirm.len)
+ break;
+
+ memset(&dir, 0, sizeof(dir));
+ el = add_exclude_list(&dir, EXC_CMDL, "manual exclude");
+ ignore_list = strbuf_split_max(&confirm, ' ', 0);
+
+ for (i = 0; ignore_list[i]; i++) {
+ strbuf_trim(ignore_list[i]);
+ if (!ignore_list[i]->len)
+ continue;
+
+ add_exclude(ignore_list[i]->buf, "", 0, el, -(i+1));
+ }
+
+ changed = 0;
+ for_each_string_list_item(item, &del_list) {
+ int dtype = DT_UNKNOWN;
+
+ if (is_excluded(&dir, item->string, &dtype)) {
+ *item->string = '\0';
+ changed++;
+ }
+ }
+
+ if (changed) {
+ string_list_remove_empty_items(&del_list, 0);
+ } else {
+ clean_print_color(CLEAN_COLOR_ERROR);
+ printf_ln(_("WARNING: Cannot find items matched by: %s"), confirm.buf);
+ clean_print_color(CLEAN_COLOR_RESET);
+ }
+
+ strbuf_list_free(ignore_list);
+ clear_directory(&dir);
+ }
+
+ strbuf_release(&confirm);
+ return 0;
+}
+
+static int select_by_numbers_cmd(void)
+{
+ struct menu_opts menu_opts;
+ struct menu_stuff menu_stuff;
+ struct string_list_item *items;
+ int *chosen;
+ int i, j;
+
+ menu_opts.header = NULL;
+ menu_opts.prompt = N_("Select items to delete");
+ menu_opts.flags = 0;
+
+ menu_stuff.type = MENU_STUFF_TYPE_STRING_LIST;
+ menu_stuff.stuff = &del_list;
+ menu_stuff.nr = del_list.nr;
+
+ chosen = list_and_choose(&menu_opts, &menu_stuff);
+ items = del_list.items;
+ for (i = 0, j = 0; i < del_list.nr; i++) {
+ if (i < chosen[j]) {
+ *(items[i].string) = '\0';
+ } else if (i == chosen[j]) {
+ /* delete selected item */
+ j++;
+ continue;
+ } else {
+ /* end of chosen (chosen[j] == EOF), won't delete */
+ *(items[i].string) = '\0';
+ }
+ }
+
+ string_list_remove_empty_items(&del_list, 0);
+
+ free(chosen);
+ return 0;
+}
+
+static int ask_each_cmd(void)
+{
+ struct strbuf confirm = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list_item *item;
+ const char *qname;
+ int changed = 0, eof = 0;
+
+ for_each_string_list_item(item, &del_list) {
+ /* Ctrl-D should stop removing files */
+ if (!eof) {
+ qname = quote_path_relative(item->string, NULL, &buf);
+ printf(_("remove %s? "), qname);
+ if (strbuf_getline(&confirm, stdin, '\n') != EOF) {
+ strbuf_trim(&confirm);
+ } else {
+ putchar('\n');
+ eof = 1;
+ }
+ }
+ if (!confirm.len || strncasecmp(confirm.buf, "yes", confirm.len)) {
+ *item->string = '\0';
+ changed++;
+ }
+ }
+
+ if (changed)
+ string_list_remove_empty_items(&del_list, 0);
+
+ strbuf_release(&buf);
+ strbuf_release(&confirm);
+ return MENU_RETURN_NO_LOOP;
+}
+
+static int quit_cmd(void)
+{
+ string_list_clear(&del_list, 0);
+ printf_ln(_("Bye."));
+ return MENU_RETURN_NO_LOOP;
+}
+
+static int help_cmd(void)
+{
+ clean_print_color(CLEAN_COLOR_HELP);
+ printf_ln(_(
+ "clean - start cleaning\n"
+ "filter by pattern - exclude items from deletion\n"
+ "select by numbers - select items to be deleted by numbers\n"
+ "ask each - confirm each deletion (like \"rm -i\")\n"
+ "quit - stop cleaning\n"
+ "help - this screen\n"
+ "? - help for prompt selection"
+ ));
+ clean_print_color(CLEAN_COLOR_RESET);
+ return 0;
+}
+
+static void interactive_main_loop(void)
+{
+ while (del_list.nr) {
+ struct menu_opts menu_opts;
+ struct menu_stuff menu_stuff;
+ struct menu_item menus[] = {
+ {'c', "clean", 0, clean_cmd},
+ {'f', "filter by pattern", 0, filter_by_patterns_cmd},
+ {'s', "select by numbers", 0, select_by_numbers_cmd},
+ {'a', "ask each", 0, ask_each_cmd},
+ {'q', "quit", 0, quit_cmd},
+ {'h', "help", 0, help_cmd},
+ };
+ int *chosen;
+
+ menu_opts.header = N_("*** Commands ***");
+ menu_opts.prompt = N_("What now");
+ menu_opts.flags = MENU_OPTS_SINGLETON;
+
+ menu_stuff.type = MENU_STUFF_TYPE_MENU_ITEM;
+ menu_stuff.stuff = menus;
+ menu_stuff.nr = sizeof(menus) / sizeof(struct menu_item);
+
+ clean_print_color(CLEAN_COLOR_HEADER);
+ printf_ln(Q_("Would remove the following item:",
+ "Would remove the following items:",
+ del_list.nr));
+ clean_print_color(CLEAN_COLOR_RESET);
+
+ pretty_print_dels();
+
+ chosen = list_and_choose(&menu_opts, &menu_stuff);
+
+ if (*chosen != EOF) {
+ int ret;
+ ret = menus[*chosen].fn();
+ if (ret != MENU_RETURN_NO_LOOP) {
+ free(chosen);
+ chosen = NULL;
+ if (!del_list.nr) {
+ clean_print_color(CLEAN_COLOR_ERROR);
+ printf_ln(_("No more files to clean, exiting."));
+ clean_print_color(CLEAN_COLOR_RESET);
+ break;
+ }
+ continue;
+ }
+ } else {
+ quit_cmd();
+ }
+
+ free(chosen);
+ chosen = NULL;
+ break;
+ }
+}
+
int cmd_clean(int argc, const char **argv, const char *prefix)
{
int i, res;
int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
- struct strbuf directory = STRBUF_INIT;
+ struct strbuf abs_path = STRBUF_INIT;
struct dir_struct dir;
- static const char **pathspec;
+ struct pathspec pathspec;
struct strbuf buf = STRBUF_INIT;
struct string_list exclude_list = STRING_LIST_INIT_NODUP;
struct exclude_list *el;
+ struct string_list_item *item;
const char *qname;
- char *seen = NULL;
struct option options[] = {
OPT__QUIET(&quiet, N_("do not print names of files removed")),
OPT__DRY_RUN(&dry_run, N_("dry run")),
OPT__FORCE(&force, N_("force")),
- OPT_BOOLEAN('d', NULL, &remove_directories,
+ OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")),
+ OPT_BOOL('d', NULL, &remove_directories,
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,
+ OPT_BOOL('x', NULL, &ignored, N_("remove ignored files, too")),
+ OPT_BOOL('X', NULL, &ignored_only,
N_("remove only ignored files")),
OPT_END()
};
@@ -186,12 +901,12 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (ignored && ignored_only)
die(_("-x and -X cannot be used together"));
- if (!dry_run && !force) {
+ if (!interactive && !dry_run && !force) {
if (config_set)
- die(_("clean.requireForce set to true and neither -n nor -f given; "
+ die(_("clean.requireForce set to true and neither -i, -n nor -f given; "
"refusing to clean"));
else
- die(_("clean.requireForce defaults to true and neither -n nor -f given; "
+ die(_("clean.requireForce defaults to true and neither -i, -n nor -f given; "
"refusing to clean"));
}
@@ -210,19 +925,19 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
for (i = 0; i < exclude_list.nr; i++)
add_exclude(exclude_list.items[i].string, "", 0, el, -(i+1));
- pathspec = get_pathspec(prefix, argv);
-
- fill_directory(&dir, pathspec);
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_CWD,
+ prefix, argv);
- if (pathspec)
- seen = xmalloc(argc > 0 ? argc : 1);
+ fill_directory(&dir, &pathspec);
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
int len, pos;
int matches = 0;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
struct stat st;
+ const char *rel;
/*
* Remove the '/' at the end that directory
@@ -242,48 +957,69 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
continue; /* Yup, this one exists unmerged */
}
+ if (lstat(ent->name, &st))
+ die_errno("Cannot lstat '%s'", ent->name);
+
+ if (pathspec.nr)
+ matches = match_pathspec_depth(&pathspec, ent->name,
+ len, 0, NULL);
+
+ if (S_ISDIR(st.st_mode)) {
+ if (remove_directories || (matches == MATCHED_EXACTLY)) {
+ rel = relative_path(ent->name, prefix, &buf);
+ string_list_append(&del_list, rel);
+ }
+ } else {
+ if (pathspec.nr && !matches)
+ continue;
+ rel = relative_path(ent->name, prefix, &buf);
+ string_list_append(&del_list, rel);
+ }
+ }
+
+ if (interactive && del_list.nr > 0)
+ interactive_main_loop();
+
+ for_each_string_list_item(item, &del_list) {
+ struct stat st;
+
+ if (prefix)
+ strbuf_addstr(&abs_path, prefix);
+
+ strbuf_addstr(&abs_path, item->string);
+
/*
* we might have removed this as part of earlier
* recursive directory removal, so lstat() here could
* fail with ENOENT.
*/
- if (lstat(ent->name, &st))
+ if (lstat(abs_path.buf, &st))
continue;
- if (pathspec) {
- memset(seen, 0, argc > 0 ? argc : 1);
- matches = match_pathspec(pathspec, ent->name, len,
- 0, seen);
- }
-
if (S_ISDIR(st.st_mode)) {
- strbuf_addstr(&directory, ent->name);
- if (remove_directories || (matches == MATCHED_EXACTLY)) {
- if (remove_dirs(&directory, prefix, rm_flags, dry_run, quiet, &gone))
- errors++;
- if (gone && !quiet) {
- qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
- printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
- }
+ if (remove_dirs(&abs_path, prefix, rm_flags, dry_run, quiet, &gone))
+ errors++;
+ if (gone && !quiet) {
+ qname = quote_path_relative(item->string, NULL, &buf);
+ printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
}
- strbuf_reset(&directory);
} else {
- if (pathspec && !matches)
- continue;
- res = dry_run ? 0 : unlink(ent->name);
+ res = dry_run ? 0 : unlink(abs_path.buf);
if (res) {
- qname = quote_path_relative(ent->name, -1, &buf, prefix);
+ qname = quote_path_relative(item->string, NULL, &buf);
warning(_(msg_warn_remove_failed), qname);
errors++;
} else if (!quiet) {
- qname = quote_path_relative(ent->name, -1, &buf, prefix);
+ qname = quote_path_relative(item->string, NULL, &buf);
printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
}
}
+ strbuf_reset(&abs_path);
}
- free(seen);
- strbuf_release(&directory);
+ strbuf_release(&abs_path);
+ strbuf_release(&buf);
+ string_list_clear(&del_list, 0);
string_list_clear(&exclude_list, 0);
return (errors != 0);
}
diff --git a/builtin/clone.c b/builtin/clone.c
index e0aaf13..ca3eb68 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -18,11 +18,11 @@
#include "transport.h"
#include "strbuf.h"
#include "dir.h"
-#include "pack-refs.h"
#include "sigchain.h"
#include "branch.h"
#include "remote.h"
#include "run-command.h"
+#include "connected.h"
/*
* Overall FIXMEs:
@@ -62,23 +62,22 @@ static struct option builtin_clone_options[] = {
OPT__VERBOSITY(&option_verbosity),
OPT_BOOL(0, "progress", &option_progress,
N_("force progress reporting")),
- OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
- N_("don't create a checkout")),
- OPT_BOOLEAN(0, "bare", &option_bare, N_("create a bare repository")),
- { OPTION_BOOLEAN, 0, "naked", &option_bare, NULL,
- N_("create a bare repository"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
- OPT_BOOLEAN(0, "mirror", &option_mirror,
- N_("create a mirror repository (implies bare)")),
+ OPT_BOOL('n', "no-checkout", &option_no_checkout,
+ N_("don't create a checkout")),
+ OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
+ OPT_HIDDEN_BOOL(0, "naked", &option_bare,
+ N_("create a bare repository")),
+ OPT_BOOL(0, "mirror", &option_mirror,
+ 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,
+ OPT_BOOL(0, "no-hardlinks", &option_no_hardlinks,
N_("don't use local hardlinks, always copy")),
- OPT_BOOLEAN('s', "shared", &option_shared,
+ OPT_BOOL('s', "shared", &option_shared,
N_("setup as shared repository")),
- OPT_BOOLEAN(0, "recursive", &option_recursive,
+ OPT_BOOL(0, "recursive", &option_recursive,
N_("initialize submodules in the clone")),
- OPT_BOOLEAN(0, "recurse-submodules", &option_recursive,
+ OPT_BOOL(0, "recurse-submodules", &option_recursive,
N_("initialize submodules in the clone")),
OPT_STRING(0, "template", &option_template, N_("template-directory"),
N_("directory from which templates will be used")),
@@ -231,16 +230,26 @@ static void strip_trailing_slashes(char *dir)
static int add_one_reference(struct string_list_item *item, void *cb_data)
{
char *ref_git;
+ const char *repo;
struct strbuf alternate = STRBUF_INIT;
- /* Beware: real_path() and mkpath() return static buffer */
+ /* Beware: read_gitfile(), real_path() and mkpath() return static buffer */
ref_git = xstrdup(real_path(item->string));
- if (is_directory(mkpath("%s/.git/objects", ref_git))) {
+
+ repo = read_gitfile(ref_git);
+ if (!repo)
+ repo = read_gitfile(mkpath("%s/.git", ref_git));
+ if (repo) {
+ free(ref_git);
+ ref_git = xstrdup(repo);
+ }
+
+ if (!repo && is_directory(mkpath("%s/.git/objects", 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)))
- die(_("reference repository '%s' is not a local directory."),
+ die(_("reference repository '%s' is not a local repository."),
item->string);
strbuf_addf(&alternate, "%s/objects", ref_git);
@@ -376,10 +385,32 @@ static void clone_local(const char *src_repo, const char *dest_repo)
static const char *junk_work_tree;
static const char *junk_git_dir;
static pid_t junk_pid;
+static enum {
+ JUNK_LEAVE_NONE,
+ JUNK_LEAVE_REPO,
+ JUNK_LEAVE_ALL
+} junk_mode = JUNK_LEAVE_NONE;
+
+static const char junk_leave_repo_msg[] =
+N_("Clone succeeded, but checkout failed.\n"
+ "You can inspect what was checked out with 'git status'\n"
+ "and retry the checkout with 'git checkout -f HEAD'\n");
static void remove_junk(void)
{
struct strbuf sb = STRBUF_INIT;
+
+ switch (junk_mode) {
+ case JUNK_LEAVE_REPO:
+ warning("%s", _(junk_leave_repo_msg));
+ /* fall-through */
+ case JUNK_LEAVE_ALL:
+ return;
+ default:
+ /* proceed to removal */
+ break;
+ }
+
if (getpid() != junk_pid)
return;
if (junk_git_dir) {
@@ -461,13 +492,16 @@ static void write_remote_refs(const struct ref *local_refs)
{
const struct ref *r;
+ lock_packed_refs(LOCK_DIE_ON_ERROR);
+
for (r = local_refs; r; r = r->next) {
if (!r->peer_ref)
continue;
add_packed_ref(r->peer_ref->name, r->old_sha1);
}
- pack_refs(PACK_REFS_ALL);
+ if (commit_packed_refs())
+ die_errno("unable to overwrite old ref-pack file");
}
static void write_followtags(const struct ref *refs, const char *msg)
@@ -485,12 +519,46 @@ static void write_followtags(const struct ref *refs, const char *msg)
}
}
+static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+{
+ struct ref **rm = cb_data;
+ struct ref *ref = *rm;
+
+ /*
+ * Skip anything missing a peer_ref, which we are not
+ * actually going to write a ref for.
+ */
+ while (ref && !ref->peer_ref)
+ ref = ref->next;
+ /* Returning -1 notes "end of list" to the caller. */
+ if (!ref)
+ return -1;
+
+ hashcpy(sha1, ref->old_sha1);
+ *rm = ref->next;
+ return 0;
+}
+
static void update_remote_refs(const struct ref *refs,
const struct ref *mapped_refs,
const struct ref *remote_head_points_at,
const char *branch_top,
- const char *msg)
+ const char *msg,
+ struct transport *transport,
+ int check_connectivity)
{
+ const struct ref *rm = mapped_refs;
+
+ if (check_connectivity) {
+ if (0 <= option_verbosity)
+ printf(_("Checking connectivity... "));
+ if (check_everything_connected_with_transport(iterate_ref_map,
+ 0, &rm, transport))
+ die(_("remote did not send all necessary objects"));
+ if (0 <= option_verbosity)
+ printf(_("done\n"));
+ }
+
if (refs) {
write_remote_refs(mapped_refs);
if (option_single_branch)
@@ -579,7 +647,8 @@ static int checkout(void)
tree = parse_tree_indirect(sha1);
parse_tree(tree);
init_tree_desc(&t, tree->buffer, tree->size);
- unpack_trees(1, &t, &opts);
+ if (unpack_trees(1, &t, &opts) < 0)
+ die(_("unable to checkout working tree"));
if (write_cache(fd, active_cache, active_nr) ||
commit_locked_index(lock_file))
@@ -634,7 +703,7 @@ static void write_refspec_config(const char* src_ref_prefix,
/*
* otherwise, the next "git fetch" will
* simply fetch from HEAD without updating
- * any remote tracking branch, which is what
+ * any remote-tracking branch, which is what
* we want.
*/
} else {
@@ -724,6 +793,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
is_local = option_local != 0 && path && !is_bundle;
if (is_local && option_depth)
warning(_("--depth is ignored in local clones; use file:// instead."));
+ if (option_local > 0 && !is_local)
+ warning(_("--local is ignored"));
if (argc == 2)
dir = xstrdup(argv[1]);
@@ -830,6 +901,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_upload_pack)
transport_set_option(transport, TRANS_OPT_UPLOADPACK,
option_upload_pack);
+
+ if (transport->smart_options && !option_depth)
+ transport->smart_options->check_self_contained_and_connected = 1;
}
refs = transport_get_remote_refs(transport);
@@ -891,19 +965,20 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
transport_fetch_refs(transport, mapped_refs);
update_remote_refs(refs, mapped_refs, remote_head_points_at,
- branch_top.buf, reflog_msg.buf);
+ branch_top.buf, reflog_msg.buf, transport, !is_local);
update_head(our_head_points_at, remote_head, reflog_msg.buf);
transport_unlock_pack(transport);
transport_disconnect(transport);
+ junk_mode = JUNK_LEAVE_REPO;
err = checkout();
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
strbuf_release(&key);
strbuf_release(&value);
- junk_pid = 0;
+ junk_mode = JUNK_LEAVE_ALL;
return err;
}
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index eac901a..f641ff2 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -10,7 +10,7 @@
#include "utf8.h"
#include "gpg-interface.h"
-static const char commit_tree_usage[] = "git commit-tree [(-p <sha1>)...] [-S<signer>] [-m <message>] [-F <file>] <sha1> <changelog";
+static const char commit_tree_usage[] = "git commit-tree [(-p <sha1>)...] [-S[<keyid>]] [-m <message>] [-F <file>] <sha1> <changelog";
static void new_parent(struct commit *parent, struct commit_list **parents_p)
{
diff --git a/builtin/commit.c b/builtin/commit.c
index d21d07a..80d886a 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -29,6 +29,7 @@
#include "gpg-interface.h"
#include "column.h"
#include "sequencer.h"
+#include "notes-utils.h"
static const char * const builtin_commit_usage[] = {
N_("git commit [options] [--] <pathspec>..."),
@@ -62,8 +63,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
"If you wish to commit it anyway, use:\n"
"\n"
" git commit --allow-empty\n"
+"\n");
+
+static const char empty_cherry_pick_advice_single[] =
+N_("Otherwise, please use 'git reset'\n");
+
+static const char empty_cherry_pick_advice_multi[] =
+N_("If you wish to skip this commit, use:\n"
+"\n"
+" git reset\n"
"\n"
-"Otherwise, please use 'git reset'\n");
+"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
+"the remaining commits.\n");
static const char *use_message_buffer;
static const char commit_editmsg[] = "COMMIT_EDITMSG";
@@ -106,24 +117,29 @@ static enum {
static const char *cleanup_arg;
static enum commit_whence whence;
+static int sequencer_in_use;
static int use_editor = 1, include_status = 1;
-static int show_ignored_in_status;
+static int show_ignored_in_status, have_option_m;
static const char *only_include_assumed;
static struct strbuf message = STRBUF_INIT;
-static enum {
+static enum status_format {
STATUS_FORMAT_NONE = 0,
STATUS_FORMAT_LONG,
STATUS_FORMAT_SHORT,
- STATUS_FORMAT_PORCELAIN
-} status_format;
+ STATUS_FORMAT_PORCELAIN,
+
+ STATUS_FORMAT_UNSPECIFIED
+} status_format = STATUS_FORMAT_UNSPECIFIED;
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
{
struct strbuf *buf = opt->value;
- if (unset)
+ if (unset) {
+ have_option_m = 0;
strbuf_setlen(buf, 0);
- else {
+ } else {
+ have_option_m = 1;
if (buf->len)
strbuf_addch(buf, '\n');
strbuf_addstr(buf, arg);
@@ -136,8 +152,11 @@ static void determine_whence(struct wt_status *s)
{
if (file_exists(git_path("MERGE_HEAD")))
whence = FROM_MERGE;
- else if (file_exists(git_path("CHERRY_PICK_HEAD")))
+ else if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
whence = FROM_CHERRY_PICK;
+ if (file_exists(git_path("sequencer")))
+ sequencer_in_use = 1;
+ }
else
whence = FROM_COMMIT;
if (s)
@@ -183,17 +202,15 @@ static int commit_index_files(void)
* and return the paths that match the given pattern in list.
*/
static int list_paths(struct string_list *list, const char *with_tree,
- const char *prefix, const char **pattern)
+ const char *prefix, const struct pathspec *pattern)
{
int i;
char *m;
- if (!pattern)
+ if (!pattern->nr)
return 0;
- for (i = 0; pattern[i]; i++)
- ;
- m = xcalloc(1, i);
+ m = xcalloc(1, pattern->nr);
if (with_tree) {
char *max_prefix = common_prefix(pattern);
@@ -202,12 +219,12 @@ static int list_paths(struct string_list *list, const char *with_tree,
}
for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
struct string_list_item *item;
if (ce->ce_flags & CE_UPDATE)
continue;
- if (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m))
+ if (!match_pathspec_depth(pattern, ce->name, ce_namelen(ce), 0, m))
continue;
item = string_list_insert(list, ce->name);
if (ce_skip_worktree(ce))
@@ -279,17 +296,17 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
{
int fd;
struct string_list partial;
- const char **pathspec = NULL;
+ struct pathspec pathspec;
char *old_index_env = NULL;
int refresh_flags = REFRESH_QUIET;
if (is_status)
refresh_flags |= REFRESH_UNMERGED;
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_FULL,
+ prefix, argv);
- if (*argv)
- pathspec = get_pathspec(prefix, argv);
-
- if (read_cache_preload(pathspec) < 0)
+ if (read_cache_preload(&pathspec) < 0)
die(_("index file corrupt"));
if (interactive) {
@@ -331,9 +348,9 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
* (A) if all goes well, commit the real index;
* (B) on failure, rollback the real index.
*/
- if (all || (also && pathspec && *pathspec)) {
+ if (all || (also && pathspec.nr)) {
fd = hold_locked_index(&index_lock, 1);
- add_files_to_cache(also ? prefix : NULL, pathspec, 0);
+ add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
refresh_cache_or_die(refresh_flags);
update_main_cache_tree(WRITE_TREE_SILENT);
if (write_cache(fd, active_cache, active_nr) ||
@@ -352,7 +369,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
* and create commit from the_index.
* We still need to refresh the index here.
*/
- if (!only && (!pathspec || !*pathspec)) {
+ if (!only && !pathspec.nr) {
fd = hold_locked_index(&index_lock, 1);
refresh_cache_or_die(refresh_flags);
if (active_cache_changed) {
@@ -397,7 +414,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
memset(&partial, 0, sizeof(partial));
partial.strdup_strings = 1;
- if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, pathspec))
+ if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec))
exit(1);
discard_cache();
@@ -457,6 +474,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(s);
break;
+ case STATUS_FORMAT_UNSPECIFIED:
+ die("BUG: finalize_deferred_config() should have been called");
+ break;
case STATUS_FORMAT_NONE:
case STATUS_FORMAT_LONG:
wt_status_print(s);
@@ -526,7 +546,6 @@ static void determine_author_info(struct strbuf *author_ident)
(lb - strlen(" ") -
(a + strlen("\nauthor "))));
email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<")));
- date = xmemdupz(rb + strlen("> "), eol - (rb + strlen("> ")));
len = eol - (rb + strlen("> "));
date = xmalloc(len + 2);
*date = '@';
@@ -702,7 +721,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
previous = eol;
}
- append_signoff(&sb, ignore_footer);
+ append_signoff(&sb, ignore_footer, 0);
}
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
@@ -803,8 +822,13 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
run_status(stdout, index_file, prefix, 0, s);
if (amend)
fputs(_(empty_amend_advice), stderr);
- else if (whence == FROM_CHERRY_PICK)
+ else if (whence == FROM_CHERRY_PICK) {
fputs(_(empty_cherry_pick_advice), stderr);
+ if (!sequencer_in_use)
+ fputs(_(empty_cherry_pick_advice_single), stderr);
+ else
+ fputs(_(empty_cherry_pick_advice_multi), stderr);
+ }
return 0;
}
@@ -955,7 +979,43 @@ static const char *read_commit_message(const char *name)
if (!commit)
die(_("could not lookup commit %s"), name);
out_enc = get_commit_output_encoding();
- return logmsg_reencode(commit, out_enc);
+ return logmsg_reencode(commit, NULL, out_enc);
+}
+
+/*
+ * Enumerate what needs to be propagated when --porcelain
+ * is not in effect here.
+ */
+static struct status_deferred_config {
+ enum status_format status_format;
+ int show_branch;
+} status_deferred_config = {
+ STATUS_FORMAT_UNSPECIFIED,
+ -1 /* unspecified */
+};
+
+static void finalize_deferred_config(struct wt_status *s)
+{
+ int use_deferred_config = (status_format != STATUS_FORMAT_PORCELAIN &&
+ !s->null_termination);
+
+ if (s->null_termination) {
+ if (status_format == STATUS_FORMAT_NONE ||
+ status_format == STATUS_FORMAT_UNSPECIFIED)
+ status_format = STATUS_FORMAT_PORCELAIN;
+ else if (status_format == STATUS_FORMAT_LONG)
+ die(_("--long and -z are incompatible"));
+ }
+
+ if (use_deferred_config && status_format == STATUS_FORMAT_UNSPECIFIED)
+ status_format = status_deferred_config.status_format;
+ if (status_format == STATUS_FORMAT_UNSPECIFIED)
+ status_format = STATUS_FORMAT_NONE;
+
+ if (use_deferred_config && s->show_branch < 0)
+ s->show_branch = status_deferred_config.show_branch;
+ if (s->show_branch < 0)
+ s->show_branch = 0;
}
static int parse_and_validate_options(int argc, const char *argv[],
@@ -968,6 +1028,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
int f = 0;
argc = parse_options(argc, argv, prefix, options, usage, 0);
+ finalize_deferred_config(s);
if (force_author && !strchr(force_author, '>'))
force_author = find_author_by_nickname(force_author);
@@ -975,7 +1036,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (force_author && renew_authorship)
die(_("Using both --reset-author and --author does not make sense"));
- if (logfile || message.len || use_message || fixup_message)
+ if (logfile || have_option_m || use_message || fixup_message)
use_editor = 0;
if (0 <= edit_flag)
use_editor = edit_flag;
@@ -1028,7 +1089,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (patch_interactive)
interactive = 1;
- if (!!also + !!only + !!all + !!interactive > 1)
+ if (also + only + all + interactive > 1)
die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
if (argc == 0 && (also || (only && !amend)))
die(_("No paths with --include/--only does not make sense."));
@@ -1052,12 +1113,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (all && argc > 0)
die(_("Paths with -a does not make sense."));
- if (s->null_termination) {
- if (status_format == STATUS_FORMAT_NONE)
- status_format = STATUS_FORMAT_PORCELAIN;
- else if (status_format == STATUS_FORMAT_LONG)
- die(_("--long and -z are incompatible"));
- }
if (status_format != STATUS_FORMAT_NONE)
dry_run = 1;
@@ -1110,6 +1165,17 @@ static int git_status_config(const char *k, const char *v, void *cb)
s->submodule_summary = -1;
return 0;
}
+ if (!strcmp(k, "status.short")) {
+ if (git_config_bool(k, v))
+ status_deferred_config.status_format = STATUS_FORMAT_SHORT;
+ else
+ status_deferred_config.status_format = STATUS_FORMAT_NONE;
+ return 0;
+ }
+ if (!strcmp(k, "status.branch")) {
+ status_deferred_config.show_branch = git_config_bool(k, v);
+ return 0;
+ }
if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
s->use_color = git_config_colorbool(k, v);
return 0;
@@ -1152,22 +1218,22 @@ int cmd_status(int argc, const char **argv, const char *prefix)
OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_SET_INT('s', "short", &status_format,
N_("show status concisely"), STATUS_FORMAT_SHORT),
- OPT_BOOLEAN('b', "branch", &s.show_branch,
- N_("show branch information")),
+ OPT_BOOL('b', "branch", &s.show_branch,
+ N_("show branch information")),
OPT_SET_INT(0, "porcelain", &status_format,
N_("machine-readable output"),
STATUS_FORMAT_PORCELAIN),
OPT_SET_INT(0, "long", &status_format,
N_("show status in long format (default)"),
STATUS_FORMAT_LONG),
- OPT_BOOLEAN('z', "null", &s.null_termination,
- N_("terminate entries with NUL")),
+ OPT_BOOL('z', "null", &s.null_termination,
+ N_("terminate entries with NUL")),
{ 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" },
- OPT_BOOLEAN(0, "ignored", &show_ignored_in_status,
- N_("show ignored files")),
+ OPT_BOOL(0, "ignored", &show_ignored_in_status,
+ 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" },
@@ -1186,22 +1252,17 @@ int cmd_status(int argc, const char **argv, const char *prefix)
builtin_status_options,
builtin_status_usage, 0);
finalize_colopts(&s.colopts, -1);
-
- if (s.null_termination) {
- if (status_format == STATUS_FORMAT_NONE)
- status_format = STATUS_FORMAT_PORCELAIN;
- else if (status_format == STATUS_FORMAT_LONG)
- die(_("--long and -z are incompatible"));
- }
+ finalize_deferred_config(&s);
handle_untracked_files_arg(&s);
if (show_ignored_in_status)
s.show_ignored_files = 1;
- if (*argv)
- s.pathspec = get_pathspec(prefix, argv);
+ parse_pathspec(&s.pathspec, 0,
+ PATHSPEC_PREFER_FULL,
+ prefix, argv);
- read_cache_preload(s.pathspec);
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
+ read_cache_preload(&s.pathspec);
+ refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);
fd = hold_locked_index(&index_lock, 0);
if (0 <= fd)
@@ -1221,6 +1282,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(&s);
break;
+ case STATUS_FORMAT_UNSPECIFIED:
+ die("BUG: finalize_deferred_config() should have been called");
+ break;
case STATUS_FORMAT_NONE:
case STATUS_FORMAT_LONG:
s.verbose = verbose;
@@ -1369,45 +1433,43 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
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_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
+ OPT_BOOL('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")),
+ OPT_BOOL(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(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_BOOL('a', "all", &all, N_("commit all changed files")),
+ OPT_BOOL('i', "include", &also, N_("add specified files to index for commit")),
+ OPT_BOOL(0, "interactive", &interactive, N_("interactively add files")),
+ OPT_BOOL('p', "patch", &patch_interactive, N_("interactively add changes")),
+ OPT_BOOL('o', "only", &only, N_("commit only specified files")),
+ OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit hook")),
+ OPT_BOOL(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, N_("show branch information")),
+ OPT_BOOL(0, "branch", &s.show_branch, N_("show branch information")),
OPT_SET_INT(0, "porcelain", &status_format,
N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
OPT_SET_INT(0, "long", &status_format,
N_("show status in long format (default)"),
STATUS_FORMAT_LONG),
- OPT_BOOLEAN('z', "null", &s.null_termination,
- N_("terminate entries with NUL")),
- OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")),
- OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
+ OPT_BOOL('z', "null", &s.null_termination,
+ N_("terminate entries with NUL")),
+ OPT_BOOL(0, "amend", &amend, N_("amend previous commit")),
+ OPT_BOOL(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,
- N_("ok to record an empty change"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
- { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
- N_("ok to record a change with an empty message"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+ OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty,
+ N_("ok to record an empty change")),
+ OPT_HIDDEN_BOOL(0, "allow-empty-message", &allow_empty_message,
+ N_("ok to record a change with an empty message")),
OPT_END()
};
@@ -1430,6 +1492,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
wt_status_prepare(&s);
gitmodules_config();
git_config(git_commit_config, &s);
+ status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
determine_whence(&s);
s.colopts = 0;
@@ -1591,7 +1654,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (cfg) {
/* we are amending, so current_head is not NULL */
copy_note_for_rewrite(cfg, current_head->object.sha1, sha1);
- finish_copy_notes_for_rewrite(cfg);
+ finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
}
run_rewrite_hook(current_head->object.sha1, sha1);
}
diff --git a/builtin/config.c b/builtin/config.c
index 33c9bf9..20e89fe 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -2,6 +2,7 @@
#include "cache.h"
#include "color.h"
#include "parse-options.h"
+#include "urlmatch.h"
static const char *const builtin_config_usage[] = {
N_("git config [options]"),
@@ -21,6 +22,7 @@ static char term = '\n';
static int use_global_config, use_system_config, use_local_config;
static const char *given_config_file;
+static const char *given_config_blob;
static int actions, types;
static const char *get_color_slot, *get_colorbool_slot;
static int end_null;
@@ -41,6 +43,7 @@ static int respect_includes = -1;
#define ACTION_SET_ALL (1<<12)
#define ACTION_GET_COLOR (1<<13)
#define ACTION_GET_COLORBOOL (1<<14)
+#define ACTION_GET_URLMATCH (1<<15)
#define TYPE_BOOL (1<<0)
#define TYPE_INT (1<<1)
@@ -49,14 +52,16 @@ static int respect_includes = -1;
static struct option builtin_config_options[] = {
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_BOOL(0, "global", &use_global_config, N_("use global config file")),
+ OPT_BOOL(0, "system", &use_system_config, N_("use system config file")),
+ OPT_BOOL(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_STRING(0, "blob", &given_config_blob, N_("blob-id"), N_("read config from given blob object")),
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, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH),
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),
@@ -73,7 +78,7 @@ static struct option builtin_config_options[] = {
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('z', "null", &end_null, N_("terminate values with NUL byte")),
OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
OPT_END(),
};
@@ -100,25 +105,13 @@ struct strbuf_list {
int alloc;
};
-static int collect_config(const char *key_, const char *value_, void *cb)
+static int format_config(struct strbuf *buf, const char *key_, const char *value_)
{
- struct strbuf_list *values = cb;
- struct strbuf *buf;
- char value[256];
- const char *vptr = value;
int must_free_vptr = 0;
int must_print_delim = 0;
+ char value[256];
+ const char *vptr = value;
- if (!use_key_regexp && strcmp(key_, key))
- return 0;
- if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
- return 0;
- if (regexp != NULL &&
- (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
- return 0;
-
- ALLOC_GROW(values->items, values->nr + 1, values->alloc);
- buf = &values->items[values->nr++];
strbuf_init(buf, 0);
if (show_keys) {
@@ -126,7 +119,8 @@ static int collect_config(const char *key_, const char *value_, void *cb)
must_print_delim = 1;
}
if (types == TYPE_INT)
- sprintf(value, "%d", git_config_int(key_, value_?value_:""));
+ sprintf(value, "%"PRId64,
+ git_config_int64(key_, value_ ? value_ : ""));
else if (types == TYPE_BOOL)
vptr = git_config_bool(key_, value_) ? "true" : "false";
else if (types == TYPE_BOOL_OR_INT) {
@@ -154,15 +148,27 @@ static int collect_config(const char *key_, const char *value_, void *cb)
strbuf_addch(buf, term);
if (must_free_vptr)
- /* If vptr must be freed, it's a pointer to a
- * dynamically allocated buffer, it's safe to cast to
- * const.
- */
free((char *)vptr);
-
return 0;
}
+static int collect_config(const char *key_, const char *value_, void *cb)
+{
+ struct strbuf_list *values = cb;
+
+ if (!use_key_regexp && strcmp(key_, key))
+ return 0;
+ if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
+ return 0;
+ if (regexp != NULL &&
+ (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
+ return 0;
+
+ ALLOC_GROW(values->items, values->nr + 1, values->alloc);
+
+ return format_config(&values->items[values->nr++], key_, value_);
+}
+
static int get_value(const char *key_, const char *regex_)
{
int ret = CONFIG_GENERIC_ERROR;
@@ -218,7 +224,8 @@ static int get_value(const char *key_, const char *regex_)
}
git_config_with_options(collect_config, &values,
- given_config_file, respect_includes);
+ given_config_file, given_config_blob,
+ respect_includes);
ret = !values.nr;
@@ -262,8 +269,8 @@ static char *normalize_value(const char *key, const char *value)
else {
normalized = xmalloc(64);
if (types == TYPE_INT) {
- int v = git_config_int(key, value);
- sprintf(normalized, "%d", v);
+ int64_t v = git_config_int64(key, value);
+ sprintf(normalized, "%"PRId64, v);
}
else if (types == TYPE_BOOL)
sprintf(normalized, "%s",
@@ -302,7 +309,8 @@ static void get_color(const char *def_color)
get_color_found = 0;
parsed_color[0] = '\0';
git_config_with_options(git_get_color_config, NULL,
- given_config_file, respect_includes);
+ given_config_file, given_config_blob,
+ respect_includes);
if (!get_color_found && def_color)
color_parse(def_color, "command line", parsed_color);
@@ -329,8 +337,10 @@ static int get_colorbool(int print)
{
get_colorbool_found = -1;
get_diff_color_found = -1;
+ get_color_ui_found = -1;
git_config_with_options(git_get_colorbool_config, NULL,
- given_config_file, respect_includes);
+ given_config_file, given_config_blob,
+ respect_includes);
if (get_colorbool_found < 0) {
if (!strcmp(get_colorbool_slot, "color.diff"))
@@ -339,6 +349,10 @@ static int get_colorbool(int print)
get_colorbool_found = get_color_ui_found;
}
+ if (get_colorbool_found < 0)
+ /* default value if none found in config */
+ get_colorbool_found = GIT_COLOR_AUTO;
+
get_colorbool_found = want_color(get_colorbool_found);
if (print) {
@@ -348,6 +362,103 @@ static int get_colorbool(int print)
return get_colorbool_found ? 0 : 1;
}
+static void check_blob_write(void)
+{
+ if (given_config_blob)
+ die("writing config blobs is not supported");
+}
+
+struct urlmatch_current_candidate_value {
+ char value_is_null;
+ struct strbuf value;
+};
+
+static int urlmatch_collect_fn(const char *var, const char *value, void *cb)
+{
+ struct string_list *values = cb;
+ struct string_list_item *item = string_list_insert(values, var);
+ struct urlmatch_current_candidate_value *matched = item->util;
+
+ if (!matched) {
+ matched = xmalloc(sizeof(*matched));
+ strbuf_init(&matched->value, 0);
+ item->util = matched;
+ } else {
+ strbuf_reset(&matched->value);
+ }
+
+ if (value) {
+ strbuf_addstr(&matched->value, value);
+ matched->value_is_null = 0;
+ } else {
+ matched->value_is_null = 1;
+ }
+ return 0;
+}
+
+static char *dup_downcase(const char *string)
+{
+ char *result;
+ size_t len, i;
+
+ len = strlen(string);
+ result = xmalloc(len + 1);
+ for (i = 0; i < len; i++)
+ result[i] = tolower(string[i]);
+ result[i] = '\0';
+ return result;
+}
+
+static int get_urlmatch(const char *var, const char *url)
+{
+ char *section_tail;
+ struct string_list_item *item;
+ struct urlmatch_config config = { STRING_LIST_INIT_DUP };
+ struct string_list values = STRING_LIST_INIT_DUP;
+
+ config.collect_fn = urlmatch_collect_fn;
+ config.cascade_fn = NULL;
+ config.cb = &values;
+
+ if (!url_normalize(url, &config.url))
+ die("%s", config.url.err);
+
+ config.section = dup_downcase(var);
+ section_tail = strchr(config.section, '.');
+ if (section_tail) {
+ *section_tail = '\0';
+ config.key = section_tail + 1;
+ show_keys = 0;
+ } else {
+ config.key = NULL;
+ show_keys = 1;
+ }
+
+ git_config_with_options(urlmatch_config_entry, &config,
+ given_config_file, NULL, respect_includes);
+
+ for_each_string_list_item(item, &values) {
+ struct urlmatch_current_candidate_value *matched = item->util;
+ struct strbuf key = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addstr(&key, item->string);
+ format_config(&buf, key.buf,
+ matched->value_is_null ? NULL : matched->value.buf);
+ fwrite(buf.buf, 1, buf.len, stdout);
+ strbuf_release(&key);
+ strbuf_release(&buf);
+
+ strbuf_release(&matched->value);
+ }
+ string_list_clear(&config.vars, 1);
+ string_list_clear(&values, 1);
+ free(config.url.url);
+
+ free((void *)config.section);
+ return 0;
+}
+
int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit = !startup_info->have_repository;
@@ -359,7 +470,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
builtin_config_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
- if (use_global_config + use_system_config + use_local_config + !!given_config_file > 1) {
+ if (use_global_config + use_system_config + use_local_config +
+ !!given_config_file + !!given_config_blob > 1) {
error("only one config file at a time.");
usage_with_options(builtin_config_usage, builtin_config_options);
}
@@ -379,8 +491,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
*/
die("$HOME not set");
- if (access_or_warn(user_config, R_OK) &&
- xdg_config && !access_or_warn(xdg_config, R_OK))
+ if (access_or_warn(user_config, R_OK, 0) &&
+ xdg_config && !access_or_warn(xdg_config, R_OK, 0))
given_config_file = xdg_config;
else
given_config_file = user_config;
@@ -438,6 +550,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_argc(argc, 0, 0);
if (git_config_with_options(show_all_config, NULL,
given_config_file,
+ given_config_blob,
respect_includes) < 0) {
if (given_config_file)
die_errno("unable to read config file '%s'",
@@ -450,6 +563,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_argc(argc, 0, 0);
if (!given_config_file && nongit)
die("not in a git directory");
+ if (given_config_blob)
+ die("editing blobs is not supported");
git_config(git_default_config, NULL);
launch_editor(given_config_file ?
given_config_file : git_path("config"),
@@ -457,6 +572,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
else if (actions == ACTION_SET) {
int ret;
+ check_blob_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
ret = git_config_set_in_file(given_config_file, argv[0], value);
@@ -466,18 +582,21 @@ int cmd_config(int argc, const char **argv, const char *prefix)
return ret;
}
else if (actions == ACTION_SET_ALL) {
+ check_blob_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
return git_config_set_multivar_in_file(given_config_file,
argv[0], value, argv[2], 0);
}
else if (actions == ACTION_ADD) {
+ check_blob_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
return git_config_set_multivar_in_file(given_config_file,
argv[0], value, "^$", 0);
}
else if (actions == ACTION_REPLACE_ALL) {
+ check_blob_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
return git_config_set_multivar_in_file(given_config_file,
@@ -499,7 +618,12 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_argc(argc, 1, 2);
return get_value(argv[0], argv[1]);
}
+ else if (actions == ACTION_GET_URLMATCH) {
+ check_argc(argc, 2, 2);
+ return get_urlmatch(argv[0], argv[1]);
+ }
else if (actions == ACTION_UNSET) {
+ check_blob_write();
check_argc(argc, 1, 2);
if (argc == 2)
return git_config_set_multivar_in_file(given_config_file,
@@ -509,12 +633,14 @@ int cmd_config(int argc, const char **argv, const char *prefix)
argv[0], NULL);
}
else if (actions == ACTION_UNSET_ALL) {
+ check_blob_write();
check_argc(argc, 1, 2);
return git_config_set_multivar_in_file(given_config_file,
argv[0], NULL, argv[1], 1);
}
else if (actions == ACTION_RENAME_SECTION) {
int ret;
+ check_blob_write();
check_argc(argc, 2, 2);
ret = git_config_rename_section_in_file(given_config_file,
argv[0], argv[1]);
@@ -525,6 +651,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
else if (actions == ACTION_REMOVE_SECTION) {
int ret;
+ check_blob_write();
check_argc(argc, 1, 1);
ret = git_config_rename_section_in_file(given_config_file,
argv[0], NULL);
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 9afaa88..a7f70cb 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -9,11 +9,22 @@
#include "builtin.h"
#include "parse-options.h"
+static unsigned long garbage;
+static off_t size_garbage;
+
+static void real_report_garbage(const char *desc, const char *path)
+{
+ struct stat st;
+ if (!stat(path, &st))
+ size_garbage += st.st_size;
+ warning("%s: %s", desc, path);
+ garbage++;
+}
+
static void count_objects(DIR *d, char *path, int len, int verbose,
unsigned long *loose,
off_t *loose_size,
- unsigned long *packed_loose,
- unsigned long *garbage)
+ unsigned long *packed_loose)
{
struct dirent *ent;
while ((ent = readdir(d)) != NULL) {
@@ -46,9 +57,11 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
}
if (bad) {
if (verbose) {
- error("garbage found: %.*s/%s",
- len + 2, path, ent->d_name);
- (*garbage)++;
+ struct strbuf sb = STRBUF_INIT;
+ strbuf_addf(&sb, "%.*s/%s",
+ len + 2, path, ent->d_name);
+ report_garbage("garbage found", sb.buf);
+ strbuf_release(&sb);
}
continue;
}
@@ -66,20 +79,22 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
}
static char const * const count_objects_usage[] = {
- N_("git count-objects [-v]"),
+ N_("git count-objects [-v] [-H | --human-readable]"),
NULL
};
int cmd_count_objects(int argc, const char **argv, const char *prefix)
{
- int i, verbose = 0;
+ int i, verbose = 0, human_readable = 0;
const char *objdir = get_object_directory();
int len = strlen(objdir);
char *path = xmalloc(len + 50);
- unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
+ unsigned long loose = 0, packed = 0, packed_loose = 0;
off_t loose_size = 0;
struct option opts[] = {
OPT__VERBOSE(&verbose, N_("be verbose")),
+ OPT_BOOL('H', "human-readable", &human_readable,
+ N_("print sizes in human readable format")),
OPT_END(),
};
@@ -87,6 +102,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
/* we do not take arguments other than flags for now */
if (argc)
usage_with_options(count_objects_usage, opts);
+ if (verbose)
+ report_garbage = real_report_garbage;
memcpy(path, objdir, len);
if (len && objdir[len-1] != '/')
path[len++] = '/';
@@ -97,13 +114,16 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
if (!d)
continue;
count_objects(d, path, len, verbose,
- &loose, &loose_size, &packed_loose, &garbage);
+ &loose, &loose_size, &packed_loose);
closedir(d);
}
if (verbose) {
struct packed_git *p;
unsigned long num_pack = 0;
off_t size_pack = 0;
+ struct strbuf loose_buf = STRBUF_INIT;
+ struct strbuf pack_buf = STRBUF_INIT;
+ struct strbuf garbage_buf = STRBUF_INIT;
if (!packed_git)
prepare_packed_git();
for (p = packed_git; p; p = p->next) {
@@ -115,16 +135,40 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
size_pack += p->pack_size + p->index_size;
num_pack++;
}
+
+ if (human_readable) {
+ strbuf_humanise_bytes(&loose_buf, loose_size);
+ strbuf_humanise_bytes(&pack_buf, size_pack);
+ strbuf_humanise_bytes(&garbage_buf, size_garbage);
+ } else {
+ strbuf_addf(&loose_buf, "%lu",
+ (unsigned long)(loose_size / 1024));
+ strbuf_addf(&pack_buf, "%lu",
+ (unsigned long)(size_pack / 1024));
+ strbuf_addf(&garbage_buf, "%lu",
+ (unsigned long)(size_garbage / 1024));
+ }
+
printf("count: %lu\n", loose);
- printf("size: %lu\n", (unsigned long) (loose_size / 1024));
+ printf("size: %s\n", loose_buf.buf);
printf("in-pack: %lu\n", packed);
printf("packs: %lu\n", num_pack);
- printf("size-pack: %lu\n", (unsigned long) (size_pack / 1024));
+ printf("size-pack: %s\n", pack_buf.buf);
printf("prune-packable: %lu\n", packed_loose);
printf("garbage: %lu\n", garbage);
+ printf("size-garbage: %s\n", garbage_buf.buf);
+ strbuf_release(&loose_buf);
+ strbuf_release(&pack_buf);
+ strbuf_release(&garbage_buf);
+ } else {
+ struct strbuf buf = STRBUF_INIT;
+ if (human_readable)
+ strbuf_humanise_bytes(&buf, loose_size);
+ else
+ strbuf_addf(&buf, "%lu kilobytes",
+ (unsigned long)(loose_size / 1024));
+ printf("%lu objects, %s\n", loose, buf.buf);
+ strbuf_release(&buf);
}
- else
- printf("%lu objects, %lu kilobytes\n",
- loose, (unsigned long) (loose_size / 1024));
return 0;
}
diff --git a/builtin/describe.c b/builtin/describe.c
index 6636a68..c94e5c3 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -7,6 +7,7 @@
#include "parse-options.h"
#include "diff.h"
#include "hash.h"
+#include "argv-array.h"
#define SEEN (1u<<0)
#define MAX_TAGS (FLAG_BITS - 1)
@@ -21,6 +22,7 @@ static int debug; /* Display lots of verbose info */
static int all; /* Any valid ref can be used */
static int tags; /* Allow lightweight tags */
static int longformat;
+static int first_parent;
static int abbrev = -1; /* unspecified */
static int max_candidates = 10;
static struct hash_table names;
@@ -42,7 +44,7 @@ struct commit_name {
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
unsigned name_checked:1;
unsigned char sha1[20];
- const char *path;
+ char *path;
};
static const char *prio_names[] = {
"head", "lightweight", "annotated",
@@ -126,12 +128,14 @@ static void add_to_known_names(const char *path,
} else {
e->next = NULL;
}
+ e->path = NULL;
}
e->tag = tag;
e->prio = prio;
e->name_checked = 0;
hashcpy(e->sha1, sha1);
- e->path = path;
+ free(e->path);
+ e->path = xstrdup(path);
}
}
@@ -336,6 +340,9 @@ static void describe(const char *arg, int last_one)
commit_list_insert_by_date(p, &list);
p->object.flags |= c->object.flags;
parents = parents->next;
+
+ if (first_parent)
+ break;
}
}
@@ -399,11 +406,12 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
{
int contains = 0;
struct option options[] = {
- 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")),
- OPT_BOOLEAN(0, "tags", &tags, N_("use any tag, even unannotated")),
- OPT_BOOLEAN(0, "long", &longformat, N_("always use long format")),
+ OPT_BOOL(0, "contains", &contains, N_("find the tag that comes after the commit")),
+ OPT_BOOL(0, "debug", &debug, N_("debug search strategy on stderr")),
+ OPT_BOOL(0, "all", &all, N_("use any ref")),
+ OPT_BOOL(0, "tags", &tags, N_("use any tag, even unannotated")),
+ OPT_BOOL(0, "long", &longformat, N_("always use long format")),
+ OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
OPT__ABBREV(&abbrev),
OPT_SET_INT(0, "exact-match", &max_candidates,
N_("only output exact matches"), 0),
@@ -411,11 +419,11 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
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,
- N_("show abbreviated commit object as fallback")),
+ OPT_BOOL(0, "always", &always,
+ 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"},
+ N_("append <mark> on dirty working tree (default: \"-dirty\")"),
+ PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
OPT_END(),
};
@@ -435,24 +443,24 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
die(_("--long is incompatible with --abbrev=0"));
if (contains) {
- const char **args = xmalloc((7 + argc) * sizeof(char *));
- int i = 0;
- args[i++] = "name-rev";
- args[i++] = "--name-only";
- args[i++] = "--no-undefined";
+ struct argv_array args;
+
+ argv_array_init(&args);
+ argv_array_pushl(&args, "name-rev",
+ "--peel-tag", "--name-only", "--no-undefined",
+ NULL);
if (always)
- args[i++] = "--always";
+ argv_array_push(&args, "--always");
if (!all) {
- args[i++] = "--tags";
- if (pattern) {
- char *s = xmalloc(strlen("--refs=refs/tags/") + strlen(pattern) + 1);
- sprintf(s, "--refs=refs/tags/%s", pattern);
- args[i++] = s;
- }
+ argv_array_push(&args, "--tags");
+ if (pattern)
+ argv_array_pushf(&args, "--refs=refs/tags/%s", pattern);
+ }
+ while (*argv) {
+ argv_array_push(&args, *argv);
+ argv++;
}
- memcpy(args + i, argv, argc * sizeof(char *));
- args[i + argc] = NULL;
- return cmd_name_rev(i + argc, args, prefix);
+ return cmd_name_rev(args.argc, args.argv, prefix);
}
init_hash(&names);
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 46085f8..9200069 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -61,7 +61,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
(rev.diffopt.output_format & DIFF_FORMAT_PATCH))
rev.combine_merges = rev.dense_combined_merges = 1;
- if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {
+ if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
perror("read_cache_preload");
return -1;
}
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 1c737f7..ce15b23 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -43,7 +43,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
usage(diff_cache_usage);
if (!cached) {
setup_work_tree();
- if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {
+ if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
perror("read_cache_preload");
return -1;
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 8c2af6c..2fb8c5d 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -140,7 +140,7 @@ static int builtin_diff_index(struct rev_info *revs,
usage(builtin_diff_usage);
if (!cached) {
setup_work_tree();
- if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
+ if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
perror("read_cache_preload");
return -1;
}
@@ -153,7 +153,8 @@ static int builtin_diff_index(struct rev_info *revs,
static int builtin_diff_tree(struct rev_info *revs,
int argc, const char **argv,
- struct object_array_entry *ent)
+ struct object_array_entry *ent0,
+ struct object_array_entry *ent1)
{
const unsigned char *(sha1[2]);
int swap = 0;
@@ -161,13 +162,14 @@ static int builtin_diff_tree(struct rev_info *revs,
if (argc > 1)
usage(builtin_diff_usage);
- /* We saw two trees, ent[0] and ent[1].
- * if ent[1] is uninteresting, they are swapped
+ /*
+ * We saw two trees, ent0 and ent1. If ent1 is uninteresting,
+ * swap them.
*/
- if (ent[1].item->flags & UNINTERESTING)
+ if (ent1->item->flags & UNINTERESTING)
swap = 1;
- sha1[swap] = ent[0].item->sha1;
- sha1[1-swap] = ent[1].item->sha1;
+ sha1[swap] = ent0->item->sha1;
+ sha1[1-swap] = ent1->item->sha1;
diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt);
log_tree_diff_flush(revs);
return 0;
@@ -240,7 +242,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
revs->combine_merges = revs->dense_combined_merges = 1;
setup_work_tree();
- if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
+ if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
perror("read_cache_preload");
return -1;
}
@@ -251,8 +253,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
{
int i;
struct rev_info rev;
- struct object_array_entry ent[100];
- int ents = 0, blobs = 0, paths = 0;
+ struct object_array ent = OBJECT_ARRAY_INIT;
+ int blobs = 0, paths = 0;
const char *path = NULL;
struct blobinfo blob[2];
int nongit;
@@ -337,9 +339,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
}
for (i = 0; i < rev.pending.nr; i++) {
- struct object_array_entry *list = rev.pending.objects+i;
- struct object *obj = list->item;
- const char *name = list->name;
+ struct object_array_entry *entry = &rev.pending.objects[i];
+ struct object *obj = entry->item;
+ const char *name = entry->name;
int flags = (obj->flags & UNINTERESTING);
if (!obj->parsed)
obj = parse_object(obj->sha1);
@@ -348,29 +350,25 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
die(_("invalid object '%s' given."), name);
if (obj->type == OBJ_COMMIT)
obj = &((struct commit *)obj)->tree->object;
+
if (obj->type == OBJ_TREE) {
- if (ARRAY_SIZE(ent) <= ents)
- die(_("more than %d trees given: '%s'"),
- (int) ARRAY_SIZE(ent), name);
obj->flags |= flags;
- ent[ents].item = obj;
- ent[ents].name = name;
- ents++;
- continue;
- }
- if (obj->type == OBJ_BLOB) {
+ add_object_array(obj, name, &ent);
+ } else if (obj->type == OBJ_BLOB) {
if (2 <= blobs)
die(_("more than two blobs given: '%s'"), name);
hashcpy(blob[blobs].sha1, obj->sha1);
blob[blobs].name = name;
- blob[blobs].mode = list->mode;
+ blob[blobs].mode = entry->mode;
blobs++;
- continue;
+ } else {
+ die(_("unhandled object '%s' given."), name);
}
- die(_("unhandled object '%s' given."), name);
}
if (rev.prune_data.nr) {
+ /* builtin_diff_b_f() */
+ GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
if (!path)
path = rev.prune_data.items[0].match;
paths += rev.prune_data.nr;
@@ -379,7 +377,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
/*
* Now, do the arguments look reasonable?
*/
- if (!ents) {
+ if (!ent.nr) {
switch (blobs) {
case 0:
result = builtin_diff_files(&rev, argc, argv);
@@ -400,23 +398,26 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
}
else if (blobs)
usage(builtin_diff_usage);
- else if (ents == 1)
+ else if (ent.nr == 1)
result = builtin_diff_index(&rev, argc, argv);
- else if (ents == 2)
- result = builtin_diff_tree(&rev, argc, argv, ent);
- else if (ent[0].item->flags & UNINTERESTING) {
+ else if (ent.nr == 2)
+ result = builtin_diff_tree(&rev, argc, argv,
+ &ent.objects[0], &ent.objects[1]);
+ else if (ent.objects[0].item->flags & UNINTERESTING) {
/*
* diff A...B where there is at least one merge base
- * between A and B. We have ent[0] == merge-base,
- * ent[ents-2] == A, and ent[ents-1] == B. Show diff
- * between the base and B. Note that we pick one
- * merge base at random if there are more than one.
+ * between A and B. We have ent.objects[0] ==
+ * merge-base, ent.objects[ents-2] == A, and
+ * ent.objects[ents-1] == B. Show diff between the
+ * base and B. Note that we pick one merge base at
+ * random if there are more than one.
*/
- ent[1] = ent[ents-1];
- result = builtin_diff_tree(&rev, argc, argv, ent);
+ result = builtin_diff_tree(&rev, argc, argv,
+ &ent.objects[0],
+ &ent.objects[ent.nr-1]);
} else
result = builtin_diff_combined(&rev, argc, argv,
- ent, ents);
+ ent.objects, ent.nr);
result = diff_result_code(&rev.diffopt, result);
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index ad9d0c4..b1b9b5e 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -24,7 +24,7 @@ static const char *fast_export_usage[] = {
};
static int progress;
-static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT;
+static enum { ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = ABORT;
static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ERROR;
static int fake_missing_tagger;
static int use_done_feature;
@@ -40,6 +40,8 @@ static int parse_opt_signed_tag_mode(const struct option *opt,
signed_tag_mode = VERBATIM;
else if (!strcmp(arg, "warn"))
signed_tag_mode = WARN;
+ else if (!strcmp(arg, "warn-strip"))
+ signed_tag_mode = WARN_STRIP;
else if (!strcmp(arg, "strip"))
signed_tag_mode = STRIP;
else
@@ -113,12 +115,13 @@ static void show_progress(void)
printf("progress %d objects\n", counter);
}
-static void handle_object(const unsigned char *sha1)
+static void export_blob(const unsigned char *sha1)
{
unsigned long size;
enum object_type type;
char *buf;
struct object *object;
+ int eaten;
if (no_data)
return;
@@ -126,16 +129,18 @@ static void handle_object(const unsigned char *sha1)
if (is_null_sha1(sha1))
return;
- object = parse_object(sha1);
- if (!object)
- die ("Could not read blob %s", sha1_to_hex(sha1));
-
- if (object->flags & SHOWN)
+ object = lookup_object(sha1);
+ if (object && object->flags & SHOWN)
return;
buf = read_sha1_file(sha1, &type, &size);
if (!buf)
die ("Could not read blob %s", sha1_to_hex(sha1));
+ if (check_sha1_signature(sha1, buf, size, typename(type)) < 0)
+ die("sha1 mismatch in blob %s", sha1_to_hex(sha1));
+ object = parse_object_buffer(sha1, type, size, buf, &eaten);
+ if (!object)
+ die("Could not read blob %s", sha1_to_hex(sha1));
mark_next_object(object);
@@ -147,7 +152,8 @@ static void handle_object(const unsigned char *sha1)
show_progress();
object->flags |= SHOWN;
- free(buf);
+ if (!eaten)
+ free(buf);
}
static int depth_first(const void *a_, const void *b_)
@@ -312,7 +318,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
/* Export the referenced blobs, and remember the marks. */
for (i = 0; i < diff_queued_diff.nr; i++)
if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
- handle_object(diff_queued_diff.queue[i]->two->sha1);
+ export_blob(diff_queued_diff.queue[i]->two->sha1);
mark_next_object(&commit->object);
if (!is_encoding_utf8(encoding))
@@ -373,7 +379,7 @@ static void handle_tag(const char *name, struct tag *tag)
int tagged_mark;
struct commit *p;
- /* Trees have no identifer in fast-export output, thus we have no way
+ /* Trees have no identifier in fast-export output, thus we have no way
* to output tags of trees, tags of tags of trees, etc. Simply omit
* such tags.
*/
@@ -424,6 +430,10 @@ static void handle_tag(const char *name, struct tag *tag)
/* fallthru */
case VERBATIM:
break;
+ case WARN_STRIP:
+ warning ("Stripping signature from tag %s",
+ sha1_to_hex(tag->object.sha1));
+ /* fallthru */
case STRIP:
message_size = signature + 1 - message;
break;
@@ -512,7 +522,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info,
commit = (struct commit *)tag;
break;
case OBJ_BLOB:
- handle_object(tag->object.sha1);
+ export_blob(tag->object.sha1);
continue;
default: /* OBJ_TAG (nested tags) is already handled */
warning("Tag points to object of unexpected type %s, skipping.",
@@ -603,6 +613,8 @@ static void import_marks(char *input_file)
char *line_end, *mark_end;
unsigned char sha1[20];
struct object *object;
+ struct commit *commit;
+ enum object_type type;
line_end = strchr(line, '\n');
if (line[0] != ':' || !line_end)
@@ -611,23 +623,30 @@ static void import_marks(char *input_file)
mark = strtoumax(line + 1, &mark_end, 10);
if (!mark || mark_end == line + 1
- || *mark_end != ' ' || get_sha1(mark_end + 1, sha1))
+ || *mark_end != ' ' || get_sha1_hex(mark_end + 1, sha1))
die("corrupt mark line: %s", line);
- object = parse_object(sha1);
- if (!object)
- die ("Could not read blob %s", sha1_to_hex(sha1));
+ if (last_idnum < mark)
+ last_idnum = mark;
- if (object->flags & SHOWN)
- error("Object %s already has a mark", sha1_to_hex(sha1));
+ type = sha1_object_info(sha1, NULL);
+ if (type < 0)
+ die("object not found: %s", sha1_to_hex(sha1));
- if (object->type != OBJ_COMMIT)
+ if (type != OBJ_COMMIT)
/* only commits */
continue;
+ commit = lookup_commit(sha1);
+ if (!commit)
+ die("not a commit? can't happen: %s", sha1_to_hex(sha1));
+
+ object = &commit->object;
+
+ if (object->flags & SHOWN)
+ error("Object %s already has a mark", sha1_to_hex(sha1));
+
mark_object(object, mark);
- if (last_idnum < mark)
- last_idnum = mark;
object->flags |= SHOWN;
}
@@ -641,6 +660,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
struct string_list extra_refs = STRING_LIST_INIT_NODUP;
struct commit *commit;
char *export_filename = NULL, *import_filename = NULL;
+ uint32_t lastimportid;
struct option options[] = {
OPT_INTEGER(0, "progress", &progress,
N_("show progress after <n> objects")),
@@ -654,11 +674,11 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
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,
- N_("Fake a tagger when tags lack one")),
- OPT_BOOLEAN(0, "full-tree", &full_tree,
- N_("Output full tree for each commit")),
- OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
+ OPT_BOOL(0, "fake-missing-tagger", &fake_missing_tagger,
+ N_("Fake a tagger when tags lack one")),
+ OPT_BOOL(0, "full-tree", &full_tree,
+ N_("Output full tree for each commit")),
+ OPT_BOOL(0, "use-done-feature", &use_done_feature,
N_("Use the done feature to terminate the stream")),
OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
OPT_END()
@@ -684,6 +704,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (import_filename)
import_marks(import_filename);
+ lastimportid = last_idnum;
if (import_filename && revs.prune_data.nr)
full_tree = 1;
@@ -706,7 +727,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
handle_tags_and_duplicates(&extra_refs);
- if (export_filename)
+ if (export_filename && lastimportid != last_idnum)
export_marks(export_filename);
if (use_done_feature)
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 940ae35..c8e8582 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -1,18 +1,39 @@
#include "builtin.h"
#include "pkt-line.h"
#include "fetch-pack.h"
+#include "remote.h"
+#include "connect.h"
static const char fetch_pack_usage[] =
"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
+static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
+ const char *name, int namelen)
+{
+ struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);
+
+ memcpy(ref->name, name, namelen);
+ ref->name[namelen] = '\0';
+ (*nr)++;
+ ALLOC_GROW(*sought, *nr, *alloc);
+ (*sought)[*nr - 1] = ref;
+}
+
+static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
+ const char *string)
+{
+ add_sought_entry_mem(sought, nr, alloc, string, strlen(string));
+}
+
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
{
int i, ret;
struct ref *ref = NULL;
const char *dest = NULL;
- struct string_list sought = STRING_LIST_INIT_DUP;
+ struct ref **sought = NULL;
+ int nr_sought = 0, alloc_sought = 0;
int fd[2];
char *pack_lockfile = NULL;
char **pack_lockfile_ptr = NULL;
@@ -81,6 +102,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
pack_lockfile_ptr = &pack_lockfile;
continue;
}
+ if (!strcmp("--check-self-contained-and-connected", arg)) {
+ args.check_self_contained_and_connected = 1;
+ continue;
+ }
usage(fetch_pack_usage);
}
@@ -94,27 +119,24 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
* refs from the standard input:
*/
for (; i < argc; i++)
- string_list_append(&sought, xstrdup(argv[i]));
+ add_sought_entry(&sought, &nr_sought, &alloc_sought, argv[i]);
if (args.stdin_refs) {
if (args.stateless_rpc) {
/* in stateless RPC mode we use pkt-line to read
* from stdin, until we get a flush packet
*/
- static char line[1000];
for (;;) {
- int n = packet_read_line(0, line, sizeof(line));
- if (!n)
+ char *line = packet_read_line(0, NULL);
+ if (!line)
break;
- if (line[n-1] == '\n')
- n--;
- string_list_append(&sought, xmemdupz(line, n));
+ add_sought_entry(&sought, &nr_sought, &alloc_sought, line);
}
}
else {
/* read from stdin one ref per line, until EOF */
struct strbuf line = STRBUF_INIT;
while (strbuf_getline(&line, stdin, '\n') != EOF)
- string_list_append(&sought, strbuf_detach(&line, NULL));
+ add_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf);
strbuf_release(&line);
}
}
@@ -128,20 +150,25 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.verbose ? CONNECT_VERBOSE : 0);
}
- get_remote_heads(fd[0], &ref, 0, NULL);
+ get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL);
ref = fetch_pack(&args, fd, conn, ref, dest,
- &sought, pack_lockfile_ptr);
+ sought, nr_sought, pack_lockfile_ptr);
if (pack_lockfile) {
printf("lock %s\n", pack_lockfile);
fflush(stdout);
}
+ if (args.check_self_contained_and_connected &&
+ args.self_contained_and_connected) {
+ printf("connectivity-ok\n");
+ fflush(stdout);
+ }
close(fd[0]);
close(fd[1]);
if (finish_connect(conn))
return 1;
- ret = !ref || sought.nr;
+ ret = !ref;
/*
* If the heads to pull were given, we should have consumed
@@ -149,8 +176,13 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
* 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);
+ for (i = 0; i < nr_sought; i++) {
+ if (!sought[i] || sought[i]->matched)
+ continue;
+ error("no such remote ref %s", sought[i]->name);
+ ret = 1;
+ }
+
while (ref) {
printf("%s %s\n",
sha1_to_hex(ref->old_sha1), ref->name);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 4b6b1df..9e654ef 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -30,13 +30,18 @@ enum {
TAGS_SET = 2
};
-static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
+static int fetch_prune_config = -1; /* unspecified */
+static int prune = -1; /* unspecified */
+#define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
+
+static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int tags = TAGS_DEFAULT, unshallow;
static const char *depth;
static const char *upload_pack;
static struct strbuf default_rla = STRBUF_INIT;
-static struct transport *transport;
+static struct transport *gtransport;
+static struct transport *gsecondary;
static const char *submodule_prefix = "";
static const char *recurse_submodules_default;
@@ -54,30 +59,39 @@ static int option_parse_recurse_submodules(const struct option *opt,
return 0;
}
+static int git_fetch_config(const char *k, const char *v, void *cb)
+{
+ if (!strcmp(k, "fetch.prune")) {
+ fetch_prune_config = git_config_bool(k, v);
+ return 0;
+ }
+ return 0;
+}
+
static struct option builtin_fetch_options[] = {
OPT__VERBOSITY(&verbosity),
- OPT_BOOLEAN(0, "all", &all,
- N_("fetch from all remotes")),
- OPT_BOOLEAN('a', "append", &append,
- N_("append to .git/FETCH_HEAD instead of overwriting")),
+ OPT_BOOL(0, "all", &all,
+ N_("fetch from all remotes")),
+ OPT_BOOL('a', "append", &append,
+ 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,
- N_("fetch from multiple remotes")),
+ OPT_BOOL('m', "multiple", &multiple,
+ N_("fetch from multiple remotes")),
OPT_SET_INT('t', "tags", &tags,
N_("fetch all tags and associated objects"), TAGS_SET),
OPT_SET_INT('n', NULL, &tags,
N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
- OPT_BOOLEAN('p', "prune", &prune,
- N_("prune remote-tracking branches no longer on remote")),
+ OPT_BOOL('p', "prune", &prune,
+ 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,
- N_("dry run")),
- OPT_BOOLEAN('k', "keep", &keep, N_("keep downloaded pack")),
- OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
+ OPT_BOOL(0, "dry-run", &dry_run,
+ N_("dry run")),
+ OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
+ OPT_BOOL('u', "update-head-ok", &update_head_ok,
N_("allow updating of HEAD ref")),
OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
OPT_STRING(0, "depth", &depth, N_("depth"),
@@ -95,8 +109,10 @@ static struct option builtin_fetch_options[] = {
static void unlock_pack(void)
{
- if (transport)
- transport_unlock_pack(transport);
+ if (gtransport)
+ transport_unlock_pack(gtransport);
+ if (gsecondary)
+ transport_unlock_pack(gsecondary);
}
static void unlock_pack_on_signal(int signo)
@@ -119,7 +135,7 @@ static void add_merge_config(struct ref **head,
for (rm = *head; rm; rm = rm->next) {
if (branch_merge_matches(branch, i, rm->name)) {
- rm->merge = 1;
+ rm->fetch_head_status = FETCH_HEAD_MERGE;
break;
}
}
@@ -140,7 +156,7 @@ static void add_merge_config(struct ref **head,
refspec.src = branch->merge[i]->src;
get_fetch_map(remote_refs, &refspec, tail, 1);
for (rm = *old_tail; rm; rm = rm->next)
- rm->merge = 1;
+ rm->fetch_head_status = FETCH_HEAD_MERGE;
}
}
@@ -160,6 +176,8 @@ static struct ref *get_ref_map(struct transport *transport,
const struct ref *remote_refs = transport_get_remote_refs(transport);
if (ref_count || tags == TAGS_SET) {
+ struct ref **old_tail;
+
for (i = 0; i < ref_count; i++) {
get_fetch_map(remote_refs, &refs[i], &tail, 0);
if (refs[i].dst && refs[i].dst[0])
@@ -167,9 +185,23 @@ static struct ref *get_ref_map(struct transport *transport,
}
/* Merge everything on the command line, but not --tags */
for (rm = ref_map; rm; rm = rm->next)
- rm->merge = 1;
+ rm->fetch_head_status = FETCH_HEAD_MERGE;
if (tags == TAGS_SET)
get_fetch_map(remote_refs, tag_refspec, &tail, 0);
+
+ /*
+ * For any refs that we happen to be fetching via command-line
+ * arguments, take the opportunity to update their configured
+ * counterparts. However, we do not want to mention these
+ * entries in FETCH_HEAD at all, as they would simply be
+ * duplicates of existing entries.
+ */
+ old_tail = tail;
+ for (i = 0; i < transport->remote->fetch_refspec_nr; i++)
+ get_fetch_map(ref_map, &transport->remote->fetch[i],
+ &tail, 1);
+ for (rm = *old_tail; rm; rm = rm->next)
+ rm->fetch_head_status = FETCH_HEAD_IGNORE;
} else {
/* Use the defaults */
struct remote *remote = transport->remote;
@@ -186,7 +218,7 @@ static struct ref *get_ref_map(struct transport *transport,
*autotags = 1;
if (!i && !has_merge && ref_map &&
!remote->fetch[0].pattern)
- ref_map->merge = 1;
+ ref_map->fetch_head_status = FETCH_HEAD_MERGE;
}
/*
* if the remote we're fetching from is the same
@@ -202,7 +234,7 @@ static struct ref *get_ref_map(struct transport *transport,
ref_map = get_remote_ref(remote_refs, "HEAD");
if (!ref_map)
die(_("Couldn't find remote ref HEAD"));
- ref_map->merge = 1;
+ ref_map->fetch_head_status = FETCH_HEAD_MERGE;
tail = &ref_map->next;
}
}
@@ -389,7 +421,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
const char *what, *kind;
struct ref *rm;
char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
- int want_merge;
+ int want_status;
fp = fopen(filename, "a");
if (!fp)
@@ -407,19 +439,22 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
}
/*
- * The first pass writes objects to be merged and then the
- * second pass writes the rest, in order to allow using
- * FETCH_HEAD as a refname to refer to the ref to be merged.
+ * We do a pass for each fetch_head_status type in their enum order, so
+ * merged entries are written before not-for-merge. That lets readers
+ * use FETCH_HEAD as a refname to refer to the ref to be merged.
*/
- for (want_merge = 1; 0 <= want_merge; want_merge--) {
+ for (want_status = FETCH_HEAD_MERGE;
+ want_status <= FETCH_HEAD_IGNORE;
+ want_status++) {
for (rm = ref_map; rm; rm = rm->next) {
struct ref *ref = NULL;
+ const char *merge_status_marker = "";
commit = lookup_commit_reference_gently(rm->old_sha1, 1);
if (!commit)
- rm->merge = 0;
+ rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
- if (rm->merge != want_merge)
+ if (rm->fetch_head_status != want_status)
continue;
if (rm->peer_ref) {
@@ -465,16 +500,26 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
strbuf_addf(&note, "%s ", kind);
strbuf_addf(&note, "'%s' of ", what);
}
- fprintf(fp, "%s\t%s\t%s",
- sha1_to_hex(rm->old_sha1),
- rm->merge ? "" : "not-for-merge",
- note.buf);
- for (i = 0; i < url_len; ++i)
- if ('\n' == url[i])
- fputs("\\n", fp);
- else
- fputc(url[i], fp);
- fputc('\n', fp);
+ switch (rm->fetch_head_status) {
+ case FETCH_HEAD_NOT_FOR_MERGE:
+ merge_status_marker = "not-for-merge";
+ /* fall-through */
+ case FETCH_HEAD_MERGE:
+ fprintf(fp, "%s\t%s\t%s",
+ sha1_to_hex(rm->old_sha1),
+ merge_status_marker,
+ note.buf);
+ for (i = 0; i < url_len; ++i)
+ if ('\n' == url[i])
+ fputs("\\n", fp);
+ else
+ fputc(url[i], fp);
+ fputc('\n', fp);
+ break;
+ default:
+ /* do not write anything to FETCH_HEAD */
+ break;
+ }
strbuf_reset(&note);
if (ref) {
@@ -571,7 +616,8 @@ static int add_existing(const char *refname, const unsigned char *sha1,
{
struct string_list *list = (struct string_list *)cbdata;
struct string_list_item *item = string_list_insert(list, refname);
- item->util = (void *)sha1;
+ item->util = xmalloc(20);
+ hashcpy(item->util, sha1);
return 0;
}
@@ -590,7 +636,7 @@ static void find_non_local_tags(struct transport *transport,
struct ref **head,
struct ref ***tail)
{
- struct string_list existing_refs = STRING_LIST_INIT_NODUP;
+ struct string_list existing_refs = STRING_LIST_INIT_DUP;
struct string_list remote_refs = STRING_LIST_INIT_NODUP;
const struct ref *ref;
struct string_list_item *item = NULL;
@@ -636,7 +682,7 @@ static void find_non_local_tags(struct transport *transport,
item = string_list_insert(&remote_refs, ref->name);
item->util = (void *)ref->old_sha1;
}
- string_list_clear(&existing_refs, 0);
+ string_list_clear(&existing_refs, 1);
/*
* We may have a final lightweight tag that needs to be
@@ -690,14 +736,56 @@ static int truncate_fetch_head(void)
return 0;
}
+static void set_option(struct transport *transport, const char *name, const char *value)
+{
+ int r = transport_set_option(transport, name, value);
+ if (r < 0)
+ die(_("Option \"%s\" value \"%s\" is not valid for %s"),
+ name, value, transport->url);
+ if (r > 0)
+ warning(_("Option \"%s\" is ignored for %s\n"),
+ name, transport->url);
+}
+
+static struct transport *prepare_transport(struct remote *remote)
+{
+ struct transport *transport;
+ transport = transport_get(remote, NULL);
+ transport_set_verbosity(transport, verbosity, progress);
+ if (upload_pack)
+ set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack);
+ if (keep)
+ set_option(transport, TRANS_OPT_KEEP, "yes");
+ if (depth)
+ set_option(transport, TRANS_OPT_DEPTH, depth);
+ return transport;
+}
+
+static void backfill_tags(struct transport *transport, struct ref *ref_map)
+{
+ if (transport->cannot_reuse) {
+ gsecondary = prepare_transport(transport->remote);
+ transport = gsecondary;
+ }
+
+ transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
+ transport_set_option(transport, TRANS_OPT_DEPTH, "0");
+ fetch_refs(transport, ref_map);
+
+ if (gsecondary) {
+ transport_disconnect(gsecondary);
+ gsecondary = NULL;
+ }
+}
+
static int do_fetch(struct transport *transport,
struct refspec *refs, int ref_count)
{
- struct string_list existing_refs = STRING_LIST_INIT_NODUP;
- struct string_list_item *peer_item = NULL;
+ struct string_list existing_refs = STRING_LIST_INIT_DUP;
struct ref *ref_map;
struct ref *rm;
int autotags = (transport->remote->fetch_tags == 1);
+ int retcode = 0;
for_each_ref(add_existing, &existing_refs);
@@ -713,9 +801,9 @@ static int do_fetch(struct transport *transport,
/* if not appending, truncate FETCH_HEAD */
if (!append && !dry_run) {
- int errcode = truncate_fetch_head();
- if (errcode)
- return errcode;
+ retcode = truncate_fetch_head();
+ if (retcode)
+ goto cleanup;
}
ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags);
@@ -724,8 +812,9 @@ static int do_fetch(struct transport *transport,
for (rm = ref_map; rm; rm = rm->next) {
if (rm->peer_ref) {
- peer_item = string_list_lookup(&existing_refs,
- rm->peer_ref->name);
+ struct string_list_item *peer_item =
+ string_list_lookup(&existing_refs,
+ rm->peer_ref->name);
if (peer_item)
hashcpy(rm->peer_ref->old_sha1,
peer_item->util);
@@ -736,10 +825,14 @@ static int do_fetch(struct transport *transport,
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
if (fetch_refs(transport, ref_map)) {
free_refs(ref_map);
- return 1;
+ retcode = 1;
+ goto cleanup;
}
if (prune) {
- /* If --tags was specified, pretend the user gave us the canonical tags refspec */
+ /*
+ * If --tags was specified, pretend that the user gave us
+ * the canonical tags refspec
+ */
if (tags == TAGS_SET) {
const char *tags_str = "refs/tags/*:refs/tags/*";
struct refspec *tags_refspec, *refspec;
@@ -771,26 +864,14 @@ static int do_fetch(struct transport *transport,
struct ref **tail = &ref_map;
ref_map = NULL;
find_non_local_tags(transport, &ref_map, &tail);
- if (ref_map) {
- transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
- transport_set_option(transport, TRANS_OPT_DEPTH, "0");
- fetch_refs(transport, ref_map);
- }
+ if (ref_map)
+ backfill_tags(transport, ref_map);
free_refs(ref_map);
}
- return 0;
-}
-
-static void set_option(const char *name, const char *value)
-{
- int r = transport_set_option(transport, name, value);
- if (r < 0)
- die(_("Option \"%s\" value \"%s\" is not valid for %s"),
- name, value, transport->url);
- if (r > 0)
- warning(_("Option \"%s\" is ignored for %s\n"),
- name, transport->url);
+ cleanup:
+ string_list_clear(&existing_refs, 1);
+ return retcode;
}
static int get_one_remote_for_fetch(struct remote *remote, void *priv)
@@ -848,7 +929,7 @@ static void add_options_to_argv(struct argv_array *argv)
{
if (dry_run)
argv_array_push(argv, "--dry-run");
- if (prune)
+ if (prune > 0)
argv_array_push(argv, "--prune");
if (update_head_ok)
argv_array_push(argv, "--update-head-ok");
@@ -915,14 +996,17 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
die(_("No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."));
- transport = transport_get(remote, NULL);
- transport_set_verbosity(transport, verbosity, progress);
- if (upload_pack)
- set_option(TRANS_OPT_UPLOADPACK, upload_pack);
- if (keep)
- set_option(TRANS_OPT_KEEP, "yes");
- if (depth)
- set_option(TRANS_OPT_DEPTH, depth);
+ gtransport = prepare_transport(remote);
+
+ if (prune < 0) {
+ /* no command line request */
+ if (0 <= gtransport->remote->prune)
+ prune = gtransport->remote->prune;
+ else if (0 <= fetch_prune_config)
+ prune = fetch_prune_config;
+ else
+ prune = PRUNE_BY_DEFAULT;
+ }
if (argc > 0) {
int j = 0;
@@ -949,10 +1033,10 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack);
refspec = parse_fetch_refspec(ref_nr, refs);
- exit_code = do_fetch(transport, refspec, ref_nr);
+ exit_code = do_fetch(gtransport, refspec, ref_nr);
free_refspec(ref_nr, refspec);
- transport_disconnect(transport);
- transport = NULL;
+ transport_disconnect(gtransport);
+ gtransport = NULL;
return exit_code;
}
@@ -973,6 +1057,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc; i++)
strbuf_addf(&default_rla, " %s", argv[i]);
+ git_config(git_fetch_config, NULL);
+
argc = parse_options(argc, argv, prefix,
builtin_fetch_options, builtin_fetch_usage, 0);
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 7f059c3..1d4083c 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -867,24 +867,29 @@ static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs
static void print_value(struct refinfo *ref, int atom, int quote_style)
{
struct atom_value *v;
+ struct strbuf sb = STRBUF_INIT;
get_value(ref, atom, &v);
switch (quote_style) {
case QUOTE_NONE:
fputs(v->s, stdout);
break;
case QUOTE_SHELL:
- sq_quote_print(stdout, v->s);
+ sq_quote_buf(&sb, v->s);
break;
case QUOTE_PERL:
- perl_quote_print(stdout, v->s);
+ perl_quote_buf(&sb, v->s);
break;
case QUOTE_PYTHON:
- python_quote_print(stdout, v->s);
+ python_quote_buf(&sb, v->s);
break;
case QUOTE_TCL:
- tcl_quote_print(stdout, v->s);
+ tcl_quote_buf(&sb, v->s);
break;
}
+ if (quote_style != QUOTE_NONE) {
+ fputs(sb.buf, stdout);
+ strbuf_release(&sb);
+ }
}
static int hex1(char ch)
diff --git a/builtin/fsck.c b/builtin/fsck.c
index bb9a2cd..39fa5e8 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -112,7 +112,7 @@ static int mark_object(struct object *obj, int type, void *data)
return 1;
}
- add_object_array(obj, (void *) parent, &pending);
+ add_object_array(obj, NULL, &pending);
return 0;
}
@@ -611,15 +611,15 @@ static char const * const fsck_usage[] = {
static struct option fsck_opts[] = {
OPT__VERBOSE(&verbose, N_("be verbose")),
- OPT_BOOLEAN(0, "unreachable", &show_unreachable, N_("show unreachable objects")),
+ OPT_BOOL(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,
+ OPT_BOOL(0, "tags", &show_tags, N_("report tags")),
+ OPT_BOOL(0, "root", &show_root, N_("report root nodes")),
+ OPT_BOOL(0, "cache", &keep_cache_objects, N_("make index objects head nodes")),
+ OPT_BOOL(0, "reflogs", &include_reflogs, N_("make reflogs head nodes (default)")),
+ OPT_BOOL(0, "full", &check_full, N_("also consider packs and alternate objects")),
+ OPT_BOOL(0, "strict", &check_strict, N_("enable more strict checking")),
+ OPT_BOOL(0, "lost-found", &write_lost_and_found,
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 6be6c8d..891a2c2 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -167,19 +167,78 @@ static int need_to_gc(void)
return 1;
}
+/* return NULL on success, else hostname running the gc */
+static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
+{
+ static struct lock_file lock;
+ static char locking_host[128];
+ char my_host[128];
+ struct strbuf sb = STRBUF_INIT;
+ struct stat st;
+ uintmax_t pid;
+ FILE *fp;
+ int fd, should_exit;
+
+ if (gethostname(my_host, sizeof(my_host)))
+ strcpy(my_host, "unknown");
+
+ fd = hold_lock_file_for_update(&lock, git_path("gc.pid"),
+ LOCK_DIE_ON_ERROR);
+ if (!force) {
+ fp = fopen(git_path("gc.pid"), "r");
+ memset(locking_host, 0, sizeof(locking_host));
+ should_exit =
+ fp != NULL &&
+ !fstat(fileno(fp), &st) &&
+ /*
+ * 12 hour limit is very generous as gc should
+ * never take that long. On the other hand we
+ * don't really need a strict limit here,
+ * running gc --auto one day late is not a big
+ * problem. --force can be used in manual gc
+ * after the user verifies that no gc is
+ * running.
+ */
+ time(NULL) - st.st_mtime <= 12 * 3600 &&
+ fscanf(fp, "%"PRIuMAX" %127c", &pid, locking_host) == 2 &&
+ /* be gentle to concurrent "gc" on remote hosts */
+ (strcmp(locking_host, my_host) || !kill(pid, 0));
+ if (fp != NULL)
+ fclose(fp);
+ if (should_exit) {
+ if (fd >= 0)
+ rollback_lock_file(&lock);
+ *ret_pid = pid;
+ return locking_host;
+ }
+ }
+
+ strbuf_addf(&sb, "%"PRIuMAX" %s",
+ (uintmax_t) getpid(), my_host);
+ write_in_full(fd, sb.buf, sb.len);
+ strbuf_release(&sb);
+ commit_lock_file(&lock);
+
+ return NULL;
+}
+
int cmd_gc(int argc, const char **argv, const char *prefix)
{
int aggressive = 0;
int auto_gc = 0;
int quiet = 0;
+ int force = 0;
+ const char *name;
+ pid_t pid;
struct option builtin_gc_options[] = {
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, N_("be more thorough (increased runtime)")),
- OPT_BOOLEAN(0, "auto", &auto_gc, N_("enable auto-gc mode")),
+ OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
+ OPT_BOOL(0, "auto", &auto_gc, N_("enable auto-gc mode")),
+ OPT_BOOL(0, "force", &force, N_("force running gc even if there may be another gc running")),
OPT_END()
};
@@ -225,6 +284,14 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
} else
add_repack_all_option();
+ name = lock_repo_for_gc(force, &pid);
+ if (name) {
+ if (auto_gc)
+ return 0; /* be quiet on --auto */
+ die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
+ name, (uintmax_t)pid);
+ }
+
if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
return error(FAILED_RUN, pack_refs_cmd.argv[0]);
diff --git a/builtin/grep.c b/builtin/grep.c
index 159e65d..03bc442 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,6 +17,7 @@
#include "grep.h"
#include "quote.h"
#include "dir.h"
+#include "pathspec.h"
static char const * const grep_usage[] = {
N_("git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"),
@@ -286,8 +287,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
struct strbuf pathbuf = STRBUF_INIT;
if (opt->relative && opt->prefix_length) {
- quote_path_relative(filename + tree_name_len, -1, &pathbuf,
- opt->prefix);
+ quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf);
strbuf_insert(&pathbuf, 0, filename, tree_name_len);
} else {
strbuf_addstr(&pathbuf, filename);
@@ -318,7 +318,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
struct strbuf buf = STRBUF_INIT;
if (opt->relative && opt->prefix_length)
- quote_path_relative(filename, -1, &buf, opt->prefix);
+ quote_path_relative(filename, opt->prefix, &buf);
else
strbuf_addstr(&buf, filename);
@@ -376,7 +376,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
read_cache();
for (nr = 0; nr < active_nr; nr++) {
- struct cache_entry *ce = active_cache[nr];
+ const struct cache_entry *ce = active_cache[nr];
if (!S_ISREG(ce->ce_mode))
continue;
if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
@@ -522,7 +522,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
if (exc_std)
setup_standard_excludes(&dir);
- fill_directory(&dir, pathspec->raw);
+ fill_directory(&dir, pathspec);
for (i = 0; i < dir.nr; i++) {
const char *name = dir.entries[i]->name;
int namelen = strlen(name);
@@ -630,7 +630,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
const char *show_in_pager = NULL, *default_pager = "dummy";
struct grep_opt opt;
struct object_array list = OBJECT_ARRAY_INIT;
- const char **paths = NULL;
struct pathspec pathspec;
struct string_list path_list = STRING_LIST_INIT_NODUP;
int i;
@@ -639,20 +638,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
struct option options[] = {
- OPT_BOOLEAN(0, "cached", &cached,
+ OPT_BOOL(0, "cached", &cached,
N_("search in index instead of in the work tree")),
OPT_NEGBIT(0, "no-index", &use_index,
N_("find in contents not managed by git"), 1),
- OPT_BOOLEAN(0, "untracked", &untracked,
+ OPT_BOOL(0, "untracked", &untracked,
N_("search in both tracked and untracked files")),
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
N_("search also in ignored files"), 1),
OPT_GROUP(""),
- OPT_BOOLEAN('v', "invert-match", &opt.invert,
+ OPT_BOOL('v', "invert-match", &opt.invert,
N_("show non-matching lines")),
- OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case,
+ OPT_BOOL('i', "ignore-case", &opt.ignore_case,
N_("case insensitive matching")),
- OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
+ OPT_BOOL('w', "word-regexp", &opt.word_regexp,
N_("match patterns only at word boundaries")),
OPT_SET_INT('a', "text", &opt.binary,
N_("process binary files as text"), GREP_BINARY_TEXT),
@@ -676,26 +675,26 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
N_("use Perl-compatible regular expressions"),
GREP_PATTERN_TYPE_PCRE),
OPT_GROUP(""),
- OPT_BOOLEAN('n', "line-number", &opt.linenum, N_("show line numbers")),
+ OPT_BOOL('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,
N_("show filenames relative to top directory"), 1),
- OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
+ OPT_BOOL('l', "files-with-matches", &opt.name_only,
N_("show only filenames instead of matching lines")),
- OPT_BOOLEAN(0, "name-only", &opt.name_only,
+ OPT_BOOL(0, "name-only", &opt.name_only,
N_("synonym for --files-with-matches")),
- OPT_BOOLEAN('L', "files-without-match",
+ OPT_BOOL('L', "files-without-match",
&opt.unmatch_name_only,
N_("show only the names of files without match")),
- OPT_BOOLEAN('z', "null", &opt.null_following_name,
+ OPT_BOOL('z', "null", &opt.null_following_name,
N_("print NUL after filenames")),
- OPT_BOOLEAN('c', "count", &opt.count,
+ OPT_BOOL('c', "count", &opt.count,
N_("show the number of matches instead of matching lines")),
OPT__COLOR(&opt.color, N_("highlight matches")),
- OPT_BOOLEAN(0, "break", &opt.file_break,
+ OPT_BOOL(0, "break", &opt.file_break,
N_("print empty line between matches from different files")),
- OPT_BOOLEAN(0, "heading", &opt.heading,
+ OPT_BOOL(0, "heading", &opt.heading,
N_("show filename only once above matches from same file")),
OPT_GROUP(""),
OPT_CALLBACK('C', "context", &opt, N_("n"),
@@ -707,9 +706,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
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,
+ OPT_BOOL('p', "show-function", &opt.funcname,
N_("show a line with the function name before matches")),
- OPT_BOOLEAN('W', "function-context", &opt.funcbody,
+ OPT_BOOL('W', "function-context", &opt.funcbody,
N_("show the surrounding function")),
OPT_GROUP(""),
OPT_CALLBACK('f', NULL, &opt, N_("file"),
@@ -719,7 +718,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK, 0, "and", &opt, NULL,
N_("combine patterns specified with -e"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
- OPT_BOOLEAN(0, "or", &dummy, ""),
+ OPT_BOOL(0, "or", &dummy, ""),
{ OPTION_CALLBACK, 0, "not", &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback },
{ OPTION_CALLBACK, '(', NULL, &opt, NULL, "",
@@ -730,7 +729,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
close_callback },
OPT__QUIET(&opt.status_only,
N_("indicate hit with exit status without output")),
- OPT_BOOLEAN(0, "all-match", &opt.all_match,
+ OPT_BOOL(0, "all-match", &opt.all_match,
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"),
@@ -739,8 +738,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_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,
- N_("allow calling of grep(1) (ignored by this build)")),
+ OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored,
+ 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()
@@ -857,8 +856,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
verify_filename(prefix, argv[j], j == i);
}
- paths = get_pathspec(prefix, argv + i);
- init_pathspec(&pathspec, paths);
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_CWD |
+ (opt.max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0),
+ prefix, argv + i);
pathspec.max_depth = opt.max_depth;
pathspec.recursive = 1;
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 8d184f1..d7fcf4c 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -70,10 +70,10 @@ static const char *vpath;
static const struct option hash_object_options[] = {
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_BOOL('w', NULL, &write_object, N_("write the object into the object database")),
+ OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
+ OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
+ OPT_BOOL( 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 d1d7181..f1e236b 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -1,6 +1,4 @@
/*
- * builtin-help.c
- *
* Builtin help command
*/
#include "cache.h"
@@ -36,10 +34,12 @@ enum help_format {
static const char *html_path;
static int show_all = 0;
+static int show_guides = 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, N_("print all available commands")),
+ OPT_BOOL('a', "all", &show_all, N_("print all available commands")),
+ OPT_BOOL('g', "guides", &show_guides, N_("print list of useful guides")),
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),
@@ -49,7 +49,7 @@ static struct option builtin_help_options[] = {
};
static const char * const builtin_help_usage[] = {
- N_("git help [--all] [--man|--web|--info] [command]"),
+ N_("git help [--all] [--guides] [--man|--web|--info] [command]"),
NULL
};
@@ -413,6 +413,37 @@ static void show_html_page(const char *git_cmd)
open_html(page_path.buf);
}
+static struct {
+ const char *name;
+ const char *help;
+} common_guides[] = {
+ { "attributes", N_("Defining attributes per path") },
+ { "glossary", N_("A Git glossary") },
+ { "ignore", N_("Specifies intentionally untracked files to ignore") },
+ { "modules", N_("Defining submodule properties") },
+ { "revisions", N_("Specifying revisions and ranges for Git") },
+ { "tutorial", N_("A tutorial introduction to Git (for version 1.5.1 or newer)") },
+ { "workflows", N_("An overview of recommended workflows with Git") },
+};
+
+static void list_common_guides_help(void)
+{
+ int i, longest = 0;
+
+ for (i = 0; i < ARRAY_SIZE(common_guides); i++) {
+ if (longest < strlen(common_guides[i].name))
+ longest = strlen(common_guides[i].name);
+ }
+
+ puts(_("The common Git guides are:\n"));
+ for (i = 0; i < ARRAY_SIZE(common_guides); i++) {
+ printf(" %s ", common_guides[i].name);
+ mput_char(' ', longest - strlen(common_guides[i].name));
+ puts(_(common_guides[i].help));
+ }
+ putchar('\n');
+}
+
int cmd_help(int argc, const char **argv, const char *prefix)
{
int nongit;
@@ -428,7 +459,16 @@ int cmd_help(int argc, const char **argv, const char *prefix)
git_config(git_help_config, NULL);
printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
list_commands(colopts, &main_cmds, &other_cmds);
+ }
+
+ if (show_guides)
+ list_common_guides_help();
+
+ if (show_all || show_guides) {
printf("%s\n", _(git_more_info_string));
+ /*
+ * We're done. Ignore any remaining args
+ */
return 0;
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 79dfe47..9c1cfac 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -77,8 +77,10 @@ static int nr_threads;
static int from_stdin;
static int strict;
+static int do_fsck_object;
static int verbose;
static int show_stat;
+static int check_self_contained_and_connected;
static struct progress *progress;
@@ -187,13 +189,13 @@ static int mark_link(struct object *obj, int type, void *data)
/* The content of each linked object must have been checked
or it must be already present in the object database */
-static void check_object(struct object *obj)
+static unsigned check_object(struct object *obj)
{
if (!obj)
- return;
+ return 0;
if (!(obj->flags & FLAG_LINK))
- return;
+ return 0;
if (!(obj->flags & FLAG_CHECKED)) {
unsigned long size;
@@ -201,17 +203,20 @@ static void check_object(struct object *obj)
if (type != obj->type || type <= 0)
die(_("object of unexpected type"));
obj->flags |= FLAG_CHECKED;
- return;
+ return 1;
}
+
+ return 0;
}
-static void check_objects(void)
+static unsigned check_objects(void)
{
- unsigned i, max;
+ unsigned i, max, foreign_nr = 0;
max = get_max_object_index();
for (i = 0; i < max; i++)
- check_object(get_indexed_object(i));
+ foreign_nr += check_object(get_indexed_object(i));
+ return foreign_nr;
}
@@ -747,8 +752,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
int eaten;
void *buf = (void *) data;
- if (!buf)
- buf = new_data = get_data_from_pack(obj_entry);
+ assert(data && "data can only be NULL for large _blobs_");
/*
* we do not need to free the memory here, as the
@@ -757,7 +761,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
obj = parse_object_buffer(sha1, type, size, buf, &eaten);
if (!obj)
die(_("invalid %s"), typename(type));
- if (fsck_object(obj, 1, fsck_error_function))
+ if (do_fsck_object &&
+ fsck_object(obj, 1, fsck_error_function))
die(_("Error in object"));
if (fsck_walk(obj, mark_link, NULL))
die(_("Not all child objects of %s are reachable"), sha1_to_hex(obj->sha1));
@@ -1491,6 +1496,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
struct pack_idx_entry **idx_objects;
struct pack_idx_option opts;
unsigned char pack_sha1[20];
+ unsigned foreign_nr = 1; /* zero is a "good" value, assume bad */
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(index_pack_usage);
@@ -1512,6 +1518,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
fix_thin_pack = 1;
} else if (!strcmp(arg, "--strict")) {
strict = 1;
+ do_fsck_object = 1;
+ } else if (!strcmp(arg, "--check-self-contained-and-connected")) {
+ strict = 1;
+ check_self_contained_and_connected = 1;
} else if (!strcmp(arg, "--verify")) {
verify = 1;
} else if (!strcmp(arg, "--verify-stat")) {
@@ -1625,7 +1635,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
free(deltas);
if (strict)
- check_objects();
+ foreign_nr = check_objects();
if (show_stat)
show_pack_info(stat_only);
@@ -1651,5 +1661,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (index_name == NULL)
free((void *) curr_index);
+ /*
+ * Let the caller know this pack is not self contained
+ */
+ if (check_self_contained_and_connected && foreign_nr)
+ return 1;
+
return 0;
}
diff --git a/builtin/log.c b/builtin/log.c
index 8f0b2e8..77d0f5f 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -19,10 +19,12 @@
#include "remote.h"
#include "string-list.h"
#include "parse-options.h"
+#include "line-log.h"
#include "branch.h"
#include "streaming.h"
#include "version.h"
#include "mailmap.h"
+#include "gpg-interface.h"
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
@@ -36,11 +38,17 @@ static const char *fmt_patch_subject_prefix = "PATCH";
static const char *fmt_pretty;
static const char * const builtin_log_usage[] = {
- N_("git log [<options>] [<since>..<until>] [[--] <path>...]\n")
+ N_("git log [<options>] [<revision range>] [[--] <path>...]\n")
N_(" or: git show [options] <object>..."),
NULL
};
+struct line_opt_callback_data {
+ struct rev_info *rev;
+ const char *prefix;
+ struct string_list args;
+};
+
static int parse_decoration_style(const char *var, const char *value)
{
switch (git_config_maybe_bool(var, value)) {
@@ -75,6 +83,19 @@ static int decorate_callback(const struct option *opt, const char *arg, int unse
return 0;
}
+static int log_line_range_callback(const struct option *option, const char *arg, int unset)
+{
+ struct line_opt_callback_data *data = option->value;
+
+ if (!arg)
+ return -1;
+
+ data->rev->line_level_traverse = 1;
+ string_list_append(&data->args, arg);
+
+ return 0;
+}
+
static void cmd_log_init_defaults(struct rev_info *rev)
{
if (fmt_pretty)
@@ -97,16 +118,23 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
{
struct userformat_want w;
int quiet = 0, source = 0, mailmap = 0;
+ static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP};
const struct option builtin_log_options[] = {
- OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
- OPT_BOOLEAN(0, "source", &source, N_("show source")),
- OPT_BOOLEAN(0, "use-mailmap", &mailmap, N_("Use mail map file")),
+ OPT__QUIET(&quiet, N_("suppress diff output")),
+ OPT_BOOL(0, "source", &source, N_("show source")),
+ OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback},
+ OPT_CALLBACK('L', NULL, &line_cb, "n,m:file",
+ "Process line range n,m in file, counting from 1",
+ log_line_range_callback),
OPT_END()
};
+ line_cb.rev = rev;
+ line_cb.prefix = prefix;
+
mailmap = use_mailmap_config;
argc = parse_options(argc, argv, prefix,
builtin_log_options, builtin_log_usage,
@@ -160,6 +188,10 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
rev->show_decorations = 1;
load_ref_decorations(decoration_style);
}
+
+ if (rev->line_level_traverse)
+ line_log_init(rev, line_cb.prefix, &line_cb.args);
+
setup_pager();
}
@@ -205,7 +237,7 @@ static void log_show_early(struct rev_info *revs, struct commit_list *list)
int i = revs->early_output;
int show_header = 1;
- sort_in_topological_order(&list, revs->lifo);
+ sort_in_topological_order(&list, revs->sort_order);
while (list && i) {
struct commit *commit = list->item;
switch (simplify_commit(revs, commit)) {
@@ -367,6 +399,8 @@ static int git_log_config(const char *var, const char *value, void *cb)
if (grep_config(var, value, cb) < 0)
return -1;
+ if (git_gpg_config(var, value, cb) < 0)
+ return -1;
return git_diff_ui_config(var, value, cb);
}
@@ -469,7 +503,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
init_grep_defaults();
git_config(git_log_config, NULL);
- init_pathspec(&match_all, NULL);
+ memset(&match_all, 0, sizeof(match_all));
init_revisions(&rev, prefix);
rev.diff = 1;
rev.always_show_header = 1;
@@ -619,6 +653,14 @@ static void add_header(const char *value)
static int thread;
static int do_signoff;
static const char *signature = git_version_string;
+static int config_cover_letter;
+
+enum {
+ COVER_UNSET,
+ COVER_OFF,
+ COVER_ON,
+ COVER_AUTO
+};
static int git_format_config(const char *var, const char *value, void *cb)
{
@@ -680,6 +722,14 @@ static int git_format_config(const char *var, const char *value, void *cb)
}
if (!strcmp(var, "format.signature"))
return git_config_string(&signature, var, value);
+ if (!strcmp(var, "format.coverletter")) {
+ if (value && !strcasecmp(value, "auto")) {
+ config_cover_letter = COVER_AUTO;
+ return 0;
+ }
+ config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
+ return 0;
+ }
return git_log_config(var, value, cb);
}
@@ -791,9 +841,37 @@ static void add_branch_description(struct strbuf *buf, const char *branch_name)
}
}
+static char *find_branch_name(struct rev_info *rev)
+{
+ int i, positive = -1;
+ unsigned char branch_sha1[20];
+ const unsigned char *tip_sha1;
+ const char *ref;
+ char *full_ref, *branch = NULL;
+
+ for (i = 0; i < rev->cmdline.nr; i++) {
+ if (rev->cmdline.rev[i].flags & UNINTERESTING)
+ continue;
+ if (positive < 0)
+ positive = i;
+ else
+ return NULL;
+ }
+ if (positive < 0)
+ return NULL;
+ ref = rev->cmdline.rev[positive].name;
+ tip_sha1 = rev->cmdline.rev[positive].item->sha1;
+ if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) &&
+ !prefixcmp(full_ref, "refs/heads/") &&
+ !hashcmp(tip_sha1, branch_sha1))
+ branch = xstrdup(full_ref + strlen("refs/heads/"));
+ free(full_ref);
+ return branch;
+}
+
static void make_cover_letter(struct rev_info *rev, int use_stdout,
struct commit *origin,
- int nr, struct commit **list, struct commit *head,
+ int nr, struct commit **list,
const char *branch_name,
int quiet)
{
@@ -807,6 +885,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
struct diff_options opts;
int need_8bit_cte = 0;
struct pretty_print_context pp = {0};
+ struct commit *head = list[0];
if (rev->commit_format != CMIT_FMT_EMAIL)
die(_("Cover letter needs email format"));
@@ -824,6 +903,9 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
if (has_non_ascii(list[i]->buffer))
need_8bit_cte = 1;
+ if (!branch_name)
+ branch_name = find_branch_name(rev);
+
msg = body;
pp.fmt = CMIT_FMT_EMAIL;
pp.date_mode = DATE_RFC2822;
@@ -1030,43 +1112,19 @@ static int cc_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
-static char *find_branch_name(struct rev_info *rev)
+static int from_callback(const struct option *opt, const char *arg, int unset)
{
- int i, positive = -1;
- unsigned char branch_sha1[20];
- const unsigned char *tip_sha1;
- const char *ref;
- char *full_ref, *branch = NULL;
+ char **from = opt->value;
- for (i = 0; i < rev->cmdline.nr; i++) {
- if (rev->cmdline.rev[i].flags & UNINTERESTING)
- continue;
- if (positive < 0)
- positive = i;
- else
- return NULL;
- }
- if (0 <= positive) {
- ref = rev->cmdline.rev[positive].name;
- tip_sha1 = rev->cmdline.rev[positive].item->sha1;
- } else if (!rev->cmdline.nr && rev->pending.nr == 1 &&
- !strcmp(rev->pending.objects[0].name, "HEAD")) {
- /*
- * No actual ref from command line, but "HEAD" from
- * rev->def was added in setup_revisions()
- * e.g. format-patch --cover-letter -12
- */
- ref = "HEAD";
- tip_sha1 = rev->pending.objects[0].item->sha1;
- } else {
- return NULL;
- }
- if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) &&
- !prefixcmp(full_ref, "refs/heads/") &&
- !hashcmp(tip_sha1, branch_sha1))
- branch = xstrdup(full_ref + strlen("refs/heads/"));
- free(full_ref);
- return branch;
+ free(*from);
+
+ if (unset)
+ *from = NULL;
+ else if (arg)
+ *from = xstrdup(arg);
+ else
+ *from = xstrdup(git_committer_info(IDENT_NO_DATE));
+ return 0;
}
int cmd_format_patch(int argc, const char **argv, const char *prefix)
@@ -1080,18 +1138,18 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int start_number = -1;
int just_numbers = 0;
int ignore_if_in_upstream = 0;
- int cover_letter = 0;
+ int cover_letter = -1;
int boundary_count = 0;
int no_binary_diff = 0;
- struct commit *origin = NULL, *head = NULL;
+ struct commit *origin = NULL;
const char *in_reply_to = NULL;
struct patch_ids ids;
- char *add_signoff = NULL;
struct strbuf buf = STRBUF_INIT;
int use_patch_format = 0;
int quiet = 0;
int reroll_count = -1;
char *branch_name = NULL;
+ char *from = NULL;
const struct option builtin_format_patch_options[] = {
{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
N_("use [PATCH n/m] even with a single patch"),
@@ -1099,12 +1157,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL,
N_("use [PATCH] even with multiple patches"),
PARSE_OPT_NOARG, no_numbered_callback },
- OPT_BOOLEAN('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
- OPT_BOOLEAN(0, "stdout", &use_stdout,
+ OPT_BOOL('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
+ OPT_BOOL(0, "stdout", &use_stdout,
N_("print patches to standard out")),
- OPT_BOOLEAN(0, "cover-letter", &cover_letter,
+ OPT_BOOL(0, "cover-letter", &cover_letter,
N_("generate a cover letter")),
- OPT_BOOLEAN(0, "numbered-files", &just_numbers,
+ OPT_BOOL(0, "numbered-files", &just_numbers,
N_("use simple number sequence for output file names")),
OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
N_("use <sfx> instead of '.patch'")),
@@ -1121,13 +1179,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK, 'k', "keep-subject", &rev, NULL,
N_("don't strip/add [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback },
- OPT_BOOLEAN(0, "no-binary", &no_binary_diff,
- N_("don't output binary diffs")),
- OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
- N_("don't include a patch matching a commit upstream")),
- { OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL,
+ OPT_BOOL(0, "no-binary", &no_binary_diff,
+ N_("don't output binary diffs")),
+ OPT_BOOL(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
+ N_("don't include a patch matching a commit upstream")),
+ { OPTION_SET_INT, 'p', "no-stat", &use_patch_format, NULL,
N_("show patch format instead of default (patch + stat)"),
- PARSE_OPT_NONEG | PARSE_OPT_NOARG },
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1},
OPT_GROUP(N_("Messaging")),
{ OPTION_CALLBACK, 0, "add-header", NULL, N_("header"),
N_("add email header"), 0, header_callback },
@@ -1135,6 +1193,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
0, to_callback },
{ OPTION_CALLBACK, 0, "cc", NULL, N_("email"), N_("add Cc: header"),
0, cc_callback },
+ { OPTION_CALLBACK, 0, "from", &from, N_("ident"),
+ N_("set From address to <ident> (or committer ident if absent)"),
+ PARSE_OPT_OPTARG, from_callback },
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"),
@@ -1149,8 +1210,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
PARSE_OPT_OPTARG, thread_callback },
OPT_STRING(0, "signature", &signature, N_("signature"),
N_("add a signature")),
- OPT_BOOLEAN(0, "quiet", &quiet,
- N_("don't print the patch filenames")),
+ OPT__QUIET(&quiet, N_("don't print the patch filenames")),
OPT_END()
};
@@ -1193,16 +1253,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.subject_prefix = strbuf_detach(&sprefix, NULL);
}
- if (do_signoff) {
- const char *committer;
- const char *endpos;
- committer = git_committer_info(IDENT_STRICT);
- endpos = strchr(committer, '>');
- if (!endpos)
- die(_("bogus committer info %s"), committer);
- add_signoff = xmemdupz(committer, endpos - committer + 1);
- }
-
for (i = 0; i < extra_hdr.nr; i++) {
strbuf_addstr(&buf, extra_hdr.items[i].string);
strbuf_addch(&buf, '\n');
@@ -1232,6 +1282,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.extra_headers = strbuf_detach(&buf, NULL);
+ if (from) {
+ if (split_ident_line(&rev.from_ident, from, strlen(from)))
+ die(_("invalid ident line: %s"), from);
+ }
+
if (start_number < 0)
start_number = 1;
@@ -1288,28 +1343,36 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
if (rev.pending.nr == 1) {
+ int check_head = 0;
+
if (rev.max_count < 0 && !rev.show_root_diff) {
/*
* This is traditional behaviour of "git format-patch
* origin" that prepares what the origin side still
* does not have.
*/
- unsigned char sha1[20];
- const char *ref;
-
rev.pending.objects[0].item->flags |= UNINTERESTING;
add_head_to_pending(&rev);
- ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
- if (ref && !prefixcmp(ref, "refs/heads/"))
- branch_name = xstrdup(ref + strlen("refs/heads/"));
- else
- branch_name = xstrdup(""); /* no branch */
+ check_head = 1;
}
/*
* Otherwise, it is "format-patch -22 HEAD", and/or
* "format-patch --root HEAD". The user wants
* get_revision() to do the usual traversal.
*/
+
+ if (!strcmp(rev.pending.objects[0].name, "HEAD"))
+ check_head = 1;
+
+ if (check_head) {
+ unsigned char sha1[20];
+ const char *ref;
+ ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
+ if (ref && !prefixcmp(ref, "refs/heads/"))
+ branch_name = xstrdup(ref + strlen("refs/heads/"));
+ else
+ branch_name = xstrdup(""); /* no branch */
+ }
}
/*
@@ -1318,29 +1381,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
*/
rev.show_root_diff = 1;
- if (cover_letter) {
- /*
- * NEEDSWORK:randomly pick one positive commit to show
- * diffstat; this is often the tip and the command
- * happens to do the right thing in most cases, but a
- * complex command like "--cover-letter a b c ^bottom"
- * picks "c" and shows diffstat between bottom..c
- * which may not match what the series represents at
- * all and totally broken.
- */
- int i;
- for (i = 0; i < rev.pending.nr; i++) {
- struct object *o = rev.pending.objects[i].item;
- if (!(o->flags & UNINTERESTING))
- head = (struct commit *)o;
- }
- /* There is nothing to show; it is not an error, though. */
- if (!head)
- return 0;
- if (!branch_name)
- branch_name = find_branch_name(&rev);
- }
-
if (ignore_if_in_upstream) {
/* Don't say anything if head and upstream are the same. */
if (rev.pending.nr == 2) {
@@ -1372,11 +1412,21 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
list = xrealloc(list, nr * sizeof(list[0]));
list[nr - 1] = commit;
}
+ if (nr == 0)
+ /* nothing to do */
+ return 0;
total = nr;
if (!keep_subject && auto_number && total > 1)
numbered = 1;
if (numbered)
rev.total = total + start_number - 1;
+ if (cover_letter == -1) {
+ if (config_cover_letter == COVER_AUTO)
+ cover_letter = (total > 1);
+ else
+ cover_letter = (config_cover_letter == COVER_ON);
+ }
+
if (in_reply_to || thread || cover_letter)
rev.ref_message_ids = xcalloc(1, sizeof(struct string_list));
if (in_reply_to) {
@@ -1389,11 +1439,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (thread)
gen_message_id(&rev, "cover");
make_cover_letter(&rev, use_stdout,
- origin, nr, list, head, branch_name, quiet);
+ origin, nr, list, branch_name, quiet);
total++;
start_number--;
}
- rev.add_signoff = add_signoff;
+ rev.add_signoff = do_signoff;
while (0 <= --nr) {
int shown;
commit = list[nr];
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 175e6e3..e1cf6d8 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -13,6 +13,7 @@
#include "parse-options.h"
#include "resolve-undo.h"
#include "string-list.h"
+#include "pathspec.h"
static int abbrev;
static int show_deleted;
@@ -30,7 +31,7 @@ static int debug_mode;
static const char *prefix;
static int max_prefix_len;
static int prefix_len;
-static const char **pathspec;
+static struct pathspec pathspec;
static int error_unmatch;
static char *ps_matched;
static const char *with_tree;
@@ -46,10 +47,14 @@ static const char *tag_modified = "";
static const char *tag_skip_worktree = "";
static const char *tag_resolve_undo = "";
-static void write_name(const char* name, size_t len)
+static void write_name(const char *name)
{
- write_name_quoted_relative(name, len, prefix, prefix_len, stdout,
- line_terminator);
+ /*
+ * With "--full-name", prefix_len=0; this caller needs to pass
+ * an empty string in that case (a NULL is good for "").
+ */
+ write_name_quoted_relative(name, prefix_len ? prefix : NULL,
+ stdout, line_terminator);
}
static void show_dir_entry(const char *tag, struct dir_entry *ent)
@@ -59,11 +64,11 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
if (len >= ent->len)
die("git ls-files: internal error - directory entry not superset of prefix");
- if (!match_pathspec(pathspec, ent->name, ent->len, len, ps_matched))
+ if (!match_pathspec_depth(&pathspec, ent->name, ent->len, len, ps_matched))
return;
fputs(tag, stdout);
- write_name(ent->name, ent->len);
+ write_name(ent->name);
}
static void show_other_files(struct dir_struct *dir)
@@ -127,14 +132,14 @@ static void show_killed_files(struct dir_struct *dir)
}
}
-static void show_ce_entry(const char *tag, struct cache_entry *ce)
+static void show_ce_entry(const char *tag, const struct cache_entry *ce)
{
int len = max_prefix_len;
if (len >= ce_namelen(ce))
die("git ls-files: internal error - cache entry not superset of prefix");
- if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), len, ps_matched))
+ if (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), len, ps_matched))
return;
if (tag && *tag && show_valid_bit &&
@@ -163,13 +168,15 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
find_unique_abbrev(ce->sha1,abbrev),
ce_stage(ce));
}
- write_name(ce->name, ce_namelen(ce));
+ write_name(ce->name);
if (debug_mode) {
- printf(" ctime: %d:%d\n", ce->ce_ctime.sec, ce->ce_ctime.nsec);
- printf(" mtime: %d:%d\n", ce->ce_mtime.sec, ce->ce_mtime.nsec);
- printf(" dev: %d\tino: %d\n", ce->ce_dev, ce->ce_ino);
- printf(" uid: %d\tgid: %d\n", ce->ce_uid, ce->ce_gid);
- printf(" size: %d\tflags: %x\n", ce->ce_size, ce->ce_flags);
+ const struct stat_data *sd = &ce->ce_stat_data;
+
+ printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec);
+ printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec);
+ printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino);
+ printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid);
+ printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags);
}
}
@@ -188,7 +195,7 @@ static void show_ru_info(void)
len = strlen(path);
if (len < max_prefix_len)
continue; /* outside of the prefix */
- if (!match_pathspec(pathspec, path, len, max_prefix_len, ps_matched))
+ if (!match_pathspec_depth(&pathspec, path, len, max_prefix_len, ps_matched))
continue; /* uninterested */
for (i = 0; i < 3; i++) {
if (!ui->mode[i])
@@ -196,38 +203,36 @@ static void show_ru_info(void)
printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
find_unique_abbrev(ui->sha1[i], abbrev),
i + 1);
- write_name(path, len);
+ write_name(path);
}
}
}
-static int ce_excluded(struct path_exclude_check *check, struct cache_entry *ce)
+static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce)
{
int dtype = ce_to_dtype(ce);
- return is_path_excluded(check, ce->name, ce_namelen(ce), &dtype);
+ return is_excluded(dir, ce->name, &dtype);
}
static void show_files(struct dir_struct *dir)
{
int i;
- struct path_exclude_check check;
-
- if ((dir->flags & DIR_SHOW_IGNORED))
- path_exclude_check_init(&check, dir);
/* For cached/deleted files we don't need to even do the readdir */
if (show_others || show_killed) {
- fill_directory(dir, pathspec);
+ if (!show_others)
+ dir->flags |= DIR_COLLECT_KILLED_ONLY;
+ fill_directory(dir, &pathspec);
if (show_others)
show_other_files(dir);
if (show_killed)
show_killed_files(dir);
}
- if (show_cached | show_stage) {
+ if (show_cached || show_stage) {
for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
if ((dir->flags & DIR_SHOW_IGNORED) &&
- !ce_excluded(&check, ce))
+ !ce_excluded(dir, ce))
continue;
if (show_unmerged && !ce_stage(ce))
continue;
@@ -237,13 +242,13 @@ static void show_files(struct dir_struct *dir)
(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
}
}
- if (show_deleted | show_modified) {
+ if (show_deleted || show_modified) {
for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
struct stat st;
int err;
if ((dir->flags & DIR_SHOW_IGNORED) &&
- !ce_excluded(&check, ce))
+ !ce_excluded(dir, ce))
continue;
if (ce->ce_flags & CE_UPDATE)
continue;
@@ -256,9 +261,6 @@ static void show_files(struct dir_struct *dir)
show_ce_entry(tag_modified, ce);
}
}
-
- if ((dir->flags & DIR_SHOW_IGNORED))
- path_exclude_check_clear(&check);
}
/*
@@ -278,7 +280,7 @@ static void prune_cache(const char *prefix)
last = active_nr;
while (last > first) {
int next = (last + first) >> 1;
- struct cache_entry *ce = active_cache[next];
+ const struct cache_entry *ce = active_cache[next];
if (!strncmp(ce->name, prefix, max_prefix_len)) {
first = next+1;
continue;
@@ -288,21 +290,6 @@ static void prune_cache(const char *prefix)
active_nr = last;
}
-static void strip_trailing_slash_from_submodules(void)
-{
- const char **p;
-
- for (p = pathspec; *p != NULL; p++) {
- int len = strlen(*p), pos;
-
- if (len < 1 || (*p)[len - 1] != '/')
- continue;
- pos = cache_name_pos(*p, len - 1);
- if (pos >= 0 && S_ISGITLINK(active_cache[pos]->ce_mode))
- *p = xstrndup(*p, len - 1);
- }
-}
-
/*
* Read the tree specified with --with-tree option
* (typically, HEAD) into stage #1 and then
@@ -334,13 +321,12 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
}
if (prefix) {
- static const char *(matchbuf[2]);
- matchbuf[0] = prefix;
- matchbuf[1] = NULL;
- init_pathspec(&pathspec, matchbuf);
- pathspec.items[0].nowildcard_len = pathspec.items[0].len;
+ static const char *(matchbuf[1]);
+ matchbuf[0] = NULL;
+ parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC,
+ PATHSPEC_PREFER_CWD, prefix, matchbuf);
} else
- init_pathspec(&pathspec, NULL);
+ memset(&pathspec, 0, sizeof(pathspec));
if (read_tree(tree, 1, &pathspec))
die("unable to read tree entries %s", tree_name);
@@ -365,15 +351,16 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
}
}
-int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix)
+int report_path_error(const char *ps_matched,
+ const struct pathspec *pathspec,
+ const char *prefix)
{
/*
* Make sure all pathspec matched; otherwise it is an error.
*/
struct strbuf sb = STRBUF_INIT;
- const char *name;
int num, errors = 0;
- for (num = 0; pathspec[num]; num++) {
+ for (num = 0; num < pathspec->nr; num++) {
int other, found_dup;
if (ps_matched[num])
@@ -381,13 +368,16 @@ int report_path_error(const char *ps_matched, const char **pathspec, const char
/*
* The caller might have fed identical pathspec
* twice. Do not barf on such a mistake.
+ * FIXME: parse_pathspec should have eliminated
+ * duplicate pathspec.
*/
for (found_dup = other = 0;
- !found_dup && pathspec[other];
+ !found_dup && other < pathspec->nr;
other++) {
if (other == num || !ps_matched[other])
continue;
- if (!strcmp(pathspec[other], pathspec[num]))
+ if (!strcmp(pathspec->items[other].original,
+ pathspec->items[num].original))
/*
* Ok, we have a match already.
*/
@@ -396,9 +386,8 @@ int report_path_error(const char *ps_matched, const char **pathspec, const char
if (found_dup)
continue;
- name = quote_path_relative(pathspec[num], -1, &sb, prefix);
error("pathspec '%s' did not match any file(s) known to git.",
- name);
+ pathspec->items[num].original);
errors++;
}
strbuf_release(&sb);
@@ -462,24 +451,24 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
N_("paths are separated with NUL character"),
PARSE_OPT_NOARG, option_parse_z },
- OPT_BOOLEAN('t', NULL, &show_tag,
+ OPT_BOOL('t', NULL, &show_tag,
N_("identify the file status with tags")),
- OPT_BOOLEAN('v', NULL, &show_valid_bit,
+ OPT_BOOL('v', NULL, &show_valid_bit,
N_("use lowercase letters for 'assume unchanged' files")),
- OPT_BOOLEAN('c', "cached", &show_cached,
+ OPT_BOOL('c', "cached", &show_cached,
N_("show cached files in the output (default)")),
- OPT_BOOLEAN('d', "deleted", &show_deleted,
+ OPT_BOOL('d', "deleted", &show_deleted,
N_("show deleted files in the output")),
- OPT_BOOLEAN('m', "modified", &show_modified,
+ OPT_BOOL('m', "modified", &show_modified,
N_("show modified files in the output")),
- OPT_BOOLEAN('o', "others", &show_others,
+ OPT_BOOL('o', "others", &show_others,
N_("show other files in the output")),
OPT_BIT('i', "ignored", &dir.flags,
N_("show ignored files in the output"),
DIR_SHOW_IGNORED),
- OPT_BOOLEAN('s', "stage", &show_stage,
+ OPT_BOOL('s', "stage", &show_stage,
N_("show staged contents' object name in the output")),
- OPT_BOOLEAN('k', "killed", &show_killed,
+ OPT_BOOL('k', "killed", &show_killed,
N_("show files on the filesystem that need to be removed")),
OPT_BIT(0, "directory", &dir.flags,
N_("show 'other' directories' name only"),
@@ -487,9 +476,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
OPT_NEGBIT(0, "empty-directory", &dir.flags,
N_("don't show empty directories"),
DIR_HIDE_EMPTY_DIRECTORIES),
- OPT_BOOLEAN('u', "unmerged", &show_unmerged,
+ OPT_BOOL('u', "unmerged", &show_unmerged,
N_("show unmerged files in the output")),
- OPT_BOOLEAN(0, "resolve-undo", &show_resolve_undo,
+ OPT_BOOL(0, "resolve-undo", &show_resolve_undo,
N_("show resolve-undo information")),
{ OPTION_CALLBACK, 'x', "exclude", &exclude_list, N_("pattern"),
N_("skip files matching pattern"),
@@ -505,12 +494,12 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
{ OPTION_SET_INT, 0, "full-name", &prefix_len, NULL,
N_("make the output relative to the project top directory"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
- OPT_BOOLEAN(0, "error-unmatch", &error_unmatch,
+ OPT_BOOL(0, "error-unmatch", &error_unmatch,
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, N_("show debugging data")),
+ OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
OPT_END()
};
@@ -556,30 +545,25 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
if (require_work_tree && !is_inside_work_tree())
setup_work_tree();
- pathspec = get_pathspec(prefix, argv);
-
- /* be nice with submodule paths ending in a slash */
- if (pathspec)
- strip_trailing_slash_from_submodules();
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_CWD |
+ PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
+ prefix, argv);
/* Find common prefix for all pathspec's */
- max_prefix = common_prefix(pathspec);
+ max_prefix = common_prefix(&pathspec);
max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
/* Treat unmatching pathspec elements as errors */
- if (pathspec && error_unmatch) {
- int num;
- for (num = 0; pathspec[num]; num++)
- ;
- ps_matched = xcalloc(1, num);
- }
+ if (pathspec.nr && error_unmatch)
+ ps_matched = xcalloc(1, pathspec.nr);
if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given)
die("ls-files --ignored needs some exclude pattern");
/* With no flags, we default to showing the cached files */
- if (!(show_stage | show_deleted | show_others | show_unmerged |
- show_killed | show_modified | show_resolve_undo))
+ if (!(show_stage || show_deleted || show_others || show_unmerged ||
+ show_killed || show_modified || show_resolve_undo))
show_cached = 1;
if (max_prefix)
@@ -599,7 +583,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
if (ps_matched) {
int bad;
- bad = report_path_error(ps_matched, pathspec, prefix);
+ bad = report_path_error(ps_matched, &pathspec, prefix);
if (bad)
fprintf(stderr, "Did you forget to 'git add'?\n");
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index fb76e38..65ec931 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -10,6 +10,7 @@
#include "quote.h"
#include "builtin.h"
#include "parse-options.h"
+#include "pathspec.h"
static int line_termination = '\n';
#define LS_RECURSIVE 1
@@ -35,7 +36,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
if (ls_options & LS_RECURSIVE)
return 1;
- s = pathspec.raw;
+ s = pathspec._raw;
if (!s)
return 0;
@@ -138,9 +139,9 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
LS_NAME_ONLY),
OPT_SET_INT(0, "full-name", &chomp_prefix,
N_("use full path names"), 0),
- OPT_BOOLEAN(0, "full-tree", &full_tree,
- N_("list entire tree; not just current directory "
- "(implies --full-name)")),
+ OPT_BOOL(0, "full-tree", &full_tree,
+ N_("list entire tree; not just current directory "
+ "(implies --full-name)")),
OPT__ABBREV(&abbrev),
OPT_END()
};
@@ -166,7 +167,15 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
if (get_sha1(argv[0], sha1))
die("Not a valid object name %s", argv[0]);
- init_pathspec(&pathspec, get_pathspec(prefix, argv + 1));
+ /*
+ * show_recursive() rolls its own matching code and is
+ * generally ignorant of 'struct pathspec'. The magic mask
+ * cannot be lifted until it is converted to use
+ * match_pathspec_depth() or tree_entry_interesting()
+ */
+ parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE,
+ PATHSPEC_PREFER_CWD,
+ prefix, argv + 1);
for (i = 0; i < pathspec.nr; i++)
pathspec.items[i].nowildcard_len = pathspec.items[i].len;
pathspec.has_wildcard = 0;
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 1bc7991..e88eb93 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -95,11 +95,11 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
int is_ancestor = 0;
struct option options[] = {
- 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_BOOL('a', "all", &show_all, N_("output all common ancestors")),
+ OPT_BOOL(0, "octopus", &octopus, N_("find ancestors for a single n-way merge")),
+ OPT_BOOL(0, "independent", &reduce, N_("list revs not reachable from others")),
+ OPT_BOOL(0, "is-ancestor", &is_ancestor,
+ N_("is the first one ancestor of the other?")),
OPT_END()
};
@@ -107,7 +107,7 @@ 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))
+ 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);
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index c0570f2..844f84f 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -30,7 +30,7 @@ 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, N_("send results to standard output")),
+ OPT_BOOL('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),
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index be5e514..b416d92 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -16,7 +16,7 @@ static int merge_entry(int pos, const char *path)
die("git merge-index: %s not in the cache", path);
found = 0;
do {
- struct cache_entry *ce = active_cache[pos];
+ const struct cache_entry *ce = active_cache[pos];
int stage = ce_stage(ce);
if (strcmp(ce->name, path))
@@ -58,7 +58,7 @@ static void merge_all(void)
{
int i;
for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
if (!ce_stage(ce))
continue;
i += merge_entry(i, ce->name)-1;
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index bc912e3..61cbde4 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -155,6 +155,11 @@ static int same_entry(struct name_entry *a, struct name_entry *b)
a->mode == b->mode;
}
+static int both_empty(struct name_entry *a, struct name_entry *b)
+{
+ return !(a->sha1 || b->sha1);
+}
+
static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsigned char *sha1, const char *path)
{
struct merge_list *res = xcalloc(1, sizeof(*res));
@@ -246,7 +251,11 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
for (i = 0; i < 3; i++) {
mask |= (1 << i);
- if (n[i].mode && S_ISDIR(n[i].mode))
+ /*
+ * Treat missing entries as directories so that we return
+ * after unresolved_directory has handled this.
+ */
+ if (!n[i].mode || S_ISDIR(n[i].mode))
dirmask |= (1 << i);
}
@@ -297,13 +306,10 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *info)
{
/* Same in both? */
- if (same_entry(entry+1, entry+2)) {
- if (entry[0].sha1) {
- /* Modified identically */
- resolve(info, NULL, entry+1);
- return mask;
- }
- /* "Both added the same" is left unresolved */
+ if (same_entry(entry+1, entry+2) || both_empty(entry+1, entry+2)) {
+ /* Modified, added or removed identically */
+ resolve(info, NULL, entry+1);
+ return mask;
}
if (same_entry(entry+0, entry+1)) {
@@ -319,12 +325,10 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
*/
}
- if (same_entry(entry+0, entry+2)) {
- if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
- /* We modified, they did not touch -- take ours */
- resolve(info, NULL, entry+1);
- return mask;
- }
+ if (same_entry(entry+0, entry+2) || both_empty(entry+0, entry+2)) {
+ /* We added, modified or removed, they did not touch -- take ours */
+ resolve(info, NULL, entry+1);
+ return mask;
}
unresolved(info, entry);
diff --git a/builtin/merge.c b/builtin/merge.c
index 0d94d89..a8cf4a2 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -47,9 +47,9 @@ static const char * const builtin_merge_usage[] = {
};
static int show_diffstat = 1, shortlog_len = -1, squash;
-static int option_commit = 1, allow_fast_forward = 1;
-static int fast_forward_only, option_edit = -1;
-static int allow_trivial = 1, have_message;
+static int option_commit = 1;
+static int option_edit = -1;
+static int allow_trivial = 1, have_message, verify_signatures;
static int overwrite_ignore = 1;
static struct strbuf merge_msg = STRBUF_INIT;
static struct strategy **use_strategies;
@@ -76,6 +76,14 @@ static struct strategy all_strategy[] = {
static const char *pull_twohead, *pull_octopus;
+enum ff_type {
+ FF_NO,
+ FF_ALLOW,
+ FF_ONLY
+};
+
+static enum ff_type fast_forward = FF_ALLOW;
+
static int option_parse_message(const struct option *opt,
const char *arg, int unset)
{
@@ -178,27 +186,36 @@ static int option_parse_n(const struct option *opt,
return 0;
}
+static int option_parse_ff_only(const struct option *opt,
+ const char *arg, int unset)
+{
+ fast_forward = FF_ONLY;
+ return 0;
+}
+
static struct option builtin_merge_options[] = {
{ OPTION_CALLBACK, 'n', NULL, NULL, NULL,
N_("do not show a diffstat at the end of the merge"),
PARSE_OPT_NOARG, option_parse_n },
- OPT_BOOLEAN(0, "stat", &show_diffstat,
+ OPT_BOOL(0, "stat", &show_diffstat,
N_("show a diffstat at the end of the merge")),
- OPT_BOOLEAN(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
+ OPT_BOOL(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,
+ OPT_BOOL(0, "squash", &squash,
N_("create a single commit instead of doing a merge")),
- OPT_BOOLEAN(0, "commit", &option_commit,
+ OPT_BOOL(0, "commit", &option_commit,
N_("perform a commit if the merge succeeds (default)")),
OPT_BOOL('e', "edit", &option_edit,
N_("edit message before committing")),
- OPT_BOOLEAN(0, "ff", &allow_fast_forward,
- N_("allow fast-forward (default)")),
- OPT_BOOLEAN(0, "ff-only", &fast_forward_only,
- N_("abort if fast-forward is not possible")),
+ OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
+ { OPTION_CALLBACK, 0, "ff-only", NULL, NULL,
+ N_("abort if fast-forward is not possible"),
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, option_parse_ff_only },
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
+ OPT_BOOL(0, "verify-signatures", &verify_signatures,
+ N_("Verify that the named commit has a valid GPG signature")),
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"),
@@ -207,12 +224,12 @@ static struct option builtin_merge_options[] = {
N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
OPT__VERBOSITY(&verbosity),
- OPT_BOOLEAN(0, "abort", &abort_current_merge,
+ OPT_BOOL(0, "abort", &abort_current_merge,
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_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
OPT_END()
};
@@ -579,10 +596,9 @@ static int git_merge_config(const char *k, const char *v, void *cb)
else if (!strcmp(k, "merge.ff")) {
int boolval = git_config_maybe_bool(k, v);
if (0 <= boolval) {
- allow_fast_forward = boolval;
+ fast_forward = boolval ? FF_ALLOW : FF_NO;
} else if (v && !strcmp(v, "only")) {
- allow_fast_forward = 1;
- fast_forward_only = 1;
+ fast_forward = FF_ONLY;
} /* do not barf on values from future versions of git */
return 0;
} else if (!strcmp(k, "merge.defaulttoupstream")) {
@@ -861,7 +877,7 @@ static int finish_automerge(struct commit *head,
free_commit_list(common);
parents = remoteheads;
- if (!head_subsumed || !allow_fast_forward)
+ if (!head_subsumed || fast_forward == FF_NO)
commit_list_insert(head, &parents);
strbuf_addch(&merge_msg, '\n');
prepare_to_commit(remoteheads);
@@ -887,7 +903,7 @@ static int suggest_conflicts(int renormalizing)
die_errno(_("Could not open '%s' for writing"), filename);
fprintf(fp, "\nConflicts:\n");
for (pos = 0; pos < active_nr; pos++) {
- struct cache_entry *ce = active_cache[pos];
+ const struct cache_entry *ce = active_cache[pos];
if (ce_stage(ce)) {
fprintf(fp, "\t%s\n", ce->name);
@@ -946,7 +962,7 @@ static int evaluate_result(void)
}
/*
- * Pretend as if the user told us to merge with the tracking
+ * Pretend as if the user told us to merge with the remote-tracking
* branch we have for the upstream of the current branch
*/
static int setup_with_upstream(const char ***argv)
@@ -965,7 +981,7 @@ static int setup_with_upstream(const char ***argv)
args = xcalloc(branch->merge_nr + 1, sizeof(char *));
for (i = 0; i < branch->merge_nr; i++) {
if (!branch->merge[i]->dst)
- die(_("No remote tracking branch for %s from %s"),
+ die(_("No remote-tracking branch for %s from %s"),
branch->merge[i]->src, branch->remote_name);
args[i] = branch->merge[i]->dst;
}
@@ -1006,7 +1022,7 @@ static void write_merge_state(struct commit_list *remoteheads)
if (fd < 0)
die_errno(_("Could not open '%s' for writing"), filename);
strbuf_reset(&buf);
- if (!allow_fast_forward)
+ if (fast_forward == FF_NO)
strbuf_addf(&buf, "no-ff");
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
die_errno(_("Could not write to '%s'"), filename);
@@ -1052,7 +1068,8 @@ static struct commit_list *collect_parents(struct commit *head_commit,
for (i = 0; i < argc; i++) {
struct commit *commit = get_merge_parent(argv[i]);
if (!commit)
- die(_("%s - not something we can merge"), argv[i]);
+ help_unknown_ref(argv[i], "merge",
+ "not something we can merge");
remotes = &commit_list_insert(commit, remotes)->next;
}
*remotes = NULL;
@@ -1154,14 +1171,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
show_diffstat = 0;
if (squash) {
- if (!allow_fast_forward)
+ if (fast_forward == FF_NO)
die(_("You cannot combine --squash with --no-ff."));
option_commit = 0;
}
- if (!allow_fast_forward && fast_forward_only)
- die(_("You cannot combine --no-ff with --ff-only."));
-
if (!abort_current_merge) {
if (!argc) {
if (default_to_upstream)
@@ -1203,7 +1217,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
"empty head"));
if (squash)
die(_("Squash commit into empty head not supported yet"));
- if (!allow_fast_forward)
+ if (fast_forward == FF_NO)
die(_("Non-fast-forward commit does not make sense into "
"an empty head"));
remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
@@ -1246,6 +1260,39 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
usage_with_options(builtin_merge_usage,
builtin_merge_options);
+ if (verify_signatures) {
+ for (p = remoteheads; p; p = p->next) {
+ struct commit *commit = p->item;
+ char hex[41];
+ struct signature_check signature_check;
+ memset(&signature_check, 0, sizeof(signature_check));
+
+ check_commit_signature(commit, &signature_check);
+
+ strcpy(hex, find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
+ switch (signature_check.result) {
+ case 'G':
+ break;
+ case 'U':
+ die(_("Commit %s has an untrusted GPG signature, "
+ "allegedly by %s."), hex, signature_check.signer);
+ case 'B':
+ die(_("Commit %s has a bad GPG signature "
+ "allegedly by %s."), hex, signature_check.signer);
+ default: /* 'N' */
+ die(_("Commit %s does not have a GPG signature."), hex);
+ }
+ if (verbosity >= 0 && signature_check.result == 'G')
+ printf(_("Commit %s has a good GPG signature by %s\n"),
+ hex, signature_check.signer);
+
+ free(signature_check.gpg_output);
+ free(signature_check.gpg_status);
+ free(signature_check.signer);
+ free(signature_check.key);
+ }
+ }
+
strbuf_addstr(&buf, "merge");
for (p = remoteheads; p; p = p->next)
strbuf_addf(&buf, " %s", merge_remote_util(p->item)->name);
@@ -1258,11 +1305,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
sha1_to_hex(commit->object.sha1));
setenv(buf.buf, merge_remote_util(commit)->name, 1);
strbuf_reset(&buf);
- if (!fast_forward_only &&
+ if (fast_forward != FF_ONLY &&
merge_remote_util(commit) &&
merge_remote_util(commit)->obj &&
merge_remote_util(commit)->obj->type == OBJ_TAG)
- allow_fast_forward = 0;
+ fast_forward = FF_NO;
}
if (option_edit < 0)
@@ -1279,7 +1326,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
for (i = 0; i < use_strategies_nr; i++) {
if (use_strategies[i]->attr & NO_FAST_FORWARD)
- allow_fast_forward = 0;
+ fast_forward = FF_NO;
if (use_strategies[i]->attr & NO_TRIVIAL)
allow_trivial = 0;
}
@@ -1309,7 +1356,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
*/
finish_up_to_date("Already up-to-date.");
goto done;
- } else if (allow_fast_forward && !remoteheads->next &&
+ } else if (fast_forward != FF_NO && !remoteheads->next &&
!common->next &&
!hashcmp(common->item->object.sha1, head_commit->object.sha1)) {
/* Again the most common case of merging one remote. */
@@ -1356,7 +1403,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* only one common.
*/
refresh_cache(REFRESH_QUIET);
- if (allow_trivial && !fast_forward_only) {
+ if (allow_trivial && fast_forward != FF_ONLY) {
/* See if it is really trivial. */
git_committer_info(IDENT_STRICT);
printf(_("Trying really trivial in-index merge...\n"));
@@ -1397,7 +1444,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
}
- if (fast_forward_only)
+ if (fast_forward == FF_ONLY)
die(_("Not possible to fast-forward, aborting."));
/* We are going to make a new commit. */
diff --git a/builtin/mv.c b/builtin/mv.c
index 034fec9..aec79d1 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -9,14 +9,16 @@
#include "cache-tree.h"
#include "string-list.h"
#include "parse-options.h"
+#include "submodule.h"
static const char * const builtin_mv_usage[] = {
N_("git mv [options] <source>... <destination>"),
NULL
};
-static const char **copy_pathspec(const char *prefix, const char **pathspec,
- int count, int base_name)
+static const char **internal_copy_pathspec(const char *prefix,
+ const char **pathspec,
+ int count, int base_name)
{
int i;
const char **result = xmalloc((count + 1) * sizeof(const char *));
@@ -56,20 +58,21 @@ static struct lock_file lock_file;
int cmd_mv(int argc, const char **argv, const char *prefix)
{
- int i, newfd;
+ int i, newfd, gitmodules_modified = 0;
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
struct option builtin_mv_options[] = {
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_BOOL('k', NULL, &ignore_errors, N_("skip move/rename errors")),
OPT_END(),
};
- const char **source, **destination, **dest_path;
+ const char **source, **destination, **dest_path, **submodule_gitfile;
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
struct stat st;
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
+ gitmodules_config();
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_mv_options,
@@ -81,17 +84,18 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die(_("index file corrupt"));
- source = copy_pathspec(prefix, argv, argc, 0);
+ source = internal_copy_pathspec(prefix, argv, argc, 0);
modes = xcalloc(argc, sizeof(enum update_mode));
- dest_path = copy_pathspec(prefix, argv + argc, 1, 0);
+ dest_path = internal_copy_pathspec(prefix, argv + argc, 1, 0);
+ submodule_gitfile = xcalloc(argc, sizeof(char *));
if (dest_path[0][0] == '\0')
/* special case: "." was normalized to "" */
- destination = copy_pathspec(dest_path[0], argv, argc, 1);
+ destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
else if (!lstat(dest_path[0], &st) &&
S_ISDIR(st.st_mode)) {
dest_path[0] = add_slash(dest_path[0]);
- destination = copy_pathspec(dest_path[0], argv, argc, 1);
+ destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
} else {
if (argc != 1)
die("destination '%s' is not a directory", dest_path[0]);
@@ -117,55 +121,68 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
&& lstat(dst, &st) == 0)
bad = _("cannot move directory over file");
else if (src_is_dir) {
- const char *src_w_slash = add_slash(src);
- int len_w_slash = length + 1;
- int first, last;
-
- modes[i] = WORKING_DIRECTORY;
-
- first = cache_name_pos(src_w_slash, len_w_slash);
- if (first >= 0)
- die (_("Huh? %.*s is in index?"),
- len_w_slash, src_w_slash);
-
- first = -1 - first;
- for (last = first; last < active_nr; last++) {
- const char *path = active_cache[last]->name;
- if (strncmp(path, src_w_slash, len_w_slash))
- break;
- }
- free((char *)src_w_slash);
-
- if (last - first < 1)
- bad = _("source directory is empty");
- else {
- int j, dst_len;
-
- if (last - first > 0) {
- source = xrealloc(source,
- (argc + last - first)
- * sizeof(char *));
- destination = xrealloc(destination,
- (argc + last - first)
- * sizeof(char *));
- modes = xrealloc(modes,
- (argc + last - first)
- * sizeof(enum update_mode));
+ int first = cache_name_pos(src, length);
+ if (first >= 0) {
+ struct strbuf submodule_dotgit = STRBUF_INIT;
+ if (!S_ISGITLINK(active_cache[first]->ce_mode))
+ die (_("Huh? Directory %s is in index and no submodule?"), src);
+ if (!is_staging_gitmodules_ok())
+ die (_("Please, stage your changes to .gitmodules or stash them to proceed"));
+ strbuf_addf(&submodule_dotgit, "%s/.git", src);
+ submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf);
+ if (submodule_gitfile[i])
+ submodule_gitfile[i] = xstrdup(submodule_gitfile[i]);
+ strbuf_release(&submodule_dotgit);
+ } else {
+ const char *src_w_slash = add_slash(src);
+ int last, len_w_slash = length + 1;
+
+ modes[i] = WORKING_DIRECTORY;
+
+ first = cache_name_pos(src_w_slash, len_w_slash);
+ if (first >= 0)
+ die (_("Huh? %.*s is in index?"),
+ len_w_slash, src_w_slash);
+
+ first = -1 - first;
+ for (last = first; last < active_nr; last++) {
+ const char *path = active_cache[last]->name;
+ if (strncmp(path, src_w_slash, len_w_slash))
+ break;
}
+ free((char *)src_w_slash);
+
+ if (last - first < 1)
+ bad = _("source directory is empty");
+ else {
+ int j, dst_len;
- dst = add_slash(dst);
- dst_len = strlen(dst);
-
- for (j = 0; j < last - first; j++) {
- const char *path =
- active_cache[first + j]->name;
- source[argc + j] = path;
- destination[argc + j] =
- prefix_path(dst, dst_len,
- path + length + 1);
- modes[argc + j] = INDEX;
+ if (last - first > 0) {
+ source = xrealloc(source,
+ (argc + last - first)
+ * sizeof(char *));
+ destination = xrealloc(destination,
+ (argc + last - first)
+ * sizeof(char *));
+ modes = xrealloc(modes,
+ (argc + last - first)
+ * sizeof(enum update_mode));
+ }
+
+ dst = add_slash(dst);
+ dst_len = strlen(dst);
+
+ for (j = 0; j < last - first; j++) {
+ const char *path =
+ active_cache[first + j]->name;
+ source[argc + j] = path;
+ destination[argc + j] =
+ prefix_path(dst, dst_len,
+ path + length + 1);
+ modes[argc + j] = INDEX;
+ }
+ argc += last - first;
}
- argc += last - first;
}
} else if (cache_name_pos(src, length) < 0)
bad = _("not under version control");
@@ -210,9 +227,14 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
int pos;
if (show_only || verbose)
printf(_("Renaming %s to %s\n"), src, dst);
- if (!show_only && mode != INDEX &&
- rename(src, dst) < 0 && !ignore_errors)
- die_errno (_("renaming '%s' failed"), src);
+ if (!show_only && mode != INDEX) {
+ if (rename(src, dst) < 0 && !ignore_errors)
+ die_errno (_("renaming '%s' failed"), src);
+ if (submodule_gitfile[i])
+ connect_work_tree_and_git_dir(dst, submodule_gitfile[i]);
+ if (!update_path_in_gitmodules(src, dst))
+ gitmodules_modified = 1;
+ }
if (mode == WORKING_DIRECTORY)
continue;
@@ -223,6 +245,9 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
rename_cache_entry_at(pos, dst);
}
+ if (gitmodules_modified)
+ stage_updated_gitmodules();
+
if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
commit_locked_index(&lock_file))
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 6238247..20fcf8c 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -4,6 +4,7 @@
#include "tag.h"
#include "refs.h"
#include "parse-options.h"
+#include "sha1-lookup.h"
#define CUTOFF_DATE_SLOP 86400 /* one day */
@@ -82,23 +83,88 @@ copy_data:
}
}
+static int subpath_matches(const char *path, const char *filter)
+{
+ const char *subpath = path;
+
+ while (subpath) {
+ if (!fnmatch(filter, subpath, 0))
+ return subpath - path;
+ subpath = strchr(subpath, '/');
+ if (subpath)
+ subpath++;
+ }
+ return -1;
+}
+
+static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
+{
+ if (shorten_unambiguous)
+ refname = shorten_unambiguous_ref(refname, 0);
+ else if (!prefixcmp(refname, "refs/heads/"))
+ refname = refname + 11;
+ else if (!prefixcmp(refname, "refs/"))
+ refname = refname + 5;
+ return refname;
+}
+
struct name_ref_data {
int tags_only;
int name_only;
const char *ref_filter;
};
+static struct tip_table {
+ struct tip_table_entry {
+ unsigned char sha1[20];
+ const char *refname;
+ } *table;
+ int nr;
+ int alloc;
+ int sorted;
+} tip_table;
+
+static void add_to_tip_table(const unsigned char *sha1, const char *refname,
+ int shorten_unambiguous)
+{
+ refname = name_ref_abbrev(refname, shorten_unambiguous);
+
+ ALLOC_GROW(tip_table.table, tip_table.nr + 1, tip_table.alloc);
+ hashcpy(tip_table.table[tip_table.nr].sha1, sha1);
+ tip_table.table[tip_table.nr].refname = xstrdup(refname);
+ tip_table.nr++;
+ tip_table.sorted = 0;
+}
+
+static int tipcmp(const void *a_, const void *b_)
+{
+ const struct tip_table_entry *a = a_, *b = b_;
+ return hashcmp(a->sha1, b->sha1);
+}
+
static int name_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data)
{
struct object *o = parse_object(sha1);
struct name_ref_data *data = cb_data;
+ int can_abbreviate_output = data->tags_only && data->name_only;
int deref = 0;
if (data->tags_only && prefixcmp(path, "refs/tags/"))
return 0;
- if (data->ref_filter && fnmatch(data->ref_filter, path, 0))
- return 0;
+ if (data->ref_filter) {
+ switch (subpath_matches(path, data->ref_filter)) {
+ case -1: /* did not match */
+ return 0;
+ case 0: /* matched fully */
+ break;
+ default: /* matched subpath */
+ can_abbreviate_output = 1;
+ break;
+ }
+ }
+
+ add_to_tip_table(sha1, path, can_abbreviate_output);
while (o && o->type == OBJ_TAG) {
struct tag *t = (struct tag *) o;
@@ -110,20 +176,38 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
if (o && o->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *)o;
- if (!prefixcmp(path, "refs/heads/"))
- path = path + 11;
- else if (data->tags_only
- && data->name_only
- && !prefixcmp(path, "refs/tags/"))
- path = path + 10;
- else if (!prefixcmp(path, "refs/"))
- path = path + 5;
-
+ path = name_ref_abbrev(path, can_abbreviate_output);
name_rev(commit, xstrdup(path), 0, 0, deref);
}
return 0;
}
+static const unsigned char *nth_tip_table_ent(size_t ix, void *table_)
+{
+ struct tip_table_entry *table = table_;
+ return table[ix].sha1;
+}
+
+static const char *get_exact_ref_match(const struct object *o)
+{
+ int found;
+
+ if (!tip_table.table || !tip_table.nr)
+ return NULL;
+
+ if (!tip_table.sorted) {
+ qsort(tip_table.table, tip_table.nr, sizeof(*tip_table.table),
+ tipcmp);
+ tip_table.sorted = 1;
+ }
+
+ found = sha1_pos(o->sha1, tip_table.table, tip_table.nr,
+ nth_tip_table_ent);
+ if (0 <= found)
+ return tip_table.table[found].refname;
+ return NULL;
+}
+
/* returns a static buffer */
static const char *get_rev_name(const struct object *o)
{
@@ -132,7 +216,7 @@ static const char *get_rev_name(const struct object *o)
struct commit *c;
if (o->type != OBJ_COMMIT)
- return NULL;
+ return get_exact_ref_match(o);
c = (struct commit *) o;
n = c->util;
if (!n)
@@ -223,25 +307,31 @@ static void name_rev_line(char *p, struct name_ref_data *data)
int cmd_name_rev(int argc, const char **argv, const char *prefix)
{
struct object_array revs = OBJECT_ARRAY_INIT;
- int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0;
+ int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
struct name_ref_data data = { 0, 0, NULL };
struct option opts[] = {
- 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_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
+ OPT_BOOL(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, 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,
+ OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
+ OPT_BOOL(0, "stdin", &transform_stdin, N_("read from stdin")),
+ OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
+ OPT_BOOL(0, "always", &always,
N_("show abbreviated commit object as fallback")),
+ {
+ /* A Hidden OPT_BOOL */
+ OPTION_SET_INT, 0, "peel-tag", &peel_tag, NULL,
+ N_("dereference tags in the input (internal use)"),
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1,
+ },
OPT_END(),
};
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
- if (!!all + !!transform_stdin + !!argc > 1) {
+ if (all + transform_stdin + !!argc > 1) {
error("Specify either a list, or --all, not both!");
usage_with_options(name_rev_usage, opts);
}
@@ -250,7 +340,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
for (; argc; argc--, argv++) {
unsigned char sha1[20];
- struct object *o;
+ struct object *object;
struct commit *commit;
if (get_sha1(*argv, sha1)) {
@@ -259,17 +349,34 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
continue;
}
- o = deref_tag(parse_object(sha1), *argv, 0);
- if (!o || o->type != OBJ_COMMIT) {
- fprintf(stderr, "Could not get commit for %s. Skipping.\n",
+ commit = NULL;
+ object = parse_object(sha1);
+ if (object) {
+ struct object *peeled = deref_tag(object, *argv, 0);
+ if (peeled && peeled->type == OBJ_COMMIT)
+ commit = (struct commit *)peeled;
+ }
+
+ if (!object) {
+ fprintf(stderr, "Could not get object for %s. Skipping.\n",
*argv);
continue;
}
- commit = (struct commit *)o;
- if (cutoff > commit->date)
- cutoff = commit->date;
- add_object_array((struct object *)commit, *argv, &revs);
+ if (commit) {
+ if (cutoff > commit->date)
+ cutoff = commit->date;
+ }
+
+ if (peel_tag) {
+ if (!commit) {
+ fprintf(stderr, "Could not get commit for %s. Skipping.\n",
+ *argv);
+ continue;
+ }
+ object = (struct object *)commit;
+ }
+ add_object_array(object, *argv, &revs);
}
if (cutoff)
diff --git a/builtin/notes.c b/builtin/notes.c
index 57748a6..d459e23 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -4,7 +4,7 @@
* Copyright (c) 2010 Johan Herland <johan@herland.net>
*
* Based on git-notes.sh by Johannes Schindelin,
- * and builtin-tag.c by Kristian Høgsberg and Carlos Rica.
+ * and builtin/tag.c by Kristian Høgsberg and Carlos Rica.
*/
#include "cache.h"
@@ -18,9 +18,7 @@
#include "parse-options.h"
#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);
+#include "notes-utils.h"
static const char * const git_notes_usage[] = {
N_("git notes [--ref <notes_ref>] [list [<object>]]"),
@@ -287,139 +285,13 @@ static int parse_reedit_arg(const struct option *opt, const char *arg, int unset
return parse_reuse_arg(opt, arg, unset);
}
-static void commit_notes(struct notes_tree *t, const char *msg)
-{
- struct strbuf buf = STRBUF_INIT;
- unsigned char commit_sha1[20];
-
- if (!t)
- t = &default_notes_tree;
- if (!t->initialized || !t->ref || !*t->ref)
- die(_("Cannot commit uninitialized/unreferenced notes tree"));
- if (!t->dirty)
- return; /* don't have to commit an unchanged tree */
-
- /* Prepare commit message and reflog message */
- strbuf_addstr(&buf, msg);
- if (buf.buf[buf.len - 1] != '\n')
- strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
-
- create_notes_commit(t, NULL, &buf, commit_sha1);
- strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
- update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, DIE_ON_ERR);
-
- strbuf_release(&buf);
-}
-
-static combine_notes_fn parse_combine_notes_fn(const char *v)
-{
- if (!strcasecmp(v, "overwrite"))
- return combine_notes_overwrite;
- else if (!strcasecmp(v, "ignore"))
- return combine_notes_ignore;
- else if (!strcasecmp(v, "concatenate"))
- return combine_notes_concatenate;
- else if (!strcasecmp(v, "cat_sort_uniq"))
- return combine_notes_cat_sort_uniq;
- else
- return NULL;
-}
-
-static int notes_rewrite_config(const char *k, const char *v, void *cb)
-{
- struct notes_rewrite_cfg *c = cb;
- if (!prefixcmp(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) {
- c->enabled = git_config_bool(k, v);
- return 0;
- } else if (!c->mode_from_env && !strcmp(k, "notes.rewritemode")) {
- if (!v)
- config_error_nonbool(k);
- c->combine = parse_combine_notes_fn(v);
- if (!c->combine) {
- error(_("Bad notes.rewriteMode value: '%s'"), v);
- return 1;
- }
- return 0;
- } else if (!c->refs_from_env && !strcmp(k, "notes.rewriteref")) {
- /* note that a refs/ prefix is implied in the
- * underlying for_each_glob_ref */
- if (!prefixcmp(v, "refs/notes/"))
- string_list_add_refs_by_glob(c->refs, v);
- else
- warning(_("Refusing to rewrite notes in %s"
- " (outside of refs/notes/)"), v);
- return 0;
- }
-
- return 0;
-}
-
-
-struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd)
-{
- struct notes_rewrite_cfg *c = xmalloc(sizeof(struct notes_rewrite_cfg));
- const char *rewrite_mode_env = getenv(GIT_NOTES_REWRITE_MODE_ENVIRONMENT);
- const char *rewrite_refs_env = getenv(GIT_NOTES_REWRITE_REF_ENVIRONMENT);
- c->cmd = cmd;
- c->enabled = 1;
- c->combine = combine_notes_concatenate;
- c->refs = xcalloc(1, sizeof(struct string_list));
- c->refs->strdup_strings = 1;
- c->refs_from_env = 0;
- c->mode_from_env = 0;
- if (rewrite_mode_env) {
- c->mode_from_env = 1;
- c->combine = parse_combine_notes_fn(rewrite_mode_env);
- if (!c->combine)
- /* TRANSLATORS: The first %s is the name of the
- environment variable, the second %s is its value */
- error(_("Bad %s value: '%s'"), GIT_NOTES_REWRITE_MODE_ENVIRONMENT,
- rewrite_mode_env);
- }
- if (rewrite_refs_env) {
- c->refs_from_env = 1;
- string_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env);
- }
- git_config(notes_rewrite_config, c);
- if (!c->enabled || !c->refs->nr) {
- string_list_clear(c->refs, 0);
- free(c->refs);
- free(c);
- return NULL;
- }
- c->trees = load_notes_trees(c->refs);
- string_list_clear(c->refs, 0);
- free(c->refs);
- return c;
-}
-
-int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
- const unsigned char *from_obj, const unsigned char *to_obj)
-{
- int ret = 0;
- int i;
- for (i = 0; c->trees[i]; i++)
- ret = copy_note(c->trees[i], from_obj, to_obj, 1, c->combine) || ret;
- return ret;
-}
-
-void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c)
-{
- int i;
- for (i = 0; c->trees[i]; i++) {
- commit_notes(c->trees[i], "Notes added by 'git notes copy'");
- free_notes(c->trees[i]);
- }
- free(c->trees);
- free(c);
-}
-
static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
{
struct strbuf buf = STRBUF_INIT;
struct notes_rewrite_cfg *c = NULL;
struct notes_tree *t = NULL;
int ret = 0;
+ const char *msg = "Notes added by 'git notes copy'";
if (rewrite_cmd) {
c = init_copy_notes_for_rewrite(rewrite_cmd);
@@ -461,10 +333,10 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
}
if (!rewrite_cmd) {
- commit_notes(t, "Notes added by 'git notes copy'");
+ commit_notes(t, msg);
free_notes(t);
} else {
- finish_copy_notes_for_rewrite(c);
+ finish_copy_notes_for_rewrite(c, msg);
}
return ret;
}
@@ -611,7 +483,7 @@ static int copy(int argc, const char **argv, const char *prefix)
const char *rewrite_cmd = NULL;
struct option options[] = {
OPT__FORCE(&force, N_("replace existing notes")),
- OPT_BOOLEAN(0, "stdin", &from_stdin, N_("read objects from stdin")),
+ OPT_BOOL(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)")),
@@ -867,13 +739,13 @@ static int merge(int argc, const char **argv, const char *prefix)
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,
+ { OPTION_SET_INT, 0, "commit", &do_commit, NULL,
N_("finalize notes merge by committing unmerged notes"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG },
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
OPT_GROUP(N_("Aborting notes merge resolution")),
- { OPTION_BOOLEAN, 0, "abort", &do_abort, NULL,
+ { OPTION_SET_INT, 0, "abort", &do_abort, NULL,
N_("abort notes merge"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG },
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
OPT_END()
};
@@ -981,7 +853,7 @@ static int remove_cmd(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "ignore-missing", &flag,
N_("attempt to remove non-existent note is not an error"),
IGNORE_MISSING),
- OPT_BOOLEAN(0, "stdin", &from_stdin,
+ OPT_BOOL(0, "stdin", &from_stdin,
N_("read object names from the standard input")),
OPT_END()
};
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index f069462..4eb0521 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1809,7 +1809,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
static void try_to_free_from_threads(size_t size)
{
read_lock();
- release_pack_memory(size, -1);
+ release_pack_memory(size);
read_unlock();
}
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index b5a0f88..b20b1ec 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -1,6 +1,6 @@
#include "builtin.h"
#include "parse-options.h"
-#include "pack-refs.h"
+#include "refs.h"
static char const * const pack_refs_usage[] = {
N_("git pack-refs [options]"),
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index 83382c1..fa6ce42 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -8,9 +8,6 @@ static const char * const prune_packed_usage[] = {
NULL
};
-#define DRY_RUN 01
-#define VERBOSE 02
-
static struct progress *progress;
static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
@@ -29,7 +26,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
if (!has_sha1_pack(sha1))
continue;
memcpy(pathname + len, de->d_name, 38);
- if (opts & DRY_RUN)
+ if (opts & PRUNE_PACKED_DRY_RUN)
printf("rm -f %s\n", pathname);
else
unlink_or_warn(pathname);
@@ -44,7 +41,7 @@ void prune_packed_objects(int opts)
const char *dir = get_object_directory();
int len = strlen(dir);
- if (opts == VERBOSE)
+ if (opts & PRUNE_PACKED_VERBOSE)
progress = start_progress_delay("Removing duplicate objects",
256, 95, 2);
@@ -71,10 +68,12 @@ void prune_packed_objects(int opts)
int cmd_prune_packed(int argc, const char **argv, const char *prefix)
{
- int opts = isatty(2) ? VERBOSE : 0;
+ int opts = isatty(2) ? PRUNE_PACKED_VERBOSE : 0;
const struct option prune_packed_options[] = {
- OPT_BIT('n', "dry-run", &opts, N_("dry run"), DRY_RUN),
- OPT_NEGBIT('q', "quiet", &opts, N_("be quiet"), VERBOSE),
+ OPT_BIT('n', "dry-run", &opts, N_("dry run"),
+ PRUNE_PACKED_DRY_RUN),
+ OPT_NEGBIT('q', "quiet", &opts, N_("be quiet"),
+ PRUNE_PACKED_VERBOSE),
OPT_END()
};
diff --git a/builtin/prune.c b/builtin/prune.c
index 85843d4..6366917 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -132,8 +132,8 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
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,
- N_("expire objects older than <time>")),
+ OPT_EXPIRY_DATE(0, "expire", &expire,
+ N_("expire objects older than <time>")),
OPT_END()
};
char *s;
@@ -165,7 +165,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
stop_progress(&progress);
prune_object_dir(get_object_directory());
- prune_packed_objects(show_only);
+ prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0);
remove_temporary_files(get_object_directory());
s = mkpathdup("%s/pack", get_object_directory());
remove_temporary_files(s);
diff --git a/builtin/push.c b/builtin/push.c
index 42b129d..7b1b66c 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -15,12 +15,14 @@ static const char * const push_usage[] = {
NULL,
};
-static int thin;
+static int thin = 1;
static int deleterefs;
static const char *receivepack;
static int verbosity;
static int progress = -1;
+static struct push_cas_option cas;
+
static const char **refspec;
static int refspec_nr;
static int refspec_alloc;
@@ -92,7 +94,7 @@ static NORETURN int die_push_simple(struct branch *branch, struct remote *remote
if (!short_upstream)
short_upstream = branch->merge[0]->src;
/*
- * Don't show advice for people who explicitely set
+ * Don't show advice for people who explicitly set
* push.default.
*/
if (push_default == PUSH_DEFAULT_UNSPECIFIED)
@@ -113,17 +115,20 @@ static NORETURN int die_push_simple(struct branch *branch, struct remote *remote
remote->name, branch->name, advice_maybe);
}
-static void setup_push_upstream(struct remote *remote, int simple)
+static const char message_detached_head_die[] =
+ N_("You are not currently on a branch.\n"
+ "To push the history leading to the current (detached HEAD)\n"
+ "state now, use\n"
+ "\n"
+ " git push %s HEAD:<name-of-remote-branch>\n");
+
+static void setup_push_upstream(struct remote *remote, struct branch *branch,
+ int triangular)
{
struct strbuf refspec = STRBUF_INIT;
- struct branch *branch = branch_get(NULL);
+
if (!branch)
- die(_("You are not currently on a branch.\n"
- "To push the history leading to the current (detached HEAD)\n"
- "state now, use\n"
- "\n"
- " git push %s HEAD:<name-of-remote-branch>\n"),
- remote->name);
+ die(_(message_detached_head_die), remote->name);
if (!branch->merge_nr || !branch->merge || !branch->remote_name)
die(_("The current branch %s has no upstream branch.\n"
"To push the current branch and set the remote as upstream, use\n"
@@ -135,18 +140,29 @@ static void setup_push_upstream(struct remote *remote, int simple)
if (branch->merge_nr != 1)
die(_("The current branch %s has multiple upstream branches, "
"refusing to push."), branch->name);
- if (strcmp(branch->remote_name, remote->name))
+ if (triangular)
die(_("You are pushing to remote '%s', which is not the upstream of\n"
"your current branch '%s', without telling me what to push\n"
"to update which remote branch."),
remote->name, branch->name);
- if (simple && strcmp(branch->refname, branch->merge[0]->src))
- die_push_simple(branch, remote);
+
+ if (push_default == PUSH_DEFAULT_SIMPLE) {
+ /* Additional safety */
+ if (strcmp(branch->refname, branch->merge[0]->src))
+ die_push_simple(branch, remote);
+ }
strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
add_refspec(refspec.buf);
}
+static void setup_push_current(struct remote *remote, struct branch *branch)
+{
+ if (!branch)
+ die(_(message_detached_head_die), remote->name);
+ add_refspec(branch->name);
+}
+
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"
@@ -171,8 +187,17 @@ static void warn_unspecified_push_default_configuration(void)
warning("%s\n", _(warn_unspecified_push_default_msg));
}
+static int is_workflow_triangular(struct remote *remote)
+{
+ struct remote *fetch_remote = remote_get(NULL);
+ return (fetch_remote && fetch_remote != remote);
+}
+
static void setup_default_push_refspecs(struct remote *remote)
{
+ struct branch *branch = branch_get(NULL);
+ int triangular = is_workflow_triangular(remote);
+
switch (push_default) {
default:
case PUSH_DEFAULT_UNSPECIFIED:
@@ -184,15 +209,18 @@ static void setup_default_push_refspecs(struct remote *remote)
break;
case PUSH_DEFAULT_SIMPLE:
- setup_push_upstream(remote, 1);
+ if (triangular)
+ setup_push_current(remote, branch);
+ else
+ setup_push_upstream(remote, branch, triangular);
break;
case PUSH_DEFAULT_UPSTREAM:
- setup_push_upstream(remote, 0);
+ setup_push_upstream(remote, branch, triangular);
break;
case PUSH_DEFAULT_CURRENT:
- add_refspec("HEAD");
+ setup_push_current(remote, branch);
break;
case PUSH_DEFAULT_NOTHING:
@@ -204,8 +232,8 @@ static void setup_default_push_refspecs(struct remote *remote)
static const char message_advice_pull_before_push[] =
N_("Updates were rejected because the tip of your current branch is behind\n"
- "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
- "before pushing again.\n"
+ "its remote counterpart. Integrate the remote changes (e.g.\n"
+ "'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details.");
static const char message_advice_use_upstream[] =
@@ -216,15 +244,15 @@ static const char message_advice_use_upstream[] =
static const char message_advice_checkout_pull_push[] =
N_("Updates were rejected because a pushed branch tip is behind its remote\n"
- "counterpart. Check out this branch and merge the remote changes\n"
- "(e.g. 'git pull') before pushing again.\n"
+ "counterpart. Check out this branch and integrate the remote changes\n"
+ "(e.g. 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details.");
static const char message_advice_ref_fetch_first[] =
N_("Updates were rejected because the remote contains work that you do\n"
"not have locally. This is usually caused by another repository pushing\n"
- "to the same ref. You may want to first merge the remote changes (e.g.,\n"
- "'git pull') before pushing again.\n"
+ "to the same ref. You may want to first integrate the remote changes\n"
+ "(e.g., 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details.");
static const char message_advice_ref_already_exists[] =
@@ -287,8 +315,14 @@ static int push_with_options(struct transport *transport, int flags)
if (receivepack)
transport_set_option(transport,
TRANS_OPT_RECEIVEPACK, receivepack);
- if (thin)
- transport_set_option(transport, TRANS_OPT_THIN, "yes");
+ transport_set_option(transport, TRANS_OPT_THIN, thin ? "yes" : NULL);
+
+ if (!is_empty_cas(&cas)) {
+ if (!transport->smart_options)
+ die("underlying transport does not support --%s option",
+ CAS_OPT_NAME);
+ transport->smart_options->cas = &cas;
+ }
if (verbosity > 0)
fprintf(stderr, _("Pushing to %s\n"), transport->url);
@@ -322,7 +356,7 @@ static int push_with_options(struct transport *transport, int flags)
static int do_push(const char *repo, int flags)
{
int i, errs;
- struct remote *remote = remote_get(repo);
+ struct remote *remote = pushremote_get(repo);
const char **url;
int url_nr;
@@ -420,15 +454,19 @@ int cmd_push(int argc, const char **argv, const char *prefix)
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, N_("delete refs")),
- OPT_BOOLEAN( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+ OPT_BOOL( 0, "delete", &deleterefs, N_("delete refs")),
+ OPT_BOOL( 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, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
+ N_("require old value of ref to be at this value"),
+ PARSE_OPT_OPTARG, parseopt_push_cas_option },
{ 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, N_("use thin pack")),
+ OPT_BOOL( 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"),
@@ -437,6 +475,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"),
TRANSPORT_PUSH_PRUNE),
OPT_BIT(0, "no-verify", &flags, N_("bypass pre-push hook"), TRANSPORT_PUSH_NO_HOOK),
+ OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"),
+ TRANSPORT_PUSH_FOLLOW_TAGS),
OPT_END()
};
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 042ac1b..0f5d7fe 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -66,7 +66,7 @@ static int exclude_per_directory_cb(const struct option *opt, const char *arg,
return 0;
}
-static void debug_stage(const char *label, struct cache_entry *ce,
+static void debug_stage(const char *label, const struct cache_entry *ce,
struct unpack_trees_options *o)
{
printf("%s ", label);
@@ -80,7 +80,8 @@ static void debug_stage(const char *label, struct cache_entry *ce,
sha1_to_hex(ce->sha1));
}
-static int debug_merge(struct cache_entry **stages, struct unpack_trees_options *o)
+static int debug_merge(const struct cache_entry * const *stages,
+ struct unpack_trees_options *o)
{
int i;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 89792b0..b7e71a0 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -8,6 +8,7 @@
#include "commit.h"
#include "object.h"
#include "remote.h"
+#include "connect.h"
#include "transport.h"
#include "string-list.h"
#include "sha1-array.h"
@@ -38,6 +39,7 @@ static int quiet;
static int prefer_ofs_delta = 1;
static int auto_update_server_info;
static int auto_gc = 1;
+static int fix_thin = 1;
static const char *head_name;
static void *head_name_to_free;
static int sent_capabilities;
@@ -754,17 +756,15 @@ static struct command *read_head_info(void)
struct command *commands = NULL;
struct command **p = &commands;
for (;;) {
- static char line[1000];
+ char *line;
unsigned char old_sha1[20], new_sha1[20];
struct command *cmd;
char *refname;
int len, reflen;
- len = packet_read_line(0, line, sizeof(line));
- if (!len)
+ line = packet_read_line(0, &len);
+ if (!line)
break;
- if (line[len-1] == '\n')
- line[--len] = 0;
if (len < 83 ||
line[40] != ' ' ||
line[81] != ' ' ||
@@ -871,7 +871,8 @@ static const char *unpack(int err_fd)
keeper[i++] = "--stdin";
if (fsck_objects)
keeper[i++] = "--strict";
- keeper[i++] = "--fix-thin";
+ if (fix_thin)
+ keeper[i++] = "--fix-thin";
keeper[i++] = hdr_arg;
keeper[i++] = keep_arg;
keeper[i++] = NULL;
@@ -935,7 +936,7 @@ static void report(struct command *commands, const char *unpack_status)
if (use_sideband)
send_sideband(1, 1, buf.buf, buf.len, use_sideband);
else
- safe_write(1, buf.buf, buf.len);
+ write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);
}
@@ -977,6 +978,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
stateless_rpc = 1;
continue;
}
+ if (!strcmp(arg, "--reject-thin-pack-for-testing")) {
+ fix_thin = 0;
+ continue;
+ }
usage(receive_pack_usage);
}
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 72a0af7..54184b3 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -496,11 +496,9 @@ static int parse_expire_cfg_value(const char *var, const char *value, unsigned l
{
if (!value)
return config_error_nonbool(var);
- if (!strcmp(value, "never") || !strcmp(value, "false")) {
- *expire = 0;
- return 0;
- }
- *expire = approxidate(value);
+ if (parse_expiry_date(value, expire))
+ return error(_("%s' for '%s' is not a valid timestamp"),
+ value, var);
return 0;
}
@@ -614,11 +612,13 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
cb.dry_run = 1;
else if (!prefixcmp(arg, "--expire=")) {
- cb.expire_total = approxidate(arg + 9);
+ if (parse_expiry_date(arg + 9, &cb.expire_total))
+ die(_("'%s' is not a valid timestamp"), arg);
explicit_expiry |= EXPIRE_TOTAL;
}
else if (!prefixcmp(arg, "--expire-unreachable=")) {
- cb.expire_unreachable = approxidate(arg + 21);
+ if (parse_expiry_date(arg + 21, &cb.expire_unreachable))
+ die(_("'%s' is not a valid timestamp"), arg);
explicit_expiry |= EXPIRE_UNREACH;
}
else if (!strcmp(arg, "--stale-fix"))
diff --git a/builtin/remote.c b/builtin/remote.c
index 5e54d36..eaac3e2 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -160,7 +160,7 @@ static int add(int argc, const char **argv)
int i;
struct option options[] = {
- OPT_BOOLEAN('f', "fetch", &fetch, N_("fetch the remote branches")),
+ OPT_BOOL('f', "fetch", &fetch, N_("fetch the remote branches")),
OPT_SET_INT(0, "tags", &fetch_tags,
N_("import all tags and associated objects when fetching"),
TAGS_SET),
@@ -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, N_("do not query remotes")),
+ OPT_BOOL('n', NULL, &no_query, N_("do not query remotes")),
OPT_END()
};
struct ref_states states;
@@ -1195,10 +1195,10 @@ static int set_head(int argc, const char **argv)
char *head_name = NULL;
struct option options[] = {
- OPT_BOOLEAN('a', "auto", &opt_a,
- N_("set refs/remotes/<name>/HEAD according to remote")),
- OPT_BOOLEAN('d', "delete", &opt_d,
- N_("delete refs/remotes/<name>/HEAD")),
+ OPT_BOOL('a', "auto", &opt_a,
+ N_("set refs/remotes/<name>/HEAD according to remote")),
+ OPT_BOOL('d', "delete", &opt_d,
+ N_("delete refs/remotes/<name>/HEAD")),
OPT_END()
};
argc = parse_options(argc, argv, NULL, options, builtin_remote_sethead_usage,
@@ -1317,8 +1317,8 @@ static int update(int argc, const char **argv)
{
int i, prune = 0;
struct option options[] = {
- OPT_BOOLEAN('p', "prune", &prune,
- N_("prune remotes after fetching")),
+ OPT_BOOL('p', "prune", &prune,
+ 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, N_("add branch")),
+ OPT_BOOL('\0', "add", &add_mode, N_("add branch")),
OPT_END()
};
@@ -1432,11 +1432,11 @@ static int set_url(int argc, const char **argv)
int urlset_nr;
struct strbuf name_buf = STRBUF_INIT;
struct option options[] = {
- OPT_BOOLEAN('\0', "push", &push_mode,
- N_("manipulate push URLs")),
- OPT_BOOLEAN('\0', "add", &add_mode,
- N_("add URL")),
- OPT_BOOLEAN('\0', "delete", &delete_mode,
+ OPT_BOOL('\0', "push", &push_mode,
+ N_("manipulate push URLs")),
+ OPT_BOOL('\0', "add", &add_mode,
+ N_("add URL")),
+ OPT_BOOL('\0', "delete", &delete_mode,
N_("delete URLs")),
OPT_END()
};
diff --git a/builtin/replace.c b/builtin/replace.c
index 398ccd5..11b0a55 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2008 Christian Couder <chriscool@tuxfamily.org>
*
- * Based on builtin-tag.c by Kristian Høgsberg <krh@redhat.com>
+ * Based on builtin/tag.c by Kristian Høgsberg <krh@redhat.com>
* and Carlos Rica <jasampler@gmail.com> that was itself based on
* git-tag.sh and mktag.c by Linus Torvalds.
*/
@@ -118,9 +118,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, 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_BOOL('l', NULL, &list, N_("list replace refs")),
+ OPT_BOOL('d', NULL, &delete, N_("delete replace refs")),
+ OPT_BOOL('f', NULL, &force, N_("replace the ref if it exists")),
OPT_END()
};
diff --git a/builtin/rerere.c b/builtin/rerere.c
index dc1708e..4e51add 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -6,6 +6,7 @@
#include "rerere.h"
#include "xdiff/xdiff.h"
#include "xdiff-interface.h"
+#include "pathspec.h"
static const char * const rerere_usage[] = {
N_("git rerere [clear | forget path... | status | remaining | diff | gc]"),
@@ -68,11 +69,12 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
return rerere(flags);
if (!strcmp(argv[0], "forget")) {
- const char **pathspec;
+ struct pathspec pathspec;
if (argc < 2)
warning("'git rerere forget' without paths is deprecated");
- pathspec = get_pathspec(prefix, argv + 1);
- return rerere_forget(pathspec);
+ parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,
+ prefix, argv + 1);
+ return rerere_forget(&pathspec);
}
fd = setup_rerere(&merge_rr, flags);
diff --git a/builtin/reset.c b/builtin/reset.c
index 6032131..5e4c551 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -93,10 +93,12 @@ static int reset_index(const unsigned char *sha1, int reset_type, int quiet)
static void print_new_head_line(struct commit *commit)
{
const char *hex, *body;
+ char *msg;
hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
printf(_("HEAD is now at %s"), hex);
- body = strstr(commit->buffer, "\n\n");
+ msg = logmsg_reencode(commit, NULL, get_log_output_encoding());
+ body = strstr(msg, "\n\n");
if (body) {
const char *eol;
size_t len;
@@ -107,6 +109,7 @@ static void print_new_head_line(struct commit *commit)
}
else
printf("\n");
+ logmsg_free(msg, commit);
}
static void update_index_from_diff(struct diff_queue_struct *q,
@@ -130,12 +133,13 @@ static void update_index_from_diff(struct diff_queue_struct *q,
}
}
-static int read_from_tree(const char **pathspec, unsigned char *tree_sha1)
+static int read_from_tree(const struct pathspec *pathspec,
+ unsigned char *tree_sha1)
{
struct diff_options opt;
memset(&opt, 0, sizeof(opt));
- diff_tree_setup_paths(pathspec, &opt);
+ copy_pathspec(&opt.pathspec, pathspec);
opt.output_format = DIFF_FORMAT_CALLBACK;
opt.format_callback = update_index_from_diff;
@@ -144,7 +148,7 @@ static int read_from_tree(const char **pathspec, unsigned char *tree_sha1)
return 1;
diffcore_std(&opt);
diff_flush(&opt);
- diff_tree_release_paths(&opt);
+ free_pathspec(&opt.pathspec);
return 0;
}
@@ -171,7 +175,10 @@ static void die_if_unmerged_cache(int reset_type)
}
-static const char **parse_args(const char **argv, const char *prefix, const char **rev_ret)
+static void parse_args(struct pathspec *pathspec,
+ const char **argv, const char *prefix,
+ int patch_mode,
+ const char **rev_ret)
{
const char *rev = "HEAD";
unsigned char unused[20];
@@ -213,7 +220,10 @@ static const char **parse_args(const char **argv, const char *prefix, const char
}
}
*rev_ret = rev;
- return argv[0] ? get_pathspec(prefix, argv) : NULL;
+ parse_pathspec(pathspec, 0,
+ PATHSPEC_PREFER_FULL |
+ (patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0),
+ prefix, argv);
}
static int update_refs(const char *rev, const unsigned char *sha1)
@@ -243,7 +253,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
int patch_mode = 0, unborn;
const char *rev;
unsigned char sha1[20];
- const char **pathspec = NULL;
+ struct pathspec pathspec;
const struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_SET_INT(0, "mixed", &reset_type,
@@ -255,7 +265,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
N_("reset HEAD, index and working tree"), MERGE),
OPT_SET_INT(0, "keep", &reset_type,
N_("reset HEAD but keep local changes"), KEEP),
- OPT_BOOLEAN('p', "patch", &patch_mode, N_("select hunks interactively")),
+ OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
OPT_END()
};
@@ -263,13 +273,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
- pathspec = parse_args(argv, prefix, &rev);
+ parse_args(&pathspec, argv, prefix, patch_mode, &rev);
unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", sha1);
if (unborn) {
/* reset on unborn branch: treat as reset to empty tree */
hashcpy(sha1, EMPTY_TREE_SHA1_BIN);
- } else if (!pathspec) {
+ } else if (!pathspec.nr) {
struct commit *commit;
if (get_sha1_committish(rev, sha1))
die(_("Failed to resolve '%s' as a valid revision."), rev);
@@ -290,13 +300,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (patch_mode) {
if (reset_type != NONE)
die(_("--patch is incompatible with --{hard,mixed,soft}"));
- return run_add_interactive(sha1_to_hex(sha1), "--patch=reset", pathspec);
+ return run_add_interactive(sha1_to_hex(sha1), "--patch=reset", &pathspec);
}
/* git reset tree [--] paths... can be used to
* load chosen paths from the tree into the index without
* affecting the working tree nor HEAD. */
- if (pathspec) {
+ if (pathspec.nr) {
if (reset_type == MIXED)
warning(_("--mixed with paths is deprecated; use 'git reset -- <paths>' instead."));
else if (reset_type != NONE)
@@ -323,7 +333,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int newfd = hold_locked_index(lock, 1);
if (reset_type == MIXED) {
- if (read_from_tree(pathspec, sha1))
+ if (read_from_tree(&pathspec, sha1))
return 1;
} else {
int err = reset_index(sha1, reset_type, quiet);
@@ -344,7 +354,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
die(_("Could not write new index file."));
}
- if (!pathspec && !unborn) {
+ if (!pathspec.nr && !unborn) {
/* Any resets without paths update HEAD to the head being
* switched to, saving the previous head in ORIG_HEAD before. */
update_ref_status = update_refs(rev, sha1);
@@ -352,7 +362,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (reset_type == HARD && !update_ref_status && !quiet)
print_new_head_line(lookup_commit_reference(sha1));
}
- if (!pathspec)
+ if (!pathspec.nr)
remove_branch_state();
return update_ref_status;
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 67701be..a5ec30d 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -111,6 +111,7 @@ static void show_commit(struct commit *commit, void *data)
ctx.date_mode = revs->date_mode;
ctx.date_mode_explicit = revs->date_mode_explicit;
ctx.fmt = revs->commit_format;
+ ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &buf);
if (revs->graph) {
if (buf.len) {
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index f267a1d..c76b89d 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -212,11 +212,17 @@ static void show_datestring(const char *flag, const char *datestr)
show(buffer);
}
-static int show_file(const char *arg)
+static int show_file(const char *arg, int output_prefix)
{
show_default();
if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
- show(arg);
+ if (output_prefix) {
+ const char *prefix = startup_info->prefix;
+ show(prefix_filename(prefix,
+ prefix ? strlen(prefix) : 0,
+ arg));
+ } else
+ show(arg);
return 1;
}
return 0;
@@ -340,9 +346,9 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
NULL
};
static struct option parseopt_opts[] = {
- OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
+ OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
N_("keep the `--` passed as an arg")),
- OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option,
+ OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
N_("stop parsing after the "
"first non-option argument")),
OPT_END(),
@@ -470,6 +476,7 @@ N_("git rev-parse --parseopt [options] -- [<args>...]\n"
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
{
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
+ int output_prefix = 0;
unsigned char sha1[20];
const char *name = NULL;
@@ -479,21 +486,6 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (argc > 1 && !strcmp("--sq-quote", argv[1]))
return cmd_sq_quote(argc - 2, argv + 2);
- if (argc == 2 && !strcmp("--local-env-vars", argv[1])) {
- int i;
- for (i = 0; local_repo_env[i]; i++)
- printf("%s\n", local_repo_env[i]);
- return 0;
- }
-
- if (argc > 2 && !strcmp(argv[1], "--resolve-git-dir")) {
- const char *gitdir = resolve_gitdir(argv[2]);
- if (!gitdir)
- die("not a gitdir '%s'", argv[2]);
- puts(gitdir);
- return 0;
- }
-
if (argc > 1 && !strcmp("-h", argv[1]))
usage(builtin_rev_parse_usage);
@@ -503,7 +495,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
const char *arg = argv[i];
if (as_is) {
- if (show_file(arg) && as_is < 2)
+ if (show_file(arg, output_prefix) && as_is < 2)
verify_filename(prefix, arg, 0);
continue;
}
@@ -527,7 +519,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
as_is = 2;
/* Pass on the "--" if we show anything but files.. */
if (filter & (DO_FLAGS | DO_REVS))
- show_file(arg);
+ show_file(arg, 0);
continue;
}
if (!strcmp(arg, "--default")) {
@@ -535,6 +527,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
i++;
continue;
}
+ if (!strcmp(arg, "--prefix")) {
+ prefix = argv[i+1];
+ startup_info->prefix = prefix;
+ output_prefix = 1;
+ i++;
+ continue;
+ }
if (!strcmp(arg, "--revs-only")) {
filter &= ~DO_NOREV;
continue;
@@ -647,6 +646,12 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
for_each_remote_ref(show_reference, NULL);
continue;
}
+ if (!strcmp(arg, "--local-env-vars")) {
+ int i;
+ for (i = 0; local_repo_env[i]; i++)
+ printf("%s\n", local_repo_env[i]);
+ continue;
+ }
if (!strcmp(arg, "--show-toplevel")) {
const char *work_tree = get_git_work_tree();
if (work_tree)
@@ -697,6 +702,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
continue;
}
+ if (!strcmp(arg, "--resolve-git-dir")) {
+ const char *gitdir = resolve_gitdir(argv[i+1]);
+ if (!gitdir)
+ die("not a gitdir '%s'", argv[i+1]);
+ puts(gitdir);
+ continue;
+ }
if (!strcmp(arg, "--is-inside-git-dir")) {
printf("%s\n", is_inside_git_dir() ? "true"
: "false");
@@ -754,7 +766,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (verify)
die_no_single_rev(quiet);
as_is = 1;
- if (!show_file(arg))
+ if (!show_file(arg, output_prefix))
continue;
verify_filename(prefix, arg, 1);
}
diff --git a/builtin/revert.c b/builtin/revert.c
index 0401fdb..8e87acd 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -54,6 +54,7 @@ static int option_parse_x(const struct option *opt,
return 0;
}
+LAST_ARG_MUST_BE_NULL
static void verify_opt_compatible(const char *me, const char *base_opt, ...)
{
const char *this_opt;
@@ -70,43 +71,19 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)
die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
}
-static void verify_opt_mutually_compatible(const char *me, ...)
-{
- const char *opt1, *opt2 = NULL;
- va_list ap;
-
- va_start(ap, me);
- while ((opt1 = va_arg(ap, const char *))) {
- if (va_arg(ap, int))
- break;
- }
- if (opt1) {
- while ((opt2 = va_arg(ap, const char *))) {
- if (va_arg(ap, int))
- break;
- }
- }
- va_end(ap);
-
- if (opt1 && opt2)
- die(_("%s: %s cannot be used with %s"), me, opt1, opt2);
-}
-
static void parse_args(int argc, const char **argv, struct replay_opts *opts)
{
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
- int remove_state = 0;
- int contin = 0;
- int rollback = 0;
+ int cmd = 0;
struct option options[] = {
- 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_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
+ OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
+ OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
+ OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
+ OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
OPT_NOOP_NOARG('r', NULL),
- OPT_BOOLEAN('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
+ OPT_BOOL('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, N_("strategy"), N_("merge strategy")),
@@ -122,11 +99,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, 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_BOOL('x', NULL, &opts->record_origin, N_("append commit name")),
+ OPT_BOOL(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
+ OPT_BOOL(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
+ OPT_BOOL(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
+ OPT_BOOL(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))
@@ -137,23 +114,16 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
PARSE_OPT_KEEP_ARGV0 |
PARSE_OPT_KEEP_UNKNOWN);
- /* Check for incompatible subcommands */
- verify_opt_mutually_compatible(me,
- "--quit", remove_state,
- "--continue", contin,
- "--abort", rollback,
- NULL);
-
/* implies allow_empty */
if (opts->keep_redundant_commits)
opts->allow_empty = 1;
/* Set the subcommand */
- if (remove_state)
+ if (cmd == 'q')
opts->subcommand = REPLAY_REMOVE_STATE;
- else if (contin)
+ else if (cmd == 'c')
opts->subcommand = REPLAY_CONTINUE;
- else if (rollback)
+ else if (cmd == 'a')
opts->subcommand = REPLAY_ROLLBACK;
else
opts->subcommand = REPLAY_NONE;
diff --git a/builtin/rm.c b/builtin/rm.c
index dabfcf6..9b59ab3 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -9,7 +9,9 @@
#include "cache-tree.h"
#include "tree-walk.h"
#include "parse-options.h"
+#include "string-list.h"
#include "submodule.h"
+#include "pathspec.h"
static const char * const builtin_rm_usage[] = {
N_("git rm [options] [--] <file>..."),
@@ -36,15 +38,52 @@ static int get_ours_cache_pos(const char *path, int pos)
return -1;
}
+static void print_error_files(struct string_list *files_list,
+ const char *main_msg,
+ const char *hints_msg,
+ int *errs)
+{
+ if (files_list->nr) {
+ int i;
+ struct strbuf err_msg = STRBUF_INIT;
+
+ strbuf_addstr(&err_msg, main_msg);
+ for (i = 0; i < files_list->nr; i++)
+ strbuf_addf(&err_msg,
+ "\n %s",
+ files_list->items[i].string);
+ if (advice_rm_hints)
+ strbuf_addstr(&err_msg, hints_msg);
+ *errs = error("%s", err_msg.buf);
+ strbuf_release(&err_msg);
+ }
+}
+
+static void error_removing_concrete_submodules(struct string_list *files, int *errs)
+{
+ print_error_files(files,
+ Q_("the following submodule (or one of its nested "
+ "submodules)\n"
+ "uses a .git directory:",
+ "the following submodules (or one of its nested "
+ "submodules)\n"
+ "use a .git directory:", files->nr),
+ _("\n(use 'rm -rf' if you really want to remove "
+ "it including all of its history)"),
+ errs);
+ string_list_clear(files, 0);
+}
+
static int check_submodules_use_gitfiles(void)
{
int i;
int errs = 0;
+ struct string_list files = STRING_LIST_INIT_NODUP;
for (i = 0; i < list.nr; i++) {
const char *name = list.entry[i].name;
int pos;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
struct stat st;
pos = cache_name_pos(name, strlen(name));
@@ -61,12 +100,11 @@ static int check_submodules_use_gitfiles(void)
continue;
if (!submodule_uses_gitfile(name))
- errs = error(_("submodule '%s' (or one of its nested "
- "submodules) uses a .git directory\n"
- "(use 'rm -rf' if you really want to remove "
- "it including all of its history)"), name);
+ string_list_append(&files, name);
}
+ error_removing_concrete_submodules(&files, &errs);
+
return errs;
}
@@ -81,12 +119,16 @@ static int check_local_mod(unsigned char *head, int index_only)
*/
int i, no_head;
int errs = 0;
+ struct string_list files_staged = STRING_LIST_INIT_NODUP;
+ struct string_list files_cached = STRING_LIST_INIT_NODUP;
+ struct string_list files_submodule = STRING_LIST_INIT_NODUP;
+ struct string_list files_local = STRING_LIST_INIT_NODUP;
no_head = is_null_sha1(head);
for (i = 0; i < list.nr; i++) {
struct stat st;
int pos;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
const char *name = list.entry[i].name;
unsigned char sha1[20];
unsigned mode;
@@ -110,7 +152,7 @@ static int check_local_mod(unsigned char *head, int index_only)
ce = active_cache[pos];
if (lstat(ce->name, &st) < 0) {
- if (errno != ENOENT)
+ if (errno != ENOENT && errno != ENOTDIR)
warning("'%s': %s", ce->name, strerror(errno));
/* It already vanished from the working tree */
continue;
@@ -171,29 +213,50 @@ static int check_local_mod(unsigned char *head, int index_only)
*/
if (local_changes && staged_changes) {
if (!index_only || !(ce->ce_flags & CE_INTENT_TO_ADD))
- errs = error(_("'%s' has staged content different "
- "from both the file and the HEAD\n"
- "(use -f to force removal)"), name);
+ string_list_append(&files_staged, name);
}
else if (!index_only) {
if (staged_changes)
- errs = error(_("'%s' has changes staged in the index\n"
- "(use --cached to keep the file, "
- "or -f to force removal)"), name);
+ string_list_append(&files_cached, name);
if (local_changes) {
if (S_ISGITLINK(ce->ce_mode) &&
- !submodule_uses_gitfile(name)) {
- errs = error(_("submodule '%s' (or one of its nested "
- "submodules) uses a .git directory\n"
- "(use 'rm -rf' if you really want to remove "
- "it including all of its history)"), name);
- } else
- errs = error(_("'%s' has local modifications\n"
- "(use --cached to keep the file, "
- "or -f to force removal)"), name);
+ !submodule_uses_gitfile(name))
+ string_list_append(&files_submodule, name);
+ else
+ string_list_append(&files_local, name);
}
}
}
+ print_error_files(&files_staged,
+ Q_("the following file has staged content different "
+ "from both the\nfile and the HEAD:",
+ "the following files have staged content different"
+ " from both the\nfile and the HEAD:",
+ files_staged.nr),
+ _("\n(use -f to force removal)"),
+ &errs);
+ string_list_clear(&files_staged, 0);
+ print_error_files(&files_cached,
+ Q_("the following file has changes "
+ "staged in the index:",
+ "the following files have changes "
+ "staged in the index:", files_cached.nr),
+ _("\n(use --cached to keep the file,"
+ " or -f to force removal)"),
+ &errs);
+ string_list_clear(&files_cached, 0);
+
+ error_removing_concrete_submodules(&files_submodule, &errs);
+
+ print_error_files(&files_local,
+ Q_("the following file has local modifications:",
+ "the following files have local modifications:",
+ files_local.nr),
+ _("\n(use --cached to keep the file,"
+ " or -f to force removal)"),
+ &errs);
+ string_list_clear(&files_local, 0);
+
return errs;
}
@@ -205,10 +268,10 @@ static int ignore_unmatch = 0;
static struct option builtin_rm_options[] = {
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_BOOL( 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,
+ OPT_BOOL('r', NULL, &recursive, N_("allow recursive removal")),
+ OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch,
N_("exit with a zero status even if nothing matched")),
OPT_END(),
};
@@ -216,9 +279,10 @@ static struct option builtin_rm_options[] = {
int cmd_rm(int argc, const char **argv, const char *prefix)
{
int i, newfd;
- const char **pathspec;
+ struct pathspec pathspec;
char *seen;
+ gitmodules_config();
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_rm_options,
@@ -249,31 +313,32 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
}
}
- pathspec = get_pathspec(prefix, argv);
- refresh_index(&the_index, REFRESH_QUIET, pathspec, NULL, NULL);
+ parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, argv);
+ refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
- seen = NULL;
- for (i = 0; pathspec[i] ; i++)
- /* nothing */;
- seen = xcalloc(i, 1);
+ seen = xcalloc(pathspec.nr, 1);
for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
- if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
+ const struct cache_entry *ce = active_cache[i];
+ if (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), 0, seen))
continue;
ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
list.entry[list.nr].name = ce->name;
- list.entry[list.nr++].is_submodule = S_ISGITLINK(ce->ce_mode);
+ list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
+ if (list.entry[list.nr++].is_submodule &&
+ !is_staging_gitmodules_ok())
+ die (_("Please, stage your changes to .gitmodules or stash them to proceed"));
}
- if (pathspec) {
- const char *match;
+ if (pathspec.nr) {
+ const char *original;
int seen_any = 0;
- for (i = 0; (match = pathspec[i]) != NULL ; i++) {
+ for (i = 0; i < pathspec.nr; i++) {
+ original = pathspec.items[i].original;
if (!seen[i]) {
if (!ignore_unmatch) {
die(_("pathspec '%s' did not match any files"),
- match);
+ original);
}
}
else {
@@ -281,10 +346,10 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
}
if (!recursive && seen[i] == MATCHED_RECURSIVELY)
die(_("not removing '%s' recursively without -r"),
- *match ? match : ".");
+ *original ? original : ".");
}
- if (! seen_any)
+ if (!seen_any)
exit(0);
}
@@ -334,13 +399,15 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
* in the middle)
*/
if (!index_only) {
- int removed = 0;
+ int removed = 0, gitmodules_modified = 0;
for (i = 0; i < list.nr; i++) {
const char *path = list.entry[i].name;
if (list.entry[i].is_submodule) {
if (is_empty_dir(path)) {
if (!rmdir(path)) {
removed = 1;
+ if (!remove_path_from_gitmodules(path))
+ gitmodules_modified = 1;
continue;
}
} else {
@@ -348,9 +415,14 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
strbuf_addstr(&buf, path);
if (!remove_dir_recursively(&buf, 0)) {
removed = 1;
+ if (!remove_path_from_gitmodules(path))
+ gitmodules_modified = 1;
strbuf_release(&buf);
continue;
- }
+ } else if (!file_exists(path))
+ /* Submodule was removed by user */
+ if (!remove_path_from_gitmodules(path))
+ gitmodules_modified = 1;
strbuf_release(&buf);
/* Fallthrough and let remove_path() fail. */
}
@@ -362,6 +434,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (!removed)
die_errno("git rm: '%s'", path);
}
+ if (gitmodules_modified)
+ stage_updated_gitmodules();
}
if (active_cache_changed) {
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 57a46b2..4482f16 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -5,6 +5,7 @@
#include "sideband.h"
#include "run-command.h"
#include "remote.h"
+#include "connect.h"
#include "send-pack.h"
#include "quote.h"
#include "transport.h"
@@ -54,6 +55,11 @@ static void print_helper_status(struct ref *ref)
msg = "needs force";
break;
+ case REF_STATUS_REJECT_STALE:
+ res = "error";
+ msg = "stale info";
+ break;
+
case REF_STATUS_REJECT_ALREADY_EXISTS:
res = "error";
msg = "already exists";
@@ -79,7 +85,7 @@ static void print_helper_status(struct ref *ref)
}
strbuf_addch(&buf, '\n');
- safe_write(1, buf.buf, buf.len);
+ write_or_die(1, buf.buf, buf.len);
}
strbuf_release(&buf);
}
@@ -102,6 +108,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
int flags;
unsigned int reject_reasons;
int progress = -1;
+ struct push_cas_option cas = {0};
argv++;
for (i = 1; i < argc; i++, argv++) {
@@ -164,6 +171,22 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
helper_status = 1;
continue;
}
+ if (!strcmp(arg, "--" CAS_OPT_NAME)) {
+ if (parse_push_cas_option(&cas, NULL, 0) < 0)
+ exit(1);
+ continue;
+ }
+ if (!strcmp(arg, "--no-" CAS_OPT_NAME)) {
+ if (parse_push_cas_option(&cas, NULL, 1) < 0)
+ exit(1);
+ continue;
+ }
+ if (!prefixcmp(arg, "--" CAS_OPT_NAME "=")) {
+ if (parse_push_cas_option(&cas,
+ strchr(arg, '=') + 1, 0) < 0)
+ exit(1);
+ continue;
+ }
usage(send_pack_usage);
}
if (!dest) {
@@ -207,7 +230,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
memset(&extra_have, 0, sizeof(extra_have));
- get_remote_heads(fd[0], &remote_refs, REF_NORMAL, &extra_have);
+ get_remote_heads(fd[0], NULL, 0, &remote_refs, REF_NORMAL, &extra_have);
transport_verify_remote_names(nr_refspecs, refspecs);
@@ -224,6 +247,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
return -1;
+ if (!is_empty_cas(&cas))
+ apply_push_cas(&cas, remote, remote_refs);
+
set_ref_status_for_push(remote_refs, args.send_mirror,
args.force_update);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 240bff3..ae73d17 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -10,9 +10,7 @@
#include "parse-options.h"
static char const * const shortlog_usage[] = {
- N_("git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"),
- "",
- N_("[rev-opts] are documented in git-rev-list(1)"),
+ N_("git shortlog [<options>] [<revision range>] [[--] [<path>...]]"),
NULL
};
@@ -139,6 +137,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.subject = "";
ctx.after_subject = "";
ctx.date_mode = DATE_NORMAL;
+ ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &ufbuf);
buffer = ufbuf.buf;
} else if (*buffer) {
@@ -225,12 +224,12 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
int nongit = !startup_info->have_repository;
static const struct option options[] = {
- OPT_BOOLEAN('n', "numbered", &log.sort_by_number,
- N_("sort output according to the number of commits per author")),
- OPT_BOOLEAN('s', "summary", &log.summary,
- N_("Suppress commit descriptions, only provides commit count")),
- OPT_BOOLEAN('e', "email", &log.email,
- N_("Show the email address of each author")),
+ OPT_BOOL('n', "numbered", &log.sort_by_number,
+ N_("sort output according to the number of commits per author")),
+ OPT_BOOL('s', "summary", &log.summary,
+ N_("Suppress commit descriptions, only provides commit count")),
+ OPT_BOOL('e', "email", &log.email,
+ 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 90fc6b1..001f29c 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -630,7 +630,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
int num_rev, i, extra = 0;
int all_heads = 0, all_remotes = 0;
int all_mask, all_revs;
- int lifo = 1;
+ enum rev_sort_order sort_order = REV_SORT_IN_GRAPH_ORDER;
char head[128];
const char *head_p;
int head_len;
@@ -646,34 +646,36 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
int dense = 1;
const char *reflog_base = NULL;
struct option builtin_show_branch_options[] = {
- OPT_BOOLEAN('a', "all", &all_heads,
- N_("show remote-tracking and local branches")),
- OPT_BOOLEAN('r', "remotes", &all_remotes,
- N_("show remote-tracking branches")),
+ OPT_BOOL('a', "all", &all_heads,
+ N_("show remote-tracking and local branches")),
+ OPT_BOOL('r', "remotes", &all_remotes,
+ N_("show remote-tracking branches")),
OPT__COLOR(&showbranch_use_color,
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, N_("synonym to more=-1"), -1),
- OPT_BOOLEAN(0, "no-name", &no_name, N_("suppress naming strings")),
- OPT_BOOLEAN(0, "current", &with_current_branch,
- N_("include the current branch")),
- OPT_BOOLEAN(0, "sha1-name", &sha1_name,
- N_("name commits with their object names")),
- OPT_BOOLEAN(0, "merge-base", &merge_base,
- N_("show possible merge bases")),
- OPT_BOOLEAN(0, "independent", &independent,
+ OPT_BOOL(0, "no-name", &no_name, N_("suppress naming strings")),
+ OPT_BOOL(0, "current", &with_current_branch,
+ N_("include the current branch")),
+ OPT_BOOL(0, "sha1-name", &sha1_name,
+ N_("name commits with their object names")),
+ OPT_BOOL(0, "merge-base", &merge_base,
+ N_("show possible merge bases")),
+ OPT_BOOL(0, "independent", &independent,
N_("show refs unreachable from any other ref")),
- OPT_BOOLEAN(0, "topo-order", &lifo,
- N_("show commits in topological order")),
- OPT_BOOLEAN(0, "topics", &topics,
- N_("show only commits not on the first branch")),
+ OPT_SET_INT(0, "topo-order", &sort_order,
+ N_("show commits in topological order"),
+ REV_SORT_IN_GRAPH_ORDER),
+ OPT_BOOL(0, "topics", &topics,
+ N_("show only commits not on the first branch")),
OPT_SET_INT(0, "sparse", &dense,
N_("show merges reachable from only one tip"), 0),
- OPT_SET_INT(0, "date-order", &lifo,
- N_("show commits where no parent comes before its "
- "children"), 0),
+ OPT_SET_INT(0, "date-order", &sort_order,
+ N_("topologically sort, maintaining date order "
+ "where possible"),
+ REV_SORT_BY_COMMIT_DATE),
{ OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
N_("show <n> most recent ref-log entries starting at "
"base"),
@@ -900,7 +902,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
exit(0);
/* Sort topologically */
- sort_in_topological_order(&seen, lifo);
+ sort_in_topological_order(&seen, sort_order);
/* Give names to commits */
if (!sha1_name && !no_name)
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 8d9b76a..9f3f5e3 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -31,6 +31,9 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
const char *hex;
unsigned char peeled[20];
+ if (show_head && !strcmp(refname, "HEAD"))
+ goto match;
+
if (tags_only || heads_only) {
int match;
@@ -103,7 +106,7 @@ static int add_existing(const char *refname, const unsigned char *sha1, int flag
*/
static int exclude_existing(const char *match)
{
- static struct string_list existing_refs = STRING_LIST_INIT_NODUP;
+ static struct string_list existing_refs = STRING_LIST_INIT_DUP;
char buf[1024];
int matchlen = match ? strlen(match) : 0;
@@ -162,15 +165,15 @@ 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, 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, "
+ OPT_BOOL(0, "tags", &tags_only, N_("only show tags (can be combined with heads)")),
+ OPT_BOOL(0, "heads", &heads_only, N_("only show heads (can be combined with tags)")),
+ OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
"requires exact ref path")),
- { OPTION_BOOLEAN, 'h', NULL, &show_head, NULL,
- N_("show the HEAD reference"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
- OPT_BOOLEAN(0, "head", &show_head, N_("show the HEAD reference")),
- OPT_BOOLEAN('d', "dereference", &deref_tags,
+ OPT_HIDDEN_BOOL('h', NULL, &show_head,
+ N_("show the HEAD reference, even if it would be filtered out")),
+ OPT_BOOL(0, "head", &show_head,
+ N_("show the HEAD reference, even if it would be filtered out")),
+ OPT_BOOL('d', "dereference", &deref_tags,
N_("dereference tags into object IDs")),
{ OPTION_CALLBACK, 's', "hash", &abbrev, N_("n"),
N_("only show SHA1 hash using <n> digits"),
diff --git a/builtin/tag.c b/builtin/tag.c
index af3af3f..b577af5 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -436,26 +436,26 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct ref_lock *lock;
struct create_tag_options opt;
char *cleanup_arg = NULL;
- int annotate = 0, force = 0, lines = -1, list = 0,
- delete = 0, verify = 0;
+ int annotate = 0, force = 0, lines = -1;
+ int cmdmode = 0;
const char *msgfile = NULL, *keyid = NULL;
struct msg_arg msg = { 0, STRBUF_INIT };
struct commit_list *with_commit = NULL;
struct option options[] = {
- OPT_BOOLEAN('l', "list", &list, N_("list tag names")),
+ OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
{ 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, N_("delete tags")),
- OPT_BOOLEAN('v', "verify", &verify, N_("verify tags")),
+ OPT_CMDMODE('d', "delete", &cmdmode, N_("delete tags"), 'd'),
+ OPT_CMDMODE('v', "verify", &cmdmode, N_("verify tags"), 'v'),
OPT_GROUP(N_("Tag creation options")),
- OPT_BOOLEAN('a', "annotate", &annotate,
+ OPT_BOOL('a', "annotate", &annotate,
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_BOOL('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"),
@@ -489,22 +489,19 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
}
if (opt.sign)
annotate = 1;
- if (argc == 0 && !(delete || verify))
- list = 1;
+ if (argc == 0 && !cmdmode)
+ cmdmode = 'l';
- if ((annotate || msg.given || msgfile || force) &&
- (list || delete || verify))
+ if ((annotate || msg.given || msgfile || force) && (cmdmode != 0))
usage_with_options(git_tag_usage, options);
- if (list + delete + verify > 1)
- usage_with_options(git_tag_usage, options);
finalize_colopts(&colopts, -1);
- if (list && lines != -1) {
+ if (cmdmode == 'l' && lines != -1) {
if (explicitly_enable_column(colopts))
die(_("--column and -n are incompatible"));
colopts = 0;
}
- if (list) {
+ if (cmdmode == 'l') {
int ret;
if (column_active(colopts)) {
struct column_options copts;
@@ -523,9 +520,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die(_("--contains option is only allowed with -l."));
if (points_at.nr)
die(_("--points-at option is only allowed with -l."));
- if (delete)
+ if (cmdmode == 'd')
return for_each_tag_name(argv, delete_tag);
- if (verify)
+ if (cmdmode == 'v')
return for_each_tag_name(argv, verify_tag);
if (msg.given || msgfile) {
diff --git a/builtin/tar-tree.c b/builtin/tar-tree.c
index 3f1e701..ba3ffe6 100644
--- a/builtin/tar-tree.c
+++ b/builtin/tar-tree.c
@@ -26,8 +26,8 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
* $0 tree-ish basedir ==>
* git archive --format-tar --prefix=basedir tree-ish
*/
- int i;
const char **nargv = xcalloc(sizeof(*nargv), argc + 3);
+ struct strbuf sb = STRBUF_INIT;
char *basedir_arg;
int nargc = 0;
@@ -65,11 +65,10 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
fprintf(stderr,
"*** \"git tar-tree\" is now deprecated.\n"
"*** Running \"git archive\" instead.\n***");
- for (i = 0; i < nargc; i++) {
- fputc(' ', stderr);
- sq_quote_print(stderr, nargv[i]);
- }
- fputc('\n', stderr);
+ sq_quote_argv(&sb, nargv, 0);
+ strbuf_addch(&sb, '\n');
+ fputs(sb.buf, stderr);
+ strbuf_release(&sb);
return cmd_archive(nargc, nargv, prefix);
}
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 5c7762e..e3a10d7 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -11,6 +11,7 @@
#include "refs.h"
#include "resolve-undo.h"
#include "parse-options.h"
+#include "pathspec.h"
/*
* Default to not allowing changes to the list of files. The
@@ -83,7 +84,7 @@ static int process_lstat_error(const char *path, int err)
return error("lstat(\"%s\"): %s", path, strerror(errno));
}
-static int add_one_path(struct cache_entry *old, const char *path, int len, struct stat *st)
+static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st)
{
int option, size;
struct cache_entry *ce;
@@ -142,7 +143,7 @@ static int process_directory(const char *path, int len, struct stat *st)
/* Exact match: file or existing gitlink */
if (pos >= 0) {
- struct cache_entry *ce = active_cache[pos];
+ const struct cache_entry *ce = active_cache[pos];
if (S_ISGITLINK(ce->ce_mode)) {
/* Do nothing to the index if there is no HEAD! */
@@ -158,7 +159,7 @@ static int process_directory(const char *path, int len, struct stat *st)
/* Inexact match: is there perhaps a subdirectory match? */
pos = -pos-1;
while (pos < active_nr) {
- struct cache_entry *ce = active_cache[pos++];
+ const struct cache_entry *ce = active_cache[pos++];
if (strncmp(ce->name, path, len))
break;
@@ -183,7 +184,7 @@ static int process_path(const char *path)
{
int pos, len;
struct stat st;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
len = strlen(path);
if (has_symlink_leading_path(path, len))
@@ -448,7 +449,7 @@ static int unresolve_one(const char *path)
/* already merged */
pos = unmerge_cache_entry_at(pos);
if (pos < active_nr) {
- struct cache_entry *ce = active_cache[pos];
+ const struct cache_entry *ce = active_cache[pos];
if (ce_stage(ce) &&
ce_namelen(ce) == namelen &&
!memcmp(ce->name, path, namelen))
@@ -462,7 +463,7 @@ static int unresolve_one(const char *path)
*/
pos = -pos-1;
if (pos < active_nr) {
- struct cache_entry *ce = active_cache[pos];
+ const struct cache_entry *ce = active_cache[pos];
if (ce_namelen(ce) == namelen &&
!memcmp(ce->name, path, namelen)) {
fprintf(stderr,
@@ -546,10 +547,11 @@ static int do_reupdate(int ac, const char **av,
*/
int pos;
int has_head = 1;
- const char **paths = get_pathspec(prefix, av + 1);
struct pathspec pathspec;
- init_pathspec(&pathspec, paths);
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_CWD,
+ prefix, av + 1);
if (read_ref("HEAD", head_sha1))
/* If there is no HEAD, that means it is an initial
@@ -558,7 +560,7 @@ static int do_reupdate(int ac, const char **av,
has_head = 0;
redo:
for (pos = 0; pos < active_nr; pos++) {
- struct cache_entry *ce = active_cache[pos];
+ const struct cache_entry *ce = active_cache[pos];
struct cache_entry *old = NULL;
int save_nr;
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 51d2684..7484d36 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -16,8 +16,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
int delete = 0, no_deref = 0, flags = 0;
struct option options[] = {
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,
+ OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
+ OPT_BOOL( 0 , "no-deref", &no_deref,
N_("update <refname> not the one it points to")),
OPT_END(),
};
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index b928beb..af2da35 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -7,6 +7,7 @@
#include "pkt-line.h"
#include "sideband.h"
#include "run-command.h"
+#include "argv-array.h"
static const char upload_archive_usage[] =
"git upload-archive <repo>";
@@ -18,51 +19,31 @@ static const char deadchild[] =
int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
{
- const char *sent_argv[MAX_ARGS];
+ struct argv_array sent_argv = ARGV_ARRAY_INIT;
const char *arg_cmd = "argument ";
- char *p, buf[4096];
- int sent_argc;
- int len;
if (argc != 2)
usage(upload_archive_usage);
- if (strlen(argv[1]) + 1 > sizeof(buf))
- die("insanely long repository name");
-
- strcpy(buf, argv[1]); /* enter-repo smudges its argument */
-
- if (!enter_repo(buf, 0))
- die("'%s' does not appear to be a git repository", buf);
+ if (!enter_repo(argv[1], 0))
+ die("'%s' does not appear to be a git repository", argv[1]);
/* put received options in sent_argv[] */
- sent_argc = 1;
- sent_argv[0] = "git-upload-archive";
- for (p = buf;;) {
- /* This will die if not enough free space in buf */
- len = packet_read_line(0, p, (buf + sizeof buf) - p);
- if (len == 0)
+ argv_array_push(&sent_argv, "git-upload-archive");
+ for (;;) {
+ char *buf = packet_read_line(0, NULL);
+ if (!buf)
break; /* got a flush */
- if (sent_argc > MAX_ARGS - 2)
- die("Too many options (>%d)", MAX_ARGS - 2);
+ if (sent_argv.argc > MAX_ARGS)
+ die("Too many options (>%d)", MAX_ARGS - 1);
- if (p[len-1] == '\n') {
- p[--len] = 0;
- }
- if (len < strlen(arg_cmd) ||
- strncmp(arg_cmd, p, strlen(arg_cmd)))
+ if (prefixcmp(buf, arg_cmd))
die("'argument' token or flush expected");
-
- len -= strlen(arg_cmd);
- memmove(p, p + strlen(arg_cmd), len);
- sent_argv[sent_argc++] = p;
- p += len;
- *p++ = 0;
+ argv_array_push(&sent_argv, buf + strlen(arg_cmd));
}
- sent_argv[sent_argc] = NULL;
/* parse all options sent by the client */
- return write_archive(sent_argc, sent_argv, prefix, 0, NULL, 1);
+ return write_archive(sent_argv.argc, sent_argv.argv, prefix, 0, NULL, 1);
}
__attribute__((format (printf, 1, 2)))
diff --git a/bulk-checkin.c b/bulk-checkin.c
index 6b0b6d4..118c625 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -114,7 +114,7 @@ static int stream_to_pack(struct bulk_checkin_state *state,
if (size && !s.avail_in) {
ssize_t rsize = size < sizeof(ibuf) ? size : sizeof(ibuf);
- if (xread(fd, ibuf, rsize) != rsize)
+ if (read_in_full(fd, ibuf, rsize) != rsize)
die("failed to read %d bytes from '%s'",
(int)rsize, path);
offset += rsize;
diff --git a/bundle.c b/bundle.c
index 4b0e5cd..3d64311 100644
--- a/bundle.c
+++ b/bundle.c
@@ -281,7 +281,7 @@ int create_bundle(struct bundle_header *header, const char *path,
if (!get_sha1_hex(buf.buf + 1, sha1)) {
struct object *object = parse_object_or_die(sha1, buf.buf);
object->flags |= UNINTERESTING;
- add_pending_object(&revs, object, xstrdup(buf.buf));
+ add_pending_object(&revs, object, buf.buf);
}
} else if (!get_sha1_hex(buf.buf, sha1)) {
struct object *object = parse_object_or_die(sha1, buf.buf);
diff --git a/cache-tree.c b/cache-tree.c
index 37e4d00..0bbec43 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -149,7 +149,7 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
cache_tree_invalidate_path(down->cache_tree, slash + 1);
}
-static int verify_cache(struct cache_entry **cache,
+static int verify_cache(const struct cache_entry * const *cache,
int entries, int flags)
{
int i, funny;
@@ -158,7 +158,7 @@ static int verify_cache(struct cache_entry **cache,
/* Verify that the tree is merged */
funny = 0;
for (i = 0; i < entries; i++) {
- struct cache_entry *ce = cache[i];
+ const struct cache_entry *ce = cache[i];
if (ce_stage(ce)) {
if (silent)
return -1;
@@ -234,7 +234,7 @@ int cache_tree_fully_valid(struct cache_tree *it)
}
static int update_one(struct cache_tree *it,
- struct cache_entry **cache,
+ const struct cache_entry * const *cache,
int entries,
const char *base,
int baselen,
@@ -265,7 +265,7 @@ static int update_one(struct cache_tree *it,
*/
i = 0;
while (i < entries) {
- struct cache_entry *ce = cache[i];
+ const struct cache_entry *ce = cache[i];
struct cache_tree_sub *sub;
const char *path, *slash;
int pathlen, sublen, subcnt, subskip;
@@ -312,7 +312,7 @@ static int update_one(struct cache_tree *it,
i = 0;
while (i < entries) {
- struct cache_entry *ce = cache[i];
+ const struct cache_entry *ce = cache[i];
struct cache_tree_sub *sub;
const char *path, *slash;
int pathlen, entlen;
@@ -397,7 +397,7 @@ static int update_one(struct cache_tree *it,
}
int cache_tree_update(struct cache_tree *it,
- struct cache_entry **cache,
+ const struct cache_entry * const *cache,
int entries,
int flags)
{
@@ -599,8 +599,8 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
was_valid = cache_tree_fully_valid(active_cache_tree);
if (!was_valid) {
if (cache_tree_update(active_cache_tree,
- active_cache, active_nr,
- flags) < 0)
+ (const struct cache_entry * const *)active_cache,
+ active_nr, flags) < 0)
return WRITE_TREE_UNMERGED_INDEX;
if (0 <= newfd) {
if (!write_cache(newfd, active_cache, active_nr) &&
@@ -701,5 +701,6 @@ int update_main_cache_tree(int flags)
if (!the_index.cache_tree)
the_index.cache_tree = cache_tree();
return cache_tree_update(the_index.cache_tree,
- the_index.cache, the_index.cache_nr, flags);
+ (const struct cache_entry * const *)the_index.cache,
+ the_index.cache_nr, flags);
}
diff --git a/cache-tree.h b/cache-tree.h
index 55d0f59..f1923ad 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -30,7 +30,7 @@ void cache_tree_write(struct strbuf *, struct cache_tree *root);
struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
int cache_tree_fully_valid(struct cache_tree *);
-int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int);
+int cache_tree_update(struct cache_tree *, const struct cache_entry * const *, int, int);
int update_main_cache_tree(int);
diff --git a/cache.h b/cache.h
index bb71bf8..a47b9c0 100644
--- a/cache.h
+++ b/cache.h
@@ -34,6 +34,7 @@ int git_inflate(git_zstream *, int flush);
void git_deflate_init(git_zstream *, int level);
void git_deflate_init_gzip(git_zstream *, int level);
+void git_deflate_init_raw(git_zstream *, int level);
void git_deflate_end(git_zstream *);
int git_deflate_abort(git_zstream *);
int git_deflate_end_gently(git_zstream *);
@@ -100,9 +101,9 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long);
#define CACHE_SIGNATURE 0x44495243 /* "DIRC" */
struct cache_header {
- unsigned int hdr_signature;
- unsigned int hdr_version;
- unsigned int hdr_entries;
+ uint32_t hdr_signature;
+ uint32_t hdr_version;
+ uint32_t hdr_entries;
};
#define INDEX_FORMAT_LB 2
@@ -114,19 +115,23 @@ struct cache_header {
* check it for equality in the 32 bits we save.
*/
struct cache_time {
- unsigned int sec;
- unsigned int nsec;
+ uint32_t sec;
+ uint32_t nsec;
+};
+
+struct stat_data {
+ struct cache_time sd_ctime;
+ struct cache_time sd_mtime;
+ unsigned int sd_dev;
+ unsigned int sd_ino;
+ unsigned int sd_uid;
+ unsigned int sd_gid;
+ unsigned int sd_size;
};
struct cache_entry {
- struct cache_time ce_ctime;
- struct cache_time ce_mtime;
- unsigned int ce_dev;
- unsigned int ce_ino;
+ struct stat_data ce_stat_data;
unsigned int ce_mode;
- unsigned int ce_uid;
- unsigned int ce_gid;
- unsigned int ce_size;
unsigned int ce_flags;
unsigned int ce_namelen;
unsigned char sha1[20];
@@ -161,6 +166,9 @@ struct cache_entry {
#define CE_UNPACKED (1 << 24)
#define CE_NEW_SKIP_WORKTREE (1 << 25)
+/* used to temporarily mark paths matched by pathspecs */
+#define CE_MATCHED (1 << 26)
+
/*
* Extended on-disk flags
*/
@@ -181,12 +189,15 @@ struct cache_entry {
#error "CE_EXTENDED_FLAGS out of range"
#endif
+struct pathspec;
+
/*
* Copy the sha1 and stat state of a cache entry from one to
* another. But we never change the name, or the hash state!
*/
#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
-static inline void copy_cache_entry(struct cache_entry *dst, struct cache_entry *src)
+static inline void copy_cache_entry(struct cache_entry *dst,
+ const struct cache_entry *src)
{
unsigned int state = dst->ce_flags & CE_STATE_MASK;
@@ -218,7 +229,8 @@ static inline unsigned int create_ce_mode(unsigned int mode)
return S_IFGITLINK;
return S_IFREG | ce_permissions(mode);
}
-static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode)
+static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce,
+ unsigned int mode)
{
extern int trust_executable_bit, has_symlinks;
if (!has_symlinks && S_ISREG(mode) &&
@@ -307,6 +319,7 @@ extern void free_name_hash(struct index_state *istate);
#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
#define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
#define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
+#define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))
#endif
enum object_type {
@@ -354,6 +367,9 @@ static inline enum object_type object_type(unsigned int mode)
#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
+#define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS"
+#define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
+#define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
/*
* This environment variable is expected to contain a boolean indicating
@@ -401,6 +417,7 @@ extern void setup_work_tree(void);
extern const char *setup_git_directory_gently(int *);
extern const char *setup_git_directory(void);
extern char *prefix_path(const char *prefix, int len, const char *path);
+extern char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
extern const char *prefix_filename(const char *prefix, int len, const char *path);
extern int check_filename(const char *prefix, const char *name);
extern void verify_filename(const char *prefix,
@@ -414,6 +431,8 @@ extern int path_inside_repo(const char *prefix, const char *path);
extern int set_git_dir_init(const char *git_dir, const char *real_git_dir, int);
extern int init_db(const char *template_dir, unsigned int flags);
+extern void sanitize_stdfds(void);
+
#define alloc_nr(x) (((x)+16)*3/2)
/*
@@ -436,7 +455,7 @@ extern int init_db(const char *template_dir, unsigned int flags);
/* Initialize and use the cache information */
extern int read_index(struct index_state *);
-extern int read_index_preload(struct index_state *, const char **pathspec);
+extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
extern int read_index_from(struct index_state *, const char *path);
extern int is_index_unborn(struct index_state *);
extern int read_index_unmerged(struct index_state *);
@@ -461,11 +480,13 @@ extern int remove_file_from_index(struct index_state *, const char *path);
#define ADD_CACHE_IGNORE_ERRORS 4
#define ADD_CACHE_IGNORE_REMOVAL 8
#define ADD_CACHE_INTENT 16
+#define ADD_CACHE_IMPLICIT_DOT 32 /* internal to "git add -u/-A" */
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
extern int add_file_to_index(struct index_state *, const char *path, int flags);
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
-extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
+extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
extern int index_name_is_other(const struct index_state *, const char *, int);
+extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
/* do stat comparison even if CE_VALID is true */
#define CE_MATCH_IGNORE_VALID 01
@@ -473,35 +494,30 @@ extern int index_name_is_other(const struct index_state *, const char *, int);
#define CE_MATCH_RACY_IS_DIRTY 02
/* do stat comparison even if CE_SKIP_WORKTREE is true */
#define CE_MATCH_IGNORE_SKIP_WORKTREE 04
-extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
-extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
-
-#define PATHSPEC_ONESTAR 1 /* the pathspec pattern sastisfies GFNM_ONESTAR */
-
-struct pathspec {
- const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
- int nr;
- unsigned int has_wildcard:1;
- unsigned int recursive:1;
- int max_depth;
- struct pathspec_item {
- const char *match;
- int len;
- int nowildcard_len;
- int flags;
- } *items;
-};
+extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
+extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
-extern int init_pathspec(struct pathspec *, const char **);
-extern void free_pathspec(struct pathspec *);
extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
-extern int limit_pathspec_to_literal(void);
-
#define HASH_WRITE_OBJECT 1
#define HASH_FORMAT_CHECK 2
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned flags);
+
+/*
+ * Record to sd the data from st that we use to check whether a file
+ * might have changed.
+ */
+extern void fill_stat_data(struct stat_data *sd, struct stat *st);
+
+/*
+ * Return 0 if st is consistent with a file not having been changed
+ * since sd was filled. If there are differences, return a
+ * combination of MTIME_CHANGED, CTIME_CHANGED, OWNER_CHANGED,
+ * INODE_CHANGED, and DATA_CHANGED.
+ */
+extern int match_stat_data(const struct stat_data *sd, struct stat *st);
+
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
#define REFRESH_REALLY 0x0001 /* ignore_valid */
@@ -510,7 +526,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
#define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */
#define REFRESH_IGNORE_SUBMODULES 0x0010 /* ignore submodules */
#define REFRESH_IN_PORCELAIN 0x0020 /* user friendly output, not "needs update" */
-extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, const char *header_msg);
+extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
struct lock_file {
struct lock_file *next;
@@ -547,6 +563,7 @@ extern int assume_unchanged;
extern int prefer_symlink_refs;
extern int log_all_ref_updates;
extern int warn_ambiguous_refs;
+extern int warn_on_object_refname_ambiguity;
extern int shared_repository;
extern const char *apply_default_whitespace;
extern const char *apply_default_ignorewhitespace;
@@ -715,8 +732,7 @@ enum sharedrepo {
PERM_EVERYBODY = 0664
};
int git_config_perm(const char *var, const char *value);
-int set_shared_perm(const char *path, int mode);
-#define adjust_shared_perm(path) set_shared_perm((path), 0)
+int adjust_shared_perm(const char *path);
int safe_create_leading_directories(char *path);
int safe_create_leading_directories_const(const char *path);
int mkdir_in_gitdir(const char *path);
@@ -731,7 +747,8 @@ int is_directory(const char *);
const char *real_path(const char *path);
const char *real_path_if_valid(const char *path);
const char *absolute_path(const char *path);
-const char *relative_path(const char *abs, const char *base);
+const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
int normalize_path_copy(char *dst, const char *src);
int longest_ancestor_length(const char *path, struct string_list *prefixes);
char *strip_path_suffix(const char *path, const char *suffix);
@@ -766,9 +783,6 @@ extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
/* global flag to enable extra checks when accessing packed objects */
extern int do_check_packed_object_crc;
-/* for development: log offset of pack access */
-extern const char *log_pack_access;
-
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
extern int move_temp_to_file(const char *tmpfile, const char *filename);
@@ -904,6 +918,7 @@ void show_date_relative(unsigned long time, int tz, const struct timeval *now,
struct strbuf *timebuf);
int parse_date(const char *date, char *buf, int bufsize);
int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
+int parse_expiry_date(const char *date, unsigned long *timestamp);
void datestamp(char *buf, int bufsize);
#define approxidate(s) approxidate_careful((s), NULL)
unsigned long approxidate_careful(const char *, int *);
@@ -1010,55 +1025,11 @@ struct pack_entry {
struct packed_git *p;
};
-struct ref {
- struct ref *next;
- unsigned char old_sha1[20];
- unsigned char new_sha1[20];
- char *symref;
- unsigned int
- force:1,
- forced_update:1,
- merge:1,
- deletion:1;
- enum {
- REF_STATUS_NONE = 0,
- REF_STATUS_OK,
- REF_STATUS_REJECT_NONFASTFORWARD,
- REF_STATUS_REJECT_ALREADY_EXISTS,
- REF_STATUS_REJECT_NODELETE,
- REF_STATUS_REJECT_FETCH_FIRST,
- REF_STATUS_REJECT_NEEDS_FORCE,
- REF_STATUS_UPTODATE,
- REF_STATUS_REMOTE_REJECT,
- REF_STATUS_EXPECTING_REPORT
- } status;
- char *remote_status;
- struct ref *peer_ref; /* when renaming */
- char name[FLEX_ARRAY]; /* more */
-};
-
-#define REF_NORMAL (1u << 0)
-#define REF_HEADS (1u << 1)
-#define REF_TAGS (1u << 2)
-
-extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
-
-#define CONNECT_VERBOSE (1u << 0)
-extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
-extern int finish_connect(struct child_process *conn);
-extern int git_connection_is_socket(struct child_process *conn);
-struct extra_have_objects {
- int nr, alloc;
- unsigned char (*array)[20];
-};
-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 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);
+/* A hook for count-objects to report invalid files in pack directory */
+extern void (*report_garbage)(const char *desc, const char *path);
+
extern void prepare_packed_git(void);
extern void reprepare_packed_git(void);
extern void install_packed_git(struct packed_git *pack);
@@ -1086,7 +1057,9 @@ extern int unpack_object_header(struct packed_git *, struct pack_window **, off_
struct object_info {
/* Request */
+ enum object_type *typep;
unsigned long *sizep;
+ unsigned long *disk_sizep;
/* Response */
enum {
@@ -1130,14 +1103,19 @@ extern int update_server_info(int);
typedef int (*config_fn_t)(const char *, const char *, void *);
extern int git_default_config(const char *, const char *, void *);
extern int git_config_from_file(config_fn_t fn, const char *, void *);
+extern int git_config_from_buf(config_fn_t fn, const char *name,
+ const char *buf, size_t len, void *data);
extern void git_config_push_parameter(const char *text);
extern int git_config_from_parameters(config_fn_t fn, void *data);
extern int git_config(config_fn_t fn, void *);
extern int git_config_with_options(config_fn_t fn, void *,
- const char *filename, int respect_includes);
+ const char *filename,
+ const char *blob_ref,
+ int respect_includes);
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
+extern int64_t git_config_int64(const char *, const char *);
extern unsigned long git_config_ulong(const char *, const char *);
extern int git_config_bool_or_int(const char *, const char *, int *);
extern int git_config_bool(const char *, const char *);
@@ -1253,7 +1231,7 @@ void packet_trace_identity(const char *prog);
* return 0 if success, 1 - if addition of a file failed and
* ADD_FILES_IGNORE_ERRORS was specified in flags
*/
-int add_files_to_cache(const char *prefix, const char **pathspec, int flags);
+int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);
/* diff.c */
extern int diff_auto_refresh_index;
@@ -1287,7 +1265,7 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule);
#define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK)
/* ls-files */
-int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix);
+int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix);
void overlay_tree_on_cache(const char *tree_name, const char *prefix);
char *alias_lookup(const char *alias);
@@ -1314,4 +1292,31 @@ int checkout_fast_forward(const unsigned char *from,
int sane_execvp(const char *file, char *const argv[]);
+/*
+ * A struct to encapsulate the concept of whether a file has changed
+ * since we last checked it. This uses criteria similar to those used
+ * for the index.
+ */
+struct stat_validity {
+ struct stat_data *sd;
+};
+
+void stat_validity_clear(struct stat_validity *sv);
+
+/*
+ * Returns 1 if the path is a regular file (or a symlink to a regular
+ * file) and matches the saved stat_validity, 0 otherwise. A missing
+ * or inaccessible file is considered a match if the struct was just
+ * initialized, or if the previous update found an inaccessible file.
+ */
+int stat_validity_check(struct stat_validity *sv, const char *path);
+
+/*
+ * Update the stat_validity from a file opened at descriptor fd. If
+ * the file is missing, inaccessible, or not a regular file, then
+ * future calls to stat_validity_check will match iff one of those
+ * conditions continues to be true.
+ */
+void stat_validity_update(struct stat_validity *sv, int fd);
+
#endif /* CACHE_H */
diff --git a/color.c b/color.c
index e8e2681..f672885 100644
--- a/color.c
+++ b/color.c
@@ -1,7 +1,7 @@
#include "cache.h"
#include "color.h"
-static int git_use_color_default = 0;
+static int git_use_color_default = GIT_COLOR_AUTO;
int color_stdout_is_tty = -1;
/*
diff --git a/combine-diff.c b/combine-diff.c
index 6288485..3b92c448 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -10,6 +10,7 @@
#include "refs.h"
#include "userdiff.h"
#include "sha1-array.h"
+#include "revision.h"
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
{
@@ -74,16 +75,24 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
/* Lines lost from parent */
struct lline {
- struct lline *next;
+ struct lline *next, *prev;
int len;
unsigned long parent_map;
char line[FLEX_ARRAY];
};
+/* Lines lost from current parent (before coalescing) */
+struct plost {
+ struct lline *lost_head, *lost_tail;
+ int len;
+};
+
/* Lines surviving in the merge result */
struct sline {
- struct lline *lost_head, **lost_tail;
- struct lline *next_lost;
+ /* Accumulated and coalesced lost lines */
+ struct lline *lost;
+ int lenlost;
+ struct plost plost;
char *bol;
int len;
/* bit 0 up to (N-1) are on if the parent has this line (i.e.
@@ -95,34 +104,6 @@ struct sline {
unsigned long *p_lno;
};
-static char *grab_blob(const unsigned char *sha1, unsigned int mode,
- unsigned long *size, struct userdiff_driver *textconv,
- const char *path)
-{
- char *blob;
- enum object_type type;
-
- if (S_ISGITLINK(mode)) {
- blob = xmalloc(100);
- *size = snprintf(blob, 100,
- "Subproject commit %s\n", sha1_to_hex(sha1));
- } else if (is_null_sha1(sha1)) {
- /* deleted blob */
- *size = 0;
- return xcalloc(1, 1);
- } else if (textconv) {
- struct diff_filespec *df = alloc_filespec(path);
- fill_filespec(df, sha1, 1, mode);
- *size = fill_textconv(textconv, df, &blob);
- free_filespec(df);
- } else {
- blob = read_sha1_file(sha1, &type, size);
- if (type != OBJ_BLOB)
- die("object '%s' is not a blob!", sha1_to_hex(sha1));
- }
- return blob;
-}
-
static int match_string_spaces(const char *line1, int len1,
const char *line2, int len2,
long flags)
@@ -163,36 +144,180 @@ static int match_string_spaces(const char *line1, int len1,
return 0;
}
-static void append_lost(struct sline *sline, int n, const char *line, int len, long flags)
+enum coalesce_direction { MATCH, BASE, NEW };
+
+/* Coalesce new lines into base by finding LCS */
+static struct lline *coalesce_lines(struct lline *base, int *lenbase,
+ struct lline *new, int lennew,
+ unsigned long parent, long flags)
{
- struct lline *lline;
- unsigned long this_mask = (1UL<<n);
- if (line[len-1] == '\n')
- len--;
+ int **lcs;
+ enum coalesce_direction **directions;
+ struct lline *baseend, *newend = NULL;
+ int i, j, origbaselen = *lenbase;
- /* Check to see if we can squash things */
- if (sline->lost_head) {
- lline = sline->next_lost;
- while (lline) {
- if (match_string_spaces(lline->line, lline->len,
- line, len, flags)) {
- lline->parent_map |= this_mask;
- sline->next_lost = lline->next;
- return;
+ if (new == NULL)
+ return base;
+
+ if (base == NULL) {
+ *lenbase = lennew;
+ return new;
+ }
+
+ /*
+ * Coalesce new lines into base by finding the LCS
+ * - Create the table to run dynamic programming
+ * - Compute the LCS
+ * - Then reverse read the direction structure:
+ * - If we have MATCH, assign parent to base flag, and consume
+ * both baseend and newend
+ * - Else if we have BASE, consume baseend
+ * - Else if we have NEW, insert newend lline into base and
+ * consume newend
+ */
+ lcs = xcalloc(origbaselen + 1, sizeof(int*));
+ directions = xcalloc(origbaselen + 1, sizeof(enum coalesce_direction*));
+ for (i = 0; i < origbaselen + 1; i++) {
+ lcs[i] = xcalloc(lennew + 1, sizeof(int));
+ directions[i] = xcalloc(lennew + 1, sizeof(enum coalesce_direction));
+ directions[i][0] = BASE;
+ }
+ for (j = 1; j < lennew + 1; j++)
+ directions[0][j] = NEW;
+
+ for (i = 1, baseend = base; i < origbaselen + 1; i++) {
+ for (j = 1, newend = new; j < lennew + 1; j++) {
+ if (match_string_spaces(baseend->line, baseend->len,
+ newend->line, newend->len, flags)) {
+ lcs[i][j] = lcs[i - 1][j - 1] + 1;
+ directions[i][j] = MATCH;
+ } else if (lcs[i][j - 1] >= lcs[i - 1][j]) {
+ lcs[i][j] = lcs[i][j - 1];
+ directions[i][j] = NEW;
+ } else {
+ lcs[i][j] = lcs[i - 1][j];
+ directions[i][j] = BASE;
}
- lline = lline->next;
+ if (newend->next)
+ newend = newend->next;
}
+ if (baseend->next)
+ baseend = baseend->next;
}
+ for (i = 0; i < origbaselen + 1; i++)
+ free(lcs[i]);
+ free(lcs);
+
+ /* At this point, baseend and newend point to the end of each lists */
+ i--;
+ j--;
+ while (i != 0 || j != 0) {
+ if (directions[i][j] == MATCH) {
+ baseend->parent_map |= 1<<parent;
+ baseend = baseend->prev;
+ newend = newend->prev;
+ i--;
+ j--;
+ } else if (directions[i][j] == NEW) {
+ struct lline *lline;
+
+ lline = newend;
+ /* Remove lline from new list and update newend */
+ if (lline->prev)
+ lline->prev->next = lline->next;
+ else
+ new = lline->next;
+ if (lline->next)
+ lline->next->prev = lline->prev;
+
+ newend = lline->prev;
+ j--;
+
+ /* Add lline to base list */
+ if (baseend) {
+ lline->next = baseend->next;
+ lline->prev = baseend;
+ if (lline->prev)
+ lline->prev->next = lline;
+ }
+ else {
+ lline->next = base;
+ base = lline;
+ }
+ (*lenbase)++;
+
+ if (lline->next)
+ lline->next->prev = lline;
+
+ } else {
+ baseend = baseend->prev;
+ i--;
+ }
+ }
+
+ newend = new;
+ while (newend) {
+ struct lline *lline = newend;
+ newend = newend->next;
+ free(lline);
+ }
+
+ for (i = 0; i < origbaselen + 1; i++)
+ free(directions[i]);
+ free(directions);
+
+ return base;
+}
+
+static char *grab_blob(const unsigned char *sha1, unsigned int mode,
+ unsigned long *size, struct userdiff_driver *textconv,
+ const char *path)
+{
+ char *blob;
+ enum object_type type;
+
+ if (S_ISGITLINK(mode)) {
+ blob = xmalloc(100);
+ *size = snprintf(blob, 100,
+ "Subproject commit %s\n", sha1_to_hex(sha1));
+ } else if (is_null_sha1(sha1)) {
+ /* deleted blob */
+ *size = 0;
+ return xcalloc(1, 1);
+ } else if (textconv) {
+ struct diff_filespec *df = alloc_filespec(path);
+ fill_filespec(df, sha1, 1, mode);
+ *size = fill_textconv(textconv, df, &blob);
+ free_filespec(df);
+ } else {
+ blob = read_sha1_file(sha1, &type, size);
+ if (type != OBJ_BLOB)
+ die("object '%s' is not a blob!", sha1_to_hex(sha1));
+ }
+ return blob;
+}
+
+static void append_lost(struct sline *sline, int n, const char *line, int len)
+{
+ struct lline *lline;
+ unsigned long this_mask = (1UL<<n);
+ if (line[len-1] == '\n')
+ len--;
+
lline = xmalloc(sizeof(*lline) + len + 1);
lline->len = len;
lline->next = NULL;
+ lline->prev = sline->plost.lost_tail;
+ if (lline->prev)
+ lline->prev->next = lline;
+ else
+ sline->plost.lost_head = lline;
+ sline->plost.lost_tail = lline;
+ sline->plost.len++;
lline->parent_map = this_mask;
memcpy(lline->line, line, len);
lline->line[len] = 0;
- *sline->lost_tail = lline;
- sline->lost_tail = &lline->next;
- sline->next_lost = NULL;
}
struct combine_diff_state {
@@ -203,7 +328,6 @@ struct combine_diff_state {
int n;
struct sline *sline;
struct sline *lost_bucket;
- long flags;
};
static void consume_line(void *state_, char *line, unsigned long len)
@@ -236,14 +360,13 @@ static void consume_line(void *state_, char *line, unsigned long len)
xcalloc(state->num_parent,
sizeof(unsigned long));
state->sline[state->nb-1].p_lno[state->n] = state->ob;
- state->lost_bucket->next_lost = state->lost_bucket->lost_head;
return;
}
if (!state->lost_bucket)
return; /* not in any hunk yet */
switch (line[0]) {
case '-':
- append_lost(state->lost_bucket, state->n, line+1, len-1, state->flags);
+ append_lost(state->lost_bucket, state->n, line+1, len-1);
break;
case '+':
state->sline[state->lno-1].flag |= state->nmask;
@@ -276,7 +399,6 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
xpp.flags = flags;
memset(&xecfg, 0, sizeof(xecfg));
memset(&state, 0, sizeof(state));
- state.flags = flags;
state.nmask = nmask;
state.sline = sline;
state.lno = 1;
@@ -298,8 +420,18 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
struct lline *ll;
sline[lno].p_lno[n] = p_lno;
+ /* Coalesce new lines */
+ if (sline[lno].plost.lost_head) {
+ struct sline *sl = &sline[lno];
+ sl->lost = coalesce_lines(sl->lost, &sl->lenlost,
+ sl->plost.lost_head,
+ sl->plost.len, n, flags);
+ sl->plost.lost_head = sl->plost.lost_tail = NULL;
+ sl->plost.len = 0;
+ }
+
/* How many lines would this sline advance the p_lno? */
- ll = sline[lno].lost_head;
+ ll = sline[lno].lost;
while (ll) {
if (ll->parent_map & nmask)
p_lno++; /* '-' means parent had it */
@@ -319,7 +451,7 @@ static int interesting(struct sline *sline, unsigned long all_mask)
/* If some parents lost lines here, or if we have added to
* some parent, it is interesting.
*/
- return ((sline->flag & all_mask) || sline->lost_head);
+ return ((sline->flag & all_mask) || sline->lost);
}
static unsigned long adjust_hunk_tail(struct sline *sline,
@@ -387,8 +519,11 @@ static int give_context(struct sline *sline, unsigned long cnt, int num_parent)
unsigned long k;
/* Paint a few lines before the first interesting line. */
- while (j < i)
- sline[j++].flag |= mark | no_pre_delete;
+ while (j < i) {
+ if (!(sline[j].flag & mark))
+ sline[j].flag |= no_pre_delete;
+ sline[j++].flag |= mark;
+ }
again:
/* we know up to i is to be included. where does the
@@ -502,7 +637,7 @@ static int make_hunks(struct sline *sline, unsigned long cnt,
has_interesting = 0;
for (j = i; j < hunk_end && !has_interesting; j++) {
unsigned long this_diff = sline[j].flag & all_mask;
- struct lline *ll = sline[j].lost_head;
+ struct lline *ll = sline[j].lost;
if (this_diff) {
/* This has some changes. Is it the
* same as others?
@@ -656,7 +791,7 @@ static void dump_sline(struct sline *sline, const char *line_prefix,
int j;
unsigned long p_mask;
struct sline *sl = &sline[lno++];
- ll = (sl->flag & no_pre_delete) ? NULL : sl->lost_head;
+ ll = (sl->flag & no_pre_delete) ? NULL : sl->lost;
while (ll) {
printf("%s%s", line_prefix, c_old);
for (j = 0; j < num_parent; j++) {
@@ -707,7 +842,7 @@ static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
jmask = (1UL<<j);
for (lno = 0; lno <= cnt; lno++) {
- struct lline *ll = sline->lost_head;
+ struct lline *ll = sline->lost;
sline->p_lno[i] = sline->p_lno[j];
while (ll) {
if (ll->parent_map & jmask)
@@ -966,10 +1101,6 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
sline = xcalloc(cnt+2, sizeof(*sline));
sline[0].bol = result;
- for (lno = 0; lno <= cnt + 1; lno++) {
- sline[lno].lost_tail = &sline[lno].lost_head;
- sline[lno].flag = 0;
- }
for (lno = 0, cp = result; cp < result + result_size; cp++) {
if (*cp == '\n') {
sline[lno].len = cp - sline[lno].bol;
@@ -1019,8 +1150,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
free(result);
for (lno = 0; lno < cnt; lno++) {
- if (sline[lno].lost_head) {
- struct lline *ll = sline[lno].lost_head;
+ if (sline[lno].lost) {
+ struct lline *ll = sline[lno].lost;
while (ll) {
struct lline *tmp = ll;
ll = ll->next;
@@ -1175,6 +1306,7 @@ void diff_tree_combined(const unsigned char *sha1,
int i, num_paths, needsep, show_log_first, num_parent = parents->nr;
diffopts = *opt;
+ copy_pathspec(&diffopts.pathspec, &opt->pathspec);
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
DIFF_OPT_SET(&diffopts, RECURSIVE);
DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
@@ -1245,12 +1377,14 @@ void diff_tree_combined(const unsigned char *sha1,
paths = paths->next;
free(tmp);
}
+
+ free_pathspec(&diffopts.pathspec);
}
void diff_tree_combined_merge(const struct commit *commit, int dense,
struct rev_info *rev)
{
- struct commit_list *parent = commit->parents;
+ struct commit_list *parent = get_saved_parents(rev, commit);
struct sha1_array parents = SHA1_ARRAY_INIT;
while (parent) {
diff --git a/command-list.txt b/command-list.txt
index bf83303..08b04e2 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -13,6 +13,7 @@ git-bundle mainporcelain
git-cat-file plumbinginterrogators
git-check-attr purehelpers
git-check-ignore purehelpers
+git-check-mailmap purehelpers
git-checkout mainporcelain common
git-checkout-index plumbingmanipulators
git-check-ref-format purehelpers
diff --git a/commit-slab.h b/commit-slab.h
new file mode 100644
index 0000000..d4c8286
--- /dev/null
+++ b/commit-slab.h
@@ -0,0 +1,97 @@
+#ifndef COMMIT_SLAB_H
+#define COMMIT_SLAB_H
+
+/*
+ * define_commit_slab(slabname, elemtype) creates boilerplate code to define
+ * a new struct (struct slabname) that is used to associate a piece of data
+ * of elemtype to commits, and a few functions to use that struct.
+ *
+ * After including this header file, using:
+ *
+ * define_commit_slab(indegee, int);
+ *
+ * will let you call the following functions:
+ *
+ * - int *indegree_at(struct indegree *, struct commit *);
+ *
+ * This function locates the data associated with the given commit in
+ * the indegree slab, and returns the pointer to it.
+ *
+ * - void init_indegree(struct indegree *);
+ * void init_indegree_with_stride(struct indegree *, int);
+ *
+ * Initializes the indegree slab that associates an array of integers
+ * to each commit. 'stride' specifies how big each array is. The slab
+ * that id initialied by the variant without "_with_stride" associates
+ * each commit with an array of one integer.
+ */
+
+/* allocate ~512kB at once, allowing for malloc overhead */
+#ifndef COMMIT_SLAB_SIZE
+#define COMMIT_SLAB_SIZE (512*1024-32)
+#endif
+
+#define define_commit_slab(slabname, elemtype) \
+ \
+struct slabname { \
+ unsigned slab_size; \
+ unsigned stride; \
+ unsigned slab_count; \
+ elemtype **slab; \
+}; \
+static int stat_ ##slabname## realloc; \
+ \
+static void init_ ##slabname## _with_stride(struct slabname *s, \
+ unsigned stride) \
+{ \
+ unsigned int elem_size; \
+ if (!stride) \
+ stride = 1; \
+ s->stride = stride; \
+ elem_size = sizeof(elemtype) * stride; \
+ s->slab_size = COMMIT_SLAB_SIZE / elem_size; \
+ s->slab_count = 0; \
+ s->slab = NULL; \
+} \
+ \
+static void init_ ##slabname(struct slabname *s) \
+{ \
+ init_ ##slabname## _with_stride(s, 1); \
+} \
+ \
+static void clear_ ##slabname(struct slabname *s) \
+{ \
+ int i; \
+ for (i = 0; i < s->slab_count; i++) \
+ free(s->slab[i]); \
+ s->slab_count = 0; \
+ free(s->slab); \
+ s->slab = NULL; \
+} \
+ \
+static elemtype *slabname## _at(struct slabname *s, \
+ const struct commit *c) \
+{ \
+ int nth_slab, nth_slot; \
+ \
+ nth_slab = c->index / s->slab_size; \
+ nth_slot = c->index % s->slab_size; \
+ \
+ if (s->slab_count <= nth_slab) { \
+ int i; \
+ s->slab = xrealloc(s->slab, \
+ (nth_slab + 1) * sizeof(s->slab)); \
+ stat_ ##slabname## realloc++; \
+ for (i = s->slab_count; i <= nth_slab; i++) \
+ s->slab[i] = NULL; \
+ s->slab_count = nth_slab + 1; \
+ } \
+ if (!s->slab[nth_slab]) \
+ s->slab[nth_slab] = xcalloc(s->slab_size, \
+ sizeof(**s->slab) * s->stride); \
+ return &s->slab[nth_slab][nth_slot * s->stride]; \
+} \
+ \
+static int stat_ ##slabname## realloc
+
+#endif /* COMMIT_SLAB_H */
diff --git a/commit.c b/commit.c
index 1a41757..de16a3c 100644
--- a/commit.c
+++ b/commit.c
@@ -8,12 +8,15 @@
#include "notes.h"
#include "gpg-interface.h"
#include "mergesort.h"
+#include "commit-slab.h"
+#include "prio-queue.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";
+static int commit_count;
static struct commit *check_commit(struct object *obj,
const unsigned char *sha1,
@@ -58,8 +61,11 @@ struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_n
struct commit *lookup_commit(const unsigned char *sha1)
{
struct object *obj = lookup_object(sha1);
- if (!obj)
- return create_object(sha1, OBJ_COMMIT, alloc_commit_node());
+ if (!obj) {
+ struct commit *c = alloc_commit_node();
+ c->index = commit_count++;
+ return create_object(sha1, OBJ_COMMIT, c);
+ }
if (!obj->type)
obj->type = OBJ_COMMIT;
return check_commit(obj, sha1, 0);
@@ -371,6 +377,22 @@ unsigned commit_list_count(const struct commit_list *l)
return c;
}
+struct commit_list *copy_commit_list(struct commit_list *list)
+{
+ struct commit_list *head = NULL;
+ struct commit_list **pp = &head;
+ while (list) {
+ struct commit_list *new;
+ new = xmalloc(sizeof(struct commit_list));
+ new->item = list->item;
+ new->next = NULL;
+ *pp = new;
+ pp = &new->next;
+ list = list->next;
+ }
+ return head;
+}
+
void free_commit_list(struct commit_list *list)
{
while (list) {
@@ -463,14 +485,23 @@ static void clear_commit_marks_1(struct commit_list **plist,
}
}
-void clear_commit_marks(struct commit *commit, unsigned int mark)
+void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark)
{
struct commit_list *list = NULL;
- commit_list_insert(commit, &list);
+
+ while (nr--) {
+ commit_list_insert(*commit, &list);
+ commit++;
+ }
while (list)
clear_commit_marks_1(&list, pop_commit(&list), mark);
}
+void clear_commit_marks(struct commit *commit, unsigned int mark)
+{
+ clear_commit_marks_many(1, &commit, mark);
+}
+
void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark)
{
struct object *object;
@@ -498,32 +529,136 @@ struct commit *pop_commit(struct commit_list **stack)
}
/*
+ * Topological sort support
+ */
+
+/* count number of children that have not been emitted */
+define_commit_slab(indegree_slab, int);
+
+/* record author-date for each commit object */
+define_commit_slab(author_date_slab, unsigned long);
+
+static void record_author_date(struct author_date_slab *author_date,
+ struct commit *commit)
+{
+ const char *buf, *line_end;
+ char *buffer = NULL;
+ struct ident_split ident;
+ char *date_end;
+ unsigned long date;
+
+ if (!commit->buffer) {
+ unsigned long size;
+ enum object_type type;
+ buffer = read_sha1_file(commit->object.sha1, &type, &size);
+ if (!buffer)
+ return;
+ }
+
+ for (buf = commit->buffer ? commit->buffer : buffer;
+ buf;
+ buf = line_end + 1) {
+ line_end = strchrnul(buf, '\n');
+ if (prefixcmp(buf, "author ")) {
+ if (!line_end[0] || line_end[1] == '\n')
+ return; /* end of header */
+ continue;
+ }
+ if (split_ident_line(&ident,
+ buf + strlen("author "),
+ line_end - (buf + strlen("author "))) ||
+ !ident.date_begin || !ident.date_end)
+ goto fail_exit; /* malformed "author" line */
+ break;
+ }
+
+ date = strtoul(ident.date_begin, &date_end, 10);
+ if (date_end != ident.date_end)
+ goto fail_exit; /* malformed date */
+ *(author_date_slab_at(author_date, commit)) = date;
+
+fail_exit:
+ free(buffer);
+}
+
+static int compare_commits_by_author_date(const void *a_, const void *b_,
+ void *cb_data)
+{
+ const struct commit *a = a_, *b = b_;
+ struct author_date_slab *author_date = cb_data;
+ unsigned long a_date = *(author_date_slab_at(author_date, a));
+ unsigned long b_date = *(author_date_slab_at(author_date, b));
+
+ /* newer commits with larger date first */
+ if (a_date < b_date)
+ return 1;
+ else if (a_date > b_date)
+ return -1;
+ return 0;
+}
+
+int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
+{
+ const struct commit *a = a_, *b = b_;
+ /* newer commits with larger date first */
+ if (a->date < b->date)
+ return 1;
+ else if (a->date > b->date)
+ return -1;
+ return 0;
+}
+
+/*
* Performs an in-place topological sort on the list supplied.
*/
-void sort_in_topological_order(struct commit_list ** list, int lifo)
+void sort_in_topological_order(struct commit_list **list, enum rev_sort_order sort_order)
{
struct commit_list *next, *orig = *list;
- struct commit_list *work, **insert;
struct commit_list **pptr;
+ struct indegree_slab indegree;
+ struct prio_queue queue;
+ struct commit *commit;
+ struct author_date_slab author_date;
if (!orig)
return;
*list = NULL;
+ init_indegree_slab(&indegree);
+ memset(&queue, '\0', sizeof(queue));
+
+ switch (sort_order) {
+ default: /* REV_SORT_IN_GRAPH_ORDER */
+ queue.compare = NULL;
+ break;
+ case REV_SORT_BY_COMMIT_DATE:
+ queue.compare = compare_commits_by_commit_date;
+ break;
+ case REV_SORT_BY_AUTHOR_DATE:
+ init_author_date_slab(&author_date);
+ queue.compare = compare_commits_by_author_date;
+ queue.cb_data = &author_date;
+ break;
+ }
+
/* Mark them and clear the indegree */
for (next = orig; next; next = next->next) {
struct commit *commit = next->item;
- commit->indegree = 1;
+ *(indegree_slab_at(&indegree, commit)) = 1;
+ /* also record the author dates, if needed */
+ if (sort_order == REV_SORT_BY_AUTHOR_DATE)
+ record_author_date(&author_date, commit);
}
/* update the indegree */
for (next = orig; next; next = next->next) {
- struct commit_list * parents = next->item->parents;
+ struct commit_list *parents = next->item->parents;
while (parents) {
struct commit *parent = parents->item;
+ int *pi = indegree_slab_at(&indegree, parent);
- if (parent->indegree)
- parent->indegree++;
+ if (*pi)
+ (*pi)++;
parents = parents->next;
}
}
@@ -535,34 +670,33 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
*
* the tips serve as a starting set for the work queue.
*/
- work = NULL;
- insert = &work;
for (next = orig; next; next = next->next) {
struct commit *commit = next->item;
- if (commit->indegree == 1)
- insert = &commit_list_insert(commit, insert)->next;
+ if (*(indegree_slab_at(&indegree, commit)) == 1)
+ prio_queue_put(&queue, commit);
}
- /* process the list in topological order */
- if (!lifo)
- commit_list_sort_by_date(&work);
+ /*
+ * This is unfortunate; the initial tips need to be shown
+ * in the order given from the revision traversal machinery.
+ */
+ if (sort_order == REV_SORT_IN_GRAPH_ORDER)
+ prio_queue_reverse(&queue);
+
+ /* We no longer need the commit list */
+ free_commit_list(orig);
pptr = list;
*list = NULL;
- while (work) {
- struct commit *commit;
- struct commit_list *parents, *work_item;
-
- work_item = work;
- work = work_item->next;
- work_item->next = NULL;
+ while ((commit = prio_queue_get(&queue)) != NULL) {
+ struct commit_list *parents;
- commit = work_item->item;
for (parents = commit->parents; parents ; parents = parents->next) {
struct commit *parent = parents->item;
+ int *pi = indegree_slab_at(&indegree, parent);
- if (!parent->indegree)
+ if (!*pi)
continue;
/*
@@ -570,21 +704,22 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
* when all their children have been emitted thereby
* guaranteeing topological order.
*/
- if (--parent->indegree == 1) {
- if (!lifo)
- commit_list_insert_by_date(parent, &work);
- else
- commit_list_insert(parent, &work);
- }
+ if (--(*pi) == 1)
+ prio_queue_put(&queue, parent);
}
/*
- * work_item is a commit all of whose children
- * have already been emitted. we can emit it now.
+ * all children of commit have already been
+ * emitted. we can emit it now.
*/
- commit->indegree = 0;
- *pptr = work_item;
- pptr = &work_item->next;
+ *(indegree_slab_at(&indegree, commit)) = 0;
+
+ pptr = &commit_list_insert(commit, pptr)->next;
}
+
+ clear_indegree_slab(&indegree);
+ clear_prio_queue(&queue);
+ if (sort_order == REV_SORT_BY_AUTHOR_DATE)
+ clear_author_date_slab(&author_date);
}
/* merge-base stuff */
@@ -797,8 +932,7 @@ struct commit_list *get_merge_bases_many(struct commit *one,
if (!result || !result->next) {
if (cleanup) {
clear_commit_marks(one, all_flags);
- for (i = 0; i < n; i++)
- clear_commit_marks(twos[i], all_flags);
+ clear_commit_marks_many(n, twos, all_flags);
}
return result;
}
@@ -816,8 +950,7 @@ struct commit_list *get_merge_bases_many(struct commit *one,
free_commit_list(result);
clear_commit_marks(one, all_flags);
- for (i = 0; i < n; i++)
- clear_commit_marks(twos[i], all_flags);
+ clear_commit_marks_many(n, twos, all_flags);
cnt = remove_redundant(rslt, cnt);
result = NULL;
@@ -852,25 +985,36 @@ int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
}
/*
- * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
+ * Is "commit" an ancestor of one of the "references"?
*/
-int in_merge_bases(struct commit *commit, struct commit *reference)
+int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference)
{
struct commit_list *bases;
- int ret = 0;
+ int ret = 0, i;
- if (parse_commit(commit) || parse_commit(reference))
+ if (parse_commit(commit))
return ret;
+ for (i = 0; i < nr_reference; i++)
+ if (parse_commit(reference[i]))
+ return ret;
- bases = paint_down_to_common(commit, 1, &reference);
+ bases = paint_down_to_common(commit, nr_reference, reference);
if (commit->object.flags & PARENT2)
ret = 1;
clear_commit_marks(commit, all_flags);
- clear_commit_marks(reference, all_flags);
+ clear_commit_marks_many(nr_reference, reference, all_flags);
free_commit_list(bases);
return ret;
}
+/*
+ * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
+ */
+int in_merge_bases(struct commit *commit, struct commit *reference)
+{
+ return in_merge_bases_many(commit, 1, &reference);
+}
+
struct commit_list *reduce_heads(struct commit_list *heads)
{
struct commit_list *p;
@@ -1023,6 +1167,76 @@ free_return:
free(buf);
}
+static struct {
+ char result;
+ const char *check;
+} sigcheck_gpg_status[] = {
+ { 'G', "\n[GNUPG:] GOODSIG " },
+ { 'B', "\n[GNUPG:] BADSIG " },
+ { 'U', "\n[GNUPG:] TRUST_NEVER" },
+ { 'U', "\n[GNUPG:] TRUST_UNDEFINED" },
+};
+
+static void parse_gpg_output(struct signature_check *sigc)
+{
+ const char *buf = sigc->gpg_status;
+ int i;
+
+ /* Iterate over all search strings */
+ for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
+ const char *found, *next;
+
+ if (!prefixcmp(buf, sigcheck_gpg_status[i].check + 1)) {
+ /* At the very beginning of the buffer */
+ found = buf + strlen(sigcheck_gpg_status[i].check + 1);
+ } else {
+ found = strstr(buf, sigcheck_gpg_status[i].check);
+ if (!found)
+ continue;
+ found += strlen(sigcheck_gpg_status[i].check);
+ }
+ sigc->result = sigcheck_gpg_status[i].result;
+ /* The trust messages are not followed by key/signer information */
+ if (sigc->result != 'U') {
+ sigc->key = xmemdupz(found, 16);
+ found += 17;
+ next = strchrnul(found, '\n');
+ sigc->signer = xmemdupz(found, next - found);
+ }
+ }
+}
+
+void check_commit_signature(const struct commit* commit, struct signature_check *sigc)
+{
+ struct strbuf payload = STRBUF_INIT;
+ struct strbuf signature = STRBUF_INIT;
+ struct strbuf gpg_output = STRBUF_INIT;
+ struct strbuf gpg_status = STRBUF_INIT;
+ int status;
+
+ sigc->result = 'N';
+
+ if (parse_signed_commit(commit->object.sha1,
+ &payload, &signature) <= 0)
+ goto out;
+ status = verify_signed_buffer(payload.buf, payload.len,
+ signature.buf, signature.len,
+ &gpg_output, &gpg_status);
+ if (status && !gpg_output.len)
+ goto out;
+ sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
+ sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
+ parse_gpg_output(sigc);
+
+ out:
+ strbuf_release(&gpg_status);
+ strbuf_release(&gpg_output);
+ strbuf_release(&payload);
+ strbuf_release(&signature);
+}
+
+
+
void append_merge_tag_headers(struct commit_list *parents,
struct commit_extra_header ***tail)
{
@@ -1152,10 +1366,15 @@ int commit_tree(const struct strbuf *msg, unsigned char *tree,
static int find_invalid_utf8(const char *buf, int len)
{
int offset = 0;
+ static const unsigned int max_codepoint[] = {
+ 0x7f, 0x7ff, 0xffff, 0x10ffff
+ };
while (len) {
unsigned char c = *buf++;
int bytes, bad_offset;
+ unsigned int codepoint;
+ unsigned int min_val, max_val;
len--;
offset++;
@@ -1176,24 +1395,48 @@ static int find_invalid_utf8(const char *buf, int len)
bytes++;
}
- /* Must be between 1 and 5 more bytes */
- if (bytes < 1 || bytes > 5)
+ /*
+ * Must be between 1 and 3 more bytes. Longer sequences result in
+ * codepoints beyond U+10FFFF, which are guaranteed never to exist.
+ */
+ if (bytes < 1 || 3 < bytes)
return bad_offset;
/* Do we *have* that many bytes? */
if (len < bytes)
return bad_offset;
+ /*
+ * Place the encoded bits at the bottom of the value and compute the
+ * valid range.
+ */
+ codepoint = (c & 0x7f) >> bytes;
+ min_val = max_codepoint[bytes-1] + 1;
+ max_val = max_codepoint[bytes];
+
offset += bytes;
len -= bytes;
/* And verify that they are good continuation bytes */
do {
+ codepoint <<= 6;
+ codepoint |= *buf & 0x3f;
if ((*buf++ & 0xc0) != 0x80)
return bad_offset;
} while (--bytes);
- /* We could/should check the value and length here too */
+ /* Reject codepoints that are out of range for the sequence length. */
+ if (codepoint < min_val || codepoint > max_val)
+ return bad_offset;
+ /* Surrogates are only for UTF-16 and cannot be encoded in UTF-8. */
+ if ((codepoint & 0x1ff800) == 0xd800)
+ return bad_offset;
+ /* U+xxFFFE and U+xxFFFF are guaranteed non-characters. */
+ if ((codepoint & 0xfffe) == 0xfffe)
+ return bad_offset;
+ /* So are anything in the range U+FDD0..U+FDEF. */
+ if (codepoint >= 0xfdd0 && codepoint <= 0xfdef)
+ return bad_offset;
}
return -1;
}
@@ -1203,9 +1446,6 @@ static int find_invalid_utf8(const char *buf, int len)
*
* 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)
{
diff --git a/commit.h b/commit.h
index 252c7f8..90a5a3c 100644
--- a/commit.h
+++ b/commit.h
@@ -5,6 +5,8 @@
#include "tree.h"
#include "strbuf.h"
#include "decorate.h"
+#include "gpg-interface.h"
+#include "string-list.h"
struct commit_list {
struct commit *item;
@@ -14,7 +16,7 @@ struct commit_list {
struct commit {
struct object object;
void *util;
- unsigned int indegree;
+ unsigned int index;
unsigned long date;
struct commit_list *parents;
struct tree *tree;
@@ -60,6 +62,9 @@ struct commit_list *commit_list_insert_by_date(struct commit *item,
struct commit_list **list);
void commit_list_sort_by_date(struct commit_list **list);
+/* Shallow copy of the input list */
+struct commit_list *copy_commit_list(struct commit_list *list);
+
void free_commit_list(struct commit_list *list);
/* Commit formats */
@@ -78,6 +83,9 @@ enum cmit_fmt {
};
struct pretty_print_context {
+ /*
+ * Callers should tweak these to change the behavior of pp_* functions.
+ */
enum cmit_fmt fmt;
int abbrev;
const char *subject;
@@ -91,6 +99,13 @@ struct pretty_print_context {
const char *output_encoding;
struct string_list *mailmap;
int color;
+ struct ident_split *from_ident;
+
+ /*
+ * Fields below here are manipulated internally by pp_* functions and
+ * should not be counted on by callers.
+ */
+ struct string_list in_body_headers;
};
struct userformat_want {
@@ -100,6 +115,7 @@ struct userformat_want {
extern int has_non_ascii(const char *text);
struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
extern char *logmsg_reencode(const struct commit *commit,
+ char **commit_encoding,
const char *output_encoding);
extern void logmsg_free(char *msg, const struct commit *commit);
extern void get_commit_format(const char *arg, struct rev_info *);
@@ -109,20 +125,20 @@ extern void userformat_find_requirements(const char *fmt, struct userformat_want
extern void format_commit_message(const struct commit *commit,
const char *format, struct strbuf *sb,
const struct pretty_print_context *context);
-extern void pretty_print_commit(const struct pretty_print_context *pp,
+extern void pretty_print_commit(struct pretty_print_context *pp,
const struct commit *commit,
struct strbuf *sb);
extern void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
struct strbuf *sb);
-void pp_user_info(const struct pretty_print_context *pp,
+void pp_user_info(struct pretty_print_context *pp,
const char *what, struct strbuf *sb,
const char *line, const char *encoding);
-void pp_title_line(const struct pretty_print_context *pp,
+void pp_title_line(struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
const char *encoding,
int need_8bit_cte);
-void pp_remainder(const struct pretty_print_context *pp,
+void pp_remainder(struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
int indent);
@@ -137,17 +153,27 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
struct commit *pop_commit(struct commit_list **stack);
void clear_commit_marks(struct commit *commit, unsigned int mark);
+void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark);
void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark);
+
+enum rev_sort_order {
+ REV_SORT_IN_GRAPH_ORDER = 0,
+ REV_SORT_BY_COMMIT_DATE,
+ REV_SORT_BY_AUTHOR_DATE
+};
+
/*
* Performs an in-place topological sort of list supplied.
*
* invariant of resulting list is:
* a reachable from b => ord(b) < ord(a)
- * in addition, when lifo == 0, commits on parallel tracks are
- * sorted in the dates order.
+ * sort_order further specifies:
+ * REV_SORT_IN_GRAPH_ORDER: try to show a commit on a single-parent
+ * chain together.
+ * REV_SORT_BY_COMMIT_DATE: show eligible commits in committer-date order.
*/
-void sort_in_topological_order(struct commit_list ** list, int lifo);
+void sort_in_topological_order(struct commit_list **, enum rev_sort_order);
struct commit_graft {
unsigned char sha1[20];
@@ -173,13 +199,16 @@ extern int for_each_commit_graft(each_commit_graft_fn, void *);
extern int is_repository_shallow(void);
extern struct commit_list *get_shallow_commits(struct object_array *heads,
int depth, int shallow_flag, int not_shallow_flag);
+extern void check_shallow_file_for_update(void);
+extern void set_alternate_shallow_file(const char *path);
int is_descendant_of(struct commit *, struct commit_list *);
int in_merge_bases(struct commit *, struct commit *);
+int in_merge_bases_many(struct commit *, int, 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,
- const char **pathspec);
+ const struct pathspec *pathspec);
static inline int single_parent(struct commit *commit)
{
@@ -230,4 +259,15 @@ extern void print_commit_list(struct commit_list *list,
const char *format_cur,
const char *format_last);
+/*
+ * Check the signature of the given commit. The result of the check is stored
+ * in sig->check_result, 'G' for a good signature, 'U' for a good signature
+ * from an untrusted signer, 'B' for a bad signature and 'N' for no signature
+ * at all. This may allocate memory for sig->gpg_output, sig->gpg_status,
+ * sig->signer and sig->key.
+ */
+extern void check_commit_signature(const struct commit* commit, struct signature_check *sigc);
+
+int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused);
+
#endif /* COMMIT_H */
diff --git a/compat/apple-common-crypto.h b/compat/apple-common-crypto.h
new file mode 100644
index 0000000..c8b9b0e
--- /dev/null
+++ b/compat/apple-common-crypto.h
@@ -0,0 +1,86 @@
+/* suppress inclusion of conflicting openssl functions */
+#define OPENSSL_NO_MD5
+#define HEADER_HMAC_H
+#define HEADER_SHA_H
+#include <CommonCrypto/CommonHMAC.h>
+#define HMAC_CTX CCHmacContext
+#define HMAC_Init(hmac, key, len, algo) CCHmacInit(hmac, algo, key, len)
+#define HMAC_Update CCHmacUpdate
+#define HMAC_Final(hmac, hash, ptr) CCHmacFinal(hmac, hash)
+#define HMAC_CTX_cleanup(ignore)
+#define EVP_md5(...) kCCHmacAlgMD5
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+#define APPLE_LION_OR_NEWER
+#include <Security/Security.h>
+/* Apple's TYPE_BOOL conflicts with config.c */
+#undef TYPE_BOOL
+#endif
+
+#ifdef APPLE_LION_OR_NEWER
+#define git_CC_error_check(pattern, err) \
+ do { \
+ if (err) { \
+ die(pattern, (long)CFErrorGetCode(err)); \
+ } \
+ } while(0)
+
+#define EVP_EncodeBlock git_CC_EVP_EncodeBlock
+static inline int git_CC_EVP_EncodeBlock(unsigned char *out,
+ const unsigned char *in, int inlen)
+{
+ CFErrorRef err;
+ SecTransformRef encoder;
+ CFDataRef input, output;
+ CFIndex length;
+
+ encoder = SecEncodeTransformCreate(kSecBase64Encoding, &err);
+ git_CC_error_check("SecEncodeTransformCreate failed: %ld", err);
+
+ input = CFDataCreate(kCFAllocatorDefault, in, inlen);
+ SecTransformSetAttribute(encoder, kSecTransformInputAttributeName,
+ input, &err);
+ git_CC_error_check("SecTransformSetAttribute failed: %ld", err);
+
+ output = SecTransformExecute(encoder, &err);
+ git_CC_error_check("SecTransformExecute failed: %ld", err);
+
+ length = CFDataGetLength(output);
+ CFDataGetBytes(output, CFRangeMake(0, length), out);
+
+ CFRelease(output);
+ CFRelease(input);
+ CFRelease(encoder);
+
+ return (int)strlen((const char *)out);
+}
+
+#define EVP_DecodeBlock git_CC_EVP_DecodeBlock
+static int inline git_CC_EVP_DecodeBlock(unsigned char *out,
+ const unsigned char *in, int inlen)
+{
+ CFErrorRef err;
+ SecTransformRef decoder;
+ CFDataRef input, output;
+ CFIndex length;
+
+ decoder = SecDecodeTransformCreate(kSecBase64Encoding, &err);
+ git_CC_error_check("SecEncodeTransformCreate failed: %ld", err);
+
+ input = CFDataCreate(kCFAllocatorDefault, in, inlen);
+ SecTransformSetAttribute(decoder, kSecTransformInputAttributeName,
+ input, &err);
+ git_CC_error_check("SecTransformSetAttribute failed: %ld", err);
+
+ output = SecTransformExecute(decoder, &err);
+ git_CC_error_check("SecTransformExecute failed: %ld", err);
+
+ length = CFDataGetLength(output);
+ CFDataGetBytes(output, CFRangeMake(0, length), out);
+
+ CFRelease(output);
+ CFRelease(input);
+ CFRelease(decoder);
+
+ return (int)strlen((const char *)out);
+}
+#endif /* APPLE_LION_OR_NEWER */
diff --git a/compat/cygwin.c b/compat/cygwin.c
deleted file mode 100644
index 5428858..0000000
--- a/compat/cygwin.c
+++ /dev/null
@@ -1,149 +0,0 @@
-#define WIN32_LEAN_AND_MEAN
-#ifdef CYGWIN_V15_WIN32API
-#include "../git-compat-util.h"
-#include "win32.h"
-#else
-#include <sys/stat.h>
-#include <sys/errno.h>
-#include "win32.h"
-#include "../git-compat-util.h"
-#endif
-#include "../cache.h" /* to read configuration */
-
-static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
-{
- long long winTime = ((long long)ft->dwHighDateTime << 32) +
- ft->dwLowDateTime;
- winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
- /* convert 100-nsecond interval to seconds and nanoseconds */
- ts->tv_sec = (time_t)(winTime/10000000);
- ts->tv_nsec = (long)(winTime - ts->tv_sec*10000000LL) * 100;
-}
-
-#define size_to_blocks(s) (((s)+511)/512)
-
-/* do_stat is a common implementation for cygwin_lstat and cygwin_stat.
- *
- * To simplify its logic, in the case of cygwin symlinks, this implementation
- * falls back to the cygwin version of stat/lstat, which is provided as the
- * last argument.
- */
-static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)
-{
- WIN32_FILE_ATTRIBUTE_DATA fdata;
-
- if (file_name[0] == '/')
- return cygstat (file_name, buf);
-
- if (!(errno = get_file_attr(file_name, &fdata))) {
- /*
- * If the system attribute is set and it is not a directory then
- * it could be a symbol link created in the nowinsymlinks mode.
- * Normally, Cygwin works in the winsymlinks mode, so this situation
- * is very unlikely. For the sake of simplicity of our code, let's
- * Cygwin to handle it.
- */
- if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
- !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
- return cygstat(file_name, buf);
-
- /* fill out the stat structure */
- buf->st_dev = buf->st_rdev = 0; /* not used by Git */
- buf->st_ino = 0;
- buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
- buf->st_nlink = 1;
- buf->st_uid = buf->st_gid = 0;
-#ifdef __CYGWIN_USE_BIG_TYPES__
- buf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +
- fdata.nFileSizeLow;
-#else
- buf->st_size = (off_t)fdata.nFileSizeLow;
-#endif
- buf->st_blocks = size_to_blocks(buf->st_size);
- filetime_to_timespec(&fdata.ftLastAccessTime, &buf->st_atim);
- filetime_to_timespec(&fdata.ftLastWriteTime, &buf->st_mtim);
- filetime_to_timespec(&fdata.ftCreationTime, &buf->st_ctim);
- return 0;
- } else if (errno == ENOENT) {
- /*
- * In the winsymlinks mode (which is the default), Cygwin
- * emulates symbol links using Windows shortcut files. These
- * files are formed by adding .lnk extension. So, if we have
- * not found the specified file name, it could be that it is
- * a symbol link. Let's Cygwin to deal with that.
- */
- return cygstat(file_name, buf);
- }
- return -1;
-}
-
-/* We provide our own lstat/stat functions, since the provided Cygwin versions
- * of these functions are too slow. These stat functions are tailored for Git's
- * usage, and therefore they are not meant to be complete and correct emulation
- * of lstat/stat functionality.
- */
-static int cygwin_lstat(const char *path, struct stat *buf)
-{
- return do_stat(path, buf, lstat);
-}
-
-static int cygwin_stat(const char *path, struct stat *buf)
-{
- return do_stat(path, buf, stat);
-}
-
-
-/*
- * At start up, we are trying to determine whether Win32 API or cygwin stat
- * functions should be used. The choice is determined by core.ignorecygwinfstricks.
- * Reading this option is not always possible immediately as git_dir may
- * not be set yet. So until it is set, use cygwin lstat/stat functions.
- * However, if core.filemode is set, we must use the Cygwin posix
- * stat/lstat as the Windows stat functions do not determine posix filemode.
- *
- * Note that git_cygwin_config() does NOT call git_default_config() and this
- * is deliberate. Many commands read from config to establish initial
- * values in variables and later tweak them from elsewhere (e.g. command line).
- * init_stat() is called lazily on demand, typically much late in the program,
- * and calling git_default_config() from here would break such variables.
- */
-static int native_stat = 1;
-static int core_filemode = 1; /* matches trust_executable_bit default */
-
-static int git_cygwin_config(const char *var, const char *value, void *cb)
-{
- if (!strcmp(var, "core.ignorecygwinfstricks"))
- native_stat = git_config_bool(var, value);
- else if (!strcmp(var, "core.filemode"))
- core_filemode = git_config_bool(var, value);
- return 0;
-}
-
-static int init_stat(void)
-{
- if (have_git_dir() && git_config(git_cygwin_config,NULL)) {
- if (!core_filemode && native_stat) {
- cygwin_stat_fn = cygwin_stat;
- cygwin_lstat_fn = cygwin_lstat;
- } else {
- cygwin_stat_fn = stat;
- cygwin_lstat_fn = lstat;
- }
- return 0;
- }
- return 1;
-}
-
-static int cygwin_stat_stub(const char *file_name, struct stat *buf)
-{
- return (init_stat() ? stat : *cygwin_stat_fn)(file_name, buf);
-}
-
-static int cygwin_lstat_stub(const char *file_name, struct stat *buf)
-{
- return (init_stat() ? lstat : *cygwin_lstat_fn)(file_name, buf);
-}
-
-stat_fn_t cygwin_stat_fn = cygwin_stat_stub;
-stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub;
-
diff --git a/compat/cygwin.h b/compat/cygwin.h
deleted file mode 100644
index a3229f5..0000000
--- a/compat/cygwin.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-typedef int (*stat_fn_t)(const char*, struct stat*);
-extern stat_fn_t cygwin_stat_fn;
-extern stat_fn_t cygwin_lstat_fn;
-
-#define stat(path, buf) (*cygwin_stat_fn)(path, buf)
-#define lstat(path, buf) (*cygwin_lstat_fn)(path, buf)
diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c
index 5ef0685..378c467 100644
--- a/compat/fnmatch/fnmatch.c
+++ b/compat/fnmatch/fnmatch.c
@@ -25,6 +25,7 @@
# define _GNU_SOURCE 1
#endif
+#include <stddef.h>
#include <errno.h>
#include <fnmatch.h>
#include <ctype.h>
@@ -121,7 +122,7 @@
whose names are inconsistent. */
# if !defined _LIBC && !defined getenv
-extern char *getenv ();
+extern char *getenv (const char *name);
# endif
# ifndef errno
diff --git a/compat/mingw.c b/compat/mingw.c
index b673625..22ee9ef 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -841,8 +841,8 @@ struct pinfo_t {
struct pinfo_t *next;
pid_t pid;
HANDLE proc;
-} pinfo_t;
-struct pinfo_t *pinfo = NULL;
+};
+static struct pinfo_t *pinfo = NULL;
CRITICAL_SECTION pinfo_cs;
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
@@ -1086,6 +1086,12 @@ int mingw_kill(pid_t pid, int sig)
errno = err_win_to_posix(GetLastError());
CloseHandle(h);
return -1;
+ } else if (pid > 0 && sig == 0) {
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+ if (h) {
+ CloseHandle(h);
+ return 0;
+ }
}
errno = EINVAL;
@@ -1253,7 +1259,7 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
else
sin->sin_addr.s_addr = INADDR_LOOPBACK;
ai->ai_addr = (struct sockaddr *)sin;
- ai->ai_next = 0;
+ ai->ai_next = NULL;
return 0;
}
@@ -1677,14 +1683,16 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out)
#undef signal
sig_handler_t mingw_signal(int sig, sig_handler_t handler)
{
- sig_handler_t old = timer_fn;
+ sig_handler_t old;
switch (sig) {
case SIGALRM:
+ old = timer_fn;
timer_fn = handler;
break;
case SIGINT:
+ old = sigint_fn;
sigint_fn = handler;
break;
diff --git a/compat/mingw.h b/compat/mingw.h
index 685cd2c..bd0a88b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -334,13 +334,20 @@ char **make_augmented_environ(const char *const *vars);
void free_environ(char **env);
/*
+ * A critical section used in the implementation of the spawn
+ * functions (mingw_spawnv[p]e()) and waitpid(). Intialised in
+ * the replacement main() macro below.
+ */
+extern CRITICAL_SECTION pinfo_cs;
+
+/*
* A replacement of main() that ensures that argv[0] has a path
* and that default fmode and std(in|out|err) are in binary mode
*/
#define main(c,v) dummy_decl_mingw_main(); \
-static int mingw_main(); \
-int main(int argc, const char **argv) \
+static int mingw_main(c,v); \
+int main(int argc, char **argv) \
{ \
extern CRITICAL_SECTION pinfo_cs; \
_fmode = _O_BINARY; \
diff --git a/compat/msvc.h b/compat/msvc.h
index aa4b563..96b6d60 100644
--- a/compat/msvc.h
+++ b/compat/msvc.h
@@ -12,6 +12,8 @@
#define __attribute__(x)
#define strncasecmp _strnicmp
#define ftruncate _chsize
+#define strtoull _strtoui64
+#define strtoll _strtoi64
static __inline int strcasecmp (const char *s1, const char *s2)
{
diff --git a/compat/nedmalloc/Readme.txt b/compat/nedmalloc/Readme.txt
index e46d8f1..07cbf50 100644
--- a/compat/nedmalloc/Readme.txt
+++ b/compat/nedmalloc/Readme.txt
@@ -97,7 +97,7 @@ Chew for reporting this.
v1.04alpha_svn915 7th October 2006:
* Fixed failure to unlock thread cache list if allocating a new list failed.
-Thanks to Dmitry Chichkov for reporting this. Futher thanks to Aleksey Sanin.
+Thanks to Dmitry Chichkov for reporting this. Further thanks to Aleksey Sanin.
* Fixed realloc(0, <size>) segfaulting. Thanks to Dmitry Chichkov for
reporting this.
* Made config defines #ifndef so they can be overridden by the build system.
diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h
index 1401a67..ed4f1fa 100644
--- a/compat/nedmalloc/malloc.c.h
+++ b/compat/nedmalloc/malloc.c.h
@@ -484,6 +484,10 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP
#define DLMALLOC_VERSION 20804
#endif /* DLMALLOC_VERSION */
+#if defined(linux)
+#define _GNU_SOURCE 1
+#endif
+
#ifndef WIN32
#ifdef _WIN32
#define WIN32 1
@@ -1802,7 +1806,7 @@ struct win32_mlock_t
static MLOCK_T malloc_global_mutex = { 0, 0, 0};
-static FORCEINLINE long win32_getcurrentthreadid() {
+static FORCEINLINE long win32_getcurrentthreadid(void) {
#ifdef _MSC_VER
#if defined(_M_IX86)
long *threadstruct=(long *)__readfsdword(0x18);
@@ -3598,8 +3602,8 @@ static void internal_malloc_stats(mstate m) {
and choose its bk node as its replacement.
2. If x was the last node of its size, but not a leaf node, it must
be replaced with a leaf node (not merely one with an open left or
- right), to make sure that lefts and rights of descendents
- correspond properly to bit masks. We use the rightmost descendent
+ right), to make sure that lefts and rights of descendants
+ correspond properly to bit masks. We use the rightmost descendant
of x. We could use any other leaf, but this is easy to locate and
tends to counteract removal of leftmosts elsewhere, and so keeps
paths shorter than minimally guaranteed. This doesn't loop much
diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c
index 91c4e7f..609ebba 100644
--- a/compat/nedmalloc/nedmalloc.c
+++ b/compat/nedmalloc/nedmalloc.c
@@ -159,8 +159,8 @@ struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo(0); }
#endif
int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt(0, parno, value); }
int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim(0, pad); }
-void nedmalloc_stats() THROWSPEC { nedpmalloc_stats(0); }
-size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint(0); }
+void nedmalloc_stats(void) THROWSPEC { nedpmalloc_stats(0); }
+size_t nedmalloc_footprint(void) THROWSPEC { return nedpmalloc_footprint(0); }
void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc(0, elemsno, elemsize, chunks); }
void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc(0, elems, sizes, chunks); }
diff --git a/compat/poll/poll.c b/compat/poll/poll.c
index 7d226ec..4410310 100644
--- a/compat/poll/poll.c
+++ b/compat/poll/poll.c
@@ -576,7 +576,7 @@ restart:
{
/* It's a socket. */
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
- WSAEventSelect ((SOCKET) h, 0, 0);
+ WSAEventSelect ((SOCKET) h, NULL, 0);
/* If we're lucky, WSAEnumNetworkEvents already provided a way
to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 030174d..7980abd 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -78,7 +78,7 @@ void precompose_argv(int argc, const char **argv)
size_t namelen;
oldarg = argv[i];
if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
- newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
+ newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, NULL);
if (newarg)
argv[i] = newarg;
}
diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c
index d0025bd..b2c5d46 100644
--- a/compat/regex/regcomp.c
+++ b/compat/regex/regcomp.c
@@ -2617,7 +2617,7 @@ parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
Build the range expression which starts from START_ELEM, and ends
at END_ELEM. The result are written to MBCSET and SBCSET.
RANGE_ALLOC is the allocated size of mbcset->range_starts, and
- mbcset->range_ends, is a pointer argument sinse we may
+ mbcset->range_ends, is a pointer argument since we may
update it. */
static reg_errcode_t
@@ -2788,7 +2788,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
const int32_t *symb_table;
const unsigned char *extra;
- /* Local function for parse_bracket_exp used in _LIBC environement.
+ /* Local function for parse_bracket_exp used in _LIBC environment.
Seek the collating symbol entry correspondings to NAME.
Return the index of the symbol in the SYMB_TABLE. */
@@ -2892,11 +2892,11 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
return UINT_MAX;
}
- /* Local function for parse_bracket_exp used in _LIBC environement.
+ /* Local function for parse_bracket_exp used in _LIBC environment.
Build the range expression which starts from START_ELEM, and ends
at END_ELEM. The result are written to MBCSET and SBCSET.
RANGE_ALLOC is the allocated size of mbcset->range_starts, and
- mbcset->range_ends, is a pointer argument sinse we may
+ mbcset->range_ends, is a pointer argument since we may
update it. */
auto inline reg_errcode_t
@@ -2976,11 +2976,11 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
return REG_NOERROR;
}
- /* Local function for parse_bracket_exp used in _LIBC environement.
+ /* Local function for parse_bracket_exp used in _LIBC environment.
Build the collating element which is represented by NAME.
The result are written to MBCSET and SBCSET.
COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
- pointer argument sinse we may update it. */
+ pointer argument since we may update it. */
auto inline reg_errcode_t
__attribute ((always_inline))
@@ -3419,7 +3419,7 @@ parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp,
Build the equivalence class which is represented by NAME.
The result are written to MBCSET and SBCSET.
EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes,
- is a pointer argument sinse we may update it. */
+ is a pointer argument since we may update it. */
static reg_errcode_t
#ifdef RE_ENABLE_I18N
@@ -3515,7 +3515,7 @@ build_equiv_class (bitset_t sbcset, const unsigned char *name)
Build the character class which is represented by NAME.
The result are written to MBCSET and SBCSET.
CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
- is a pointer argument sinse we may update it. */
+ is a pointer argument since we may update it. */
static reg_errcode_t
#ifdef RE_ENABLE_I18N
diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c
index 0194965..eb5e1d4 100644
--- a/compat/regex/regexec.c
+++ b/compat/regex/regexec.c
@@ -455,7 +455,7 @@ re_search_stub (struct re_pattern_buffer *bufp,
rval = 0;
- /* I hope we needn't fill ther regs with -1's when no match was found. */
+ /* I hope we needn't fill their regs with -1's when no match was found. */
if (result != REG_NOERROR)
rval = -1;
else if (regs != NULL)
@@ -1071,7 +1071,7 @@ acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx,
FL_LONGEST_MATCH means we want the POSIX longest matching.
If P_MATCH_FIRST is not NULL, and the match fails, it is set to the
next place where we may want to try matching.
- Note that the matcher assume that the maching starts from the current
+ Note that the matcher assume that the matching starts from the current
index of the buffer. */
static int
@@ -2239,7 +2239,7 @@ sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx,
dfa->nexts[node_idx]))
/* The node can't accept the `multi byte', or the
destination was already thrown away, then the node
- could't accept the current input `multi byte'. */
+ couldn't accept the current input `multi byte'. */
naccepted = 0;
/* Otherwise, it is sure that the node could accept
`naccepted' bytes input. */
@@ -2313,7 +2313,7 @@ transit_state (reg_errcode_t *err, re_match_context_t *mctx,
}
/* Update the state_log if we need */
-re_dfastate_t *
+static re_dfastate_t *
internal_function
merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
re_dfastate_t *next_state)
@@ -2326,7 +2326,7 @@ merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
mctx->state_log[cur_idx] = next_state;
mctx->state_log_top = cur_idx;
}
- else if (mctx->state_log[cur_idx] == 0)
+ else if (mctx->state_log[cur_idx] == NULL)
{
mctx->state_log[cur_idx] = next_state;
}
@@ -2392,7 +2392,7 @@ merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
/* Skip bytes in the input that correspond to part of a
multi-byte match, then look in the log for a state
from which to restart matching. */
-re_dfastate_t *
+static re_dfastate_t *
internal_function
find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
{
diff --git a/compat/terminal.c b/compat/terminal.c
index 9b5e3d1..313897d 100644
--- a/compat/terminal.c
+++ b/compat/terminal.c
@@ -3,7 +3,7 @@
#include "sigchain.h"
#include "strbuf.h"
-#if defined(HAVE_DEV_TTY) || defined(WIN32)
+#if defined(HAVE_DEV_TTY) || defined(GIT_WINDOWS_NATIVE)
static void restore_term(void);
@@ -53,7 +53,7 @@ error:
return -1;
}
-#elif defined(WIN32)
+#elif defined(GIT_WINDOWS_NATIVE)
#define INPUT_PATH "CONIN$"
#define OUTPUT_PATH "CONOUT$"
diff --git a/compat/unsetenv.c b/compat/unsetenv.c
index eb29f5e..bf5fd70 100644
--- a/compat/unsetenv.c
+++ b/compat/unsetenv.c
@@ -2,7 +2,9 @@
void gitunsetenv (const char *name)
{
+#if !defined(__MINGW32__)
extern char **environ;
+#endif
int src, dst;
size_t nmln;
diff --git a/compat/vcbuild/include/sys/poll.h b/compat/vcbuild/include/sys/poll.h
deleted file mode 100644
index 0d8552a..0000000
--- a/compat/vcbuild/include/sys/poll.h
+++ /dev/null
@@ -1 +0,0 @@
-/* Intentionally empty file to support building git with MSVC */
diff --git a/compat/vcbuild/include/unistd.h b/compat/vcbuild/include/unistd.h
index b14fcf9..c65c2cd 100644
--- a/compat/vcbuild/include/unistd.h
+++ b/compat/vcbuild/include/unistd.h
@@ -49,6 +49,9 @@ typedef int64_t off64_t;
#define INTMAX_MAX _I64_MAX
#define UINTMAX_MAX _UI64_MAX
+#define UINT32_MAX 0xffffffff /* 4294967295U */
+
+#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
diff --git a/compat/win32.h b/compat/win32.h
index 8ce9104..a97e880 100644
--- a/compat/win32.h
+++ b/compat/win32.h
@@ -2,7 +2,7 @@
#define WIN32_H
/* common Win32 functions for MinGW and Cygwin */
-#ifndef WIN32 /* Not defined by Cygwin */
+#ifndef GIT_WINDOWS_NATIVE /* Not defined for Cygwin */
#include <windows.h>
#endif
diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c
index 010e875..e18f5c6 100644
--- a/compat/win32/pthread.c
+++ b/compat/win32/pthread.c
@@ -52,7 +52,7 @@ int win32_pthread_join(pthread_t *thread, void **value_ptr)
pthread_t pthread_self(void)
{
- pthread_t t = { 0 };
+ pthread_t t = { NULL };
t.tid = GetCurrentThreadId();
return t;
}
diff --git a/compat/win32mmap.c b/compat/win32mmap.c
index 61d2ef8..80a8c9a 100644
--- a/compat/win32mmap.c
+++ b/compat/win32mmap.c
@@ -21,8 +21,8 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
if (!(flags & MAP_PRIVATE))
die("Invalid usage of mmap when built with USE_WIN32_MMAP");
- hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), 0, PAGE_WRITECOPY,
- 0, 0, 0);
+ hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL,
+ PAGE_WRITECOPY, 0, 0, NULL);
if (!hmap)
return MAP_FAILED;
diff --git a/config.c b/config.c
index aefd80b..6588cf5 100644
--- a/config.c
+++ b/config.c
@@ -10,20 +10,69 @@
#include "strbuf.h"
#include "quote.h"
-typedef struct config_file {
- struct config_file *prev;
- FILE *f;
+struct config_source {
+ struct config_source *prev;
+ union {
+ FILE *file;
+ struct config_buf {
+ const char *buf;
+ size_t len;
+ size_t pos;
+ } buf;
+ } u;
const char *name;
+ int die_on_error;
int linenr;
int eof;
struct strbuf value;
struct strbuf var;
-} config_file;
-static config_file *cf;
+ int (*do_fgetc)(struct config_source *c);
+ int (*do_ungetc)(int c, struct config_source *conf);
+ long (*do_ftell)(struct config_source *c);
+};
+
+static struct config_source *cf;
static int zlib_compression_seen;
+static int config_file_fgetc(struct config_source *conf)
+{
+ return fgetc(conf->u.file);
+}
+
+static int config_file_ungetc(int c, struct config_source *conf)
+{
+ return ungetc(c, conf->u.file);
+}
+
+static long config_file_ftell(struct config_source *conf)
+{
+ return ftell(conf->u.file);
+}
+
+
+static int config_buf_fgetc(struct config_source *conf)
+{
+ if (conf->u.buf.pos < conf->u.buf.len)
+ return conf->u.buf.buf[conf->u.buf.pos++];
+
+ return EOF;
+}
+
+static int config_buf_ungetc(int c, struct config_source *conf)
+{
+ if (conf->u.buf.pos > 0)
+ return conf->u.buf.buf[--conf->u.buf.pos];
+
+ return EOF;
+}
+
+static long config_buf_ftell(struct config_source *conf)
+{
+ return conf->u.buf.pos;
+}
+
#define MAX_INCLUDE_DEPTH 10
static const char include_depth_advice[] =
"exceeded maximum include depth (%d) while including\n"
@@ -58,7 +107,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
path = buf.buf;
}
- if (!access_or_die(path, R_OK)) {
+ if (!access_or_die(path, R_OK, 0)) {
if (++inc->depth > MAX_INCLUDE_DEPTH)
die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
cf && cf->name ? cf->name : "the command line");
@@ -168,27 +217,22 @@ int git_config_from_parameters(config_fn_t fn, void *data)
static int get_next_char(void)
{
- int c;
- FILE *f;
-
- c = '\n';
- if (cf && ((f = cf->f) != NULL)) {
- c = fgetc(f);
- if (c == '\r') {
- /* DOS like systems */
- c = fgetc(f);
- if (c != '\n') {
- ungetc(c, f);
- c = '\r';
- }
- }
- if (c == '\n')
- cf->linenr++;
- if (c == EOF) {
- cf->eof = 1;
- c = '\n';
+ int c = cf->do_fgetc(cf);
+
+ if (c == '\r') {
+ /* DOS like systems */
+ c = cf->do_fgetc(cf);
+ if (c != '\n') {
+ cf->do_ungetc(c, cf);
+ c = '\r';
}
}
+ if (c == '\n')
+ cf->linenr++;
+ if (c == EOF) {
+ cf->eof = 1;
+ c = '\n';
+ }
return c;
}
@@ -339,7 +383,7 @@ static int get_base_var(struct strbuf *name)
}
}
-static int git_parse_file(config_fn_t fn, void *data)
+static int git_parse_source(config_fn_t fn, void *data)
{
int comment = 0;
int baselen = 0;
@@ -399,7 +443,10 @@ static int git_parse_file(config_fn_t fn, void *data)
if (get_value(fn, data, var) < 0)
break;
}
- die("bad config file line %d in %s", cf->linenr, cf->name);
+ if (cf->die_on_error)
+ die("bad config file line %d in %s", cf->linenr, cf->name);
+ else
+ return error("bad config file line %d in %s", cf->linenr, cf->name);
}
static int parse_unit_factor(const char *end, uintmax_t *val)
@@ -421,7 +468,7 @@ static int parse_unit_factor(const char *end, uintmax_t *val)
return 0;
}
-static int git_parse_long(const char *value, long *ret)
+static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
{
if (value && *value) {
char *end;
@@ -433,21 +480,25 @@ static int git_parse_long(const char *value, long *ret)
val = strtoimax(value, &end, 0);
if (errno == ERANGE)
return 0;
- if (!parse_unit_factor(end, &factor))
+ if (!parse_unit_factor(end, &factor)) {
+ errno = EINVAL;
return 0;
+ }
uval = abs(val);
uval *= factor;
- if ((uval > maximum_signed_value_of_type(long)) ||
- (abs(val) > uval))
+ if (uval > max || abs(val) > uval) {
+ errno = ERANGE;
return 0;
+ }
val *= factor;
*ret = val;
return 1;
}
+ errno = EINVAL;
return 0;
}
-int git_parse_ulong(const char *value, unsigned long *ret)
+int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
{
if (value && *value) {
char *end;
@@ -459,29 +510,75 @@ int git_parse_ulong(const char *value, unsigned long *ret)
if (errno == ERANGE)
return 0;
oldval = val;
- if (!parse_unit_factor(end, &val))
+ if (!parse_unit_factor(end, &val)) {
+ errno = EINVAL;
return 0;
- if ((val > maximum_unsigned_value_of_type(long)) ||
- (oldval > val))
+ }
+ if (val > max || oldval > val) {
+ errno = ERANGE;
return 0;
+ }
*ret = val;
return 1;
}
+ errno = EINVAL;
return 0;
}
-static void die_bad_config(const char *name)
+static int git_parse_int(const char *value, int *ret)
+{
+ intmax_t tmp;
+ if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+static int git_parse_int64(const char *value, int64_t *ret)
{
+ intmax_t tmp;
+ if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+int git_parse_ulong(const char *value, unsigned long *ret)
+{
+ uintmax_t tmp;
+ if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+static void die_bad_number(const char *name, const char *value)
+{
+ const char *reason = errno == ERANGE ?
+ "out of range" :
+ "invalid unit";
+ if (!value)
+ value = "";
+
if (cf && cf->name)
- die("bad config value for '%s' in %s", name, cf->name);
- die("bad config value for '%s'", name);
+ die("bad numeric config value '%s' for '%s' in %s: %s",
+ value, name, cf->name, reason);
+ die("bad numeric config value '%s' for '%s': %s", value, name, reason);
}
int git_config_int(const char *name, const char *value)
{
- long ret = 0;
- if (!git_parse_long(value, &ret))
- die_bad_config(name);
+ int ret;
+ if (!git_parse_int(value, &ret))
+ die_bad_number(name, value);
+ return ret;
+}
+
+int64_t git_config_int64(const char *name, const char *value)
+{
+ int64_t ret;
+ if (!git_parse_int64(value, &ret))
+ die_bad_number(name, value);
return ret;
}
@@ -489,7 +586,7 @@ unsigned long git_config_ulong(const char *name, const char *value)
{
unsigned long ret;
if (!git_parse_ulong(value, &ret))
- die_bad_config(name);
+ die_bad_number(name, value);
return ret;
}
@@ -512,10 +609,10 @@ static int git_config_maybe_bool_text(const char *name, const char *value)
int git_config_maybe_bool(const char *name, const char *value)
{
- long v = git_config_maybe_bool_text(name, value);
+ int v = git_config_maybe_bool_text(name, value);
if (0 <= v)
return v;
- if (git_parse_long(value, &v))
+ if (git_parse_int(value, &v))
return !!v;
return -1;
}
@@ -566,7 +663,20 @@ static int git_default_core_config(const char *var, const char *value)
trust_ctime = git_config_bool(var, value);
return 0;
}
- if (!strcmp(var, "core.statinfo")) {
+ if (!strcmp(var, "core.statinfo") ||
+ !strcmp(var, "core.checkstat")) {
+ /*
+ * NEEDSWORK: statinfo was a typo in v1.8.2 that has
+ * never been advertised. we will remove it at Git
+ * 2.0 boundary.
+ */
+ if (!strcmp(var, "core.statinfo")) {
+ static int warned;
+ if (!warned++) {
+ warning("'core.statinfo' will be removed in Git 2.0; "
+ "use 'core.checkstat' instead.");
+ }
+ }
if (!strcasecmp(value, "default"))
check_stat = 1;
else if (!strcasecmp(value, "minimal"))
@@ -675,9 +785,6 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}
- if (!strcmp(var, "core.logpackaccess"))
- return git_config_string(&log_pack_access, var, value);
-
if (!strcmp(var, "core.autocrlf")) {
if (value && !strcasecmp(value, "input")) {
if (core_eol == EOL_CRLF)
@@ -896,6 +1003,33 @@ int git_default_config(const char *var, const char *value, void *dummy)
return 0;
}
+/*
+ * All source specific fields in the union, die_on_error, name and the callbacks
+ * fgetc, ungetc, ftell of top need to be initialized before calling
+ * this function.
+ */
+static int do_config_from(struct config_source *top, config_fn_t fn, void *data)
+{
+ int ret;
+
+ /* push config-file parsing state stack */
+ top->prev = cf;
+ top->linenr = 1;
+ top->eof = 0;
+ strbuf_init(&top->value, 1024);
+ strbuf_init(&top->var, 1024);
+ cf = top;
+
+ ret = git_parse_source(fn, data);
+
+ /* pop config-file parsing state stack */
+ strbuf_release(&top->value);
+ strbuf_release(&top->var);
+ cf = top->prev;
+
+ return ret;
+}
+
int git_config_from_file(config_fn_t fn, const char *filename, void *data)
{
int ret;
@@ -903,30 +1037,74 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
ret = -1;
if (f) {
- config_file top;
+ struct config_source top;
- /* push config-file parsing state stack */
- top.prev = cf;
- top.f = f;
+ top.u.file = f;
top.name = filename;
- top.linenr = 1;
- top.eof = 0;
- strbuf_init(&top.value, 1024);
- strbuf_init(&top.var, 1024);
- cf = &top;
-
- ret = git_parse_file(fn, data);
+ top.die_on_error = 1;
+ top.do_fgetc = config_file_fgetc;
+ top.do_ungetc = config_file_ungetc;
+ top.do_ftell = config_file_ftell;
- /* pop config-file parsing state stack */
- strbuf_release(&top.value);
- strbuf_release(&top.var);
- cf = top.prev;
+ ret = do_config_from(&top, fn, data);
fclose(f);
}
return ret;
}
+int git_config_from_buf(config_fn_t fn, const char *name, const char *buf,
+ size_t len, void *data)
+{
+ struct config_source top;
+
+ top.u.buf.buf = buf;
+ top.u.buf.len = len;
+ top.u.buf.pos = 0;
+ top.name = name;
+ top.die_on_error = 0;
+ top.do_fgetc = config_buf_fgetc;
+ top.do_ungetc = config_buf_ungetc;
+ top.do_ftell = config_buf_ftell;
+
+ return do_config_from(&top, fn, data);
+}
+
+static int git_config_from_blob_sha1(config_fn_t fn,
+ const char *name,
+ const unsigned char *sha1,
+ void *data)
+{
+ enum object_type type;
+ char *buf;
+ unsigned long size;
+ int ret;
+
+ buf = read_sha1_file(sha1, &type, &size);
+ if (!buf)
+ return error("unable to load config blob object '%s'", name);
+ if (type != OBJ_BLOB) {
+ free(buf);
+ return error("reference '%s' does not point to a blob", name);
+ }
+
+ ret = git_config_from_buf(fn, name, buf, size, data);
+ free(buf);
+
+ return ret;
+}
+
+static int git_config_from_blob_ref(config_fn_t fn,
+ const char *name,
+ void *data)
+{
+ unsigned char sha1[20];
+
+ if (get_sha1(name, sha1) < 0)
+ return error("unable to resolve config blob '%s'", name);
+ return git_config_from_blob_sha1(fn, name, sha1, data);
+}
+
const char *git_etc_gitconfig(void)
{
static const char *system_wide;
@@ -954,23 +1132,23 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
home_config_paths(&user_config, &xdg_config, "config");
- if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK)) {
+ if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
ret += git_config_from_file(fn, git_etc_gitconfig(),
data);
found += 1;
}
- if (xdg_config && !access_or_die(xdg_config, R_OK)) {
+ if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK)) {
ret += git_config_from_file(fn, xdg_config, data);
found += 1;
}
- if (user_config && !access_or_die(user_config, R_OK)) {
+ if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK)) {
ret += git_config_from_file(fn, user_config, data);
found += 1;
}
- if (repo_config && !access_or_die(repo_config, R_OK)) {
+ if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
ret += git_config_from_file(fn, repo_config, data);
found += 1;
}
@@ -992,7 +1170,9 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
}
int git_config_with_options(config_fn_t fn, void *data,
- const char *filename, int respect_includes)
+ const char *filename,
+ const char *blob_ref,
+ int respect_includes)
{
char *repo_config = NULL;
int ret;
@@ -1011,6 +1191,8 @@ int git_config_with_options(config_fn_t fn, void *data,
*/
if (filename)
return git_config_from_file(fn, filename, data);
+ else if (blob_ref)
+ return git_config_from_blob_ref(fn, blob_ref, data);
repo_config = git_pathdup("config");
ret = git_config_early(fn, data, repo_config);
@@ -1021,7 +1203,7 @@ int git_config_with_options(config_fn_t fn, void *data,
int git_config(config_fn_t fn, void *data)
{
- return git_config_with_options(fn, data, NULL, 1);
+ return git_config_with_options(fn, data, NULL, NULL, 1);
}
/*
@@ -1053,7 +1235,6 @@ static int store_aux(const char *key, const char *value, void *cb)
{
const char *ep;
size_t section_len;
- FILE *f = cf->f;
switch (store.state) {
case KEY_SEEN:
@@ -1065,7 +1246,7 @@ static int store_aux(const char *key, const char *value, void *cb)
return 1;
}
- store.offset[store.seen] = ftell(f);
+ store.offset[store.seen] = cf->do_ftell(cf);
store.seen++;
}
break;
@@ -1092,19 +1273,19 @@ static int store_aux(const char *key, const char *value, void *cb)
* Do not increment matches: this is no match, but we
* just made sure we are in the desired section.
*/
- store.offset[store.seen] = ftell(f);
+ store.offset[store.seen] = cf->do_ftell(cf);
/* fallthru */
case SECTION_END_SEEN:
case START:
if (matches(key, value)) {
- store.offset[store.seen] = ftell(f);
+ store.offset[store.seen] = cf->do_ftell(cf);
store.state = KEY_SEEN;
store.seen++;
} else {
if (strrchr(key, '.') - key == store.baselen &&
!strncmp(key, store.key, store.baselen)) {
store.state = SECTION_SEEN;
- store.offset[store.seen] = ftell(f);
+ store.offset[store.seen] = cf->do_ftell(cf);
}
}
}
diff --git a/config.mak.in b/config.mak.in
index fa02bdd..e6a6d0f 100644
--- a/config.mak.in
+++ b/config.mak.in
@@ -22,9 +22,3 @@ docdir = @docdir@
mandir = @mandir@
htmldir = @htmldir@
-
-srcdir = @srcdir@
-VPATH = @srcdir@
-
-export exec_prefix mandir
-export srcdir VPATH
diff --git a/config.mak.uname b/config.mak.uname
index e09af8f..7d61531 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -158,19 +158,18 @@ ifeq ($(uname_O),Cygwin)
NO_SYMLINK_HEAD = YesPlease
NO_IPV6 = YesPlease
OLD_ICONV = UnfortunatelyYes
- CYGWIN_V15_WIN32API = YesPlease
+ NO_THREAD_SAFE_PREAD = YesPlease
+ # There are conflicting reports about this.
+ # On some boxes NO_MMAP is needed, and not so elsewhere.
+ # Try commenting this out if you suspect MMAP is more efficient
+ NO_MMAP = YesPlease
+ else
+ NO_REGEX = UnfortunatelyYes
endif
- NO_THREAD_SAFE_PREAD = YesPlease
NEEDS_LIBICONV = YesPlease
NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
- NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
- # There are conflicting reports about this.
- # On some boxes NO_MMAP is needed, and not so elsewhere.
- # Try commenting this out if you suspect MMAP is more efficient
- NO_MMAP = YesPlease
X = .exe
- COMPAT_OBJS += compat/cygwin.o
UNRELIABLE_FSTAT = UnfortunatelyYes
SPARSE_FLAGS = -isystem /usr/include/w32api -Wno-one-bit-signed-bitfield
endif
@@ -326,7 +325,6 @@ ifeq ($(uname_S),Windows)
# NEEDS_LIBICONV = YesPlease
NO_ICONV = YesPlease
NO_STRTOUMAX = YesPlease
- NO_STRTOULL = YesPlease
NO_MKDTEMP = YesPlease
NO_MKSTEMPS = YesPlease
SNPRINTF_RETURNS_BOGUS = YesPlease
@@ -343,6 +341,9 @@ ifeq ($(uname_S),Windows)
NO_CURL = YesPlease
NO_PYTHON = YesPlease
BLK_SHA1 = YesPlease
+ ETAGS_TARGET = ETAGS
+ NO_INET_PTON = YesPlease
+ NO_INET_NTOP = YesPlease
NO_POSIX_GOODIES = UnfortunatelyYes
NATIVE_CRLF = YesPlease
DEFAULT_HELP_FORMAT = html
@@ -478,7 +479,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
NO_FNMATCH = YesPlease
NO_MEMMEM = YesPlease
NEEDS_LIBICONV = YesPlease
- OLD_ICONV = YesPlease
NO_STRTOUMAX = YesPlease
NO_MKDTEMP = YesPlease
NO_MKSTEMPS = YesPlease
@@ -498,13 +498,18 @@ ifneq (,$(findstring MINGW,$(uname_S)))
NO_INET_PTON = YesPlease
NO_INET_NTOP = YesPlease
NO_POSIX_GOODIES = UnfortunatelyYes
+ DEFAULT_HELP_FORMAT = html
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
compat/win32/dirent.o
+ BASIC_LDFLAGS += -Wl,--large-address-aware
EXTLIBS += -lws2_32
+ GITLIBS += git.res
PTHREAD_LIBS =
+ RC = windres -O coff
+ NATIVE_CRLF = YesPlease
X = .exe
SPARSE_FLAGS = -Wno-one-bit-signed-bitfield
ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
@@ -515,6 +520,7 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
NO_R_TO_GCC_LINKER = YesPlease
INTERNAL_QSORT = YesPlease
HAVE_LIBCHARSET_H = YesPlease
+ NO_GETTEXT = YesPlease
else
NO_CURL = YesPlease
endif
diff --git a/configure.ac b/configure.ac
index f3462d9..2f43393 100644
--- a/configure.ac
+++ b/configure.ac
@@ -193,7 +193,7 @@ AC_ARG_ENABLE([pthreads],
[FLAGS is the value to pass to the compiler to enable POSIX Threads.]
[The default if FLAGS is not specified is to try first -pthread]
[and then -lpthread.]
- [--without-pthreads will disable threading.])],
+ [--disable-pthreads will disable threading.])],
[
if test "x$enableval" = "xyes"; then
AC_MSG_NOTICE([Will try -pthread then -lpthread to enable POSIX Threads])
diff --git a/connect.c b/connect.c
index 49e56ba..a80ebd3 100644
--- a/connect.c
+++ b/connect.c
@@ -5,6 +5,7 @@
#include "refs.h"
#include "run-command.h"
#include "remote.h"
+#include "connect.h"
#include "url.h"
static char *server_capabilities;
@@ -62,8 +63,8 @@ static void die_initial_contact(int got_at_least_one_head)
/*
* Read all the refs from the other end
*/
-struct ref **get_remote_heads(int in, struct ref **list,
- unsigned int flags,
+struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
+ struct ref **list, unsigned int flags,
struct extra_have_objects *extra_have)
{
int got_at_least_one_head = 0;
@@ -72,18 +73,19 @@ struct ref **get_remote_heads(int in, struct ref **list,
for (;;) {
struct ref *ref;
unsigned char old_sha1[20];
- static char buffer[1000];
char *name;
int len, name_len;
+ char *buffer = packet_buffer;
- len = packet_read(in, buffer, sizeof(buffer));
+ len = packet_read(in, &src_buf, &src_len,
+ packet_buffer, sizeof(packet_buffer),
+ PACKET_READ_GENTLE_ON_EOF |
+ PACKET_READ_CHOMP_NEWLINE);
if (len < 0)
die_initial_contact(got_at_least_one_head);
if (!len)
break;
- if (buffer[len-1] == '\n')
- buffer[--len] = 0;
if (len > 4 && !prefixcmp(buffer, "ERR "))
die("remote error: %s", buffer + 4);
@@ -550,8 +552,11 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
path = strchr(end, c);
if (path && !has_dos_drive_prefix(end)) {
if (c == ':') {
- protocol = PROTO_SSH;
- *path++ = '\0';
+ if (path < strchrnul(host, '/')) {
+ protocol = PROTO_SSH;
+ *path++ = '\0';
+ } else /* '/' in the host part, assume local path */
+ path = end;
}
} else
path = end;
diff --git a/connect.h b/connect.h
new file mode 100644
index 0000000..9dff25c
--- /dev/null
+++ b/connect.h
@@ -0,0 +1,13 @@
+#ifndef CONNECT_H
+#define CONNECT_H
+
+#define CONNECT_VERBOSE (1u << 0)
+extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
+extern int finish_connect(struct child_process *conn);
+extern int git_connection_is_socket(struct child_process *conn);
+extern int server_supports(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);
+
+#endif
diff --git a/connected.c b/connected.c
index 1e89c1c..fae8d64 100644
--- a/connected.c
+++ b/connected.c
@@ -2,7 +2,12 @@
#include "run-command.h"
#include "sigchain.h"
#include "connected.h"
+#include "transport.h"
+int check_everything_connected(sha1_iterate_fn fn, int quiet, void *cb_data)
+{
+ return check_everything_connected_with_transport(fn, quiet, cb_data, NULL);
+}
/*
* If we feed all the commits we want to verify to this command
*
@@ -14,7 +19,10 @@
*
* Returns 0 if everything is connected, non-zero otherwise.
*/
-int check_everything_connected(sha1_iterate_fn fn, int quiet, void *cb_data)
+int check_everything_connected_with_transport(sha1_iterate_fn fn,
+ int quiet,
+ void *cb_data,
+ struct transport *transport)
{
struct child_process rev_list;
const char *argv[] = {"rev-list", "--objects",
@@ -22,10 +30,23 @@ int check_everything_connected(sha1_iterate_fn fn, int quiet, void *cb_data)
char commit[41];
unsigned char sha1[20];
int err = 0;
+ struct packed_git *new_pack = NULL;
if (fn(cb_data, sha1))
return err;
+ if (transport && transport->smart_options &&
+ transport->smart_options->self_contained_and_connected &&
+ transport->pack_lockfile &&
+ !suffixcmp(transport->pack_lockfile, ".keep")) {
+ struct strbuf idx_file = STRBUF_INIT;
+ strbuf_addstr(&idx_file, transport->pack_lockfile);
+ strbuf_setlen(&idx_file, idx_file.len - 5); /* ".keep" */
+ strbuf_addstr(&idx_file, ".idx");
+ new_pack = add_packed_git(idx_file.buf, idx_file.len, 1);
+ strbuf_release(&idx_file);
+ }
+
if (quiet)
argv[5] = "--quiet";
@@ -42,6 +63,17 @@ int check_everything_connected(sha1_iterate_fn fn, int quiet, void *cb_data)
commit[40] = '\n';
do {
+ /*
+ * If index-pack already checked that:
+ * - there are no dangling pointers in the new pack
+ * - the pack is self contained
+ * Then if the updated ref is in the new pack, then we
+ * are sure the ref is good and not sending it to
+ * rev-list for verification.
+ */
+ if (new_pack && find_pack_entry_one(sha1, new_pack))
+ continue;
+
memcpy(commit, sha1_to_hex(sha1), 40);
if (write_in_full(rev_list.in, commit, 41) < 0) {
if (errno != EPIPE && errno != EINVAL)
diff --git a/connected.h b/connected.h
index 7e4585a..0b060b7 100644
--- a/connected.h
+++ b/connected.h
@@ -1,6 +1,8 @@
#ifndef CONNECTED_H
#define CONNECTED_H
+struct transport;
+
/*
* Take callback data, and return next object name in the buffer.
* When called after returning the name for the last object, return -1
@@ -16,5 +18,8 @@ typedef int (*sha1_iterate_fn)(void *, unsigned char [20]);
* Return 0 if Ok, non zero otherwise (i.e. some missing objects)
*/
extern int check_everything_connected(sha1_iterate_fn, int quiet, void *cb_data);
+extern int check_everything_connected_with_transport(sha1_iterate_fn, int quiet,
+ void *cb_data,
+ struct transport *transport);
#endif /* CONNECTED_H */
diff --git a/contrib/blameview/README b/contrib/blameview/README
deleted file mode 100644
index fada5ce..0000000
--- a/contrib/blameview/README
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a sample program to use 'git-blame --incremental', based
-on this message.
-
-From: Jeff King <peff@peff.net>
-Subject: Re: More precise tag following
-To: Linus Torvalds <torvalds@linux-foundation.org>
-Cc: git@vger.kernel.org
-Date: Sat, 27 Jan 2007 18:52:38 -0500
-Message-ID: <20070127235238.GA28706@coredump.intra.peff.net>
diff --git a/contrib/blameview/blameview.perl b/contrib/blameview/blameview.perl
deleted file mode 100755
index 1dec001..0000000
--- a/contrib/blameview/blameview.perl
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/perl
-
-use Gtk2 -init;
-use Gtk2::SimpleList;
-
-my $hash;
-my $fn;
-if ( @ARGV == 1 ) {
- $hash = "HEAD";
- $fn = shift;
-} elsif ( @ARGV == 2 ) {
- $hash = shift;
- $fn = shift;
-} else {
- die "Usage blameview [<rev>] <filename>";
-}
-
-Gtk2::Rc->parse_string(<<'EOS');
-style "treeview_style"
-{
- GtkTreeView::vertical-separator = 0
-}
-class "GtkTreeView" style "treeview_style"
-EOS
-
-my $window = Gtk2::Window->new('toplevel');
-$window->signal_connect(destroy => sub { Gtk2->main_quit });
-my $vpan = Gtk2::VPaned->new();
-$window->add($vpan);
-my $scrolled_window = Gtk2::ScrolledWindow->new;
-$vpan->pack1($scrolled_window, 1, 1);
-my $fileview = Gtk2::SimpleList->new(
- 'Commit' => 'text',
- 'FileLine' => 'text',
- 'Data' => 'text'
-);
-$scrolled_window->add($fileview);
-$fileview->get_column(0)->set_spacing(0);
-$fileview->set_size_request(1024, 768);
-$fileview->set_rules_hint(1);
-$fileview->signal_connect (row_activated => sub {
- my ($sl, $path, $column) = @_;
- my $row_ref = $sl->get_row_data_from_path ($path);
- system("blameview @$row_ref[0]~1 $fn &");
- });
-
-my $commitwindow = Gtk2::ScrolledWindow->new();
-$commitwindow->set_policy ('GTK_POLICY_AUTOMATIC','GTK_POLICY_AUTOMATIC');
-$vpan->pack2($commitwindow, 1, 1);
-my $commit_text = Gtk2::TextView->new();
-my $commit_buffer = Gtk2::TextBuffer->new();
-$commit_text->set_buffer($commit_buffer);
-$commitwindow->add($commit_text);
-
-$fileview->signal_connect (cursor_changed => sub {
- my ($sl) = @_;
- my ($path, $focus_column) = $sl->get_cursor();
- my $row_ref = $sl->get_row_data_from_path ($path);
- my $c_fh;
- open($c_fh, '-|', "git cat-file commit @$row_ref[0]")
- or die "unable to find commit @$row_ref[0]";
- my @buffer = <$c_fh>;
- $commit_buffer->set_text("@buffer");
- close($c_fh);
- });
-
-my $fh;
-open($fh, '-|', "git cat-file blob $hash:$fn")
- or die "unable to open $fn: $!";
-
-while(<$fh>) {
- chomp;
- $fileview->{data}->[$.] = ['HEAD', "$fn:$.", $_];
-}
-
-my $blame;
-open($blame, '-|', qw(git blame --incremental --), $fn, $hash)
- or die "cannot start git-blame $fn";
-
-Glib::IO->add_watch(fileno($blame), 'in', \&read_blame_line);
-
-$window->show_all;
-Gtk2->main;
-exit 0;
-
-my %commitinfo = ();
-
-sub flush_blame_line {
- my ($attr) = @_;
-
- return unless defined $attr;
-
- my ($commit, $s_lno, $lno, $cnt) =
- @{$attr}{qw(COMMIT S_LNO LNO CNT)};
-
- my ($filename, $author, $author_time, $author_tz) =
- @{$commitinfo{$commit}}{qw(FILENAME AUTHOR AUTHOR-TIME AUTHOR-TZ)};
- my $info = $author . ' ' . format_time($author_time, $author_tz);
-
- for(my $i = 0; $i < $cnt; $i++) {
- @{$fileview->{data}->[$lno+$i-1]}[0,1,2] =
- (substr($commit, 0, 8), $filename . ':' . ($s_lno+$i));
- }
-}
-
-my $buf;
-my $current;
-sub read_blame_line {
-
- my $r = sysread($blame, $buf, 1024, length($buf));
- die "I/O error" unless defined $r;
-
- if ($r == 0) {
- flush_blame_line($current);
- $current = undef;
- return 0;
- }
-
- while ($buf =~ s/([^\n]*)\n//) {
- my $line = $1;
-
- if (($commit, $s_lno, $lno, $cnt) =
- ($line =~ /^([0-9a-f]{40}) (\d+) (\d+) (\d+)$/)) {
- flush_blame_line($current);
- $current = +{
- COMMIT => $1,
- S_LNO => $2,
- LNO => $3,
- CNT => $4,
- };
- next;
- }
-
- # extended attribute values
- if ($line =~ /^(author|author-mail|author-time|author-tz|committer|committer-mail|committer-time|committer-tz|summary|filename) (.*)$/) {
- my $commit = $current->{COMMIT};
- $commitinfo{$commit}{uc($1)} = $2;
- next;
- }
- }
- return 1;
-}
-
-sub format_time {
- my $time = shift;
- my $tz = shift;
-
- my $minutes = $tz < 0 ? 0-$tz : $tz;
- $minutes = ($minutes / 100)*60 + ($minutes % 100);
- $minutes = $tz < 0 ? 0-$minutes : $minutes;
- $time += $minutes * 60;
- my @t = gmtime($time);
- return sprintf('%04d-%02d-%02d %02d:%02d:%02d %s',
- $t[5] + 1900, @t[4,3,2,1,0], $tz);
-}
diff --git a/contrib/ciabot/ciabot.py b/contrib/ciabot/ciabot.py
index 36b5665..befa0c3 100755
--- a/contrib/ciabot/ciabot.py
+++ b/contrib/ciabot/ciabot.py
@@ -70,7 +70,7 @@ tinyifier = "http://tinyurl.com/api-create.php?url="
# The template used to generate the XML messages to CIA. You can make
# visible changes to the IRC-bot notification lines by hacking this.
-# The default will produce a notfication line that looks like this:
+# The default will produce a notification line that looks like this:
#
# ${project}: ${author} ${repo}:${branch} * ${rev} ${files}: ${logmsg} ${url}
#
diff --git a/contrib/ciabot/ciabot.sh b/contrib/ciabot/ciabot.sh
index 3fbbc53..dfb71a1 100755
--- a/contrib/ciabot/ciabot.sh
+++ b/contrib/ciabot/ciabot.sh
@@ -39,7 +39,7 @@
# done
#
# The reason for the tac call is that git rev-list emits commits from
-# most recent to least - better to ship notifactions from oldest to newest.
+# most recent to least - better to ship notifications from oldest to newest.
#
# Configuration variables affecting this script:
#
@@ -64,7 +64,7 @@
# down. It is unknown whether this is still an issue in 2010, but
# XML-RPC would be annoying to do from sh in any case. (XML-RPC does
# have the advantage that it guarantees notification of multiple commits
-# shpped from an update in their actual order.)
+# shipped from an update in their actual order.)
#
# The project as known to CIA. You can set this with a -p option,
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index e769800..e1b7313 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -33,8 +33,6 @@ 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"
@@ -53,19 +51,6 @@ __gitdir ()
fi
}
-__gitcomp_1 ()
-{
- local c IFS=$' \t\n'
- for c in $1; do
- c="$c$2"
- case $c in
- --*=*|*.) ;;
- *) c="$c " ;;
- esac
- printf '%s\n' "$c"
- done
-}
-
# The following function is based on code from:
#
# bash_completion - programmable completion functions for bash 3.2+
@@ -195,8 +180,18 @@ _get_comp_words_by_ref ()
}
fi
-# Generates completion reply with compgen, appending a space to possible
-# completion words, if necessary.
+__gitcompadd ()
+{
+ local i=0
+ for x in $1; do
+ if [[ "$x" == "$3"* ]]; then
+ COMPREPLY[i++]="$2$x$4"
+ fi
+ done
+}
+
+# Generates completion reply, appending a space to possible completion words,
+# if necessary.
# It accepts 1 to 4 arguments:
# 1: List of possible completion words.
# 2: A prefix to be added to each possible completion word (optional).
@@ -208,19 +203,25 @@ __gitcomp ()
case "$cur_" in
--*=)
- COMPREPLY=()
;;
*)
- local IFS=$'\n'
- COMPREPLY=($(compgen -P "${2-}" \
- -W "$(__gitcomp_1 "${1-}" "${4-}")" \
- -- "$cur_"))
+ local c i=0 IFS=$' \t\n'
+ for c in $1; do
+ c="$c${4-}"
+ if [[ $c == "$cur_"* ]]; then
+ case $c in
+ --*=*|*.) ;;
+ *) c="$c " ;;
+ esac
+ COMPREPLY[i++]="${2-}$c"
+ fi
+ done
;;
esac
}
-# Generates completion reply with compgen from newline-separated possible
-# completion words by appending a space to all of them.
+# Generates completion reply from newline-separated possible completion words
+# by appending a space to all of them.
# It accepts 1 to 4 arguments:
# 1: List of possible completion words, separated by a single newline.
# 2: A prefix to be added to each possible completion word (optional).
@@ -231,7 +232,7 @@ __gitcomp ()
__gitcomp_nl ()
{
local IFS=$'\n'
- COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
+ __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }"
}
# Generates completion reply with compgen from newline-separated possible
@@ -249,106 +250,50 @@ __gitcomp_file ()
# since tilde expansion is not applied.
# This means that COMPREPLY will be empty and Bash default
# completion will be used.
- COMPREPLY=($(compgen -P "${2-}" -W "$1" -- "${3-$cur}"))
-
- # Tell Bash that compspec generates filenames.
- compopt -o filenames 2>/dev/null
-}
-
-__git_index_file_list_filter_compat ()
-{
- local path
-
- while read -r path; do
- case "$path" in
- ?*/*) echo "${path%%/*}/" ;;
- *) echo "$path" ;;
- esac
- done
-}
-
-__git_index_file_list_filter_bash ()
-{
- local path
-
- while read -r path; do
- case "$path" in
- ?*/*)
- # XXX if we append a slash to directory names when using
- # `compopt -o filenames`, Bash will append another slash.
- # This is pretty stupid, and this the reason why we have to
- # define a compatible version for this function.
- echo "${path%%/*}" ;;
- *)
- echo "$path" ;;
- esac
- done
-}
+ __gitcompadd "$1" "${2-}" "${3-$cur}" ""
-# Process path list returned by "ls-files" and "diff-index --name-only"
-# commands, in order to list only file names relative to a specified
-# directory, and append a slash to directory names.
-__git_index_file_list_filter ()
-{
- # Default to Bash >= 4.x
- __git_index_file_list_filter_bash
+ # use a hack to enable file mode in bash < 4
+ compopt -o filenames +o nospace 2>/dev/null ||
+ compgen -f /non-existing-dir/ > /dev/null
}
-# Execute git ls-files, returning paths relative to the directory
-# specified in the first argument, and using the options specified in
-# the second argument.
+# Execute 'git ls-files', unless the --committable option is specified, in
+# which case it runs 'git diff-index' to find out the files that can be
+# committed. It return paths relative to the directory specified in the first
+# argument, and using the options specified in the second argument.
__git_ls_files_helper ()
{
(
test -n "${CDPATH+set}" && unset CDPATH
- # NOTE: $2 is not quoted in order to support multiple options
- cd "$1" && git ls-files --exclude-standard $2
+ cd "$1"
+ if [ "$2" == "--committable" ]; then
+ git diff-index --name-only --relative HEAD
+ else
+ # NOTE: $2 is not quoted in order to support multiple options
+ git ls-files --exclude-standard $2
+ fi
) 2>/dev/null
}
-# Execute git diff-index, returning paths relative to the directory
-# specified in the first argument, and using the tree object id
-# specified in the second argument.
-__git_diff_index_helper ()
-{
- (
- test -n "${CDPATH+set}" && unset CDPATH
- cd "$1" && git diff-index --name-only --relative "$2"
- ) 2>/dev/null
-}
-
# __git_index_files accepts 1 or 2 arguments:
# 1: Options to pass to ls-files (required).
-# Supported options are --cached, --modified, --deleted, --others,
-# and --directory.
# 2: A directory path (optional).
# If provided, only files within the specified directory are listed.
# Sub directories are never recursed. Path must have a trailing
# slash.
__git_index_files ()
{
- local dir="$(__gitdir)" root="${2-.}"
+ local dir="$(__gitdir)" root="${2-.}" file
if [ -d "$dir" ]; then
- __git_ls_files_helper "$root" "$1" | __git_index_file_list_filter |
- sort | uniq
- fi
-}
-
-# __git_diff_index_files accepts 1 or 2 arguments:
-# 1) The id of a tree object.
-# 2) A directory path (optional).
-# If provided, only files within the specified directory are listed.
-# Sub directories are never recursed. Path must have a trailing
-# slash.
-__git_diff_index_files ()
-{
- local dir="$(__gitdir)" root="${2-.}"
-
- if [ -d "$dir" ]; then
- __git_diff_index_helper "$root" "$1" | __git_index_file_list_filter |
- sort | uniq
+ __git_ls_files_helper "$root" "$1" |
+ while read -r file; do
+ case "$file" in
+ ?*/*) echo "${file%%/*}" ;;
+ *) echo "$file" ;;
+ esac
+ done | sort | uniq
fi
}
@@ -424,14 +369,8 @@ __git_refs ()
done
;;
*)
- git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \
- while read -r hash i; do
- case "$i" in
- *^{}) ;;
- refs/*) echo "${i#refs/*/}" ;;
- *) echo "$i" ;;
- esac
- done
+ echo "HEAD"
+ git for-each-ref --format="%(refname:short)" -- "refs/remotes/$dir/" | sed -e "s#^$dir/##"
;;
esac
}
@@ -549,44 +488,23 @@ __git_complete_revlist_file ()
}
-# __git_complete_index_file requires 1 argument: the options to pass to
-# ls-file
+# __git_complete_index_file requires 1 argument:
+# 1: the options to pass to ls-file
+#
+# The exception is --committable, which finds the files appropriate commit.
__git_complete_index_file ()
{
- local pfx cur_="$cur"
+ local pfx="" cur_="$cur"
case "$cur_" in
?*/*)
pfx="${cur_%/*}"
cur_="${cur_##*/}"
pfx="${pfx}/"
-
- __gitcomp_file "$(__git_index_files "$1" "$pfx")" "$pfx" "$cur_"
- ;;
- *)
- __gitcomp_file "$(__git_index_files "$1")" "" "$cur_"
;;
esac
-}
-
-# __git_complete_diff_index_file requires 1 argument: the id of a tree
-# object
-__git_complete_diff_index_file ()
-{
- local pfx cur_="$cur"
-
- case "$cur_" in
- ?*/*)
- pfx="${cur_%/*}"
- cur_="${cur_##*/}"
- pfx="${pfx}/"
- __gitcomp_file "$(__git_diff_index_files "$1" "$pfx")" "$pfx" "$cur_"
- ;;
- *)
- __gitcomp_file "$(__git_diff_index_files "$1")" "" "$cur_"
- ;;
- esac
+ __gitcomp_file "$(__git_index_files "$1" "$pfx")" "$pfx" "$cur_"
}
__git_complete_file ()
@@ -614,7 +532,6 @@ __git_complete_remote_or_refspec ()
case "$cmd" in
push) no_complete_refspec=1 ;;
fetch)
- COMPREPLY=()
return
;;
*) ;;
@@ -630,7 +547,6 @@ __git_complete_remote_or_refspec ()
return
fi
if [ $no_complete_refspec = 1 ]; then
- COMPREPLY=()
return
fi
[ "$remote" = "." ] && remote=
@@ -732,6 +648,7 @@ __git_list_porcelain_commands ()
cat-file) : plumbing;;
check-attr) : plumbing;;
check-ignore) : plumbing;;
+ check-mailmap) : plumbing;;
check-ref-format) : plumbing;;
checkout-index) : plumbing;;
commit-tree) : plumbing;;
@@ -951,7 +868,6 @@ _git_am ()
"
return
esac
- COMPREPLY=()
}
_git_apply ()
@@ -971,7 +887,6 @@ _git_apply ()
"
return
esac
- COMPREPLY=()
}
_git_add ()
@@ -1031,7 +946,6 @@ _git_bisect ()
__gitcomp_nl "$(__git_refs)"
;;
*)
- COMPREPLY=()
;;
esac
}
@@ -1124,9 +1038,14 @@ _git_cherry ()
_git_cherry_pick ()
{
+ local dir="$(__gitdir)"
+ if [ -f "$dir"/CHERRY_PICK_HEAD ]; then
+ __gitcomp "--continue --quit --abort"
+ return
+ fi
case "$cur" in
--*)
- __gitcomp "--edit --no-commit"
+ __gitcomp "--edit --no-commit --signoff --strategy= --mainline"
;;
*)
__gitcomp_nl "$(__git_refs)"
@@ -1170,7 +1089,6 @@ _git_clone ()
return
;;
esac
- COMPREPLY=()
}
_git_commit ()
@@ -1211,7 +1129,7 @@ _git_commit ()
esac
if git rev-parse --verify --quiet HEAD >/dev/null; then
- __git_complete_diff_index_file "HEAD"
+ __git_complete_index_file "--committable"
else
# This is the first commit
__git_complete_index_file "--cached"
@@ -1244,7 +1162,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
--no-prefix --src-prefix= --dst-prefix=
--inter-hunk-context=
--patience --histogram --minimal
- --raw
+ --raw --word-diff
--dirstat --dirstat= --dirstat-by-file
--dirstat-by-file= --cumulative
--diff-algorithm=
@@ -1292,7 +1210,7 @@ _git_difftool ()
return
;;
esac
- __git_complete_file
+ __git_complete_revlist_file
}
__git_fetch_options="
@@ -1312,11 +1230,12 @@ _git_fetch ()
}
__git_format_patch_options="
- --stdout --attach --no-attach --thread --thread= --output-directory
+ --stdout --attach --no-attach --thread --thread= --no-thread
--numbered --start-number --numbered-files --keep-subject --signoff
--signature --no-signature --in-reply-to= --cc= --full-index --binary
--not --all --cover-letter --no-prefix --src-prefix= --dst-prefix=
--inline --suffix= --ignore-if-in-upstream --subject-prefix=
+ --output-directory --reroll-count --to= --quiet --notes
"
_git_format_patch ()
@@ -1347,7 +1266,6 @@ _git_fsck ()
return
;;
esac
- COMPREPLY=()
}
_git_gc ()
@@ -1358,7 +1276,6 @@ _git_gc ()
return
;;
esac
- COMPREPLY=()
}
_git_gitk ()
@@ -1435,7 +1352,6 @@ _git_init ()
return
;;
esac
- COMPREPLY=()
}
_git_ls_files ()
@@ -1571,7 +1487,6 @@ _git_mergetool ()
return
;;
esac
- COMPREPLY=()
}
_git_merge_base ()
@@ -1812,7 +1727,7 @@ __git_config_get_set_variables ()
_git_config ()
{
case "$prev" in
- branch.*.remote)
+ branch.*.remote|branch.*.pushremote)
__gitcomp_nl "$(__git_remotes)"
return
;;
@@ -1824,11 +1739,15 @@ _git_config ()
__gitcomp "false true"
return
;;
+ remote.pushdefault)
+ __gitcomp_nl "$(__git_remotes)"
+ return
+ ;;
remote.*.fetch)
local remote="${prev#remote.}"
remote="${remote%.fetch}"
if [ -z "$cur" ]; then
- COMPREPLY=("refs/heads/")
+ __gitcomp_nl "refs/heads/" "" "" ""
return
fi
__gitcomp_nl "$(__git_refs_remotes "$remote")"
@@ -1892,7 +1811,6 @@ _git_config ()
return
;;
*.*)
- COMPREPLY=()
return
;;
esac
@@ -1909,7 +1827,7 @@ _git_config ()
;;
branch.*.*)
local pfx="${cur%.*}." cur_="${cur##*.}"
- __gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur_"
+ __gitcomp "remote pushremote merge mergeoptions rebase" "$pfx" "$cur_"
return
;;
branch.*)
@@ -2040,7 +1958,6 @@ _git_config ()
core.fileMode
core.fsyncobjectfiles
core.gitProxy
- core.ignoreCygwinFSTricks
core.ignoreStat
core.ignorecase
core.logAllRefUpdates
@@ -2204,6 +2121,7 @@ _git_config ()
receive.fsckObjects
receive.unpackLimit
receive.updateserverinfo
+ remote.pushdefault
remotes.
repack.usedeltabaseoffset
rerere.autoupdate
@@ -2274,7 +2192,6 @@ _git_remote ()
__gitcomp "$c"
;;
*)
- COMPREPLY=()
;;
esac
}
@@ -2358,7 +2275,7 @@ _git_show ()
return
;;
esac
- __git_complete_file
+ __git_complete_revlist_file
}
_git_show_branch ()
@@ -2390,8 +2307,6 @@ _git_stash ()
*)
if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then
__gitcomp "$subcommands"
- else
- COMPREPLY=()
fi
;;
esac
@@ -2404,14 +2319,12 @@ _git_stash ()
__gitcomp "--index --quiet"
;;
show,--*|drop,--*|branch,--*)
- COMPREPLY=()
;;
show,*|apply,*|drop,*|pop,*|branch,*)
__gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \
| sed -n -e 's/:.*//p')"
;;
*)
- COMPREPLY=()
;;
esac
fi
@@ -2421,7 +2334,7 @@ _git_submodule ()
{
__git_has_doubledash && return
- local subcommands="add status init update summary foreach sync"
+ local subcommands="add status init deinit update summary foreach sync"
if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
case "$cur" in
--*)
@@ -2453,7 +2366,7 @@ _git_svn ()
--no-metadata --use-svm-props --use-svnsync-props
--log-window-size= --no-checkout --quiet
--repack-flags --use-log-author --localtime
- --ignore-paths= $remote_opts
+ --ignore-paths= --include-paths= $remote_opts
"
local init_opts="
--template= --shared= --trunk= --tags=
@@ -2528,7 +2441,6 @@ _git_svn ()
__gitcomp "--revision= --parent"
;;
*)
- COMPREPLY=()
;;
esac
fi
@@ -2553,13 +2465,10 @@ _git_tag ()
case "$prev" in
-m|-F)
- COMPREPLY=()
;;
-*|tag)
if [ $f = 1 ]; then
__gitcomp_nl "$(__git_tags)"
- else
- COMPREPLY=()
fi
;;
*)
@@ -2581,9 +2490,10 @@ __git_main ()
i="${words[c]}"
case "$i" in
--git-dir=*) __git_dir="${i#--git-dir=}" ;;
+ --git-dir) ((c++)) ; __git_dir="${words[c]}" ;;
--bare) __git_dir="." ;;
--help) command="help"; break ;;
- -c) c=$((++c)) ;;
+ -c|--work-tree|--namespace) ((c++)) ;;
-*) ;;
*) command="$i"; break ;;
esac
@@ -2601,6 +2511,7 @@ __git_main ()
--exec-path
--exec-path=
--html-path
+ --man-path
--info-path
--work-tree=
--namespace=
@@ -2669,7 +2580,7 @@ if [[ -n ${ZSH_VERSION-} ]]; then
--*=*|*.) ;;
*) c="$c " ;;
esac
- array[$#array+1]="$c"
+ array[${#array[@]}+1]="$c"
done
compset -P '*[=:]'
compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
@@ -2695,35 +2606,19 @@ if [[ -n ${ZSH_VERSION-} ]]; then
compadd -Q -p "${2-}" -f -- ${=1} && _ret=0
}
- __git_zsh_helper ()
- {
- emulate -L ksh
- local cur cword prev
- cur=${words[CURRENT-1]}
- prev=${words[CURRENT-2]}
- let cword=CURRENT-1
- __${service}_main
- }
-
_git ()
{
- emulate -L zsh
- local _ret=1
- __git_zsh_helper
- let _ret && _default -S '' && _ret=0
+ local _ret=1 cur cword prev
+ cur=${words[CURRENT]}
+ prev=${words[CURRENT-1]}
+ let cword=CURRENT-1
+ emulate ksh -c __${service}_main
+ let _ret && _default && _ret=0
return _ret
}
compdef _git git gitk
return
-elif [[ -n ${BASH_VERSION-} ]]; then
- if ((${BASH_VERSINFO[0]} < 4)); then
- # compopt is not supported
- __git_index_file_list_filter ()
- {
- __git_index_file_list_filter_compat
- }
- fi
fi
__git_func_wrap ()
diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
index 2565d2e..fac5e71 100644
--- a/contrib/completion/git-completion.zsh
+++ b/contrib/completion/git-completion.zsh
@@ -4,18 +4,17 @@
#
# Copyright (c) 2012-2013 Felipe Contreras <felipe.contreras@gmail.com>
#
-# You need git's bash completion script installed somewhere, by default on the
-# same directory as this script.
+# You need git's bash completion script installed somewhere, by default it
+# would be the location bash-completion uses.
#
-# If your script is on ~/.git-completion.sh instead, you can configure it on
-# your ~/.zshrc:
+# If your script is somewhere else, you can configure it on your ~/.zshrc:
#
# zstyle ':completion:*:*:git:*' script ~/.git-completion.sh
#
-# The recommended way to install this script is to copy to
-# '~/.zsh/completion/_git', and then add the following to your ~/.zshrc file:
+# The recommended way to install this script is to copy to '~/.zsh/_git', and
+# then add the following to your ~/.zshrc file:
#
-# fpath=(~/.zsh/completion $fpath)
+# fpath=(~/.zsh $fpath)
complete ()
{
@@ -27,7 +26,19 @@ zstyle -T ':completion:*:*:git:*' tag-order && \
zstyle ':completion:*:*:git:*' tag-order 'common-commands'
zstyle -s ":completion:*:*:git:*" script script
-test -z "$script" && script="$(dirname ${funcsourcetrace[1]%:*})"/git-completion.bash
+if [ -z "$script" ]; then
+ local -a locations
+ local e
+ locations=(
+ '/etc/bash_completion.d/git' # fedora, old debian
+ '/usr/share/bash-completion/completions/git' # arch, ubuntu, new debian
+ '/usr/share/bash-completion/git' # gentoo
+ $(dirname ${funcsourcetrace[1]%:*})/git-completion.bash
+ )
+ for e in $locations; do
+ test -f $e && script="$e" && break
+ done
+fi
ZSH_VERSION='' . "$script"
__gitcomp ()
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 054c52e..d6c61b2 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -3,7 +3,7 @@
# 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.
+# This script allows you to see repository status in your prompt.
#
# To enable:
#
@@ -13,23 +13,27 @@
# 3a) Change your PS1 to call __git_ps1 as
# command-substitution:
# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
-# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
+# ZSH: setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
# the optional argument will be used as format string.
-# 3b) Alternatively, if you are using bash, __git_ps1 can be
-# used for PROMPT_COMMAND with two parameters, <pre> and
-# <post>, which are strings you would put in $PS1 before
-# and after the status string generated by the git-prompt
-# machinery. e.g.
-# PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
-# will show username, at-sign, host, colon, cwd, then
-# various status string, followed by dollar and SP, as
-# your prompt.
+# 3b) Alternatively, for a slightly faster prompt, __git_ps1 can
+# be used for PROMPT_COMMAND in Bash or for precmd() in Zsh
+# with two parameters, <pre> and <post>, which are strings
+# you would put in $PS1 before and after the status string
+# generated by the git-prompt machinery. e.g.
+# Bash: PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
+# will show username, at-sign, host, colon, cwd, then
+# various status string, followed by dollar and SP, as
+# your prompt.
+# ZSH: precmd () { __git_ps1 "%n" ":%~$ " "|%s" }
+# will show username, pipe, then various status string,
+# followed by colon, cwd, dollar and SP, as your prompt.
# Optionally, you can supply a third argument with a printf
# format string to finetune the output of the branch status
#
-# The argument to __git_ps1 will be displayed only if you are currently
-# in a git repository. The %s token will be the name of the current
-# branch.
+# The repository status will be displayed only if you are currently in a
+# git repository. The %s token is the placeholder for the shown status.
+#
+# The prompt status always includes the current branch name.
#
# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,
# unstaged (*) and staged (+) changes will be shown next to the branch
@@ -77,31 +81,12 @@
#
# If you would like a colored hint about the current dirty state, set
# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
-# the colored output of "git status -sb".
+# the colored output of "git status -sb" and are available only when
+# using __git_ps1 for PROMPT_COMMAND or precmd.
-# __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
-}
+# check whether printf supports -v
+__git_printf_supports_v=
+printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1
# stores the divergence from upstream in $p
# used by GIT_PS1_SHOWUPSTREAM
@@ -124,7 +109,7 @@ __git_ps1_show_upstream ()
fi
;;
svn-remote.*.url)
- svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
+ svn_remote[$((${#svn_remote[@]} + 1))]="$value"
svn_url_pattern+="\\|$value"
upstream=svn+git # default upstream is SVN if available, else git
;;
@@ -146,10 +131,11 @@ __git_ps1_show_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 \
+ local -a svn_upstream
+ 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[${#svn_upstream[@]} - 2]}
svn_upstream=${svn_upstream%@*}
local n_stop="${#svn_remote[@]}"
for ((n=1; n <= n_stop; n++)); do
@@ -222,6 +208,51 @@ __git_ps1_show_upstream ()
}
+# Helper function that is meant to be called from __git_ps1. It
+# injects color codes into the appropriate gitstring variables used
+# to build a gitstring.
+__git_ps1_colorize_gitstring ()
+{
+ if [[ -n ${ZSH_VERSION-} ]]; then
+ local c_red='%F{red}'
+ local c_green='%F{green}'
+ local c_lblue='%F{blue}'
+ local c_clear='%f'
+ else
+ # Using \[ and \] around colors is necessary to prevent
+ # issues with command line editing/browsing/completion!
+ local c_red='\[\e[31m\]'
+ local c_green='\[\e[32m\]'
+ local c_lblue='\[\e[1;34m\]'
+ local c_clear='\[\e[0m\]'
+ fi
+ local bad_color=$c_red
+ local ok_color=$c_green
+ local flags_color="$c_lblue"
+
+ local branch_color=""
+ if [ $detached = no ]; then
+ branch_color="$ok_color"
+ else
+ branch_color="$bad_color"
+ fi
+ c="$branch_color$c"
+
+ z="$c_clear$z"
+ if [ "$w" = "*" ]; then
+ w="$bad_color$w"
+ fi
+ if [ -n "$i" ]; then
+ i="$ok_color$i"
+ fi
+ if [ -n "$s" ]; then
+ s="$flags_color$s"
+ fi
+ if [ -n "$u" ]; then
+ u="$bad_color$u"
+ fi
+ r="$c_clear$r"
+}
# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
# when called from PS1 using command substitution
@@ -254,41 +285,83 @@ __git_ps1 ()
;;
esac
- local g="$(__gitdir)"
- if [ -z "$g" ]; then
+ local repo_info rev_parse_exit_code
+ repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
+ --is-bare-repository --is-inside-work-tree \
+ --short HEAD 2>/dev/null)"
+ rev_parse_exit_code="$?"
+
+ if [ -z "$repo_info" ]; then
if [ $pcmode = yes ]; then
#In PC mode PS1 always needs to be set
PS1="$ps1pc_start$ps1pc_end"
fi
- else
- local r=""
- local b=""
+ return
+ fi
+
+ local short_sha
+ if [ "$rev_parse_exit_code" = "0" ]; then
+ short_sha="${repo_info##*$'\n'}"
+ repo_info="${repo_info%$'\n'*}"
+ fi
+ local inside_worktree="${repo_info##*$'\n'}"
+ repo_info="${repo_info%$'\n'*}"
+ local bare_repo="${repo_info##*$'\n'}"
+ repo_info="${repo_info%$'\n'*}"
+ local inside_gitdir="${repo_info##*$'\n'}"
+ local g="${repo_info%$'\n'*}"
+
+ local r=""
+ local b=""
+ local step=""
+ local total=""
+ if [ -d "$g/rebase-merge" ]; then
+ read b 2>/dev/null <"$g/rebase-merge/head-name"
+ read step 2>/dev/null <"$g/rebase-merge/msgnum"
+ read total 2>/dev/null <"$g/rebase-merge/end"
if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
- b="$(cat "$g/rebase-merge/head-name")"
- elif [ -d "$g/rebase-merge" ]; then
+ else
r="|REBASE-m"
- b="$(cat "$g/rebase-merge/head-name")"
+ fi
+ else
+ if [ -d "$g/rebase-apply" ]; then
+ read step 2>/dev/null <"$g/rebase-apply/next"
+ read total 2>/dev/null <"$g/rebase-apply/last"
+ if [ -f "$g/rebase-apply/rebasing" ]; then
+ read b 2>/dev/null <"$g/rebase-apply/head-name"
+ 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/REVERT_HEAD" ]; then
+ r="|REVERTING"
+ elif [ -f "$g/BISECT_LOG" ]; then
+ r="|BISECTING"
+ fi
+
+ if [ -n "$b" ]; then
+ :
+ elif [ -h "$g/HEAD" ]; then
+ # symlink symbolic ref
+ b="$(git symbolic-ref HEAD 2>/dev/null)"
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"
+ local head=""
+ if ! read head 2>/dev/null <"$g/HEAD"; then
+ if [ $pcmode = yes ]; then
+ PS1="$ps1pc_start$ps1pc_end"
fi
- elif [ -f "$g/MERGE_HEAD" ]; then
- r="|MERGING"
- elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
- r="|CHERRY-PICKING"
- elif [ -f "$g/REVERT_HEAD" ]; then
- r="|REVERTING"
- elif [ -f "$g/BISECT_LOG" ]; then
- r="|BISECTING"
+ return
fi
-
- b="$(git symbolic-ref HEAD 2>/dev/null)" || {
+ # is it a symbolic ref?
+ b="${head#ref: }"
+ if [ "$head" = "$b" ]; then
detached=yes
b="$(
case "${GIT_PS1_DESCRIBE_STYLE-}" in
@@ -302,100 +375,75 @@ __git_ps1 ()
git describe --tags --exact-match HEAD ;;
esac 2>/dev/null)" ||
- b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
- b="unknown"
+ b="$short_sha..."
b="($b)"
- }
+ fi
fi
+ fi
+
+ if [ -n "$step" ] && [ -n "$total" ]; then
+ r="$r $step/$total"
+ fi
- local w=""
- local i=""
- local s=""
- local u=""
- local c=""
- local p=""
+ 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:"
+ if [ "true" = "$inside_gitdir" ]; then
+ if [ "true" = "$bare_repo" ]; then
+ c="BARE:"
+ else
+ b="GIT_DIR!"
+ fi
+ elif [ "true" = "$inside_worktree" ]; then
+ if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
+ [ "$(git config --bool bash.showDirtyState)" != "false" ]
+ then
+ git diff --no-ext-diff --quiet --exit-code || w="*"
+ if [ -n "$short_sha" ]; then
+ git diff-index --cached --quiet HEAD -- || i="+"
else
- b="GIT_DIR!"
- fi
- elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
- if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
- [ "$(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
- if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
- git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
+ i="#"
fi
+ fi
+ if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] &&
+ [ -r "$g/refs/stash" ]; then
+ s="$"
+ fi
- if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
- [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
- [ -n "$(git ls-files --others --exclude-standard)" ]
- then
- u="%${ZSH_VERSION+%}"
- fi
+ if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
+ [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
+ git ls-files --others --exclude-standard --error-unmatch -- '*' >/dev/null 2>/dev/null
+ then
+ u="%${ZSH_VERSION+%}"
+ fi
- if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
- __git_ps1_show_upstream
- fi
+ if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
+ __git_ps1_show_upstream
fi
+ fi
- local f="$w$i$s$u"
- if [ $pcmode = yes ]; then
- local gitstring=
- if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
- local c_red='\e[31m'
- local c_green='\e[32m'
- local c_lblue='\e[1;34m'
- local c_clear='\e[0m'
- local bad_color=$c_red
- local ok_color=$c_green
- local branch_color="$c_clear"
- local flags_color="$c_lblue"
- local branchstring="$c${b##refs/heads/}"
+ local z="${GIT_PS1_STATESEPARATOR-" "}"
- if [ $detached = no ]; then
- branch_color="$ok_color"
- else
- branch_color="$bad_color"
- fi
+ # NO color option unless in PROMPT_COMMAND mode
+ if [ $pcmode = yes ] && [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
+ __git_ps1_colorize_gitstring
+ fi
- # Setting gitstring directly with \[ and \] around colors
- # is necessary to prevent wrapping issues!
- gitstring="\[$branch_color\]$branchstring\[$c_clear\]"
+ local f="$w$i$s$u"
+ local gitstring="$c${b##refs/heads/}${f:+$z$f}$r$p"
- if [ -n "$w$i$s$u$r$p" ]; then
- gitstring="$gitstring "
- fi
- if [ "$w" = "*" ]; then
- gitstring="$gitstring\[$bad_color\]$w"
- fi
- if [ -n "$i" ]; then
- gitstring="$gitstring\[$ok_color\]$i"
- fi
- if [ -n "$s" ]; then
- gitstring="$gitstring\[$flags_color\]$s"
- fi
- if [ -n "$u" ]; then
- gitstring="$gitstring\[$bad_color\]$u"
- fi
- gitstring="$gitstring\[$c_clear\]$r$p"
- else
- gitstring="$c${b##refs/heads/}${f:+ $f}$r$p"
- fi
+ if [ $pcmode = yes ]; then
+ if [ "${__git_printf_supports_v-}" != yes ]; then
gitstring=$(printf -- "$printf_format" "$gitstring")
- PS1="$ps1pc_start$gitstring$ps1pc_end"
else
- # NO color option unless in PROMPT_COMMAND mode
- printf -- "$printf_format" "$c${b##refs/heads/}${f:+ $f}$r$p"
+ printf -v gitstring -- "$printf_format" "$gitstring"
fi
+ PS1="$ps1pc_start$gitstring$ps1pc_end"
+ else
+ printf -- "$printf_format" "$gitstring"
fi
}
diff --git a/contrib/contacts/git-contacts b/contrib/contacts/git-contacts
new file mode 100755
index 0000000..fb6429b
--- /dev/null
+++ b/contrib/contacts/git-contacts
@@ -0,0 +1,201 @@
+#!/usr/bin/perl
+
+# List people who might be interested in a patch. Useful as the argument to
+# git-send-email --cc-cmd option, and in other situations.
+#
+# Usage: git contacts <file | rev-list option> ...
+
+use strict;
+use warnings;
+use IPC::Open2;
+
+my $since = '5-years-ago';
+my $min_percent = 10;
+my $labels_rx = qr/Signed-off-by|Reviewed-by|Acked-by|Cc/i;
+my %seen;
+
+sub format_contact {
+ my ($name, $email) = @_;
+ return "$name <$email>";
+}
+
+sub parse_commit {
+ my ($commit, $data) = @_;
+ my $contacts = $commit->{contacts};
+ my $inbody = 0;
+ for (split(/^/m, $data)) {
+ if (not $inbody) {
+ if (/^author ([^<>]+) <(\S+)> .+$/) {
+ $contacts->{format_contact($1, $2)} = 1;
+ } elsif (/^$/) {
+ $inbody = 1;
+ }
+ } elsif (/^$labels_rx:\s+([^<>]+)\s+<(\S+?)>$/o) {
+ $contacts->{format_contact($1, $2)} = 1;
+ }
+ }
+}
+
+sub import_commits {
+ my ($commits) = @_;
+ return unless %$commits;
+ my $pid = open2 my $reader, my $writer, qw(git cat-file --batch);
+ for my $id (keys(%$commits)) {
+ print $writer "$id\n";
+ my $line = <$reader>;
+ if ($line =~ /^([0-9a-f]{40}) commit (\d+)/) {
+ my ($cid, $len) = ($1, $2);
+ die "expected $id but got $cid\n" unless $id eq $cid;
+ my $data;
+ # cat-file emits newline after data, so read len+1
+ read $reader, $data, $len + 1;
+ parse_commit($commits->{$id}, $data);
+ }
+ }
+ close $reader;
+ close $writer;
+ waitpid($pid, 0);
+ die "git-cat-file error: $?\n" if $?;
+}
+
+sub get_blame {
+ my ($commits, $source, $from, $ranges) = @_;
+ return unless @$ranges;
+ open my $f, '-|',
+ qw(git blame --porcelain -C),
+ map({"-L$_->[0],+$_->[1]"} @$ranges),
+ '--since', $since, "$from^", '--', $source or die;
+ while (<$f>) {
+ if (/^([0-9a-f]{40}) \d+ \d+ \d+$/) {
+ my $id = $1;
+ $commits->{$id} = { id => $id, contacts => {} }
+ unless $seen{$id};
+ $seen{$id} = 1;
+ }
+ }
+ close $f;
+}
+
+sub blame_sources {
+ my ($sources, $commits) = @_;
+ for my $s (keys %$sources) {
+ for my $id (keys %{$sources->{$s}}) {
+ get_blame($commits, $s, $id, $sources->{$s}{$id});
+ }
+ }
+}
+
+sub scan_patches {
+ my ($sources, $id, $f) = @_;
+ my $source;
+ while (<$f>) {
+ if (/^From ([0-9a-f]{40}) Mon Sep 17 00:00:00 2001$/) {
+ $id = $1;
+ $seen{$id} = 1;
+ }
+ next unless $id;
+ if (m{^--- (?:a/(.+)|/dev/null)$}) {
+ $source = $1;
+ } elsif (/^--- /) {
+ die "Cannot parse hunk source: $_\n";
+ } elsif (/^@@ -(\d+)(?:,(\d+))?/ && $source) {
+ my $len = defined($2) ? $2 : 1;
+ push @{$sources->{$source}{$id}}, [$1, $len] if $len;
+ }
+ }
+}
+
+sub scan_patch_file {
+ my ($commits, $file) = @_;
+ open my $f, '<', $file or die "read failure: $file: $!\n";
+ scan_patches($commits, undef, $f);
+ close $f;
+}
+
+sub parse_rev_args {
+ my @args = @_;
+ open my $f, '-|',
+ qw(git rev-parse --revs-only --default HEAD --symbolic), @args
+ or die;
+ my @revs;
+ while (<$f>) {
+ chomp;
+ push @revs, $_;
+ }
+ close $f;
+ return @revs if scalar(@revs) != 1;
+ return "^$revs[0]", 'HEAD' unless $revs[0] =~ /^-/;
+ return $revs[0], 'HEAD';
+}
+
+sub scan_rev_args {
+ my ($commits, $args) = @_;
+ my @revs = parse_rev_args(@$args);
+ open my $f, '-|', qw(git rev-list --reverse), @revs or die;
+ while (<$f>) {
+ chomp;
+ my $id = $_;
+ $seen{$id} = 1;
+ open my $g, '-|', qw(git show -C --oneline), $id or die;
+ scan_patches($commits, $id, $g);
+ close $g;
+ }
+ close $f;
+}
+
+sub mailmap_contacts {
+ my ($contacts) = @_;
+ my %mapped;
+ my $pid = open2 my $reader, my $writer, qw(git check-mailmap --stdin);
+ for my $contact (keys(%$contacts)) {
+ print $writer "$contact\n";
+ my $canonical = <$reader>;
+ chomp $canonical;
+ $mapped{$canonical} += $contacts->{$contact};
+ }
+ close $reader;
+ close $writer;
+ waitpid($pid, 0);
+ die "git-check-mailmap error: $?\n" if $?;
+ return \%mapped;
+}
+
+if (!@ARGV) {
+ die "No input revisions or patch files\n";
+}
+
+my (@files, @rev_args);
+for (@ARGV) {
+ if (-e) {
+ push @files, $_;
+ } else {
+ push @rev_args, $_;
+ }
+}
+
+my %sources;
+for (@files) {
+ scan_patch_file(\%sources, $_);
+}
+if (@rev_args) {
+ scan_rev_args(\%sources, \@rev_args)
+}
+
+my %commits;
+blame_sources(\%sources, \%commits);
+import_commits(\%commits);
+
+my $contacts = {};
+for my $commit (values %commits) {
+ for my $contact (keys %{$commit->{contacts}}) {
+ $contacts->{$contact}++;
+ }
+}
+$contacts = mailmap_contacts($contacts);
+
+my $ncommits = scalar(keys %commits);
+for my $contact (keys %$contacts) {
+ my $percent = $contacts->{$contact} * 100 / $ncommits;
+ next if $percent < $min_percent;
+ print "$contact\n";
+}
diff --git a/contrib/contacts/git-contacts.txt b/contrib/contacts/git-contacts.txt
new file mode 100644
index 0000000..dd914d1
--- /dev/null
+++ b/contrib/contacts/git-contacts.txt
@@ -0,0 +1,94 @@
+git-contacts(1)
+===============
+
+NAME
+----
+git-contacts - List people who might be interested in a set of changes
+
+
+SYNOPSIS
+--------
+[verse]
+'git contacts' (<patch>|<range>|<rev>)...
+
+
+DESCRIPTION
+-----------
+
+Given a set of changes, specified as patch files or revisions, determine people
+who might be interested in those changes. This is done by consulting the
+history of each patch or revision hunk to find people mentioned by commits
+which touched the lines of files under consideration.
+
+Input consists of one or more patch files or revision arguments. A revision
+argument can be a range or a single `<rev>` which is interpreted as
+`<rev>..HEAD`, thus the same revision arguments are accepted as for
+linkgit:git-format-patch[1]. Patch files and revision arguments can be combined
+in the same invocation.
+
+This command can be useful for determining the list of people with whom to
+discuss proposed changes, or for finding the list of recipients to Cc: when
+submitting a patch series via `git send-email`. For the latter case, `git
+contacts` can be used as the argument to `git send-email`'s `--cc-cmd` option.
+
+
+DISCUSSION
+----------
+
+`git blame` is invoked for each hunk in a patch file or revision. For each
+commit mentioned by `git blame`, the commit message is consulted for people who
+authored, reviewed, signed, acknowledged, or were Cc:'d. Once the list of
+participants is known, each person's relevance is computed by considering how
+many commits mentioned that person compared with the total number of commits
+under consideration. The final output consists only of participants who exceed
+a minimum threshold of participation.
+
+
+OUTPUT
+------
+
+For each person of interest, a single line is output, terminated by a newline.
+If the person's name is known, ``Name $$<user@host>$$'' is printed; otherwise
+only ``$$<user@host>$$'' is printed.
+
+
+EXAMPLES
+--------
+
+* Consult patch files:
++
+------------
+$ git contacts feature/*.patch
+------------
+
+* Revision range:
++
+------------
+$ git contacts R1..R2
+------------
+
+* From a single revision to `HEAD`:
++
+------------
+$ git contacts origin
+------------
+
+* Helper for `git send-email`:
++
+------------
+$ git send-email --cc-cmd='git contacts' feature/*.patch
+------------
+
+
+LIMITATIONS
+-----------
+
+Several conditions controlling a person's significance are currently
+hard-coded, such as minimum participation level (10%), blame date-limiting (5
+years), and `-C` level for detecting moved and copied lines (a single `-C`). In
+the future, these conditions may become configurable.
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/contrib/continuous/cidaemon b/contrib/continuous/cidaemon
deleted file mode 100644
index 4009a15..0000000
--- a/contrib/continuous/cidaemon
+++ /dev/null
@@ -1,503 +0,0 @@
-#!/usr/bin/perl
-#
-# A daemon that waits for update events sent by its companion
-# post-receive-cinotify hook, checks out a new copy of source,
-# compiles it, and emails the guilty parties if the compile
-# (and optionally test suite) fails.
-#
-# To use this daemon, configure it and run it. It will disconnect
-# from your terminal and fork into the background. The daemon must
-# have local filesystem access to the source repositories, as it
-# uses objects/info/alternates to avoid copying objects.
-#
-# Add its companion post-receive-cinotify hook as the post-receive
-# hook to each repository that the daemon should monitor. Yes, a
-# single daemon can monitor more than one repository.
-#
-# To use multiple daemons on the same system, give them each a
-# unique queue file and tmpdir.
-#
-# Global Config
-# -------------
-# Reads from a Git style configuration file. This will be
-# ~/.gitconfig by default but can be overridden by setting
-# the GIT_CONFIG_FILE environment variable before starting.
-#
-# cidaemon.smtpHost
-# Hostname of the SMTP server the daemon will send email
-# through. Defaults to 'localhost'.
-#
-# cidaemon.smtpUser
-# Username to authenticate to the SMTP server as. This
-# variable is optional; if it is not supplied then no
-# authentication will be performed.
-#
-# cidaemon.smtpPassword
-# Password to authenticate to the SMTP server as. This
-# variable is optional. If not supplied but smtpUser was,
-# the daemon prompts for the password before forking into
-# the background.
-#
-# cidaemon.smtpAuth
-# Type of authentication to perform with the SMTP server.
-# If set to 'login' and smtpUser was defined, this will
-# use the AUTH LOGIN command, which is suitable for use
-# with at least one version of Microsoft Exchange Server.
-# If not set the daemon will use whatever auth methods
-# are supported by your version of Net::SMTP.
-#
-# cidaemon.email
-# Email address that daemon generated emails will be sent
-# from. This should be a useful email address within your
-# organization. Required.
-#
-# cidaemon.name
-# Human friendly name that the daemon will send emails as.
-# Defaults to 'cidaemon'.
-#
-# cidaemon.scanDelay
-# Number of seconds to sleep between polls of the queue file.
-# Defaults to 60.
-#
-# cidaemon.recentCache
-# Number of recent commit SHA-1s per repository to cache and
-# skip building if they appear again. This is useful to avoid
-# rebuilding the same commit multiple times just because it was
-# pushed into more than one branch. Defaults to 100.
-#
-# cidaemon.tmpdir
-# Scratch directory to create the builds within. The daemon
-# makes a new subdirectory for each build, then deletes it when
-# the build has finished. The pid file is also placed here.
-# Defaults to '/tmp'.
-#
-# cidaemon.queue
-# Path to the queue file that the post-receive-cinotify hook
-# appends events to. This file is polled by the daemon. It
-# must not be on an NFS mount (uses flock). Required.
-#
-# cidaemon.nocc
-# Perl regex patterns to match against author and committer
-# lines. If a pattern matches, that author or committer will
-# not be notified of a build failure.
-#
-# Per Repository Config
-# ----------------------
-# Read from the source repository's config file.
-#
-# builder.command
-# Shell command to execute the build. This command must
-# return 0 on "success" and non-zero on failure. If you
-# also want to run a test suite, make sure your command
-# does that too. Required.
-#
-# builder.queue
-# Queue file to notify the cidaemon through. Should match
-# cidaemon.queue. If not set the hook will not notify the
-# cidaemon.
-#
-# builder.skip
-# Perl regex patterns of refs that should not be sent to
-# cidaemon. Updates of these refs will be ignored.
-#
-# builder.newBranchBase
-# Glob patterns of refs that should be used to form the
-# 'old' revions of a newly created ref. This should set
-# to be globs that match your 'mainline' branches. This
-# way a build failure of a brand new topic branch does not
-# attempt to email everyone since the beginning of time;
-# instead it only emails those authors of commits not in
-# these 'mainline' branches.
-
-local $ENV{PATH} = join ':', qw(
- /opt/git/bin
- /usr/bin
- /bin
- );
-
-use strict;
-use warnings;
-use FindBin qw($RealBin);
-use File::Spec;
-use lib File::Spec->catfile($RealBin, '..', 'perl5');
-use Storable qw(retrieve nstore);
-use Fcntl ':flock';
-use POSIX qw(strftime);
-use Getopt::Long qw(:config no_auto_abbrev auto_help);
-
-sub git_config ($;$)
-{
- my $var = shift;
- my $required = shift || 0;
- local *GIT;
- open GIT, '-|','git','config','--get',$var;
- my $r = <GIT>;
- chop $r if $r;
- close GIT;
- die "error: $var not set.\n" if ($required && !$r);
- return $r;
-}
-
-package EXCHANGE_NET_SMTP;
-
-# Microsoft Exchange Server requires an 'AUTH LOGIN'
-# style of authentication. This is different from
-# the default supported by Net::SMTP so we subclass
-# and override the auth method to support that.
-
-use Net::SMTP;
-use Net::Cmd;
-use MIME::Base64 qw(encode_base64);
-our @ISA = qw(Net::SMTP);
-our $auth_type = ::git_config 'cidaemon.smtpAuth';
-
-sub new
-{
- my $self = shift;
- my $type = ref($self) || $self;
- $type->SUPER::new(@_);
-}
-
-sub auth
-{
- my $self = shift;
- return $self->SUPER::auth(@_) unless $auth_type eq 'login';
-
- my $user = encode_base64 shift, '';
- my $pass = encode_base64 shift, '';
- return 0 unless CMD_MORE == $self->command("AUTH LOGIN")->response;
- return 0 unless CMD_MORE == $self->command($user)->response;
- CMD_OK == $self->command($pass)->response;
-}
-
-package main;
-
-my ($debug_flag, %recent);
-
-my $ex_host = git_config('cidaemon.smtpHost') || 'localhost';
-my $ex_user = git_config('cidaemon.smtpUser');
-my $ex_pass = git_config('cidaemon.smtpPassword');
-
-my $ex_from_addr = git_config('cidaemon.email', 1);
-my $ex_from_name = git_config('cidaemon.name') || 'cidaemon';
-
-my $scan_delay = git_config('cidaemon.scanDelay') || 60;
-my $recent_size = git_config('cidaemon.recentCache') || 100;
-my $tmpdir = git_config('cidaemon.tmpdir') || '/tmp';
-my $queue_name = git_config('cidaemon.queue', 1);
-my $queue_lock = "$queue_name.lock";
-
-my @nocc_list;
-open GIT,'git config --get-all cidaemon.nocc|';
-while (<GIT>) {
- chop;
- push @nocc_list, $_;
-}
-close GIT;
-
-sub nocc_author ($)
-{
- local $_ = shift;
- foreach my $pat (@nocc_list) {
- return 1 if /$pat/;
- }
- 0;
-}
-
-sub input_echo ($)
-{
- my $prompt = shift;
-
- local $| = 1;
- print $prompt;
- my $input = <STDIN>;
- chop $input;
- return $input;
-}
-
-sub input_noecho ($)
-{
- my $prompt = shift;
-
- my $end = sub {system('stty','echo');print "\n";exit};
- local $SIG{TERM} = $end;
- local $SIG{INT} = $end;
- system('stty','-echo');
-
- local $| = 1;
- print $prompt;
- my $input = <STDIN>;
- system('stty','echo');
- print "\n";
- chop $input;
- return $input;
-}
-
-sub rfc2822_date ()
-{
- strftime("%a, %d %b %Y %H:%M:%S %Z", localtime);
-}
-
-sub send_email ($$$)
-{
- my ($subj, $body, $to) = @_;
- my $now = rfc2822_date;
- my $to_str = '';
- my @rcpt_to;
- foreach (@$to) {
- my $s = $_;
- $s =~ s/^/"/;
- $s =~ s/(\s+<)/"$1/;
- $to_str .= ', ' if $to_str;
- $to_str .= $s;
- push @rcpt_to, $1 if $s =~ /<(.*)>/;
- }
- die "Nobody to send to.\n" unless @rcpt_to;
- my $msg = <<EOF;
-From: "$ex_from_name" <$ex_from_addr>
-To: $to_str
-Date: $now
-Subject: $subj
-
-$body
-EOF
-
- my $smtp = EXCHANGE_NET_SMTP->new(Host => $ex_host)
- or die "Cannot connect to $ex_host: $!\n";
- if ($ex_user && $ex_pass) {
- $smtp->auth($ex_user,$ex_pass)
- or die "$ex_host rejected $ex_user\n";
- }
- $smtp->mail($ex_from_addr)
- or die "$ex_host rejected $ex_from_addr\n";
- scalar($smtp->recipient(@rcpt_to, { SkipBad => 1 }))
- or die "$ex_host did not accept any addresses.\n";
- $smtp->data($msg)
- or die "$ex_host rejected message data\n";
- $smtp->quit;
-}
-
-sub pop_queue ()
-{
- open LOCK, ">$queue_lock" or die "Can't open $queue_lock: $!";
- flock LOCK, LOCK_EX;
-
- my $queue = -f $queue_name ? retrieve $queue_name : [];
- my $ent = shift @$queue;
- nstore $queue, $queue_name;
-
- flock LOCK, LOCK_UN;
- close LOCK;
- $ent;
-}
-
-sub git_exec (@)
-{
- system('git',@_) == 0 or die "Cannot git " . join(' ', @_) . "\n";
-}
-
-sub git_val (@)
-{
- open(C, '-|','git',@_);
- my $r = <C>;
- chop $r if $r;
- close C;
- $r;
-}
-
-sub do_build ($$)
-{
- my ($git_dir, $new) = @_;
-
- my $tmp = File::Spec->catfile($tmpdir, "builder$$");
- system('rm','-rf',$tmp) == 0 or die "Cannot clear $tmp\n";
- die "Cannot clear $tmp.\n" if -e $tmp;
-
- my $result = 1;
- eval {
- my $command;
- {
- local $ENV{GIT_DIR} = $git_dir;
- $command = git_val 'config','builder.command';
- }
- die "No builder.command for $git_dir.\n" unless $command;
-
- git_exec 'clone','-n','-l','-s',$git_dir,$tmp;
- chmod 0700, $tmp or die "Cannot lock $tmp\n";
- chdir $tmp or die "Cannot enter $tmp\n";
-
- git_exec 'update-ref','HEAD',$new;
- git_exec 'read-tree','-m','-u','HEAD','HEAD';
- system $command;
- if ($? == -1) {
- print STDERR "failed to execute '$command': $!\n";
- $result = 1;
- } elsif ($? & 127) {
- my $sig = $? & 127;
- print STDERR "'$command' died from signal $sig\n";
- $result = 1;
- } else {
- my $r = $? >> 8;
- print STDERR "'$command' exited with $r\n" if $r;
- $result = $r;
- }
- };
- if ($@) {
- $result = 2;
- print STDERR "$@\n";
- }
-
- chdir '/';
- system('rm','-rf',$tmp);
- rmdir $tmp;
- $result;
-}
-
-sub build_failed ($$$$$)
-{
- my ($git_dir, $ref, $old, $new, $msg) = @_;
-
- $git_dir =~ m,/([^/]+)$,;
- my $repo_name = $1;
- $ref =~ s,^refs/(heads|tags)/,,;
-
- my %authors;
- my $shortlog;
- my $revstr;
- {
- local $ENV{GIT_DIR} = $git_dir;
- my @revs = ($new);
- push @revs, '--not', @$old if @$old;
- open LOG,'-|','git','rev-list','--pretty=raw',@revs;
- while (<LOG>) {
- if (s/^(author|committer) //) {
- chomp;
- s/>.*$/>/;
- $authors{$_} = 1 unless nocc_author $_;
- }
- }
- close LOG;
- open LOG,'-|','git','shortlog',@revs;
- $shortlog .= $_ while <LOG>;
- close LOG;
- $revstr = join(' ', @revs);
- }
-
- my @to = sort keys %authors;
- unless (@to) {
- print STDERR "error: No authors in $revstr\n";
- return;
- }
-
- my $subject = "[$repo_name] $ref : Build Failed";
- my $body = <<EOF;
-Project: $git_dir
-Branch: $ref
-Commits: $revstr
-
-$shortlog
-Build Output:
---------------------------------------------------------------
-$msg
-EOF
- send_email($subject, $body, \@to);
-}
-
-sub run_build ($$$$)
-{
- my ($git_dir, $ref, $old, $new) = @_;
-
- if ($debug_flag) {
- my @revs = ($new);
- push @revs, '--not', @$old if @$old;
- print "BUILDING $git_dir\n";
- print " BRANCH: $ref\n";
- print " COMMITS: ", join(' ', @revs), "\n";
- }
-
- local(*R, *W);
- pipe R, W or die "cannot pipe builder: $!";
-
- my $builder = fork();
- if (!defined $builder) {
- die "cannot fork builder: $!";
- } elsif (0 == $builder) {
- close R;
- close STDIN;open(STDIN, '/dev/null');
- open(STDOUT, '>&W');
- open(STDERR, '>&W');
- exit do_build $git_dir, $new;
- } else {
- close W;
- my $out = '';
- $out .= $_ while <R>;
- close R;
- waitpid $builder, 0;
- build_failed $git_dir, $ref, $old, $new, $out if $?;
- }
-
- print "DONE\n\n" if $debug_flag;
-}
-
-sub daemon_loop ()
-{
- my $run = 1;
- my $stop_sub = sub {$run = 0};
- $SIG{HUP} = $stop_sub;
- $SIG{INT} = $stop_sub;
- $SIG{TERM} = $stop_sub;
-
- mkdir $tmpdir, 0755;
- my $pidfile = File::Spec->catfile($tmpdir, "cidaemon.pid");
- open(O, ">$pidfile"); print O "$$\n"; close O;
-
- while ($run) {
- my $ent = pop_queue;
- if ($ent) {
- my ($git_dir, $ref, $old, $new) = @$ent;
-
- $ent = $recent{$git_dir};
- $recent{$git_dir} = $ent = [[], {}] unless $ent;
- my ($rec_arr, $rec_hash) = @$ent;
- next if $rec_hash->{$new}++;
- while (@$rec_arr >= $recent_size) {
- my $to_kill = shift @$rec_arr;
- delete $rec_hash->{$to_kill};
- }
- push @$rec_arr, $new;
-
- run_build $git_dir, $ref, $old, $new;
- } else {
- sleep $scan_delay;
- }
- }
-
- unlink $pidfile;
-}
-
-$debug_flag = 0;
-GetOptions(
- 'debug|d' => \$debug_flag,
- 'smtp-user=s' => \$ex_user,
-) or die "usage: $0 [--debug] [--smtp-user=user]\n";
-
-$ex_pass = input_noecho("$ex_user SMTP password: ")
- if ($ex_user && !$ex_pass);
-
-if ($debug_flag) {
- daemon_loop;
- exit 0;
-}
-
-my $daemon = fork();
-if (!defined $daemon) {
- die "cannot fork daemon: $!";
-} elsif (0 == $daemon) {
- close STDIN;open(STDIN, '/dev/null');
- close STDOUT;open(STDOUT, '>/dev/null');
- close STDERR;open(STDERR, '>/dev/null');
- daemon_loop;
- exit 0;
-} else {
- print "Daemon $daemon running in the background.\n";
-}
diff --git a/contrib/continuous/post-receive-cinotify b/contrib/continuous/post-receive-cinotify
deleted file mode 100644
index b8f5a60..0000000
--- a/contrib/continuous/post-receive-cinotify
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/perl
-#
-# A hook that notifies its companion cidaemon through a simple
-# queue file that a ref has been updated via a push (actually
-# by a receive-pack running on the server).
-#
-# See cidaemon for per-repository configuration details.
-#
-# To use this hook, add it as the post-receive hook, make it
-# executable, and set its configuration options.
-#
-
-local $ENV{PATH} = '/opt/git/bin';
-
-use strict;
-use warnings;
-use File::Spec;
-use Storable qw(retrieve nstore);
-use Fcntl ':flock';
-
-my $git_dir = File::Spec->rel2abs($ENV{GIT_DIR});
-my $queue_name = `git config --get builder.queue`;chop $queue_name;
-$queue_name =~ m,^([^\s]+)$,; $queue_name = $1; # untaint
-unless ($queue_name) {
- 1 while <STDIN>;
- print STDERR "\nerror: builder.queue not set. Not enqueing.\n\n";
- exit;
-}
-my $queue_lock = "$queue_name.lock";
-
-my @skip;
-open S, "git config --get-all builder.skip|";
-while (<S>) {
- chop;
- push @skip, $_;
-}
-close S;
-
-my @new_branch_base;
-open S, "git config --get-all builder.newBranchBase|";
-while (<S>) {
- chop;
- push @new_branch_base, $_;
-}
-close S;
-
-sub skip ($)
-{
- local $_ = shift;
- foreach my $p (@skip) {
- return 1 if /^$p/;
- }
- 0;
-}
-
-open LOCK, ">$queue_lock" or die "Can't open $queue_lock: $!";
-flock LOCK, LOCK_EX;
-
-my $queue = -f $queue_name ? retrieve $queue_name : [];
-my %existing;
-foreach my $r (@$queue) {
- my ($gd, $ref) = @$r;
- $existing{$gd}{$ref} = $r;
-}
-
-my @new_branch_commits;
-my $loaded_new_branch_commits = 0;
-
-while (<STDIN>) {
- chop;
- my ($old, $new, $ref) = split / /, $_, 3;
-
- next if $old eq $new;
- next if $new =~ /^0{40}$/;
- next if skip $ref;
-
- my $r = $existing{$git_dir}{$ref};
- if ($r) {
- $r->[3] = $new;
- } else {
- if ($old =~ /^0{40}$/) {
- if (!$loaded_new_branch_commits && @new_branch_base) {
- open M,'-|','git','show-ref',@new_branch_base;
- while (<M>) {
- ($_) = split / /, $_;
- push @new_branch_commits, $_;
- }
- close M;
- $loaded_new_branch_commits = 1;
- }
- $old = [@new_branch_commits];
- } else {
- $old = [$old];
- }
-
- $r = [$git_dir, $ref, $old, $new];
- $existing{$git_dir}{$ref} = $r;
- push @$queue, $r;
- }
-}
-nstore $queue, $queue_name;
-
-flock LOCK, LOCK_UN;
-close LOCK;
diff --git a/contrib/credential/netrc/Makefile b/contrib/credential/netrc/Makefile
new file mode 100644
index 0000000..51b7613
--- /dev/null
+++ b/contrib/credential/netrc/Makefile
@@ -0,0 +1,5 @@
+test:
+ ./test.pl
+
+testverbose:
+ ./test.pl -d -v
diff --git a/contrib/credential/netrc/git-credential-netrc b/contrib/credential/netrc/git-credential-netrc
new file mode 100755
index 0000000..6c51c43
--- /dev/null
+++ b/contrib/credential/netrc/git-credential-netrc
@@ -0,0 +1,421 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+use File::Basename;
+
+my $VERSION = "0.1";
+
+my %options = (
+ help => 0,
+ debug => 0,
+ verbose => 0,
+ insecure => 0,
+ file => [],
+
+ # identical token maps, e.g. host -> host, will be inserted later
+ tmap => {
+ port => 'protocol',
+ machine => 'host',
+ path => 'path',
+ login => 'username',
+ user => 'username',
+ password => 'password',
+ }
+ );
+
+# Map each credential protocol token to itself on the netrc side.
+foreach (values %{$options{tmap}}) {
+ $options{tmap}->{$_} = $_;
+}
+
+# Now, $options{tmap} has a mapping from the netrc format to the Git credential
+# helper protocol.
+
+# Next, we build the reverse token map.
+
+# When $rmap{foo} contains 'bar', that means that what the Git credential helper
+# protocol calls 'bar' is found as 'foo' in the netrc/authinfo file. Keys in
+# %rmap are what we expect to read from the netrc/authinfo file.
+
+my %rmap;
+foreach my $k (keys %{$options{tmap}}) {
+ push @{$rmap{$options{tmap}->{$k}}}, $k;
+}
+
+Getopt::Long::Configure("bundling");
+
+# TODO: maybe allow the token map $options{tmap} to be configurable.
+GetOptions(\%options,
+ "help|h",
+ "debug|d",
+ "insecure|k",
+ "verbose|v",
+ "file|f=s@",
+ );
+
+if ($options{help}) {
+ my $shortname = basename($0);
+ $shortname =~ s/git-credential-//;
+
+ print <<EOHIPPUS;
+
+$0 [-f AUTHFILE1] [-f AUTHFILEN] [-d] [-v] [-k] get
+
+Version $VERSION by tzz\@lifelogs.com. License: BSD.
+
+Options:
+
+ -f|--file AUTHFILE : specify netrc-style files. Files with the .gpg extension
+ will be decrypted by GPG before parsing. Multiple -f
+ arguments are OK. They are processed in order, and the
+ first matching entry found is returned via the credential
+ helper protocol (see below).
+
+ When no -f option is given, .authinfo.gpg, .netrc.gpg,
+ .authinfo, and .netrc files in your home directory are used
+ in this order.
+
+ -k|--insecure : ignore bad file ownership or permissions
+
+ -d|--debug : turn on debugging (developer info)
+
+ -v|--verbose : be more verbose (show files and information found)
+
+To enable this credential helper:
+
+ git config credential.helper '$shortname -f AUTHFILE1 -f AUTHFILE2'
+
+(Note that Git will prepend "git-credential-" to the helper name and look for it
+in the path.)
+
+...and if you want lots of debugging info:
+
+ git config credential.helper '$shortname -f AUTHFILE -d'
+
+...or to see the files opened and data found:
+
+ git config credential.helper '$shortname -f AUTHFILE -v'
+
+Only "get" mode is supported by this credential helper. It opens every AUTHFILE
+and looks for the first entry that matches the requested search criteria:
+
+ 'port|protocol':
+ The protocol that will be used (e.g., https). (protocol=X)
+
+ 'machine|host':
+ The remote hostname for a network credential. (host=X)
+
+ 'path':
+ The path with which the credential will be used. (path=X)
+
+ 'login|user|username':
+ The credential’s username, if we already have one. (username=X)
+
+Thus, when we get this query on STDIN:
+
+host=github.com
+protocol=https
+username=tzz
+
+this credential helper will look for the first entry in every AUTHFILE that
+matches
+
+machine github.com port https login tzz
+
+OR
+
+machine github.com protocol https login tzz
+
+OR... etc. acceptable tokens as listed above. Any unknown tokens are
+simply ignored.
+
+Then, the helper will print out whatever tokens it got from the entry, including
+"password" tokens, mapping back to Git's helper protocol; e.g. "port" is mapped
+back to "protocol". Any redundant entry tokens (part of the original query) are
+skipped.
+
+Again, note that only the first matching entry from all the AUTHFILEs, processed
+in the sequence given on the command line, is used.
+
+Netrc/authinfo tokens can be quoted as 'STRING' or "STRING".
+
+No caching is performed by this credential helper.
+
+EOHIPPUS
+
+ exit 0;
+}
+
+my $mode = shift @ARGV;
+
+# Credentials must get a parameter, so die if it's missing.
+die "Syntax: $0 [-f AUTHFILE1] [-f AUTHFILEN] [-d] get" unless defined $mode;
+
+# Only support 'get' mode; with any other unsupported ones we just exit.
+exit 0 unless $mode eq 'get';
+
+my $files = $options{file};
+
+# if no files were given, use a predefined list.
+# note that .gpg files come first
+unless (scalar @$files) {
+ my @candidates = qw[
+ ~/.authinfo.gpg
+ ~/.netrc.gpg
+ ~/.authinfo
+ ~/.netrc
+ ];
+
+ $files = $options{file} = [ map { glob $_ } @candidates ];
+}
+
+my $query = read_credential_data_from_stdin();
+
+FILE:
+foreach my $file (@$files) {
+ my $gpgmode = $file =~ m/\.gpg$/;
+ unless (-r $file) {
+ log_verbose("Unable to read $file; skipping it");
+ next FILE;
+ }
+
+ # the following check is copied from Net::Netrc, for non-GPG files
+ # OS/2 and Win32 do not handle stat in a way compatible with this check :-(
+ unless ($gpgmode || $options{insecure} ||
+ $^O eq 'os2'
+ || $^O eq 'MSWin32'
+ || $^O eq 'MacOS'
+ || $^O =~ /^cygwin/) {
+ my @stat = stat($file);
+
+ if (@stat) {
+ if ($stat[2] & 077) {
+ log_verbose("Insecure $file (mode=%04o); skipping it",
+ $stat[2] & 07777);
+ next FILE;
+ }
+
+ if ($stat[4] != $<) {
+ log_verbose("Not owner of $file; skipping it");
+ next FILE;
+ }
+ }
+ }
+
+ my @entries = load_netrc($file, $gpgmode);
+
+ unless (scalar @entries) {
+ if ($!) {
+ log_verbose("Unable to open $file: $!");
+ } else {
+ log_verbose("No netrc entries found in $file");
+ }
+
+ next FILE;
+ }
+
+ my $entry = find_netrc_entry($query, @entries);
+ if ($entry) {
+ print_credential_data($entry, $query);
+ # we're done!
+ last FILE;
+ }
+}
+
+exit 0;
+
+sub load_netrc {
+ my $file = shift @_;
+ my $gpgmode = shift @_;
+
+ my $io;
+ if ($gpgmode) {
+ my @cmd = (qw(gpg --decrypt), $file);
+ log_verbose("Using GPG to open $file: [@cmd]");
+ open $io, "-|", @cmd;
+ } else {
+ log_verbose("Opening $file...");
+ open $io, '<', $file;
+ }
+
+ # nothing to do if the open failed (we log the error later)
+ return unless $io;
+
+ # Net::Netrc does this, but the functionality is merged with the file
+ # detection logic, so we have to extract just the part we need
+ my @netrc_entries = net_netrc_loader($io);
+
+ # these entries will use the credential helper protocol token names
+ my @entries;
+
+ foreach my $nentry (@netrc_entries) {
+ my %entry;
+ my $num_port;
+
+ if (!defined $nentry->{machine}) {
+ next;
+ }
+ if (defined $nentry->{port} && $nentry->{port} =~ m/^\d+$/) {
+ $num_port = $nentry->{port};
+ delete $nentry->{port};
+ }
+
+ # create the new entry for the credential helper protocol
+ $entry{$options{tmap}->{$_}} = $nentry->{$_} foreach keys %$nentry;
+
+ # for "host X port Y" where Y is an integer (captured by
+ # $num_port above), set the host to "X:Y"
+ if (defined $entry{host} && defined $num_port) {
+ $entry{host} = join(':', $entry{host}, $num_port);
+ }
+
+ push @entries, \%entry;
+ }
+
+ return @entries;
+}
+
+sub net_netrc_loader {
+ my $fh = shift @_;
+ my @entries;
+ my ($mach, $macdef, $tok, @tok);
+
+ LINE:
+ while (<$fh>) {
+ undef $macdef if /\A\n\Z/;
+
+ if ($macdef) {
+ next LINE;
+ }
+
+ s/^\s*//;
+ chomp;
+
+ while (length && s/^("((?:[^"]+|\\.)*)"|((?:[^\\\s]+|\\.)*))\s*//) {
+ (my $tok = $+) =~ s/\\(.)/$1/g;
+ push(@tok, $tok);
+ }
+
+ TOKEN:
+ while (@tok) {
+ if ($tok[0] eq "default") {
+ shift(@tok);
+ $mach = { machine => undef };
+ next TOKEN;
+ }
+
+ $tok = shift(@tok);
+
+ if ($tok eq "machine") {
+ my $host = shift @tok;
+ $mach = { machine => $host };
+ push @entries, $mach;
+ } elsif (exists $options{tmap}->{$tok}) {
+ unless ($mach) {
+ log_debug("Skipping token $tok because no machine was given");
+ next TOKEN;
+ }
+
+ my $value = shift @tok;
+ unless (defined $value) {
+ log_debug("Token $tok had no value, skipping it.");
+ next TOKEN;
+ }
+
+ # Following line added by rmerrell to remove '/' escape char in .netrc
+ $value =~ s/\/\\/\\/g;
+ $mach->{$tok} = $value;
+ } elsif ($tok eq "macdef") { # we ignore macros
+ next TOKEN unless $mach;
+ my $value = shift @tok;
+ $macdef = 1;
+ }
+ }
+ }
+
+ return @entries;
+}
+
+sub read_credential_data_from_stdin {
+ # the query: start with every token with no value
+ my %q = map { $_ => undef } values(%{$options{tmap}});
+
+ while (<STDIN>) {
+ next unless m/^([^=]+)=(.+)/;
+
+ my ($token, $value) = ($1, $2);
+ die "Unknown search token $token" unless exists $q{$token};
+ $q{$token} = $value;
+ log_debug("We were given search token $token and value $value");
+ }
+
+ foreach (sort keys %q) {
+ log_debug("Searching for %s = %s", $_, $q{$_} || '(any value)');
+ }
+
+ return \%q;
+}
+
+# takes the search tokens and then a list of entries
+# each entry is a hash reference
+sub find_netrc_entry {
+ my $query = shift @_;
+
+ ENTRY:
+ foreach my $entry (@_)
+ {
+ my $entry_text = join ', ', map { "$_=$entry->{$_}" } keys %$entry;
+ foreach my $check (sort keys %$query) {
+ if (defined $query->{$check}) {
+ log_debug("compare %s [%s] to [%s] (entry: %s)",
+ $check,
+ $entry->{$check},
+ $query->{$check},
+ $entry_text);
+ unless ($query->{$check} eq $entry->{$check}) {
+ next ENTRY;
+ }
+ } else {
+ log_debug("OK: any value satisfies check $check");
+ }
+ }
+
+ return $entry;
+ }
+
+ # nothing was found
+ return;
+}
+
+sub print_credential_data {
+ my $entry = shift @_;
+ my $query = shift @_;
+
+ log_debug("entry has passed all the search checks");
+ TOKEN:
+ foreach my $git_token (sort keys %$entry) {
+ log_debug("looking for useful token $git_token");
+ # don't print unknown (to the credential helper protocol) tokens
+ next TOKEN unless exists $query->{$git_token};
+
+ # don't print things asked in the query (the entry matches them)
+ next TOKEN if defined $query->{$git_token};
+
+ log_debug("FOUND: $git_token=$entry->{$git_token}");
+ printf "%s=%s\n", $git_token, $entry->{$git_token};
+ }
+}
+sub log_verbose {
+ return unless $options{verbose};
+ printf STDERR @_;
+ printf STDERR "\n";
+}
+
+sub log_debug {
+ return unless $options{debug};
+ printf STDERR @_;
+ printf STDERR "\n";
+}
diff --git a/contrib/credential/netrc/test.netrc b/contrib/credential/netrc/test.netrc
new file mode 100644
index 0000000..ba119a9
--- /dev/null
+++ b/contrib/credential/netrc/test.netrc
@@ -0,0 +1,13 @@
+machine imap login tzz@lifelogs.com port imaps password letmeknow
+machine imap login bob port imaps password bobwillknow
+
+# comment test
+
+machine imap2 login tzz port 1099 password tzzknow
+machine imap2 login bob password bobwillknow
+
+# another command
+
+machine github.com
+ multilinetoken anothervalue
+ login carol password carolknows
diff --git a/contrib/credential/netrc/test.pl b/contrib/credential/netrc/test.pl
new file mode 100755
index 0000000..169b646
--- /dev/null
+++ b/contrib/credential/netrc/test.pl
@@ -0,0 +1,106 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+use Test;
+use IPC::Open2;
+
+BEGIN { plan tests => 15 }
+
+my @global_credential_args = @ARGV;
+my $netrc = './test.netrc';
+print "# Testing insecure file, nothing should be found\n";
+chmod 0644, $netrc;
+my $cred = run_credential(['-f', $netrc, 'get'],
+ { host => 'github.com' });
+
+ok(scalar keys %$cred, 0, "Got 0 keys from insecure file");
+
+print "# Testing missing file, nothing should be found\n";
+chmod 0644, $netrc;
+$cred = run_credential(['-f', '///nosuchfile///', 'get'],
+ { host => 'github.com' });
+
+ok(scalar keys %$cred, 0, "Got 0 keys from missing file");
+
+chmod 0600, $netrc;
+
+print "# Testing with invalid data\n";
+$cred = run_credential(['-f', $netrc, 'get'],
+ "bad data");
+ok(scalar keys %$cred, 4, "Got first found keys with bad data");
+
+print "# Testing netrc file for a missing corovamilkbar entry\n";
+$cred = run_credential(['-f', $netrc, 'get'],
+ { host => 'corovamilkbar' });
+
+ok(scalar keys %$cred, 0, "Got no corovamilkbar keys");
+
+print "# Testing netrc file for a github.com entry\n";
+$cred = run_credential(['-f', $netrc, 'get'],
+ { host => 'github.com' });
+
+ok(scalar keys %$cred, 2, "Got 2 Github keys");
+
+ok($cred->{password}, 'carolknows', "Got correct Github password");
+ok($cred->{username}, 'carol', "Got correct Github username");
+
+print "# Testing netrc file for a username-specific entry\n";
+$cred = run_credential(['-f', $netrc, 'get'],
+ { host => 'imap', username => 'bob' });
+
+ok(scalar keys %$cred, 2, "Got 2 username-specific keys");
+
+ok($cred->{password}, 'bobwillknow', "Got correct user-specific password");
+ok($cred->{protocol}, 'imaps', "Got correct user-specific protocol");
+
+print "# Testing netrc file for a host:port-specific entry\n";
+$cred = run_credential(['-f', $netrc, 'get'],
+ { host => 'imap2:1099' });
+
+ok(scalar keys %$cred, 2, "Got 2 host:port-specific keys");
+
+ok($cred->{password}, 'tzzknow', "Got correct host:port-specific password");
+ok($cred->{username}, 'tzz', "Got correct host:port-specific username");
+
+print "# Testing netrc file that 'host:port kills host' entry\n";
+$cred = run_credential(['-f', $netrc, 'get'],
+ { host => 'imap2' });
+
+ok(scalar keys %$cred, 2, "Got 2 'host:port kills host' keys");
+
+ok($cred->{password}, 'bobwillknow', "Got correct 'host:port kills host' password");
+ok($cred->{username}, 'bob', "Got correct 'host:port kills host' username");
+
+sub run_credential
+{
+ my $args = shift @_;
+ my $data = shift @_;
+ my $pid = open2(my $chld_out, my $chld_in,
+ './git-credential-netrc', @global_credential_args,
+ @$args);
+
+ die "Couldn't open pipe to netrc credential helper: $!" unless $pid;
+
+ if (ref $data eq 'HASH')
+ {
+ print $chld_in "$_=$data->{$_}\n" foreach sort keys %$data;
+ }
+ else
+ {
+ print $chld_in "$data\n";
+ }
+
+ close $chld_in;
+ my %ret;
+
+ while (<$chld_out>)
+ {
+ chomp;
+ next unless m/^([^=]+)=(.+)/;
+
+ $ret{$1} = $2;
+ }
+
+ return \%ret;
+}
diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
index 3940202..bcd3f57 100644
--- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c
+++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
@@ -127,10 +127,20 @@ static void read_credential(void)
*v++ = '\0';
if (!strcmp(buf, "protocol")) {
- if (!strcmp(v, "https"))
+ if (!strcmp(v, "imap"))
+ protocol = kSecProtocolTypeIMAP;
+ else if (!strcmp(v, "imaps"))
+ protocol = kSecProtocolTypeIMAPS;
+ else if (!strcmp(v, "ftp"))
+ protocol = kSecProtocolTypeFTP;
+ else if (!strcmp(v, "ftps"))
+ protocol = kSecProtocolTypeFTPS;
+ else if (!strcmp(v, "https"))
protocol = kSecProtocolTypeHTTPS;
else if (!strcmp(v, "http"))
protocol = kSecProtocolTypeHTTP;
+ else if (!strcmp(v, "smtp"))
+ protocol = kSecProtocolTypeSMTP;
else /* we don't yet handle other protocols */
exit(0);
}
diff --git a/contrib/examples/git-log.sh b/contrib/examples/git-log.sh
new file mode 100755
index 0000000..c2ea71c
--- /dev/null
+++ b/contrib/examples/git-log.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+#
+
+USAGE='[--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [git-rev-list options]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
+revs=$(git-rev-parse --revs-only --no-flags --default HEAD "$@") || exit
+[ "$revs" ] || {
+ die "No HEAD ref"
+}
+git-rev-list --pretty $(git-rev-parse --default HEAD "$@") |
+LESS=-S ${PAGER:-less}
diff --git a/contrib/examples/git-whatchanged.sh b/contrib/examples/git-whatchanged.sh
new file mode 100755
index 0000000..1fb9feb
--- /dev/null
+++ b/contrib/examples/git-whatchanged.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+USAGE='[-p] [--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [-m] [git-diff-tree options] [git-rev-list options]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
+diff_tree_flags=$(git-rev-parse --sq --no-revs --flags "$@") || exit
+case "$0" in
+*whatchanged)
+ count=
+ test -z "$diff_tree_flags" &&
+ diff_tree_flags=$(git-repo-config --get whatchanged.difftree)
+ diff_tree_default_flags='-c -M --abbrev' ;;
+*show)
+ count=-n1
+ test -z "$diff_tree_flags" &&
+ diff_tree_flags=$(git-repo-config --get show.difftree)
+ diff_tree_default_flags='--cc --always' ;;
+esac
+test -z "$diff_tree_flags" &&
+ diff_tree_flags="$diff_tree_default_flags"
+
+rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") &&
+diff_tree_args=$(git-rev-parse --sq --no-revs --no-flags "$@") &&
+
+eval "git-rev-list $count $rev_list_args" |
+eval "git-diff-tree --stdin --pretty -r $diff_tree_flags $diff_tree_args" |
+LESS="$LESS -S" ${PAGER:-less}
diff --git a/contrib/hg-to-git/hg-to-git.py b/contrib/hg-to-git/hg-to-git.py
index 232625a..60dec86 100755
--- a/contrib/hg-to-git/hg-to-git.py
+++ b/contrib/hg-to-git/hg-to-git.py
@@ -225,7 +225,7 @@ for cset in range(int(tip) + 1):
os.system('git ls-files -x .hg --deleted | git update-index --remove --stdin')
# commit
- os.system(getgitenv(user, date) + 'git commit --allow-empty -a -F %s' % filecomment)
+ os.system(getgitenv(user, date) + 'git commit --allow-empty --allow-empty-message -a -F %s' % filecomment)
os.unlink(filecomment)
# tag
diff --git a/contrib/hooks/multimail/README b/contrib/hooks/multimail/README
new file mode 100644
index 0000000..9904396
--- /dev/null
+++ b/contrib/hooks/multimail/README
@@ -0,0 +1,486 @@
+ git-multimail
+ =============
+
+git-multimail is a tool for sending notification emails on pushes to a
+Git repository. It includes a Python module called git_multimail.py,
+which can either be used as a hook script directly or can be imported
+as a Python module into another script.
+
+git-multimail is derived from the Git project's old
+contrib/hooks/post-receive-email, and is mostly compatible with that
+script. See README.migrate-from-post-receive-email for details about
+the differences and for how to migrate from post-receive-email to
+git-multimail.
+
+git-multimail, like the rest of the Git project, is licensed under
+GPLv2 (see the COPYING file for details).
+
+Please note: although, as a convenience, git-multimail may be
+distributed along with the main Git project, development of
+git-multimail takes place in its own, separate project. See section
+"Getting involved" below for more information.
+
+
+By default, for each push received by the repository, git-multimail:
+
+1. Outputs one email summarizing each reference that was changed.
+ These "reference change" (called "refchange" below) emails describe
+ the nature of the change (e.g., was the reference created, deleted,
+ fast-forwarded, etc.) and include a one-line summary of each commit
+ that was added to the reference.
+
+2. Outputs one email for each new commit that was introduced by the
+ reference change. These "commit" emails include a list of the
+ files changed by the commit, followed by the diffs of files
+ modified by the commit. The commit emails are threaded to the
+ corresponding reference change email via "In-Reply-To". This style
+ (similar to the "git format-patch" style used on the Git mailing
+ list) makes it easy to scan through the emails, jump to patches
+ that need further attention, and write comments about specific
+ commits. Commits are handled in reverse topological order (i.e.,
+ parents shown before children). For example,
+
+ [git] branch master updated
+ + [git] 01/08: doc: fix xref link from api docs to manual pages
+ + [git] 02/08: api-credentials.txt: show the big picture first
+ + [git] 03/08: api-credentials.txt: mention credential.helper explicitly
+ + [git] 04/08: api-credentials.txt: add "see also" section
+ + [git] 05/08: t3510 (cherry-pick-sequence): add missing '&&'
+ + [git] 06/08: Merge branch 'rr/maint-t3510-cascade-fix'
+ + [git] 07/08: Merge branch 'mm/api-credentials-doc'
+ + [git] 08/08: Git 1.7.11-rc2
+
+ Each commit appears in exactly one commit email, the first time
+ that it is pushed to the repository. If a commit is later merged
+ into another branch, then a one-line summary of the commit is
+ included in the reference change email (as usual), but no
+ additional commit email is generated.
+
+ By default, reference change emails have their "Reply-To" field set
+ to the person who pushed the change, and commit emails have their
+ "Reply-To" field set to the author of the commit.
+
+3. Output one "announce" mail for each new annotated tag, including
+ information about the tag and optionally a shortlog describing the
+ changes since the previous tag. Such emails might be useful if you
+ use annotated tags to mark releases of your project.
+
+
+Requirements
+------------
+
+* Python 2.x, version 2.4 or later. No non-standard Python modules
+ are required. git-multimail does *not* currently work with Python
+ 3.x.
+
+ The example scripts invoke Python using the following shebang line
+ (following PEP 394 [1]):
+
+ #! /usr/bin/env python2
+
+ If your system's Python2 interpreter is not in your PATH or is not
+ called "python2", you can change the lines accordingly. Or you can
+ invoke the Python interpreter explicitly, for example via a tiny
+ shell script like
+
+ #! /bin/sh
+ /usr/local/bin/python /path/to/git_multimail.py "$@"
+
+* The "git" command must be in your PATH. git-multimail is known to
+ work with Git versions back to 1.7.1. (Earlier versions have not
+ been tested; if you do so, please report your results.)
+
+* To send emails using the default configuration, a standard sendmail
+ program must be located at '/usr/sbin/sendmail' and configured
+ correctly to send emails. If this is not the case, see the
+ multimailhook.mailer configuration variable below for how to
+ configure git-multimail to send emails via an SMTP server.
+
+
+Invocation
+----------
+
+git_multimail.py is designed to be used as a "post-receive" hook in a
+Git repository (see githooks(5)). Link or copy it to
+$GIT_DIR/hooks/post-receive within the repository for which email
+notifications are desired. Usually it should be installed on the
+central repository for a project, to which all commits are eventually
+pushed.
+
+For use on pre-v1.5.1 Git servers, git_multimail.py can also work as
+an "update" hook, taking its arguments on the command line. To use
+this script in this manner, link or copy it to $GIT_DIR/hooks/update.
+Please note that the script is not completely reliable in this mode
+[2].
+
+Alternatively, git_multimail.py can be imported as a Python module
+into your own Python post-receive script. This method is a bit more
+work, but allows the behavior of the hook to be customized using
+arbitrary Python code. For example, you can use a custom environment
+(perhaps inheriting from GenericEnvironment or GitoliteEnvironment) to
+
+* change how the user who did the push is determined
+
+* read users' email addresses from an LDAP server or from a database
+
+* decide which users should be notified about which commits based on
+ the contents of the commits (e.g., for users who want to be notified
+ only about changes affecting particular files or subdirectories)
+
+Or you can change how emails are sent by writing your own Mailer
+class. The "post-receive" script in this directory demonstrates how
+to use git_multimail.py as a Python module. (If you make interesting
+changes of this type, please consider sharing them with the
+community.)
+
+
+Configuration
+-------------
+
+By default, git-multimail mostly takes its configuration from the
+following "git config" settings:
+
+multimailhook.environment
+
+ This describes the general environment of the repository.
+ Currently supported values:
+
+ "generic" -- the username of the pusher is read from $USER and the
+ repository name is derived from the repository's path.
+
+ "gitolite" -- the username of the pusher is read from $GL_USER and
+ the repository name from $GL_REPO.
+
+ If neither of these environments is suitable for your setup, then
+ you can implement a Python class that inherits from Environment
+ and instantiate it via a script that looks like the example
+ post-receive script.
+
+ The environment value can be specified on the command line using
+ the --environment option. If it is not specified on the command
+ line or by multimailhook.environment, then it defaults to
+ "gitolite" if the environment contains variables $GL_USER and
+ $GL_REPO; otherwise "generic".
+
+multimailhook.repoName
+
+ A short name of this Git repository, to be used in various places
+ in the notification email text. The default is to use $GL_REPO
+ for gitolite repositories, or otherwise to derive this value from
+ the repository path name.
+
+multimailhook.mailinglist
+
+ The list of email addresses to which notification emails should be
+ sent, as RFC 2822 email addresses separated by commas. This
+ configuration option can be multivalued. Leave it unset or set it
+ to the empty string to not send emails by default. The next few
+ settings can be used to configure specific address lists for
+ specific types of notification email.
+
+multimailhook.refchangeList
+
+ The list of email addresses to which summary emails about
+ reference changes should be sent, as RFC 2822 email addresses
+ separated by commas. This configuration option can be
+ multivalued. The default is the value in
+ multimailhook.mailinglist. Set this value to the empty string to
+ prevent reference change emails from being sent.
+
+multimailhook.announceList
+
+ The list of email addresses to which emails about new annotated
+ tags should be sent, as RFC 2822 email addresses separated by
+ commas. This configuration option can be multivalued. The
+ default is the value in multimailhook.refchangelist or
+ multimailhook.mailinglist. Set this value to the empty string to
+ prevent annotated tag announcement emails from being sent.
+
+multimailhook.commitList
+
+ The list of email addresses to which emails about individual new
+ commits should be sent, as RFC 2822 email addresses separated by
+ commas. This configuration option can be multivalued. The
+ default is the value in multimailhook.mailinglist. Set this value
+ to the empty string to prevent notification emails about
+ individual commits from being sent.
+
+multimailhook.announceShortlog
+
+ If this option is set to true, then emails about changes to
+ annotated tags include a shortlog of changes since the previous
+ tag. This can be useful if the annotated tags represent releases;
+ then the shortlog will be a kind of rough summary of what has
+ happened since the last release. But if your tagging policy is
+ not so straightforward, then the shortlog might be confusing
+ rather than useful. Default is false.
+
+multimailhook.refchangeShowLog
+
+ If this option is set to true, then summary emails about reference
+ changes will include a detailed log of the added commits in
+ addition to the one line summary. The log is generated by running
+ "git log" with the options specified in multimailhook.logOpts.
+ Default is false.
+
+multimailhook.mailer
+
+ This option changes the way emails are sent. Accepted values are:
+
+ - sendmail (the default): use the command /usr/sbin/sendmail or
+ /usr/lib/sendmail (or sendmailCommand, if configured). This
+ mode can be further customized via the following options:
+
+ multimailhook.sendmailCommand
+
+ The command used by mailer "sendmail" to send emails. Shell
+ quoting is allowed in the value of this setting, but remember that
+ Git requires double-quotes to be escaped; e.g.,
+
+ git config multimailhook.sendmailcommand '/usr/sbin/sendmail -t -F \"Git Repo\"'
+
+ Default is '/usr/sbin/sendmail -t' or '/usr/lib/sendmail
+ -t' (depending on which file is present and executable).
+
+ multimailhook.envelopeSender
+
+ If set then pass this value to sendmail via the -f option to set
+ the envelope sender address.
+
+ - smtp: use Python's smtplib. This is useful when the sendmail
+ command is not available on the system. This mode can be
+ further customized via the following options:
+
+ multimailhook.smtpServer
+
+ The name of the SMTP server to connect to. The value can
+ also include a colon and a port number; e.g.,
+ "mail.example.com:25". Default is 'localhost' using port
+ 25.
+
+ multimailhook.envelopeSender
+
+ The sender address to be passed to the SMTP server. If
+ unset, then the value of multimailhook.from is used.
+
+multimailhook.from
+
+ If set then use this value in the From: field of generated emails.
+ If unset, then use the repository's user configuration (user.name
+ and user.email). If user.email is also unset, then use
+ multimailhook.envelopeSender.
+
+multimailhook.administrator
+
+ The name and/or email address of the administrator of the Git
+ repository; used in FOOTER_TEMPLATE. Default is
+ multimailhook.envelopesender if it is set; otherwise a generic
+ string is used.
+
+multimailhook.emailPrefix
+
+ All emails have this string prepended to their subjects, to aid
+ email filtering (though filtering based on the X-Git-* email
+ headers is probably more robust). Default is the short name of
+ the repository in square brackets; e.g., "[myrepo]".
+
+multimailhook.emailMaxLines
+
+ The maximum number of lines that should be included in the body of
+ a generated email. If not specified, there is no limit. Lines
+ beyond the limit are suppressed and counted, and a final line is
+ added indicating the number of suppressed lines.
+
+multimailhook.emailMaxLineLength
+
+ The maximum length of a line in the email body. Lines longer than
+ this limit are truncated to this length with a trailing " [...]"
+ added to indicate the missing text. The default is 500, because
+ (a) diffs with longer lines are probably from binary files, for
+ which a diff is useless, and (b) even if a text file has such long
+ lines, the diffs are probably unreadable anyway. To disable line
+ truncation, set this option to 0.
+
+multimailhook.maxCommitEmails
+
+ The maximum number of commit emails to send for a given change.
+ When the number of patches is larger that this value, only the
+ summary refchange email is sent. This can avoid accidental
+ mailbombing, for example on an initial push. To disable commit
+ emails limit, set this option to 0. The default is 500.
+
+multimailhook.emailStrictUTF8
+
+ If this boolean option is set to "true", then the main part of the
+ email body is forced to be valid UTF-8. Any characters that are
+ not valid UTF-8 are converted to the Unicode replacement
+ character, U+FFFD. The default is "true".
+
+multimailhook.diffOpts
+
+ Options passed to "git diff-tree" when generating the summary
+ information for ReferenceChange emails. Default is "--stat
+ --summary --find-copies-harder". Add -p to those options to
+ include a unified diff of changes in addition to the usual summary
+ output. Shell quoting is allowed; see multimailhook.logOpts for
+ details.
+
+multimailhook.logOpts
+
+ Options passed to "git log" to generate additional info for
+ reference change emails (used only if refchangeShowLog is set).
+ For example, adding --graph will show the graph of revisions, -p
+ will show the complete diff, etc. The default is empty.
+
+ Shell quoting is allowed; for example, a log format that contains
+ spaces can be specified using something like:
+
+ git config multimailhook.logopts '--pretty=format:"%h %aN <%aE>%n%s%n%n%b%n"'
+
+ If you want to set this by editing your configuration file
+ directly, remember that Git requires double-quotes to be escaped
+ (see git-config(1) for more information):
+
+ [multimailhook]
+ logopts = --pretty=format:\"%h %aN <%aE>%n%s%n%n%b%n\"
+
+multimailhook.emailDomain
+
+ Domain name appended to the username of the person doing the push
+ to convert it into an email address (via "%s@%s" % (username,
+ emaildomain)). More complicated schemes can be implemented by
+ overriding Environment and overriding its get_pusher_email()
+ method.
+
+multimailhook.replyTo
+multimailhook.replyToCommit
+multimailhook.replyToRefchange
+
+ Addresses to use in the Reply-To: field for commit emails
+ (replyToCommit) and refchange emails (replyToRefchange).
+ multimailhook.replyTo is used as default when replyToCommit or
+ replyToRefchange is not set. The value for these variables can be
+ either:
+
+ - An email address, which will be used directly.
+
+ - The value "pusher", in which case the pusher's address (if
+ available) will be used. This is the default for refchange
+ emails.
+
+ - The value "author" (meaningful only for replyToCommit), in which
+ case the commit author's address will be used. This is the
+ default for commit emails.
+
+ - The value "none", in which case the Reply-To: field will be
+ omitted.
+
+
+Email filtering aids
+--------------------
+
+All emails include extra headers to enable fine tuned filtering and
+give information for debugging. All emails include the headers
+"X-Git-Repo", "X-Git-Refname", and "X-Git-Reftype". ReferenceChange
+emails also include headers "X-Git-Oldrev" and "X-Git-Newrev";
+Revision emails also include header "X-Git-Rev".
+
+
+Customizing email contents
+--------------------------
+
+git-multimail mostly generates emails by expanding templates. The
+templates can be customized. To avoid the need to edit
+git_multimail.py directly, the preferred way to change the templates
+is to write a separate Python script that imports git_multimail.py as
+a module, then replaces the templates in place. See the provided
+post-receive script for an example of how this is done.
+
+
+Customizing git-multimail for your environment
+----------------------------------------------
+
+git-multimail is mostly customized via an "environment" that describes
+the local environment in which Git is running. Two types of
+environment are built in:
+
+* GenericEnvironment: a stand-alone Git repository.
+
+* GitoliteEnvironment: a Git repository that is managed by gitolite
+ [3]. For such repositories, the identity of the pusher is read from
+ environment variable $GL_USER, and the name of the repository is
+ read from $GL_REPO (if it is not overridden by
+ multimailhook.reponame).
+
+By default, git-multimail assumes GitoliteEnvironment if $GL_USER and
+$GL_REPO are set, and otherwise assumes GenericEnvironment.
+Alternatively, you can choose one of these two environments explicitly
+by setting a "multimailhook.environment" config setting (which can
+have the value "generic" or "gitolite") or by passing an --environment
+option to the script.
+
+If you need to customize the script in ways that are not supported by
+the existing environments, you can define your own environment class
+class using arbitrary Python code. To do so, you need to import
+git_multimail.py as a Python module, as demonstrated by the example
+post-receive script. Then implement your environment class; it should
+usually inherit from one of the existing Environment classes and
+possibly one or more of the EnvironmentMixin classes. Then set the
+"environment" variable to an instance of your own environment class
+and pass it to run_as_post_receive_hook().
+
+The standard environment classes, GenericEnvironment and
+GitoliteEnvironment, are in fact themselves put together out of a
+number of mixin classes, each of which handles one aspect of the
+customization. For the finest control over your configuration, you
+can specify exactly which mixin classes your own environment class
+should inherit from, and override individual methods (or even add your
+own mixin classes) to implement entirely new behaviors. If you
+implement any mixins that might be useful to other people, please
+consider sharing them with the community!
+
+
+Getting involved
+----------------
+
+git-multimail is an open-source project, built by volunteers. We
+would welcome your help!
+
+The current maintainer is Michael Haggerty <mhagger@alum.mit.edu>.
+
+General discussion of git-multimail takes place on the main Git
+mailing list,
+
+ git@vger.kernel.org
+
+Please CC emails regarding git-multimail to me so that I don't
+overlook them.
+
+The git-multimail project itself is currently hosted on GitHub:
+
+ https://github.com/mhagger/git-multimail
+
+We use the GitHub issue tracker to keep track of bugs and feature
+requests, and GitHub pull requests to exchange patches (though, if you
+prefer, you can send patches via the Git mailing list with cc to me).
+
+Please note that although a copy of git-multimail will probably be
+distributed in the "contrib" section of the main Git project,
+development takes place in the separate git-multimail repository on
+GitHub! (Whenever enough changes to git-multimail have accumulated, a
+new code-drop of git-multimail will be submitted for inclusion in the
+Git project.)
+
+
+Footnotes
+---------
+
+[1] http://www.python.org/dev/peps/pep-0394/
+
+[2] Because of the way information is passed to update hooks, the
+ script's method of determining whether a commit has already been
+ seen does not work when it is used as an "update" script. In
+ particular, no notification email will be generated for a new
+ commit that is added to multiple references in the same push.
+
+[3] https://github.com/sitaramc/gitolite
diff --git a/contrib/hooks/multimail/README.Git b/contrib/hooks/multimail/README.Git
new file mode 100644
index 0000000..9c2e66a
--- /dev/null
+++ b/contrib/hooks/multimail/README.Git
@@ -0,0 +1,15 @@
+This copy of git-multimail is distributed as part of the "contrib"
+section of the Git project as a convenience to Git users.
+git-multimail is developed as an independent project at the following
+website:
+
+ https://github.com/mhagger/git-multimail
+
+The version in this directory was obtained from the upstream project
+on 2013-07-14 and consists of the "git-multimail" subdirectory from
+revision
+
+ 1a5cb09c698a74d15a715a86b09ead5f56bf4b06
+
+Please see the README file in this directory for information about how
+to report bugs or contribute to git-multimail.
diff --git a/contrib/hooks/multimail/README.migrate-from-post-receive-email b/contrib/hooks/multimail/README.migrate-from-post-receive-email
new file mode 100644
index 0000000..1e6a976
--- /dev/null
+++ b/contrib/hooks/multimail/README.migrate-from-post-receive-email
@@ -0,0 +1,145 @@
+git-multimail is close to, but not exactly, a plug-in replacement for
+the old Git project script contrib/hooks/post-receive-email. This
+document describes the differences and explains how to configure
+git-multimail to get behavior closest to that of post-receive-email.
+
+If you are in a hurry
+=====================
+
+A script called migrate-mailhook-config is included with
+git-multimail. If you run this script within a Git repository that is
+configured to use post-receive-email, it will convert the
+configuration settings into the approximate equivalent settings for
+git-multimail. For more information, run
+
+ migrate-mailhook-config --help
+
+
+Configuration differences
+=========================
+
+* The names of the config options for git-multimail are in namespace
+ "multimailhook.*" instead of "hooks.*". (Editorial comment:
+ post-receive-email should never have used such a generic top-level
+ namespace.)
+
+* In emails about new annotated tags, post-receive-email includes a
+ shortlog of all changes since the previous annotated tag. To get
+ this behavior with git-multimail, you need to set
+ multimailhook.announceshortlog to true:
+
+ git config multimailhook.announceshortlog true
+
+* multimailhook.commitlist -- This is a new configuration variable.
+ Recipients listed here will receive a separate email for each new
+ commit. However, if this variable is *not* set, it defaults to the
+ value of multimailhook.mailinglist. Therefore, if you *don't* want
+ the members of multimailhook.mailinglist to receive one email per
+ commit, then set this value to the empty string:
+
+ git config multimailhook.commitlist ''
+
+* multimailhook.emailprefix -- If this value is not set, then the
+ subjects of generated emails are prefixed with the short name of the
+ repository enclosed in square brackets; e.g., "[myrepo]".
+ post-receive-email defaults to prefix "[SCM]" if this option is not
+ set. So if you were using the old default and want to retain it
+ (for example, to avoid having to change your email filters), set
+ this variable explicitly to the old value:
+
+ git config multimailhook.emailprefix "[SCM]"
+
+* The "multimailhook.showrev" configuration option is not supported.
+ Its main use is obsoleted by the one-email-per-commit feature of
+ git-multimail.
+
+
+Other differences
+=================
+
+This section describes other differences in the behavior of
+git-multimail vs. post-receive-email. For full details, please refer
+to the main README file:
+
+* One email per commit. For each reference change, the script first
+ outputs one email summarizing the reference change (including
+ one-line summaries of the new commits), then it outputs a separate
+ email for each new commit that was introduced, including patches.
+ These one-email-per-commit emails go to the addresses listed in
+ multimailhook.commitlist. post-receive-email sends only one email
+ for each *reference* that is changed, no matter how many commits
+ were added to the reference.
+
+* Better algorithm for detecting new commits. post-receive-email
+ processes one reference change at a time, which causes it to fail to
+ describe new commits that were included in multiple branches. For
+ example, if a single push adds the "*" commits in the diagram below,
+ then post-receive-email would never include the details of the two
+ commits that are common to "master" and "branch" in its
+ notifications.
+
+ o---o---o---*---*---* <-- master
+ \
+ *---* <-- branch
+
+ git-multimail analyzes all reference modifications to determine
+ which commits were not present before the change, therefore avoiding
+ that error.
+
+* In reference change emails, git-multimail tells which commits have
+ been added to the reference vs. are entirely new to the repository,
+ and which commits that have been omitted from the reference
+ vs. entirely discarded from the repository.
+
+* The environment in which Git is running can be configured via an
+ "Environment" abstraction.
+
+* Built-in support for Gitolite-managed repositories.
+
+* Instead of using full SHA1 object names in emails, git-multimail
+ mostly uses abbreviated SHA1s, plus one-line log message summaries
+ where appropriate.
+
+* In the schematic diagrams that explain non-fast-forward commits,
+ git-multimail shows the names of the branches involved.
+
+* The emails generated by git-multimail include the name of the Git
+ repository that was modified; this is convenient for recipients who
+ are monitoring multiple repositories.
+
+* git-multimail allows the email "From" addresses to be configured.
+
+* The recipients lists (multimailhook.mailinglist,
+ multimailhook.refchangelist, multimailhook.announcelist, and
+ multimailhook.commitlist) can be comma-separated values and/or
+ multivalued settings in the config file; e.g.,
+
+ [multimailhook]
+ mailinglist = mr.brown@example.com, mr.black@example.com
+ announcelist = Him <him@example.com>
+ announcelist = Jim <jim@example.com>
+ announcelist = pop@example.com
+
+ This might make it easier to maintain short recipients lists without
+ requiring full-fledged mailing list software.
+
+* By default, git-multimail sets email "Reply-To" headers to reply to
+ the pusher (for reference updates) and to the author (for commit
+ notifications). By default, the pusher's email address is
+ constructed by appending "multimailhook.emaildomain" to the pusher's
+ username.
+
+* The generated emails contain a configurable footer. By default, it
+ lists the name of the administrator who should be contacted to
+ unsubscribe from notification emails.
+
+* New option multimailhook.emailmaxlinelength to limit the length of
+ lines in the main part of the email body. The default limit is 500
+ characters.
+
+* New option multimailhook.emailstrictutf8 to ensure that the main
+ part of the email body is valid UTF-8. Invalid characters are
+ turned into the Unicode replacement character, U+FFFD. By default
+ this option is turned on.
+
+* Written in Python. Easier to add new features.
diff --git a/contrib/hooks/multimail/git_multimail.py b/contrib/hooks/multimail/git_multimail.py
new file mode 100755
index 0000000..81c6a51
--- /dev/null
+++ b/contrib/hooks/multimail/git_multimail.py
@@ -0,0 +1,2393 @@
+#! /usr/bin/env python2
+
+# Copyright (c) 2012,2013 Michael Haggerty
+# Derived from contrib/hooks/post-receive-email, which is
+# Copyright (c) 2007 Andy Parkins
+# and also includes contributions by other authors.
+#
+# This file is part of git-multimail.
+#
+# git-multimail is free software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License version
+# 2 as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+"""Generate notification emails for pushes to a git repository.
+
+This hook sends emails describing changes introduced by pushes to a
+git repository. For each reference that was changed, it emits one
+ReferenceChange email summarizing how the reference was changed,
+followed by one Revision email for each new commit that was introduced
+by the reference change.
+
+Each commit is announced in exactly one Revision email. If the same
+commit is merged into another branch in the same or a later push, then
+the ReferenceChange email will list the commit's SHA1 and its one-line
+summary, but no new Revision email will be generated.
+
+This script is designed to be used as a "post-receive" hook in a git
+repository (see githooks(5)). It can also be used as an "update"
+script, but this usage is not completely reliable and is deprecated.
+
+To help with debugging, this script accepts a --stdout option, which
+causes the emails to be written to standard output rather than sent
+using sendmail.
+
+See the accompanying README file for the complete documentation.
+
+"""
+
+import sys
+import os
+import re
+import bisect
+import subprocess
+import shlex
+import optparse
+import smtplib
+
+try:
+ from email.utils import make_msgid
+ from email.utils import getaddresses
+ from email.utils import formataddr
+ from email.header import Header
+except ImportError:
+ # Prior to Python 2.5, the email module used different names:
+ from email.Utils import make_msgid
+ from email.Utils import getaddresses
+ from email.Utils import formataddr
+ from email.Header import Header
+
+
+DEBUG = False
+
+ZEROS = '0' * 40
+LOGBEGIN = '- Log -----------------------------------------------------------------\n'
+LOGEND = '-----------------------------------------------------------------------\n'
+
+
+# It is assumed in many places that the encoding is uniformly UTF-8,
+# so changing these constants is unsupported. But define them here
+# anyway, to make it easier to find (at least most of) the places
+# where the encoding is important.
+(ENCODING, CHARSET) = ('UTF-8', 'utf-8')
+
+
+REF_CREATED_SUBJECT_TEMPLATE = (
+ '%(emailprefix)s%(refname_type)s %(short_refname)s created'
+ ' (now %(newrev_short)s)'
+ )
+REF_UPDATED_SUBJECT_TEMPLATE = (
+ '%(emailprefix)s%(refname_type)s %(short_refname)s updated'
+ ' (%(oldrev_short)s -> %(newrev_short)s)'
+ )
+REF_DELETED_SUBJECT_TEMPLATE = (
+ '%(emailprefix)s%(refname_type)s %(short_refname)s deleted'
+ ' (was %(oldrev_short)s)'
+ )
+
+REFCHANGE_HEADER_TEMPLATE = """\
+To: %(recipients)s
+Subject: %(subject)s
+MIME-Version: 1.0
+Content-Type: text/plain; charset=%(charset)s
+Content-Transfer-Encoding: 8bit
+Message-ID: %(msgid)s
+From: %(fromaddr)s
+Reply-To: %(reply_to)s
+X-Git-Repo: %(repo_shortname)s
+X-Git-Refname: %(refname)s
+X-Git-Reftype: %(refname_type)s
+X-Git-Oldrev: %(oldrev)s
+X-Git-Newrev: %(newrev)s
+Auto-Submitted: auto-generated
+"""
+
+REFCHANGE_INTRO_TEMPLATE = """\
+This is an automated email from the git hooks/post-receive script.
+
+%(pusher)s pushed a change to %(refname_type)s %(short_refname)s
+in repository %(repo_shortname)s.
+
+"""
+
+
+FOOTER_TEMPLATE = """\
+
+-- \n\
+To stop receiving notification emails like this one, please contact
+%(administrator)s.
+"""
+
+
+REWIND_ONLY_TEMPLATE = """\
+This update removed existing revisions from the reference, leaving the
+reference pointing at a previous point in the repository history.
+
+ * -- * -- N %(refname)s (%(newrev_short)s)
+ \\
+ O -- O -- O (%(oldrev_short)s)
+
+Any revisions marked "omits" are not gone; other references still
+refer to them. Any revisions marked "discards" are gone forever.
+"""
+
+
+NON_FF_TEMPLATE = """\
+This update added new revisions after undoing existing revisions.
+That is to say, some revisions that were in the old version of the
+%(refname_type)s are not in the new version. This situation occurs
+when a user --force pushes a change and generates a repository
+containing something like this:
+
+ * -- * -- B -- O -- O -- O (%(oldrev_short)s)
+ \\
+ N -- N -- N %(refname)s (%(newrev_short)s)
+
+You should already have received notification emails for all of the O
+revisions, and so the following emails describe only the N revisions
+from the common base, B.
+
+Any revisions marked "omits" are not gone; other references still
+refer to them. Any revisions marked "discards" are gone forever.
+"""
+
+
+NO_NEW_REVISIONS_TEMPLATE = """\
+No new revisions were added by this update.
+"""
+
+
+DISCARDED_REVISIONS_TEMPLATE = """\
+This change permanently discards the following revisions:
+"""
+
+
+NO_DISCARDED_REVISIONS_TEMPLATE = """\
+The revisions that were on this %(refname_type)s are still contained in
+other references; therefore, this change does not discard any commits
+from the repository.
+"""
+
+
+NEW_REVISIONS_TEMPLATE = """\
+The %(tot)s revisions listed above as "new" are entirely new to this
+repository and will be described in separate emails. The revisions
+listed as "adds" were already present in the repository and have only
+been added to this reference.
+
+"""
+
+
+TAG_CREATED_TEMPLATE = """\
+ at %(newrev_short)-9s (%(newrev_type)s)
+"""
+
+
+TAG_UPDATED_TEMPLATE = """\
+*** WARNING: tag %(short_refname)s was modified! ***
+
+ from %(oldrev_short)-9s (%(oldrev_type)s)
+ to %(newrev_short)-9s (%(newrev_type)s)
+"""
+
+
+TAG_DELETED_TEMPLATE = """\
+*** WARNING: tag %(short_refname)s was deleted! ***
+
+"""
+
+
+# The template used in summary tables. It looks best if this uses the
+# same alignment as TAG_CREATED_TEMPLATE and TAG_UPDATED_TEMPLATE.
+BRIEF_SUMMARY_TEMPLATE = """\
+%(action)10s %(rev_short)-9s %(text)s
+"""
+
+
+NON_COMMIT_UPDATE_TEMPLATE = """\
+This is an unusual reference change because the reference did not
+refer to a commit either before or after the change. We do not know
+how to provide full information about this reference change.
+"""
+
+
+REVISION_HEADER_TEMPLATE = """\
+To: %(recipients)s
+Subject: %(emailprefix)s%(num)02d/%(tot)02d: %(oneline)s
+MIME-Version: 1.0
+Content-Type: text/plain; charset=%(charset)s
+Content-Transfer-Encoding: 8bit
+From: %(fromaddr)s
+Reply-To: %(reply_to)s
+In-Reply-To: %(reply_to_msgid)s
+References: %(reply_to_msgid)s
+X-Git-Repo: %(repo_shortname)s
+X-Git-Refname: %(refname)s
+X-Git-Reftype: %(refname_type)s
+X-Git-Rev: %(rev)s
+Auto-Submitted: auto-generated
+"""
+
+REVISION_INTRO_TEMPLATE = """\
+This is an automated email from the git hooks/post-receive script.
+
+%(pusher)s pushed a commit to %(refname_type)s %(short_refname)s
+in repository %(repo_shortname)s.
+
+"""
+
+
+REVISION_FOOTER_TEMPLATE = FOOTER_TEMPLATE
+
+
+class CommandError(Exception):
+ def __init__(self, cmd, retcode):
+ self.cmd = cmd
+ self.retcode = retcode
+ Exception.__init__(
+ self,
+ 'Command "%s" failed with retcode %s' % (' '.join(cmd), retcode,)
+ )
+
+
+class ConfigurationException(Exception):
+ pass
+
+
+def read_git_output(args, input=None, keepends=False, **kw):
+ """Read the output of a Git command."""
+
+ return read_output(
+ ['git', '-c', 'i18n.logoutputencoding=%s' % (ENCODING,)] + args,
+ input=input, keepends=keepends, **kw
+ )
+
+
+def read_output(cmd, input=None, keepends=False, **kw):
+ if input:
+ stdin = subprocess.PIPE
+ else:
+ stdin = None
+ p = subprocess.Popen(
+ cmd, stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kw
+ )
+ (out, err) = p.communicate(input)
+ retcode = p.wait()
+ if retcode:
+ raise CommandError(cmd, retcode)
+ if not keepends:
+ out = out.rstrip('\n\r')
+ return out
+
+
+def read_git_lines(args, keepends=False, **kw):
+ """Return the lines output by Git command.
+
+ Return as single lines, with newlines stripped off."""
+
+ return read_git_output(args, keepends=True, **kw).splitlines(keepends)
+
+
+class Config(object):
+ def __init__(self, section, git_config=None):
+ """Represent a section of the git configuration.
+
+ If git_config is specified, it is passed to "git config" in
+ the GIT_CONFIG environment variable, meaning that "git config"
+ will read the specified path rather than the Git default
+ config paths."""
+
+ self.section = section
+ if git_config:
+ self.env = os.environ.copy()
+ self.env['GIT_CONFIG'] = git_config
+ else:
+ self.env = None
+
+ @staticmethod
+ def _split(s):
+ """Split NUL-terminated values."""
+
+ words = s.split('\0')
+ assert words[-1] == ''
+ return words[:-1]
+
+ def get(self, name, default=None):
+ try:
+ values = self._split(read_git_output(
+ ['config', '--get', '--null', '%s.%s' % (self.section, name)],
+ env=self.env, keepends=True,
+ ))
+ assert len(values) == 1
+ return values[0]
+ except CommandError:
+ return default
+
+ def get_bool(self, name, default=None):
+ try:
+ value = read_git_output(
+ ['config', '--get', '--bool', '%s.%s' % (self.section, name)],
+ env=self.env,
+ )
+ except CommandError:
+ return default
+ return value == 'true'
+
+ def get_all(self, name, default=None):
+ """Read a (possibly multivalued) setting from the configuration.
+
+ Return the result as a list of values, or default if the name
+ is unset."""
+
+ try:
+ return self._split(read_git_output(
+ ['config', '--get-all', '--null', '%s.%s' % (self.section, name)],
+ env=self.env, keepends=True,
+ ))
+ except CommandError, e:
+ if e.retcode == 1:
+ # "the section or key is invalid"; i.e., there is no
+ # value for the specified key.
+ return default
+ else:
+ raise
+
+ def get_recipients(self, name, default=None):
+ """Read a recipients list from the configuration.
+
+ Return the result as a comma-separated list of email
+ addresses, or default if the option is unset. If the setting
+ has multiple values, concatenate them with comma separators."""
+
+ lines = self.get_all(name, default=None)
+ if lines is None:
+ return default
+ return ', '.join(line.strip() for line in lines)
+
+ def set(self, name, value):
+ read_git_output(
+ ['config', '%s.%s' % (self.section, name), value],
+ env=self.env,
+ )
+
+ def add(self, name, value):
+ read_git_output(
+ ['config', '--add', '%s.%s' % (self.section, name), value],
+ env=self.env,
+ )
+
+ def has_key(self, name):
+ return self.get_all(name, default=None) is not None
+
+ def unset_all(self, name):
+ try:
+ read_git_output(
+ ['config', '--unset-all', '%s.%s' % (self.section, name)],
+ env=self.env,
+ )
+ except CommandError, e:
+ if e.retcode == 5:
+ # The name doesn't exist, which is what we wanted anyway...
+ pass
+ else:
+ raise
+
+ def set_recipients(self, name, value):
+ self.unset_all(name)
+ for pair in getaddresses([value]):
+ self.add(name, formataddr(pair))
+
+
+def generate_summaries(*log_args):
+ """Generate a brief summary for each revision requested.
+
+ log_args are strings that will be passed directly to "git log" as
+ revision selectors. Iterate over (sha1_short, subject) for each
+ commit specified by log_args (subject is the first line of the
+ commit message as a string without EOLs)."""
+
+ cmd = [
+ 'log', '--abbrev', '--format=%h %s',
+ ] + list(log_args) + ['--']
+ for line in read_git_lines(cmd):
+ yield tuple(line.split(' ', 1))
+
+
+def limit_lines(lines, max_lines):
+ for (index, line) in enumerate(lines):
+ if index < max_lines:
+ yield line
+
+ if index >= max_lines:
+ yield '... %d lines suppressed ...\n' % (index + 1 - max_lines,)
+
+
+def limit_linelength(lines, max_linelength):
+ for line in lines:
+ # Don't forget that lines always include a trailing newline.
+ if len(line) > max_linelength + 1:
+ line = line[:max_linelength - 7] + ' [...]\n'
+ yield line
+
+
+class CommitSet(object):
+ """A (constant) set of object names.
+
+ The set should be initialized with full SHA1 object names. The
+ __contains__() method returns True iff its argument is an
+ abbreviation of any the names in the set."""
+
+ def __init__(self, names):
+ self._names = sorted(names)
+
+ def __len__(self):
+ return len(self._names)
+
+ def __contains__(self, sha1_abbrev):
+ """Return True iff this set contains sha1_abbrev (which might be abbreviated)."""
+
+ i = bisect.bisect_left(self._names, sha1_abbrev)
+ return i < len(self) and self._names[i].startswith(sha1_abbrev)
+
+
+class GitObject(object):
+ def __init__(self, sha1, type=None):
+ if sha1 == ZEROS:
+ self.sha1 = self.type = self.commit_sha1 = None
+ else:
+ self.sha1 = sha1
+ self.type = type or read_git_output(['cat-file', '-t', self.sha1])
+
+ if self.type == 'commit':
+ self.commit_sha1 = self.sha1
+ elif self.type == 'tag':
+ try:
+ self.commit_sha1 = read_git_output(
+ ['rev-parse', '--verify', '%s^0' % (self.sha1,)]
+ )
+ except CommandError:
+ # Cannot deref tag to determine commit_sha1
+ self.commit_sha1 = None
+ else:
+ self.commit_sha1 = None
+
+ self.short = read_git_output(['rev-parse', '--short', sha1])
+
+ def get_summary(self):
+ """Return (sha1_short, subject) for this commit."""
+
+ if not self.sha1:
+ raise ValueError('Empty commit has no summary')
+
+ return iter(generate_summaries('--no-walk', self.sha1)).next()
+
+ def __eq__(self, other):
+ return isinstance(other, GitObject) and self.sha1 == other.sha1
+
+ def __hash__(self):
+ return hash(self.sha1)
+
+ def __nonzero__(self):
+ return bool(self.sha1)
+
+ def __str__(self):
+ return self.sha1 or ZEROS
+
+
+class Change(object):
+ """A Change that has been made to the Git repository.
+
+ Abstract class from which both Revisions and ReferenceChanges are
+ derived. A Change knows how to generate a notification email
+ describing itself."""
+
+ def __init__(self, environment):
+ self.environment = environment
+ self._values = None
+
+ def _compute_values(self):
+ """Return a dictionary {keyword : expansion} for this Change.
+
+ Derived classes overload this method to add more entries to
+ the return value. This method is used internally by
+ get_values(). The return value should always be a new
+ dictionary."""
+
+ return self.environment.get_values()
+
+ def get_values(self, **extra_values):
+ """Return a dictionary {keyword : expansion} for this Change.
+
+ Return a dictionary mapping keywords to the values that they
+ should be expanded to for this Change (used when interpolating
+ template strings). If any keyword arguments are supplied, add
+ those to the return value as well. The return value is always
+ a new dictionary."""
+
+ if self._values is None:
+ self._values = self._compute_values()
+
+ values = self._values.copy()
+ if extra_values:
+ values.update(extra_values)
+ return values
+
+ def expand(self, template, **extra_values):
+ """Expand template.
+
+ Expand the template (which should be a string) using string
+ interpolation of the values for this Change. If any keyword
+ arguments are provided, also include those in the keywords
+ available for interpolation."""
+
+ return template % self.get_values(**extra_values)
+
+ def expand_lines(self, template, **extra_values):
+ """Break template into lines and expand each line."""
+
+ values = self.get_values(**extra_values)
+ for line in template.splitlines(True):
+ yield line % values
+
+ def expand_header_lines(self, template, **extra_values):
+ """Break template into lines and expand each line as an RFC 2822 header.
+
+ Encode values and split up lines that are too long. Silently
+ skip lines that contain references to unknown variables."""
+
+ values = self.get_values(**extra_values)
+ for line in template.splitlines():
+ (name, value) = line.split(':', 1)
+
+ try:
+ value = value % values
+ except KeyError, e:
+ if DEBUG:
+ sys.stderr.write(
+ 'Warning: unknown variable %r in the following line; line skipped:\n'
+ ' %s\n'
+ % (e.args[0], line,)
+ )
+ else:
+ try:
+ h = Header(value, header_name=name)
+ except UnicodeDecodeError:
+ h = Header(value, header_name=name, charset=CHARSET, errors='replace')
+ for splitline in ('%s: %s\n' % (name, h.encode(),)).splitlines(True):
+ yield splitline
+
+ def generate_email_header(self):
+ """Generate the RFC 2822 email headers for this Change, a line at a time.
+
+ The output should not include the trailing blank line."""
+
+ raise NotImplementedError()
+
+ def generate_email_intro(self):
+ """Generate the email intro for this Change, a line at a time.
+
+ The output will be used as the standard boilerplate at the top
+ of the email body."""
+
+ raise NotImplementedError()
+
+ def generate_email_body(self):
+ """Generate the main part of the email body, a line at a time.
+
+ The text in the body might be truncated after a specified
+ number of lines (see multimailhook.emailmaxlines)."""
+
+ raise NotImplementedError()
+
+ def generate_email_footer(self):
+ """Generate the footer of the email, a line at a time.
+
+ The footer is always included, irrespective of
+ multimailhook.emailmaxlines."""
+
+ raise NotImplementedError()
+
+ def generate_email(self, push, body_filter=None):
+ """Generate an email describing this change.
+
+ Iterate over the lines (including the header lines) of an
+ email describing this change. If body_filter is not None,
+ then use it to filter the lines that are intended for the
+ email body."""
+
+ for line in self.generate_email_header():
+ yield line
+ yield '\n'
+ for line in self.generate_email_intro():
+ yield line
+
+ body = self.generate_email_body(push)
+ if body_filter is not None:
+ body = body_filter(body)
+ for line in body:
+ yield line
+
+ for line in self.generate_email_footer():
+ yield line
+
+
+class Revision(Change):
+ """A Change consisting of a single git commit."""
+
+ def __init__(self, reference_change, rev, num, tot):
+ Change.__init__(self, reference_change.environment)
+ self.reference_change = reference_change
+ self.rev = rev
+ self.change_type = self.reference_change.change_type
+ self.refname = self.reference_change.refname
+ self.num = num
+ self.tot = tot
+ self.author = read_git_output(['log', '--no-walk', '--format=%aN <%aE>', self.rev.sha1])
+ self.recipients = self.environment.get_revision_recipients(self)
+
+ def _compute_values(self):
+ values = Change._compute_values(self)
+
+ oneline = read_git_output(
+ ['log', '--format=%s', '--no-walk', self.rev.sha1]
+ )
+
+ values['rev'] = self.rev.sha1
+ values['rev_short'] = self.rev.short
+ values['change_type'] = self.change_type
+ values['refname'] = self.refname
+ values['short_refname'] = self.reference_change.short_refname
+ values['refname_type'] = self.reference_change.refname_type
+ values['reply_to_msgid'] = self.reference_change.msgid
+ values['num'] = self.num
+ values['tot'] = self.tot
+ values['recipients'] = self.recipients
+ values['oneline'] = oneline
+ values['author'] = self.author
+
+ reply_to = self.environment.get_reply_to_commit(self)
+ if reply_to:
+ values['reply_to'] = reply_to
+
+ return values
+
+ def generate_email_header(self):
+ for line in self.expand_header_lines(REVISION_HEADER_TEMPLATE):
+ yield line
+
+ def generate_email_intro(self):
+ for line in self.expand_lines(REVISION_INTRO_TEMPLATE):
+ yield line
+
+ def generate_email_body(self, push):
+ """Show this revision."""
+
+ return read_git_lines(
+ [
+ 'log', '-C',
+ '--stat', '-p', '--cc',
+ '-1', self.rev.sha1,
+ ],
+ keepends=True,
+ )
+
+ def generate_email_footer(self):
+ return self.expand_lines(REVISION_FOOTER_TEMPLATE)
+
+
+class ReferenceChange(Change):
+ """A Change to a Git reference.
+
+ An abstract class representing a create, update, or delete of a
+ Git reference. Derived classes handle specific types of reference
+ (e.g., tags vs. branches). These classes generate the main
+ reference change email summarizing the reference change and
+ whether it caused any any commits to be added or removed.
+
+ ReferenceChange objects are usually created using the static
+ create() method, which has the logic to decide which derived class
+ to instantiate."""
+
+ REF_RE = re.compile(r'^refs\/(?P<area>[^\/]+)\/(?P<shortname>.*)$')
+
+ @staticmethod
+ def create(environment, oldrev, newrev, refname):
+ """Return a ReferenceChange object representing the change.
+
+ Return an object that represents the type of change that is being
+ made. oldrev and newrev should be SHA1s or ZEROS."""
+
+ old = GitObject(oldrev)
+ new = GitObject(newrev)
+ rev = new or old
+
+ # The revision type tells us what type the commit is, combined with
+ # the location of the ref we can decide between
+ # - working branch
+ # - tracking branch
+ # - unannotated tag
+ # - annotated tag
+ m = ReferenceChange.REF_RE.match(refname)
+ if m:
+ area = m.group('area')
+ short_refname = m.group('shortname')
+ else:
+ area = ''
+ short_refname = refname
+
+ if rev.type == 'tag':
+ # Annotated tag:
+ klass = AnnotatedTagChange
+ elif rev.type == 'commit':
+ if area == 'tags':
+ # Non-annotated tag:
+ klass = NonAnnotatedTagChange
+ elif area == 'heads':
+ # Branch:
+ klass = BranchChange
+ elif area == 'remotes':
+ # Tracking branch:
+ sys.stderr.write(
+ '*** Push-update of tracking branch %r\n'
+ '*** - incomplete email generated.\n'
+ % (refname,)
+ )
+ klass = OtherReferenceChange
+ else:
+ # Some other reference namespace:
+ sys.stderr.write(
+ '*** Push-update of strange reference %r\n'
+ '*** - incomplete email generated.\n'
+ % (refname,)
+ )
+ klass = OtherReferenceChange
+ else:
+ # Anything else (is there anything else?)
+ sys.stderr.write(
+ '*** Unknown type of update to %r (%s)\n'
+ '*** - incomplete email generated.\n'
+ % (refname, rev.type,)
+ )
+ klass = OtherReferenceChange
+
+ return klass(
+ environment,
+ refname=refname, short_refname=short_refname,
+ old=old, new=new, rev=rev,
+ )
+
+ def __init__(self, environment, refname, short_refname, old, new, rev):
+ Change.__init__(self, environment)
+ self.change_type = {
+ (False, True) : 'create',
+ (True, True) : 'update',
+ (True, False) : 'delete',
+ }[bool(old), bool(new)]
+ self.refname = refname
+ self.short_refname = short_refname
+ self.old = old
+ self.new = new
+ self.rev = rev
+ self.msgid = make_msgid()
+ self.diffopts = environment.diffopts
+ self.logopts = environment.logopts
+ self.showlog = environment.refchange_showlog
+
+ def _compute_values(self):
+ values = Change._compute_values(self)
+
+ values['change_type'] = self.change_type
+ values['refname_type'] = self.refname_type
+ values['refname'] = self.refname
+ values['short_refname'] = self.short_refname
+ values['msgid'] = self.msgid
+ values['recipients'] = self.recipients
+ values['oldrev'] = str(self.old)
+ values['oldrev_short'] = self.old.short
+ values['newrev'] = str(self.new)
+ values['newrev_short'] = self.new.short
+
+ if self.old:
+ values['oldrev_type'] = self.old.type
+ if self.new:
+ values['newrev_type'] = self.new.type
+
+ reply_to = self.environment.get_reply_to_refchange(self)
+ if reply_to:
+ values['reply_to'] = reply_to
+
+ return values
+
+ def get_subject(self):
+ template = {
+ 'create' : REF_CREATED_SUBJECT_TEMPLATE,
+ 'update' : REF_UPDATED_SUBJECT_TEMPLATE,
+ 'delete' : REF_DELETED_SUBJECT_TEMPLATE,
+ }[self.change_type]
+ return self.expand(template)
+
+ def generate_email_header(self):
+ for line in self.expand_header_lines(
+ REFCHANGE_HEADER_TEMPLATE, subject=self.get_subject(),
+ ):
+ yield line
+
+ def generate_email_intro(self):
+ for line in self.expand_lines(REFCHANGE_INTRO_TEMPLATE):
+ yield line
+
+ def generate_email_body(self, push):
+ """Call the appropriate body-generation routine.
+
+ Call one of generate_create_summary() /
+ generate_update_summary() / generate_delete_summary()."""
+
+ change_summary = {
+ 'create' : self.generate_create_summary,
+ 'delete' : self.generate_delete_summary,
+ 'update' : self.generate_update_summary,
+ }[self.change_type](push)
+ for line in change_summary:
+ yield line
+
+ for line in self.generate_revision_change_summary(push):
+ yield line
+
+ def generate_email_footer(self):
+ return self.expand_lines(FOOTER_TEMPLATE)
+
+ def generate_revision_change_log(self, new_commits_list):
+ if self.showlog:
+ yield '\n'
+ yield 'Detailed log of new commits:\n\n'
+ for line in read_git_lines(
+ ['log', '--no-walk']
+ + self.logopts
+ + new_commits_list
+ + ['--'],
+ keepends=True,
+ ):
+ yield line
+
+ def generate_revision_change_summary(self, push):
+ """Generate a summary of the revisions added/removed by this change."""
+
+ if self.new.commit_sha1 and not self.old.commit_sha1:
+ # A new reference was created. List the new revisions
+ # brought by the new reference (i.e., those revisions that
+ # were not in the repository before this reference
+ # change).
+ sha1s = list(push.get_new_commits(self))
+ sha1s.reverse()
+ tot = len(sha1s)
+ new_revisions = [
+ Revision(self, GitObject(sha1), num=i+1, tot=tot)
+ for (i, sha1) in enumerate(sha1s)
+ ]
+
+ if new_revisions:
+ yield self.expand('This %(refname_type)s includes the following new commits:\n')
+ yield '\n'
+ for r in new_revisions:
+ (sha1, subject) = r.rev.get_summary()
+ yield r.expand(
+ BRIEF_SUMMARY_TEMPLATE, action='new', text=subject,
+ )
+ yield '\n'
+ for line in self.expand_lines(NEW_REVISIONS_TEMPLATE, tot=tot):
+ yield line
+ for line in self.generate_revision_change_log([r.rev.sha1 for r in new_revisions]):
+ yield line
+ else:
+ for line in self.expand_lines(NO_NEW_REVISIONS_TEMPLATE):
+ yield line
+
+ elif self.new.commit_sha1 and self.old.commit_sha1:
+ # A reference was changed to point at a different commit.
+ # List the revisions that were removed and/or added *from
+ # that reference* by this reference change, along with a
+ # diff between the trees for its old and new values.
+
+ # List of the revisions that were added to the branch by
+ # this update. Note this list can include revisions that
+ # have already had notification emails; we want such
+ # revisions in the summary even though we will not send
+ # new notification emails for them.
+ adds = list(generate_summaries(
+ '--topo-order', '--reverse', '%s..%s'
+ % (self.old.commit_sha1, self.new.commit_sha1,)
+ ))
+
+ # List of the revisions that were removed from the branch
+ # by this update. This will be empty except for
+ # non-fast-forward updates.
+ discards = list(generate_summaries(
+ '%s..%s' % (self.new.commit_sha1, self.old.commit_sha1,)
+ ))
+
+ if adds:
+ new_commits_list = push.get_new_commits(self)
+ else:
+ new_commits_list = []
+ new_commits = CommitSet(new_commits_list)
+
+ if discards:
+ discarded_commits = CommitSet(push.get_discarded_commits(self))
+ else:
+ discarded_commits = CommitSet([])
+
+ if discards and adds:
+ for (sha1, subject) in discards:
+ if sha1 in discarded_commits:
+ action = 'discards'
+ else:
+ action = 'omits'
+ yield self.expand(
+ BRIEF_SUMMARY_TEMPLATE, action=action,
+ rev_short=sha1, text=subject,
+ )
+ for (sha1, subject) in adds:
+ if sha1 in new_commits:
+ action = 'new'
+ else:
+ action = 'adds'
+ yield self.expand(
+ BRIEF_SUMMARY_TEMPLATE, action=action,
+ rev_short=sha1, text=subject,
+ )
+ yield '\n'
+ for line in self.expand_lines(NON_FF_TEMPLATE):
+ yield line
+
+ elif discards:
+ for (sha1, subject) in discards:
+ if sha1 in discarded_commits:
+ action = 'discards'
+ else:
+ action = 'omits'
+ yield self.expand(
+ BRIEF_SUMMARY_TEMPLATE, action=action,
+ rev_short=sha1, text=subject,
+ )
+ yield '\n'
+ for line in self.expand_lines(REWIND_ONLY_TEMPLATE):
+ yield line
+
+ elif adds:
+ (sha1, subject) = self.old.get_summary()
+ yield self.expand(
+ BRIEF_SUMMARY_TEMPLATE, action='from',
+ rev_short=sha1, text=subject,
+ )
+ for (sha1, subject) in adds:
+ if sha1 in new_commits:
+ action = 'new'
+ else:
+ action = 'adds'
+ yield self.expand(
+ BRIEF_SUMMARY_TEMPLATE, action=action,
+ rev_short=sha1, text=subject,
+ )
+
+ yield '\n'
+
+ if new_commits:
+ for line in self.expand_lines(NEW_REVISIONS_TEMPLATE, tot=len(new_commits)):
+ yield line
+ for line in self.generate_revision_change_log(new_commits_list):
+ yield line
+ else:
+ for line in self.expand_lines(NO_NEW_REVISIONS_TEMPLATE):
+ yield line
+
+ # The diffstat is shown from the old revision to the new
+ # revision. This is to show the truth of what happened in
+ # this change. There's no point showing the stat from the
+ # base to the new revision because the base is effectively a
+ # random revision at this point - the user will be interested
+ # in what this revision changed - including the undoing of
+ # previous revisions in the case of non-fast-forward updates.
+ yield '\n'
+ yield 'Summary of changes:\n'
+ for line in read_git_lines(
+ ['diff-tree']
+ + self.diffopts
+ + ['%s..%s' % (self.old.commit_sha1, self.new.commit_sha1,)],
+ keepends=True,
+ ):
+ yield line
+
+ elif self.old.commit_sha1 and not self.new.commit_sha1:
+ # A reference was deleted. List the revisions that were
+ # removed from the repository by this reference change.
+
+ sha1s = list(push.get_discarded_commits(self))
+ tot = len(sha1s)
+ discarded_revisions = [
+ Revision(self, GitObject(sha1), num=i+1, tot=tot)
+ for (i, sha1) in enumerate(sha1s)
+ ]
+
+ if discarded_revisions:
+ for line in self.expand_lines(DISCARDED_REVISIONS_TEMPLATE):
+ yield line
+ yield '\n'
+ for r in discarded_revisions:
+ (sha1, subject) = r.rev.get_summary()
+ yield r.expand(
+ BRIEF_SUMMARY_TEMPLATE, action='discards', text=subject,
+ )
+ else:
+ for line in self.expand_lines(NO_DISCARDED_REVISIONS_TEMPLATE):
+ yield line
+
+ elif not self.old.commit_sha1 and not self.new.commit_sha1:
+ for line in self.expand_lines(NON_COMMIT_UPDATE_TEMPLATE):
+ yield line
+
+ def generate_create_summary(self, push):
+ """Called for the creation of a reference."""
+
+ # This is a new reference and so oldrev is not valid
+ (sha1, subject) = self.new.get_summary()
+ yield self.expand(
+ BRIEF_SUMMARY_TEMPLATE, action='at',
+ rev_short=sha1, text=subject,
+ )
+ yield '\n'
+
+ def generate_update_summary(self, push):
+ """Called for the change of a pre-existing branch."""
+
+ return iter([])
+
+ def generate_delete_summary(self, push):
+ """Called for the deletion of any type of reference."""
+
+ (sha1, subject) = self.old.get_summary()
+ yield self.expand(
+ BRIEF_SUMMARY_TEMPLATE, action='was',
+ rev_short=sha1, text=subject,
+ )
+ yield '\n'
+
+
+class BranchChange(ReferenceChange):
+ refname_type = 'branch'
+
+ def __init__(self, environment, refname, short_refname, old, new, rev):
+ ReferenceChange.__init__(
+ self, environment,
+ refname=refname, short_refname=short_refname,
+ old=old, new=new, rev=rev,
+ )
+ self.recipients = environment.get_refchange_recipients(self)
+
+
+class AnnotatedTagChange(ReferenceChange):
+ refname_type = 'annotated tag'
+
+ def __init__(self, environment, refname, short_refname, old, new, rev):
+ ReferenceChange.__init__(
+ self, environment,
+ refname=refname, short_refname=short_refname,
+ old=old, new=new, rev=rev,
+ )
+ self.recipients = environment.get_announce_recipients(self)
+ self.show_shortlog = environment.announce_show_shortlog
+
+ ANNOTATED_TAG_FORMAT = (
+ '%(*objectname)\n'
+ '%(*objecttype)\n'
+ '%(taggername)\n'
+ '%(taggerdate)'
+ )
+
+ def describe_tag(self, push):
+ """Describe the new value of an annotated tag."""
+
+ # Use git for-each-ref to pull out the individual fields from
+ # the tag
+ [tagobject, tagtype, tagger, tagged] = read_git_lines(
+ ['for-each-ref', '--format=%s' % (self.ANNOTATED_TAG_FORMAT,), self.refname],
+ )
+
+ yield self.expand(
+ BRIEF_SUMMARY_TEMPLATE, action='tagging',
+ rev_short=tagobject, text='(%s)' % (tagtype,),
+ )
+ if tagtype == 'commit':
+ # If the tagged object is a commit, then we assume this is a
+ # release, and so we calculate which tag this tag is
+ # replacing
+ try:
+ prevtag = read_git_output(['describe', '--abbrev=0', '%s^' % (self.new,)])
+ except CommandError:
+ prevtag = None
+ if prevtag:
+ yield ' replaces %s\n' % (prevtag,)
+ else:
+ prevtag = None
+ yield ' length %s bytes\n' % (read_git_output(['cat-file', '-s', tagobject]),)
+
+ yield ' tagged by %s\n' % (tagger,)
+ yield ' on %s\n' % (tagged,)
+ yield '\n'
+
+ # Show the content of the tag message; this might contain a
+ # change log or release notes so is worth displaying.
+ yield LOGBEGIN
+ contents = list(read_git_lines(['cat-file', 'tag', self.new.sha1], keepends=True))
+ contents = contents[contents.index('\n') + 1:]
+ if contents and contents[-1][-1:] != '\n':
+ contents.append('\n')
+ for line in contents:
+ yield line
+
+ if self.show_shortlog and tagtype == 'commit':
+ # Only commit tags make sense to have rev-list operations
+ # performed on them
+ yield '\n'
+ if prevtag:
+ # Show changes since the previous release
+ revlist = read_git_output(
+ ['rev-list', '--pretty=short', '%s..%s' % (prevtag, self.new,)],
+ keepends=True,
+ )
+ else:
+ # No previous tag, show all the changes since time
+ # began
+ revlist = read_git_output(
+ ['rev-list', '--pretty=short', '%s' % (self.new,)],
+ keepends=True,
+ )
+ for line in read_git_lines(['shortlog'], input=revlist, keepends=True):
+ yield line
+
+ yield LOGEND
+ yield '\n'
+
+ def generate_create_summary(self, push):
+ """Called for the creation of an annotated tag."""
+
+ for line in self.expand_lines(TAG_CREATED_TEMPLATE):
+ yield line
+
+ for line in self.describe_tag(push):
+ yield line
+
+ def generate_update_summary(self, push):
+ """Called for the update of an annotated tag.
+
+ This is probably a rare event and may not even be allowed."""
+
+ for line in self.expand_lines(TAG_UPDATED_TEMPLATE):
+ yield line
+
+ for line in self.describe_tag(push):
+ yield line
+
+ def generate_delete_summary(self, push):
+ """Called when a non-annotated reference is updated."""
+
+ for line in self.expand_lines(TAG_DELETED_TEMPLATE):
+ yield line
+
+ yield self.expand(' tag was %(oldrev_short)s\n')
+ yield '\n'
+
+
+class NonAnnotatedTagChange(ReferenceChange):
+ refname_type = 'tag'
+
+ def __init__(self, environment, refname, short_refname, old, new, rev):
+ ReferenceChange.__init__(
+ self, environment,
+ refname=refname, short_refname=short_refname,
+ old=old, new=new, rev=rev,
+ )
+ self.recipients = environment.get_refchange_recipients(self)
+
+ def generate_create_summary(self, push):
+ """Called for the creation of an annotated tag."""
+
+ for line in self.expand_lines(TAG_CREATED_TEMPLATE):
+ yield line
+
+ def generate_update_summary(self, push):
+ """Called when a non-annotated reference is updated."""
+
+ for line in self.expand_lines(TAG_UPDATED_TEMPLATE):
+ yield line
+
+ def generate_delete_summary(self, push):
+ """Called when a non-annotated reference is updated."""
+
+ for line in self.expand_lines(TAG_DELETED_TEMPLATE):
+ yield line
+
+ for line in ReferenceChange.generate_delete_summary(self, push):
+ yield line
+
+
+class OtherReferenceChange(ReferenceChange):
+ refname_type = 'reference'
+
+ def __init__(self, environment, refname, short_refname, old, new, rev):
+ # We use the full refname as short_refname, because otherwise
+ # the full name of the reference would not be obvious from the
+ # text of the email.
+ ReferenceChange.__init__(
+ self, environment,
+ refname=refname, short_refname=refname,
+ old=old, new=new, rev=rev,
+ )
+ self.recipients = environment.get_refchange_recipients(self)
+
+
+class Mailer(object):
+ """An object that can send emails."""
+
+ def send(self, lines, to_addrs):
+ """Send an email consisting of lines.
+
+ lines must be an iterable over the lines constituting the
+ header and body of the email. to_addrs is a list of recipient
+ addresses (can be needed even if lines already contains a
+ "To:" field). It can be either a string (comma-separated list
+ of email addresses) or a Python list of individual email
+ addresses.
+
+ """
+
+ raise NotImplementedError()
+
+
+class SendMailer(Mailer):
+ """Send emails using 'sendmail -t'."""
+
+ SENDMAIL_CANDIDATES = [
+ '/usr/sbin/sendmail',
+ '/usr/lib/sendmail',
+ ]
+
+ @staticmethod
+ def find_sendmail():
+ for path in SendMailer.SENDMAIL_CANDIDATES:
+ if os.access(path, os.X_OK):
+ return path
+ else:
+ raise ConfigurationException(
+ 'No sendmail executable found. '
+ 'Try setting multimailhook.sendmailCommand.'
+ )
+
+ def __init__(self, command=None, envelopesender=None):
+ """Construct a SendMailer instance.
+
+ command should be the command and arguments used to invoke
+ sendmail, as a list of strings. If an envelopesender is
+ provided, it will also be passed to the command, via '-f
+ envelopesender'."""
+
+ if command:
+ self.command = command[:]
+ else:
+ self.command = [self.find_sendmail(), '-t']
+
+ if envelopesender:
+ self.command.extend(['-f', envelopesender])
+
+ def send(self, lines, to_addrs):
+ try:
+ p = subprocess.Popen(self.command, stdin=subprocess.PIPE)
+ except OSError, e:
+ sys.stderr.write(
+ '*** Cannot execute command: %s\n' % ' '.join(self.command)
+ + '*** %s\n' % str(e)
+ + '*** Try setting multimailhook.mailer to "smtp"\n'
+ '*** to send emails without using the sendmail command.\n'
+ )
+ sys.exit(1)
+ try:
+ p.stdin.writelines(lines)
+ except:
+ sys.stderr.write(
+ '*** Error while generating commit email\n'
+ '*** - mail sending aborted.\n'
+ )
+ p.terminate()
+ raise
+ else:
+ p.stdin.close()
+ retcode = p.wait()
+ if retcode:
+ raise CommandError(self.command, retcode)
+
+
+class SMTPMailer(Mailer):
+ """Send emails using Python's smtplib."""
+
+ def __init__(self, envelopesender, smtpserver):
+ if not envelopesender:
+ sys.stderr.write(
+ 'fatal: git_multimail: cannot use SMTPMailer without a sender address.\n'
+ 'please set either multimailhook.envelopeSender or user.email\n'
+ )
+ sys.exit(1)
+ self.envelopesender = envelopesender
+ self.smtpserver = smtpserver
+ try:
+ self.smtp = smtplib.SMTP(self.smtpserver)
+ except Exception, e:
+ sys.stderr.write('*** Error establishing SMTP connection to %s***\n' % self.smtpserver)
+ sys.stderr.write('*** %s\n' % str(e))
+ sys.exit(1)
+
+ def __del__(self):
+ self.smtp.quit()
+
+ def send(self, lines, to_addrs):
+ try:
+ msg = ''.join(lines)
+ # turn comma-separated list into Python list if needed.
+ if isinstance(to_addrs, basestring):
+ to_addrs = [email for (name, email) in getaddresses([to_addrs])]
+ self.smtp.sendmail(self.envelopesender, to_addrs, msg)
+ except Exception, e:
+ sys.stderr.write('*** Error sending email***\n')
+ sys.stderr.write('*** %s\n' % str(e))
+ self.smtp.quit()
+ sys.exit(1)
+
+
+class OutputMailer(Mailer):
+ """Write emails to an output stream, bracketed by lines of '=' characters.
+
+ This is intended for debugging purposes."""
+
+ SEPARATOR = '=' * 75 + '\n'
+
+ def __init__(self, f):
+ self.f = f
+
+ def send(self, lines, to_addrs):
+ self.f.write(self.SEPARATOR)
+ self.f.writelines(lines)
+ self.f.write(self.SEPARATOR)
+
+
+def get_git_dir():
+ """Determine GIT_DIR.
+
+ Determine GIT_DIR either from the GIT_DIR environment variable or
+ from the working directory, using Git's usual rules."""
+
+ try:
+ return read_git_output(['rev-parse', '--git-dir'])
+ except CommandError:
+ sys.stderr.write('fatal: git_multimail: not in a git directory\n')
+ sys.exit(1)
+
+
+class Environment(object):
+ """Describes the environment in which the push is occurring.
+
+ An Environment object encapsulates information about the local
+ environment. For example, it knows how to determine:
+
+ * the name of the repository to which the push occurred
+
+ * what user did the push
+
+ * what users want to be informed about various types of changes.
+
+ An Environment object is expected to have the following methods:
+
+ get_repo_shortname()
+
+ Return a short name for the repository, for display
+ purposes.
+
+ get_repo_path()
+
+ Return the absolute path to the Git repository.
+
+ get_emailprefix()
+
+ Return a string that will be prefixed to every email's
+ subject.
+
+ get_pusher()
+
+ Return the username of the person who pushed the changes.
+ This value is used in the email body to indicate who
+ pushed the change.
+
+ get_pusher_email() (may return None)
+
+ Return the email address of the person who pushed the
+ changes. The value should be a single RFC 2822 email
+ address as a string; e.g., "Joe User <user@example.com>"
+ if available, otherwise "user@example.com". If set, the
+ value is used as the Reply-To address for refchange
+ emails. If it is impossible to determine the pusher's
+ email, this attribute should be set to None (in which case
+ no Reply-To header will be output).
+
+ get_sender()
+
+ Return the address to be used as the 'From' email address
+ in the email envelope.
+
+ get_fromaddr()
+
+ Return the 'From' email address used in the email 'From:'
+ headers. (May be a full RFC 2822 email address like 'Joe
+ User <user@example.com>'.)
+
+ get_administrator()
+
+ Return the name and/or email of the repository
+ administrator. This value is used in the footer as the
+ person to whom requests to be removed from the
+ notification list should be sent. Ideally, it should
+ include a valid email address.
+
+ get_reply_to_refchange()
+ get_reply_to_commit()
+
+ Return the address to use in the email "Reply-To" header,
+ as a string. These can be an RFC 2822 email address, or
+ None to omit the "Reply-To" header.
+ get_reply_to_refchange() is used for refchange emails;
+ get_reply_to_commit() is used for individual commit
+ emails.
+
+ They should also define the following attributes:
+
+ announce_show_shortlog (bool)
+
+ True iff announce emails should include a shortlog.
+
+ refchange_showlog (bool)
+
+ True iff refchanges emails should include a detailed log.
+
+ diffopts (list of strings)
+
+ The options that should be passed to 'git diff' for the
+ summary email. The value should be a list of strings
+ representing words to be passed to the command.
+
+ logopts (list of strings)
+
+ Analogous to diffopts, but contains options passed to
+ 'git log' when generating the detailed log for a set of
+ commits (see refchange_showlog)
+
+ """
+
+ REPO_NAME_RE = re.compile(r'^(?P<name>.+?)(?:\.git)$')
+
+ def __init__(self, osenv=None):
+ self.osenv = osenv or os.environ
+ self.announce_show_shortlog = False
+ self.maxcommitemails = 500
+ self.diffopts = ['--stat', '--summary', '--find-copies-harder']
+ self.logopts = []
+ self.refchange_showlog = False
+
+ self.COMPUTED_KEYS = [
+ 'administrator',
+ 'charset',
+ 'emailprefix',
+ 'fromaddr',
+ 'pusher',
+ 'pusher_email',
+ 'repo_path',
+ 'repo_shortname',
+ 'sender',
+ ]
+
+ self._values = None
+
+ def get_repo_shortname(self):
+ """Use the last part of the repo path, with ".git" stripped off if present."""
+
+ basename = os.path.basename(os.path.abspath(self.get_repo_path()))
+ m = self.REPO_NAME_RE.match(basename)
+ if m:
+ return m.group('name')
+ else:
+ return basename
+
+ def get_pusher(self):
+ raise NotImplementedError()
+
+ def get_pusher_email(self):
+ return None
+
+ def get_administrator(self):
+ return 'the administrator of this repository'
+
+ def get_emailprefix(self):
+ return ''
+
+ def get_repo_path(self):
+ if read_git_output(['rev-parse', '--is-bare-repository']) == 'true':
+ path = get_git_dir()
+ else:
+ path = read_git_output(['rev-parse', '--show-toplevel'])
+ return os.path.abspath(path)
+
+ def get_charset(self):
+ return CHARSET
+
+ def get_values(self):
+ """Return a dictionary {keyword : expansion} for this Environment.
+
+ This method is called by Change._compute_values(). The keys
+ in the returned dictionary are available to be used in any of
+ the templates. The dictionary is created by calling
+ self.get_NAME() for each of the attributes named in
+ COMPUTED_KEYS and recording those that do not return None.
+ The return value is always a new dictionary."""
+
+ if self._values is None:
+ values = {}
+
+ for key in self.COMPUTED_KEYS:
+ value = getattr(self, 'get_%s' % (key,))()
+ if value is not None:
+ values[key] = value
+
+ self._values = values
+
+ return self._values.copy()
+
+ def get_refchange_recipients(self, refchange):
+ """Return the recipients for notifications about refchange.
+
+ Return the list of email addresses to which notifications
+ about the specified ReferenceChange should be sent."""
+
+ raise NotImplementedError()
+
+ def get_announce_recipients(self, annotated_tag_change):
+ """Return the recipients for notifications about annotated_tag_change.
+
+ Return the list of email addresses to which notifications
+ about the specified AnnotatedTagChange should be sent."""
+
+ raise NotImplementedError()
+
+ def get_reply_to_refchange(self, refchange):
+ return self.get_pusher_email()
+
+ def get_revision_recipients(self, revision):
+ """Return the recipients for messages about revision.
+
+ Return the list of email addresses to which notifications
+ about the specified Revision should be sent. This method
+ could be overridden, for example, to take into account the
+ contents of the revision when deciding whom to notify about
+ it. For example, there could be a scheme for users to express
+ interest in particular files or subdirectories, and only
+ receive notification emails for revisions that affecting those
+ files."""
+
+ raise NotImplementedError()
+
+ def get_reply_to_commit(self, revision):
+ return revision.author
+
+ def filter_body(self, lines):
+ """Filter the lines intended for an email body.
+
+ lines is an iterable over the lines that would go into the
+ email body. Filter it (e.g., limit the number of lines, the
+ line length, character set, etc.), returning another iterable.
+ See FilterLinesEnvironmentMixin and MaxlinesEnvironmentMixin
+ for classes implementing this functionality."""
+
+ return lines
+
+
+class ConfigEnvironmentMixin(Environment):
+ """A mixin that sets self.config to its constructor's config argument.
+
+ This class's constructor consumes the "config" argument.
+
+ Mixins that need to inspect the config should inherit from this
+ class (1) to make sure that "config" is still in the constructor
+ arguments with its own constructor runs and/or (2) to be sure that
+ self.config is set after construction."""
+
+ def __init__(self, config, **kw):
+ super(ConfigEnvironmentMixin, self).__init__(**kw)
+ self.config = config
+
+
+class ConfigOptionsEnvironmentMixin(ConfigEnvironmentMixin):
+ """An Environment that reads most of its information from "git config"."""
+
+ def __init__(self, config, **kw):
+ super(ConfigOptionsEnvironmentMixin, self).__init__(
+ config=config, **kw
+ )
+
+ self.announce_show_shortlog = config.get_bool(
+ 'announceshortlog', default=self.announce_show_shortlog
+ )
+
+ self.refchange_showlog = config.get_bool(
+ 'refchangeshowlog', default=self.refchange_showlog
+ )
+
+ maxcommitemails = config.get('maxcommitemails')
+ if maxcommitemails is not None:
+ try:
+ self.maxcommitemails = int(maxcommitemails)
+ except ValueError:
+ sys.stderr.write(
+ '*** Malformed value for multimailhook.maxCommitEmails: %s\n' % maxcommitemails
+ + '*** Expected a number. Ignoring.\n'
+ )
+
+ diffopts = config.get('diffopts')
+ if diffopts is not None:
+ self.diffopts = shlex.split(diffopts)
+
+ logopts = config.get('logopts')
+ if logopts is not None:
+ self.logopts = shlex.split(logopts)
+
+ reply_to = config.get('replyTo')
+ self.__reply_to_refchange = config.get('replyToRefchange', default=reply_to)
+ if (
+ self.__reply_to_refchange is not None
+ and self.__reply_to_refchange.lower() == 'author'
+ ):
+ raise ConfigurationException(
+ '"author" is not an allowed setting for replyToRefchange'
+ )
+ self.__reply_to_commit = config.get('replyToCommit', default=reply_to)
+
+ def get_administrator(self):
+ return (
+ self.config.get('administrator')
+ or self.get_sender()
+ or super(ConfigOptionsEnvironmentMixin, self).get_administrator()
+ )
+
+ def get_repo_shortname(self):
+ return (
+ self.config.get('reponame')
+ or super(ConfigOptionsEnvironmentMixin, self).get_repo_shortname()
+ )
+
+ def get_emailprefix(self):
+ emailprefix = self.config.get('emailprefix')
+ if emailprefix and emailprefix.strip():
+ return emailprefix.strip() + ' '
+ else:
+ return '[%s] ' % (self.get_repo_shortname(),)
+
+ def get_sender(self):
+ return self.config.get('envelopesender')
+
+ def get_fromaddr(self):
+ fromaddr = self.config.get('from')
+ if fromaddr:
+ return fromaddr
+ else:
+ config = Config('user')
+ fromname = config.get('name', default='')
+ fromemail = config.get('email', default='')
+ if fromemail:
+ return formataddr([fromname, fromemail])
+ else:
+ return self.get_sender()
+
+ def get_reply_to_refchange(self, refchange):
+ if self.__reply_to_refchange is None:
+ return super(ConfigOptionsEnvironmentMixin, self).get_reply_to_refchange(refchange)
+ elif self.__reply_to_refchange.lower() == 'pusher':
+ return self.get_pusher_email()
+ elif self.__reply_to_refchange.lower() == 'none':
+ return None
+ else:
+ return self.__reply_to_refchange
+
+ def get_reply_to_commit(self, revision):
+ if self.__reply_to_commit is None:
+ return super(ConfigOptionsEnvironmentMixin, self).get_reply_to_commit(revision)
+ elif self.__reply_to_commit.lower() == 'author':
+ return revision.get_author()
+ elif self.__reply_to_commit.lower() == 'pusher':
+ return self.get_pusher_email()
+ elif self.__reply_to_commit.lower() == 'none':
+ return None
+ else:
+ return self.__reply_to_commit
+
+
+class FilterLinesEnvironmentMixin(Environment):
+ """Handle encoding and maximum line length of body lines.
+
+ emailmaxlinelength (int or None)
+
+ The maximum length of any single line in the email body.
+ Longer lines are truncated at that length with ' [...]'
+ appended.
+
+ strict_utf8 (bool)
+
+ If this field is set to True, then the email body text is
+ expected to be UTF-8. Any invalid characters are
+ converted to U+FFFD, the Unicode replacement character
+ (encoded as UTF-8, of course).
+
+ """
+
+ def __init__(self, strict_utf8=True, emailmaxlinelength=500, **kw):
+ super(FilterLinesEnvironmentMixin, self).__init__(**kw)
+ self.__strict_utf8 = strict_utf8
+ self.__emailmaxlinelength = emailmaxlinelength
+
+ def filter_body(self, lines):
+ lines = super(FilterLinesEnvironmentMixin, self).filter_body(lines)
+ if self.__strict_utf8:
+ lines = (line.decode(ENCODING, 'replace') for line in lines)
+ # Limit the line length in Unicode-space to avoid
+ # splitting characters:
+ if self.__emailmaxlinelength:
+ lines = limit_linelength(lines, self.__emailmaxlinelength)
+ lines = (line.encode(ENCODING, 'replace') for line in lines)
+ elif self.__emailmaxlinelength:
+ lines = limit_linelength(lines, self.__emailmaxlinelength)
+
+ return lines
+
+
+class ConfigFilterLinesEnvironmentMixin(
+ ConfigEnvironmentMixin,
+ FilterLinesEnvironmentMixin,
+ ):
+ """Handle encoding and maximum line length based on config."""
+
+ def __init__(self, config, **kw):
+ strict_utf8 = config.get_bool('emailstrictutf8', default=None)
+ if strict_utf8 is not None:
+ kw['strict_utf8'] = strict_utf8
+
+ emailmaxlinelength = config.get('emailmaxlinelength')
+ if emailmaxlinelength is not None:
+ kw['emailmaxlinelength'] = int(emailmaxlinelength)
+
+ super(ConfigFilterLinesEnvironmentMixin, self).__init__(
+ config=config, **kw
+ )
+
+
+class MaxlinesEnvironmentMixin(Environment):
+ """Limit the email body to a specified number of lines."""
+
+ def __init__(self, emailmaxlines, **kw):
+ super(MaxlinesEnvironmentMixin, self).__init__(**kw)
+ self.__emailmaxlines = emailmaxlines
+
+ def filter_body(self, lines):
+ lines = super(MaxlinesEnvironmentMixin, self).filter_body(lines)
+ if self.__emailmaxlines:
+ lines = limit_lines(lines, self.__emailmaxlines)
+ return lines
+
+
+class ConfigMaxlinesEnvironmentMixin(
+ ConfigEnvironmentMixin,
+ MaxlinesEnvironmentMixin,
+ ):
+ """Limit the email body to the number of lines specified in config."""
+
+ def __init__(self, config, **kw):
+ emailmaxlines = int(config.get('emailmaxlines', default='0'))
+ super(ConfigMaxlinesEnvironmentMixin, self).__init__(
+ config=config,
+ emailmaxlines=emailmaxlines,
+ **kw
+ )
+
+
+class PusherDomainEnvironmentMixin(ConfigEnvironmentMixin):
+ """Deduce pusher_email from pusher by appending an emaildomain."""
+
+ def __init__(self, **kw):
+ super(PusherDomainEnvironmentMixin, self).__init__(**kw)
+ self.__emaildomain = self.config.get('emaildomain')
+
+ def get_pusher_email(self):
+ if self.__emaildomain:
+ # Derive the pusher's full email address in the default way:
+ return '%s@%s' % (self.get_pusher(), self.__emaildomain)
+ else:
+ return super(PusherDomainEnvironmentMixin, self).get_pusher_email()
+
+
+class StaticRecipientsEnvironmentMixin(Environment):
+ """Set recipients statically based on constructor parameters."""
+
+ def __init__(
+ self,
+ refchange_recipients, announce_recipients, revision_recipients,
+ **kw
+ ):
+ super(StaticRecipientsEnvironmentMixin, self).__init__(**kw)
+
+ # The recipients for various types of notification emails, as
+ # RFC 2822 email addresses separated by commas (or the empty
+ # string if no recipients are configured). Although there is
+ # a mechanism to choose the recipient lists based on on the
+ # actual *contents* of the change being reported, we only
+ # choose based on the *type* of the change. Therefore we can
+ # compute them once and for all:
+ self.__refchange_recipients = refchange_recipients
+ self.__announce_recipients = announce_recipients
+ self.__revision_recipients = revision_recipients
+
+ def get_refchange_recipients(self, refchange):
+ return self.__refchange_recipients
+
+ def get_announce_recipients(self, annotated_tag_change):
+ return self.__announce_recipients
+
+ def get_revision_recipients(self, revision):
+ return self.__revision_recipients
+
+
+class ConfigRecipientsEnvironmentMixin(
+ ConfigEnvironmentMixin,
+ StaticRecipientsEnvironmentMixin
+ ):
+ """Determine recipients statically based on config."""
+
+ def __init__(self, config, **kw):
+ super(ConfigRecipientsEnvironmentMixin, self).__init__(
+ config=config,
+ refchange_recipients=self._get_recipients(
+ config, 'refchangelist', 'mailinglist',
+ ),
+ announce_recipients=self._get_recipients(
+ config, 'announcelist', 'refchangelist', 'mailinglist',
+ ),
+ revision_recipients=self._get_recipients(
+ config, 'commitlist', 'mailinglist',
+ ),
+ **kw
+ )
+
+ def _get_recipients(self, config, *names):
+ """Return the recipients for a particular type of message.
+
+ Return the list of email addresses to which a particular type
+ of notification email should be sent, by looking at the config
+ value for "multimailhook.$name" for each of names. Use the
+ value from the first name that is configured. The return
+ value is a (possibly empty) string containing RFC 2822 email
+ addresses separated by commas. If no configuration could be
+ found, raise a ConfigurationException."""
+
+ for name in names:
+ retval = config.get_recipients(name)
+ if retval is not None:
+ return retval
+ if len(names) == 1:
+ hint = 'Please set "%s.%s"' % (config.section, name)
+ else:
+ hint = (
+ 'Please set one of the following:\n "%s"'
+ % ('"\n "'.join('%s.%s' % (config.section, name) for name in names))
+ )
+
+ raise ConfigurationException(
+ 'The list of recipients for %s is not configured.\n%s' % (names[0], hint)
+ )
+
+
+class ProjectdescEnvironmentMixin(Environment):
+ """Make a "projectdesc" value available for templates.
+
+ By default, it is set to the first line of $GIT_DIR/description
+ (if that file is present and appears to be set meaningfully)."""
+
+ def __init__(self, **kw):
+ super(ProjectdescEnvironmentMixin, self).__init__(**kw)
+ self.COMPUTED_KEYS += ['projectdesc']
+
+ def get_projectdesc(self):
+ """Return a one-line descripition of the project."""
+
+ git_dir = get_git_dir()
+ try:
+ projectdesc = open(os.path.join(git_dir, 'description')).readline().strip()
+ if projectdesc and not projectdesc.startswith('Unnamed repository'):
+ return projectdesc
+ except IOError:
+ pass
+
+ return 'UNNAMED PROJECT'
+
+
+class GenericEnvironmentMixin(Environment):
+ def get_pusher(self):
+ return self.osenv.get('USER', 'unknown user')
+
+
+class GenericEnvironment(
+ ProjectdescEnvironmentMixin,
+ ConfigMaxlinesEnvironmentMixin,
+ ConfigFilterLinesEnvironmentMixin,
+ ConfigRecipientsEnvironmentMixin,
+ PusherDomainEnvironmentMixin,
+ ConfigOptionsEnvironmentMixin,
+ GenericEnvironmentMixin,
+ Environment,
+ ):
+ pass
+
+
+class GitoliteEnvironmentMixin(Environment):
+ def get_repo_shortname(self):
+ # The gitolite environment variable $GL_REPO is a pretty good
+ # repo_shortname (though it's probably not as good as a value
+ # the user might have explicitly put in his config).
+ return (
+ self.osenv.get('GL_REPO', None)
+ or super(GitoliteEnvironmentMixin, self).get_repo_shortname()
+ )
+
+ def get_pusher(self):
+ return self.osenv.get('GL_USER', 'unknown user')
+
+
+class GitoliteEnvironment(
+ ProjectdescEnvironmentMixin,
+ ConfigMaxlinesEnvironmentMixin,
+ ConfigFilterLinesEnvironmentMixin,
+ ConfigRecipientsEnvironmentMixin,
+ PusherDomainEnvironmentMixin,
+ ConfigOptionsEnvironmentMixin,
+ GitoliteEnvironmentMixin,
+ Environment,
+ ):
+ pass
+
+
+class Push(object):
+ """Represent an entire push (i.e., a group of ReferenceChanges).
+
+ It is easy to figure out what commits were added to a *branch* by
+ a Reference change:
+
+ git rev-list change.old..change.new
+
+ or removed from a *branch*:
+
+ git rev-list change.new..change.old
+
+ But it is not quite so trivial to determine which entirely new
+ commits were added to the *repository* by a push and which old
+ commits were discarded by a push. A big part of the job of this
+ class is to figure out these things, and to make sure that new
+ commits are only detailed once even if they were added to multiple
+ references.
+
+ The first step is to determine the "other" references--those
+ unaffected by the current push. They are computed by
+ Push._compute_other_ref_sha1s() by listing all references then
+ removing any affected by this push.
+
+ The commits contained in the repository before this push were
+
+ git rev-list other1 other2 other3 ... change1.old change2.old ...
+
+ Where "changeN.old" is the old value of one of the references
+ affected by this push.
+
+ The commits contained in the repository after this push are
+
+ git rev-list other1 other2 other3 ... change1.new change2.new ...
+
+ The commits added by this push are the difference between these
+ two sets, which can be written
+
+ git rev-list \
+ ^other1 ^other2 ... \
+ ^change1.old ^change2.old ... \
+ change1.new change2.new ...
+
+ The commits removed by this push can be computed by
+
+ git rev-list \
+ ^other1 ^other2 ... \
+ ^change1.new ^change2.new ... \
+ change1.old change2.old ...
+
+ The last point is that it is possible that other pushes are
+ occurring simultaneously to this one, so reference values can
+ change at any time. It is impossible to eliminate all race
+ conditions, but we reduce the window of time during which problems
+ can occur by translating reference names to SHA1s as soon as
+ possible and working with SHA1s thereafter (because SHA1s are
+ immutable)."""
+
+ # A map {(changeclass, changetype) : integer} specifying the order
+ # that reference changes will be processed if multiple reference
+ # changes are included in a single push. The order is significant
+ # mostly because new commit notifications are threaded together
+ # with the first reference change that includes the commit. The
+ # following order thus causes commits to be grouped with branch
+ # changes (as opposed to tag changes) if possible.
+ SORT_ORDER = dict(
+ (value, i) for (i, value) in enumerate([
+ (BranchChange, 'update'),
+ (BranchChange, 'create'),
+ (AnnotatedTagChange, 'update'),
+ (AnnotatedTagChange, 'create'),
+ (NonAnnotatedTagChange, 'update'),
+ (NonAnnotatedTagChange, 'create'),
+ (BranchChange, 'delete'),
+ (AnnotatedTagChange, 'delete'),
+ (NonAnnotatedTagChange, 'delete'),
+ (OtherReferenceChange, 'update'),
+ (OtherReferenceChange, 'create'),
+ (OtherReferenceChange, 'delete'),
+ ])
+ )
+
+ def __init__(self, changes):
+ self.changes = sorted(changes, key=self._sort_key)
+
+ # The SHA-1s of commits referred to by references unaffected
+ # by this push:
+ other_ref_sha1s = self._compute_other_ref_sha1s()
+
+ self._old_rev_exclusion_spec = self._compute_rev_exclusion_spec(
+ other_ref_sha1s.union(
+ change.old.sha1
+ for change in self.changes
+ if change.old.type in ['commit', 'tag']
+ )
+ )
+ self._new_rev_exclusion_spec = self._compute_rev_exclusion_spec(
+ other_ref_sha1s.union(
+ change.new.sha1
+ for change in self.changes
+ if change.new.type in ['commit', 'tag']
+ )
+ )
+
+ @classmethod
+ def _sort_key(klass, change):
+ return (klass.SORT_ORDER[change.__class__, change.change_type], change.refname,)
+
+ def _compute_other_ref_sha1s(self):
+ """Return the GitObjects referred to by references unaffected by this push."""
+
+ # The refnames being changed by this push:
+ updated_refs = set(
+ change.refname
+ for change in self.changes
+ )
+
+ # The SHA-1s of commits referred to by all references in this
+ # repository *except* updated_refs:
+ sha1s = set()
+ fmt = (
+ '%(objectname) %(objecttype) %(refname)\n'
+ '%(*objectname) %(*objecttype) %(refname)'
+ )
+ for line in read_git_lines(['for-each-ref', '--format=%s' % (fmt,)]):
+ (sha1, type, name) = line.split(' ', 2)
+ if sha1 and type == 'commit' and name not in updated_refs:
+ sha1s.add(sha1)
+
+ return sha1s
+
+ def _compute_rev_exclusion_spec(self, sha1s):
+ """Return an exclusion specification for 'git rev-list'.
+
+ git_objects is an iterable over GitObject instances. Return a
+ string that can be passed to the standard input of 'git
+ rev-list --stdin' to exclude all of the commits referred to by
+ git_objects."""
+
+ return ''.join(
+ ['^%s\n' % (sha1,) for sha1 in sorted(sha1s)]
+ )
+
+ def get_new_commits(self, reference_change=None):
+ """Return a list of commits added by this push.
+
+ Return a list of the object names of commits that were added
+ by the part of this push represented by reference_change. If
+ reference_change is None, then return a list of *all* commits
+ added by this push."""
+
+ if not reference_change:
+ new_revs = sorted(
+ change.new.sha1
+ for change in self.changes
+ if change.new
+ )
+ elif not reference_change.new.commit_sha1:
+ return []
+ else:
+ new_revs = [reference_change.new.commit_sha1]
+
+ cmd = ['rev-list', '--stdin'] + new_revs
+ return read_git_lines(cmd, input=self._old_rev_exclusion_spec)
+
+ def get_discarded_commits(self, reference_change):
+ """Return a list of commits discarded by this push.
+
+ Return a list of the object names of commits that were
+ entirely discarded from the repository by the part of this
+ push represented by reference_change."""
+
+ if not reference_change.old.commit_sha1:
+ return []
+ else:
+ old_revs = [reference_change.old.commit_sha1]
+
+ cmd = ['rev-list', '--stdin'] + old_revs
+ return read_git_lines(cmd, input=self._new_rev_exclusion_spec)
+
+ def send_emails(self, mailer, body_filter=None):
+ """Use send all of the notification emails needed for this push.
+
+ Use send all of the notification emails (including reference
+ change emails and commit emails) needed for this push. Send
+ the emails using mailer. If body_filter is not None, then use
+ it to filter the lines that are intended for the email
+ body."""
+
+ # The sha1s of commits that were introduced by this push.
+ # They will be removed from this set as they are processed, to
+ # guarantee that one (and only one) email is generated for
+ # each new commit.
+ unhandled_sha1s = set(self.get_new_commits())
+ for change in self.changes:
+ # Check if we've got anyone to send to
+ if not change.recipients:
+ sys.stderr.write(
+ '*** no recipients configured so no email will be sent\n'
+ '*** for %r update %s->%s\n'
+ % (change.refname, change.old.sha1, change.new.sha1,)
+ )
+ else:
+ sys.stderr.write('Sending notification emails to: %s\n' % (change.recipients,))
+ mailer.send(change.generate_email(self, body_filter), change.recipients)
+
+ sha1s = []
+ for sha1 in reversed(list(self.get_new_commits(change))):
+ if sha1 in unhandled_sha1s:
+ sha1s.append(sha1)
+ unhandled_sha1s.remove(sha1)
+
+ max_emails = change.environment.maxcommitemails
+ if max_emails and len(sha1s) > max_emails:
+ sys.stderr.write(
+ '*** Too many new commits (%d), not sending commit emails.\n' % len(sha1s)
+ + '*** Try setting multimailhook.maxCommitEmails to a greater value\n'
+ + '*** Currently, multimailhook.maxCommitEmails=%d\n' % max_emails
+ )
+ return
+
+ for (num, sha1) in enumerate(sha1s):
+ rev = Revision(change, GitObject(sha1), num=num+1, tot=len(sha1s))
+ if rev.recipients:
+ mailer.send(rev.generate_email(self, body_filter), rev.recipients)
+
+ # Consistency check:
+ if unhandled_sha1s:
+ sys.stderr.write(
+ 'ERROR: No emails were sent for the following new commits:\n'
+ ' %s\n'
+ % ('\n '.join(sorted(unhandled_sha1s)),)
+ )
+
+
+def run_as_post_receive_hook(environment, mailer):
+ changes = []
+ for line in sys.stdin:
+ (oldrev, newrev, refname) = line.strip().split(' ', 2)
+ changes.append(
+ ReferenceChange.create(environment, oldrev, newrev, refname)
+ )
+ push = Push(changes)
+ push.send_emails(mailer, body_filter=environment.filter_body)
+
+
+def run_as_update_hook(environment, mailer, refname, oldrev, newrev):
+ changes = [
+ ReferenceChange.create(
+ environment,
+ read_git_output(['rev-parse', '--verify', oldrev]),
+ read_git_output(['rev-parse', '--verify', newrev]),
+ refname,
+ ),
+ ]
+ push = Push(changes)
+ push.send_emails(mailer, body_filter=environment.filter_body)
+
+
+def choose_mailer(config, environment):
+ mailer = config.get('mailer', default='sendmail')
+
+ if mailer == 'smtp':
+ smtpserver = config.get('smtpserver', default='localhost')
+ mailer = SMTPMailer(
+ envelopesender=(environment.get_sender() or environment.get_fromaddr()),
+ smtpserver=smtpserver,
+ )
+ elif mailer == 'sendmail':
+ command = config.get('sendmailcommand')
+ if command:
+ command = shlex.split(command)
+ mailer = SendMailer(command=command, envelopesender=environment.get_sender())
+ else:
+ sys.stderr.write(
+ 'fatal: multimailhook.mailer is set to an incorrect value: "%s"\n' % mailer
+ + 'please use one of "smtp" or "sendmail".\n'
+ )
+ sys.exit(1)
+ return mailer
+
+
+KNOWN_ENVIRONMENTS = {
+ 'generic' : GenericEnvironmentMixin,
+ 'gitolite' : GitoliteEnvironmentMixin,
+ }
+
+
+def choose_environment(config, osenv=None, env=None, recipients=None):
+ if not osenv:
+ osenv = os.environ
+
+ environment_mixins = [
+ ProjectdescEnvironmentMixin,
+ ConfigMaxlinesEnvironmentMixin,
+ ConfigFilterLinesEnvironmentMixin,
+ PusherDomainEnvironmentMixin,
+ ConfigOptionsEnvironmentMixin,
+ ]
+ environment_kw = {
+ 'osenv' : osenv,
+ 'config' : config,
+ }
+
+ if not env:
+ env = config.get('environment')
+
+ if not env:
+ if 'GL_USER' in osenv and 'GL_REPO' in osenv:
+ env = 'gitolite'
+ else:
+ env = 'generic'
+
+ environment_mixins.append(KNOWN_ENVIRONMENTS[env])
+
+ if recipients:
+ environment_mixins.insert(0, StaticRecipientsEnvironmentMixin)
+ environment_kw['refchange_recipients'] = recipients
+ environment_kw['announce_recipients'] = recipients
+ environment_kw['revision_recipients'] = recipients
+ else:
+ environment_mixins.insert(0, ConfigRecipientsEnvironmentMixin)
+
+ environment_klass = type(
+ 'EffectiveEnvironment',
+ tuple(environment_mixins) + (Environment,),
+ {},
+ )
+ return environment_klass(**environment_kw)
+
+
+def main(args):
+ parser = optparse.OptionParser(
+ description=__doc__,
+ usage='%prog [OPTIONS]\n or: %prog [OPTIONS] REFNAME OLDREV NEWREV',
+ )
+
+ parser.add_option(
+ '--environment', '--env', action='store', type='choice',
+ choices=['generic', 'gitolite'], default=None,
+ help=(
+ 'Choose type of environment is in use. Default is taken from '
+ 'multimailhook.environment if set; otherwise "generic".'
+ ),
+ )
+ parser.add_option(
+ '--stdout', action='store_true', default=False,
+ help='Output emails to stdout rather than sending them.',
+ )
+ parser.add_option(
+ '--recipients', action='store', default=None,
+ help='Set list of email recipients for all types of emails.',
+ )
+ parser.add_option(
+ '--show-env', action='store_true', default=False,
+ help=(
+ 'Write to stderr the values determined for the environment '
+ '(intended for debugging purposes).'
+ ),
+ )
+
+ (options, args) = parser.parse_args(args)
+
+ config = Config('multimailhook')
+
+ try:
+ environment = choose_environment(
+ config, osenv=os.environ,
+ env=options.environment,
+ recipients=options.recipients,
+ )
+
+ if options.show_env:
+ sys.stderr.write('Environment values:\n')
+ for (k,v) in sorted(environment.get_values().items()):
+ sys.stderr.write(' %s : %r\n' % (k,v))
+ sys.stderr.write('\n')
+
+ if options.stdout:
+ mailer = OutputMailer(sys.stdout)
+ else:
+ mailer = choose_mailer(config, environment)
+
+ # Dual mode: if arguments were specified on the command line, run
+ # like an update hook; otherwise, run as a post-receive hook.
+ if args:
+ if len(args) != 3:
+ parser.error('Need zero or three non-option arguments')
+ (refname, oldrev, newrev) = args
+ run_as_update_hook(environment, mailer, refname, oldrev, newrev)
+ else:
+ run_as_post_receive_hook(environment, mailer)
+ except ConfigurationException, e:
+ sys.exit(str(e))
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/contrib/hooks/multimail/migrate-mailhook-config b/contrib/hooks/multimail/migrate-mailhook-config
new file mode 100755
index 0000000..04eeaac
--- /dev/null
+++ b/contrib/hooks/multimail/migrate-mailhook-config
@@ -0,0 +1,269 @@
+#! /usr/bin/env python2
+
+"""Migrate a post-receive-email configuration to be usable with git_multimail.py.
+
+See README.migrate-from-post-receive-email for more information.
+
+"""
+
+import sys
+import optparse
+
+from git_multimail import CommandError
+from git_multimail import Config
+from git_multimail import read_output
+
+
+OLD_NAMES = [
+ 'mailinglist',
+ 'announcelist',
+ 'envelopesender',
+ 'emailprefix',
+ 'showrev',
+ 'emailmaxlines',
+ 'diffopts',
+ ]
+
+NEW_NAMES = [
+ 'environment',
+ 'reponame',
+ 'mailinglist',
+ 'refchangelist',
+ 'commitlist',
+ 'announcelist',
+ 'announceshortlog',
+ 'envelopesender',
+ 'administrator',
+ 'emailprefix',
+ 'emailmaxlines',
+ 'diffopts',
+ 'emaildomain',
+ ]
+
+
+INFO = """\
+
+SUCCESS!
+
+Your post-receive-email configuration has been converted to
+git-multimail format. Please see README and
+README.migrate-from-post-receive-email to learn about other
+git-multimail configuration possibilities.
+
+For example, git-multimail has the following new options with no
+equivalent in post-receive-email. You might want to read about them
+to see if they would be useful in your situation:
+
+"""
+
+
+def _check_old_config_exists(old):
+ """Check that at least one old configuration value is set."""
+
+ for name in OLD_NAMES:
+ if old.has_key(name):
+ return True
+
+ return False
+
+
+def _check_new_config_clear(new):
+ """Check that none of the new configuration names are set."""
+
+ retval = True
+ for name in NEW_NAMES:
+ if new.has_key(name):
+ if retval:
+ sys.stderr.write('INFO: The following configuration values already exist:\n\n')
+ sys.stderr.write(' "%s.%s"\n' % (new.section, name))
+ retval = False
+
+ return retval
+
+
+def erase_values(config, names):
+ for name in names:
+ if config.has_key(name):
+ try:
+ sys.stderr.write('...unsetting "%s.%s"\n' % (config.section, name))
+ config.unset_all(name)
+ except CommandError:
+ sys.stderr.write(
+ '\nWARNING: could not unset "%s.%s". '
+ 'Perhaps it is not set at the --local level?\n\n'
+ % (config.section, name)
+ )
+
+
+def is_section_empty(section, local):
+ """Return True iff the specified configuration section is empty.
+
+ Iff local is True, use the --local option when invoking 'git
+ config'."""
+
+ if local:
+ local_option = ['--local']
+ else:
+ local_option = []
+
+ try:
+ read_output(
+ ['git', 'config']
+ + local_option
+ + ['--get-regexp', '^%s\.' % (section,)]
+ )
+ except CommandError, e:
+ if e.retcode == 1:
+ # This means that no settings were found.
+ return True
+ else:
+ raise
+ else:
+ return False
+
+
+def remove_section_if_empty(section):
+ """If the specified configuration section is empty, delete it."""
+
+ try:
+ empty = is_section_empty(section, local=True)
+ except CommandError:
+ # Older versions of git do not support the --local option, so
+ # if the first attempt fails, try without --local.
+ try:
+ empty = is_section_empty(section, local=False)
+ except CommandError:
+ sys.stderr.write(
+ '\nINFO: If configuration section "%s.*" is empty, you might want '
+ 'to delete it.\n\n'
+ % (section,)
+ )
+ return
+
+ if empty:
+ sys.stderr.write('...removing section "%s.*"\n' % (section,))
+ read_output(['git', 'config', '--remove-section', section])
+ else:
+ sys.stderr.write(
+ '\nINFO: Configuration section "%s.*" still has contents. '
+ 'It will not be deleted.\n\n'
+ % (section,)
+ )
+
+
+def migrate_config(strict=False, retain=False, overwrite=False):
+ old = Config('hooks')
+ new = Config('multimailhook')
+ if not _check_old_config_exists(old):
+ sys.exit(
+ 'Your repository has no post-receive-email configuration. '
+ 'Nothing to do.'
+ )
+ if not _check_new_config_clear(new):
+ if overwrite:
+ sys.stderr.write('\nWARNING: Erasing the above values...\n\n')
+ erase_values(new, NEW_NAMES)
+ else:
+ sys.exit(
+ '\nERROR: Refusing to overwrite existing values. Use the --overwrite\n'
+ 'option to continue anyway.'
+ )
+
+ name = 'showrev'
+ if old.has_key(name):
+ msg = 'git-multimail does not support "%s.%s"' % (old.section, name,)
+ if strict:
+ sys.exit(
+ 'ERROR: %s.\n'
+ 'Please unset that value then try again, or run without --strict.'
+ % (msg,)
+ )
+ else:
+ sys.stderr.write('\nWARNING: %s (ignoring).\n\n' % (msg,))
+
+ for name in ['mailinglist', 'announcelist']:
+ if old.has_key(name):
+ sys.stderr.write(
+ '...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
+ )
+ new.set_recipients(name, old.get_recipients(name))
+
+ if strict:
+ sys.stderr.write(
+ '...setting "%s.commitlist" to the empty string\n' % (new.section,)
+ )
+ new.set_recipients('commitlist', '')
+ sys.stderr.write(
+ '...setting "%s.announceshortlog" to "true"\n' % (new.section,)
+ )
+ new.set('announceshortlog', 'true')
+
+ for name in ['envelopesender', 'emailmaxlines', 'diffopts']:
+ if old.has_key(name):
+ sys.stderr.write(
+ '...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
+ )
+ new.set(name, old.get(name))
+
+ name = 'emailprefix'
+ if old.has_key(name):
+ sys.stderr.write(
+ '...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
+ )
+ new.set(name, old.get(name))
+ elif strict:
+ sys.stderr.write(
+ '...setting "%s.%s" to "[SCM]" to preserve old subject lines\n'
+ % (new.section, name)
+ )
+ new.set(name, '[SCM]')
+
+ if not retain:
+ erase_values(old, OLD_NAMES)
+ remove_section_if_empty(old.section)
+
+ sys.stderr.write(INFO)
+ for name in NEW_NAMES:
+ if name not in OLD_NAMES:
+ sys.stderr.write(' "%s.%s"\n' % (new.section, name,))
+ sys.stderr.write('\n')
+
+
+def main(args):
+ parser = optparse.OptionParser(
+ description=__doc__,
+ usage='%prog [OPTIONS]',
+ )
+
+ parser.add_option(
+ '--strict', action='store_true', default=False,
+ help=(
+ 'Slavishly configure git-multimail as closely as possible to '
+ 'the post-receive-email configuration. Default is to turn '
+ 'on some new features that have no equivalent in post-receive-email.'
+ ),
+ )
+ parser.add_option(
+ '--retain', action='store_true', default=False,
+ help=(
+ 'Retain the post-receive-email configuration values. '
+ 'Default is to delete them after the new values are set.'
+ ),
+ )
+ parser.add_option(
+ '--overwrite', action='store_true', default=False,
+ help=(
+ 'Overwrite any existing git-multimail configuration settings. '
+ 'Default is to abort if such settings already exist.'
+ ),
+ )
+
+ (options, args) = parser.parse_args(args)
+
+ if args:
+ parser.error('Unexpected arguments: %s' % (' '.join(args),))
+
+ migrate_config(strict=options.strict, retain=options.retain, overwrite=options.overwrite)
+
+
+main(sys.argv[1:])
diff --git a/contrib/hooks/multimail/post-receive b/contrib/hooks/multimail/post-receive
new file mode 100755
index 0000000..93ebb43
--- /dev/null
+++ b/contrib/hooks/multimail/post-receive
@@ -0,0 +1,90 @@
+#! /usr/bin/env python2
+
+"""Example post-receive hook based on git-multimail.
+
+This script is a simple example of a post-receive hook implemented
+using git_multimail.py as a Python module. It is intended to be
+customized before use; see the comments in the script to help you get
+started.
+
+It is possible to use git_multimail.py itself as a post-receive or
+update hook, configured via git config settings and/or command-line
+parameters. But for more flexibility, it can also be imported as a
+Python module by a custom post-receive script as done here. The
+latter has the following advantages:
+
+* The tool's behavior can be customized using arbitrary Python code,
+ without having to edit git_multimail.py.
+
+* Configuration settings can be read from other sources; for example,
+ user names and email addresses could be read from LDAP or from a
+ database. Or the settings can even be hardcoded in the importing
+ Python script, if this is preferred.
+
+This script is a very basic example of how to use git_multimail.py as
+a module. The comments below explain some of the points at which the
+script's behavior could be changed or customized.
+
+"""
+
+import sys
+import os
+
+# If necessary, add the path to the directory containing
+# git_multimail.py to the Python path as follows. (This is not
+# necessary if git_multimail.py is in the same directory as this
+# script):
+
+#LIBDIR = 'path/to/directory/containing/module'
+#sys.path.insert(0, LIBDIR)
+
+import git_multimail
+
+
+# It is possible to modify the output templates here; e.g.:
+
+#git_multimail.FOOTER_TEMPLATE = """\
+#
+#-- \n\
+#This email was generated by the wonderful git-multimail tool.
+#"""
+
+
+# Specify which "git config" section contains the configuration for
+# git-multimail:
+config = git_multimail.Config('multimailhook')
+
+
+# Select the type of environment:
+environment = git_multimail.GenericEnvironment(config=config)
+#environment = git_multimail.GitoliteEnvironment(config=config)
+
+
+# Choose the method of sending emails based on the git config:
+mailer = git_multimail.choose_mailer(config, environment)
+
+# Alternatively, you may hardcode the mailer using code like one of
+# the following:
+
+# Use "/usr/sbin/sendmail -t" to send emails. The envelopesender
+# argument is optional:
+#mailer = git_multimail.SendMailer(
+# command=['/usr/sbin/sendmail', '-t'],
+# envelopesender='git-repo@example.com',
+# )
+
+# Use Python's smtplib to send emails. Both arguments are required.
+#mailer = git_multimail.SMTPMailer(
+# envelopesender='git-repo@example.com',
+# # The smtpserver argument can also include a port number; e.g.,
+# # smtpserver='mail.example.com:25'
+# smtpserver='mail.example.com',
+# )
+
+# OutputMailer is intended only for testing; it writes the emails to
+# the specified file stream.
+#mailer = git_multimail.OutputMailer(sys.stdout)
+
+
+# Read changes from stdin and send notification emails:
+git_multimail.run_as_post_receive_hook(environment, mailer)
diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email
index 0e5b72d..8ee410f 100755
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -2,10 +2,19 @@
#
# Copyright (c) 2007 Andy Parkins
#
-# An example hook script to mail out commit update information. This hook
-# sends emails listing new revisions to the repository introduced by the
-# change being reported. The rule is that (for branch updates) each commit
-# will appear on one email and one email only.
+# An example hook script to mail out commit update information.
+#
+# NOTE: This script is no longer under active development. There
+# is another script, git-multimail, which is more capable and
+# configurable and is largely backwards-compatible with this script;
+# please see "contrib/hooks/multimail/". For instructions on how to
+# migrate from post-receive-email to git-multimail, please see
+# "README.migrate-from-post-receive-email" in that directory.
+#
+# This hook sends emails listing new revisions to the repository
+# introduced by the change being reported. The rule is that (for
+# branch updates) each commit will appear on one email and one email
+# only.
#
# This hook is stored in the contrib/hooks directory. Your distribution
# will have put this somewhere standard. You should make this script
@@ -233,6 +242,9 @@ generate_email_header()
cat <<-EOF
To: $recipients
Subject: ${emailprefix}$projectdesc $refname_type $short_refname ${change_type}d. $describe
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=utf-8
+ Content-Transfer-Encoding: 8bit
X-Git-Refname: $refname
X-Git-Reftype: $refname_type
X-Git-Oldrev: $oldrev
@@ -462,7 +474,7 @@ generate_delete_branch_email()
echo " was $oldrev"
echo ""
echo $LOGBEGIN
- git show -s --pretty=oneline $oldrev
+ git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev
echo $LOGEND
}
@@ -538,11 +550,11 @@ generate_atag_email()
# performed on them
if [ -n "$prevtag" ]; then
# Show changes since the previous release
- git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
+ git shortlog "$prevtag..$newrev"
else
# No previous tag, show all the changes since time
# began
- git rev-list --pretty=short $newrev | git shortlog
+ git shortlog $newrev
fi
;;
*)
@@ -562,7 +574,7 @@ generate_delete_atag_email()
echo " was $oldrev"
echo ""
echo $LOGBEGIN
- git show -s --pretty=oneline $oldrev
+ git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev
echo $LOGEND
}
@@ -608,7 +620,7 @@ generate_general_email()
echo ""
if [ "$newrev_type" = "commit" ]; then
echo $LOGBEGIN
- git show --no-color --root -s --pretty=medium $newrev
+ git diff-tree -s --always --encoding=UTF-8 --pretty=medium $newrev
echo $LOGEND
else
# What can we do here? The tag marks an object that is not
@@ -627,7 +639,7 @@ generate_delete_general_email()
echo " was $oldrev"
echo ""
echo $LOGBEGIN
- git show -s --pretty=oneline $oldrev
+ git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev
echo $LOGEND
}
diff --git a/contrib/mw-to-git/.gitignore b/contrib/mw-to-git/.gitignore
index b919655..ae545b0 100644
--- a/contrib/mw-to-git/.gitignore
+++ b/contrib/mw-to-git/.gitignore
@@ -1 +1,2 @@
git-remote-mediawiki
+git-mw
diff --git a/contrib/mw-to-git/.perlcriticrc b/contrib/mw-to-git/.perlcriticrc
new file mode 100644
index 0000000..5a9955d
--- /dev/null
+++ b/contrib/mw-to-git/.perlcriticrc
@@ -0,0 +1,28 @@
+# These 3 rules demand to add the s, m and x flag to *every* regexp. This is
+# overkill and would be harmful for readability.
+[-RegularExpressions::RequireExtendedFormatting]
+[-RegularExpressions::RequireDotMatchAnything]
+[-RegularExpressions::RequireLineBoundaryMatching]
+
+# This rule says that builtin functions should not be called with parentheses
+# e.g.: (taken from CPAN's documentation)
+# open($handle, '>', $filename); #not ok
+# open $handle, '>', $filename; #ok
+# Applying such a rule would mean modifying a huge number of lines for a
+# question of style.
+[-CodeLayout::ProhibitParensWithBuiltins]
+
+# This rule states that each system call should have its return value checked
+# The problem is that it includes the print call. Checking every print call's
+# return value would be harmful to the code readabilty.
+# This configuration keeps all default function but print.
+[InputOutput::RequireCheckedSyscalls]
+functions = open say close
+
+# This rules demands to add a dependancy for the Readonly module. This is not
+# wished.
+[-ValuesAndExpressions::ProhibitConstantPragma]
+
+# This rule is not really useful (rather a question of style) and produces many
+# warnings among the code.
+[-ValuesAndExpressions::ProhibitNoisyQuotes]
diff --git a/contrib/mw-to-git/Git/Mediawiki.pm b/contrib/mw-to-git/Git/Mediawiki.pm
new file mode 100644
index 0000000..d13c4df
--- /dev/null
+++ b/contrib/mw-to-git/Git/Mediawiki.pm
@@ -0,0 +1,100 @@
+package Git::Mediawiki;
+
+use 5.008;
+use strict;
+use Git;
+
+BEGIN {
+
+our ($VERSION, @ISA, @EXPORT, @EXPORT_OK);
+
+# Totally unstable API.
+$VERSION = '0.01';
+
+require Exporter;
+
+@ISA = qw(Exporter);
+
+@EXPORT = ();
+
+# Methods which can be called as standalone functions as well:
+@EXPORT_OK = qw(clean_filename smudge_filename connect_maybe
+ EMPTY HTTP_CODE_OK HTTP_CODE_PAGE_NOT_FOUND);
+}
+
+# Mediawiki filenames can contain forward slashes. This variable decides by which pattern they should be replaced
+use constant SLASH_REPLACEMENT => '%2F';
+
+# Used to test for empty strings
+use constant EMPTY => q{};
+
+# HTTP codes
+use constant HTTP_CODE_OK => 200;
+use constant HTTP_CODE_PAGE_NOT_FOUND => 404;
+
+sub clean_filename {
+ my $filename = shift;
+ $filename =~ s{@{[SLASH_REPLACEMENT]}}{/}g;
+ # [, ], |, {, and } are forbidden by MediaWiki, even URL-encoded.
+ # Do a variant of URL-encoding, i.e. looks like URL-encoding,
+ # but with _ added to prevent MediaWiki from thinking this is
+ # an actual special character.
+ $filename =~ s/[\[\]\{\}\|]/sprintf("_%%_%x", ord($&))/ge;
+ # If we use the uri escape before
+ # we should unescape here, before anything
+
+ return $filename;
+}
+
+sub smudge_filename {
+ my $filename = shift;
+ $filename =~ s{/}{@{[SLASH_REPLACEMENT]}}g;
+ $filename =~ s/ /_/g;
+ # Decode forbidden characters encoded in clean_filename
+ $filename =~ s/_%_([0-9a-fA-F][0-9a-fA-F])/sprintf('%c', hex($1))/ge;
+ return $filename;
+}
+
+sub connect_maybe {
+ my $wiki = shift;
+ if ($wiki) {
+ return $wiki;
+ }
+
+ my $remote_name = shift;
+ my $remote_url = shift;
+ my ($wiki_login, $wiki_password, $wiki_domain);
+
+ $wiki_login = Git::config("remote.${remote_name}.mwLogin");
+ $wiki_password = Git::config("remote.${remote_name}.mwPassword");
+ $wiki_domain = Git::config("remote.${remote_name}.mwDomain");
+
+ $wiki = MediaWiki::API->new;
+ $wiki->{config}->{api_url} = "${remote_url}/api.php";
+ if ($wiki_login) {
+ my %credential = (
+ 'url' => $remote_url,
+ 'username' => $wiki_login,
+ 'password' => $wiki_password
+ );
+ Git::credential(\%credential);
+ my $request = {lgname => $credential{username},
+ lgpassword => $credential{password},
+ lgdomain => $wiki_domain};
+ if ($wiki->login($request)) {
+ Git::credential(\%credential, 'approve');
+ print {*STDERR} qq(Logged in mediawiki user "$credential{username}".\n);
+ } else {
+ print {*STDERR} qq(Failed to log in mediawiki user "$credential{username}" on ${remote_url}\n);
+ print {*STDERR} ' (error ' .
+ $wiki->{error}->{code} . ': ' .
+ $wiki->{error}->{details} . ")\n";
+ Git::credential(\%credential, 'reject');
+ exit 1;
+ }
+ }
+
+ return $wiki;
+}
+
+1; # Famous last words
diff --git a/contrib/mw-to-git/Makefile b/contrib/mw-to-git/Makefile
index f149719..f206f96 100644
--- a/contrib/mw-to-git/Makefile
+++ b/contrib/mw-to-git/Makefile
@@ -2,16 +2,51 @@
# Copyright (C) 2013
# Matthieu Moy <Matthieu.Moy@imag.fr>
#
-## Build git-remote-mediawiki
+# To build and test:
+#
+# make
+# bin-wrapper/git mw preview Some_page.mw
+# bin-wrapper/git clone mediawiki::http://example.com/wiki/
+#
+# To install, run Git's toplevel 'make install' then run:
+#
+# make install
+GIT_MEDIAWIKI_PM=Git/Mediawiki.pm
SCRIPT_PERL=git-remote-mediawiki.perl
+SCRIPT_PERL+=git-mw.perl
GIT_ROOT_DIR=../..
HERE=contrib/mw-to-git/
SCRIPT_PERL_FULL=$(patsubst %,$(HERE)/%,$(SCRIPT_PERL))
+INSTLIBDIR=$(shell $(MAKE) -C $(GIT_ROOT_DIR)/perl \
+ -s --no-print-directory instlibdir)
all: build
-build install clean:
- $(MAKE) -C $(GIT_ROOT_DIR) SCRIPT_PERL=$(SCRIPT_PERL_FULL) \
- $@-perl-script
+test: all
+ $(MAKE) -C t
+
+check: perlcritic test
+
+install_pm:
+ install $(GIT_MEDIAWIKI_PM) $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM)
+
+build:
+ $(MAKE) -C $(GIT_ROOT_DIR) SCRIPT_PERL="$(SCRIPT_PERL_FULL)" \
+ build-perl-script
+
+install: install_pm
+ $(MAKE) -C $(GIT_ROOT_DIR) SCRIPT_PERL="$(SCRIPT_PERL_FULL)" \
+ install-perl-script
+
+clean:
+ $(MAKE) -C $(GIT_ROOT_DIR) SCRIPT_PERL="$(SCRIPT_PERL_FULL)" \
+ clean-perl-script
+ rm $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM)
+
+perlcritic:
+ perlcritic -5 $(SCRIPT_PERL)
+ -perlcritic -2 $(SCRIPT_PERL)
+
+.PHONY: all test check install_pm install clean perlcritic
diff --git a/contrib/mw-to-git/bin-wrapper/git b/contrib/mw-to-git/bin-wrapper/git
new file mode 100755
index 0000000..6663ae5
--- /dev/null
+++ b/contrib/mw-to-git/bin-wrapper/git
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# git executable wrapper script for Git-Mediawiki to run tests without
+# installing all the scripts and perl packages.
+
+GIT_ROOT_DIR=../../..
+GIT_EXEC_PATH=$(cd "$(dirname "$0")" && cd ${GIT_ROOT_DIR} && pwd)
+
+GITPERLLIB="$GIT_EXEC_PATH"'/contrib/mw-to-git'"${GITPERLLIB:+:$GITPERLLIB}"
+PATH="$GIT_EXEC_PATH"'/contrib/mw-to-git:'"$PATH"
+
+export GITPERLLIB PATH
+
+exec "${GIT_EXEC_PATH}/bin-wrappers/git" "$@"
diff --git a/contrib/mw-to-git/git-mw.perl b/contrib/mw-to-git/git-mw.perl
new file mode 100755
index 0000000..28df3ee
--- /dev/null
+++ b/contrib/mw-to-git/git-mw.perl
@@ -0,0 +1,368 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2013
+# Benoit Person <benoit.person@ensimag.imag.fr>
+# Celestin Matte <celestin.matte@ensimag.imag.fr>
+# License: GPL v2 or later
+
+# Set of tools for git repo with a mediawiki remote.
+# Documentation & bugtracker: https://github.com/moy/Git-Mediawiki/
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+use URI::URL qw(url);
+use LWP::UserAgent;
+use HTML::TreeBuilder;
+
+use Git;
+use MediaWiki::API;
+use Git::Mediawiki qw(clean_filename connect_maybe
+ EMPTY HTTP_CODE_PAGE_NOT_FOUND);
+
+# By default, use UTF-8 to communicate with Git and the user
+binmode STDERR, ':encoding(UTF-8)';
+binmode STDOUT, ':encoding(UTF-8)';
+
+# Global parameters
+my $verbose = 0;
+sub v_print {
+ if ($verbose) {
+ return print {*STDERR} @_;
+ }
+ return;
+}
+
+# Preview parameters
+my $file_name = EMPTY;
+my $remote_name = EMPTY;
+my $preview_file_name = EMPTY;
+my $autoload = 0;
+sub file {
+ $file_name = shift;
+ return $file_name;
+}
+
+my %commands = (
+ 'help' =>
+ [\&help, {}, \&help],
+ 'preview' =>
+ [\&preview, {
+ '<>' => \&file,
+ 'output|o=s' => \$preview_file_name,
+ 'remote|r=s' => \$remote_name,
+ 'autoload|a' => \$autoload
+ }, \&preview_help]
+);
+
+# Search for sub-command
+my $cmd = $commands{'help'};
+for (0..@ARGV-1) {
+ if (defined $commands{$ARGV[$_]}) {
+ $cmd = $commands{$ARGV[$_]};
+ splice @ARGV, $_, 1;
+ last;
+ }
+};
+GetOptions( %{$cmd->[1]},
+ 'help|h' => \&{$cmd->[2]},
+ 'verbose|v' => \$verbose);
+
+# Launch command
+&{$cmd->[0]};
+
+############################# Preview Functions ################################
+
+sub preview_help {
+ print {*STDOUT} <<'END';
+USAGE: git mw preview [--remote|-r <remote name>] [--autoload|-a]
+ [--output|-o <output filename>] [--verbose|-v]
+ <blob> | <filename>
+
+DESCRIPTION:
+Preview is an utiliy to preview local content of a mediawiki repo as if it was
+pushed on the remote.
+
+For that, preview searches for the remote name of the current branch's
+upstream if --remote is not set. If that remote is not found or if it
+is not a mediawiki, it lists all mediawiki remotes configured and asks
+you to replay your command with the --remote option set properly.
+
+Then, it searches for a file named 'filename'. If it's not found in
+the current dir, it will assume it's a blob.
+
+The content retrieved in the file (or in the blob) will then be parsed
+by the remote mediawiki and combined with a template retrieved from
+the mediawiki.
+
+Finally, preview will save the HTML result in a file. and autoload it
+in your default web browser if the option --autoload is present.
+
+OPTIONS:
+ -r <remote name>, --remote <remote name>
+ If the remote is a mediawiki, the template and the parse engine
+ used for the preview will be those of that remote.
+ If not, a list of valid remotes will be shown.
+
+ -a, --autoload
+ Try to load the HTML output in a new tab (or new window) of your
+ default web browser.
+
+ -o <output filename>, --output <output filename>
+ Change the HTML output filename. Default filename is based on the
+ input filename with its extension replaced by '.html'.
+
+ -v, --verbose
+ Show more information on what's going on under the hood.
+END
+ exit;
+}
+
+sub preview {
+ my $wiki;
+ my ($remote_url, $wiki_page_name);
+ my ($new_content, $template);
+ my $file_content;
+
+ if ($file_name eq EMPTY) {
+ die "Missing file argument, see `git mw help`\n";
+ }
+
+ v_print("### Selecting remote\n");
+ if ($remote_name eq EMPTY) {
+ $remote_name = find_upstream_remote_name();
+ if ($remote_name) {
+ $remote_url = mediawiki_remote_url_maybe($remote_name);
+ }
+
+ if (! $remote_url) {
+ my @valid_remotes = find_mediawiki_remotes();
+
+ if ($#valid_remotes == 0) {
+ print {*STDERR} "No mediawiki remote in this repo. \n";
+ exit 1;
+ } else {
+ my $remotes_list = join("\n\t", @valid_remotes);
+ print {*STDERR} <<"MESSAGE";
+There are multiple mediawiki remotes, which of:
+ ${remotes_list}
+do you want ? Use the -r option to specify the remote.
+MESSAGE
+ }
+
+ exit 1;
+ }
+ } else {
+ if (!is_valid_remote($remote_name)) {
+ die "${remote_name} is not a remote\n";
+ }
+
+ $remote_url = mediawiki_remote_url_maybe($remote_name);
+ if (! $remote_url) {
+ die "${remote_name} is not a mediawiki remote\n";
+ }
+ }
+ v_print("selected remote:\n\tname: ${remote_name}\n\turl: ${remote_url}\n");
+
+ $wiki = connect_maybe($wiki, $remote_name, $remote_url);
+
+ # Read file content
+ if (! -e $file_name) {
+ $file_content = git_cmd_try {
+ Git::command('cat-file', 'blob', $file_name); }
+ "%s failed w/ code %d";
+
+ if ($file_name =~ /(.+):(.+)/) {
+ $file_name = $2;
+ }
+ } else {
+ open my $read_fh, "<", $file_name
+ or die "could not open ${file_name}: $!\n";
+ $file_content = do { local $/ = undef; <$read_fh> };
+ close $read_fh
+ or die "unable to close: $!\n";
+ }
+
+ v_print("### Retrieving template\n");
+ ($wiki_page_name = clean_filename($file_name)) =~ s/\.[^.]+$//;
+ $template = get_template($remote_url, $wiki_page_name);
+
+ v_print("### Parsing local content\n");
+ $new_content = $wiki->api({
+ action => 'parse',
+ text => $file_content,
+ title => $wiki_page_name
+ }, {
+ skip_encoding => 1
+ }) or die "No response from remote mediawiki\n";
+ $new_content = $new_content->{'parse'}->{'text'}->{'*'};
+
+ v_print("### Merging contents\n");
+ if ($preview_file_name eq EMPTY) {
+ ($preview_file_name = $file_name) =~ s/\.[^.]+$/.html/;
+ }
+ open(my $save_fh, '>:encoding(UTF-8)', $preview_file_name)
+ or die "Could not open: $!\n";
+ print {$save_fh} merge_contents($template, $new_content, $remote_url);
+ close($save_fh)
+ or die "Could not close: $!\n";
+
+ v_print("### Results\n");
+ if ($autoload) {
+ v_print("Launching browser w/ file: ${preview_file_name}");
+ system('git', 'web--browse', $preview_file_name);
+ } else {
+ print {*STDERR} "Preview file saved as: ${preview_file_name}\n";
+ }
+
+ exit;
+}
+
+# uses global scope variable: $remote_name
+sub merge_contents {
+ my $template = shift;
+ my $content = shift;
+ my $remote_url = shift;
+ my ($content_tree, $html_tree, $mw_content_text);
+ my $template_content_id = 'bodyContent';
+
+ $html_tree = HTML::TreeBuilder->new;
+ $html_tree->parse($template);
+
+ $content_tree = HTML::TreeBuilder->new;
+ $content_tree->parse($content);
+
+ $template_content_id = Git::config("remote.${remote_name}.mwIDcontent")
+ || $template_content_id;
+ v_print("Using '${template_content_id}' as the content ID\n");
+
+ $mw_content_text = $html_tree->look_down('id', $template_content_id);
+ if (!defined $mw_content_text) {
+ print {*STDERR} <<"CONFIG";
+Could not combine the new content with the template. You might want to
+configure `mediawiki.IDContent` in your config:
+ git config --add remote.${remote_name}.mwIDcontent <id>
+and re-run the command afterward.
+CONFIG
+ exit 1;
+ }
+ $mw_content_text->delete_content();
+ $mw_content_text->push_content($content_tree);
+
+ make_links_absolute($html_tree, $remote_url);
+
+ return $html_tree->as_HTML;
+}
+
+sub make_links_absolute {
+ my $html_tree = shift;
+ my $remote_url = shift;
+ for (@{ $html_tree->extract_links() }) {
+ my ($link, $element, $attr) = @{ $_ };
+ my $url = url($link)->canonical;
+ if ($url !~ /#/) {
+ $element->attr($attr, URI->new_abs($url, $remote_url));
+ }
+ }
+ return $html_tree;
+}
+
+sub is_valid_remote {
+ my $remote = shift;
+ my @remotes = git_cmd_try {
+ Git::command('remote') }
+ "%s failed w/ code %d";
+ my $found_remote = 0;
+ foreach my $remote (@remotes) {
+ if ($remote eq $remote) {
+ $found_remote = 1;
+ last;
+ }
+ }
+ return $found_remote;
+}
+
+sub find_mediawiki_remotes {
+ my @remotes = git_cmd_try {
+ Git::command('remote'); }
+ "%s failed w/ code %d";
+ my $remote_url;
+ my @valid_remotes = ();
+ foreach my $remote (@remotes) {
+ $remote_url = mediawiki_remote_url_maybe($remote);
+ if ($remote_url) {
+ push(@valid_remotes, $remote);
+ }
+ }
+ return @valid_remotes;
+}
+
+sub find_upstream_remote_name {
+ my $current_branch = git_cmd_try {
+ Git::command_oneline('symbolic-ref', '--short', 'HEAD') }
+ "%s failed w/ code %d";
+ return Git::config("branch.${current_branch}.remote");
+}
+
+sub mediawiki_remote_url_maybe {
+ my $remote = shift;
+
+ # Find remote url
+ my $remote_url = Git::config("remote.${remote}.url");
+ if ($remote_url =~ s/mediawiki::(.*)/$1/) {
+ return url($remote_url)->canonical;
+ }
+
+ return;
+}
+
+sub get_template {
+ my $url = shift;
+ my $page_name = shift;
+ my ($req, $res, $code, $url_after);
+
+ $req = LWP::UserAgent->new;
+ if ($verbose) {
+ $req->show_progress(1);
+ }
+
+ $res = $req->get("${url}/index.php?title=${page_name}");
+ if (!$res->is_success) {
+ $code = $res->code;
+ $url_after = $res->request()->uri(); # resolve all redirections
+ if ($code == HTTP_CODE_PAGE_NOT_FOUND) {
+ if ($verbose) {
+ print {*STDERR} <<"WARNING";
+Warning: Failed to retrieve '$page_name'. Create it on the mediawiki if you want
+all the links to work properly.
+Trying to use the mediawiki homepage as a fallback template ...
+WARNING
+ }
+
+ # LWP automatically redirects GET request
+ $res = $req->get("${url}/index.php");
+ if (!$res->is_success) {
+ $url_after = $res->request()->uri(); # resolve all redirections
+ die "Failed to get homepage @ ${url_after} w/ code ${code}\n";
+ }
+ } else {
+ die "Failed to get '${page_name}' @ ${url_after} w/ code ${code}\n";
+ }
+ }
+
+ return $res->decoded_content;
+}
+
+############################## Help Functions ##################################
+
+sub help {
+ print {*STDOUT} <<'END';
+usage: git mw <command> <args>
+
+git mw commands are:
+ help Display help information about git mw
+ preview Parse and render local file into HTML
+END
+ exit;
+}
diff --git a/contrib/mw-to-git/git-remote-mediawiki.perl b/contrib/mw-to-git/git-remote-mediawiki.perl
index 9c14c1f..c9a4805 100755
--- a/contrib/mw-to-git/git-remote-mediawiki.perl
+++ b/contrib/mw-to-git/git-remote-mediawiki.perl
@@ -13,19 +13,17 @@
use strict;
use MediaWiki::API;
+use Git;
+use Git::Mediawiki qw(clean_filename smudge_filename connect_maybe
+ EMPTY HTTP_CODE_OK);
use DateTime::Format::ISO8601;
+use warnings;
# By default, use UTF-8 to communicate with Git and the user
-binmode STDERR, ":utf8";
-binmode STDOUT, ":utf8";
+binmode STDERR, ':encoding(UTF-8)';
+binmode STDOUT, ':encoding(UTF-8)';
use URI::Escape;
-use IPC::Open2;
-
-use warnings;
-
-# Mediawiki filenames can contain forward slashes. This variable decides by which pattern they should be replaced
-use constant SLASH_REPLACEMENT => "%2F";
# It's not always possible to delete pages (may require some
# privileges). Deleted pages are replaced with this content.
@@ -36,45 +34,57 @@ use constant DELETED_CONTENT => "[[Category:Deleted]]\n";
use constant EMPTY_CONTENT => "<!-- empty page -->\n";
# used to reflect file creation or deletion in diff.
-use constant NULL_SHA1 => "0000000000000000000000000000000000000000";
+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*';
+# Number of pages taken into account at once in submodule get_mw_page_list
+use constant SLICE_SIZE => 50;
+
+# Number of linked mediafile to get at once in get_linked_mediafiles
+# The query is split in small batches because of the MW API limit of
+# the number of links to be returned (500 links max).
+use constant BATCH_SIZE => 10;
+
+if (@ARGV != 2) {
+ exit_error_usage();
+}
+
my $remotename = $ARGV[0];
my $url = $ARGV[1];
# Accept both space-separated and multiple keys in config file.
# Spaces should be written as _ anyway because we'll use chomp.
-my @tracked_pages = split(/[ \n]/, run_git("config --get-all remote.". $remotename .".pages"));
+my @tracked_pages = split(/[ \n]/, run_git("config --get-all remote.${remotename}.pages"));
chomp(@tracked_pages);
# Just like @tracked_pages, but for MediaWiki categories.
-my @tracked_categories = split(/[ \n]/, run_git("config --get-all remote.". $remotename .".categories"));
+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");
+my $import_media = run_git("config --get --bool remote.${remotename}.mediaimport");
chomp($import_media);
-$import_media = ($import_media eq "true");
+$import_media = ($import_media eq 'true');
# Export media files on push
-my $export_media = run_git("config --get --bool remote.". $remotename .".mediaexport");
+my $export_media = run_git("config --get --bool remote.${remotename}.mediaexport");
chomp($export_media);
-$export_media = !($export_media eq "false");
+$export_media = !($export_media eq 'false');
-my $wiki_login = run_git("config --get remote.". $remotename .".mwLogin");
+my $wiki_login = run_git("config --get remote.${remotename}.mwLogin");
# 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");
+my $wiki_passwd = run_git("config --get remote.${remotename}.mwPassword");
+my $wiki_domain = run_git("config --get remote.${remotename}.mwDomain");
chomp($wiki_login);
chomp($wiki_passwd);
chomp($wiki_domain);
# Import only last revisions (both for clone and fetch)
-my $shallow_import = run_git("config --get --bool remote.". $remotename .".shallow");
+my $shallow_import = run_git("config --get --bool remote.${remotename}.shallow");
chomp($shallow_import);
-$shallow_import = ($shallow_import eq "true");
+$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
@@ -82,15 +92,18 @@ $shallow_import = ($shallow_import eq "true");
# 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");
+my $fetch_strategy = run_git("config --get remote.${remotename}.fetchStrategy");
+if (!$fetch_strategy) {
+ $fetch_strategy = run_git('config --get mediawiki.fetchStrategy');
}
chomp($fetch_strategy);
-unless ($fetch_strategy) {
- $fetch_strategy = "by_page";
+if (!$fetch_strategy) {
+ $fetch_strategy = 'by_page';
}
+# Remember the timestamp corresponding to a revision id.
+my %basetimestamps;
+
# Dumb push: don't update notes and mediawiki ref to reflect the last push.
#
# Configurable with mediawiki.dumbPush, or per-remote with
@@ -105,48 +118,25 @@ unless ($fetch_strategy) {
# will get the history with information lost). If the import is
# deterministic, this means everybody gets the same sha1 for each
# MediaWiki revision.
-my $dumb_push = run_git("config --get --bool remote.$remotename.dumbPush");
-unless ($dumb_push) {
- $dumb_push = run_git("config --get --bool mediawiki.dumbPush");
+my $dumb_push = run_git("config --get --bool remote.${remotename}.dumbPush");
+if (!$dumb_push) {
+ $dumb_push = run_git('config --get --bool mediawiki.dumbPush');
}
chomp($dumb_push);
-$dumb_push = ($dumb_push eq "true");
+$dumb_push = ($dumb_push eq 'true');
my $wiki_name = $url;
-$wiki_name =~ s/[^\/]*:\/\///;
+$wiki_name =~ s{[^/]*://}{};
# If URL is like http://user:password@example.com/, we clearly don't
# want the password in $wiki_name. While we're there, also remove user
# and '@' sign, to avoid author like MWUser@HTTPUser@host.com
$wiki_name =~ s/^.*@//;
# Commands parser
-my $entry;
-my @cmd;
while (<STDIN>) {
chomp;
- @cmd = split(/ /);
- if (defined($cmd[0])) {
- # Line not blank
- if ($cmd[0] eq "capabilities") {
- die("Too many arguments for capabilities") unless (!defined($cmd[1]));
- mw_capabilities();
- } elsif ($cmd[0] eq "list") {
- die("Too many arguments for list") unless (!defined($cmd[2]));
- mw_list($cmd[1]);
- } elsif ($cmd[0] eq "import") {
- die("Invalid arguments for import") unless ($cmd[1] ne "" && !defined($cmd[2]));
- mw_import($cmd[1]);
- } elsif ($cmd[0] eq "option") {
- die("Too many arguments for option") unless ($cmd[1] ne "" && $cmd[2] ne "" && !defined($cmd[3]));
- mw_option($cmd[1],$cmd[2]);
- } elsif ($cmd[0] eq "push") {
- mw_push($cmd[1]);
- } else {
- print STDERR "Unknown command. Aborting...\n";
- last;
- }
- } else {
- # blank line: we should terminate
+
+ if (!parse_command($_)) {
last;
}
@@ -156,107 +146,91 @@ 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;
+## error handling
+sub exit_error_usage {
+ die "ERROR: git-remote-mediawiki module was not called with a correct number of\n" .
+ "parameters\n" .
+ "You may obtain this error because you attempted to run the git-remote-mediawiki\n" .
+ "module directly.\n" .
+ "This module can be used the following way:\n" .
+ "\tgit clone mediawiki://<address of a mediawiki>\n" .
+ "Then, use git commit, push and pull as with every normal git repository.\n";
}
-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 parse_command {
+ my ($line) = @_;
+ my @cmd = split(/ /, $line);
+ if (!defined $cmd[0]) {
+ return 0;
}
-}
-
-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);
+ if ($cmd[0] eq 'capabilities') {
+ die("Too many arguments for capabilities\n")
+ if (defined($cmd[1]));
+ mw_capabilities();
+ } elsif ($cmd[0] eq 'list') {
+ die("Too many arguments for list\n") if (defined($cmd[2]));
+ mw_list($cmd[1]);
+ } elsif ($cmd[0] eq 'import') {
+ die("Invalid argument for import\n")
+ if ($cmd[1] eq EMPTY);
+ die("Too many arguments for import\n")
+ if (defined($cmd[2]));
+ mw_import($cmd[1]);
+ } elsif ($cmd[0] eq 'option') {
+ die("Invalid arguments for option\n")
+ if ($cmd[1] eq EMPTY || $cmd[2] eq EMPTY);
+ die("Too many arguments for option\n")
+ if (defined($cmd[3]));
+ mw_option($cmd[1],$cmd[2]);
+ } elsif ($cmd[0] eq 'push') {
+ mw_push($cmd[1]);
} 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.";
+ print {*STDERR} "Unknown command. Aborting...\n";
+ return 0;
}
+ return 1;
}
# MediaWiki API instance, created lazily.
my $mediawiki;
-sub mw_connect_maybe {
- if ($mediawiki) {
- return;
- }
- $mediawiki = MediaWiki::API->new;
- $mediawiki->{config}->{api_url} = "$url/api.php";
- if ($wiki_login) {
- 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 "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;
- }
+sub fatal_mw_error {
+ my $action = shift;
+ print STDERR "fatal: could not $action.\n";
+ print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
+ if ($url =~ /^https/) {
+ print STDERR "fatal: make sure '$url/api.php' is a valid page\n";
+ print STDERR "fatal: and the SSL certificate is correct.\n";
+ } else {
+ print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
}
+ print STDERR "fatal: (error " .
+ $mediawiki->{error}->{code} . ': ' .
+ $mediawiki->{error}->{details} . ")\n";
+ 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);
+ return;
}
sub get_mw_page_list {
my $page_list = shift;
my $pages = shift;
- my @some_pages = @$page_list;
+ my @some_pages = @{$page_list};
while (@some_pages) {
- my $last = 50;
- if ($#some_pages < $last) {
- $last = $#some_pages;
+ my $last_page = SLICE_SIZE;
+ if ($#some_pages < $last_page) {
+ $last_page = $#some_pages;
}
- my @slice = @some_pages[0..$last];
+ my @slice = @some_pages[0..$last_page];
get_mw_first_pages(\@slice, $pages);
- @some_pages = @some_pages[51..$#some_pages];
+ @some_pages = @some_pages[(SLICE_SIZE + 1)..$#some_pages];
}
+ return;
}
sub get_mw_tracked_categories {
@@ -266,7 +240,7 @@ sub get_mw_tracked_categories {
# Mediawiki requires the Category
# prefix, but let's not force the user
# to specify it.
- $category = "Category:" . $category;
+ $category = "Category:${category}";
}
my $mw_pages = $mediawiki->list( {
action => 'query',
@@ -274,11 +248,12 @@ sub get_mw_tracked_categories {
cmtitle => $category,
cmlimit => 'max' } )
|| die $mediawiki->{error}->{code} . ': '
- . $mediawiki->{error}->{details};
+ . $mediawiki->{error}->{details} . "\n";
foreach my $page (@{$mw_pages}) {
$pages->{$page->{title}} = $page;
}
}
+ return;
}
sub get_mw_all_pages {
@@ -290,14 +265,12 @@ sub get_mw_all_pages {
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;
+ fatal_mw_error("get the list of wiki pages");
}
foreach my $page (@{$mw_pages}) {
$pages->{$page->{title}} = $page;
}
+ return;
}
# queries the wiki for a set of pages. Meant to be used within a loop
@@ -316,25 +289,23 @@ sub get_mw_first_pages {
titles => $titles,
});
if (!defined($mw_pages)) {
- print STDERR "fatal: could not query 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;
+ fatal_mw_error("query the list of wiki pages");
}
while (my ($id, $page) = each(%{$mw_pages->{query}->{pages}})) {
if ($id < 0) {
- print STDERR "Warning: page $page->{title} not found on wiki\n";
+ print {*STDERR} "Warning: page $page->{title} not found on wiki\n";
} else {
$pages->{$page->{title}} = $page;
}
}
+ return;
}
# Get the list of pages to be fetched according to configuration.
sub get_mw_pages {
- mw_connect_maybe();
+ $mediawiki = connect_maybe($mediawiki, $remotename, $url);
- print STDERR "Listing pages on remote wiki...\n";
+ print {*STDERR} "Listing pages on remote wiki...\n";
my %pages; # hash on page titles to avoid duplicates
my $user_defined;
@@ -352,14 +323,14 @@ sub get_mw_pages {
get_mw_all_pages(\%pages);
}
if ($import_media) {
- print STDERR "Getting media files for selected pages...\n";
+ print {*STDERR} "Getting media files for selected pages...\n";
if ($user_defined) {
get_linked_mediafiles(\%pages);
} else {
get_all_mediafiles(\%pages);
}
}
- print STDERR (scalar keys %pages) . " pages found.\n";
+ print {*STDERR} (scalar keys %pages) . " pages found.\n";
return %pages;
}
@@ -367,9 +338,13 @@ sub get_mw_pages {
# $out = run_git("command args", "raw"); # don't interpret output as UTF-8.
sub run_git {
my $args = shift;
- my $encoding = (shift || "encoding(UTF-8)");
- open(my $git, "-|:$encoding", "git " . $args);
- my $res = do { local $/; <$git> };
+ my $encoding = (shift || 'encoding(UTF-8)');
+ open(my $git, "-|:${encoding}", "git ${args}")
+ or die "Unable to fork: $!\n";
+ my $res = do {
+ local $/ = undef;
+ <$git>
+ };
close($git);
return $res;
@@ -384,27 +359,26 @@ sub get_all_mediafiles {
my $mw_pages = $mediawiki->list({
action => 'query',
list => 'allpages',
- apnamespace => get_mw_namespace_id("File"),
+ 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";
+ 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;
}
+ return;
}
sub get_linked_mediafiles {
my $pages = shift;
- my @titles = map $_->{title}, values(%{$pages});
+ 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;
+ my $batch = BATCH_SIZE;
while (@titles) {
if ($#titles < $batch) {
$batch = $#titles;
@@ -420,7 +394,7 @@ sub get_linked_mediafiles {
action => 'query',
prop => 'links|images',
titles => $mw_titles,
- plnamespace => get_mw_namespace_id("File"),
+ plnamespace => get_mw_namespace_id('File'),
pllimit => 'max'
};
my $result = $mediawiki->api($query);
@@ -428,11 +402,13 @@ sub get_linked_mediafiles {
while (my ($id, $page) = each(%{$result->{query}->{pages}})) {
my @media_titles;
if (defined($page->{links})) {
- my @link_titles = map $_->{title}, @{$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}};
+ my @image_titles
+ = map { $_->{title} } @{$page->{images}};
push(@media_titles, @image_titles);
}
if (@media_titles) {
@@ -442,6 +418,7 @@ sub get_linked_mediafiles {
@titles = @titles[($batch+1)..$#titles];
}
+ return;
}
sub get_mw_mediafile_for_page_revision {
@@ -455,7 +432,7 @@ sub get_mw_mediafile_for_page_revision {
my $query = {
action => 'query',
prop => 'imageinfo',
- titles => "File:" . $filename,
+ titles => "File:${filename}",
iistart => $timestamp,
iiend => $timestamp,
iiprop => 'timestamp|archivename|url',
@@ -473,53 +450,50 @@ sub get_mw_mediafile_for_page_revision {
$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";
+ 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 $download_url = shift;
- my $response = $mediawiki->{ua}->get($url);
- if ($response->code == 200) {
+ my $response = $mediawiki->{ua}->get($download_url);
+ if ($response->code == HTTP_CODE_OK) {
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";
+ print {*STDERR} "Error downloading mediafile from :\n";
+ print {*STDERR} "URL: ${download_url}\n";
+ print {*STDERR} 'Server response: ' . $response->code . q{ } . $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");
+ my $note = run_git("notes --ref=${remotename}/mediawiki show refs/mediawiki/${remotename}/master 2>/dev/null");
my @note_info = split(/ /, $note);
my $lastrevision_number;
- if (!(defined($note_info[0]) && $note_info[0] eq "mediawiki_revision:")) {
- print STDERR "No previous mediawiki revision found";
+ if (!(defined($note_info[0]) && $note_info[0] eq 'mediawiki_revision:')) {
+ print {*STDERR} 'No previous mediawiki revision found';
$lastrevision_number = 0;
} else {
# Notes are formatted : mediawiki_revision: #number
$lastrevision_number = $note_info[1];
chomp($lastrevision_number);
- print STDERR "Last local mediawiki revision found is $lastrevision_number";
+ print {*STDERR} "Last local mediawiki revision found is ${lastrevision_number}";
}
return $lastrevision_number;
}
-# 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();
+ $mediawiki = connect_maybe($mediawiki, $remotename, $url);
my $query = {
action => 'query',
@@ -535,14 +509,14 @@ sub get_last_global_remote_rev {
# Get the last remote revision concerning the tracked pages and the tracked
# categories.
sub get_last_remote_revision {
- mw_connect_maybe();
+ $mediawiki = connect_maybe($mediawiki, $remotename, $url);
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";
+ print {*STDERR} "Getting last revision id on tracked pages...\n";
foreach my $page (@pages) {
my $id = $page->{pageid};
@@ -563,7 +537,7 @@ sub get_last_remote_revision {
$max_rev_num = ($lastrev->{revid} > $max_rev_num ? $lastrev->{revid} : $max_rev_num);
}
- print STDERR "Last remote revision found is $max_rev_num.\n";
+ print {*STDERR} "Last remote revision found is $max_rev_num.\n";
return $max_rev_num;
}
@@ -574,7 +548,7 @@ sub mediawiki_clean {
# Mediawiki does not allow blank space at the end of a page and ends with a single \n.
# This function right trims a string and adds a \n at the end to follow this rule
$string =~ s/\s+$//;
- if ($string eq "" && $page_created) {
+ if ($string eq EMPTY && $page_created) {
# Creating empty pages is forbidden.
$string = EMPTY_CONTENT;
}
@@ -585,38 +559,16 @@ sub mediawiki_clean {
sub mediawiki_smudge {
my $string = shift;
if ($string eq EMPTY_CONTENT) {
- $string = "";
+ $string = EMPTY;
}
# This \n is important. This is due to mediawiki's way to handle end of files.
- return $string."\n";
-}
-
-sub mediawiki_clean_filename {
- my $filename = shift;
- $filename =~ s/@{[SLASH_REPLACEMENT]}/\//g;
- # [, ], |, {, and } are forbidden by MediaWiki, even URL-encoded.
- # Do a variant of URL-encoding, i.e. looks like URL-encoding,
- # but with _ added to prevent MediaWiki from thinking this is
- # an actual special character.
- $filename =~ s/[\[\]\{\}\|]/sprintf("_%%_%x", ord($&))/ge;
- # If we use the uri escape before
- # we should unescape here, before anything
-
- return $filename;
-}
-
-sub mediawiki_smudge_filename {
- my $filename = shift;
- $filename =~ s/\//@{[SLASH_REPLACEMENT]}/g;
- $filename =~ s/ /_/g;
- # Decode forbidden characters encoded in mediawiki_clean_filename
- $filename =~ s/_%_([0-9a-fA-F][0-9a-fA-F])/sprintf("%c", hex($1))/ge;
- return $filename;
+ return "${string}\n";
}
sub literal_data {
my ($content) = @_;
- print STDOUT "data ", bytes::length($content), "\n", $content;
+ print {*STDOUT} 'data ', bytes::length($content), "\n", $content;
+ return;
}
sub literal_data_raw {
@@ -624,33 +576,40 @@ sub literal_data_raw {
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";
+ binmode STDOUT, ':raw';
+ print {*STDOUT} 'data ', bytes::length($content), "\n", $content;
+ binmode STDOUT, ':encoding(UTF-8)';
+ return;
}
sub mw_capabilities {
# Revisions are imported to the private namespace
# refs/mediawiki/$remotename/ by the helper and fetched into
# refs/remotes/$remotename later by fetch.
- print STDOUT "refspec refs/heads/*:refs/mediawiki/$remotename/*\n";
- print STDOUT "import\n";
- print STDOUT "list\n";
- print STDOUT "push\n";
- print STDOUT "\n";
+ print {*STDOUT} "refspec refs/heads/*:refs/mediawiki/${remotename}/*\n";
+ print {*STDOUT} "import\n";
+ print {*STDOUT} "list\n";
+ print {*STDOUT} "push\n";
+ if ($dumb_push) {
+ print {*STDOUT} "no-private-update\n";
+ }
+ print {*STDOUT} "\n";
+ return;
}
sub mw_list {
# MediaWiki do not have branches, we consider one branch arbitrarily
# called master, and HEAD pointing to it.
- print STDOUT "? refs/heads/master\n";
- print STDOUT "\@refs/heads/master HEAD\n";
- print STDOUT "\n";
+ print {*STDOUT} "? refs/heads/master\n";
+ print {*STDOUT} "\@refs/heads/master HEAD\n";
+ print {*STDOUT} "\n";
+ return;
}
sub mw_option {
- print STDERR "remote-helper command 'option $_[0]' not yet implemented\n";
- print STDOUT "unsupported\n";
+ print {*STDERR} "remote-helper command 'option $_[0]' not yet implemented\n";
+ print {*STDOUT} "unsupported\n";
+ return;
}
sub fetch_mw_revisions_for_page {
@@ -681,15 +640,15 @@ sub fetch_mw_revisions_for_page {
push(@page_revs, $page_rev_ids);
$revnum++;
}
- last unless $result->{'query-continue'};
+ last if (!$result->{'query-continue'});
$query->{rvstartid} = $result->{'query-continue'}->{revisions}->{rvstartid};
}
if ($shallow_import && @page_revs) {
- print STDERR " Found 1 revision (shallow import).\n";
+ print {*STDERR} " Found 1 revision (shallow import).\n";
@page_revs = sort {$b->{revid} <=> $a->{revid}} (@page_revs);
return $page_revs[0];
}
- print STDERR " Found ", $revnum, " revision(s).\n";
+ print {*STDERR} " Found ${revnum} revision(s).\n";
return @page_revs;
}
@@ -701,8 +660,7 @@ sub fetch_mw_revisions {
my $n = 1;
foreach my $page (@pages) {
my $id = $page->{pageid};
-
- print STDERR "page $n/", scalar(@pages), ": ". $page->{title} ."\n";
+ print {*STDERR} "page ${n}/", scalar(@pages), ': ', $page->{title}, "\n";
$n++;
my @page_revs = fetch_mw_revisions_for_page($page, $id, $fetch_from);
@revisions = (@page_revs, @revisions);
@@ -716,7 +674,7 @@ sub fe_escape_path {
$path =~ s/\\/\\\\/g;
$path =~ s/"/\\"/g;
$path =~ s/\n/\\n/g;
- return '"' . $path . '"';
+ return qq("${path}");
}
sub import_file_revision {
@@ -736,42 +694,43 @@ sub import_file_revision {
my $author = $commit{author};
my $date = $commit{date};
- print STDOUT "commit refs/mediawiki/$remotename/master\n";
- print STDOUT "mark :$n\n";
- print STDOUT "committer $author <$author\@$wiki_name> ", $date->epoch, " +0000\n";
+ print {*STDOUT} "commit refs/mediawiki/${remotename}/master\n";
+ print {*STDOUT} "mark :${n}\n";
+ print {*STDOUT} "committer ${author} <${author}\@${wiki_name}> " . $date->epoch . " +0000\n";
literal_data($comment);
# If it's not a clone, we need to know where to start from
if (!$full_import && $n == 1) {
- print STDOUT "from refs/mediawiki/$remotename/master^0\n";
+ print {*STDOUT} "from refs/mediawiki/${remotename}/master^0\n";
}
if ($content ne DELETED_CONTENT) {
- print STDOUT "M 644 inline " .
- fe_escape_path($title . ".mw") . "\n";
+ print {*STDOUT} 'M 644 inline ' .
+ fe_escape_path("${title}.mw") . "\n";
literal_data($content);
if (%mediafile) {
- print STDOUT "M 644 inline "
+ print {*STDOUT} 'M 644 inline '
. fe_escape_path($mediafile{title}) . "\n";
literal_data_raw($mediafile{content});
}
- print STDOUT "\n\n";
+ print {*STDOUT} "\n\n";
} else {
- print STDOUT "D " . fe_escape_path($title . ".mw") . "\n";
+ print {*STDOUT} 'D ' . fe_escape_path("${title}.mw") . "\n";
}
# mediawiki revision number in the git note
if ($full_import && $n == 1) {
- print STDOUT "reset refs/notes/$remotename/mediawiki\n";
+ print {*STDOUT} "reset refs/notes/${remotename}/mediawiki\n";
}
- print STDOUT "commit refs/notes/$remotename/mediawiki\n";
- print STDOUT "committer $author <$author\@$wiki_name> ", $date->epoch, " +0000\n";
- literal_data("Note added by git-mediawiki during import");
+ print {*STDOUT} "commit refs/notes/${remotename}/mediawiki\n";
+ print {*STDOUT} "committer ${author} <${author}\@${wiki_name}> " . $date->epoch . " +0000\n";
+ literal_data('Note added by git-mediawiki during import');
if (!$full_import && $n == 1) {
- print STDOUT "from refs/notes/$remotename/mediawiki^0\n";
+ print {*STDOUT} "from refs/notes/${remotename}/mediawiki^0\n";
}
- print STDOUT "N inline :$n\n";
- literal_data("mediawiki_revision: " . $commit{mw_revision});
- print STDOUT "\n\n";
+ print {*STDOUT} "N inline :${n}\n";
+ literal_data("mediawiki_revision: $commit{mw_revision}");
+ print {*STDOUT} "\n\n";
+ return;
}
# parse a sequence of
@@ -784,23 +743,25 @@ sub get_more_refs {
my @refs;
while (1) {
my $line = <STDIN>;
- if ($line =~ m/^$cmd (.*)$/) {
+ if ($line =~ /^$cmd (.*)$/) {
push(@refs, $1);
} elsif ($line eq "\n") {
return @refs;
} else {
- die("Invalid command in a '$cmd' batch: ". $_);
+ die("Invalid command in a '$cmd' batch: $_\n");
}
}
+ return;
}
sub mw_import {
# multiple import commands can follow each other.
- my @refs = (shift, get_more_refs("import"));
+ my @refs = (shift, get_more_refs('import'));
foreach my $ref (@refs) {
mw_import_ref($ref);
}
- print STDOUT "done\n";
+ print {*STDOUT} "done\n";
+ return;
}
sub mw_import_ref {
@@ -810,40 +771,41 @@ sub mw_import_ref {
# Since HEAD is a symbolic ref to master (by convention,
# followed by the output of the command "list" that we gave),
# we don't need to do anything in this case.
- if ($ref eq "HEAD") {
+ if ($ref eq 'HEAD') {
return;
}
- mw_connect_maybe();
+ $mediawiki = connect_maybe($mediawiki, $remotename, $url);
- print STDERR "Searching revisions...\n";
+ print {*STDERR} "Searching revisions...\n";
my $last_local = get_last_local_revision();
my $fetch_from = $last_local + 1;
if ($fetch_from == 1) {
- print STDERR ", fetching from beginning.\n";
+ print {*STDERR} ", fetching from beginning.\n";
} else {
- print STDERR ", fetching from here.\n";
+ print {*STDERR} ", fetching from here.\n";
}
my $n = 0;
- if ($fetch_strategy eq "by_rev") {
- print STDERR "Fetching & writing export data by revs...\n";
+ 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";
+ } 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";
+ print {*STDERR} qq(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";
+ 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 referring to unknown object 0000000000000000000
# and the clone fails.
}
+ return;
}
sub mw_import_ref_by_pages {
@@ -855,7 +817,7 @@ sub mw_import_ref_by_pages {
my ($n, @revisions) = fetch_mw_revisions(\@pages, $fetch_from);
@revisions = sort {$a->{revid} <=> $b->{revid}} @revisions;
- my @revision_ids = map $_->{revid}, @revisions;
+ my @revision_ids = map { $_->{revid} } @revisions;
return mw_import_revids($fetch_from, \@revision_ids, \%pages_hash);
}
@@ -882,7 +844,7 @@ sub mw_import_revids {
my $n_actual = 0;
my $last_timestamp = 0; # Placeholer in case $rev->timestamp is undefined
- foreach my $pagerevid (@$revision_ids) {
+ foreach my $pagerevid (@{$revision_ids}) {
# Count page even if we skip it, since we display
# $n/$total and $total includes skipped pages.
$n++;
@@ -898,7 +860,7 @@ sub mw_import_revids {
my $result = $mediawiki->api($query);
if (!$result) {
- die "Failed to retrieve modified page for revision $pagerevid";
+ die "Failed to retrieve modified page for revision $pagerevid\n";
}
if (defined($result->{query}->{badrevids}->{$pagerevid})) {
@@ -907,7 +869,7 @@ sub mw_import_revids {
}
if (!defined($result->{query}->{pages})) {
- die "Invalid revision $pagerevid.";
+ die "Invalid revision ${pagerevid}.\n";
}
my @result_pages = values(%{$result->{query}->{pages}});
@@ -917,8 +879,8 @@ sub mw_import_revids {
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";
+ print {*STDERR} "${n}/", scalar(@{$revision_ids}),
+ ": Skipping revision #$rev->{revid} of ${page_title}\n";
next;
}
@@ -927,7 +889,7 @@ sub mw_import_revids {
my %commit;
$commit{author} = $rev->{user} || 'Anonymous';
$commit{comment} = $rev->{comment} || EMPTY_MESSAGE;
- $commit{title} = mediawiki_smudge_filename($page_title);
+ $commit{title} = smudge_filename($page_title);
$commit{mw_revision} = $rev->{revid};
$commit{content} = mediawiki_smudge($rev->{'*'});
@@ -943,14 +905,14 @@ sub mw_import_revids {
my %mediafile;
if ($namespace) {
my $id = get_mw_namespace_id($namespace);
- if ($id && $id == get_mw_namespace_id("File")) {
+ 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";
+ print {*STDERR} "${n}/", scalar(@{$revision_ids}), ": Revision #$rev->{revid} of $commit{title}\n";
import_file_revision(\%commit, ($fetch_from == 1), $n_actual, \%mediafile);
}
@@ -958,17 +920,17 @@ sub mw_import_revids {
}
sub error_non_fast_forward {
- my $advice = run_git("config --bool advice.pushNonFastForward");
+ my $advice = run_git('config --bool advice.pushNonFastForward');
chomp($advice);
- if ($advice ne "false") {
+ if ($advice ne 'false') {
# Native git-push would show this after the summary.
# We can't ask it to display it cleanly, so print it
# ourselves before.
- print STDERR "To prevent you from losing history, non-fast-forward updates were rejected\n";
- print STDERR "Merge the remote changes (e.g. 'git pull') before pushing again. See the\n";
- print STDERR "'Note about fast-forwards' section of 'git push --help' for details.\n";
+ print {*STDERR} "To prevent you from losing history, non-fast-forward updates were rejected\n";
+ print {*STDERR} "Merge the remote changes (e.g. 'git pull') before pushing again. See the\n";
+ print {*STDERR} "'Note about fast-forwards' section of 'git push --help' for details.\n";
}
- print STDOUT "error $_[0] \"non-fast-forward\"\n";
+ print {*STDOUT} qq(error $_[0] "non-fast-forward"\n);
return 0;
}
@@ -979,34 +941,34 @@ sub mw_upload_file {
my $file_deleted = shift;
my $summary = shift;
my $newrevid;
- my $path = "File:" . $complete_file_name;
+ 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";
+ 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();
+ $mediawiki = connect_maybe($mediawiki, $remotename, $url);
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};
+ 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();
+ my $content = run_git("cat-file blob ${new_sha1}", 'raw');
+ if ($content ne EMPTY) {
+ $mediawiki = connect_maybe($mediawiki, $remotename, $url);
$mediawiki->{config}->{upload_url} =
- "$url/index.php/Special:Upload";
+ "${url}/index.php/Special:Upload";
$mediawiki->edit({
action => 'upload',
filename => $complete_file_name,
@@ -1018,12 +980,12 @@ sub mw_upload_file {
}, {
skip_encoding => 1
} ) || die $mediawiki->{error}->{code} . ':'
- . $mediawiki->{error}->{details};
+ . $mediawiki->{error}->{details} . "\n";
my $last_file_page = $mediawiki->get_page({title => $path});
$newrevid = $last_file_page->{revid};
- print STDERR "Pushed file: $new_sha1 - $complete_file_name.\n";
+ print {*STDERR} "Pushed file: ${new_sha1} - ${complete_file_name}.\n";
} else {
- print STDERR "Empty file $complete_file_name not pushed.\n";
+ print {*STDERR} "Empty file ${complete_file_name} not pushed.\n";
}
}
return $newrevid;
@@ -1045,24 +1007,24 @@ sub mw_push_file {
my $newrevid;
if ($summary eq EMPTY_MESSAGE) {
- $summary = '';
+ $summary = EMPTY;
}
my $new_sha1 = $diff_info_split[3];
my $old_sha1 = $diff_info_split[2];
my $page_created = ($old_sha1 eq NULL_SHA1);
my $page_deleted = ($new_sha1 eq NULL_SHA1);
- $complete_file_name = mediawiki_clean_filename($complete_file_name);
+ $complete_file_name = clean_filename($complete_file_name);
my ($title, $extension) = $complete_file_name =~ /^(.*)\.([^\.]*)$/;
if (!defined($extension)) {
- $extension = "";
+ $extension = EMPTY;
}
- if ($extension eq "mw") {
+ 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");
+ 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) {
@@ -1072,10 +1034,10 @@ sub mw_push_file {
# with this content instead:
$file_content = DELETED_CONTENT;
} else {
- $file_content = run_git("cat-file blob $new_sha1");
+ $file_content = run_git("cat-file blob ${new_sha1}");
}
- mw_connect_maybe();
+ $mediawiki = connect_maybe($mediawiki, $remotename, $url);
my $result = $mediawiki->edit( {
action => 'edit',
@@ -1089,49 +1051,49 @@ sub mw_push_file {
if (!$result) {
if ($mediawiki->{error}->{code} == 3) {
# edit conflicts, considered as non-fast-forward
- print STDERR 'Warning: Error ' .
+ print {*STDERR} 'Warning: Error ' .
$mediawiki->{error}->{code} .
- ' from mediwiki: ' . $mediawiki->{error}->{details} .
+ ' from mediawiki: ' . $mediawiki->{error}->{details} .
".\n";
- return ($oldrevid, "non-fast-forward");
+ return ($oldrevid, 'non-fast-forward');
} else {
# Other errors. Shouldn't happen => just die()
die 'Fatal: Error ' .
$mediawiki->{error}->{code} .
- ' from mediwiki: ' . $mediawiki->{error}->{details};
+ ' from mediawiki: ' . $mediawiki->{error}->{details} . "\n";
}
}
$newrevid = $result->{edit}->{newrevid};
- print STDERR "Pushed file: $new_sha1 - $title\n";
+ 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 "Ignoring media file $title\n";
+ print {*STDERR} "Ignoring media file ${title}\n";
}
$newrevid = ($newrevid or $oldrevid);
- return ($newrevid, "ok");
+ return ($newrevid, 'ok');
}
sub mw_push {
# multiple push statements can follow each other
- my @refsspecs = (shift, get_more_refs("push"));
+ my @refsspecs = (shift, get_more_refs('push'));
my $pushed;
for my $refspec (@refsspecs) {
my ($force, $local, $remote) = $refspec =~ /^(\+)?([^:]*):([^:]*)$/
- or die("Invalid refspec for push. Expected <src>:<dst> or +<src>:<dst>");
+ or die("Invalid refspec for push. Expected <src>:<dst> or +<src>:<dst>\n");
if ($force) {
- print STDERR "Warning: forced push not allowed on a MediaWiki.\n";
+ print {*STDERR} "Warning: forced push not allowed on a MediaWiki.\n";
}
- if ($local eq "") {
- print STDERR "Cannot delete remote branch on a MediaWiki\n";
- print STDOUT "error $remote cannot delete\n";
+ if ($local eq EMPTY) {
+ print {*STDERR} "Cannot delete remote branch on a MediaWiki\n";
+ print {*STDOUT} "error ${remote} cannot delete\n";
next;
}
- if ($remote ne "refs/heads/master") {
- print STDERR "Only push to the branch 'master' is supported on a MediaWiki\n";
- print STDOUT "error $remote only master allowed\n";
+ if ($remote ne 'refs/heads/master') {
+ print {*STDERR} "Only push to the branch 'master' is supported on a MediaWiki\n";
+ print {*STDOUT} "error ${remote} only master allowed\n";
next;
}
if (mw_push_revision($local, $remote)) {
@@ -1140,30 +1102,32 @@ sub mw_push {
}
# Notify Git that the push is done
- print STDOUT "\n";
+ print {*STDOUT} "\n";
if ($pushed && $dumb_push) {
- print STDERR "Just pushed some revisions to MediaWiki.\n";
- print STDERR "The pushed revisions now have to be re-imported, and your current branch\n";
- print STDERR "needs to be updated with these re-imported commits. You can do this with\n";
- print STDERR "\n";
- print STDERR " git pull --rebase\n";
- print STDERR "\n";
+ print {*STDERR} "Just pushed some revisions to MediaWiki.\n";
+ print {*STDERR} "The pushed revisions now have to be re-imported, and your current branch\n";
+ print {*STDERR} "needs to be updated with these re-imported commits. You can do this with\n";
+ print {*STDERR} "\n";
+ print {*STDERR} " git pull --rebase\n";
+ print {*STDERR} "\n";
}
+ return;
}
sub mw_push_revision {
my $local = shift;
my $remote = shift; # actually, this has to be "refs/heads/master" at this point.
my $last_local_revid = get_last_local_revision();
- print STDERR ".\n"; # Finish sentence started by get_last_local_revision()
+ print {*STDERR} ".\n"; # Finish sentence started by get_last_local_revision()
my $last_remote_revid = get_last_remote_revision();
my $mw_revision = $last_remote_revid;
# Get sha1 of commit pointed by local HEAD
- my $HEAD_sha1 = run_git("rev-parse $local 2>/dev/null"); chomp($HEAD_sha1);
+ my $HEAD_sha1 = run_git("rev-parse ${local} 2>/dev/null");
+ chomp($HEAD_sha1);
# Get sha1 of commit pointed by remotes/$remotename/master
- my $remoteorigin_sha1 = run_git("rev-parse refs/remotes/$remotename/master 2>/dev/null");
+ my $remoteorigin_sha1 = run_git("rev-parse refs/remotes/${remotename}/master 2>/dev/null");
chomp($remoteorigin_sha1);
if ($last_local_revid > 0 &&
@@ -1182,22 +1146,22 @@ 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"));
+ 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)) {
+ if (my ($child, $parents) = $line =~ /^-?([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";
+ } elsif (!$line =~ /^([a-f0-9]+)/) {
+ die "Unexpected output from git rev-list: ${line}\n";
}
}
while ($parsed_sha1 ne $HEAD_sha1) {
my $child = $local_ancestry{$parsed_sha1};
if (!$child) {
- printf STDERR "Cannot find a path in history from remote commit to last commit\n";
+ print {*STDERR} "Cannot find a path in history from remote commit to last commit\n";
return error_non_fast_forward($remote);
}
push(@commit_pairs, [$parsed_sha1, $child]);
@@ -1206,12 +1170,12 @@ sub mw_push_revision {
} else {
# No remote mediawiki revision. Export the whole
# history (linearized with --first-parent)
- print STDERR "Warning: no common ancestor, pushing complete history\n";
- my $history = run_git("rev-list --first-parent --children $local");
- my @history = split('\n', $history);
+ print {*STDERR} "Warning: no common ancestor, pushing complete history\n";
+ my $history = run_git("rev-list --first-parent --children ${local}");
+ my @history = split(/\n/, $history);
@history = @history[1..$#history];
foreach my $line (reverse @history) {
- my @commit_info_split = split(/ |\n/, $line);
+ my @commit_info_split = split(/[ \n]/, $line);
push(@commit_pairs, \@commit_info_split);
}
}
@@ -1219,12 +1183,12 @@ sub mw_push_revision {
foreach my $commit_info_split (@commit_pairs) {
my $sha1_child = @{$commit_info_split}[0];
my $sha1_commit = @{$commit_info_split}[1];
- my $diff_infos = run_git("diff-tree -r --raw -z $sha1_child $sha1_commit");
+ my $diff_infos = run_git("diff-tree -r --raw -z ${sha1_child} ${sha1_commit}");
# 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 subject line of the commit message as mediawiki comment for the revision
- my $commit_msg = run_git("log --no-walk --format=\"%s\" $sha1_commit");
+ my $commit_msg = run_git(qq(log --no-walk --format="%s" ${sha1_commit}));
chomp($commit_msg);
# Push every blob
while (@diff_info_list) {
@@ -1236,7 +1200,7 @@ sub mw_push_revision {
my $info = shift(@diff_info_list);
my $file = shift(@diff_info_list);
($mw_revision, $status) = mw_push_file($info, $file, $commit_msg, $mw_revision);
- if ($status eq "non-fast-forward") {
+ if ($status eq 'non-fast-forward') {
# we may already have sent part of the
# commit to MediaWiki, but it's too
# late to cancel it. Stop the push in
@@ -1244,22 +1208,21 @@ sub mw_push_revision {
# accurate error message.
return error_non_fast_forward($remote);
}
- if ($status ne "ok") {
- die("Unknown error from mw_push_file()");
+ if ($status ne 'ok') {
+ die("Unknown error from mw_push_file()\n");
}
}
- unless ($dumb_push) {
- 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");
+ if (!$dumb_push) {
+ run_git(qq(notes --ref=${remotename}/mediawiki add -f -m "mediawiki_revision: ${mw_revision}" ${sha1_commit}));
}
}
- print STDOUT "ok $remote\n";
+ print {*STDOUT} "ok ${remote}\n";
return 1;
}
sub get_allowed_file_extensions {
- mw_connect_maybe();
+ $mediawiki = connect_maybe($mediawiki, $remotename, $url);
my $query = {
action => 'query',
@@ -1267,8 +1230,8 @@ sub get_allowed_file_extensions {
siprop => 'fileextensions'
};
my $result = $mediawiki->api($query);
- my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}};
- my %hashFile = map {$_ => 1}@file_extensions;
+ my @file_extensions = map { $_->{ext}} @{$result->{query}->{fileextensions}};
+ my %hashFile = map { $_ => 1 } @file_extensions;
return %hashFile;
}
@@ -1283,15 +1246,15 @@ my %cached_mw_namespace_id;
# Return MediaWiki id for a canonical namespace name.
# Ex.: "File", "Project".
sub get_mw_namespace_id {
- mw_connect_maybe();
+ $mediawiki = connect_maybe($mediawiki, $remotename, $url);
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"));
+ my @temp = split(/\n/,
+ run_git("config --get-all remote.${remotename}.namespaceCache"));
chomp(@temp);
foreach my $ns (@temp) {
my ($n, $id) = split(/:/, $ns);
@@ -1305,7 +1268,7 @@ sub get_mw_namespace_id {
}
if (!exists $namespace_id{$name}) {
- print STDERR "Namespace $name not found in cache, querying the wiki ...\n";
+ 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 = {
@@ -1329,8 +1292,8 @@ sub get_mw_namespace_id {
my $ns = $namespace_id{$name};
my $id;
- unless (defined $ns) {
- print STDERR "No such namespace $name on MediaWiki.\n";
+ if (!defined $ns) {
+ print {*STDERR} "No such namespace ${name} on MediaWiki.\n";
$ns = {is_namespace => 0};
$namespace_id{$name} = $ns;
}
@@ -1344,15 +1307,15 @@ sub get_mw_namespace_id {
# Store explicitely requested namespaces on disk
if (!exists $cached_mw_namespace_id{$name}) {
- run_git("config --add remote.". $remotename
- .".namespaceCache \"". $name .":". $store_id ."\"");
+ run_git(qq(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] =~ /^([^:]*):/) {
+ my $namespace = shift;
+ if ($namespace =~ /^([^:]*):/) {
return get_mw_namespace_id($namespace);
} else {
return;
diff --git a/contrib/mw-to-git/t/test-gitmw-lib.sh b/contrib/mw-to-git/t/test-gitmw-lib.sh
index 3b2cfac..ca6860f 100755
--- a/contrib/mw-to-git/t/test-gitmw-lib.sh
+++ b/contrib/mw-to-git/t/test-gitmw-lib.sh
@@ -62,12 +62,8 @@ test_check_precond () {
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
+ GIT_EXEC_PATH=$(cd "$(dirname "$0")" && cd "../.." && pwd)
+ PATH="$GIT_EXEC_PATH"'/bin-wrapper:'"$PATH"
if [ ! -d "$WIKI_DIR_INST/$WIKI_DIR_NAME" ];
then
@@ -336,20 +332,21 @@ wiki_install () {
fi
# Fetch MediaWiki's archive if not already present in the TMP directory
+ MW_FILENAME="mediawiki-$MW_VERSION_MAJOR.$MW_VERSION_MINOR.tar.gz"
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" ||
+ if [ ! -f $MW_FILENAME ] ; then
+ echo "Downloading $MW_VERSION_MAJOR.$MW_VERSION_MINOR sources ..."
+ wget "http://download.wikimedia.org/mediawiki/$MW_VERSION_MAJOR/$MW_FILENAME" ||
error "Unable to download "\
- "http://download.wikimedia.org/mediawiki/1.19/"\
- "mediawiki-1.19.0.tar.gz. "\
+ "http://download.wikimedia.org/mediawiki/$MW_VERSION_MAJOR/"\
+ "$MW_FILENAME. "\
"Please fix your connection and launch the script again."
- echo "$MW_VERSION.tar.gz downloaded in `pwd`. "\
+ echo "$MW_FILENAME downloaded in `pwd`. "\
"You can delete it later if you want."
else
- echo "Reusing existing $MW_VERSION.tar.gz downloaded in `pwd`."
+ echo "Reusing existing $MW_FILENAME downloaded in `pwd`."
fi
- archive_abs_path=$(pwd)/"$MW_VERSION.tar.gz"
+ archive_abs_path=$(pwd)/$MW_FILENAME
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 ||
@@ -431,5 +428,5 @@ wiki_delete () {
# 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"
+ rm -rf "$TMP/mediawiki-$MW_VERSION_MAJOR.$MW_VERSION_MINOR.tar.gz"
}
diff --git a/contrib/mw-to-git/t/test.config b/contrib/mw-to-git/t/test.config
index 958b37b..4cfebe9 100644
--- a/contrib/mw-to-git/t/test.config
+++ b/contrib/mw-to-git/t/test.config
@@ -30,6 +30,8 @@ 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
+# tested versions: 1.19.X -> 1.21.1
+MW_VERSION_MAJOR=1.21
+MW_VERSION_MINOR=1
FILES_FOLDER=install-wiki
DB_INSTALL_SCRIPT=db_install.php
diff --git a/contrib/patches/docbook-xsl-manpages-charmap.patch b/contrib/patches/docbook-xsl-manpages-charmap.patch
deleted file mode 100644
index f2b08b4..0000000
--- a/contrib/patches/docbook-xsl-manpages-charmap.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-From: Ismail Dönmez <ismail@pardus.org.tr>
-
-Trying to build the documentation with docbook-xsl 1.73 may result in
-the following error. This patch fixes it.
-
-$ xmlto -m callouts.xsl man git-add.xml
-runtime error: file
-file:///usr/share/sgml/docbook/xsl-stylesheets-1.73.0/manpages/other.xsl line
-129 element call-template
-The called template 'read-character-map' was not found.
-
---- docbook-xsl-1.73.0/manpages/docbook.xsl.manpages-charmap 2007-07-23 16:24:23.000000000 +0100
-+++ docbook-xsl-1.73.0/manpages/docbook.xsl 2007-07-23 16:25:16.000000000 +0100
-@@ -37,6 +37,7 @@
- <xsl:include href="lists.xsl"/>
- <xsl:include href="endnotes.xsl"/>
- <xsl:include href="table.xsl"/>
-+ <xsl:include href="../common/charmap.xsl"/>
-
- <!-- * we rename the following just to avoid using params with "man" -->
- <!-- * prefixes in the table.xsl stylesheet (because that stylesheet -->
diff --git a/contrib/remote-helpers/Makefile b/contrib/remote-helpers/Makefile
index 9a76575..239161d 100644
--- a/contrib/remote-helpers/Makefile
+++ b/contrib/remote-helpers/Makefile
@@ -3,6 +3,7 @@ TESTS := $(wildcard test*.sh)
export T := $(addprefix $(CURDIR)/,$(TESTS))
export MAKE := $(MAKE) -e
export PATH := $(CURDIR):$(PATH)
+export TEST_LINT := test-lint-executable test-lint-shell-syntax
test:
$(MAKE) -C ../../t $@
diff --git a/contrib/remote-helpers/git-remote-bzr b/contrib/remote-helpers/git-remote-bzr
index c5822e4..1e0044b 100755
--- a/contrib/remote-helpers/git-remote-bzr
+++ b/contrib/remote-helpers/git-remote-bzr
@@ -13,6 +13,9 @@
# or
# % git clone bzr::lp:myrepo
#
+# If you want to specify which branches you want track (per repo):
+# git config remote-bzr.branches 'trunk, devel, test'
+#
import sys
@@ -25,15 +28,21 @@ bzrlib.plugin.load_plugins()
import bzrlib.generate_ids
import bzrlib.transport
+import bzrlib.errors
+import bzrlib.ui
+import bzrlib.urlutils
+import bzrlib.branch
import sys
import os
import json
import re
import StringIO
+import atexit, shutil, hashlib, urlparse, subprocess
NAME_RE = re.compile('^([^<>]+)')
AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$')
+EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)')
RAW_AUTHOR_RE = re.compile('^(\w+) (.+)? <(.*)> (\d+) ([+-]\d+)')
def die(msg, *args):
@@ -46,6 +55,12 @@ def warn(msg, *args):
def gittz(tz):
return '%+03d%02d' % (tz / 3600, tz % 3600 / 60)
+def get_config(config):
+ cmd = ['git', 'config', '--get', config]
+ process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ output, _ = process.communicate()
+ return output
+
class Marks:
def __init__(self, path):
@@ -81,7 +96,7 @@ class Marks:
return self.marks[rev]
def to_rev(self, mark):
- return self.rev_marks[mark]
+ return str(self.rev_marks[mark])
def next_mark(self):
self.last_mark += 1
@@ -93,7 +108,7 @@ class Marks:
return self.last_mark
def is_marked(self, rev):
- return self.marks.has_key(rev)
+ return rev in self.marks
def new_mark(self, rev, mark):
self.marks[rev] = mark
@@ -101,7 +116,10 @@ class Marks:
self.last_mark = mark
def get_tip(self, branch):
- return self.tips.get(branch, None)
+ try:
+ return str(self.tips[branch])
+ except KeyError:
+ return None
def set_tip(self, branch, tip):
self.tips[branch] = tip
@@ -171,9 +189,19 @@ def fixup_user(user):
name = m.group(1)
mail = m.group(2).strip()
else:
- m = NAME_RE.match(user)
+ m = EMAIL_RE.match(user)
if m:
- name = m.group(1).strip()
+ name = m.group(1)
+ mail = m.group(2)
+ else:
+ m = NAME_RE.match(user)
+ if m:
+ name = m.group(1).strip()
+
+ if not name:
+ name = 'unknown'
+ if not mail:
+ mail = 'Unknown'
return '%s <%s>' % (name, mail)
@@ -183,15 +211,24 @@ def get_filechanges(cur, prev):
changes = cur.changes_from(prev)
+ def u(s):
+ return s.encode('utf-8')
+
for path, fid, kind in changes.added:
- modified[path] = fid
+ modified[u(path)] = fid
for path, fid, kind in changes.removed:
- removed[path] = None
+ removed[u(path)] = None
for path, fid, kind, mod, _ in changes.modified:
- modified[path] = fid
+ modified[u(path)] = fid
for oldpath, newpath, fid, kind, mod, _ in changes.renamed:
- removed[oldpath] = None
- modified[newpath] = fid
+ removed[u(oldpath)] = None
+ if kind == 'directory':
+ lst = cur.list_files(from_dir=newpath, recursive=True)
+ for path, file_class, kind, fid, entry in lst:
+ if kind != 'directory':
+ modified[u(newpath + '/' + path)] = fid
+ else:
+ modified[u(newpath)] = fid
return modified, removed
@@ -214,7 +251,7 @@ def export_files(tree, files):
else:
mode = '100644'
- # is the blog already exported?
+ # is the blob already exported?
if h in filenodes:
mark = filenodes[h]
final.append((mode, mark, path))
@@ -238,29 +275,44 @@ def export_files(tree, files):
return final
-def export_branch(branch, name):
- global prefix, dirname
+def export_branch(repo, name):
+ global prefix
ref = '%s/heads/%s' % (prefix, name)
tip = marks.get_tip(name)
+ branch = get_remote_branch(name)
repo = branch.repository
- repo.lock_read()
+
+ branch.lock_read()
revs = branch.iter_merge_sorted_revisions(None, tip, 'exclude', 'forward')
- count = 0
+ try:
+ tip_revno = branch.revision_id_to_revno(tip)
+ last_revno, _ = branch.last_revision_info()
+ total = last_revno - tip_revno
+ except bzrlib.errors.NoSuchRevision:
+ tip_revno = 0
+ total = 0
- revs = [revid for revid, _, _, _ in revs if not marks.is_marked(revid)]
+ for revid, _, seq, _ in revs:
- for revid in revs:
+ if marks.is_marked(revid):
+ continue
rev = repo.get_revision(revid)
+ revno = seq[0]
parents = rev.parent_ids
time = rev.timestamp
tz = rev.timezone
committer = rev.committer.encode('utf-8')
committer = "%s %u %s" % (fixup_user(committer), time, gittz(tz))
- author = committer
+ authors = rev.get_apparent_authors()
+ if authors:
+ author = authors[0].encode('utf-8')
+ author = "%s %u %s" % (fixup_user(author), time, gittz(tz))
+ else:
+ author = committer
msg = rev.message.encode('utf-8')
msg += '\n'
@@ -297,18 +349,24 @@ def export_branch(branch, name):
else:
print "merge :%s" % m
+ for f in removed:
+ print "D %s" % (f,)
for f in modified_final:
print "M %s :%u %s" % f
- for f in removed:
- print "D %s" % (f)
print
- count += 1
- if (count % 100 == 0):
- print "progress revision %s (%d/%d)" % (revid, count, len(revs))
- print "#############################################################"
+ if len(seq) > 1:
+ # let's skip branch revisions from the progress report
+ continue
+
+ progress = (revno - tip_revno)
+ if (progress % 100 == 0):
+ if total:
+ print "progress revision %d '%s' (%d/%d)" % (revno, name, progress, total)
+ else:
+ print "progress revision %d '%s' (%d)" % (revno, name, progress)
- repo.unlock()
+ branch.unlock()
revid = branch.last_revision()
@@ -320,34 +378,34 @@ def export_branch(branch, name):
marks.set_tip(name, revid)
def export_tag(repo, name):
- global tags
- try:
- print "reset refs/tags/%s" % name
- print "from :%u" % rev_to_mark(tags[name])
- print
- except KeyError:
- warn("TODO: fetch tag '%s'" % name)
+ global tags, prefix
+
+ ref = '%s/tags/%s' % (prefix, name)
+ print "reset %s" % ref
+ print "from :%u" % rev_to_mark(tags[name])
+ print
def do_import(parser):
global dirname
- branch = parser.repo
+ repo = parser.repo
path = os.path.join(dirname, 'marks-git')
print "feature done"
if os.path.exists(path):
print "feature import-marks=%s" % path
print "feature export-marks=%s" % path
+ print "feature force"
sys.stdout.flush()
while parser.check('import'):
ref = parser[1]
if ref.startswith('refs/heads/'):
name = ref[len('refs/heads/'):]
- export_branch(branch, name)
+ export_branch(repo, name)
if ref.startswith('refs/tags/'):
name = ref[len('refs/tags/'):]
- export_tag(branch, name)
+ export_tag(repo, name)
parser.next()
print 'done'
@@ -366,23 +424,21 @@ def parse_blob(parser):
class CustomTree():
- def __init__(self, repo, revid, parents, files):
+ def __init__(self, branch, revid, parents, files):
global files_cache
- self.repo = repo
- self.revid = revid
- self.parents = parents
self.updates = {}
+ self.branch = branch
def copy_tree(revid):
files = files_cache[revid] = {}
- tree = repo.repository.revision_tree(revid)
- repo.lock_read()
+ branch.lock_read()
+ tree = branch.repository.revision_tree(revid)
try:
for path, entry in tree.iter_entries_by_dir():
- files[path] = entry.file_id
+ files[path] = [entry.file_id, None]
finally:
- repo.unlock()
+ branch.unlock()
return files
if len(parents) == 0:
@@ -395,12 +451,18 @@ class CustomTree():
self.base_files = copy_tree(self.base_id)
self.files = files_cache[revid] = self.base_files.copy()
+ self.rev_files = {}
+
+ for path, data in self.files.iteritems():
+ fid, mark = data
+ self.rev_files[fid] = [path, mark]
for path, f in files.iteritems():
- fid = self.files.get(path, None)
+ fid, mark = self.files.get(path, [None, None])
if not fid:
fid = bzrlib.generate_ids.gen_file_id(path)
f['path'] = path
+ self.rev_files[fid] = [path, mark]
self.updates[fid] = f
def last_revision(self):
@@ -410,16 +472,16 @@ class CustomTree():
changes = []
def get_parent(dirname, basename):
- parent_fid = self.base_files.get(dirname, None)
+ parent_fid, mark = self.base_files.get(dirname, [None, None])
if parent_fid:
return parent_fid
- parent_fid = self.files.get(dirname, None)
+ parent_fid, mark = self.files.get(dirname, [None, None])
if parent_fid:
return parent_fid
if basename == '':
return None
fid = bzrlib.generate_ids.gen_file_id(path)
- d = add_entry(fid, dirname, 'directory')
+ add_entry(fid, dirname, 'directory')
return fid
def add_entry(fid, path, kind, mode = None):
@@ -440,9 +502,8 @@ class CustomTree():
(None, basename),
(None, kind),
(None, executable))
- self.files[path] = change[0]
+ self.files[path] = [change[0], None]
changes.append(change)
- return change
def update_entry(fid, path, kind, mode = None):
dirname, basename = os.path.split(path)
@@ -462,9 +523,8 @@ class CustomTree():
(None, basename),
(None, kind),
(None, executable))
- self.files[path] = change[0]
+ self.files[path] = [change[0], None]
changes.append(change)
- return change
def remove_entry(fid, path, kind):
dirname, basename = os.path.split(path)
@@ -479,7 +539,6 @@ class CustomTree():
(None, None))
del self.files[path]
changes.append(change)
- return change
for fid, f in self.updates.iteritems():
path = f['path']
@@ -493,16 +552,38 @@ class CustomTree():
else:
add_entry(fid, path, 'file', f['mode'])
+ self.files[path][1] = f['mark']
+ self.rev_files[fid][1] = f['mark']
+
return changes
+ def get_content(self, file_id):
+ path, mark = self.rev_files[file_id]
+ if mark:
+ return blob_marks[mark]
+
+ # last resort
+ tree = self.branch.repository.revision_tree(self.base_id)
+ return tree.get_file_text(file_id)
+
def get_file_with_stat(self, file_id, path=None):
- return (StringIO.StringIO(self.updates[file_id]['data']), None)
+ content = self.get_content(file_id)
+ return (StringIO.StringIO(content), None)
def get_symlink_target(self, file_id):
- return self.updates[file_id]['data']
+ return self.get_content(file_id)
+
+ def id2path(self, file_id):
+ path, mark = self.rev_files[file_id]
+ return path
+
+def c_style_unescape(string):
+ if string[0] == string[-1] == '"':
+ return string.decode('string-escape')[1:-1]
+ return string
def parse_commit(parser):
- global marks, blob_marks, bmarks, parsed_refs
+ global marks, blob_marks, parsed_refs
global mode
parents = []
@@ -510,8 +591,11 @@ def parse_commit(parser):
ref = parser[1]
parser.next()
- if ref != 'refs/heads/master':
- die("bzr doesn't support multiple branches; use 'master'")
+ if ref.startswith('refs/heads/'):
+ name = ref[len('refs/heads/'):]
+ branch = get_remote_branch(name)
+ else:
+ die('unknown ref')
commit_mark = parser.get_mark()
parser.next()
@@ -528,34 +612,37 @@ def parse_commit(parser):
parents.append(parser.get_mark())
parser.next()
+ # fast-export adds an extra newline
+ if data[-1] == '\n':
+ data = data[:-1]
+
files = {}
for line in parser:
if parser.check('M'):
t, m, mark_ref, path = line.split(' ', 3)
mark = int(mark_ref[1:])
- f = { 'mode' : m, 'data' : blob_marks[mark] }
+ f = { 'mode' : m, 'mark' : mark }
elif parser.check('D'):
- t, path = line.split(' ')
+ t, path = line.split(' ', 1)
f = { 'deleted' : True }
else:
die('Unknown file command: %s' % line)
+ path = c_style_unescape(path).decode('utf-8')
files[path] = f
- repo = parser.repo
-
committer, date, tz = committer
- parents = [str(mark_to_rev(p)) for p in parents]
+ parents = [mark_to_rev(p) for p in parents]
revid = bzrlib.generate_ids.gen_revision_id(committer, date)
props = {}
- props['branch-nick'] = repo.nick
+ props['branch-nick'] = branch.nick
- mtree = CustomTree(repo, revid, parents, files)
+ mtree = CustomTree(branch, revid, parents, files)
changes = mtree.iter_changes()
- repo.lock_write()
+ branch.lock_write()
try:
- builder = repo.get_commit_builder(parents, None, date, tz, committer, props, revid)
+ builder = branch.get_commit_builder(parents, None, date, tz, committer, props, revid)
try:
list(builder.record_iter_changes(mtree, mtree.last_revision(), changes))
builder.finish_inventory()
@@ -564,7 +651,7 @@ def parse_commit(parser):
builder.abort()
raise
finally:
- repo.unlock()
+ branch.unlock()
parsed_refs[ref] = revid
marks.new_mark(revid, commit_mark)
@@ -575,9 +662,6 @@ def parse_reset(parser):
ref = parser[1]
parser.next()
- if ref != 'refs/heads/master':
- die("bzr doesn't support multiple branches; use 'master'")
-
# ugh
if parser.check('commit'):
parse_commit(parser)
@@ -590,7 +674,7 @@ def parse_reset(parser):
parsed_refs[ref] = mark_to_rev(from_mark)
def do_export(parser):
- global parsed_refs, dirname, peer
+ global parsed_refs, dirname, transports
parser.next()
@@ -608,22 +692,36 @@ def do_export(parser):
else:
die('unhandled export command: %s' % line)
- repo = parser.repo
-
for ref, revid in parsed_refs.iteritems():
- if ref == 'refs/heads/master':
- repo.generate_revision_history(revid, marks.get_tip('master'))
- revno, revid = repo.last_revision_info()
- if peer:
- if hasattr(peer, "import_last_revision_info_and_tags"):
- peer.import_last_revision_info_and_tags(repo, revno, revid)
- else:
- peer.import_last_revision_info(repo.repository, revno, revid)
- wt = peer.bzrdir.open_workingtree()
- else:
- wt = repo.bzrdir.open_workingtree()
- wt.update()
+ if ref.startswith('refs/heads/'):
+ name = ref[len('refs/heads/'):]
+ branch = get_remote_branch(name)
+ branch.generate_revision_history(revid, marks.get_tip(name))
+
+ if name in peers:
+ peer = bzrlib.branch.Branch.open(peers[name],
+ possible_transports=transports)
+ try:
+ peer.bzrdir.push_branch(branch, revision_id=revid)
+ except bzrlib.errors.DivergedBranches:
+ print "error %s non-fast forward" % ref
+ continue
+
+ try:
+ wt = branch.bzrdir.open_workingtree()
+ wt.update()
+ except bzrlib.errors.NoWorkingTree:
+ pass
+ elif ref.startswith('refs/tags/'):
+ # TODO: implement tag push
+ print "error %s pushing tags not supported" % ref
+ continue
+ else:
+ # transport-helper/fast-export bugs
+ continue
+
print "ok %s" % ref
+
print
def do_capabilities(parser):
@@ -632,6 +730,7 @@ def do_capabilities(parser):
print "import"
print "export"
print "refspec refs/heads/*:%s/heads/*" % prefix
+ print "refspec refs/tags/*:%s/tags/*" % prefix
path = os.path.join(dirname, 'marks-git')
@@ -641,66 +740,204 @@ def do_capabilities(parser):
print
+def ref_is_valid(name):
+ return not True in [c in name for c in '~^: \\']
+
def do_list(parser):
global tags
- print "? refs/heads/%s" % 'master'
- for tag, revid in parser.repo.tags.get_tag_dict().items():
+
+ master_branch = None
+
+ for name in branches:
+ if not master_branch:
+ master_branch = name
+ print "? refs/heads/%s" % name
+
+ branch = get_remote_branch(master_branch)
+ branch.lock_read()
+ for tag, revid in branch.tags.get_tag_dict().items():
+ try:
+ branch.revision_id_to_dotted_revno(revid)
+ except bzrlib.errors.NoSuchRevision:
+ continue
+ if not ref_is_valid(tag):
+ continue
print "? refs/tags/%s" % tag
tags[tag] = revid
- print "@refs/heads/%s HEAD" % 'master'
+ branch.unlock()
+
+ print "@refs/heads/%s HEAD" % master_branch
print
+def clone(path, remote_branch):
+ global transports
+ try:
+ bdir = bzrlib.bzrdir.BzrDir.create(path, possible_transports=transports)
+ except bzrlib.errors.AlreadyControlDirError:
+ bdir = bzrlib.bzrdir.BzrDir.open(path, possible_transports=transports)
+ repo = bdir.find_repository()
+ repo.fetch(remote_branch.repository)
+ return remote_branch.sprout(bdir, repository=repo)
+
+def get_remote_branch(name):
+ global dirname, branches, transports
+
+ remote_branch = bzrlib.branch.Branch.open(branches[name],
+ possible_transports=transports)
+ if isinstance(remote_branch.user_transport, bzrlib.transport.local.LocalTransport):
+ return remote_branch
+
+ branch_path = os.path.join(dirname, 'clone', name)
+
+ try:
+ branch = bzrlib.branch.Branch.open(branch_path,
+ possible_transports=transports)
+ except bzrlib.errors.NotBranchError:
+ # clone
+ branch = clone(branch_path, remote_branch)
+ else:
+ # pull
+ try:
+ branch.pull(remote_branch, overwrite=True)
+ except bzrlib.errors.DivergedBranches:
+ # use remote branch for now
+ return remote_branch
+
+ return branch
+
+def find_branches(repo):
+ transport = repo.bzrdir.root_transport
+
+ for fn in transport.iter_files_recursive():
+ if not fn.endswith('.bzr/branch-format'):
+ continue
+
+ name = subdir = fn[:-len('/.bzr/branch-format')]
+ name = name if name != '' else 'master'
+ name = name.replace('/', '+')
+
+ try:
+ cur = transport.clone(subdir)
+ branch = bzrlib.branch.Branch.open_from_transport(cur)
+ except bzrlib.errors.NotBranchError:
+ continue
+ else:
+ yield name, branch.base
+
def get_repo(url, alias):
- global dirname, peer
+ global dirname, peer, branches, transports
- origin = bzrlib.bzrdir.BzrDir.open(url)
- branch = origin.open_branch()
+ normal_url = bzrlib.urlutils.normalize_url(url)
+ origin = bzrlib.bzrdir.BzrDir.open(url, possible_transports=transports)
+ is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
- if not isinstance(origin.transport, bzrlib.transport.local.LocalTransport):
+ shared_path = os.path.join(gitdir, 'bzr')
+ try:
+ shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path,
+ possible_transports=transports)
+ except bzrlib.errors.NotBranchError:
+ shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path,
+ possible_transports=transports)
+ try:
+ shared_repo = shared_dir.open_repository()
+ except bzrlib.errors.NoRepositoryPresent:
+ shared_repo = shared_dir.create_repository(shared=True)
+
+ if not is_local:
clone_path = os.path.join(dirname, 'clone')
- remote_branch = branch
- if os.path.exists(clone_path):
- # pull
- d = bzrlib.bzrdir.BzrDir.open(clone_path)
- branch = d.open_branch()
- result = branch.pull(remote_branch, [], None, False)
+ if not os.path.exists(clone_path):
+ os.mkdir(clone_path)
else:
- # clone
- d = origin.sprout(clone_path, None,
- hardlink=True, create_tree_if_local=False,
- source_branch=remote_branch)
- branch = d.open_branch()
- branch.bind(remote_branch)
-
- peer = remote_branch
+ # check and remove old organization
+ try:
+ bdir = bzrlib.bzrdir.BzrDir.open(clone_path,
+ possible_transports=transports)
+ bdir.destroy_repository()
+ except bzrlib.errors.NotBranchError:
+ pass
+ except bzrlib.errors.NoRepositoryPresent:
+ pass
+
+ wanted = get_config('remote-bzr.branches').rstrip().split(', ')
+ # stupid python
+ wanted = [e for e in wanted if e]
+
+ if not wanted:
+ try:
+ repo = origin.open_repository()
+ if not repo.user_transport.listable():
+ # this repository is not usable for us
+ raise bzrlib.errors.NoRepositoryPresent(repo.bzrdir)
+ except bzrlib.errors.NoRepositoryPresent:
+ wanted = ['master']
+
+ if wanted:
+ def list_wanted(url, wanted):
+ for name in wanted:
+ subdir = name if name != 'master' else ''
+ yield name, bzrlib.urlutils.join(url, subdir)
+
+ branch_list = list_wanted(url, wanted)
else:
- peer = None
+ branch_list = find_branches(repo)
- return branch
+ for name, url in branch_list:
+ if not is_local:
+ peers[name] = url
+ branches[name] = url
+
+ return origin
+
+def fix_path(alias, orig_url):
+ url = urlparse.urlparse(orig_url, 'file')
+ if url.scheme != 'file' or os.path.isabs(url.path):
+ return
+ abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url)
+ cmd = ['git', 'config', 'remote.%s.url' % alias, "bzr::%s" % abs_url]
+ subprocess.call(cmd)
def main(args):
- global marks, prefix, dirname
+ global marks, prefix, gitdir, dirname
global tags, filenodes
global blob_marks
global parsed_refs
global files_cache
+ global is_tmp
+ global branches, peers
+ global transports
alias = args[1]
url = args[2]
- prefix = 'refs/bzr/%s' % alias
tags = {}
filenodes = {}
blob_marks = {}
parsed_refs = {}
files_cache = {}
+ marks = None
+ branches = {}
+ peers = {}
+ transports = []
+
+ if alias[5:] == url:
+ is_tmp = True
+ alias = hashlib.sha1(alias).hexdigest()
+ else:
+ is_tmp = False
+ prefix = 'refs/bzr/%s' % alias
gitdir = os.environ['GIT_DIR']
dirname = os.path.join(gitdir, 'bzr', alias)
+ if not is_tmp:
+ fix_path(alias, url)
+
if not os.path.exists(dirname):
os.makedirs(dirname)
+ if hasattr(bzrlib.ui.ui_factory, 'be_quiet'):
+ bzrlib.ui.ui_factory.be_quiet(True)
+
repo = get_repo(url, alias)
marks_path = os.path.join(dirname, 'marks-int')
@@ -720,6 +957,13 @@ def main(args):
die('unhandled command: %s' % line)
sys.stdout.flush()
- marks.store()
+def bye():
+ if not marks:
+ return
+ if not is_tmp:
+ marks.store()
+ else:
+ shutil.rmtree(dirname)
+atexit.register(bye)
sys.exit(main(sys.argv))
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index 45f6c80..c276039 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -8,8 +8,11 @@
# Just copy to your ~/bin, or anywhere in your $PATH.
# Then you can clone with:
# git clone hg::/path/to/mercurial/repo/
+#
+# For remote repositories a local clone is stored in
+# "$GIT_DIR/hg/origin/clone/.hg/".
-from mercurial import hg, ui, bookmarks, context, util, encoding
+from mercurial import hg, ui, bookmarks, context, encoding, node, error, extensions, discovery, util
import re
import sys
@@ -18,8 +21,17 @@ import json
import shutil
import subprocess
import urllib
+import atexit
+import urlparse, hashlib
#
+# If you are not in hg-git-compat mode and want to disable the tracking of
+# named branches:
+# git config --global remote-hg.track-branches false
+#
+# If you want the equivalent of hg's clone/pull--insecure option:
+# git config --global remote-hg.insecure true
+#
# If you want to switch to hg-git compatibility mode:
# git config --global remote-hg.hg-git-compat true
#
@@ -36,9 +48,12 @@ import urllib
NAME_RE = re.compile('^([^<>]+)')
AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$')
+EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)')
AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$')
RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)')
+VERSION = 2
+
def die(msg, *args):
sys.stderr.write('ERROR: %s\n' % (msg % args))
sys.exit(1)
@@ -56,22 +71,61 @@ def hgmode(mode):
m = { '100755': 'x', '120000': 'l' }
return m.get(mode, '')
+def hghex(n):
+ return node.hex(n)
+
+def hgbin(n):
+ return node.bin(n)
+
+def hgref(ref):
+ return ref.replace('___', ' ')
+
+def gitref(ref):
+ return ref.replace(' ', '___')
+
+def check_version(*check):
+ if not hg_version:
+ return True
+ return hg_version >= check
+
def get_config(config):
cmd = ['git', 'config', '--get', config]
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
output, _ = process.communicate()
return output
+def get_config_bool(config, default=False):
+ value = get_config(config).rstrip('\n')
+ if value == "true":
+ return True
+ elif value == "false":
+ return False
+ else:
+ return default
+
class Marks:
- def __init__(self, path):
+ def __init__(self, path, repo):
self.path = path
+ self.repo = repo
+ self.clear()
+ self.load()
+
+ if self.version < VERSION:
+ if self.version == 1:
+ self.upgrade_one()
+
+ # upgraded?
+ if self.version < VERSION:
+ self.clear()
+ self.version = VERSION
+
+ def clear(self):
self.tips = {}
self.marks = {}
self.rev_marks = {}
self.last_mark = 0
-
- self.load()
+ self.version = 0
def load(self):
if not os.path.exists(self.path):
@@ -82,12 +136,21 @@ class Marks:
self.tips = tmp['tips']
self.marks = tmp['marks']
self.last_mark = tmp['last-mark']
+ self.version = tmp.get('version', 1)
for rev, mark in self.marks.iteritems():
- self.rev_marks[mark] = int(rev)
+ self.rev_marks[mark] = rev
+
+ def upgrade_one(self):
+ def get_id(rev):
+ return hghex(self.repo.changelog.node(int(rev)))
+ self.tips = dict((name, get_id(rev)) for name, rev in self.tips.iteritems())
+ self.marks = dict((get_id(rev), mark) for rev, mark in self.marks.iteritems())
+ self.rev_marks = dict((mark, get_id(rev)) for mark, rev in self.rev_marks.iteritems())
+ self.version = 2
def dict(self):
- return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark }
+ return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version }
def store(self):
json.dump(self.dict(), open(self.path, 'w'))
@@ -96,26 +159,30 @@ class Marks:
return str(self.dict())
def from_rev(self, rev):
- return self.marks[str(rev)]
+ return self.marks[rev]
def to_rev(self, mark):
- return self.rev_marks[mark]
+ return str(self.rev_marks[mark])
+
+ def next_mark(self):
+ self.last_mark += 1
+ return self.last_mark
def get_mark(self, rev):
self.last_mark += 1
- self.marks[str(rev)] = self.last_mark
+ self.marks[rev] = self.last_mark
return self.last_mark
def new_mark(self, rev, mark):
- self.marks[str(rev)] = mark
+ self.marks[rev] = mark
self.rev_marks[mark] = rev
self.last_mark = mark
def is_marked(self, rev):
- return self.marks.has_key(str(rev))
+ return rev in self.marks
def get_tip(self, branch):
- return self.tips.get(branch, 0)
+ return str(self.tips[branch])
def set_tip(self, branch, tip):
self.tips[branch] = tip
@@ -188,19 +255,43 @@ class Parser:
tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
return (user, int(date), -tz)
-def export_file(fc):
- d = fc.data()
- print "M %s inline %s" % (gitmode(fc.flags()), fc.path())
- print "data %d" % len(d)
- print d
+def fix_file_path(path):
+ if not os.path.isabs(path):
+ return path
+ return os.path.relpath(path, '/')
+
+def export_files(files):
+ global marks, filenodes
+
+ final = []
+ for f in files:
+ fid = node.hex(f.filenode())
+
+ if fid in filenodes:
+ mark = filenodes[fid]
+ else:
+ mark = marks.next_mark()
+ filenodes[fid] = mark
+ d = f.data()
+
+ print "blob"
+ print "mark :%u" % mark
+ print "data %d" % len(d)
+ print d
+
+ path = fix_file_path(f.path())
+ final.append((gitmode(f.flags()), mark, path))
+
+ return final
def get_filechanges(repo, ctx, parent):
modified = set()
added = set()
removed = set()
+ # load earliest manifest first for caching reasons
+ prev = parent.manifest().copy()
cur = ctx.manifest()
- prev = repo[parent].manifest().copy()
for fn in cur:
if fn in prev:
@@ -221,9 +312,14 @@ def fixup_user_git(user):
name = m.group(1)
mail = m.group(2).strip()
else:
- m = NAME_RE.match(user)
+ m = EMAIL_RE.match(user)
if m:
- name = m.group(1).strip()
+ name = m.group(1)
+ mail = m.group(2)
+ else:
+ m = NAME_RE.match(user)
+ if m:
+ name = m.group(1).strip()
return (name, mail)
def fixup_user_hg(user):
@@ -262,29 +358,79 @@ def fixup_user(user):
return '%s <%s>' % (name, mail)
+def updatebookmarks(repo, peer):
+ remotemarks = peer.listkeys('bookmarks')
+ localmarks = repo._bookmarks
+
+ if not remotemarks:
+ return
+
+ for k, v in remotemarks.iteritems():
+ localmarks[k] = hgbin(v)
+
+ if hasattr(localmarks, 'write'):
+ localmarks.write()
+ else:
+ bookmarks.write(repo)
+
def get_repo(url, alias):
global dirname, peer
myui = ui.ui()
myui.setconfig('ui', 'interactive', 'off')
+ myui.fout = sys.stderr
+
+ if get_config_bool('remote-hg.insecure'):
+ myui.setconfig('web', 'cacerts', '')
- if hg.islocal(url):
+ extensions.loadall(myui)
+
+ if hg.islocal(url) and not os.environ.get('GIT_REMOTE_HG_TEST_REMOTE'):
repo = hg.repository(myui, url)
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
else:
+ shared_path = os.path.join(gitdir, 'hg')
+
+ # check and upgrade old organization
+ hg_path = os.path.join(shared_path, '.hg')
+ if os.path.exists(shared_path) and not os.path.exists(hg_path):
+ repos = os.listdir(shared_path)
+ for x in repos:
+ local_hg = os.path.join(shared_path, x, 'clone', '.hg')
+ if not os.path.exists(local_hg):
+ continue
+ if not os.path.exists(hg_path):
+ shutil.move(local_hg, hg_path)
+ shutil.rmtree(os.path.join(shared_path, x, 'clone'))
+
+ # setup shared repo (if not there)
+ try:
+ hg.peer(myui, {}, shared_path, create=True)
+ except error.RepoError:
+ pass
+
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+
local_path = os.path.join(dirname, 'clone')
if not os.path.exists(local_path):
- peer, dstpeer = hg.clone(myui, {}, url, local_path, update=False, pull=True)
- repo = dstpeer.local()
- else:
- repo = hg.repository(myui, local_path)
+ hg.share(myui, shared_path, local_path, update=False)
+
+ repo = hg.repository(myui, local_path)
+ try:
peer = hg.peer(myui, {}, url)
- repo.pull(peer, heads=None, force=True)
+ except:
+ die('Repository error')
+ repo.pull(peer, heads=None, force=True)
+
+ updatebookmarks(repo, peer)
return repo
def rev_to_mark(rev):
global marks
- return marks.from_rev(rev)
+ return marks.from_rev(rev.hex())
def mark_to_rev(mark):
global marks
@@ -294,21 +440,24 @@ def export_ref(repo, name, kind, head):
global prefix, marks, mode
ename = '%s/%s' % (kind, name)
- tip = marks.get_tip(ename)
+ try:
+ tip = marks.get_tip(ename)
+ tip = repo[tip].rev()
+ except:
+ tip = 0
- # mercurial takes too much time checking this
- if tip and tip == head.rev():
- # nothing to do
- return
revs = xrange(tip, head.rev() + 1)
- count = 0
-
- revs = [rev for rev in revs if not marks.is_marked(rev)]
+ total = len(revs)
for rev in revs:
c = repo[rev]
- (manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(c.node())
+ node = c.node()
+
+ if marks.is_marked(c.hex()):
+ continue
+
+ (manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(node)
rev_branch = extra['branch']
author = "%s %d %s" % (fixup_user(user), time, gittz(tz))
@@ -318,7 +467,7 @@ def export_ref(repo, name, kind, head):
else:
committer = author
- parents = [p for p in repo.changelog.parentrevs(rev) if p >= 0]
+ parents = [repo[p] for p in repo.changelog.parentrevs(rev) if p >= 0]
if len(parents) == 0:
modified = c.manifest().keys()
@@ -357,8 +506,10 @@ def export_ref(repo, name, kind, head):
if len(parents) == 0 and rev:
print 'reset %s/%s' % (prefix, ename)
+ modified_final = export_files(c.filectx(f) for f in modified)
+
print "commit %s/%s" % (prefix, ename)
- print "mark :%d" % (marks.get_mark(rev))
+ print "mark :%d" % (marks.get_mark(c.hex()))
print "author %s" % (author)
print "committer %s" % (committer)
print "data %d" % (len(desc))
@@ -369,29 +520,28 @@ def export_ref(repo, name, kind, head):
if len(parents) > 1:
print "merge :%s" % (rev_to_mark(parents[1]))
- for f in modified:
- export_file(c.filectx(f))
for f in removed:
- print "D %s" % (f)
+ print "D %s" % (fix_file_path(f))
+ for f in modified_final:
+ print "M %s :%u %s" % f
print
- count += 1
- if (count % 100 == 0):
- print "progress revision %d '%s' (%d/%d)" % (rev, name, count, len(revs))
- print "#############################################################"
+ progress = (rev - tip)
+ if (progress % 100 == 0):
+ print "progress revision %d '%s' (%d/%d)" % (rev, name, progress, total)
# make sure the ref is updated
print "reset %s/%s" % (prefix, ename)
- print "from :%u" % rev_to_mark(rev)
+ print "from :%u" % rev_to_mark(head)
print
- marks.set_tip(ename, rev)
+ marks.set_tip(ename, head.hex())
def export_tag(repo, tag):
- export_ref(repo, tag, 'tags', repo[tag])
+ export_ref(repo, tag, 'tags', repo[hgref(tag)])
def export_bookmark(repo, bmark):
- head = bmarks[bmark]
+ head = bmarks[hgref(bmark)]
export_ref(repo, bmark, 'bookmarks', head)
def export_branch(repo, branch):
@@ -417,73 +567,72 @@ def do_capabilities(parser):
if os.path.exists(path):
print "*import-marks %s" % path
print "*export-marks %s" % path
+ print "option"
print
+def branch_tip(branch):
+ return branches[branch][-1]
+
def get_branch_tip(repo, branch):
global branches
- heads = branches.get(branch, None)
+ heads = branches.get(hgref(branch), None)
if not heads:
return None
# verify there's only one head
if (len(heads) > 1):
warn("Branch '%s' has more than one head, consider merging" % branch)
- # older versions of mercurial don't have this
- if hasattr(repo, "branchtip"):
- return repo.branchtip(branch)
+ return branch_tip(hgref(branch))
return heads[0]
def list_head(repo, cur):
- global g_head, bmarks
+ global g_head, bmarks, fake_bmark
- head = bookmarks.readcurrent(repo)
- if head:
- node = repo[head]
- else:
- # fake bookmark from current branch
- head = cur
- node = repo['.']
- if not node:
- node = repo['tip']
- if not node:
- return
- if head == 'default':
- head = 'master'
- bmarks[head] = node
+ if 'default' not in branches:
+ # empty repo
+ return
+ node = repo[branch_tip('default')]
+ head = 'master' if not 'master' in bmarks else 'default'
+ fake_bmark = head
+ bmarks[head] = node
+
+ head = gitref(head)
print "@refs/heads/%s HEAD" % head
g_head = (head, node)
def do_list(parser):
- global branches, bmarks, mode, track_branches
+ global branches, bmarks, track_branches
repo = parser.repo
for bmark, node in bookmarks.listbookmarks(repo).iteritems():
bmarks[bmark] = repo[node]
cur = repo.dirstate.branch()
+ orig = peer if peer else repo
+
+ for branch, heads in orig.branchmap().iteritems():
+ # only open heads
+ heads = [h for h in heads if 'close' not in repo.changelog.read(h)[5]]
+ if heads:
+ branches[branch] = heads
list_head(repo, cur)
if track_branches:
- for branch in repo.branchmap():
- heads = repo.branchheads(branch)
- if len(heads):
- branches[branch] = heads
-
for branch in branches:
- print "? refs/heads/branches/%s" % branch
+ print "? refs/heads/branches/%s" % gitref(branch)
for bmark in bmarks:
- print "? refs/heads/%s" % bmark
+ print "? refs/heads/%s" % gitref(bmark)
for tag, node in repo.tagslist():
if tag == 'tip':
continue
- print "? refs/tags/%s" % tag
+ print "? refs/tags/%s" % gitref(tag)
print
@@ -496,6 +645,7 @@ def do_import(parser):
if os.path.exists(path):
print "feature import-marks=%s" % path
print "feature export-marks=%s" % path
+ print "feature force"
sys.stdout.flush()
tmp = encoding.encoding
@@ -532,7 +682,6 @@ def parse_blob(parser):
data = parser.get_data()
blob_marks[mark] = data
parser.next()
- return
def get_merge_files(repo, p1, p2, files):
for e in repo[p1].files():
@@ -543,7 +692,7 @@ def get_merge_files(repo, p1, p2, files):
files[e] = f
def parse_commit(parser):
- global marks, blob_marks, bmarks, parsed_refs
+ global marks, blob_marks, parsed_refs
global mode
from_mark = merge_mark = None
@@ -568,6 +717,10 @@ def parse_commit(parser):
if parser.check('merge'):
die('octopus merges are not supported yet')
+ # fast-export adds an extra newline
+ if data[-1] == '\n':
+ data = data[:-1]
+
files = {}
for line in parser:
@@ -576,12 +729,17 @@ def parse_commit(parser):
mark = int(mark_ref[1:])
f = { 'mode' : hgmode(m), 'data' : blob_marks[mark] }
elif parser.check('D'):
- t, path = line.split(' ')
+ t, path = line.split(' ', 1)
f = { 'deleted' : True }
else:
die('Unknown file command: %s' % line)
files[path] = f
+ # only export the commits if we are on an internal proxy repo
+ if dry_run and not peer:
+ parsed_refs[ref] = None
+ return
+
def getfilectx(repo, memctx, f):
of = files[f]
if 'deleted' in of:
@@ -603,14 +761,14 @@ def parse_commit(parser):
extra['committer'] = "%s %u %u" % committer
if from_mark:
- p1 = repo.changelog.node(mark_to_rev(from_mark))
+ p1 = mark_to_rev(from_mark)
else:
- p1 = '\0' * 20
+ p1 = '0' * 40
if merge_mark:
- p2 = repo.changelog.node(mark_to_rev(merge_mark))
+ p2 = mark_to_rev(merge_mark)
else:
- p2 = '\0' * 20
+ p2 = '0' * 40
#
# If files changed from any of the parents, hg wants to know, but in git if
@@ -619,11 +777,16 @@ def parse_commit(parser):
if merge_mark:
get_merge_files(repo, p1, p2, files)
+ # Check if the ref is supposed to be a named branch
+ if ref.startswith('refs/heads/branches/'):
+ branch = ref[len('refs/heads/branches/'):]
+ extra['branch'] = hgref(branch)
+
if mode == 'hg':
i = data.find('\n--HG--\n')
if i >= 0:
tmp = data[i + len('\n--HG--\n'):].strip()
- for k, v in [e.split(' : ') for e in tmp.split('\n')]:
+ for k, v in [e.split(' : ', 1) for e in tmp.split('\n')]:
if k == 'rename':
old, new = v.split(' => ', 1)
files[new]['rename'] = old
@@ -641,17 +804,16 @@ def parse_commit(parser):
tmp = encoding.encoding
encoding.encoding = 'utf-8'
- node = repo.commitctx(ctx)
+ node = hghex(repo.commitctx(ctx))
encoding.encoding = tmp
- rev = repo[node].rev()
-
parsed_refs[ref] = node
-
- marks.new_mark(rev, commit_mark)
+ marks.new_mark(node, commit_mark)
def parse_reset(parser):
+ global parsed_refs
+
ref = parser[1]
parser.next()
# ugh
@@ -663,8 +825,11 @@ def parse_reset(parser):
from_mark = parser.get_mark()
parser.next()
- node = parser.repo.changelog.node(mark_to_rev(from_mark))
- parsed_refs[ref] = node
+ try:
+ rev = mark_to_rev(from_mark)
+ except KeyError:
+ rev = None
+ parsed_refs[ref] = rev
def parse_tag(parser):
name = parser[1]
@@ -676,11 +841,176 @@ def parse_tag(parser):
data = parser.get_data()
parser.next()
- # nothing to do
+ parsed_tags[name] = (tagger, data)
+
+def write_tag(repo, tag, node, msg, author):
+ branch = repo[node].branch()
+ tip = branch_tip(branch)
+ tip = repo[tip]
+
+ def getfilectx(repo, memctx, f):
+ try:
+ fctx = tip.filectx(f)
+ data = fctx.data()
+ except error.ManifestLookupError:
+ data = ""
+ content = data + "%s %s\n" % (node, tag)
+ return context.memfilectx(f, content, False, False, None)
+
+ p1 = tip.hex()
+ p2 = '0' * 40
+ if author:
+ user, date, tz = author
+ date_tz = (date, tz)
+ else:
+ cmd = ['git', 'var', 'GIT_COMMITTER_IDENT']
+ process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ output, _ = process.communicate()
+ m = re.match('^.* <.*>', output)
+ if m:
+ user = m.group(0)
+ else:
+ user = repo.ui.username()
+ date_tz = None
+
+ ctx = context.memctx(repo, (p1, p2), msg,
+ ['.hgtags'], getfilectx,
+ user, date_tz, {'branch' : branch})
+
+ tmp = encoding.encoding
+ encoding.encoding = 'utf-8'
+
+ tagnode = repo.commitctx(ctx)
+
+ encoding.encoding = tmp
+
+ return (tagnode, branch)
+
+def checkheads_bmark(repo, ref, ctx):
+ bmark = ref[len('refs/heads/'):]
+ if not bmark in bmarks:
+ # new bmark
+ return True
+
+ ctx_old = bmarks[bmark]
+ ctx_new = ctx
+ if not repo.changelog.descendant(ctx_old.rev(), ctx_new.rev()):
+ if force_push:
+ print "ok %s forced update" % ref
+ else:
+ print "error %s non-fast forward" % ref
+ return False
+
+ return True
+
+def checkheads(repo, remote, p_revs):
+
+ remotemap = remote.branchmap()
+ if not remotemap:
+ # empty repo
+ return True
+
+ new = {}
+ ret = True
+
+ for node, ref in p_revs.iteritems():
+ ctx = repo[node]
+ branch = ctx.branch()
+ if not branch in remotemap:
+ # new branch
+ continue
+ if not ref.startswith('refs/heads/branches'):
+ if ref.startswith('refs/heads/'):
+ if not checkheads_bmark(repo, ref, ctx):
+ ret = False
+
+ # only check branches
+ continue
+ new.setdefault(branch, []).append(ctx.rev())
+
+ for branch, heads in new.iteritems():
+ old = [repo.changelog.rev(x) for x in remotemap[branch]]
+ for rev in heads:
+ if check_version(2, 3):
+ ancestors = repo.changelog.ancestors([rev], stoprev=min(old))
+ else:
+ ancestors = repo.changelog.ancestors(rev)
+ found = False
+
+ for x in old:
+ if x in ancestors:
+ found = True
+ break
+
+ if found:
+ continue
+
+ node = repo.changelog.node(rev)
+ ref = p_revs[node]
+ if force_push:
+ print "ok %s forced update" % ref
+ else:
+ print "error %s non-fast forward" % ref
+ ret = False
+
+ return ret
+
+def push_unsafe(repo, remote, parsed_refs, p_revs):
+
+ force = force_push
+
+ fci = discovery.findcommonincoming
+ commoninc = fci(repo, remote, force=force)
+ common, _, remoteheads = commoninc
+
+ if not checkheads(repo, remote, p_revs):
+ return None
+
+ cg = repo.getbundle('push', heads=list(p_revs), common=common)
+
+ unbundle = remote.capable('unbundle')
+ if unbundle:
+ if force:
+ remoteheads = ['force']
+ return remote.unbundle(cg, remoteheads, 'push')
+ else:
+ return remote.addchangegroup(cg, 'push', repo.url())
+
+def push(repo, remote, parsed_refs, p_revs):
+ if hasattr(remote, 'canpush') and not remote.canpush():
+ print "error cannot push"
+
+ if not p_revs:
+ # nothing to push
+ return
+
+ lock = None
+ unbundle = remote.capable('unbundle')
+ if not unbundle:
+ lock = remote.lock()
+ try:
+ ret = push_unsafe(repo, remote, parsed_refs, p_revs)
+ finally:
+ if lock is not None:
+ lock.release()
+
+ return ret
+
+def check_tip(ref, kind, name, heads):
+ try:
+ ename = '%s/%s' % (kind, name)
+ tip = marks.get_tip(ename)
+ except KeyError:
+ return True
+ else:
+ return tip in heads
def do_export(parser):
global parsed_refs, bmarks, peer
+ p_bmarks = []
+ p_revs = {}
+
parser.next()
for line in parser.each_block('done'):
@@ -697,58 +1027,139 @@ def do_export(parser):
else:
die('unhandled export command: %s' % line)
+ need_fetch = False
+
for ref, node in parsed_refs.iteritems():
+ bnode = hgbin(node) if node else None
if ref.startswith('refs/heads/branches'):
- pass
+ branch = ref[len('refs/heads/branches/'):]
+ if branch in branches and bnode in branches[branch]:
+ # up to date
+ continue
+
+ if peer:
+ remotemap = peer.branchmap()
+ if remotemap and branch in remotemap:
+ heads = [hghex(e) for e in remotemap[branch]]
+ if not check_tip(ref, 'branches', branch, heads):
+ print "error %s fetch first" % ref
+ need_fetch = True
+ continue
+
+ p_revs[bnode] = ref
+ print "ok %s" % ref
elif ref.startswith('refs/heads/'):
bmark = ref[len('refs/heads/'):]
- if bmark in bmarks:
- old = bmarks[bmark].hex()
- else:
- old = ''
- if not bookmarks.pushbookmark(parser.repo, bmark, old, node):
+ new = node
+ old = bmarks[bmark].hex() if bmark in bmarks else ''
+
+ if old == new:
continue
+
+ print "ok %s" % ref
+ if bmark != fake_bmark and \
+ not (bmark == 'master' and bmark not in parser.repo._bookmarks):
+ p_bmarks.append((ref, bmark, old, new))
+
+ if peer:
+ remote_old = peer.listkeys('bookmarks').get(bmark)
+ if remote_old:
+ if not check_tip(ref, 'bookmarks', bmark, remote_old):
+ print "error %s fetch first" % ref
+ need_fetch = True
+ continue
+
+ p_revs[bnode] = ref
elif ref.startswith('refs/tags/'):
+ if dry_run:
+ print "ok %s" % ref
+ continue
tag = ref[len('refs/tags/'):]
- parser.repo.tag([tag], node, None, True, None, {})
+ tag = hgref(tag)
+ author, msg = parsed_tags.get(tag, (None, None))
+ if mode == 'git':
+ if not msg:
+ msg = 'Added tag %s for changeset %s' % (tag, node[:12]);
+ tagnode, branch = write_tag(parser.repo, tag, node, msg, author)
+ p_revs[tagnode] = 'refs/heads/branches/' + gitref(branch)
+ else:
+ fp = parser.repo.opener('localtags', 'a')
+ fp.write('%s %s\n' % (node, tag))
+ fp.close()
+ p_revs[bnode] = ref
+ print "ok %s" % ref
else:
# transport-helper/fast-export bugs
continue
- print "ok %s" % ref
- print
+ if need_fetch:
+ print
+ return
+
+ if dry_run:
+ if peer and not force_push:
+ checkheads(parser.repo, peer, p_revs)
+ print
+ return
if peer:
- parser.repo.push(peer, force=False)
+ if not push(parser.repo, peer, parsed_refs, p_revs):
+ # do not update bookmarks
+ print
+ return
+
+ # update remote bookmarks
+ remote_bmarks = peer.listkeys('bookmarks')
+ for ref, bmark, old, new in p_bmarks:
+ if force_push:
+ old = remote_bmarks.get(bmark, '')
+ if not peer.pushkey('bookmarks', bmark, old, new):
+ print "error %s" % ref
+ else:
+ # update local bookmarks
+ for ref, bmark, old, new in p_bmarks:
+ if not bookmarks.pushbookmark(parser.repo, bmark, old, new):
+ print "error %s" % ref
+
+ print
+
+def do_option(parser):
+ global dry_run, force_push
+ _, key, value = parser.line.split(' ')
+ if key == 'dry-run':
+ dry_run = (value == 'true')
+ print 'ok'
+ elif key == 'force':
+ force_push = (value == 'true')
+ print 'ok'
+ else:
+ print 'unsupported'
def fix_path(alias, repo, orig_url):
- repo_url = util.url(repo.url())
- url = util.url(orig_url)
- if str(url) == str(repo_url):
+ url = urlparse.urlparse(orig_url, 'file')
+ if url.scheme != 'file' or os.path.isabs(os.path.expanduser(url.path)):
return
- cmd = ['git', 'config', 'remote.%s.url' % alias, "hg::%s" % repo_url]
+ abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url)
+ cmd = ['git', 'config', 'remote.%s.url' % alias, "hg::%s" % abs_url]
subprocess.call(cmd)
def main(args):
- global prefix, dirname, branches, bmarks
+ global prefix, gitdir, dirname, branches, bmarks
global marks, blob_marks, parsed_refs
global peer, mode, bad_mail, bad_name
- global track_branches
+ global track_branches, force_push, is_tmp
+ global parsed_tags
+ global filenodes
+ global fake_bmark, hg_version
+ global dry_run
alias = args[1]
url = args[2]
peer = None
- hg_git_compat = False
- track_branches = True
- try:
- if get_config('remote-hg.hg-git-compat') == 'true\n':
- hg_git_compat = True
- track_branches = False
- if get_config('remote-hg.track-branches') == 'false\n':
- track_branches = False
- except subprocess.CalledProcessError:
- pass
+ hg_git_compat = get_config_bool('remote-hg.hg-git-compat')
+ track_branches = get_config_bool('remote-hg.track-branches', True)
+ force_push = False
if hg_git_compat:
mode = 'hg'
@@ -761,7 +1172,7 @@ def main(args):
if alias[4:] == url:
is_tmp = True
- alias = util.sha1(alias).hexdigest()
+ alias = hashlib.sha1(alias).hexdigest()
else:
is_tmp = False
@@ -771,6 +1182,15 @@ def main(args):
bmarks = {}
blob_marks = {}
parsed_refs = {}
+ marks = None
+ parsed_tags = {}
+ filenodes = {}
+ fake_bmark = None
+ try:
+ hg_version = tuple(int(e) for e in util.version().split('.'))
+ except:
+ hg_version = None
+ dry_run = False
repo = get_repo(url, alias)
prefix = 'refs/hg/%s' % alias
@@ -778,11 +1198,12 @@ def main(args):
if not is_tmp:
fix_path(alias, peer or repo, url)
- if not os.path.exists(dirname):
- os.makedirs(dirname)
-
marks_path = os.path.join(dirname, 'marks-hg')
- marks = Marks(marks_path)
+ marks = Marks(marks_path, repo)
+
+ if sys.platform == 'win32':
+ import msvcrt
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
parser = Parser(repo)
for line in parser:
@@ -794,13 +1215,19 @@ def main(args):
do_import(parser)
elif parser.check('export'):
do_export(parser)
+ elif parser.check('option'):
+ do_option(parser)
else:
die('unhandled command: %s' % line)
sys.stdout.flush()
+def bye():
+ if not marks:
+ return
if not is_tmp:
marks.store()
else:
shutil.rmtree(dirname)
+atexit.register(bye)
sys.exit(main(sys.argv))
diff --git a/contrib/remote-helpers/test-bzr.sh b/contrib/remote-helpers/test-bzr.sh
index 70aa8a0..dce281f 100755
--- a/contrib/remote-helpers/test-bzr.sh
+++ b/contrib/remote-helpers/test-bzr.sh
@@ -12,100 +12,90 @@ if ! test_have_prereq PYTHON; then
test_done
fi
-if ! "$PYTHON_PATH" -c 'import bzrlib'; then
+if ! python -c 'import bzrlib'; then
skip_all='skipping remote-bzr tests; bzr not available'
test_done
fi
-cmd='
-import bzrlib
-bzrlib.initialize()
-import bzrlib.plugin
-bzrlib.plugin.load_plugins()
-import bzrlib.plugins.fastimport
-'
-
-if ! "$PYTHON_PATH" -c "$cmd"; then
- echo "consider setting BZR_PLUGIN_PATH=$HOME/.bazaar/plugins" 1>&2
- skip_all='skipping remote-bzr tests; bzr-fastimport not available'
- test_done
-fi
-
check () {
- (cd $1 &&
- git log --format='%s' -1 &&
- git symbolic-ref HEAD) > actual &&
- (echo $2 &&
- echo "refs/heads/$3") > expected &&
+ echo $3 > expected &&
+ git --git-dir=$1/.git log --format='%s' -1 $2 > actual
test_cmp expected actual
}
bzr whoami "A U Thor <author@example.com>"
test_expect_success 'cloning' '
- (bzr init bzrrepo &&
- cd bzrrepo &&
- echo one > content &&
- bzr add content &&
- bzr commit -m one
- ) &&
-
- git clone "bzr::$PWD/bzrrepo" gitrepo &&
- check gitrepo one master
+ (
+ bzr init bzrrepo &&
+ cd bzrrepo &&
+ echo one > content &&
+ bzr add content &&
+ bzr commit -m one
+ ) &&
+
+ git clone "bzr::bzrrepo" gitrepo &&
+ check gitrepo HEAD one
'
test_expect_success 'pulling' '
- (cd bzrrepo &&
- echo two > content &&
- bzr commit -m two
- ) &&
+ (
+ cd bzrrepo &&
+ echo two > content &&
+ bzr commit -m two
+ ) &&
- (cd gitrepo && git pull) &&
+ (cd gitrepo && git pull) &&
- check gitrepo two master
+ check gitrepo HEAD two
'
test_expect_success 'pushing' '
- (cd gitrepo &&
- echo three > content &&
- git commit -a -m three &&
- git push
- ) &&
-
- echo three > expected &&
- cat bzrrepo/content > actual &&
- test_cmp expected actual
+ (
+ cd gitrepo &&
+ echo three > content &&
+ git commit -a -m three &&
+ git push
+ ) &&
+
+ echo three > expected &&
+ cat bzrrepo/content > actual &&
+ test_cmp expected actual
'
test_expect_success 'roundtrip' '
- (cd gitrepo &&
- git pull &&
- git log --format="%s" -1 origin/master > actual) &&
- echo three > expected &&
- test_cmp expected actual &&
+ (
+ cd gitrepo &&
+ git pull &&
+ git log --format="%s" -1 origin/master > actual
+ ) &&
+ echo three > expected &&
+ test_cmp expected actual &&
- (cd gitrepo && git push && git pull) &&
+ (cd gitrepo && git push && git pull) &&
- (cd bzrrepo &&
- echo four > content &&
- bzr commit -m four
- ) &&
+ (
+ cd bzrrepo &&
+ echo four > content &&
+ bzr commit -m four
+ ) &&
- (cd gitrepo && git pull && git push) &&
+ (cd gitrepo && git pull && git push) &&
- check gitrepo four master &&
+ check gitrepo HEAD four &&
- (cd gitrepo &&
- echo five > content &&
- git commit -a -m five &&
- git push && git pull
- ) &&
+ (
+ cd gitrepo &&
+ echo five > content &&
+ git commit -a -m five &&
+ git push && git pull
+ ) &&
- (cd bzrrepo && bzr revert) &&
+ (cd bzrrepo && bzr revert) &&
- echo five > expected &&
- cat bzrrepo/content > actual &&
- test_cmp expected actual
+ echo five > expected &&
+ cat bzrrepo/content > actual &&
+ test_cmp expected actual
'
cat > expected <<EOF
@@ -115,29 +105,257 @@ cat > expected <<EOF
EOF
test_expect_success 'special modes' '
- (cd bzrrepo &&
- echo exec > executable
- chmod +x executable &&
- bzr add executable
- bzr commit -m exec &&
- ln -s content link
- bzr add link
- bzr commit -m link &&
- mkdir dir &&
- bzr add dir &&
- bzr commit -m dir) &&
-
- (cd gitrepo &&
- git pull
- git ls-tree HEAD > ../actual) &&
-
- test_cmp expected actual &&
-
- (cd gitrepo &&
- git cat-file -p HEAD:link > ../actual) &&
-
- echo -n content > expected &&
- test_cmp expected actual
+ (
+ cd bzrrepo &&
+ echo exec > executable
+ chmod +x executable &&
+ bzr add executable
+ bzr commit -m exec &&
+ ln -s content link
+ bzr add link
+ bzr commit -m link &&
+ mkdir dir &&
+ bzr add dir &&
+ bzr commit -m dir
+ ) &&
+
+ (
+ cd gitrepo &&
+ git pull
+ git ls-tree HEAD > ../actual
+ ) &&
+
+ test_cmp expected actual &&
+
+ (
+ cd gitrepo &&
+ git cat-file -p HEAD:link > ../actual
+ ) &&
+
+ printf content > expected &&
+ test_cmp expected actual
+'
+
+cat > expected <<EOF
+100644 blob 54f9d6da5c91d556e6b54340b1327573073030af content
+100755 blob 68769579c3eaadbe555379b9c3538e6628bae1eb executable
+120000 blob 6b584e8ece562ebffc15d38808cd6b98fc3d97ea link
+040000 tree 35c0caa46693cef62247ac89a680f0c5ce32b37b movedir-new
+EOF
+
+test_expect_success 'moving directory' '
+ (
+ cd bzrrepo &&
+ mkdir movedir &&
+ echo one > movedir/one &&
+ echo two > movedir/two &&
+ bzr add movedir &&
+ bzr commit -m movedir &&
+ bzr mv movedir movedir-new &&
+ bzr commit -m movedir-new
+ ) &&
+
+ (
+ cd gitrepo &&
+ git pull &&
+ git ls-tree HEAD > ../actual
+ ) &&
+
+ test_cmp expected actual
+'
+
+test_expect_success 'different authors' '
+ (
+ cd bzrrepo &&
+ echo john >> content &&
+ bzr commit -m john \
+ --author "Jane Rey <jrey@example.com>" \
+ --author "John Doe <jdoe@example.com>"
+ ) &&
+
+ (
+ cd gitrepo &&
+ git pull &&
+ git show --format="%an <%ae>, %cn <%ce>" --quiet > ../actual
+ ) &&
+
+ echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" > expected &&
+ test_cmp expected actual
+'
+
+# cleanup previous stuff
+rm -rf bzrrepo gitrepo
+
+test_expect_success 'fetch utf-8 filenames' '
+ test_when_finished "rm -rf bzrrepo gitrepo && LC_ALL=C" &&
+
+ LC_ALL=en_US.UTF-8
+ export LC_ALL
+
+ (
+ bzr init bzrrepo &&
+ cd bzrrepo &&
+
+ echo test >> "ærø" &&
+ bzr add "ærø" &&
+ echo test >> "ø~?" &&
+ bzr add "ø~?" &&
+ bzr commit -m add-utf-8 &&
+ echo test >> "ærø" &&
+ bzr commit -m test-utf-8 &&
+ bzr rm "ø~?" &&
+ bzr mv "ærø" "ø~?" &&
+ bzr commit -m bzr-mv-utf-8
+ ) &&
+
+ (
+ git clone "bzr::bzrrepo" gitrepo &&
+ cd gitrepo &&
+ git -c core.quotepath=false ls-files > ../actual
+ ) &&
+ echo "ø~?" > expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'push utf-8 filenames' '
+ test_when_finished "rm -rf bzrrepo gitrepo && LC_ALL=C" &&
+
+ mkdir -p tmp && cd tmp &&
+
+ LC_ALL=en_US.UTF-8
+ export LC_ALL
+
+ (
+ bzr init bzrrepo &&
+ cd bzrrepo &&
+
+ echo one >> content &&
+ bzr add content &&
+ bzr commit -m one
+ ) &&
+
+ (
+ git clone "bzr::bzrrepo" gitrepo &&
+ cd gitrepo &&
+
+ echo test >> "ærø" &&
+ git add "ærø" &&
+ git commit -m utf-8 &&
+
+ git push
+ ) &&
+
+ (cd bzrrepo && bzr ls > ../actual) &&
+ printf "content\nærø\n" > expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'pushing a merge' '
+ test_when_finished "rm -rf bzrrepo gitrepo" &&
+
+ (
+ bzr init bzrrepo &&
+ cd bzrrepo &&
+ echo one > content &&
+ bzr add content &&
+ bzr commit -m one
+ ) &&
+
+ git clone "bzr::bzrrepo" gitrepo &&
+
+ (
+ cd bzrrepo &&
+ echo two > content &&
+ bzr commit -m two
+ ) &&
+
+ (
+ cd gitrepo &&
+ echo three > content &&
+ git commit -a -m three &&
+ git fetch &&
+ git merge origin/master || true &&
+ echo three > content &&
+ git commit -a --no-edit &&
+ git push
+ ) &&
+
+ echo three > expected &&
+ cat bzrrepo/content > actual &&
+ test_cmp expected actual
+'
+
+cat > expected <<EOF
+origin/HEAD
+origin/branch
+origin/trunk
+EOF
+
+test_expect_success 'proper bzr repo' '
+ test_when_finished "rm -rf bzrrepo gitrepo" &&
+
+ bzr init-repo bzrrepo &&
+
+ (
+ bzr init bzrrepo/trunk &&
+ cd bzrrepo/trunk &&
+ echo one >> content &&
+ bzr add content &&
+ bzr commit -m one
+ ) &&
+
+ (
+ bzr branch bzrrepo/trunk bzrrepo/branch &&
+ cd bzrrepo/branch &&
+ echo two >> content &&
+ bzr commit -m one
+ ) &&
+
+ (
+ git clone "bzr::bzrrepo" gitrepo &&
+ cd gitrepo &&
+ git for-each-ref --format "%(refname:short)" refs/remotes/origin > ../actual
+ ) &&
+
+ test_cmp expected actual
+'
+
+test_expect_success 'strip' '
+ test_when_finished "rm -rf bzrrepo gitrepo" &&
+
+ (
+ bzr init bzrrepo &&
+ cd bzrrepo &&
+
+ echo one >> content &&
+ bzr add content &&
+ bzr commit -m one &&
+
+ echo two >> content &&
+ bzr commit -m two
+ ) &&
+
+ git clone "bzr::bzrrepo" gitrepo &&
+
+ (
+ cd bzrrepo &&
+ bzr uncommit --force &&
+
+ echo three >> content &&
+ bzr commit -m three &&
+
+ echo four >> content &&
+ bzr commit -m four &&
+ bzr log --line | sed -e "s/^[0-9][0-9]*: //" > ../expected
+ ) &&
+
+ (
+ cd gitrepo &&
+ git fetch &&
+ git log --format="%an %ad %s" --date=short origin/master > ../actual
+ ) &&
+
+ test_cmp expected actual
'
test_done
diff --git a/contrib/remote-helpers/test-hg-bidi.sh b/contrib/remote-helpers/test-hg-bidi.sh
index 2a5d85d..f83d67d 100755
--- a/contrib/remote-helpers/test-hg-bidi.sh
+++ b/contrib/remote-helpers/test-hg-bidi.sh
@@ -15,15 +15,14 @@ if ! test_have_prereq PYTHON; then
test_done
fi
-if ! "$PYTHON_PATH" -c 'import mercurial'; then
+if ! python -c 'import mercurial'; then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
# clone to a git repo
git_clone () {
- hg -R $1 bookmark -f -r tip master &&
- git clone -q "hg::$PWD/$1" $2
+ git clone -q "hg::$1" $2
}
# clone to an hg repo
@@ -31,7 +30,7 @@ hg_clone () {
(
hg init $2 &&
cd $1 &&
- git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
+ git push -q "hg::../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
) &&
(cd $2 && hg -q update)
@@ -41,16 +40,15 @@ hg_clone () {
hg_push () {
(
cd $2
- old=$(git symbolic-ref --short HEAD)
git checkout -q -b tmp &&
- git fetch -q "hg::$PWD/../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
- git checkout -q $old &&
+ git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
+ git checkout -q @{-1} &&
git branch -q -D tmp 2> /dev/null || true
)
}
hg_log () {
- hg -R $1 log --graph --debug | grep -v 'tag: *default/'
+ hg -R $1 log --graph --debug
}
setup () {
@@ -62,8 +60,11 @@ setup () {
echo "commit = -d \"0 0\""
echo "debugrawcommit = -d \"0 0\""
echo "tag = -d \"0 0\""
+ echo "[extensions]"
+ echo "graphlog ="
) >> "$HOME"/.hgrc &&
git config --global remote-hg.hg-git-compat true
+ git config --global remote-hg.track-branches true
HGEDITOR=/usr/bin/true
GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
@@ -74,8 +75,7 @@ setup () {
setup
test_expect_success 'encoding' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -112,8 +112,7 @@ test_expect_success 'encoding' '
'
test_expect_success 'file removal' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -145,8 +144,7 @@ test_expect_success 'file removal' '
'
test_expect_success 'git tags' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -174,8 +172,7 @@ test_expect_success 'git tags' '
'
test_expect_success 'hg branch' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -191,7 +188,7 @@ test_expect_success 'hg branch' '
hg_clone gitrepo hgrepo &&
cd hgrepo &&
- hg -q co master &&
+ hg -q co default &&
hg mv alpha beta &&
hg -q commit -m "rename alpha to beta" &&
hg branch gamma | grep -v "permanent and global" &&
@@ -201,8 +198,8 @@ test_expect_success 'hg branch' '
hg_push hgrepo gitrepo &&
hg_clone gitrepo hgrepo2 &&
- : TODO, avoid "master" bookmark &&
- (cd hgrepo2 && hg checkout gamma) &&
+ : Back to the common revision &&
+ (cd hgrepo && hg checkout default) &&
hg_log hgrepo > expected &&
hg_log hgrepo2 > actual &&
@@ -211,8 +208,7 @@ test_expect_success 'hg branch' '
'
test_expect_success 'hg tags' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -228,7 +224,7 @@ test_expect_success 'hg tags' '
hg_clone gitrepo hgrepo &&
cd hgrepo &&
- hg co master &&
+ hg co default &&
hg tag alpha
) &&
diff --git a/contrib/remote-helpers/test-hg-hg-git.sh b/contrib/remote-helpers/test-hg-hg-git.sh
index 9aaf043..2219284 100755
--- a/contrib/remote-helpers/test-hg-hg-git.sh
+++ b/contrib/remote-helpers/test-hg-hg-git.sh
@@ -15,28 +15,29 @@ if ! test_have_prereq PYTHON; then
test_done
fi
-if ! "$PYTHON_PATH" -c 'import mercurial'; then
+if ! python -c 'import mercurial'; then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
-if ! "$PYTHON_PATH" -c 'import hggit'; then
+if ! python -c 'import hggit'; then
skip_all='skipping remote-hg tests; hg-git not available'
test_done
fi
# clone to a git repo with git
git_clone_git () {
- hg -R $1 bookmark -f -r tip master &&
- git clone -q "hg::$PWD/$1" $2
+ git clone -q "hg::$1" $2 &&
+ (cd $2 && git checkout master && git branch -D default)
}
# clone to an hg repo with git
hg_clone_git () {
(
hg init $2 &&
+ hg -R $2 bookmark -i master &&
cd $1 &&
- git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
+ git push -q "hg::../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
) &&
(cd $2 && hg -q update)
@@ -47,7 +48,7 @@ git_clone_hg () {
(
git init -q $2 &&
cd $1 &&
- hg bookmark -f -r tip master &&
+ hg bookmark -i -f -r tip master &&
hg -q push -r master ../$2 || true
)
}
@@ -61,10 +62,10 @@ hg_clone_hg () {
hg_push_git () {
(
cd $2
- old=$(git symbolic-ref --short HEAD)
git checkout -q -b tmp &&
- git fetch -q "hg::$PWD/../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
- git checkout -q $old &&
+ git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
+ git branch -D default &&
+ git checkout -q @{-1} &&
git branch -q -D tmp 2> /dev/null || true
)
}
@@ -78,7 +79,8 @@ hg_push_hg () {
}
hg_log () {
- hg -R $1 log --graph --debug | grep -v 'tag: *default/'
+ hg -R $1 log --graph --debug >log &&
+ grep -v 'tag: *default/' log
}
git_log () {
@@ -97,22 +99,24 @@ setup () {
echo "[extensions]"
echo "hgext.bookmarks ="
echo "hggit ="
+ echo "graphlog ="
) >> "$HOME"/.hgrc &&
git config --global receive.denycurrentbranch warn
git config --global remote-hg.hg-git-compat true
+ git config --global remote-hg.track-branches false
- HGEDITOR=/usr/bin/true
+ HGEDITOR=true
+ HGMERGE=true
GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
- export HGEDITOR GIT_AUTHOR_DATE GIT_COMMITTER_DATE
+ export HGEDITOR HGMERGE GIT_AUTHOR_DATE GIT_COMMITTER_DATE
}
setup
test_expect_success 'executable bit' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -141,15 +145,13 @@ test_expect_success 'executable bit' '
git_clone_$x hgrepo-$x gitrepo2-$x &&
git_log gitrepo2-$x > log-$x
done &&
- cp -r log-* output-* /tmp/foo/ &&
test_cmp output-hg output-git &&
test_cmp log-hg log-git
'
test_expect_success 'symlink' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -179,8 +181,7 @@ test_expect_success 'symlink' '
'
test_expect_success 'merge conflict 1' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
hg init hgrepo1 &&
@@ -196,7 +197,7 @@ test_expect_success 'merge conflict 1' '
echo C > afile &&
hg ci -m "A->C" &&
- hg merge -r1 || true &&
+ hg merge -r1 &&
echo C > afile &&
hg resolve -m afile &&
hg ci -m "merge to C"
@@ -214,8 +215,7 @@ test_expect_success 'merge conflict 1' '
'
test_expect_success 'merge conflict 2' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
hg init hgrepo1 &&
@@ -249,8 +249,7 @@ test_expect_success 'merge conflict 2' '
'
test_expect_success 'converged merge' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
hg init hgrepo1 &&
@@ -285,8 +284,7 @@ test_expect_success 'converged merge' '
'
test_expect_success 'encoding' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -325,8 +323,7 @@ test_expect_success 'encoding' '
'
test_expect_success 'file removal' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -365,8 +362,7 @@ test_expect_success 'file removal' '
'
test_expect_success 'git tags' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
@@ -392,8 +388,7 @@ test_expect_success 'git tags' '
'
test_expect_success 'hg author' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
for x in hg git; do
(
@@ -454,15 +449,12 @@ test_expect_success 'hg author' '
git_log gitrepo-$x > git-log-$x
done &&
- test_cmp git-log-hg git-log-git &&
-
test_cmp hg-log-hg hg-log-git &&
test_cmp git-log-hg git-log-git
'
test_expect_success 'hg branch' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
for x in hg git; do
(
@@ -498,8 +490,7 @@ test_expect_success 'hg branch' '
'
test_expect_success 'hg tags' '
- mkdir -p tmp && cd tmp &&
- test_when_finished "cd .. && rm -rf tmp" &&
+ test_when_finished "rm -rf gitrepo* hgrepo*" &&
for x in hg git; do
(
diff --git a/contrib/remote-helpers/test-hg.sh b/contrib/remote-helpers/test-hg.sh
index 7bb81f2..f7ce8aa 100755
--- a/contrib/remote-helpers/test-hg.sh
+++ b/contrib/remote-helpers/test-hg.sh
@@ -15,107 +15,678 @@ if ! test_have_prereq PYTHON; then
test_done
fi
-if ! "$PYTHON_PATH" -c 'import mercurial'; then
+if ! python -c 'import mercurial'; then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
check () {
- (cd $1 &&
- git log --format='%s' -1 &&
- git symbolic-ref HEAD) > actual &&
- (echo $2 &&
- echo "refs/heads/$3") > expected &&
+ echo $3 > expected &&
+ git --git-dir=$1/.git log --format='%s' -1 $2 > actual
test_cmp expected actual
}
+check_branch () {
+ if [ -n "$3" ]; then
+ echo $3 > expected &&
+ hg -R $1 log -r $2 --template '{desc}\n' > actual &&
+ test_cmp expected actual
+ else
+ hg -R $1 branches > out &&
+ ! grep $2 out
+ fi
+}
+
+check_bookmark () {
+ if [ -n "$3" ]; then
+ echo $3 > expected &&
+ hg -R $1 log -r "bookmark('$2')" --template '{desc}\n' > actual &&
+ test_cmp expected actual
+ else
+ hg -R $1 bookmarks > out &&
+ ! grep $2 out
+ fi
+}
+
+check_push () {
+ local expected_ret=$1 ret=0 ref_ret=0 IFS=':'
+
+ shift
+ git push origin "$@" 2> error
+ ret=$?
+ cat error
+
+ while read branch kind
+ do
+ case "$kind" in
+ 'new')
+ grep "^ \* \[new branch\] *${branch} -> ${branch}$" error || ref_ret=1
+ ;;
+ 'non-fast-forward')
+ grep "^ ! \[rejected\] *${branch} -> ${branch} (non-fast-forward)$" error || ref_ret=1
+ ;;
+ 'fetch-first')
+ grep "^ ! \[rejected\] *${branch} -> ${branch} (fetch first)$" error || ref_ret=1
+ ;;
+ 'forced-update')
+ grep "^ + [a-f0-9]*\.\.\.[a-f0-9]* *${branch} -> ${branch} (forced update)$" error || ref_ret=1
+ ;;
+ '')
+ grep "^ [a-f0-9]*\.\.[a-f0-9]* *${branch} -> ${branch}$" error || ref_ret=1
+ ;;
+ esac
+ let 'ref_ret' && echo "match for '$branch' failed" && break
+ done
+
+ if let 'expected_ret != ret || ref_ret'
+ then
+ return 1
+ fi
+
+ return 0
+}
+
setup () {
(
echo "[ui]"
echo "username = H G Wells <wells@example.com>"
- ) >> "$HOME"/.hgrc
+ echo "[extensions]"
+ echo "mq ="
+ ) >> "$HOME"/.hgrc &&
+
+ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" &&
+ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" &&
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
}
setup
test_expect_success 'cloning' '
- test_when_finished "rm -rf gitrepo*" &&
+ test_when_finished "rm -rf gitrepo*" &&
- (
- hg init hgrepo &&
- cd hgrepo &&
- echo zero > content &&
- hg add content &&
- hg commit -m zero
- ) &&
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+ echo zero > content &&
+ hg add content &&
+ hg commit -m zero
+ ) &&
- git clone "hg::$PWD/hgrepo" gitrepo &&
- check gitrepo zero master
+ git clone "hg::hgrepo" gitrepo &&
+ check gitrepo HEAD zero
'
test_expect_success 'cloning with branches' '
- test_when_finished "rm -rf gitrepo*" &&
+ test_when_finished "rm -rf gitrepo*" &&
- (
- cd hgrepo &&
- hg branch next &&
- echo next > content &&
- hg commit -m next
- ) &&
+ (
+ cd hgrepo &&
+ hg branch next &&
+ echo next > content &&
+ hg commit -m next
+ ) &&
- git clone "hg::$PWD/hgrepo" gitrepo &&
- check gitrepo next next &&
+ git clone "hg::hgrepo" gitrepo &&
+ check gitrepo origin/branches/next next
+'
+
+test_expect_success 'cloning with bookmarks' '
+ test_when_finished "rm -rf gitrepo*" &&
- (cd hgrepo && hg checkout default) &&
+ (
+ cd hgrepo &&
+ hg checkout default &&
+ hg bookmark feature-a &&
+ echo feature-a > content &&
+ hg commit -m feature-a
+ ) &&
- git clone "hg::$PWD/hgrepo" gitrepo2 &&
- check gitrepo2 zero master
+ git clone "hg::hgrepo" gitrepo &&
+ check gitrepo origin/feature-a feature-a
'
-test_expect_success 'cloning with bookmarks' '
- test_when_finished "rm -rf gitrepo*" &&
+test_expect_success 'update bookmark' '
+ test_when_finished "rm -rf gitrepo*" &&
- (
- cd hgrepo &&
- hg bookmark feature-a &&
- echo feature-a > content &&
- hg commit -m feature-a
- ) &&
+ (
+ cd hgrepo &&
+ hg bookmark devel
+ ) &&
- git clone "hg::$PWD/hgrepo" gitrepo &&
- check gitrepo feature-a feature-a
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ cd gitrepo &&
+ git checkout --quiet devel &&
+ echo devel > content &&
+ git commit -a -m devel &&
+ git push --quiet
+ ) &&
+
+ check_bookmark hgrepo devel devel
'
-test_expect_success 'cloning with detached head' '
- test_when_finished "rm -rf gitrepo*" &&
+test_expect_success 'new bookmark' '
+ test_when_finished "rm -rf gitrepo*" &&
- (
- cd hgrepo &&
- hg update -r 0
- ) &&
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ cd gitrepo &&
+ git checkout --quiet -b feature-b &&
+ echo feature-b > content &&
+ git commit -a -m feature-b &&
+ git push --quiet origin feature-b
+ ) &&
- git clone "hg::$PWD/hgrepo" gitrepo &&
- check gitrepo zero master
+ check_bookmark hgrepo feature-b feature-b
'
-test_expect_success 'update bookmark' '
- test_when_finished "rm -rf gitrepo*" &&
-
- (
- cd hgrepo &&
- hg bookmark devel
- ) &&
-
- (
- git clone "hg::$PWD/hgrepo" gitrepo &&
- cd gitrepo &&
- git checkout devel &&
- echo devel > content &&
- git commit -a -m devel &&
- git push
- ) &&
-
- hg -R hgrepo bookmarks | egrep "devel[ ]+3:"
+# cleanup previous stuff
+rm -rf hgrepo
+
+author_test () {
+ echo $1 >> content &&
+ hg commit -u "$2" -m "add $1" &&
+ echo "$3" >> ../expected
+}
+
+test_expect_success 'authors' '
+ test_when_finished "rm -rf hgrepo gitrepo" &&
+
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+
+ touch content &&
+ hg add content &&
+
+ > ../expected &&
+ author_test alpha "" "H G Wells <wells@example.com>" &&
+ author_test beta "test" "test <unknown>" &&
+ author_test beta "test <test@example.com> (comment)" "test <test@example.com>" &&
+ author_test gamma "<test@example.com>" "Unknown <test@example.com>" &&
+ author_test delta "name<test@example.com>" "name <test@example.com>" &&
+ author_test epsilon "name <test@example.com" "name <test@example.com>" &&
+ author_test zeta " test " "test <unknown>" &&
+ author_test eta "test < test@example.com >" "test <test@example.com>" &&
+ author_test theta "test >test@example.com>" "test <test@example.com>" &&
+ author_test iota "test < test <at> example <dot> com>" "test <unknown>" &&
+ author_test kappa "test@example.com" "Unknown <test@example.com>"
+ ) &&
+
+ git clone "hg::hgrepo" gitrepo &&
+ git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" > actual &&
+
+ test_cmp expected actual
+'
+
+test_expect_success 'strip' '
+ test_when_finished "rm -rf hgrepo gitrepo" &&
+
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+
+ echo one >> content &&
+ hg add content &&
+ hg commit -m one &&
+
+ echo two >> content &&
+ hg commit -m two
+ ) &&
+
+ git clone "hg::hgrepo" gitrepo &&
+
+ (
+ cd hgrepo &&
+ hg strip 1 &&
+
+ echo three >> content &&
+ hg commit -m three &&
+
+ echo four >> content &&
+ hg commit -m four
+ ) &&
+
+ (
+ cd gitrepo &&
+ git fetch &&
+ git log --format="%s" origin/master > ../actual
+ ) &&
+
+ hg -R hgrepo log --template "{desc}\n" > expected &&
+ test_cmp actual expected
+'
+
+test_expect_success 'remote push with master bookmark' '
+ test_when_finished "rm -rf hgrepo gitrepo*" &&
+
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+ echo zero > content &&
+ hg add content &&
+ hg commit -m zero &&
+ hg bookmark master &&
+ echo one > content &&
+ hg commit -m one
+ ) &&
+
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ cd gitrepo &&
+ echo two > content &&
+ git commit -a -m two &&
+ git push
+ ) &&
+
+ check_branch hgrepo default two
+'
+
+cat > expected <<EOF
+changeset: 0:6e2126489d3d
+tag: tip
+user: A U Thor <author@example.com>
+date: Mon Jan 01 00:00:00 2007 +0230
+summary: one
+
+EOF
+
+test_expect_success 'remote push from master branch' '
+ test_when_finished "rm -rf hgrepo gitrepo*" &&
+
+ hg init hgrepo &&
+
+ (
+ git init gitrepo &&
+ cd gitrepo &&
+ git remote add origin "hg::../hgrepo" &&
+ echo one > content &&
+ git add content &&
+ git commit -a -m one &&
+ git push origin master
+ ) &&
+
+ hg -R hgrepo log > actual &&
+ cat actual &&
+ test_cmp expected actual &&
+
+ check_branch hgrepo default one
+'
+
+GIT_REMOTE_HG_TEST_REMOTE=1
+export GIT_REMOTE_HG_TEST_REMOTE
+
+test_expect_success 'remote cloning' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+ echo zero > content &&
+ hg add content &&
+ hg commit -m zero
+ ) &&
+
+ git clone "hg::hgrepo" gitrepo &&
+ check gitrepo HEAD zero
+'
+
+test_expect_success 'remote update bookmark' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ cd hgrepo &&
+ hg bookmark devel
+ ) &&
+
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ cd gitrepo &&
+ git checkout --quiet devel &&
+ echo devel > content &&
+ git commit -a -m devel &&
+ git push --quiet
+ ) &&
+
+ check_bookmark hgrepo devel devel
+'
+
+test_expect_success 'remote new bookmark' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ cd gitrepo &&
+ git checkout --quiet -b feature-b &&
+ echo feature-b > content &&
+ git commit -a -m feature-b &&
+ git push --quiet origin feature-b
+ ) &&
+
+ check_bookmark hgrepo feature-b feature-b
+'
+
+test_expect_success 'remote push diverged' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ git clone "hg::hgrepo" gitrepo &&
+
+ (
+ cd hgrepo &&
+ hg checkout default &&
+ echo bump > content &&
+ hg commit -m bump
+ ) &&
+
+ (
+ cd gitrepo &&
+ echo diverge > content &&
+ git commit -a -m diverged &&
+ check_push 1 <<-EOF
+ master:non-fast-forward
+ EOF
+ ) &&
+
+ check_branch hgrepo default bump
+'
+
+test_expect_success 'remote update bookmark diverge' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ cd hgrepo &&
+ hg checkout tip^ &&
+ hg bookmark diverge
+ ) &&
+
+ git clone "hg::hgrepo" gitrepo &&
+
+ (
+ cd hgrepo &&
+ echo "bump bookmark" > content &&
+ hg commit -m "bump bookmark"
+ ) &&
+
+ (
+ cd gitrepo &&
+ git checkout --quiet diverge &&
+ echo diverge > content &&
+ git commit -a -m diverge &&
+ check_push 1 <<-EOF
+ diverge:fetch-first
+ EOF
+ ) &&
+
+ check_bookmark hgrepo diverge "bump bookmark"
+'
+
+test_expect_success 'remote new bookmark multiple branch head' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ cd gitrepo &&
+ git checkout --quiet -b feature-c HEAD^ &&
+ echo feature-c > content &&
+ git commit -a -m feature-c &&
+ git push --quiet origin feature-c
+ ) &&
+
+ check_bookmark hgrepo feature-c feature-c
+'
+
+# cleanup previous stuff
+rm -rf hgrepo
+
+setup_big_push () {
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+ echo zero > content &&
+ hg add content &&
+ hg commit -m zero &&
+ hg bookmark bad_bmark1 &&
+ echo one > content &&
+ hg commit -m one &&
+ hg bookmark bad_bmark2 &&
+ hg bookmark good_bmark &&
+ hg bookmark -i good_bmark &&
+ hg -q branch good_branch &&
+ echo "good branch" > content &&
+ hg commit -m "good branch" &&
+ hg -q branch bad_branch &&
+ echo "bad branch" > content &&
+ hg commit -m "bad branch"
+ ) &&
+
+ git clone "hg::hgrepo" gitrepo &&
+
+ (
+ cd gitrepo &&
+ echo two > content &&
+ git commit -q -a -m two &&
+
+ git checkout -q good_bmark &&
+ echo three > content &&
+ git commit -q -a -m three &&
+
+ git checkout -q bad_bmark1 &&
+ git reset --hard HEAD^ &&
+ echo four > content &&
+ git commit -q -a -m four &&
+
+ git checkout -q bad_bmark2 &&
+ git reset --hard HEAD^ &&
+ echo five > content &&
+ git commit -q -a -m five &&
+
+ git checkout -q -b new_bmark master &&
+ echo six > content &&
+ git commit -q -a -m six &&
+
+ git checkout -q branches/good_branch &&
+ echo seven > content &&
+ git commit -q -a -m seven &&
+ echo eight > content &&
+ git commit -q -a -m eight &&
+
+ git checkout -q branches/bad_branch &&
+ git reset --hard HEAD^ &&
+ echo nine > content &&
+ git commit -q -a -m nine &&
+
+ git checkout -q -b branches/new_branch master &&
+ echo ten > content &&
+ git commit -q -a -m ten
+ )
+}
+
+test_expect_success 'remote big push' '
+ test_when_finished "rm -rf hgrepo gitrepo*" &&
+
+ setup_big_push
+
+ (
+ cd gitrepo &&
+
+ check_push 1 --all <<-EOF
+ master
+ good_bmark
+ branches/good_branch
+ new_bmark:new
+ branches/new_branch:new
+ bad_bmark1:non-fast-forward
+ bad_bmark2:non-fast-forward
+ branches/bad_branch:non-fast-forward
+ EOF
+ ) &&
+
+ check_branch hgrepo default one &&
+ check_branch hgrepo good_branch "good branch" &&
+ check_branch hgrepo bad_branch "bad branch" &&
+ check_branch hgrepo new_branch '' &&
+ check_bookmark hgrepo good_bmark one &&
+ check_bookmark hgrepo bad_bmark1 one &&
+ check_bookmark hgrepo bad_bmark2 one &&
+ check_bookmark hgrepo new_bmark ''
+'
+
+test_expect_success 'remote big push fetch first' '
+ test_when_finished "rm -rf hgrepo gitrepo*" &&
+
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+ echo zero > content &&
+ hg add content &&
+ hg commit -m zero &&
+ hg bookmark bad_bmark &&
+ hg bookmark good_bmark &&
+ hg bookmark -i good_bmark &&
+ hg -q branch good_branch &&
+ echo "good branch" > content &&
+ hg commit -m "good branch" &&
+ hg -q branch bad_branch &&
+ echo "bad branch" > content &&
+ hg commit -m "bad branch"
+ ) &&
+
+ git clone "hg::hgrepo" gitrepo &&
+
+ (
+ cd hgrepo &&
+ hg bookmark -f bad_bmark &&
+ echo update_bmark > content &&
+ hg commit -m "update bmark"
+ ) &&
+
+ (
+ cd gitrepo &&
+ echo two > content &&
+ git commit -q -a -m two &&
+
+ git checkout -q good_bmark &&
+ echo three > content &&
+ git commit -q -a -m three &&
+
+ git checkout -q bad_bmark &&
+ echo four > content &&
+ git commit -q -a -m four &&
+
+ git checkout -q branches/bad_branch &&
+ echo five > content &&
+ git commit -q -a -m five &&
+
+ check_push 1 --all <<-EOF
+ master
+ good_bmark
+ new_bmark:new
+ new_branch:new
+ bad_bmark:fetch-first
+ branches/bad_branch:festch-first
+ EOF
+
+ git fetch &&
+
+ check_push 1 --all <<-EOF
+ master
+ good_bmark
+ bad_bmark:non-fast-forward
+ branches/bad_branch:non-fast-forward
+ EOF
+ )
+'
+
+test_expect_failure 'remote big push force' '
+ test_when_finished "rm -rf hgrepo gitrepo*" &&
+
+ setup_big_push
+
+ (
+ cd gitrepo &&
+
+ check_push 0 --force --all <<-EOF
+ master
+ good_bmark
+ branches/good_branch
+ new_bmark:new
+ branches/new_branch:new
+ bad_bmark1:forced-update
+ bad_bmark2:forced-update
+ branches/bad_branch:forced-update
+ EOF
+ ) &&
+
+ check_branch hgrepo default six &&
+ check_branch hgrepo good_branch eight &&
+ check_branch hgrepo bad_branch nine &&
+ check_branch hgrepo new_branch ten &&
+ check_bookmark hgrepo good_bmark three &&
+ check_bookmark hgrepo bad_bmark1 four &&
+ check_bookmark hgrepo bad_bmark2 five &&
+ check_bookmark hgrepo new_bmark six
+'
+
+test_expect_failure 'remote big push dry-run' '
+ test_when_finished "rm -rf hgrepo gitrepo*" &&
+
+ setup_big_push
+
+ (
+ cd gitrepo &&
+
+ check_push 0 --dry-run --all <<-EOF
+ master
+ good_bmark
+ branches/good_branch
+ new_bmark:new
+ branches/new_branch:new
+ bad_bmark1:non-fast-forward
+ bad_bmark2:non-fast-forward
+ branches/bad_branch:non-fast-forward
+ EOF
+
+ check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-EOF
+ master
+ good_bmark
+ branches/good_branch
+ new_bmark:new
+ branches/new_branch:new
+ EOF
+ ) &&
+
+ check_branch hgrepo default one &&
+ check_branch hgrepo good_branch "good branch" &&
+ check_branch hgrepo bad_branch "bad branch" &&
+ check_branch hgrepo new_branch '' &&
+ check_bookmark hgrepo good_bmark one &&
+ check_bookmark hgrepo bad_bmark1 one &&
+ check_bookmark hgrepo bad_bmark2 one &&
+ check_bookmark hgrepo new_bmark ''
+'
+
+test_expect_success 'remote double failed push' '
+ test_when_finished "rm -rf hgrepo gitrepo*" &&
+
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+ echo zero > content &&
+ hg add content &&
+ hg commit -m zero &&
+ echo one > content &&
+ hg commit -m one
+ ) &&
+
+ (
+ git clone "hg::hgrepo" gitrepo &&
+ cd gitrepo &&
+ git reset --hard HEAD^ &&
+ echo two > content &&
+ git commit -a -m two &&
+ test_expect_code 1 git push &&
+ test_expect_code 1 git push
+ )
'
test_done
diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile
index b507505..435b2de 100644
--- a/contrib/subtree/Makefile
+++ b/contrib/subtree/Makefile
@@ -30,6 +30,7 @@ $(GIT_SUBTREE): $(GIT_SUBTREE_SH)
doc: $(GIT_SUBTREE_DOC)
install: $(GIT_SUBTREE)
+ $(INSTALL) -d -m 755 $(DESTDIR)$(libexecdir)
$(INSTALL) -m 755 $(GIT_SUBTREE) $(DESTDIR)$(libexecdir)
install-doc: install-man
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 8a23f58..7d7af03 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
#
# git-subtree.sh: split/join git repositories in subdirectories of this one
#
@@ -311,7 +311,7 @@ copy_commit()
GIT_COMMITTER_NAME \
GIT_COMMITTER_EMAIL \
GIT_COMMITTER_DATE
- (echo -n "$annotate"; cat ) |
+ (printf "%s" "$annotate"; cat ) |
git commit-tree "$2" $3 # reads the rest of stdin
) || die "Can't copy commit $1"
}
@@ -715,7 +715,8 @@ cmd_push()
repository=$1
refspec=$2
echo "git push using: " $repository $refspec
- git push $repository $(git subtree split --prefix=$prefix):refs/heads/$refspec
+ localrev=$(git subtree split --prefix="$prefix") || die
+ git push $repository $localrev:refs/heads/$refspec
else
die "'$dir' must already exist. Try 'git subtree add'."
fi
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 7ba853e..e0957ee 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -270,7 +270,7 @@ git-extensions repository in ~/git-extensions/:
name
You can omit the --squash flag, but doing so will increase the number
-of commits that are incldued in your local repository.
+of commits that are included in your local repository.
We now have a ~/git-extensions/git-subtree directory containing code
from the master branch of git://github.com/apenwarr/git-subtree.git
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index b0f8536..66ce4b0 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -182,9 +182,9 @@ test_expect_success 'merge new subproj history into subdir' '
test_expect_success 'Check that prefix argument is required for split' '
echo "You must provide the --prefix option." > expected &&
test_must_fail git subtree split > actual 2>&1 &&
- test_debug "echo -n expected: " &&
+ test_debug "printf '"'"'expected: '"'"'" &&
test_debug "cat expected" &&
- test_debug "echo -n actual: " &&
+ test_debug "printf '"'"'actual: '"'"'" &&
test_debug "cat actual" &&
test_cmp expected actual &&
rm -f expected actual
@@ -193,9 +193,9 @@ test_expect_success 'Check that prefix argument is required for split' '
test_expect_success 'Check that the <prefix> exists for a split' '
echo "'"'"'non-existent-directory'"'"'" does not exist\; use "'"'"'git subtree add'"'"'" > expected &&
test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
- test_debug "echo -n expected: " &&
+ test_debug "printf '"'"'expected: '"'"'" &&
test_debug "cat expected" &&
- test_debug "echo -n actual: " &&
+ test_debug "printf '"'"'actual: '"'"'" &&
test_debug "cat actual" &&
test_cmp expected actual
# rm -f expected actual
diff --git a/convert.c b/convert.c
index 3520252..11a95fc 100644
--- a/convert.c
+++ b/convert.c
@@ -153,36 +153,13 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,
static int has_cr_in_index(const char *path)
{
- int pos, len;
unsigned long sz;
- enum object_type type;
void *data;
int has_cr;
- struct index_state *istate = &the_index;
- len = strlen(path);
- pos = index_name_pos(istate, path, len);
- if (pos < 0) {
- /*
- * We might be in the middle of a merge, in which
- * case we would read stage #2 (ours).
- */
- int i;
- for (i = -pos - 1;
- (pos < 0 && i < istate->cache_nr &&
- !strcmp(istate->cache[i]->name, path));
- i++)
- if (ce_stage(istate->cache[i]) == 2)
- pos = i;
- }
- if (pos < 0)
+ data = read_blob_data_from_cache(path, &sz);
+ if (!data)
return 0;
- data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
- if (!data || type != OBJ_BLOB) {
- free(data);
- return 0;
- }
-
has_cr = memchr(data, '\r', sz) != NULL;
free(data);
return has_cr;
@@ -858,7 +835,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str
/*****************************************************************
*
- * Streaming converison support
+ * Streaming conversion support
*
*****************************************************************/
diff --git a/convert.h b/convert.h
index ec5fd69..0c2143c 100644
--- a/convert.h
+++ b/convert.h
@@ -48,7 +48,7 @@ static inline int would_convert_to_git(const char *path, const char *src,
/*****************************************************************
*
- * Streaming converison support
+ * Streaming conversion support
*
*****************************************************************/
diff --git a/credential-store.c b/credential-store.c
index 26f7589..f9146e5 100644
--- a/credential-store.c
+++ b/credential-store.c
@@ -114,7 +114,7 @@ static int lookup_credential(const char *fn, struct credential *c)
return c->username && c->password;
}
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
const char * const usage[] = {
"git credential-store [options] <action>",
@@ -131,7 +131,7 @@ int main(int argc, const char **argv)
umask(077);
- argc = parse_options(argc, argv, NULL, options, usage, 0);
+ argc = parse_options(argc, (const char **)argv, NULL, options, usage, 0);
if (argc != 1)
usage_with_options(usage, options);
op = argv[0];
diff --git a/daemon.c b/daemon.c
index df8c0ab..34916c5 100644
--- a/daemon.c
+++ b/daemon.c
@@ -600,7 +600,7 @@ static void parse_host_arg(char *extra_args, int buflen)
static int execute(void)
{
- static char line[1000];
+ char *line = packet_buffer;
int pktlen, len, i;
char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT");
@@ -608,7 +608,7 @@ static int execute(void)
loginfo("Connection from %s:%s", addr, port);
alarm(init_timeout ? init_timeout : timeout);
- pktlen = packet_read_line(0, line, sizeof(line));
+ pktlen = packet_read(0, NULL, NULL, packet_buffer, sizeof(packet_buffer), 0);
alarm(0);
len = strlen(line);
@@ -760,7 +760,7 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
snprintf(portbuf, sizeof(portbuf), "REMOTE_PORT=%d",
ntohs(sin_addr->sin_port));
#ifndef NO_IPV6
- } else if (addr && addr->sa_family == AF_INET6) {
+ } else if (addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6_addr = (void *) addr;
char *buf = addrbuf + 12;
@@ -1047,18 +1047,6 @@ static int service_loop(struct socketlist *socklist)
}
}
-/* if any standard file descriptor is missing open it to /dev/null */
-static void sanitize_stdfds(void)
-{
- int fd = open("/dev/null", O_RDWR, 0);
- while (fd != -1 && fd < 2)
- fd = dup(fd);
- if (fd == -1)
- die_errno("open /dev/null or dup failed");
- if (fd > 2)
- close(fd);
-}
-
#ifdef NO_POSIX_GOODIES
struct credentials;
diff --git a/date.c b/date.c
index 57331ed..29f1540 100644
--- a/date.c
+++ b/date.c
@@ -383,7 +383,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
* sense to specify timestamp way into the future. Make
* sure it is not later than ten days from now...
*/
- if (now + 10*24*3600 < specified)
+ if ((specified != -1) && (now + 10*24*3600 < specified))
return 0;
tm->tm_mon = r->tm_mon;
tm->tm_mday = r->tm_mday;
@@ -694,8 +694,14 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)
/* mktime uses local timezone */
*timestamp = tm_to_time_t(&tm);
- if (*offset == -1)
- *offset = ((time_t)*timestamp - mktime(&tm)) / 60;
+ if (*offset == -1) {
+ time_t temp_time = mktime(&tm);
+ if ((time_t)*timestamp > temp_time) {
+ *offset = ((time_t)*timestamp - temp_time) / 60;
+ } else {
+ *offset = -(int)((temp_time - (time_t)*timestamp) / 60);
+ }
+ }
if (*timestamp == -1)
return -1;
@@ -705,6 +711,28 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)
return 0; /* success */
}
+int parse_expiry_date(const char *date, unsigned long *timestamp)
+{
+ int errors = 0;
+
+ if (!strcmp(date, "never") || !strcmp(date, "false"))
+ *timestamp = 0;
+ else if (!strcmp(date, "all") || !strcmp(date, "now"))
+ /*
+ * We take over "now" here, which usually translates
+ * to the current timestamp. This is because the user
+ * really means to expire everything she has done in
+ * the past, and by definition reflogs are the record
+ * of the past, and there is nothing from the future
+ * to be kept.
+ */
+ *timestamp = ULONG_MAX;
+ else
+ *timestamp = approxidate_careful(date, &errors);
+
+ return errors;
+}
+
int parse_date(const char *date, char *result, int maxlen)
{
unsigned long timestamp;
diff --git a/decorate.c b/decorate.c
index 2f8a63e..7cb5d29 100644
--- a/decorate.c
+++ b/decorate.c
@@ -49,7 +49,7 @@ static void grow_decoration(struct decoration *n)
const struct object *base = old_hash[i].base;
void *decoration = old_hash[i].decoration;
- if (!base)
+ if (!decoration)
continue;
insert_decoration(n, base, decoration);
}
diff --git a/diff-delta.c b/diff-delta.c
index 93385e1..3797ce6 100644
--- a/diff-delta.c
+++ b/diff-delta.c
@@ -155,7 +155,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
entries = 0xfffffffeU / RABIN_WINDOW;
}
hsize = entries / 4;
- for (i = 4; (1u << i) < hsize && i < 31; i++);
+ for (i = 4; (1u << i) < hsize; i++);
hsize = 1 << i;
hmask = hsize - 1;
diff --git a/diff-lib.c b/diff-lib.c
index f35de0f..346cac6 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -64,8 +64,9 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
* commits, untracked content and/or modified content).
*/
static int match_stat_with_submodule(struct diff_options *diffopt,
- struct cache_entry *ce, struct stat *st,
- unsigned ce_option, unsigned *dirty_submodule)
+ const struct cache_entry *ce,
+ struct stat *st, unsigned ce_option,
+ unsigned *dirty_submodule)
{
int changed = ce_match_stat(ce, st, ce_option);
if (S_ISGITLINK(ce->ce_mode)) {
@@ -86,10 +87,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
{
int entries, i;
int diff_unmerged_stage = revs->max_count;
- int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
? CE_MATCH_RACY_IS_DIRTY : 0);
+ if (option & DIFF_SILENT_ON_REMOVED)
+ handle_deprecated_show_diff_q(&revs->diffopt);
+
diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
if (diff_unmerged_stage < 0)
@@ -136,8 +139,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
perror(ce->name);
continue;
}
- if (silent_on_removed)
- continue;
wt_mode = 0;
}
dpath->mode = wt_mode;
@@ -203,8 +204,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
perror(ce->name);
continue;
}
- if (silent_on_removed)
- continue;
diff_addremove(&revs->diffopt, '-', ce->ce_mode,
ce->sha1, !is_null_sha1(ce->sha1),
ce->name, 0);
@@ -237,7 +236,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
/* A file entry went away or appeared */
static void diff_index_show_file(struct rev_info *revs,
const char *prefix,
- struct cache_entry *ce,
+ const struct cache_entry *ce,
const unsigned char *sha1, int sha1_valid,
unsigned int mode,
unsigned dirty_submodule)
@@ -246,7 +245,7 @@ static void diff_index_show_file(struct rev_info *revs,
sha1, sha1_valid, ce->name, dirty_submodule);
}
-static int get_stat_data(struct cache_entry *ce,
+static int get_stat_data(const struct cache_entry *ce,
const unsigned char **sha1p,
unsigned int *modep,
int cached, int match_missing,
@@ -283,7 +282,7 @@ static int get_stat_data(struct cache_entry *ce,
}
static void show_new_file(struct rev_info *revs,
- struct cache_entry *new,
+ const struct cache_entry *new,
int cached, int match_missing)
{
const unsigned char *sha1;
@@ -302,8 +301,8 @@ static void show_new_file(struct rev_info *revs,
}
static int show_modified(struct rev_info *revs,
- struct cache_entry *old,
- struct cache_entry *new,
+ const struct cache_entry *old,
+ const struct cache_entry *new,
int report_missing,
int cached, int match_missing)
{
@@ -362,8 +361,8 @@ static int show_modified(struct rev_info *revs,
* give you the position and number of entries in the index).
*/
static void do_oneway_diff(struct unpack_trees_options *o,
- struct cache_entry *idx,
- struct cache_entry *tree)
+ const struct cache_entry *idx,
+ const struct cache_entry *tree)
{
struct rev_info *revs = o->unpack_data;
int match_missing, cached;
@@ -423,10 +422,11 @@ static void do_oneway_diff(struct unpack_trees_options *o,
* the fairly complex unpack_trees() semantic requirements, including
* the skipping, the path matching, the type conflict cases etc.
*/
-static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
+static int oneway_diff(const struct cache_entry * const *src,
+ struct unpack_trees_options *o)
{
- struct cache_entry *idx = src[0];
- struct cache_entry *tree = src[1];
+ const struct cache_entry *idx = src[0];
+ const struct cache_entry *tree = src[1];
struct rev_info *revs = o->unpack_data;
/*
@@ -474,7 +474,6 @@ static int diff_cache(struct rev_info *revs,
opts.dst_index = NULL;
opts.pathspec = &revs->diffopt.pathspec;
opts.pathspec->recursive = 1;
- opts.pathspec->max_depth = -1;
init_tree_desc(&t, tree->buffer, tree->size);
return unpack_trees(1, &t, &opts);
@@ -500,7 +499,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
struct rev_info revs;
init_revisions(&revs, NULL);
- init_pathspec(&revs.prune_data, opt->pathspec.raw);
+ copy_pathspec(&revs.prune_data, &opt->pathspec);
revs.diffopt = *opt;
if (diff_cache(&revs, tree_sha1, NULL, 1))
diff --git a/diff-no-index.c b/diff-no-index.c
index 74da659..e301aaf 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -45,7 +45,7 @@ static int get_mode(const char *path, int *mode)
if (!path || !strcmp(path, "/dev/null"))
*mode = 0;
-#ifdef _WIN32
+#ifdef GIT_WINDOWS_NATIVE
else if (!strcasecmp(path, "nul"))
*mode = 0;
#endif
@@ -187,7 +187,7 @@ void diff_no_index(struct rev_info *revs,
{
int i, prefixlen;
int no_index = 0;
- unsigned options = 0;
+ unsigned deprecated_show_diff_q_option_used = 0;
const char *paths[2];
/* Were we asked to do --no-index explicitly? */
@@ -225,7 +225,7 @@ void diff_no_index(struct rev_info *revs,
if (!strcmp(argv[i], "--no-index"))
i++;
else if (!strcmp(argv[i], "-q")) {
- options |= DIFF_SILENT_ON_REMOVED;
+ deprecated_show_diff_q_option_used = 1;
i++;
}
else if (!strcmp(argv[i], "--"))
@@ -260,6 +260,9 @@ void diff_no_index(struct rev_info *revs,
revs->max_count = -2;
diff_setup_done(&revs->diffopt);
+ if (deprecated_show_diff_q_option_used)
+ handle_deprecated_show_diff_q(&revs->diffopt);
+
setup_diff_pager(&revs->diffopt);
DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
diff --git a/diff.c b/diff.c
index 649ec86..a04a34d 100644
--- a/diff.c
+++ b/diff.c
@@ -669,7 +669,7 @@ static void emit_rewrite_diff(const char *name_a,
memset(&ecbdata, 0, sizeof(ecbdata));
ecbdata.color_diff = want_color(o->use_color);
ecbdata.found_changesp = &o->found_changes;
- ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
+ ecbdata.ws_rule = whitespace_rule(name_b);
ecbdata.opt = o;
if (ecbdata.ws_rule & WS_BLANK_AT_EOF) {
mmfile_t mf1, mf2;
@@ -1683,9 +1683,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
del = deleted;
if (graph_width <= max_change) {
- int total = add + del;
-
- total = scale_linear(add + del, graph_width, max_change);
+ int total = scale_linear(add + del, graph_width, max_change);
if (total < 2 && add && del)
/* width >= 2 due to the sanity check */
total = 2;
@@ -2254,7 +2252,8 @@ static void builtin_diff(const char *name_a,
(!two->mode || S_ISGITLINK(two->mode))) {
const char *del = diff_get_color_opt(o, DIFF_FILE_OLD);
const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
- show_submodule_summary(o->file, one ? one->path : two->path,
+ show_submodule_summary(o->file, one->path ? one->path : two->path,
+ line_prefix,
one->sha1, two->sha1, two->dirty_submodule,
meta, del, add, reset);
return;
@@ -2373,7 +2372,7 @@ static void builtin_diff(const char *name_a,
ecbdata.label_path = lbl;
ecbdata.color_diff = want_color(o->use_color);
ecbdata.found_changesp = &o->found_changes;
- ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
+ ecbdata.ws_rule = whitespace_rule(name_b);
if (ecbdata.ws_rule & WS_BLANK_AT_EOF)
check_blank_at_eof(&mf1, &mf2, &ecbdata);
ecbdata.opt = o;
@@ -2585,7 +2584,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
*/
static int reuse_worktree_file(const char *name, const unsigned char *sha1, int want_file)
{
- struct cache_entry *ce;
+ const struct cache_entry *ce;
struct stat st;
int pos, len;
@@ -2676,6 +2675,14 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
int diff_populate_filespec(struct diff_filespec *s, int size_only)
{
int err = 0;
+ /*
+ * demote FAIL to WARN to allow inspecting the situation
+ * instead of refusing.
+ */
+ enum safe_crlf crlf_warn = (safe_crlf == SAFE_CRLF_FAIL
+ ? SAFE_CRLF_WARN
+ : safe_crlf);
+
if (!DIFF_FILE_VALID(s))
die("internal error: asking to populate invalid file.");
if (S_ISDIR(s->mode))
@@ -2731,7 +2738,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
/*
* Convert from working tree format to canonical git format
*/
- if (convert_to_git(s->path, s->data, s->size, &buf, safe_crlf)) {
+ if (convert_to_git(s->path, s->data, s->size, &buf, crlf_warn)) {
size_t size = 0;
munmap(s->data, s->size);
s->should_munmap = 0;
@@ -3496,6 +3503,93 @@ static int parse_submodule_opt(struct diff_options *options, const char *value)
return 1;
}
+static const char diff_status_letters[] = {
+ DIFF_STATUS_ADDED,
+ DIFF_STATUS_COPIED,
+ DIFF_STATUS_DELETED,
+ DIFF_STATUS_MODIFIED,
+ DIFF_STATUS_RENAMED,
+ DIFF_STATUS_TYPE_CHANGED,
+ DIFF_STATUS_UNKNOWN,
+ DIFF_STATUS_UNMERGED,
+ DIFF_STATUS_FILTER_AON,
+ DIFF_STATUS_FILTER_BROKEN,
+ '\0',
+};
+
+static unsigned int filter_bit['Z' + 1];
+
+static void prepare_filter_bits(void)
+{
+ int i;
+
+ if (!filter_bit[DIFF_STATUS_ADDED]) {
+ for (i = 0; diff_status_letters[i]; i++)
+ filter_bit[(int) diff_status_letters[i]] = (1 << i);
+ }
+}
+
+static unsigned filter_bit_tst(char status, const struct diff_options *opt)
+{
+ return opt->filter & filter_bit[(int) status];
+}
+
+static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt)
+{
+ int i, optch;
+
+ prepare_filter_bits();
+
+ /*
+ * If there is a negation e.g. 'd' in the input, and we haven't
+ * initialized the filter field with another --diff-filter, start
+ * from full set of bits, except for AON.
+ */
+ if (!opt->filter) {
+ for (i = 0; (optch = optarg[i]) != '\0'; i++) {
+ if (optch < 'a' || 'z' < optch)
+ continue;
+ opt->filter = (1 << (ARRAY_SIZE(diff_status_letters) - 1)) - 1;
+ opt->filter &= ~filter_bit[DIFF_STATUS_FILTER_AON];
+ break;
+ }
+ }
+
+ for (i = 0; (optch = optarg[i]) != '\0'; i++) {
+ unsigned int bit;
+ int negate;
+
+ if ('a' <= optch && optch <= 'z') {
+ negate = 1;
+ optch = toupper(optch);
+ } else {
+ negate = 0;
+ }
+
+ bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0;
+ if (!bit)
+ return optarg[i];
+ if (negate)
+ opt->filter &= ~bit;
+ else
+ opt->filter |= bit;
+ }
+ return 0;
+}
+
+/* Used only by "diff-files" and "diff --no-index" */
+void handle_deprecated_show_diff_q(struct diff_options *opt)
+{
+ warning("'diff -q' and 'diff-files -q' are deprecated.");
+ warning("Use 'diff --diff-filter=d' instead to ignore deleted filepairs.");
+ parse_diff_filter_opt("d", opt);
+}
+
+static void enable_patch_output(int *fmt) {
+ *fmt &= ~DIFF_FORMAT_NO_OUTPUT;
+ *fmt |= DIFF_FORMAT_PATCH;
+}
+
int diff_opt_parse(struct diff_options *options, const char **av, int ac)
{
const char *arg = av[0];
@@ -3503,15 +3597,15 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
int argcount;
/* Output format options */
- if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch"))
- options->output_format |= DIFF_FORMAT_PATCH;
- else if (opt_arg(arg, 'U', "unified", &options->context))
- options->output_format |= DIFF_FORMAT_PATCH;
+ if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch")
+ || opt_arg(arg, 'U', "unified", &options->context))
+ enable_patch_output(&options->output_format);
else if (!strcmp(arg, "--raw"))
options->output_format |= DIFF_FORMAT_RAW;
- else if (!strcmp(arg, "--patch-with-raw"))
- options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW;
- else if (!strcmp(arg, "--numstat"))
+ else if (!strcmp(arg, "--patch-with-raw")) {
+ enable_patch_output(&options->output_format);
+ options->output_format |= DIFF_FORMAT_RAW;
+ } else if (!strcmp(arg, "--numstat"))
options->output_format |= DIFF_FORMAT_NUMSTAT;
else if (!strcmp(arg, "--shortstat"))
options->output_format |= DIFF_FORMAT_SHORTSTAT;
@@ -3533,13 +3627,14 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->output_format |= DIFF_FORMAT_CHECKDIFF;
else if (!strcmp(arg, "--summary"))
options->output_format |= DIFF_FORMAT_SUMMARY;
- else if (!strcmp(arg, "--patch-with-stat"))
- options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT;
- else if (!strcmp(arg, "--name-only"))
+ else if (!strcmp(arg, "--patch-with-stat")) {
+ enable_patch_output(&options->output_format);
+ options->output_format |= DIFF_FORMAT_DIFFSTAT;
+ } else if (!strcmp(arg, "--name-only"))
options->output_format |= DIFF_FORMAT_NAME;
else if (!strcmp(arg, "--name-status"))
options->output_format |= DIFF_FORMAT_NAME_STATUS;
- else if (!strcmp(arg, "-s"))
+ else if (!strcmp(arg, "-s") || !strcmp(arg, "--no-patch"))
options->output_format |= DIFF_FORMAT_NO_OUTPUT;
else if (!prefixcmp(arg, "--stat"))
/* --stat, --stat-width, --stat-name-width, or --stat-count */
@@ -3592,6 +3687,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE);
else if (!strcmp(arg, "--ignore-space-at-eol"))
DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
+ else if (!strcmp(arg, "--ignore-blank-lines"))
+ DIFF_XDL_SET(options, IGNORE_BLANK_LINES);
else if (!strcmp(arg, "--patience"))
options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
else if (!strcmp(arg, "--histogram"))
@@ -3610,7 +3707,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
/* flags options */
else if (!strcmp(arg, "--binary")) {
- options->output_format |= DIFF_FORMAT_PATCH;
+ enable_patch_output(&options->output_format);
DIFF_OPT_SET(options, BINARY);
}
else if (!strcmp(arg, "--full-index"))
@@ -3717,7 +3814,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
return argcount;
}
else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) {
- options->filter = optarg;
+ int offending = parse_diff_filter_opt(optarg, options);
+ if (offending)
+ die("unknown change class '%c' in --diff-filter=%s",
+ offending, optarg);
return argcount;
}
else if (!strcmp(arg, "--abbrev"))
@@ -4449,7 +4549,7 @@ void diff_flush(struct diff_options *options)
DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
/*
* run diff_flush_patch for the exit status. setting
- * options->file to /dev/null should be safe, becaue we
+ * options->file to /dev/null should be safe, because we
* aren't supposed to produce any output anyway.
*/
if (options->close_file)
@@ -4509,27 +4609,32 @@ free_queue:
}
}
-static void diffcore_apply_filter(const char *filter)
+static int match_filter(const struct diff_options *options, const struct diff_filepair *p)
+{
+ return (((p->status == DIFF_STATUS_MODIFIED) &&
+ ((p->score &&
+ filter_bit_tst(DIFF_STATUS_FILTER_BROKEN, options)) ||
+ (!p->score &&
+ filter_bit_tst(DIFF_STATUS_MODIFIED, options)))) ||
+ ((p->status != DIFF_STATUS_MODIFIED) &&
+ filter_bit_tst(p->status, options)));
+}
+
+static void diffcore_apply_filter(struct diff_options *options)
{
int i;
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq;
+
DIFF_QUEUE_CLEAR(&outq);
- if (!filter)
+ if (!options->filter)
return;
- if (strchr(filter, DIFF_STATUS_FILTER_AON)) {
+ if (filter_bit_tst(DIFF_STATUS_FILTER_AON, options)) {
int found;
for (i = found = 0; !found && i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- if (((p->status == DIFF_STATUS_MODIFIED) &&
- ((p->score &&
- strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
- (!p->score &&
- strchr(filter, DIFF_STATUS_MODIFIED)))) ||
- ((p->status != DIFF_STATUS_MODIFIED) &&
- strchr(filter, p->status)))
+ if (match_filter(options, q->queue[i]))
found++;
}
if (found)
@@ -4547,14 +4652,7 @@ static void diffcore_apply_filter(const char *filter)
/* Only the matching ones */
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
-
- if (((p->status == DIFF_STATUS_MODIFIED) &&
- ((p->score &&
- strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
- (!p->score &&
- strchr(filter, DIFF_STATUS_MODIFIED)))) ||
- ((p->status != DIFF_STATUS_MODIFIED) &&
- strchr(filter, p->status)))
+ if (match_filter(options, p))
diff_q(&outq, p);
else
diff_free_filepair(p);
@@ -4661,7 +4759,7 @@ void diffcore_std(struct diff_options *options)
if (!options->found_follow)
/* See try_to_follow_renames() in tree-diff.c */
diff_resolve_rename_copy();
- diffcore_apply_filter(options->filter);
+ diffcore_apply_filter(options);
if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
DIFF_OPT_SET(options, HAS_CHANGES);
diff --git a/diff.h b/diff.h
index 78b4091..44092c2 100644
--- a/diff.h
+++ b/diff.h
@@ -5,6 +5,7 @@
#define DIFF_H
#include "tree-walk.h"
+#include "pathspec.h"
struct rev_info;
struct diff_options;
@@ -103,12 +104,15 @@ enum diff_words_type {
};
struct diff_options {
- const char *filter;
const char *orderfile;
const char *pickaxe;
const char *single_follow;
const char *a_prefix, *b_prefix;
unsigned flags;
+
+ /* diff-filter bits */
+ unsigned int filter;
+
int use_color;
int context;
int interhunkcontext;
@@ -179,8 +183,6 @@ const char *diff_line_prefix(struct diff_options *);
extern const char mime_boundary_leader[];
-extern void diff_tree_setup_paths(const char **paths, struct diff_options *);
-extern void diff_tree_release_paths(struct diff_options *);
extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
const char *base, struct diff_options *opt);
extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new,
@@ -338,6 +340,8 @@ extern int parse_rename_score(const char **cp_p);
extern long parse_algorithm_value(const char *value);
+extern void handle_deprecated_show_diff_q(struct diff_options *);
+
extern int print_stat_summary(FILE *fp, int files,
int insertions, int deletions);
extern void setup_diff_pager(struct diff_options *);
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index 63722f8..401eb72 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -122,7 +122,7 @@ static void diffcore_pickaxe_grep(struct diff_options *o)
char errbuf[1024];
regerror(err, &regex, errbuf, 1024);
regfree(&regex);
- die("invalid log-grep regex: %s", errbuf);
+ die("invalid regex: %s", errbuf);
}
pickaxe(&diff_queued_diff, o, &regex, NULL, diff_grep);
@@ -131,8 +131,7 @@ static void diffcore_pickaxe_grep(struct diff_options *o)
return;
}
-static unsigned int contains(mmfile_t *mf, struct diff_options *o,
- regex_t *regexp, kwset_t kws)
+static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)
{
unsigned int cnt;
unsigned long sz;
@@ -176,11 +175,9 @@ static int has_changes(mmfile_t *one, mmfile_t *two,
struct diff_options *o,
regex_t *regexp, kwset_t kws)
{
- if (!one)
- return contains(two, o, regexp, kws) != 0;
- if (!two)
- return contains(one, o, regexp, kws) != 0;
- return contains(one, o, regexp, kws) != contains(two, o, regexp, kws);
+ unsigned int one_contains = one ? contains(one, regexp, kws) : 0;
+ unsigned int two_contains = two ? contains(two, regexp, kws) : 0;
+ return one_contains != two_contains;
}
static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
@@ -246,7 +243,7 @@ static void diffcore_pickaxe_count(struct diff_options *o)
char errbuf[1024];
regerror(err, &regex, errbuf, 1024);
regfree(&regex);
- die("invalid pickaxe regex: %s", errbuf);
+ die("invalid regex: %s", errbuf);
}
regexp = &regex;
} else {
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 512d0ac..6c7a72f 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -389,6 +389,7 @@ static int find_exact_renames(struct diff_options *options)
struct hash_table file_table;
init_hash(&file_table);
+ preallocate_hash(&file_table, rename_src_nr + rename_dst_nr);
for (i = 0; i < rename_src_nr; i++)
insert_file_table(&file_table, -1, i, rename_src[i].p->one);
diff --git a/dir.c b/dir.c
index 1e42b2b..b439ff0 100644
--- a/dir.c
+++ b/dir.c
@@ -11,13 +11,28 @@
#include "dir.h"
#include "refs.h"
#include "wildmatch.h"
+#include "pathspec.h"
struct path_simplify {
int len;
const char *path;
};
-static int read_directory_recursive(struct dir_struct *dir, const char *path, int len,
+/*
+ * Tells read_directory_recursive how a file or directory should be treated.
+ * Values are ordered by significance, e.g. if a directory contains both
+ * excluded and untracked files, it is listed as untracked because
+ * path_untracked > path_excluded.
+ */
+enum path_treatment {
+ path_none = 0,
+ path_recurse,
+ path_excluded,
+ path_untracked
+};
+
+static enum path_treatment read_directory_recursive(struct dir_struct *dir,
+ const char *path, int len,
int check_only, const struct path_simplify *simplify);
static int get_dtype(struct dirent *de, const char *path, int len);
@@ -37,26 +52,32 @@ int fnmatch_icase(const char *pattern, const char *string, int flags)
return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));
}
-inline int git_fnmatch(const char *pattern, const char *string,
- int flags, int prefix)
+inline int git_fnmatch(const struct pathspec_item *item,
+ const char *pattern, const char *string,
+ int prefix)
{
- int fnm_flags = 0;
- if (flags & GFNM_PATHNAME)
- fnm_flags |= FNM_PATHNAME;
if (prefix > 0) {
- if (strncmp(pattern, string, prefix))
+ if (ps_strncmp(item, pattern, string, prefix))
return FNM_NOMATCH;
pattern += prefix;
string += prefix;
}
- if (flags & GFNM_ONESTAR) {
+ if (item->flags & PATHSPEC_ONESTAR) {
int pattern_len = strlen(++pattern);
int string_len = strlen(string);
return string_len < pattern_len ||
- strcmp(pattern,
- string + string_len - pattern_len);
+ ps_strcmp(item, pattern,
+ string + string_len - pattern_len);
}
- return fnmatch(pattern, string, fnm_flags);
+ if (item->magic & PATHSPEC_GLOB)
+ return wildmatch(pattern, string,
+ WM_PATHNAME |
+ (item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0),
+ NULL);
+ else
+ /* wildmatch has not learned no FNM_PATHNAME mode yet */
+ return fnmatch(pattern, string,
+ item->magic & PATHSPEC_ICASE ? FNM_CASEFOLD : 0);
}
static int fnmatch_icase_mem(const char *pattern, int patternlen,
@@ -88,26 +109,40 @@ static int fnmatch_icase_mem(const char *pattern, int patternlen,
return match_status;
}
-static size_t common_prefix_len(const char **pathspec)
+static size_t common_prefix_len(const struct pathspec *pathspec)
{
- const char *n, *first;
+ int n;
size_t max = 0;
- int literal = limit_pathspec_to_literal();
- if (!pathspec)
- return max;
-
- first = *pathspec;
- while ((n = *pathspec++)) {
- size_t i, len = 0;
- for (i = 0; first == n || i < max; i++) {
- char c = n[i];
- if (!c || c != first[i] || (!literal && is_glob_special(c)))
+ /*
+ * ":(icase)path" is treated as a pathspec full of
+ * wildcard. In other words, only prefix is considered common
+ * prefix. If the pathspec is abc/foo abc/bar, running in
+ * subdir xyz, the common prefix is still xyz, not xuz/abc as
+ * in non-:(icase).
+ */
+ GUARD_PATHSPEC(pathspec,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
+ for (n = 0; n < pathspec->nr; n++) {
+ size_t i = 0, len = 0, item_len;
+ if (pathspec->items[n].magic & PATHSPEC_ICASE)
+ item_len = pathspec->items[n].prefix;
+ else
+ item_len = pathspec->items[n].nowildcard_len;
+ while (i < item_len && (n == 0 || i < max)) {
+ char c = pathspec->items[n].match[i];
+ if (c != pathspec->items[0].match[i])
break;
if (c == '/')
len = i + 1;
+ i++;
}
- if (first == n || len < max) {
+ if (n == 0 || len < max) {
max = len;
if (!max)
break;
@@ -120,14 +155,14 @@ static size_t common_prefix_len(const char **pathspec)
* Returns a copy of the longest leading path common among all
* pathspecs.
*/
-char *common_prefix(const char **pathspec)
+char *common_prefix(const struct pathspec *pathspec)
{
unsigned long len = common_prefix_len(pathspec);
- return len ? xmemdupz(*pathspec, len) : NULL;
+ return len ? xmemdupz(pathspec->items[0].match, len) : NULL;
}
-int fill_directory(struct dir_struct *dir, const char **pathspec)
+int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
{
size_t len;
@@ -138,7 +173,7 @@ int fill_directory(struct dir_struct *dir, const char **pathspec)
len = common_prefix_len(pathspec);
/* Read the directory and prune it */
- read_directory(dir, pathspec ? *pathspec : "", len, pathspec);
+ read_directory(dir, pathspec->nr ? pathspec->_raw[0] : "", len, pathspec);
return len;
}
@@ -169,113 +204,6 @@ int within_depth(const char *name, int namelen,
*
* It returns 0 when there is no match.
*/
-static int match_one(const char *match, const char *name, int namelen)
-{
- int matchlen;
- int literal = limit_pathspec_to_literal();
-
- /* If the match was just the prefix, we matched */
- if (!*match)
- return MATCHED_RECURSIVELY;
-
- if (ignore_case) {
- for (;;) {
- unsigned char c1 = tolower(*match);
- unsigned char c2 = tolower(*name);
- if (c1 == '\0' || (!literal && is_glob_special(c1)))
- break;
- if (c1 != c2)
- return 0;
- match++;
- name++;
- namelen--;
- }
- } else {
- for (;;) {
- unsigned char c1 = *match;
- unsigned char c2 = *name;
- if (c1 == '\0' || (!literal && is_glob_special(c1)))
- break;
- if (c1 != c2)
- return 0;
- match++;
- name++;
- namelen--;
- }
- }
-
- /*
- * If we don't match the matchstring exactly,
- * we need to match by fnmatch
- */
- matchlen = strlen(match);
- if (strncmp_icase(match, name, matchlen)) {
- if (literal)
- return 0;
- return !fnmatch_icase(match, name, 0) ? MATCHED_FNMATCH : 0;
- }
-
- if (namelen == matchlen)
- return MATCHED_EXACTLY;
- if (match[matchlen-1] == '/' || name[matchlen] == '/')
- return MATCHED_RECURSIVELY;
- return 0;
-}
-
-/*
- * Given a name and a list of pathspecs, returns the nature of the
- * closest (i.e. most specific) match of the name to any of the
- * pathspecs.
- *
- * The caller typically calls this multiple times with the same
- * pathspec and seen[] array but with different name/namelen
- * (e.g. entries from the index) and is interested in seeing if and
- * how each pathspec matches all the names it calls this function
- * with. A mark is left in the seen[] array for each pathspec element
- * indicating the closest type of match that element achieved, so if
- * seen[n] remains zero after multiple invocations, that means the nth
- * pathspec did not match any names, which could indicate that the
- * user mistyped the nth pathspec.
- */
-int match_pathspec(const char **pathspec, const char *name, int namelen,
- int prefix, char *seen)
-{
- int i, retval = 0;
-
- if (!pathspec)
- return 1;
-
- name += prefix;
- namelen -= prefix;
-
- for (i = 0; pathspec[i] != NULL; i++) {
- int how;
- const char *match = pathspec[i] + prefix;
- if (seen && seen[i] == MATCHED_EXACTLY)
- continue;
- how = match_one(match, name, namelen);
- if (how) {
- if (retval < how)
- retval = how;
- if (seen && seen[i] < how)
- seen[i] = how;
- }
- }
- return retval;
-}
-
-/*
- * Does 'match' match the given name?
- * A match is found if
- *
- * (1) the 'match' string is leading directory of 'name', or
- * (2) the 'match' string is a wildcard and matches 'name', or
- * (3) the 'match' string is exactly the same as 'name'.
- *
- * and the return value tells which case it was.
- *
- * It returns 0 when there is no match.
- */
static int match_pathspec_item(const struct pathspec_item *item, int prefix,
const char *name, int namelen)
{
@@ -283,11 +211,44 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
const char *match = item->match + prefix;
int matchlen = item->len - prefix;
+ /*
+ * The normal call pattern is:
+ * 1. prefix = common_prefix_len(ps);
+ * 2. prune something, or fill_directory
+ * 3. match_pathspec_depth()
+ *
+ * 'prefix' at #1 may be shorter than the command's prefix and
+ * it's ok for #2 to match extra files. Those extras will be
+ * trimmed at #3.
+ *
+ * Suppose the pathspec is 'foo' and '../bar' running from
+ * subdir 'xyz'. The common prefix at #1 will be empty, thanks
+ * to "../". We may have xyz/foo _and_ XYZ/foo after #2. The
+ * user does not want XYZ/foo, only the "foo" part should be
+ * case-insensitive. We need to filter out XYZ/foo here. In
+ * other words, we do not trust the caller on comparing the
+ * prefix part when :(icase) is involved. We do exact
+ * comparison ourselves.
+ *
+ * Normally the caller (common_prefix_len() in fact) does
+ * _exact_ matching on name[-prefix+1..-1] and we do not need
+ * to check that part. Be defensive and check it anyway, in
+ * case common_prefix_len is changed, or a new caller is
+ * introduced that does not use common_prefix_len.
+ *
+ * If the penalty turns out too high when prefix is really
+ * long, maybe change it to
+ * strncmp(match, name, item->prefix - prefix)
+ */
+ if (item->prefix && (item->magic & PATHSPEC_ICASE) &&
+ strncmp(item->match, name - prefix, item->prefix))
+ return 0;
+
/* If the match was just the prefix, we matched */
if (!*match)
return MATCHED_RECURSIVELY;
- if (matchlen <= namelen && !strncmp(match, name, matchlen)) {
+ if (matchlen <= namelen && !ps_strncmp(item, match, name, matchlen)) {
if (matchlen == namelen)
return MATCHED_EXACTLY;
@@ -296,8 +257,7 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
}
if (item->nowildcard_len < item->len &&
- !git_fnmatch(match, name,
- item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
+ !git_fnmatch(item, match, name,
item->nowildcard_len - prefix))
return MATCHED_FNMATCH;
@@ -325,8 +285,17 @@ int match_pathspec_depth(const struct pathspec *ps,
{
int i, retval = 0;
+ GUARD_PATHSPEC(ps,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
if (!ps->nr) {
- if (!ps->recursive || ps->max_depth == -1)
+ if (!ps->recursive ||
+ !(ps->magic & PATHSPEC_MAXDEPTH) ||
+ ps->max_depth == -1)
return MATCHED_RECURSIVELY;
if (within_depth(name, namelen, 0, ps->max_depth))
@@ -343,7 +312,9 @@ int match_pathspec_depth(const struct pathspec *ps,
if (seen && seen[i] == MATCHED_EXACTLY)
continue;
how = match_pathspec_item(ps->items+i, prefix, name, namelen);
- if (ps->recursive && ps->max_depth != -1 &&
+ if (ps->recursive &&
+ (ps->magic & PATHSPEC_MAXDEPTH) &&
+ ps->max_depth != -1 &&
how && how != MATCHED_FNMATCH) {
int len = ps->items[i].len;
if (name[len] == '/')
@@ -366,7 +337,7 @@ int match_pathspec_depth(const struct pathspec *ps,
/*
* Return the length of the "simple" part of a path match limiter.
*/
-static int simple_length(const char *match)
+int simple_length(const char *match)
{
int len = -1;
@@ -378,7 +349,7 @@ static int simple_length(const char *match)
}
}
-static int no_wildcard(const char *string)
+int no_wildcard(const char *string)
{
return string[simple_length(string)] == '\0';
}
@@ -458,15 +429,14 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
unsigned long sz;
enum object_type type;
void *data;
- struct index_state *istate = &the_index;
len = strlen(path);
- pos = index_name_pos(istate, path, len);
+ pos = cache_name_pos(path, len);
if (pos < 0)
return NULL;
- if (!ce_skip_worktree(istate->cache[pos]))
+ if (!ce_skip_worktree(active_cache[pos]))
return NULL;
- data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+ data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
if (!data || type != OBJ_BLOB) {
free(data);
return NULL;
@@ -578,78 +548,6 @@ void add_excludes_from_file(struct dir_struct *dir, const char *fname)
die("cannot use %s as an exclude file", fname);
}
-/*
- * Loads the per-directory exclude list for the substring of base
- * which has a char length of baselen.
- */
-static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
-{
- struct exclude_list_group *group;
- struct exclude_list *el;
- struct exclude_stack *stk = NULL;
- int current;
-
- if ((!dir->exclude_per_dir) ||
- (baselen + strlen(dir->exclude_per_dir) >= PATH_MAX))
- return; /* too long a path -- ignore */
-
- group = &dir->exclude_list_group[EXC_DIRS];
-
- /* Pop the exclude lists from the EXCL_DIRS exclude_list_group
- * which originate from directories not in the prefix of the
- * path being checked. */
- while ((stk = dir->exclude_stack) != NULL) {
- if (stk->baselen <= baselen &&
- !strncmp(dir->basebuf, base, stk->baselen))
- break;
- el = &group->el[dir->exclude_stack->exclude_ix];
- dir->exclude_stack = stk->prev;
- free((char *)el->src); /* see strdup() below */
- clear_exclude_list(el);
- free(stk);
- group->nr--;
- }
-
- /* Read from the parent directories and push them down. */
- current = stk ? stk->baselen : -1;
- while (current < baselen) {
- struct exclude_stack *stk = xcalloc(1, sizeof(*stk));
- const char *cp;
-
- if (current < 0) {
- cp = base;
- current = 0;
- }
- else {
- cp = strchr(base + current + 1, '/');
- if (!cp)
- die("oops in prep_exclude");
- cp++;
- }
- stk->prev = dir->exclude_stack;
- stk->baselen = cp - base;
- memcpy(dir->basebuf + current, base + current,
- stk->baselen - current);
- strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
- /*
- * dir->basebuf gets reused by the traversal, but we
- * need fname to remain unchanged to ensure the src
- * member of each struct exclude correctly
- * back-references its source file. Other invocations
- * of add_exclude_list provide stable strings, so we
- * strdup() and free() here in the caller.
- */
- el = add_exclude_list(dir, EXC_DIRS, strdup(dir->basebuf));
- stk->exclude_ix = group->nr - 1;
- add_excludes_from_file_to_list(dir->basebuf,
- dir->basebuf, stk->baselen,
- el, 1);
- dir->exclude_stack = stk;
- current = stk->baselen;
- }
- dir->basebuf[baselen] = '\0';
-}
-
int match_basename(const char *basename, int basenamelen,
const char *pattern, int prefix, int patternlen,
int flags)
@@ -795,25 +693,13 @@ int is_excluded_from_list(const char *pathname,
return -1; /* undecided */
}
-/*
- * Loads the exclude lists for the directory containing pathname, then
- * scans all exclude lists to determine whether pathname is excluded.
- * Returns the exclude_list element which matched, or NULL for
- * undecided.
- */
-static struct exclude *last_exclude_matching(struct dir_struct *dir,
- const char *pathname,
- int *dtype_p)
+static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir,
+ const char *pathname, int pathlen, const char *basename,
+ int *dtype_p)
{
- int pathlen = strlen(pathname);
int i, j;
struct exclude_list_group *group;
struct exclude *exclude;
- const char *basename = strrchr(pathname, '/');
- basename = (basename) ? basename+1 : pathname;
-
- prep_exclude(dir, pathname, basename-pathname);
-
for (i = EXC_CMDL; i <= EXC_FILE; i++) {
group = &dir->exclude_list_group[i];
for (j = group->nr - 1; j >= 0; j--) {
@@ -828,101 +714,134 @@ static struct exclude *last_exclude_matching(struct dir_struct *dir,
}
/*
- * Loads the exclude lists for the directory containing pathname, then
- * scans all exclude lists to determine whether pathname is excluded.
- * Returns 1 if true, otherwise 0.
+ * Loads the per-directory exclude list for the substring of base
+ * which has a char length of baselen.
*/
-static int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
-{
- struct exclude *exclude =
- last_exclude_matching(dir, pathname, dtype_p);
- if (exclude)
- return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
- return 0;
-}
-
-void path_exclude_check_init(struct path_exclude_check *check,
- struct dir_struct *dir)
+static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
{
- check->dir = dir;
- check->exclude = NULL;
- strbuf_init(&check->path, 256);
-}
+ struct exclude_list_group *group;
+ struct exclude_list *el;
+ struct exclude_stack *stk = NULL;
+ int current;
-void path_exclude_check_clear(struct path_exclude_check *check)
-{
- strbuf_release(&check->path);
-}
+ group = &dir->exclude_list_group[EXC_DIRS];
-/*
- * For each subdirectory in name, starting with the top-most, checks
- * to see if that subdirectory is excluded, and if so, returns the
- * corresponding exclude structure. Otherwise, checks whether name
- * itself (which is presumably a file) is excluded.
- *
- * A path to a directory known to be excluded is left in check->path to
- * optimize for repeated checks for files in the same excluded directory.
- */
-struct exclude *last_exclude_matching_path(struct path_exclude_check *check,
- const char *name, int namelen,
- int *dtype)
-{
- int i;
- struct strbuf *path = &check->path;
- struct exclude *exclude;
+ /* Pop the exclude lists from the EXCL_DIRS exclude_list_group
+ * which originate from directories not in the prefix of the
+ * path being checked. */
+ while ((stk = dir->exclude_stack) != NULL) {
+ if (stk->baselen <= baselen &&
+ !strncmp(dir->basebuf, base, stk->baselen))
+ break;
+ el = &group->el[dir->exclude_stack->exclude_ix];
+ dir->exclude_stack = stk->prev;
+ dir->exclude = NULL;
+ free((char *)el->src); /* see strdup() below */
+ clear_exclude_list(el);
+ free(stk);
+ group->nr--;
+ }
- /*
- * we allow the caller to pass namelen as an optimization; it
- * must match the length of the name, as we eventually call
- * is_excluded() on the whole name string.
- */
- if (namelen < 0)
- namelen = strlen(name);
+ /* Skip traversing into sub directories if the parent is excluded */
+ if (dir->exclude)
+ return;
- /*
- * If path is non-empty, and name is equal to path or a
- * subdirectory of path, name should be excluded, because
- * it's inside a directory which is already known to be
- * excluded and was previously left in check->path.
- */
- if (path->len &&
- path->len <= namelen &&
- !memcmp(name, path->buf, path->len) &&
- (!name[path->len] || name[path->len] == '/'))
- return check->exclude;
+ /* Read from the parent directories and push them down. */
+ current = stk ? stk->baselen : -1;
+ while (current < baselen) {
+ struct exclude_stack *stk = xcalloc(1, sizeof(*stk));
+ const char *cp;
- strbuf_setlen(path, 0);
- for (i = 0; name[i]; i++) {
- int ch = name[i];
+ if (current < 0) {
+ cp = base;
+ current = 0;
+ }
+ else {
+ cp = strchr(base + current + 1, '/');
+ if (!cp)
+ die("oops in prep_exclude");
+ cp++;
+ }
+ stk->prev = dir->exclude_stack;
+ stk->baselen = cp - base;
+ stk->exclude_ix = group->nr;
+ el = add_exclude_list(dir, EXC_DIRS, NULL);
+ memcpy(dir->basebuf + current, base + current,
+ stk->baselen - current);
- if (ch == '/') {
+ /* Abort if the directory is excluded */
+ if (stk->baselen) {
int dt = DT_DIR;
- exclude = last_exclude_matching(check->dir,
- path->buf, &dt);
- if (exclude) {
- check->exclude = exclude;
- return exclude;
+ dir->basebuf[stk->baselen - 1] = 0;
+ dir->exclude = last_exclude_matching_from_lists(dir,
+ dir->basebuf, stk->baselen - 1,
+ dir->basebuf + current, &dt);
+ dir->basebuf[stk->baselen - 1] = '/';
+ if (dir->exclude &&
+ dir->exclude->flags & EXC_FLAG_NEGATIVE)
+ dir->exclude = NULL;
+ if (dir->exclude) {
+ dir->basebuf[stk->baselen] = 0;
+ dir->exclude_stack = stk;
+ return;
}
}
- strbuf_addch(path, ch);
+
+ /* Try to read per-directory file unless path is too long */
+ if (dir->exclude_per_dir &&
+ stk->baselen + strlen(dir->exclude_per_dir) < PATH_MAX) {
+ strcpy(dir->basebuf + stk->baselen,
+ dir->exclude_per_dir);
+ /*
+ * dir->basebuf gets reused by the traversal, but we
+ * need fname to remain unchanged to ensure the src
+ * member of each struct exclude correctly
+ * back-references its source file. Other invocations
+ * of add_exclude_list provide stable strings, so we
+ * strdup() and free() here in the caller.
+ */
+ el->src = strdup(dir->basebuf);
+ add_excludes_from_file_to_list(dir->basebuf,
+ dir->basebuf, stk->baselen, el, 1);
+ }
+ dir->exclude_stack = stk;
+ current = stk->baselen;
}
+ dir->basebuf[baselen] = '\0';
+}
- /* An entry in the index; cannot be a directory with subentries */
- strbuf_setlen(path, 0);
+/*
+ * Loads the exclude lists for the directory containing pathname, then
+ * scans all exclude lists to determine whether pathname is excluded.
+ * Returns the exclude_list element which matched, or NULL for
+ * undecided.
+ */
+struct exclude *last_exclude_matching(struct dir_struct *dir,
+ const char *pathname,
+ int *dtype_p)
+{
+ int pathlen = strlen(pathname);
+ const char *basename = strrchr(pathname, '/');
+ basename = (basename) ? basename+1 : pathname;
+
+ prep_exclude(dir, pathname, basename-pathname);
+
+ if (dir->exclude)
+ return dir->exclude;
- return last_exclude_matching(check->dir, name, dtype);
+ return last_exclude_matching_from_lists(dir, pathname, pathlen,
+ basename, dtype_p);
}
/*
- * Is this name excluded? This is for a caller like show_files() that
- * do not honor directory hierarchy and iterate through paths that are
- * possibly in an ignored directory.
+ * Loads the exclude lists for the directory containing pathname, then
+ * scans all exclude lists to determine whether pathname is excluded.
+ * Returns 1 if true, otherwise 0.
*/
-int is_path_excluded(struct path_exclude_check *check,
- const char *name, int namelen, int *dtype)
+int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
{
struct exclude *exclude =
- last_exclude_matching_path(check, name, namelen, dtype);
+ last_exclude_matching(dir, pathname, dtype_p);
if (exclude)
return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
return 0;
@@ -941,8 +860,7 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)
static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
{
- if (!(dir->flags & DIR_SHOW_IGNORED) &&
- cache_name_exists(pathname, len, ignore_case))
+ if (cache_name_exists(pathname, len, ignore_case))
return NULL;
ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
@@ -965,13 +883,13 @@ enum exist_status {
};
/*
- * Do not use the alphabetically stored index to look up
+ * Do not use the alphabetically sorted index to look up
* the directory name; instead, use the case insensitive
* name hash.
*/
static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
{
- struct cache_entry *ce = index_name_exists(&the_index, dirname, len + 1, ignore_case);
+ const struct cache_entry *ce = cache_name_exists(dirname, len + 1, ignore_case);
unsigned char endchar;
if (!ce)
@@ -1015,7 +933,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
if (pos < 0)
pos = -pos-1;
while (pos < active_nr) {
- struct cache_entry *ce = active_cache[pos++];
+ const struct cache_entry *ce = active_cache[pos++];
unsigned char endchar;
if (strncmp(ce->name, dirname, len))
@@ -1044,9 +962,8 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
* traversal routine.
*
* Case 1: If we *already* have entries in the index under that
- * directory name, we recurse into the directory to see all the files,
- * unless the directory is excluded and we want to show ignored
- * directories
+ * directory name, we always recurse into the directory to see
+ * all the files.
*
* Case 2: If we *already* have that directory name as a gitlink,
* we always continue to see it as a gitlink, regardless of whether
@@ -1058,38 +975,24 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
*
* (a) if "show_other_directories" is true, we show it as
* just a directory, unless "hide_empty_directories" is
- * also true and the directory is empty, in which case
- * we just ignore it entirely.
- * if we are looking for ignored directories, look if it
- * contains only ignored files to decide if it must be shown as
- * ignored or not.
+ * also true, in which case we need to check if it contains any
+ * untracked and / or ignored files.
* (b) if it looks like a git directory, and we don't have
* 'no_gitlinks' set we treat it as a gitlink, and show it
* as a directory.
* (c) otherwise, we recurse into it.
*/
-enum directory_treatment {
- show_directory,
- ignore_directory,
- recurse_into_directory
-};
-
-static enum directory_treatment treat_directory(struct dir_struct *dir,
+static enum path_treatment treat_directory(struct dir_struct *dir,
const char *dirname, int len, int exclude,
const struct path_simplify *simplify)
{
/* The "len-1" is to strip the final '/' */
switch (directory_exists_in_index(dirname, len-1)) {
case index_directory:
- if ((dir->flags & DIR_SHOW_OTHER_DIRECTORIES) && exclude)
- break;
-
- return recurse_into_directory;
+ return path_recurse;
case index_gitdir:
- if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
- return ignore_directory;
- return show_directory;
+ return path_none;
case index_nonexistent:
if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
@@ -1097,72 +1000,17 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
if (!(dir->flags & DIR_NO_GITLINKS)) {
unsigned char sha1[20];
if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
- return show_directory;
+ return path_untracked;
}
- return recurse_into_directory;
+ return path_recurse;
}
/* This is the "show_other_directories" case */
- /*
- * We are looking for ignored files and our directory is not ignored,
- * check if it contains only ignored files
- */
- if ((dir->flags & DIR_SHOW_IGNORED) && !exclude) {
- int ignored;
- dir->flags &= ~DIR_SHOW_IGNORED;
- dir->flags |= DIR_HIDE_EMPTY_DIRECTORIES;
- ignored = read_directory_recursive(dir, dirname, len, 1, simplify);
- dir->flags &= ~DIR_HIDE_EMPTY_DIRECTORIES;
- dir->flags |= DIR_SHOW_IGNORED;
-
- return ignored ? ignore_directory : show_directory;
- }
- if (!(dir->flags & DIR_SHOW_IGNORED) &&
- !(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
- return show_directory;
- if (!read_directory_recursive(dir, dirname, len, 1, simplify))
- return ignore_directory;
- return show_directory;
-}
-
-/*
- * Decide what to do when we find a file while traversing the
- * filesystem. Mostly two cases:
- *
- * 1. We are looking for ignored files
- * (a) File is ignored, include it
- * (b) File is in ignored path, include it
- * (c) File is not ignored, exclude it
- *
- * 2. Other scenarios, include the file if not excluded
- *
- * Return 1 for exclude, 0 for include.
- */
-static int treat_file(struct dir_struct *dir, struct strbuf *path, int exclude, int *dtype)
-{
- struct path_exclude_check check;
- int exclude_file = 0;
-
- if (exclude)
- exclude_file = !(dir->flags & DIR_SHOW_IGNORED);
- else if (dir->flags & DIR_SHOW_IGNORED) {
- /* Always exclude indexed files */
- struct cache_entry *ce = index_name_exists(&the_index,
- path->buf, path->len, ignore_case);
-
- if (ce)
- return 1;
+ if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
+ return exclude ? path_excluded : path_untracked;
- path_exclude_check_init(&check, dir);
-
- if (!is_path_excluded(&check, path->buf, path->len, dtype))
- exclude_file = 1;
-
- path_exclude_check_clear(&check);
- }
-
- return exclude_file;
+ return read_directory_recursive(dir, dirname, len, 1, simplify);
}
/*
@@ -1221,7 +1069,7 @@ static int exclude_matches_pathspec(const char *path, int len,
static int get_index_dtype(const char *path, int len)
{
int pos;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
ce = cache_name_exists(path, len, 0);
if (ce) {
@@ -1277,57 +1125,77 @@ static int get_dtype(struct dirent *de, const char *path, int len)
return dtype;
}
-enum path_treatment {
- path_ignored,
- path_handled,
- path_recurse
-};
-
static enum path_treatment treat_one_path(struct dir_struct *dir,
struct strbuf *path,
const struct path_simplify *simplify,
int dtype, struct dirent *de)
{
- int exclude = is_excluded(dir, path->buf, &dtype);
- if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
- && exclude_matches_pathspec(path->buf, path->len, simplify))
- dir_add_ignored(dir, path->buf, path->len);
+ int exclude;
+ int has_path_in_index = !!cache_name_exists(path->buf, path->len, ignore_case);
+
+ if (dtype == DT_UNKNOWN)
+ dtype = get_dtype(de, path->buf, path->len);
+
+ /* Always exclude indexed files */
+ if (dtype != DT_DIR && has_path_in_index)
+ return path_none;
+
+ /*
+ * When we are looking at a directory P in the working tree,
+ * there are three cases:
+ *
+ * (1) P exists in the index. Everything inside the directory P in
+ * the working tree needs to go when P is checked out from the
+ * index.
+ *
+ * (2) P does not exist in the index, but there is P/Q in the index.
+ * We know P will stay a directory when we check out the contents
+ * of the index, but we do not know yet if there is a directory
+ * P/Q in the working tree to be killed, so we need to recurse.
+ *
+ * (3) P does not exist in the index, and there is no P/Q in the index
+ * to require P to be a directory, either. Only in this case, we
+ * know that everything inside P will not be killed without
+ * recursing.
+ */
+ if ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&
+ (dtype == DT_DIR) &&
+ !has_path_in_index) {
+ /*
+ * NEEDSWORK: directory_exists_in_index_icase()
+ * assumes that one byte past the given path is
+ * readable and has '/', which needs to be fixed, but
+ * until then, work it around in the caller.
+ */
+ strbuf_addch(path, '/');
+ if (directory_exists_in_index(path->buf, path->len - 1) ==
+ index_nonexistent) {
+ strbuf_setlen(path, path->len - 1);
+ return path_none;
+ }
+ strbuf_setlen(path, path->len - 1);
+ }
+
+ exclude = is_excluded(dir, path->buf, &dtype);
/*
* Excluded? If we don't explicitly want to show
* ignored files, ignore it
*/
- if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
- return path_ignored;
-
- if (dtype == DT_UNKNOWN)
- dtype = get_dtype(de, path->buf, path->len);
+ if (exclude && !(dir->flags & (DIR_SHOW_IGNORED|DIR_SHOW_IGNORED_TOO)))
+ return path_excluded;
switch (dtype) {
default:
- return path_ignored;
+ return path_none;
case DT_DIR:
strbuf_addch(path, '/');
-
- switch (treat_directory(dir, path->buf, path->len, exclude, simplify)) {
- case show_directory:
- break;
- case recurse_into_directory:
- return path_recurse;
- case ignore_directory:
- return path_ignored;
- }
- break;
+ return treat_directory(dir, path->buf, path->len, exclude,
+ simplify);
case DT_REG:
case DT_LNK:
- switch (treat_file(dir, path, exclude, &dtype)) {
- case 1:
- return path_ignored;
- default:
- break;
- }
+ return exclude ? path_excluded : path_untracked;
}
- return path_handled;
}
static enum path_treatment treat_path(struct dir_struct *dir,
@@ -1339,11 +1207,11 @@ static enum path_treatment treat_path(struct dir_struct *dir,
int dtype;
if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
- return path_ignored;
+ return path_none;
strbuf_setlen(path, baselen);
strbuf_addstr(path, de->d_name);
if (simplify_away(path->buf, path->len, simplify))
- return path_ignored;
+ return path_none;
dtype = DTYPE(de);
return treat_one_path(dir, path, simplify, dtype, de);
@@ -1357,14 +1225,16 @@ static enum path_treatment treat_path(struct dir_struct *dir,
*
* Also, we ignore the name ".git" (even if it is not a directory).
* That likely will not change.
+ *
+ * Returns the most significant path_treatment value encountered in the scan.
*/
-static int read_directory_recursive(struct dir_struct *dir,
+static enum path_treatment read_directory_recursive(struct dir_struct *dir,
const char *base, int baselen,
int check_only,
const struct path_simplify *simplify)
{
DIR *fdir;
- int contents = 0;
+ enum path_treatment state, subdir_state, dir_state = path_none;
struct dirent *de;
struct strbuf path = STRBUF_INIT;
@@ -1375,27 +1245,53 @@ static int read_directory_recursive(struct dir_struct *dir,
goto out;
while ((de = readdir(fdir)) != NULL) {
- switch (treat_path(dir, de, &path, baselen, simplify)) {
- case path_recurse:
- contents += read_directory_recursive(dir, path.buf,
- path.len, 0,
- simplify);
- continue;
- case path_ignored:
+ /* check how the file or directory should be treated */
+ state = treat_path(dir, de, &path, baselen, simplify);
+ if (state > dir_state)
+ dir_state = state;
+
+ /* recurse into subdir if instructed by treat_path */
+ if (state == path_recurse) {
+ subdir_state = read_directory_recursive(dir, path.buf,
+ path.len, check_only, simplify);
+ if (subdir_state > dir_state)
+ dir_state = subdir_state;
+ }
+
+ if (check_only) {
+ /* abort early if maximum state has been reached */
+ if (dir_state == path_untracked)
+ break;
+ /* skip the dir_add_* part */
continue;
- case path_handled:
- break;
}
- contents++;
- if (check_only)
+
+ /* add the path to the appropriate result list */
+ switch (state) {
+ case path_excluded:
+ if (dir->flags & DIR_SHOW_IGNORED)
+ dir_add_name(dir, path.buf, path.len);
+ else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
+ ((dir->flags & DIR_COLLECT_IGNORED) &&
+ exclude_matches_pathspec(path.buf, path.len,
+ simplify)))
+ dir_add_ignored(dir, path.buf, path.len);
break;
- dir_add_name(dir, path.buf, path.len);
+
+ case path_untracked:
+ if (!(dir->flags & DIR_SHOW_IGNORED))
+ dir_add_name(dir, path.buf, path.len);
+ break;
+
+ default:
+ break;
+ }
}
closedir(fdir);
out:
strbuf_release(&path);
- return contents;
+ return dir_state;
}
static int cmp_name(const void *p1, const void *p2)
@@ -1444,12 +1340,14 @@ static int treat_leading_path(struct dir_struct *dir,
struct strbuf sb = STRBUF_INIT;
int baselen, rc = 0;
const char *cp;
+ int old_flags = dir->flags;
while (len && path[len - 1] == '/')
len--;
if (!len)
return 1;
baselen = 0;
+ dir->flags &= ~DIR_SHOW_OTHER_DIRECTORIES;
while (1) {
cp = path + baselen + !!baselen;
cp = memchr(cp, '/', path + len - cp);
@@ -1464,7 +1362,7 @@ static int treat_leading_path(struct dir_struct *dir,
if (simplify_away(sb.buf, sb.len, simplify))
break;
if (treat_one_path(dir, &sb, simplify,
- DT_DIR, NULL) == path_ignored)
+ DT_DIR, NULL) == path_none)
break; /* do not recurse into it */
if (len <= baselen) {
rc = 1;
@@ -1472,17 +1370,29 @@ static int treat_leading_path(struct dir_struct *dir,
}
}
strbuf_release(&sb);
+ dir->flags = old_flags;
return rc;
}
-int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)
+int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)
{
struct path_simplify *simplify;
+ /*
+ * Check out create_simplify()
+ */
+ if (pathspec)
+ GUARD_PATHSPEC(pathspec,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
if (has_symlink_leading_path(path, len))
return dir->nr;
- simplify = create_simplify(pathspec);
+ simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
if (!len || treat_leading_path(dir, path, len, simplify))
read_directory_recursive(dir, path, len, 0, simplify);
free_simplify(simplify);
@@ -1637,9 +1547,9 @@ void setup_standard_excludes(struct dir_struct *dir)
home_config_paths(NULL, &xdg_path, "ignore");
excludes_file = xdg_path;
}
- if (!access_or_warn(path, R_OK))
+ if (!access_or_warn(path, R_OK, 0))
add_excludes_from_file(dir, path);
- if (excludes_file && !access_or_warn(excludes_file, R_OK))
+ if (excludes_file && !access_or_warn(excludes_file, R_OK, 0))
add_excludes_from_file(dir, excludes_file);
}
@@ -1647,7 +1557,7 @@ int remove_path(const char *name)
{
char *slash;
- if (unlink(name) && errno != ENOENT)
+ if (unlink(name) && errno != ENOENT && errno != ENOTDIR)
return -1;
slash = strrchr(name, '/');
@@ -1662,71 +1572,6 @@ int remove_path(const char *name)
return 0;
}
-static int pathspec_item_cmp(const void *a_, const void *b_)
-{
- struct pathspec_item *a, *b;
-
- a = (struct pathspec_item *)a_;
- b = (struct pathspec_item *)b_;
- return strcmp(a->match, b->match);
-}
-
-int init_pathspec(struct pathspec *pathspec, const char **paths)
-{
- const char **p = paths;
- int i;
-
- memset(pathspec, 0, sizeof(*pathspec));
- if (!p)
- return 0;
- while (*p)
- p++;
- pathspec->raw = paths;
- pathspec->nr = p - paths;
- if (!pathspec->nr)
- return 0;
-
- pathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr);
- for (i = 0; i < pathspec->nr; i++) {
- struct pathspec_item *item = pathspec->items+i;
- const char *path = paths[i];
-
- item->match = path;
- item->len = strlen(path);
- item->flags = 0;
- if (limit_pathspec_to_literal()) {
- item->nowildcard_len = item->len;
- } else {
- item->nowildcard_len = simple_length(path);
- if (item->nowildcard_len < item->len) {
- pathspec->has_wildcard = 1;
- if (path[item->nowildcard_len] == '*' &&
- no_wildcard(path + item->nowildcard_len + 1))
- item->flags |= PATHSPEC_ONESTAR;
- }
- }
- }
-
- qsort(pathspec->items, pathspec->nr,
- sizeof(struct pathspec_item), pathspec_item_cmp);
-
- return 0;
-}
-
-void free_pathspec(struct pathspec *pathspec)
-{
- free(pathspec->items);
- pathspec->items = NULL;
-}
-
-int limit_pathspec_to_literal(void)
-{
- static int flag = -1;
- if (flag < 0)
- flag = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
- return flag;
-}
-
/*
* Frees memory within dir which was allocated for exclude lists and
* the exclude_stack. Does not free dir itself.
diff --git a/dir.h b/dir.h
index c3eb4b5..9b7e4e7 100644
--- a/dir.h
+++ b/dir.h
@@ -79,7 +79,9 @@ struct dir_struct {
DIR_SHOW_OTHER_DIRECTORIES = 1<<1,
DIR_HIDE_EMPTY_DIRECTORIES = 1<<2,
DIR_NO_GITLINKS = 1<<3,
- DIR_COLLECT_IGNORED = 1<<4
+ DIR_COLLECT_IGNORED = 1<<4,
+ DIR_SHOW_IGNORED_TOO = 1<<5,
+ DIR_COLLECT_KILLED_ONLY = 1<<6
} flags;
struct dir_entry **entries;
struct dir_entry **ignored;
@@ -110,9 +112,11 @@ struct dir_struct {
*
* exclude_stack points to the top of the exclude_stack, and
* basebuf contains the full path to the current
- * (sub)directory in the traversal.
+ * (sub)directory in the traversal. Exclude points to the
+ * matching exclude struct if the directory is excluded.
*/
struct exclude_stack *exclude_stack;
+ struct exclude *exclude;
char basebuf[PATH_MAX];
};
@@ -125,15 +129,16 @@ struct dir_struct {
#define MATCHED_RECURSIVELY 1
#define MATCHED_FNMATCH 2
#define MATCHED_EXACTLY 3
-extern char *common_prefix(const char **pathspec);
-extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
+extern int simple_length(const char *match);
+extern int no_wildcard(const char *string);
+extern char *common_prefix(const struct pathspec *pathspec);
extern int match_pathspec_depth(const struct pathspec *pathspec,
const char *name, int namelen,
int prefix, char *seen);
extern int within_depth(const char *name, int namelen, int depth, int max_depth);
-extern int fill_directory(struct dir_struct *dir, const char **pathspec);
-extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);
+extern int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec);
+extern int read_directory(struct dir_struct *, const char *path, int len, const struct pathspec *pathspec);
extern int is_excluded_from_list(const char *pathname, int pathlen, const char *basename,
int *dtype, struct exclude_list *el);
@@ -149,22 +154,10 @@ extern int match_pathname(const char *, int,
const char *, int,
const char *, int, int, int);
-/*
- * The is_excluded() API is meant for callers that check each level of leading
- * directory hierarchies with is_excluded() to avoid recursing into excluded
- * directories. Callers that do not do so should use this API instead.
- */
-struct path_exclude_check {
- struct dir_struct *dir;
- struct exclude *exclude;
- struct strbuf path;
-};
-extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *);
-extern void path_exclude_check_clear(struct path_exclude_check *);
-extern struct exclude *last_exclude_matching_path(struct path_exclude_check *, const char *,
- int namelen, int *dtype);
-extern int is_path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);
+extern struct exclude *last_exclude_matching(struct dir_struct *dir,
+ const char *name, int *dtype);
+extern int is_excluded(struct dir_struct *dir, const char *name, int *dtype);
extern struct exclude_list *add_exclude_list(struct dir_struct *dir,
int group_type, const char *src);
@@ -207,10 +200,9 @@ extern int fnmatch_icase(const char *pattern, const char *string, int flags);
/*
* The prefix part of pattern must not contains wildcards.
*/
-#define GFNM_PATHNAME 1 /* similar to FNM_PATHNAME */
-#define GFNM_ONESTAR 2 /* there is only _one_ wildcard, a star */
-
-extern int git_fnmatch(const char *pattern, const char *string,
- int flags, int prefix);
+struct pathspec_item;
+extern int git_fnmatch(const struct pathspec_item *item,
+ const char *pattern, const char *string,
+ int prefix);
#endif
diff --git a/editor.c b/editor.c
index 27bdecd..0abbd8d 100644
--- a/editor.c
+++ b/editor.c
@@ -37,7 +37,7 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en
return error("Terminal is dumb, but EDITOR unset");
if (strcmp(editor, ":")) {
- const char *args[] = { editor, path, NULL };
+ const char *args[] = { editor, real_path(path), NULL };
struct child_process p;
int ret, sig;
diff --git a/entry.c b/entry.c
index 63c52ed..acc892f 100644
--- a/entry.c
+++ b/entry.c
@@ -79,7 +79,7 @@ static int create_file(const char *path, unsigned int mode)
return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
}
-static void *read_blob_entry(struct cache_entry *ce, unsigned long *size)
+static void *read_blob_entry(const struct cache_entry *ce, unsigned long *size)
{
enum object_type type;
void *new = read_sha1_file(ce->sha1, &type, size);
@@ -92,7 +92,7 @@ static void *read_blob_entry(struct cache_entry *ce, unsigned long *size)
return NULL;
}
-static int open_output_fd(char *path, struct cache_entry *ce, int to_tempfile)
+static int open_output_fd(char *path, const struct cache_entry *ce, int to_tempfile)
{
int symlink = (ce->ce_mode & S_IFMT) != S_IFREG;
if (to_tempfile) {
@@ -115,26 +115,29 @@ static int fstat_output(int fd, const struct checkout *state, struct stat *st)
return 0;
}
-static int streaming_write_entry(struct cache_entry *ce, char *path,
+static int streaming_write_entry(const struct cache_entry *ce, char *path,
struct stream_filter *filter,
const struct checkout *state, int to_tempfile,
int *fstat_done, struct stat *statbuf)
{
- int result = -1;
+ int result = 0;
int fd;
fd = open_output_fd(path, ce, to_tempfile);
- if (0 <= fd) {
- result = stream_blob_to_fd(fd, ce->sha1, filter, 1);
- *fstat_done = fstat_output(fd, state, statbuf);
- result = close(fd);
- }
- if (result && 0 <= fd)
+ if (fd < 0)
+ return -1;
+
+ result |= stream_blob_to_fd(fd, ce->sha1, filter, 1);
+ *fstat_done = fstat_output(fd, state, statbuf);
+ result |= close(fd);
+
+ if (result)
unlink(path);
return result;
}
-static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile)
+static int write_entry(struct cache_entry *ce,
+ char *path, const struct checkout *state, int to_tempfile)
{
unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT;
int fd, ret, fstat_done = 0;
@@ -197,9 +200,9 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
break;
case S_IFGITLINK:
if (to_tempfile)
- return error("cannot create temporary subproject %s", path);
+ return error("cannot create temporary submodule %s", path);
if (mkdir(path, 0777) < 0)
- return error("cannot create subproject directory %s", path);
+ return error("cannot create submodule directory %s", path);
break;
default:
return error("unknown file mode for %s in index", path);
@@ -231,7 +234,8 @@ static int check_path(const char *path, int len, struct stat *st, int skiplen)
return lstat(path, st);
}
-int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath)
+int checkout_entry(struct cache_entry *ce,
+ const struct checkout *state, char *topath)
{
static char path[PATH_MAX + 1];
struct stat st;
diff --git a/environment.c b/environment.c
index e2e75c1..5398c36 100644
--- a/environment.c
+++ b/environment.c
@@ -22,6 +22,7 @@ int prefer_symlink_refs;
int is_bare_repository_cfg = -1; /* unspecified */
int log_all_ref_updates = -1; /* unspecified */
int warn_ambiguous_refs = 1;
+int warn_on_object_refname_ambiguity = 1;
int repository_format_version;
const char *git_commit_encoding;
const char *git_log_output_encoding;
@@ -37,7 +38,6 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
size_t delta_base_cache_limit = 16 * 1024 * 1024;
unsigned long big_file_threshold = 512 * 1024 * 1024;
-const char *log_pack_access;
const char *pager_program;
int pager_use_color = 1;
const char *editor_program;
diff --git a/exec_cmd.h b/exec_cmd.h
index e2b546b..e4c9702 100644
--- a/exec_cmd.h
+++ b/exec_cmd.h
@@ -7,6 +7,7 @@ extern const char *git_exec_path(void);
extern void setup_path(void);
extern const char **prepare_git_cmd(const char **argv);
extern int execv_git_cmd(const char **argv); /* NULL terminated */
+LAST_ARG_MUST_BE_NULL
extern int execl_git_cmd(const char *cmd, ...);
extern const char *system_path(const char *path);
diff --git a/fast-import.c b/fast-import.c
index 5f539d7..21db3fc 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -297,7 +297,7 @@ static int failure;
static FILE *pack_edges;
static unsigned int show_stats = 1;
static int global_argc;
-static const char **global_argv;
+static char **global_argv;
/* Memory pools */
static size_t mem_pool_alloc = 2*1024*1024 - sizeof(struct mem_pool);
@@ -1568,7 +1568,8 @@ static int tree_content_set(
static int tree_content_remove(
struct tree_entry *root,
const char *p,
- struct tree_entry *backup_leaf)
+ struct tree_entry *backup_leaf,
+ int allow_root)
{
struct tree_content *t;
const char *slash1;
@@ -1583,6 +1584,12 @@ static int tree_content_remove(
if (!root->tree)
load_tree(root);
+
+ if (!*p && allow_root) {
+ e = root;
+ goto del_entry;
+ }
+
t = root->tree;
for (i = 0; i < t->entry_count; i++) {
e = t->entries[i];
@@ -1599,7 +1606,7 @@ static int tree_content_remove(
goto del_entry;
if (!e->tree)
load_tree(e);
- if (tree_content_remove(e, slash1 + 1, backup_leaf)) {
+ if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) {
for (n = 0; n < e->tree->entry_count; n++) {
if (e->tree->entries[n]->versions[1].mode) {
hashclr(root->versions[1].sha1);
@@ -1629,7 +1636,8 @@ del_entry:
static int tree_content_get(
struct tree_entry *root,
const char *p,
- struct tree_entry *leaf)
+ struct tree_entry *leaf,
+ int allow_root)
{
struct tree_content *t;
const char *slash1;
@@ -1641,31 +1649,39 @@ static int tree_content_get(
n = slash1 - p;
else
n = strlen(p);
- if (!n)
+ if (!n && !allow_root)
die("Empty path component found in input");
if (!root->tree)
load_tree(root);
+
+ if (!n) {
+ e = root;
+ goto found_entry;
+ }
+
t = root->tree;
for (i = 0; i < t->entry_count; i++) {
e = t->entries[i];
if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
- if (!slash1) {
- memcpy(leaf, e, sizeof(*leaf));
- if (e->tree && is_null_sha1(e->versions[1].sha1))
- leaf->tree = dup_tree_content(e->tree);
- else
- leaf->tree = NULL;
- return 1;
- }
+ if (!slash1)
+ goto found_entry;
if (!S_ISDIR(e->versions[1].mode))
return 0;
if (!e->tree)
load_tree(e);
- return tree_content_get(e, slash1 + 1, leaf);
+ return tree_content_get(e, slash1 + 1, leaf, 0);
}
}
return 0;
+
+found_entry:
+ memcpy(leaf, e, sizeof(*leaf));
+ if (e->tree && is_null_sha1(e->versions[1].sha1))
+ leaf->tree = dup_tree_content(e->tree);
+ else
+ leaf->tree = NULL;
+ return 1;
}
static int update_branch(struct branch *b)
@@ -1822,7 +1838,7 @@ static void read_marks(void)
*end = 0;
mark = strtoumax(line + 1, &end, 10);
if (!mark || end == line + 1
- || *end != ' ' || get_sha1(end + 1, sha1))
+ || *end != ' ' || get_sha1_hex(end + 1, sha1))
die("corrupt mark line: %s", line);
e = find_object(sha1);
if (!e) {
@@ -2179,7 +2195,7 @@ static uintmax_t do_change_note_fanout(
}
/* Rename fullpath to realpath */
- if (!tree_content_remove(orig_root, fullpath, &leaf))
+ if (!tree_content_remove(orig_root, fullpath, &leaf, 0))
die("Failed to remove path %s", fullpath);
tree_content_set(orig_root, realpath,
leaf.versions[1].sha1,
@@ -2314,7 +2330,7 @@ static void file_change_m(struct branch *b)
/* Git does not track empty, non-toplevel directories. */
if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) {
- tree_content_remove(&b->branch_tree, p, NULL);
+ tree_content_remove(&b->branch_tree, p, NULL, 0);
return;
}
@@ -2375,7 +2391,7 @@ static void file_change_d(struct branch *b)
die("Garbage after path in: %s", command_buf.buf);
p = uq.buf;
}
- tree_content_remove(&b->branch_tree, p, NULL);
+ tree_content_remove(&b->branch_tree, p, NULL, 1);
}
static void file_change_cr(struct branch *b, int rename)
@@ -2413,9 +2429,9 @@ static void file_change_cr(struct branch *b, int rename)
memset(&leaf, 0, sizeof(leaf));
if (rename)
- tree_content_remove(&b->branch_tree, s, &leaf);
+ tree_content_remove(&b->branch_tree, s, &leaf, 1);
else
- tree_content_get(&b->branch_tree, s, &leaf);
+ tree_content_get(&b->branch_tree, s, &leaf, 1);
if (!leaf.versions[1].mode)
die("Path %s not in branch", s);
if (!*d) { /* C "path/to/subdir" "" */
@@ -2521,7 +2537,7 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
}
construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path);
- if (tree_content_remove(&b->branch_tree, path, NULL))
+ if (tree_content_remove(&b->branch_tree, path, NULL, 0))
b->num_notes--;
if (is_null_sha1(sha1))
@@ -3051,6 +3067,8 @@ static void parse_ls(struct branch *b)
struct object_entry *e = parse_treeish_dataref(&p);
root = new_tree_entry();
hashcpy(root->versions[1].sha1, e->idx.sha1);
+ if (!is_null_sha1(root->versions[1].sha1))
+ root->versions[1].mode = S_IFDIR;
load_tree(root);
if (*p++ != ' ')
die("Missing space after tree-ish: %s", command_buf.buf);
@@ -3065,7 +3083,7 @@ static void parse_ls(struct branch *b)
die("Garbage after path in: %s", command_buf.buf);
p = uq.buf;
}
- tree_content_get(root, p, &leaf);
+ tree_content_get(root, p, &leaf, 1);
/*
* A directory in preparation would have a sha1 of zero
* until it is saved. Save, for simplicity.
@@ -3347,7 +3365,7 @@ static void parse_argv(void)
read_marks();
}
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
unsigned int i;
diff --git a/fetch-pack.c b/fetch-pack.c
index 6d8926a..094267f 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -9,8 +9,10 @@
#include "fetch-pack.h"
#include "remote.h"
#include "run-command.h"
+#include "connect.h"
#include "transport.h"
#include "version.h"
+#include "prio-queue.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@@ -20,6 +22,8 @@ static int no_done;
static int fetch_fsck_objects = -1;
static int transfer_fsck_objects = -1;
static int agent_supported;
+static struct lock_file shallow_lock;
+static const char *alternate_shallow_file;
#define COMPLETE (1U << 0)
#define COMMON (1U << 1)
@@ -35,8 +39,8 @@ static int marked;
*/
#define MAX_IN_VAIN 256
-static struct commit_list *rev_list;
-static int non_common_revs, multi_ack, use_sideband;
+static struct prio_queue rev_list = { compare_commits_by_commit_date };
+static int non_common_revs, multi_ack, use_sideband, allow_tip_sha1_in_want;
static void rev_list_push(struct commit *commit, int mark)
{
@@ -47,7 +51,7 @@ static void rev_list_push(struct commit *commit, int mark)
if (parse_commit(commit))
return;
- commit_list_insert_by_date(commit, &rev_list);
+ prio_queue_put(&rev_list, commit);
if (!(commit->object.flags & COMMON))
non_common_revs++;
@@ -120,10 +124,10 @@ static const unsigned char *get_rev(void)
unsigned int mark;
struct commit_list *parents;
- if (rev_list == NULL || non_common_revs == 0)
+ if (rev_list.nr == 0 || non_common_revs == 0)
return NULL;
- commit = rev_list->item;
+ commit = prio_queue_get(&rev_list);
if (!commit->object.parsed)
parse_commit(commit);
parents = commit->parents;
@@ -150,8 +154,6 @@ static const unsigned char *get_rev(void)
mark_common(parents->item, 1, 0);
parents = parents->next;
}
-
- rev_list = rev_list->next;
}
return commit->object.sha1;
@@ -172,8 +174,8 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)
* shallow and unshallow commands every time there
* is a block of have lines exchanged.
*/
- char line[1000];
- while (packet_read_line(fd, line, sizeof(line))) {
+ char *line;
+ while ((line = packet_read_line(fd, NULL))) {
if (!prefixcmp(line, "shallow "))
continue;
if (!prefixcmp(line, "unshallow "))
@@ -215,17 +217,17 @@ static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
static enum ack_type get_ack(int fd, unsigned char *result_sha1)
{
- static char line[1000];
- int len = packet_read_line(fd, line, sizeof(line));
+ int len;
+ char *line = packet_read_line(fd, &len);
if (!len)
die("git fetch-pack: expected ACK/NAK, got EOF");
- if (line[len-1] == '\n')
- line[--len] = 0;
if (!strcmp(line, "NAK"))
return NAK;
if (!prefixcmp(line, "ACK ")) {
if (!get_sha1_hex(line+4, result_sha1)) {
+ if (len < 45)
+ return ACK;
if (strstr(line+45, "continue"))
return ACK_continue;
if (strstr(line+45, "common"))
@@ -245,7 +247,7 @@ static void send_request(struct fetch_pack_args *args,
send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);
packet_flush(fd);
} else
- safe_write(fd, buf->buf, buf->len);
+ write_or_die(fd, buf->buf, buf->len);
}
static void insert_one_alternate_ref(const struct ref *ref, void *unused)
@@ -346,11 +348,11 @@ static int find_common(struct fetch_pack_args *args,
state_len = req_buf.len;
if (args->depth > 0) {
- char line[1024];
+ char *line;
unsigned char sha1[20];
send_request(args, fd[1], &req_buf);
- while (packet_read_line(fd[0], line, sizeof(line))) {
+ while ((line = packet_read_line(fd[0], NULL))) {
if (!prefixcmp(line, "shallow ")) {
if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);
@@ -440,7 +442,7 @@ static int find_common(struct fetch_pack_args *args,
in_vain = 0;
got_continue = 1;
if (ack == ACK_ready) {
- rev_list = NULL;
+ clear_prio_queue(&rev_list);
got_ready = 1;
}
break;
@@ -503,7 +505,7 @@ static int mark_complete(const char *refname, const unsigned char *sha1, int fla
struct commit *commit = (struct commit *)o;
if (!(commit->object.flags & COMPLETE)) {
commit->object.flags |= COMPLETE;
- commit_list_insert_by_date(commit, &complete);
+ commit_list_insert(commit, &complete);
}
}
return 0;
@@ -520,47 +522,37 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,
}
}
-static int non_matching_ref(struct string_list_item *item, void *unused)
-{
- if (item->util) {
- item->util = NULL;
- return 0;
- }
- else
- return 1;
-}
-
static void filter_refs(struct fetch_pack_args *args,
- struct ref **refs, struct string_list *sought)
+ struct ref **refs,
+ struct ref **sought, int nr_sought)
{
struct ref *newlist = NULL;
struct ref **newtail = &newlist;
struct ref *ref, *next;
- int sought_pos;
+ int i;
- sought_pos = 0;
+ i = 0;
for (ref = *refs; ref; ref = next) {
int keep = 0;
next = ref->next;
+
if (!memcmp(ref->name, "refs/", 5) &&
check_refname_format(ref->name + 5, 0))
; /* trash */
else {
- while (sought_pos < sought->nr) {
- int cmp = strcmp(ref->name, sought->items[sought_pos].string);
+ while (i < nr_sought) {
+ int cmp = strcmp(ref->name, sought[i]->name);
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;
+ sought[i]->matched = 1;
}
- else
- sought_pos++; /* might have it; keep looking */
+ i++;
}
}
- if (! keep && args->fetch_all &&
+ if (!keep && args->fetch_all &&
(!args->depth || prefixcmp(ref->name, "refs/tags/")))
keep = 1;
@@ -573,7 +565,21 @@ static void filter_refs(struct fetch_pack_args *args,
}
}
- filter_string_list(sought, 0, non_matching_ref, NULL);
+ /* Append unmatched requests to the list */
+ if (allow_tip_sha1_in_want) {
+ for (i = 0; i < nr_sought; i++) {
+ ref = sought[i];
+ if (ref->matched)
+ continue;
+ if (get_sha1_hex(ref->name, ref->old_sha1))
+ continue;
+
+ ref->matched = 1;
+ *newtail = ref;
+ ref->next = NULL;
+ newtail = &ref->next;
+ }
+ }
*refs = newlist;
}
@@ -583,7 +589,8 @@ static void mark_alternate_complete(const struct ref *ref, void *unused)
}
static int everything_local(struct fetch_pack_args *args,
- struct ref **refs, struct string_list *sought)
+ struct ref **refs,
+ struct ref **sought, int nr_sought)
{
struct ref *ref;
int retval;
@@ -615,6 +622,7 @@ static int everything_local(struct fetch_pack_args *args,
if (!args->depth) {
for_each_ref(mark_complete, NULL);
for_each_alternate_ref(mark_alternate_complete, NULL);
+ commit_list_sort_by_date(&complete);
if (cutoff)
mark_recent_complete_commits(args, cutoff);
}
@@ -637,7 +645,7 @@ static int everything_local(struct fetch_pack_args *args,
}
}
- filter_refs(args, refs, sought);
+ filter_refs(args, refs, sought, nr_sought);
for (retval = 1, ref = *refs; ref ; ref = ref->next) {
const unsigned char *remote = ref->old_sha1;
@@ -678,12 +686,13 @@ static int get_pack(struct fetch_pack_args *args,
int xd[2], char **pack_lockfile)
{
struct async demux;
- const char *argv[20];
+ const char *argv[22];
char keep_arg[256];
char hdr_arg[256];
const char **av;
int do_keep = args->keep_pack;
struct child_process cmd;
+ int ret;
memset(&demux, 0, sizeof(demux));
if (use_sideband) {
@@ -719,6 +728,11 @@ static int get_pack(struct fetch_pack_args *args,
do_keep = 1;
}
+ if (alternate_shallow_file) {
+ *av++ = "--shallow-file";
+ *av++ = alternate_shallow_file;
+ }
+
if (do_keep) {
if (pack_lockfile)
cmd.out = -1;
@@ -735,11 +749,14 @@ static int get_pack(struct fetch_pack_args *args,
strcpy(keep_arg + s, "localhost");
*av++ = keep_arg;
}
+ if (args->check_self_contained_and_connected)
+ *av++ = "--check-self-contained-and-connected";
}
else {
*av++ = "unpack-objects";
if (args->quiet || args->no_progress)
*av++ = "-q";
+ args->check_self_contained_and_connected = 0;
}
if (*hdr_arg)
*av++ = hdr_arg;
@@ -760,17 +777,50 @@ static int get_pack(struct fetch_pack_args *args,
close(cmd.out);
}
- if (finish_command(&cmd))
+ ret = finish_command(&cmd);
+ if (!ret || (args->check_self_contained_and_connected && ret == 1))
+ args->self_contained_and_connected =
+ args->check_self_contained_and_connected &&
+ ret == 0;
+ else
die("%s failed", argv[0]);
if (use_sideband && finish_async(&demux))
die("error in sideband demultiplexer");
return 0;
}
+static int cmp_ref_by_name(const void *a_, const void *b_)
+{
+ const struct ref *a = *((const struct ref **)a_);
+ const struct ref *b = *((const struct ref **)b_);
+ return strcmp(a->name, b->name);
+}
+
+static void setup_alternate_shallow(void)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int fd;
+
+ check_shallow_file_for_update();
+ fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
+ LOCK_DIE_ON_ERROR);
+ if (write_shallow_commits(&sb, 0)) {
+ if (write_in_full(fd, sb.buf, sb.len) != sb.len)
+ die_errno("failed to write to %s", shallow_lock.filename);
+ alternate_shallow_file = shallow_lock.filename;
+ } else
+ /*
+ * is_repository_shallow() sees empty string as "no
+ * shallow file".
+ */
+ alternate_shallow_file = "";
+ strbuf_release(&sb);
+}
+
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int fd[2],
const struct ref *orig_ref,
- struct string_list *sought,
+ struct ref **sought, int nr_sought,
char **pack_lockfile)
{
struct ref *ref = copy_ref_list(orig_ref);
@@ -779,6 +829,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int agent_len;
sort_ref_list(&ref, ref_compare_name);
+ qsort(sought, nr_sought, sizeof(*sought), cmp_ref_by_name);
if (is_repository_shallow() && !server_supports("shallow"))
die("Server does not support shallow clients");
@@ -808,6 +859,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
fprintf(stderr, "Server supports side-band\n");
use_sideband = 1;
}
+ if (server_supports("allow-tip-sha1-in-want")) {
+ if (args->verbose)
+ fprintf(stderr, "Server supports allow-tip-sha1-in-want\n");
+ allow_tip_sha1_in_want = 1;
+ }
if (!server_supports("thin-pack"))
args->use_thin_pack = 0;
if (!server_supports("no-progress"))
@@ -827,7 +883,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
agent_len, agent_feature);
}
- if (everything_local(args, &ref, sought)) {
+ if (everything_local(args, &ref, sought, nr_sought)) {
packet_flush(fd[1]);
goto all_done;
}
@@ -840,6 +896,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (args->stateless_rpc)
packet_flush(fd[1]);
+ if (args->depth > 0)
+ setup_alternate_shallow();
+ else
+ alternate_shallow_file = NULL;
if (get_pack(args, fd, pack_lockfile))
die("git fetch-pack: fetch failed.");
@@ -890,62 +950,52 @@ static void fetch_pack_setup(void)
did_setup = 1;
}
+static int remove_duplicates_in_refs(struct ref **ref, int nr)
+{
+ struct string_list names = STRING_LIST_INIT_NODUP;
+ int src, dst;
+
+ for (src = dst = 0; src < nr; src++) {
+ struct string_list_item *item;
+ item = string_list_insert(&names, ref[src]->name);
+ if (item->util)
+ continue; /* already have it */
+ item->util = ref[src];
+ if (src != dst)
+ ref[dst] = ref[src];
+ dst++;
+ }
+ for (src = dst; src < nr; src++)
+ ref[src] = NULL;
+ string_list_clear(&names, 0);
+ return dst;
+}
+
struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
const struct ref *ref,
const char *dest,
- struct string_list *sought,
+ struct ref **sought, int nr_sought,
char **pack_lockfile)
{
- struct stat st;
struct ref *ref_cpy;
fetch_pack_setup();
- if (args->depth > 0) {
- if (stat(git_path("shallow"), &st))
- st.st_mtime = 0;
- }
-
- if (sought->nr) {
- sort_string_list(sought);
- string_list_remove_duplicates(sought, 0);
- }
+ if (nr_sought)
+ nr_sought = remove_duplicates_in_refs(sought, nr_sought);
if (!ref) {
packet_flush(fd[1]);
die("no matching remote head");
}
- ref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile);
+ ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile);
- if (args->depth > 0) {
- static struct lock_file lock;
- struct cache_time mtime;
- struct strbuf sb = STRBUF_INIT;
- char *shallow = git_path("shallow");
- int fd;
-
- mtime.sec = st.st_mtime;
- mtime.nsec = ST_MTIME_NSEC(st);
- if (stat(shallow, &st)) {
- if (mtime.sec)
- die("shallow file was removed during fetch");
- } else if (st.st_mtime != mtime.sec
-#ifdef USE_NSEC
- || ST_MTIME_NSEC(st) != mtime.nsec
-#endif
- )
- die("shallow file was changed during fetch");
-
- fd = hold_lock_file_for_update(&lock, shallow,
- LOCK_DIE_ON_ERROR);
- if (!write_shallow_commits(&sb, 0)
- || write_in_full(fd, sb.buf, sb.len) != sb.len) {
- unlink_or_warn(shallow);
- rollback_lock_file(&lock);
- } else {
- commit_lock_file(&lock);
- }
- strbuf_release(&sb);
+ if (args->depth > 0 && alternate_shallow_file) {
+ if (*alternate_shallow_file == '\0') { /* --unshallow */
+ unlink_or_warn(git_path("shallow"));
+ rollback_lock_file(&shallow_lock);
+ } else
+ commit_lock_file(&shallow_lock);
}
reprepare_packed_git();
diff --git a/fetch-pack.h b/fetch-pack.h
index cb14871..461cbf3 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -2,6 +2,7 @@
#define FETCH_PACK_H
#include "string-list.h"
+#include "run-command.h"
struct fetch_pack_args {
const char *uploadpack;
@@ -16,21 +17,22 @@ struct fetch_pack_args {
verbose:1,
no_progress:1,
include_tag:1,
- stateless_rpc:1;
+ stateless_rpc:1,
+ check_self_contained_and_connected:1,
+ self_contained_and_connected: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).
+ * sought represents remote references that should be updated from.
+ * On return, the names that were found on the remote will have been
+ * marked as such.
*/
struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
const struct ref *ref,
const char *dest,
- struct string_list *sought,
+ struct ref **sought,
+ int nr_sought,
char **pack_lockfile);
#endif
diff --git a/fixup-builtins b/fixup-builtins
deleted file mode 100755
index 63dfa4c..0000000
--- a/fixup-builtins
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-while [ "$1" ]
-do
- if [ "$1" != "git-sh-setup" -a "$1" != "git-parse-remote" -a "$1" != "git-svn" ]; then
- old="$1"
- new=$(echo "$1" | sed 's/git-/git /')
- echo "Converting '$old' to '$new'"
- sed -i "s/\\<$old\\>/$new/g" $(git ls-files '*.sh')
- fi
- shift
-done
-
-sed -i 's/git merge-one-file/git-merge-one-file/g
-s/git rebase-todo/git-rebase-todo/g' $(git ls-files '*.sh')
-git update-index --refresh >& /dev/null
-exit 0
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index d2c4ce6..75a991f 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -44,6 +44,8 @@ my ($diff_new_color) =
my $normal_color = $repo->get_color("", "reset");
+my $diff_algorithm = $repo->config('diff.algorithm');
+
my $use_readkey = 0;
my $use_termcap = 0;
my %term_escapes;
@@ -731,6 +733,9 @@ sub run_git_apply {
sub parse_diff {
my ($path) = @_;
my @diff_cmd = split(" ", $patch_mode_flavour{DIFF});
+ if (defined $diff_algorithm) {
+ splice @diff_cmd, 1, 0, "--diff-algorithm=${diff_algorithm}";
+ }
if (defined $patch_mode_revision) {
push @diff_cmd, $patch_mode_revision;
}
diff --git a/git-am.sh b/git-am.sh
index 202130f..7ea40fe 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -6,7 +6,7 @@ SUBDIRECTORY_OK=Yes
OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
git am [options] [(<mbox>|<Maildir>)...]
-git am [options] (--resolved | --skip | --abort)
+git am [options] (--continue | --skip | --abort)
--
i,interactive run interactively
b,binary* (historical option -- no-op)
@@ -102,7 +102,7 @@ stop_here_user_resolve () {
printf '%s\n' "$resolvemsg"
stop_here $1
fi
- eval_gettextln "When you have resolved this problem, run \"\$cmdline --resolved\".
+ eval_gettextln "When you have resolved this problem, run \"\$cmdline --continue\".
If you prefer to skip this patch, run \"\$cmdline --skip\" instead.
To restore the original branch and stop patching, run \"\$cmdline --abort\"."
@@ -446,6 +446,8 @@ done
# If the dotest directory exists, but we have finished applying all the
# patches in them, clear it out.
if test -d "$dotest" &&
+ test -f "$dotest/last" &&
+ test -f "$dotest/next" &&
last=$(cat "$dotest/last") &&
next=$(cat "$dotest/next") &&
test $# != 0 &&
@@ -454,7 +456,7 @@ then
rm -fr "$dotest"
fi
-if test -d "$dotest"
+if test -d "$dotest" && test -f "$dotest/last" && test -f "$dotest/next"
then
case "$#,$skip$resolved$abort" in
0,*t*)
@@ -504,7 +506,24 @@ then
esac
rm -f "$dotest/dirtyindex"
else
- # Make sure we are not given --skip, --resolved, nor --abort
+ # Possible stray $dotest directory in the independent-run
+ # case; in the --rebasing case, it is upto the caller
+ # (git-rebase--am) to take care of stray directories.
+ if test -d "$dotest" && test -z "$rebasing"
+ then
+ case "$skip,$resolved,$abort" in
+ ,,t)
+ rm -fr "$dotest"
+ exit 0
+ ;;
+ *)
+ die "$(eval_gettext "Stray \$dotest directory found.
+Use \"git am --abort\" to remove it.")"
+ ;;
+ esac
+ fi
+
+ # Make sure we are not given --skip, --continue, nor --abort
test "$skip$resolved$abort" = "" ||
die "$(gettext "Resolve operation not in progress, we are not resuming.")"
@@ -651,7 +670,7 @@ do
# - patch is the patch body.
#
# When we are resuming, these files are either already prepared
- # by the user, or the user can tell us to do so by --resolved flag.
+ # by the user, or the user can tell us to do so by --continue flag.
case "$resume" in
'')
if test -f "$dotest/rebasing"
@@ -778,13 +797,6 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
action=yes
fi
- if test -f "$dotest/final-commit"
- then
- FIRSTLINE=$(sed 1q "$dotest/final-commit")
- else
- FIRSTLINE=""
- fi
-
if test $action = skip
then
go_next
@@ -797,6 +809,13 @@ To restore the original branch and stop patching run \"\$cmdline --abort\"."
stop_here $this
fi
+ if test -f "$dotest/final-commit"
+ then
+ FIRSTLINE=$(sed 1q "$dotest/final-commit")
+ else
+ FIRSTLINE=""
+ fi
+
say "$(eval_gettext "Applying: \$FIRSTLINE")"
case "$resolved" in
@@ -904,5 +923,10 @@ if test -s "$dotest"/rewritten; then
fi
fi
-rm -fr "$dotest"
-git gc --auto
+# If am was called with --rebasing (from git-rebase--am), it's up to
+# the caller to take care of housekeeping.
+if ! test -f "$dotest/rebasing"
+then
+ rm -fr "$dotest"
+ git gc --auto
+fi
diff --git a/git-bisect.sh b/git-bisect.sh
index 99efbe8..9f064b6 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -311,7 +311,23 @@ bisect_next() {
res=$?
# Check if we should exit because bisection is finished
- test $res -eq 10 && exit 0
+ if test $res -eq 10
+ then
+ bad_rev=$(git show-ref --hash --verify refs/bisect/bad)
+ bad_commit=$(git show-branch $bad_rev)
+ echo "# first bad commit: $bad_commit" >>"$GIT_DIR/BISECT_LOG"
+ exit 0
+ elif test $res -eq 2
+ then
+ echo "# only skipped commits left to test" >>"$GIT_DIR/BISECT_LOG"
+ good_revs=$(git for-each-ref --format="%(objectname)" "refs/bisect/good-*")
+ for skipped in $(git rev-list refs/bisect/bad --not $good_revs)
+ do
+ skipped_commit=$(git show-branch $skipped)
+ echo "# possible first bad commit: $skipped_commit" >>"$GIT_DIR/BISECT_LOG"
+ done
+ exit $res
+ fi
# Check for an error in the bisection process
test $res -ne 0 && exit $res
diff --git a/git-compat-util.h b/git-compat-util.h
index ad47624..9549de6 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,10 +85,14 @@
#define _NETBSD_SOURCE 1
#define _SGI_SOURCE 1
-#ifdef WIN32 /* Both MinGW and MSVC */
+#if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
+# if defined (_MSC_VER)
+# define _WIN32_WINNT 0x0502
+# endif
#define WIN32_LEAN_AND_MEAN /* stops windows.h including winsock.h */
#include <winsock2.h>
#include <windows.h>
+#define GIT_WINDOWS_NATIVE
#endif
#include <unistd.h>
@@ -124,6 +128,7 @@
#else
#include <poll.h>
#endif
+
#if defined(__MINGW32__)
/* pull in Windows compatibility stuff */
#include "compat/mingw.h"
@@ -164,7 +169,6 @@ typedef unsigned long uintptr_t;
#undef _XOPEN_SOURCE
#include <grp.h>
#define _XOPEN_SOURCE 600
-#include "compat/cygwin.h"
#else
#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
#include <grp.h>
@@ -291,6 +295,13 @@ extern char *gitbasename(char *);
#endif
#endif
+/* The sentinel attribute is valid from gcc version 4.0 */
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define LAST_ARG_MUST_BE_NULL __attribute__((sentinel))
+#else
+#define LAST_ARG_MUST_BE_NULL
+#endif
+
#include "compat/bswap.h"
#ifdef USE_WILDMATCH
@@ -314,6 +325,16 @@ extern NORETURN void die_errno(const char *err, ...) __attribute__((format (prin
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
+#ifndef NO_OPENSSL
+#ifdef APPLE_COMMON_CRYPTO
+#include "compat/apple-common-crypto.h"
+#else
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#endif /* APPLE_COMMON_CRYPTO */
+#include <openssl/x509v3.h>
+#endif /* NO_OPENSSL */
+
/*
* Let callers be aware of the constant return value; this can help
* gcc with -Wuninitialized analysis. We restrict this trick to gcc, though,
@@ -498,7 +519,7 @@ int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
-extern void release_pack_memory(size_t, int);
+extern void release_pack_memory(size_t);
typedef void (*try_to_free_t)(size_t);
extern try_to_free_t set_try_to_free_routine(try_to_free_t);
@@ -688,8 +709,9 @@ int remove_or_warn(unsigned int mode, const char *path);
* Call access(2), but warn for any error except "missing file"
* (ENOENT or ENOTDIR).
*/
-int access_or_warn(const char *path, int mode);
-int access_or_die(const char *path, int mode);
+#define ACCESS_EACCES_OK (1U << 0)
+int access_or_warn(const char *path, int mode, unsigned flag);
+int access_or_die(const char *path, int mode, unsigned flag);
/* Warn on an inaccessible file that ought to be accessible */
void warn_on_inaccessible(const char *path);
diff --git a/git-difftool.perl b/git-difftool.perl
index 0a90de4..e57d3d12 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -13,9 +13,9 @@
use 5.008;
use strict;
use warnings;
+use Error qw(:try);
use File::Basename qw(dirname);
use File::Copy;
-use File::Compare;
use File::Find;
use File::stat;
use File::Path qw(mkpath rmtree);
@@ -83,6 +83,54 @@ sub exit_cleanup
exit($status | ($status >> 8));
}
+sub use_wt_file
+{
+ my ($repo, $workdir, $file, $sha1) = @_;
+ my $null_sha1 = '0' x 40;
+
+ if (! -e "$workdir/$file") {
+ # If the file doesn't exist in the working tree, we cannot
+ # use it.
+ return (0, $null_sha1);
+ }
+
+ my $wt_sha1 = $repo->command_oneline('hash-object', "$workdir/$file");
+ my $use = ($sha1 eq $null_sha1) || ($sha1 eq $wt_sha1);
+ return ($use, $wt_sha1);
+}
+
+sub changed_files
+{
+ my ($repo_path, $index, $worktree) = @_;
+ $ENV{GIT_INDEX_FILE} = $index;
+ $ENV{GIT_WORK_TREE} = $worktree;
+ my $must_unset_git_dir = 0;
+ if (not defined($ENV{GIT_DIR})) {
+ $must_unset_git_dir = 1;
+ $ENV{GIT_DIR} = $repo_path;
+ }
+
+ my @refreshargs = qw/update-index --really-refresh -q --unmerged/;
+ my @gitargs = qw/diff-files --name-only -z/;
+ try {
+ Git::command_oneline(@refreshargs);
+ } catch Git::Error::Command with {};
+
+ my $line = Git::command_oneline(@gitargs);
+ my @files;
+ if (defined $line) {
+ @files = split('\0', $line);
+ } else {
+ @files = ();
+ }
+
+ delete($ENV{GIT_INDEX_FILE});
+ delete($ENV{GIT_WORK_TREE});
+ delete($ENV{GIT_DIR}) if ($must_unset_git_dir);
+
+ return map { $_ => 1 } @files;
+}
+
sub setup_dir_diff
{
my ($repo, $workdir, $symlinks) = @_;
@@ -106,6 +154,7 @@ sub setup_dir_diff
my $null_sha1 = '0' x 40;
my $lindex = '';
my $rindex = '';
+ my $wtindex = '';
my %submodule;
my %symlink;
my @working_tree = ();
@@ -159,10 +208,13 @@ EOF
}
if ($rmode ne $null_mode) {
- if ($rsha1 ne $null_sha1) {
- $rindex .= "$rmode $rsha1\t$dst_path\0";
+ my ($use, $wt_sha1) = use_wt_file($repo, $workdir,
+ $dst_path, $rsha1);
+ if ($use) {
+ push @working_tree, $dst_path;
+ $wtindex .= "$rmode $wt_sha1\t$dst_path\0";
} else {
- push(@working_tree, $dst_path);
+ $rindex .= "$rmode $rsha1\t$dst_path\0";
}
}
}
@@ -203,13 +255,21 @@ EOF
$rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/");
exit_cleanup($tmpdir, $rc) if $rc != 0;
+ $ENV{GIT_INDEX_FILE} = "$tmpdir/wtindex";
+ ($inpipe, $ctx) =
+ $repo->command_input_pipe(qw(update-index --info-only -z --index-info));
+ print($inpipe $wtindex);
+ $repo->command_close_pipe($inpipe, $ctx);
+
# If $GIT_DIR was explicitly set just for the update/checkout
# commands, then it should be unset before continuing.
delete($ENV{GIT_DIR}) if ($must_unset_git_dir);
delete($ENV{GIT_INDEX_FILE});
# Changes in the working tree need special treatment since they are
- # not part of the index
+ # not part of the index. Remove any trailing slash from $workdir
+ # before starting to avoid double slashes in symlink targets.
+ $workdir =~ s|/$||;
for my $file (@working_tree) {
my $dir = dirname($file);
unless (-d "$rdir/$dir") {
@@ -336,7 +396,7 @@ sub main
}
if ($opts{gui}) {
my $guitool = Git::config('diff.guitool');
- if (length($guitool) > 0) {
+ if (defined($guitool) && length($guitool) > 0) {
$ENV{GIT_DIFF_TOOL} = $guitool;
}
}
@@ -373,19 +433,34 @@ sub dir_diff
# 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.
+ #
+ # These hashes are loaded lazily since they aren't needed
+ # in the common case of --symlinks and the difftool updating
+ # files through the symlink.
+ my %wt_modified;
+ my %tmp_modified;
+ my $indices_loaded = 0;
+
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";
+ if (!$indices_loaded) {
+ %wt_modified = changed_files($repo->repo_path(),
+ "$tmpdir/wtindex", "$workdir");
+ %tmp_modified = changed_files($repo->repo_path(),
+ "$tmpdir/wtindex", "$b");
+ $indices_loaded = 1;
+ }
+
+ if (exists $wt_modified{$file} and exists $tmp_modified{$file}) {
+ my $errmsg = "warning: Both files modified: ";
+ $errmsg .= "'$workdir/$file' and '$b/$file'.\n";
+ $errmsg .= "warning: Working tree file has been left.\n";
+ $errmsg .= "warning:\n";
warn $errmsg;
$error = 1;
- } elsif ($diff == 1) {
+ } elsif (exists $tmp_modified{$file}) {
my $mode = stat("$b/$file")->mode;
copy("$b/$file", "$workdir/$file") or
exit_cleanup($tmpdir, 1);
diff --git a/git-gui/GIT-VERSION-GEN b/git-gui/GIT-VERSION-GEN
index 49b62ea..0a1f8d4 100755
--- a/git-gui/GIT-VERSION-GEN
+++ b/git-gui/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=0.17.GITGUI
+DEF_VER=0.18.GITGUI
LF='
'
diff --git a/git-gui/Makefile b/git-gui/Makefile
index e22ba5c..e9c2bc3 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -254,7 +254,7 @@ lib/tclIndex: $(ALL_LIBFILES) GIT-GUI-VARS
auto_mkindex lib '*.tcl' \
| $(TCL_PATH) $(QUIET_2DEVNULL); then : ok; \
else \
- echo 1>&2 " * $(TCL_PATH) failed; using unoptimized loading"; \
+ echo >&2 " * $(TCL_PATH) failed; using unoptimized loading"; \
rm -f $@ ; \
echo '# Autogenerated by git-gui Makefile' >$@ && \
echo >>$@ && \
@@ -274,8 +274,8 @@ TRACK_VARS = \
GIT-GUI-VARS: FORCE
@VARS='$(TRACK_VARS)'; \
if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \
- echo 1>&2 " * new locations or Tcl/Tk interpreter"; \
- echo 1>$@ "$$VARS"; \
+ echo >&2 " * new locations or Tcl/Tk interpreter"; \
+ echo >$@ "$$VARS"; \
fi
ifdef GITGUI_MACOSXAPP
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 89f636f..153f85d 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -137,6 +137,20 @@ unset oguimsg
######################################################################
##
+## On Mac, bring the current Wish process window to front
+
+if {[tk windowingsystem] eq "aqua"} {
+ catch {
+ exec osascript -e [format {
+ tell application "System Events"
+ set frontmost of processes whose unix id is %d to true
+ end tell
+ } [pid]]
+ }
+}
+
+######################################################################
+##
## read only globals
set _appname {Git Gui}
@@ -3003,18 +3017,11 @@ blame {
set jump_spec {}
set is_path 0
foreach a $argv {
- if {[file exists $a]} {
- if {$path ne {}} usage
- set path [normalize_relpath $a]
- break
- } elseif {[file exists $_prefix$a]} {
- if {$path ne {}} usage
- set path [normalize_relpath $_prefix$a]
- break
- }
+ set p [file join $_prefix $a]
- if {$is_path} {
+ if {$is_path || [file exists $p]} {
if {$path ne {}} usage
+ set path [normalize_relpath $p]
break
} elseif {$a eq {--}} {
if {$path ne {}} {
diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl
index 657f7d5..ee58981 100644
--- a/git-gui/lib/choose_repository.tcl
+++ b/git-gui/lib/choose_repository.tcl
@@ -286,7 +286,9 @@ method _next {action} {
destroy $w_body
if {![winfo exists $w_next]} {
${NS}::button $w_next -default active
- pack $w_next -side right -padx 5 -before $w_quit
+ set pos -before
+ if {[tk windowingsystem] eq "win32"} { set pos -after }
+ pack $w_next -side right -padx 5 $pos $w_quit
}
_do_$action $this
}
diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl
index ec44055..30d9a79 100644
--- a/git-gui/lib/diff.tcl
+++ b/git-gui/lib/diff.tcl
@@ -764,8 +764,15 @@ proc apply_range_or_line {x y} {
# context line
set ln [$ui_diff get $i_l $next_l]
set patch "$patch$pre_context$ln"
- set n [expr $n+1]
- set m [expr $m+1]
+ # Skip the "\ No newline at end of
+ # file". Depending on the locale setting
+ # we don't know what this line looks
+ # like exactly. The only thing we do
+ # know is that it starts with "\ "
+ if {![string match {\\ *} $ln]} {
+ set n [expr $n+1]
+ set m [expr $m+1]
+ }
set pre_context {}
} elseif {$c1 eq $to_context} {
# turn change line into context line
diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl
index 3c8e73b..120bc40 100644
--- a/git-gui/lib/mergetool.tcl
+++ b/git-gui/lib/mergetool.tcl
@@ -189,9 +189,9 @@ proc merge_resolve_tool2 {} {
}
bc3 {
if {$base_stage ne {}} {
- set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" -mergeoutput="$MERGED"]
+ set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" "-mergeoutput=$MERGED"]
} else {
- set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -mergeoutput="$MERGED"]
+ set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" "-mergeoutput=$MERGED"]
}
}
ecmerge {
diff --git a/git-gui/lib/remote.tcl b/git-gui/lib/remote.tcl
index 5e4e7f4..4e5c784 100644
--- a/git-gui/lib/remote.tcl
+++ b/git-gui/lib/remote.tcl
@@ -245,7 +245,8 @@ proc update_all_remotes_menu_entry {} {
set prune_m $remote_m.prune
if {$have_remote > 1} {
make_sure_remote_submenues_exist $remote_m
- if {[$fetch_m entrycget end -label] ne "All"} {
+ if {[$fetch_m type end] eq "command" \
+ && [$fetch_m entrycget end -label] ne "All"} {
$fetch_m insert end separator
$fetch_m insert end command \
@@ -259,7 +260,8 @@ proc update_all_remotes_menu_entry {} {
}
} else {
if {[winfo exists $fetch_m]} {
- if {[$fetch_m entrycget end -label] eq "All"} {
+ if {[$fetch_m type end] eq "command" \
+ && [$fetch_m entrycget end -label] eq "All"} {
delete_from_menu $fetch_m end
delete_from_menu $fetch_m end
diff --git a/git-gui/po/fr.po b/git-gui/po/fr.po
index 40441db..0aff186 100644
--- a/git-gui/po/fr.po
+++ b/git-gui/po/fr.po
@@ -1139,7 +1139,7 @@ msgstr "Standard (rapide, semi-redondant, liens durs)"
#: lib/choose_repository.tcl:514
msgid "Full Copy (Slower, Redundant Backup)"
-msgstr "Copy complète (plus lent, sauvegarde redondante)"
+msgstr "Copie complète (plus lent, sauvegarde redondante)"
#: lib/choose_repository.tcl:520
msgid "Shared (Fastest, Not Recommended, No Backup)"
diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh
index 3373c04..07dfeb8 100755
--- a/git-merge-one-file.sh
+++ b/git-merge-one-file.sh
@@ -27,7 +27,7 @@ SUBDIRECTORY_OK=Yes
cd_to_toplevel
require_work_tree
-if ! test "$#" -eq 7
+if test $# != 7
then
echo "$LONG_USAGE"
exit 1
@@ -38,7 +38,8 @@ case "${1:-.}${2:-.}${3:-.}" in
# Deleted in both or deleted in one and unchanged in the other
#
"$1.." | "$1.$1" | "$1$1.")
- if [ "$2" ]; then
+ if test -n "$2"
+ then
echo "Removing $4"
else
# read-tree checked that index matches HEAD already,
@@ -48,7 +49,8 @@ case "${1:-.}${2:-.}${3:-.}" in
# we do not have it in the index, though.
exec git update-index --remove -- "$4"
fi
- if test -f "$4"; then
+ if test -f "$4"
+ then
rm -f -- "$4" &&
rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || :
fi &&
@@ -67,7 +69,7 @@ case "${1:-.}${2:-.}${3:-.}" in
echo "Adding $4"
if test -f "$4"
then
- echo "ERROR: untracked $4 is overwritten by the merge."
+ echo "ERROR: untracked $4 is overwritten by the merge." >&2
exit 1
fi
git update-index --add --cacheinfo "$7" "$3" "$4" &&
@@ -78,9 +80,10 @@ case "${1:-.}${2:-.}${3:-.}" in
# Added in both, identically (check for same permissions).
#
".$3$2")
- if [ "$6" != "$7" ]; then
- echo "ERROR: File $4 added identically in both branches,"
- echo "ERROR: but permissions conflict $6->$7."
+ if test "$6" != "$7"
+ then
+ echo "ERROR: File $4 added identically in both branches," >&2
+ echo "ERROR: but permissions conflict $6->$7." >&2
exit 1
fi
echo "Adding $4"
@@ -95,44 +98,36 @@ case "${1:-.}${2:-.}${3:-.}" in
case ",$6,$7," in
*,120000,*)
- echo "ERROR: $4: Not merging symbolic link changes."
+ echo "ERROR: $4: Not merging symbolic link changes." >&2
exit 1
;;
*,160000,*)
- echo "ERROR: $4: Not merging conflicting submodule changes."
+ echo "ERROR: $4: Not merging conflicting submodule changes." >&2
exit 1
;;
esac
- src2=`git-unpack-file $3`
+ src1=$(git-unpack-file $2)
+ src2=$(git-unpack-file $3)
case "$1" in
'')
echo "Added $4 in both, but differently."
- # This extracts OUR file in $orig, and uses git apply to
- # remove lines that are unique to ours.
- orig=`git-unpack-file $2`
- sz0=`wc -c <"$orig"`
- @@DIFF@@ -u -La/$orig -Lb/$orig $orig $src2 | git apply --no-add
- sz1=`wc -c <"$orig"`
-
- # If we do not have enough common material, it is not
- # worth trying two-file merge using common subsections.
- expr $sz0 \< $sz1 \* 2 >/dev/null || : >$orig
+ orig=$(git-unpack-file $2)
+ create_virtual_base "$orig" "$src2"
;;
*)
echo "Auto-merging $4"
- orig=`git-unpack-file $1`
+ orig=$(git-unpack-file $1)
;;
esac
- # Be careful for funny filename such as "-L" in "$4", which
- # would confuse "merge" greatly.
- src1=`git-unpack-file $2`
git merge-file "$src1" "$orig" "$src2"
ret=$?
msg=
- if [ $ret -ne 0 ]; then
+ if test $ret != 0 || test -z "$1"
+ then
msg='content conflict'
+ ret=1
fi
# Create the working tree file, using "our tree" version from the
@@ -140,26 +135,26 @@ case "${1:-.}${2:-.}${3:-.}" in
git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1
rm -f -- "$orig" "$src1" "$src2"
- if [ "$6" != "$7" ]; then
- if [ -n "$msg" ]; then
+ if test "$6" != "$7"
+ then
+ if test -n "$msg"
+ then
msg="$msg, "
fi
msg="${msg}permissions conflict: $5->$6,$7"
ret=1
fi
- if [ "$1" = '' ]; then
- ret=1
- fi
- if [ $ret -ne 0 ]; then
- echo "ERROR: $msg in $4"
+ if test $ret != 0
+ then
+ echo "ERROR: $msg in $4" >&2
exit 1
fi
exec git update-index -- "$4"
;;
*)
- echo "ERROR: $4: Not handling case $1 -> $2 -> $3"
+ echo "ERROR: $4: Not handling case $1 -> $2 -> $3" >&2
;;
esac
exit 1
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index e338be5..feee6a4 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -114,10 +114,37 @@ valid_tool () {
test -n "$cmd"
}
+setup_user_tool () {
+ merge_tool_cmd=$(get_merge_tool_cmd "$tool")
+ test -n "$merge_tool_cmd" || return 1
+
+ diff_cmd () {
+ ( eval $merge_tool_cmd )
+ status=$?
+ return $status
+ }
+
+ merge_cmd () {
+ 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
+ }
+}
+
setup_tool () {
tool="$1"
- # Fallback definitions, to be overriden by tools.
+ # Fallback definitions, to be overridden by tools.
can_merge () {
return 0
}
@@ -142,15 +169,15 @@ setup_tool () {
if ! test -f "$MERGE_TOOLS_DIR/$tool"
then
- # Use a special return code for this case since we want to
- # source "defaults" even when an explicit tool path is
- # configured since the user can use that to override the
- # default path in the scriptlet.
- return 2
+ setup_user_tool
+ return $?
fi
# Load the redefined functions
. "$MERGE_TOOLS_DIR/$tool"
+ # Now let the user override the default command for the tool. If
+ # they have not done so then this will return 1 which we ignore.
+ setup_user_tool
if merge_mode && ! can_merge
then
@@ -187,20 +214,7 @@ run_merge_tool () {
status=0
# Bring tool-specific functions into scope
- setup_tool "$1"
- exitcode=$?
- case $exitcode in
- 0)
- :
- ;;
- 2)
- # The configured tool is not a built-in tool.
- test -n "$merge_tool_path" || return 1
- ;;
- *)
- return $exitcode
- ;;
- esac
+ setup_tool "$1" || return 1
if merge_mode
then
@@ -213,38 +227,12 @@ run_merge_tool () {
# 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
+ diff_cmd "$1"
}
# 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
+ merge_cmd "$1"
}
list_merge_tool_candidates () {
diff --git a/git-p4.py b/git-p4.py
index 647f110..a53a6dc 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -79,12 +79,27 @@ def p4_build_cmd(cmd):
real_cmd += cmd
return real_cmd
-def chdir(dir):
- # P4 uses the PWD environment variable rather than getcwd(). Since we're
- # not using the shell, we have to set it ourselves. This path could
- # be relative, so go there first, then figure out where we ended up.
- os.chdir(dir)
- os.environ['PWD'] = os.getcwd()
+def chdir(path, is_client_path=False):
+ """Do chdir to the given path, and set the PWD environment
+ variable for use by P4. It does not look at getcwd() output.
+ Since we're not using the shell, it is necessary to set the
+ PWD environment variable explicitly.
+
+ Normally, expand the path to force it to be absolute. This
+ addresses the use of relative path names inside P4 settings,
+ e.g. P4CONFIG=.p4config. P4 does not simply open the filename
+ as given; it looks for .p4config using PWD.
+
+ If is_client_path, the path was handed to us directly by p4,
+ and may be a symbolic link. Do not call os.getcwd() in this
+ case, because it will cause p4 to think that PWD is not inside
+ the client path.
+ """
+
+ os.chdir(path)
+ if not is_client_path:
+ path = os.getcwd()
+ os.environ['PWD'] = path
def die(msg):
if verbose:
@@ -1624,7 +1639,7 @@ class P4Submit(Command, P4UserMap):
new_client_dir = True
os.makedirs(self.clientPath)
- chdir(self.clientPath)
+ chdir(self.clientPath, is_client_path=True)
if self.dry_run:
print "Would synchronize p4 checkout in %s" % self.clientPath
else:
@@ -1771,7 +1786,7 @@ class P4Submit(Command, P4UserMap):
missingGitTags = gitTags - p4Labels
self.exportGitTags(missingGitTags)
- # exit with error unless everything applied perfecly
+ # exit with error unless everything applied perfectly
if len(commits) != len(applied):
sys.exit(1)
@@ -2165,9 +2180,13 @@ class P4Sync(Command, P4UserMap):
git_mode = "100755"
if type_base == "symlink":
git_mode = "120000"
- # p4 print on a symlink contains "target\n"; remove the newline
+ # p4 print on a symlink sometimes contains "target\n";
+ # if it does, remove the newline
data = ''.join(contents)
- contents = [data[:-1]]
+ if data[-1] == '\n':
+ contents = [data[:-1]]
+ else:
+ contents = [data]
if type_base == "utf16":
# p4 delivers different text in the python output to -G
@@ -3153,7 +3172,7 @@ class P4Rebase(Command):
if os.system("git update-index --refresh") != 0:
die("Some files in your working directory are modified and different than what is in your index. You can use git update-index <filename> to bring the index up-to-date or stash away all your changes with git stash.");
if len(read_pipe("git diff-index HEAD --")) > 0:
- die("You have uncommited changes. Please commit them before rebasing or stash them away with git stash.");
+ die("You have uncommitted changes. Please commit them before rebasing or stash them away with git stash.");
[upstream, settings] = findUpstreamBranchPoint()
if len(upstream) == 0:
diff --git a/git-pull.sh b/git-pull.sh
index 5d97e97..e11d9a0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -4,8 +4,8 @@
#
# Fetch one or more remote refs and merge it/them into the current HEAD.
-USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s strategy]... [<fetch-options>] <repo> <head>...'
-LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEAD.'
+USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [--[no-]rebase|--rebase=preserve] [-s strategy]... [<fetch-options>] <repo> <head>...'
+LONG_USAGE='Fetch one or more remote refs and integrate it/them with the current HEAD.'
SUBDIRECTORY_OK=Yes
OPTIONS_SPEC=
. git-sh-setup
@@ -38,15 +38,19 @@ Please, commit your changes before you can merge.")"
test -z "$(git ls-files -u)" || die_conflict
test -f "$GIT_DIR/MERGE_HEAD" && die_merge
+bool_or_string_config () {
+ git config --bool "$1" 2>/dev/null || git config "$1"
+}
+
strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
-log_arg= verbosity= progress= recurse_submodules=
-merge_args= edit=
+log_arg= verbosity= progress= recurse_submodules= verify_signatures=
+merge_args= edit= rebase_args=
curr_branch=$(git symbolic-ref -q HEAD)
curr_branch_short="${curr_branch#refs/heads/}"
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+rebase=$(bool_or_string_config branch.$curr_branch_short.rebase)
if test -z "$rebase"
then
- rebase=$(git config --bool pull.rebase)
+ rebase=$(bool_or_string_config pull.rebase)
fi
dry_run=
while :
@@ -110,6 +114,9 @@ do
esac
merge_args="$merge_args$xx "
;;
+ -r=*|--r=*|--re=*|--reb=*|--reba=*|--rebas=*|--rebase=*)
+ rebase="${1#*=}"
+ ;;
-r|--r|--re|--reb|--reba|--rebas|--rebase)
rebase=true
;;
@@ -125,6 +132,12 @@ do
--no-recurse-submodules)
recurse_submodules=--no-recurse-submodules
;;
+ --verify-signatures)
+ verify_signatures=--verify-signatures
+ ;;
+ --no-verify-signatures)
+ verify_signatures=--no-verify-signatures
+ ;;
--d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)
dry_run=--dry-run
;;
@@ -139,6 +152,20 @@ do
shift
done
+case "$rebase" in
+preserve)
+ rebase=true
+ rebase_args=--preserve-merges
+ ;;
+true|false|'')
+ ;;
+*)
+ echo "Invalid value for --rebase, should be true, false, or preserve"
+ usage
+ exit 1
+ ;;
+esac
+
error_on_no_merge_candidates () {
exec >&2
for opt
@@ -260,10 +287,17 @@ case "$merge_head" in
;;
esac
+# Pulling into unborn branch: a shorthand for branching off
+# FETCH_HEAD, for lazy typers.
if test -z "$orig_head"
then
- git update-ref -m "initial pull" HEAD $merge_head "$curr_head" &&
- git read-tree -m -u HEAD || exit 1
+ # Two-way merge: we claim the index is based on an empty tree,
+ # and try to fast-forward to HEAD. This ensures we will not
+ # lose index/worktree changes that the user already made on
+ # the unborn branch.
+ empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+ git read-tree -m -u $empty_tree $merge_head &&
+ git update-ref -m "initial pull" HEAD $merge_head "$curr_head"
exit
fi
@@ -279,11 +313,11 @@ fi
merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
case "$rebase" in
true)
- eval="git-rebase $diffstat $strategy_args $merge_args $verbosity"
+ eval="git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity"
eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
;;
*)
- eval="git-merge $diffstat $no_commit $edit $squash $no_ff $ff_only"
+ eval="git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only"
eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress"
eval="$eval \"\$merge_name\" HEAD $merge_head"
;;
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index 97f31dc..34e3102 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -7,12 +7,12 @@ case "$action" in
continue)
git am --resolved --resolvemsg="$resolvemsg" &&
move_to_original_branch
- exit
+ return
;;
skip)
git am --skip --resolvemsg="$resolvemsg" &&
move_to_original_branch
- exit
+ return
;;
esac
@@ -31,8 +31,8 @@ else
rm -f "$GIT_DIR/rebased-patches"
git format-patch -k --stdout --full-index --ignore-if-in-upstream \
- --src-prefix=a/ --dst-prefix=b/ \
- --no-renames $root_flag "$revisions" >"$GIT_DIR/rebased-patches"
+ --src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \
+ $root_flag "$revisions" >"$GIT_DIR/rebased-patches"
ret=$?
if test 0 != $ret
@@ -56,7 +56,7 @@ else
As a result, git cannot rebase them.
EOF
- exit $?
+ return $?
fi
git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" <"$GIT_DIR/rebased-patches"
@@ -68,7 +68,7 @@ fi
if test 0 != $ret
then
test -d "$state_dir" && write_basic_state
- exit $ret
+ return $ret
fi
move_to_original_branch
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 048a140..10bf318 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -57,6 +57,9 @@ rewritten="$state_dir"/rewritten
dropped="$state_dir"/dropped
+end="$state_dir"/end
+msgnum="$state_dir"/msgnum
+
# A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
# GIT_AUTHOR_DATE that will be used for the commit that is currently
# being rebased.
@@ -77,6 +80,18 @@ amend="$state_dir"/amend
rewritten_list="$state_dir"/rewritten-list
rewritten_pending="$state_dir"/rewritten-pending
+strategy_args=
+if test -n "$do_merge"
+then
+ strategy_args=${strategy:+--strategy=$strategy}
+ eval '
+ for strategy_opt in '"$strategy_opts"'
+ do
+ strategy_args="$strategy_args -X$(git rev-parse --sq-quote "${strategy_opt#--}")"
+ done
+ '
+fi
+
GIT_CHERRY_PICK_HELP="$resolvemsg"
export GIT_CHERRY_PICK_HELP
@@ -109,7 +124,9 @@ mark_action_done () {
sed -e 1d < "$todo" >> "$todo".new
mv -f "$todo".new "$todo"
new_count=$(git stripspace --strip-comments <"$done" | wc -l)
+ echo $new_count >"$msgnum"
total=$(($new_count + $(git stripspace --strip-comments <"$todo" | wc -l)))
+ echo $total >"$end"
if test "$last_count" != "$new_count"
then
last_count=$new_count
@@ -234,7 +251,7 @@ pick_one () {
test -d "$rewritten" &&
pick_one_preserving_merges "$@" && return
- output git cherry-pick $empty_args $ff "$@"
+ output eval git cherry-pick "$strategy_args" $empty_args $ff "$@"
}
pick_one_preserving_merges () {
@@ -335,9 +352,9 @@ pick_one_preserving_merges () {
msg_content="$(commit_message $sha1)"
# No point in merging the first parent, that's HEAD
new_parents=${new_parents# $first_parent}
- if ! do_with_author output \
- git merge --no-ff ${strategy:+-s $strategy} -m \
- "$msg_content" $new_parents
+ merge_args="--no-log --no-ff"
+ if ! do_with_author output eval \
+ 'git merge $merge_args $strategy_args -m "$msg_content" $new_parents'
then
printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
die_with_patch $sha1 "Error redoing merge $sha1"
@@ -345,7 +362,7 @@ pick_one_preserving_merges () {
echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list"
;;
*)
- output git cherry-pick "$@" ||
+ output eval git cherry-pick "$strategy_args" "$@" ||
die_with_patch $sha1 "Could not pick $sha1"
;;
esac
@@ -623,17 +640,16 @@ do_next () {
"$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list"
true # we don't care if this hook failed
fi &&
- rm -rf "$state_dir" &&
- git gc --auto &&
warn "Successfully rebased and updated $head_name."
- exit
+ return 1 # not failure; just to break the do_rest loop
}
+# can only return 0, when the infinite loop breaks
do_rest () {
while :
do
- do_next
+ do_next || break
done
}
@@ -656,7 +672,7 @@ skip_unnecessary_picks () {
;;
esac
;;
- 3,#*|3,)
+ 3,"$comment_char"*|3,)
# copy comments
;;
*)
@@ -674,6 +690,32 @@ skip_unnecessary_picks () {
die "Could not skip unnecessary pick commands"
}
+transform_todo_ids () {
+ while read -r command rest
+ do
+ case "$command" in
+ "$comment_char"* | exec)
+ # Be careful for oddball commands like 'exec'
+ # that do not have a SHA-1 at the beginning of $rest.
+ ;;
+ *)
+ sha1=$(git rev-parse --verify --quiet "$@" ${rest%% *}) &&
+ rest="$sha1 ${rest#* }"
+ ;;
+ esac
+ printf '%s\n' "$command${rest:+ }$rest"
+ done <"$todo" >"$todo.new" &&
+ mv -f "$todo.new" "$todo"
+}
+
+expand_todo_ids() {
+ transform_todo_ids
+}
+
+collapse_todo_ids() {
+ transform_todo_ids --short=7
+}
+
# Rearrange the todo list that has both "pick sha1 msg" and
# "pick sha1 fixup!/squash! msg" appears in it so that the latter
# comes immediately after the former, and change "pick" to
@@ -685,8 +727,22 @@ rearrange_squash () {
case "$message" in
"squash! "*|"fixup! "*)
action="${message%%!*}"
- rest="${message#*! }"
- echo "$sha1 $action $rest"
+ rest=$message
+ prefix=
+ # skip all squash! or fixup! (but save for later)
+ while :
+ do
+ case "$rest" in
+ "squash! "*|"fixup! "*)
+ prefix="$prefix${rest%%!*},"
+ rest="${rest#*! }"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ done
+ echo "$sha1 $action $prefix $rest"
# if it's a single word, try to resolve to a full sha1 and
# emit a second copy. This allows us to match on both message
# and on sha1 prefix
@@ -695,7 +751,7 @@ rearrange_squash () {
if test -n "$fullsha"; then
# prefix the action to uniquely identify this line as
# intended for full sha1 match
- echo "$sha1 +$action $fullsha"
+ echo "$sha1 +$action $prefix $fullsha"
fi
fi
esac
@@ -710,7 +766,7 @@ rearrange_squash () {
esac
printf '%s\n' "$pick $sha1 $message"
used="$used$sha1 "
- while read -r squash action msg_content
+ while read -r squash action msg_prefix msg_content
do
case " $used" in
*" $squash "*) continue ;;
@@ -726,7 +782,8 @@ rearrange_squash () {
case "$message" in "$msg_content"*) emit=1;; esac ;;
esac
if test $emit = 1; then
- printf '%s\n' "$action $squash $action! $msg_content"
+ real_prefix=$(echo "$msg_prefix" | sed "s/,/! /g")
+ printf '%s\n' "$action $squash ${real_prefix}$msg_content"
used="$used$squash "
fi
done <"$1.sq"
@@ -800,15 +857,18 @@ first and then run 'git rebase --continue' again."
require_clean_work_tree "rebase"
do_rest
+ return 0
;;
skip)
git rerere clear
do_rest
+ return 0
;;
edit-todo)
git stripspace --strip-comments <"$todo" >"$todo".new
mv -f "$todo".new "$todo"
+ collapse_todo_ids
append_todo_help
git stripspace --comment-lines >>"$todo" <<\EOF
@@ -820,6 +880,7 @@ EOF
git_sequence_editor "$todo" ||
die "Could not execute editor"
+ expand_todo_ids
exit
;;
@@ -832,12 +893,15 @@ comment_for_reflog start
if test ! -z "$switch_to"
then
+ GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to"
output git checkout "$switch_to" -- ||
- die "Could not checkout $switch_to"
+ die "Could not checkout $switch_to"
+
+ comment_for_reflog start
fi
orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?"
-mkdir "$state_dir" || die "Could not create temporary $state_dir"
+mkdir -p "$state_dir" || die "Could not create temporary $state_dir"
: > "$state_dir"/interactive || die "Could not mark as interactive"
write_basic_state
@@ -973,8 +1037,11 @@ git_sequence_editor "$todo" ||
has_action "$todo" ||
die_abort "Nothing to do"
+expand_todo_ids
+
test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
+GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
output git checkout $onto || die_abort "could not detach HEAD"
git update-ref ORIG_HEAD $orig_head
do_rest
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index b10f2cf..16d1817 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -96,7 +96,6 @@ finish_rb_merge () {
"$GIT_DIR"/hooks/post-rewrite rebase <"$state_dir"/rewritten
fi
fi
- rm -r "$state_dir"
say All done.
}
@@ -110,7 +109,7 @@ continue)
continue_merge
done
finish_rb_merge
- exit
+ return
;;
skip)
read_state
@@ -122,7 +121,7 @@ skip)
continue_merge
done
finish_rb_merge
- exit
+ return
;;
esac
diff --git a/git-rebase.sh b/git-rebase.sh
index b2f1c76..8d7659a 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -13,6 +13,7 @@ git-rebase --continue | --abort | --skip | --edit-todo
Available options are
v,verbose! display a diffstat of what changed upstream
q,quiet! be quiet. implies --no-stat
+autostash! automatically stash/stash pop before and after
onto=! rebase onto given branch instead of upstream
p,preserve-merges! try to recreate merges instead of ignoring them
s,strategy=! use the given merge strategy
@@ -64,6 +65,7 @@ apply_dir="$GIT_DIR"/rebase-apply
verbose=
diffstat=
test "$(git config --bool rebase.stat)" = true && diffstat=t
+autostash="$(git config --bool rebase.autostash || echo false)"
git_am_opt=
rebase_root=
force_rebase=
@@ -82,6 +84,8 @@ keep_empty=
test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
read_basic_state () {
+ test -f "$state_dir/head-name" &&
+ test -f "$state_dir/onto" &&
head_name=$(cat "$state_dir"/head-name) &&
onto=$(cat "$state_dir"/onto) &&
# We always write to orig-head, but interactive rebase used to write to
@@ -143,6 +147,26 @@ move_to_original_branch () {
esac
}
+finish_rebase () {
+ if test -f "$state_dir/autostash"
+ then
+ stash_sha1=$(cat "$state_dir/autostash")
+ if git stash apply $stash_sha1 2>&1 >/dev/null
+ then
+ echo "$(gettext 'Applied autostash.')"
+ else
+ git stash store -m "autostash" -q $stash_sha1 ||
+ die "$(eval_gettext "Cannot store \$stash_sha1")"
+ gettext 'Applying autostash resulted in conflicts.
+Your changes are safe in the stash.
+You can run "git stash pop" or "git stash drop" at any time.
+'
+ fi
+ fi
+ git gc --auto &&
+ rm -rf "$state_dir"
+}
+
run_specific_rebase () {
if [ "$interactive_rebase" = implied ]; then
GIT_EDITOR=:
@@ -150,6 +174,12 @@ run_specific_rebase () {
autosquash=
fi
. git-rebase--$type
+ ret=$?
+ if test $ret -eq 0
+ then
+ finish_rebase
+ fi
+ exit $ret
}
run_pre_rebase_hook () {
@@ -241,6 +271,9 @@ do
--stat)
diffstat=t
;;
+ --autostash)
+ autostash=true
+ ;;
-v)
verbose=t
diffstat=t
@@ -341,7 +374,7 @@ abort)
;;
esac
output git reset --hard $orig_head
- rm -r "$state_dir"
+ finish_rebase
exit
;;
edit-todo)
@@ -400,7 +433,7 @@ then
shift
;;
esac
- upstream=`git rev-parse --verify "${upstream_name}^0"` ||
+ upstream=$(peel_committish "${upstream_name}") ||
die "$(eval_gettext "invalid upstream \$upstream_name")"
upstream_arg="$upstream_name"
else
@@ -436,7 +469,7 @@ case "$onto_name" in
fi
;;
*)
- onto=$(git rev-parse --verify "${onto_name}^0") ||
+ onto=$(peel_committish "$onto_name") ||
die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
;;
esac
@@ -473,13 +506,25 @@ case "$#" in
head_name="detached HEAD"
branch_name=HEAD ;# detached
fi
- orig_head=$(git rev-parse --verify "${branch_name}^0") || exit
+ orig_head=$(git rev-parse --verify HEAD) || exit
;;
*)
die "BUG: unexpected number of arguments left to parse"
;;
esac
+if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
+then
+ stash_sha1=$(git stash create "autostash") ||
+ die "$(gettext 'Cannot autostash')"
+
+ mkdir -p "$state_dir" &&
+ echo $stash_sha1 >"$state_dir/autostash" &&
+ stash_abbrev=$(git rev-parse --short $stash_sha1) &&
+ echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
+ git reset --hard
+fi
+
require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
# Now we are rebasing commits $upstream..$orig_head (or with --root,
@@ -497,8 +542,11 @@ then
if test -z "$force_rebase"
then
# Lazily switch to the target branch if needed...
- test -z "$switch_to" || git checkout "$switch_to" --
+ test -z "$switch_to" ||
+ GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
+ git checkout "$switch_to" --
say "$(eval_gettext "Current branch \$branch_name is up to date.")"
+ finish_rebase
exit 0
else
say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
@@ -522,7 +570,9 @@ test "$type" = interactive && run_specific_rebase
# Detach HEAD and reset the tree
say "$(gettext "First, rewinding head to replay your work on top of it...")"
-git checkout -q "$onto^0" || die "could not detach HEAD"
+
+GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
+ git checkout -q "$onto^0" || die "could not detach HEAD"
git update-ref ORIG_HEAD $orig_head
# If the $onto is a proper descendant of the tip of the branch, then
@@ -531,6 +581,7 @@ if test "$mb" = "$orig_head"
then
say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
move_to_original_branch
+ finish_rebase
exit 0
fi
diff --git a/git-remote-testgit b/git-remote-testgit.sh
index b395c8d..6d2f282 100755
--- a/git-remote-testgit
+++ b/git-remote-testgit.sh
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/bin/sh
# Copyright (c) 2012 Felipe Contreras
alias=$1
@@ -23,7 +23,6 @@ then
testgitmarks="$dir/testgit.marks"
test -e "$gitmarks" || >"$gitmarks"
test -e "$testgitmarks" || >"$testgitmarks"
- testgitmarks_args=( "--"{import,export}"-marks=$testgitmarks" )
fi
while read line
@@ -38,6 +37,8 @@ do
echo "*import-marks $gitmarks"
echo "*export-marks $gitmarks"
fi
+ test -n "$GIT_REMOTE_TESTGIT_SIGNED_TAGS" && echo "signed-tags"
+ test -n "$GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE" && echo "no-private-update"
echo
;;
list)
@@ -61,24 +62,55 @@ do
echo "feature import-marks=$gitmarks"
echo "feature export-marks=$gitmarks"
fi
+
+ if test -n "$GIT_REMOTE_TESTGIT_FAILURE"
+ then
+ echo "feature done"
+ exit 1
+ fi
+
echo "feature done"
- git fast-export "${testgitmarks_args[@]}" $refs |
+ git fast-export \
+ ${testgitmarks:+"--import-marks=$testgitmarks"} \
+ ${testgitmarks:+"--export-marks=$testgitmarks"} \
+ $refs |
sed -e "s#refs/heads/#${prefix}/heads/#g"
echo "done"
;;
export)
- before=$(git for-each-ref --format='%(refname) %(objectname)')
+ if test -n "$GIT_REMOTE_TESTGIT_FAILURE"
+ then
+ # consume input so fast-export doesn't get SIGPIPE;
+ # git would also notice that case, but we want
+ # to make sure we are exercising the later
+ # error checks
+ while read line; do
+ test "done" = "$line" && break
+ done
+ exit 1
+ fi
- git fast-import "${testgitmarks_args[@]}" --quiet
+ before=$(git for-each-ref --format=' %(refname) %(objectname) ')
- after=$(git for-each-ref --format='%(refname) %(objectname)')
+ git fast-import \
+ ${testgitmarks:+"--import-marks=$testgitmarks"} \
+ ${testgitmarks:+"--export-marks=$testgitmarks"} \
+ --quiet
# figure out which refs were updated
- join -e 0 -o '0 1.2 2.2' -a 2 <(echo "$before") <(echo "$after") |
- while read ref a b
+ git for-each-ref --format='%(refname) %(objectname)' |
+ while read ref a
do
- test $a == $b && continue
- echo "ok $ref"
+ case "$before" in
+ *" $ref $a "*)
+ continue ;; # unchanged
+ esac
+ if test -z "$GIT_REMOTE_TESTGIT_PUSH_ERROR"
+ then
+ echo "ok $ref"
+ else
+ echo "error $ref $GIT_REMOTE_TESTGIT_PUSH_ERROR"
+ fi
done
echo
diff --git a/git-request-pull.sh b/git-request-pull.sh
index d566015..ebf1269 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -51,8 +51,18 @@ fi
tag_name=$(git describe --exact "$head^0" 2>/dev/null)
test -n "$base" && test -n "$url" || usage
-baserev=$(git rev-parse --verify "$base"^0) &&
-headrev=$(git rev-parse --verify "$head"^0) || exit
+
+baserev=$(git rev-parse --verify --quiet "$base"^0)
+if test -z "$baserev"
+then
+ die "fatal: Not a valid revision: $base"
+fi
+
+headrev=$(git rev-parse --verify --quiet "$head"^0)
+if test -z "$headrev"
+then
+ die "fatal: Not a valid revision: $head"
+fi
merge_base=$(git merge-base $baserev $headrev) ||
die "fatal: No commits in common between $base and $head"
diff --git a/git-send-email.perl b/git-send-email.perl
index 70cad15..2162478 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -54,7 +54,7 @@ git send-email [options] <file | directory | rev-list options >
--[no-]bcc <str> * Email Bcc:
--subject <str> * Email "Subject:"
--in-reply-to <str> * Email "In-Reply-To:"
- --annotate * Review each patch that will be sent in an editor.
+ --[no-]annotate * Review each patch that will be sent in an editor.
--compose * Open an editor for introduction.
--compose-encoding <str> * Encoding to assume for introduction.
--8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
@@ -69,6 +69,9 @@ git send-email [options] <file | directory | rev-list options >
--smtp-pass <str> * Password for SMTP-AUTH; not necessary.
--smtp-encryption <str> * tls or ssl; anything else disables.
--smtp-ssl * Deprecated. Use '--smtp-encryption ssl'.
+ --smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file).
+ Pass an empty string to disable certificate
+ verification.
--smtp-domain <str> * The domain name sent to HELO/EHLO handshake
--smtp-debug <0|1> * Disable, enable Net::SMTP debug.
@@ -194,7 +197,7 @@ sub do_edit {
my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc);
my ($to_cmd, $cc_cmd);
my ($smtp_server, $smtp_server_port, @smtp_server_options);
-my ($smtp_authuser, $smtp_encryption);
+my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
my ($identity, $aliasfiletype, @alias_files, $smtp_domain);
my ($validate, $confirm);
my (@suppress_cc);
@@ -203,16 +206,15 @@ my ($compose_encoding);
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
-my $not_set_by_user = "true but not set by the user";
-
my %config_bool_settings = (
"thread" => [\$thread, 1],
- "chainreplyto" => [\$chain_reply_to, $not_set_by_user],
+ "chainreplyto" => [\$chain_reply_to, 0],
"suppressfrom" => [\$suppress_from, undef],
"signedoffbycc" => [\$signed_off_by_cc, undef],
"signedoffcc" => [\$signed_off_by_cc, undef], # Deprecated
"validate" => [\$validate, 1],
- "multiedit" => [\$multiedit, undef]
+ "multiedit" => [\$multiedit, undef],
+ "annotate" => [\$annotate, undef]
);
my %config_settings = (
@@ -221,6 +223,7 @@ my %config_settings = (
"smtpserveroption" => \@smtp_server_options,
"smtpuser" => \$smtp_authuser,
"smtppass" => \$smtp_authpass,
+ "smtpsslcertpath" => \$smtp_ssl_cert_path,
"smtpdomain" => \$smtp_domain,
"to" => \@initial_to,
"tocmd" => \$to_cmd,
@@ -240,19 +243,6 @@ my %config_path_settings = (
"aliasesfile" => \@alias_files,
);
-# Help users prepare for 1.7.0
-sub chain_reply_to {
- if (defined $chain_reply_to &&
- $chain_reply_to eq $not_set_by_user) {
- print STDERR
- "In git 1.7.0, the default has changed to --no-chain-reply-to\n" .
- "Set sendemail.chainreplyto configuration variable to true if\n" .
- "you want to keep --chain-reply-to as your default.\n";
- $chain_reply_to = 0;
- }
- return $chain_reply_to;
-}
-
# Handle Uncouth Termination
sub signal_handler {
@@ -301,10 +291,11 @@ my $rc = GetOptions("h" => \$help,
"smtp-pass:s" => \$smtp_authpass,
"smtp-ssl" => sub { $smtp_encryption = 'ssl' },
"smtp-encryption=s" => \$smtp_encryption,
+ "smtp-ssl-cert-path" => \$smtp_ssl_cert_path,
"smtp-debug:i" => \$debug_net_smtp,
"smtp-domain:s" => \$smtp_domain,
"identity=s" => \$identity,
- "annotate" => \$annotate,
+ "annotate!" => \$annotate,
"compose" => \$compose,
"quiet" => \$quiet,
"cc-cmd=s" => \$cc_cmd,
@@ -759,6 +750,11 @@ if (!defined $sender) {
$sender = $repoauthor || $repocommitter || '';
}
+# $sender could be an already sanitized address
+# (e.g. sendemail.from could be manually sanitized by user).
+# But it's a no-op to run sanitize_address on an already sanitized address.
+$sender = sanitize_address($sender);
+
my $prompting = 0;
if (!@initial_to && !defined $to_cmd) {
my $to = ask("Who should the emails be sent to (if any)? ",
@@ -1047,6 +1043,75 @@ sub maildomain {
return maildomain_net() || maildomain_mta() || 'localhost.localdomain';
}
+sub smtp_host_string {
+ if (defined $smtp_server_port) {
+ return "$smtp_server:$smtp_server_port";
+ } else {
+ return $smtp_server;
+ }
+}
+
+# Returns 1 if authentication succeeded or was not necessary
+# (smtp_user was not specified), and 0 otherwise.
+
+sub smtp_auth_maybe {
+ if (!defined $smtp_authuser || $auth) {
+ return 1;
+ }
+
+ # Workaround AUTH PLAIN/LOGIN interaction defect
+ # with Authen::SASL::Cyrus
+ eval {
+ require Authen::SASL;
+ Authen::SASL->import(qw(Perl));
+ };
+
+ # TODO: Authentication may fail not because credentials were
+ # invalid but due to other reasons, in which we should not
+ # reject credentials.
+ $auth = Git::credential({
+ 'protocol' => 'smtp',
+ 'host' => smtp_host_string(),
+ 'username' => $smtp_authuser,
+ # if there's no password, "git credential fill" will
+ # give us one, otherwise it'll just pass this one.
+ 'password' => $smtp_authpass
+ }, sub {
+ my $cred = shift;
+ return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
+ });
+
+ return $auth;
+}
+
+sub ssl_verify_params {
+ eval {
+ require IO::Socket::SSL;
+ IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
+ };
+ if ($@) {
+ print STDERR "Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
+ return;
+ }
+
+ if (!defined $smtp_ssl_cert_path) {
+ $smtp_ssl_cert_path = "/etc/ssl/certs";
+ }
+
+ if ($smtp_ssl_cert_path eq "") {
+ return (SSL_verify_mode => SSL_VERIFY_NONE());
+ } elsif (-d $smtp_ssl_cert_path) {
+ return (SSL_verify_mode => SSL_VERIFY_PEER(),
+ SSL_ca_path => $smtp_ssl_cert_path);
+ } elsif (-f $smtp_ssl_cert_path) {
+ return (SSL_verify_mode => SSL_VERIFY_PEER(),
+ SSL_ca_file => $smtp_ssl_cert_path);
+ } else {
+ print STDERR "Not using SSL_VERIFY_PEER because the CA path does not exist.\n";
+ return (SSL_verify_mode => SSL_VERIFY_NONE());
+ }
+}
+
# Returns 1 if the message was sent, and 0 otherwise.
# In actuality, the whole program dies when there
# is an error sending a message.
@@ -1071,10 +1136,9 @@ sub send_message {
if ($cc ne '') {
$ccline = "\nCc: $cc";
}
- my $sanitized_sender = sanitize_address($sender);
make_message_id() unless defined($message_id);
- my $header = "From: $sanitized_sender
+ my $header = "From: $sender
To: $to${ccline}
Subject: $subject
Date: $date
@@ -1091,7 +1155,7 @@ X-Mailer: git-send-email $gitversion
}
my @sendmail_parameters = ('-i', @recipients);
- my $raw_from = $sanitized_sender;
+ my $raw_from = $sender;
if (defined $envelope_sender && $envelope_sender ne "auto") {
$raw_from = $envelope_sender;
}
@@ -1152,22 +1216,24 @@ X-Mailer: git-send-email $gitversion
$smtp_domain ||= maildomain();
$smtp ||= Net::SMTP::SSL->new($smtp_server,
Hello => $smtp_domain,
- Port => $smtp_server_port);
+ Port => $smtp_server_port,
+ ssl_verify_params());
}
else {
require Net::SMTP;
$smtp_domain ||= maildomain();
- $smtp ||= Net::SMTP->new((defined $smtp_server_port)
- ? "$smtp_server:$smtp_server_port"
- : $smtp_server,
+ $smtp_server_port ||= 25;
+ $smtp ||= Net::SMTP->new($smtp_server,
Hello => $smtp_domain,
- Debug => $debug_net_smtp);
+ Debug => $debug_net_smtp,
+ Port => $smtp_server_port);
if ($smtp_encryption eq 'tls' && $smtp) {
require Net::SMTP::SSL;
$smtp->command('STARTTLS');
$smtp->response();
if ($smtp->code == 220) {
- $smtp = Net::SMTP::SSL->start_SSL($smtp)
+ $smtp = Net::SMTP::SSL->start_SSL($smtp,
+ ssl_verify_params())
or die "STARTTLS failed! ".$smtp->message;
$smtp_encryption = '';
# Send EHLO again to receive fresh
@@ -1187,31 +1253,7 @@ X-Mailer: git-send-email $gitversion
defined $smtp_server_port ? " port=$smtp_server_port" : "";
}
- if (defined $smtp_authuser) {
- # Workaround AUTH PLAIN/LOGIN interaction defect
- # with Authen::SASL::Cyrus
- eval {
- require Authen::SASL;
- Authen::SASL->import(qw(Perl));
- };
-
- if (!defined $smtp_authpass) {
-
- system "stty -echo";
-
- do {
- print "Password: ";
- $_ = <STDIN>;
- print "\n";
- } while (!defined $_);
-
- chomp($smtp_authpass = $_);
-
- system "stty echo";
- }
-
- $auth ||= $smtp->auth( $smtp_authuser, $smtp_authpass ) or die $smtp->message;
- }
+ smtp_auth_maybe or die $smtp->message;
$smtp->mail( $raw_from ) or die $smtp->message;
$smtp->to( @recipients ) or die $smtp->message;
@@ -1254,6 +1296,7 @@ foreach my $t (@files) {
open my $fh, "<", $t or die "can't open file $t";
my $author = undef;
+ my $sauthor = undef;
my $author_encoding;
my $has_content_type;
my $body_encoding;
@@ -1292,8 +1335,9 @@ foreach my $t (@files) {
}
elsif (/^From:\s+(.*)$/i) {
($author, $author_encoding) = unquote_rfc2047($1);
+ $sauthor = sanitize_address($author);
next if $suppress_cc{'author'};
- next if $suppress_cc{'self'} and $author eq $sender;
+ next if $suppress_cc{'self'} and $sauthor eq $sender;
printf("(mbox) Adding cc: %s from line '%s'\n",
$1, $_) unless $quiet;
push @cc, $1;
@@ -1307,7 +1351,9 @@ foreach my $t (@files) {
}
elsif (/^Cc:\s+(.*)$/i) {
foreach my $addr (parse_address_line($1)) {
- if (unquote_rfc2047($addr) eq $sender) {
+ my $qaddr = unquote_rfc2047($addr);
+ my $saddr = sanitize_address($qaddr);
+ if ($saddr eq $sender) {
next if ($suppress_cc{'self'});
} else {
next if ($suppress_cc{'cc'});
@@ -1354,7 +1400,8 @@ foreach my $t (@files) {
chomp;
my ($what, $c) = ($1, $2);
chomp $c;
- if ($c eq $sender) {
+ my $sc = sanitize_address($c);
+ if ($sc eq $sender) {
next if ($suppress_cc{'self'});
} else {
next if $suppress_cc{'sob'} and $what =~ /Signed-off-by/i;
@@ -1384,7 +1431,7 @@ foreach my $t (@files) {
$subject = quote_subject($subject, $auto_8bit_encoding);
}
- if (defined $author and $author ne $sender) {
+ if (defined $sauthor and $sauthor ne $sender) {
$message = "From: $author\n\n$message";
if (defined $author_encoding) {
if ($has_content_type) {
@@ -1421,7 +1468,7 @@ foreach my $t (@files) {
# set up for the next message
if ($thread && $message_was_sent &&
- (chain_reply_to() || !defined $reply_to || length($reply_to) == 0 ||
+ ($chain_reply_to || !defined $reply_to || length($reply_to) == 0 ||
$message_num == 1)) {
$reply_to = $message_id;
if (length $references > 0) {
@@ -1438,7 +1485,6 @@ foreach my $t (@files) {
sub recipients_cmd {
my ($prefix, $what, $cmd, $file) = @_;
- my $sanitized_sender = sanitize_address($sender);
my @addresses = ();
open my $fh, "-|", "$cmd \Q$file\E"
or die "($prefix) Could not execute '$cmd'";
@@ -1446,7 +1492,7 @@ sub recipients_cmd {
$address =~ s/^\s*//g;
$address =~ s/\s*$//g;
$address = sanitize_address($address);
- next if ($address eq $sanitized_sender and $suppress_from);
+ next if ($address eq $sender and $suppress_cc{'self'});
push @addresses, $address;
printf("($prefix) Adding %s: %s from: '%s'\n",
$what, $address, $cmd) unless $quiet;
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 9cfbe7f..e15be51 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -53,7 +53,7 @@ die () {
die_with_status () {
status=$1
shift
- echo >&2 "$*"
+ printf >&2 '%s\n' "$*"
exit "$status"
}
@@ -249,6 +249,18 @@ clear_local_git_env() {
unset $(git rev-parse --local-env-vars)
}
+# Generate a virtual base file for a two-file merge. Uses git apply to
+# remove lines from $1 that are not in $2, leaving only common lines.
+create_virtual_base() {
+ sz0=$(wc -c <"$1")
+ @@DIFF@@ -u -La/"$1" -Lb/"$1" "$1" "$2" | git apply --no-add
+ sz1=$(wc -c <"$1")
+
+ # If we do not have enough common material, it is not
+ # worth trying two-file merge using common subsections.
+ expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$1"
+}
+
# Platform specific tweaks to work around some commands
case $(uname -s) in
@@ -301,3 +313,15 @@ then
}
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
fi
+
+peel_committish () {
+ case "$1" in
+ :/*)
+ peeltmp=$(git rev-parse --verify "$1") &&
+ git rev-parse --verify "${peeltmp}^0"
+ ;;
+ *)
+ git rev-parse --verify "${1}^0"
+ ;;
+ esac
+}
diff --git a/git-stash.sh b/git-stash.sh
index bbefdf6..1e541a2 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -156,6 +156,41 @@ create_stash () {
die "$(gettext "Cannot record working tree state")"
}
+store_stash () {
+ while test $# != 0
+ do
+ case "$1" in
+ -m|--message)
+ shift
+ stash_msg="$1"
+ ;;
+ -q|--quiet)
+ quiet=t
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+ test $# = 1 ||
+ die "$(eval_gettext "\"$dashless store\" requires one <commit> argument")"
+
+ w_commit="$1"
+ if test -z "$stash_msg"
+ then
+ stash_msg="Created via \"git stash store\"."
+ fi
+
+ # Make sure the reflog for stash is kept.
+ : >>"$GIT_DIR/logs/$ref_stash"
+ git update-ref -m "$stash_msg" $ref_stash $w_commit
+ ret=$?
+ test $ret != 0 && test -z $quiet &&
+ die "$(eval_gettext "Cannot update \$ref_stash with \$w_commit")"
+ return $ret
+}
+
save_stash () {
keep_index=
patch_mode=
@@ -227,12 +262,8 @@ save_stash () {
clear_stash || die "$(gettext "Cannot initialize stash")"
create_stash "$stash_msg" $untracked
-
- # Make sure the reflog for stash is kept.
- : >>"$GIT_DIR/logs/$ref_stash"
-
- git update-ref -m "$stash_msg" $ref_stash $w_commit ||
- die "$(gettext "Cannot save the current status")"
+ store_stash -m "$stash_msg" -q $w_commit ||
+ die "$(gettext "Cannot save the current status")"
say Saved working directory and index state "$stash_msg"
if test -z "$patch_mode"
@@ -546,12 +577,13 @@ clear)
clear_stash "$@"
;;
create)
- if test $# -gt 0 && test "$1" = create
- then
- shift
- fi
+ shift
create_stash "$*" && echo "$w_commit"
;;
+store)
+ shift
+ store_stash "$@"
+ ;;
drop)
shift
drop_stash "$@"
diff --git a/git-submodule.sh b/git-submodule.sh
index b3108b8..2979197 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -8,15 +8,19 @@ dashless=$(basename "$0" | sed -e 's/-/ /')
USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
or: $dashless [--quiet] init [--] [<path>...]
+ or: $dashless [--quiet] deinit [-f|--force] [--] <path>...
or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
or: $dashless [--quiet] foreach [--recursive] <command>
or: $dashless [--quiet] sync [--recursive] [--] [<path>...]"
OPTIONS_SPEC=
+SUBDIRECTORY_OK=Yes
. git-sh-setup
. git-sh-i18n
. git-parse-remote
require_work_tree
+wt_prefix=$(git rev-parse --show-prefix)
+cd_to_toplevel
command=
branch=
@@ -31,6 +35,7 @@ nofetch=
update=
prefix=
custom_name=
+depth=
# The function takes at most 2 arguments. The first argument is the
# URL that navigates to the submodule origin repo. When relative, this URL
@@ -105,14 +110,50 @@ resolve_relative_url ()
echo "${is_relative:+${up_path}}${remoteurl#./}"
}
+# Resolve a path to be relative to another path. This is intended for
+# converting submodule paths when git-submodule is run in a subdirectory
+# and only handles paths where the directory separator is '/'.
+#
+# The output is the first argument as a path relative to the second argument,
+# which defaults to $wt_prefix if it is omitted.
+relative_path ()
+{
+ local target curdir result
+ target=$1
+ curdir=${2-$wt_prefix}
+ curdir=${curdir%/}
+ result=
+
+ while test -n "$curdir"
+ do
+ case "$target" in
+ "$curdir/"*)
+ target=${target#"$curdir"/}
+ break
+ ;;
+ esac
+
+ result="${result}../"
+ if test "$curdir" = "${curdir%/*}"
+ then
+ curdir=
+ else
+ curdir="${curdir%/*}"
+ fi
+ done
+
+ echo "$result$target"
+}
+
#
# Get submodule info for registered submodules
# $@ = path to limit submodule list
#
module_list()
{
+ eval "set $(git rev-parse --sq --prefix "$wt_prefix" -- "$@")"
(
- git ls-files --error-unmatch --stage -- "$@" ||
+ git ls-files -z --error-unmatch --stage -- "$@" ||
echo "unmatched pathspec exists"
) |
perl -e '
@@ -120,6 +161,7 @@ module_list()
my ($null_sha1) = ("0" x 40);
my @out = ();
my $unmatched = 0;
+ $/ = "\0";
while (<STDIN>) {
if (/^unmatched pathspec/) {
$unmatched = 1;
@@ -210,6 +252,7 @@ module_clone()
name=$2
url=$3
reference="$4"
+ depth="$5"
quiet=
if test -n "$GIT_QUIET"
then
@@ -232,7 +275,7 @@ module_clone()
mkdir -p "$gitdir_base"
(
clear_local_git_env
- git clone $quiet -n ${reference:+"$reference"} \
+ git clone $quiet ${depth:+"$depth"} -n ${reference:+"$reference"} \
--separate-git-dir "$gitdir" "$url" "$sm_path"
) ||
die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")"
@@ -281,6 +324,7 @@ isnumber()
cmd_add()
{
# parse $args after "submodule ... add".
+ reference_path=
while test $# -ne 0
do
case "$1" in
@@ -297,17 +341,25 @@ cmd_add()
;;
--reference)
case "$2" in '') usage ;; esac
- reference="--reference=$2"
+ reference_path=$2
shift
;;
--reference=*)
- reference="$1"
+ reference_path="${1#--reference=}"
;;
--name)
case "$2" in '') usage ;; esac
custom_name=$2
shift
;;
+ --depth)
+ case "$2" in '') usage ;; esac
+ depth="--depth=$2"
+ shift
+ ;;
+ --depth=*)
+ depth=$1
+ ;;
--)
shift
break
@@ -322,6 +374,14 @@ cmd_add()
shift
done
+ if test -n "$reference_path"
+ then
+ is_absolute_path "$reference_path" ||
+ reference_path="$wt_prefix$reference_path"
+
+ reference="--reference=$reference_path"
+ fi
+
repo=$1
sm_path=$2
@@ -334,9 +394,14 @@ cmd_add()
usage
fi
+ is_absolute_path "$sm_path" || sm_path="$wt_prefix$sm_path"
+
# assure repo is absolute or relative to parent
case "$repo" in
./*|../*)
+ test -z "$wt_prefix" ||
+ die "$(gettext "Relative path can only be used from the toplevel of the working tree")"
+
# dereference source url relative to parent's url
realrepo=$(resolve_relative_url "$repo") || exit
;;
@@ -404,7 +469,7 @@ Use -f if you really want to add it." >&2
echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
fi
fi
- module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" || exit
+ module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" || exit
(
clear_local_git_env
cd "$sm_path" &&
@@ -470,21 +535,23 @@ cmd_foreach()
die_if_unmatched "$mode"
if test -e "$sm_path"/.git
then
- say "$(eval_gettext "Entering '\$prefix\$sm_path'")"
+ displaypath=$(relative_path "$sm_path")
+ say "$(eval_gettext "Entering '\$prefix\$displaypath'")"
name=$(module_name "$sm_path")
(
prefix="$prefix$sm_path/"
clear_local_git_env
- # we make $path available to scripts ...
- path=$sm_path
cd "$sm_path" &&
+ sm_path=$(relative_path "$sm_path") &&
+ # we make $path available to scripts ...
+ path=$sm_path &&
eval "$@" &&
if test -n "$recursive"
then
cmd_foreach "--recursive" "$@"
fi
) <&3 3<&- ||
- die "$(eval_gettext "Stopping at '\$sm_path'; script returned non-zero status.")"
+ die "$(eval_gettext "Stopping at '\$prefix\$displaypath'; script returned non-zero status.")"
fi
done
}
@@ -523,12 +590,14 @@ cmd_init()
die_if_unmatched "$mode"
name=$(module_name "$sm_path") || exit
+ displaypath=$(relative_path "$sm_path")
+
# Copy url setting when it is not set yet
if test -z "$(git config "submodule.$name.url")"
then
url=$(git config -f .gitmodules submodule."$name".url)
test -z "$url" &&
- die "$(eval_gettext "No url found for submodule path '\$sm_path' in .gitmodules")"
+ die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")"
# Possibly a url relative to parent
case "$url" in
@@ -537,9 +606,9 @@ cmd_init()
;;
esac
git config submodule."$name".url "$url" ||
- die "$(eval_gettext "Failed to register url for submodule path '\$sm_path'")"
+ die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")"
- say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$sm_path'")"
+ say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")"
fi
# Copy "update" setting when it is not set yet
@@ -547,7 +616,85 @@ cmd_init()
test -z "$upd" ||
test -n "$(git config submodule."$name".update)" ||
git config submodule."$name".update "$upd" ||
- die "$(eval_gettext "Failed to register update mode for submodule path '\$sm_path'")"
+ die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
+ done
+}
+
+#
+# Unregister submodules from .git/config and remove their work tree
+#
+# $@ = requested paths (use '.' to deinit all submodules)
+#
+cmd_deinit()
+{
+ # parse $args after "submodule ... deinit".
+ while test $# -ne 0
+ do
+ case "$1" in
+ -f|--force)
+ force=$1
+ ;;
+ -q|--quiet)
+ GIT_QUIET=1
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
+ if test $# = 0
+ then
+ die "$(eval_gettext "Use '.' if you really want to deinitialize all submodules")"
+ fi
+
+ module_list "$@" |
+ while read mode sha1 stage sm_path
+ do
+ die_if_unmatched "$mode"
+ name=$(module_name "$sm_path") || exit
+
+ displaypath=$(relative_path "$sm_path")
+
+ # Remove the submodule work tree (unless the user already did it)
+ if test -d "$sm_path"
+ then
+ # Protect submodules containing a .git directory
+ if test -d "$sm_path/.git"
+ then
+ echo >&2 "$(eval_gettext "Submodule work tree '\$displaypath' contains a .git directory")"
+ die "$(eval_gettext "(use 'rm -rf' if you really want to remove it including all of its history)")"
+ fi
+
+ if test -z "$force"
+ then
+ git rm -qn "$sm_path" ||
+ die "$(eval_gettext "Submodule work tree '\$displaypath' contains local modifications; use '-f' to discard them")"
+ fi
+ rm -rf "$sm_path" &&
+ say "$(eval_gettext "Cleared directory '\$displaypath'")" ||
+ say "$(eval_gettext "Could not remove submodule work tree '\$displaypath'")"
+ fi
+
+ mkdir "$sm_path" || say "$(eval_gettext "Could not create empty submodule directory '\$displaypath'")"
+
+ # Remove the .git/config entries (unless the user already did it)
+ if test -n "$(git config --get-regexp submodule."$name\.")"
+ then
+ # Remove the whole section so we have a clean state when
+ # the user later decides to init this submodule again
+ url=$(git config submodule."$name".url)
+ git config --remove-section submodule."$name" 2>/dev/null &&
+ say "$(eval_gettext "Submodule '\$name' (\$url) unregistered for path '\$displaypath'")"
+ fi
done
}
@@ -599,6 +746,14 @@ cmd_update()
--checkout)
update="checkout"
;;
+ --depth)
+ case "$2" in '') usage ;; esac
+ depth="--depth=$2"
+ shift
+ ;;
+ --depth=*)
+ depth=$1
+ ;;
--)
shift
break
@@ -640,9 +795,11 @@ cmd_update()
update_module=$(git config submodule."$name".update)
fi
+ displaypath=$(relative_path "$prefix$sm_path")
+
if test "$update_module" = "none"
then
- echo "Skipping submodule '$prefix$sm_path'"
+ echo "Skipping submodule '$displaypath'"
continue
fi
@@ -651,20 +808,20 @@ cmd_update()
# Only mention uninitialized submodules when its
# path have been specified
test "$#" != "0" &&
- say "$(eval_gettext "Submodule path '\$prefix\$sm_path' not initialized
+ say "$(eval_gettext "Submodule path '\$displaypath' not initialized
Maybe you want to use 'update --init'?")"
continue
fi
if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
then
- module_clone "$sm_path" "$name" "$url" "$reference" || exit
+ module_clone "$sm_path" "$name" "$url" "$reference" "$depth" || exit
cloned_modules="$cloned_modules;$name"
subsha1=
else
subsha1=$(clear_local_git_env; cd "$sm_path" &&
git rev-parse --verify HEAD) ||
- die "$(eval_gettext "Unable to find current revision in submodule path '\$prefix\$sm_path'")"
+ die "$(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")"
fi
if test -n "$remote"
@@ -697,7 +854,7 @@ Maybe you want to use 'update --init'?")"
(clear_local_git_env; cd "$sm_path" &&
( (rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) &&
test -z "$rev") || git-fetch)) ||
- die "$(eval_gettext "Unable to fetch in submodule path '\$prefix\$sm_path'")"
+ die "$(eval_gettext "Unable to fetch in submodule path '\$displaypath'")"
fi
# Is this something we just cloned?
@@ -711,20 +868,26 @@ Maybe you want to use 'update --init'?")"
case "$update_module" in
rebase)
command="git rebase"
- die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$prefix\$sm_path'")"
- say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': rebased into '\$sha1'")"
+ die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$displaypath'")"
+ say_msg="$(eval_gettext "Submodule path '\$displaypath': rebased into '\$sha1'")"
must_die_on_failure=yes
;;
merge)
command="git merge"
- die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$prefix\$sm_path'")"
- say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': merged in '\$sha1'")"
+ die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$displaypath'")"
+ say_msg="$(eval_gettext "Submodule path '\$displaypath': merged in '\$sha1'")"
+ must_die_on_failure=yes
+ ;;
+ !*)
+ command="${update_module#!}"
+ die_msg="$(eval_gettext "Execution of '\$command \$sha1' failed in submodule path '\$prefix\$sm_path'")"
+ say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': '\$command \$sha1'")"
must_die_on_failure=yes
;;
*)
command="git checkout $subforce -q"
- die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$prefix\$sm_path'")"
- say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': checked out '\$sha1'")"
+ die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")"
+ say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")"
;;
esac
@@ -751,7 +914,7 @@ Maybe you want to use 'update --init'?")"
res=$?
if test $res -gt 0
then
- die_msg="$(eval_gettext "Failed to recurse into submodule path '\$prefix\$sm_path'")"
+ die_msg="$(eval_gettext "Failed to recurse into submodule path '\$displaypath'")"
if test $res -eq 1
then
err="${err};$die_msg"
@@ -865,6 +1028,7 @@ cmd_summary() {
fi
cd_to_toplevel
+ eval "set $(git rev-parse --sq --prefix "$wt_prefix" -- "$@")"
# Get modified modules cared by user
modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" |
sane_egrep '^:([0-7]* )?160000' |
@@ -914,16 +1078,18 @@ cmd_summary() {
! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
missing_dst=t
+ display_name=$(relative_path "$name")
+
total_commits=
case "$missing_src,$missing_dst" in
t,)
- errmsg="$(eval_gettext " Warn: \$name doesn't contain commit \$sha1_src")"
+ errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commit \$sha1_src")"
;;
,t)
- errmsg="$(eval_gettext " Warn: \$name doesn't contain commit \$sha1_dst")"
+ errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commit \$sha1_dst")"
;;
t,t)
- errmsg="$(eval_gettext " Warn: \$name doesn't contain commits \$sha1_src and \$sha1_dst")"
+ errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commits \$sha1_src and \$sha1_dst")"
;;
*)
errmsg=
@@ -952,12 +1118,12 @@ cmd_summary() {
submodule="$(gettext "submodule")"
if test $mod_dst = 160000
then
- echo "* $name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:"
+ echo "* $display_name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:"
else
- echo "* $name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:"
+ echo "* $display_name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:"
fi
else
- echo "* $name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
+ echo "* $display_name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
fi
if test -n "$errmsg"
then
@@ -1041,7 +1207,7 @@ cmd_status()
die_if_unmatched "$mode"
name=$(module_name "$sm_path") || exit
url=$(git config submodule."$name".url)
- displaypath="$prefix$sm_path"
+ displaypath=$(relative_path "$prefix$sm_path")
if test "$stage" = U
then
say "U$sha1 $displaypath"
@@ -1052,16 +1218,16 @@ cmd_status()
say "-$sha1 $displaypath"
continue;
fi
- set_name_rev "$sm_path" "$sha1"
if git diff-files --ignore-submodules=dirty --quiet -- "$sm_path"
then
+ set_name_rev "$sm_path" "$sha1"
say " $sha1 $displaypath$revname"
else
if test -z "$cached"
then
sha1=$(clear_local_git_env; cd "$sm_path" && git rev-parse --verify HEAD)
- set_name_rev "$sm_path" "$sha1"
fi
+ set_name_rev "$sm_path" "$sha1"
say "+$sha1 $displaypath$revname"
fi
@@ -1136,7 +1302,8 @@ cmd_sync()
if git config "submodule.$name.url" >/dev/null 2>/dev/null
then
- say "$(eval_gettext "Synchronizing submodule url for '\$prefix\$sm_path'")"
+ displaypath=$(relative_path "$prefix$sm_path")
+ say "$(eval_gettext "Synchronizing submodule url for '\$displaypath'")"
git config submodule."$name".url "$super_config_url"
if test -e "$sm_path"/.git
@@ -1167,7 +1334,7 @@ cmd_sync()
while test $# != 0 && test -z "$command"
do
case "$1" in
- add | foreach | init | update | status | summary | sync)
+ add | foreach | init | deinit | update | status | summary | sync)
command=$1
;;
-q|--quiet)
diff --git a/git-svn.perl b/git-svn.perl
index 6c7bd95..ff1ce3d 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -113,7 +113,7 @@ my ($_stdin, $_help, $_edit,
$_template, $_shared,
$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
$_before, $_after,
- $_merge, $_strategy, $_preserve_merges, $_dry_run, $_local,
+ $_merge, $_strategy, $_preserve_merges, $_dry_run, $_parents, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
$_commit_url, $_tag, $_merge_info, $_interactive);
@@ -126,6 +126,7 @@ my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
'config-dir=s' => \$Git::SVN::Ra::config_dir,
'no-auth-cache' => \$Git::SVN::Prompt::_no_auth_cache,
'ignore-paths=s' => \$Git::SVN::Fetcher::_ignore_regex,
+ 'include-paths=s' => \$Git::SVN::Fetcher::_include_regex,
'ignore-refs=s' => \$Git::SVN::Ra::_ignore_refs_regex );
my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
'authors-file|A=s' => \$_authors,
@@ -202,6 +203,7 @@ my %cmd = (
{ 'message|m=s' => \$_message,
'destination|d=s' => \$_branch_dest,
'dry-run|n' => \$_dry_run,
+ 'parents' => \$_parents,
'tag|t' => \$_tag,
'username=s' => \$Git::SVN::Prompt::_username,
'commit-url=s' => \$_commit_url } ],
@@ -210,6 +212,7 @@ my %cmd = (
{ 'message|m=s' => \$_message,
'destination|d=s' => \$_branch_dest,
'dry-run|n' => \$_dry_run,
+ 'parents' => \$_parents,
'username=s' => \$Git::SVN::Prompt::_username,
'commit-url=s' => \$_commit_url } ],
'set-tree' => [ \&cmd_set_tree,
@@ -470,6 +473,9 @@ sub do_git_init_db {
my $ignore_paths_regex = \$Git::SVN::Fetcher::_ignore_regex;
command_noisy('config', "$pfx.ignore-paths", $$ignore_paths_regex)
if defined $$ignore_paths_regex;
+ my $include_paths_regex = \$Git::SVN::Fetcher::_include_regex;
+ command_noisy('config', "$pfx.include-paths", $$include_paths_regex)
+ if defined $$include_paths_regex;
my $ignore_refs_regex = \$Git::SVN::Ra::_ignore_refs_regex;
command_noisy('config', "$pfx.ignore-refs", $$ignore_refs_regex)
if defined $$ignore_refs_regex;
@@ -669,12 +675,14 @@ sub merge_revs_into_hash {
}
sub merge_merge_info {
- my ($mergeinfo_one, $mergeinfo_two) = @_;
+ my ($mergeinfo_one, $mergeinfo_two, $ignore_branch) = @_;
my %result_hash = ();
merge_revs_into_hash(\%result_hash, $mergeinfo_one);
merge_revs_into_hash(\%result_hash, $mergeinfo_two);
+ delete $result_hash{$ignore_branch} if $ignore_branch;
+
my $result = '';
# Sort below is for consistency's sake
for my $branchname (sort keys(%result_hash)) {
@@ -695,6 +703,7 @@ sub populate_merge_info {
my $all_parents_ok = 1;
my $aggregate_mergeinfo = '';
my $rooturl = $gs->repos_root;
+ my ($target_branch) = $gs->full_pushurl =~ /^\Q$rooturl\E(.*)/;
if (defined($rewritten_parent)) {
# Replace first parent with newly-rewritten version
@@ -726,7 +735,8 @@ sub populate_merge_info {
# Merge previous mergeinfo values
$aggregate_mergeinfo =
merge_merge_info($aggregate_mergeinfo,
- $par_mergeinfo, 0);
+ $par_mergeinfo,
+ $target_branch);
next if $parent eq $parents[0]; # Skip first parent
# Add new changes being placed in tree by merge
@@ -769,7 +779,8 @@ sub populate_merge_info {
my $newmergeinfo = "$branchpath:" . join(',', @revsin);
$aggregate_mergeinfo =
merge_merge_info($aggregate_mergeinfo,
- $newmergeinfo, 1);
+ $newmergeinfo,
+ $target_branch);
}
if ($all_parents_ok and $aggregate_mergeinfo) {
return $aggregate_mergeinfo;
@@ -820,7 +831,7 @@ sub dcommit_rebase {
sub cmd_dcommit {
my $head = shift;
command_noisy(qw/update-index --refresh/);
- git_cmd_try { command_oneline(qw/diff-index --quiet HEAD/) }
+ git_cmd_try { command_oneline(qw/diff-index --quiet HEAD --/) }
'Cannot dcommit with a dirty index. Commit your changes first, '
. "or stash them with `git stash'.\n";
$head ||= 'HEAD';
@@ -1163,6 +1174,10 @@ sub cmd_branch {
$ctx->ls($dst, 'HEAD', 0);
} and die "branch ${branch_name} already exists\n";
+ if ($_parents) {
+ mk_parent_dirs($ctx, $dst);
+ }
+
print "Copying ${src} at r${rev} to ${dst}...\n";
$ctx->copy($src, $rev, $dst)
unless $_dry_run;
@@ -1170,6 +1185,17 @@ sub cmd_branch {
$gs->fetch_all;
}
+sub mk_parent_dirs {
+ my ($ctx, $parent) = @_;
+ $parent =~ s{/[^/]*$}{};
+
+ if (!eval{$ctx->ls($parent, 'HEAD', 0)}) {
+ mk_parent_dirs($ctx, $parent);
+ print "Creating parent folder ${parent} ...\n";
+ $ctx->mkdir($parent) unless $_dry_run;
+ }
+}
+
sub cmd_find_rev {
my $revision_or_hash = shift or die "SVN or git revision required ",
"as a command-line argument\n";
@@ -1220,7 +1246,7 @@ sub cmd_rebase {
return;
}
if (command(qw/diff-index HEAD --/)) {
- print STDERR "Cannot rebase with uncommited changes:\n";
+ print STDERR "Cannot rebase with uncommitted changes:\n";
command_noisy('status');
exit 1;
}
@@ -1906,7 +1932,7 @@ sub cmt_sha2rev_batch {
sub working_head_info {
my ($head, $refs) = @_;
my @args = qw/rev-list --first-parent --pretty=medium/;
- my ($fh, $ctx) = command_output_pipe(@args, $head);
+ my ($fh, $ctx) = command_output_pipe(@args, $head, "--");
my $hash;
my %max;
while (<$fh>) {
diff --git a/git-web--browse.sh b/git-web--browse.sh
index 1e82726..1d72ec7 100755
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -32,8 +32,9 @@ valid_custom_tool()
valid_tool() {
case "$1" in
firefox | iceweasel | seamonkey | iceape | \
- chrome | google-chrome | chromium | chromium-browser |\
- konqueror | opera | w3m | elinks | links | lynx | dillo | open | start)
+ chrome | google-chrome | chromium | chromium-browser | \
+ konqueror | opera | w3m | elinks | links | lynx | dillo | open | \
+ start | cygstart)
;; # happy
*)
valid_custom_tool "$1" || return 1
@@ -119,14 +120,18 @@ if test -z "$browser" ; then
browser_candidates="w3m elinks links lynx"
fi
# SECURITYSESSIONID indicates an OS X GUI login session
- if test -n "$SECURITYSESSIONID" \
- -o "$TERM_PROGRAM" = "Apple_Terminal" ; then
+ if test -n "$SECURITYSESSIONID" || test -n "$TERM_PROGRAM"
+ then
browser_candidates="open $browser_candidates"
fi
# /bin/start indicates MinGW
if test -x /bin/start; then
browser_candidates="start $browser_candidates"
fi
+ # /usr/bin/cygstart indicates Cygwin
+ if test -x /usr/bin/cygstart; then
+ browser_candidates="cygstart $browser_candidates"
+ fi
for i in $browser_candidates; do
init_browser_path $i
@@ -174,7 +179,7 @@ konqueror)
;;
esac
;;
-w3m|elinks|links|lynx|open)
+w3m|elinks|links|lynx|open|cygstart)
"$browser_path" "$@"
;;
start)
diff --git a/git.c b/git.c
index 850d3f5..b3893e7 100644
--- a/git.c
+++ b/git.c
@@ -4,6 +4,7 @@
#include "help.h"
#include "quote.h"
#include "run-command.h"
+#include "commit.h"
const char git_usage_string[] =
"git [--version] [--help] [-c name=value]\n"
@@ -13,7 +14,9 @@ const char git_usage_string[] =
" <command> [<args>]";
const char git_more_info_string[] =
- N_("See 'git help <command>' for more information on a specific command.");
+ N_("'git help -a' and 'git help -g' lists available subcommands and some\n"
+ "concept guides. See 'git help <command>' or 'git help <concept>'\n"
+ "to read about a specific subcommand or concept.");
static struct startup_info git_startup_info;
static int use_pager = -1;
@@ -144,6 +147,24 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "0", 1);
if (envchanged)
*envchanged = 1;
+ } else if (!strcmp(cmd, "--glob-pathspecs")) {
+ setenv(GIT_GLOB_PATHSPECS_ENVIRONMENT, "1", 1);
+ if (envchanged)
+ *envchanged = 1;
+ } else if (!strcmp(cmd, "--noglob-pathspecs")) {
+ setenv(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, "1", 1);
+ if (envchanged)
+ *envchanged = 1;
+ } else if (!strcmp(cmd, "--icase-pathspecs")) {
+ setenv(GIT_ICASE_PATHSPECS_ENVIRONMENT, "1", 1);
+ if (envchanged)
+ *envchanged = 1;
+ } else if (!strcmp(cmd, "--shallow-file")) {
+ (*argv)++;
+ (*argc)--;
+ set_alternate_shallow_file((*argv)[0]);
+ if (envchanged)
+ *envchanged = 1;
} else {
fprintf(stderr, "Unknown option: %s\n", cmd);
usage(git_usage_string);
@@ -315,6 +336,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "cat-file", cmd_cat_file, RUN_SETUP },
{ "check-attr", cmd_check_attr, RUN_SETUP },
{ "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
+ { "check-mailmap", cmd_check_mailmap, RUN_SETUP },
{ "check-ref-format", cmd_check_ref_format },
{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
{ "checkout-index", cmd_checkout_index,
@@ -505,8 +527,9 @@ static int run_argv(int *argcp, const char ***argv)
}
-int main(int argc, const char **argv)
+int main(int argc, char **av)
{
+ const char **argv = (const char **) av;
const char *cmd;
startup_info = &git_startup_info;
@@ -515,6 +538,13 @@ int main(int argc, const char **argv)
if (!cmd)
cmd = "git-help";
+ /*
+ * Always open file descriptors 0/1/2 to avoid clobbering files
+ * in die(). It also avoids messing up when the pipes are dup'ed
+ * onto stdin/stdout/stderr in the child processes we spawn.
+ */
+ sanitize_stdfds();
+
git_setup_gettext();
/*
diff --git a/git.rc b/git.rc
new file mode 100644
index 0000000..bce6db9
--- /dev/null
+++ b/git.rc
@@ -0,0 +1,22 @@
+1 VERSIONINFO
+FILEVERSION MAJOR,MINOR,PATCH,0
+PRODUCTVERSION MAJOR,MINOR,PATCH,0
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
+ BEGIN
+ VALUE "CompanyName", "The Git Development Community\0"
+ VALUE "FileDescription", "Git for Windows\0"
+ VALUE "InternalName", "git\0"
+ VALUE "OriginalFilename", "git.exe\0"
+ VALUE "ProductName", "Git\0"
+ VALUE "ProductVersion", GIT_VERSION "\0"
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/gitk-git/gitk b/gitk-git/gitk
index b3706fc..5cd00d8 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -1998,6 +1998,9 @@ proc mca {str} {
return [string map {&& & & {}} [mc $str]]
}
+proc cleardropsel {w} {
+ $w selection clear
+}
proc makedroplist {w varname args} {
global use_ttk
if {$use_ttk} {
@@ -2007,7 +2010,9 @@ proc makedroplist {w varname args} {
if {$cx > $width} {set width $cx}
}
set gm [ttk::combobox $w -width $width -state readonly\
- -textvariable $varname -values $args]
+ -textvariable $varname -values $args \
+ -exportselection false]
+ bind $gm <<ComboboxSelected>> [list $gm selection clear]
} else {
set gm [eval [linsert $args 0 tk_optionMenu $w $varname]]
}
@@ -2026,6 +2031,9 @@ proc makewindow {} {
global highlight_files gdttype
global searchstring sstring
global bgcolor fgcolor bglist fglist diffcolors selectbgcolor
+ global uifgcolor uifgdisabledcolor
+ global filesepbgcolor filesepfgcolor
+ global mergecolors foundbgcolor currentsearchhitbgcolor
global headctxmenu progresscanv progressitem progresscoords statusw
global fprogitem fprogcoord lastprogupdate progupdatepending
global rprogitem rprogcoord rownumsel numcommits
@@ -2177,10 +2185,10 @@ proc makewindow {} {
0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
}
- image create bitmap bm-left -data $bm_left_data
- image create bitmap bm-left-gray -data $bm_left_data -foreground "#999"
- image create bitmap bm-right -data $bm_right_data
- image create bitmap bm-right-gray -data $bm_right_data -foreground "#999"
+ image create bitmap bm-left -data $bm_left_data -foreground $uifgcolor
+ image create bitmap bm-left-gray -data $bm_left_data -foreground $uifgdisabledcolor
+ image create bitmap bm-right -data $bm_right_data -foreground $uifgcolor
+ image create bitmap bm-right-gray -data $bm_right_data -foreground $uifgdisabledcolor
${NS}::button .tf.bar.leftbut -command goback -state disabled -width 26
if {$use_ttk} {
@@ -2245,7 +2253,8 @@ proc makewindow {} {
set gm [makedroplist .tf.lbar.gdttype gdttype \
[mc "containing:"] \
[mc "touching paths:"] \
- [mc "adding/removing string:"]]
+ [mc "adding/removing string:"] \
+ [mc "changing lines matching:"]]
trace add variable gdttype write gdttype_change
pack .tf.lbar.gdttype -side left -fill y
@@ -2349,32 +2358,32 @@ proc makewindow {} {
lappend fglist $ctext
$ctext tag conf comment -wrap $wrapcomment
- $ctext tag conf filesep -font textfontbold -back "#aaaaaa"
+ $ctext tag conf filesep -font textfontbold -fore $filesepfgcolor -back $filesepbgcolor
$ctext tag conf hunksep -fore [lindex $diffcolors 2]
$ctext tag conf d0 -fore [lindex $diffcolors 0]
$ctext tag conf dresult -fore [lindex $diffcolors 1]
- $ctext tag conf m0 -fore red
- $ctext tag conf m1 -fore blue
- $ctext tag conf m2 -fore green
- $ctext tag conf m3 -fore purple
- $ctext tag conf m4 -fore brown
- $ctext tag conf m5 -fore "#009090"
- $ctext tag conf m6 -fore magenta
- $ctext tag conf m7 -fore "#808000"
- $ctext tag conf m8 -fore "#009000"
- $ctext tag conf m9 -fore "#ff0080"
- $ctext tag conf m10 -fore cyan
- $ctext tag conf m11 -fore "#b07070"
- $ctext tag conf m12 -fore "#70b0f0"
- $ctext tag conf m13 -fore "#70f0b0"
- $ctext tag conf m14 -fore "#f0b070"
- $ctext tag conf m15 -fore "#ff70b0"
+ $ctext tag conf m0 -fore [lindex $mergecolors 0]
+ $ctext tag conf m1 -fore [lindex $mergecolors 1]
+ $ctext tag conf m2 -fore [lindex $mergecolors 2]
+ $ctext tag conf m3 -fore [lindex $mergecolors 3]
+ $ctext tag conf m4 -fore [lindex $mergecolors 4]
+ $ctext tag conf m5 -fore [lindex $mergecolors 5]
+ $ctext tag conf m6 -fore [lindex $mergecolors 6]
+ $ctext tag conf m7 -fore [lindex $mergecolors 7]
+ $ctext tag conf m8 -fore [lindex $mergecolors 8]
+ $ctext tag conf m9 -fore [lindex $mergecolors 9]
+ $ctext tag conf m10 -fore [lindex $mergecolors 10]
+ $ctext tag conf m11 -fore [lindex $mergecolors 11]
+ $ctext tag conf m12 -fore [lindex $mergecolors 12]
+ $ctext tag conf m13 -fore [lindex $mergecolors 13]
+ $ctext tag conf m14 -fore [lindex $mergecolors 14]
+ $ctext tag conf m15 -fore [lindex $mergecolors 15]
$ctext tag conf mmax -fore darkgrey
set mergemax 16
$ctext tag conf mresult -font textfontbold
$ctext tag conf msep -font textfontbold
- $ctext tag conf found -back yellow
- $ctext tag conf currentsearchhit -back orange
+ $ctext tag conf found -back $foundbgcolor
+ $ctext tag conf currentsearchhit -back $currentsearchhitbgcolor
$ctext tag conf wwrap -wrap word
.pwbottom add .bleft
@@ -2559,6 +2568,7 @@ proc makewindow {} {
{mc "Compare with marked commit" command compare_commits}
{mc "Diff this -> marked commit" command {diffvsmark 0}}
{mc "Diff marked commit -> this" command {diffvsmark 1}}
+ {mc "Revert this commit" command revert}
}
$rowctxmenu configure -tearoff 0
@@ -2721,6 +2731,14 @@ proc savestuff {w} {
global viewname viewfiles viewargs viewargscmd viewperm nextviewnum
global cmitmode wrapcomment datetimeformat limitdiffs
global colors uicolor bgcolor fgcolor diffcolors diffcontext selectbgcolor
+ global uifgcolor uifgdisabledcolor
+ global headbgcolor headfgcolor headoutlinecolor remotebgcolor
+ global tagbgcolor tagfgcolor tagoutlinecolor
+ global reflinecolor filesepbgcolor filesepfgcolor
+ global mergecolors foundbgcolor currentsearchhitbgcolor
+ global linehoverbgcolor linehoverfgcolor linehoveroutlinecolor circlecolors
+ global mainheadcirclecolor workingfilescirclecolor indexcirclecolor
+ global linkfgcolor circleoutlinecolor
global autoselect autosellen extdifftool perfile_attrs markbgcolor use_ttk
global hideremotes want_ttk maxrefs
@@ -2753,13 +2771,37 @@ proc savestuff {w} {
puts $f [list set want_ttk $want_ttk]
puts $f [list set bgcolor $bgcolor]
puts $f [list set fgcolor $fgcolor]
+ puts $f [list set uifgcolor $uifgcolor]
+ puts $f [list set uifgdisabledcolor $uifgdisabledcolor]
puts $f [list set colors $colors]
puts $f [list set diffcolors $diffcolors]
+ puts $f [list set mergecolors $mergecolors]
puts $f [list set markbgcolor $markbgcolor]
puts $f [list set diffcontext $diffcontext]
puts $f [list set selectbgcolor $selectbgcolor]
+ puts $f [list set foundbgcolor $foundbgcolor]
+ puts $f [list set currentsearchhitbgcolor $currentsearchhitbgcolor]
puts $f [list set extdifftool $extdifftool]
puts $f [list set perfile_attrs $perfile_attrs]
+ puts $f [list set headbgcolor $headbgcolor]
+ puts $f [list set headfgcolor $headfgcolor]
+ puts $f [list set headoutlinecolor $headoutlinecolor]
+ puts $f [list set remotebgcolor $remotebgcolor]
+ puts $f [list set tagbgcolor $tagbgcolor]
+ puts $f [list set tagfgcolor $tagfgcolor]
+ puts $f [list set tagoutlinecolor $tagoutlinecolor]
+ puts $f [list set reflinecolor $reflinecolor]
+ puts $f [list set filesepbgcolor $filesepbgcolor]
+ puts $f [list set filesepfgcolor $filesepfgcolor]
+ puts $f [list set linehoverbgcolor $linehoverbgcolor]
+ puts $f [list set linehoverfgcolor $linehoverfgcolor]
+ puts $f [list set linehoveroutlinecolor $linehoveroutlinecolor]
+ puts $f [list set mainheadcirclecolor $mainheadcirclecolor]
+ puts $f [list set workingfilescirclecolor $workingfilescirclecolor]
+ puts $f [list set indexcirclecolor $indexcirclecolor]
+ puts $f [list set circlecolors $circlecolors]
+ puts $f [list set linkfgcolor $linkfgcolor]
+ puts $f [list set circleoutlinecolor $circleoutlinecolor]
puts $f "set geometry(main) [wm geometry .]"
puts $f "set geometry(state) [wm state .]"
@@ -4617,6 +4659,8 @@ proc do_file_hl {serial} {
set gdtargs [concat -- $relative_paths]
} elseif {$gdttype eq [mc "adding/removing string:"]} {
set gdtargs [list "-S$highlight_files"]
+ } elseif {$gdttype eq [mc "changing lines matching:"]} {
+ set gdtargs [list "-G$highlight_files"]
} else {
# must be "containing:", i.e. we're searching commit info
return
@@ -5925,15 +5969,17 @@ proc drawcmittext {id row col} {
global linehtag linentag linedtag selectedline
global canvxmax boldids boldnameids fgcolor markedid
global mainheadid nullid nullid2 circleitem circlecolors ctxbut
+ global mainheadcirclecolor workingfilescirclecolor indexcirclecolor
+ global circleoutlinecolor
# listed is 0 for boundary, 1 for normal, 2 for negative, 3 for left, 4 for right
set listed $cmitlisted($curview,$id)
if {$id eq $nullid} {
- set ofill red
+ set ofill $workingfilescirclecolor
} elseif {$id eq $nullid2} {
- set ofill green
+ set ofill $indexcirclecolor
} elseif {$id eq $mainheadid} {
- set ofill yellow
+ set ofill $mainheadcirclecolor
} else {
set ofill [lindex $circlecolors $listed]
}
@@ -5943,21 +5989,21 @@ proc drawcmittext {id row col} {
if {$listed <= 2} {
set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
[expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
- -fill $ofill -outline $fgcolor -width 1 -tags circle]
+ -fill $ofill -outline $circleoutlinecolor -width 1 -tags circle]
} elseif {$listed == 3} {
# triangle pointing left for left-side commits
set t [$canv create polygon \
[expr {$x - $orad}] $y \
[expr {$x + $orad - 1}] [expr {$y - $orad}] \
[expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
- -fill $ofill -outline $fgcolor -width 1 -tags circle]
+ -fill $ofill -outline $circleoutlinecolor -width 1 -tags circle]
} else {
# triangle pointing right for right-side commits
set t [$canv create polygon \
[expr {$x + $orad - 1}] $y \
[expr {$x - $orad}] [expr {$y - $orad}] \
[expr {$x - $orad}] [expr {$y + $orad - 1}] \
- -fill $ofill -outline $fgcolor -width 1 -tags circle]
+ -fill $ofill -outline $circleoutlinecolor -width 1 -tags circle]
}
set circleitem($row) $t
$canv raise $t
@@ -6345,6 +6391,9 @@ proc drawtags {id x xt y1} {
global idtags idheads idotherrefs mainhead
global linespc lthickness
global canv rowtextx curview fgcolor bgcolor ctxbut
+ global headbgcolor headfgcolor headoutlinecolor remotebgcolor
+ global tagbgcolor tagfgcolor tagoutlinecolor
+ global reflinecolor
set marks {}
set ntags 0
@@ -6382,7 +6431,7 @@ proc drawtags {id x xt y1} {
set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
}
set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
- -width $lthickness -fill black -tags tag.$id]
+ -width $lthickness -fill $reflinecolor -tags tag.$id]
$canv lower $t
foreach tag $marks x $xvals wid $wvals {
set tag_quoted [string map {% %%} $tag]
@@ -6393,13 +6442,14 @@ proc drawtags {id x xt y1} {
# draw a tag
set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
$xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
- -width 1 -outline black -fill yellow -tags tag.$id]
+ -width 1 -outline $tagoutlinecolor -fill $tagbgcolor \
+ -tags tag.$id]
$canv bind $t <1> [list showtag $tag_quoted 1]
set rowtextx([rowofcommit $id]) [expr {$xr + $linespc}]
} else {
# draw a head or other ref
if {[incr nheads -1] >= 0} {
- set col green
+ set col $headbgcolor
if {$tag eq $mainhead} {
set font mainfontbold
}
@@ -6415,10 +6465,10 @@ proc drawtags {id x xt y1} {
set yti [expr {$yt + 1}]
set xri [expr {$x + $rwid}]
$canv create polygon $xi $yti $xri $yti $xri $yb $xi $yb \
- -width 0 -fill "#ffddaa" -tags tag.$id
+ -width 0 -fill $remotebgcolor -tags tag.$id
}
}
- set t [$canv create text $xl $y1 -anchor w -text $tag -fill $fgcolor \
+ set t [$canv create text $xl $y1 -anchor w -text $tag -fill $headfgcolor \
-font $font -tags [list tag.$id text]]
if {$ntags >= 0} {
$canv bind $t <1> [list showtag $tag_quoted 1]
@@ -6799,6 +6849,7 @@ proc appendwithlinks {text tags} {
proc setlink {id lk} {
global curview ctext pendinglinks
+ global linkfgcolor
if {[string range $id 0 1] eq "-g"} {
set id [string range $id 2 end]
@@ -6816,7 +6867,7 @@ proc setlink {id lk} {
set known [commitinview $id $curview]
}
if {$known} {
- $ctext tag conf $lk -foreground blue -underline 1
+ $ctext tag conf $lk -foreground $linkfgcolor -underline 1
$ctext tag bind $lk <1> [list selbyid $id]
$ctext tag bind $lk <Enter> {linkcursor %W 1}
$ctext tag bind $lk <Leave> {linkcursor %W -1}
@@ -7571,9 +7622,13 @@ proc diffcmd {ids flags} {
}
proc gettreediffs {ids} {
- global treediff treepending
+ global treediff treepending limitdiffs vfilelimit curview
- if {[catch {set gdtf [open [diffcmd $ids {--no-commit-id}] r]}]} return
+ set cmd [diffcmd $ids {--no-commit-id}]
+ if {$limitdiffs && $vfilelimit($curview) ne {}} {
+ set cmd [concat $cmd -- $vfilelimit($curview)]
+ }
+ if {[catch {set gdtf [open $cmd r]}]} return
set treepending $ids
set treediff {}
@@ -7617,17 +7672,7 @@ proc gettreediffline {gdtf ids} {
return [expr {$nr >= $max? 2: 1}]
}
close $gdtf
- if {$limitdiffs && $vfilelimit($curview) ne {}} {
- set flist {}
- foreach f $treediff {
- if {[path_filter $vfilelimit($curview) $f]} {
- lappend flist $f
- }
- }
- set treediffs($ids) $flist
- } else {
- set treediffs($ids) $treediff
- }
+ set treediffs($ids) $treediff
unset treepending
if {$cmitmode eq "tree" && [llength $diffids] == 1} {
gettree $diffids
@@ -8459,6 +8504,8 @@ proc lineleave {id} {
proc linehover {} {
global hoverx hovery hoverid hovertimer
global canv linespc lthickness
+ global linehoverbgcolor linehoverfgcolor linehoveroutlinecolor
+
global commitinfo
set text [lindex $commitinfo($hoverid) 0]
@@ -8472,10 +8519,11 @@ proc linehover {} {
set x1 [expr {$x + [font measure mainfont $text] + 2 * $lthickness}]
set y1 [expr {$y + $linespc + 2 * $lthickness}]
set t [$canv create rectangle $x0 $y0 $x1 $y1 \
- -fill \#ffff80 -outline black -width 1 -tags hover]
+ -fill $linehoverbgcolor -outline $linehoveroutlinecolor \
+ -width 1 -tags hover]
$canv raise $t
set t [$canv create text $x $y -anchor nw -text $text -tags hover \
- -font mainfont]
+ -font mainfont -fill $linehoverfgcolor]
$canv raise $t
}
@@ -9039,12 +9087,13 @@ proc domktag {} {
proc redrawtags {id} {
global canv linehtag idpos currentid curview cmitlisted markedid
global canvxmax iddrawn circleitem mainheadid circlecolors
+ global mainheadcirclecolor
if {![commitinview $id $curview]} return
if {![info exists iddrawn($id)]} return
set row [rowofcommit $id]
if {$id eq $mainheadid} {
- set ofill yellow
+ set ofill $mainheadcirclecolor
} else {
set ofill [lindex $circlecolors $cmitlisted($curview,$id)]
}
@@ -9301,6 +9350,67 @@ proc cherrypick {} {
notbusy cherrypick
}
+proc revert {} {
+ global rowmenuid curview
+ global mainhead mainheadid
+ global gitdir
+
+ set oldhead [exec git rev-parse HEAD]
+ set dheads [descheads $rowmenuid]
+ if { $dheads eq {} || [lsearch -exact $dheads $oldhead] == -1 } {
+ set ok [confirm_popup [mc "Commit %s is not\
+ included in branch %s -- really revert it?" \
+ [string range $rowmenuid 0 7] $mainhead]]
+ if {!$ok} return
+ }
+ nowbusy revert [mc "Reverting"]
+ update
+
+ if [catch {exec git revert --no-edit $rowmenuid} err] {
+ notbusy revert
+ if [regexp {files would be overwritten by merge:(\n(( |\t)+[^\n]+\n)+)}\
+ $err match files] {
+ regsub {\n( |\t)+} $files "\n" files
+ error_popup [mc "Revert failed because of local changes to\
+ the following files:%s Please commit, reset or stash \
+ your changes and try again." $files]
+ } elseif [regexp {error: could not revert} $err] {
+ if [confirm_popup [mc "Revert failed because of merge conflict.\n\
+ Do you wish to run git citool to resolve it?"]] {
+ # Force citool to read MERGE_MSG
+ file delete [file join $gitdir "GITGUI_MSG"]
+ exec_citool {} $rowmenuid
+ }
+ } else { error_popup $err }
+ run updatecommits
+ return
+ }
+
+ set newhead [exec git rev-parse HEAD]
+ if { $newhead eq $oldhead } {
+ notbusy revert
+ error_popup [mc "No changes committed"]
+ return
+ }
+
+ addnewchild $newhead $oldhead
+
+ if [commitinview $oldhead $curview] {
+ # XXX this isn't right if we have a path limit...
+ insertrow $newhead $oldhead $curview
+ if {$mainhead ne {}} {
+ movehead $newhead $mainhead
+ movedhead $newhead $mainhead
+ }
+ set mainheadid $newhead
+ redrawtags $oldhead
+ redrawtags $newhead
+ selbyid $newhead
+ }
+
+ notbusy revert
+}
+
proc resethead {} {
global mainhead rowmenuid confirm_ok resettype NS
@@ -10780,7 +10890,7 @@ proc showtag {tag isnew} {
set linknum 0
if {![info exists cached_tagcontent($tag)]} {
catch {
- set cached_tagcontent($tag) [exec git cat-file tag $tag]
+ set cached_tagcontent($tag) [exec git cat-file -p $tag]
}
}
if {[info exists cached_tagcontent($tag)]} {
@@ -11641,6 +11751,15 @@ if {[catch {package require Tk 8.4} err]} {
exit 1
}
+# on OSX bring the current Wish process window to front
+if {[tk windowingsystem] eq "aqua"} {
+ exec osascript -e [format {
+ tell application "System Events"
+ set frontmost of processes whose unix id is %d to true
+ end tell
+ } [pid] ]
+}
+
# Unset GIT_TRACE var if set
if { [info exists ::env(GIT_TRACE)] } {
unset ::env(GIT_TRACE)
@@ -11728,22 +11847,47 @@ if {[tk windowingsystem] eq "aqua"} {
set colors {green red blue magenta darkgrey brown orange}
if {[tk windowingsystem] eq "win32"} {
set uicolor SystemButtonFace
+ set uifgcolor SystemButtonText
+ set uifgdisabledcolor SystemDisabledText
set bgcolor SystemWindow
- set fgcolor SystemButtonText
+ set fgcolor SystemWindowText
set selectbgcolor SystemHighlight
} else {
set uicolor grey85
+ set uifgcolor black
+ set uifgdisabledcolor "#999"
set bgcolor white
set fgcolor black
set selectbgcolor gray85
}
set diffcolors {red "#00a000" blue}
set diffcontext 3
+set mergecolors {red blue green purple brown "#009090" magenta "#808000" "#009000" "#ff0080" cyan "#b07070" "#70b0f0" "#70f0b0" "#f0b070" "#ff70b0"}
set ignorespace 0
set worddiff ""
set markbgcolor "#e0e0ff"
+set headbgcolor green
+set headfgcolor black
+set headoutlinecolor black
+set remotebgcolor #ffddaa
+set tagbgcolor yellow
+set tagfgcolor black
+set tagoutlinecolor black
+set reflinecolor black
+set filesepbgcolor #aaaaaa
+set filesepfgcolor black
+set linehoverbgcolor #ffff80
+set linehoverfgcolor black
+set linehoveroutlinecolor black
+set mainheadcirclecolor yellow
+set workingfilescirclecolor red
+set indexcirclecolor green
set circlecolors {white blue gray blue blue}
+set linkfgcolor blue
+set circleoutlinecolor $fgcolor
+set foundbgcolor yellow
+set currentsearchhitbgcolor orange
# button for popping up context menus
if {[tk windowingsystem] eq "aqua"} {
diff --git a/gitk-git/po/sv.po b/gitk-git/po/sv.po
index 8cc98dc..df95e01 100644
--- a/gitk-git/po/sv.po
+++ b/gitk-git/po/sv.po
@@ -1,16 +1,16 @@
# Swedish translation for gitk
-# Copyright (C) 2005-2012 Paul Mackerras
+# Copyright (C) 2005-2013 Paul Mackerras
# This file is distributed under the same license as the gitk package.
#
# Mikael Magnusson <mikachu@gmail.com>, 2008.
-# Peter Krefting <peter@softwolves.pp.se>, 2008, 2009, 2010, 2012.
+# Peter Krefting <peter@softwolves.pp.se>, 2008, 2009, 2010, 2012, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: sv\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-10-03 08:09+0100\n"
-"PO-Revision-Date: 2012-10-03 08:13+0100\n"
+"POT-Creation-Date: 2013-05-16 08:06+0100\n"
+"PO-Revision-Date: 2013-05-16 08:12+0100\n"
"Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"Language: sv\n"
@@ -22,11 +22,11 @@ msgstr ""
msgid "Couldn't get list of unmerged files:"
msgstr "Kunde inte hämta lista över ej sammanslagna filer:"
-#: gitk:210 gitk:2317
+#: gitk:210 gitk:2334
msgid "Color words"
msgstr "Färga ord"
-#: gitk:215 gitk:2317 gitk:7888 gitk:7921
+#: gitk:215 gitk:2334 gitk:7977 gitk:8010
msgid "Markup words"
msgstr "Märk upp ord"
@@ -60,11 +60,11 @@ msgstr "Fel vid körning av git log:"
msgid "Reading"
msgstr "Läser"
-#: gitk:484 gitk:4353
+#: gitk:484 gitk:4409
msgid "Reading commits..."
msgstr "Läser incheckningar..."
-#: gitk:487 gitk:1625 gitk:4356
+#: gitk:487 gitk:1625 gitk:4412
msgid "No commits selected"
msgstr "Inga incheckningar markerade"
@@ -80,278 +80,286 @@ msgstr "Ingen incheckningsinformation är tillgänglig"
msgid "mc"
msgstr "mc"
-#: gitk:1911 gitk:4146 gitk:9282 gitk:10824 gitk:11100
+#: gitk:1911 gitk:4202 gitk:9437 gitk:10979 gitk:11258
msgid "OK"
msgstr "OK"
-#: gitk:1913 gitk:4148 gitk:8871 gitk:8950 gitk:9065 gitk:9114 gitk:9284
-#: gitk:10825 gitk:11101
+#: gitk:1913 gitk:4204 gitk:8964 gitk:9043 gitk:9159 gitk:9208 gitk:9439
+#: gitk:10980 gitk:11259
msgid "Cancel"
msgstr "Avbryt"
-#: gitk:2040
+#: gitk:2048
msgid "Update"
msgstr "Uppdatera"
-#: gitk:2041
+#: gitk:2049
msgid "Reload"
msgstr "Ladda om"
-#: gitk:2042
+#: gitk:2050
msgid "Reread references"
msgstr "Läs om referenser"
-#: gitk:2043
+#: gitk:2051
msgid "List references"
msgstr "Visa referenser"
-#: gitk:2045
+#: gitk:2053
msgid "Start git gui"
msgstr "Starta git gui"
-#: gitk:2047
+#: gitk:2055
msgid "Quit"
msgstr "Avsluta"
-#: gitk:2039
+#: gitk:2047
msgid "File"
msgstr "Arkiv"
-#: gitk:2051
+#: gitk:2059
msgid "Preferences"
msgstr "Inställningar"
-#: gitk:2050
+#: gitk:2058
msgid "Edit"
msgstr "Redigera"
-#: gitk:2055
+#: gitk:2063
msgid "New view..."
msgstr "Ny vy..."
-#: gitk:2056
+#: gitk:2064
msgid "Edit view..."
msgstr "Ändra vy..."
-#: gitk:2057
+#: gitk:2065
msgid "Delete view"
msgstr "Ta bort vy"
-#: gitk:2059
+#: gitk:2067
msgid "All files"
msgstr "Alla filer"
-#: gitk:2054 gitk:3899
+#: gitk:2062 gitk:3955
msgid "View"
msgstr "Visa"
-#: gitk:2064 gitk:2074 gitk:2869
+#: gitk:2072 gitk:2082 gitk:2925
msgid "About gitk"
msgstr "Om gitk"
-#: gitk:2065 gitk:2079
+#: gitk:2073 gitk:2087
msgid "Key bindings"
msgstr "Tangentbordsbindningar"
-#: gitk:2063 gitk:2078
+#: gitk:2071 gitk:2086
msgid "Help"
msgstr "Hjälp"
-#: gitk:2156 gitk:8330
+#: gitk:2164 gitk:8420
msgid "SHA1 ID:"
msgstr "SHA1-id:"
-#: gitk:2192
+#: gitk:2208
msgid "Row"
msgstr "Rad"
-#: gitk:2230
+#: gitk:2246
msgid "Find"
msgstr "Sök"
-#: gitk:2231
+#: gitk:2247
msgid "next"
msgstr "nästa"
-#: gitk:2232
+#: gitk:2248
msgid "prev"
msgstr "föreg"
-#: gitk:2233
+#: gitk:2249
msgid "commit"
msgstr "incheckning"
-#: gitk:2236 gitk:2238 gitk:4514 gitk:4537 gitk:4561 gitk:6528 gitk:6600
-#: gitk:6685
+#: gitk:2252 gitk:2254 gitk:4570 gitk:4593 gitk:4617 gitk:6592 gitk:6664
+#: gitk:6749
msgid "containing:"
msgstr "som innehåller:"
-#: gitk:2239 gitk:3381 gitk:3386 gitk:4590
+#: gitk:2255 gitk:3437 gitk:3442 gitk:4646
msgid "touching paths:"
msgstr "som rör sökväg:"
-#: gitk:2240 gitk:4604
+#: gitk:2256 gitk:4660
msgid "adding/removing string:"
msgstr "som lägger/till tar bort sträng:"
-#: gitk:2249 gitk:2251 gitk:4593
+#: gitk:2257 gitk:4662
+msgid "changing lines matching:"
+msgstr "ändrar rader som matchar:"
+
+#: gitk:2266 gitk:2268 gitk:4649
msgid "Exact"
msgstr "Exakt"
-#: gitk:2251 gitk:4679 gitk:6496
+#: gitk:2268 gitk:4737 gitk:6560
msgid "IgnCase"
msgstr "IgnVersaler"
-#: gitk:2251 gitk:4563 gitk:4677 gitk:6492
+#: gitk:2268 gitk:4619 gitk:4735 gitk:6556
msgid "Regexp"
msgstr "Reg.uttr."
-#: gitk:2253 gitk:2254 gitk:4699 gitk:4729 gitk:4736 gitk:6621 gitk:6689
+#: gitk:2270 gitk:2271 gitk:4757 gitk:4787 gitk:4794 gitk:6685 gitk:6753
msgid "All fields"
msgstr "Alla fält"
-#: gitk:2254 gitk:4696 gitk:4729 gitk:6559
+#: gitk:2271 gitk:4754 gitk:4787 gitk:6623
msgid "Headline"
msgstr "Rubrik"
-#: gitk:2255 gitk:4696 gitk:6559 gitk:6689 gitk:7126
+#: gitk:2272 gitk:4754 gitk:6623 gitk:6753 gitk:7221
msgid "Comments"
msgstr "Kommentarer"
-#: gitk:2255 gitk:4696 gitk:4701 gitk:4736 gitk:6559 gitk:7061 gitk:8505
-#: gitk:8520
+#: gitk:2272 gitk:4754 gitk:4759 gitk:4794 gitk:6623 gitk:7156 gitk:8598
+#: gitk:8613
msgid "Author"
msgstr "Författare"
-#: gitk:2255 gitk:4696 gitk:6559 gitk:7063
+#: gitk:2272 gitk:4754 gitk:6623 gitk:7158
msgid "Committer"
msgstr "Incheckare"
-#: gitk:2286
+#: gitk:2303
msgid "Search"
msgstr "Sök"
-#: gitk:2294
+#: gitk:2311
msgid "Diff"
msgstr "Diff"
-#: gitk:2296
+#: gitk:2313
msgid "Old version"
msgstr "Gammal version"
-#: gitk:2298
+#: gitk:2315
msgid "New version"
msgstr "Ny version"
-#: gitk:2300
+#: gitk:2317
msgid "Lines of context"
msgstr "Rader sammanhang"
-#: gitk:2310
+#: gitk:2327
msgid "Ignore space change"
msgstr "Ignorera ändringar i blanksteg"
-#: gitk:2314 gitk:2316 gitk:7646 gitk:7874
+#: gitk:2331 gitk:2333 gitk:7735 gitk:7963
msgid "Line diff"
msgstr "Rad-diff"
-#: gitk:2379
+#: gitk:2397
msgid "Patch"
msgstr "Patch"
-#: gitk:2381
+#: gitk:2399
msgid "Tree"
msgstr "Träd"
-#: gitk:2540 gitk:2559
+#: gitk:2557 gitk:2577
msgid "Diff this -> selected"
msgstr "Diff denna -> markerad"
-#: gitk:2541 gitk:2560
+#: gitk:2558 gitk:2578
msgid "Diff selected -> this"
msgstr "Diff markerad -> denna"
-#: gitk:2542 gitk:2561
+#: gitk:2559 gitk:2579
msgid "Make patch"
msgstr "Skapa patch"
-#: gitk:2543 gitk:8929
+#: gitk:2560 gitk:9022
msgid "Create tag"
msgstr "Skapa tagg"
-#: gitk:2544 gitk:9045
+#: gitk:2561 gitk:9139
msgid "Write commit to file"
msgstr "Skriv incheckning till fil"
-#: gitk:2545 gitk:9102
+#: gitk:2562 gitk:9196
msgid "Create new branch"
msgstr "Skapa ny gren"
-#: gitk:2546
+#: gitk:2563
msgid "Cherry-pick this commit"
msgstr "Plocka denna incheckning"
-#: gitk:2547
+#: gitk:2564
msgid "Reset HEAD branch to here"
msgstr "Återställ HEAD-grenen hit"
-#: gitk:2548
+#: gitk:2565
msgid "Mark this commit"
msgstr "Markera denna incheckning"
-#: gitk:2549
+#: gitk:2566
msgid "Return to mark"
msgstr "Återgå till markering"
-#: gitk:2550
+#: gitk:2567
msgid "Find descendant of this and mark"
msgstr "Hitta efterföljare till denna och markera"
-#: gitk:2551
+#: gitk:2568
msgid "Compare with marked commit"
msgstr "Jämför med markerad incheckning"
-#: gitk:2552 gitk:2562
+#: gitk:2569 gitk:2580
msgid "Diff this -> marked commit"
msgstr "Diff denna -> markerad incheckning"
-#: gitk:2553 gitk:2563
+#: gitk:2570 gitk:2581
msgid "Diff marked commit -> this"
msgstr "Diff markerad incheckning -> denna"
-#: gitk:2569
+#: gitk:2571
+msgid "Revert this commit"
+msgstr "Ã…ngra denna incheckning"
+
+#: gitk:2587
msgid "Check out this branch"
msgstr "Checka ut denna gren"
-#: gitk:2570
+#: gitk:2588
msgid "Remove this branch"
msgstr "Ta bort denna gren"
-#: gitk:2577
+#: gitk:2595
msgid "Highlight this too"
msgstr "Markera även detta"
-#: gitk:2578
+#: gitk:2596
msgid "Highlight this only"
msgstr "Markera bara detta"
-#: gitk:2579
+#: gitk:2597
msgid "External diff"
msgstr "Extern diff"
-#: gitk:2580
+#: gitk:2598
msgid "Blame parent commit"
msgstr "Klandra föräldraincheckning"
-#: gitk:2587
+#: gitk:2605
msgid "Show origin of this line"
msgstr "Visa ursprunget för den här raden"
-#: gitk:2588
+#: gitk:2606
msgid "Run git gui blame on this line"
msgstr "Kör git gui blame på den här raden"
-#: gitk:2871
+#: gitk:2927
msgid ""
"\n"
"Gitk - a commit viewer for git\n"
@@ -367,302 +375,302 @@ msgstr ""
"\n"
"Använd och vidareförmedla enligt villkoren i GNU General Public License"
-#: gitk:2879 gitk:2944 gitk:9468
+#: gitk:2935 gitk:3000 gitk:9623
msgid "Close"
msgstr "Stäng"
-#: gitk:2900
+#: gitk:2956
msgid "Gitk key bindings"
msgstr "Tangentbordsbindningar för Gitk"
-#: gitk:2903
+#: gitk:2959
msgid "Gitk key bindings:"
msgstr "Tangentbordsbindningar för Gitk:"
-#: gitk:2905
+#: gitk:2961
#, tcl-format
msgid "<%s-Q>\t\tQuit"
msgstr "<%s-Q>\t\tAvsluta"
-#: gitk:2906
+#: gitk:2962
#, tcl-format
msgid "<%s-W>\t\tClose window"
msgstr "<%s-W>\t\tStäng fönster"
-#: gitk:2907
+#: gitk:2963
msgid "<Home>\t\tMove to first commit"
msgstr "<Home>\t\tGå till första incheckning"
-#: gitk:2908
+#: gitk:2964
msgid "<End>\t\tMove to last commit"
msgstr "<End>\t\tGÃ¥ till sista incheckning"
-#: gitk:2909
+#: gitk:2965
msgid "<Up>, p, k\tMove up one commit"
msgstr "<Upp>, p, k\tGÃ¥ en incheckning upp"
-#: gitk:2910
+#: gitk:2966
msgid "<Down>, n, j\tMove down one commit"
msgstr "<Ned>, n, j\tGÃ¥ en incheckning ned"
-#: gitk:2911
+#: gitk:2967
msgid "<Left>, z, h\tGo back in history list"
msgstr "<Vänster>, z, h\tGå bakåt i historiken"
-#: gitk:2912
+#: gitk:2968
msgid "<Right>, x, l\tGo forward in history list"
msgstr "<Höger>, x, l\tGå framåt i historiken"
-#: gitk:2913
+#: gitk:2969
msgid "<PageUp>\tMove up one page in commit list"
msgstr "<PageUp>\tGÃ¥ upp en sida i incheckningslistan"
-#: gitk:2914
+#: gitk:2970
msgid "<PageDown>\tMove down one page in commit list"
msgstr "<PageDown>\tGÃ¥ ned en sida i incheckningslistan"
-#: gitk:2915
+#: gitk:2971
#, tcl-format
msgid "<%s-Home>\tScroll to top of commit list"
msgstr "<%s-Home>\tRulla till början av incheckningslistan"
-#: gitk:2916
+#: gitk:2972
#, tcl-format
msgid "<%s-End>\tScroll to bottom of commit list"
msgstr "<%s-End>\tRulla till slutet av incheckningslistan"
-#: gitk:2917
+#: gitk:2973
#, tcl-format
msgid "<%s-Up>\tScroll commit list up one line"
msgstr "<%s-Upp>\tRulla incheckningslistan upp ett steg"
-#: gitk:2918
+#: gitk:2974
#, tcl-format
msgid "<%s-Down>\tScroll commit list down one line"
msgstr "<%s-Ned>\tRulla incheckningslistan ned ett steg"
-#: gitk:2919
+#: gitk:2975
#, tcl-format
msgid "<%s-PageUp>\tScroll commit list up one page"
msgstr "<%s-PageUp>\tRulla incheckningslistan upp en sida"
-#: gitk:2920
+#: gitk:2976
#, tcl-format
msgid "<%s-PageDown>\tScroll commit list down one page"
msgstr "<%s-PageDown>\tRulla incheckningslistan ned en sida"
-#: gitk:2921
+#: gitk:2977
msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
msgstr "<Skift-Upp>\tSök bakåt (uppåt, senare incheckningar)"
-#: gitk:2922
+#: gitk:2978
msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
msgstr "<Skift-Ned>\tSök framåt (nedåt, tidigare incheckningar)"
-#: gitk:2923
+#: gitk:2979
msgid "<Delete>, b\tScroll diff view up one page"
msgstr "<Delete>, b\tRulla diffvisningen upp en sida"
-#: gitk:2924
+#: gitk:2980
msgid "<Backspace>\tScroll diff view up one page"
msgstr "<Baksteg>\tRulla diffvisningen upp en sida"
-#: gitk:2925
+#: gitk:2981
msgid "<Space>\t\tScroll diff view down one page"
msgstr "<Blanksteg>\tRulla diffvisningen ned en sida"
-#: gitk:2926
+#: gitk:2982
msgid "u\t\tScroll diff view up 18 lines"
msgstr "u\t\tRulla diffvisningen upp 18 rader"
-#: gitk:2927
+#: gitk:2983
msgid "d\t\tScroll diff view down 18 lines"
msgstr "d\t\tRulla diffvisningen ned 18 rader"
-#: gitk:2928
+#: gitk:2984
#, tcl-format
msgid "<%s-F>\t\tFind"
msgstr "<%s-F>\t\tSök"
-#: gitk:2929
+#: gitk:2985
#, tcl-format
msgid "<%s-G>\t\tMove to next find hit"
msgstr "<%s-G>\t\tGå till nästa sökträff"
-#: gitk:2930
+#: gitk:2986
msgid "<Return>\tMove to next find hit"
msgstr "<Return>\t\tGå till nästa sökträff"
-#: gitk:2931
+#: gitk:2987
msgid "/\t\tFocus the search box"
msgstr "/\t\tFokusera sökrutan"
-#: gitk:2932
+#: gitk:2988
msgid "?\t\tMove to previous find hit"
msgstr "?\t\tGå till föregående sökträff"
-#: gitk:2933
+#: gitk:2989
msgid "f\t\tScroll diff view to next file"
msgstr "f\t\tRulla diffvisningen till nästa fil"
-#: gitk:2934
+#: gitk:2990
#, tcl-format
msgid "<%s-S>\t\tSearch for next hit in diff view"
msgstr "<%s-S>\t\tGå till nästa sökträff i diffvisningen"
-#: gitk:2935
+#: gitk:2991
#, tcl-format
msgid "<%s-R>\t\tSearch for previous hit in diff view"
msgstr "<%s-R>\t\tGå till föregående sökträff i diffvisningen"
-#: gitk:2936
+#: gitk:2992
#, tcl-format
msgid "<%s-KP+>\tIncrease font size"
msgstr "<%s-Num+>\tÖka teckenstorlek"
-#: gitk:2937
+#: gitk:2993
#, tcl-format
msgid "<%s-plus>\tIncrease font size"
msgstr "<%s-plus>\tÖka teckenstorlek"
-#: gitk:2938
+#: gitk:2994
#, tcl-format
msgid "<%s-KP->\tDecrease font size"
msgstr "<%s-Num->\tMinska teckenstorlek"
-#: gitk:2939
+#: gitk:2995
#, tcl-format
msgid "<%s-minus>\tDecrease font size"
msgstr "<%s-minus>\tMinska teckenstorlek"
-#: gitk:2940
+#: gitk:2996
msgid "<F5>\t\tUpdate"
msgstr "<F5>\t\tUppdatera"
-#: gitk:3395 gitk:3404
+#: gitk:3451 gitk:3460
#, tcl-format
msgid "Error creating temporary directory %s:"
msgstr "Fel vid skapande av temporär katalog %s:"
-#: gitk:3417
+#: gitk:3473
#, tcl-format
msgid "Error getting \"%s\" from %s:"
msgstr "Fel vid hämtning av \"%s\" från %s:"
-#: gitk:3480
+#: gitk:3536
msgid "command failed:"
msgstr "kommando misslyckades:"
-#: gitk:3629
+#: gitk:3685
msgid "No such commit"
msgstr "Incheckning saknas"
-#: gitk:3643
+#: gitk:3699
msgid "git gui blame: command failed:"
msgstr "git gui blame: kommando misslyckades:"
-#: gitk:3674
+#: gitk:3730
#, tcl-format
msgid "Couldn't read merge head: %s"
msgstr "Kunde inte läsa sammanslagningshuvud: %s"
-#: gitk:3682
+#: gitk:3738
#, tcl-format
msgid "Error reading index: %s"
msgstr "Fel vid läsning av index: %s"
-#: gitk:3707
+#: gitk:3763
#, tcl-format
msgid "Couldn't start git blame: %s"
msgstr "Kunde inte starta git blame: %s"
-#: gitk:3710 gitk:6527
+#: gitk:3766 gitk:6591
msgid "Searching"
msgstr "Söker"
-#: gitk:3742
+#: gitk:3798
#, tcl-format
msgid "Error running git blame: %s"
msgstr "Fel vid körning av git blame: %s"
-#: gitk:3770
+#: gitk:3826
#, tcl-format
msgid "That line comes from commit %s, which is not in this view"
msgstr "Raden kommer från incheckningen %s, som inte finns i denna vy"
-#: gitk:3784
+#: gitk:3840
msgid "External diff viewer failed:"
msgstr "Externt diff-verktyg misslyckades:"
-#: gitk:3902
+#: gitk:3958
msgid "Gitk view definition"
msgstr "Definition av Gitk-vy"
-#: gitk:3906
+#: gitk:3962
msgid "Remember this view"
msgstr "Spara denna vy"
-#: gitk:3907
+#: gitk:3963
msgid "References (space separated list):"
msgstr "Referenser (blankstegsavdelad lista):"
-#: gitk:3908
+#: gitk:3964
msgid "Branches & tags:"
msgstr "Grenar & taggar:"
-#: gitk:3909
+#: gitk:3965
msgid "All refs"
msgstr "Alla referenser"
-#: gitk:3910
+#: gitk:3966
msgid "All (local) branches"
msgstr "Alla (lokala) grenar"
-#: gitk:3911
+#: gitk:3967
msgid "All tags"
msgstr "Alla taggar"
-#: gitk:3912
+#: gitk:3968
msgid "All remote-tracking branches"
msgstr "Alla fjärrspårande grenar"
-#: gitk:3913
+#: gitk:3969
msgid "Commit Info (regular expressions):"
msgstr "Incheckningsinfo (reguljära uttryck):"
-#: gitk:3914
+#: gitk:3970
msgid "Author:"
msgstr "Författare:"
-#: gitk:3915
+#: gitk:3971
msgid "Committer:"
msgstr "Incheckare:"
-#: gitk:3916
+#: gitk:3972
msgid "Commit Message:"
msgstr "Incheckningsmeddelande:"
-#: gitk:3917
+#: gitk:3973
msgid "Matches all Commit Info criteria"
msgstr "Motsvarar alla kriterier för incheckningsinfo"
-#: gitk:3918
+#: gitk:3974
msgid "Changes to Files:"
msgstr "Ändringar av filer:"
-#: gitk:3919
+#: gitk:3975
msgid "Fixed String"
msgstr "Fast sträng"
-#: gitk:3920
+#: gitk:3976
msgid "Regular Expression"
msgstr "Reguljärt uttryck"
-#: gitk:3921
+#: gitk:3977
msgid "Search string:"
msgstr "Söksträng:"
-#: gitk:3922
+#: gitk:3978
msgid ""
"Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 "
"15:27:38\"):"
@@ -670,197 +678,201 @@ msgstr ""
"Incheckingsdatum (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 "
"15:27:38\"):"
-#: gitk:3923
+#: gitk:3979
msgid "Since:"
msgstr "Från:"
-#: gitk:3924
+#: gitk:3980
msgid "Until:"
msgstr "Till:"
-#: gitk:3925
+#: gitk:3981
msgid "Limit and/or skip a number of revisions (positive integer):"
msgstr "Begränsa och/eller hoppa över ett antal revisioner (positivt heltal):"
-#: gitk:3926
+#: gitk:3982
msgid "Number to show:"
msgstr "Antal att visa:"
-#: gitk:3927
+#: gitk:3983
msgid "Number to skip:"
msgstr "Antal att hoppa över:"
-#: gitk:3928
+#: gitk:3984
msgid "Miscellaneous options:"
msgstr "Diverse alternativ:"
-#: gitk:3929
+#: gitk:3985
msgid "Strictly sort by date"
msgstr "Strikt datumsortering"
-#: gitk:3930
+#: gitk:3986
msgid "Mark branch sides"
msgstr "Markera sidogrenar"
-#: gitk:3931
+#: gitk:3987
msgid "Limit to first parent"
msgstr "Begränsa till första förälder"
-#: gitk:3932
+#: gitk:3988
msgid "Simple history"
msgstr "Enkel historik"
-#: gitk:3933
+#: gitk:3989
msgid "Additional arguments to git log:"
msgstr "Ytterligare argument till git log:"
-#: gitk:3934
+#: gitk:3990
msgid "Enter files and directories to include, one per line:"
msgstr "Ange filer och kataloger att ta med, en per rad:"
-#: gitk:3935
+#: gitk:3991
msgid "Command to generate more commits to include:"
msgstr "Kommando för att generera fler incheckningar att ta med:"
-#: gitk:4059
+#: gitk:4115
msgid "Gitk: edit view"
msgstr "Gitk: redigera vy"
-#: gitk:4067
+#: gitk:4123
msgid "-- criteria for selecting revisions"
msgstr " - kriterier för val av revisioner"
-#: gitk:4072
+#: gitk:4128
msgid "View Name"
msgstr "Namn på vy"
-#: gitk:4147
+#: gitk:4203
msgid "Apply (F5)"
msgstr "Använd (F5)"
-#: gitk:4185
+#: gitk:4241
msgid "Error in commit selection arguments:"
msgstr "Fel i argument för val av incheckningar:"
-#: gitk:4238 gitk:4290 gitk:4749 gitk:4763 gitk:6027 gitk:11849 gitk:11850
+#: gitk:4294 gitk:4346 gitk:4807 gitk:4821 gitk:6087 gitk:12041 gitk:12042
msgid "None"
msgstr "Inget"
-#: gitk:4846 gitk:4851
+#: gitk:4904 gitk:4909
msgid "Descendant"
msgstr "Avkomling"
-#: gitk:4847
+#: gitk:4905
msgid "Not descendant"
msgstr "Inte avkomling"
-#: gitk:4854 gitk:4859
+#: gitk:4912 gitk:4917
msgid "Ancestor"
msgstr "Förfader"
-#: gitk:4855
+#: gitk:4913
msgid "Not ancestor"
msgstr "Inte förfader"
-#: gitk:5145
+#: gitk:5203
msgid "Local changes checked in to index but not committed"
msgstr "Lokala ändringar sparade i indexet men inte incheckade"
-#: gitk:5181
+#: gitk:5239
msgid "Local uncommitted changes, not checked in to index"
msgstr "Lokala ändringar, ej sparade i indexet"
-#: gitk:6882
+#: gitk:6971
+msgid "and many more"
+msgstr "med många flera"
+
+#: gitk:6974
msgid "many"
msgstr "många"
-#: gitk:7065
+#: gitk:7160
msgid "Tags:"
msgstr "Taggar:"
-#: gitk:7082 gitk:7088 gitk:8500
+#: gitk:7177 gitk:7183 gitk:8593
msgid "Parent"
msgstr "Förälder"
-#: gitk:7093
+#: gitk:7188
msgid "Child"
msgstr "Barn"
-#: gitk:7102
+#: gitk:7197
msgid "Branch"
msgstr "Gren"
-#: gitk:7105
+#: gitk:7200
msgid "Follows"
msgstr "Följer"
-#: gitk:7108
+#: gitk:7203
msgid "Precedes"
msgstr "Föregår"
-#: gitk:7653
+#: gitk:7742
#, tcl-format
msgid "Error getting diffs: %s"
msgstr "Fel vid hämtning av diff: %s"
-#: gitk:8328
+#: gitk:8418
msgid "Goto:"
msgstr "GÃ¥ till:"
-#: gitk:8349
+#: gitk:8439
#, tcl-format
msgid "Short SHA1 id %s is ambiguous"
msgstr "Förkortat SHA1-id %s är tvetydigt"
-#: gitk:8356
+#: gitk:8446
#, tcl-format
msgid "Revision %s is not known"
msgstr "Revisionen %s är inte känd"
-#: gitk:8366
+#: gitk:8456
#, tcl-format
msgid "SHA1 id %s is not known"
msgstr "SHA-id:t %s är inte känt"
-#: gitk:8368
+#: gitk:8458
#, tcl-format
msgid "Revision %s is not in the current view"
msgstr "Revisionen %s finns inte i den nuvarande vyn"
-#: gitk:8507 gitk:8522
+#: gitk:8600 gitk:8615
msgid "Date"
msgstr "Datum"
-#: gitk:8510
+#: gitk:8603
msgid "Children"
msgstr "Barn"
-#: gitk:8573
+#: gitk:8666
#, tcl-format
msgid "Reset %s branch to here"
msgstr "Återställ grenen %s hit"
-#: gitk:8575
+#: gitk:8668
msgid "Detached head: can't reset"
msgstr "Frånkopplad head: kan inte återställa"
-#: gitk:8680 gitk:8686
+#: gitk:8773 gitk:8779
msgid "Skipping merge commit "
msgstr "Hoppar över sammanslagningsincheckning "
-#: gitk:8695 gitk:8700
+#: gitk:8788 gitk:8793
msgid "Error getting patch ID for "
msgstr "Fel vid hämtning av patch-id för "
-#: gitk:8696 gitk:8701
+#: gitk:8789 gitk:8794
msgid " - stopping\n"
msgstr " - stannar\n"
-#: gitk:8706 gitk:8709 gitk:8717 gitk:8731 gitk:8740
+#: gitk:8799 gitk:8802 gitk:8810 gitk:8824 gitk:8833
msgid "Commit "
msgstr "Incheckning "
-#: gitk:8710
+#: gitk:8803
msgid ""
" is the same patch as\n"
" "
@@ -868,7 +880,7 @@ msgstr ""
" är samma patch som\n"
" "
-#: gitk:8718
+#: gitk:8811
msgid ""
" differs from\n"
" "
@@ -876,7 +888,7 @@ msgstr ""
" skiljer sig från\n"
" "
-#: gitk:8720
+#: gitk:8813
msgid ""
"Diff of commits:\n"
"\n"
@@ -884,131 +896,131 @@ msgstr ""
"Skillnad mellan incheckningar:\n"
"\n"
-#: gitk:8732 gitk:8741
+#: gitk:8825 gitk:8834
#, tcl-format
msgid " has %s children - stopping\n"
msgstr " har %s barn - stannar\n"
-#: gitk:8760
+#: gitk:8853
#, tcl-format
msgid "Error writing commit to file: %s"
msgstr "Fel vid skrivning av incheckning till fil: %s"
-#: gitk:8766
+#: gitk:8859
#, tcl-format
msgid "Error diffing commits: %s"
msgstr "Fel vid jämförelse av incheckningar: %s"
-#: gitk:8812
+#: gitk:8905
msgid "Top"
msgstr "Topp"
-#: gitk:8813
+#: gitk:8906
msgid "From"
msgstr "Från"
-#: gitk:8818
+#: gitk:8911
msgid "To"
msgstr "Till"
-#: gitk:8842
+#: gitk:8935
msgid "Generate patch"
msgstr "Generera patch"
-#: gitk:8844
+#: gitk:8937
msgid "From:"
msgstr "Från:"
-#: gitk:8853
+#: gitk:8946
msgid "To:"
msgstr "Till:"
-#: gitk:8862
+#: gitk:8955
msgid "Reverse"
msgstr "Vänd"
-#: gitk:8864 gitk:9059
+#: gitk:8957 gitk:9153
msgid "Output file:"
msgstr "Utdatafil:"
-#: gitk:8870
+#: gitk:8963
msgid "Generate"
msgstr "Generera"
-#: gitk:8908
+#: gitk:9001
msgid "Error creating patch:"
msgstr "Fel vid generering av patch:"
-#: gitk:8931 gitk:9047 gitk:9104
+#: gitk:9024 gitk:9141 gitk:9198
msgid "ID:"
msgstr "Id:"
-#: gitk:8940
+#: gitk:9033
msgid "Tag name:"
msgstr "Taggnamn:"
-#: gitk:8943
+#: gitk:9036
msgid "Tag message is optional"
msgstr "Taggmeddelandet är valfritt"
-#: gitk:8945
+#: gitk:9038
msgid "Tag message:"
msgstr "Taggmeddelande:"
-#: gitk:8949 gitk:9113
+#: gitk:9042 gitk:9207
msgid "Create"
msgstr "Skapa"
-#: gitk:8967
+#: gitk:9060
msgid "No tag name specified"
msgstr "Inget taggnamn angavs"
-#: gitk:8971
+#: gitk:9064
#, tcl-format
msgid "Tag \"%s\" already exists"
msgstr "Taggen \"%s\" finns redan"
-#: gitk:8981
+#: gitk:9074
msgid "Error creating tag:"
msgstr "Fel vid skapande av tagg:"
-#: gitk:9056
+#: gitk:9150
msgid "Command:"
msgstr "Kommando:"
-#: gitk:9064
+#: gitk:9158
msgid "Write"
msgstr "Skriv"
-#: gitk:9082
+#: gitk:9176
msgid "Error writing commit:"
msgstr "Fel vid skrivning av incheckning:"
-#: gitk:9109
+#: gitk:9203
msgid "Name:"
msgstr "Namn:"
-#: gitk:9132
+#: gitk:9226
msgid "Please specify a name for the new branch"
msgstr "Ange ett namn för den nya grenen"
-#: gitk:9137
+#: gitk:9231
#, tcl-format
msgid "Branch '%s' already exists. Overwrite?"
msgstr "Grenen \"%s\" finns redan. Skriva över?"
-#: gitk:9204
+#: gitk:9298
#, tcl-format
msgid "Commit %s is already included in branch %s -- really re-apply it?"
msgstr ""
"Incheckningen %s finns redan på grenen %s -- skall den verkligen appliceras "
"på nytt?"
-#: gitk:9209
+#: gitk:9303
msgid "Cherry-picking"
msgstr "Plockar"
-#: gitk:9218
+#: gitk:9312
#, tcl-format
msgid ""
"Cherry-pick failed because of local changes to file '%s'.\n"
@@ -1018,7 +1030,7 @@ msgstr ""
"Checka in, återställ eller spara undan (stash) dina ändringar och försök "
"igen."
-#: gitk:9224
+#: gitk:9318
msgid ""
"Cherry-pick failed because of merge conflict.\n"
"Do you wish to run git citool to resolve it?"
@@ -1026,32 +1038,59 @@ msgstr ""
"Cherry-pick misslyckades på grund av en sammanslagningskonflikt.\n"
"Vill du köra git citool för att lösa den?"
-#: gitk:9240
+#: gitk:9334 gitk:9392
msgid "No changes committed"
msgstr "Inga ändringar incheckade"
-#: gitk:9266
+#: gitk:9361
+#, tcl-format
+msgid "Commit %s is not included in branch %s -- really revert it?"
+msgstr "Incheckningen %s finns inte på grenen %s -- vill du verkligen ångra?"
+
+#: gitk:9366
+msgid "Reverting"
+msgstr "Ã…ngrar"
+
+#: gitk:9374
+#, tcl-format
+msgid ""
+"Revert failed because of local changes to the following files:%s Please "
+"commit, reset or stash your changes and try again."
+msgstr ""
+"Misslyckades med att ångra på grund av lokala ändringar i följande filer:%s. "
+"Checka in, återställ eller spara undan (stash) dina ändringar och försök "
+"igen."
+
+#: gitk:9378
+msgid ""
+"Revert failed because of merge conflict.\n"
+" Do you wish to run git citool to resolve it?"
+msgstr ""
+"Misslyckades med att ångra på grund av en sammanslagningskonflikt.\n"
+" Vill du köra git citool för att lösa den?"
+
+#: gitk:9421
msgid "Confirm reset"
msgstr "Bekräfta återställning"
-#: gitk:9268
+#: gitk:9423
#, tcl-format
msgid "Reset branch %s to %s?"
msgstr "Återställa grenen %s till %s?"
-#: gitk:9270
+#: gitk:9425
msgid "Reset type:"
msgstr "Typ av återställning:"
-#: gitk:9273
+#: gitk:9428
msgid "Soft: Leave working tree and index untouched"
msgstr "Mjuk: Rör inte utcheckning och index"
-#: gitk:9276
+#: gitk:9431
msgid "Mixed: Leave working tree untouched, reset index"
msgstr "Blandad: Rör inte utcheckning, återställ index"
-#: gitk:9279
+#: gitk:9434
msgid ""
"Hard: Reset working tree and index\n"
"(discard ALL local changes)"
@@ -1059,19 +1098,19 @@ msgstr ""
"Hård: Återställ utcheckning och index\n"
"(förkastar ALLA lokala ändringar)"
-#: gitk:9296
+#: gitk:9451
msgid "Resetting"
msgstr "Återställer"
-#: gitk:9356
+#: gitk:9511
msgid "Checking out"
msgstr "Checkar ut"
-#: gitk:9409
+#: gitk:9564
msgid "Cannot delete the currently checked-out branch"
msgstr "Kan inte ta bort den just nu utcheckade grenen"
-#: gitk:9415
+#: gitk:9570
#, tcl-format
msgid ""
"The commits on branch %s aren't on any other branch.\n"
@@ -1080,16 +1119,16 @@ msgstr ""
"Incheckningarna på grenen %s existerar inte på någon annan gren.\n"
"Vill du verkligen ta bort grenen %s?"
-#: gitk:9446
+#: gitk:9601
#, tcl-format
msgid "Tags and heads: %s"
msgstr "Taggar och huvuden: %s"
-#: gitk:9461
+#: gitk:9616
msgid "Filter"
msgstr "Filter"
-#: gitk:9757
+#: gitk:9912
msgid ""
"Error reading commit topology information; branch and preceding/following "
"tag information will be incomplete."
@@ -1097,210 +1136,214 @@ msgstr ""
"Fel vid läsning av information om incheckningstopologi; information om "
"grenar och föregående/senare taggar kommer inte vara komplett."
-#: gitk:10744
+#: gitk:10899
msgid "Tag"
msgstr "Tagg"
-#: gitk:10744
+#: gitk:10899
msgid "Id"
msgstr "Id"
-#: gitk:10793
+#: gitk:10948
msgid "Gitk font chooser"
msgstr "Teckensnittsväljare för Gitk"
-#: gitk:10810
+#: gitk:10965
msgid "B"
msgstr "F"
-#: gitk:10813
+#: gitk:10968
msgid "I"
msgstr "K"
-#: gitk:10931
+#: gitk:11086
msgid "Commit list display options"
msgstr "Alternativ för incheckningslistvy"
-#: gitk:10934
+#: gitk:11089
msgid "Maximum graph width (lines)"
msgstr "Maximal grafbredd (rader)"
-#: gitk:10937
+#: gitk:11092
#, tcl-format
msgid "Maximum graph width (% of pane)"
msgstr "Maximal grafbredd (% av ruta)"
-#: gitk:10940
+#: gitk:11095
msgid "Show local changes"
msgstr "Visa lokala ändringar"
-#: gitk:10943
+#: gitk:11098
msgid "Auto-select SHA1 (length)"
msgstr "Välj SHA1 (längd) automatiskt"
-#: gitk:10947
+#: gitk:11102
msgid "Hide remote refs"
msgstr "Dölj fjärr-referenser"
-#: gitk:10951
+#: gitk:11106
msgid "Diff display options"
msgstr "Alternativ för diffvy"
-#: gitk:10953
+#: gitk:11108
msgid "Tab spacing"
msgstr "Blanksteg för tabulatortecken"
-#: gitk:10956
-msgid "Display nearby tags"
-msgstr "Visa närliggande taggar"
+#: gitk:11111
+msgid "Display nearby tags/heads"
+msgstr "Visa närliggande taggar/huvuden"
+
+#: gitk:11114
+msgid "Maximum # tags/heads to show"
+msgstr "Maximalt antal taggar/huvuden att visa"
-#: gitk:10959
+#: gitk:11117
msgid "Limit diffs to listed paths"
msgstr "Begränsa diff till listade sökvägar"
-#: gitk:10962
+#: gitk:11120
msgid "Support per-file encodings"
msgstr "Stöd för filspecifika teckenkodningar"
-#: gitk:10968 gitk:11115
+#: gitk:11126 gitk:11273
msgid "External diff tool"
msgstr "Externt diff-verktyg"
-#: gitk:10969
+#: gitk:11127
msgid "Choose..."
msgstr "Välj..."
-#: gitk:10974
+#: gitk:11132
msgid "General options"
msgstr "Allmänna inställningar"
-#: gitk:10977
+#: gitk:11135
msgid "Use themed widgets"
msgstr "Använd tema på fönsterelement"
-#: gitk:10979
+#: gitk:11137
msgid "(change requires restart)"
msgstr "(ändringen kräver omstart)"
-#: gitk:10981
+#: gitk:11139
msgid "(currently unavailable)"
msgstr "(för närvarande inte tillgängligt)"
-#: gitk:10992
+#: gitk:11150
msgid "Colors: press to choose"
msgstr "Färger: tryck för att välja"
-#: gitk:10995
+#: gitk:11153
msgid "Interface"
msgstr "Gränssnitt"
-#: gitk:10996
+#: gitk:11154
msgid "interface"
msgstr "gränssnitt"
-#: gitk:10999
+#: gitk:11157
msgid "Background"
msgstr "Bakgrund"
-#: gitk:11000 gitk:11030
+#: gitk:11158 gitk:11188
msgid "background"
msgstr "bakgrund"
-#: gitk:11003
+#: gitk:11161
msgid "Foreground"
msgstr "Förgrund"
-#: gitk:11004
+#: gitk:11162
msgid "foreground"
msgstr "förgrund"
-#: gitk:11007
+#: gitk:11165
msgid "Diff: old lines"
msgstr "Diff: gamla rader"
-#: gitk:11008
+#: gitk:11166
msgid "diff old lines"
msgstr "diff gamla rader"
-#: gitk:11012
+#: gitk:11170
msgid "Diff: new lines"
msgstr "Diff: nya rader"
-#: gitk:11013
+#: gitk:11171
msgid "diff new lines"
msgstr "diff nya rader"
-#: gitk:11017
+#: gitk:11175
msgid "Diff: hunk header"
msgstr "Diff: delhuvud"
-#: gitk:11019
+#: gitk:11177
msgid "diff hunk header"
msgstr "diff delhuvud"
-#: gitk:11023
+#: gitk:11181
msgid "Marked line bg"
msgstr "Markerad rad bakgrund"
-#: gitk:11025
+#: gitk:11183
msgid "marked line background"
msgstr "markerad rad bakgrund"
-#: gitk:11029
+#: gitk:11187
msgid "Select bg"
msgstr "Markerad bakgrund"
-#: gitk:11038
+#: gitk:11196
msgid "Fonts: press to choose"
msgstr "Teckensnitt: tryck för att välja"
-#: gitk:11040
+#: gitk:11198
msgid "Main font"
msgstr "Huvudteckensnitt"
-#: gitk:11041
+#: gitk:11199
msgid "Diff display font"
msgstr "Teckensnitt för diffvisning"
-#: gitk:11042
+#: gitk:11200
msgid "User interface font"
msgstr "Teckensnitt för användargränssnitt"
-#: gitk:11064
+#: gitk:11222
msgid "Gitk preferences"
msgstr "Inställningar för Gitk"
-#: gitk:11073
+#: gitk:11231
msgid "General"
msgstr "Allmänt"
-#: gitk:11074
+#: gitk:11232
msgid "Colors"
msgstr "Färger"
-#: gitk:11075
+#: gitk:11233
msgid "Fonts"
msgstr "Teckensnitt"
-#: gitk:11125
+#: gitk:11283
#, tcl-format
msgid "Gitk: choose color for %s"
msgstr "Gitk: välj färg för %s"
-#: gitk:11745
+#: gitk:11937
msgid "Cannot find a git repository here."
msgstr "Hittar inget git-arkiv här."
-#: gitk:11792
+#: gitk:11984
#, tcl-format
msgid "Ambiguous argument '%s': both revision and filename"
msgstr "Tvetydigt argument \"%s\": både revision och filnamn"
-#: gitk:11804
+#: gitk:11996
msgid "Bad arguments to gitk:"
msgstr "Felaktiga argument till gitk:"
-#: gitk:11907
+#: gitk:12099
msgid "Command line"
msgstr "Kommandorad"
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 80950c0..b5d156f 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -85,6 +85,9 @@ our $project_maxdepth = "++GITWEB_PROJECT_MAXDEPTH++";
# string of the home link on top of all pages
our $home_link_str = "++GITWEB_HOME_LINK_STR++";
+# extra breadcrumbs preceding the home link
+our @extra_breadcrumbs = ();
+
# name of your site or organization to appear in page titles
# replace this with something more descriptive for clearer bookmarks
our $site_name = "++GITWEB_SITENAME++"
@@ -1086,7 +1089,7 @@ sub evaluate_and_validate_params {
our $search_use_regexp = $input_params{'search_use_regexp'};
our $searchtext = $input_params{'searchtext'};
- our $search_regexp;
+ our $search_regexp = undef;
if (defined $searchtext) {
if (length($searchtext) < 2) {
die_error(403, "At least two characters are required for search parameter");
@@ -3982,7 +3985,9 @@ sub print_nav_breadcrumbs_path {
sub print_nav_breadcrumbs {
my %opts = @_;
- print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
+ for my $crumb (@extra_breadcrumbs, [ $home_link_str => $home_link ]) {
+ print $cgi->a({-href => esc_url($crumb->[1])}, $crumb->[0]) . " / ";
+ }
if (defined $project) {
my @dirname = split '/', $project;
my $projectbasename = pop @dirname;
@@ -4030,8 +4035,8 @@ sub print_search_form {
$cgi->input({-name=>"h", -value=>$search_hash, -type=>"hidden"}) . "\n" .
$cgi->popup_menu(-name => 'st', -default => 'commit',
-values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) .
- $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
- " search:\n",
+ " " . $cgi->a({-href => href(action=>"search_help"),
+ -title => "search help" }, "?") . " search:\n",
$cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" .
"<span title=\"Extended regular expression\">" .
$cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
@@ -6463,7 +6468,7 @@ sub git_summary {
print "<div class=\"title\">&nbsp;</div>\n";
print "<table class=\"projects_list\">\n" .
"<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n";
- unless ($omit_owner) {
+ if ($owner and not $omit_owner) {
print "<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
}
if (defined $cd{'rfc2822'}) {
diff --git a/gitweb/static/gitweb.css b/gitweb/static/gitweb.css
index cb86d2d..3b4d833 100644
--- a/gitweb/static/gitweb.css
+++ b/gitweb/static/gitweb.css
@@ -68,12 +68,13 @@ div.page_path {
}
div.page_footer {
- height: 17px;
+ height: 22px;
padding: 4px 8px;
background-color: #d9d8d1;
}
div.page_footer_text {
+ line-height: 22px;
float: left;
color: #555555;
font-style: italic;
@@ -548,8 +549,7 @@ a.linenr {
a.rss_logo {
float: right;
- padding: 3px 0px;
- width: 35px;
+ padding: 3px 5px;
line-height: 10px;
border: 1px solid;
border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
diff --git a/gpg-interface.h b/gpg-interface.h
index cf99021..a85cb5b 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -1,6 +1,18 @@
#ifndef GPG_INTERFACE_H
#define GPG_INTERFACE_H
+struct signature_check {
+ char *gpg_output;
+ char *gpg_status;
+ char result; /* 0 (not checked),
+ * N (checked but no further result),
+ * U (untrusted good),
+ * G (good)
+ * B (bad) */
+ char *signer;
+ char *key;
+};
+
extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key);
extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output, struct strbuf *gpg_status);
extern int git_gpg_config(const char *, const char *, void *);
diff --git a/hash.h b/hash.h
index b875ce6..1d43ac0 100644
--- a/hash.h
+++ b/hash.h
@@ -40,4 +40,11 @@ static inline void init_hash(struct hash_table *table)
table->array = NULL;
}
+static inline void preallocate_hash(struct hash_table *table, unsigned int elts)
+{
+ assert(table->size == 0 && table->nr == 0 && table->array == NULL);
+ table->size = elts * 2;
+ table->array = xcalloc(sizeof(struct hash_table_entry), table->size);
+}
+
#endif
diff --git a/help.c b/help.c
index 02ba043..f068925 100644
--- a/help.c
+++ b/help.c
@@ -7,6 +7,7 @@
#include "string-list.h"
#include "column.h"
#include "version.h"
+#include "refs.h"
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
{
@@ -106,10 +107,7 @@ static int is_executable(const char *name)
!S_ISREG(st.st_mode))
return 0;
-#if defined(WIN32) || defined(__CYGWIN__)
-#if defined(__CYGWIN__)
-if ((st.st_mode & S_IXUSR) == 0)
-#endif
+#if defined(GIT_WINDOWS_NATIVE)
{ /* cannot trust the executable bit, peek into the file instead */
char buf[3] = { 0 };
int n;
@@ -404,3 +402,52 @@ int cmd_version(int argc, const char **argv, const char *prefix)
printf("git version %s\n", git_version_string);
return 0;
}
+
+struct similar_ref_cb {
+ const char *base_ref;
+ struct string_list *similar_refs;
+};
+
+static int append_similar_ref(const char *refname, const unsigned char *sha1,
+ int flags, void *cb_data)
+{
+ struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
+ char *branch = strrchr(refname, '/') + 1;
+ /* A remote branch of the same name is deemed similar */
+ if (!prefixcmp(refname, "refs/remotes/") &&
+ !strcmp(branch, cb->base_ref))
+ string_list_append(cb->similar_refs,
+ refname + strlen("refs/remotes/"));
+ return 0;
+}
+
+static struct string_list guess_refs(const char *ref)
+{
+ struct similar_ref_cb ref_cb;
+ struct string_list similar_refs = STRING_LIST_INIT_NODUP;
+
+ ref_cb.base_ref = ref;
+ ref_cb.similar_refs = &similar_refs;
+ for_each_ref(append_similar_ref, &ref_cb);
+ return similar_refs;
+}
+
+void help_unknown_ref(const char *ref, const char *cmd, const char *error)
+{
+ int i;
+ struct string_list suggested_refs = guess_refs(ref);
+
+ fprintf_ln(stderr, _("%s: %s - %s"), cmd, ref, error);
+
+ if (suggested_refs.nr > 0) {
+ fprintf_ln(stderr,
+ Q_("\nDid you mean this?",
+ "\nDid you mean one of these?",
+ suggested_refs.nr));
+ for (i = 0; i < suggested_refs.nr; i++)
+ fprintf(stderr, "\t%s\n", suggested_refs.items[i].string);
+ }
+
+ string_list_clear(&suggested_refs, 0);
+ exit(1);
+}
diff --git a/help.h b/help.h
index 0ae5a12..b21d7c9 100644
--- a/help.h
+++ b/help.h
@@ -27,4 +27,9 @@ extern void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
extern int is_in_cmdlist(struct cmdnames *cmds, const char *name);
extern void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);
+/*
+ * call this to die(), when it is suspected that the user mistyped a
+ * ref to the command, to give suggested "correct" refs.
+ */
+extern void help_unknown_ref(const char *ref, const char *cmd, const char *error);
#endif /* HELP_H */
diff --git a/http-backend.c b/http-backend.c
index f50e77f..0324417 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -70,7 +70,7 @@ static void format_write(int fd, const char *fmt, ...)
if (n >= sizeof(buffer))
die("protocol error: impossibly long line");
- safe_write(fd, buffer, n);
+ write_or_die(fd, buffer, n);
}
static void http_status(unsigned code, const char *msg)
@@ -111,7 +111,7 @@ static void hdr_cache_forever(void)
static void end_headers(void)
{
- safe_write(1, "\r\n", 2);
+ write_or_die(1, "\r\n", 2);
}
__attribute__((format (printf, 1, 2)))
@@ -157,7 +157,7 @@ static void send_strbuf(const char *type, struct strbuf *buf)
hdr_int(content_length, buf->len);
hdr_str(content_type, type);
end_headers();
- safe_write(1, buf->buf, buf->len);
+ write_or_die(1, buf->buf, buf->len);
}
static void send_local_file(const char *the_type, const char *name)
@@ -185,7 +185,7 @@ static void send_local_file(const char *the_type, const char *name)
die_errno("Cannot read '%s'", p);
if (!n)
break;
- safe_write(1, buf, n);
+ write_or_die(1, buf, n);
}
close(fd);
free(buf);
@@ -361,17 +361,19 @@ static void run_service(const char **argv)
static int show_text_ref(const char *name, const unsigned char *sha1,
int flag, void *cb_data)
{
+ const char *name_nons = strip_namespace(name);
struct strbuf *buf = cb_data;
struct object *o = parse_object(sha1);
if (!o)
return 0;
- strbuf_addf(buf, "%s\t%s\n", sha1_to_hex(sha1), name);
+ strbuf_addf(buf, "%s\t%s\n", sha1_to_hex(sha1), name_nons);
if (o->type == OBJ_TAG) {
o = deref_tag(o, name, 0);
if (!o)
return 0;
- strbuf_addf(buf, "%s\t%s^{}\n", sha1_to_hex(o->sha1), name);
+ strbuf_addf(buf, "%s\t%s^{}\n", sha1_to_hex(o->sha1),
+ name_nons);
}
return 0;
}
@@ -402,12 +404,40 @@ static void get_info_refs(char *arg)
} else {
select_getanyfile();
- for_each_ref(show_text_ref, &buf);
+ for_each_namespaced_ref(show_text_ref, &buf);
send_strbuf("text/plain", &buf);
}
strbuf_release(&buf);
}
+static int show_head_ref(const char *refname, const unsigned char *sha1,
+ int flag, void *cb_data)
+{
+ struct strbuf *buf = cb_data;
+
+ if (flag & REF_ISSYMREF) {
+ unsigned char unused[20];
+ const char *target = resolve_ref_unsafe(refname, unused, 1, NULL);
+ const char *target_nons = strip_namespace(target);
+
+ strbuf_addf(buf, "ref: %s\n", target_nons);
+ } else {
+ strbuf_addf(buf, "%s\n", sha1_to_hex(sha1));
+ }
+
+ return 0;
+}
+
+static void get_head(char *arg)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ select_getanyfile();
+ head_ref_namespaced(show_head_ref, &buf);
+ send_strbuf("text/plain", &buf);
+ strbuf_release(&buf);
+}
+
static void get_info_packs(char *arg)
{
size_t objdirlen = strlen(get_object_directory());
@@ -520,7 +550,7 @@ static struct service_cmd {
const char *pattern;
void (*imp)(char *);
} services[] = {
- {"GET", "/HEAD$", get_text_file},
+ {"GET", "/HEAD$", get_head},
{"GET", "/info/refs$", get_info_refs},
{"GET", "/objects/info/alternates$", get_text_file},
{"GET", "/objects/info/http-alternates$", get_text_file},
diff --git a/http-push.c b/http-push.c
index bd66f6a..6dad188 100644
--- a/http-push.c
+++ b/http-push.c
@@ -663,7 +663,7 @@ static void add_fetch_request(struct object *obj)
static int add_send_request(struct object *obj, struct remote_lock *lock)
{
- struct transfer_request *request = request_queue_head;
+ struct transfer_request *request;
struct packed_git *target;
/* Keep locks active */
@@ -1551,7 +1551,7 @@ static int remote_exists(const char *path)
ret = 0;
break;
case HTTP_ERROR:
- http_error(url, HTTP_ERROR);
+ error("unable to access '%s': %s", url, curl_errorstr);
default:
ret = -1;
}
diff --git a/http.c b/http.c
index d9d1aad..f3e1439 100644
--- a/http.c
+++ b/http.c
@@ -3,8 +3,10 @@
#include "sideband.h"
#include "run-command.h"
#include "url.h"
+#include "urlmatch.h"
#include "credential.h"
#include "version.h"
+#include "pkt-line.h"
int active_requests;
int http_is_verbose;
@@ -30,6 +32,7 @@ static CURL *curl_default;
char curl_errorstr[CURL_ERROR_SIZE];
static int curl_ssl_verify = -1;
+static int curl_ssl_try;
static const char *ssl_cert;
#if LIBCURL_VERSION_NUM >= 0x070903
static const char *ssl_key;
@@ -43,6 +46,7 @@ static long curl_low_speed_time = -1;
static int curl_ftp_no_epsv;
static const char *curl_http_proxy;
static const char *curl_cookie_file;
+static int curl_save_cookies;
static struct credential http_auth = CREDENTIAL_INIT;
static int http_proactive_auth;
static const char *user_agent;
@@ -158,8 +162,11 @@ static int http_options(const char *var, const char *value, void *cb)
if (!strcmp("http.sslcainfo", var))
return git_config_string(&ssl_cainfo, var, value);
if (!strcmp("http.sslcertpasswordprotected", var)) {
- if (git_config_bool(var, value))
- ssl_cert_password_required = 1;
+ ssl_cert_password_required = git_config_bool(var, value);
+ return 0;
+ }
+ if (!strcmp("http.ssltry", var)) {
+ curl_ssl_try = git_config_bool(var, value);
return 0;
}
if (!strcmp("http.minsessions", var)) {
@@ -194,6 +201,10 @@ static int http_options(const char *var, const char *value, void *cb)
if (!strcmp("http.cookiefile", var))
return git_config_string(&curl_cookie_file, var, value);
+ if (!strcmp("http.savecookies", var)) {
+ curl_save_cookies = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp("http.postbuffer", var)) {
http_post_buffer = git_config_int(var, value);
@@ -222,9 +233,15 @@ static void init_curl_http_auth(CURL *result)
#else
{
static struct strbuf up = STRBUF_INIT;
- strbuf_reset(&up);
- strbuf_addf(&up, "%s:%s",
- http_auth.username, http_auth.password);
+ /*
+ * Note that we assume we only ever have a single set of
+ * credentials in a given program run, so we do not have
+ * to worry about updating this buffer, only setting its
+ * initial value.
+ */
+ if (!up.len)
+ strbuf_addf(&up, "%s:%s",
+ http_auth.username, http_auth.password);
curl_easy_setopt(result, CURLOPT_USERPWD, up.buf);
}
#endif
@@ -281,7 +298,6 @@ static CURL *get_curl_handle(void)
#endif
if (ssl_cainfo != NULL)
curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
- curl_easy_setopt(result, CURLOPT_FAILONERROR, 1);
if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
@@ -306,6 +322,11 @@ static CURL *get_curl_handle(void)
if (curl_ftp_no_epsv)
curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
+#ifdef CURLOPT_USE_SSL
+ if (curl_ssl_try)
+ curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY);
+#endif
+
if (curl_http_proxy) {
curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
@@ -325,10 +346,20 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
{
char *low_speed_limit;
char *low_speed_time;
+ char *normalized_url;
+ struct urlmatch_config config = { STRING_LIST_INIT_DUP };
+
+ config.section = "http";
+ config.key = NULL;
+ config.collect_fn = http_options;
+ config.cascade_fn = git_default_config;
+ config.cb = NULL;
http_is_verbose = 0;
+ normalized_url = url_normalize(url, &config.url);
- git_config(http_options, NULL);
+ git_config(urlmatch_config_entry, &config);
+ free(normalized_url);
curl_global_init(CURL_GLOBAL_ALL);
@@ -497,6 +528,8 @@ struct active_request_slot *get_active_slot(void)
slot->callback_data = NULL;
slot->callback_func = NULL;
curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file);
+ if (curl_save_cookies)
+ curl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
@@ -505,6 +538,7 @@ struct active_request_slot *get_active_slot(void)
curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
+ curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
if (http_auth.password)
init_curl_http_auth(slot->curl);
@@ -760,6 +794,25 @@ char *get_remote_object_url(const char *url, const char *hex,
int handle_curl_result(struct slot_results *results)
{
+ /*
+ * If we see a failing http code with CURLE_OK, we have turned off
+ * FAILONERROR (to keep the server's custom error response), and should
+ * translate the code into failure here.
+ */
+ if (results->curl_result == CURLE_OK &&
+ results->http_code >= 400) {
+ results->curl_result = CURLE_HTTP_RETURNED_ERROR;
+ /*
+ * Normally curl will already have put the "reason phrase"
+ * from the server into curl_errorstr; unfortunately without
+ * FAILONERROR it is lost, so we can give only the numeric
+ * status code.
+ */
+ snprintf(curl_errorstr, sizeof(curl_errorstr),
+ "The requested URL returned error: %ld",
+ results->http_code);
+ }
+
if (results->curl_result == CURLE_OK) {
credential_approve(&http_auth);
return HTTP_OK;
@@ -824,6 +877,8 @@ static int http_request(const char *url, struct strbuf *type,
strbuf_addstr(&buf, "Pragma:");
if (options & HTTP_NO_CACHE)
strbuf_addstr(&buf, " no-cache");
+ if (options & HTTP_KEEP_ERROR)
+ curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0);
headers = curl_slist_append(headers, buf.buf);
@@ -835,7 +890,8 @@ static int http_request(const char *url, struct strbuf *type,
run_active_slot(slot);
ret = handle_curl_result(&results);
} else {
- error("Unable to start HTTP request for %s", url);
+ snprintf(curl_errorstr, sizeof(curl_errorstr),
+ "failed to start HTTP request");
ret = HTTP_START_FAILED;
}
@@ -861,6 +917,22 @@ static int http_request_reauth(const char *url,
int ret = http_request(url, type, result, target, options);
if (ret != HTTP_REAUTH)
return ret;
+
+ /*
+ * If we are using KEEP_ERROR, the previous request may have
+ * put cruft into our output stream; we should clear it out before
+ * making our next request. We only know how to do this for
+ * the strbuf case, but that is enough to satisfy current callers.
+ */
+ if (options & HTTP_KEEP_ERROR) {
+ switch (target) {
+ case HTTP_REQUEST_STRBUF:
+ strbuf_reset(result);
+ break;
+ default:
+ die("BUG: HTTP_KEEP_ERROR is only supported with strbufs");
+ }
+ }
return http_request(url, type, result, target, options);
}
@@ -902,15 +974,6 @@ cleanup:
return ret;
}
-int http_error(const char *url, int ret)
-{
- /* http_request has already handled HTTP_START_FAILED. */
- if (ret != HTTP_START_FAILED)
- error("%s while accessing %s", curl_errorstr, url);
-
- return ret;
-}
-
int http_fetch_ref(const char *base, struct ref *ref)
{
char *url;
diff --git a/http.h b/http.h
index 25d1931..d77c1b5 100644
--- a/http.h
+++ b/http.h
@@ -42,6 +42,15 @@
#define NO_CURL_IOCTL
#endif
+/*
+ * CURLOPT_USE_SSL was known as CURLOPT_FTP_SSL up to 7.16.4,
+ * and the constants were known as CURLFTPSSL_*
+*/
+#if !defined(CURLOPT_USE_SSL) && defined(CURLOPT_FTP_SSL)
+#define CURLOPT_USE_SSL CURLOPT_FTP_SSL
+#define CURLUSESSL_TRY CURLFTPSSL_TRY
+#endif
+
struct slot_results {
CURLcode curl_result;
long http_code;
@@ -118,6 +127,7 @@ extern char *get_remote_object_url(const char *url, const char *hex,
/* Options for http_request_*() */
#define HTTP_NO_CACHE 1
+#define HTTP_KEEP_ERROR 2
/* Return values for http_request_*() */
#define HTTP_OK 0
@@ -134,12 +144,6 @@ extern char *get_remote_object_url(const char *url, const char *hex,
*/
int http_get_strbuf(const char *url, struct strbuf *content_type, struct strbuf *result, int options);
-/*
- * Prints an error message using error() containing url and curl_errorstr,
- * and returns ret.
- */
-int http_error(const char *url, int ret);
-
extern int http_fetch_ref(const char *base, struct ref *ref);
/* Helpers for fetching packs */
diff --git a/imap-send.c b/imap-send.c
index d9bcfb4..6f5cc4f 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -28,10 +28,6 @@
#include "prompt.h"
#ifdef NO_OPENSSL
typedef void *SSL;
-#else
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#include <openssl/x509v3.h>
#endif
static const char imap_send_usage[] = "git imap-send < <mbox>";
diff --git a/kwset.c b/kwset.c
index 5800999..a0f49b3 100644
--- a/kwset.c
+++ b/kwset.c
@@ -65,7 +65,7 @@ struct trie
struct trie *fail; /* Aho-Corasick failure function. */
int depth; /* Depth of this node from the root. */
int shift; /* Shift function for search failures. */
- int maxshift; /* Max shift of self and descendents. */
+ int maxshift; /* Max shift of self and descendants. */
};
/* Structure returned opaquely to the caller, containing everything. */
@@ -308,7 +308,7 @@ treefails (register struct tree const *tree, struct trie const *fail,
treefails(tree->rlink, fail, recourse);
/* Find, in the chain of fails going back to the root, the first
- node that has a descendent on the current label. */
+ node that has a descendant on the current label. */
while (fail)
{
link = fail->links;
@@ -426,13 +426,13 @@ kwsprep (kwset_t kws)
computing the delta table, failure function, and shift function. */
for (curr = last = kwset->trie; curr; curr = curr->next)
{
- /* Enqueue the immediate descendents in the level order queue. */
+ /* Enqueue the immediate descendants in the level order queue. */
enqueue(curr->links, &last);
curr->shift = kwset->mind;
curr->maxshift = kwset->mind;
- /* Update the delta table for the descendents of this node. */
+ /* Update the delta table for the descendants of this node. */
treedelta(curr->links, curr->depth, delta);
/* Compute the failure function for the descendants of this node. */
@@ -450,7 +450,7 @@ kwsprep (kwset_t kws)
fail->shift = curr->depth - fail->depth;
/* If the current node is accepting then the shift at the
- fail and its descendents should be no larger than the
+ fail and its descendants should be no larger than the
difference of their depths. */
if (curr->accepting && fail->maxshift > curr->depth - fail->depth)
fail->maxshift = curr->depth - fail->depth;
diff --git a/line-log.c b/line-log.c
new file mode 100644
index 0000000..8b6e497
--- /dev/null
+++ b/line-log.c
@@ -0,0 +1,1286 @@
+#include "git-compat-util.h"
+#include "line-range.h"
+#include "cache.h"
+#include "tag.h"
+#include "blob.h"
+#include "tree.h"
+#include "diff.h"
+#include "commit.h"
+#include "decorate.h"
+#include "revision.h"
+#include "xdiff-interface.h"
+#include "strbuf.h"
+#include "log-tree.h"
+#include "graph.h"
+#include "userdiff.h"
+#include "line-log.h"
+
+static void range_set_grow(struct range_set *rs, size_t extra)
+{
+ ALLOC_GROW(rs->ranges, rs->nr + extra, rs->alloc);
+}
+
+/* Either initialization would be fine */
+#define RANGE_SET_INIT {0}
+
+void range_set_init(struct range_set *rs, size_t prealloc)
+{
+ rs->alloc = rs->nr = 0;
+ rs->ranges = NULL;
+ if (prealloc)
+ range_set_grow(rs, prealloc);
+}
+
+void range_set_release(struct range_set *rs)
+{
+ free(rs->ranges);
+ rs->alloc = rs->nr = 0;
+ rs->ranges = NULL;
+}
+
+/* dst must be uninitialized! */
+static void range_set_copy(struct range_set *dst, struct range_set *src)
+{
+ range_set_init(dst, src->nr);
+ memcpy(dst->ranges, src->ranges, src->nr*sizeof(struct range_set));
+ dst->nr = src->nr;
+}
+static void range_set_move(struct range_set *dst, struct range_set *src)
+{
+ range_set_release(dst);
+ dst->ranges = src->ranges;
+ dst->nr = src->nr;
+ dst->alloc = src->alloc;
+ src->ranges = NULL;
+ src->alloc = src->nr = 0;
+}
+
+/* tack on a _new_ range _at the end_ */
+void range_set_append_unsafe(struct range_set *rs, long a, long b)
+{
+ assert(a <= b);
+ range_set_grow(rs, 1);
+ rs->ranges[rs->nr].start = a;
+ rs->ranges[rs->nr].end = b;
+ rs->nr++;
+}
+
+void range_set_append(struct range_set *rs, long a, long b)
+{
+ assert(rs->nr == 0 || rs->ranges[rs->nr-1].end <= a);
+ range_set_append_unsafe(rs, a, b);
+}
+
+static int range_cmp(const void *_r, const void *_s)
+{
+ const struct range *r = _r;
+ const struct range *s = _s;
+
+ /* this could be simply 'return r.start-s.start', but for the types */
+ if (r->start == s->start)
+ return 0;
+ if (r->start < s->start)
+ return -1;
+ return 1;
+}
+
+/*
+ * Check that the ranges are non-empty, sorted and non-overlapping
+ */
+static void range_set_check_invariants(struct range_set *rs)
+{
+ int i;
+
+ if (!rs)
+ return;
+
+ if (rs->nr)
+ assert(rs->ranges[0].start < rs->ranges[0].end);
+
+ for (i = 1; i < rs->nr; i++) {
+ assert(rs->ranges[i-1].end < rs->ranges[i].start);
+ assert(rs->ranges[i].start < rs->ranges[i].end);
+ }
+}
+
+/*
+ * In-place pass of sorting and merging the ranges in the range set,
+ * to establish the invariants when we get the ranges from the user
+ */
+void sort_and_merge_range_set(struct range_set *rs)
+{
+ int i;
+ int o = 0; /* output cursor */
+
+ qsort(rs->ranges, rs->nr, sizeof(struct range), range_cmp);
+
+ for (i = 0; i < rs->nr; i++) {
+ if (rs->ranges[i].start == rs->ranges[i].end)
+ continue;
+ if (o > 0 && rs->ranges[i].start <= rs->ranges[o-1].end) {
+ if (rs->ranges[o-1].end < rs->ranges[i].end)
+ rs->ranges[o-1].end = rs->ranges[i].end;
+ } else {
+ rs->ranges[o].start = rs->ranges[i].start;
+ rs->ranges[o].end = rs->ranges[i].end;
+ o++;
+ }
+ }
+ assert(o <= rs->nr);
+ rs->nr = o;
+
+ range_set_check_invariants(rs);
+}
+
+/*
+ * Union of range sets (i.e., sets of line numbers). Used to merge
+ * them when searches meet at a common ancestor.
+ *
+ * This is also where the ranges are consolidated into canonical form:
+ * overlapping and adjacent ranges are merged, and empty ranges are
+ * removed.
+ */
+static void range_set_union(struct range_set *out,
+ struct range_set *a, struct range_set *b)
+{
+ int i = 0, j = 0, o = 0;
+ struct range *ra = a->ranges;
+ struct range *rb = b->ranges;
+ /* cannot make an alias of out->ranges: it may change during grow */
+
+ assert(out->nr == 0);
+ while (i < a->nr || j < b->nr) {
+ struct range *new;
+ if (i < a->nr && j < b->nr) {
+ if (ra[i].start < rb[j].start)
+ new = &ra[i++];
+ else if (ra[i].start > rb[j].start)
+ new = &rb[j++];
+ else if (ra[i].end < rb[j].end)
+ new = &ra[i++];
+ else
+ new = &rb[j++];
+ } else if (i < a->nr) /* b exhausted */
+ new = &ra[i++];
+ else /* a exhausted */
+ new = &rb[j++];
+ if (new->start == new->end)
+ ; /* empty range */
+ else if (!o || out->ranges[o-1].end < new->start) {
+ range_set_grow(out, 1);
+ out->ranges[o].start = new->start;
+ out->ranges[o].end = new->end;
+ o++;
+ } else if (out->ranges[o-1].end < new->end) {
+ out->ranges[o-1].end = new->end;
+ }
+ }
+ out->nr = o;
+}
+
+/*
+ * Difference of range sets (out = a \ b). Pass the "interesting"
+ * ranges as 'a' and the target side of the diff as 'b': it removes
+ * the ranges for which the commit is responsible.
+ */
+static void range_set_difference(struct range_set *out,
+ struct range_set *a, struct range_set *b)
+{
+ int i, j = 0;
+ for (i = 0; i < a->nr; i++) {
+ long start = a->ranges[i].start;
+ long end = a->ranges[i].end;
+ while (start < end) {
+ while (j < b->nr && start >= b->ranges[j].end)
+ /*
+ * a: |-------
+ * b: ------|
+ */
+ j++;
+ if (j >= b->nr || end < b->ranges[j].start) {
+ /*
+ * b exhausted, or
+ * a: ----|
+ * b: |----
+ */
+ range_set_append(out, start, end);
+ break;
+ }
+ if (start >= b->ranges[j].start) {
+ /*
+ * a: |--????
+ * b: |------|
+ */
+ start = b->ranges[j].end;
+ } else if (end > b->ranges[j].start) {
+ /*
+ * a: |-----|
+ * b: |--?????
+ */
+ if (start < b->ranges[j].start)
+ range_set_append(out, start, b->ranges[j].start);
+ start = b->ranges[j].end;
+ }
+ }
+ }
+}
+
+static void diff_ranges_init(struct diff_ranges *diff)
+{
+ range_set_init(&diff->parent, 0);
+ range_set_init(&diff->target, 0);
+}
+
+static void diff_ranges_release(struct diff_ranges *diff)
+{
+ range_set_release(&diff->parent);
+ range_set_release(&diff->target);
+}
+
+void line_log_data_init(struct line_log_data *r)
+{
+ memset(r, 0, sizeof(struct line_log_data));
+ range_set_init(&r->ranges, 0);
+}
+
+static void line_log_data_clear(struct line_log_data *r)
+{
+ range_set_release(&r->ranges);
+ if (r->pair)
+ diff_free_filepair(r->pair);
+}
+
+static void free_line_log_data(struct line_log_data *r)
+{
+ while (r) {
+ struct line_log_data *next = r->next;
+ line_log_data_clear(r);
+ free(r);
+ r = next;
+ }
+}
+
+static struct line_log_data *
+search_line_log_data(struct line_log_data *list, const char *path,
+ struct line_log_data **insertion_point)
+{
+ struct line_log_data *p = list;
+ if (insertion_point)
+ *insertion_point = NULL;
+ while (p) {
+ int cmp = strcmp(p->path, path);
+ if (!cmp)
+ return p;
+ if (insertion_point && cmp < 0)
+ *insertion_point = p;
+ p = p->next;
+ }
+ return NULL;
+}
+
+/*
+ * Note: takes ownership of 'path', which happens to be what the only
+ * caller needs.
+ */
+static void line_log_data_insert(struct line_log_data **list,
+ char *path,
+ long begin, long end)
+{
+ struct line_log_data *ip;
+ struct line_log_data *p = search_line_log_data(*list, path, &ip);
+
+ if (p) {
+ range_set_append_unsafe(&p->ranges, begin, end);
+ free(path);
+ return;
+ }
+
+ p = xcalloc(1, sizeof(struct line_log_data));
+ p->path = path;
+ range_set_append(&p->ranges, begin, end);
+ if (ip) {
+ p->next = ip->next;
+ ip->next = p;
+ } else {
+ p->next = *list;
+ *list = p;
+ }
+}
+
+struct collect_diff_cbdata {
+ struct diff_ranges *diff;
+};
+
+static int collect_diff_cb(long start_a, long count_a,
+ long start_b, long count_b,
+ void *data)
+{
+ struct collect_diff_cbdata *d = data;
+
+ if (count_a >= 0)
+ range_set_append(&d->diff->parent, start_a, start_a + count_a);
+ if (count_b >= 0)
+ range_set_append(&d->diff->target, start_b, start_b + count_b);
+
+ return 0;
+}
+
+static void collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges *out)
+{
+ struct collect_diff_cbdata cbdata = {NULL};
+ xpparam_t xpp;
+ xdemitconf_t xecfg;
+ xdemitcb_t ecb;
+
+ memset(&xpp, 0, sizeof(xpp));
+ memset(&xecfg, 0, sizeof(xecfg));
+ xecfg.ctxlen = xecfg.interhunkctxlen = 0;
+
+ cbdata.diff = out;
+ xecfg.hunk_func = collect_diff_cb;
+ memset(&ecb, 0, sizeof(ecb));
+ ecb.priv = &cbdata;
+ xdi_diff(parent, target, &xpp, &xecfg, &ecb);
+}
+
+/*
+ * These are handy for debugging. Removing them with #if 0 silences
+ * the "unused function" warning.
+ */
+#if 0
+static void dump_range_set(struct range_set *rs, const char *desc)
+{
+ int i;
+ printf("range set %s (%d items):\n", desc, rs->nr);
+ for (i = 0; i < rs->nr; i++)
+ printf("\t[%ld,%ld]\n", rs->ranges[i].start, rs->ranges[i].end);
+}
+
+static void dump_line_log_data(struct line_log_data *r)
+{
+ char buf[4096];
+ while (r) {
+ snprintf(buf, 4096, "file %s\n", r->path);
+ dump_range_set(&r->ranges, buf);
+ r = r->next;
+ }
+}
+
+static void dump_diff_ranges(struct diff_ranges *diff, const char *desc)
+{
+ int i;
+ assert(diff->parent.nr == diff->target.nr);
+ printf("diff ranges %s (%d items):\n", desc, diff->parent.nr);
+ printf("\tparent\ttarget\n");
+ for (i = 0; i < diff->parent.nr; i++) {
+ printf("\t[%ld,%ld]\t[%ld,%ld]\n",
+ diff->parent.ranges[i].start,
+ diff->parent.ranges[i].end,
+ diff->target.ranges[i].start,
+ diff->target.ranges[i].end);
+ }
+}
+#endif
+
+
+static int ranges_overlap(struct range *a, struct range *b)
+{
+ return !(a->end <= b->start || b->end <= a->start);
+}
+
+/*
+ * Given a diff and the set of interesting ranges, determine all hunks
+ * of the diff which touch (overlap) at least one of the interesting
+ * ranges in the target.
+ */
+static void diff_ranges_filter_touched(struct diff_ranges *out,
+ struct diff_ranges *diff,
+ struct range_set *rs)
+{
+ int i, j = 0;
+
+ assert(out->target.nr == 0);
+
+ for (i = 0; i < diff->target.nr; i++) {
+ while (diff->target.ranges[i].start > rs->ranges[j].end) {
+ j++;
+ if (j == rs->nr)
+ return;
+ }
+ if (ranges_overlap(&diff->target.ranges[i], &rs->ranges[j])) {
+ range_set_append(&out->parent,
+ diff->parent.ranges[i].start,
+ diff->parent.ranges[i].end);
+ range_set_append(&out->target,
+ diff->target.ranges[i].start,
+ diff->target.ranges[i].end);
+ }
+ }
+}
+
+/*
+ * Adjust the line counts in 'rs' to account for the lines
+ * added/removed in the diff.
+ */
+static void range_set_shift_diff(struct range_set *out,
+ struct range_set *rs,
+ struct diff_ranges *diff)
+{
+ int i, j = 0;
+ long offset = 0;
+ struct range *src = rs->ranges;
+ struct range *target = diff->target.ranges;
+ struct range *parent = diff->parent.ranges;
+
+ for (i = 0; i < rs->nr; i++) {
+ while (j < diff->target.nr && src[i].start >= target[j].start) {
+ offset += (parent[j].end-parent[j].start)
+ - (target[j].end-target[j].start);
+ j++;
+ }
+ range_set_append(out, src[i].start+offset, src[i].end+offset);
+ }
+}
+
+/*
+ * Given a diff and the set of interesting ranges, map the ranges
+ * across the diff. That is: observe that the target commit takes
+ * blame for all the + (target-side) ranges. So for every pair of
+ * ranges in the diff that was touched, we remove the latter and add
+ * its parent side.
+ */
+static void range_set_map_across_diff(struct range_set *out,
+ struct range_set *rs,
+ struct diff_ranges *diff,
+ struct diff_ranges **touched_out)
+{
+ struct diff_ranges *touched = xmalloc(sizeof(*touched));
+ struct range_set tmp1 = RANGE_SET_INIT;
+ struct range_set tmp2 = RANGE_SET_INIT;
+
+ diff_ranges_init(touched);
+ diff_ranges_filter_touched(touched, diff, rs);
+ range_set_difference(&tmp1, rs, &touched->target);
+ range_set_shift_diff(&tmp2, &tmp1, diff);
+ range_set_union(out, &tmp2, &touched->parent);
+ range_set_release(&tmp1);
+ range_set_release(&tmp2);
+
+ *touched_out = touched;
+}
+
+static struct commit *check_single_commit(struct rev_info *revs)
+{
+ struct object *commit = NULL;
+ int found = -1;
+ int i;
+
+ for (i = 0; i < revs->pending.nr; i++) {
+ struct object *obj = revs->pending.objects[i].item;
+ if (obj->flags & UNINTERESTING)
+ continue;
+ while (obj->type == OBJ_TAG)
+ obj = deref_tag(obj, NULL, 0);
+ if (obj->type != OBJ_COMMIT)
+ die("Non commit %s?", revs->pending.objects[i].name);
+ if (commit)
+ die("More than one commit to dig from: %s and %s?",
+ revs->pending.objects[i].name,
+ revs->pending.objects[found].name);
+ commit = obj;
+ found = i;
+ }
+
+ if (!commit)
+ die("No commit specified?");
+
+ return (struct commit *) commit;
+}
+
+static void fill_blob_sha1(struct commit *commit, struct diff_filespec *spec)
+{
+ unsigned mode;
+ unsigned char sha1[20];
+
+ if (get_tree_entry(commit->object.sha1, spec->path,
+ sha1, &mode))
+ die("There is no path %s in the commit", spec->path);
+ fill_filespec(spec, sha1, 1, mode);
+
+ return;
+}
+
+static void fill_line_ends(struct diff_filespec *spec, long *lines,
+ unsigned long **line_ends)
+{
+ int num = 0, size = 50;
+ long cur = 0;
+ unsigned long *ends = NULL;
+ char *data = NULL;
+
+ if (diff_populate_filespec(spec, 0))
+ die("Cannot read blob %s", sha1_to_hex(spec->sha1));
+
+ ends = xmalloc(size * sizeof(*ends));
+ ends[cur++] = 0;
+ data = spec->data;
+ while (num < spec->size) {
+ if (data[num] == '\n' || num == spec->size - 1) {
+ ALLOC_GROW(ends, (cur + 1), size);
+ ends[cur++] = num;
+ }
+ num++;
+ }
+
+ /* shrink the array to fit the elements */
+ ends = xrealloc(ends, cur * sizeof(*ends));
+ *lines = cur-1;
+ *line_ends = ends;
+}
+
+struct nth_line_cb {
+ struct diff_filespec *spec;
+ long lines;
+ unsigned long *line_ends;
+};
+
+static const char *nth_line(void *data, long line)
+{
+ struct nth_line_cb *d = data;
+ assert(d && line <= d->lines);
+ assert(d->spec && d->spec->data);
+
+ if (line == 0)
+ return (char *)d->spec->data;
+ else
+ return (char *)d->spec->data + d->line_ends[line] + 1;
+}
+
+static struct line_log_data *
+parse_lines(struct commit *commit, const char *prefix, struct string_list *args)
+{
+ long lines = 0;
+ unsigned long *ends = NULL;
+ struct nth_line_cb cb_data;
+ struct string_list_item *item;
+ struct line_log_data *ranges = NULL;
+ struct line_log_data *p;
+
+ for_each_string_list_item(item, args) {
+ const char *name_part, *range_part;
+ char *full_name;
+ struct diff_filespec *spec;
+ long begin = 0, end = 0;
+ long anchor;
+
+ name_part = skip_range_arg(item->string);
+ if (!name_part || *name_part != ':' || !name_part[1])
+ die("-L argument '%s' not of the form start,end:file",
+ item->string);
+ range_part = xstrndup(item->string, name_part - item->string);
+ name_part++;
+
+ full_name = prefix_path(prefix, prefix ? strlen(prefix) : 0,
+ name_part);
+
+ spec = alloc_filespec(full_name);
+ fill_blob_sha1(commit, spec);
+ fill_line_ends(spec, &lines, &ends);
+ cb_data.spec = spec;
+ cb_data.lines = lines;
+ cb_data.line_ends = ends;
+
+ p = search_line_log_data(ranges, full_name, NULL);
+ if (p && p->ranges.nr)
+ anchor = p->ranges.ranges[p->ranges.nr - 1].end + 1;
+ else
+ anchor = 1;
+
+ if (parse_range_arg(range_part, nth_line, &cb_data,
+ lines, anchor, &begin, &end,
+ full_name))
+ die("malformed -L argument '%s'", range_part);
+ if (lines < end || ((lines || begin) && lines < begin))
+ die("file %s has only %lu lines", name_part, lines);
+ if (begin < 1)
+ begin = 1;
+ if (end < 1)
+ end = lines;
+ begin--;
+ line_log_data_insert(&ranges, full_name, begin, end);
+
+ free_filespec(spec);
+ free(ends);
+ ends = NULL;
+ }
+
+ for (p = ranges; p; p = p->next)
+ sort_and_merge_range_set(&p->ranges);
+
+ return ranges;
+}
+
+static struct line_log_data *line_log_data_copy_one(struct line_log_data *r)
+{
+ struct line_log_data *ret = xmalloc(sizeof(*ret));
+
+ assert(r);
+ line_log_data_init(ret);
+ range_set_copy(&ret->ranges, &r->ranges);
+
+ ret->path = xstrdup(r->path);
+
+ return ret;
+}
+
+static struct line_log_data *
+line_log_data_copy(struct line_log_data *r)
+{
+ struct line_log_data *ret = NULL;
+ struct line_log_data *tmp = NULL, *prev = NULL;
+
+ assert(r);
+ ret = tmp = prev = line_log_data_copy_one(r);
+ r = r->next;
+ while (r) {
+ tmp = line_log_data_copy_one(r);
+ prev->next = tmp;
+ prev = tmp;
+ r = r->next;
+ }
+
+ return ret;
+}
+
+/* merge two range sets across files */
+static struct line_log_data *line_log_data_merge(struct line_log_data *a,
+ struct line_log_data *b)
+{
+ struct line_log_data *head = NULL, **pp = &head;
+
+ while (a || b) {
+ struct line_log_data *src;
+ struct line_log_data *src2 = NULL;
+ struct line_log_data *d;
+ int cmp;
+ if (!a)
+ cmp = 1;
+ else if (!b)
+ cmp = -1;
+ else
+ cmp = strcmp(a->path, b->path);
+ if (cmp < 0) {
+ src = a;
+ a = a->next;
+ } else if (cmp == 0) {
+ src = a;
+ a = a->next;
+ src2 = b;
+ b = b->next;
+ } else {
+ src = b;
+ b = b->next;
+ }
+ d = xmalloc(sizeof(struct line_log_data));
+ line_log_data_init(d);
+ d->path = xstrdup(src->path);
+ *pp = d;
+ pp = &d->next;
+ if (src2)
+ range_set_union(&d->ranges, &src->ranges, &src2->ranges);
+ else
+ range_set_copy(&d->ranges, &src->ranges);
+ }
+
+ return head;
+}
+
+static void add_line_range(struct rev_info *revs, struct commit *commit,
+ struct line_log_data *range)
+{
+ struct line_log_data *old = NULL;
+ struct line_log_data *new = NULL;
+
+ old = lookup_decoration(&revs->line_log_data, &commit->object);
+ if (old && range) {
+ new = line_log_data_merge(old, range);
+ free_line_log_data(old);
+ } else if (range)
+ new = line_log_data_copy(range);
+
+ if (new)
+ add_decoration(&revs->line_log_data, &commit->object, new);
+}
+
+static void clear_commit_line_range(struct rev_info *revs, struct commit *commit)
+{
+ struct line_log_data *r;
+ r = lookup_decoration(&revs->line_log_data, &commit->object);
+ if (!r)
+ return;
+ free_line_log_data(r);
+ add_decoration(&revs->line_log_data, &commit->object, NULL);
+}
+
+static struct line_log_data *lookup_line_range(struct rev_info *revs,
+ struct commit *commit)
+{
+ struct line_log_data *ret = NULL;
+ struct line_log_data *d;
+
+ ret = lookup_decoration(&revs->line_log_data, &commit->object);
+
+ for (d = ret; d; d = d->next)
+ range_set_check_invariants(&d->ranges);
+
+ return ret;
+}
+
+void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args)
+{
+ struct commit *commit = NULL;
+ struct line_log_data *range;
+
+ commit = check_single_commit(rev);
+ range = parse_lines(commit, prefix, args);
+ add_line_range(rev, commit, range);
+
+ if (!rev->diffopt.detect_rename) {
+ int i, count = 0;
+ struct line_log_data *r = range;
+ const char **paths;
+ while (r) {
+ count++;
+ r = r->next;
+ }
+ paths = xmalloc((count+1)*sizeof(char *));
+ r = range;
+ for (i = 0; i < count; i++) {
+ paths[i] = xstrdup(r->path);
+ r = r->next;
+ }
+ paths[count] = NULL;
+ parse_pathspec(&rev->diffopt.pathspec, 0, 0, "", paths);
+ free(paths);
+ }
+}
+
+static void load_tree_desc(struct tree_desc *desc, void **tree,
+ const unsigned char *sha1)
+{
+ unsigned long size;
+ *tree = read_object_with_reference(sha1, tree_type, &size, NULL);
+ if (!*tree)
+ die("Unable to read tree (%s)", sha1_to_hex(sha1));
+ init_tree_desc(desc, *tree, size);
+}
+
+static int count_parents(struct commit *commit)
+{
+ struct commit_list *parents = commit->parents;
+ int count = 0;
+ while (parents) {
+ count++;
+ parents = parents->next;
+ }
+ return count;
+}
+
+static void move_diff_queue(struct diff_queue_struct *dst,
+ struct diff_queue_struct *src)
+{
+ assert(src != dst);
+ memcpy(dst, src, sizeof(struct diff_queue_struct));
+ DIFF_QUEUE_CLEAR(src);
+}
+
+static void filter_diffs_for_paths(struct line_log_data *range, int keep_deletions)
+{
+ int i;
+ struct diff_queue_struct outq;
+ DIFF_QUEUE_CLEAR(&outq);
+
+ for (i = 0; i < diff_queued_diff.nr; i++) {
+ struct diff_filepair *p = diff_queued_diff.queue[i];
+ struct line_log_data *rg = NULL;
+
+ if (!DIFF_FILE_VALID(p->two)) {
+ if (keep_deletions)
+ diff_q(&outq, p);
+ else
+ diff_free_filepair(p);
+ continue;
+ }
+ for (rg = range; rg; rg = rg->next) {
+ if (!strcmp(rg->path, p->two->path))
+ break;
+ }
+ if (rg)
+ diff_q(&outq, p);
+ else
+ diff_free_filepair(p);
+ }
+ free(diff_queued_diff.queue);
+ diff_queued_diff = outq;
+}
+
+static inline int diff_might_be_rename(void)
+{
+ int i;
+ for (i = 0; i < diff_queued_diff.nr; i++)
+ if (!DIFF_FILE_VALID(diff_queued_diff.queue[i]->one)) {
+ /* fprintf(stderr, "diff_might_be_rename found creation of: %s\n", */
+ /* diff_queued_diff.queue[i]->two->path); */
+ return 1;
+ }
+ return 0;
+}
+
+static void queue_diffs(struct line_log_data *range,
+ struct diff_options *opt,
+ struct diff_queue_struct *queue,
+ struct commit *commit, struct commit *parent)
+{
+ void *tree1 = NULL, *tree2 = NULL;
+ struct tree_desc desc1, desc2;
+
+ assert(commit);
+ load_tree_desc(&desc2, &tree2, commit->tree->object.sha1);
+ if (parent)
+ load_tree_desc(&desc1, &tree1, parent->tree->object.sha1);
+ else
+ init_tree_desc(&desc1, "", 0);
+
+ DIFF_QUEUE_CLEAR(&diff_queued_diff);
+ diff_tree(&desc1, &desc2, "", opt);
+ if (opt->detect_rename) {
+ filter_diffs_for_paths(range, 1);
+ if (diff_might_be_rename())
+ diffcore_std(opt);
+ filter_diffs_for_paths(range, 0);
+ }
+ move_diff_queue(queue, &diff_queued_diff);
+
+ if (tree1)
+ free(tree1);
+ if (tree2)
+ free(tree2);
+}
+
+static char *get_nth_line(long line, unsigned long *ends, void *data)
+{
+ if (line == 0)
+ return (char *)data;
+ else
+ return (char *)data + ends[line] + 1;
+}
+
+static void print_line(const char *prefix, char first,
+ long line, unsigned long *ends, void *data,
+ const char *color, const char *reset)
+{
+ char *begin = get_nth_line(line, ends, data);
+ char *end = get_nth_line(line+1, ends, data);
+ int had_nl = 0;
+
+ if (end > begin && end[-1] == '\n') {
+ end--;
+ had_nl = 1;
+ }
+
+ fputs(prefix, stdout);
+ fputs(color, stdout);
+ putchar(first);
+ fwrite(begin, 1, end-begin, stdout);
+ fputs(reset, stdout);
+ putchar('\n');
+ if (!had_nl)
+ fputs("\\ No newline at end of file\n", stdout);
+}
+
+static char *output_prefix(struct diff_options *opt)
+{
+ char *prefix = "";
+
+ if (opt->output_prefix) {
+ struct strbuf *sb = opt->output_prefix(opt, opt->output_prefix_data);
+ prefix = sb->buf;
+ }
+
+ return prefix;
+}
+
+static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *range)
+{
+ int i, j = 0;
+ long p_lines, t_lines;
+ unsigned long *p_ends = NULL, *t_ends = NULL;
+ struct diff_filepair *pair = range->pair;
+ struct diff_ranges *diff = &range->diff;
+
+ struct diff_options *opt = &rev->diffopt;
+ char *prefix = output_prefix(opt);
+ const char *c_reset = diff_get_color(opt->use_color, DIFF_RESET);
+ const char *c_frag = diff_get_color(opt->use_color, DIFF_FRAGINFO);
+ const char *c_meta = diff_get_color(opt->use_color, DIFF_METAINFO);
+ const char *c_old = diff_get_color(opt->use_color, DIFF_FILE_OLD);
+ const char *c_new = diff_get_color(opt->use_color, DIFF_FILE_NEW);
+ const char *c_plain = diff_get_color(opt->use_color, DIFF_PLAIN);
+
+ if (!pair || !diff)
+ return;
+
+ if (pair->one->sha1_valid)
+ fill_line_ends(pair->one, &p_lines, &p_ends);
+ fill_line_ends(pair->two, &t_lines, &t_ends);
+
+ printf("%s%sdiff --git a/%s b/%s%s\n", prefix, c_meta, pair->one->path, pair->two->path, c_reset);
+ printf("%s%s--- %s%s%s\n", prefix, c_meta,
+ pair->one->sha1_valid ? "a/" : "",
+ pair->one->sha1_valid ? pair->one->path : "/dev/null",
+ c_reset);
+ printf("%s%s+++ b/%s%s\n", prefix, c_meta, pair->two->path, c_reset);
+ for (i = 0; i < range->ranges.nr; i++) {
+ long p_start, p_end;
+ long t_start = range->ranges.ranges[i].start;
+ long t_end = range->ranges.ranges[i].end;
+ long t_cur = t_start;
+ int j_last;
+
+ while (j < diff->target.nr && diff->target.ranges[j].end < t_start)
+ j++;
+ if (j == diff->target.nr || diff->target.ranges[j].start > t_end)
+ continue;
+
+ /* Scan ahead to determine the last diff that falls in this range */
+ j_last = j;
+ while (j_last < diff->target.nr && diff->target.ranges[j_last].start < t_end)
+ j_last++;
+ if (j_last > j)
+ j_last--;
+
+ /*
+ * Compute parent hunk headers: we know that the diff
+ * has the correct line numbers (but not all hunks).
+ * So it suffices to shift the start/end according to
+ * the line numbers of the first/last hunk(s) that
+ * fall in this range.
+ */
+ if (t_start < diff->target.ranges[j].start)
+ p_start = diff->parent.ranges[j].start - (diff->target.ranges[j].start-t_start);
+ else
+ p_start = diff->parent.ranges[j].start;
+ if (t_end > diff->target.ranges[j_last].end)
+ p_end = diff->parent.ranges[j_last].end + (t_end-diff->target.ranges[j_last].end);
+ else
+ p_end = diff->parent.ranges[j_last].end;
+
+ if (!p_start && !p_end) {
+ p_start = -1;
+ p_end = -1;
+ }
+
+ /* Now output a diff hunk for this range */
+ printf("%s%s@@ -%ld,%ld +%ld,%ld @@%s\n",
+ prefix, c_frag,
+ p_start+1, p_end-p_start, t_start+1, t_end-t_start,
+ c_reset);
+ while (j < diff->target.nr && diff->target.ranges[j].start < t_end) {
+ int k;
+ for (; t_cur < diff->target.ranges[j].start; t_cur++)
+ print_line(prefix, ' ', t_cur, t_ends, pair->two->data,
+ c_plain, c_reset);
+ for (k = diff->parent.ranges[j].start; k < diff->parent.ranges[j].end; k++)
+ print_line(prefix, '-', k, p_ends, pair->one->data,
+ c_old, c_reset);
+ for (; t_cur < diff->target.ranges[j].end && t_cur < t_end; t_cur++)
+ print_line(prefix, '+', t_cur, t_ends, pair->two->data,
+ c_new, c_reset);
+ j++;
+ }
+ for (; t_cur < t_end; t_cur++)
+ print_line(prefix, ' ', t_cur, t_ends, pair->two->data,
+ c_plain, c_reset);
+ }
+
+ free(p_ends);
+ free(t_ends);
+}
+
+/*
+ * NEEDSWORK: manually building a diff here is not the Right
+ * Thing(tm). log -L should be built into the diff pipeline.
+ */
+static void dump_diff_hacky(struct rev_info *rev, struct line_log_data *range)
+{
+ puts(output_prefix(&rev->diffopt));
+ while (range) {
+ dump_diff_hacky_one(rev, range);
+ range = range->next;
+ }
+}
+
+/*
+ * Unlike most other functions, this destructively operates on
+ * 'range'.
+ */
+static int process_diff_filepair(struct rev_info *rev,
+ struct diff_filepair *pair,
+ struct line_log_data *range,
+ struct diff_ranges **diff_out)
+{
+ struct line_log_data *rg = range;
+ struct range_set tmp;
+ struct diff_ranges diff;
+ mmfile_t file_parent, file_target;
+
+ assert(pair->two->path);
+ while (rg) {
+ assert(rg->path);
+ if (!strcmp(rg->path, pair->two->path))
+ break;
+ rg = rg->next;
+ }
+
+ if (!rg)
+ return 0;
+ if (rg->ranges.nr == 0)
+ return 0;
+
+ assert(pair->two->sha1_valid);
+ diff_populate_filespec(pair->two, 0);
+ file_target.ptr = pair->two->data;
+ file_target.size = pair->two->size;
+
+ if (pair->one->sha1_valid) {
+ diff_populate_filespec(pair->one, 0);
+ file_parent.ptr = pair->one->data;
+ file_parent.size = pair->one->size;
+ } else {
+ file_parent.ptr = "";
+ file_parent.size = 0;
+ }
+
+ diff_ranges_init(&diff);
+ collect_diff(&file_parent, &file_target, &diff);
+
+ /* NEEDSWORK should apply some heuristics to prevent mismatches */
+ free(rg->path);
+ rg->path = xstrdup(pair->one->path);
+
+ range_set_init(&tmp, 0);
+ range_set_map_across_diff(&tmp, &rg->ranges, &diff, diff_out);
+ range_set_release(&rg->ranges);
+ range_set_move(&rg->ranges, &tmp);
+
+ diff_ranges_release(&diff);
+
+ return ((*diff_out)->parent.nr > 0);
+}
+
+static struct diff_filepair *diff_filepair_dup(struct diff_filepair *pair)
+{
+ struct diff_filepair *new = xmalloc(sizeof(struct diff_filepair));
+ new->one = pair->one;
+ new->two = pair->two;
+ new->one->count++;
+ new->two->count++;
+ return new;
+}
+
+static void free_diffqueues(int n, struct diff_queue_struct *dq)
+{
+ int i, j;
+ for (i = 0; i < n; i++)
+ for (j = 0; j < dq[i].nr; j++)
+ diff_free_filepair(dq[i].queue[j]);
+ free(dq);
+}
+
+static int process_all_files(struct line_log_data **range_out,
+ struct rev_info *rev,
+ struct diff_queue_struct *queue,
+ struct line_log_data *range)
+{
+ int i, changed = 0;
+
+ *range_out = line_log_data_copy(range);
+
+ for (i = 0; i < queue->nr; i++) {
+ struct diff_ranges *pairdiff = NULL;
+ struct diff_filepair *pair = queue->queue[i];
+ if (process_diff_filepair(rev, pair, *range_out, &pairdiff)) {
+ /*
+ * Store away the diff for later output. We
+ * tuck it in the ranges we got as _input_,
+ * since that's the commit that caused the
+ * diff.
+ *
+ * NEEDSWORK not enough when we get around to
+ * doing something interesting with merges;
+ * currently each invocation on a merge parent
+ * trashes the previous one's diff.
+ *
+ * NEEDSWORK tramples over data structures not owned here
+ */
+ struct line_log_data *rg = range;
+ changed++;
+ while (rg && strcmp(rg->path, pair->two->path))
+ rg = rg->next;
+ assert(rg);
+ rg->pair = diff_filepair_dup(queue->queue[i]);
+ memcpy(&rg->diff, pairdiff, sizeof(struct diff_ranges));
+ }
+ }
+
+ return changed;
+}
+
+int line_log_print(struct rev_info *rev, struct commit *commit)
+{
+ struct line_log_data *range = lookup_line_range(rev, commit);
+
+ show_log(rev);
+ dump_diff_hacky(rev, range);
+ return 1;
+}
+
+static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *commit,
+ struct line_log_data *range)
+{
+ struct commit *parent = NULL;
+ struct diff_queue_struct queue;
+ struct line_log_data *parent_range;
+ int changed;
+
+ if (commit->parents)
+ parent = commit->parents->item;
+
+ queue_diffs(range, &rev->diffopt, &queue, commit, parent);
+ changed = process_all_files(&parent_range, rev, &queue, range);
+ if (parent)
+ add_line_range(rev, parent, parent_range);
+ return changed;
+}
+
+static int process_ranges_merge_commit(struct rev_info *rev, struct commit *commit,
+ struct line_log_data *range)
+{
+ struct diff_queue_struct *diffqueues;
+ struct line_log_data **cand;
+ struct commit **parents;
+ struct commit_list *p;
+ int i;
+ int nparents = count_parents(commit);
+
+ diffqueues = xmalloc(nparents * sizeof(*diffqueues));
+ cand = xmalloc(nparents * sizeof(*cand));
+ parents = xmalloc(nparents * sizeof(*parents));
+
+ p = commit->parents;
+ for (i = 0; i < nparents; i++) {
+ parents[i] = p->item;
+ p = p->next;
+ queue_diffs(range, &rev->diffopt, &diffqueues[i], commit, parents[i]);
+ }
+
+ for (i = 0; i < nparents; i++) {
+ int changed;
+ cand[i] = NULL;
+ changed = process_all_files(&cand[i], rev, &diffqueues[i], range);
+ if (!changed) {
+ /*
+ * This parent can take all the blame, so we
+ * don't follow any other path in history
+ */
+ add_line_range(rev, parents[i], cand[i]);
+ clear_commit_line_range(rev, commit);
+ commit->parents = xmalloc(sizeof(struct commit_list));
+ commit->parents->item = parents[i];
+ commit->parents->next = NULL;
+ free(parents);
+ free(cand);
+ free_diffqueues(nparents, diffqueues);
+ /* NEEDSWORK leaking like a sieve */
+ return 0;
+ }
+ }
+
+ /*
+ * No single parent took the blame. We add the candidates
+ * from the above loop to the parents.
+ */
+ for (i = 0; i < nparents; i++) {
+ add_line_range(rev, parents[i], cand[i]);
+ }
+
+ clear_commit_line_range(rev, commit);
+ free(parents);
+ free(cand);
+ free_diffqueues(nparents, diffqueues);
+ return 1;
+
+ /* NEEDSWORK evil merge detection stuff */
+ /* NEEDSWORK leaking like a sieve */
+}
+
+static int process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit)
+{
+ struct line_log_data *range = lookup_line_range(rev, commit);
+ int changed = 0;
+
+ if (range) {
+ if (!commit->parents || !commit->parents->next)
+ changed = process_ranges_ordinary_commit(rev, commit, range);
+ else
+ changed = process_ranges_merge_commit(rev, commit, range);
+ }
+
+ if (!changed)
+ commit->object.flags |= TREESAME;
+
+ return changed;
+}
+
+static enum rewrite_result line_log_rewrite_one(struct rev_info *rev, struct commit **pp)
+{
+ for (;;) {
+ struct commit *p = *pp;
+ if (p->parents && p->parents->next)
+ return rewrite_one_ok;
+ if (p->object.flags & UNINTERESTING)
+ return rewrite_one_ok;
+ if (!(p->object.flags & TREESAME))
+ return rewrite_one_ok;
+ if (!p->parents)
+ return rewrite_one_noparents;
+ *pp = p->parents->item;
+ }
+}
+
+int line_log_filter(struct rev_info *rev)
+{
+ struct commit *commit;
+ struct commit_list *list = rev->commits;
+ struct commit_list *out = NULL, **pp = &out;
+
+ while (list) {
+ struct commit_list *to_free = NULL;
+ commit = list->item;
+ if (process_ranges_arbitrary_commit(rev, commit)) {
+ *pp = list;
+ pp = &list->next;
+ } else
+ to_free = list;
+ list = list->next;
+ free(to_free);
+ }
+ *pp = NULL;
+
+ for (list = out; list; list = list->next)
+ rewrite_parents(rev, list->item, line_log_rewrite_one);
+
+ rev->commits = out;
+
+ return 0;
+}
diff --git a/line-log.h b/line-log.h
new file mode 100644
index 0000000..a9212d8
--- /dev/null
+++ b/line-log.h
@@ -0,0 +1,65 @@
+#ifndef LINE_LOG_H
+#define LINE_LOG_H
+
+#include "diffcore.h"
+
+struct rev_info;
+struct commit;
+
+/* A range [start,end]. Lines are numbered starting at 0, and the
+ * ranges include start but exclude end. */
+struct range {
+ long start, end;
+};
+
+/* A set of ranges. The ranges must always be disjoint and sorted. */
+struct range_set {
+ int alloc, nr;
+ struct range *ranges;
+};
+
+/* A diff, encoded as the set of pre- and post-image ranges where the
+ * files differ. A pair of ranges corresponds to a hunk. */
+struct diff_ranges {
+ struct range_set parent;
+ struct range_set target;
+};
+
+extern void range_set_init(struct range_set *, size_t prealloc);
+extern void range_set_release(struct range_set *);
+/* Range includes start; excludes end */
+extern void range_set_append_unsafe(struct range_set *, long start, long end);
+/* New range must begin at or after end of last added range */
+extern void range_set_append(struct range_set *, long start, long end);
+/*
+ * In-place pass of sorting and merging the ranges in the range set,
+ * to sort and make the ranges disjoint.
+ */
+extern void sort_and_merge_range_set(struct range_set *);
+
+/* Linked list of interesting files and their associated ranges. The
+ * list must be kept sorted by path.
+ *
+ * For simplicity, even though this is highly redundant, each
+ * line_log_data owns its 'path'.
+ */
+struct line_log_data {
+ struct line_log_data *next;
+ char *path;
+ char status;
+ struct range_set ranges;
+ int arg_alloc, arg_nr;
+ const char **args;
+ struct diff_filepair *pair;
+ struct diff_ranges diff;
+};
+
+extern void line_log_data_init(struct line_log_data *r);
+
+extern void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args);
+
+extern int line_log_filter(struct rev_info *rev);
+
+extern int line_log_print(struct rev_info *rev, struct commit *commit);
+
+#endif /* LINE_LOG_H */
diff --git a/line-range.c b/line-range.c
new file mode 100644
index 0000000..de4e32f
--- /dev/null
+++ b/line-range.c
@@ -0,0 +1,290 @@
+#include "git-compat-util.h"
+#include "line-range.h"
+#include "xdiff-interface.h"
+#include "strbuf.h"
+#include "userdiff.h"
+
+/*
+ * Parse one item in the -L option
+ *
+ * 'begin' is applicable only to relative range anchors. Absolute anchors
+ * ignore this value.
+ *
+ * When parsing "-L A,B", parse_loc() is called once for A and once for B.
+ *
+ * When parsing A, 'begin' must be a negative number, the absolute value of
+ * which is the line at which relative start-of-range anchors should be
+ * based. Beginning of file is represented by -1.
+ *
+ * When parsing B, 'begin' must be the positive line number immediately
+ * following the line computed for 'A'.
+ */
+static const char *parse_loc(const char *spec, nth_line_fn_t nth_line,
+ void *data, long lines, long begin, long *ret)
+{
+ char *term;
+ const char *line;
+ long num;
+ int reg_error;
+ regex_t regexp;
+ regmatch_t match[1];
+
+ /* Allow "-L <something>,+20" to mean starting at <something>
+ * for 20 lines, or "-L <something>,-5" for 5 lines ending at
+ * <something>.
+ */
+ if (1 <= begin && (spec[0] == '+' || spec[0] == '-')) {
+ num = strtol(spec + 1, &term, 10);
+ if (term != spec + 1) {
+ if (!ret)
+ return term;
+ if (num == 0)
+ die("-L invalid empty range");
+ if (spec[0] == '-')
+ num = 0 - num;
+ if (0 < num)
+ *ret = begin + num - 2;
+ else if (!num)
+ *ret = begin;
+ else
+ *ret = begin + num;
+ return term;
+ }
+ return spec;
+ }
+ num = strtol(spec, &term, 10);
+ if (term != spec) {
+ if (ret) {
+ if (num <= 0)
+ die("-L invalid line number: %ld", num);
+ *ret = num;
+ }
+ return term;
+ }
+
+ if (begin < 0) {
+ if (spec[0] != '^')
+ begin = -begin;
+ else {
+ begin = 1;
+ spec++;
+ }
+ }
+
+ if (spec[0] != '/')
+ return spec;
+
+ /* it could be a regexp of form /.../ */
+ for (term = (char *) spec + 1; *term && *term != '/'; term++) {
+ if (*term == '\\')
+ term++;
+ }
+ if (*term != '/')
+ return spec;
+
+ /* in the scan-only case we are not interested in the regex */
+ if (!ret)
+ return term+1;
+
+ /* try [spec+1 .. term-1] as regexp */
+ *term = 0;
+ begin--; /* input is in human terms */
+ line = nth_line(data, begin);
+
+ if (!(reg_error = regcomp(&regexp, spec + 1, REG_NEWLINE)) &&
+ !(reg_error = regexec(&regexp, line, 1, match, 0))) {
+ const char *cp = line + match[0].rm_so;
+ const char *nline;
+
+ while (begin++ < lines) {
+ nline = nth_line(data, begin);
+ if (line <= cp && cp < nline)
+ break;
+ line = nline;
+ }
+ *ret = begin;
+ regfree(&regexp);
+ *term++ = '/';
+ return term;
+ }
+ else {
+ char errbuf[1024];
+ regerror(reg_error, &regexp, errbuf, 1024);
+ die("-L parameter '%s' starting at line %ld: %s",
+ spec + 1, begin + 1, errbuf);
+ }
+}
+
+static int match_funcname(xdemitconf_t *xecfg, const char *bol, const char *eol)
+{
+ if (xecfg) {
+ char buf[1];
+ return xecfg->find_func(bol, eol - bol, buf, 1,
+ xecfg->find_func_priv) >= 0;
+ }
+
+ if (bol == eol)
+ return 0;
+ if (isalpha(*bol) || *bol == '_' || *bol == '$')
+ return 1;
+ return 0;
+}
+
+static const char *find_funcname_matching_regexp(xdemitconf_t *xecfg, const char *start,
+ regex_t *regexp)
+{
+ int reg_error;
+ regmatch_t match[1];
+ while (1) {
+ const char *bol, *eol;
+ reg_error = regexec(regexp, start, 1, match, 0);
+ if (reg_error == REG_NOMATCH)
+ return NULL;
+ else if (reg_error) {
+ char errbuf[1024];
+ regerror(reg_error, regexp, errbuf, 1024);
+ die("-L parameter: regexec() failed: %s", errbuf);
+ }
+ /* determine extent of line matched */
+ bol = start+match[0].rm_so;
+ eol = start+match[0].rm_eo;
+ while (bol > start && *bol != '\n')
+ bol--;
+ if (*bol == '\n')
+ bol++;
+ while (*eol && *eol != '\n')
+ eol++;
+ if (*eol == '\n')
+ eol++;
+ /* is it a funcname line? */
+ if (match_funcname(xecfg, (char*) bol, (char*) eol))
+ return bol;
+ start = eol;
+ }
+}
+
+static const char *parse_range_funcname(const char *arg, nth_line_fn_t nth_line_cb,
+ void *cb_data, long lines, long anchor, long *begin, long *end,
+ const char *path)
+{
+ char *pattern;
+ const char *term;
+ struct userdiff_driver *drv;
+ xdemitconf_t *xecfg = NULL;
+ const char *start;
+ const char *p;
+ int reg_error;
+ regex_t regexp;
+
+ if (*arg == '^') {
+ anchor = 1;
+ arg++;
+ }
+
+ assert(*arg == ':');
+ term = arg+1;
+ while (*term && *term != ':') {
+ if (*term == '\\' && *(term+1))
+ term++;
+ term++;
+ }
+ if (term == arg+1)
+ return NULL;
+ if (!begin) /* skip_range_arg case */
+ return term;
+
+ pattern = xstrndup(arg+1, term-(arg+1));
+
+ anchor--; /* input is in human terms */
+ start = nth_line_cb(cb_data, anchor);
+
+ drv = userdiff_find_by_path(path);
+ if (drv && drv->funcname.pattern) {
+ const struct userdiff_funcname *pe = &drv->funcname;
+ xecfg = xcalloc(1, sizeof(*xecfg));
+ xdiff_set_find_func(xecfg, pe->pattern, pe->cflags);
+ }
+
+ reg_error = regcomp(&regexp, pattern, REG_NEWLINE);
+ if (reg_error) {
+ char errbuf[1024];
+ regerror(reg_error, &regexp, errbuf, 1024);
+ die("-L parameter '%s': %s", pattern, errbuf);
+ }
+
+ p = find_funcname_matching_regexp(xecfg, (char*) start, &regexp);
+ if (!p)
+ die("-L parameter '%s' starting at line %ld: no match",
+ pattern, anchor + 1);
+ *begin = 0;
+ while (p > nth_line_cb(cb_data, *begin))
+ (*begin)++;
+
+ if (*begin >= lines)
+ die("-L parameter '%s' matches at EOF", pattern);
+
+ *end = *begin+1;
+ while (*end < lines) {
+ const char *bol = nth_line_cb(cb_data, *end);
+ const char *eol = nth_line_cb(cb_data, *end+1);
+ if (match_funcname(xecfg, bol, eol))
+ break;
+ (*end)++;
+ }
+
+ regfree(&regexp);
+ free(xecfg);
+ free(pattern);
+
+ /* compensate for 1-based numbering */
+ (*begin)++;
+
+ return term;
+}
+
+int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb,
+ void *cb_data, long lines, long anchor,
+ long *begin, long *end, const char *path)
+{
+ *begin = *end = 0;
+
+ if (anchor < 1)
+ anchor = 1;
+ if (anchor > lines)
+ anchor = lines + 1;
+
+ if (*arg == ':' || (*arg == '^' && *(arg + 1) == ':')) {
+ arg = parse_range_funcname(arg, nth_line_cb, cb_data, lines, anchor, begin, end, path);
+ if (!arg || *arg)
+ return -1;
+ return 0;
+ }
+
+ arg = parse_loc(arg, nth_line_cb, cb_data, lines, -anchor, begin);
+
+ if (*arg == ',')
+ arg = parse_loc(arg + 1, nth_line_cb, cb_data, lines, *begin + 1, end);
+
+ if (*arg)
+ return -1;
+
+ if (*begin && *end && *end < *begin) {
+ long tmp;
+ tmp = *end; *end = *begin; *begin = tmp;
+ }
+
+ return 0;
+}
+
+const char *skip_range_arg(const char *arg)
+{
+ if (*arg == ':' || (*arg == '^' && *(arg + 1) == ':'))
+ return parse_range_funcname(arg, NULL, NULL, 0, 0, NULL, NULL, NULL);
+
+ arg = parse_loc(arg, NULL, NULL, 0, -1, NULL);
+
+ if (*arg == ',')
+ arg = parse_loc(arg+1, NULL, NULL, 0, 0, NULL);
+
+ return arg;
+}
diff --git a/line-range.h b/line-range.h
new file mode 100644
index 0000000..83ba3c2
--- /dev/null
+++ b/line-range.h
@@ -0,0 +1,39 @@
+#ifndef LINE_RANGE_H
+#define LINE_RANGE_H
+
+/*
+ * Parse one item in an -L begin,end option w.r.t. the notional file
+ * object 'cb_data' consisting of 'lines' lines.
+ *
+ * The 'nth_line_cb' callback is used to determine the start of the
+ * line 'lno' inside the 'cb_data'. The caller is expected to already
+ * have a suitable map at hand to make this a constant-time lookup.
+ *
+ * 'anchor' is the 1-based line at which relative range specifications
+ * should be anchored. Absolute ranges are unaffected by this value.
+ *
+ * Returns 0 in case of success and -1 if there was an error. The
+ * actual range is stored in *begin and *end. The counting starts
+ * at 1! In case of error, the caller should show usage message.
+ */
+
+typedef const char *(*nth_line_fn_t)(void *data, long lno);
+
+extern int parse_range_arg(const char *arg,
+ nth_line_fn_t nth_line_cb,
+ void *cb_data, long lines, long anchor,
+ long *begin, long *end,
+ const char *path);
+
+/*
+ * Scan past a range argument that could be parsed by
+ * 'parse_range_arg', to help the caller determine the start of the
+ * filename in '-L n,m:file' syntax.
+ *
+ * Returns a pointer to the first character after the 'n,m' part, or
+ * NULL in case the argument is obviously malformed.
+ */
+
+extern const char *skip_range_arg(const char *arg);
+
+#endif /* LINE_RANGE_H */
diff --git a/lockfile.c b/lockfile.c
index c6fb77b..8fbcb6a 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -124,15 +124,17 @@ static char *resolve_symlink(char *p, size_t s)
static int lock_file(struct lock_file *lk, const char *path, int flags)
{
- if (strlen(path) >= sizeof(lk->filename))
- return -1;
- strcpy(lk->filename, path);
/*
* subtract 5 from size to make sure there's room for adding
* ".lock" for the lock file name
*/
+ static const size_t max_path_len = sizeof(lk->filename) - 5;
+
+ if (strlen(path) >= max_path_len)
+ return -1;
+ strcpy(lk->filename, path);
if (!(flags & LOCK_NODEREF))
- resolve_symlink(lk->filename, sizeof(lk->filename)-5);
+ resolve_symlink(lk->filename, max_path_len);
strcat(lk->filename, ".lock");
lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
if (0 <= lk->fd) {
diff --git a/log-tree.c b/log-tree.c
index 3d88823..8534d91 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -9,6 +9,8 @@
#include "string-list.h"
#include "color.h"
#include "gpg-interface.h"
+#include "sequencer.h"
+#include "line-log.h"
struct decoration name_decoration = { "object names" };
@@ -174,119 +176,52 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
}
}
-void show_decorations(struct rev_info *opt, struct commit *commit)
+/*
+ * The caller makes sure there is no funny color before
+ * calling. format_decorations makes sure the same after return.
+ */
+void format_decorations(struct strbuf *sb,
+ const struct commit *commit,
+ int use_color)
{
const char *prefix;
struct name_decoration *decoration;
const char *color_commit =
- diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
+ diff_get_color(use_color, DIFF_COMMIT);
const char *color_reset =
- decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
+ decorate_get_color(use_color, DECORATION_NONE);
- if (opt->show_source && commit->util)
- printf("\t%s", (char *) commit->util);
- if (!opt->show_decorations)
- return;
decoration = lookup_decoration(&name_decoration, &commit->object);
if (!decoration)
return;
prefix = " (";
while (decoration) {
- printf("%s", prefix);
- fputs(decorate_get_color_opt(&opt->diffopt, decoration->type),
- stdout);
+ strbuf_addstr(sb, color_commit);
+ strbuf_addstr(sb, prefix);
+ strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
if (decoration->type == DECORATION_REF_TAG)
- fputs("tag: ", stdout);
- printf("%s", decoration->name);
- fputs(color_reset, stdout);
- fputs(color_commit, stdout);
+ strbuf_addstr(sb, "tag: ");
+ strbuf_addstr(sb, decoration->name);
+ strbuf_addstr(sb, color_reset);
prefix = ", ";
decoration = decoration->next;
}
- putchar(')');
+ strbuf_addstr(sb, color_commit);
+ strbuf_addch(sb, ')');
+ strbuf_addstr(sb, color_reset);
}
-/*
- * Search for "^[-A-Za-z]+: [^@]+@" pattern. It usually matches
- * Signed-off-by: and Acked-by: lines.
- */
-static int detect_any_signoff(char *letter, int size)
-{
- char *cp;
- int seen_colon = 0;
- int seen_at = 0;
- int seen_name = 0;
- int seen_head = 0;
-
- cp = letter + size;
- while (letter <= --cp && *cp == '\n')
- continue;
-
- while (letter <= cp) {
- char ch = *cp--;
- if (ch == '\n')
- break;
-
- if (!seen_at) {
- if (ch == '@')
- seen_at = 1;
- continue;
- }
- if (!seen_colon) {
- if (ch == '@')
- return 0;
- else if (ch == ':')
- seen_colon = 1;
- else
- seen_name = 1;
- continue;
- }
- if (('A' <= ch && ch <= 'Z') ||
- ('a' <= ch && ch <= 'z') ||
- ch == '-') {
- seen_head = 1;
- continue;
- }
- /* no empty last line doesn't match */
- return 0;
- }
- return seen_head && seen_name;
-}
-
-static void append_signoff(struct strbuf *sb, const char *signoff)
+void show_decorations(struct rev_info *opt, struct commit *commit)
{
- static const char signed_off_by[] = "Signed-off-by: ";
- size_t signoff_len = strlen(signoff);
- int has_signoff = 0;
- char *cp;
-
- cp = sb->buf;
+ struct strbuf sb = STRBUF_INIT;
- /* First see if we already have the sign-off by the signer */
- while ((cp = strstr(cp, signed_off_by))) {
-
- has_signoff = 1;
-
- cp += strlen(signed_off_by);
- if (cp + signoff_len >= sb->buf + sb->len)
- break;
- if (strncmp(cp, signoff, signoff_len))
- continue;
- if (!isspace(cp[signoff_len]))
- continue;
- /* we already have him */
+ if (opt->show_source && commit->util)
+ printf("\t%s", (char *) commit->util);
+ if (!opt->show_decorations)
return;
- }
-
- if (!has_signoff)
- has_signoff = detect_any_signoff(sb->buf, sb->len);
-
- if (!has_signoff)
- strbuf_addch(sb, '\n');
-
- strbuf_addstr(sb, signed_off_by);
- strbuf_add(sb, signoff, signoff_len);
- strbuf_addch(sb, '\n');
+ format_decorations(&sb, commit, opt->diffopt.use_color);
+ fputs(sb.buf, stdout);
+ strbuf_release(&sb);
}
static unsigned int digits_in_number(unsigned int number)
@@ -622,8 +557,8 @@ void show_log(struct rev_info *opt)
printf(" (from %s)",
find_unique_abbrev(parent->object.sha1,
abbrev_commit));
+ fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), stdout);
show_decorations(opt, commit);
- printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
if (opt->commit_format == CMIT_FMT_ONELINE) {
putchar(' ');
} else {
@@ -669,8 +604,10 @@ void show_log(struct rev_info *opt)
/*
* And then the pretty-printed message itself
*/
- if (ctx.need_8bit_cte >= 0)
- ctx.need_8bit_cte = has_non_ascii(opt->add_signoff);
+ if (ctx.need_8bit_cte >= 0 && opt->add_signoff)
+ ctx.need_8bit_cte =
+ has_non_ascii(fmt_name(getenv("GIT_COMMITTER_NAME"),
+ getenv("GIT_COMMITTER_EMAIL")));
ctx.date_mode = opt->date_mode;
ctx.date_mode_explicit = opt->date_mode_explicit;
ctx.abbrev = opt->diffopt.abbrev;
@@ -680,10 +617,13 @@ void show_log(struct rev_info *opt)
ctx.fmt = opt->commit_format;
ctx.mailmap = opt->mailmap;
ctx.color = opt->diffopt.use_color;
+ ctx.output_encoding = get_log_output_encoding();
+ if (opt->from_ident.mail_begin && opt->from_ident.name_begin)
+ ctx.from_ident = &opt->from_ident;
pretty_print_commit(&ctx, commit, &msgbuf);
if (opt->add_signoff)
- append_signoff(&msgbuf, opt->add_signoff);
+ append_signoff(&msgbuf, 0, APPEND_SIGNOFF_DEDUP);
if ((ctx.fmt != CMIT_FMT_USERFORMAT) &&
ctx.notes_message && *ctx.notes_message) {
@@ -789,13 +729,16 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
{
int showed_log;
struct commit_list *parents;
- unsigned const char *sha1 = commit->object.sha1;
+ unsigned const char *sha1;
if (!opt->diff && !DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS))
return 0;
+ parse_commit(commit);
+ sha1 = commit->tree->object.sha1;
+
/* Root commit? */
- parents = commit->parents;
+ parents = get_saved_parents(opt, commit);
if (!parents) {
if (opt->show_root_diff) {
diff_root_tree_sha1(sha1, "", &opt->diffopt);
@@ -816,7 +759,9 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
* parent, showing summary diff of the others
* we merged _in_.
*/
- diff_tree_sha1(parents->item->object.sha1, sha1, "", &opt->diffopt);
+ parse_commit(parents->item);
+ diff_tree_sha1(parents->item->tree->object.sha1,
+ sha1, "", &opt->diffopt);
log_tree_diff_flush(opt);
return !opt->loginfo;
}
@@ -829,7 +774,9 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
for (;;) {
struct commit *parent = parents->item;
- diff_tree_sha1(parent->object.sha1, sha1, "", &opt->diffopt);
+ parse_commit(parent);
+ diff_tree_sha1(parent->tree->object.sha1,
+ sha1, "", &opt->diffopt);
log_tree_diff_flush(opt);
showed_log |= !opt->loginfo;
@@ -853,6 +800,9 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
log.parent = NULL;
opt->loginfo = &log;
+ if (opt->line_level_traverse)
+ return line_log_print(opt, commit);
+
shown = log_tree_diff(opt, commit, &log);
if (!shown && opt->loginfo && opt->always_show_header) {
log.parent = NULL;
diff --git a/log-tree.h b/log-tree.h
index 9140f48..d6ecd4d 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -13,6 +13,7 @@ int log_tree_diff_flush(struct rev_info *);
int log_tree_commit(struct rev_info *, struct commit *);
int log_tree_opt_parse(struct rev_info *, const char **, int);
void show_log(struct rev_info *opt);
+void format_decorations(struct strbuf *sb, const struct commit *commit, int use_color);
void show_decorations(struct rev_info *opt, struct commit *commit);
void log_write_email_headers(struct rev_info *opt, struct commit *commit,
const char **subject_p,
diff --git a/mailmap.c b/mailmap.c
index 2a7b366..a7969c4 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -5,8 +5,10 @@
#define DEBUG_MAILMAP 0
#if DEBUG_MAILMAP
#define debug_mm(...) fprintf(stderr, __VA_ARGS__)
+#define debug_str(X) ((X) ? (X) : "(none)")
#else
static inline void debug_mm(const char *format, ...) {}
+static inline const char *debug_str(const char *s) { return s; }
#endif
const char *git_mailmap_file;
@@ -29,7 +31,8 @@ struct mailmap_entry {
static void free_mailmap_info(void *p, const char *s)
{
struct mailmap_info *mi = (struct mailmap_info *)p;
- debug_mm("mailmap: -- complex: '%s' -> '%s' <%s>\n", s, mi->name, mi->email);
+ debug_mm("mailmap: -- complex: '%s' -> '%s' <%s>\n",
+ s, debug_str(mi->name), debug_str(mi->email));
free(mi->name);
free(mi->email);
}
@@ -37,8 +40,11 @@ static void free_mailmap_info(void *p, const char *s)
static void free_mailmap_entry(void *p, const char *s)
{
struct mailmap_entry *me = (struct mailmap_entry *)p;
- debug_mm("mailmap: removing entries for <%s>, with %d sub-entries\n", s, me->namemap.nr);
- debug_mm("mailmap: - simple: '%s' <%s>\n", me->name, me->email);
+ debug_mm("mailmap: removing entries for <%s>, with %d sub-entries\n",
+ s, me->namemap.nr);
+ debug_mm("mailmap: - simple: '%s' <%s>\n",
+ debug_str(me->name), debug_str(me->email));
+
free(me->name);
free(me->email);
@@ -47,18 +53,11 @@ static void free_mailmap_entry(void *p, const char *s)
}
static void add_mapping(struct string_list *map,
- char *new_name, char *new_email, char *old_name, char *old_email)
+ char *new_name, char *new_email,
+ char *old_name, char *old_email)
{
struct mailmap_entry *me;
int index;
- char *p;
-
- if (old_email)
- for (p = old_email; *p; p++)
- *p = tolower(*p);
- if (new_email)
- for (p = new_email; *p; p++)
- *p = tolower(*p);
if (old_email == NULL) {
old_email = new_email;
@@ -68,16 +67,21 @@ static void add_mapping(struct string_list *map,
if ((index = string_list_find_insert_index(map, old_email, 1)) < 0) {
/* mailmap entry exists, invert index value */
index = -1 - index;
+ me = (struct mailmap_entry *)map->items[index].util;
} else {
/* create mailmap entry */
- struct string_list_item *item = string_list_insert_at_index(map, index, old_email);
- item->util = xcalloc(1, sizeof(struct mailmap_entry));
- ((struct mailmap_entry *)item->util)->namemap.strdup_strings = 1;
+ struct string_list_item *item;
+
+ item = string_list_insert_at_index(map, index, old_email);
+ me = xcalloc(1, sizeof(struct mailmap_entry));
+ me->namemap.strdup_strings = 1;
+ me->namemap.cmp = strcasecmp;
+ item->util = me;
}
- me = (struct mailmap_entry *)map->items[index].util;
if (old_name == NULL) {
- debug_mm("mailmap: adding (simple) entry for %s at index %d\n", old_email, index);
+ debug_mm("mailmap: adding (simple) entry for %s at index %d\n",
+ old_email, index);
/* Replace current name and new email for simple entry */
if (new_name) {
free(me->name);
@@ -89,7 +93,8 @@ static void add_mapping(struct string_list *map,
}
} else {
struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
- debug_mm("mailmap: adding (complex) entry for %s at index %d\n", old_email, index);
+ debug_mm("mailmap: adding (complex) entry for %s at index %d\n",
+ old_email, index);
if (new_name)
mi->name = xstrdup(new_name);
if (new_email)
@@ -98,11 +103,12 @@ static void add_mapping(struct string_list *map,
}
debug_mm("mailmap: '%s' <%s> -> '%s' <%s>\n",
- old_name, old_email, new_name, new_email);
+ debug_str(old_name), old_email,
+ debug_str(new_name), debug_str(new_email));
}
static char *parse_name_and_email(char *buffer, char **name,
- char **email, int allow_empty_email)
+ char **email, int allow_empty_email)
{
char *left, *right, *nstart, *nend;
*name = *email = NULL;
@@ -122,7 +128,7 @@ static char *parse_name_and_email(char *buffer, char **name,
while (nend > nstart && isspace(*nend))
--nend;
- *name = (nstart < nend ? nstart : NULL);
+ *name = (nstart <= nend ? nstart : NULL);
*email = left+1;
*(nend+1) = '\0';
*right++ = '\0';
@@ -147,8 +153,7 @@ static void read_mailmap_line(struct string_list *map, char *buffer,
if (!strncmp(buffer, abbrev, abblen)) {
char *cp;
- if (repo_abbrev)
- free(*repo_abbrev);
+ free(*repo_abbrev);
*repo_abbrev = xmalloc(len);
for (cp = buffer + abblen; isspace(*cp); cp++)
@@ -187,20 +192,17 @@ static int read_mailmap_file(struct string_list *map, const char *filename,
return 0;
}
-static void read_mailmap_buf(struct string_list *map,
- const char *buf, unsigned long len,
- char **repo_abbrev)
+static void read_mailmap_string(struct string_list *map, char *buf,
+ char **repo_abbrev)
{
- while (len) {
- const char *end = strchrnul(buf, '\n');
- unsigned long linelen = end - buf + 1;
- char *line = xmemdupz(buf, linelen);
+ while (*buf) {
+ char *end = strchrnul(buf, '\n');
- read_mailmap_line(map, line, repo_abbrev);
+ if (*end)
+ *end++ = '\0';
- free(line);
- buf += linelen;
- len -= linelen;
+ read_mailmap_line(map, buf, repo_abbrev);
+ buf = end;
}
}
@@ -224,7 +226,7 @@ static int read_mailmap_blob(struct string_list *map,
if (type != OBJ_BLOB)
return error("mailmap is not a blob: %s", name);
- read_mailmap_buf(map, buf, size, repo_abbrev);
+ read_mailmap_string(map, buf, repo_abbrev);
free(buf);
return 0;
@@ -306,21 +308,25 @@ static struct string_list_item *lookup_prefix(struct string_list *map,
}
int map_user(struct string_list *map,
- const char **email, size_t *emaillen,
- const char **name, size_t *namelen)
+ const char **email, size_t *emaillen,
+ const char **name, size_t *namelen)
{
struct string_list_item *item;
struct mailmap_entry *me;
debug_mm("map_user: map '%.*s' <%.*s>\n",
- *name, *namelen, *emaillen, *email);
+ (int)*namelen, debug_str(*name),
+ (int)*emaillen, debug_str(*email));
item = lookup_prefix(map, *email, *emaillen);
if (item != NULL) {
me = (struct mailmap_entry *)item->util;
if (me->namemap.nr) {
- /* The item has multiple items, so we'll look up on name too */
- /* If the name is not found, we choose the simple entry */
+ /*
+ * The item has multiple items, so we'll look up on
+ * name too. If the name is not found, we choose the
+ * simple entry.
+ */
struct string_list_item *subitem;
subitem = lookup_prefix(&me->namemap, *name, *namelen);
if (subitem)
@@ -341,8 +347,9 @@ int map_user(struct string_list *map,
*name = mi->name;
*namelen = strlen(*name);
}
- debug_mm("map_user: to '%.*s' <.*%s>\n", *namelen, *name,
- *emaillen, *email);
+ debug_mm("map_user: to '%.*s' <%.*s>\n",
+ (int)*namelen, debug_str(*name),
+ (int)*emaillen, debug_str(*email));
return 1;
}
debug_mm("map_user: --\n");
diff --git a/match-trees.c b/match-trees.c
index 2bb734d..7873cde 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -47,6 +47,22 @@ static int score_matches(unsigned mode1, unsigned mode2, const char *path)
return score;
}
+static void *fill_tree_desc_strict(struct tree_desc *desc,
+ const unsigned char *hash)
+{
+ void *buffer;
+ enum object_type type;
+ unsigned long size;
+
+ buffer = read_sha1_file(hash, &type, &size);
+ if (!buffer)
+ die("unable to read tree (%s)", sha1_to_hex(hash));
+ if (type != OBJ_TREE)
+ die("%s is not a tree", sha1_to_hex(hash));
+ init_tree_desc(desc, buffer, size);
+ return buffer;
+}
+
static int base_name_entries_compare(const struct name_entry *a,
const struct name_entry *b)
{
@@ -61,23 +77,10 @@ static int score_trees(const unsigned char *hash1, const unsigned char *hash2)
{
struct tree_desc one;
struct tree_desc two;
- void *one_buf, *two_buf;
+ void *one_buf = fill_tree_desc_strict(&one, hash1);
+ void *two_buf = fill_tree_desc_strict(&two, hash2);
int score = 0;
- enum object_type type;
- unsigned long size;
- one_buf = read_sha1_file(hash1, &type, &size);
- if (!one_buf)
- die("unable to read tree (%s)", sha1_to_hex(hash1));
- if (type != OBJ_TREE)
- die("%s is not a tree", sha1_to_hex(hash1));
- init_tree_desc(&one, one_buf, size);
- two_buf = read_sha1_file(hash2, &type, &size);
- if (!two_buf)
- die("unable to read tree (%s)", sha1_to_hex(hash2));
- if (type != OBJ_TREE)
- die("%s is not a tree", sha1_to_hex(hash2));
- init_tree_desc(&two, two_buf, size);
for (;;) {
struct name_entry e1, e2;
int got_entry_from_one = tree_entry(&one, &e1);
@@ -124,16 +127,7 @@ static void match_trees(const unsigned char *hash1,
int recurse_limit)
{
struct tree_desc one;
- void *one_buf;
- enum object_type type;
- unsigned long size;
-
- one_buf = read_sha1_file(hash1, &type, &size);
- if (!one_buf)
- die("unable to read tree (%s)", sha1_to_hex(hash1));
- if (type != OBJ_TREE)
- die("%s is not a tree", sha1_to_hex(hash1));
- init_tree_desc(&one, one_buf, size);
+ void *one_buf = fill_tree_desc_strict(&one, hash1);
while (one.size) {
const char *path;
diff --git a/merge-recursive.c b/merge-recursive.c
index ea9dbd3..40eb840 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -251,7 +251,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)
int i;
fprintf(stderr, "BUG: There are unmerged index entries:\n");
for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
if (ce_stage(ce))
fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce),
(int)ce_namelen(ce), ce->name);
@@ -264,7 +264,8 @@ 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)
+ (const struct cache_entry * const *)active_cache,
+ active_nr, 0) < 0)
die(_("error building trees"));
result = lookup_tree(active_cache_tree->sha1);
@@ -297,7 +298,7 @@ static int get_files_dirs(struct merge_options *o, struct tree *tree)
{
int n;
struct pathspec match_all;
- init_pathspec(&match_all, NULL);
+ memset(&match_all, 0, sizeof(match_all));
if (read_tree_recursive(tree, "", 0, 0, &match_all, save_files_dirs, o))
return 0;
n = o->current_file_set.nr + o->current_directory_set.nr;
@@ -339,7 +340,7 @@ static struct string_list *get_unmerged(void)
for (i = 0; i < active_nr; i++) {
struct string_list_item *item;
struct stage_data *e;
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
if (!ce_stage(ce))
continue;
diff --git a/mergetools/p4merge b/mergetools/p4merge
index 8a36916..5a608ab 100644
--- a/mergetools/p4merge
+++ b/mergetools/p4merge
@@ -21,8 +21,12 @@ diff_cmd () {
merge_cmd () {
touch "$BACKUP"
- $base_present || >"$BASE"
- "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
+ if ! $base_present
+ then
+ cp -- "$LOCAL" "$BASE"
+ create_virtual_base "$BASE" "$REMOTE"
+ fi
+ "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED"
check_unchanged
}
diff --git a/name-hash.c b/name-hash.c
index 6d7e198..617c86c 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -150,6 +150,8 @@ static void lazy_init_name_hash(struct index_state *istate)
if (istate->name_hash_initialized)
return;
+ if (istate->cache_nr)
+ preallocate_hash(&istate->name_hash, istate->cache_nr);
for (nr = 0; nr < istate->cache_nr; nr++)
hash_index_entry(istate, istate->cache[nr]);
istate->name_hash_initialized = 1;
diff --git a/notes-merge.c b/notes-merge.c
index 0f67bd3..94a1a8a 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -9,6 +9,7 @@
#include "notes.h"
#include "notes-merge.h"
#include "strbuf.h"
+#include "notes-utils.h"
struct notes_merge_pair {
unsigned char obj[20], base[20], local[20], remote[20];
@@ -169,7 +170,7 @@ static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
sha1_to_hex(mp->remote));
}
diff_flush(&opt);
- diff_tree_release_paths(&opt);
+ free_pathspec(&opt.pathspec);
*num_changes = len;
return changes;
@@ -255,7 +256,7 @@ static void diff_tree_local(struct notes_merge_options *o,
sha1_to_hex(mp->local));
}
diff_flush(&opt);
- diff_tree_release_paths(&opt);
+ free_pathspec(&opt.pathspec);
}
static void check_notes_merge_worktree(struct notes_merge_options *o)
@@ -530,32 +531,6 @@ static int merge_from_diffs(struct notes_merge_options *o,
return conflicts ? -1 : 1;
}
-void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
- const struct strbuf *msg, unsigned char *result_sha1)
-{
- unsigned char tree_sha1[20];
-
- assert(t->initialized);
-
- if (write_notes_tree(t, tree_sha1))
- die("Failed to write notes tree to database");
-
- if (!parents) {
- /* Deduce parent commit from t->ref */
- unsigned char parent_sha1[20];
- if (!read_ref(t->ref, parent_sha1)) {
- struct commit *parent = lookup_commit(parent_sha1);
- if (!parent || parse_commit(parent))
- die("Failed to find/parse commit %s", t->ref);
- commit_list_insert(parent, &parents);
- }
- /* else: t->ref points to nothing, assume root/orphan commit */
- }
-
- if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL))
- die("Failed to commit notes tree to database");
-}
-
int notes_merge(struct notes_merge_options *o,
struct notes_tree *local_tree,
unsigned char *result_sha1)
diff --git a/notes-merge.h b/notes-merge.h
index 0c11b17..1d01f6a 100644
--- a/notes-merge.h
+++ b/notes-merge.h
@@ -26,20 +26,6 @@ struct notes_merge_options {
void init_notes_merge_options(struct notes_merge_options *o);
/*
- * Create new notes commit from the given notes tree
- *
- * Properties of the created commit:
- * - tree: the result of converting t to a tree object with write_notes_tree().
- * - parents: the given parents OR (if NULL) the commit referenced by t->ref.
- * - author/committer: the default determined by commmit_tree().
- * - commit message: msg
- *
- * The resulting commit SHA1 is stored in result_sha1.
- */
-void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
- const struct strbuf *msg, unsigned char *result_sha1);
-
-/*
* Merge notes from o->remote_ref into o->local_ref
*
* The given notes_tree 'local_tree' must be the notes_tree referenced by the
diff --git a/notes-utils.c b/notes-utils.c
new file mode 100644
index 0000000..9107c37
--- /dev/null
+++ b/notes-utils.c
@@ -0,0 +1,157 @@
+#include "cache.h"
+#include "commit.h"
+#include "refs.h"
+#include "notes-utils.h"
+
+void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
+ const struct strbuf *msg, unsigned char *result_sha1)
+{
+ unsigned char tree_sha1[20];
+
+ assert(t->initialized);
+
+ if (write_notes_tree(t, tree_sha1))
+ die("Failed to write notes tree to database");
+
+ if (!parents) {
+ /* Deduce parent commit from t->ref */
+ unsigned char parent_sha1[20];
+ if (!read_ref(t->ref, parent_sha1)) {
+ struct commit *parent = lookup_commit(parent_sha1);
+ if (!parent || parse_commit(parent))
+ die("Failed to find/parse commit %s", t->ref);
+ commit_list_insert(parent, &parents);
+ }
+ /* else: t->ref points to nothing, assume root/orphan commit */
+ }
+
+ if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL))
+ die("Failed to commit notes tree to database");
+}
+
+void commit_notes(struct notes_tree *t, const char *msg)
+{
+ struct strbuf buf = STRBUF_INIT;
+ unsigned char commit_sha1[20];
+
+ if (!t)
+ t = &default_notes_tree;
+ if (!t->initialized || !t->ref || !*t->ref)
+ die(_("Cannot commit uninitialized/unreferenced notes tree"));
+ if (!t->dirty)
+ return; /* don't have to commit an unchanged tree */
+
+ /* Prepare commit message and reflog message */
+ strbuf_addstr(&buf, msg);
+ if (buf.buf[buf.len - 1] != '\n')
+ strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
+
+ create_notes_commit(t, NULL, &buf, commit_sha1);
+ strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
+ update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, DIE_ON_ERR);
+
+ strbuf_release(&buf);
+}
+
+static combine_notes_fn parse_combine_notes_fn(const char *v)
+{
+ if (!strcasecmp(v, "overwrite"))
+ return combine_notes_overwrite;
+ else if (!strcasecmp(v, "ignore"))
+ return combine_notes_ignore;
+ else if (!strcasecmp(v, "concatenate"))
+ return combine_notes_concatenate;
+ else if (!strcasecmp(v, "cat_sort_uniq"))
+ return combine_notes_cat_sort_uniq;
+ else
+ return NULL;
+}
+
+static int notes_rewrite_config(const char *k, const char *v, void *cb)
+{
+ struct notes_rewrite_cfg *c = cb;
+ if (!prefixcmp(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) {
+ c->enabled = git_config_bool(k, v);
+ return 0;
+ } else if (!c->mode_from_env && !strcmp(k, "notes.rewritemode")) {
+ if (!v)
+ config_error_nonbool(k);
+ c->combine = parse_combine_notes_fn(v);
+ if (!c->combine) {
+ error(_("Bad notes.rewriteMode value: '%s'"), v);
+ return 1;
+ }
+ return 0;
+ } else if (!c->refs_from_env && !strcmp(k, "notes.rewriteref")) {
+ /* note that a refs/ prefix is implied in the
+ * underlying for_each_glob_ref */
+ if (!prefixcmp(v, "refs/notes/"))
+ string_list_add_refs_by_glob(c->refs, v);
+ else
+ warning(_("Refusing to rewrite notes in %s"
+ " (outside of refs/notes/)"), v);
+ return 0;
+ }
+
+ return 0;
+}
+
+
+struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd)
+{
+ struct notes_rewrite_cfg *c = xmalloc(sizeof(struct notes_rewrite_cfg));
+ const char *rewrite_mode_env = getenv(GIT_NOTES_REWRITE_MODE_ENVIRONMENT);
+ const char *rewrite_refs_env = getenv(GIT_NOTES_REWRITE_REF_ENVIRONMENT);
+ c->cmd = cmd;
+ c->enabled = 1;
+ c->combine = combine_notes_concatenate;
+ c->refs = xcalloc(1, sizeof(struct string_list));
+ c->refs->strdup_strings = 1;
+ c->refs_from_env = 0;
+ c->mode_from_env = 0;
+ if (rewrite_mode_env) {
+ c->mode_from_env = 1;
+ c->combine = parse_combine_notes_fn(rewrite_mode_env);
+ if (!c->combine)
+ /* TRANSLATORS: The first %s is the name of the
+ environment variable, the second %s is its value */
+ error(_("Bad %s value: '%s'"), GIT_NOTES_REWRITE_MODE_ENVIRONMENT,
+ rewrite_mode_env);
+ }
+ if (rewrite_refs_env) {
+ c->refs_from_env = 1;
+ string_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env);
+ }
+ git_config(notes_rewrite_config, c);
+ if (!c->enabled || !c->refs->nr) {
+ string_list_clear(c->refs, 0);
+ free(c->refs);
+ free(c);
+ return NULL;
+ }
+ c->trees = load_notes_trees(c->refs);
+ string_list_clear(c->refs, 0);
+ free(c->refs);
+ return c;
+}
+
+int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
+ const unsigned char *from_obj, const unsigned char *to_obj)
+{
+ int ret = 0;
+ int i;
+ for (i = 0; c->trees[i]; i++)
+ ret = copy_note(c->trees[i], from_obj, to_obj, 1, c->combine) || ret;
+ return ret;
+}
+
+void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c, const char *msg)
+{
+ int i;
+ for (i = 0; c->trees[i]; i++) {
+ commit_notes(c->trees[i], msg);
+ free_notes(c->trees[i]);
+ }
+ free(c->trees);
+ free(c);
+}
diff --git a/notes-utils.h b/notes-utils.h
new file mode 100644
index 0000000..564e30c
--- /dev/null
+++ b/notes-utils.h
@@ -0,0 +1,37 @@
+#ifndef NOTES_UTILS_H
+#define NOTES_UTILS_H
+
+#include "notes.h"
+
+/*
+ * Create new notes commit from the given notes tree
+ *
+ * Properties of the created commit:
+ * - tree: the result of converting t to a tree object with write_notes_tree().
+ * - parents: the given parents OR (if NULL) the commit referenced by t->ref.
+ * - author/committer: the default determined by commit_tree().
+ * - commit message: msg
+ *
+ * The resulting commit SHA1 is stored in result_sha1.
+ */
+void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
+ const struct strbuf *msg, unsigned char *result_sha1);
+
+void commit_notes(struct notes_tree *t, const char *msg);
+
+struct notes_rewrite_cfg {
+ struct notes_tree **trees;
+ const char *cmd;
+ int enabled;
+ combine_notes_fn combine;
+ struct string_list *refs;
+ int refs_from_env;
+ int mode_from_env;
+};
+
+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);
+void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c, const char *msg);
+
+#endif
diff --git a/notes.c b/notes.c
index f63fd57..b69c0b8 100644
--- a/notes.c
+++ b/notes.c
@@ -918,17 +918,21 @@ out:
return ret;
}
-static int string_list_add_one_ref(const char *path, const unsigned char *sha1,
+static int string_list_add_one_ref(const char *refname, const unsigned char *sha1,
int flag, void *cb)
{
struct string_list *refs = cb;
- if (!unsorted_string_list_has_string(refs, path))
- string_list_append(refs, path);
+ if (!unsorted_string_list_has_string(refs, refname))
+ string_list_append(refs, refname);
return 0;
}
+/*
+ * The list argument must have strdup_strings set on it.
+ */
void string_list_add_refs_by_glob(struct string_list *list, const char *glob)
{
+ assert(list->strdup_strings);
if (has_glob_specials(glob)) {
for_each_glob_ref(string_list_add_one_ref, glob, list);
} else {
diff --git a/notes.h b/notes.h
index 3324c48..2a3f923 100644
--- a/notes.h
+++ b/notes.h
@@ -77,7 +77,7 @@ const char *default_notes_ref(void);
* variable is used, and if that is missing, the default notes ref is used
* ("refs/notes/commits").
*
- * If you need to re-intialize a notes_tree structure (e.g. when switching from
+ * If you need to re-initialize a notes_tree structure (e.g. when switching from
* one notes ref to another), you must first de-initialize the notes_tree
* structure by calling free_notes(struct notes_tree *).
*
diff --git a/object.c b/object.c
index 20703f5..d8a4b1f 100644
--- a/object.c
+++ b/object.c
@@ -71,13 +71,13 @@ static unsigned int hashtable_index(const unsigned char *sha1)
struct object *lookup_object(const unsigned char *sha1)
{
- unsigned int i;
+ unsigned int i, first;
struct object *obj;
if (!obj_hash)
return NULL;
- i = hashtable_index(sha1);
+ first = i = hashtable_index(sha1);
while ((obj = obj_hash[i]) != NULL) {
if (!hashcmp(sha1, obj->sha1))
break;
@@ -85,6 +85,16 @@ struct object *lookup_object(const unsigned char *sha1)
if (i == obj_hash_size)
i = 0;
}
+ if (obj && i != first) {
+ /*
+ * Move object to where we started to look for it so
+ * that we do not need to walk the hash table the next
+ * time we look for it.
+ */
+ struct object *tmp = obj_hash[i];
+ obj_hash[i] = obj_hash[first];
+ obj_hash[first] = tmp;
+ }
return obj;
}
@@ -135,7 +145,7 @@ struct object *lookup_unknown_object(const unsigned char *sha1)
struct object *parse_object_buffer(const unsigned char *sha1, enum object_type type, unsigned long size, void *buffer, int *eaten_p)
{
struct object *obj;
- int eaten = 0;
+ *eaten_p = 0;
obj = NULL;
if (type == OBJ_BLOB) {
@@ -154,7 +164,7 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t
if (!tree->object.parsed) {
if (parse_tree_buffer(tree, buffer, size))
return NULL;
- eaten = 1;
+ *eaten_p = 1;
}
}
} else if (type == OBJ_COMMIT) {
@@ -164,7 +174,7 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t
return NULL;
if (!commit->buffer) {
commit->buffer = buffer;
- eaten = 1;
+ *eaten_p = 1;
}
obj = &commit->object;
}
@@ -181,7 +191,6 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t
}
if (obj && obj->type == OBJ_NONE)
obj->type = type;
- *eaten_p = eaten;
return obj;
}
@@ -260,11 +269,18 @@ void add_object_array(struct object *obj, const char *name, struct object_array
add_object_array_with_mode(obj, name, array, S_IFINVALID);
}
+/*
+ * A zero-length string to which object_array_entry::name can be
+ * initialized without requiring a malloc/free.
+ */
+static char object_array_slopbuf[1];
+
void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode)
{
unsigned nr = array->nr;
unsigned alloc = array->alloc;
struct object_array_entry *objects = array->objects;
+ struct object_array_entry *entry;
if (nr >= alloc) {
alloc = (alloc + 32) * 2;
@@ -272,28 +288,67 @@ void add_object_array_with_mode(struct object *obj, const char *name, struct obj
array->alloc = alloc;
array->objects = objects;
}
- objects[nr].item = obj;
- objects[nr].name = name;
- objects[nr].mode = mode;
+ entry = &objects[nr];
+ entry->item = obj;
+ if (!name)
+ entry->name = NULL;
+ else if (!*name)
+ /* Use our own empty string instead of allocating one: */
+ entry->name = object_array_slopbuf;
+ else
+ entry->name = xstrdup(name);
+ entry->mode = mode;
array->nr = ++nr;
}
-void object_array_remove_duplicates(struct object_array *array)
+void object_array_filter(struct object_array *array,
+ object_array_each_func_t want, void *cb_data)
{
- unsigned int ref, src, dst;
+ unsigned nr = array->nr, src, dst;
struct object_array_entry *objects = array->objects;
- for (ref = 0; ref + 1 < array->nr; ref++) {
- for (src = ref + 1, dst = src;
- src < array->nr;
- src++) {
- if (!strcmp(objects[ref].name, objects[src].name))
- continue;
+ for (src = dst = 0; src < nr; src++) {
+ if (want(&objects[src], cb_data)) {
if (src != dst)
objects[dst] = objects[src];
dst++;
+ } else {
+ if (objects[src].name != object_array_slopbuf)
+ free(objects[src].name);
+ }
+ }
+ array->nr = dst;
+}
+
+/*
+ * Return true iff array already contains an entry with name.
+ */
+static int contains_name(struct object_array *array, const char *name)
+{
+ unsigned nr = array->nr, i;
+ struct object_array_entry *object = array->objects;
+
+ for (i = 0; i < nr; i++, object++)
+ if (!strcmp(object->name, name))
+ return 1;
+ return 0;
+}
+
+void object_array_remove_duplicates(struct object_array *array)
+{
+ unsigned nr = array->nr, src;
+ struct object_array_entry *objects = array->objects;
+
+ array->nr = 0;
+ for (src = 0; src < nr; src++) {
+ if (!contains_name(array, objects[src].name)) {
+ if (src != array->nr)
+ objects[array->nr] = objects[src];
+ array->nr++;
+ } else {
+ if (objects[src].name != object_array_slopbuf)
+ free(objects[src].name);
}
- array->nr = dst;
}
}
diff --git a/object.h b/object.h
index 97d384b..2ff68c5 100644
--- a/object.h
+++ b/object.h
@@ -11,7 +11,13 @@ struct object_array {
unsigned int alloc;
struct object_array_entry {
struct object *item;
- const char *name;
+ /*
+ * name or NULL. If non-NULL, the memory pointed to
+ * is owned by this object *except* if it points at
+ * object_array_slopbuf, which is a static copy of the
+ * empty string.
+ */
+ char *name;
unsigned mode;
} *objects;
};
@@ -85,7 +91,22 @@ int object_list_contains(struct object_list *list, struct object *obj);
/* Object array handling .. */
void add_object_array(struct object *obj, const char *name, struct object_array *array);
void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode);
-void object_array_remove_duplicates(struct object_array *);
+
+typedef int (*object_array_each_func_t)(struct object_array_entry *, void *);
+
+/*
+ * Apply want to each entry in array, retaining only the entries for
+ * which the function returns true. Preserve the order of the entries
+ * that are retained.
+ */
+void object_array_filter(struct object_array *array,
+ object_array_each_func_t want, void *cb_data);
+
+/*
+ * Remove from array all but the first entry with a given name.
+ * Warning: this function uses an O(N^2) algorithm.
+ */
+void object_array_remove_duplicates(struct object_array *array);
void clear_object_flags(unsigned flags);
diff --git a/pack-refs.c b/pack-refs.c
deleted file mode 100644
index 4461f71..0000000
--- a/pack-refs.c
+++ /dev/null
@@ -1,148 +0,0 @@
-#include "cache.h"
-#include "refs.h"
-#include "tag.h"
-#include "pack-refs.h"
-
-struct ref_to_prune {
- struct ref_to_prune *next;
- unsigned char sha1[20];
- char name[FLEX_ARRAY];
-};
-
-struct pack_refs_cb_data {
- unsigned int flags;
- struct ref_to_prune *ref_to_prune;
- FILE *refs_file;
-};
-
-static int do_not_prune(int flags)
-{
- /* If it is already packed or if it is a symref,
- * do not prune it.
- */
- return (flags & (REF_ISSYMREF|REF_ISPACKED));
-}
-
-static int handle_one_ref(const char *path, const unsigned char *sha1,
- int flags, void *cb_data)
-{
- struct pack_refs_cb_data *cb = cb_data;
- struct object *o;
- int is_tag_ref;
-
- /* Do not pack the symbolic refs */
- if ((flags & REF_ISSYMREF))
- return 0;
- is_tag_ref = !prefixcmp(path, "refs/tags/");
-
- /* ALWAYS pack refs that were already packed or are tags */
- if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref && !(flags & REF_ISPACKED))
- return 0;
-
- fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
-
- o = parse_object_or_die(sha1, path);
- if (o->type == OBJ_TAG) {
- o = deref_tag(o, path, 0);
- if (o)
- fprintf(cb->refs_file, "^%s\n",
- sha1_to_hex(o->sha1));
- }
-
- if ((cb->flags & PACK_REFS_PRUNE) && !do_not_prune(flags)) {
- int namelen = strlen(path) + 1;
- struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
- hashcpy(n->sha1, sha1);
- strcpy(n->name, path);
- n->next = cb->ref_to_prune;
- cb->ref_to_prune = n;
- }
- return 0;
-}
-
-/*
- * Remove empty parents, but spare refs/ and immediate subdirs.
- * Note: munges *name.
- */
-static void try_remove_empty_parents(char *name)
-{
- char *p, *q;
- int i;
- p = name;
- for (i = 0; i < 2; i++) { /* refs/{heads,tags,...}/ */
- while (*p && *p != '/')
- p++;
- /* tolerate duplicate slashes; see check_refname_format() */
- while (*p == '/')
- p++;
- }
- for (q = p; *q; q++)
- ;
- while (1) {
- while (q > p && *q != '/')
- q--;
- while (q > p && *(q-1) == '/')
- q--;
- if (q == p)
- break;
- *q = '\0';
- if (rmdir(git_path("%s", name)))
- break;
- }
-}
-
-/* make sure nobody touched the ref, and unlink */
-static void prune_ref(struct ref_to_prune *r)
-{
- struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
-
- if (lock) {
- unlink_or_warn(git_path("%s", r->name));
- unlock_ref(lock);
- try_remove_empty_parents(r->name);
- }
-}
-
-static void prune_refs(struct ref_to_prune *r)
-{
- while (r) {
- prune_ref(r);
- r = r->next;
- }
-}
-
-static struct lock_file packed;
-
-int pack_refs(unsigned int flags)
-{
- int fd;
- struct pack_refs_cb_data cbdata;
-
- memset(&cbdata, 0, sizeof(cbdata));
- cbdata.flags = flags;
-
- fd = hold_lock_file_for_update(&packed, git_path("packed-refs"),
- LOCK_DIE_ON_ERROR);
- cbdata.refs_file = fdopen(fd, "w");
- if (!cbdata.refs_file)
- die_errno("unable to create ref-pack file structure");
-
- /* perhaps other traits later as well */
- fprintf(cbdata.refs_file, "# pack-refs with: peeled fully-peeled \n");
-
- for_each_ref(handle_one_ref, &cbdata);
- if (ferror(cbdata.refs_file))
- die("failed to write ref-pack file");
- if (fflush(cbdata.refs_file) || fsync(fd) || fclose(cbdata.refs_file))
- die_errno("failed to write ref-pack file");
- /*
- * Since the lock file was fdopen()'ed and then fclose()'ed above,
- * assign -1 to the lock file descriptor so that commit_lock_file()
- * won't try to close() it.
- */
- packed.fd = -1;
- if (commit_lock_file(&packed) < 0)
- die_errno("unable to overwrite old ref-pack file");
- prune_refs(cbdata.ref_to_prune);
- return 0;
-}
diff --git a/pack-refs.h b/pack-refs.h
deleted file mode 100644
index 518acfb..0000000
--- a/pack-refs.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef PACK_REFS_H
-#define PACK_REFS_H
-
-/*
- * Flags for controlling behaviour of pack_refs()
- * PACK_REFS_PRUNE: Prune loose refs after packing
- * PACK_REFS_ALL: Pack _all_ refs, not just tags and already packed refs
- */
-#define PACK_REFS_PRUNE 0x0001
-#define PACK_REFS_ALL 0x0002
-
-/*
- * Write a packed-refs file for the current repository.
- * flags: Combination of the above PACK_REFS_* flags.
- */
-int pack_refs(unsigned int flags);
-
-#endif /* PACK_REFS_H */
diff --git a/pack-revindex.c b/pack-revindex.c
index 77a0465..b4d2b35 100644
--- a/pack-revindex.c
+++ b/pack-revindex.c
@@ -59,11 +59,101 @@ static void init_pack_revindex(void)
/* revindex elements are lazily initialized */
}
-static int cmp_offset(const void *a_, const void *b_)
+/*
+ * This is a least-significant-digit radix sort.
+ *
+ * It sorts each of the "n" items in "entries" by its offset field. The "max"
+ * parameter must be at least as large as the largest offset in the array,
+ * and lets us quit the sort early.
+ */
+static void sort_revindex(struct revindex_entry *entries, unsigned n, off_t max)
{
- const struct revindex_entry *a = a_;
- const struct revindex_entry *b = b_;
- return (a->offset < b->offset) ? -1 : (a->offset > b->offset) ? 1 : 0;
+ /*
+ * We use a "digit" size of 16 bits. That keeps our memory
+ * usage reasonable, and we can generally (for a 4G or smaller
+ * packfile) quit after two rounds of radix-sorting.
+ */
+#define DIGIT_SIZE (16)
+#define BUCKETS (1 << DIGIT_SIZE)
+ /*
+ * We want to know the bucket that a[i] will go into when we are using
+ * the digit that is N bits from the (least significant) end.
+ */
+#define BUCKET_FOR(a, i, bits) (((a)[(i)].offset >> (bits)) & (BUCKETS-1))
+
+ /*
+ * We need O(n) temporary storage. Rather than do an extra copy of the
+ * partial results into "entries", we sort back and forth between the
+ * real array and temporary storage. In each iteration of the loop, we
+ * keep track of them with alias pointers, always sorting from "from"
+ * to "to".
+ */
+ struct revindex_entry *tmp = xmalloc(n * sizeof(*tmp));
+ struct revindex_entry *from = entries, *to = tmp;
+ int bits;
+ unsigned *pos = xmalloc(BUCKETS * sizeof(*pos));
+
+ /*
+ * If (max >> bits) is zero, then we know that the radix digit we are
+ * on (and any higher) will be zero for all entries, and our loop will
+ * be a no-op, as everybody lands in the same zero-th bucket.
+ */
+ for (bits = 0; max >> bits; bits += DIGIT_SIZE) {
+ struct revindex_entry *swap;
+ unsigned i;
+
+ memset(pos, 0, BUCKETS * sizeof(*pos));
+
+ /*
+ * We want pos[i] to store the index of the last element that
+ * will go in bucket "i" (actually one past the last element).
+ * To do this, we first count the items that will go in each
+ * bucket, which gives us a relative offset from the last
+ * bucket. We can then cumulatively add the index from the
+ * previous bucket to get the true index.
+ */
+ for (i = 0; i < n; i++)
+ pos[BUCKET_FOR(from, i, bits)]++;
+ for (i = 1; i < BUCKETS; i++)
+ pos[i] += pos[i-1];
+
+ /*
+ * Now we can drop the elements into their correct buckets (in
+ * our temporary array). We iterate the pos counter backwards
+ * to avoid using an extra index to count up. And since we are
+ * going backwards there, we must also go backwards through the
+ * array itself, to keep the sort stable.
+ *
+ * Note that we use an unsigned iterator to make sure we can
+ * handle 2^32-1 objects, even on a 32-bit system. But this
+ * means we cannot use the more obvious "i >= 0" loop condition
+ * for counting backwards, and must instead check for
+ * wrap-around with UINT_MAX.
+ */
+ for (i = n - 1; i != UINT_MAX; i--)
+ to[--pos[BUCKET_FOR(from, i, bits)]] = from[i];
+
+ /*
+ * Now "to" contains the most sorted list, so we swap "from" and
+ * "to" for the next iteration.
+ */
+ swap = from;
+ from = to;
+ to = swap;
+ }
+
+ /*
+ * If we ended with our data in the original array, great. If not,
+ * we have to move it back from the temporary storage.
+ */
+ if (from != entries)
+ memcpy(entries, tmp, n * sizeof(*entries));
+ free(tmp);
+ free(pos);
+
+#undef BUCKET_FOR
+#undef BUCKETS
+#undef DIGIT_SIZE
}
/*
@@ -72,8 +162,8 @@ static int cmp_offset(const void *a_, const void *b_)
static void create_pack_revindex(struct pack_revindex *rix)
{
struct packed_git *p = rix->p;
- int num_ent = p->num_objects;
- int i;
+ unsigned num_ent = p->num_objects;
+ unsigned i;
const char *index = p->index_data;
rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
@@ -108,13 +198,13 @@ static void create_pack_revindex(struct pack_revindex *rix)
*/
rix->revindex[num_ent].offset = p->pack_size - 20;
rix->revindex[num_ent].nr = -1;
- qsort(rix->revindex, num_ent, sizeof(*rix->revindex), cmp_offset);
+ sort_revindex(rix->revindex, num_ent, p->pack_size);
}
struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs)
{
int num;
- int lo, hi;
+ unsigned lo, hi;
struct pack_revindex *rix;
struct revindex_entry *revindex;
@@ -132,7 +222,7 @@ struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs)
lo = 0;
hi = p->num_objects + 1;
do {
- int mi = (lo + hi) / 2;
+ unsigned mi = lo + (hi - lo) / 2;
if (revindex[mi].offset == ofs) {
return revindex + mi;
} else if (ofs < revindex[mi].offset)
diff --git a/parse-options-cb.c b/parse-options-cb.c
index 0de5fb1..be8c413 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -33,6 +33,12 @@ int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
return 0;
}
+int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,
+ int unset)
+{
+ return parse_expiry_date(arg, (unsigned long *)opt->value);
+}
+
int parse_opt_color_flag_cb(const struct option *opt, const char *arg,
int unset)
{
diff --git a/parse-options.c b/parse-options.c
index c2cbca2..62e9b1c 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -43,8 +43,42 @@ static void fix_filename(const char *prefix, const char **file)
*file = xstrdup(prefix_filename(prefix, strlen(prefix), *file));
}
+static int opt_command_mode_error(const struct option *opt,
+ const struct option *all_opts,
+ int flags)
+{
+ const struct option *that;
+ struct strbuf message = STRBUF_INIT;
+ struct strbuf that_name = STRBUF_INIT;
+
+ /*
+ * Find the other option that was used to set the variable
+ * already, and report that this is not compatible with it.
+ */
+ for (that = all_opts; that->type != OPTION_END; that++) {
+ if (that == opt ||
+ that->type != OPTION_CMDMODE ||
+ that->value != opt->value ||
+ that->defval != *(int *)opt->value)
+ continue;
+
+ if (that->long_name)
+ strbuf_addf(&that_name, "--%s", that->long_name);
+ else
+ strbuf_addf(&that_name, "-%c", that->short_name);
+ strbuf_addf(&message, ": incompatible with %s", that_name.buf);
+ strbuf_release(&that_name);
+ opterror(opt, message.buf, flags);
+ strbuf_release(&message);
+ return -1;
+ }
+ return opterror(opt, ": incompatible with something else", flags);
+}
+
static int get_value(struct parse_opt_ctx_t *p,
- const struct option *opt, int flags)
+ const struct option *opt,
+ const struct option *all_opts,
+ int flags)
{
const char *s, *arg;
const int unset = flags & OPT_UNSET;
@@ -83,6 +117,16 @@ static int get_value(struct parse_opt_ctx_t *p,
*(int *)opt->value = unset ? 0 : opt->defval;
return 0;
+ case OPTION_CMDMODE:
+ /*
+ * Giving the same mode option twice, although is unnecessary,
+ * is not a grave error, so let it pass.
+ */
+ if (*(int *)opt->value && *(int *)opt->value != opt->defval)
+ return opt_command_mode_error(opt, all_opts, flags);
+ *(int *)opt->value = opt->defval;
+ return 0;
+
case OPTION_SET_PTR:
*(void **)opt->value = unset ? NULL : (void *)opt->defval;
return 0;
@@ -143,12 +187,13 @@ static int get_value(struct parse_opt_ctx_t *p,
static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
{
+ const struct option *all_opts = options;
const struct option *numopt = NULL;
for (; options->type != OPTION_END; options++) {
if (options->short_name == *p->opt) {
p->opt = p->opt[1] ? p->opt + 1 : NULL;
- return get_value(p, options, OPT_SHORT);
+ return get_value(p, options, all_opts, OPT_SHORT);
}
/*
@@ -177,6 +222,7 @@ static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *optio
static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
const struct option *options)
{
+ const struct option *all_opts = options;
const char *arg_end = strchr(arg, '=');
const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
int abbrev_flags = 0, ambiguous_flags = 0;
@@ -253,7 +299,7 @@ is_abbreviated:
continue;
p->opt = rest + 1;
}
- return get_value(p, options, flags ^ opt_flags);
+ return get_value(p, options, all_opts, flags ^ opt_flags);
}
if (ambiguous_option)
@@ -265,18 +311,20 @@ is_abbreviated:
(abbrev_flags & OPT_UNSET) ? "no-" : "",
abbrev_option->long_name);
if (abbrev_option)
- return get_value(p, abbrev_option, abbrev_flags);
+ return get_value(p, abbrev_option, all_opts, abbrev_flags);
return -2;
}
static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg,
const struct option *options)
{
+ const struct option *all_opts = options;
+
for (; options->type != OPTION_END; options++) {
if (!(options->flags & PARSE_OPT_NODASH))
continue;
if (options->short_name == arg[0] && arg[1] == '\0')
- return get_value(p, options, OPT_SHORT);
+ return get_value(p, options, all_opts, OPT_SHORT);
}
return -2;
}
diff --git a/parse-options.h b/parse-options.h
index 1c8bd8d..8736006 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -13,6 +13,7 @@ enum parse_opt_type {
OPTION_COUNTUP,
OPTION_SET_INT,
OPTION_SET_PTR,
+ OPTION_CMDMODE,
/* options with arguments (usually) */
OPTION_STRING,
OPTION_INTEGER,
@@ -21,9 +22,6 @@ enum parse_opt_type {
OPTION_FILENAME
};
-/* Deprecated synonym */
-#define OPTION_BOOLEAN OPTION_COUNTUP
-
enum parse_opt_flags {
PARSE_OPT_KEEP_DASHDASH = 1,
PARSE_OPT_STOP_AT_NON_OPTION = 2,
@@ -128,8 +126,12 @@ struct option {
#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG, NULL, (i) }
#define OPT_BOOL(s, l, v, h) OPT_SET_INT(s, l, v, h, 1)
+#define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \
+ (h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1}
#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG, NULL, (p) }
+#define OPT_CMDMODE(s, l, v, h, i) { OPTION_CMDMODE, (s), (l), (v), NULL, \
+ (h), PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) }
#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), N_("n"), (h) }
#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
#define OPT_STRING_LIST(s, l, v, a, h) \
@@ -140,6 +142,9 @@ struct option {
#define OPT_DATE(s, l, v, h) \
{ OPTION_CALLBACK, (s), (l), (v), N_("time"),(h), 0, \
parse_opt_approxidate_cb }
+#define OPT_EXPIRY_DATE(s, l, v, h) \
+ { OPTION_CALLBACK, (s), (l), (v), N_("expiry date"),(h), 0, \
+ parse_opt_expiry_date_cb }
#define OPT_CALLBACK(s, l, v, a, h, f) \
{ OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
#define OPT_NUMBER_CALLBACK(v, h, f) \
@@ -177,7 +182,7 @@ extern NORETURN void usage_msg_opt(const char *msg,
extern int optbug(const struct option *opt, const char *reason);
extern int opterror(const struct option *opt, const char *reason, int flags);
-#if defined(__GNUC__) && ! defined(clang)
+#if defined(__GNUC__) && ! defined(__clang__)
#define opterror(o,r,f) (opterror((o),(r),(f)), -1)
#endif
@@ -219,6 +224,7 @@ extern int parse_options_concat(struct option *dst, size_t, struct option *src);
/*----- some often used options -----*/
extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
+extern int parse_opt_expiry_date_cb(const struct option *, const char *, int);
extern int parse_opt_color_flag_cb(const struct option *, const char *, int);
extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
extern int parse_opt_with_commit(const struct option *, const char *, int);
diff --git a/path.c b/path.c
index d3d3f8b..9fd28bcd 100644
--- a/path.c
+++ b/path.c
@@ -1,19 +1,19 @@
/*
- * I'm tired of doing "vsnprintf()" etc just to open a
- * file, so here's a "return static buffer with printf"
- * interface for paths.
- *
- * It's obviously not thread-safe. Sue me. But it's quite
- * useful for doing things like
- *
- * f = open(mkpath("%s/%s.git", base, name), O_RDONLY);
- *
- * which is what it's designed for.
+ * Utilities for paths and pathnames
*/
#include "cache.h"
#include "strbuf.h"
#include "string-list.h"
+static int get_st_mode_bits(const char *path, int *mode)
+{
+ struct stat st;
+ if (lstat(path, &st) < 0)
+ return -1;
+ *mode = st.st_mode;
+ return 0;
+}
+
static char bad_path[] = "/bad-path/";
static char *get_pathname(void)
@@ -389,28 +389,14 @@ const char *enter_repo(const char *path, int strict)
return NULL;
}
-int set_shared_perm(const char *path, int mode)
+static int calc_shared_perm(int mode)
{
- struct stat st;
- int tweak, shared, orig_mode;
+ int tweak;
- if (!shared_repository) {
- if (mode)
- return chmod(path, mode & ~S_IFMT);
- return 0;
- }
- if (!mode) {
- if (lstat(path, &st) < 0)
- return -1;
- mode = st.st_mode;
- orig_mode = mode;
- } else
- orig_mode = 0;
if (shared_repository < 0)
- shared = -shared_repository;
+ tweak = -shared_repository;
else
- shared = shared_repository;
- tweak = shared;
+ tweak = shared_repository;
if (!(mode & S_IWUSR))
tweak &= ~0222;
@@ -422,56 +408,126 @@ int set_shared_perm(const char *path, int mode)
else
mode |= tweak;
- if (S_ISDIR(mode)) {
+ return mode;
+}
+
+
+int adjust_shared_perm(const char *path)
+{
+ int old_mode, new_mode;
+
+ if (!shared_repository)
+ return 0;
+ if (get_st_mode_bits(path, &old_mode) < 0)
+ return -1;
+
+ new_mode = calc_shared_perm(old_mode);
+ if (S_ISDIR(old_mode)) {
/* Copy read bits to execute bits */
- mode |= (shared & 0444) >> 2;
- mode |= FORCE_DIR_SET_GID;
+ new_mode |= (new_mode & 0444) >> 2;
+ new_mode |= FORCE_DIR_SET_GID;
}
- if (((shared_repository < 0
- ? (orig_mode & (FORCE_DIR_SET_GID | 0777))
- : (orig_mode & mode)) != mode) &&
- chmod(path, (mode & ~S_IFMT)) < 0)
+ if (((old_mode ^ new_mode) & ~S_IFMT) &&
+ chmod(path, (new_mode & ~S_IFMT)) < 0)
return -2;
return 0;
}
-const char *relative_path(const char *abs, const char *base)
+/*
+ * Give path as relative to prefix.
+ *
+ * The strbuf may or may not be used, so do not assume it contains the
+ * returned path.
+ */
+const char *relative_path(const char *in, const char *prefix,
+ struct strbuf *sb)
{
- static char buf[PATH_MAX + 1];
+ int in_len = in ? strlen(in) : 0;
+ int prefix_len = prefix ? strlen(prefix) : 0;
+ int in_off = 0;
+ int prefix_off = 0;
int i = 0, j = 0;
- if (!base || !base[0])
- return abs;
- while (base[i]) {
- if (is_dir_sep(base[i])) {
- if (!is_dir_sep(abs[j]))
- return abs;
- while (is_dir_sep(base[i]))
+ if (!in_len)
+ return "./";
+ else if (!prefix_len)
+ return in;
+
+ while (i < prefix_len && j < in_len && prefix[i] == in[j]) {
+ if (is_dir_sep(prefix[i])) {
+ while (is_dir_sep(prefix[i]))
i++;
- while (is_dir_sep(abs[j]))
+ while (is_dir_sep(in[j]))
+ j++;
+ prefix_off = i;
+ in_off = j;
+ } else {
+ i++;
+ j++;
+ }
+ }
+
+ if (
+ /* "prefix" seems like prefix of "in" */
+ i >= prefix_len &&
+ /*
+ * but "/foo" is not a prefix of "/foobar"
+ * (i.e. prefix not end with '/')
+ */
+ prefix_off < prefix_len) {
+ if (j >= in_len) {
+ /* in="/a/b", prefix="/a/b" */
+ in_off = in_len;
+ } else if (is_dir_sep(in[j])) {
+ /* in="/a/b/c", prefix="/a/b" */
+ while (is_dir_sep(in[j]))
j++;
+ in_off = j;
+ } else {
+ /* in="/a/bbb/c", prefix="/a/b" */
+ i = prefix_off;
+ }
+ } else if (
+ /* "in" is short than "prefix" */
+ j >= in_len &&
+ /* "in" not end with '/' */
+ in_off < in_len) {
+ if (is_dir_sep(prefix[i])) {
+ /* in="/a/b", prefix="/a/b/c/" */
+ while (is_dir_sep(prefix[i]))
+ i++;
+ in_off = in_len;
+ }
+ }
+ in += in_off;
+ in_len -= in_off;
+
+ if (i >= prefix_len) {
+ if (!in_len)
+ return "./";
+ else
+ return in;
+ }
+
+ strbuf_reset(sb);
+ strbuf_grow(sb, in_len);
+
+ while (i < prefix_len) {
+ if (is_dir_sep(prefix[i])) {
+ strbuf_addstr(sb, "../");
+ while (is_dir_sep(prefix[i]))
+ i++;
continue;
- } else if (abs[j] != base[i]) {
- return abs;
}
i++;
- j++;
}
- if (
- /* "/foo" is a prefix of "/foo" */
- abs[j] &&
- /* "/foo" is not a prefix of "/foobar" */
- !is_dir_sep(base[i-1]) && !is_dir_sep(abs[j])
- )
- return abs;
- while (is_dir_sep(abs[j]))
- j++;
- if (!abs[j])
- strcpy(buf, ".");
- else
- strcpy(buf, abs + j);
- return buf;
+ if (!is_dir_sep(prefix[prefix_len - 1]))
+ strbuf_addstr(sb, "../");
+
+ strbuf_addstr(sb, in);
+
+ return sb->buf;
}
/*
@@ -487,8 +543,14 @@ const char *relative_path(const char *abs, const char *base)
*
* Note that this function is purely textual. It does not follow symlinks,
* verify the existence of the path, or make any system calls.
+ *
+ * prefix_len != NULL is for a specific case of prefix_pathspec():
+ * assume that src == dst and src[0..prefix_len-1] is already
+ * normalized, any time "../" eats up to the prefix_len part,
+ * prefix_len is reduced. In the end prefix_len is the remaining
+ * prefix that has not been overridden by user pathspec.
*/
-int normalize_path_copy(char *dst, const char *src)
+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
{
char *dst0;
@@ -563,11 +625,18 @@ int normalize_path_copy(char *dst, const char *src)
/* Windows: dst[-1] cannot be backslash anymore */
while (dst0 < dst && dst[-1] != '/')
dst--;
+ if (prefix_len && *prefix_len > dst - dst0)
+ *prefix_len = dst - dst0;
}
*dst = '\0';
return 0;
}
+int normalize_path_copy(char *dst, const char *src)
+{
+ return normalize_path_copy_len(dst, src, NULL);
+}
+
/*
* path = Canonical absolute path
* prefixes = string_list containing normalized, absolute paths without
diff --git a/pathspec.c b/pathspec.c
index 284f397..ad1a9f5 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -15,8 +15,8 @@
* If seen[] has not already been written to, it may make sense
* to use find_pathspecs_matching_against_index() instead.
*/
-void add_pathspec_matches_against_index(const char **pathspec,
- char *seen, int specs)
+void add_pathspec_matches_against_index(const struct pathspec *pathspec,
+ char *seen)
{
int num_unmatched = 0, i;
@@ -26,14 +26,14 @@ void add_pathspec_matches_against_index(const char **pathspec,
* mistakenly think that the user gave a pathspec that did not match
* anything.
*/
- for (i = 0; i < specs; i++)
+ for (i = 0; i < pathspec->nr; i++)
if (!seen[i])
num_unmatched++;
if (!num_unmatched)
return;
for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
- match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);
+ const struct cache_entry *ce = active_cache[i];
+ match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen);
}
}
@@ -45,57 +45,430 @@ void add_pathspec_matches_against_index(const char **pathspec,
* nature of the "closest" (i.e. most specific) matches which each of the
* given pathspecs achieves against all items in the index.
*/
-char *find_pathspecs_matching_against_index(const char **pathspec)
+char *find_pathspecs_matching_against_index(const struct pathspec *pathspec)
{
- char *seen;
- int i;
-
- for (i = 0; pathspec[i]; i++)
- ; /* just counting */
- seen = xcalloc(i, 1);
- add_pathspec_matches_against_index(pathspec, seen, i);
+ char *seen = xcalloc(pathspec->nr, 1);
+ add_pathspec_matches_against_index(pathspec, seen);
return seen;
}
/*
- * Check the index to see whether path refers to a submodule, or
- * something inside a submodule. If the former, returns the path with
- * any trailing slash stripped. If the latter, dies with an error
- * message.
+ * Magic pathspec
+ *
+ * Possible future magic semantics include stuff like:
+ *
+ * { PATHSPEC_RECURSIVE, '*', "recursive" },
+ * { PATHSPEC_REGEXP, '\0', "regexp" },
+ *
+ */
+
+static struct pathspec_magic {
+ unsigned bit;
+ char mnemonic; /* this cannot be ':'! */
+ const char *name;
+} pathspec_magic[] = {
+ { PATHSPEC_FROMTOP, '/', "top" },
+ { PATHSPEC_LITERAL, 0, "literal" },
+ { PATHSPEC_GLOB, '\0', "glob" },
+ { PATHSPEC_ICASE, '\0', "icase" },
+};
+
+/*
+ * Take an element of a pathspec and check for magic signatures.
+ * Append the result to the prefix. Return the magic bitmap.
+ *
+ * For now, we only parse the syntax and throw out anything other than
+ * "top" magic.
+ *
+ * NEEDSWORK: This needs to be rewritten when we start migrating
+ * get_pathspec() users to use the "struct pathspec" interface. For
+ * example, a pathspec element may be marked as case-insensitive, but
+ * the prefix part must always match literally, and a single stupid
+ * string cannot express such a case.
*/
-const char *check_path_for_gitlink(const char *path)
+static unsigned prefix_pathspec(struct pathspec_item *item,
+ unsigned *p_short_magic,
+ const char **raw, unsigned flags,
+ const char *prefix, int prefixlen,
+ const char *elt)
{
- int i, path_len = strlen(path);
- for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
- if (S_ISGITLINK(ce->ce_mode)) {
- int ce_len = ce_namelen(ce);
- if (path_len <= ce_len || path[ce_len] != '/' ||
- memcmp(ce->name, path, ce_len))
- /* path does not refer to this
- * submodule or anything inside it */
+ static int literal_global = -1;
+ static int glob_global = -1;
+ static int noglob_global = -1;
+ static int icase_global = -1;
+ unsigned magic = 0, short_magic = 0, global_magic = 0;
+ const char *copyfrom = elt, *long_magic_end = NULL;
+ char *match;
+ int i, pathspec_prefix = -1;
+
+ if (literal_global < 0)
+ literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
+ if (literal_global)
+ global_magic |= PATHSPEC_LITERAL;
+
+ if (glob_global < 0)
+ glob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
+ if (glob_global)
+ global_magic |= PATHSPEC_GLOB;
+
+ if (noglob_global < 0)
+ noglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);
+
+ if (glob_global && noglob_global)
+ die(_("global 'glob' and 'noglob' pathspec settings are incompatible"));
+
+
+ if (icase_global < 0)
+ icase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
+ if (icase_global)
+ global_magic |= PATHSPEC_ICASE;
+
+ if ((global_magic & PATHSPEC_LITERAL) &&
+ (global_magic & ~PATHSPEC_LITERAL))
+ die(_("global 'literal' pathspec setting is incompatible "
+ "with all other global pathspec settings"));
+
+ if (elt[0] != ':' || literal_global) {
+ ; /* nothing to do */
+ } else if (elt[1] == '(') {
+ /* longhand */
+ const char *nextat;
+ for (copyfrom = elt + 2;
+ *copyfrom && *copyfrom != ')';
+ copyfrom = nextat) {
+ size_t len = strcspn(copyfrom, ",)");
+ if (copyfrom[len] == ',')
+ nextat = copyfrom + len + 1;
+ else
+ /* handle ')' and '\0' */
+ nextat = copyfrom + len;
+ if (!len)
continue;
- if (path_len == ce_len + 1) {
- /* path refers to submodule;
- * strip trailing slash */
- return xstrndup(ce->name, ce_len);
+ for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
+ if (strlen(pathspec_magic[i].name) == len &&
+ !strncmp(pathspec_magic[i].name, copyfrom, len)) {
+ magic |= pathspec_magic[i].bit;
+ break;
+ }
+ if (!prefixcmp(copyfrom, "prefix:")) {
+ char *endptr;
+ pathspec_prefix = strtol(copyfrom + 7,
+ &endptr, 10);
+ if (endptr - copyfrom != len)
+ die(_("invalid parameter for pathspec magic 'prefix'"));
+ /* "i" would be wrong, but it does not matter */
+ break;
+ }
+ }
+ if (ARRAY_SIZE(pathspec_magic) <= i)
+ die(_("Invalid pathspec magic '%.*s' in '%s'"),
+ (int) len, copyfrom, elt);
+ }
+ if (*copyfrom != ')')
+ die(_("Missing ')' at the end of pathspec magic in '%s'"), elt);
+ long_magic_end = copyfrom;
+ copyfrom++;
+ } else {
+ /* shorthand */
+ for (copyfrom = elt + 1;
+ *copyfrom && *copyfrom != ':';
+ copyfrom++) {
+ char ch = *copyfrom;
+
+ if (!is_pathspec_magic(ch))
+ break;
+ for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
+ if (pathspec_magic[i].mnemonic == ch) {
+ short_magic |= pathspec_magic[i].bit;
+ break;
+ }
+ if (ARRAY_SIZE(pathspec_magic) <= i)
+ die(_("Unimplemented pathspec magic '%c' in '%s'"),
+ ch, elt);
+ }
+ if (*copyfrom == ':')
+ copyfrom++;
+ }
+
+ magic |= short_magic;
+ *p_short_magic = short_magic;
+
+ /* --noglob-pathspec adds :(literal) _unless_ :(glob) is specifed */
+ if (noglob_global && !(magic & PATHSPEC_GLOB))
+ global_magic |= PATHSPEC_LITERAL;
+
+ /* --glob-pathspec is overriden by :(literal) */
+ if ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))
+ global_magic &= ~PATHSPEC_GLOB;
+
+ magic |= global_magic;
+
+ if (pathspec_prefix >= 0 &&
+ (prefixlen || (prefix && *prefix)))
+ die("BUG: 'prefix' magic is supposed to be used at worktree's root");
+
+ if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))
+ die(_("%s: 'literal' and 'glob' are incompatible"), elt);
+
+ if (pathspec_prefix >= 0) {
+ match = xstrdup(copyfrom);
+ prefixlen = pathspec_prefix;
+ } else if (magic & PATHSPEC_FROMTOP) {
+ match = xstrdup(copyfrom);
+ prefixlen = 0;
+ } else {
+ match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);
+ if (!match)
+ die(_("%s: '%s' is outside repository"), elt, copyfrom);
+ }
+ *raw = item->match = match;
+ /*
+ * Prefix the pathspec (keep all magic) and assign to
+ * original. Useful for passing to another command.
+ */
+ if (flags & PATHSPEC_PREFIX_ORIGIN) {
+ struct strbuf sb = STRBUF_INIT;
+ const char *start = elt;
+ if (prefixlen && !literal_global) {
+ /* Preserve the actual prefix length of each pattern */
+ if (short_magic)
+ die("BUG: prefixing on short magic is not supported");
+ else if (long_magic_end) {
+ strbuf_add(&sb, start, long_magic_end - start);
+ strbuf_addf(&sb, ",prefix:%d", prefixlen);
+ start = long_magic_end;
} else {
- die (_("Path '%s' is in submodule '%.*s'"),
- path, ce_len, ce->name);
+ if (*start == ':')
+ start++;
+ strbuf_addf(&sb, ":(prefix:%d)", prefixlen);
}
}
+ strbuf_add(&sb, start, copyfrom - start);
+ strbuf_addstr(&sb, match);
+ item->original = strbuf_detach(&sb, NULL);
+ } else
+ item->original = elt;
+ item->len = strlen(item->match);
+ item->prefix = prefixlen;
+
+ if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
+ (item->len >= 1 && item->match[item->len - 1] == '/') &&
+ (i = cache_name_pos(item->match, item->len - 1)) >= 0 &&
+ S_ISGITLINK(active_cache[i]->ce_mode)) {
+ item->len--;
+ match[item->len] = '\0';
+ }
+
+ if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+ int ce_len = ce_namelen(ce);
+
+ if (!S_ISGITLINK(ce->ce_mode))
+ continue;
+
+ if (item->len <= ce_len || match[ce_len] != '/' ||
+ memcmp(ce->name, match, ce_len))
+ continue;
+ if (item->len == ce_len + 1) {
+ /* strip trailing slash */
+ item->len--;
+ match[item->len] = '\0';
+ } else
+ die (_("Pathspec '%s' is in submodule '%.*s'"),
+ elt, ce_len, ce->name);
+ }
+
+ if (magic & PATHSPEC_LITERAL)
+ item->nowildcard_len = item->len;
+ else {
+ item->nowildcard_len = simple_length(item->match);
+ if (item->nowildcard_len < prefixlen)
+ item->nowildcard_len = prefixlen;
+ }
+ item->flags = 0;
+ if (magic & PATHSPEC_GLOB) {
+ /*
+ * FIXME: should we enable ONESTAR in _GLOB for
+ * pattern "* * / * . c"?
+ */
+ } else {
+ if (item->nowildcard_len < item->len &&
+ item->match[item->nowildcard_len] == '*' &&
+ no_wildcard(item->match + item->nowildcard_len + 1))
+ item->flags |= PATHSPEC_ONESTAR;
+ }
+
+ /* sanity checks, pathspec matchers assume these are sane */
+ assert(item->nowildcard_len <= item->len &&
+ item->prefix <= item->len);
+ return magic;
+}
+
+static int pathspec_item_cmp(const void *a_, const void *b_)
+{
+ struct pathspec_item *a, *b;
+
+ a = (struct pathspec_item *)a_;
+ b = (struct pathspec_item *)b_;
+ return strcmp(a->match, b->match);
+}
+
+static void NORETURN unsupported_magic(const char *pattern,
+ unsigned magic,
+ unsigned short_magic)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int i, n;
+ for (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
+ const struct pathspec_magic *m = pathspec_magic + i;
+ if (!(magic & m->bit))
+ continue;
+ if (sb.len)
+ strbuf_addstr(&sb, " ");
+ if (short_magic & m->bit)
+ strbuf_addf(&sb, "'%c'", m->mnemonic);
+ else
+ strbuf_addf(&sb, "'%s'", m->name);
+ n++;
}
- return path;
+ /*
+ * We may want to substitute "this command" with a command
+ * name. E.g. when add--interactive dies when running
+ * "checkout -p"
+ */
+ die(_("%s: pathspec magic not supported by this command: %s"),
+ pattern, sb.buf);
}
/*
- * Dies if the given path refers to a file inside a symlinked
- * directory in the index.
+ * Given command line arguments and a prefix, convert the input to
+ * pathspec. die() if any magic in magic_mask is used.
*/
-void die_if_path_beyond_symlink(const char *path, const char *prefix)
+void parse_pathspec(struct pathspec *pathspec,
+ unsigned magic_mask, unsigned flags,
+ const char *prefix, const char **argv)
{
- if (has_symlink_leading_path(path, strlen(path))) {
- int len = prefix ? strlen(prefix) : 0;
- die(_("'%s' is beyond a symbolic link"), path + len);
+ struct pathspec_item *item;
+ const char *entry = argv ? *argv : NULL;
+ int i, n, prefixlen;
+
+ memset(pathspec, 0, sizeof(*pathspec));
+
+ if (flags & PATHSPEC_MAXDEPTH_VALID)
+ pathspec->magic |= PATHSPEC_MAXDEPTH;
+
+ /* No arguments, no prefix -> no pathspec */
+ if (!entry && !prefix)
+ return;
+
+ if ((flags & PATHSPEC_PREFER_CWD) &&
+ (flags & PATHSPEC_PREFER_FULL))
+ die("BUG: PATHSPEC_PREFER_CWD and PATHSPEC_PREFER_FULL are incompatible");
+
+ /* No arguments with prefix -> prefix pathspec */
+ if (!entry) {
+ static const char *raw[2];
+
+ if (flags & PATHSPEC_PREFER_FULL)
+ return;
+
+ if (!(flags & PATHSPEC_PREFER_CWD))
+ die("BUG: PATHSPEC_PREFER_CWD requires arguments");
+
+ pathspec->items = item = xmalloc(sizeof(*item));
+ memset(item, 0, sizeof(*item));
+ item->match = prefix;
+ item->original = prefix;
+ item->nowildcard_len = item->len = strlen(prefix);
+ item->prefix = item->len;
+ raw[0] = prefix;
+ raw[1] = NULL;
+ pathspec->nr = 1;
+ pathspec->_raw = raw;
+ return;
}
+
+ n = 0;
+ while (argv[n])
+ n++;
+
+ pathspec->nr = n;
+ pathspec->items = item = xmalloc(sizeof(*item) * n);
+ pathspec->_raw = argv;
+ prefixlen = prefix ? strlen(prefix) : 0;
+
+ for (i = 0; i < n; i++) {
+ unsigned short_magic;
+ entry = argv[i];
+
+ item[i].magic = prefix_pathspec(item + i, &short_magic,
+ argv + i, flags,
+ prefix, prefixlen, entry);
+ if (item[i].magic & magic_mask)
+ unsupported_magic(entry,
+ item[i].magic & magic_mask,
+ short_magic);
+
+ if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&
+ has_symlink_leading_path(item[i].match, item[i].len)) {
+ die(_("pathspec '%s' is beyond a symbolic link"), entry);
+ }
+
+ if (item[i].nowildcard_len < item[i].len)
+ pathspec->has_wildcard = 1;
+ pathspec->magic |= item[i].magic;
+ }
+
+
+ if (pathspec->magic & PATHSPEC_MAXDEPTH) {
+ if (flags & PATHSPEC_KEEP_ORDER)
+ die("BUG: PATHSPEC_MAXDEPTH_VALID and PATHSPEC_KEEP_ORDER are incompatible");
+ qsort(pathspec->items, pathspec->nr,
+ sizeof(struct pathspec_item), pathspec_item_cmp);
+ }
+}
+
+/*
+ * N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
+ * based interface - see pathspec.c:parse_pathspec().
+ *
+ * Arguments:
+ * - prefix - a path relative to the root of the working tree
+ * - pathspec - a list of paths underneath the prefix path
+ *
+ * Iterates over pathspec, prepending each path with prefix,
+ * and return the resulting list.
+ *
+ * If pathspec is empty, return a singleton list containing prefix.
+ *
+ * If pathspec and prefix are both empty, return an empty list.
+ *
+ * This is typically used by built-in commands such as add.c, in order
+ * to normalize argv arguments provided to the built-in into a list of
+ * paths to process, all relative to the root of the working tree.
+ */
+const char **get_pathspec(const char *prefix, const char **pathspec)
+{
+ struct pathspec ps;
+ parse_pathspec(&ps,
+ PATHSPEC_ALL_MAGIC &
+ ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
+ PATHSPEC_PREFER_CWD,
+ prefix, pathspec);
+ return ps._raw;
+}
+
+void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
+{
+ *dst = *src;
+ dst->items = xmalloc(sizeof(struct pathspec_item) * dst->nr);
+ memcpy(dst->items, src->items,
+ sizeof(struct pathspec_item) * dst->nr);
+}
+
+void free_pathspec(struct pathspec *pathspec)
+{
+ free(pathspec->items);
+ pathspec->items = NULL;
}
diff --git a/pathspec.h b/pathspec.h
index db0184a..944baeb 100644
--- a/pathspec.h
+++ b/pathspec.h
@@ -1,8 +1,92 @@
#ifndef PATHSPEC_H
#define PATHSPEC_H
-extern char *find_pathspecs_matching_against_index(const char **pathspec);
-extern void add_pathspec_matches_against_index(const char **pathspec, char *seen, int specs);
+/* Pathspec magic */
+#define PATHSPEC_FROMTOP (1<<0)
+#define PATHSPEC_MAXDEPTH (1<<1)
+#define PATHSPEC_LITERAL (1<<2)
+#define PATHSPEC_GLOB (1<<3)
+#define PATHSPEC_ICASE (1<<4)
+#define PATHSPEC_ALL_MAGIC \
+ (PATHSPEC_FROMTOP | \
+ PATHSPEC_MAXDEPTH | \
+ PATHSPEC_LITERAL | \
+ PATHSPEC_GLOB | \
+ PATHSPEC_ICASE)
+
+#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
+
+struct pathspec {
+ const char **_raw; /* get_pathspec() result, not freed by free_pathspec() */
+ int nr;
+ unsigned int has_wildcard:1;
+ unsigned int recursive:1;
+ unsigned magic;
+ int max_depth;
+ struct pathspec_item {
+ const char *match;
+ const char *original;
+ unsigned magic;
+ int len, prefix;
+ int nowildcard_len;
+ int flags;
+ } *items;
+};
+
+#define GUARD_PATHSPEC(ps, mask) \
+ do { \
+ if ((ps)->magic & ~(mask)) \
+ die("BUG:%s:%d: unsupported magic %x", \
+ __FILE__, __LINE__, (ps)->magic & ~(mask)); \
+ } while (0)
+
+/* parse_pathspec flags */
+#define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */
+#define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */
+#define PATHSPEC_MAXDEPTH_VALID (1<<2) /* max_depth field is valid */
+/* strip the trailing slash if the given path is a gitlink */
+#define PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP (1<<3)
+/* die if a symlink is part of the given path's directory */
+#define PATHSPEC_SYMLINK_LEADING_PATH (1<<4)
+/*
+ * This is like a combination of ..LEADING_PATH and .._SLASH_CHEAP
+ * (but not the same): it strips the trailing slash if the given path
+ * is a gitlink but also checks and dies if gitlink is part of the
+ * leading path (i.e. the given path goes beyond a submodule). It's
+ * safer than _SLASH_CHEAP and also more expensive.
+ */
+#define PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE (1<<5)
+#define PATHSPEC_PREFIX_ORIGIN (1<<6)
+#define PATHSPEC_KEEP_ORDER (1<<7)
+
+extern void parse_pathspec(struct pathspec *pathspec,
+ unsigned magic_mask,
+ unsigned flags,
+ const char *prefix,
+ const char **args);
+extern void copy_pathspec(struct pathspec *dst, const struct pathspec *src);
+extern void free_pathspec(struct pathspec *);
+
+static inline int ps_strncmp(const struct pathspec_item *item,
+ const char *s1, const char *s2, size_t n)
+{
+ if (item->magic & PATHSPEC_ICASE)
+ return strncasecmp(s1, s2, n);
+ else
+ return strncmp(s1, s2, n);
+}
+
+static inline int ps_strcmp(const struct pathspec_item *item,
+ const char *s1, const char *s2)
+{
+ if (item->magic & PATHSPEC_ICASE)
+ return strcasecmp(s1, s2);
+ else
+ return strcmp(s1, s2);
+}
+
+extern char *find_pathspecs_matching_against_index(const struct pathspec *pathspec);
+extern void add_pathspec_matches_against_index(const struct pathspec *pathspec, char *seen);
extern const char *check_path_for_gitlink(const char *path);
extern void die_if_path_beyond_symlink(const char *path, const char *prefix);
diff --git a/perl/Git.pm b/perl/Git.pm
index a69467f..204fdc6 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -60,7 +60,8 @@ require Exporter;
version exec_path html_path hash_object git_cmd_try
remote_refs prompt
get_tz_offset
- temp_acquire temp_release temp_reset temp_path);
+ credential credential_read credential_write
+ temp_acquire temp_is_locked temp_release temp_reset temp_path);
=head1 DESCRIPTION
@@ -269,13 +270,13 @@ sub command {
if (not defined wantarray) {
# Nothing to pepper the possible exception with.
- _cmd_close($fh, $ctx);
+ _cmd_close($ctx, $fh);
} elsif (not wantarray) {
local $/;
my $text = <$fh>;
try {
- _cmd_close($fh, $ctx);
+ _cmd_close($ctx, $fh);
} catch Git::Error::Command with {
# Pepper with the output:
my $E = shift;
@@ -288,7 +289,7 @@ sub command {
my @lines = <$fh>;
defined and chomp for @lines;
try {
- _cmd_close($fh, $ctx);
+ _cmd_close($ctx, $fh);
} catch Git::Error::Command with {
my $E = shift;
$E->{'-outputref'} = \@lines;
@@ -315,7 +316,7 @@ sub command_oneline {
my $line = <$fh>;
defined $line and chomp $line;
try {
- _cmd_close($fh, $ctx);
+ _cmd_close($ctx, $fh);
} catch Git::Error::Command with {
# Pepper with the output:
my $E = shift;
@@ -383,7 +384,7 @@ have more complicated structure.
sub command_close_pipe {
my ($self, $fh, $ctx) = _maybe_self(@_);
$ctx ||= '<unknown>';
- _cmd_close($fh, $ctx);
+ _cmd_close($ctx, $fh);
}
=item command_bidi_pipe ( COMMAND [, ARGUMENTS... ] )
@@ -420,7 +421,7 @@ and it is the fourth value returned by C<command_bidi_pipe()>. The call idiom
is:
my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe('cat-file --batch-check');
- print "000000000\n" $out;
+ print $out "000000000\n";
while (<$in>) { ... }
$r->command_close_bidi_pipe($pid, $in, $out, $ctx);
@@ -428,23 +429,26 @@ Note that you should not rely on whatever actually is in C<CTX>;
currently it is simply the command name but in future the context might
have more complicated structure.
+C<PIPE_IN> and C<PIPE_OUT> may be C<undef> if they have been closed prior to
+calling this function. This may be useful in a query-response type of
+commands where caller first writes a query and later reads response, eg:
+
+ my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe('cat-file --batch-check');
+ print $out "000000000\n";
+ close $out;
+ while (<$in>) { ... }
+ $r->command_close_bidi_pipe($pid, $in, undef, $ctx);
+
+This idiom may prevent potential dead locks caused by data sent to the output
+pipe not being flushed and thus not reaching the executed command.
+
=cut
sub command_close_bidi_pipe {
local $?;
- my ($pid, $in, $out, $ctx) = @_;
- foreach my $fh ($in, $out) {
- unless (close $fh) {
- if ($!) {
- carp "error closing pipe: $!";
- } elsif ($? >> 8) {
- throw Git::Error::Command($ctx, $? >>8);
- }
- }
- }
-
+ my ($self, $pid, $in, $out, $ctx) = _maybe_self(@_);
+ _cmd_close($ctx, (grep { defined } ($in, $out)));
waitpid $pid, 0;
-
if ($? >> 8) {
throw Git::Error::Command($ctx, $? >>8);
}
@@ -1020,6 +1024,156 @@ sub _close_cat_blob {
}
+=item credential_read( FILEHANDLE )
+
+Reads credential key-value pairs from C<FILEHANDLE>. Reading stops at EOF or
+when an empty line is encountered. Each line must be of the form C<key=value>
+with a non-empty key. Function returns hash with all read values. Any white
+space (other than new-line character) is preserved.
+
+=cut
+
+sub credential_read {
+ my ($self, $reader) = _maybe_self(@_);
+ my %credential;
+ while (<$reader>) {
+ chomp;
+ if ($_ eq '') {
+ last;
+ } elsif (!/^([^=]+)=(.*)$/) {
+ throw Error::Simple("unable to parse git credential data:\n$_");
+ }
+ $credential{$1} = $2;
+ }
+ return %credential;
+}
+
+=item credential_write( FILEHANDLE, CREDENTIAL_HASHREF )
+
+Writes credential key-value pairs from hash referenced by
+C<CREDENTIAL_HASHREF> to C<FILEHANDLE>. Keys and values cannot contain
+new-lines or NUL bytes characters, and key cannot contain equal signs nor be
+empty (if they do Error::Simple is thrown). Any white space is preserved. If
+value for a key is C<undef>, it will be skipped.
+
+If C<'url'> key exists it will be written first. (All the other key-value
+pairs are written in sorted order but you should not depend on that). Once
+all lines are written, an empty line is printed.
+
+=cut
+
+sub credential_write {
+ my ($self, $writer, $credential) = _maybe_self(@_);
+ my ($key, $value);
+
+ # Check if $credential is valid prior to writing anything
+ while (($key, $value) = each %$credential) {
+ if (!defined $key || !length $key) {
+ throw Error::Simple("credential key empty or undefined");
+ } elsif ($key =~ /[=\n\0]/) {
+ throw Error::Simple("credential key contains invalid characters: $key");
+ } elsif (defined $value && $value =~ /[\n\0]/) {
+ throw Error::Simple("credential value for key=$key contains invalid characters: $value");
+ }
+ }
+
+ for $key (sort {
+ # url overwrites other fields, so it must come first
+ return -1 if $a eq 'url';
+ return 1 if $b eq 'url';
+ return $a cmp $b;
+ } keys %$credential) {
+ if (defined $credential->{$key}) {
+ print $writer $key, '=', $credential->{$key}, "\n";
+ }
+ }
+ print $writer "\n";
+}
+
+sub _credential_run {
+ my ($self, $credential, $op) = _maybe_self(@_);
+ my ($pid, $reader, $writer, $ctx) = command_bidi_pipe('credential', $op);
+
+ credential_write $writer, $credential;
+ close $writer;
+
+ if ($op eq "fill") {
+ %$credential = credential_read $reader;
+ }
+ if (<$reader>) {
+ throw Error::Simple("unexpected output from git credential $op response:\n$_\n");
+ }
+
+ command_close_bidi_pipe($pid, $reader, undef, $ctx);
+}
+
+=item credential( CREDENTIAL_HASHREF [, OPERATION ] )
+
+=item credential( CREDENTIAL_HASHREF, CODE )
+
+Executes C<git credential> for a given set of credentials and specified
+operation. In both forms C<CREDENTIAL_HASHREF> needs to be a reference to
+a hash which stores credentials. Under certain conditions the hash can
+change.
+
+In the first form, C<OPERATION> can be C<'fill'>, C<'approve'> or C<'reject'>,
+and function will execute corresponding C<git credential> sub-command. If
+it's omitted C<'fill'> is assumed. In case of C<'fill'> the values stored in
+C<CREDENTIAL_HASHREF> will be changed to the ones returned by the C<git
+credential fill> command. The usual usage would look something like:
+
+ my %cred = (
+ 'protocol' => 'https',
+ 'host' => 'example.com',
+ 'username' => 'bob'
+ );
+ Git::credential \%cred;
+ if (try_to_authenticate($cred{'username'}, $cred{'password'})) {
+ Git::credential \%cred, 'approve';
+ ... do more stuff ...
+ } else {
+ Git::credential \%cred, 'reject';
+ }
+
+In the second form, C<CODE> needs to be a reference to a subroutine. The
+function will execute C<git credential fill> to fill the provided credential
+hash, then call C<CODE> with C<CREDENTIAL_HASHREF> as the sole argument. If
+C<CODE>'s return value is defined, the function will execute C<git credential
+approve> (if return value yields true) or C<git credential reject> (if return
+value is false). If the return value is undef, nothing at all is executed;
+this is useful, for example, if the credential could neither be verified nor
+rejected due to an unrelated network error. The return value is the same as
+what C<CODE> returns. With this form, the usage might look as follows:
+
+ if (Git::credential {
+ 'protocol' => 'https',
+ 'host' => 'example.com',
+ 'username' => 'bob'
+ }, sub {
+ my $cred = shift;
+ return !!try_to_authenticate($cred->{'username'},
+ $cred->{'password'});
+ }) {
+ ... do more stuff ...
+ }
+
+=cut
+
+sub credential {
+ my ($self, $credential, $op_or_code) = (_maybe_self(@_), 'fill');
+
+ if ('CODE' eq ref $op_or_code) {
+ _credential_run $credential, 'fill';
+ my $ret = $op_or_code->($credential);
+ if (defined $ret) {
+ _credential_run $credential, $ret ? 'approve' : 'reject';
+ }
+ return $ret;
+ } else {
+ _credential_run $credential, $op_or_code;
+ }
+}
+
{ # %TEMP_* Lexical Context
my (%TEMP_FILEMAP, %TEMP_FILES);
@@ -1052,6 +1206,35 @@ sub temp_acquire {
$temp_fd;
}
+=item temp_is_locked ( NAME )
+
+Returns true if the internal lock created by a previous C<temp_acquire()>
+call with C<NAME> is still in effect.
+
+When temp_acquire is called on a C<NAME>, it internally locks the temporary
+file mapped to C<NAME>. That lock will not be released until C<temp_release()>
+is called with either the original C<NAME> or the L<File::Handle> that was
+returned from the original call to temp_acquire.
+
+Subsequent attempts to call C<temp_acquire()> with the same C<NAME> will fail
+unless there has been an intervening C<temp_release()> call for that C<NAME>
+(or its corresponding L<File::Handle> that was returned by the original
+C<temp_acquire()> call).
+
+If true is returned by C<temp_is_locked()> for a C<NAME>, an attempt to
+C<temp_acquire()> the same C<NAME> will cause an error unless
+C<temp_release> is first called on that C<NAME> (or its corresponding
+L<File::Handle> that was returned by the original C<temp_acquire()> call).
+
+=cut
+
+sub temp_is_locked {
+ my ($self, $name) = _maybe_self(@_);
+ my $temp_fd = \$TEMP_FILEMAP{$name};
+
+ defined $$temp_fd && $$temp_fd->opened && $TEMP_FILES{$$temp_fd}{locked};
+}
+
=item temp_release ( NAME )
=item temp_release ( FILEHANDLE )
@@ -1111,7 +1294,7 @@ sub _temp_cache {
$tmpdir = $self->repo_path();
}
- ($$temp_fd, $fname) = File::Temp->tempfile(
+ ($$temp_fd, $fname) = File::Temp::tempfile(
'Git_XXXXXX', UNLINK => 1, DIR => $tmpdir,
) or throw Error::Simple("couldn't open new temp file");
@@ -1375,9 +1558,11 @@ sub _execv_git_cmd { exec('git', @_); }
# Close pipe to a subprocess.
sub _cmd_close {
- my ($fh, $ctx) = @_;
- if (not close $fh) {
- if ($!) {
+ my $ctx = shift @_;
+ foreach my $fh (@_) {
+ if (close $fh) {
+ # nop
+ } elsif ($!) {
# It's just close, no point in fatalities
carp "error closing pipe: $!";
} elsif ($? >> 8) {
diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm
index fa0d3c6..b3bcd47 100644
--- a/perl/Git/SVN/Editor.pm
+++ b/perl/Git/SVN/Editor.pm
@@ -499,6 +499,8 @@ sub apply_diff {
1;
__END__
+=head1 NAME
+
Git::SVN::Editor - commit driver for "git svn set-tree" and dcommit
=head1 SYNOPSIS
diff --git a/perl/Git/SVN/Fetcher.pm b/perl/Git/SVN/Fetcher.pm
index 046a7a2..10edb27 100644
--- a/perl/Git/SVN/Fetcher.pm
+++ b/perl/Git/SVN/Fetcher.pm
@@ -1,6 +1,7 @@
package Git::SVN::Fetcher;
-use vars qw/@ISA $_ignore_regex $_preserve_empty_dirs $_placeholder_filename
- @deleted_gpath %added_placeholder $repo_id/;
+use vars qw/@ISA $_ignore_regex $_include_regex $_preserve_empty_dirs
+ $_placeholder_filename @deleted_gpath %added_placeholder
+ $repo_id/;
use strict;
use warnings;
use SVN::Delta;
@@ -33,6 +34,10 @@ sub new {
my $v = eval { command_oneline('config', '--get', $k) };
$self->{ignore_regex} = $v;
+ $k = "svn-remote.$repo_id.include-paths";
+ $v = eval { command_oneline('config', '--get', $k) };
+ $self->{include_regex} = $v;
+
$k = "svn-remote.$repo_id.preserve-empty-dirs";
$v = eval { command_oneline('config', '--get', '--bool', $k) };
if ($v && $v eq 'true') {
@@ -117,11 +122,18 @@ sub in_dot_git {
}
# return value: 0 -- don't ignore, 1 -- ignore
+# This will also check whether the path is explicitly included
sub is_path_ignored {
my ($self, $path) = @_;
return 1 if in_dot_git($path);
return 1 if defined($self->{ignore_regex}) &&
$path =~ m!$self->{ignore_regex}!;
+ return 0 if defined($self->{include_regex}) &&
+ $path =~ m!$self->{include_regex}!;
+ return 0 if defined($_include_regex) &&
+ $path =~ m!$_include_regex!;
+ return 1 if defined($self->{include_regex});
+ return 1 if defined($_include_regex);
return 0 unless defined($_ignore_regex);
return 1 if $path =~ m!$_ignore_regex!o;
return 0;
@@ -303,11 +315,13 @@ sub change_file_prop {
sub apply_textdelta {
my ($self, $fb, $exp) = @_;
return undef if $self->is_path_ignored($fb->{path});
- my $fh = $::_repository->temp_acquire('svn_delta');
+ my $suffix = 0;
+ ++$suffix while $::_repository->temp_is_locked("svn_delta_${$}_$suffix");
+ my $fh = $::_repository->temp_acquire("svn_delta_${$}_$suffix");
# $fh gets auto-closed() by SVN::TxDelta::apply(),
# (but $base does not,) so dup() it for reading in close_file
open my $dup, '<&', $fh or croak $!;
- my $base = $::_repository->temp_acquire('git_blob');
+ my $base = $::_repository->temp_acquire("git_blob_${$}_$suffix");
if ($fb->{blob}) {
my ($base_is_link, $size);
@@ -512,6 +526,8 @@ sub stash_placeholder_list {
1;
__END__
+=head1 NAME
+
Git::SVN::Fetcher - tree delta consumer for "git svn fetch"
=head1 SYNOPSIS
diff --git a/perl/Git/SVN/Prompt.pm b/perl/Git/SVN/Prompt.pm
index 74daa7a..e940b08 100644
--- a/perl/Git/SVN/Prompt.pm
+++ b/perl/Git/SVN/Prompt.pm
@@ -125,6 +125,8 @@ sub _read_password {
1;
__END__
+=head1 NAME
+
Git::SVN::Prompt - authentication callbacks for git-svn
=head1 SYNOPSIS
diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm
index 049c97b..75ecc42 100644
--- a/perl/Git/SVN/Ra.pm
+++ b/perl/Git/SVN/Ra.pm
@@ -295,7 +295,7 @@ sub gs_do_switch {
my $full_url = add_path_to_url( $self->url, $path );
my ($ra, $reparented);
- if ($old_url =~ m#^svn(\+ssh)?://# ||
+ if ($old_url =~ m#^svn(\+\w+)?://# ||
($full_url =~ m#^https?://# &&
canonicalize_url($full_url) ne $full_url)) {
$_[0] = undef;
@@ -627,6 +627,8 @@ sub skip_unknown_revs {
1;
__END__
+=head1 NAME
+
Git::SVN::Ra - Subversion remote access functions for git-svn
=head1 SYNOPSIS
diff --git a/pkt-line.c b/pkt-line.c
index eaba15f..70f1950 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "pkt-line.h"
+char packet_buffer[LARGE_PACKET_MAX];
static const char *packet_trace_prefix = "git";
static const char trace_key[] = "GIT_TRACE_PACKET";
@@ -47,45 +48,13 @@ static void packet_trace(const char *buf, unsigned int len, int write)
}
/*
- * Write a packetized stream, where each line is preceded by
- * its length (including the header) as a 4-byte hex number.
- * A length of 'zero' means end of stream (and a length of 1-3
- * would be an error).
- *
- * This is all pretty stupid, but we use this packetized line
- * format to make a streaming format possible without ever
- * over-running the read buffers. That way we'll never read
- * into what might be the pack data (which should go to another
- * process entirely).
- *
- * The writing side could use stdio, but since the reading
- * side can't, we stay with pure read/write interfaces.
- */
-ssize_t safe_write(int fd, const void *buf, ssize_t n)
-{
- ssize_t nn = n;
- while (n) {
- int ret = xwrite(fd, buf, n);
- if (ret > 0) {
- buf = (char *) buf + ret;
- n -= ret;
- continue;
- }
- if (!ret)
- die("write error (disk full?)");
- die_errno("write error");
- }
- return nn;
-}
-
-/*
* If we buffered things up above (we don't, but we should),
* we'd flush it here
*/
void packet_flush(int fd)
{
packet_trace("0000", 4, 1);
- safe_write(fd, "0000", 4);
+ write_or_die(fd, "0000", 4);
}
void packet_buf_flush(struct strbuf *buf)
@@ -121,7 +90,7 @@ void packet_write(int fd, const char *fmt, ...)
va_start(args, fmt);
n = format_packet(fmt, args);
va_end(args);
- safe_write(fd, buffer, n);
+ write_or_die(fd, buffer, n);
}
void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
@@ -135,13 +104,29 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
strbuf_add(buf, buffer, n);
}
-static int safe_read(int fd, void *buffer, unsigned size, int return_line_fail)
+static int get_packet_data(int fd, char **src_buf, size_t *src_size,
+ void *dst, unsigned size, int options)
{
- ssize_t ret = read_in_full(fd, buffer, size);
- if (ret < 0)
- die_errno("read error");
- else if (ret < size) {
- if (return_line_fail)
+ ssize_t ret;
+
+ if (fd >= 0 && src_buf && *src_buf)
+ die("BUG: multiple sources given to packet_read");
+
+ /* Read up to "size" bytes from our source, whatever it is. */
+ if (src_buf && *src_buf) {
+ ret = size < *src_size ? size : *src_size;
+ memcpy(dst, *src_buf, ret);
+ *src_buf += ret;
+ *src_size -= ret;
+ } else {
+ ret = read_in_full(fd, dst, size);
+ if (ret < 0)
+ die_errno("read error");
+ }
+
+ /* And complain if we didn't get enough bytes to satisfy the read. */
+ if (ret < size) {
+ if (options & PACKET_READ_GENTLE_ON_EOF)
return -1;
die("The remote end hung up unexpectedly");
@@ -175,13 +160,14 @@ static int packet_length(const char *linelen)
return len;
}
-static int packet_read_internal(int fd, char *buffer, unsigned size, int return_line_fail)
+int packet_read(int fd, char **src_buf, size_t *src_len,
+ char *buffer, unsigned size, int options)
{
int len, ret;
char linelen[4];
- ret = safe_read(fd, linelen, 4, return_line_fail);
- if (return_line_fail && ret < 0)
+ ret = get_packet_data(fd, src_buf, src_len, linelen, 4, options);
+ if (ret < 0)
return ret;
len = packet_length(linelen);
if (len < 0)
@@ -193,50 +179,37 @@ static int packet_read_internal(int fd, char *buffer, unsigned size, int return_
len -= 4;
if (len >= size)
die("protocol error: bad line length %d", len);
- ret = safe_read(fd, buffer, len, return_line_fail);
- if (return_line_fail && ret < 0)
+ ret = get_packet_data(fd, src_buf, src_len, buffer, len, options);
+ if (ret < 0)
return ret;
+
+ if ((options & PACKET_READ_CHOMP_NEWLINE) &&
+ len && buffer[len-1] == '\n')
+ len--;
+
buffer[len] = 0;
packet_trace(buffer, len, 0);
return len;
}
-int packet_read(int fd, char *buffer, unsigned size)
+static char *packet_read_line_generic(int fd,
+ char **src, size_t *src_len,
+ int *dst_len)
{
- return packet_read_internal(fd, buffer, size, 1);
+ int len = packet_read(fd, src, src_len,
+ packet_buffer, sizeof(packet_buffer),
+ PACKET_READ_CHOMP_NEWLINE);
+ if (dst_len)
+ *dst_len = len;
+ return len ? packet_buffer : NULL;
}
-int packet_read_line(int fd, char *buffer, unsigned size)
+char *packet_read_line(int fd, int *len_p)
{
- return packet_read_internal(fd, buffer, size, 0);
+ return packet_read_line_generic(fd, NULL, NULL, len_p);
}
-int packet_get_line(struct strbuf *out,
- char **src_buf, size_t *src_len)
+char *packet_read_line_buf(char **src, size_t *src_len, int *dst_len)
{
- int len;
-
- if (*src_len < 4)
- return -1;
- len = packet_length(*src_buf);
- if (len < 0)
- return -1;
- if (!len) {
- *src_buf += 4;
- *src_len -= 4;
- packet_trace("0000", 4, 0);
- return 0;
- }
- if (*src_len < len)
- return -2;
-
- *src_buf += 4;
- *src_len -= 4;
- len -= 4;
-
- strbuf_add(out, *src_buf, len);
- *src_buf += len;
- *src_len -= len;
- packet_trace(out->buf, out->len, 0);
- return len;
+ return packet_read_line_generic(-1, src, src_len, dst_len);
}
diff --git a/pkt-line.h b/pkt-line.h
index 8cfeb0c..0a838d1 100644
--- a/pkt-line.h
+++ b/pkt-line.h
@@ -5,16 +5,78 @@
#include "strbuf.h"
/*
- * Silly packetized line writing interface
+ * Write a packetized stream, where each line is preceded by
+ * its length (including the header) as a 4-byte hex number.
+ * A length of 'zero' means end of stream (and a length of 1-3
+ * would be an error).
+ *
+ * This is all pretty stupid, but we use this packetized line
+ * format to make a streaming format possible without ever
+ * over-running the read buffers. That way we'll never read
+ * into what might be the pack data (which should go to another
+ * process entirely).
+ *
+ * The writing side could use stdio, but since the reading
+ * side can't, we stay with pure read/write interfaces.
*/
void packet_flush(int fd);
void packet_write(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
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);
+/*
+ * Read a packetized line into the buffer, which must be at least size bytes
+ * long. The return value specifies the number of bytes read into the buffer.
+ *
+ * If src_buffer is not NULL (and nor is *src_buffer), it should point to a
+ * buffer containing the packet data to parse, of at least *src_len bytes.
+ * After the function returns, src_buf will be incremented and src_len
+ * decremented by the number of bytes consumed.
+ *
+ * If src_buffer (or *src_buffer) is NULL, then data is read from the
+ * descriptor "fd".
+ *
+ * If options does not contain PACKET_READ_GENTLE_ON_EOF, we will die under any
+ * of the following conditions:
+ *
+ * 1. Read error from descriptor.
+ *
+ * 2. Protocol error from the remote (e.g., bogus length characters).
+ *
+ * 3. Receiving a packet larger than "size" bytes.
+ *
+ * 4. Truncated output from the remote (e.g., we expected a packet but got
+ * EOF, or we got a partial packet followed by EOF).
+ *
+ * If options does contain PACKET_READ_GENTLE_ON_EOF, we will not die on
+ * condition 4 (truncated input), but instead return -1. However, we will still
+ * die for the other 3 conditions.
+ *
+ * If options contains PACKET_READ_CHOMP_NEWLINE, a trailing newline (if
+ * present) is removed from the buffer before returning.
+ */
+#define PACKET_READ_GENTLE_ON_EOF (1u<<0)
+#define PACKET_READ_CHOMP_NEWLINE (1u<<1)
+int packet_read(int fd, char **src_buffer, size_t *src_len, char
+ *buffer, unsigned size, int options);
+
+/*
+ * Convenience wrapper for packet_read that is not gentle, and sets the
+ * CHOMP_NEWLINE option. The return value is NULL for a flush packet,
+ * and otherwise points to a static buffer (that may be overwritten by
+ * subsequent calls). If the size parameter is not NULL, the length of the
+ * packet is written to it.
+ */
+char *packet_read_line(int fd, int *size);
+
+/*
+ * Same as packet_read_line, but read from a buf rather than a descriptor;
+ * see packet_read for details on how src_* is used.
+ */
+char *packet_read_line_buf(char **src_buf, size_t *src_len, int *size);
+
+#define DEFAULT_PACKET_MAX 1000
+#define LARGE_PACKET_MAX 65520
+extern char packet_buffer[LARGE_PACKET_MAX];
#endif
diff --git a/po/TEAMS b/po/TEAMS
index 5eb5aad..107aa59 100644
--- a/po/TEAMS
+++ b/po/TEAMS
@@ -12,6 +12,11 @@ Members: Thomas Rast <trast@student.ethz.ch>
Jan Krüger <jk@jk.gs>
Christian Stimming <stimming@tuhh.de>
+Language: fr (French)
+Repository: https://github.com/jnavila/git
+Leader: Jean-Noël Avila <jn.avila@free.fr>
+Members: Sébastien Helleu <flashcode@flashtux.org>
+
Language: is (Icelandic)
Leader: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
diff --git a/po/de.po b/po/de.po
index 83c30b1..11dde11 100644
--- a/po/de.po
+++ b/po/de.po
@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: git 1.8.2\n"
+"Project-Id-Version: git 1.8.4\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2013-03-05 12:36+0800\n"
-"PO-Revision-Date: 2012-10-02 19:35+0200\n"
+"POT-Creation-Date: 2013-08-06 14:10+0800\n"
+"PO-Revision-Date: 2013-07-28 18:42+0200\n"
"Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
"Language-Team: German <>\n"
"Language: de\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
-#: advice.c:49
+#: advice.c:57
#, c-format
msgid "hint: %.*s\n"
msgstr "Hinweis: %.*s\n"
@@ -26,21 +26,21 @@ msgstr "Hinweis: %.*s\n"
#. * Message used both when 'git commit' fails and when
#. * other commands doing a merge do.
#.
-#: advice.c:79
+#: advice.c:87
msgid ""
"Fix them up in the work tree,\n"
"and then use 'git add/rm <file>' as\n"
"appropriate to mark resolution and make a commit,\n"
"or use 'git commit -a'."
msgstr ""
-"Korrigieren Sie dies im Arbeitsbaum,\n"
+"Korrigieren Sie dies im Arbeitsverzeichnis,\n"
"und benutzen Sie dann 'git add/rm <Datei>'\n"
-"um die Auflösung entsprechend zu markieren und einzutragen,\n"
+"um die Auflösung entsprechend zu markieren und zu committen,\n"
"oder benutzen Sie 'git commit -a'."
#: archive.c:10
msgid "git archive [options] <tree-ish> [<path>...]"
-msgstr "git archive [Optionen] <Versionsreferenz> [<Pfad>...]"
+msgstr "git archive [Optionen] <Commit-Referenz> [<Pfad>...]"
#: archive.c:11
msgid "git archive --list"
@@ -50,12 +50,12 @@ msgstr "git archive --list"
msgid ""
"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"
msgstr ""
-"git archive --remote <Projektarchiv> [--exec <Programm>] [Optionen] "
-"<Versionsreferenz> [Pfad...]"
+"git archive --remote <Repository> [--exec <Programm>] [Optionen] <Commit-"
+"Referenz> [Pfad...]"
#: archive.c:13
msgid "git archive --remote <repo> [--exec <cmd>] --list"
-msgstr "git archive --remote <Projektarchiv> [--exec <Programm>] --list"
+msgstr "git archive --remote <Repository> [--exec <Programm>] --list"
#: archive.c:323
msgid "fmt"
@@ -63,27 +63,27 @@ msgstr "Format"
#: archive.c:323
msgid "archive format"
-msgstr "Ausgabeformat"
+msgstr "Archivformat"
-#: archive.c:324 builtin/log.c:1115
+#: archive.c:324 builtin/log.c:1173
msgid "prefix"
msgstr "Prefix"
#: archive.c:325
msgid "prepend prefix to each pathname in the archive"
-msgstr "stellt einen Präfix vor jeden Pfadnamen in der Ausgabe"
+msgstr "stellt einen Präfix vor jeden Pfadnamen in dem Archiv"
-#: archive.c:326 builtin/archive.c:91 builtin/blame.c:2366
-#: builtin/blame.c:2367 builtin/config.c:55 builtin/fast-export.c:653
-#: builtin/fast-export.c:655 builtin/grep.c:715 builtin/hash-object.c:77
-#: builtin/ls-files.c:497 builtin/ls-files.c:500 builtin/notes.c:536
-#: builtin/notes.c:693 builtin/read-tree.c:107 parse-options.h:149
+#: archive.c:326 builtin/archive.c:88 builtin/blame.c:2292
+#: builtin/blame.c:2293 builtin/config.c:56 builtin/fast-export.c:673
+#: builtin/fast-export.c:675 builtin/grep.c:714 builtin/hash-object.c:77
+#: builtin/ls-files.c:496 builtin/ls-files.c:499 builtin/notes.c:408
+#: builtin/notes.c:565 builtin/read-tree.c:108 parse-options.h:152
msgid "file"
msgstr "Datei"
-#: archive.c:327 builtin/archive.c:92
+#: archive.c:327 builtin/archive.c:89
msgid "write the archive to this file"
-msgstr "schreibt die Ausgabe in diese Datei"
+msgstr "schreibt das Archiv in diese Datei"
#: archive.c:329
msgid "read .gitattributes in working directory"
@@ -107,21 +107,21 @@ msgstr "besser komprimieren"
#: archive.c:343
msgid "list supported archive formats"
-msgstr "listet unterstützte Ausgabeformate auf"
+msgstr "listet unterstützte Archivformate auf"
-#: archive.c:345 builtin/archive.c:93 builtin/clone.c:85
+#: archive.c:345 builtin/archive.c:90 builtin/clone.c:85
msgid "repo"
-msgstr "Projektarchiv"
+msgstr "Repository"
-#: archive.c:346 builtin/archive.c:94
+#: archive.c:346 builtin/archive.c:91
msgid "retrieve the archive from remote repository <repo>"
-msgstr "ruft das Archiv von externem Projektarchiv <Projektarchiv> ab"
+msgstr "ruft das Archiv von Remote-Repository <Repository> ab"
-#: archive.c:347 builtin/archive.c:95 builtin/notes.c:615
+#: archive.c:347 builtin/archive.c:92 builtin/notes.c:487
msgid "command"
msgstr "Programm"
-#: archive.c:348 builtin/archive.c:96
+#: archive.c:348 builtin/archive.c:93
msgid "path to the remote git-upload-archive command"
msgstr "Pfad zum externen \"git-upload-archive\"-Programm"
@@ -133,6 +133,136 @@ msgstr ""
"Verneinende Muster werden in Git-Attributen ignoriert.\n"
"Benutzen Sie '\\!' für führende Ausrufezeichen."
+#: branch.c:60
+#, c-format
+msgid "Not setting branch %s as its own upstream."
+msgstr "Branch %s kann nicht sein eigener Upstream-Branch sein."
+
+#: branch.c:82
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s by rebasing."
+msgstr ""
+"Branch %s konfiguriert zum Folgen von Remote-Branch %s von %s durch Rebase."
+
+#: branch.c:83
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s."
+msgstr "Branch %s konfiguriert zum Folgen von Remote-Branch %s von %s."
+
+#: branch.c:87
+#, c-format
+msgid "Branch %s set up to track local branch %s by rebasing."
+msgstr "Branch %s konfiguriert zum Folgen von lokalem Branch %s durch Rebase."
+
+#: branch.c:88
+#, c-format
+msgid "Branch %s set up to track local branch %s."
+msgstr "Branch %s konfiguriert zum Folgen von lokalem Branch %s."
+
+#: branch.c:92
+#, c-format
+msgid "Branch %s set up to track remote ref %s by rebasing."
+msgstr "Branch %s konfiguriert zum Folgen von Remote-Referenz %s durch Rebase."
+
+#: branch.c:93
+#, c-format
+msgid "Branch %s set up to track remote ref %s."
+msgstr "Branch %s konfiguriert zum Folgen von Remote-Referenz %s."
+
+#: branch.c:97
+#, c-format
+msgid "Branch %s set up to track local ref %s by rebasing."
+msgstr ""
+"Branch %s konfiguriert zum Folgen von lokaler Referenz %s durch Rebase."
+
+#: branch.c:98
+#, c-format
+msgid "Branch %s set up to track local ref %s."
+msgstr "Branch %s konfiguriert zum Folgen von lokaler Referenz %s."
+
+#: branch.c:118
+#, c-format
+msgid "Tracking not set up: name too long: %s"
+msgstr ""
+"Konfiguration zum Folgen von Branch nicht eingerichtet. Name zu lang: %s"
+
+#: branch.c:137
+#, c-format
+msgid "Not tracking: ambiguous information for ref %s"
+msgstr ""
+"Konfiguration zum Folgen von Branch nicht eingerichtet. Referenz %s ist "
+"mehrdeutig."
+
+#: branch.c:182
+#, c-format
+msgid "'%s' is not a valid branch name."
+msgstr "'%s' ist kein gültiger Branchname."
+
+#: branch.c:187
+#, c-format
+msgid "A branch named '%s' already exists."
+msgstr "Branch '%s' existiert bereits."
+
+#: branch.c:195
+msgid "Cannot force update the current branch."
+msgstr "Kann Aktualisierung des aktuellen Branches nicht erzwingen."
+
+#: branch.c:216
+#, c-format
+msgid "Cannot setup tracking information; starting point '%s' is not a branch."
+msgstr ""
+"Kann Tracking-Informationen nicht einrichten; Startpunkt '%s' ist kein "
+"Branch."
+
+#: branch.c:218
+#, c-format
+msgid "the requested upstream branch '%s' does not exist"
+msgstr "der angeforderte Upstream-Branch '%s' existiert nicht"
+
+#: branch.c:220
+msgid ""
+"\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push."
+msgstr ""
+"\n"
+"Falls Sie vorhaben, Ihre Arbeit auf einem bereits existierenden\n"
+"Upstream-Branch aufzubauen, sollten Sie \"git fetch\"\n"
+"ausführen, um diesen abzurufen.\n"
+"\n"
+"Falls Sie vorhaben, einen neuen lokalen Branch zu versenden\n"
+"der seinem externen Gegenstück folgen soll, können Sie\n"
+"\"git push -u\" verwenden, um den Upstream-Branch beim \"push\"\n"
+"zu konfigurieren."
+
+#: branch.c:265
+#, c-format
+msgid "Not a valid object name: '%s'."
+msgstr "Ungültiger Objekt-Name: '%s'"
+
+#: branch.c:285
+#, c-format
+msgid "Ambiguous object name: '%s'."
+msgstr "mehrdeutiger Objekt-Name: '%s'"
+
+#: branch.c:290
+#, c-format
+msgid "Not a valid branch point: '%s'."
+msgstr "Ungültiger Branchpunkt: '%s'"
+
+#: branch.c:296
+msgid "Failed to lock ref for update"
+msgstr "Fehler beim Sperren der Referenz zur Aktualisierung."
+
+#: branch.c:314
+msgid "Failed to write ref"
+msgstr "Fehler beim Schreiben der Referenz."
+
#: bundle.c:36
#, c-format
msgid "'%s' does not look like a v2 bundle file"
@@ -143,44 +273,44 @@ 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:674
+#: bundle.c:89 builtin/commit.c:697
#, 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 vorausgesetzte Versionen:"
+msgstr "Dem Repository fehlen folgende vorausgesetzte Commits:"
-#: bundle.c:164 sequencer.c:566 sequencer.c:998 builtin/log.c:299
-#: builtin/log.c:751 builtin/log.c:1358 builtin/log.c:1574 builtin/merge.c:347
-#: builtin/shortlog.c:157
+#: bundle.c:164 sequencer.c:661 sequencer.c:1111 builtin/log.c:331
+#: builtin/log.c:801 builtin/log.c:1399 builtin/log.c:1625 builtin/merge.c:364
+#: builtin/shortlog.c:156
msgid "revision walk setup failed"
msgstr "Einrichtung des Revisionsgangs fehlgeschlagen"
#: bundle.c:186
#, c-format
-msgid "The bundle contains %d ref"
-msgid_plural "The bundle contains %d refs"
-msgstr[0] "Das Paket enthält %d Referenz"
-msgstr[1] "Das Paket enthält %d Referenzen"
+msgid "The bundle contains this ref:"
+msgid_plural "The bundle contains these %d refs:"
+msgstr[0] "Das Paket enthält diese Referenz:"
+msgstr[1] "Das Paket enthält diese %d Referenzen:"
-#: bundle.c:192
+#: bundle.c:193
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"
+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:294
msgid "rev-list died"
msgstr "\"rev-list\" abgebrochen"
-#: bundle.c:300 builtin/log.c:1254 builtin/shortlog.c:260
+#: bundle.c:300 builtin/log.c:1310 builtin/shortlog.c:259
#, c-format
msgid "unrecognized argument: %s"
msgstr "nicht erkanntes Argument: %s"
@@ -211,30 +341,30 @@ msgstr "kann '%s' nicht erstellen"
msgid "index-pack died"
msgstr "Erstellung der Paketindexdatei abgebrochen"
-#: commit.c:50
+#: commit.c:53
#, c-format
msgid "could not parse %s"
msgstr "konnte %s nicht parsen"
-#: commit.c:52
+#: commit.c:55
#, c-format
msgid "%s %s is not a commit!"
-msgstr "%s %s ist keine Version!"
+msgstr "%s %s ist kein Commit!"
#: compat/obstack.c:406 compat/obstack.c:408
msgid "memory exhausted"
msgstr "Speicher verbraucht"
-#: connected.c:39
+#: connected.c:60
msgid "Could not run 'git rev-list'"
msgstr "Konnte 'git rev-list' nicht ausführen"
-#: connected.c:48
+#: connected.c:80
#, c-format
msgid "failed write to rev-list: %s"
msgstr "Fehler beim Schreiben nach rev-list: %s"
-#: connected.c:56
+#: connected.c:88
#, c-format
msgid "failed to close rev-list's stdin: %s"
msgstr "Fehler beim Schließen von rev-list's Standard-Eingabe: %s"
@@ -331,7 +461,7 @@ msgstr ""
"Fehler in 'diff.dirstat' Konfigurationsvariable gefunden:\n"
"%s"
-#: diff.c:3468
+#: diff.c:3487
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -340,12 +470,12 @@ msgstr ""
"Fehler beim Parsen des --dirstat/-X Optionsparameters:\n"
"%s"
-#: diff.c:3482
+#: diff.c:3501
#, c-format
msgid "Failed to parse --submodule option parameter: '%s'"
msgstr "Fehler beim Parsen des --submodule Optionsparameters: '%s'"
-#: gpg-interface.c:59 gpg-interface.c:127
+#: gpg-interface.c:59 gpg-interface.c:131
msgid "could not run gpg."
msgstr "konnte gpg nicht ausführen"
@@ -357,45 +487,45 @@ msgstr "gpg hat die Daten nicht akzeptiert"
msgid "gpg failed to sign the data"
msgstr "gpg beim Signieren der Daten fehlgeschlagen"
-#: gpg-interface.c:112
+#: gpg-interface.c:115
#, c-format
msgid "could not create temporary file '%s': %s"
msgstr "konnte temporäre Datei '%s' nicht erstellen: %s"
-#: gpg-interface.c:115
+#: gpg-interface.c:118
#, c-format
msgid "failed writing detached signature to '%s': %s"
msgstr "Fehler beim Schreiben der Signatur nach '%s': %s"
-#: grep.c:1622
+#: grep.c:1623
#, c-format
msgid "'%s': unable to read %s"
msgstr "'%s': konnte nicht lesen %s"
-#: grep.c:1639
+#: grep.c:1640
#, c-format
msgid "'%s': %s"
msgstr "'%s': %s"
-#: grep.c:1650
+#: grep.c:1651
#, c-format
msgid "'%s': short read %s"
msgstr "'%s': read() zu kurz %s"
-#: help.c:212
+#: help.c:210
#, c-format
msgid "available git commands in '%s'"
msgstr "Vorhandene Git-Kommandos in '%s'"
-#: help.c:219
+#: help.c:217
msgid "git commands available from elsewhere on your $PATH"
msgstr "Vorhandene Git-Kommandos irgendwo in Ihrem $PATH"
-#: help.c:235
+#: help.c:233
msgid "The most commonly used git commands are:"
msgstr "Die allgemein verwendeten Git-Kommandos sind:"
-#: help.c:292
+#: help.c:290
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -404,11 +534,11 @@ msgstr ""
"'%s' scheint ein git-Kommando zu sein, konnte aber\n"
"nicht ausgeführt werden. Vielleicht ist git-%s fehlerhaft?"
-#: help.c:349
+#: help.c:347
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "Uh oh. Keine Git-Kommandos auf Ihrem System vorhanden."
-#: help.c:371
+#: help.c:369
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -417,17 +547,17 @@ msgstr ""
"Warnung: Sie haben das nicht existierende Git-Kommando '%s' ausgeführt.\n"
"Setze fort unter der Annahme, dass Sie '%s' gemeint haben"
-#: help.c:376
+#: help.c:374
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr "automatisch in %0.1f Sekunden..."
-#: help.c:383
+#: help.c:381
#, 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:387
+#: help.c:385 help.c:444
msgid ""
"\n"
"Did you mean this?"
@@ -441,89 +571,94 @@ msgstr[1] ""
"\n"
"Haben Sie eines von diesen gemeint?"
+#: help.c:440
+#, c-format
+msgid "%s: %s - %s"
+msgstr "%s: %s - %s"
+
#: merge.c:56
msgid "failed to read the cache"
msgstr "Lesen des Zwischenspeichers fehlgeschlagen"
-#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534
-#: builtin/clone.c:586
+#: merge.c:110 builtin/checkout.c:365 builtin/checkout.c:566
+#: builtin/clone.c:656
msgid "unable to write new index file"
-msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
+msgstr "Konnte neue Staging-Area-Datei nicht schreiben."
#: merge-recursive.c:190
#, c-format
msgid "(bad commit)\n"
-msgstr "(ungültige Version)\n"
+msgstr "(ungültiger Commit)\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
+#: merge-recursive.c:269
msgid "error building trees"
-msgstr "Fehler beim Erstellen der Bäume"
+msgstr "Fehler beim Erstellen der \"Tree\"-Objekte"
-#: merge-recursive.c:672
+#: merge-recursive.c:673
#, c-format
msgid "failed to create path '%s'%s"
msgstr "Fehler beim Erstellen des Pfades '%s'%s"
-#: merge-recursive.c:683
+#: merge-recursive.c:684
#, 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
+#: merge-recursive.c:698 merge-recursive.c:719
msgid ": perhaps a D/F conflict?"
msgstr ": vielleicht ein Verzeichnis/Datei-Konflikt?"
-#: merge-recursive.c:708
+#: merge-recursive.c:709
#, 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
+#: merge-recursive.c:749
#, c-format
msgid "cannot read object %s '%s'"
msgstr "kann Objekt %s '%s' nicht lesen"
-#: merge-recursive.c:750
+#: merge-recursive.c:751
#, c-format
msgid "blob expected for %s '%s'"
msgstr "Blob erwartet für %s '%s'"
-#: merge-recursive.c:773 builtin/clone.c:302
+#: merge-recursive.c:774 builtin/clone.c:312
#, c-format
msgid "failed to open '%s'"
msgstr "Fehler beim Öffnen von '%s'"
-#: merge-recursive.c:781
+#: merge-recursive.c:782
#, c-format
msgid "failed to symlink '%s'"
-msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s'"
+msgstr "Fehler beim Erstellen eines symbolischen Verweises für '%s'"
-#: merge-recursive.c:784
+#: merge-recursive.c:785
#, 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:922
+#: merge-recursive.c:923
msgid "Failed to execute internal merge"
-msgstr "Fehler bei Ausführung der internen Zusammenführung"
+msgstr "Fehler bei Ausführung des internen Merges"
-#: merge-recursive.c:926
+#: merge-recursive.c:927
#, c-format
msgid "Unable to add %s to database"
msgstr "Konnte %s nicht zur Datenbank hinzufügen"
-#: merge-recursive.c:942
+#: merge-recursive.c:943
msgid "unsupported object type in the tree"
-msgstr "nicht unterstützter Objekttyp im Baum"
+msgstr "nicht unterstützter Objekttyp im Verzeichnis"
-#: merge-recursive.c:1021 merge-recursive.c:1035
+#: merge-recursive.c:1022 merge-recursive.c:1036
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -532,7 +667,7 @@ msgstr ""
"KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde "
"im Arbeitsbereich gelassen."
-#: merge-recursive.c:1027 merge-recursive.c:1040
+#: merge-recursive.c:1028 merge-recursive.c:1041
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -541,172 +676,200 @@ 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:1081
+#: merge-recursive.c:1082
msgid "rename"
msgstr "umbenennen"
-#: merge-recursive.c:1081
+#: merge-recursive.c:1082
msgid "renamed"
msgstr "umbenannt"
-#: merge-recursive.c:1137
+#: merge-recursive.c:1138
#, 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:1159
+#: merge-recursive.c:1160
#, 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"
+"KONFLIKT (umbenennen/umbenennen): Benenne um \"%s\"->\"%s\" in Branch \"%s\" "
+"und \"%s\"->\"%s\" in Branch \"%s\"%s"
-#: merge-recursive.c:1164
+#: merge-recursive.c:1165
msgid " (left unresolved)"
msgstr " (bleibt unaufgelöst)"
-#: merge-recursive.c:1218
+#: merge-recursive.c:1219
#, 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:1248
+#: merge-recursive.c:1249
#, 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:1447
+#: merge-recursive.c:1448
#, 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:1457
+#: merge-recursive.c:1458
#, c-format
msgid "Adding merged %s"
msgstr "Füge zusammengeführte Datei %s hinzu"
-#: merge-recursive.c:1462 merge-recursive.c:1660
+#: merge-recursive.c:1463 merge-recursive.c:1661
#, c-format
msgid "Adding as %s instead"
msgstr "Füge stattdessen als %s hinzu"
-#: merge-recursive.c:1513
+#: merge-recursive.c:1514
#, c-format
msgid "cannot read object %s"
msgstr "kann Objekt %s nicht lesen"
-#: merge-recursive.c:1516
+#: merge-recursive.c:1517
#, c-format
msgid "object %s is not a blob"
msgstr "Objekt %s ist kein Blob"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modify"
msgstr "ändern"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modified"
msgstr "geändert"
-#: merge-recursive.c:1574
+#: merge-recursive.c:1575
msgid "content"
msgstr "Inhalt"
-#: merge-recursive.c:1581
+#: merge-recursive.c:1582
msgid "add/add"
msgstr "hinzufügen/hinzufügen"
-#: merge-recursive.c:1615
+#: merge-recursive.c:1616
#, c-format
msgid "Skipped %s (merged same as existing)"
-msgstr "%s ausgelassen (Ergebnis der Zusammenführung existiert bereits)"
+msgstr "%s ausgelassen (Ergebnis des Merges existiert bereits)"
-#: merge-recursive.c:1629
+#: merge-recursive.c:1630
#, c-format
msgid "Auto-merging %s"
-msgstr "automatische Zusammenführung von %s"
+msgstr "automatischer Merge von %s"
-#: merge-recursive.c:1633 git-submodule.sh:942
+#: merge-recursive.c:1634 git-submodule.sh:1118
msgid "submodule"
-msgstr "Unterprojekt"
+msgstr "Submodul"
-#: merge-recursive.c:1634
+#: merge-recursive.c:1635
#, c-format
msgid "CONFLICT (%s): Merge conflict in %s"
-msgstr "KONFLIKT (%s): Zusammenführungskonflikt in %s"
+msgstr "KONFLIKT (%s): Merge-Konflikt in %s"
-#: merge-recursive.c:1724
+#: merge-recursive.c:1725
#, c-format
msgid "Removing %s"
msgstr "Entferne %s"
-#: merge-recursive.c:1749
+#: merge-recursive.c:1750
msgid "file/directory"
msgstr "Datei/Verzeichnis"
-#: merge-recursive.c:1755
+#: merge-recursive.c:1756
msgid "directory/file"
msgstr "Verzeichnis/Datei"
-#: merge-recursive.c:1760
+#: merge-recursive.c:1761
#, 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:1770
+#: merge-recursive.c:1771
#, c-format
msgid "Adding %s"
msgstr "Füge %s hinzu"
-#: merge-recursive.c:1787
+#: merge-recursive.c:1788
msgid "Fatal merge failure, shouldn't happen."
-msgstr "Fataler Fehler bei der Zusammenführung. Sollte nicht passieren."
+msgstr "Fataler Merge-Fehler. Sollte nicht passieren."
-#: merge-recursive.c:1806
+#: merge-recursive.c:1807
msgid "Already up-to-date!"
msgstr "Bereits aktuell!"
-#: merge-recursive.c:1815
+#: merge-recursive.c:1816
#, c-format
msgid "merging of trees %s and %s failed"
-msgstr "Zusammenführen der Bäume %s und %s fehlgeschlagen"
+msgstr "Zusammenführen der \"Tree\"-Objekte %s und %s fehlgeschlagen"
-#: merge-recursive.c:1845
+#: merge-recursive.c:1846
#, c-format
msgid "Unprocessed path??? %s"
msgstr "unverarbeiteter Pfad??? %s"
-#: merge-recursive.c:1890
+#: merge-recursive.c:1891
msgid "Merging:"
-msgstr "Zusammenführung:"
+msgstr "Merge:"
-#: merge-recursive.c:1903
+#: merge-recursive.c:1904
#, 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"
+msgstr[0] "%u gemeinsamen Vorgänger-Commit gefunden"
+msgstr[1] "%u gemeinsame Vorgänger-Commits gefunden"
-#: merge-recursive.c:1940
+#: merge-recursive.c:1941
msgid "merge returned no commit"
-msgstr "Zusammenführung hat keine Version zurückgegeben"
+msgstr "Merge hat keinen Commit zurückgegeben"
-#: merge-recursive.c:1997
+#: merge-recursive.c:1998
#, c-format
msgid "Could not parse object '%s'"
msgstr "Konnte Objekt '%s' nicht parsen."
-#: merge-recursive.c:2009 builtin/merge.c:643
+#: merge-recursive.c:2010 builtin/merge.c:672
msgid "Unable to write index."
-msgstr "Konnte Bereitstellung nicht schreiben."
+msgstr "Konnte Staging-Area nicht schreiben."
+
+#: notes-utils.c:40
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr ""
+"Kann uninitialisiertes/unreferenzierte Notiz-Verzeichnis nicht committen."
+
+#: notes-utils.c:81
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "Ungültiger notes.rewriteMode Wert: '%s'"
+
+#: notes-utils.c:91
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr ""
+"Umschreiben der Notizen in %s zurückgewiesen (außerhalb von refs/notes/)"
+
+#. TRANSLATORS: The first %s is the name of the
+#. environment variable, the second %s is its value
+#: notes-utils.c:118
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr "Ungültiger %s Wert: '%s'"
+
+#: object.c:204
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "Konnte Objekt '%s' nicht parsen."
#: parse-options.c:489
msgid "..."
@@ -736,41 +899,40 @@ msgstr "-NUM"
#: pathspec.c:83
#, c-format
msgid "Path '%s' is in submodule '%.*s'"
-msgstr "Pfad '%s' befindet sich in Unterprojekt '%.*s'"
+msgstr "Pfad '%s' befindet sich in Submodul '%.*s'"
#: pathspec.c:99
#, c-format
msgid "'%s' is beyond a symbolic link"
-msgstr "'%s' ist über einem symbolischen Link"
+msgstr "'%s' ist hinter einem symbolischen Verweis"
-#: remote.c:1653
+#: remote.c:1788
#, 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] "Ihr Zweig ist vor '%s' um %d Version.\n"
-msgstr[1] "Ihr Zweig ist vor '%s' um %d Versionen.\n"
+msgstr[0] "Ihr Branch ist vor '%s' um %d Commit.\n"
+msgstr[1] "Ihr Branch ist vor '%s' um %d Commits.\n"
-#: remote.c:1659
+#: remote.c:1794
msgid " (use \"git push\" to publish your local commits)\n"
-msgstr " (benutzen Sie \"git push\" um lokalen Versionen herauszubringen)\n"
+msgstr " (benutzen Sie \"git push\" um lokale Commits zu publizieren)\n"
-#: remote.c:1662
+#: remote.c:1797
#, 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] ""
-"Ihr Zweig ist zu '%s' um %d Version hinterher, und kann vorgespult werden.\n"
+"Ihr Branch ist zu '%s' um %d Commit hinterher, und kann vorgespult werden.\n"
msgstr[1] ""
-"Ihr Zweig ist zu '%s' um %d Versionen hinterher, und kann vorgespult "
-"werden.\n"
+"Ihr Branch ist zu '%s' um %d Commits hinterher, und kann vorgespult werden.\n"
-#: remote.c:1670
+#: remote.c:1805
msgid " (use \"git pull\" to update your local branch)\n"
msgstr ""
-" (benutzen Sie \"git pull\" um Ihren lokalen Zweig zu aktualisieren)\n"
+" (benutzen Sie \"git pull\" um Ihren lokalen Branch zu aktualisieren)\n"
-#: remote.c:1673
+#: remote.c:1808
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -779,31 +941,40 @@ msgid_plural ""
"Your branch and '%s' have diverged,\n"
"and have %d and %d different commits each, respectively.\n"
msgstr[0] ""
-"Ihr Zweig und '%s' sind divergiert,\n"
-"und haben jeweils %d und %d unterschiedliche Versionen.\n"
+"Ihr Branch und '%s' sind divergiert,\n"
+"und haben jeweils %d und %d unterschiedliche Commits.\n"
msgstr[1] ""
-"Ihr Zweig und '%s' sind divergiert,\n"
-"und haben jeweils %d und %d unterschiedliche Versionen.\n"
+"Ihr Branch und '%s' sind divergiert,\n"
+"und haben jeweils %d und %d unterschiedliche Commits.\n"
-#: remote.c:1683
+#: remote.c:1818
msgid " (use \"git pull\" to merge the remote branch into yours)\n"
msgstr ""
-" (benutzen Sie \"git pull\" um Ihren Zweig mit dem externen "
+" (benutzen Sie \"git pull\" um Ihren Branch mit dem Remote-Branch "
"zusammenzuführen)\n"
-#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
-#: builtin/merge.c:994
+#: run-command.c:80
+msgid "open /dev/null failed"
+msgstr "Öffnen von /dev/null fehlgeschlagen"
+
+#: run-command.c:82
+#, c-format
+msgid "dup2(%d,%d) failed"
+msgstr "dup2(%d,%d) fehlgeschlagen"
+
+#: sequencer.c:206 builtin/merge.c:790 builtin/merge.c:903
+#: builtin/merge.c:1013 builtin/merge.c:1023
#, c-format
msgid "Could not open '%s' for writing"
msgstr "Konnte '%s' nicht zum Schreiben öffnen."
-#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986
-#: builtin/merge.c:999
+#: sequencer.c:208 builtin/merge.c:350 builtin/merge.c:793
+#: builtin/merge.c:1015 builtin/merge.c:1028
#, c-format
msgid "Could not write to '%s'"
msgstr "Konnte nicht nach '%s' schreiben."
-#: sequencer.c:146
+#: sequencer.c:229
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
@@ -811,7 +982,7 @@ msgstr ""
"nach Auflösung der Konflikte, markieren Sie die korrigierten Pfade\n"
"mit 'git add <Pfade>' oder 'git rm <Pfade>'"
-#: sequencer.c:149
+#: sequencer.c:232
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'\n"
@@ -821,652 +992,742 @@ msgstr ""
"mit 'git add <Pfade>' oder 'git rm <Pfade>'und tragen Sie das Ergebnis mit\n"
"'git commit' ein"
-#: sequencer.c:162 sequencer.c:774 sequencer.c:857
+#: sequencer.c:245 sequencer.c:869 sequencer.c:952
#, c-format
msgid "Could not write to %s"
msgstr "Konnte nicht nach %s schreiben"
-#: sequencer.c:165
+#: sequencer.c:248
#, c-format
msgid "Error wrapping up %s"
msgstr "Fehler bei Nachbereitung von %s"
-#: sequencer.c:180
+#: sequencer.c:263
msgid "Your local changes would be overwritten by cherry-pick."
msgstr ""
"Ihre lokalen Änderungen würden von \"cherry-pick\" überschrieben werden."
-#: sequencer.c:182
+#: sequencer.c:265
msgid "Your local changes would be overwritten by revert."
msgstr "Ihre lokalen Änderungen würden von \"revert\" überschrieben werden."
-#: sequencer.c:185
+#: sequencer.c:268
msgid "Commit your changes or stash them to proceed."
msgstr ""
"Tragen Sie Ihre Änderungen ein oder benutzen Sie \"stash\" um fortzufahren."
#. TRANSLATORS: %s will be "revert" or "cherry-pick"
-#: sequencer.c:236
+#: sequencer.c:324
#, c-format
msgid "%s: Unable to write new index file"
-msgstr "%s: Konnte neue Bereitstellungsdatei nicht schreiben"
+msgstr "%s: Konnte neue Staging-Area-Datei nicht schreiben"
-#: sequencer.c:267
+#: sequencer.c:355
msgid "Could not resolve HEAD commit\n"
-msgstr "Konnte Version der Zweigspitze (HEAD) nicht auflösen\n"
+msgstr "Konnte Commit von HEAD nicht auflösen\n"
-#: sequencer.c:288
+#: sequencer.c:377
msgid "Unable to update cache tree\n"
-msgstr "Konnte zwischengespeicherten Baum nicht aktualisieren\n"
+msgstr "Konnte Cache-Verzeichnis nicht aktualisieren\n"
-#: sequencer.c:333
+#: sequencer.c:422
#, c-format
msgid "Could not parse commit %s\n"
-msgstr "Konnte Version %s nicht parsen\n"
+msgstr "Konnte Commit %s nicht parsen\n"
-#: sequencer.c:338
+#: sequencer.c:427
#, c-format
msgid "Could not parse parent commit %s\n"
-msgstr "Konnte Elternversion %s nicht parsen\n"
+msgstr "Konnte Eltern-Commit %s nicht parsen\n"
-#: sequencer.c:404
+#: sequencer.c:493
msgid "Your index file is unmerged."
-msgstr "Ihre Bereitstellungsdatei ist nicht zusammengeführt."
+msgstr "Ihre Staging-Area-Datei ist nicht zusammengeführt."
-#: sequencer.c:423
+#: sequencer.c:512
#, c-format
msgid "Commit %s is a merge but no -m option was given."
-msgstr ""
-"Version %s ist eine Zusammenführung, aber die Option -m wurde nicht "
-"angegeben."
+msgstr "Commit %s ist ein Merge, aber die Option -m wurde nicht angegeben."
-#: sequencer.c:431
+#: sequencer.c:520
#, c-format
msgid "Commit %s does not have parent %d"
-msgstr "Version %s hat keinen Elternteil %d"
+msgstr "Commit %s hat keinen Elternteil %d"
-#: sequencer.c:435
+#: sequencer.c:524
#, c-format
msgid "Mainline was specified but commit %s is not a merge."
-msgstr ""
-"Hauptlinie wurde spezifiziert, aber Version %s ist keine Zusammenführung."
+msgstr "Hauptlinie wurde spezifiziert, aber Commit %s ist kein Merge."
#. TRANSLATORS: The first %s will be "revert" or
#. "cherry-pick", the second %s a SHA1
-#: sequencer.c:448
+#: sequencer.c:537
#, c-format
msgid "%s: cannot parse parent commit %s"
-msgstr "%s: kann Elternversion %s nicht parsen"
+msgstr "%s: kann Eltern-Commit %s nicht parsen"
-#: sequencer.c:452
+#: sequencer.c:541
#, c-format
msgid "Cannot get commit message for %s"
-msgstr "Kann keine Versionsbeschreibung für %s bekommen"
+msgstr "Kann keine Commit-Beschreibung für %s bekommen"
-#: sequencer.c:536
+#: sequencer.c:627
#, c-format
msgid "could not revert %s... %s"
-msgstr "Konnte %s nicht zurücksetzen... %s"
+msgstr "Konnte \"revert\" nicht auf %s ausführen... %s"
-#: sequencer.c:537
+#: sequencer.c:628
#, c-format
msgid "could not apply %s... %s"
msgstr "Konnte %s nicht anwenden... %s"
-#: sequencer.c:569
+#: sequencer.c:664
msgid "empty commit set passed"
-msgstr "leere Menge von Versionen übergeben"
+msgstr "leere Menge von Commits übergeben"
-#: sequencer.c:577
+#: sequencer.c:672
#, c-format
msgid "git %s: failed to read the index"
-msgstr "git %s: Fehler beim Lesen der Bereitstellung"
+msgstr "git %s: Fehler beim Lesen der Staging-Area"
-#: sequencer.c:582
+#: sequencer.c:677
#, c-format
msgid "git %s: failed to refresh the index"
-msgstr "git %s: Fehler beim Aktualisieren der Bereitstellung"
+msgstr "git %s: Fehler beim Aktualisieren der Staging-Area"
-#: sequencer.c:640
+#: sequencer.c:735
#, c-format
msgid "Cannot %s during a %s"
msgstr "Kann %s nicht während eines %s durchführen"
-#: sequencer.c:662
+#: sequencer.c:757
#, c-format
msgid "Could not parse line %d."
msgstr "Konnte Zeile %d nicht parsen."
-#: sequencer.c:667
+#: sequencer.c:762
msgid "No commits parsed."
-msgstr "Keine Versionen geparst."
+msgstr "Keine Commits geparst."
-#: sequencer.c:680
+#: sequencer.c:775
#, c-format
msgid "Could not open %s"
msgstr "Konnte %s nicht öffnen"
-#: sequencer.c:684
+#: sequencer.c:779
#, c-format
msgid "Could not read %s."
msgstr "Konnte %s nicht lesen."
-#: sequencer.c:691
+#: sequencer.c:786
#, c-format
msgid "Unusable instruction sheet: %s"
msgstr "Unbenutzbares Instruktionsblatt: %s"
-#: sequencer.c:719
+#: sequencer.c:814
#, c-format
msgid "Invalid key: %s"
msgstr "Ungültiger Schlüssel: %s"
-#: sequencer.c:722
+#: sequencer.c:817
#, c-format
msgid "Invalid value for %s: %s"
msgstr "Ungültiger Wert für %s: %s"
-#: sequencer.c:734
+#: sequencer.c:829
#, c-format
msgid "Malformed options sheet: %s"
msgstr "Fehlerhaftes Optionsblatt: %s"
-#: sequencer.c:755
+#: sequencer.c:850
msgid "a cherry-pick or revert is already in progress"
msgstr "\"cherry-pick\" oder \"revert\" ist bereits im Gang"
-#: sequencer.c:756
+#: sequencer.c:851
msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
msgstr "versuchen Sie \"git cherry-pick (--continue | --quit | --abort)\""
-#: sequencer.c:760
+#: sequencer.c:855
#, c-format
msgid "Could not create sequencer directory %s"
msgstr "Konnte \"sequencer\"-Verzeichnis %s nicht erstellen"
-#: sequencer.c:776 sequencer.c:861
+#: sequencer.c:871 sequencer.c:956
#, c-format
msgid "Error wrapping up %s."
msgstr "Fehler beim Einpacken von %s."
-#: sequencer.c:795 sequencer.c:929
+#: sequencer.c:890 sequencer.c:1024
msgid "no cherry-pick or revert in progress"
msgstr "kein \"cherry-pick\" oder \"revert\" im Gang"
-#: sequencer.c:797
+#: sequencer.c:892
msgid "cannot resolve HEAD"
-msgstr "kann Zweigspitze (HEAD) nicht auflösen"
+msgstr "kann HEAD nicht auflösen"
-#: sequencer.c:799
+#: sequencer.c:894
msgid "cannot abort from a branch yet to be born"
-msgstr "kann nicht abbrechen: bin auf einem Zweig, der noch geboren wird"
+msgstr "kann nicht abbrechen: bin auf einem Branch, der noch geboren wird"
-#: sequencer.c:821 builtin/apply.c:4056
+#: sequencer.c:916 builtin/apply.c:4061
#, c-format
msgid "cannot open %s: %s"
msgstr "Kann %s nicht öffnen: %s"
-#: sequencer.c:824
+#: sequencer.c:919
#, c-format
msgid "cannot read %s: %s"
msgstr "Kann %s nicht lesen: %s"
-#: sequencer.c:825
+#: sequencer.c:920
msgid "unexpected end of file"
msgstr "Unerwartetes Dateiende"
-#: sequencer.c:831
+#: sequencer.c:926
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
-msgstr ""
-"gespeicherte \"pre-cherry-pick\" Datei der Zweigspitze (HEAD) '%s' ist "
-"beschädigt"
+msgstr "gespeicherte \"pre-cherry-pick\" HEAD Datei '%s' ist beschädigt"
-#: sequencer.c:854
+#: sequencer.c:949
#, c-format
msgid "Could not format %s."
msgstr "Konnte %s nicht formatieren."
-#: sequencer.c:1016
+#: sequencer.c:1092
+#, c-format
+msgid "%s: can't cherry-pick a %s"
+msgstr "%s: %s kann nicht in \"cherry-pick\" benutzt werden"
+
+#: sequencer.c:1095
+#, c-format
+msgid "%s: bad revision"
+msgstr "%s: ungültiger Commit"
+
+#: sequencer.c:1129
msgid "Can't revert as initial commit"
-msgstr "Kann nicht zu initialer Version zurücksetzen."
+msgstr "Kann nicht als allerersten Commit einen Revert ausführen."
-#: sequencer.c:1017
+#: sequencer.c:1130
msgid "Can't cherry-pick into empty head"
-msgstr "Kann \"cherry-pick\" nicht in einem leerem Kopf ausführen."
+msgstr "Kann nicht als allerersten Commit einen Cherry-Pick ausführen."
-#: sha1_name.c:1044
+#: sha1_name.c:440
+msgid ""
+"Git normally never creates a ref that ends with 40 hex characters\n"
+"because it will be ignored when you just specify 40-hex. These refs\n"
+"may be created by mistake. For example,\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
+"examine these refs and maybe delete them. Turn this message off by\n"
+"running \"git config advice.objectNameWarning false\""
+msgstr ""
+"Git erzeugt normalerweise keine Referenzen die mit\n"
+"40 Hex-Zeichen enden, da diese ignoriert werden wenn\n"
+"Sie diese angeben. Diese Referenzen könnten aus Versehen\n"
+"erzeugt worden sein. Zum Beispiel,\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"wobei \"$br\" leer ist und eine 40-Hex-Referenz erzeugt\n"
+"wurde. Bitte prüfen Sie diese Referenzen und löschen\n"
+"Sie sie gegebenenfalls. Unterdrücken Sie diese Meldung\n"
+"indem Sie \"git config advice.objectNameWarning false\"\n"
+"ausführen."
+
+#: sha1_name.c:1097
msgid "HEAD does not point to a branch"
-msgstr "Zweigspitze (HEAD) zeigt auf keinen Zweig"
+msgstr "HEAD zeigt auf keinen Branch"
-#: sha1_name.c:1047
+#: sha1_name.c:1100
#, c-format
msgid "No such branch: '%s'"
-msgstr "Kein solcher Zweig '%s'"
+msgstr "Kein solcher Branch '%s'"
-#: sha1_name.c:1049
+#: sha1_name.c:1102
#, c-format
msgid "No upstream configured for branch '%s'"
-msgstr "Kein entferntes Projektarchiv für Zweig '%s' konfiguriert."
+msgstr "Kein Upstream-Branch für Branch '%s' konfiguriert."
-#: sha1_name.c:1052
+#: sha1_name.c:1106
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
-msgstr ""
-"Zweig '%s' des entfernten Projektarchivs ist kein gefolgter Ãœbernahmezweig"
+msgstr "Upstream-Branch '%s' ist nicht als Remote-Tracking-Branch gespeichert"
#: wrapper.c:408
#, c-format
msgid "unable to access '%s': %s"
msgstr "konnte nicht auf '%s' zugreifen: %s"
-#: wrapper.c:423
+#: wrapper.c:429
#, c-format
msgid "unable to access '%s'"
msgstr "konnte nicht auf '%s' zugreifen"
-#: wrapper.c:434
+#: wrapper.c:440
#, c-format
msgid "unable to look up current user in the passwd file: %s"
msgstr "konnte aktuellen Benutzer nicht in Passwort-Datei finden: %s"
-#: wrapper.c:435
+#: wrapper.c:441
msgid "no such user"
msgstr "kein solcher Benutzer"
-#: wt-status.c:140
+#: wt-status.c:141
msgid "Unmerged paths:"
msgstr "Nicht zusammengeführte Pfade:"
-#: wt-status.c:167 wt-status.c:194
+#: wt-status.c:168 wt-status.c:195
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr ""
-" (benutzen Sie \"git reset %s <Datei>...\" zum Herausnehmen aus der "
-"Bereitstellung)"
+" (benutzen Sie \"git reset %s <Datei>...\" zum Entfernen aus der Staging-"
+"Area)"
-#: wt-status.c:169 wt-status.c:196
+#: wt-status.c:170 wt-status.c:197
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr ""
-" (benutzen Sie \"git rm --cached <Datei>...\" zum Herausnehmen aus der "
-"Bereitstellung)"
+" (benutzen Sie \"git rm --cached <Datei>...\" zum Entfernen aus der Staging-"
+"Area)"
-#: wt-status.c:173
+#: wt-status.c:174
msgid " (use \"git add <file>...\" to mark resolution)"
msgstr ""
" (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
-#: wt-status.c:175 wt-status.c:179
+#: wt-status.c:176 wt-status.c:180
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr ""
" (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung entsprechend zu "
"markieren)"
-#: wt-status.c:177
+#: wt-status.c:178
msgid " (use \"git rm <file>...\" to mark resolution)"
msgstr ""
" (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
-#: wt-status.c:188
+#: wt-status.c:189
msgid "Changes to be committed:"
-msgstr "zum Eintragen bereitgestellte Änderungen:"
+msgstr "zum Commit vorgemerkte Änderungen:"
-#: wt-status.c:206
+#: wt-status.c:207
msgid "Changes not staged for commit:"
-msgstr "Änderungen, die nicht zum Eintragen bereitgestellt sind:"
+msgstr "Änderungen, die nicht zum Commit vorgemerkt sind:"
-#: wt-status.c:210
+#: wt-status.c:211
msgid " (use \"git add <file>...\" to update what will be committed)"
-msgstr " (benutzen Sie \"git add <Datei>...\" zum Bereitstellen)"
+msgstr ""
+" (benutzen Sie \"git add <Datei>...\" um die Änderungen zum Commit "
+"vorzumerken)"
-#: wt-status.c:212
+#: wt-status.c:213
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
-msgstr " (benutzen Sie \"git add/rm <Datei>...\" zum Bereitstellen)"
+msgstr ""
+" (benutzen Sie \"git add/rm <Datei>...\" um die Änderungen zum Commit "
+"vorzumerken)"
-#: wt-status.c:213
+#: wt-status.c:214
msgid ""
" (use \"git checkout -- <file>...\" to discard changes in working directory)"
msgstr ""
" (benutzen Sie \"git checkout -- <Datei>...\" um die Änderungen im "
"Arbeitsverzeichnis zu verwerfen)"
-#: wt-status.c:215
+#: wt-status.c:216
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr ""
-" (tragen Sie ein oder verwerfen Sie den unbeobachteten oder geänderten "
-"Inhalt in den Unterprojekten)"
+" (committen oder verwerfen Sie den unbeobachteten oder geänderten Inhalt in "
+"den Submodulen)"
-#: wt-status.c:227
+#: wt-status.c:228
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
-msgstr " (benutzen Sie \"git %s <Datei>...\" zum Einfügen in die Eintragung)"
+msgstr ""
+" (benutzen Sie \"git %s <Datei>...\" um die Änderungen zum Commit "
+"vorzumerken)"
-#: wt-status.c:244
+#: wt-status.c:245
msgid "bug"
msgstr "Fehler"
-#: wt-status.c:249
+#: wt-status.c:250
msgid "both deleted:"
msgstr "beide gelöscht:"
-#: wt-status.c:250
+#: wt-status.c:251
msgid "added by us:"
msgstr "von uns hinzugefügt:"
-#: wt-status.c:251
+#: wt-status.c:252
msgid "deleted by them:"
msgstr "von denen gelöscht:"
-#: wt-status.c:252
+#: wt-status.c:253
msgid "added by them:"
msgstr "von denen hinzugefügt:"
-#: wt-status.c:253
+#: wt-status.c:254
msgid "deleted by us:"
msgstr "von uns gelöscht:"
-#: wt-status.c:254
+#: wt-status.c:255
msgid "both added:"
msgstr "von beiden hinzugefügt:"
-#: wt-status.c:255
+#: wt-status.c:256
msgid "both modified:"
msgstr "von beiden geändert:"
-#: wt-status.c:285
+#: wt-status.c:286
msgid "new commits, "
-msgstr "neue Versionen, "
+msgstr "neue Commits, "
-#: wt-status.c:287
+#: wt-status.c:288
msgid "modified content, "
msgstr "geänderter Inhalt, "
-#: wt-status.c:289
+#: wt-status.c:290
msgid "untracked content, "
msgstr "unbeobachteter Inhalt, "
-#: wt-status.c:303
+#: wt-status.c:307
#, c-format
msgid "new file: %s"
msgstr "neue Datei: %s"
-#: wt-status.c:306
+#: wt-status.c:310
#, c-format
msgid "copied: %s -> %s"
msgstr "kopiert: %s -> %s"
-#: wt-status.c:309
+#: wt-status.c:313
#, c-format
msgid "deleted: %s"
msgstr "gelöscht: %s"
-#: wt-status.c:312
+#: wt-status.c:316
#, c-format
msgid "modified: %s"
msgstr "geändert: %s"
-#: wt-status.c:315
+#: wt-status.c:319
#, c-format
msgid "renamed: %s -> %s"
msgstr "umbenannt: %s -> %s"
-#: wt-status.c:318
+#: wt-status.c:322
#, c-format
msgid "typechange: %s"
msgstr "Typänderung: %s"
-#: wt-status.c:321
+#: wt-status.c:325
#, c-format
msgid "unknown: %s"
msgstr "unbekannt: %s"
-#: wt-status.c:324
+#: wt-status.c:328
#, c-format
msgid "unmerged: %s"
msgstr "nicht zusammengeführt: %s"
-#: wt-status.c:327
+#: wt-status.c:331
#, c-format
msgid "bug: unhandled diff status %c"
msgstr "Fehler: unbehandelter Differenz-Status %c"
-#: wt-status.c:789
+#: wt-status.c:803
msgid "You have unmerged paths."
msgstr "Sie haben nicht zusammengeführte Pfade."
-#: wt-status.c:792 wt-status.c:944
+#: wt-status.c:806
msgid " (fix conflicts and run \"git commit\")"
msgstr " (beheben Sie die Konflikte und führen Sie \"git commit\" aus)"
-#: wt-status.c:795
+#: wt-status.c:809
msgid "All conflicts fixed but you are still merging."
-msgstr ""
-"Alle Konflikte sind behoben, aber Sie sind immer noch beim Zusammenführen."
+msgstr "Alle Konflikte sind behoben, aber Sie sind immer noch beim Merge."
-#: wt-status.c:798
+#: wt-status.c:812
msgid " (use \"git commit\" to conclude merge)"
-msgstr " (benutzen Sie \"git commit\" um die Zusammenführung abzuschließen)"
+msgstr " (benutzen Sie \"git commit\" um den Merge abzuschließen)"
-#: wt-status.c:808
+#: wt-status.c:822
msgid "You are in the middle of an am session."
msgstr "Eine \"am\"-Sitzung ist im Gange."
-#: wt-status.c:811
+#: wt-status.c:825
msgid "The current patch is empty."
msgstr "Der aktuelle Patch ist leer."
-#: wt-status.c:815
-msgid " (fix conflicts and then run \"git am --resolved\")"
+#: wt-status.c:829
+msgid " (fix conflicts and then run \"git am --continue\")"
msgstr ""
-" (beheben Sie die Konflikte und führen Sie dann \"git am --resolved\" aus)"
+" (beheben Sie die Konflikte und führen Sie dann \"git am --continue\" aus)"
-#: wt-status.c:817
+#: wt-status.c:831
msgid " (use \"git am --skip\" to skip this patch)"
-msgstr " (benutzen Sie \"git am --skip\" um diesen Patch auszulassen)"
+msgstr " (benutzen Sie \"git am --skip\" um diesen Patch auszulassen)"
-#: wt-status.c:819
+#: wt-status.c:833
msgid " (use \"git am --abort\" to restore the original branch)"
msgstr ""
-" (benutzen Sie \"git am --abort\" um den ursprünglichen Zweig "
+" (benutzen Sie \"git am --abort\" um den ursprünglichen Branch "
"wiederherzustellen)"
-#: wt-status.c:879 wt-status.c:896
+#: wt-status.c:893 wt-status.c:910
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
-msgstr "Sie sind gerade beim Neuaufbau von Zweig '%s' auf '%s'."
+msgstr "Sie sind gerade beim Rebase von Branch '%s' auf '%s'."
-#: wt-status.c:884 wt-status.c:901
+#: wt-status.c:898 wt-status.c:915
msgid "You are currently rebasing."
-msgstr "Sie sind gerade beim Neuaufbau."
+msgstr "Sie sind gerade beim Rebase."
-#: wt-status.c:887
+#: wt-status.c:901
msgid " (fix conflicts and then run \"git rebase --continue\")"
msgstr ""
" (beheben Sie die Konflikte und führen Sie dann \"git rebase --continue\" "
"aus)"
-#: wt-status.c:889
+#: wt-status.c:903
msgid " (use \"git rebase --skip\" to skip this patch)"
msgstr " (benutzen Sie \"git rebase --skip\" um diesen Patch auszulassen)"
-#: wt-status.c:891
+#: wt-status.c:905
msgid " (use \"git rebase --abort\" to check out the original branch)"
msgstr ""
-" (benutzen Sie \"git rebase --abort\" um den ursprünglichen Zweig "
+" (benutzen Sie \"git rebase --abort\" um den ursprünglichen Branch "
"auszuchecken)"
-#: wt-status.c:904
+#: wt-status.c:918
msgid " (all conflicts fixed: run \"git rebase --continue\")"
msgstr " (alle Konflikte behoben: führen Sie \"git rebase --continue\" aus)"
-#: wt-status.c:908
+#: wt-status.c:922
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
msgstr ""
-"Sie teilen gerade eine Version auf, während ein Neuaufbau von Zweig '%s' auf "
+"Sie teilen gerade einen Commit auf, während ein Rebase von Branch '%s' auf "
"'%s' im Gange ist."
-#: wt-status.c:913
+#: wt-status.c:927
msgid "You are currently splitting a commit during a rebase."
-msgstr "Sie teilen gerade eine Version während eines Neuaufbaus auf."
+msgstr "Sie teilen gerade einen Commit während eines Rebase auf."
-#: wt-status.c:916
+#: wt-status.c:930
msgid " (Once your working directory is clean, run \"git rebase --continue\")"
msgstr ""
-" (Sobald Ihr Arbeitsverzeichnis sauber ist, führen Sie \"git rebase --"
+" (Sobald Ihr Arbeitsverzeichnis unverändert ist, führen Sie \"git rebase --"
"continue\" aus)"
-#: wt-status.c:920
+#: wt-status.c:934
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr ""
-"Sie editieren gerade eine Version während eines Neuaufbaus von Zweig '%s' "
-"auf '%s'."
+"Sie editieren gerade einen Commit während eines Rebase von Branch '%s' auf "
+"'%s'."
-#: wt-status.c:925
+#: wt-status.c:939
msgid "You are currently editing a commit during a rebase."
-msgstr "Sie editieren gerade eine Version während eines Neuaufbaus."
+msgstr "Sie editieren gerade einen Commit während eines Rebase."
-#: wt-status.c:928
+#: wt-status.c:942
msgid " (use \"git commit --amend\" to amend the current commit)"
msgstr ""
-" (benutzen Sie \"git commit --amend\" um die aktuelle Version nachzubessern)"
+" (benutzen Sie \"git commit --amend\" um den aktuellen Commit nachzubessern)"
-#: wt-status.c:930
+#: wt-status.c:944
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
msgstr ""
" (benutzen Sie \"git rebase --continue\" sobald Ihre Änderungen "
"abgeschlossen sind)"
-#: wt-status.c:940
+#: wt-status.c:954
msgid "You are currently cherry-picking."
msgstr "Sie führen gerade \"cherry-pick\" aus."
-#: wt-status.c:947
-msgid " (all conflicts fixed: run \"git commit\")"
-msgstr " (alle Konflikte behoben: führen Sie \"git commit\" aus)"
-
#: wt-status.c:958
+msgid " (fix conflicts and run \"git cherry-pick --continue\")"
+msgstr ""
+" (beheben Sie die Konflikte und führen Sie dann \"git cherry-pick --continue"
+"\" aus)"
+
+#: wt-status.c:961
+msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
+msgstr ""
+" (alle Konflikte behoben: führen Sie \"git cherry-pick --continue\" aus)"
+
+#: wt-status.c:963
+msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
+msgstr ""
+" (benutzen Sie \"git cherry-pick --abort\" um die Cherry-Pick-Operation "
+"abzubrechen)"
+
+#: wt-status.c:972
+#, c-format
+msgid "You are currently reverting commit %s."
+msgstr "Sie sind gerade an einem Revert von Commit '%s'."
+
+#: wt-status.c:977
+msgid " (fix conflicts and run \"git revert --continue\")"
+msgstr ""
+" (beheben Sie die Konflikte und führen Sie dann \"git revert --continue\" "
+"aus)"
+
+#: wt-status.c:980
+msgid " (all conflicts fixed: run \"git revert --continue\")"
+msgstr " (alle Konflikte behoben: führen Sie \"git revert --continue\" aus)"
+
+#: wt-status.c:982
+msgid " (use \"git revert --abort\" to cancel the revert operation)"
+msgstr ""
+" (benutzen Sie \"git revert --abort\" um die Revert-Operation abzubrechen)"
+
+#: wt-status.c:993
#, c-format
-msgid "You are currently bisecting branch '%s'."
-msgstr "Sie sind gerade bei einer binären Suche in Zweig '%s'."
+msgid "You are currently bisecting, started from branch '%s'."
+msgstr "Sie sind gerade bei einer binären Suche, gestartet von Branch '%s'."
-#: wt-status.c:962
+#: wt-status.c:997
msgid "You are currently bisecting."
msgstr "Sie sind gerade bei einer binären Suche."
-#: wt-status.c:965
+#: wt-status.c:1000
msgid " (use \"git bisect reset\" to get back to the original branch)"
msgstr ""
-" (benutzen Sie \"git bisect reset\" um zum ursprünglichen Zweig "
+" (benutzen Sie \"git bisect reset\" um zum ursprünglichen Branch "
"zurückzukehren)"
-#: wt-status.c:1064
+#: wt-status.c:1173
msgid "On branch "
-msgstr "Auf Zweig "
+msgstr "Auf Branch "
+
+#: wt-status.c:1180
+msgid "rebase in progress; onto "
+msgstr "Rebase im Gange; auf "
-#: wt-status.c:1071
+#: wt-status.c:1187
+msgid "HEAD detached at "
+msgstr "HEAD losgelöst bei "
+
+#: wt-status.c:1189
+msgid "HEAD detached from "
+msgstr "HEAD losgelöst von "
+
+#: wt-status.c:1192
msgid "Not currently on any branch."
-msgstr "Im Moment auf keinem Zweig."
+msgstr "Im Moment auf keinem Branch."
-#: wt-status.c:1083
+#: wt-status.c:1209
msgid "Initial commit"
-msgstr "Initiale Version"
+msgstr "Initialer Commit"
-#: wt-status.c:1097
+#: wt-status.c:1223
msgid "Untracked files"
msgstr "Unbeobachtete Dateien"
-#: wt-status.c:1099
+#: wt-status.c:1225
msgid "Ignored files"
msgstr "Ignorierte Dateien"
-#: wt-status.c:1101
+#: wt-status.c:1229
+#, c-format
+msgid ""
+"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
+"may speed it up, but you have to be careful not to forget to add\n"
+"new files yourself (see 'git help status')."
+msgstr ""
+"Es dauerte %.2f Sekunden die unbeobachteten Dateien zu bestimmen.\n"
+"'status -uno' könnte das beschleunigen, aber Sie müssen darauf achten,\n"
+"neue Dateien selbstständig hinzuzufügen (siehe 'git help status')."
+
+#: wt-status.c:1235
#, c-format
msgid "Untracked files not listed%s"
msgstr "Unbeobachtete Dateien nicht aufgelistet%s"
-#: wt-status.c:1103
+#: wt-status.c:1237
msgid " (use -u option to show untracked files)"
msgstr " (benutzen Sie die Option -u um unbeobachteten Dateien anzuzeigen)"
-#: wt-status.c:1109
+#: wt-status.c:1243
msgid "No changes"
msgstr "Keine Änderungen"
-#: wt-status.c:1114
+#: wt-status.c:1248
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr ""
-"keine Änderungen zum Eintragen hinzugefügt (benutzen Sie \"git add\" und/"
-"oder \"git commit -a\")\n"
+"keine Änderungen zum Commit vorgemerkt (benutzen Sie \"git add\" und/oder "
+"\"git commit -a\")\n"
-#: wt-status.c:1117
+#: wt-status.c:1251
#, c-format
msgid "no changes added to commit\n"
-msgstr "keine Änderungen zum Eintragen hinzugefügt\n"
+msgstr "keine Änderungen zum Commit vorgemerkt\n"
-#: wt-status.c:1120
+#: wt-status.c:1254
#, c-format
msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
"track)\n"
msgstr ""
-"nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien "
-"(benutzen Sie \"git add\" zum Beobachten)\n"
+"nichts zum Commit vorgemerkt, aber es gibt unbeobachtete Dateien (benutzen "
+"Sie \"git add\" zum Beobachten)\n"
-#: wt-status.c:1123
+#: wt-status.c:1257
#, c-format
msgid "nothing added to commit but untracked files present\n"
-msgstr "nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien\n"
+msgstr "nichts zum Commit vorgemerkt, aber es gibt unbeobachtete Dateien\n"
-#: wt-status.c:1126
+#: wt-status.c:1260
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
msgstr ""
-"nichts einzutragen (Erstellen/Kopieren Sie Dateien und benutzen Sie \"git add"
-"\" zum Beobachten)\n"
+"nichts zu committen (Erstellen/Kopieren Sie Dateien und benutzen Sie \"git "
+"add\" zum Beobachten)\n"
-#: wt-status.c:1129 wt-status.c:1134
+#: wt-status.c:1263 wt-status.c:1268
#, c-format
msgid "nothing to commit\n"
-msgstr "nichts einzutragen\n"
+msgstr "nichts zu committen\n"
-#: wt-status.c:1132
+#: wt-status.c:1266
#, c-format
msgid "nothing to commit (use -u to show untracked files)\n"
msgstr ""
-"nichts einzutragen (benutzen Sie die Option -u, um unbeobachtete Dateien "
+"nichts zu committen (benutzen Sie die Option -u, um unbeobachtete Dateien "
"anzuzeigen)\n"
-#: wt-status.c:1136
+#: wt-status.c:1270
#, c-format
msgid "nothing to commit, working directory clean\n"
-msgstr "nichts einzutragen, Arbeitsverzeichnis sauber\n"
+msgstr "nichts zu committen, Arbeitsverzeichnis unverändert\n"
-#: wt-status.c:1244
+#: wt-status.c:1378
msgid "HEAD (no branch)"
-msgstr "HEAD (kein Zweig)"
+msgstr "HEAD (kein Branch)"
-#: wt-status.c:1250
+#: wt-status.c:1384
msgid "Initial commit on "
-msgstr "Initiale Version auf "
+msgstr "Initialer Commit auf "
-#: wt-status.c:1265
+#: wt-status.c:1399
msgid "behind "
msgstr "hinterher "
-#: wt-status.c:1268 wt-status.c:1271
+#: wt-status.c:1402 wt-status.c:1405
msgid "ahead "
msgstr "voraus "
-#: wt-status.c:1273
+#: wt-status.c:1407
msgid ", behind "
msgstr ", hinterher "
-#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#: compat/precompose_utf8.c:58 builtin/clone.c:351
#, c-format
msgid "failed to unlink '%s'"
msgstr "Konnte '%s' nicht entfernen."
@@ -1475,203 +1736,235 @@ msgstr "Konnte '%s' nicht entfernen."
msgid "git add [options] [--] <pathspec>..."
msgstr "git add [Optionen] [--] [<Pfadspezifikation>...]"
-#: builtin/add.c:63
+#.
+#. * To be consistent with "git add -p" and most Git
+#. * commands, we should default to being tree-wide, but
+#. * this is not the original behavior and can't be
+#. * changed until users trained themselves not to type
+#. * "git add -u" or "git add -A". For now, we warn and
+#. * keep the old behavior. Later, the behavior can be changed
+#. * to tree-wide, keeping the warning for a while, and
+#. * eventually we can drop the warning.
+#.
+#: builtin/add.c:58
+#, c-format
+msgid ""
+"The behavior of 'git add %s (or %s)' with no path argument from a\n"
+"subdirectory of the tree will change in Git 2.0 and should not be used "
+"anymore.\n"
+"To add content for the whole tree, run:\n"
+"\n"
+" git add %s :/\n"
+" (or git add %s :/)\n"
+"\n"
+"To restrict the command to the current directory, run:\n"
+"\n"
+" git add %s .\n"
+" (or git add %s .)\n"
+"\n"
+"With the current Git version, the command is restricted to the current "
+"directory.\n"
+msgstr ""
+"Das Verhalten von 'git add %s (oder %s)' ohne ein Pfad-Argument von\n"
+"einem Unterverzeichnis aus wird in Git 2.0 geändert und sollte nicht\n"
+"mehr verwendet werden.\n"
+"Um Dateien des gesamten Projektverzeichnisses hinzuzufügen, führen Sie aus:\n"
+"\n"
+" git add %s :/\n"
+" (oder git add %s :/)\n"
+"\n"
+"Zur Einschränkung auf das aktuelle Verzeichnis führen Sie aus:\n"
+"\n"
+" git add %s .\n"
+" (oder git add %s .)\n"
+"\n"
+"Mit der aktuellen Version von Git ist das Kommando auf das aktuelle\n"
+"Verzeichnis beschränkt.\n"
+
+#: builtin/add.c:100
+#, c-format
+msgid ""
+"You ran 'git add' with neither '-A (--all)' or '--ignore-removal',\n"
+"whose behaviour will change in Git 2.0 with respect to paths you removed.\n"
+"Paths like '%s' that are\n"
+"removed from your working tree are ignored with this version of Git.\n"
+"\n"
+"* 'git add --ignore-removal <pathspec>', which is the current default,\n"
+" ignores paths you removed from your working tree.\n"
+"\n"
+"* 'git add --all <pathspec>' will let you also record the removals.\n"
+"\n"
+"Run 'git status' to check the paths you removed from your working tree.\n"
+msgstr ""
+"Sie haben 'git add' weder mit '-A (--all)' noch mit '--ignore-removal'\n"
+"ausgeführt. Das Verhalten des Kommandos ändert sich in Git 2.0 durch\n"
+"Berücksichtigung der gelöschten Pfade.\n"
+"Pfade wie '%s', die im Arbeitsverzeichnis gelöscht wurden, werden in\n"
+"dieser Version von Git ignoriert.\n"
+"\n"
+"* 'git add --ignore-removal <Pfadspezifikation>', was der aktuelle\n"
+" Standardwert ist, ignoriert gelöschte Pfade im Arbeitsverzeichnis.\n"
+"* 'git add --all <Pfadspezifikation>' berücksichtigt ebenfalls gelöschte\n"
+" Pfade.\n"
+"Führen Sie 'git status' aus, um die gelöschten Pfade zu überprüfen.\n"
+
+#: builtin/add.c:144
#, c-format
msgid "unexpected diff status %c"
msgstr "unerwarteter Differenz-Status %c"
-#: builtin/add.c:68 builtin/commit.c:231
+#: builtin/add.c:149 builtin/commit.c:252
msgid "updating files failed"
msgstr "Aktualisierung der Dateien fehlgeschlagen"
-#: builtin/add.c:78
+#: builtin/add.c:163
#, c-format
msgid "remove '%s'\n"
msgstr "lösche '%s'\n"
-#: builtin/add.c:148
+#: builtin/add.c:253
msgid "Unstaged changes after refreshing the index:"
msgstr ""
-"Nicht bereitgestellte Änderungen nach Aktualisierung der Bereitstellung:"
+"Nicht zum Commit vorgemerkte Änderungen nach Aktualisierung der Staging-Area:"
-#: builtin/add.c:151 builtin/add.c:460 builtin/rm.c:275
+#: builtin/add.c:256 builtin/add.c:573 builtin/rm.c:337
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "Pfadspezifikation '%s' stimmt mit keinen Dateien überein"
-#: builtin/add.c:234
+#: builtin/add.c:339
msgid "Could not read the index"
-msgstr "Konnte die Bereitstellung nicht lesen"
+msgstr "Konnte die Staging-Area nicht lesen"
-#: builtin/add.c:244
+#: builtin/add.c:350
#, c-format
msgid "Could not open '%s' for writing."
msgstr "Konnte '%s' nicht zum Schreiben öffnen."
-#: builtin/add.c:248
+#: builtin/add.c:354
msgid "Could not write patch"
msgstr "Konnte Patch nicht schreiben"
-#: builtin/add.c:253
+#: builtin/add.c:359
#, c-format
msgid "Could not stat '%s'"
msgstr "Konnte Verzeichnis '%s' nicht lesen"
-#: builtin/add.c:255
+#: builtin/add.c:361
msgid "Empty patch. Aborted."
msgstr "Leerer Patch. Abgebrochen."
-#: builtin/add.c:261
+#: builtin/add.c:367
#, c-format
msgid "Could not apply '%s'"
msgstr "Konnte '%s' nicht anwenden."
-#: builtin/add.c:271
+#: builtin/add.c:377
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr ""
"Die folgenden Pfade werden durch eine Ihrer \".gitignore\" Dateien "
"ignoriert:\n"
-#: builtin/add.c:277 builtin/clean.c:161 builtin/fetch.c:78 builtin/mv.c:63
-#: builtin/prune-packed.c:76 builtin/push.c:425 builtin/remote.c:1253
-#: builtin/rm.c:206
+#: builtin/add.c:394 builtin/clean.c:875 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:73 builtin/push.c:451 builtin/remote.c:1253
+#: builtin/rm.c:268
msgid "dry run"
msgstr "Probelauf"
-#: builtin/add.c:278 builtin/apply.c:4405 builtin/check-ignore.c:19
-#: builtin/commit.c:1150 builtin/count-objects.c:82 builtin/fsck.c:613
-#: builtin/log.c:1522 builtin/mv.c:62 builtin/read-tree.c:112
+#: builtin/add.c:395 builtin/apply.c:4410 builtin/check-ignore.c:19
+#: builtin/commit.c:1220 builtin/count-objects.c:95 builtin/fsck.c:613
+#: builtin/log.c:1573 builtin/mv.c:62 builtin/read-tree.c:113
msgid "be verbose"
msgstr "erweiterte Ausgaben"
-#: builtin/add.c:280
+#: builtin/add.c:397
msgid "interactive picking"
msgstr "interaktives Auswählen"
-#: builtin/add.c:281 builtin/checkout.c:1031 builtin/reset.c:258
+#: builtin/add.c:398 builtin/checkout.c:1073 builtin/reset.c:261
msgid "select hunks interactively"
-msgstr "interaktiv Bereiche auswählen"
+msgstr "Blöcke interaktiv auswählen"
-#: builtin/add.c:282
+#: builtin/add.c:399
msgid "edit current diff and apply"
msgstr "aktuelle Unterschiede editieren und anwenden"
-#: builtin/add.c:283
+#: builtin/add.c:400
msgid "allow adding otherwise ignored files"
msgstr "erlaubt das Hinzufügen andernfalls ignorierter Dateien"
-#: builtin/add.c:284
+#: builtin/add.c:401
msgid "update tracked files"
msgstr "aktualisiert beobachtete Dateien"
-#: builtin/add.c:285
+#: builtin/add.c:402
msgid "record only the fact that the path will be added later"
msgstr "speichert nur, dass der Pfad später hinzugefügt werden soll"
-#: builtin/add.c:286
+#: builtin/add.c:403
msgid "add changes from all tracked and untracked files"
msgstr ""
"fügt Änderungen von allen beobachteten und unbeobachteten Dateien hinzu"
-#: builtin/add.c:287
+#. takes no arguments
+#: builtin/add.c:406
+msgid "ignore paths removed in the working tree (same as --no-all)"
+msgstr "ignoriert gelöschte Pfade im Arbeitsverzeichnis (genau wie --no-all)"
+
+#: builtin/add.c:408
msgid "don't add, only refresh the index"
-msgstr "fügt nichts hinzu, aktualisiert nur die Bereitstellung"
+msgstr "fügt nichts hinzu, aktualisiert nur die Staging-Area"
-#: builtin/add.c:288
+#: builtin/add.c:409
msgid "just skip files which cannot be added because of errors"
msgstr ""
"überspringt Dateien, die aufgrund von Fehlern nicht hinzugefügt werden "
"konnten"
-#: builtin/add.c:289
+#: builtin/add.c:410
msgid "check if - even missing - files are ignored in dry run"
msgstr "prüft ob - auch fehlende - Dateien im Probelauf ignoriert werden"
-#: builtin/add.c:311
+#: builtin/add.c:432
#, c-format
msgid "Use -f if you really want to add them.\n"
msgstr "Verwenden Sie -f wenn Sie diese wirklich hinzufügen möchten.\n"
-#: builtin/add.c:312
+#: builtin/add.c:433
msgid "no files added"
msgstr "keine Dateien hinzugefügt"
-#: builtin/add.c:318
+#: builtin/add.c:439
msgid "adding files failed"
msgstr "Hinzufügen von Dateien fehlgeschlagen"
-#.
-#. * To be consistent with "git add -p" and most Git
-#. * commands, we should default to being tree-wide, but
-#. * this is not the original behavior and can't be
-#. * changed until users trained themselves not to type
-#. * "git add -u" or "git add -A". For now, we warn and
-#. * keep the old behavior. Later, this warning can be
-#. * turned into a die(...), and eventually we may
-#. * reallow the command with a new behavior.
-#.
-#: builtin/add.c:335
-#, c-format
-msgid ""
-"The behavior of 'git add %s (or %s)' with no path argument from a\n"
-"subdirectory of the tree will change in Git 2.0 and should not be used "
-"anymore.\n"
-"To add content for the whole tree, run:\n"
-"\n"
-" git add %s :/\n"
-" (or git add %s :/)\n"
-"\n"
-"To restrict the command to the current directory, run:\n"
-"\n"
-" git add %s .\n"
-" (or git add %s .)\n"
-"\n"
-"With the current Git version, the command is restricted to the current "
-"directory."
-msgstr ""
-"Das Verhalten von 'git add %s (oder %s)' ohne ein Pfad-Argument von\n"
-"einem Unterverzeichnis aus wird in Git 2.0 geändert und sollte nicht\n"
-"mehr verwendet werden.\n"
-"Um Dateien des gesamten Projektverzeichnisses hinzuzufügen, führen Sie aus:\n"
-"\n"
-" git add %s :/\n"
-" (oder git add %s :/)\n"
-"\n"
-"Zur Einschränkung auf das aktuelle Verzeichnis führen Sie aus:\n"
-"\n"
-" git add %s .\n"
-" (oder git add %s .)\n"
-"\n"
-"Mit der aktuellen Version von Git ist das Kommando auf das aktuelle\n"
-"Verzeichnis beschränkt."
-
-#: builtin/add.c:381
+#: builtin/add.c:478
msgid "-A and -u are mutually incompatible"
msgstr "Die Optionen -A und -u sind zueinander inkompatibel."
-#: builtin/add.c:383
+#: builtin/add.c:496
msgid "Option --ignore-missing can only be used together with --dry-run"
msgstr ""
"Die Option --ignore-missing kann nur zusammen mit --dry-run verwendet werden."
-#: builtin/add.c:414
+#: builtin/add.c:526
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr "Nichts spezifiziert, nichts hinzugefügt.\n"
-#: builtin/add.c:415
+#: builtin/add.c:527
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "Wollten Sie vielleicht 'git add .' sagen?\n"
-#: builtin/add.c:421 builtin/check-ignore.c:67 builtin/clean.c:204
-#: builtin/commit.c:291 builtin/mv.c:82 builtin/rm.c:235
+#: builtin/add.c:533 builtin/check-ignore.c:161 builtin/clean.c:919
+#: builtin/commit.c:312 builtin/mv.c:82 builtin/rm.c:297
msgid "index file corrupt"
-msgstr "Bereitstellungsdatei beschädigt"
+msgstr "Staging-Area-Datei beschädigt"
-#: builtin/add.c:481 builtin/apply.c:4501 builtin/mv.c:229 builtin/rm.c:370
+#: builtin/add.c:605 builtin/apply.c:4506 builtin/mv.c:229 builtin/rm.c:432
msgid "Unable to write new index file"
-msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
+msgstr "Konnte neue Staging-Area-Datei nicht schreiben."
#: builtin/apply.c:57
msgid "git apply [options] [<patch>...]"
@@ -1680,12 +1973,12 @@ msgstr "git apply [Optionen] [<Patch>...]"
#: builtin/apply.c:110
#, c-format
msgid "unrecognized whitespace option '%s'"
-msgstr "nicht erkannte Option für Leerzeichen: '%s'"
+msgstr "nicht erkannte Whitespace-Option: '%s'"
#: builtin/apply.c:125
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
-msgstr "nicht erkannte Option zum Ignorieren von Leerzeichen: '%s'"
+msgstr "nicht erkannte Option zum Ignorieren von Whitespace: '%s'"
#: builtin/apply.c:823
#, c-format
@@ -1798,19 +2091,19 @@ msgstr "Patch mit nutzlosen Informationen bei Zeile %d"
#: builtin/apply.c:2076
#, c-format
msgid "unable to read symlink %s"
-msgstr "konnte symbolische Verknüpfung %s nicht lesen"
+msgstr "konnte symbolischen Verweis %s nicht lesen"
#: builtin/apply.c:2080
#, c-format
msgid "unable to open or read %s"
msgstr "konnte %s nicht öffnen oder lesen"
-#: builtin/apply.c:2684
+#: builtin/apply.c:2688
#, c-format
msgid "invalid start of line: '%c'"
msgstr "Ungültiger Zeilenanfang: '%c'"
-#: builtin/apply.c:2802
+#: builtin/apply.c:2806
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
@@ -1818,12 +2111,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:2814
+#: builtin/apply.c:2818
#, 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:2820
+#: builtin/apply.c:2824
#, c-format
msgid ""
"while searching for:\n"
@@ -1832,345 +2125,341 @@ msgstr ""
"bei der Suche nach:\n"
"%.*s"
-#: builtin/apply.c:2839
+#: builtin/apply.c:2843
#, c-format
msgid "missing binary patch data for '%s'"
msgstr "keine Daten in Binär-Patch für '%s'"
-#: builtin/apply.c:2942
+#: builtin/apply.c:2946
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr "Konnte Binär-Patch nicht auf '%s' anwenden"
-#: builtin/apply.c:2948
+#: builtin/apply.c:2952
#, 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:2969
+#: builtin/apply.c:2973
#, c-format
msgid "patch failed: %s:%ld"
msgstr "Anwendung des Patches fehlgeschlagen: %s:%ld"
-#: builtin/apply.c:3091
+#: builtin/apply.c:3095
#, c-format
msgid "cannot checkout %s"
msgstr "kann %s nicht auschecken"
-#: builtin/apply.c:3136 builtin/apply.c:3145 builtin/apply.c:3189
+#: builtin/apply.c:3140 builtin/apply.c:3149 builtin/apply.c:3194
#, c-format
msgid "read of %s failed"
msgstr "Konnte %s nicht lesen"
-#: builtin/apply.c:3169 builtin/apply.c:3391
+#: builtin/apply.c:3174 builtin/apply.c:3396
#, c-format
msgid "path %s has been renamed/deleted"
msgstr "Pfad %s wurde umbenannt/gelöscht"
-#: builtin/apply.c:3250 builtin/apply.c:3405
+#: builtin/apply.c:3255 builtin/apply.c:3410
#, c-format
msgid "%s: does not exist in index"
-msgstr "%s ist nicht bereitgestellt"
+msgstr "%s ist nicht in der Staging-Area"
-#: builtin/apply.c:3254 builtin/apply.c:3397 builtin/apply.c:3419
+#: builtin/apply.c:3259 builtin/apply.c:3402 builtin/apply.c:3424
#, c-format
msgid "%s: %s"
msgstr "%s: %s"
-#: builtin/apply.c:3259 builtin/apply.c:3413
+#: builtin/apply.c:3264 builtin/apply.c:3418
#, c-format
msgid "%s: does not match index"
-msgstr "%s entspricht nicht der Bereitstellung"
+msgstr "%s entspricht nicht der Version in der Staging-Area"
-#: builtin/apply.c:3361
+#: builtin/apply.c:3366
msgid "removal patch leaves file contents"
msgstr "Lösch-Patch hinterlässt Dateiinhalte"
-#: builtin/apply.c:3430
+#: builtin/apply.c:3435
#, c-format
msgid "%s: wrong type"
msgstr "%s: falscher Typ"
-#: builtin/apply.c:3432
+#: builtin/apply.c:3437
#, c-format
msgid "%s has type %o, expected %o"
msgstr "%s ist vom Typ %o, erwartete %o"
-#: builtin/apply.c:3533
+#: builtin/apply.c:3538
#, c-format
msgid "%s: already exists in index"
msgstr "%s ist bereits bereitgestellt"
-#: builtin/apply.c:3536
+#: builtin/apply.c:3541
#, c-format
msgid "%s: already exists in working directory"
msgstr "%s existiert bereits im Arbeitsverzeichnis"
-#: builtin/apply.c:3556
+#: builtin/apply.c:3561
#, 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:3561
+#: builtin/apply.c:3566
#, 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:3569
+#: builtin/apply.c:3574
#, c-format
msgid "%s: patch does not apply"
msgstr "%s: Patch konnte nicht angewendet werden"
-#: builtin/apply.c:3582
+#: builtin/apply.c:3587
#, c-format
msgid "Checking patch %s..."
msgstr "Prüfe Patch %s..."
-#: builtin/apply.c:3675 builtin/checkout.c:215 builtin/reset.c:124
+#: builtin/apply.c:3680 builtin/checkout.c:216 builtin/reset.c:127
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "make_cache_entry für Pfad '%s' fehlgeschlagen"
-#: builtin/apply.c:3818
+#: builtin/apply.c:3823
#, c-format
msgid "unable to remove %s from index"
-msgstr "konnte %s nicht aus der Bereitstellung entfernen"
+msgstr "konnte %s nicht aus der Staging-Area entfernen"
-#: builtin/apply.c:3846
+#: builtin/apply.c:3851
#, c-format
-msgid "corrupt patch for subproject %s"
-msgstr "fehlerhafter Patch für Unterprojekt %s"
+msgid "corrupt patch for submodule %s"
+msgstr "fehlerhafter Patch für Submodul %s"
-#: builtin/apply.c:3850
+#: builtin/apply.c:3855
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr "konnte neu erstellte Datei '%s' nicht lesen"
-#: builtin/apply.c:3855
+#: builtin/apply.c:3860
#, 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:3858 builtin/apply.c:3966
+#: builtin/apply.c:3863 builtin/apply.c:3971
#, 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:3891
+#: builtin/apply.c:3896
#, c-format
msgid "closing file '%s'"
msgstr "schließe Datei '%s'"
-#: builtin/apply.c:3940
+#: builtin/apply.c:3945
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "konnte Datei '%s' mit Modus %o nicht schreiben"
-#: builtin/apply.c:4027
+#: builtin/apply.c:4032
#, c-format
msgid "Applied patch %s cleanly."
msgstr "Patch %s sauber angewendet"
-#: builtin/apply.c:4035
+#: builtin/apply.c:4040
msgid "internal error"
msgstr "interner Fehler"
#. Say this even without --verbose
-#: builtin/apply.c:4038
+#: builtin/apply.c:4043
#, 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:4048
+#: builtin/apply.c:4053
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "Verkürze Name von .rej Datei zu %.*s.rej"
-#: builtin/apply.c:4069
+#: builtin/apply.c:4074
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "Patch-Bereich #%d sauber angewendet."
-#: builtin/apply.c:4072
+#: builtin/apply.c:4077
#, c-format
msgid "Rejected hunk #%d."
-msgstr "Patch-Bereich #%d zurückgewiesen."
+msgstr "Patch-Block #%d zurückgewiesen."
-#: builtin/apply.c:4222
+#: builtin/apply.c:4227
msgid "unrecognized input"
msgstr "nicht erkannte Eingabe"
-#: builtin/apply.c:4233
+#: builtin/apply.c:4238
msgid "unable to read index file"
-msgstr "Konnte Bereitstellungsdatei nicht lesen"
+msgstr "Konnte Staging-Area-Datei nicht lesen"
-#: builtin/apply.c:4352 builtin/apply.c:4355 builtin/clone.c:91
+#: builtin/apply.c:4357 builtin/apply.c:4360 builtin/clone.c:91
#: builtin/fetch.c:63
msgid "path"
msgstr "Pfad"
-#: builtin/apply.c:4353
+#: builtin/apply.c:4358
msgid "don't apply changes matching the given path"
msgstr "wendet keine Änderungen im angegebenen Pfad an"
-#: builtin/apply.c:4356
+#: builtin/apply.c:4361
msgid "apply changes matching the given path"
msgstr "wendet Änderungen nur im angegebenen Pfad an"
-#: builtin/apply.c:4358
+#: builtin/apply.c:4363
msgid "num"
msgstr "Anzahl"
-#: builtin/apply.c:4359
+#: builtin/apply.c:4364
msgid "remove <num> leading slashes from traditional diff paths"
msgstr ""
"entfernt <Anzahl> vorangestellte Schrägstriche von herkömmlichen "
"Differenzpfaden"
-#: builtin/apply.c:4362
+#: builtin/apply.c:4367
msgid "ignore additions made by the patch"
msgstr "ignoriert hinzugefügte Zeilen des Patches"
-#: builtin/apply.c:4364
+#: builtin/apply.c:4369
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:4368
+#: builtin/apply.c:4373
msgid "show number of added and deleted lines in decimal notation"
msgstr ""
"zeigt die Anzahl von hinzugefügten/entfernten Zeilen in Dezimalnotation"
-#: builtin/apply.c:4370
+#: builtin/apply.c:4375
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:4372
+#: builtin/apply.c:4377
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:4374
+#: builtin/apply.c:4379
msgid "make sure the patch is applicable to the current index"
msgstr ""
-"stellt sicher, dass der Patch in der aktuellen Bereitstellung angewendet "
+"stellt sicher, dass der Patch in der aktuellen Staging-Area angewendet "
"werden kann"
-#: builtin/apply.c:4376
+#: builtin/apply.c:4381
msgid "apply a patch without touching the working tree"
-msgstr "wendet einen Patch an, ohne Änderungen im Arbeitszweig vorzunehmen"
+msgstr ""
+"wendet einen Patch an, ohne Änderungen im Arbeitsverzeichnis vorzunehmen"
-#: builtin/apply.c:4378
+#: builtin/apply.c:4383
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr "wendet den Patch an (Benutzung mit --stat/--summary/--check)"
-#: builtin/apply.c:4380
+#: builtin/apply.c:4385
msgid "attempt three-way merge if a patch does not apply"
-msgstr ""
-"versucht 3-Wege-Zusammenführung, wenn der Patch nicht angewendet werden "
-"konnte"
+msgstr "versucht 3-Wege-Merge, wenn der Patch nicht angewendet werden konnte"
-#: builtin/apply.c:4382
+#: builtin/apply.c:4387
msgid "build a temporary index based on embedded index information"
msgstr ""
-"erstellt eine temporäre Bereitstellung basierend auf den integrierten "
-"Bereitstellungsinformationen"
+"erstellt eine temporäre Staging-Area basierend auf den integrierten Staging-"
+"Area-Informationen"
-#: builtin/apply.c:4384 builtin/checkout-index.c:197 builtin/ls-files.c:463
+#: builtin/apply.c:4389 builtin/checkout-index.c:197 builtin/ls-files.c:462
msgid "paths are separated with NUL character"
msgstr "Pfade sind getrennt durch NUL Zeichen"
-#: builtin/apply.c:4387
+#: builtin/apply.c:4392
msgid "ensure at least <n> lines of context match"
msgstr "stellt sicher, dass mindestens <n> Zeilen des Kontextes übereinstimmen"
-#: builtin/apply.c:4388
+#: builtin/apply.c:4393
msgid "action"
msgstr "Aktion"
-#: builtin/apply.c:4389
+#: builtin/apply.c:4394
msgid "detect new or modified lines that have whitespace errors"
-msgstr "ermittelt neue oder geänderte Zeilen die Fehler in Leerzeichen haben"
+msgstr "ermittelt neue oder geänderte Zeilen die Whitespace-Fehler haben"
-#: builtin/apply.c:4392 builtin/apply.c:4395
+#: builtin/apply.c:4397 builtin/apply.c:4400
msgid "ignore changes in whitespace when finding context"
-msgstr "ignoriert Änderungen in Leerzeichen bei der Suche des Kontextes"
+msgstr "ignoriert Änderungen im Whitespace bei der Suche des Kontextes"
-#: builtin/apply.c:4398
+#: builtin/apply.c:4403
msgid "apply the patch in reverse"
msgstr "wendet den Patch in umgekehrter Reihenfolge an"
-#: builtin/apply.c:4400
+#: builtin/apply.c:4405
msgid "don't expect at least one line of context"
msgstr "erwartet keinen Kontext"
-#: builtin/apply.c:4402
+#: builtin/apply.c:4407
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr ""
-"hinterlässt zurückgewiesene Patch-Bereiche in den entsprechenden *.rej "
-"Dateien"
+"hinterlässt zurückgewiesene Patch-Blöcke in entsprechenden *.rej Dateien"
-#: builtin/apply.c:4404
+#: builtin/apply.c:4409
msgid "allow overlapping hunks"
-msgstr "erlaubt sich überlappende Patch-Bereiche"
+msgstr "erlaubt sich überlappende Patch-Blöcke"
-#: builtin/apply.c:4407
+#: builtin/apply.c:4412
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr "toleriert fehlerhaft erkannten fehlenden Zeilenumbruch am Dateiende"
-#: builtin/apply.c:4410
+#: builtin/apply.c:4415
msgid "do not trust the line counts in the hunk headers"
-msgstr "vertraut nicht den Zeilennummern im Kopf des Patch-Bereiches"
+msgstr "vertraut nicht den Zeilennummern im Kopf des Patch-Blocks"
-#: builtin/apply.c:4412
+#: builtin/apply.c:4417
msgid "root"
msgstr "Wurzelverzeichnis"
-#: builtin/apply.c:4413
+#: builtin/apply.c:4418
msgid "prepend <root> to all filenames"
msgstr "stellt <Wurzelverzeichnis> vor alle Dateinamen"
-#: builtin/apply.c:4435
+#: builtin/apply.c:4440
msgid "--3way outside a repository"
msgstr ""
-"Die Option --3way kann nicht außerhalb eines Projektarchivs verwendet werden."
+"Die Option --3way kann nicht außerhalb eines Repositories verwendet werden."
-#: builtin/apply.c:4443
+#: builtin/apply.c:4448
msgid "--index outside a repository"
msgstr ""
-"Die Option --index kann nicht außerhalb eines Projektarchivs verwendet "
-"werden."
+"Die Option --index kann nicht außerhalb eines Repositories verwendet werden."
-#: builtin/apply.c:4446
+#: builtin/apply.c:4451
msgid "--cached outside a repository"
msgstr ""
-"Die Option --cached kann nicht außerhalb eines Projektarchivs verwendet "
-"werden."
+"Die Option --cached kann nicht außerhalb eines Repositories verwendet werden."
-#: builtin/apply.c:4462
+#: builtin/apply.c:4467
#, c-format
msgid "can't open patch '%s'"
msgstr "kann Patch '%s' nicht öffnen"
-#: builtin/apply.c:4476
+#: builtin/apply.c:4481
#, 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"
+msgstr[0] "unterdrückte %d Whitespace-Fehler"
+msgstr[1] "unterdrückte %d Whitespace-Fehler"
-#: builtin/apply.c:4482 builtin/apply.c:4492
+#: builtin/apply.c:4487 builtin/apply.c:4497
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
-msgstr[0] "%d Zeile fügt Fehler in Leerzeichen hinzu."
-msgstr[1] "%d Zeilen fügen Fehler in Leerzeichen hinzu."
+msgstr[0] "%d Zeile fügt Whitespace-Fehler hinzu."
+msgstr[1] "%d Zeilen fügen Whitespace-Fehler hinzu."
#: builtin/archive.c:17
#, c-format
@@ -2189,21 +2478,21 @@ msgstr "git archive: Externes Archiv ohne URL"
msgid "git archive: expected ACK/NAK, got EOF"
msgstr "git archive: habe ACK/NAK erwartet, aber EOF bekommen"
-#: builtin/archive.c:63
+#: builtin/archive.c:61
#, c-format
msgid "git archive: NACK %s"
msgstr "git archive: NACK %s"
-#: builtin/archive.c:65
+#: builtin/archive.c:63
#, c-format
msgid "remote error: %s"
msgstr "Fehler am anderen Ende: %s"
-#: builtin/archive.c:66
+#: builtin/archive.c:64
msgid "git archive: protocol error"
msgstr "git archive: Protokollfehler"
-#: builtin/archive.c:71
+#: builtin/archive.c:68
msgid "git archive: expected a flush"
msgstr "git archive: erwartete eine Spülung (flush)"
@@ -2217,446 +2506,491 @@ msgstr "führt 'git bisect next' aus"
#: builtin/bisect--helper.c:19
msgid "update BISECT_HEAD instead of checking out the current commit"
-msgstr "aktualisiert BISECT_HEAD, anstatt die aktuelle Version auszuchecken"
+msgstr "aktualisiert BISECT_HEAD, anstatt den aktuellen Commit auszuchecken"
-#: builtin/blame.c:25
+#: builtin/blame.c:26
msgid "git blame [options] [rev-opts] [rev] [--] file"
msgstr "git blame [Optionen] [rev-opts] [rev] [--] Datei"
-#: builtin/blame.c:30 builtin/shortlog.c:15
+#: builtin/blame.c:31
msgid "[rev-opts] are documented in git-rev-list(1)"
msgstr "[rev-opts] sind dokumentiert in git-rev-list(1)"
-#: builtin/blame.c:2350
+#: builtin/blame.c:2276
msgid "Show blame entries as we find them, incrementally"
msgstr "Zeigt \"blame\"-Einträge schrittweise, während wir sie generieren"
-#: builtin/blame.c:2351
+#: builtin/blame.c:2277
msgid "Show blank SHA-1 for boundary commits (Default: off)"
-msgstr "Zeigt leere SHA-1 für Grenzversionen (Standard: aus)"
+msgstr "Zeigt leere SHA-1 für Grenz-Commits (Standard: aus)"
-#: builtin/blame.c:2352
+#: builtin/blame.c:2278
msgid "Do not treat root commits as boundaries (Default: off)"
-msgstr "Behandelt Ursprungsversionen nicht als Grenzen (Standard: aus)"
+msgstr "Behandelt Ursprungs-Commit nicht als Grenzen (Standard: aus)"
-#: builtin/blame.c:2353
+#: builtin/blame.c:2279
msgid "Show work cost statistics"
msgstr "Zeigt Statistiken zum Arbeitsaufwand"
-#: builtin/blame.c:2354
+#: builtin/blame.c:2280
msgid "Show output score for blame entries"
msgstr "Zeigt Ausgabebewertung für \"blame\"-Einträge"
-#: builtin/blame.c:2355
+#: builtin/blame.c:2281
msgid "Show original filename (Default: auto)"
msgstr "Zeigt ursprünglichen Dateinamen (Standard: auto)"
-#: builtin/blame.c:2356
+#: builtin/blame.c:2282
msgid "Show original linenumber (Default: off)"
msgstr "Zeigt ursprüngliche Zeilennummer (Standard: aus)"
-#: builtin/blame.c:2357
+#: builtin/blame.c:2283
msgid "Show in a format designed for machine consumption"
msgstr "Anzeige in einem Format für maschinelle Auswertung"
-#: builtin/blame.c:2358
+#: builtin/blame.c:2284
msgid "Show porcelain format with per-line commit information"
msgstr ""
-"Anzeige in Format für Fremdprogramme mit Versionsinformationen pro Zeile"
+"Anzeige in Format für Fremdprogramme mit Commit-Informationen pro Zeile"
-#: builtin/blame.c:2359
+#: builtin/blame.c:2285
msgid "Use the same output mode as git-annotate (Default: off)"
msgstr "Benutzt den gleichen Ausgabemodus wie \"git-annotate\" (Standard: aus)"
-#: builtin/blame.c:2360
+#: builtin/blame.c:2286
msgid "Show raw timestamp (Default: off)"
msgstr "Zeigt unbearbeiteten Zeitstempel (Standard: aus)"
-#: builtin/blame.c:2361
+#: builtin/blame.c:2287
msgid "Show long commit SHA1 (Default: off)"
-msgstr "Zeigt langen Versions-SHA1 (Standard: aus)"
+msgstr "Zeigt langen Commit-SHA1 (Standard: aus)"
-#: builtin/blame.c:2362
+#: builtin/blame.c:2288
msgid "Suppress author name and timestamp (Default: off)"
msgstr "Unterdrückt den Namen des Autors und den Zeitstempel (Standard: aus)"
-#: builtin/blame.c:2363
+#: builtin/blame.c:2289
msgid "Show author email instead of name (Default: off)"
msgstr "Zeigt anstatt des Namens die Email-Adresse des Autors (Standard: aus)"
-#: builtin/blame.c:2364
+#: builtin/blame.c:2290
msgid "Ignore whitespace differences"
-msgstr "Ignoriert Unterschiede in Leerzeichen"
+msgstr "Ignoriert Unterschiede im Whitespace"
-#: builtin/blame.c:2365
+#: builtin/blame.c:2291
msgid "Spend extra cycles to find better match"
msgstr "arbeite länger, um bessere Übereinstimmungen zu finden"
-#: builtin/blame.c:2366
+#: builtin/blame.c:2292
msgid "Use revisions from <file> instead of calling git-rev-list"
-msgstr "Benutzt Revisionen von <Datei> anstatt \"git-rev-list\" aufzurufen"
+msgstr "Benutzt Commits von <Datei> anstatt \"git-rev-list\" aufzurufen"
-#: builtin/blame.c:2367
+#: builtin/blame.c:2293
msgid "Use <file>'s contents as the final image"
msgstr "Benutzt Inhalte der <Datei>en als entgültiges Abbild"
-#: builtin/blame.c:2368 builtin/blame.c:2369
+#: builtin/blame.c:2294 builtin/blame.c:2295
msgid "score"
msgstr "Bewertung"
-#: builtin/blame.c:2368
+#: builtin/blame.c:2294
msgid "Find line copies within and across files"
msgstr "Findet kopierte Zeilen innerhalb oder zwischen Dateien"
-#: builtin/blame.c:2369
+#: builtin/blame.c:2295
msgid "Find line movements within and across files"
msgstr "Findet verschobene Zeilen innerhalb oder zwischen Dateien"
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
msgid "n,m"
msgstr "n,m"
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
msgid "Process only line range n,m, counting from 1"
msgstr "Verarbeitet nur Zeilen im Bereich n,m, gezählt von 1"
-#: builtin/branch.c:23
+#: builtin/branch.c:24
msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
msgstr "git branch [Optionen] [-r | -a] [--merged | --no-merged]"
-#: builtin/branch.c:24
+#: builtin/branch.c:25
msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
-msgstr "git branch [Optionen] [-l] [-f] <Zweigname> [<Startpunkt>]"
+msgstr "git branch [Optionen] [-l] [-f] <Branchname> [<Startpunkt>]"
-#: builtin/branch.c:25
+#: builtin/branch.c:26
msgid "git branch [options] [-r] (-d | -D) <branchname>..."
-msgstr "git branch [Optionen] [-r] (-d | -D) <Zweigname>..."
+msgstr "git branch [Optionen] [-r] (-d | -D) <Branchname>..."
-#: builtin/branch.c:26
+#: builtin/branch.c:27
msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
-msgstr "git branch [Optionen] (-m | -M) [<alterZweig>] <neuerZweig>"
+msgstr "git branch [Optionen] (-m | -M) [<alterBranch>] <neuerBranch>"
-#: builtin/branch.c:145
+#: builtin/branch.c:150
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
" '%s', but not yet merged to HEAD."
msgstr ""
-"entferne Zweig '%s', der zusammengeführt wurde mit\n"
-" '%s', aber noch nicht mit der Zweigspitze (HEAD) zusammengeführt "
-"wurde."
+"entferne Branch '%s', der zusammengeführt wurde mit\n"
+" '%s', aber noch nicht mit HEAD zusammengeführt wurde."
-#: builtin/branch.c:149
+#: builtin/branch.c:154
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
" '%s', even though it is merged to HEAD."
msgstr ""
-"entferne Zweig '%s' nicht, der noch nicht zusammengeführt wurde mit\n"
-" '%s', obwohl er mit der Zweigspitze (HEAD) zusammengeführt wurde."
+"entferne Branch '%s' nicht, der noch nicht zusammengeführt wurde mit\n"
+" '%s', obwohl er mit HEAD zusammengeführt wurde."
-#: builtin/branch.c:163
+#: builtin/branch.c:168
#, c-format
msgid "Couldn't look up commit object for '%s'"
-msgstr "Konnte Versionsobjekt für '%s' nicht nachschlagen."
+msgstr "Konnte Commit-Objekt für '%s' nicht nachschlagen."
-#: builtin/branch.c:167
+#: builtin/branch.c:172
#, c-format
msgid ""
"The branch '%s' is not fully merged.\n"
"If you are sure you want to delete it, run 'git branch -D %s'."
msgstr ""
-"Der Zweig '%s' ist nicht vollständig zusammengeführt.\n"
-"Wenn Sie sicher sind diesen Zweig zu entfernen, führen Sie 'git branch -D "
+"Der Branch '%s' ist nicht vollständig zusammengeführt.\n"
+"Wenn Sie sicher sind diesen Branch zu entfernen, führen Sie 'git branch -D "
"%s' aus."
-#: builtin/branch.c:180
+#: builtin/branch.c:185
msgid "Update of config-file failed"
msgstr "Aktualisierung der Konfigurationsdatei fehlgeschlagen."
-#: builtin/branch.c:208
+#: builtin/branch.c:213
msgid "cannot use -a with -d"
msgstr "kann -a nicht mit -d benutzen"
-#: builtin/branch.c:214
+#: builtin/branch.c:219
msgid "Couldn't look up commit object for HEAD"
-msgstr "Konnte Versionsobjekt für Zweigspitze (HEAD) nicht nachschlagen."
+msgstr "Konnte Commit-Objekt für HEAD nicht nachschlagen."
-#: builtin/branch.c:222
+#: builtin/branch.c:227
#, c-format
msgid "Cannot delete the branch '%s' which you are currently on."
msgstr ""
-"Kann Zweig '%s' nicht entfernen, da Sie sich gerade auf diesem befinden."
+"Kann Branch '%s' nicht entfernen, da Sie sich gerade auf diesem befinden."
-#: builtin/branch.c:235
+#: builtin/branch.c:240
#, c-format
msgid "remote branch '%s' not found."
-msgstr "externer Zweig '%s' nicht gefunden"
+msgstr "Remote-Branch '%s' nicht gefunden"
-#: builtin/branch.c:236
+#: builtin/branch.c:241
#, c-format
msgid "branch '%s' not found."
-msgstr "Zweig '%s' nicht gefunden."
+msgstr "Branch '%s' nicht gefunden."
-#: builtin/branch.c:250
+#: builtin/branch.c:255
#, c-format
msgid "Error deleting remote branch '%s'"
-msgstr "Fehler beim Entfernen des externen Zweiges '%s'"
+msgstr "Fehler beim Entfernen des Remote-Branches '%s'"
-#: builtin/branch.c:251
+#: builtin/branch.c:256
#, c-format
msgid "Error deleting branch '%s'"
-msgstr "Fehler beim Entfernen des Zweiges '%s'"
+msgstr "Fehler beim Entfernen des Branches '%s'"
-#: builtin/branch.c:258
+#: builtin/branch.c:263
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
-msgstr "Externer Zweig %s entfernt (war %s).\n"
+msgstr "Remote-Branch %s entfernt (war %s).\n"
-#: builtin/branch.c:259
+#: builtin/branch.c:264
#, c-format
msgid "Deleted branch %s (was %s).\n"
-msgstr "Zweig %s entfernt (war %s).\n"
+msgstr "Branch %s entfernt (war %s).\n"
-#: builtin/branch.c:361
+#: builtin/branch.c:366
#, c-format
msgid "branch '%s' does not point at a commit"
-msgstr "Zweig '%s' zeigt auf keine Version"
+msgstr "Branch '%s' zeigt auf keinen Commit"
-#: builtin/branch.c:433
+#: builtin/branch.c:453
#, c-format
msgid "[%s: behind %d]"
msgstr "[%s: %d hinterher]"
-#: builtin/branch.c:435
+#: builtin/branch.c:455
#, c-format
msgid "[behind %d]"
msgstr "[%d hinterher]"
-#: builtin/branch.c:439
+#: builtin/branch.c:459
#, c-format
msgid "[%s: ahead %d]"
msgstr "[%s: %d voraus]"
-#: builtin/branch.c:441
+#: builtin/branch.c:461
#, c-format
msgid "[ahead %d]"
msgstr "[%d voraus]"
-#: builtin/branch.c:444
+#: builtin/branch.c:464
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr "[%s: %d voraus, %d hinterher]"
-#: builtin/branch.c:447
+#: builtin/branch.c:467
#, c-format
msgid "[ahead %d, behind %d]"
msgstr "[%d voraus, %d hinterher]"
-#: builtin/branch.c:469
+#: builtin/branch.c:490
msgid " **** invalid ref ****"
msgstr " **** ungültige Referenz ****"
-#: builtin/branch.c:560
+#: builtin/branch.c:582
+#, c-format
+msgid "(no branch, rebasing %s)"
+msgstr "(kein Branch, Rebase von Branch %s im Gange)"
+
+#: builtin/branch.c:585
+#, c-format
+msgid "(no branch, bisect started on %s)"
+msgstr "(kein Branch, binäre Suche begonnen bei %s)"
+
+#: builtin/branch.c:588
+#, c-format
+msgid "(detached from %s)"
+msgstr "(losgelöst von %s)"
+
+#: builtin/branch.c:591
msgid "(no branch)"
-msgstr "(kein Zweig)"
+msgstr "(kein Branch)"
-#: builtin/branch.c:593
+#: builtin/branch.c:637
#, c-format
msgid "object '%s' does not point to a commit"
-msgstr "Objekt '%s' zeigt auf keine Version"
+msgstr "Objekt '%s' zeigt auf keinen Commit"
-#: builtin/branch.c:625
+#: builtin/branch.c:669
msgid "some refs could not be read"
msgstr "Konnte einige Referenzen nicht lesen"
-#: builtin/branch.c:638
+#: builtin/branch.c:682
msgid "cannot rename the current branch while not on any."
msgstr ""
-"Kann aktuellen Zweig nicht umbenennen, solange Sie sich auf keinem befinden."
+"Kann aktuellen Branch nicht umbenennen, solange Sie sich auf keinem befinden."
-#: builtin/branch.c:648
+#: builtin/branch.c:692
#, c-format
msgid "Invalid branch name: '%s'"
-msgstr "Ungültiger Zweig-Name: '%s'"
+msgstr "Ungültiger Branchname: '%s'"
-#: builtin/branch.c:663
+#: builtin/branch.c:707
msgid "Branch rename failed"
-msgstr "Umbenennung des Zweiges fehlgeschlagen"
+msgstr "Umbenennung des Branches fehlgeschlagen"
-#: builtin/branch.c:667
+#: builtin/branch.c:711
#, c-format
msgid "Renamed a misnamed branch '%s' away"
-msgstr "falsch benannten Zweig '%s' umbenannt"
+msgstr "falsch benannten Branch '%s' umbenannt"
-#: builtin/branch.c:671
+#: builtin/branch.c:715
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "Zweig umbenannt zu %s, aber Zweigspitze (HEAD) ist nicht aktualisiert!"
+msgstr "Branch umbenannt zu %s, aber HEAD ist nicht aktualisiert!"
-#: builtin/branch.c:678
+#: builtin/branch.c:722
msgid "Branch is renamed, but update of config-file failed"
msgstr ""
-"Zweig ist umbenannt, aber die Aktualisierung der Konfigurationsdatei ist "
+"Branch ist umbenannt, aber die Aktualisierung der Konfigurationsdatei ist "
"fehlgeschlagen."
-#: builtin/branch.c:693
+#: builtin/branch.c:737
#, c-format
msgid "malformed object name %s"
msgstr "Missgebildeter Objektname %s"
-#: builtin/branch.c:717
+#: builtin/branch.c:761
#, c-format
msgid "could not write branch description template: %s"
-msgstr "Konnte Beschreibungsvorlage für Zweig nicht schreiben: %s"
+msgstr "Konnte Beschreibungsvorlage für Branch nicht schreiben: %s"
-#: builtin/branch.c:747
+#: builtin/branch.c:791
msgid "Generic options"
msgstr "Allgemeine Optionen"
-#: builtin/branch.c:749
+#: builtin/branch.c:793
msgid "show hash and subject, give twice for upstream branch"
-msgstr "Zeigt Hash und Betreff; -vv: zusätzlich externen Übernahmezweig"
+msgstr "Zeigt Hash und Betreff; -vv: zusätzlich Upstream-Branch"
-#: builtin/branch.c:750
+#: builtin/branch.c:794
msgid "suppress informational messages"
msgstr "unterdrückt Informationsmeldungen"
-#: builtin/branch.c:751
+#: builtin/branch.c:795
msgid "set up tracking mode (see git-pull(1))"
msgstr "stellt den Ãœbernahmemodus ein (siehe git-pull(1))"
-#: builtin/branch.c:753
+#: builtin/branch.c:797
msgid "change upstream info"
-msgstr "ändert Informationen zum externen Übernahmezweig"
+msgstr "ändert Informationen zum Upstream-Branch"
-#: builtin/branch.c:757
+#: builtin/branch.c:801
msgid "use colored output"
msgstr "verwendet farbliche Ausgaben"
-#: builtin/branch.c:758
+#: builtin/branch.c:802
msgid "act on remote-tracking branches"
-msgstr "wirkt auf externe Ãœbernahmezweige"
+msgstr "wirkt auf Remote-Tracking-Branches"
-#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788
-#: builtin/branch.c:794 builtin/commit.c:1366 builtin/commit.c:1367
-#: builtin/commit.c:1368 builtin/commit.c:1369 builtin/tag.c:468
+#: builtin/branch.c:805 builtin/branch.c:811 builtin/branch.c:832
+#: builtin/branch.c:838 builtin/commit.c:1433 builtin/commit.c:1434
+#: builtin/commit.c:1435 builtin/commit.c:1436 builtin/tag.c:468
msgid "commit"
-msgstr "Version"
+msgstr "Commit"
-#: builtin/branch.c:762 builtin/branch.c:768
+#: builtin/branch.c:806 builtin/branch.c:812
msgid "print only branches that contain the commit"
-msgstr "gibt nur Zweige aus, welche diese Version beinhalten"
+msgstr "gibt nur Branches aus, welche diesen Commit beinhalten"
-#: builtin/branch.c:774
+#: builtin/branch.c:818
msgid "Specific git-branch actions:"
msgstr "spezifische Aktionen für \"git-branch\":"
-#: builtin/branch.c:775
+#: builtin/branch.c:819
msgid "list both remote-tracking and local branches"
-msgstr "listet externe Ãœbernahmezweige und lokale Zweige auf"
+msgstr "listet Remote-Tracking und lokale Branches auf"
-#: builtin/branch.c:777
+#: builtin/branch.c:821
msgid "delete fully merged branch"
-msgstr "entfernt vollständig zusammengeführten Zweig"
+msgstr "entfernt vollständig zusammengeführten Branch"
-#: builtin/branch.c:778
+#: builtin/branch.c:822
msgid "delete branch (even if not merged)"
-msgstr "löscht Zweig (auch wenn nicht zusammengeführt)"
+msgstr "löscht Branch (auch wenn nicht zusammengeführt)"
-#: builtin/branch.c:779
+#: builtin/branch.c:823
msgid "move/rename a branch and its reflog"
-msgstr "verschiebt/benennt einen Zweig und dessen Referenzprotokoll um"
+msgstr "verschiebt/benennt einen Branch und dessen Reflog um"
-#: builtin/branch.c:780
+#: builtin/branch.c:824
msgid "move/rename a branch, even if target exists"
msgstr ""
-"verschiebt/benennt einen Zweig um, auch wenn das Ziel bereits existiert"
+"verschiebt/benennt einen Branch um, auch wenn das Ziel bereits existiert"
-#: builtin/branch.c:781
+#: builtin/branch.c:825
msgid "list branch names"
-msgstr "listet Zweignamen auf"
+msgstr "listet Branchnamen auf"
-#: builtin/branch.c:782
+#: builtin/branch.c:826
msgid "create the branch's reflog"
-msgstr "erzeugt das Referenzprotokoll des Zweiges"
+msgstr "erzeugt das Reflog des Branches"
-#: builtin/branch.c:784
+#: builtin/branch.c:828
msgid "edit the description for the branch"
-msgstr "bearbeitet die Beschreibung für den Zweig"
+msgstr "bearbeitet die Beschreibung für den Branch"
-#: builtin/branch.c:785
+#: builtin/branch.c:829
msgid "force creation (when already exists)"
-msgstr "erzeuge auch, wenn der Zweig bereits existiert"
+msgstr "erzeuge auch, wenn der Branch bereits existiert"
-#: builtin/branch.c:788
+#: builtin/branch.c:832
msgid "print only not merged branches"
-msgstr "gibt nur Zweige aus, die nicht zusammengeführt sind"
+msgstr "gibt nur Branches aus, die nicht zusammengeführt sind"
-#: builtin/branch.c:794
+#: builtin/branch.c:838
msgid "print only merged branches"
-msgstr "gibt nur Zweige aus, die zusammengeführt sind"
+msgstr "gibt nur Branches aus, die zusammengeführt sind"
-#: builtin/branch.c:798
+#: builtin/branch.c:842
msgid "list branches in columns"
-msgstr "listet Zweige in Spalten auf"
+msgstr "listet Branches in Spalten auf"
-#: builtin/branch.c:811
+#: builtin/branch.c:855
msgid "Failed to resolve HEAD as a valid ref."
-msgstr "Konnte Zweigspitze (HEAD) nicht als gültige Referenz auflösen."
+msgstr "Konnte HEAD nicht als gültige Referenz auflösen."
-#: builtin/branch.c:816 builtin/clone.c:561
+#: builtin/branch.c:860 builtin/clone.c:630
msgid "HEAD not found below refs/heads!"
-msgstr "Zweigspitze (HEAD) wurde nicht unter \"refs/heads\" gefunden!"
+msgstr "HEAD wurde nicht unter \"refs/heads\" gefunden!"
-#: builtin/branch.c:839
+#: builtin/branch.c:883
msgid "--column and --verbose are incompatible"
msgstr "Die Optionen --column und --verbose sind inkompatibel."
-#: builtin/branch.c:845
+#: builtin/branch.c:889 builtin/branch.c:928
msgid "branch name required"
-msgstr "Zweigname erforderlich"
+msgstr "Branchname erforderlich"
-#: builtin/branch.c:860
+#: builtin/branch.c:904
msgid "Cannot give description to detached HEAD"
-msgstr ""
-"zu losgelöster Zweigspitze (HEAD) kann keine Beschreibung hinterlegt werden"
+msgstr "zu losgelöstem HEAD kann keine Beschreibung hinterlegt werden"
-#: builtin/branch.c:865
+#: builtin/branch.c:909
msgid "cannot edit description of more than one branch"
-msgstr "Beschreibung von mehr als einem Zweig kann nicht bearbeitet werden"
+msgstr "Beschreibung von mehr als einem Branch kann nicht bearbeitet werden"
-#: builtin/branch.c:872
+#: builtin/branch.c:916
#, c-format
msgid "No commit on branch '%s' yet."
-msgstr "Noch keine Version in Zweig '%s'."
+msgstr "Noch kein Commit in Branch '%s'."
-#: builtin/branch.c:875
+#: builtin/branch.c:919
#, c-format
msgid "No branch named '%s'."
-msgstr "Zweig '%s' nicht vorhanden."
+msgstr "Branch '%s' nicht vorhanden."
-#: builtin/branch.c:888
+#: builtin/branch.c:934
msgid "too many branches for a rename operation"
-msgstr "zu viele Zweige für eine Umbenennen-Operation angegeben"
+msgstr "zu viele Branches für eine Umbenennen-Operation angegeben"
-#: builtin/branch.c:893
+#: builtin/branch.c:939
+msgid "too many branches to set new upstream"
+msgstr "zu viele Branches angegeben um Upstream-Branch zu setzen"
+
+#: builtin/branch.c:943
+#, c-format
+msgid ""
+"could not set upstream of HEAD to %s when it does not point to any branch."
+msgstr ""
+"Konnte keinen neuen Upstream-Branch von HEAD zu %s setzen, da dieser auf\n"
+"keinen Branch zeigt."
+
+#: builtin/branch.c:946 builtin/branch.c:968 builtin/branch.c:990
+#, c-format
+msgid "no such branch '%s'"
+msgstr "Kein solcher Branch '%s'"
+
+#: builtin/branch.c:950
#, c-format
msgid "branch '%s' does not exist"
-msgstr "Zweig '%s' existiert nicht"
+msgstr "Branch '%s' existiert nicht"
+
+#: builtin/branch.c:962
+msgid "too many branches to unset upstream"
+msgstr ""
+"zu viele Branches angegeben um Konfiguration zu Upstream-Branch zu entfernen"
+
+#: builtin/branch.c:966
+msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgstr ""
+"Konnte Konfiguration zu Upstream-Branch von HEAD nicht entfernen, da dieser\n"
+"auf keinen Branch zeigt."
-#: builtin/branch.c:905
+#: builtin/branch.c:972
#, c-format
msgid "Branch '%s' has no upstream information"
-msgstr "Zweig '%s' hat keinen externen Ãœbernahmezweig gesetzt"
+msgstr "Branch '%s' hat keinen Upstream-Branch gesetzt"
-#: builtin/branch.c:920
+#: builtin/branch.c:987
+msgid "it does not make sense to create 'HEAD' manually"
+msgstr "'HEAD' darf nicht manuell erstellt werden"
+
+#: builtin/branch.c:993
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
msgstr ""
"Die Optionen -a und -r bei 'git branch' können nicht gemeimsam mit einem "
-"Zweignamen verwendet werden."
+"Branchnamen verwendet werden."
-#: builtin/branch.c:923
+#: builtin/branch.c:996
#, c-format
msgid ""
"The --set-upstream flag is deprecated and will be removed. Consider using --"
@@ -2665,7 +2999,7 @@ msgstr ""
"Die --set-upstream Option ist veraltet und wird entfernt. Benutzen Sie --"
"track oder --set-upstream-to\n"
-#: builtin/branch.c:940
+#: builtin/branch.c:1013
#, c-format
msgid ""
"\n"
@@ -2673,15 +3007,15 @@ msgid ""
"\n"
msgstr ""
"\n"
-"Wenn Sie wollten, dass '%s' den Zweig '%s' als externen Ãœbernahmezweig hat, "
-"führen Sie aus:\n"
+"Wenn Sie wollten, dass '%s' den Branch '%s' als Upstream-Branch hat, führen "
+"Sie aus:\n"
-#: builtin/branch.c:941
+#: builtin/branch.c:1014
#, c-format
msgid " git branch -d %s\n"
msgstr " git branch -d %s\n"
-#: builtin/branch.c:942
+#: builtin/branch.c:1015
#, c-format
msgid " git branch --set-upstream-to %s\n"
msgstr " git branch --set-upstream-to %s\n"
@@ -2693,51 +3027,51 @@ msgstr "%s ist in Ordnung\n"
#: builtin/bundle.c:56
msgid "Need a repository to create a bundle."
-msgstr "Um ein Paket zu erstellen wird ein Projektarchiv benötigt."
+msgstr "Um ein Paket zu erstellen wird ein Repository benötigt."
#: builtin/bundle.c:60
msgid "Need a repository to unbundle."
-msgstr "Zum Entpacken wird ein Projektarchiv benötigt."
+msgstr "Zum Entpacken wird ein Repository benötigt."
-#: builtin/cat-file.c:247
+#: builtin/cat-file.c:285
msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
msgstr "git cat-file (-t|-s|-e|-p|<Art>|--textconv) <Objekt>"
-#: builtin/cat-file.c:248
+#: builtin/cat-file.c:286
msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
msgstr "git cat-file (--batch|--batch-check) < <Liste_von_Objekten>"
-#: builtin/cat-file.c:266
+#: builtin/cat-file.c:323
msgid "<type> can be one of: blob, tree, commit, tag"
msgstr "<Art> kann sein: blob, tree, commit, tag"
-#: builtin/cat-file.c:267
+#: builtin/cat-file.c:324
msgid "show object type"
msgstr "zeigt Objektart"
-#: builtin/cat-file.c:268
+#: builtin/cat-file.c:325
msgid "show object size"
msgstr "zeigt Objektgröße"
-#: builtin/cat-file.c:270
+#: builtin/cat-file.c:327
msgid "exit with zero when there's no error"
msgstr "beendet mit Rückgabewert 0, wenn kein Fehler aufgetreten ist"
-#: builtin/cat-file.c:271
+#: builtin/cat-file.c:328
msgid "pretty-print object's content"
msgstr "ansprechende Anzeige des Objektinhaltes"
-#: builtin/cat-file.c:273
+#: builtin/cat-file.c:330
msgid "for blob objects, run textconv on object's content"
msgstr "führt eine Textkonvertierung auf den Inhalt von Blob-Objekten aus"
-#: builtin/cat-file.c:275
+#: builtin/cat-file.c:332
msgid "show info and content of objects fed from the standard input"
msgstr ""
"Anzeige von Informationen und Inhalt von Objekten, gelesen von der Standard-"
"Eingabe"
-#: builtin/cat-file.c:278
+#: builtin/cat-file.c:335
msgid "show info about objects fed from the standard input"
msgstr ""
"Anzeige von Informationen über Objekte, gelesen von der Standard-Eingabe"
@@ -2757,7 +3091,7 @@ msgstr "gibt alle Attribute einer Datei aus"
#: builtin/check-attr.c:20
msgid "use .gitattributes only from the index"
-msgstr "verwendet .gitattributes nur von der Bereitstellung"
+msgstr "verwendet .gitattributes nur von der Staging-Area"
#: builtin/check-attr.c:21 builtin/check-ignore.c:22 builtin/hash-object.c:75
msgid "read file names from stdin"
@@ -2767,38 +3101,63 @@ msgstr "liest Dateinamen von der Standard-Eingabe"
msgid "input paths are terminated by a null character"
msgstr "Eingabepfade sind durch ein NUL Zeichen abgeschlossen"
-#: builtin/check-ignore.c:18 builtin/checkout.c:1012 builtin/gc.c:177
+#: builtin/check-ignore.c:18 builtin/checkout.c:1054 builtin/gc.c:177
msgid "suppress progress reporting"
msgstr "unterdrückt Fortschrittsanzeige"
-#: builtin/check-ignore.c:151
+#: builtin/check-ignore.c:26
+msgid "show non-matching input paths"
+msgstr "zeigt Eingabe-Pfade ohne Ãœbereinstimmungen"
+
+#: builtin/check-ignore.c:143
msgid "cannot specify pathnames with --stdin"
msgstr "Angabe von Pfadnamen kann nicht gemeinsam mit --stdin verwendet werden"
-#: builtin/check-ignore.c:154
+#: builtin/check-ignore.c:146
msgid "-z only makes sense with --stdin"
msgstr "Die Option -z kann nur mit --stdin verwendet werden."
-#: builtin/check-ignore.c:156
+#: builtin/check-ignore.c:148
msgid "no path specified"
msgstr "kein Pfad angegeben"
-#: builtin/check-ignore.c:160
+#: builtin/check-ignore.c:152
msgid "--quiet is only valid with a single pathname"
msgstr "Die Option --quiet ist nur mit einem einzelnen Pfadnamen gültig."
-#: builtin/check-ignore.c:162
+#: builtin/check-ignore.c:154
msgid "cannot have both --quiet and --verbose"
msgstr ""
"Die Optionen --quiet und --verbose können nicht gemeinsam verwendet werden."
+#: builtin/check-ignore.c:157
+msgid "--non-matching is only valid with --verbose"
+msgstr "--non-matching ist nur mit --verbose zulässig"
+
+#: builtin/check-mailmap.c:8
+msgid "git check-mailmap [options] <contact>..."
+msgstr "git check-mailmap [Optionen] <Kontakt>..."
+
+#: builtin/check-mailmap.c:13
+msgid "also read contacts from stdin"
+msgstr "liest ebenfalls Kontakte von der Standard-Eingabe"
+
+#: builtin/check-mailmap.c:24
+#, c-format
+msgid "unable to parse contact: %s"
+msgstr "Konnte Kontakt '%s' nicht parsen."
+
+#: builtin/check-mailmap.c:47
+msgid "no contacts specified"
+msgstr "keine Kontakte angegeben"
+
#: builtin/checkout-index.c:126
msgid "git checkout-index [options] [--] [<file>...]"
msgstr "git checkout-index [Optionen] [--] [<Datei>...]"
#: builtin/checkout-index.c:187
msgid "check out all files in the index"
-msgstr "checkt alle Dateien in der Bereitstellung aus"
+msgstr "checkt alle Dateien in der Staging-Area aus"
#: builtin/checkout-index.c:188
msgid "force overwrite of existing files"
@@ -2808,7 +3167,7 @@ msgstr "erzwingt das Ãœberschreiben bereits existierender Dateien"
msgid "no warning for existing files and files not in index"
msgstr ""
"keine Warnung für existierende Dateien, und Dateien, die sich nicht in der "
-"Bereitstellung befinden"
+"Staging-Area befinden"
#: builtin/checkout-index.c:192
msgid "don't checkout new files"
@@ -2816,7 +3175,7 @@ msgstr "checkt keine neuen Dateien aus"
#: builtin/checkout-index.c:194
msgid "update stat information in the index file"
-msgstr "aktualisiert Dateiinformationen in der Bereitstellungsdatei"
+msgstr "aktualisiert Dateiinformationen in der Staging-Area-Datei"
#: builtin/checkout-index.c:200
msgid "read list of paths from the standard input"
@@ -2841,112 +3200,113 @@ msgstr "kopiert Dateien von dem benannten Stand"
#: builtin/checkout.c:25
msgid "git checkout [options] <branch>"
-msgstr "git checkout [Optionen] <Zweig>"
+msgstr "git checkout [Optionen] <Branch>"
#: builtin/checkout.c:26
msgid "git checkout [options] [<branch>] -- <file>..."
-msgstr "git checkout [Optionen] [Zweig>] -- <Datei>..."
+msgstr "git checkout [Optionen] [<Branch>] -- <Datei>..."
-#: builtin/checkout.c:116 builtin/checkout.c:149
+#: builtin/checkout.c:117 builtin/checkout.c:150
#, c-format
msgid "path '%s' does not have our version"
msgstr "Pfad '%s' hat nicht unsere Version."
-#: builtin/checkout.c:118 builtin/checkout.c:151
+#: builtin/checkout.c:119 builtin/checkout.c:152
#, c-format
msgid "path '%s' does not have their version"
msgstr "Pfad '%s' hat nicht deren Version."
-#: builtin/checkout.c:134
+#: builtin/checkout.c:135
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr "Pfad '%s' hat nicht alle notwendigen Versionen."
-#: builtin/checkout.c:178
+#: builtin/checkout.c:179
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr "Pfad '%s' hat nicht die notwendigen Versionen."
-#: builtin/checkout.c:195
+#: builtin/checkout.c:196
#, c-format
msgid "path '%s': cannot merge"
msgstr "Pfad '%s': kann nicht zusammenführen"
-#: builtin/checkout.c:212
+#: builtin/checkout.c:213
#, c-format
msgid "Unable to add merge result for '%s'"
-msgstr "Konnte Ergebnis der Zusammenführung von '%s' nicht hinzufügen."
+msgstr "Konnte Merge-Ergebnis von '%s' nicht hinzufügen."
-#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
-#: builtin/checkout.c:245
+#: builtin/checkout.c:237 builtin/checkout.c:240 builtin/checkout.c:243
+#: builtin/checkout.c:246
#, c-format
msgid "'%s' cannot be used with updating paths"
msgstr "'%s' kann nicht mit Pfaden verwendet werden"
-#: builtin/checkout.c:248 builtin/checkout.c:251
+#: builtin/checkout.c:249 builtin/checkout.c:252
#, c-format
msgid "'%s' cannot be used with %s"
msgstr "'%s' kann nicht mit '%s' verwendet werden"
-#: builtin/checkout.c:254
+#: builtin/checkout.c:255
#, c-format
msgid "Cannot update paths and switch to branch '%s' at the same time."
-msgstr "Kann nicht gleichzeitig Pfade aktualisieren und zu Zweig '%s' wechseln"
+msgstr ""
+"Kann nicht gleichzeitig Pfade aktualisieren und zu Branch '%s' wechseln"
-#: builtin/checkout.c:265 builtin/checkout.c:426
+#: builtin/checkout.c:266 builtin/checkout.c:458
msgid "corrupt index file"
-msgstr "beschädigte Bereitstellungsdatei"
+msgstr "beschädigte Staging-Area-Datei"
-#: builtin/checkout.c:295 builtin/checkout.c:302
+#: builtin/checkout.c:329 builtin/checkout.c:336
#, c-format
msgid "path '%s' is unmerged"
msgstr "Pfad '%s' ist nicht zusammengeführt."
-#: builtin/checkout.c:448
+#: builtin/checkout.c:480
msgid "you need to resolve your current index first"
-msgstr "Sie müssen zuerst Ihre aktuelle Bereitstellung auflösen."
+msgstr "Sie müssen zuerst Ihre aktuelle Staging-Area auflösen."
-#: builtin/checkout.c:569
+#: builtin/checkout.c:601
#, c-format
msgid "Can not do reflog for '%s'\n"
msgstr "Konnte \"reflog\" für '%s' nicht durchführen\n"
-#: builtin/checkout.c:602
+#: builtin/checkout.c:639
msgid "HEAD is now at"
-msgstr "Zweigspitze (HEAD) ist jetzt bei"
+msgstr "HEAD ist jetzt bei"
-#: builtin/checkout.c:609
+#: builtin/checkout.c:646
#, c-format
msgid "Reset branch '%s'\n"
-msgstr "Setze Zweig '%s' neu\n"
+msgstr "Setze Branch '%s' neu\n"
-#: builtin/checkout.c:612
+#: builtin/checkout.c:649
#, c-format
msgid "Already on '%s'\n"
msgstr "Bereits auf '%s'\n"
-#: builtin/checkout.c:616
+#: builtin/checkout.c:653
#, c-format
msgid "Switched to and reset branch '%s'\n"
-msgstr "Gewechselt zu neu gesetztem Zweig '%s'\n"
+msgstr "Gewechselt zu umgesetzten Branch '%s'\n"
-#: builtin/checkout.c:618 builtin/checkout.c:955
+#: builtin/checkout.c:655 builtin/checkout.c:997
#, c-format
msgid "Switched to a new branch '%s'\n"
-msgstr "Gewechselt zu einem neuen Zweig '%s'\n"
+msgstr "Gewechselt zu einem neuem Branch '%s'\n"
-#: builtin/checkout.c:620
+#: builtin/checkout.c:657
#, c-format
msgid "Switched to branch '%s'\n"
-msgstr "Gewechselt zu Zweig '%s'\n"
+msgstr "Gewechselt zu Branch '%s'\n"
-#: builtin/checkout.c:676
+#: builtin/checkout.c:713
#, c-format
msgid " ... and %d more.\n"
msgstr " ... und %d weitere.\n"
#. The singular version
-#: builtin/checkout.c:682
+#: builtin/checkout.c:719
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -2959,17 +3319,17 @@ msgid_plural ""
"\n"
"%s\n"
msgstr[0] ""
-"Warnung: Sie sind um %d Version hinterher, nicht verbunden zu\n"
-"einem Ihrer Zweige:\n"
+"Warnung: Sie sind um %d Commit hinterher, nicht verbunden zu\n"
+"einem Ihrer Branches:\n"
"\n"
"%s\n"
msgstr[1] ""
-"Warnung: Sie sind um %d Versionen hinterher, nicht verbunden zu\n"
-"einem Ihrer Zweige:\n"
+"Warnung: Sie sind um %d Commits hinterher, nicht verbunden zu\n"
+"einem Ihrer Branches:\n"
"\n"
"%s\n"
-#: builtin/checkout.c:700
+#: builtin/checkout.c:737
#, c-format
msgid ""
"If you want to keep them by creating a new branch, this may be a good time\n"
@@ -2978,243 +3338,350 @@ msgid ""
" git branch new_branch_name %s\n"
"\n"
msgstr ""
-"Wenn Sie diese durch einen neuen Zweig behalten möchten, dann könnte jetzt\n"
+"Wenn Sie diese durch einen neuen Branch behalten möchten, dann könnte jetzt\n"
"ein guter Zeitpunkt sein dies zu tun mit:\n"
"\n"
-" git branch neuer_zweig_name %s\n"
+" git branch neuer_branch_name %s\n"
"\n"
-#: builtin/checkout.c:730
+#: builtin/checkout.c:767
msgid "internal error in revision walk"
msgstr "interner Fehler im Revisionsgang"
-#: builtin/checkout.c:734
+#: builtin/checkout.c:771
msgid "Previous HEAD position was"
-msgstr "Vorherige Position der Zweigspitze (HEAD) war"
+msgstr "Vorherige Position von HEAD war"
-#: builtin/checkout.c:761 builtin/checkout.c:950
+#: builtin/checkout.c:798 builtin/checkout.c:992
msgid "You are on a branch yet to be born"
-msgstr "Sie sind auf einem Zweig, der noch geboren wird"
+msgstr "Sie sind auf einem Branch, der noch geboren wird"
#. case (1)
-#: builtin/checkout.c:886
+#: builtin/checkout.c:928
#, c-format
msgid "invalid reference: %s"
msgstr "Ungültige Referenz: %s"
#. case (1): want a tree
-#: builtin/checkout.c:925
+#: builtin/checkout.c:967
#, c-format
msgid "reference is not a tree: %s"
-msgstr "Referenz ist kein Baum: %s"
+msgstr "Referenz ist kein \"Tree\"-Objekt: %s"
-#: builtin/checkout.c:964
+#: builtin/checkout.c:1006
msgid "paths cannot be used with switching branches"
-msgstr "Pfade können nicht beim Wechseln von Zweigen verwendet werden"
+msgstr "Pfade können nicht beim Wechseln von Branches verwendet werden"
-#: builtin/checkout.c:967 builtin/checkout.c:971
+#: builtin/checkout.c:1009 builtin/checkout.c:1013
#, c-format
msgid "'%s' cannot be used with switching branches"
-msgstr "'%s' kann nicht beim Wechseln von Zweigen verwendet werden"
+msgstr "'%s' kann nicht beim Wechseln von Branches verwendet werden"
-#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983
-#: builtin/checkout.c:986
+#: builtin/checkout.c:1017 builtin/checkout.c:1020 builtin/checkout.c:1025
+#: builtin/checkout.c:1028
#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "'%s' kann nicht mit '%s' verwendet werden"
-#: builtin/checkout.c:991
+#: builtin/checkout.c:1033
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
-msgstr "Kann Zweig nicht zu Nicht-Version '%s' wechseln"
+msgstr "Kann Branch nicht zu Nicht-Commit '%s' wechseln"
-#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89
+#: builtin/checkout.c:1055 builtin/checkout.c:1057 builtin/clone.c:89
#: builtin/remote.c:169 builtin/remote.c:171
msgid "branch"
-msgstr "Zweig"
+msgstr "Branch"
-#: builtin/checkout.c:1014
+#: builtin/checkout.c:1056
msgid "create and checkout a new branch"
-msgstr "erzeugt und checkt einen neuen Zweig aus"
+msgstr "erzeugt und checkt einen neuen Branch aus"
-#: builtin/checkout.c:1016
+#: builtin/checkout.c:1058
msgid "create/reset and checkout a branch"
-msgstr "erzeugt/setzt neu und checkt einen Zweig aus"
+msgstr "erzeugt/setzt um und checkt einen Branch aus"
-#: builtin/checkout.c:1017
+#: builtin/checkout.c:1059
msgid "create reflog for new branch"
-msgstr "erzeugt Referenzprotokoll für den neuen Zweig"
+msgstr "erzeugt das Reflog für den neuen Branch"
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1060
msgid "detach the HEAD at named commit"
-msgstr "setzt die Zweigspitze (HEAD) zu benannter Version"
+msgstr "setzt HEAD zu benanntem Commit"
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1061
msgid "set upstream info for new branch"
-msgstr "setzt Informationen zum externen Übernahmezweig für den neuen Zweig"
+msgstr "setzt Informationen zum Upstream-Branch für den neuen Branch"
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new branch"
-msgstr "neuer Zweig"
+msgstr "neuer Branch"
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new unparented branch"
-msgstr "neuer Zweig ohne Elternversion"
+msgstr "neuer Branch ohne Eltern-Commit"
-#: builtin/checkout.c:1022
+#: builtin/checkout.c:1064
msgid "checkout our version for unmerged files"
msgstr "checkt unsere Variante für nicht zusammengeführte Dateien aus"
-#: builtin/checkout.c:1024
+#: builtin/checkout.c:1066
msgid "checkout their version for unmerged files"
msgstr "checkt ihre Variante für nicht zusammengeführte Dateien aus"
-#: builtin/checkout.c:1026
+#: builtin/checkout.c:1068
msgid "force checkout (throw away local modifications)"
msgstr "erzwingt Auschecken (verwirft lokale Änderungen)"
-#: builtin/checkout.c:1027
+#: builtin/checkout.c:1069
msgid "perform a 3-way merge with the new branch"
-msgstr "führt eine 3-Wege-Zusammenführung mit dem neuen Zweig aus"
+msgstr "führt einen 3-Wege-Merge mit dem neuen Branch aus"
-#: builtin/checkout.c:1028 builtin/merge.c:215
+#: builtin/checkout.c:1070 builtin/merge.c:232
msgid "update ignored files (default)"
msgstr "aktualisiert ignorierte Dateien (Standard)"
-#: builtin/checkout.c:1029 builtin/log.c:1147 parse-options.h:245
+#: builtin/checkout.c:1071 builtin/log.c:1208 parse-options.h:249
msgid "style"
msgstr "Stil"
-#: builtin/checkout.c:1030
+#: builtin/checkout.c:1072
msgid "conflict style (merge or diff3)"
msgstr "Konfliktstil (merge oder diff3)"
-#: builtin/checkout.c:1033
+#: builtin/checkout.c:1075
+msgid "do not limit pathspecs to sparse entries only"
+msgstr "Pfadspezifikationen ignorieren Einstellungen zum partiellen Auschecken"
+
+#: builtin/checkout.c:1077
msgid "second guess 'git checkout no-such-branch'"
msgstr "second guess 'git checkout no-such-branch'"
-#: builtin/checkout.c:1057
+#: builtin/checkout.c:1101
msgid "-b, -B and --orphan are mutually exclusive"
msgstr "Die Optionen -b, -B und --orphan schließen sich gegenseitig aus."
-#: builtin/checkout.c:1074
+#: builtin/checkout.c:1118
msgid "--track needs a branch name"
-msgstr "Bei der Option --track muss ein Zweigname angegeben werden."
+msgstr "Bei der Option --track muss ein Branchname angegeben werden."
-#: builtin/checkout.c:1081
+#: builtin/checkout.c:1125
msgid "Missing branch name; try -b"
-msgstr "Vermisse Zweignamen; versuchen Sie -b"
+msgstr "Vermisse Branchnamen; versuchen Sie -b"
-#: builtin/checkout.c:1116
+#: builtin/checkout.c:1160
msgid "invalid path specification"
msgstr "ungültige Pfadspezifikation"
-#: builtin/checkout.c:1123
+#: builtin/checkout.c:1167
#, c-format
msgid ""
"Cannot update paths and switch to branch '%s' at the same time.\n"
"Did you intend to checkout '%s' which can not be resolved as commit?"
msgstr ""
-"Kann nicht gleichzeitig Pfade aktualisieren und zu Zweig '%s' wechseln.\n"
-"Haben Sie beabsichtigt '%s' auszuchecken, welcher nicht als Version "
-"aufgelöst werden kann?"
+"Kann nicht gleichzeitig Pfade aktualisieren und zu Branch '%s' wechseln.\n"
+"Haben Sie beabsichtigt '%s' auszuchecken, welcher nicht als Commit aufgelöst "
+"werden kann?"
-#: builtin/checkout.c:1128
+#: builtin/checkout.c:1172
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
msgstr "git checkout: --detach nimmt kein Pfad-Argument '%s'"
-#: builtin/checkout.c:1132
+#: builtin/checkout.c:1176
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
msgstr ""
"git checkout: --ours/--theirs, --force und --merge sind inkompatibel wenn\n"
-"Sie aus der Bereitstellung auschecken."
+"Sie aus der Staging-Area auschecken."
-#: builtin/clean.c:20
-msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
-msgstr "git clean [-d] [-f] [-n] [-q] [-e <Muster>] [-x | -X] [--] <Pfade>..."
+#: builtin/clean.c:25
+msgid ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <Muster>] [-x | -X] [--] <Pfade>..."
-#: builtin/clean.c:24
+#: builtin/clean.c:29
#, c-format
msgid "Removing %s\n"
msgstr "Lösche %s\n"
-#: builtin/clean.c:25
+#: builtin/clean.c:30
#, c-format
msgid "Would remove %s\n"
msgstr "Würde %s löschen\n"
-#: builtin/clean.c:26
+#: builtin/clean.c:31
#, c-format
msgid "Skipping repository %s\n"
-msgstr "Ãœberspringe Projektarchiv %s\n"
+msgstr "Ãœberspringe Repository %s\n"
-#: builtin/clean.c:27
+#: builtin/clean.c:32
#, c-format
msgid "Would skip repository %s\n"
-msgstr "Würde Projektarchiv %s überspringen\n"
+msgstr "Würde Repository %s überspringen\n"
-#: builtin/clean.c:28
+#: builtin/clean.c:33
#, c-format
msgid "failed to remove %s"
msgstr "Fehler beim Löschen von %s"
-#: builtin/clean.c:160
+#: builtin/clean.c:293
+msgid ""
+"Prompt help:\n"
+"1 - select a numbered item\n"
+"foo - select item based on unique prefix\n"
+" - (empty) select nothing"
+msgstr ""
+"Eingabehilfe:\n"
+"1 - nummeriertes Element auswählen\n"
+"foo - Element anhand eines eindeutigen Prefix auswählen\n"
+" - (leer) nichts auswählen"
+
+#: builtin/clean.c:297
+msgid ""
+"Prompt help:\n"
+"1 - select a single item\n"
+"3-5 - select a range of items\n"
+"2-3,6-9 - select multiple ranges\n"
+"foo - select item based on unique prefix\n"
+"-... - unselect specified items\n"
+"* - choose all items\n"
+" - (empty) finish selecting"
+msgstr ""
+"Eingabehilfe:\n"
+"1 - einzelnes Element auswählen\n"
+"3-5 - Bereich von Elementen auswählen\n"
+"2-3,6-9 - mehrere Bereiche auswählen\n"
+"foo - Element anhand eines eindeutigen Prefix auswählen\n"
+"-... - angegebenes Element abwählen\n"
+"* - alle Elemente auswählen\n"
+" - (leer) Auswahl beenden"
+
+#: builtin/clean.c:515
+#, c-format
+msgid "Huh (%s)?"
+msgstr "Wie bitte (%s)?"
+
+#: builtin/clean.c:658
+#, c-format
+msgid "Input ignore patterns>> "
+msgstr "Ignorier-Muster eingeben>> "
+
+#: builtin/clean.c:695
+#, c-format
+msgid "WARNING: Cannot find items matched by: %s"
+msgstr "WARNUNG: Kann keine Einträge finden die Muster entsprechen: %s"
+
+#: builtin/clean.c:716
+msgid "Select items to delete"
+msgstr "Wählen Sie Einträge zum Löschen"
+
+#: builtin/clean.c:756
+#, c-format
+msgid "remove %s? "
+msgstr "'%s' löschen? "
+
+#: builtin/clean.c:781
+msgid "Bye."
+msgstr "Tschüss."
+
+#: builtin/clean.c:789
+msgid ""
+"clean - start cleaning\n"
+"filter by pattern - exclude items from deletion\n"
+"select by numbers - select items to be deleted by numbers\n"
+"ask each - confirm each deletion (like \"rm -i\")\n"
+"quit - stop cleaning\n"
+"help - this screen\n"
+"? - help for prompt selection"
+msgstr ""
+"clean - Clean starten\n"
+"filter by pattern - Einträge von Löschung ausschließen\n"
+"select by numbers - Auswahl von Einträgen über Nummern\n"
+"ask each - jede Löschung bestätigen (wie \"rm -i\")\n"
+"quit - Clean beenden\n"
+"help - diese Meldung anzeigen\n"
+"? - Hilfe zur Auswahl mittels Eingabe anzeigen"
+
+#: builtin/clean.c:816
+msgid "*** Commands ***"
+msgstr "*** Kommandos ***"
+
+#: builtin/clean.c:817
+msgid "What now"
+msgstr "Was nun"
+
+#: builtin/clean.c:825
+msgid "Would remove the following item:"
+msgid_plural "Would remove the following items:"
+msgstr[0] "Würde das folgende Element entfernen:"
+msgstr[1] "Würde die folgenden Elemente entfernen:"
+
+#: builtin/clean.c:842
+msgid "No more files to clean, exiting."
+msgstr "Keine Dateien mehr zum Löschen, beende."
+
+#: builtin/clean.c:874
msgid "do not print names of files removed"
msgstr "gibt keine Namen von gelöschten Dateien aus"
-#: builtin/clean.c:162
+#: builtin/clean.c:876
msgid "force"
msgstr "erzwingt Aktion"
-#: builtin/clean.c:164
+#: builtin/clean.c:877
+msgid "interactive cleaning"
+msgstr "interaktives Clean"
+
+#: builtin/clean.c:879
msgid "remove whole directories"
msgstr "löscht ganze Verzeichnisse"
-#: builtin/clean.c:165 builtin/describe.c:413 builtin/grep.c:717
-#: builtin/ls-files.c:494 builtin/name-rev.c:231 builtin/show-ref.c:182
+#: builtin/clean.c:880 builtin/describe.c:420 builtin/grep.c:716
+#: builtin/ls-files.c:493 builtin/name-rev.c:315 builtin/show-ref.c:186
msgid "pattern"
msgstr "Muster"
-#: builtin/clean.c:166
+#: builtin/clean.c:881
msgid "add <pattern> to ignore rules"
msgstr "fügt <Muster> zu den Regeln für ignorierte Pfade hinzu"
-#: builtin/clean.c:167
+#: builtin/clean.c:882
msgid "remove ignored files, too"
msgstr "löscht auch ignorierte Dateien"
-#: builtin/clean.c:169
+#: builtin/clean.c:884
msgid "remove only ignored files"
msgstr "löscht nur ignorierte Dateien"
-#: builtin/clean.c:187
+#: builtin/clean.c:902
msgid "-x and -X cannot be used together"
msgstr "Die Optionen -x und -X können nicht gemeinsam verwendet werden."
-#: builtin/clean.c:191
+#: builtin/clean.c:906
msgid ""
-"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+"clean.requireForce set to true and neither -i, -n nor -f given; refusing to "
+"clean"
msgstr ""
-"clean.requireForce auf \"true\" gesetzt und weder -n noch -f gegeben; "
-"Säuberung verweigert"
+"clean.requireForce auf \"true\" gesetzt und weder -i, -n noch -f gegeben; "
+"\"clean\" verweigert"
-#: builtin/clean.c:194
+#: builtin/clean.c:909
msgid ""
-"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
-"clean"
+"clean.requireForce defaults to true and neither -i, -n nor -f given; "
+"refusing to clean"
msgstr ""
-"clean.requireForce standardmäßig auf \"true\" gesetzt und weder -n noch -f "
-"gegeben; Säuberung verweigert"
+"clean.requireForce standardmäßig auf \"true\" gesetzt und weder -i, -n noch -"
+"f gegeben; \"clean\" verweigert"
#: builtin/clone.c:36
msgid "git clone [options] [--] <repo> [<dir>]"
-msgstr "git clone [Optionen] [--] <Projektarchiv> [<Verzeichnis>]"
+msgstr "git clone [Optionen] [--] <Repository> [<Verzeichnis>]"
-#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
-#: builtin/push.c:436
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:229
+#: builtin/push.c:462
msgid "force progress reporting"
msgstr "erzwingt Fortschrittsanzeige"
@@ -3224,27 +3691,27 @@ msgstr "kein Auschecken"
#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
msgid "create a bare repository"
-msgstr "erstellt ein bloßes Projektarchiv"
+msgstr "erstellt ein Bare-Repository"
#: builtin/clone.c:72
msgid "create a mirror repository (implies bare)"
-msgstr "erstellt ein Spiegelarchiv (impliziert bloßes Projektarchiv)"
+msgstr "erstellt ein Spiegelarchiv (impliziert --bare)"
#: builtin/clone.c:74
msgid "to clone from a local repository"
-msgstr "um von einem lokalen Projektarchiv zu klonen"
+msgstr "um von einem lokalen Repository zu klonen"
#: builtin/clone.c:76
msgid "don't use local hardlinks, always copy"
-msgstr "verwendet lokal keine harten Links, immer Kopien"
+msgstr "verwendet lokal keine harten Verweise, immer Kopien"
#: builtin/clone.c:78
msgid "setup as shared repository"
-msgstr "Einrichtung als verteiltes Projektarchiv"
+msgstr "Einrichtung als verteiltes Repository"
#: builtin/clone.c:80 builtin/clone.c:82
msgid "initialize submodules in the clone"
-msgstr "initialisiert Unterprojekte im Klon"
+msgstr "initialisiert Submodule im Klon"
#: builtin/clone.c:83 builtin/init-db.c:485
msgid "template-directory"
@@ -3256,7 +3723,7 @@ msgstr "Verzeichnis, von welchem die Vorlagen verwendet werden"
#: builtin/clone.c:86
msgid "reference repository"
-msgstr "referenziert Projektarchiv"
+msgstr "referenziert Repository"
#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
msgid "name"
@@ -3264,18 +3731,17 @@ msgstr "Name"
#: builtin/clone.c:88
msgid "use <name> instead of 'origin' to track upstream"
-msgstr "verwendet <Name> statt 'origin' für externes Projektarchiv"
+msgstr "verwendet <Name> statt 'origin' für Upstream-Repository"
#: builtin/clone.c:90
msgid "checkout <branch> instead of the remote's HEAD"
-msgstr ""
-"checkt <Zweig> aus, anstatt Zweigspitze (HEAD) des externen Projektarchivs"
+msgstr "checkt <Branch> aus, anstatt HEAD des Remote-Repositories"
#: builtin/clone.c:92
msgid "path to git-upload-pack on the remote"
msgstr "Pfad zu \"git-upload-pack\" auf der Gegenseite"
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:661
msgid "depth"
msgstr "Tiefe"
@@ -3285,7 +3751,7 @@ msgstr "erstellt einen flachen Klon mit dieser Tiefe"
#: builtin/clone.c:96
msgid "clone only one branch, HEAD or --branch"
-msgstr "klont nur einen Zweig, Zweigspitze (HEAD) oder --branch"
+msgstr "klont nur einen Branch, HEAD oder --branch"
#: builtin/clone.c:97 builtin/init-db.c:494
msgid "gitdir"
@@ -3293,7 +3759,7 @@ msgstr ".git-Verzeichnis"
#: builtin/clone.c:98 builtin/init-db.c:495
msgid "separate git dir from working tree"
-msgstr "separiert Git-Verzeichnis vom Arbeitsbaum"
+msgstr "separiert Git-Verzeichnis vom Arbeitsverzeichnis"
#: builtin/clone.c:99
msgid "key=value"
@@ -3301,130 +3767,162 @@ msgstr "Schlüssel=Wert"
#: builtin/clone.c:100
msgid "set config inside the new repository"
-msgstr "setzt Konfiguration innerhalb des neuen Projektarchivs"
+msgstr "setzt Konfiguration innerhalb des neuen Repositories"
-#: builtin/clone.c:243
+#: builtin/clone.c:253
#, c-format
-msgid "reference repository '%s' is not a local directory."
-msgstr "Referenziertes Projektarchiv '%s' ist kein lokales Verzeichnis."
+msgid "reference repository '%s' is not a local repository."
+msgstr "Referenziertes Repository '%s' ist kein lokales Repository."
-#: builtin/clone.c:306
+#: builtin/clone.c:316
#, c-format
msgid "failed to create directory '%s'"
msgstr "Fehler beim Erstellen von Verzeichnis '%s'"
-#: builtin/clone.c:308 builtin/diff.c:77
+#: builtin/clone.c:318 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
msgstr "Konnte '%s' nicht lesen"
-#: builtin/clone.c:310
+#: builtin/clone.c:320
#, c-format
msgid "%s exists and is not a directory"
msgstr "%s existiert und ist kein Verzeichnis"
-#: builtin/clone.c:324
+#: builtin/clone.c:334
#, c-format
msgid "failed to stat %s\n"
msgstr "Konnte %s nicht lesen\n"
-#: builtin/clone.c:346
+#: builtin/clone.c:356
#, c-format
msgid "failed to create link '%s'"
-msgstr "Konnte Verknüpfung '%s' nicht erstellen"
+msgstr "Konnte Verweis '%s' nicht erstellen"
-#: builtin/clone.c:350
+#: builtin/clone.c:360
#, c-format
msgid "failed to copy file to '%s'"
msgstr "Konnte Datei nicht nach '%s' kopieren"
-#: builtin/clone.c:373
+#: builtin/clone.c:383
#, c-format
msgid "done.\n"
msgstr "Fertig.\n"
-#: builtin/clone.c:443
+#: builtin/clone.c:396
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry the checkout with 'git checkout -f HEAD'\n"
+msgstr ""
+"Klonen erfolgreich, Auschecken ist aber fehlgeschlagen.\n"
+"Sie können mit 'git status' prüfen, was ausgecheckt worden ist\n"
+"und das Auschecken mit 'git checkout -f HEAD' erneut versuchen.\n"
+
+#: builtin/clone.c:475
#, c-format
msgid "Could not find remote branch %s to clone."
-msgstr "Konnte zu klonenden externer Zweig %s nicht finden."
+msgstr "Konnte zu klonenden Remote-Branch %s nicht finden."
+
+#: builtin/clone.c:555
+#, c-format
+msgid "Checking connectivity... "
+msgstr "Prüfe Konnektivität... "
+
+#: builtin/clone.c:558
+msgid "remote did not send all necessary objects"
+msgstr "Remote-Repository hat nicht alle erforderlichen Objekte gesendet."
-#: builtin/clone.c:552
+#: builtin/clone.c:560
+#, c-format
+msgid "done\n"
+msgstr "Fertig\n"
+
+#: builtin/clone.c:621
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"
+"Externer HEAD bezieht sich auf eine nicht existierende Referenz und kann "
+"nicht ausgecheckt werden.\n"
+
+#: builtin/clone.c:652
+msgid "unable to checkout working tree"
+msgstr "Arbeitsverzeichnis konnte nicht ausgecheckt werden"
-#: builtin/clone.c:690
+#: builtin/clone.c:760
msgid "Too many arguments."
msgstr "Zu viele Argumente."
-#: builtin/clone.c:694
+#: builtin/clone.c:764
msgid "You must specify a repository to clone."
-msgstr "Sie müssen ein Projektarchiv zum Klonen angeben."
+msgstr "Sie müssen ein Repository zum Klonen angeben."
-#: builtin/clone.c:705
+#: builtin/clone.c:775
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr "Die Optionen --bare und --origin %s sind inkompatibel."
-#: builtin/clone.c:708
+#: builtin/clone.c:778
msgid "--bare and --separate-git-dir are incompatible."
msgstr "Die Optionen --bare und --separate-git-dir sind inkompatibel."
-#: builtin/clone.c:721
+#: builtin/clone.c:791
#, c-format
msgid "repository '%s' does not exist"
-msgstr "Projektarchiv '%s' existiert nicht."
+msgstr "Repository '%s' existiert nicht."
-#: builtin/clone.c:726
+#: builtin/clone.c:796
msgid "--depth is ignored in local clones; use file:// instead."
msgstr ""
"Die Option --depth wird in lokalen Klonen ignoriert; benutzen Sie "
"stattdessen file://"
-#: builtin/clone.c:736
+#: builtin/clone.c:798
+msgid "--local is ignored"
+msgstr "--local wird ignoriert"
+
+#: builtin/clone.c:808
#, 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:746
+#: builtin/clone.c:818
#, c-format
msgid "working tree '%s' already exists."
-msgstr "Arbeitsbaum '%s' existiert bereits."
+msgstr "Arbeitsverzeichnis '%s' existiert bereits."
-#: builtin/clone.c:759 builtin/clone.c:771
+#: builtin/clone.c:831 builtin/clone.c:843
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "Konnte führende Verzeichnisse von '%s' nicht erstellen."
-#: builtin/clone.c:762
+#: builtin/clone.c:834
#, c-format
msgid "could not create work tree dir '%s'."
msgstr "Konnte Arbeitsverzeichnis '%s' nicht erstellen."
-#: builtin/clone.c:781
+#: builtin/clone.c:853
#, c-format
msgid "Cloning into bare repository '%s'...\n"
-msgstr "Klone in bloßes Projektarchiv '%s'...\n"
+msgstr "Klone in Bare-Repository '%s'...\n"
-#: builtin/clone.c:783
+#: builtin/clone.c:855
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "Klone nach '%s'...\n"
-#: builtin/clone.c:818
+#: builtin/clone.c:890
#, c-format
msgid "Don't know how to clone %s"
msgstr "Weiß nicht wie %s zu klonen ist."
-#: builtin/clone.c:867
+#: builtin/clone.c:942
#, c-format
msgid "Remote branch %s not found in upstream %s"
-msgstr "externer Zweig %s nicht im anderen Projektarchiv %s gefunden"
+msgstr "Remote-Branch %s nicht im Upstream-Repository %s gefunden"
-#: builtin/clone.c:874
+#: builtin/clone.c:949
msgid "You appear to have cloned an empty repository."
-msgstr "Sie scheinen ein leeres Projektarchiv geklont zu haben."
+msgstr "Sie scheinen ein leeres Repository geklont zu haben."
#: builtin/column.c:9
msgid "git column [options]"
@@ -3458,15 +3956,15 @@ msgstr "Abstand zwischen Spalten"
msgid "--command must be the first argument"
msgstr "Die Option --command muss an erster Stelle stehen."
-#: builtin/commit.c:34
+#: builtin/commit.c:35
msgid "git commit [options] [--] <pathspec>..."
msgstr "git commit [Optionen] [--] <Pfadspezifikation>..."
-#: builtin/commit.c:39
+#: builtin/commit.c:40
msgid "git status [options] [--] <pathspec>..."
msgstr "git status [Optionen] [--] <Pfadspezifikation>..."
-#: builtin/commit.c:44
+#: builtin/commit.c:45
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
@@ -3487,129 +3985,144 @@ msgstr ""
" git config --global user.name \"Ihr Name\"\n"
" git config --global user.email ihre@emailadresse.de\n"
"\n"
-"Nachdem Sie das getan hast, können Sie Ihre Identität für diese Version "
+"Nachdem Sie das getan hast, können Sie Ihre Identität für diesen Commit "
"ändern mit:\n"
"\n"
" git commit --amend --reset-author\n"
-#: builtin/commit.c:56
+#: builtin/commit.c:57
msgid ""
"You asked to amend the most recent commit, but doing so would make\n"
"it empty. You can repeat your command with --allow-empty, or you can\n"
"remove the commit entirely with \"git reset HEAD^\".\n"
msgstr ""
-"Sie fragten die jüngste Version nachzubessern, aber das würde diese leer\n"
-"machen. Sie können Ihr Kommando mit --allow-empty wiederholen, oder die\n"
-"Version mit \"git reset HEAD^\" vollständig entfernen.\n"
+"Sie fragten den jüngsten Commit nachzubessern, aber das würde diesen leer\n"
+"machen. Sie können Ihr Kommando mit --allow-empty wiederholen, oder diesen\n"
+"Commit mit \"git reset HEAD^\" vollständig entfernen.\n"
-#: builtin/commit.c:61
+#: builtin/commit.c:62
msgid ""
"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
"If you wish to commit it anyway, use:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Otherwise, please use 'git reset'\n"
msgstr ""
"Der letzte \"cherry-pick\" ist jetzt leer, möglicherweise durch eine "
"Konfliktauflösung.\n"
-"Wenn Sie dies trotzdem eintragen wollen, benutzen Sie:\n"
+"Wenn Sie dies trotzdem committen wollen, benutzen Sie:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Andernfalls benutzen Sie bitte 'git reset'\n"
-#: builtin/commit.c:258
+#: builtin/commit.c:69
+msgid "Otherwise, please use 'git reset'\n"
+msgstr "Andernfalls benutzen Sie bitte 'git reset'\n"
+
+#: builtin/commit.c:72
+msgid ""
+"If you wish to skip this commit, use:\n"
+"\n"
+" git reset\n"
+"\n"
+"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
+"the remaining commits.\n"
+msgstr ""
+"Wenn Sie diesen Commit auslassen möchten, benutzen Sie:\n"
+"\n"
+" git reset\n"
+"\n"
+"Benutzen Sie anschließend \"git cherry-pick --continue\", um die\n"
+"Cherry-Pick-Operation mit den verbleibenden Commits fortzusetzen.\n"
+
+#: builtin/commit.c:279
msgid "failed to unpack HEAD tree object"
-msgstr "Fehler beim Entpacken des Baum-Objektes der Zweigspitze (HEAD)."
+msgstr "Fehler beim Entpacken des \"Tree\"-Objektes von HEAD."
-#: builtin/commit.c:300
+#: builtin/commit.c:321
msgid "unable to create temporary index"
-msgstr "Konnte temporäre Bereitstellung nicht erstellen."
+msgstr "Konnte temporäre Staging-Area nicht erstellen."
-#: builtin/commit.c:306
+#: builtin/commit.c:327
msgid "interactive add failed"
msgstr "interaktives Hinzufügen fehlgeschlagen"
-#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410
+#: builtin/commit.c:360 builtin/commit.c:381 builtin/commit.c:431
msgid "unable to write new_index file"
msgstr "Konnte new_index Datei nicht schreiben"
-#: builtin/commit.c:391
+#: builtin/commit.c:412
msgid "cannot do a partial commit during a merge."
-msgstr ""
-"Kann keine partielle Eintragung durchführen, während eine Zusammenführung im "
-"Gange ist."
+msgstr "Kann keinen Teil-Commit durchführen, während ein Merge im Gange ist."
-#: builtin/commit.c:393
+#: builtin/commit.c:414
msgid "cannot do a partial commit during a cherry-pick."
msgstr ""
-"Kann keine partielle Eintragung durchführen, während \"cherry-pick\" im "
-"Gange ist."
+"Kann keinen Teil-Commit durchführen, während \"cherry-pick\" im Gange ist."
-#: builtin/commit.c:403
+#: builtin/commit.c:424
msgid "cannot read the index"
-msgstr "Kann Bereitstellung nicht lesen"
+msgstr "Kann Staging-Area nicht lesen"
-#: builtin/commit.c:423
+#: builtin/commit.c:444
msgid "unable to write temporary index file"
-msgstr "Konnte temporäre Bereitstellungsdatei nicht schreiben."
+msgstr "Konnte temporäre Staging-Area-Datei nicht schreiben."
-#: builtin/commit.c:511 builtin/commit.c:517
+#: builtin/commit.c:535 builtin/commit.c:541
#, c-format
msgid "invalid commit: %s"
-msgstr "Ungültige Version: %s"
+msgstr "Ungültiger Commit: %s"
-#: builtin/commit.c:540
+#: builtin/commit.c:563
msgid "malformed --author parameter"
msgstr "Fehlerhafter --author Parameter"
-#: builtin/commit.c:560
+#: builtin/commit.c:583
#, c-format
msgid "Malformed ident string: '%s'"
-msgstr "Fehlerhafte Identifikations-String: '%s'"
+msgstr "Fehlerhafter Ident-String: '%s'"
-#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954
+#: builtin/commit.c:621 builtin/commit.c:654 builtin/commit.c:982
#, c-format
msgid "could not lookup commit %s"
-msgstr "Konnte Version %s nicht nachschlagen"
+msgstr "Konnte Commit %s nicht nachschlagen"
-#: builtin/commit.c:610 builtin/shortlog.c:272
+#: builtin/commit.c:633 builtin/shortlog.c:271
#, c-format
msgid "(reading log message from standard input)\n"
msgstr "(lese Log-Nachricht von Standard-Eingabe)\n"
-#: builtin/commit.c:612
+#: builtin/commit.c:635
msgid "could not read log from standard input"
msgstr "Konnte Log nicht von Standard-Eingabe lesen."
-#: builtin/commit.c:616
+#: builtin/commit.c:639
#, c-format
msgid "could not read log file '%s'"
msgstr "Konnte Log-Datei '%s' nicht lesen"
-#: builtin/commit.c:622
+#: builtin/commit.c:645
msgid "commit has empty message"
-msgstr "Version hat eine leere Beschreibung"
+msgstr "Commit hat eine leere Beschreibung"
-#: builtin/commit.c:638
+#: builtin/commit.c:661
msgid "could not read MERGE_MSG"
msgstr "Konnte MERGE_MSG nicht lesen"
-#: builtin/commit.c:642
+#: builtin/commit.c:665
msgid "could not read SQUASH_MSG"
msgstr "Konnte SQUASH_MSG nicht lesen"
-#: builtin/commit.c:646
+#: builtin/commit.c:669
#, c-format
msgid "could not read '%s'"
msgstr "Konnte '%s' nicht lesen"
-#: builtin/commit.c:707
+#: builtin/commit.c:730
msgid "could not write commit template"
-msgstr "Konnte Versionsvorlage nicht schreiben"
+msgstr "Konnte Commit-Vorlage nicht schreiben"
-#: builtin/commit.c:718
+#: builtin/commit.c:741
#, c-format
msgid ""
"\n"
@@ -3619,12 +4132,12 @@ msgid ""
"and try again.\n"
msgstr ""
"\n"
-"Es sieht so aus, als tragen Sie eine Zusammenführung ein.\n"
+"Es sieht so aus, als committen Sie einen Merge.\n"
"Falls das nicht korrekt ist, löschen Sie bitte die Datei\n"
"\t%s\n"
"und versuchen Sie es erneut.\n"
-#: builtin/commit.c:723
+#: builtin/commit.c:746
#, c-format
msgid ""
"\n"
@@ -3634,406 +4147,406 @@ msgid ""
"and try again.\n"
msgstr ""
"\n"
-"Es sieht so aus, als tragen Sie ein \"cherry-pick\" ein.\n"
+"Es sieht so aus, als committen Sie einen \"cherry-pick\".\n"
"Falls das nicht korrekt ist, löschen Sie bitte die Datei\n"
"\t%s\n"
"und versuchen Sie es erneut.\n"
-#: builtin/commit.c:735
+#: builtin/commit.c:758
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '%c' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
-"Bitte geben Sie eine Versionsbeschreibung für Ihre Änderungen ein. Zeilen,\n"
-"die mit '%c' beginnen, werden ignoriert, und eine leere "
-"Versionsbeschreibung\n"
-"bricht die Eintragung ab.\n"
+"Bitte geben Sie eine Commit-Beschreibung für Ihre Änderungen ein. Zeilen,\n"
+"die mit '%c' beginnen, werden ignoriert, und eine leere Beschreibung\n"
+"bricht den Commit ab.\n"
-#: builtin/commit.c:740
+#: builtin/commit.c:763
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '%c' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
-"Bitte geben Sie eine Versionsbeschreibung für Ihre Änderungen ein. Zeilen, "
+"Bitte geben Sie eine Commit-Beschreibung für Ihre Änderungen ein. Zeilen, "
"die\n"
"mit '%c' beginnen, werden beibehalten; wenn Sie möchten, können Sie diese "
"entfernen.\n"
-"Eine leere Versionsbeschreibung bricht die Eintragung ab.\n"
+"Eine leere Beschreibung bricht den Commit ab.\n"
-#: builtin/commit.c:753
+#: builtin/commit.c:776
#, c-format
msgid "%sAuthor: %s"
msgstr "%sAutor: %s"
-#: builtin/commit.c:760
+#: builtin/commit.c:783
#, c-format
msgid "%sCommitter: %s"
-msgstr "%sEintragender: %s"
+msgstr "%sCommit-Ersteller: %s"
-#: builtin/commit.c:780
+#: builtin/commit.c:803
msgid "Cannot read index"
-msgstr "Kann Bereitstellung nicht lesen"
+msgstr "Kann Staging-Area nicht lesen"
-#: builtin/commit.c:817
+#: builtin/commit.c:845
msgid "Error building trees"
-msgstr "Fehler beim Erzeugen der Zweige"
+msgstr "Fehler beim Erzeugen der \"Tree\"-Objekte"
-#: builtin/commit.c:832 builtin/tag.c:359
+#: builtin/commit.c:860 builtin/tag.c:359
#, 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"
+msgstr ""
+"Bitte liefern Sie eine Beschreibung entweder mit der Option -m oder -F.\n"
-#: builtin/commit.c:929
+#: builtin/commit.c:957
#, c-format
msgid "No existing author found with '%s'"
msgstr "Kein existierender Autor mit '%s' gefunden."
-#: builtin/commit.c:944 builtin/commit.c:1138
+#: builtin/commit.c:972 builtin/commit.c:1208
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr "Ungültiger Modus '%s' für unbeobachtete Dateien"
-#: builtin/commit.c:974
+#: builtin/commit.c:1009
+msgid "--long and -z are incompatible"
+msgstr "Die Optionen --long und -z sind inkompatibel."
+
+#: builtin/commit.c:1039
msgid "Using both --reset-author and --author does not make sense"
msgstr ""
"Die Optionen --reset-author und --author können nicht gemeinsam verwendet "
"werden."
-#: builtin/commit.c:985
+#: builtin/commit.c:1050
msgid "You have nothing to amend."
-msgstr "Sie haben nichts zum nachbessern."
+msgstr "Sie haben nichts für \"--amend\"."
-#: builtin/commit.c:988
+#: builtin/commit.c:1053
msgid "You are in the middle of a merge -- cannot amend."
-msgstr "Eine Zusammenführung ist im Gange -- kann nicht nachbessern."
+msgstr "Ein Merge ist im Gange -- kann \"--amend\" nicht ausführen."
-#: builtin/commit.c:990
+#: builtin/commit.c:1055
msgid "You are in the middle of a cherry-pick -- cannot amend."
-msgstr "\"cherry-pick\" ist im Gange -- kann nicht nachbessern."
+msgstr "\"cherry-pick\" ist im Gange -- kann \"--amend\" nicht ausführen."
-#: builtin/commit.c:993
+#: builtin/commit.c:1058
msgid "Options --squash and --fixup cannot be used together"
msgstr ""
"Die Optionen --squash und --fixup können nicht gemeinsam verwendet werden."
-#: builtin/commit.c:1003
+#: builtin/commit.c:1068
msgid "Only one of -c/-C/-F/--fixup can be used."
msgstr "Es kann nur eine Option von -c/-C/-F/--fixup verwendet werden."
-#: builtin/commit.c:1005
+#: builtin/commit.c:1070
msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
msgstr "Die Option -m kann nicht mit -c/-C/-F/--fixup kombiniert werden."
-#: builtin/commit.c:1013
+#: builtin/commit.c:1078
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr ""
"Die Option --reset--author kann nur mit -C, -c oder --amend verwendet werden."
-#: builtin/commit.c:1030
+#: builtin/commit.c:1095
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
msgstr ""
"Es kann nur eine Option von --include/--only/--all/--interactive/--patch "
"verwendet werden."
-#: builtin/commit.c:1032
+#: builtin/commit.c:1097
msgid "No paths with --include/--only does not make sense."
msgstr ""
"Die Optionen --include und --only können nur mit der Angabe von Pfaden "
"verwendet werden."
-#: builtin/commit.c:1034
+#: builtin/commit.c:1099
msgid "Clever... amending the last one with dirty index."
msgstr ""
-"Klug... die letzte Version mit einer unsauberen Bereitstellung nachbessern."
+"Klug... den letzten Commit mit einer geänderten Staging-Area nachbessern."
-#: builtin/commit.c:1036
+#: builtin/commit.c:1101
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:1046 builtin/tag.c:575
+#: builtin/commit.c:1111 builtin/tag.c:575
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "Ungültiger \"cleanup\" Modus %s"
-#: builtin/commit.c:1051
+#: builtin/commit.c:1116
msgid "Paths with -a does not make sense."
msgstr "Die Option -a kann nur mit der Angabe von Pfaden verwendet werden."
-#: builtin/commit.c:1057 builtin/commit.c:1192
-msgid "--long and -z are incompatible"
-msgstr "Die Optionen --long und -z sind inkompatibel."
-
-#: builtin/commit.c:1152 builtin/commit.c:1388
+#: builtin/commit.c:1222 builtin/commit.c:1455
msgid "show status concisely"
msgstr "zeigt Status im Kurzformat"
-#: builtin/commit.c:1154 builtin/commit.c:1390
+#: builtin/commit.c:1224 builtin/commit.c:1457
msgid "show branch information"
-msgstr "zeigt Zweiginformationen"
+msgstr "zeigt Branchinformationen"
-#: builtin/commit.c:1156 builtin/commit.c:1392 builtin/push.c:426
+#: builtin/commit.c:1226 builtin/commit.c:1459 builtin/push.c:452
msgid "machine-readable output"
msgstr "maschinenlesbare Ausgabe"
-#: builtin/commit.c:1159 builtin/commit.c:1394
+#: builtin/commit.c:1229 builtin/commit.c:1461
msgid "show status in long format (default)"
msgstr "zeigt Status im Langformat (Standard)"
-#: builtin/commit.c:1162 builtin/commit.c:1397
+#: builtin/commit.c:1232 builtin/commit.c:1464
msgid "terminate entries with NUL"
msgstr "schließt Einträge mit NUL-Zeichen ab"
-#: builtin/commit.c:1164 builtin/commit.c:1400 builtin/fast-export.c:647
-#: builtin/fast-export.c:650 builtin/tag.c:459
+#: builtin/commit.c:1234 builtin/commit.c:1467 builtin/fast-export.c:667
+#: builtin/fast-export.c:670 builtin/tag.c:459
msgid "mode"
msgstr "Modus"
-#: builtin/commit.c:1165 builtin/commit.c:1400
+#: builtin/commit.c:1235 builtin/commit.c:1467
msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
msgstr ""
"zeigt nicht beobachtete Dateien, optionale Modi: all, normal, no. (Standard: "
"all)"
-#: builtin/commit.c:1168
+#: builtin/commit.c:1238
msgid "show ignored files"
msgstr "zeigt ignorierte Dateien"
-#: builtin/commit.c:1169 parse-options.h:151
+#: builtin/commit.c:1239 parse-options.h:154
msgid "when"
msgstr "wann"
-#: builtin/commit.c:1170
+#: builtin/commit.c:1240
msgid ""
"ignore changes to submodules, optional when: all, dirty, untracked. "
"(Default: all)"
msgstr ""
-"ignoriert Änderungen in Unterprojekten, optional wenn: all, dirty, "
-"untracked. (Standard: all)"
+"ignoriert Änderungen in Submodulen, optional wenn: all, dirty, untracked. "
+"(Standard: all)"
-#: builtin/commit.c:1172
+#: builtin/commit.c:1242
msgid "list untracked files in columns"
msgstr "listet unbeobachtete Dateien in Spalten auf"
-#: builtin/commit.c:1246
+#: builtin/commit.c:1313
msgid "couldn't look up newly created commit"
-msgstr "Konnte neu erstellte Version nicht nachschlagen."
+msgstr "Konnte neu erstellten Commit nicht nachschlagen."
-#: builtin/commit.c:1248
+#: builtin/commit.c:1315
msgid "could not parse newly created commit"
-msgstr "Konnte neulich erstellte Version nicht analysieren."
+msgstr "Konnte neulich erstellten Commit nicht analysieren."
-#: builtin/commit.c:1289
+#: builtin/commit.c:1356
msgid "detached HEAD"
-msgstr "losgelöste Zweigspitze (HEAD)"
+msgstr "losgelöster HEAD"
-#: builtin/commit.c:1291
+#: builtin/commit.c:1358
msgid " (root-commit)"
-msgstr " (Basis-Version)"
+msgstr " (Basis-Commit)"
-#: builtin/commit.c:1358
+#: builtin/commit.c:1425
msgid "suppress summary after successful commit"
-msgstr "unterdrückt Zusammenfassung nach erfolgreicher Eintragung"
+msgstr "unterdrückt Zusammenfassung nach erfolgreichem Commit"
-#: builtin/commit.c:1359
+#: builtin/commit.c:1426
msgid "show diff in commit message template"
-msgstr "zeigt Unterschiede in Versionsbeschreibungsvorlage an"
+msgstr "zeigt Unterschiede in Commit-Beschreibungsvorlage an"
-#: builtin/commit.c:1361
+#: builtin/commit.c:1428
msgid "Commit message options"
-msgstr "Optionen für Versionsbeschreibung"
+msgstr "Optionen für Commit-Beschreibung"
-#: builtin/commit.c:1362 builtin/tag.c:457
+#: builtin/commit.c:1429 builtin/tag.c:457
msgid "read message from file"
msgstr "liest Beschreibung von Datei"
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "author"
msgstr "Autor"
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "override author for commit"
-msgstr "überschreibt Autor von Version"
+msgstr "überschreibt Autor eines Commits"
-#: builtin/commit.c:1364 builtin/gc.c:178
+#: builtin/commit.c:1431 builtin/gc.c:178
msgid "date"
msgstr "Datum"
-#: builtin/commit.c:1364
+#: builtin/commit.c:1431
msgid "override date for commit"
-msgstr "überschreibt Datum von Version"
+msgstr "überschreibt Datum eines Commits"
-#: builtin/commit.c:1365 builtin/merge.c:206 builtin/notes.c:533
-#: builtin/notes.c:690 builtin/tag.c:455
+#: builtin/commit.c:1432 builtin/merge.c:223 builtin/notes.c:405
+#: builtin/notes.c:562 builtin/tag.c:455
msgid "message"
msgstr "Beschreibung"
-#: builtin/commit.c:1365
+#: builtin/commit.c:1432
msgid "commit message"
-msgstr "Versionsbeschreibung"
+msgstr "Commit-Beschreibung"
-#: builtin/commit.c:1366
+#: builtin/commit.c:1433
msgid "reuse and edit message from specified commit"
-msgstr "verwendet wieder und editiert Beschreibung von der angegebenen Version"
+msgstr "verwendet wieder und editiert Beschreibung des angegebenen Commits"
-#: builtin/commit.c:1367
+#: builtin/commit.c:1434
msgid "reuse message from specified commit"
-msgstr "verwendet Beschreibung der angegebenen Version wieder"
+msgstr "verwendet Beschreibung des angegebenen Commits wieder"
-#: builtin/commit.c:1368
+#: builtin/commit.c:1435
msgid "use autosquash formatted message to fixup specified commit"
msgstr ""
-"verwendet eine automatisch zusammengesetzte Beschreibung zum Nachbessern der "
-"angegebenen Version"
+"verwendet eine automatisch zusammengesetzte Beschreibung zum Nachbessern des "
+"angegebenen Commits"
-#: builtin/commit.c:1369
+#: builtin/commit.c:1436
msgid "use autosquash formatted message to squash specified commit"
msgstr ""
-"verwendet eine automatisch zusammengesetzte Beschreibung zum Zusammenführen "
-"der angegebenen Version"
+"verwendet eine automatisch zusammengesetzte Beschreibung beim \"squash\" des "
+"angegebenen Commits"
-#: builtin/commit.c:1370
+#: builtin/commit.c:1437
msgid "the commit is authored by me now (used with -C/-c/--amend)"
-msgstr "Setzt Sie als Autor der Version (verwendet mit -C/-c/--amend)"
+msgstr "Setzt Sie als Autor des Commits (verwendet mit -C/-c/--amend)"
-#: builtin/commit.c:1371 builtin/log.c:1102 builtin/revert.c:109
+#: builtin/commit.c:1438 builtin/log.c:1160 builtin/revert.c:111
msgid "add Signed-off-by:"
msgstr "fügt 'Signed-off-by:'-Zeile hinzu"
-#: builtin/commit.c:1372
+#: builtin/commit.c:1439
msgid "use specified template file"
msgstr "verwendet angegebene Vorlagendatei"
-#: builtin/commit.c:1373
+#: builtin/commit.c:1440
msgid "force edit of commit"
-msgstr "erzwingt Bearbeitung der Version"
+msgstr "erzwingt Bearbeitung des Commits"
-#: builtin/commit.c:1374
+#: builtin/commit.c:1441
msgid "default"
msgstr "Standard"
-#: builtin/commit.c:1374 builtin/tag.c:460
+#: builtin/commit.c:1441 builtin/tag.c:460
msgid "how to strip spaces and #comments from message"
msgstr ""
"wie Leerzeichen und #Kommentare von der Beschreibung getrennt werden sollen"
-#: builtin/commit.c:1375
+#: builtin/commit.c:1442
msgid "include status in commit message template"
-msgstr "fügt Status in die Versionsbeschreibungsvorlage ein"
+msgstr "fügt Status in die Commit-Beschreibungsvorlage ein"
-#: builtin/commit.c:1376 builtin/merge.c:213 builtin/tag.c:461
+#: builtin/commit.c:1443 builtin/merge.c:230 builtin/tag.c:461
msgid "key id"
msgstr "Schlüssel-ID"
-#: builtin/commit.c:1377 builtin/merge.c:214
+#: builtin/commit.c:1444 builtin/merge.c:231
msgid "GPG sign commit"
-msgstr "signiert Version mit GPG"
+msgstr "signiert Commit mit GPG"
#. end commit message options
-#: builtin/commit.c:1380
+#: builtin/commit.c:1447
msgid "Commit contents options"
-msgstr "Optionen für Versionsinhalt"
+msgstr "Optionen für Commit-Inhalt"
-#: builtin/commit.c:1381
+#: builtin/commit.c:1448
msgid "commit all changed files"
-msgstr "trägt alle geänderten Dateien ein"
+msgstr "committet alle geänderten Dateien"
-#: builtin/commit.c:1382
+#: builtin/commit.c:1449
msgid "add specified files to index for commit"
-msgstr "trägt die angegebenen Dateien zusätzlich zur Bereitstellung ein"
+msgstr "merkt die angegebenen Dateien zusätzlich zum Commit vor"
-#: builtin/commit.c:1383
+#: builtin/commit.c:1450
msgid "interactively add files"
msgstr "interaktives Hinzufügen von Dateien"
-#: builtin/commit.c:1384
+#: builtin/commit.c:1451
msgid "interactively add changes"
msgstr "interaktives Hinzufügen von Änderungen"
-#: builtin/commit.c:1385
+#: builtin/commit.c:1452
msgid "commit only specified files"
-msgstr "trägt nur die angegebenen Dateien ein"
+msgstr "committet nur die angegebenen Dateien"
-#: builtin/commit.c:1386
+#: builtin/commit.c:1453
msgid "bypass pre-commit hook"
msgstr "umgeht \"pre-commit hook\""
-#: builtin/commit.c:1387
+#: builtin/commit.c:1454
msgid "show what would be committed"
-msgstr "zeigt an, was eingetragen werden würde"
+msgstr "zeigt an, was committet werden würde"
-#: builtin/commit.c:1398
+#: builtin/commit.c:1465
msgid "amend previous commit"
-msgstr "ändert vorherige Version"
+msgstr "ändert vorherigen Commit"
-#: builtin/commit.c:1399
+#: builtin/commit.c:1466
msgid "bypass post-rewrite hook"
msgstr "umgeht \"post-rewrite hook\""
-#: builtin/commit.c:1404
+#: builtin/commit.c:1471
msgid "ok to record an empty change"
msgstr "erlaubt Aufzeichnung einer leeren Änderung"
-#: builtin/commit.c:1407
+#: builtin/commit.c:1474
msgid "ok to record a change with an empty message"
msgstr "erlaubt Aufzeichnung einer Änderung mit einer leeren Beschreibung"
-#: builtin/commit.c:1439
+#: builtin/commit.c:1507
msgid "could not parse HEAD commit"
-msgstr "Konnte Version der Zweigspitze (HEAD) nicht analysieren."
+msgstr "Konnte Commit von HEAD nicht analysieren."
-#: builtin/commit.c:1477 builtin/merge.c:508
+#: builtin/commit.c:1545 builtin/merge.c:525
#, c-format
msgid "could not open '%s' for reading"
msgstr "Konnte '%s' nicht zum Lesen öffnen."
-#: builtin/commit.c:1484
+#: builtin/commit.c:1552
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "Beschädigte MERGE_HEAD-Datei (%s)"
-#: builtin/commit.c:1491
+#: builtin/commit.c:1559
msgid "could not read MERGE_MODE"
msgstr "Konnte MERGE_MODE nicht lesen"
-#: builtin/commit.c:1510
+#: builtin/commit.c:1578
#, c-format
msgid "could not read commit message: %s"
-msgstr "Konnte Versionsbeschreibung nicht lesen: %s"
+msgstr "Konnte Commit-Beschreibung nicht lesen: %s"
-#: builtin/commit.c:1524
+#: builtin/commit.c:1592
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
-msgstr "Eintragung abgebrochen; Sie haben die Beschreibung nicht editiert.\n"
+msgstr "Commit abgebrochen; Sie haben die Beschreibung nicht editiert.\n"
-#: builtin/commit.c:1529
+#: builtin/commit.c:1597
#, c-format
msgid "Aborting commit due to empty commit message.\n"
-msgstr "Eintragung aufgrund leerer Versionsbeschreibung abgebrochen.\n"
+msgstr "Commit aufgrund leerer Beschreibung abgebrochen.\n"
-#: builtin/commit.c:1544 builtin/merge.c:832 builtin/merge.c:857
+#: builtin/commit.c:1612 builtin/merge.c:861 builtin/merge.c:886
msgid "failed to write commit object"
-msgstr "Fehler beim Schreiben des Versionsobjektes."
+msgstr "Fehler beim Schreiben des Commit-Objektes."
-#: builtin/commit.c:1565
+#: builtin/commit.c:1633
msgid "cannot lock HEAD ref"
-msgstr "Kann Referenz der Zweigspitze (HEAD) nicht sperren."
+msgstr "Kann Referenz von HEAD nicht sperren."
-#: builtin/commit.c:1569
+#: builtin/commit.c:1637
msgid "cannot update HEAD ref"
-msgstr "Kann Referenz der Zweigspitze (HEAD) nicht aktualisieren."
+msgstr "Kann Referenz von HEAD nicht aktualisieren."
-#: builtin/commit.c:1580
+#: builtin/commit.c:1648
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"
+"Das Repository wurde aktualisiert, aber die \"new_index\"-Datei\n"
"konnte nicht geschrieben werden. Prüfen Sie, dass Ihre Festplatte nicht\n"
"voll und Ihr Kontingent nicht aufgebraucht ist und führen Sie\n"
"anschließend \"git reset HEAD\" zu Wiederherstellung aus."
@@ -4042,289 +4555,301 @@ msgstr ""
msgid "git config [options]"
msgstr "git config [Optionen]"
-#: builtin/config.c:51
+#: builtin/config.c:52
msgid "Config file location"
msgstr "Ort der Konfigurationsdatei"
-#: builtin/config.c:52
+#: builtin/config.c:53
msgid "use global config file"
msgstr "verwendet globale Konfigurationsdatei"
-#: builtin/config.c:53
+#: builtin/config.c:54
msgid "use system config file"
msgstr "verwendet systemweite Konfigurationsdatei"
-#: builtin/config.c:54
+#: builtin/config.c:55
msgid "use repository config file"
-msgstr "verwendet Konfigurationsdatei des Projektarchivs"
+msgstr "verwendet Konfigurationsdatei des Repositories"
-#: builtin/config.c:55
+#: builtin/config.c:56
msgid "use given config file"
msgstr "verwendet die angegebene Konfigurationsdatei"
-#: builtin/config.c:56
+#: builtin/config.c:57
+msgid "blob-id"
+msgstr "Blob-Id"
+
+#: builtin/config.c:57
+msgid "read config from given blob object"
+msgstr "liest Konfiguration von angegebenem Blob-Objekt"
+
+#: builtin/config.c:58
msgid "Action"
msgstr "Aktion"
-#: builtin/config.c:57
+#: builtin/config.c:59
msgid "get value: name [value-regex]"
msgstr "gibt Wert zurück: Name [Wert-regex]"
-#: builtin/config.c:58
+#: builtin/config.c:60
msgid "get all values: key [value-regex]"
msgstr "gibt alle Werte zurück: Schlüssel [Wert-regex]"
-#: builtin/config.c:59
+#: builtin/config.c:61
msgid "get values for regexp: name-regex [value-regex]"
msgstr "gibt Werte für den regulären Ausdruck zurück: Name-regex [Wert-regex]"
-#: builtin/config.c:60
+#: builtin/config.c:62
msgid "replace all matching variables: name value [value_regex]"
msgstr "ersetzt alle passenden Variablen: Name Wert [Wert-regex] "
-#: builtin/config.c:61
+#: builtin/config.c:63
msgid "add a new variable: name value"
msgstr "fügt neue Variable hinzu: Name Wert"
-#: builtin/config.c:62
+#: builtin/config.c:64
msgid "remove a variable: name [value-regex]"
msgstr "entfernt eine Variable: Name [Wert-regex]"
-#: builtin/config.c:63
+#: builtin/config.c:65
msgid "remove all matches: name [value-regex]"
msgstr "entfernt alle Ãœbereinstimmungen: Name [Wert-regex]"
-#: builtin/config.c:64
+#: builtin/config.c:66
msgid "rename section: old-name new-name"
msgstr "benennt eine Sektion um: alter-Name neuer-Name"
-#: builtin/config.c:65
+#: builtin/config.c:67
msgid "remove a section: name"
msgstr "entfernt eine Sektion: Name"
-#: builtin/config.c:66
+#: builtin/config.c:68
msgid "list all"
msgstr "listet alles auf"
-#: builtin/config.c:67
+#: builtin/config.c:69
msgid "open an editor"
msgstr "öffnet einen Editor"
-#: builtin/config.c:68 builtin/config.c:69
+#: builtin/config.c:70 builtin/config.c:71
msgid "slot"
msgstr "Slot"
-#: builtin/config.c:68
+#: builtin/config.c:70
msgid "find the color configured: [default]"
msgstr "findet die konfigurierte Farbe: [Standard]"
-#: builtin/config.c:69
+#: builtin/config.c:71
msgid "find the color setting: [stdout-is-tty]"
msgstr "findet die Farbeinstellung: [Standard-Ausgabe-ist-Terminal]"
-#: builtin/config.c:70
+#: builtin/config.c:72
msgid "Type"
msgstr "Typ"
-#: builtin/config.c:71
+#: builtin/config.c:73
msgid "value is \"true\" or \"false\""
msgstr "Wert ist \"true\" oder \"false\""
-#: builtin/config.c:72
+#: builtin/config.c:74
msgid "value is decimal number"
msgstr "Wert ist eine Dezimalzahl"
-#: builtin/config.c:73
+#: builtin/config.c:75
msgid "value is --bool or --int"
msgstr "Wert ist --bool oder --int"
-#: builtin/config.c:74
+#: builtin/config.c:76
msgid "value is a path (file or directory name)"
msgstr "Wert ist ein Pfad (Datei oder Verzeichnisname)"
-#: builtin/config.c:75
+#: builtin/config.c:77
msgid "Other"
msgstr "Sonstiges"
-#: builtin/config.c:76
+#: builtin/config.c:78
msgid "terminate values with NUL byte"
msgstr "schließt Werte mit NUL-Byte ab"
-#: builtin/config.c:77
+#: builtin/config.c:79
msgid "respect include directives on lookup"
msgstr "beachtet \"include\"-Direktiven beim Nachschlagen"
-#: builtin/count-objects.c:69
-msgid "git count-objects [-v]"
-msgstr "git count-objects [-v]"
+#: builtin/count-objects.c:82
+msgid "git count-objects [-v] [-H | --human-readable]"
+msgstr "git count-objects [-v] [-H | --human-readable]"
+
+#: builtin/count-objects.c:97
+msgid "print sizes in human readable format"
+msgstr "gibt Größenangaben in menschenlesbaren Format aus"
-#: builtin/describe.c:15
+#: builtin/describe.c:16
msgid "git describe [options] <committish>*"
msgstr "git describe [Optionen] <committish>*"
-#: builtin/describe.c:16
+#: builtin/describe.c:17
msgid "git describe [options] --dirty"
msgstr "git describe [Optionen] --dirty"
-#: builtin/describe.c:234
+#: builtin/describe.c:237
#, c-format
msgid "annotated tag %s not available"
-msgstr "annotierte Markierung %s ist nicht verfügbar"
+msgstr "annotierter Tag %s ist nicht verfügbar"
-#: builtin/describe.c:238
+#: builtin/describe.c:241
#, c-format
msgid "annotated tag %s has no embedded name"
-msgstr "annotierte Markierung %s hat keinen eingebetteten Namen"
+msgstr "annotierter Tag %s hat keinen eingebetteten Namen"
-#: builtin/describe.c:240
+#: builtin/describe.c:243
#, c-format
msgid "tag '%s' is really '%s' here"
-msgstr "Markierung '%s' ist eigentlich '%s' hier"
+msgstr "Tag '%s' ist eigentlich '%s' hier"
-#: builtin/describe.c:267
+#: builtin/describe.c:270
#, c-format
msgid "Not a valid object name %s"
msgstr "%s ist kein gültiger Objekt-Name"
-#: builtin/describe.c:270
+#: builtin/describe.c:273
#, c-format
msgid "%s is not a valid '%s' object"
msgstr "%s ist kein gültiges '%s' Objekt"
-#: builtin/describe.c:287
+#: builtin/describe.c:290
#, c-format
msgid "no tag exactly matches '%s'"
-msgstr "kein Markierung entspricht exakt '%s'"
+msgstr "kein Tag entspricht exakt '%s'"
-#: builtin/describe.c:289
+#: builtin/describe.c:292
#, c-format
msgid "searching to describe %s\n"
msgstr "suche zur Beschreibung von %s\n"
-#: builtin/describe.c:329
+#: builtin/describe.c:332
#, c-format
msgid "finished search at %s\n"
msgstr "beendete Suche bei %s\n"
-#: builtin/describe.c:353
+#: builtin/describe.c:359
#, c-format
msgid ""
"No annotated tags can describe '%s'.\n"
"However, there were unannotated tags: try --tags."
msgstr ""
-"Keine annotierten Markierungen können '%s' beschreiben.\n"
-"Jedoch gab es nicht annotierte Markierungen: versuchen Sie --tags."
+"Keine annotierten Tags können '%s' beschreiben.\n"
+"Jedoch gab es nicht-annotierte Tags: versuchen Sie --tags."
-#: builtin/describe.c:357
+#: builtin/describe.c:363
#, c-format
msgid ""
"No tags can describe '%s'.\n"
"Try --always, or create some tags."
msgstr ""
-"Keine Markierungen können '%s' beschreiben.\n"
-"Versuchen Sie --always oder erstellen Sie einige Markierungen."
+"Keine Tags können '%s' beschreiben.\n"
+"Versuchen Sie --always oder erstellen Sie einige Tags."
-#: builtin/describe.c:378
+#: builtin/describe.c:384
#, c-format
msgid "traversed %lu commits\n"
-msgstr "%lu Versionen durchlaufen\n"
+msgstr "%lu Commits durchlaufen\n"
-#: builtin/describe.c:381
+#: builtin/describe.c:387
#, c-format
msgid ""
"more than %i tags found; listed %i most recent\n"
"gave up search at %s\n"
msgstr ""
-"mehr als %i Markierungen gefunden; Führe die ersten %i auf\n"
+"mehr als %i Tags gefunden; Führe die ersten %i auf\n"
"Suche bei %s aufgegeben\n"
-#: builtin/describe.c:403
+#: builtin/describe.c:409
msgid "find the tag that comes after the commit"
-msgstr "findet die Markierung, die nach der Version kommt"
+msgstr "findet den Tag, die nach Commit kommt"
-#: builtin/describe.c:404
+#: builtin/describe.c:410
msgid "debug search strategy on stderr"
msgstr "protokolliert die Suchstrategie in der Standard-Fehlerausgabe"
-#: builtin/describe.c:405
-msgid "use any ref in .git/refs"
-msgstr "verwendet alle Referenzen in .git/refs"
+#: builtin/describe.c:411
+msgid "use any ref"
+msgstr "verwendet alle Referenzen"
-#: builtin/describe.c:406
-msgid "use any tag in .git/refs/tags"
-msgstr "verwendet alle Markierungen in .git/refs/tags"
+#: builtin/describe.c:412
+msgid "use any tag, even unannotated"
+msgstr "verwendet jeden Tag, auch nicht-annotierte"
-#: builtin/describe.c:407
+#: builtin/describe.c:413
msgid "always use long format"
msgstr "verwendet immer langes Format"
-#: builtin/describe.c:410
+#: builtin/describe.c:414
+msgid "only follow first parent"
+msgstr "folgt nur erstem Elternteil"
+
+#: builtin/describe.c:417
msgid "only output exact matches"
msgstr "gibt nur exakte Ãœbereinstimmungen aus"
-#: builtin/describe.c:412
+#: builtin/describe.c:419
msgid "consider <n> most recent tags (default: 10)"
-msgstr "betrachtet die jüngsten <n> Markierungen (Standard: 10)"
+msgstr "betrachtet die jüngsten <n> Tags (Standard: 10)"
-#: builtin/describe.c:414
+#: builtin/describe.c:421
msgid "only consider tags matching <pattern>"
-msgstr "betrachtet nur Markierungen die <Muster> entsprechen"
+msgstr "betrachtet nur Tags die <Muster> entsprechen"
-#: builtin/describe.c:416 builtin/name-rev.c:238
+#: builtin/describe.c:423 builtin/name-rev.c:322
msgid "show abbreviated commit object as fallback"
-msgstr "zeigt gekürztes Versionsobjekt, wenn sonst nichts zutrifft"
+msgstr "zeigt gekürztes Commit-Objekt, wenn sonst nichts zutrifft"
-#: builtin/describe.c:417
+#: builtin/describe.c:424
msgid "mark"
msgstr "Kennzeichen"
-#: builtin/describe.c:418
+#: builtin/describe.c:425
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
msgstr ""
-"fügt <Kennzeichen> bei geändertem Arbeitsbaum hinzu (Standard: \"-dirty\")"
+"fügt <Kennzeichen> bei geändertem Arbeitsverzeichnis hinzu (Standard: \"-"
+"dirty\")"
-#: builtin/describe.c:436
+#: builtin/describe.c:443
msgid "--long is incompatible with --abbrev=0"
msgstr "Die Optionen --long und --abbrev=0 sind inkompatibel."
-#: builtin/describe.c:462
+#: builtin/describe.c:469
msgid "No names found, cannot describe anything."
msgstr "Keine Namen gefunden, kann nichts beschreiben."
-#: builtin/describe.c:482
+#: builtin/describe.c:489
msgid "--dirty is incompatible with committishes"
-msgstr "Die Option --dirty kann nicht mit Versionen verwendet werden."
+msgstr "Die Option --dirty kann nicht mit Commits verwendet werden."
#: builtin/diff.c:79
#, c-format
msgid "'%s': not a regular file or symlink"
-msgstr "'%s': keine reguläre Datei oder symbolischer Link"
+msgstr "'%s': keine reguläre Datei oder symbolischer Verweis"
-#: builtin/diff.c:228
+#: builtin/diff.c:230
#, c-format
msgid "invalid option: %s"
msgstr "Ungültige Option: %s"
-#: builtin/diff.c:305
+#: builtin/diff.c:307
msgid "Not a git repository"
-msgstr "Kein Git-Projektarchiv"
+msgstr "Kein Git-Repository"
-#: builtin/diff.c:348
+#: builtin/diff.c:350
#, c-format
msgid "invalid object '%s' given."
msgstr "Objekt '%s' ist ungültig."
-#: builtin/diff.c:353
-#, c-format
-msgid "more than %d trees given: '%s'"
-msgstr "Mehr als %d Zweige angegeben: '%s'"
-
-#: builtin/diff.c:363
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
msgstr "Mehr als zwei Blobs angegeben: '%s'"
-#: builtin/diff.c:371
+#: builtin/diff.c:366
#, c-format
msgid "unhandled object '%s' given."
msgstr "unbehandeltes Objekt '%s' angegeben"
@@ -4333,46 +4858,45 @@ msgstr "unbehandeltes Objekt '%s' angegeben"
msgid "git fast-export [rev-list-opts]"
msgstr "git fast-export [rev-list-opts]"
-#: builtin/fast-export.c:646
+#: builtin/fast-export.c:666
msgid "show progress after <n> objects"
msgstr "zeigt Fortschritt nach <n> Objekten an"
-#: builtin/fast-export.c:648
+#: builtin/fast-export.c:668
msgid "select handling of signed tags"
-msgstr "wählt Behandlung von signierten Markierungen"
+msgstr "wählt Behandlung von signierten Tags"
-#: builtin/fast-export.c:651
+#: builtin/fast-export.c:671
msgid "select handling of tags that tag filtered objects"
-msgstr "wählt Behandlung von Markierungen, die gefilterte Objekte markieren"
+msgstr "wählt Behandlung von Tags, die gefilterte Objekte markieren"
-#: builtin/fast-export.c:654
+#: builtin/fast-export.c:674
msgid "Dump marks to this file"
msgstr "Schreibt Kennzeichen in diese Datei"
-#: builtin/fast-export.c:656
+#: builtin/fast-export.c:676
msgid "Import marks from this file"
msgstr "Importiert Kennzeichen von dieser Datei"
-#: builtin/fast-export.c:658
+#: builtin/fast-export.c:678
msgid "Fake a tagger when tags lack one"
-msgstr ""
-"erzeugt künstlich einen Markierungsersteller, wenn die Markierung keinen hat"
+msgstr "erzeugt künstlich einen Tag-Ersteller, wenn der Tag keinen hat"
-#: builtin/fast-export.c:660
+#: builtin/fast-export.c:680
msgid "Output full tree for each commit"
-msgstr "gibt für jede Version den gesamten Baum aus"
+msgstr "gibt für jeden Commit das gesamte Verzeichnis aus"
-#: builtin/fast-export.c:662
+#: builtin/fast-export.c:682
msgid "Use the done feature to terminate the stream"
msgstr "Benutzt die \"done\"-Funktion um den Strom abzuschließen"
-#: builtin/fast-export.c:663
+#: builtin/fast-export.c:683
msgid "Skip output of blob data"
msgstr "Ãœberspringt Ausgabe von Blob-Daten"
#: builtin/fetch.c:20
msgid "git fetch [<options>] [<repository> [<refspec>...]]"
-msgstr "git fetch [<Optionen>] [<Projektarchiv> [<Referenzspezifikation>...]]"
+msgstr "git fetch [<Optionen>] [<Repository> [<Refspec>...]]"
#: builtin/fetch.c:21
msgid "git fetch [<options>] <group>"
@@ -4380,7 +4904,7 @@ msgstr "git fetch [<Optionen>] <Gruppe>"
#: builtin/fetch.c:22
msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
-msgstr "git fetch --multiple [<Optionen>] [(<Projektarchiv> | <Gruppe>)...]"
+msgstr "git fetch --multiple [<Optionen>] [(<Repository> | <Gruppe>)...]"
#: builtin/fetch.c:23
msgid "git fetch --all [<options>]"
@@ -4388,7 +4912,7 @@ msgstr "git fetch --all [<Optionen>]"
#: builtin/fetch.c:60
msgid "fetch from all remotes"
-msgstr "fordert von allen externen Projektarchiven an"
+msgstr "fordert von allen Remote-Repositories an"
#: builtin/fetch.c:62
msgid "append to .git/FETCH_HEAD instead of overwriting"
@@ -4400,24 +4924,25 @@ msgstr "Pfad des Programms zum Hochladen von Paketen auf der Gegenseite"
#: builtin/fetch.c:65
msgid "force overwrite of local branch"
-msgstr "erzwingt das Ãœberschreiben von lokalen Zweigen"
+msgstr "erzwingt das Ãœberschreiben von lokalen Branches"
#: builtin/fetch.c:67
msgid "fetch from multiple remotes"
-msgstr "fordert von mehreren externen Projektarchiven an"
+msgstr "fordert von mehreren Remote-Repositories an"
#: builtin/fetch.c:69
msgid "fetch all tags and associated objects"
-msgstr "fordert alle Markierungen und verbundene Objekte an"
+msgstr "fordert alle Tags und verbundene Objekte an"
#: builtin/fetch.c:71
msgid "do not fetch all tags (--no-tags)"
-msgstr "fordert nicht alle Markierungen an (--no-tags)"
+msgstr "fordert nicht alle Tags an (--no-tags)"
#: builtin/fetch.c:73
msgid "prune remote-tracking branches no longer on remote"
msgstr ""
-"entfernt externe Ãœbernahmezweige, die sich nicht mehr im Fernarchiv befinden"
+"entfernt Remote-Tracking-Branches, die sich nicht mehr im Remote-Repository "
+"befinden"
#: builtin/fetch.c:74
msgid "on-demand"
@@ -4425,7 +4950,7 @@ msgstr "bei-Bedarf"
#: builtin/fetch.c:75
msgid "control recursive fetching of submodules"
-msgstr "kontrolliert rekursive Anforderungen von Unterprojekten"
+msgstr "kontrolliert rekursive Anforderungen von Submodulen"
#: builtin/fetch.c:79
msgid "keep downloaded pack"
@@ -4437,223 +4962,224 @@ msgstr "erlaubt Aktualisierung der \"HEAD\"-Referenz"
#: builtin/fetch.c:84
msgid "deepen history of shallow clone"
-msgstr "vertieft die Historie eines flachen Klon"
+msgstr "vertieft die Historie eines flachen Klons"
#: builtin/fetch.c:86
msgid "convert to a complete repository"
-msgstr "konvertiert zu einem vollständigen Projektarchiv"
+msgstr "konvertiert zu einem vollständigen Repository"
-#: builtin/fetch.c:88 builtin/log.c:1119
+#: builtin/fetch.c:88 builtin/log.c:1177
msgid "dir"
msgstr "Verzeichnis"
#: builtin/fetch.c:89
msgid "prepend this to submodule path output"
-msgstr "stellt dies an die Ausgabe der Unterprojekt-Pfade voran"
+msgstr "stellt dies an die Ausgabe der Submodul-Pfade voran"
#: builtin/fetch.c:92
msgid "default mode for recursion"
msgstr "Standard-Modus für Rekursion"
-#: builtin/fetch.c:204
+#: builtin/fetch.c:220
msgid "Couldn't find remote ref HEAD"
-msgstr "Konnte externe Referenz der Zweigspitze (HEAD) nicht finden."
+msgstr "Konnte Remote-Referenz von HEAD nicht finden."
-#: builtin/fetch.c:257
+#: builtin/fetch.c:273
#, c-format
msgid "object %s not found"
msgstr "Objekt %s nicht gefunden"
-#: builtin/fetch.c:262
+#: builtin/fetch.c:278
msgid "[up to date]"
msgstr "[aktuell]"
-#: builtin/fetch.c:276
+#: builtin/fetch.c:292
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
-msgstr "! %-*s %-*s -> %s (kann nicht im aktuellen Zweig anfordern)"
+msgstr ""
+"! %-*s %-*s -> %s (kann \"fetch\" im aktuellen Branch nicht ausführen)"
-#: builtin/fetch.c:277 builtin/fetch.c:363
+#: builtin/fetch.c:293 builtin/fetch.c:379
msgid "[rejected]"
msgstr "[zurückgewiesen]"
-#: builtin/fetch.c:288
+#: builtin/fetch.c:304
msgid "[tag update]"
-msgstr "[Markierungsaktualisierung]"
+msgstr "[Tag Aktualisierung]"
-#: builtin/fetch.c:290 builtin/fetch.c:325 builtin/fetch.c:343
+#: builtin/fetch.c:306 builtin/fetch.c:341 builtin/fetch.c:359
msgid " (unable to update local ref)"
msgstr " (kann lokale Referenz nicht aktualisieren)"
-#: builtin/fetch.c:308
+#: builtin/fetch.c:324
msgid "[new tag]"
-msgstr "[neue Markierung]"
+msgstr "[neuer Tag]"
-#: builtin/fetch.c:311
+#: builtin/fetch.c:327
msgid "[new branch]"
-msgstr "[neuer Zweig]"
+msgstr "[neuer Branch]"
-#: builtin/fetch.c:314
+#: builtin/fetch.c:330
msgid "[new ref]"
msgstr "[neue Referenz]"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "unable to update local ref"
msgstr "kann lokale Referenz nicht aktualisieren"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "forced update"
msgstr "Aktualisierung erzwungen"
-#: builtin/fetch.c:365
+#: builtin/fetch.c:381
msgid "(non-fast-forward)"
msgstr "(kein Vorspulen)"
-#: builtin/fetch.c:396 builtin/fetch.c:688
+#: builtin/fetch.c:412 builtin/fetch.c:718
#, c-format
msgid "cannot open %s: %s\n"
msgstr "kann %s nicht öffnen: %s\n"
-#: builtin/fetch.c:405
+#: builtin/fetch.c:421
#, c-format
msgid "%s did not send all necessary objects\n"
msgstr "%s hat nicht alle erforderlichen Objekte gesendet\n"
-#: builtin/fetch.c:491
+#: builtin/fetch.c:520
#, c-format
msgid "From %.*s\n"
msgstr "Von %.*s\n"
-#: builtin/fetch.c:502
+#: builtin/fetch.c:531
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting branches"
msgstr ""
"Einige lokale Referenzen konnten nicht aktualisiert werden; versuchen Sie\n"
-"'git remote prune %s' um jeden älteren, widersprüchlichen Zweig zu löschen."
+"'git remote prune %s' um jeden älteren, widersprüchlichen Branch zu löschen."
-#: builtin/fetch.c:552
+#: builtin/fetch.c:581
#, c-format
msgid " (%s will become dangling)"
msgstr " (%s wird unreferenziert)"
-#: builtin/fetch.c:553
+#: builtin/fetch.c:582
#, c-format
msgid " (%s has become dangling)"
msgstr " (%s wurde unreferenziert)"
-#: builtin/fetch.c:560
+#: builtin/fetch.c:589
msgid "[deleted]"
msgstr "[gelöscht]"
-#: builtin/fetch.c:561 builtin/remote.c:1055
+#: builtin/fetch.c:590 builtin/remote.c:1055
msgid "(none)"
msgstr "(nichts)"
-#: builtin/fetch.c:678
+#: builtin/fetch.c:708
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
msgstr ""
-"Das Anfordern in den aktuellen Zweig %s von einem nicht-bloßen Projektarchiv "
+"Der \"fetch\" in den aktuellen Branch %s von einem nicht-Bare-Repository "
"wurde verweigert."
-#: builtin/fetch.c:712
+#: builtin/fetch.c:742
#, c-format
msgid "Don't know how to fetch from %s"
msgstr "Weiß nicht wie von %s angefordert wird."
-#: builtin/fetch.c:789
+#: builtin/fetch.c:823
#, c-format
msgid "Option \"%s\" value \"%s\" is not valid for %s"
msgstr "Option \"%s\" Wert \"%s\" ist nicht gültig für %s"
-#: builtin/fetch.c:792
+#: builtin/fetch.c:826
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr "Option \"%s\" wird ignoriert für %s\n"
-#: builtin/fetch.c:894
+#: builtin/fetch.c:928
#, c-format
msgid "Fetching %s\n"
msgstr "Fordere an von %s\n"
-#: builtin/fetch.c:896 builtin/remote.c:100
+#: builtin/fetch.c:930 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
msgstr "Konnte nicht von %s anfordern"
-#: builtin/fetch.c:915
+#: builtin/fetch.c:949
msgid ""
"No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."
msgstr ""
-"Kein externes Projektarchiv angegeben. Bitte geben Sie entweder eine URL\n"
-"oder den Namen des externen Archivs an, von welchem neue\n"
-"Revisionen angefordert werden sollen."
+"Kein Remote-Repository angegeben. Bitte geben Sie entweder eine URL\n"
+"oder den Namen des Remote-Repositories an, von welchem neue\n"
+"Commits angefordert werden sollen."
-#: builtin/fetch.c:935
+#: builtin/fetch.c:969
msgid "You need to specify a tag name."
-msgstr "Sie müssen den Namen der Markierung angeben."
+msgstr "Sie müssen den Namen des Tags angeben."
-#: builtin/fetch.c:981
+#: builtin/fetch.c:1015
msgid "--depth and --unshallow cannot be used together"
msgstr ""
"Die Optionen --depth und --unshallow können nicht gemeinsam verwendet werden."
-#: builtin/fetch.c:983
+#: builtin/fetch.c:1017
msgid "--unshallow on a complete repository does not make sense"
msgstr ""
-"Die Option --unshallow kann nicht in einem vollständigen Projektarchiv "
+"Die Option --unshallow kann nicht in einem vollständigen Repository "
"verwendet werden."
-#: builtin/fetch.c:1002
+#: builtin/fetch.c:1036
msgid "fetch --all does not take a repository argument"
-msgstr "fetch --all akzeptiert kein Projektarchiv als Argument"
+msgstr "fetch --all akzeptiert kein Repository als Argument"
-#: builtin/fetch.c:1004
+#: builtin/fetch.c:1038
msgid "fetch --all does not make sense with refspecs"
-msgstr "fetch --all kann nicht mit Referenzspezifikationen verwendet werden."
+msgstr "fetch --all kann nicht mit Refspecs verwendet werden."
-#: builtin/fetch.c:1015
+#: builtin/fetch.c:1049
#, c-format
msgid "No such remote or remote group: %s"
-msgstr "Kein externes Archiv (einzeln oder Gruppe): %s"
+msgstr "Kein Remote-Repository (einzeln oder Gruppe): %s"
-#: builtin/fetch.c:1023
+#: builtin/fetch.c:1057
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr ""
-"Das Abholen einer Gruppe von externen Archiven kann nicht mit der Angabe\n"
-"von Referenzspezifikationen verwendet werden."
+"Das Abholen einer Gruppe von Remote-Repositories kann nicht mit der Angabe\n"
+"von Refspecs verwendet werden."
#: builtin/fmt-merge-msg.c:13
msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
msgstr ""
"git fmt-merge-msg [-m <Beschreibung>] [--log[=<n>]|--no-log] [--file <Datei>]"
-#: builtin/fmt-merge-msg.c:659 builtin/fmt-merge-msg.c:662 builtin/grep.c:701
-#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175
-#: builtin/tag.c:446 parse-options.h:133 parse-options.h:239
+#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:700
+#: builtin/merge.c:203 builtin/show-branch.c:655 builtin/show-ref.c:179
+#: builtin/tag.c:446 parse-options.h:133 parse-options.h:243
msgid "n"
msgstr "Anzahl"
-#: builtin/fmt-merge-msg.c:660
+#: builtin/fmt-merge-msg.c:664
msgid "populate log with at most <n> entries from shortlog"
msgstr "fügt Historie mit höchstens <n> Einträgen von \"shortlog\" hinzu"
-#: builtin/fmt-merge-msg.c:663
+#: builtin/fmt-merge-msg.c:667
msgid "alias for --log (deprecated)"
msgstr "Alias für --log (veraltet)"
-#: builtin/fmt-merge-msg.c:666
+#: builtin/fmt-merge-msg.c:670
msgid "text"
msgstr "Text"
-#: builtin/fmt-merge-msg.c:667
+#: builtin/fmt-merge-msg.c:671
msgid "use <text> as start of message"
msgstr "verwendet <Text> als Beschreibungsanfang"
-#: builtin/fmt-merge-msg.c:668
+#: builtin/fmt-merge-msg.c:672
msgid "file to read from"
msgstr "Datei zum Einlesen"
@@ -4711,7 +5237,7 @@ msgstr "zeigt unreferenzierte Objekte"
#: builtin/fsck.c:616
msgid "report tags"
-msgstr "meldet Markierungen"
+msgstr "meldet Tags"
#: builtin/fsck.c:617
msgid "report root nodes"
@@ -4719,11 +5245,11 @@ msgstr "meldet Hauptwurzeln"
#: builtin/fsck.c:618
msgid "make index objects head nodes"
-msgstr "erzeugt Kopfknoten der Bereitstellungsobjekte"
+msgstr "prüft Objekte in der Staging-Area"
#: builtin/fsck.c:619
msgid "make reflogs head nodes (default)"
-msgstr "erzeugt Kopfknoten des Referenzprotokolls (Standard)"
+msgstr "prüft die Reflogs (Standard)"
#: builtin/fsck.c:620
msgid "also consider packs and alternate objects"
@@ -4773,7 +5299,7 @@ msgid ""
"Auto packing the repository for optimum performance. You may also\n"
"run \"git gc\" manually. See \"git help gc\" for more information.\n"
msgstr ""
-"Die Datenbank des Projektarchivs wird für eine optimale Performance\n"
+"Die Datenbank des Repositories wird für eine optimale Performance\n"
"komprimiert. Sie können auch \"git gc\" manuell ausführen.\n"
"Siehe \"git help gc\" für weitere Informationen.\n"
@@ -4786,245 +5312,240 @@ msgstr ""
#: builtin/grep.c:22
msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
-msgstr "git grep [Optionen] [-e] <Muster> [<Revision>...] [[--] <Pfad>...]"
+msgstr "git grep [Optionen] [-e] <Muster> [<Commit>...] [[--] <Pfad>...]"
#: builtin/grep.c:217
#, c-format
msgid "grep: failed to create thread: %s"
msgstr "grep: Fehler beim Erzeugen eines Thread: %s"
-#: builtin/grep.c:365
+#: builtin/grep.c:364
#, c-format
msgid "Failed to chdir: %s"
msgstr "Fehler beim Verzeichniswechsel: %s"
-#: builtin/grep.c:443 builtin/grep.c:478
+#: builtin/grep.c:442 builtin/grep.c:477
#, c-format
msgid "unable to read tree (%s)"
-msgstr "konnte Zweig (%s) nicht lesen"
+msgstr "konnte \"Tree\"-Objekt (%s) nicht lesen"
-#: builtin/grep.c:493
+#: builtin/grep.c:492
#, 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:551
+#: builtin/grep.c:550
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr "Schalter '%c' erwartet einen numerischen Wert"
-#: builtin/grep.c:568
+#: builtin/grep.c:567
#, c-format
msgid "cannot open '%s'"
msgstr "kann '%s' nicht öffnen"
-#: builtin/grep.c:643
+#: builtin/grep.c:642
msgid "search in index instead of in the work tree"
-msgstr "sucht in der Bereitstellung anstatt im Arbeitsbaum"
+msgstr "sucht in der Staging-Area anstatt im Arbeitsverzeichnis"
-#: builtin/grep.c:645
+#: builtin/grep.c:644
msgid "find in contents not managed by git"
msgstr "findet auch in Inhalten, die nicht von Git verwaltet werden"
-#: builtin/grep.c:647
+#: builtin/grep.c:646
msgid "search in both tracked and untracked files"
msgstr "sucht in beobachteten und unbeobachteten Dateien"
-#: builtin/grep.c:649
+#: builtin/grep.c:648
msgid "search also in ignored files"
msgstr "sucht auch in ignorierten Dateien"
-#: builtin/grep.c:652
+#: builtin/grep.c:651
msgid "show non-matching lines"
msgstr "zeigt Zeilen ohne Ãœbereinstimmungen"
-#: builtin/grep.c:654
+#: builtin/grep.c:653
msgid "case insensitive matching"
msgstr "findet Übereinstimmungen unabhängig von Groß- und Kleinschreibung"
-#: builtin/grep.c:656
+#: builtin/grep.c:655
msgid "match patterns only at word boundaries"
msgstr "sucht nur ganze Wörter"
-#: builtin/grep.c:658
+#: builtin/grep.c:657
msgid "process binary files as text"
msgstr "verarbeitet binäre Dateien als Text"
-#: builtin/grep.c:660
+#: builtin/grep.c:659
msgid "don't match patterns in binary files"
msgstr "findet keine Muster in Binärdateien"
-#: builtin/grep.c:663
+#: builtin/grep.c:662
msgid "descend at most <depth> levels"
msgstr "durchläuft höchstens <Tiefe> Ebenen"
-#: builtin/grep.c:667
+#: builtin/grep.c:666
msgid "use extended POSIX regular expressions"
msgstr "verwendet erweiterte reguläre Ausdrücke aus POSIX"
-#: builtin/grep.c:670
+#: builtin/grep.c:669
msgid "use basic POSIX regular expressions (default)"
msgstr "verwendet grundlegende reguläre Ausdrücke aus POSIX (Standard)"
-#: builtin/grep.c:673
+#: builtin/grep.c:672
msgid "interpret patterns as fixed strings"
msgstr "interpretiert Muster als feste Zeichenketten"
-#: builtin/grep.c:676
+#: builtin/grep.c:675
msgid "use Perl-compatible regular expressions"
msgstr "verwendet Perl-kompatible reguläre Ausdrücke"
-#: builtin/grep.c:679
+#: builtin/grep.c:678
msgid "show line numbers"
msgstr "zeigt Zeilennummern"
-#: builtin/grep.c:680
+#: builtin/grep.c:679
msgid "don't show filenames"
msgstr "zeigt keine Dateinamen"
-#: builtin/grep.c:681
+#: builtin/grep.c:680
msgid "show filenames"
msgstr "zeigt Dateinamen"
-#: builtin/grep.c:683
+#: builtin/grep.c:682
msgid "show filenames relative to top directory"
msgstr "zeigt Dateinamen relativ zum Projektverzeichnis"
-#: builtin/grep.c:685
+#: builtin/grep.c:684
msgid "show only filenames instead of matching lines"
msgstr "zeigt nur Dateinamen anstatt übereinstimmende Zeilen"
-#: builtin/grep.c:687
+#: builtin/grep.c:686
msgid "synonym for --files-with-matches"
msgstr "Synonym für --files-with-matches"
-#: builtin/grep.c:690
+#: builtin/grep.c:689
msgid "show only the names of files without match"
msgstr "zeigt nur die Dateinamen ohne Ãœbereinstimmungen"
-#: builtin/grep.c:692
+#: builtin/grep.c:691
msgid "print NUL after filenames"
msgstr "gibt NUL-Zeichen nach Dateinamen aus"
-#: builtin/grep.c:694
+#: builtin/grep.c:693
msgid "show the number of matches instead of matching lines"
msgstr "zeigt, anstatt der Zeilen, die Anzahl der übereinstimmenden Zeilen"
-#: builtin/grep.c:695
+#: builtin/grep.c:694
msgid "highlight matches"
msgstr "hebt Ãœbereinstimmungen hervor"
-#: builtin/grep.c:697
+#: builtin/grep.c:696
msgid "print empty line between matches from different files"
msgstr ""
"gibt eine Leerzeile zwischen Ãœbereinstimmungen in verschiedenen Dateien aus"
-#: builtin/grep.c:699
+#: builtin/grep.c:698
msgid "show filename only once above matches from same file"
msgstr ""
"zeigt den Dateinamen nur einmal oberhalb der Ãœbereinstimmungen aus dieser "
"Datei an"
-#: builtin/grep.c:702
+#: builtin/grep.c:701
msgid "show <n> context lines before and after matches"
msgstr "zeigt <n> Zeilen vor und nach den Ãœbereinstimmungen an"
-#: builtin/grep.c:705
+#: builtin/grep.c:704
msgid "show <n> context lines before matches"
msgstr "zeigt <n> Zeilen vor den Ãœbereinstimmungen an"
-#: builtin/grep.c:707
+#: builtin/grep.c:706
msgid "show <n> context lines after matches"
msgstr "zeigt <n> Zeilen nach den Ãœbereinstimmungen an"
-#: builtin/grep.c:708
+#: builtin/grep.c:707
msgid "shortcut for -C NUM"
msgstr "Kurzform für -C NUM"
-#: builtin/grep.c:711
+#: builtin/grep.c:710
msgid "show a line with the function name before matches"
msgstr "zeigt eine Zeile mit dem Funktionsnamen vor Ãœbereinstimmungen an"
-#: builtin/grep.c:713
+#: builtin/grep.c:712
msgid "show the surrounding function"
msgstr "zeigt die umgebende Funktion an"
-#: builtin/grep.c:716
+#: builtin/grep.c:715
msgid "read patterns from file"
msgstr "liest Muster von einer Datei"
-#: builtin/grep.c:718
+#: builtin/grep.c:717
msgid "match <pattern>"
msgstr "findet <Muster>"
-#: builtin/grep.c:720
+#: builtin/grep.c:719
msgid "combine patterns specified with -e"
msgstr "kombiniert Muster, die mit -e angegeben wurden"
-#: builtin/grep.c:732
+#: builtin/grep.c:731
msgid "indicate hit with exit status without output"
msgstr "zeigt Ãœbereinstimmungen nur durch Beendigungsstatus an"
-#: builtin/grep.c:734
+#: builtin/grep.c:733
msgid "show only matches from files that match all patterns"
msgstr "zeigt nur Ãœbereinstimmungen von Dateien, die allen Mustern entsprechen"
-#: builtin/grep.c:736
+#: builtin/grep.c:735
msgid "show parse tree for grep expression"
-msgstr "zeigt geparsten Baum für \"grep\"-Ausdruck"
+msgstr "zeigt geparstes Verzeichnis für \"grep\"-Ausdruck"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "pager"
msgstr "Anzeigeprogramm"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "show matching files in the pager"
msgstr "zeigt Dateien mit Ãœbereinstimmungen im Anzeigeprogramm"
-#: builtin/grep.c:743
+#: builtin/grep.c:742
msgid "allow calling of grep(1) (ignored by this build)"
msgstr "erlaubt den Aufruf von grep(1) (von dieser Programmversion ignoriert)"
-#: builtin/grep.c:744 builtin/show-ref.c:184
+#: builtin/grep.c:743 builtin/show-ref.c:188
msgid "show usage"
msgstr "zeigt Verwendung"
-#: builtin/grep.c:811
+#: builtin/grep.c:810
msgid "no pattern given."
msgstr "keine Muster angegeben"
-#: builtin/grep.c:825
-#, c-format
-msgid "bad object %s"
-msgstr "ungültiges Objekt %s"
-
-#: builtin/grep.c:868
+#: builtin/grep.c:865
msgid "--open-files-in-pager only works on the worktree"
msgstr ""
-"Die Option --open-files-in-pager kann nur innerhalb des Arbeitsbaums "
-"verwendet werden."
+"Die Option --open-files-in-pager kann nur innerhalb des "
+"Arbeitsverzeichnisses verwendet werden."
-#: builtin/grep.c:891
+#: builtin/grep.c:888
msgid "--cached or --untracked cannot be used with --no-index."
msgstr ""
"Die Optionen --cached und --untracked können nicht mit --no-index verwendet "
"werden."
-#: builtin/grep.c:896
+#: builtin/grep.c:893
msgid "--no-index or --untracked cannot be used with revs."
msgstr ""
-"Die Optionen --no-index und --untracked können nicht mit Versionen verwendet "
+"Die Optionen --no-index und --untracked können nicht mit Commits verwendet "
"werden."
-#: builtin/grep.c:899
+#: builtin/grep.c:896
msgid "--[no-]exclude-standard cannot be used for tracked contents."
msgstr ""
"Die Option --[no-]exclude-standard kann nicht mit beobachteten Inhalten "
"verwendet werden."
-#: builtin/grep.c:907
+#: builtin/grep.c:904
msgid "both --cached and trees are given."
-msgstr "Die Option --cached kann nicht mit Zweigen verwendet werden."
+msgstr "Die Option --cached kann nicht mit \"Tree\"-Objekten verwendet werden."
#: builtin/hash-object.c:60
msgid ""
@@ -5062,10 +5583,14 @@ msgstr "speichert Datei wie sie ist, ohne Filter"
msgid "process file as it were from this path"
msgstr "verarbeitet Datei, als ob sie von diesem Pfad wäre"
-#: builtin/help.c:42
+#: builtin/help.c:41
msgid "print all available commands"
msgstr "Anzeige aller vorhandenen Kommandos"
+#: builtin/help.c:42
+msgid "print list of useful guides"
+msgstr "zeigt Liste von allgemein verwendeten Anleitungen"
+
#: builtin/help.c:43
msgid "show man page"
msgstr "zeigt Handbuch"
@@ -5079,8 +5604,8 @@ msgid "show info page"
msgstr "zeigt Info-Seite"
#: builtin/help.c:52
-msgid "git help [--all] [--man|--web|--info] [command]"
-msgstr "git help [--all] [--man|--web|--info] [Kommando]"
+msgid "git help [--all] [--guides] [--man|--web|--info] [command]"
+msgstr "git help [--all] [--guides] [--man|--web|--info] [Kommando]"
#: builtin/help.c:64
#, c-format
@@ -5136,291 +5661,323 @@ msgstr "kein Handbuch-Betrachter konnte mit dieser Anfrage umgehen"
msgid "no info viewer handled the request"
msgstr "kein Informations-Betrachter konnte mit dieser Anfrage umgehen"
-#: builtin/help.c:429 builtin/help.c:436
+#: builtin/help.c:420
+msgid "Defining attributes per path"
+msgstr "Definition von Attributen pro Pfad"
+
+#: builtin/help.c:421
+msgid "A Git glossary"
+msgstr "Ein Git-Glossar"
+
+#: builtin/help.c:422
+msgid "Specifies intentionally untracked files to ignore"
+msgstr "Spezifikation von bewusst ignorierten, unbeobachteten Dateien"
+
+#: builtin/help.c:423
+msgid "Defining submodule properties"
+msgstr "Definition von Submodul-Eigenschaften"
+
+#: builtin/help.c:424
+msgid "Specifying revisions and ranges for Git"
+msgstr "Spezifikation von Commits und Bereichen für Git"
+
+#: builtin/help.c:425
+msgid "A tutorial introduction to Git (for version 1.5.1 or newer)"
+msgstr "Eine einführende Anleitung zu Git (für Version 1.5.1 oder neuer)"
+
+#: builtin/help.c:426
+msgid "An overview of recommended workflows with Git"
+msgstr "Eine Übersicht über empfohlene Arbeitsabläufe mit Git"
+
+#: builtin/help.c:438
+msgid "The common Git guides are:\n"
+msgstr "Die allgemein verwendeten Git-Anleitungen sind:\n"
+
+#: builtin/help.c:460 builtin/help.c:476
#, c-format
msgid "usage: %s%s"
msgstr "Verwendung: %s%s"
-#: builtin/help.c:452
+#: builtin/help.c:492
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr "für `git %s' wurde der Alias `%s' angelegt"
-#: builtin/index-pack.c:170
+#: builtin/index-pack.c:184
#, c-format
msgid "object type mismatch at %s"
msgstr "Objekt-Typen passen bei %s nicht zusammen"
-#: builtin/index-pack.c:190
+#: builtin/index-pack.c:204
msgid "object of unexpected type"
msgstr "Objekt hat unerwarteten Typ"
-#: builtin/index-pack.c:227
+#: builtin/index-pack.c:244
#, 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:237
+#: builtin/index-pack.c:254
msgid "early EOF"
msgstr "zu frühes Dateiende"
-#: builtin/index-pack.c:238
+#: builtin/index-pack.c:255
msgid "read error on input"
msgstr "Fehler beim Lesen der Eingabe"
-#: builtin/index-pack.c:250
+#: builtin/index-pack.c:267
msgid "used more bytes than were available"
msgstr "verwendete mehr Bytes als verfügbar waren"
-#: builtin/index-pack.c:257
+#: builtin/index-pack.c:274
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:273
+#: builtin/index-pack.c:290
#, c-format
msgid "unable to create '%s'"
msgstr "konnte '%s' nicht erstellen"
-#: builtin/index-pack.c:278
+#: builtin/index-pack.c:295
#, c-format
msgid "cannot open packfile '%s'"
msgstr "Kann Paketdatei '%s' nicht öffnen"
-#: builtin/index-pack.c:292
+#: builtin/index-pack.c:309
msgid "pack signature mismatch"
msgstr "Paketsignatur stimmt nicht überein"
-#: builtin/index-pack.c:294
+#: builtin/index-pack.c:311
#, c-format
msgid "pack version %<PRIu32> unsupported"
msgstr "Paketversion %<PRIu32> nicht unterstützt"
-#: builtin/index-pack.c:312
+#: builtin/index-pack.c:329
#, 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:434
+#: builtin/index-pack.c:451
#, c-format
msgid "inflate returned %d"
msgstr "Dekomprimierung gab %d zurück"
-#: builtin/index-pack.c:483
+#: builtin/index-pack.c:500
msgid "offset value overflow for delta base object"
msgstr "Wert für Versatz bei Differenzobjekt übergelaufen"
-#: builtin/index-pack.c:491
+#: builtin/index-pack.c:508
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:499
+#: builtin/index-pack.c:516
#, c-format
msgid "unknown object type %d"
msgstr "Unbekannter Objekt-Typ %d"
-#: builtin/index-pack.c:530
+#: builtin/index-pack.c:547
msgid "cannot pread pack file"
msgstr "Kann Paketdatei %s nicht lesen"
-#: builtin/index-pack.c:532
+#: builtin/index-pack.c:549
#, 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:558
+#: builtin/index-pack.c:575
msgid "serious inflate inconsistency"
msgstr "ernsthafte Inkonsistenz nach Dekomprimierung"
-#: 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
+#: builtin/index-pack.c:666 builtin/index-pack.c:672 builtin/index-pack.c:695
+#: builtin/index-pack.c:729 builtin/index-pack.c:738
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "SHA1 KOLLISION MIT %s GEFUNDEN !"
-#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/index-pack.c:669 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
+#: builtin/index-pack.c:735
#, c-format
msgid "cannot read existing object %s"
msgstr "Kann existierendes Objekt %s nicht lesen."
-#: builtin/index-pack.c:732
+#: builtin/index-pack.c:749
#, c-format
msgid "invalid blob object %s"
msgstr "ungültiges Blob-Objekt %s"
-#: builtin/index-pack.c:747
+#: builtin/index-pack.c:763
#, c-format
msgid "invalid %s"
msgstr "Ungültiger Objekt-Typ %s"
-#: builtin/index-pack.c:749
+#: builtin/index-pack.c:766
msgid "Error in object"
msgstr "Fehler in Objekt"
-#: builtin/index-pack.c:751
+#: builtin/index-pack.c:768
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr "Nicht alle Kind-Objekte von %s sind erreichbar"
-#: builtin/index-pack.c:821 builtin/index-pack.c:847
+#: builtin/index-pack.c:838 builtin/index-pack.c:868
msgid "failed to apply delta"
msgstr "Konnte Dateiunterschied nicht anwenden"
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Receiving objects"
msgstr "Empfange Objekte"
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Indexing objects"
msgstr "Indiziere Objekte"
-#: builtin/index-pack.c:1012
+#: builtin/index-pack.c:1035
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "Paket ist beschädigt (SHA1 unterschiedlich)"
-#: builtin/index-pack.c:1017
+#: builtin/index-pack.c:1040
msgid "cannot fstat packfile"
msgstr "kann Paketdatei nicht lesen"
-#: builtin/index-pack.c:1020
+#: builtin/index-pack.c:1043
msgid "pack has junk at the end"
msgstr "Paketende enthält nicht verwendbaren Inhalt"
-#: builtin/index-pack.c:1031
+#: builtin/index-pack.c:1054
msgid "confusion beyond insanity in parse_pack_objects()"
msgstr "Fehler beim Ausführen von \"parse_pack_objects()\""
-#: builtin/index-pack.c:1054
+#: builtin/index-pack.c:1077
msgid "Resolving deltas"
msgstr "Löse Unterschiede auf"
-#: builtin/index-pack.c:1064
+#: builtin/index-pack.c:1087
#, c-format
msgid "unable to create thread: %s"
msgstr "kann Thread nicht erzeugen: %s"
-#: builtin/index-pack.c:1106
+#: builtin/index-pack.c:1129
msgid "confusion beyond insanity"
msgstr "Fehler beim Auflösen der Unterschiede"
-#: builtin/index-pack.c:1112
+#: builtin/index-pack.c:1137
#, c-format
msgid "completed with %d local objects"
msgstr "vervollständigt mit %d lokalen Objekten"
-#: builtin/index-pack.c:1121
+#: builtin/index-pack.c:1147
#, c-format
msgid "Unexpected tail checksum for %s (disk corruption?)"
msgstr "Unerwartete Prüfsumme für %s (Festplattenfehler?)"
-#: builtin/index-pack.c:1125
+#: builtin/index-pack.c:1151
#, 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:1150
+#: builtin/index-pack.c:1176
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr "Konnte angehängtes Objekt (%d) nicht komprimieren"
-#: builtin/index-pack.c:1229
+#: builtin/index-pack.c:1255
#, c-format
msgid "local object %s is corrupt"
msgstr "lokales Objekt %s ist beschädigt"
-#: builtin/index-pack.c:1253
+#: builtin/index-pack.c:1279
msgid "error while closing pack file"
msgstr "Fehler beim Schließen der Paketdatei"
-#: builtin/index-pack.c:1266
+#: builtin/index-pack.c:1292
#, c-format
msgid "cannot write keep file '%s'"
msgstr "Kann Paketbeschreibungsdatei '%s' nicht schreiben"
-#: builtin/index-pack.c:1274
+#: builtin/index-pack.c:1300
#, c-format
msgid "cannot close written keep file '%s'"
msgstr "Kann eben erstellte Paketbeschreibungsdatei '%s' nicht schließen"
-#: builtin/index-pack.c:1287
+#: builtin/index-pack.c:1313
msgid "cannot store pack file"
msgstr "Kann Paketdatei nicht speichern"
-#: builtin/index-pack.c:1298
+#: builtin/index-pack.c:1324
msgid "cannot store index file"
msgstr "Kann Indexdatei nicht speichern"
-#: builtin/index-pack.c:1331
+#: builtin/index-pack.c:1357
#, c-format
msgid "bad pack.indexversion=%<PRIu32>"
msgstr "\"pack.indexversion=%<PRIu32>\" ist ungültig"
-#: builtin/index-pack.c:1337
+#: builtin/index-pack.c:1363
#, c-format
msgid "invalid number of threads specified (%d)"
msgstr "ungültige Anzahl von Threads angegeben (%d)"
-#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#: builtin/index-pack.c:1367 builtin/index-pack.c:1545
#, c-format
msgid "no threads support, ignoring %s"
msgstr "keine Unterstützung von Threads, '%s' wird ignoriert"
-#: builtin/index-pack.c:1399
+#: builtin/index-pack.c:1425
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr "Kann existierende Paketdatei '%s' nicht öffnen"
-#: builtin/index-pack.c:1401
+#: builtin/index-pack.c:1427
#, 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:1448
+#: builtin/index-pack.c:1474
#, 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:1455
+#: builtin/index-pack.c:1481
#, 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:1482
+#: builtin/index-pack.c:1509
msgid "Cannot come back to cwd"
msgstr "Kann nicht zurück zu Arbeitsverzeichnis wechseln"
-#: builtin/index-pack.c:1526 builtin/index-pack.c:1529
-#: builtin/index-pack.c:1541 builtin/index-pack.c:1545
+#: builtin/index-pack.c:1557 builtin/index-pack.c:1560
+#: builtin/index-pack.c:1572 builtin/index-pack.c:1576
#, c-format
msgid "bad %s"
msgstr "%s ist ungültig"
-#: builtin/index-pack.c:1559
+#: builtin/index-pack.c:1590
msgid "--fix-thin cannot be used without --stdin"
msgstr "Die Option --fix-thin kann nicht ohne --stdin verwendet werden."
-#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
+#: builtin/index-pack.c:1594 builtin/index-pack.c:1604
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr "Name der Paketdatei '%s' endet nicht mit '.pack'"
-#: builtin/index-pack.c:1582
+#: builtin/index-pack.c:1613
msgid "--verify with no packfile name given"
msgstr "Die Option --verify wurde ohne Namen der Paketdatei angegeben."
@@ -5452,17 +6009,17 @@ msgstr "kann Verzeichnis '%s' nicht öffnen"
#: builtin/init-db.c:97
#, c-format
msgid "cannot readlink '%s'"
-msgstr "kann Verknüpfung '%s' nicht lesen"
+msgstr "kann Verweis '%s' nicht lesen"
#: builtin/init-db.c:99
#, c-format
msgid "insanely long symlink %s"
-msgstr "zu lange symbolische Verknüpfung %s"
+msgstr "zu langer symbolischer Verweis %s"
#: builtin/init-db.c:102
#, c-format
msgid "cannot symlink '%s' '%s'"
-msgstr "kann '%s' nicht mit '%s' symbolisch verknüpfen"
+msgstr "kann symbolischen Verweis '%s' auf '%s' nicht erstellen"
#: builtin/init-db.c:106
#, c-format
@@ -5512,7 +6069,7 @@ msgstr "Konnte %s nicht nach %s verschieben"
#: builtin/init-db.c:363
#, c-format
msgid "Could not create git link %s"
-msgstr "Konnte git-Verknüpfung %s nicht erstellen"
+msgstr "Konnte git-Verweis %s nicht erstellen"
#.
#. * TRANSLATORS: The first '%s' is either "Reinitialized
@@ -5522,7 +6079,7 @@ msgstr "Konnte git-Verknüpfung %s nicht erstellen"
#: 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"
+msgstr "%s%s Git-Repository in %s%s\n"
#: builtin/init-db.c:421
msgid "Reinitialized existing"
@@ -5554,10 +6111,9 @@ msgstr "Berechtigungen"
#: builtin/init-db.c:491
msgid "specify that the git repository is to be shared amongst several users"
-msgstr ""
-"gibt an, dass das Git-Projektarchiv mit mehreren Benutzern geteilt wird"
+msgstr "gibt an, dass das Git-Repository mit mehreren Benutzern geteilt wird"
-#: builtin/init-db.c:493 builtin/prune-packed.c:77
+#: builtin/init-db.c:493 builtin/prune-packed.c:75
msgid "be quiet"
msgstr "weniger Ausgaben"
@@ -5587,373 +6143,385 @@ msgstr "Kann nicht auf aktuelles Arbeitsverzeichnis zugreifen."
#: builtin/init-db.c:586
#, c-format
msgid "Cannot access work tree '%s'"
-msgstr "Kann nicht auf Arbeitsbaum '%s' zugreifen."
+msgstr "Kann nicht auf Arbeitsverzeichnis '%s' zugreifen."
-#: builtin/log.c:39
-msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
-msgstr "git log [<Optionen>] [<seit>..<bis>] [[--] <Pfad>...]\n"
+#: builtin/log.c:41
+msgid "git log [<options>] [<revision range>] [[--] <path>...]\n"
+msgstr "git log [<Optionen>] [Commitbereich>] [[--] <Pfad>...]\n"
-#: builtin/log.c:40
+#: builtin/log.c:42
msgid " or: git show [options] <object>..."
msgstr " oder: git show [Optionen] <Objekt>..."
-#: builtin/log.c:102
+#: builtin/log.c:124
msgid "suppress diff output"
msgstr "unterdrückt Ausgabe der Unterschiede"
-#: builtin/log.c:103
+#: builtin/log.c:125
msgid "show source"
msgstr "zeigt Quelle"
-#: builtin/log.c:104
+#: builtin/log.c:126
msgid "Use mail map file"
msgstr "verwendet \"mailmap\"-Datei"
-#: builtin/log.c:105
+#: builtin/log.c:127
msgid "decorate options"
msgstr "decorate-Optionen"
-#: builtin/log.c:198
+#: builtin/log.c:230
#, c-format
msgid "Final output: %d %s\n"
msgstr "letzte Ausgabe: %d %s\n"
-#: builtin/log.c:419 builtin/log.c:511
+#: builtin/log.c:453 builtin/log.c:545
#, c-format
msgid "Could not read object %s"
msgstr "Kann Objekt %s nicht lesen."
-#: builtin/log.c:535
+#: builtin/log.c:569
#, c-format
msgid "Unknown type: %d"
msgstr "Unbekannter Typ: %d"
-#: builtin/log.c:627
+#: builtin/log.c:669
msgid "format.headers without value"
msgstr "format.headers ohne Wert"
-#: builtin/log.c:701
+#: builtin/log.c:751
msgid "name of output directory is too long"
msgstr "Name des Ausgabeverzeichnisses ist zu lang."
-#: builtin/log.c:717
+#: builtin/log.c:767
#, c-format
msgid "Cannot open patch file %s"
msgstr "Kann Patch-Datei %s nicht öffnen"
-#: builtin/log.c:731
+#: builtin/log.c:781
msgid "Need exactly one range."
-msgstr "Brauche genau einen Versionsbereich."
+msgstr "Brauche genau einen Commit-Bereich."
-#: builtin/log.c:739
+#: builtin/log.c:789
msgid "Not a range."
-msgstr "Kein Versionsbereich."
+msgstr "Kein Commit-Bereich."
-#: builtin/log.c:812
+#: builtin/log.c:891
msgid "Cover letter needs email format"
msgstr "Anschreiben benötigt E-Mail-Format"
-#: builtin/log.c:885
+#: builtin/log.c:967
#, c-format
msgid "insane in-reply-to: %s"
msgstr "ungültiges in-reply-to: %s"
-#: builtin/log.c:913
+#: builtin/log.c:995
msgid "git format-patch [options] [<since> | <revision range>]"
-msgstr "git format-patch [Optionen] [<seit> | <Revisionsbereich>]"
+msgstr "git format-patch [Optionen] [<seit> | <Commitbereich>]"
-#: builtin/log.c:958
+#: builtin/log.c:1040
msgid "Two output directories?"
msgstr "Zwei Ausgabeverzeichnisse?"
-#: builtin/log.c:1097
+#: builtin/log.c:1155
msgid "use [PATCH n/m] even with a single patch"
msgstr "verwendet [PATCH n/m] auch mit einzelnem Patch"
-#: builtin/log.c:1100
+#: builtin/log.c:1158
msgid "use [PATCH] even with multiple patches"
msgstr "verwendet [PATCH] auch mit mehreren Patches"
-#: builtin/log.c:1104
+#: builtin/log.c:1162
msgid "print patches to standard out"
msgstr "Ausgabe der Patches in Standard-Ausgabe"
-#: builtin/log.c:1106
+#: builtin/log.c:1164
msgid "generate a cover letter"
msgstr "erzeugt ein Deckblatt"
-#: builtin/log.c:1108
+#: builtin/log.c:1166
msgid "use simple number sequence for output file names"
msgstr "verwendet einfache Nummernfolge für die Namen der Ausgabedateien"
-#: builtin/log.c:1109
+#: builtin/log.c:1167
msgid "sfx"
msgstr "Dateiendung"
-#: builtin/log.c:1110
+#: builtin/log.c:1168
msgid "use <sfx> instead of '.patch'"
msgstr "verwendet <Dateiendung> anstatt '.patch'"
-#: builtin/log.c:1112
+#: builtin/log.c:1170
msgid "start numbering patches at <n> instead of 1"
msgstr "beginnt die Nummerierung der Patches bei <n> anstatt bei 1"
-#: builtin/log.c:1114
+#: builtin/log.c:1172
msgid "mark the series as Nth re-roll"
msgstr "kennzeichnet die Serie als n-te Fassung"
-#: builtin/log.c:1116
+#: builtin/log.c:1174
msgid "Use [<prefix>] instead of [PATCH]"
msgstr "verwendet [<Prefix>] anstatt [PATCH]"
-#: builtin/log.c:1119
+#: builtin/log.c:1177
msgid "store resulting files in <dir>"
msgstr "speichert erzeugte Dateien in <Verzeichnis>"
-#: builtin/log.c:1122
+#: builtin/log.c:1180
msgid "don't strip/add [PATCH]"
msgstr "[PATCH] wird nicht entfernt/hinzugefügt"
-#: builtin/log.c:1125
+#: builtin/log.c:1183
msgid "don't output binary diffs"
msgstr "gibt keine binären Unterschiede aus"
-#: builtin/log.c:1127
+#: builtin/log.c:1185
msgid "don't include a patch matching a commit upstream"
msgstr ""
-"schließt keine Patches ein, die einer Version im Übernahmezweig entsprechen"
+"schließt keine Patches ein, die einem Commit im Upstream-Branch entsprechen"
-#: builtin/log.c:1129
+#: builtin/log.c:1187
msgid "show patch format instead of default (patch + stat)"
msgstr "zeigt Patchformat anstatt des Standards (Patch + Zusammenfassung)"
-#: builtin/log.c:1131
+#: builtin/log.c:1189
msgid "Messaging"
msgstr "Email-Einstellungen"
-#: builtin/log.c:1132
+#: builtin/log.c:1190
msgid "header"
msgstr "Header"
-#: builtin/log.c:1133
+#: builtin/log.c:1191
msgid "add email header"
msgstr "fügt Email-Header hinzu"
-#: builtin/log.c:1134 builtin/log.c:1136
+#: builtin/log.c:1192 builtin/log.c:1194
msgid "email"
msgstr "Email"
-#: builtin/log.c:1134
+#: builtin/log.c:1192
msgid "add To: header"
msgstr "fügt \"To:\"-Header hinzu"
-#: builtin/log.c:1136
+#: builtin/log.c:1194
msgid "add Cc: header"
msgstr "fügt \"Cc:\"-Header hinzu"
-#: builtin/log.c:1138
+#: builtin/log.c:1196
+msgid "ident"
+msgstr "Ident"
+
+#: builtin/log.c:1197
+msgid "set From address to <ident> (or committer ident if absent)"
+msgstr ""
+"setzt \"From\"-Adresse auf <Ident> (oder Ident des Commit-Erstellers,wenn "
+"fehlend)"
+
+#: builtin/log.c:1199
msgid "message-id"
msgstr "message-id"
-#: builtin/log.c:1139
+#: builtin/log.c:1200
msgid "make first mail a reply to <message-id>"
msgstr "macht aus erster Email eine Antwort zu <message-id>"
-#: builtin/log.c:1140 builtin/log.c:1143
+#: builtin/log.c:1201 builtin/log.c:1204
msgid "boundary"
msgstr "Grenze"
-#: builtin/log.c:1141
+#: builtin/log.c:1202
msgid "attach the patch"
msgstr "hängt einen Patch an"
-#: builtin/log.c:1144
+#: builtin/log.c:1205
msgid "inline the patch"
msgstr "fügt den Patch direkt in die Nachricht ein"
-#: builtin/log.c:1148
+#: builtin/log.c:1209
msgid "enable message threading, styles: shallow, deep"
msgstr "aktiviert Nachrichtenverkettung, Stile: shallow, deep"
-#: builtin/log.c:1150
+#: builtin/log.c:1211
msgid "signature"
msgstr "Signatur"
-#: builtin/log.c:1151
+#: builtin/log.c:1212
msgid "add a signature"
msgstr "fügt eine Signatur hinzu"
-#: builtin/log.c:1153
+#: builtin/log.c:1214
msgid "don't print the patch filenames"
msgstr "zeigt keine Dateinamen der Patches"
-#: builtin/log.c:1202
+#: builtin/log.c:1288
#, c-format
-msgid "bogus committer info %s"
-msgstr "unechte Einreicher-Informationen %s"
+msgid "invalid ident line: %s"
+msgstr "Ungültige Identifikationszeile: %s"
-#: builtin/log.c:1247
+#: builtin/log.c:1303
msgid "-n and -k are mutually exclusive."
msgstr "Die Optionen -n und -k schließen sich gegenseitig aus."
-#: builtin/log.c:1249
+#: builtin/log.c:1305
msgid "--subject-prefix and -k are mutually exclusive."
msgstr "Die Optionen --subject-prefix und -k schließen sich gegenseitig aus."
-#: builtin/log.c:1257
+#: builtin/log.c:1313
msgid "--name-only does not make sense"
msgstr "Die Option --name-only kann nicht verwendet werden."
-#: builtin/log.c:1259
+#: builtin/log.c:1315
msgid "--name-status does not make sense"
msgstr "Die Option --name-status kann nicht verwendet werden."
-#: builtin/log.c:1261
+#: builtin/log.c:1317
msgid "--check does not make sense"
msgstr "Die Option --check kann nicht verwendet werden."
-#: builtin/log.c:1284
+#: builtin/log.c:1340
msgid "standard output, or directory, which one?"
msgstr "Standard-Ausgabe oder Verzeichnis, welches von beidem?"
-#: builtin/log.c:1286
+#: builtin/log.c:1342
#, c-format
msgid "Could not create directory '%s'"
msgstr "Konnte Verzeichnis '%s' nicht erstellen."
-#: builtin/log.c:1439
+#: builtin/log.c:1490
msgid "Failed to create output files"
msgstr "Fehler beim Erstellen der Ausgabedateien."
-#: builtin/log.c:1488
+#: builtin/log.c:1539
msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
-msgstr "git cherry [-v] [<Ãœbernahmezweig> [<Arbeitszweig> [<Limit>]]]"
+msgstr "git cherry [-v] [<Upstream> [<Branch> [<Limit>]]]"
-#: builtin/log.c:1543
+#: builtin/log.c:1594
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
msgstr ""
-"Konnte gefolgten, externen Zweig nicht finden, bitte geben Sie <upstream> "
+"Konnte gefolgten Remote-Branch nicht finden, bitte geben Sie <Upstream> "
"manuell an.\n"
-#: builtin/log.c:1556 builtin/log.c:1558 builtin/log.c:1570
+#: builtin/log.c:1607 builtin/log.c:1609 builtin/log.c:1621
#, c-format
msgid "Unknown commit %s"
-msgstr "Unbekannte Version %s"
+msgstr "Unbekannter Commit %s"
-#: builtin/ls-files.c:409
+#: builtin/ls-files.c:408
msgid "git ls-files [options] [<file>...]"
msgstr "git ls-files [Optionen] [<Datei>...]"
-#: builtin/ls-files.c:466
+#: builtin/ls-files.c:465
msgid "identify the file status with tags"
-msgstr "zeigt den Dateistatus mit Markierungen"
+msgstr "zeigt den Dateistatus mit Tags"
-#: builtin/ls-files.c:468
+#: builtin/ls-files.c:467
msgid "use lowercase letters for 'assume unchanged' files"
msgstr ""
"verwendet Kleinbuchstaben für Dateien mit 'assume unchanged' Markierung"
-#: builtin/ls-files.c:470
+#: builtin/ls-files.c:469
msgid "show cached files in the output (default)"
msgstr "zeigt zwischengespeicherten Dateien in der Ausgabe an (Standard)"
-#: builtin/ls-files.c:472
+#: builtin/ls-files.c:471
msgid "show deleted files in the output"
msgstr "zeigt entfernte Dateien in der Ausgabe an"
-#: builtin/ls-files.c:474
+#: builtin/ls-files.c:473
msgid "show modified files in the output"
msgstr "zeigt geänderte Dateien in der Ausgabe an"
-#: builtin/ls-files.c:476
+#: builtin/ls-files.c:475
msgid "show other files in the output"
msgstr "zeigt sonstige Dateien in der Ausgabe an"
-#: builtin/ls-files.c:478
+#: builtin/ls-files.c:477
msgid "show ignored files in the output"
msgstr "zeigt ignorierte Dateien in der Ausgabe an"
-#: builtin/ls-files.c:481
+#: builtin/ls-files.c:480
msgid "show staged contents' object name in the output"
-msgstr "zeigt Objektnamen von Inhalten in der Bereitstellung in der Ausgabe an"
+msgstr ""
+"zeigt Objektnamen von Inhalten, die zum Commit vorgemerkt sind, in der "
+"Ausgabe an"
-#: builtin/ls-files.c:483
+#: builtin/ls-files.c:482
msgid "show files on the filesystem that need to be removed"
msgstr "zeigt Dateien im Dateisystem, die gelöscht werden müssen, an"
-#: builtin/ls-files.c:485
+#: builtin/ls-files.c:484
msgid "show 'other' directories' name only"
msgstr "zeigt nur Namen von 'sonstigen' Verzeichnissen an"
-#: builtin/ls-files.c:488
+#: builtin/ls-files.c:487
msgid "don't show empty directories"
msgstr "zeigt keine leeren Verzeichnisse an"
-#: builtin/ls-files.c:491
+#: builtin/ls-files.c:490
msgid "show unmerged files in the output"
msgstr "zeigt nicht zusammengeführte Dateien in der Ausgabe an"
-#: builtin/ls-files.c:493
+#: builtin/ls-files.c:492
msgid "show resolve-undo information"
msgstr "zeigt 'resolve-undo' Informationen an"
-#: builtin/ls-files.c:495
+#: builtin/ls-files.c:494
msgid "skip files matching pattern"
msgstr "lässt Dateien aus, die einem Muster entsprechen"
-#: builtin/ls-files.c:498
+#: builtin/ls-files.c:497
msgid "exclude patterns are read from <file>"
msgstr "schließt Muster, gelesen von <Datei>, aus"
-#: builtin/ls-files.c:501
+#: builtin/ls-files.c:500
msgid "read additional per-directory exclude patterns in <file>"
msgstr "liest zusätzliche pro-Verzeichnis Auschlussmuster aus <Datei>"
-#: builtin/ls-files.c:503
+#: builtin/ls-files.c:502
msgid "add the standard git exclusions"
msgstr "fügt die standardmäßigen Git-Ausschlüsse hinzu"
-#: builtin/ls-files.c:506
+#: builtin/ls-files.c:505
msgid "make the output relative to the project top directory"
msgstr "Ausgabe relativ zum Projektverzeichnis"
-#: builtin/ls-files.c:509
+#: builtin/ls-files.c:508
msgid "if any <file> is not in the index, treat this as an error"
msgstr ""
-"behandle es als Fehler, wenn sich eine <Datei> nicht in der Bereitstellung "
+"behandle es als Fehler, wenn sich eine <Datei> nicht in der Staging-Area "
"befindet"
-#: builtin/ls-files.c:510
+#: builtin/ls-files.c:509
msgid "tree-ish"
-msgstr "Versionsreferenz"
+msgstr "Commit-Referenz"
-#: builtin/ls-files.c:511
+#: builtin/ls-files.c:510
msgid "pretend that paths removed since <tree-ish> are still present"
msgstr ""
-"gibt vor, dass Pfade, die seit <Versionsreferenz> gelöscht wurden, immer "
-"noch vorhanden sind"
+"gibt vor, dass Pfade, die seit <Commit-Referenz> gelöscht wurden, immer noch "
+"vorhanden sind"
-#: builtin/ls-files.c:513
+#: builtin/ls-files.c:512
msgid "show debugging data"
msgstr "zeigt Ausgaben zur Fehlersuche an"
#: builtin/ls-tree.c:27
msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
-msgstr "git ls-tree [<Optionen>] <Versionsreferenz> [<Pfad>...]"
+msgstr "git ls-tree [<Optionen>] <Commit-Referenz> [<Pfad>...]"
#: builtin/ls-tree.c:125
msgid "only show trees"
-msgstr "zeigt nur Bäume an"
+msgstr "zeigt nur Verzeichnisse an"
#: builtin/ls-tree.c:127
msgid "recurse into subtrees"
-msgstr "führt Rekursion in Teilbäumen durch"
+msgstr "führt Rekursion in Unterverzeichnissen durch"
#: builtin/ls-tree.c:129
msgid "show trees when recursing"
-msgstr "zeigt Bäume bei Rekursion an"
+msgstr "zeigt Verzeichnisse bei Rekursion an"
#: builtin/ls-tree.c:132
msgid "terminate entries with NUL byte"
@@ -5974,191 +6542,187 @@ msgstr "verwendet vollständige Pfadnamen"
#: builtin/ls-tree.c:142
msgid "list entire tree; not just current directory (implies --full-name)"
msgstr ""
-"listet den gesamten Baum auf; nicht nur das aktuelle Verzeichnis (impliziert "
-"--full-name)"
+"listet das gesamte Verzeichnis auf; nicht nur das aktuelle Verzeichnis "
+"(impliziert --full-name)"
#: builtin/merge.c:43
msgid "git merge [options] [<commit>...]"
-msgstr "git merge [Optionen] [<Version>...]"
+msgstr "git merge [Optionen] [<Commit>...]"
#: builtin/merge.c:44
msgid "git merge [options] <msg> HEAD <commit>"
-msgstr "git merge [Optionen] <Beschreibung> HEAD <Version>"
+msgstr "git merge [Optionen] <Beschreibung> HEAD <Commit>"
#: builtin/merge.c:45
msgid "git merge --abort"
msgstr "git merge --abort"
-#: builtin/merge.c:90
+#: builtin/merge.c:98
msgid "switch `m' requires a value"
msgstr "Schalter 'm' erfordert einen Wert."
-#: builtin/merge.c:127
+#: builtin/merge.c:135
#, c-format
msgid "Could not find merge strategy '%s'.\n"
-msgstr "Konnte Zusammenführungsstrategie '%s' nicht finden.\n"
+msgstr "Konnte Merge-Strategie '%s' nicht finden.\n"
-#: builtin/merge.c:128
+#: builtin/merge.c:136
#, c-format
msgid "Available strategies are:"
msgstr "Verfügbare Strategien sind:"
-#: builtin/merge.c:133
+#: builtin/merge.c:141
#, c-format
msgid "Available custom strategies are:"
msgstr "Verfügbare benutzerdefinierte Strategien sind:"
-#: builtin/merge.c:183
+#: builtin/merge.c:198
msgid "do not show a diffstat at the end of the merge"
-msgstr ""
-"zeigt keine Zusammenfassung der Unterschiede am Schluss der Zusammenführung "
-"an"
+msgstr "zeigt keine Zusammenfassung der Unterschiede am Schluss des Merges an"
-#: builtin/merge.c:186
+#: builtin/merge.c:201
msgid "show a diffstat at the end of the merge"
-msgstr ""
-"zeigt eine Zusammenfassung der Unterschiede am Schluss der Zusammenführung an"
+msgstr "zeigt eine Zusammenfassung der Unterschiede am Schluss des Merges an"
-#: builtin/merge.c:187
+#: builtin/merge.c:202
msgid "(synonym to --stat)"
msgstr "(Synonym für --stat)"
-#: builtin/merge.c:189
+#: builtin/merge.c:204
msgid "add (at most <n>) entries from shortlog to merge commit message"
msgstr ""
-"fügt (höchstens <n>) Einträge von \"shortlog\" zur Beschreibung der "
-"Zusammenführung hinzu"
+"fügt (höchstens <n>) Einträge von \"shortlog\" zur Beschreibung des Merge-"
+"Commits hinzu"
-#: builtin/merge.c:192
+#: builtin/merge.c:207
msgid "create a single commit instead of doing a merge"
-msgstr "erzeugt eine einzelne Version anstatt einer Zusammenführung"
+msgstr "erzeugt einen einzelnen Commit anstatt eines Merges"
-#: builtin/merge.c:194
+#: builtin/merge.c:209
msgid "perform a commit if the merge succeeds (default)"
-msgstr ""
-"führt eine Eintragung durch, wenn die Zusammenführung erfolgreich war "
-"(Standard)"
+msgstr "führt einen Commit durch, wenn der Merge erfolgreich war (Standard)"
-#: builtin/merge.c:196
+#: builtin/merge.c:211
msgid "edit message before committing"
-msgstr "Bearbeitung der Versionsbeschreibung vor der Eintragung"
+msgstr "Bearbeitung der Beschreibung vor dem Commit"
-#: builtin/merge.c:198
+#: builtin/merge.c:212
msgid "allow fast-forward (default)"
msgstr "erlaubt Vorspulen (Standard)"
-#: builtin/merge.c:200
+#: builtin/merge.c:214
msgid "abort if fast-forward is not possible"
msgstr "bricht ab, wenn kein Vorspulen möglich ist"
-#: builtin/merge.c:202 builtin/notes.c:866 builtin/revert.c:112
+#: builtin/merge.c:218
+msgid "Verify that the named commit has a valid GPG signature"
+msgstr "überprüft den genannten Commit auf eine gültige GPG-Signatur"
+
+#: builtin/merge.c:219 builtin/notes.c:738 builtin/revert.c:114
msgid "strategy"
msgstr "Strategie"
-#: builtin/merge.c:203
+#: builtin/merge.c:220
msgid "merge strategy to use"
-msgstr "zu verwendende Zusammenführungsstrategie"
+msgstr "zu verwendende Merge-Strategie"
-#: builtin/merge.c:204
+#: builtin/merge.c:221
msgid "option=value"
msgstr "Option=Wert"
-#: builtin/merge.c:205
+#: builtin/merge.c:222
msgid "option for selected merge strategy"
-msgstr "Option für ausgewählte Zusammenführungsstrategie"
+msgstr "Option für ausgewählte Merge-Strategie"
-#: builtin/merge.c:207
+#: builtin/merge.c:224
msgid "merge commit message (for a non-fast-forward merge)"
msgstr ""
-"führt Versionsbeschreibung zusammen (für eine Zusammenführung, die kein "
-"Vorspulen war)"
+"führt Commit-Beschreibung zusammen (für einen Merge, der kein Vorspulen war)"
-#: builtin/merge.c:211
+#: builtin/merge.c:228
msgid "abort the current in-progress merge"
-msgstr "bricht die sich im Gange befindliche Zusammenführung ab"
+msgstr "bricht den sich im Gange befindlichen Merge ab"
-#: builtin/merge.c:240
+#: builtin/merge.c:257
msgid "could not run stash."
msgstr "Konnte \"stash\" nicht ausführen."
-#: builtin/merge.c:245
+#: builtin/merge.c:262
msgid "stash failed"
msgstr "\"stash\" fehlgeschlagen"
-#: builtin/merge.c:250
+#: builtin/merge.c:267
#, c-format
msgid "not a valid object: %s"
msgstr "kein gültiges Objekt: %s"
-#: builtin/merge.c:269 builtin/merge.c:286
+#: builtin/merge.c:286 builtin/merge.c:303
msgid "read-tree failed"
msgstr "read-tree fehlgeschlagen"
-#: builtin/merge.c:316
+#: builtin/merge.c:333
msgid " (nothing to squash)"
msgstr " (nichts zu quetschen)"
-#: builtin/merge.c:329
+#: builtin/merge.c:346
#, c-format
msgid "Squash commit -- not updating HEAD\n"
-msgstr "Quetsche Version -- Zweigspitze (HEAD) wird nicht aktualisiert\n"
+msgstr "Quetsche Commit -- HEAD wird nicht aktualisiert\n"
-#: builtin/merge.c:361
+#: builtin/merge.c:378
msgid "Writing SQUASH_MSG"
msgstr "Schreibe SQUASH_MSG"
-#: builtin/merge.c:363
+#: builtin/merge.c:380
msgid "Finishing SQUASH_MSG"
msgstr "Schließe SQUASH_MSG ab"
-#: builtin/merge.c:386
+#: builtin/merge.c:403
#, c-format
msgid "No merge message -- not updating HEAD\n"
-msgstr ""
-"Keine Zusammenführungsbeschreibung -- Zweigspitze (HEAD) wird nicht "
-"aktualisiert\n"
+msgstr "Keine Merge-Commit-Beschreibung -- HEAD wird nicht aktualisiert\n"
-#: builtin/merge.c:436
+#: builtin/merge.c:453
#, c-format
msgid "'%s' does not point to a commit"
-msgstr "'%s' zeigt auf keine Version"
+msgstr "'%s' zeigt auf keinen Commit"
-#: builtin/merge.c:535
+#: builtin/merge.c:565
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Ungültiger branch.%s.mergeoptions String: %s"
-#: builtin/merge.c:628
+#: builtin/merge.c:657
msgid "git write-tree failed to write a tree"
-msgstr "\"git write-tree\" schlug beim Schreiben eines Baumes fehl"
+msgstr "\"git write-tree\" schlug beim Schreiben eines \"Tree\"-Objektes fehl"
-#: builtin/merge.c:656
+#: builtin/merge.c:685
msgid "Not handling anything other than two heads merge."
-msgstr "Es wird nur die Zusammenführung von zwei Zweigen behandelt."
+msgstr "Es wird nur der Merge von zwei Branches behandelt."
-#: builtin/merge.c:670
+#: builtin/merge.c:699
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr "Unbekannte Option für merge-recursive: -X%s"
-#: builtin/merge.c:684
+#: builtin/merge.c:713
#, c-format
msgid "unable to write %s"
msgstr "konnte %s nicht schreiben"
-#: builtin/merge.c:773
+#: builtin/merge.c:802
#, c-format
msgid "Could not read from '%s'"
msgstr "konnte nicht von '%s' lesen"
-#: builtin/merge.c:782
+#: builtin/merge.c:811
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
-"Zusammenführung wurde nicht eingetragen; benutzen Sie 'git commit' um die "
-"Zusammenführung abzuschließen.\n"
+"Merge wurde nicht committet; benutzen Sie 'git commit' um den Merge "
+"abzuschließen.\n"
-#: builtin/merge.c:788
+#: builtin/merge.c:817
#, c-format
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
@@ -6167,197 +6731,212 @@ msgid ""
"Lines starting with '%c' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"Bitte geben Sie eine Versionsbeschreibung ein um zu erklären, warum diese "
-"Zusammenführung erforderlich ist,\n"
-"insbesondere wenn es einen aktualisierten, externen Zweig mit einem Thema-"
-"Zweig zusammenführt.\n"
+"Bitte geben Sie eine Commit-Beschreibung ein um zu erklären, warum dieser\n"
+"Merge erforderlich ist, insbesondere wenn es einen aktualisierten\n"
+"Upstream-Branch mit einem Thema-Branch zusammenführt.\n"
"\n"
-"Zeilen beginnend mit '%c' werden ignoriert, und eine leere Beschreibung "
-"bricht die Eintragung ab.\n"
+"Zeilen beginnend mit '%c' werden ignoriert, und eine leere Beschreibung\n"
+"bricht den Commit ab.\n"
-#: builtin/merge.c:812
+#: builtin/merge.c:841
msgid "Empty commit message."
-msgstr "Leere Versionsbeschreibung"
+msgstr "Leere Commit-Beschreibung"
-#: builtin/merge.c:824
+#: builtin/merge.c:853
#, c-format
msgid "Wonderful.\n"
msgstr "Wunderbar.\n"
-#: builtin/merge.c:889
+#: builtin/merge.c:918
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr ""
-"Automatische Zusammenführung fehlgeschlagen; beheben Sie die Konflikte und "
-"tragen Sie dann das Ergebnis ein.\n"
+"Automatischer Merge fehlgeschlagen; beheben Sie die Konflikte und committen "
+"Sie dann das Ergebnis.\n"
-#: builtin/merge.c:905
+#: builtin/merge.c:934
#, c-format
msgid "'%s' is not a commit"
-msgstr "'%s' ist keine Version"
+msgstr "'%s' ist kein Commit"
-#: builtin/merge.c:946
+#: builtin/merge.c:975
msgid "No current branch."
-msgstr "Sie befinden sich auf keinem Zweig."
+msgstr "Sie befinden sich auf keinem Branch."
-#: builtin/merge.c:948
+#: builtin/merge.c:977
msgid "No remote for the current branch."
-msgstr "Kein externes Archiv für den aktuellen Zweig."
+msgstr "Kein Remote-Repository für den aktuellen Branch."
-#: builtin/merge.c:950
+#: builtin/merge.c:979
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:955
-#, c-format
-msgid "No remote tracking branch for %s from %s"
-msgstr "Kein externer Übernahmezweig für %s von %s"
+"Es ist kein Standard-Upstream-Branch für den aktuellen Branch definiert."
-#: builtin/merge.c:1042 builtin/merge.c:1199
+#: builtin/merge.c:984
#, c-format
-msgid "%s - not something we can merge"
-msgstr "%s - nichts was wir zusammenführen können"
+msgid "No remote-tracking branch for %s from %s"
+msgstr "Kein Remote-Tracking-Branch für %s von %s"
-#: builtin/merge.c:1110
+#: builtin/merge.c:1140
msgid "There is no merge to abort (MERGE_HEAD missing)."
-msgstr "Es gibt keine Zusammenführung zum Abbrechen (vermisse MERGE_HEAD)"
+msgstr "Es gibt keinen Merge zum Abbrechen (vermisse MERGE_HEAD)"
-#: builtin/merge.c:1126 git-pull.sh:31
+#: builtin/merge.c:1156 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
msgstr ""
-"Sie haben Ihre Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert).\n"
-"Bitte tragen Sie Ihre Änderungen ein, bevor Sie zusammenführen können."
+"Sie haben Ihren Merge nicht abgeschlossen (MERGE_HEAD existiert).\n"
+"Bitte committen Sie Ihre Änderungen, bevor Sie \"merge\" ausführen können."
-#: builtin/merge.c:1129 git-pull.sh:34
+#: builtin/merge.c:1159 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
-msgstr ""
-"Sie haben Ihre Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert)."
+msgstr "Sie haben Ihren Merge nicht abgeschlossen (MERGE_HEAD existiert)."
-#: builtin/merge.c:1133
+#: builtin/merge.c:1163
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
msgstr ""
"Sie haben \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert).\n"
-"Bitte tragen Sie Ihre Änderungen ein, bevor Sie zusammenführen können."
+"Bitte committen Sie Ihre Änderungen, bevor Sie \"merge\" ausführen können."
-#: builtin/merge.c:1136
+#: builtin/merge.c:1166
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr ""
"Sie haben \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert)."
-#: builtin/merge.c:1145
+#: builtin/merge.c:1175
msgid "You cannot combine --squash with --no-ff."
msgstr "Sie können --squash nicht mit --no-ff kombinieren."
-#: builtin/merge.c:1150
-msgid "You cannot combine --no-ff with --ff-only."
-msgstr "Sie können --no-ff nicht mit --ff--only kombinieren."
-
-#: builtin/merge.c:1157
+#: builtin/merge.c:1184
msgid "No commit specified and merge.defaultToUpstream not set."
-msgstr "Keine Version angegeben und merge.defaultToUpstream ist nicht gesetzt."
+msgstr "Kein Commit angegeben und merge.defaultToUpstream ist nicht gesetzt."
-#: builtin/merge.c:1189
+#: builtin/merge.c:1216
msgid "Can merge only exactly one commit into empty head"
-msgstr "Kann nur exakt eine Version in einem leeren Zweig zusammenführen."
+msgstr "Kann nur exakt einen Commit in einem leeren Branch zusammenführen."
-#: builtin/merge.c:1192
+#: builtin/merge.c:1219
msgid "Squash commit into empty head not supported yet"
-msgstr "Bin auf einem Zweig, der noch geboren wird; kann nicht quetschen."
+msgstr ""
+"Bin auf einem Commit, der noch geboren wird; kann \"squash\" nicht ausführen."
-#: builtin/merge.c:1194
+#: builtin/merge.c:1221
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr ""
-"Nicht vorzuspulende Version kann nicht in einem leeren Zweig verwendet "
+"Nicht vorzuspulender Commit kann nicht in einem leeren Branch verwendet "
"werden."
-#: builtin/merge.c:1310
+#: builtin/merge.c:1226
+#, c-format
+msgid "%s - not something we can merge"
+msgstr "%s - nichts was wir zusammenführen können"
+
+#: builtin/merge.c:1277
+#, c-format
+msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
+msgstr ""
+"Commit %s hat eine nicht vertrauenswürdige GPG-Signatur, angeblich von %s."
+
+#: builtin/merge.c:1280
+#, c-format
+msgid "Commit %s has a bad GPG signature allegedly by %s."
+msgstr "Commit %s hat eine ungültige GPG-Signatur, angeblich von %s."
+
+#. 'N'
+#: builtin/merge.c:1283
+#, c-format
+msgid "Commit %s does not have a GPG signature."
+msgstr "Commit %s hat keine GPG-Signatur."
+
+#: builtin/merge.c:1286
+#, c-format
+msgid "Commit %s has a good GPG signature by %s\n"
+msgstr "Commit %s hat eine gültige GPG-Signatur von %s\n"
+
+#: builtin/merge.c:1370
#, c-format
msgid "Updating %s..%s\n"
msgstr "Aktualisiere %s..%s\n"
-#: builtin/merge.c:1349
+#: builtin/merge.c:1409
#, c-format
msgid "Trying really trivial in-index merge...\n"
-msgstr "Probiere wirklich triviale \"in-index\"-Zusammenführung...\n"
+msgstr "Probiere wirklich trivialen \"in-index\"-Merge...\n"
-#: builtin/merge.c:1356
+#: builtin/merge.c:1416
#, c-format
msgid "Nope.\n"
msgstr "Nein.\n"
-#: builtin/merge.c:1388
+#: builtin/merge.c:1448
msgid "Not possible to fast-forward, aborting."
msgstr "Vorspulen nicht möglich, breche ab."
-#: builtin/merge.c:1411 builtin/merge.c:1490
+#: builtin/merge.c:1471 builtin/merge.c:1550
#, c-format
msgid "Rewinding the tree to pristine...\n"
-msgstr "Rücklauf des Zweiges bis zum Ursprung...\n"
+msgstr "Rücklauf des Verzeichnisses bis zum Ursprung...\n"
-#: builtin/merge.c:1415
+#: builtin/merge.c:1475
#, c-format
msgid "Trying merge strategy %s...\n"
-msgstr "Probiere Zusammenführungsstrategie %s...\n"
+msgstr "Probiere Merge-Strategie %s...\n"
-#: builtin/merge.c:1481
+#: builtin/merge.c:1541
#, c-format
msgid "No merge strategy handled the merge.\n"
-msgstr "Keine Zusammenführungsstrategie behandelt diese Zusammenführung.\n"
+msgstr "Keine Merge-Strategie behandelt diesen Merge.\n"
-#: builtin/merge.c:1483
+#: builtin/merge.c:1543
#, c-format
msgid "Merge with strategy %s failed.\n"
-msgstr "Zusammenführung mit Strategie %s fehlgeschlagen.\n"
+msgstr "Merge mit Strategie %s fehlgeschlagen.\n"
-#: builtin/merge.c:1492
+#: builtin/merge.c:1552
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr "Benutzen Sie \"%s\" um die Auflösung per Hand vorzubereiten.\n"
-#: builtin/merge.c:1504
+#: builtin/merge.c:1564
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
-"Automatische Zusammenführung abgeschlossen; halte, wie gewünscht, vor der "
-"Eintragung an\n"
+"Automatischer Merge abgeschlossen; halte, wie gewünscht, vor dem Commit an\n"
#: builtin/merge-base.c:26
msgid "git merge-base [-a|--all] <commit> <commit>..."
-msgstr "git merge-base [-a|--all] <Version> <Version>..."
+msgstr "git merge-base [-a|--all] <Commit> <Commit>..."
#: builtin/merge-base.c:27
msgid "git merge-base [-a|--all] --octopus <commit>..."
-msgstr "git merge-base [-a|--all] --octopus <Version>..."
+msgstr "git merge-base [-a|--all] --octopus <Commit>..."
#: builtin/merge-base.c:28
msgid "git merge-base --independent <commit>..."
-msgstr "git merge-base --independent <Version>..."
+msgstr "git merge-base --independent <Commit>..."
#: builtin/merge-base.c:29
msgid "git merge-base --is-ancestor <commit> <commit>"
-msgstr "git merge-base --is-ancestor <Version> <Version>"
+msgstr "git merge-base --is-ancestor <Commit> <Commit>"
#: builtin/merge-base.c:98
msgid "output all common ancestors"
-msgstr "Ausgabe aller gemeinsamen Vorfahren"
+msgstr "Ausgabe aller gemeinsamen Vorgänger-Commits"
#: builtin/merge-base.c:99
msgid "find ancestors for a single n-way merge"
-msgstr "findet Vorfahren für eine einzelne n-Wege-Zusammenführung"
+msgstr "findet Vorgänger-Commits für einen einzelnen n-Wege-Merge"
#: builtin/merge-base.c:100
msgid "list revs not reachable from others"
-msgstr "listet Versionen auf, die nicht durch Andere erreichbar sind"
+msgstr "listet Commits auf, die nicht durch Andere erreichbar sind"
#: builtin/merge-base.c:102
msgid "is the first one ancestor of the other?"
-msgstr "ist der Erste ein Vorfahre von dem Anderen?"
+msgstr "ist der Erste ein Vorgänger-Commit von dem Anderen?"
#: builtin/merge-file.c:8
msgid ""
@@ -6373,7 +6952,7 @@ msgstr "sendet Ergebnisse zur Standard-Ausgabe"
#: builtin/merge-file.c:34
msgid "use a diff3 based merge"
-msgstr "verwendet eine diff3 basierte Zusammenführung"
+msgstr "verwendet einen diff3 basierten Merge"
#: builtin/merge-file.c:35
msgid "for conflicts, use our version"
@@ -6413,7 +6992,7 @@ msgstr "erlaubt fehlende Objekte"
#: builtin/mktree.c:155
msgid "allow creation of more than one tree"
-msgstr "erlaubt die Erstellung von mehr als einem Baum"
+msgstr "erlaubt die Erstellung von mehr als einem \"Tree\"-Objekt"
#: builtin/mv.c:14
msgid "git mv [options] <source>... <destination>"
@@ -6447,7 +7026,7 @@ msgstr "kann Verzeichnis nicht über Datei verschieben"
#: builtin/mv.c:128
#, c-format
msgid "Huh? %.*s is in index?"
-msgstr "Huh? %.*s ist in der Bereitstellung?"
+msgstr "Huh? %.*s ist zum Commit vorgemerkt?"
#: builtin/mv.c:140
msgid "source directory is empty"
@@ -6489,47 +7068,51 @@ msgstr "Benenne %s nach %s um\n"
msgid "renaming '%s' failed"
msgstr "Umbenennung von '%s' fehlgeschlagen"
-#: builtin/name-rev.c:175
+#: builtin/name-rev.c:259
msgid "git name-rev [options] <commit>..."
-msgstr "git name-rev [Optionen] <Version>..."
+msgstr "git name-rev [Optionen] <Commit>..."
-#: builtin/name-rev.c:176
+#: builtin/name-rev.c:260
msgid "git name-rev [options] --all"
msgstr "git name-rev [Optionen] --all"
-#: builtin/name-rev.c:177
+#: builtin/name-rev.c:261
msgid "git name-rev [options] --stdin"
msgstr "git name-rev [Optionen] --stdin"
-#: builtin/name-rev.c:229
+#: builtin/name-rev.c:313
msgid "print only names (no SHA-1)"
msgstr "zeigt nur Namen an (keine SHA-1)"
-#: builtin/name-rev.c:230
+#: builtin/name-rev.c:314
msgid "only use tags to name the commits"
-msgstr "verwendet nur Markierungen um die Versionen zu benennen"
+msgstr "verwendet nur Tags um die Commits zu benennen"
-#: builtin/name-rev.c:232
+#: builtin/name-rev.c:316
msgid "only use refs matching <pattern>"
msgstr "verwendet nur Referenzen die <Muster> entsprechen"
-#: builtin/name-rev.c:234
+#: builtin/name-rev.c:318
msgid "list all commits reachable from all refs"
-msgstr "listet alle Versionen auf, die von allen Referenzen erreichbar sind"
+msgstr "listet alle Commits auf, die von allen Referenzen erreichbar sind"
-#: builtin/name-rev.c:235
+#: builtin/name-rev.c:319
msgid "read from stdin"
msgstr "liest von der Standard-Eingabe"
-#: builtin/name-rev.c:236
+#: builtin/name-rev.c:320
msgid "allow to print `undefined` names"
msgstr "erlaubt Ausgabe von `undefinierten` Namen"
-#: builtin/notes.c:26
+#: builtin/name-rev.c:326
+msgid "dereference tags in the input (internal use)"
+msgstr "dereferenziert Tags in der Eingabe (interne Verwendung)"
+
+#: builtin/notes.c:24
msgid "git notes [--ref <notes_ref>] [list [<object>]]"
msgstr "git notes [--ref <Notiz-Referenz>] [list [<Objekt>]]"
-#: builtin/notes.c:27
+#: builtin/notes.c:25
msgid ""
"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
@@ -6537,12 +7120,12 @@ msgstr ""
"git notes [--ref <Notiz-Referenz>] add [-f] [-m <Nachricht> | -F <Datei> | (-"
"c | -C) <Objekt>] [<Objekt>]"
-#: builtin/notes.c:28
+#: builtin/notes.c:26
msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
msgstr ""
"git notes [--ref <Notiz-Referenz>] copy [-f] <von-Objekt> <nach-Objekt>"
-#: builtin/notes.c:29
+#: builtin/notes.c:27
msgid ""
"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
@@ -6550,223 +7133,201 @@ msgstr ""
"git notes [--ref <Notiz-Referenz>] append [-m <Nachricht> | -F <Datei> | (-c "
"| -C) <Objekt>] [<Objekt>]"
-#: builtin/notes.c:30
+#: builtin/notes.c:28
msgid "git notes [--ref <notes_ref>] edit [<object>]"
msgstr "git notes [--ref <Notiz-Referenz>] edit [<Objekt>]"
-#: builtin/notes.c:31
+#: builtin/notes.c:29
msgid "git notes [--ref <notes_ref>] show [<object>]"
msgstr "git notes [--ref <Notiz-Referenz>] show [<Objekt>]"
-#: builtin/notes.c:32
+#: builtin/notes.c:30
msgid ""
"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
msgstr ""
"git notes [--ref <Notiz-Referenz>] merge [-v | -q] [-s <Strategie> ] <Notiz-"
"Referenz>"
-#: builtin/notes.c:33
+#: builtin/notes.c:31
msgid "git notes merge --commit [-v | -q]"
msgstr "git notes merge --commit [-v | -q]"
-#: builtin/notes.c:34
+#: builtin/notes.c:32
msgid "git notes merge --abort [-v | -q]"
msgstr "git notes merge --abort [-v | -q]"
-#: builtin/notes.c:35
+#: builtin/notes.c:33
msgid "git notes [--ref <notes_ref>] remove [<object>...]"
msgstr "git notes [--ref <Notiz-Referenz>] remove [<Objekt>...]"
-#: builtin/notes.c:36
+#: builtin/notes.c:34
msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
msgstr "git notes [--ref <Notiz-Referenz>] prune [-n | -v]"
-#: builtin/notes.c:37
+#: builtin/notes.c:35
msgid "git notes [--ref <notes_ref>] get-ref"
msgstr "git notes [--ref <Notiz-Referenz>] get-ref"
-#: builtin/notes.c:42
+#: builtin/notes.c:40
msgid "git notes [list [<object>]]"
msgstr "git notes [list [<Objekt>]]"
-#: builtin/notes.c:47
+#: builtin/notes.c:45
msgid "git notes add [<options>] [<object>]"
msgstr "git notes add [<Optionen>] [<Objekt>]"
-#: builtin/notes.c:52
+#: builtin/notes.c:50
msgid "git notes copy [<options>] <from-object> <to-object>"
msgstr "git notes copy [<Optionen>] <von-Objekt> <nach-Objekt>"
-#: builtin/notes.c:53
+#: builtin/notes.c:51
msgid "git notes copy --stdin [<from-object> <to-object>]..."
msgstr "git notes copy --stdin [<von-Objekt> <nach-Objekt>]..."
-#: builtin/notes.c:58
+#: builtin/notes.c:56
msgid "git notes append [<options>] [<object>]"
msgstr "git notes append [<Optionen>] [<Objekt>]"
-#: builtin/notes.c:63
+#: builtin/notes.c:61
msgid "git notes edit [<object>]"
msgstr "git notes edit [<Objekt>]"
-#: builtin/notes.c:68
+#: builtin/notes.c:66
msgid "git notes show [<object>]"
msgstr "git notes show [<Objekt>]"
-#: builtin/notes.c:73
+#: builtin/notes.c:71
msgid "git notes merge [<options>] <notes_ref>"
msgstr "git notes merge [<Optionen>] <Notiz-Referenz>"
-#: builtin/notes.c:74
+#: builtin/notes.c:72
msgid "git notes merge --commit [<options>]"
msgstr "git notes merge --commit [<Optionen>]"
-#: builtin/notes.c:75
+#: builtin/notes.c:73
msgid "git notes merge --abort [<options>]"
msgstr "git notes merge --abort [<Optionen>]"
-#: builtin/notes.c:80
+#: builtin/notes.c:78
msgid "git notes remove [<object>]"
msgstr "git notes remove [<Objekt>]"
-#: builtin/notes.c:85
+#: builtin/notes.c:83
msgid "git notes prune [<options>]"
msgstr "git notes prune [<Optionen>]"
-#: builtin/notes.c:90
+#: builtin/notes.c:88
msgid "git notes get-ref"
msgstr "git notes get-ref"
-#: builtin/notes.c:139
+#: builtin/notes.c:137
#, c-format
msgid "unable to start 'show' for object '%s'"
msgstr "konnte 'show' für Objekt '%s' nicht starten"
-#: builtin/notes.c:143
+#: builtin/notes.c:141
msgid "could not read 'show' output"
msgstr "Konnte Ausgabe von 'show' nicht lesen."
-#: builtin/notes.c:151
+#: builtin/notes.c:149
#, c-format
msgid "failed to finish 'show' for object '%s'"
msgstr "konnte 'show' für Objekt '%s' nicht abschließen"
-#: builtin/notes.c:169 builtin/tag.c:341
+#: builtin/notes.c:167 builtin/tag.c:341
#, c-format
msgid "could not create file '%s'"
msgstr "konnte Datei '%s' nicht erstellen"
-#: builtin/notes.c:188
+#: builtin/notes.c:186
msgid "Please supply the note contents using either -m or -F option"
msgstr ""
"Bitte liefern Sie den Notiz-Inhalt unter Verwendung der Option -m oder -F."
-#: builtin/notes.c:209 builtin/notes.c:972
+#: builtin/notes.c:207 builtin/notes.c:844
#, c-format
msgid "Removing note for object %s\n"
msgstr "Entferne Notiz für Objekt %s\n"
-#: builtin/notes.c:214
+#: builtin/notes.c:212
msgid "unable to write note object"
msgstr "Konnte Notiz-Objekt nicht schreiben"
-#: builtin/notes.c:216
+#: builtin/notes.c:214
#, c-format
msgid "The note contents has been left in %s"
msgstr "Die Notiz-Inhalte wurden in %s belassen"
-#: builtin/notes.c:250 builtin/tag.c:540
+#: builtin/notes.c:248 builtin/tag.c:540
#, c-format
msgid "cannot read '%s'"
msgstr "kann '%s' nicht lesen"
-#: builtin/notes.c:252 builtin/tag.c:543
+#: builtin/notes.c:250 builtin/tag.c:543
#, c-format
msgid "could not open or read '%s'"
msgstr "konnte '%s' nicht öffnen oder lesen"
-#: builtin/notes.c:271 builtin/notes.c:444 builtin/notes.c:446
-#: builtin/notes.c:506 builtin/notes.c:560 builtin/notes.c:643
-#: builtin/notes.c:648 builtin/notes.c:723 builtin/notes.c:765
-#: builtin/notes.c:967 builtin/tag.c:556
+#: builtin/notes.c:269 builtin/notes.c:316 builtin/notes.c:318
+#: builtin/notes.c:378 builtin/notes.c:432 builtin/notes.c:515
+#: builtin/notes.c:520 builtin/notes.c:595 builtin/notes.c:637
+#: builtin/notes.c:839 builtin/tag.c:556
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
msgstr "Konnte '%s' nicht als gültige Referenz auflösen."
-#: builtin/notes.c:274
+#: builtin/notes.c:272
#, c-format
msgid "Failed to read object '%s'."
msgstr "Fehler beim Lesen des Objektes '%s'."
-#: builtin/notes.c:298
-msgid "Cannot commit uninitialized/unreferenced notes tree"
-msgstr "Kann uninitialisierten/unreferenzierten Notiz-Baum nicht eintragen."
-
-#: builtin/notes.c:339
-#, c-format
-msgid "Bad notes.rewriteMode value: '%s'"
-msgstr "Ungültiger notes.rewriteMode Wert: '%s'"
-
-#: builtin/notes.c:349
-#, c-format
-msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
-msgstr ""
-"Umschreiben der Notizen in %s zurückgewiesen (außerhalb von refs/notes/)"
-
-#. TRANSLATORS: The first %s is the name of the
-#. environment variable, the second %s is its value
-#: builtin/notes.c:376
-#, c-format
-msgid "Bad %s value: '%s'"
-msgstr "Ungültiger %s Wert: '%s'"
-
-#: builtin/notes.c:440
+#: builtin/notes.c:312
#, c-format
msgid "Malformed input line: '%s'."
msgstr "Fehlerhafte Eingabezeile: '%s'."
-#: builtin/notes.c:455
+#: builtin/notes.c:327
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
msgstr "Fehler beim Kopieren der Notizen von '%s' nach '%s'"
-#: builtin/notes.c:499 builtin/notes.c:553 builtin/notes.c:626
-#: builtin/notes.c:638 builtin/notes.c:711 builtin/notes.c:758
-#: builtin/notes.c:1032
+#: builtin/notes.c:371 builtin/notes.c:425 builtin/notes.c:498
+#: builtin/notes.c:510 builtin/notes.c:583 builtin/notes.c:630
+#: builtin/notes.c:904
msgid "too many parameters"
msgstr "zu viele Parameter"
-#: builtin/notes.c:512 builtin/notes.c:771
+#: builtin/notes.c:384 builtin/notes.c:643
#, c-format
msgid "No note found for object %s."
msgstr "Kein Notiz für Objekt %s gefunden."
-#: builtin/notes.c:534 builtin/notes.c:691
+#: builtin/notes.c:406 builtin/notes.c:563
msgid "note contents as a string"
msgstr "Notizinhalte als Zeichenkette"
-#: builtin/notes.c:537 builtin/notes.c:694
+#: builtin/notes.c:409 builtin/notes.c:566
msgid "note contents in a file"
msgstr "Notizinhalte in einer Datei"
-#: builtin/notes.c:539 builtin/notes.c:542 builtin/notes.c:696
-#: builtin/notes.c:699 builtin/tag.c:474
+#: builtin/notes.c:411 builtin/notes.c:414 builtin/notes.c:568
+#: builtin/notes.c:571 builtin/tag.c:474
msgid "object"
msgstr "Objekt"
-#: builtin/notes.c:540 builtin/notes.c:697
+#: builtin/notes.c:412 builtin/notes.c:569
msgid "reuse and edit specified note object"
msgstr "Wiederverwendung und Bearbeitung des angegebenen Notiz-Objektes"
-#: builtin/notes.c:543 builtin/notes.c:700
+#: builtin/notes.c:415 builtin/notes.c:572
msgid "reuse specified note object"
msgstr "Wiederverwendung des angegebenen Notiz-Objektes"
-#: builtin/notes.c:545 builtin/notes.c:613
+#: builtin/notes.c:417 builtin/notes.c:485
msgid "replace existing notes"
msgstr "ersetzt existierende Notizen"
-#: builtin/notes.c:579
+#: builtin/notes.c:451
#, c-format
msgid ""
"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6775,26 +7336,26 @@ msgstr ""
"Konnte Notizen nicht hinzufügen. Existierende Notizen für Objekt %s "
"gefunden. Verwenden Sie '-f' um die existierenden Notizen zu überschreiben."
-#: builtin/notes.c:584 builtin/notes.c:661
+#: builtin/notes.c:456 builtin/notes.c:533
#, c-format
msgid "Overwriting existing notes for object %s\n"
msgstr "Überschreibe existierende Notizen für Objekt %s\n"
-#: builtin/notes.c:614
+#: builtin/notes.c:486
msgid "read objects from stdin"
msgstr "liest Objekte von der Standard-Eingabe"
-#: builtin/notes.c:616
+#: builtin/notes.c:488
msgid "load rewriting config for <command> (implies --stdin)"
msgstr ""
"lädt Konfiguration für <Kommando> beim Umschreiben von Versionen (impliziert "
"--stdin)"
-#: builtin/notes.c:634
+#: builtin/notes.c:506
msgid "too few parameters"
msgstr "zu wenig Parameter"
-#: builtin/notes.c:655
+#: builtin/notes.c:527
#, c-format
msgid ""
"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6803,12 +7364,12 @@ msgstr ""
"Kann Notizen nicht kopieren. Existierende Notizen für Objekt %s gefunden. "
"Verwenden Sie '-f' um die existierenden Notizen zu überschreiben."
-#: builtin/notes.c:667
+#: builtin/notes.c:539
#, c-format
msgid "Missing notes on source object %s. Cannot copy."
msgstr "Keine Notizen für Quell-Objekt %s. Kopie nicht möglich."
-#: builtin/notes.c:716
+#: builtin/notes.c:588
#, c-format
msgid ""
"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
@@ -6817,15 +7378,15 @@ msgstr ""
"Die Optionen -m/-F/-c/-C sind für das Unterkommando 'edit' veraltet.\n"
"Bitte benutzen Sie stattdessen 'git notes add -f -m/-F/-c/-C'.\n"
-#: builtin/notes.c:863
+#: builtin/notes.c:735
msgid "General options"
msgstr "Allgemeine Optionen"
-#: builtin/notes.c:865
+#: builtin/notes.c:737
msgid "Merge options"
-msgstr "Optionen für Zusammenführung"
+msgstr "Merge-Optionen"
-#: builtin/notes.c:867
+#: builtin/notes.c:739
msgid ""
"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
"cat_sort_uniq)"
@@ -6833,46 +7394,46 @@ msgstr ""
"löst Konflikte bei Notizen mit der angegebenen Strategie auf (manual/ours/"
"theirs/union/cat_sort_uniq)"
-#: builtin/notes.c:869
+#: builtin/notes.c:741
msgid "Committing unmerged notes"
msgstr "trägt nicht zusammengeführte Notizen ein"
-#: builtin/notes.c:871
+#: builtin/notes.c:743
msgid "finalize notes merge by committing unmerged notes"
msgstr ""
-"schließt Zusammenführung von Notizen ab, in dem nicht zusammengeführte "
-"Notizen eingetragen werden"
+"schließt Merge von Notizen ab, in dem nicht zusammengeführte Notizen "
+"committet werden"
-#: builtin/notes.c:873
+#: builtin/notes.c:745
msgid "Aborting notes merge resolution"
-msgstr "bricht Konfliktauflösung bei Zusammenführung von Notizen ab"
+msgstr "bricht Konfliktauflösung beim Merge von Notizen ab"
-#: builtin/notes.c:875
+#: builtin/notes.c:747
msgid "abort notes merge"
-msgstr "bricht Zusammenführung von Notizen ab"
+msgstr "bricht Merge von Notizen ab"
-#: builtin/notes.c:970
+#: builtin/notes.c:842
#, c-format
msgid "Object %s has no note\n"
msgstr "Objekt %s hat keine Notiz\n"
-#: builtin/notes.c:982
+#: builtin/notes.c:854
msgid "attempt to remove non-existent note is not an error"
msgstr "der Versuch, eine nicht existierende Notiz zu löschen, ist kein Fehler"
-#: builtin/notes.c:985
+#: builtin/notes.c:857
msgid "read object names from the standard input"
msgstr "liest Objektnamen von der Standard-Eingabe"
-#: builtin/notes.c:1066
+#: builtin/notes.c:938
msgid "notes_ref"
msgstr "Notiz-Referenz"
-#: builtin/notes.c:1067
+#: builtin/notes.c:939
msgid "use notes from <notes_ref>"
msgstr "verwendet Notizen von <Notiz-Referenz>"
-#: builtin/notes.c:1102 builtin/remote.c:1598
+#: builtin/notes.c:974 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
msgstr "Unbekanntes Unterkommando: %s"
@@ -6895,12 +7456,12 @@ msgstr "Fehler beim Komprimieren (%d)"
#: builtin/pack-objects.c:2397
#, c-format
msgid "unsupported index version %s"
-msgstr "Nicht unterstützte Bereitstellungsversion %s"
+msgstr "Nicht unterstützte Staging-Area-Version %s"
#: builtin/pack-objects.c:2401
#, c-format
msgid "bad index version '%s'"
-msgstr "Ungültige Bereitstellungsversion '%s'"
+msgstr "Ungültige Staging-Area-Version '%s'"
#: builtin/pack-objects.c:2424
#, c-format
@@ -6986,7 +7547,7 @@ msgstr "erzeugt keine leeren Pakete"
#: builtin/pack-objects.c:2481
msgid "read revision arguments from standard input"
-msgstr "liest Argumente bezüglich Revisionen von der Standard-Eingabe"
+msgstr "liest Argumente bezüglich Commits von der Standard-Eingabe"
#: builtin/pack-objects.c:2483
msgid "limit the objects to those that are not yet packed"
@@ -6999,8 +7560,7 @@ msgstr "schließt Objekte ein, die von jeder Referenz erreichbar sind"
#: builtin/pack-objects.c:2489
msgid "include objects referred by reflog entries"
msgstr ""
-"schließt Objekte ein, die von Einträgen des Referenzprotokolls referenziert "
-"werden"
+"schließt Objekte ein, die von Einträgen des Reflogs referenziert werden"
#: builtin/pack-objects.c:2492
msgid "output pack to stdout"
@@ -7008,8 +7568,7 @@ msgstr "schreibt Paket in die Standard-Ausgabe"
#: builtin/pack-objects.c:2494
msgid "include tag objects that refer to objects to be packed"
-msgstr ""
-"schließt Markierungsobjekte ein, die auf gepackte Objekte referenzieren"
+msgstr "schließt Tag-Objekte ein, die auf gepackte Objekte referenzieren"
#: builtin/pack-objects.c:2496
msgid "keep unreachable objects"
@@ -7037,7 +7596,7 @@ msgstr "Komprimierungsgrad für Paketierung"
#: builtin/pack-objects.c:2507
msgid "do not hide commits by grafts"
-msgstr "verbirgt keine Versionen mit künstlichen Vorgängern (\"grafts\")"
+msgstr "verbirgt keine Commits mit künstlichen Vorgängern (\"grafts\")"
#: builtin/pack-refs.c:6
msgid "git pack-refs [options]"
@@ -7057,7 +7616,7 @@ msgstr "git prune-packed [-n|--dry-run] [-q|--quiet]"
#: builtin/prune.c:12
msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
-msgstr "git prune [-n] [-v] [--expire <Zeit>] [--] [<Zweigspitze>...]"
+msgstr "git prune [-n] [-v] [--expire <Zeit>] [--] [<head>...]"
#: builtin/prune.c:132
msgid "do not remove, show only"
@@ -7073,11 +7632,11 @@ msgstr "lässt Objekte älter als <Zeit> verfallen"
#: builtin/push.c:14
msgid "git push [<options>] [<repository> [<refspec>...]]"
-msgstr "git push [<Optionen>] [<Projektarchiv> [<Referenzspezifikation>...]]"
+msgstr "git push [<Optionen>] [<Repository> [<Refspec>...]]"
#: builtin/push.c:45
msgid "tag shorthand without <tag>"
-msgstr "Kurzschrift für Markierung ohne <Markierung>"
+msgstr "Kurzschrift für Tag ohne <Tag>"
#: builtin/push.c:64
msgid "--delete only accepts plain target ref names"
@@ -7106,19 +7665,19 @@ msgid ""
" git push %s %s\n"
"%s"
msgstr ""
-"Der Name des externen Ãœbernahmezweiges stimmt nicht mit dem Namen Ihres\n"
-"aktuellen Zweiges überein. Um auf den Übernahmezweig in dem externen\n"
-"Projektarchiv zu versenden, benutzen Sie:\n"
+"Der Name des Upstream-Branches stimmt nicht mit dem Namen Ihres\n"
+"aktuellen Branches überein. Um auf den Upstream-Branch in dem Remote-\n"
+"Repository zu versenden, benutzen Sie:\n"
"\n"
" git push %s HEAD:%s\n"
"\n"
-"Um auf den Zweig mit dem selben Namen in dem externen Projekarchiv\n"
-"zu versenden, benutzen Sie:\n"
+"Um auf den Branch mit dem selben Namen im Remote-Repository zu versenden,\n"
+"benutzen Sie:\n"
"\n"
" git push %s %s\n"
"%s"
-#: builtin/push.c:121
+#: builtin/push.c:117
#, c-format
msgid ""
"You are not currently on a branch.\n"
@@ -7127,13 +7686,13 @@ msgid ""
"\n"
" git push %s HEAD:<name-of-remote-branch>\n"
msgstr ""
-"Sie befinden sich im Moment auf keinem Zweig.\n"
-"Um die Historie, führend zum aktuellen (freistehende Zweigspitze (HEAD))\n"
+"Sie befinden sich im Moment auf keinem Branch.\n"
+"Um die Historie, führend zum aktuellen (losgelöster HEAD)\n"
"Status zu versenden, benutzen Sie\n"
"\n"
-" git push %s HEAD:<Name-des-externen-Zweiges>\n"
+" git push %s HEAD:<Name-des-Remote-Branches>\n"
-#: builtin/push.c:128
+#: builtin/push.c:131
#, c-format
msgid ""
"The current branch %s has no upstream branch.\n"
@@ -7141,29 +7700,30 @@ msgid ""
"\n"
" git push --set-upstream %s %s\n"
msgstr ""
-"Der aktuelle Zweig %s hat keinen Zweig im externen Projektarchiv.\n"
-"Um den aktuellen Zweig zu versenden und das Fernarchiv als externes\n"
-"Projektarchiv zu verwenden, benutzen Sie\n"
+"Der aktuelle Branch %s hat keinen Upstream-Branch.\n"
+"Um den aktuellen Branch zu versenden und den Remote-Branch\n"
+"als Upstream-Branch zu setzen, benutzen Sie\n"
"\n"
" git push --set-upstream %s %s\n"
-#: builtin/push.c:136
+#: builtin/push.c:139
#, c-format
msgid "The current branch %s has multiple upstream branches, refusing to push."
-msgstr "Der aktuelle Zweig %s hat mehrere externe Zweige, Versand verweigert."
+msgstr ""
+"Der aktuelle Branch %s hat mehrere Upstream-Branches, \"push\" verweigert."
-#: builtin/push.c:139
+#: builtin/push.c:142
#, c-format
msgid ""
"You are pushing to remote '%s', which is not the upstream of\n"
"your current branch '%s', without telling me what to push\n"
"to update which remote branch."
msgstr ""
-"Sie versenden nach '%s', welches kein externes Projektarchiv Ihres\n"
-"aktuellen Zweiges '%s' ist, ohne mir mitzuteilen, was ich versenden\n"
-"soll, um welchen externen Zweig zu aktualisieren."
+"Sie versenden nach '%s', welches kein Upstream-Repository Ihres aktuellen\n"
+"Branches '%s' ist, ohne mir mitzuteilen, was ich versenden soll, um welchen\n"
+"Remote-Branch zu aktualisieren."
-#: builtin/push.c:151
+#: builtin/push.c:165
msgid ""
"push.default is unset; its implicit value is changing in\n"
"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
@@ -7184,6 +7744,7 @@ msgstr ""
"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, benutzen Sie:\n"
+"\n"
" git config --global push.default matching\n"
"\n"
"Um diese Meldung zu unterdrücken und das neue Verhalten jetzt zu übernehmen, "
@@ -7197,28 +7758,28 @@ msgstr ""
"Modus 'current' anstatt 'simple', falls Sie gelegentlich ältere Versionen "
"von Git benutzen.)"
-#: builtin/push.c:199
+#: builtin/push.c:225
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
-"Sie haben keine Referenzspezifikationen zum Versenden angegeben, und push."
-"default ist \"nothing\"."
+"Sie haben keine Refspec für \"push\" angegeben, und push.default ist "
+"\"nothing\"."
-#: builtin/push.c:206
+#: builtin/push.c:232
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
-"before pushing again.\n"
+"its remote counterpart. Integrate the remote changes (e.g.\n"
+"'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"Aktualisierungen wurden zurückgewiesen, weil die Spitze Ihres aktuellen\n"
-"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Führen Sie\n"
-"die externen Änderungen zusammen (z.B. 'git pull') bevor Sie erneut\n"
-"versenden.\n"
+"Branches hinter seinem externen Gegenstück zurückgefallen ist. Führen Sie\n"
+"die externen Änderungen zusammen (z.B. 'git pull ...') bevor Sie \"push\"\n"
+"erneut ausführen.\n"
"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
"für weitere Details."
-#: builtin/push.c:212
+#: builtin/push.c:238
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"
@@ -7226,80 +7787,79 @@ msgid ""
"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 Sie "
+"Branches hinter seinem externen Gegenstück zurückgefallen ist. Wenn Sie "
"nicht\n"
-"beabsichtigt haben, diesen Zweig zu versenden, können Sie auch den zu "
+"beabsichtigt haben, diesen Branch zu versenden, können Sie auch den zu "
"versendenden\n"
-"Zweig spezifizieren oder die Konfigurationsvariable 'push.default' zu "
+"Branch spezifizieren oder die Konfigurationsvariable 'push.default' zu "
"'simple', 'current'\n"
-"oder 'upstream' setzen, um nur den aktuellen Zweig zu versenden."
+"oder 'upstream' setzen, um nur den aktuellen Branch zu versenden."
-#: builtin/push.c:218
+#: builtin/push.c:244
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and merge the remote changes\n"
-"(e.g. 'git pull') before pushing again.\n"
+"counterpart. Check out this branch and integrate the remote changes\n"
+"(e.g. 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"Aktualisierungen wurden zurückgewiesen, weil die Spitze eines versendeten\n"
-"Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Checken Sie\n"
-"diesen Zweig aus und führen Sie die externen Änderungen zusammen\n"
-"(z.B. 'git pull') bevor Sie erneut versenden.\n"
+"Branches hinter seinem externen Gegenstück zurückgefallen ist. Checken Sie\n"
+"diesen Branch aus und führen Sie die externen Änderungen zusammen\n"
+"(z.B. 'git pull ...') bevor Sie erneut \"push\" ausführen.\n"
"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
"für weitere Details."
-#: builtin/push.c:224
+#: builtin/push.c:250
msgid ""
"Updates were rejected because the remote contains work that you do\n"
"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first merge the remote changes (e.g.,\n"
-"'git pull') before pushing again.\n"
+"to the same ref. You may want to first integrate the remote changes\n"
+"(e.g., 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-"Aktualisierungen wurden zurückgewiesen, weil das Fernarchiv Versionen "
+"Aktualisierungen wurden zurückgewiesen, weil das Remote-Repository Commits "
"enthält,\n"
-"die lokal nicht vorhanden sind. Das wird üblicherweise durch das Versenden "
+"die lokal nicht vorhanden sind. Das wird üblicherweise durch einen \"push\" "
"von\n"
-"Versionen auf dieselbe Referenz von einem anderen Projektarchiv aus "
-"verursacht.\n"
+"Commits auf dieselbe Referenz von einem anderen Repository aus verursacht.\n"
"Vielleicht müssen Sie die externen Änderungen zusammenzuführen (z.B. 'git "
-"pull')\n"
-"bevor Sie erneut versenden.\n"
+"pull ...')\n"
+"bevor Sie erneut \"push\" ausführen.\n"
"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
"für weitere Details."
-#: builtin/push.c:231
+#: builtin/push.c:257
msgid "Updates were rejected because the tag already exists in the remote."
msgstr ""
-"Aktualisierungen wurden zurückgewiesen, weil die Markierung bereits\n"
-"im Fernarchiv existiert."
+"Aktualisierungen wurden zurückgewiesen, weil der Tag bereits\n"
+"im Remote-Repository existiert."
-#: builtin/push.c:234
+#: builtin/push.c:260
msgid ""
"You cannot update a remote ref that points at a non-commit object,\n"
"or update a remote ref to make it point at a non-commit object,\n"
"without using the '--force' option.\n"
msgstr ""
-"Sie können keine externe Referenz aktualisieren, die auf ein Objekt zeigt,\n"
-"das keine Version ist, oder es auf ein solches Objekt zeigen lassen, ohne\n"
+"Sie können keine Remote-Referenz aktualisieren, die auf ein Objekt zeigt,\n"
+"das kein Commit ist, oder es auf ein solches Objekt zeigen lassen, ohne\n"
"die Option '--force' zu verwenden.\n"
-#: builtin/push.c:294
+#: builtin/push.c:320
#, c-format
msgid "Pushing to %s\n"
msgstr "Versende nach %s\n"
-#: builtin/push.c:298
+#: builtin/push.c:324
#, c-format
msgid "failed to push some refs to '%s'"
msgstr "Fehler beim Versenden einiger Referenzen nach '%s'"
-#: builtin/push.c:331
+#: builtin/push.c:357
#, c-format
msgid "bad repository '%s'"
-msgstr "ungültiges Projektarchiv '%s'"
+msgstr "ungültiges Repository '%s'"
-#: builtin/push.c:332
+#: builtin/push.c:358
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -7311,96 +7871,97 @@ msgid ""
"\n"
" git push <name>\n"
msgstr ""
-"Kein Ziel zum Versenden konfiguriert.\n"
+"Kein Ziel für \"push\" konfiguriert.\n"
"Entweder spezifizieren Sie die URL von der Kommandozeile oder konfigurieren "
-"ein externes Projektarchiv unter Benutzung von\n"
+"ein Remote-Repository unter Benutzung von\n"
"\n"
" git remote add <Name> <URL>\n"
"\n"
-"und versenden dann unter Benutzung dieses Namens\n"
+"und führen \"push\" dann unter Benutzung dieses Namens aus\n"
"\n"
" git push <Name>\n"
-#: builtin/push.c:347
+#: builtin/push.c:373
msgid "--all and --tags are incompatible"
msgstr "Die Optionen --all und --tags sind inkompatibel."
-#: builtin/push.c:348
+#: builtin/push.c:374
msgid "--all can't be combined with refspecs"
-msgstr ""
-"Die Option --all kann nicht mit Referenzspezifikationen kombiniert werden."
+msgstr "Die Option --all kann nicht mit Refspecs kombiniert werden."
-#: builtin/push.c:353
+#: builtin/push.c:379
msgid "--mirror and --tags are incompatible"
msgstr "Die Optionen --mirror und --tags sind inkompatibel."
-#: builtin/push.c:354
+#: builtin/push.c:380
msgid "--mirror can't be combined with refspecs"
-msgstr ""
-"Die Option --mirror kann nicht mit Referenzspezifikationen kombiniert werden."
+msgstr "Die Option --mirror kann nicht mit Refspecs kombiniert werden."
-#: builtin/push.c:359
+#: builtin/push.c:385
msgid "--all and --mirror are incompatible"
msgstr "Die Optionen --all und --mirror sind inkompatibel."
-#: builtin/push.c:419
+#: builtin/push.c:445
msgid "repository"
-msgstr "Projektarchiv"
+msgstr "Repository"
-#: builtin/push.c:420
+#: builtin/push.c:446
msgid "push all refs"
msgstr "versendet alle Referenzen"
-#: builtin/push.c:421
+#: builtin/push.c:447
msgid "mirror all refs"
msgstr "spiegelt alle Referenzen"
-#: builtin/push.c:423
+#: builtin/push.c:449
msgid "delete refs"
msgstr "löscht Referenzen"
-#: builtin/push.c:424
+#: builtin/push.c:450
msgid "push tags (can't be used with --all or --mirror)"
-msgstr ""
-"versendet Markierungen (kann nicht mit --all oder --mirror verwendet werden)"
+msgstr "versendet Tags (kann nicht mit --all oder --mirror verwendet werden)"
-#: builtin/push.c:427
+#: builtin/push.c:453
msgid "force updates"
msgstr "erzwingt Aktualisierung"
-#: builtin/push.c:428
+#: builtin/push.c:454
msgid "check"
msgstr ""
-#: builtin/push.c:429
+#: builtin/push.c:455
msgid "control recursive pushing of submodules"
-msgstr "steuert rekursives Versenden von Unterprojekten"
+msgstr "steuert rekursiven \"push\" von Submodulen"
-#: builtin/push.c:431
+#: builtin/push.c:457
msgid "use thin pack"
msgstr "verwendet kleinere Pakete"
-#: builtin/push.c:432 builtin/push.c:433
+#: builtin/push.c:458 builtin/push.c:459
msgid "receive pack program"
msgstr "'receive pack' Programm"
-#: builtin/push.c:434
+#: builtin/push.c:460
msgid "set upstream for git pull/status"
-msgstr "setzt externes Projektarchiv für \"git pull/status\""
+msgstr "setzt Upstream für \"git pull/status\""
-#: builtin/push.c:437
+#: builtin/push.c:463
msgid "prune locally removed refs"
msgstr "entfernt lokal gelöschte Referenzen"
-#: builtin/push.c:439
+#: builtin/push.c:465
msgid "bypass pre-push hook"
msgstr "umgeht \"pre-push hook\""
-#: builtin/push.c:448
+#: builtin/push.c:466
+msgid "push missing but relevant tags"
+msgstr "versendet fehlende, aber relevante Tags"
+
+#: builtin/push.c:476
msgid "--delete is incompatible with --all, --mirror and --tags"
msgstr "Die Option --delete ist inkompatibel mit --all, --mirror und --tags."
-#: builtin/push.c:450
+#: builtin/push.c:478
msgid "--delete doesn't make sense without any refs"
msgstr "Die Option --delete kann nur mit Referenzen verwendet werden."
@@ -7412,76 +7973,83 @@ msgid ""
msgstr ""
"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<Prefix>] "
"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
-"index-output=<Datei>] (--empty | <Versionsreferenz1> [<Versionsreferenz2> "
-"[<Versionsreferenz3>]])"
+"index-output=<Datei>] (--empty | <Commit-Referenz1> [<Commit-Referenz2> "
+"[<Commit-Referenz3>]])"
-#: builtin/read-tree.c:108
+#: builtin/read-tree.c:109
msgid "write resulting index to <file>"
-msgstr "schreibt resultierende Bereitstellung nach <Datei>"
+msgstr "schreibt resultierende Staging-Area nach <Datei>"
-#: builtin/read-tree.c:111
+#: builtin/read-tree.c:112
msgid "only empty the index"
-msgstr "leert die Bereitstellung"
+msgstr "leert die Staging-Area"
-#: builtin/read-tree.c:113
+#: builtin/read-tree.c:114
msgid "Merging"
-msgstr "Zusammenführung"
+msgstr "Merge"
-#: builtin/read-tree.c:115
+#: builtin/read-tree.c:116
msgid "perform a merge in addition to a read"
-msgstr "führt eine Zusammenführung zusätzlich zum Lesen aus"
+msgstr "führt einen Merge zusätzlich zum Lesen aus"
-#: builtin/read-tree.c:117
+#: builtin/read-tree.c:118
msgid "3-way merge if no file level merging required"
-msgstr ""
-"3-Wege-Zusammenführung, wenn keine Zusammenführung auf Dateiebene "
-"erforderlich ist"
+msgstr "3-Wege-Merge, wenn kein Merge auf Dateiebene erforderlich ist"
-#: builtin/read-tree.c:119
+#: builtin/read-tree.c:120
msgid "3-way merge in presence of adds and removes"
-msgstr ""
-"3-Wege-Zusammenführung bei Vorhandensein von hinzugefügten/entfernten Zeilen"
+msgstr "3-Wege-Merge bei Vorhandensein von hinzugefügten/entfernten Zeilen"
-#: builtin/read-tree.c:121
+#: builtin/read-tree.c:122
msgid "same as -m, but discard unmerged entries"
msgstr "genau wie -m, verwirft aber nicht zusammengeführte Einträge"
-#: builtin/read-tree.c:122
+#: builtin/read-tree.c:123
msgid "<subdirectory>/"
msgstr "<Unterverzeichnis>/"
-#: builtin/read-tree.c:123
+#: builtin/read-tree.c:124
msgid "read the tree into the index under <subdirectory>/"
-msgstr "liest den Baum in die Bereitstellung unter <Unterverzeichnis>/"
+msgstr "liest das Verzeichnis in die Staging-Area unter <Unterverzeichnis>/"
-#: builtin/read-tree.c:126
+#: builtin/read-tree.c:127
msgid "update working tree with merge result"
-msgstr "aktualisiert Arbeitsbaum mit Ergebnis der Zusammenführung"
+msgstr "aktualisiert Arbeitsverzeichnis mit dem Ergebnis des Merges"
-#: builtin/read-tree.c:128
+#: builtin/read-tree.c:129
msgid "gitignore"
msgstr "gitignore"
-#: builtin/read-tree.c:129
+#: builtin/read-tree.c:130
msgid "allow explicitly ignored files to be overwritten"
msgstr "erlaubt explizit ignorierte Dateien zu überschreiben"
-#: builtin/read-tree.c:132
+#: builtin/read-tree.c:133
msgid "don't check the working tree after merging"
-msgstr "prüft nicht den Arbeitsbaum nach der Zusammenführung"
+msgstr "prüft nicht das Arbeitsverzeichnis nach dem Merge"
-#: builtin/read-tree.c:133
+#: builtin/read-tree.c:134
msgid "don't update the index or the work tree"
-msgstr "aktualisiert weder die Bereitstellung, noch den Arbeitsbaum"
+msgstr "aktualisiert weder die Staging-Area, noch das Arbeitsverzeichnis"
-#: builtin/read-tree.c:135
+#: builtin/read-tree.c:136
msgid "skip applying sparse checkout filter"
msgstr "überspringt Anwendung des Filters für spärliches Auschecken"
-#: builtin/read-tree.c:137
+#: builtin/read-tree.c:138
msgid "debug unpack-trees"
msgstr "protokolliert Entpacken der Bäume"
+#: builtin/reflog.c:500
+#, c-format
+msgid "%s' for '%s' is not a valid timestamp"
+msgstr "'%s' für '%s' ist kein gültiger Zeitstempel"
+
+#: builtin/reflog.c:616 builtin/reflog.c:621
+#, c-format
+msgid "'%s' is not a valid timestamp"
+msgstr "'%s' ist kein gültiger Zeitstempel"
+
#: builtin/remote.c:11
msgid "git remote [-v | --verbose]"
msgstr "git remote [-v | --verbose]"
@@ -7491,7 +8059,7 @@ msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
"mirror=<fetch|push>] <name> <url>"
msgstr ""
-"git remote add [-t <Zweig>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"git remote add [-t <Branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
"mirror=<fetch|push>] <Name> <URL>"
#: builtin/remote.c:13 builtin/remote.c:32
@@ -7504,7 +8072,7 @@ msgstr "git remote remove <Name>"
#: builtin/remote.c:15 builtin/remote.c:42
msgid "git remote set-head <name> (-a | -d | <branch>)"
-msgstr "git remote set-head <Name> (-a | -d | <Zweig>)"
+msgstr "git remote set-head <Name> (-a | -d | <Branch>)"
#: builtin/remote.c:16
msgid "git remote [-v | --verbose] show [-n] <name>"
@@ -7518,12 +8086,11 @@ msgstr "git remote prune [-n | --dry-run] <Name>"
msgid ""
"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
msgstr ""
-"git remote [-v | --verbose] update [-p | --prune] [(<Gruppe> | "
-"<externesProjektarchiv>)...]"
+"git remote [-v | --verbose] update [-p | --prune] [(<Gruppe> | <Remote>)...]"
#: builtin/remote.c:19
msgid "git remote set-branches [--add] <name> <branch>..."
-msgstr "git remote set-branches [--add] <Name> <Zweig>..."
+msgstr "git remote set-branches [--add] <Name> <Branch>..."
#: builtin/remote.c:20 builtin/remote.c:68
msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
@@ -7543,11 +8110,11 @@ msgstr "git remote add [<Optionen>] <Name> <URL>"
#: builtin/remote.c:47
msgid "git remote set-branches <name> <branch>..."
-msgstr "git remote set-branches <Name> <Zweig>..."
+msgstr "git remote set-branches <Name> <Branch>..."
#: builtin/remote.c:48
msgid "git remote set-branches --add <name> <branch>..."
-msgstr "git remote set-branches --add <Name> <Zweig>..."
+msgstr "git remote set-branches --add <Name> <Branch>..."
#: builtin/remote.c:53
msgid "git remote show [<options>] <name>"
@@ -7559,7 +8126,7 @@ msgstr "git remote prune [<Optionen>] <Name>"
#: builtin/remote.c:63
msgid "git remote update [<options>] [<group> | <remote>]..."
-msgstr "git remote update [<Optionen>] [<Gruppe> | <externesProjektarchiv>]..."
+msgstr "git remote update [<Optionen>] [<Gruppe> | <externesRepository>]..."
#: builtin/remote.c:98
#, c-format
@@ -7581,11 +8148,11 @@ msgstr "unbekanntes Argument für Option --mirror: %s"
#: builtin/remote.c:163
msgid "fetch the remote branches"
-msgstr "fordert die externen Zweige an"
+msgstr "fordert die Remote-Branches an"
#: builtin/remote.c:165
msgid "import all tags and associated objects when fetching"
-msgstr "importiert alle Markierungen und verbundene Objekte beim Anfordern"
+msgstr "importiert alle Tags und verbundene Objekte beim Anfordern"
#: builtin/remote.c:168
msgid "or do not fetch any tag at all (--no-tags)"
@@ -7593,11 +8160,11 @@ msgstr "oder fordere gar keine Zweige an (--no-tags)"
#: builtin/remote.c:170
msgid "branch(es) to track"
-msgstr "Zweige zur Ãœbernahme"
+msgstr "Branch(es) zur Ãœbernahme"
#: builtin/remote.c:171
msgid "master branch"
-msgstr "Hauptzweig"
+msgstr "Hauptbranch"
#: builtin/remote.c:172
msgid "push|fetch"
@@ -7606,34 +8173,35 @@ msgstr "push|fetch"
#: builtin/remote.c:173
msgid "set up remote as a mirror to push to or fetch from"
msgstr ""
-"Aufsetzen des Fernarchivs als Spiegelarchiv zum Versenden und Anfordern"
+"Aufsetzen des Remote-Repositories als Spiegel-Repository für \"push\" und "
+"\"fetch\""
#: builtin/remote.c:185
msgid "specifying a master branch makes no sense with --mirror"
msgstr ""
-"Die Option --mirror kann nicht mit der Angabe eines Hauptzweiges verwendet "
+"Die Option --mirror kann nicht mit der Angabe eines Hauptbranches verwendet "
"werden."
#: builtin/remote.c:187
msgid "specifying branches to track makes sense only with fetch mirrors"
msgstr ""
-"Die Angabe von zu folgenden Zweigen kann nur mit dem Anfordern von "
+"Die Angabe von zu folgenden Branches kann nur mit dem Anfordern von "
"Spiegelarchiven verwendet werden."
#: builtin/remote.c:195 builtin/remote.c:646
#, c-format
msgid "remote %s already exists."
-msgstr "externes Projektarchiv %s existiert bereits"
+msgstr "externes Repository %s existiert bereits"
#: builtin/remote.c:199 builtin/remote.c:650
#, c-format
msgid "'%s' is not a valid remote name"
-msgstr "'%s' ist kein gültiger Name für ein externes Projektarchiv"
+msgstr "'%s' ist kein gültiger Name für ein Remote-Repository"
#: builtin/remote.c:243
#, c-format
msgid "Could not setup master '%s'"
-msgstr "Konnte symbolische Referenz für Hauptzweig von '%s' nicht einrichten"
+msgstr "Konnte symbolische Referenz für Hauptbranch von '%s' nicht einrichten"
#: builtin/remote.c:299
#, c-format
@@ -7643,7 +8211,7 @@ msgstr "mehr als ein %s"
#: builtin/remote.c:339
#, c-format
msgid "Could not get fetch map for refspec %s"
-msgstr "Konnte Abholungszuordnung für Referenzspezifikation %s nicht bekommen"
+msgstr "Konnte Fetch-Map für Refspec %s nicht bekommen"
#: builtin/remote.c:440 builtin/remote.c:448
msgid "(matching)"
@@ -7661,7 +8229,7 @@ msgstr "Konnte '%s' nicht an '%s' anhängen."
#: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890
#, c-format
msgid "No such remote: %s"
-msgstr "Kein solches externes Archiv: %s"
+msgstr "Kein solches Remote-Repository: %s"
#: builtin/remote.c:656
#, c-format
@@ -7680,8 +8248,7 @@ msgid ""
"\t%s\n"
"\tPlease update the configuration manually if necessary."
msgstr ""
-"Keine Aktualisierung der nicht standardmäßigen Referenzspezifikation zum "
-"Abholen\n"
+"Keine Aktualisierung der nicht standardmäßigen Refspec für \"fetch\"\n"
"\t%s\n"
"\tBitte aktualisieren Sie, falls notwendig, die Konfiguration manuell."
@@ -7708,7 +8275,7 @@ msgstr "Konnte '%s' nicht erstellen"
#: builtin/remote.c:764
#, c-format
msgid "Could not remove branch %s"
-msgstr "Konnte Zweig %s nicht löschen"
+msgstr "Konnte Branch %s nicht löschen"
#: builtin/remote.c:834
msgid ""
@@ -7718,18 +8285,18 @@ msgid_plural ""
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
"to delete them, use:"
msgstr[0] ""
-"Hinweis: Ein Zweig außerhalb der /refs/remotes/ Hierachie wurde nicht "
+"Hinweis: Ein Branch außerhalb der refs/remotes/ Hierachie wurde nicht "
"gelöscht;\n"
"um diesen zu löschen, benutzen Sie:"
msgstr[1] ""
-"Hinweis: Einige Zweige außer der /refs/remotes/ Hierarchie wurden nicht "
+"Hinweis: Einige Branches außer der refs/remotes/ Hierarchie wurden nicht "
"entfernt;\n"
"um diese zu entfernen, benutzen Sie:"
#: builtin/remote.c:943
#, c-format
msgid " new (next fetch will store in remotes/%s)"
-msgstr " neu (wird bei nächster Abholung in remotes/%s gespeichert)"
+msgstr " neu (wird bei nächstem \"fetch\" in remotes/%s gespeichert)"
#: builtin/remote.c:946
msgid " tracked"
@@ -7746,30 +8313,30 @@ msgstr " ???"
#: builtin/remote.c:991
#, c-format
msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
-msgstr "ungültiges branch.%s.merge; kann nicht auf > 1 Zweig neu aufbauen"
+msgstr "ungültiges branch.%s.merge; kann Rebase nicht auf > 1 Branch ausführen"
#: builtin/remote.c:998
#, c-format
msgid "rebases onto remote %s"
-msgstr "baut neu auf externen Zweig %s auf"
+msgstr "Rebase auf Remote-Branch %s"
#: builtin/remote.c:1001
#, c-format
msgid " merges with remote %s"
-msgstr " führt mit externem Zweig %s zusammen"
+msgstr " führt mit Remote-Branch %s zusammen"
#: builtin/remote.c:1002
msgid " and with remote"
-msgstr " und mit externem Zweig"
+msgstr " und mit Remote-Branch"
#: builtin/remote.c:1004
#, c-format
msgid "merges with remote %s"
-msgstr "führt mit externem Zweig %s zusammen"
+msgstr "führt mit Remote-Branch %s zusammen"
#: builtin/remote.c:1005
msgid " and with remote"
-msgstr " und mit externem Zweig"
+msgstr " und mit Remote-Branch"
#: builtin/remote.c:1051
msgid "create"
@@ -7813,12 +8380,12 @@ msgstr " %-*s versendet nach %s"
#: builtin/remote.c:1091
msgid "do not query remotes"
-msgstr "keine Abfrage von Fernarchiven"
+msgstr "keine Abfrage von Remote-Repositories"
#: builtin/remote.c:1118
#, c-format
msgid "* remote %s"
-msgstr "* externes Projektarchiv %s"
+msgstr "* Remote-Repository %s"
#: builtin/remote.c:1119
#, c-format
@@ -7837,22 +8404,22 @@ msgstr " URL zum Versenden: %s"
#: builtin/remote.c:1133 builtin/remote.c:1135 builtin/remote.c:1137
#, c-format
msgid " HEAD branch: %s"
-msgstr " Hauptzweig: %s"
+msgstr " Hauptbranch: %s"
#: builtin/remote.c:1139
#, c-format
msgid ""
" HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
msgstr ""
-" Hauptzweig (externer Hauptzweig ist mehrdeutig, könnte einer der folgenden "
+" Hauptbranch (externer HEAD ist mehrdeutig, könnte einer der folgenden "
"sein):\n"
#: builtin/remote.c:1151
#, c-format
msgid " Remote branch:%s"
msgid_plural " Remote branches:%s"
-msgstr[0] " externer Zweig:%s"
-msgstr[1] " externe Zweige:%s"
+msgstr[0] " Remote-Branch:%s"
+msgstr[1] " Remote-Branches:%s"
#: builtin/remote.c:1154 builtin/remote.c:1181
msgid " (status not queried)"
@@ -7861,8 +8428,8 @@ msgstr " (Zustand nicht abgefragt)"
#: builtin/remote.c:1163
msgid " Local branch configured for 'git pull':"
msgid_plural " Local branches configured for 'git pull':"
-msgstr[0] " Lokaler Zweig konfiguriert für 'git pull':"
-msgstr[1] " Lokale Zweige konfiguriert für 'git pull':"
+msgstr[0] " Lokaler Branch konfiguriert für 'git pull':"
+msgstr[1] " Lokale Branches konfiguriert für 'git pull':"
#: builtin/remote.c:1171
msgid " Local refs will be mirrored by 'git push'"
@@ -7877,7 +8444,7 @@ msgstr[1] " Lokale Referenzen konfiguriert für 'git push'%s:"
#: builtin/remote.c:1199
msgid "set refs/remotes/<name>/HEAD according to remote"
-msgstr "setzt refs/remotes/<Name>/HEAD gemäß dem Fernarchiv"
+msgstr "setzt refs/remotes/<Name>/HEAD gemäß dem Remote-Repository"
#: builtin/remote.c:1201
msgid "delete refs/remotes/<name>/HEAD"
@@ -7885,13 +8452,13 @@ msgstr "entfernt refs/remotes/<Name>/HEAD"
#: builtin/remote.c:1216
msgid "Cannot determine remote HEAD"
-msgstr "Kann Hauptzweig des externen Projektarchivs nicht bestimmen"
+msgstr "Kann HEAD des Remote-Repositories nicht bestimmen"
#: builtin/remote.c:1218
msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
msgstr ""
-"Mehrere Hauptzweige im externen Projektarchiv. Bitte wählen Sie explizit "
-"einen aus mit:"
+"Mehrere Hauptbranches im Remote-Repository. Bitte wählen Sie explizit einen "
+"aus mit:"
#: builtin/remote.c:1228
#, c-format
@@ -7921,7 +8488,7 @@ msgstr " %s wurde unreferenziert!"
#: builtin/remote.c:1281
#, c-format
msgid "Pruning %s"
-msgstr "entferne veraltete Zweige von %s"
+msgstr "entferne veraltete Branches von %s"
#: builtin/remote.c:1282
#, c-format
@@ -7931,33 +8498,33 @@ msgstr "URL: %s"
#: builtin/remote.c:1295
#, c-format
msgid " * [would prune] %s"
-msgstr " * [würde veralteten Zweig entfernen] %s"
+msgstr " * [würde veralteten Branch entfernen] %s"
#: builtin/remote.c:1298
#, c-format
msgid " * [pruned] %s"
-msgstr "* [veralteten Zweig entfernt] %s"
+msgstr "* [veralteten Branch entfernt] %s"
#: builtin/remote.c:1321
msgid "prune remotes after fetching"
-msgstr "entfernt veraltete Zweige im Fernarchiv nach dem Abholen"
+msgstr "entfernt veraltete Branches im Remote-Repository nach \"fetch\""
#: builtin/remote.c:1387 builtin/remote.c:1461
#, c-format
msgid "No such remote '%s'"
-msgstr "Kein solches externes Projektarchiv '%s'"
+msgstr "Kein solches Remote-Repository '%s'"
#: builtin/remote.c:1407
msgid "add branch"
-msgstr "fügt Zweig hinzu"
+msgstr "fügt Branch hinzu"
#: builtin/remote.c:1414
msgid "no remote specified"
-msgstr "kein externes Projektarchiv angegeben"
+msgstr "kein Remote-Repository angegeben"
#: builtin/remote.c:1436
msgid "manipulate push URLs"
-msgstr "manipuliert URLs zum Versenden"
+msgstr "manipuliert URLs für \"push\""
#: builtin/remote.c:1438
msgid "add URL"
@@ -7984,7 +8551,7 @@ msgstr "Keine solche URL gefunden: %s"
#: builtin/remote.c:1497
msgid "Will not delete all non-push URLs"
-msgstr "Werde keine URLs entfernen, die nicht für den Versand bestimmt sind"
+msgstr "Werde keine URLs entfernen, die nicht für \"push\" bestimmt sind"
#: builtin/remote.c:1569
msgid "be verbose; must be placed before a subcommand"
@@ -8020,21 +8587,21 @@ msgstr "git rerere [clean | forget path... | status | remaining | diff | gc]"
#: builtin/rerere.c:56
msgid "register clean resolutions in index"
-msgstr "registriert saubere Auflösungen in der Bereitstellung"
+msgstr "registriert saubere Auflösungen in der Staging-Area"
#: builtin/reset.c:25
msgid ""
"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
msgstr ""
-"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<Version>]"
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<Commit>]"
#: builtin/reset.c:26
msgid "git reset [-q] <tree-ish> [--] <paths>..."
-msgstr "git reset [-q] <Versionsreferenz> [--] <Pfade>..."
+msgstr "git reset [-q] <Commit-Referenz> [--] <Pfade>..."
#: builtin/reset.c:27
msgid "git reset --patch [<tree-ish>] [--] [<paths>...]"
-msgstr "git reset --patch [<Versionsreferenz>] [--] [<Pfade>...]"
+msgstr "git reset --patch [<Commit-Referenz>] [--] [<Pfade>...]"
#: builtin/reset.c:33
msgid "mixed"
@@ -8058,110 +8625,108 @@ msgstr "keep"
#: builtin/reset.c:73
msgid "You do not have a valid HEAD."
-msgstr "Sie haben keine gültige Zweigspitze (HEAD)."
+msgstr "Sie haben keinen gültigen HEAD."
#: builtin/reset.c:75
msgid "Failed to find tree of HEAD."
-msgstr "Fehler beim Finden des Baumes der Zweigspitze (HEAD)."
+msgstr "Fehler beim Finden des \"Tree\"-Objektes von HEAD."
#: builtin/reset.c:81
#, c-format
msgid "Failed to find tree of %s."
-msgstr "Fehler beim Finden des Baumes von %s."
+msgstr "Fehler beim Finden des \"Tree\"-Objektes von %s."
-#: builtin/reset.c:98
+#: builtin/reset.c:99
#, c-format
msgid "HEAD is now at %s"
-msgstr "Zweigspitze (HEAD) ist jetzt bei %s"
+msgstr "HEAD ist jetzt bei %s"
-#: builtin/reset.c:169
+#: builtin/reset.c:172
#, c-format
msgid "Cannot do a %s reset in the middle of a merge."
-msgstr ""
-"Kann keine '%s' Zurücksetzung durchführen, während eine Zusammenführung im "
-"Gange ist."
+msgstr "Kann keinen '%s'-Reset durchführen, während ein Merge im Gange ist."
-#: builtin/reset.c:248
+#: builtin/reset.c:251
msgid "be quiet, only report errors"
msgstr "weniger Ausgaben, meldet nur Fehler"
-#: builtin/reset.c:250
+#: builtin/reset.c:253
msgid "reset HEAD and index"
-msgstr "setzt Zweigspitze (HEAD) und Bereitstellung neu"
+msgstr "setzt HEAD und Staging-Area um"
-#: builtin/reset.c:251
+#: builtin/reset.c:254
msgid "reset only HEAD"
-msgstr "setzt nur Zweigspitze (HEAD) neu"
+msgstr "setzt nur HEAD um"
-#: builtin/reset.c:253 builtin/reset.c:255
+#: builtin/reset.c:256 builtin/reset.c:258
msgid "reset HEAD, index and working tree"
-msgstr "setzt Zweigspitze (HEAD), Bereitstellung und Arbeitsbaum neu"
+msgstr "setzt HEAD, Staging-Area und Arbeitsverzeichnis um"
-#: builtin/reset.c:257
+#: builtin/reset.c:260
msgid "reset HEAD but keep local changes"
-msgstr "setzt Zweigspitze (HEAD) neu, behält aber lokale Änderungen"
+msgstr "setzt HEAD um, behält aber lokale Änderungen"
-#: builtin/reset.c:275
+#: builtin/reset.c:278
#, c-format
msgid "Failed to resolve '%s' as a valid revision."
-msgstr "Konnte '%s' nicht als gültige Revision auflösen."
+msgstr "Konnte '%s' nicht als gültigen Commit auflösen."
-#: builtin/reset.c:278 builtin/reset.c:286
+#: builtin/reset.c:281 builtin/reset.c:289
#, c-format
msgid "Could not parse object '%s'."
msgstr "Konnte Objekt '%s' nicht parsen."
-#: builtin/reset.c:283
+#: builtin/reset.c:286
#, c-format
msgid "Failed to resolve '%s' as a valid tree."
-msgstr "Konnte '%s' nicht als gültigen Baum auflösen."
+msgstr "Konnte '%s' nicht als gültiges \"Tree\"-Objekt auflösen."
-#: builtin/reset.c:292
+#: builtin/reset.c:295
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr "--patch ist inkompatibel mit --{hard,mixed,soft}"
-#: builtin/reset.c:301
+#: builtin/reset.c:304
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
"--mixed mit Pfaden ist veraltet; benutzen Sie stattdessen 'git reset -- "
"<Pfade>'."
-#: builtin/reset.c:303
+#: builtin/reset.c:306
#, c-format
msgid "Cannot do %s reset with paths."
-msgstr "Eine '%s' Zurücksetzung mit Pfaden ist nicht möglich."
+msgstr "Ein '%s'-Reset mit Pfaden ist nicht möglich."
-#: builtin/reset.c:313
+#: builtin/reset.c:316
#, c-format
msgid "%s reset is not allowed in a bare repository"
-msgstr "'%s' Zurücksetzung ist in einem bloßen Projektarchiv nicht erlaubt"
+msgstr "'%s'-Reset ist in einem Bare-Repository nicht erlaubt"
-#: builtin/reset.c:333
+#: builtin/reset.c:336
#, c-format
msgid "Could not reset index file to revision '%s'."
-msgstr "Konnte Bereitstellungsdatei nicht zu Revision '%s' setzen."
+msgstr "Konnte Staging-Area-Datei nicht zu Commit '%s' setzen."
-#: builtin/reset.c:339
+#: builtin/reset.c:342
msgid "Unstaged changes after reset:"
-msgstr "Nicht bereitgestellte Änderungen nach Zurücksetzung:"
+msgstr "Nicht zum Commit vorgemerkte Änderungen nach Zurücksetzung:"
-#: builtin/reset.c:344
+#: builtin/reset.c:347
msgid "Could not write new index file."
-msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
+msgstr "Konnte neue Staging-Area-Datei nicht schreiben."
-#: builtin/rev-parse.c:339
+#: builtin/rev-parse.c:345
msgid "git rev-parse --parseopt [options] -- [<args>...]"
msgstr "git rev-parse --parseopt [Optionen] -- [<Argumente>...]"
-#: builtin/rev-parse.c:344
+#: builtin/rev-parse.c:350
msgid "keep the `--` passed as an arg"
msgstr "lässt `--` als Argument"
-#: builtin/rev-parse.c:346
+#: builtin/rev-parse.c:352
msgid "stop parsing after the first non-option argument"
msgstr "stoppt das Parsen nach dem ersten Argument was keine Option ist"
-#: builtin/rev-parse.c:464
+#: builtin/rev-parse.c:470
msgid ""
"git rev-parse --parseopt [options] -- [<args>...]\n"
" or: git rev-parse --sq-quote [<arg>...]\n"
@@ -8177,196 +8742,221 @@ msgstr ""
"erster Verwendung aus."
#: builtin/revert.c:22
-msgid "git revert [options] <commit-ish>"
-msgstr "git revert [options] <Versionsangabe>"
+msgid "git revert [options] <commit-ish>..."
+msgstr "git revert [Optionen] <Commit-Angabe>..."
#: builtin/revert.c:23
msgid "git revert <subcommand>"
msgstr "git revert <Unterkommando>"
#: builtin/revert.c:28
-msgid "git cherry-pick [options] <commit-ish>"
-msgstr "git cherry-pick [Optionen] <Versionsangabe>"
+msgid "git cherry-pick [options] <commit-ish>..."
+msgstr "git cherry-pick [Optionen] <Commit-Angabe>..."
#: builtin/revert.c:29
msgid "git cherry-pick <subcommand>"
msgstr "git cherry-pick <Unterkommando>"
-#: builtin/revert.c:70 builtin/revert.c:92
+#: builtin/revert.c:71 builtin/revert.c:94
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr "%s: %s kann nicht mit %s verwendet werden"
-#: builtin/revert.c:103
+#: builtin/revert.c:105
msgid "end revert or cherry-pick sequence"
msgstr "beendet \"revert\" oder \"cherry-pick\" Ablauf"
-#: builtin/revert.c:104
+#: builtin/revert.c:106
msgid "resume revert or cherry-pick sequence"
msgstr "setzt \"revert\" oder \"cherry-pick\" Ablauf fort"
-#: builtin/revert.c:105
+#: builtin/revert.c:107
msgid "cancel revert or cherry-pick sequence"
msgstr "bricht \"revert\" oder \"cherry-pick\" Ablauf ab"
-#: builtin/revert.c:106
+#: builtin/revert.c:108
msgid "don't automatically commit"
-msgstr "trägt nicht automatisch ein"
+msgstr "committet nicht automatisch"
-#: builtin/revert.c:107
+#: builtin/revert.c:109
msgid "edit the commit message"
-msgstr "Bearbeitung der Versionsbeschreibung"
+msgstr "Bearbeitung der Commit-Beschreibung"
-#: builtin/revert.c:110
+#: builtin/revert.c:112
msgid "parent number"
msgstr "Nummer des Elternteils"
-#: builtin/revert.c:112
+#: builtin/revert.c:114
msgid "merge strategy"
-msgstr "Zusammenführungsstrategie"
+msgstr "Merge-Strategie"
-#: builtin/revert.c:113
+#: builtin/revert.c:115
msgid "option"
msgstr "Option"
-#: builtin/revert.c:114
+#: builtin/revert.c:116
msgid "option for merge strategy"
-msgstr "Option für Zusammenführungsstrategie"
+msgstr "Option für Merge-Strategie"
-#: builtin/revert.c:125
+#: builtin/revert.c:127
msgid "append commit name"
-msgstr "hängt Versionsnamen an"
+msgstr "hängt Commit-Namen an"
-#: builtin/revert.c:126
+#: builtin/revert.c:128
msgid "allow fast-forward"
msgstr "erlaubt Vorspulen"
-#: builtin/revert.c:127
+#: builtin/revert.c:129
msgid "preserve initially empty commits"
-msgstr "erhält ursprüngliche, leere Versionen"
+msgstr "erhält ursprüngliche, leere Commits"
-#: builtin/revert.c:128
+#: builtin/revert.c:130
msgid "allow commits with empty messages"
-msgstr "erlaubt Version mit leerer Beschreibung"
+msgstr "erlaubt Commits mit leerer Beschreibung"
-#: builtin/revert.c:129
+#: builtin/revert.c:131
msgid "keep redundant, empty commits"
-msgstr "behält redundante, leere Versionen"
+msgstr "behält redundante, leere Commits"
-#: builtin/revert.c:133
+#: builtin/revert.c:135
msgid "program error"
msgstr "Programmfehler"
-#: builtin/revert.c:223
+#: builtin/revert.c:225
msgid "revert failed"
msgstr "\"revert\" fehlgeschlagen"
-#: builtin/revert.c:238
+#: builtin/revert.c:240
msgid "cherry-pick failed"
msgstr "\"cherry-pick\" fehlgeschlagen"
-#: builtin/rm.c:15
+#: builtin/rm.c:16
msgid "git rm [options] [--] <file>..."
msgstr "git rm [Optionen] [--] [<Datei>...]"
-#: builtin/rm.c:64 builtin/rm.c:186
-#, c-format
+#: builtin/rm.c:64
msgid ""
-"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"the following submodule (or one of its nested submodules)\n"
+"uses a .git directory:"
+msgid_plural ""
+"the following submodules (or one of its nested submodules)\n"
+"use a .git directory:"
+msgstr[0] ""
+"das folgende Submodul (oder ein geschachteltes Submodul hiervon)\n"
+"benutzt ein .git-Verzeichnis:"
+msgstr[1] ""
+"die folgenden Submodule (oder ein geschachteltes Submodul hiervon)\n"
+"benutzen ein .git-Verzeichnis:"
+
+#: builtin/rm.c:70
+msgid ""
+"\n"
"(use 'rm -rf' if you really want to remove it including all of its history)"
msgstr ""
-"Unterprojekt '%s' (oder ein geschachteltes Unterprojekt hiervon) verwendet\n"
-"ein .git-Verzeichnis (benutzen Sie 'rm -rf' wenn Sie dieses wirklich "
-"mitsamt\n"
+"\n"
+"(benutzen Sie 'rm -rf' wenn Sie dieses Submodul wirklich mitsamt\n"
"seiner Historie löschen möchten)"
-#: builtin/rm.c:174
-#, c-format
+#: builtin/rm.c:230
msgid ""
-"'%s' has staged content different from both the file and the HEAD\n"
-"(use -f to force removal)"
-msgstr ""
-"'%s' hat bereitgestellten Inhalt unterschiedlich zu der Datei und der\n"
-"Zweigspitze (HEAD) (benutzen Sie -f um die Entfernung zu erzwingen)"
+"the following file has staged content different from both the\n"
+"file and the HEAD:"
+msgid_plural ""
+"the following files have staged content different from both the\n"
+"file and the HEAD:"
+msgstr[0] ""
+"die folgende Datei hat zum Commit vorgemerkte Änderungen unterschiedlich\n"
+"zu der Datei und HEAD:"
+msgstr[1] ""
+"die folgenden Dateien haben zum Commit vorgemerkte Änderungen "
+"unterschiedlich\n"
+"zu der Datei und HEAD:"
-#: builtin/rm.c:180
-#, c-format
+#: builtin/rm.c:235
msgid ""
-"'%s' has changes staged in the index\n"
-"(use --cached to keep the file, or -f to force removal)"
+"\n"
+"(use -f to force removal)"
msgstr ""
-"'%s' hat Änderungen in der Bereitstellung\n"
-"(benutzen Sie --cached um die Datei zu behalten, oder -f um die Entfernung "
-"zu erzwingen)"
+"\n"
+"(benutzen Sie -f um die Löschung zu erzwingen)"
-#: builtin/rm.c:191
-#, c-format
+#: builtin/rm.c:239
+msgid "the following file has changes staged in the index:"
+msgid_plural "the following files have changes staged in the index:"
+msgstr[0] "die folgende Datei hat zum Commit vorgemerkte Änderungen:"
+msgstr[1] "die folgenden Dateien haben zum Commit vorgemerkte Änderungen:"
+
+#: builtin/rm.c:243 builtin/rm.c:254
msgid ""
-"'%s' has local modifications\n"
+"\n"
"(use --cached to keep the file, or -f to force removal)"
msgstr ""
-"'%s' hat lokale Modifikationen\n"
+"\n"
"(benutzen Sie --cached um die Datei zu behalten, oder -f um die Entfernung "
"zu erzwingen)"
-#: builtin/rm.c:207
+#: builtin/rm.c:251
+msgid "the following file has local modifications:"
+msgid_plural "the following files have local modifications:"
+msgstr[0] "die folgende Datei hat lokale Änderungen:"
+msgstr[1] "die folgenden Dateien haben lokale Änderungen:"
+
+#: builtin/rm.c:269
msgid "do not list removed files"
msgstr "listet keine gelöschten Dateien auf"
-#: builtin/rm.c:208
+#: builtin/rm.c:270
msgid "only remove from the index"
-msgstr "entfernt nur aus der Bereitstellung"
+msgstr "entfernt nur aus der Staging-Area"
-#: builtin/rm.c:209
+#: builtin/rm.c:271
msgid "override the up-to-date check"
msgstr "überschreibt die \"up-to-date\" Prüfung"
-#: builtin/rm.c:210
+#: builtin/rm.c:272
msgid "allow recursive removal"
msgstr "erlaubt rekursive Entfernung"
-#: builtin/rm.c:212
+#: builtin/rm.c:274
msgid "exit with a zero status even if nothing matched"
msgstr "beendet mit Rückgabewert 0, wenn keine Übereinstimmung gefunden wurde"
-#: builtin/rm.c:283
+#: builtin/rm.c:345
#, c-format
msgid "not removing '%s' recursively without -r"
msgstr "'%s' wird nicht ohne -r rekursiv entfernt"
-#: builtin/rm.c:322
+#: builtin/rm.c:384
#, c-format
msgid "git rm: unable to remove %s"
msgstr "git rm: konnte %s nicht löschen"
#: builtin/shortlog.c:13
-msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
-msgstr ""
-"git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] "
-"[<Versionsidentifikation>... ]"
+msgid "git shortlog [<options>] [<revision range>] [[--] [<path>...]]"
+msgstr "git shortlog [<Optionen>] [Commitbereich] [[--] <Pfad>...]"
-#: builtin/shortlog.c:133
+#: builtin/shortlog.c:131
#, c-format
msgid "Missing author: %s"
msgstr "fehlender Autor: %s"
-#: builtin/shortlog.c:229
+#: builtin/shortlog.c:228
msgid "sort output according to the number of commits per author"
-msgstr "sortiert die Ausgabe entsprechend der Anzahl von Versionen pro Autor"
+msgstr "sortiert die Ausgabe entsprechend der Anzahl von Commits pro Autor"
-#: builtin/shortlog.c:231
+#: builtin/shortlog.c:230
msgid "Suppress commit descriptions, only provides commit count"
-msgstr "Unterdrückt Versionsbeschreibungen, liefert nur Anzahl der Versionen"
+msgstr "Unterdrückt Commit-Beschreibungen, liefert nur Anzahl der Commits"
-#: builtin/shortlog.c:233
+#: builtin/shortlog.c:232
msgid "Show the email address of each author"
msgstr "Zeigt die Email-Adresse von jedem Autor"
-#: builtin/shortlog.c:234
+#: builtin/shortlog.c:233
msgid "w[,i1[,i2]]"
msgstr "w[,i1[,i2]]"
-#: builtin/shortlog.c:235
+#: builtin/shortlog.c:234
msgid "Linewrap output"
msgstr "Ausgabe mit Zeilenumbrüchen"
@@ -8379,78 +8969,76 @@ msgid ""
msgstr ""
"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--"
"current] [--color[=<Wann>] | --no-color] [--sparse] [--more=<n> | --list | --"
-"independent | --merge-base] [--no-name | --sha1-name] [--topics] "
-"[(<Revision> | <glob>)...]"
+"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<Commit> "
+"| <glob>)...]"
#: builtin/show-branch.c:10
msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
msgstr "git show-branch (-g|--reflog)[=<n>[,<Basis>]] [--list] [<Referenz>]"
-#: builtin/show-branch.c:651
+#: builtin/show-branch.c:650
msgid "show remote-tracking and local branches"
-msgstr "zeigt externe Ãœbernahmezweige und lokale Zweige an"
+msgstr "zeigt Remote-Tracking und lokale Branches an"
-#: builtin/show-branch.c:653
+#: builtin/show-branch.c:652
msgid "show remote-tracking branches"
-msgstr "zeigt externe Ãœbernahmezweige an"
+msgstr "zeigt Remote-Tracking-Branches an"
-#: builtin/show-branch.c:655
+#: builtin/show-branch.c:654
msgid "color '*!+-' corresponding to the branch"
-msgstr "färbt '*!+-' entsprechend des Zweiges ein"
+msgstr "färbt '*!+-' entsprechend des Branches ein"
-#: builtin/show-branch.c:657
+#: builtin/show-branch.c:656
msgid "show <n> more commits after the common ancestor"
-msgstr "zeigt <n> weitere Versionen nach dem gemeinsamen Vorfahren"
+msgstr "zeigt <n> weitere Commits nach dem gemeinsamen Vorgänger-Commit"
-#: builtin/show-branch.c:659
+#: builtin/show-branch.c:658
msgid "synonym to more=-1"
msgstr "Synonym für more=-1"
-#: builtin/show-branch.c:660
+#: builtin/show-branch.c:659
msgid "suppress naming strings"
msgstr "unterdrückt Namen"
-#: builtin/show-branch.c:662
+#: builtin/show-branch.c:661
msgid "include the current branch"
-msgstr "bezieht den aktuellen Zweig ein"
+msgstr "bezieht den aktuellen Branch ein"
-#: builtin/show-branch.c:664
+#: builtin/show-branch.c:663
msgid "name commits with their object names"
-msgstr "benennt Versionen nach ihren Objektnamen"
+msgstr "benennt Commits nach ihren Objektnamen"
-#: builtin/show-branch.c:666
+#: builtin/show-branch.c:665
msgid "show possible merge bases"
-msgstr "zeigt mögliche Basen für Zusammenführung"
+msgstr "zeigt mögliche Merge-Basen an"
-#: builtin/show-branch.c:668
+#: builtin/show-branch.c:667
msgid "show refs unreachable from any other ref"
msgstr "zeigt Referenzen die unerreichbar von allen anderen Referenzen sind"
-#: builtin/show-branch.c:670
+#: builtin/show-branch.c:669
msgid "show commits in topological order"
-msgstr "zeigt Versionen in topologischer Ordnung"
+msgstr "zeigt Commits in topologischer Ordnung"
#: builtin/show-branch.c:672
msgid "show only commits not on the first branch"
-msgstr "zeigt nur Versionen, die sich nicht im ersten Zweig befinden"
+msgstr "zeigt nur Commits, die sich nicht im ersten Branch befinden"
#: builtin/show-branch.c:674
msgid "show merges reachable from only one tip"
-msgstr ""
-"zeigt Zusammenführungen, die nur von einer Zweigspitze aus erreichbar sind"
+msgstr "zeigt Merges, die nur von einem Branch aus erreichbar sind"
#: builtin/show-branch.c:676
-msgid "show commits where no parent comes before its children"
-msgstr "zeigt Versionen, wo kein Elternteil vor seinem Kind kommt"
+msgid "topologically sort, maintaining date order where possible"
+msgstr "topologische Sortierung, Beibehaltung Datumsordnung wo möglich"
-#: builtin/show-branch.c:678
+#: builtin/show-branch.c:679
msgid "<n>[,<base>]"
msgstr "<n>[,<Basis>]"
-#: builtin/show-branch.c:679
+#: builtin/show-branch.c:680
msgid "show <n> most recent ref-log entries starting at base"
-msgstr ""
-"zeigt die <n> jüngsten Einträge im Referenzprotokoll beginnend an der Basis"
+msgstr "zeigt die <n> jüngsten Einträge im Reflog beginnend an der Basis"
#: builtin/show-ref.c:10
msgid ""
@@ -8464,40 +9052,40 @@ msgstr ""
msgid "git show-ref --exclude-existing[=pattern] < ref-list"
msgstr "git show-ref --exclude-existing[=Muster] < ref-list"
-#: builtin/show-ref.c:165
+#: builtin/show-ref.c:168
msgid "only show tags (can be combined with heads)"
-msgstr "zeigt nur Markierungen (kann mit \"heads\" kombiniert werden)"
+msgstr "zeigt nur Tags (kann mit \"heads\" kombiniert werden)"
-#: builtin/show-ref.c:166
+#: builtin/show-ref.c:169
msgid "only show heads (can be combined with tags)"
-msgstr "zeigt nur Zweigspitzen (kann mit \"tags\" kombiniert werden)"
+msgstr "zeigt nur Branches (kann mit \"tags\" kombiniert werden)"
-#: builtin/show-ref.c:167
+#: builtin/show-ref.c:170
msgid "stricter reference checking, requires exact ref path"
msgstr "strengere Referenzprüfung, erfordert exakten Referenzpfad"
-#: builtin/show-ref.c:170 builtin/show-ref.c:172
-msgid "show the HEAD reference"
-msgstr "zeigt Referenz der Zweigspitze (HEAD)"
+#: builtin/show-ref.c:173 builtin/show-ref.c:176
+msgid "show the HEAD reference, even if it would be filtered out"
+msgstr "zeigt die HEAD-Referenz, selbst wenn diese ausgefiltert werden würde"
-#: builtin/show-ref.c:174
+#: builtin/show-ref.c:178
msgid "dereference tags into object IDs"
-msgstr "dereferenziert Markierungen in Objekt-Identifikationen"
+msgstr "dereferenziert Tags in Objekt-Identifikationen"
-#: builtin/show-ref.c:176
+#: builtin/show-ref.c:180
msgid "only show SHA1 hash using <n> digits"
msgstr "zeigt nur SHA1 Hash mit <n> Ziffern"
-#: builtin/show-ref.c:180
+#: builtin/show-ref.c:184
msgid "do not print results to stdout (useful with --verify)"
msgstr ""
"keine Ausgabe der Ergebnisse in die Standard-Ausgabe (nützlich mit --verify)"
-#: builtin/show-ref.c:182
+#: builtin/show-ref.c:186
msgid "show refs from stdin that aren't in local repository"
msgstr ""
"zeigt Referenzen von der Standard-Eingabe, die sich nicht im lokalen "
-"Projektarchiv befinden, an"
+"Repository befinden, an"
#: builtin/symbolic-ref.c:7
msgid "git symbolic-ref [options] name [ref]"
@@ -8532,24 +9120,24 @@ msgstr "Grund für die Aktualisierung"
msgid ""
"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"
msgstr ""
-"git tag [-a|-s|-u <Schlüssel-id>] [-f] [-m <Nachricht>|-F <Datei>] "
-"<Markierungsname> [<Zweig>]"
+"git tag [-a|-s|-u <Schlüssel-id>] [-f] [-m <Nachricht>|-F <Datei>] <Tagname> "
+"[<Commit>]"
#: builtin/tag.c:23
msgid "git tag -d <tagname>..."
-msgstr "git tag -d <Markierungsname>..."
+msgstr "git tag -d <Tagname>..."
#: builtin/tag.c:24
msgid ""
"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
"\t\t[<pattern>...]"
msgstr ""
-"git tag -l [-n[<Nummer>]] [--contains <Version>] [--points-at <Objekt>] \n"
+"git tag -l [-n[<Nummer>]] [--contains <Commit>] [--points-at <Objekt>] \n"
"\t\t[<Muster>...]"
#: builtin/tag.c:26
msgid "git tag -v <tagname>..."
-msgstr "git tag -v <Markierungsname>..."
+msgstr "git tag -v <Tagname>..."
#: builtin/tag.c:60
#, c-format
@@ -8559,22 +9147,22 @@ msgstr "fehlerhaftes Objekt bei '%s'"
#: builtin/tag.c:207
#, c-format
msgid "tag name too long: %.*s..."
-msgstr "Markierungsname zu lang: %.*s..."
+msgstr "Tagname zu lang: %.*s..."
#: builtin/tag.c:212
#, c-format
msgid "tag '%s' not found."
-msgstr "Markierung '%s' nicht gefunden."
+msgstr "Tag '%s' nicht gefunden."
#: builtin/tag.c:227
#, c-format
msgid "Deleted tag '%s' (was %s)\n"
-msgstr "Gelöschte Markierung '%s' (war %s)\n"
+msgstr "Tag '%s' gelöscht (war %s)\n"
#: builtin/tag.c:239
#, c-format
msgid "could not verify the tag '%s'"
-msgstr "Konnte Markierung '%s' nicht verifizieren"
+msgstr "Konnte Tag '%s' nicht verifizieren"
#: builtin/tag.c:249
#, c-format
@@ -8584,7 +9172,7 @@ msgid ""
"Lines starting with '%c' will be ignored.\n"
msgstr ""
"\n"
-"Geben Sie eine Markierungsbeschreibung ein.\n"
+"Geben Sie eine Tag-Beschreibung ein.\n"
"Zeilen, die mit '%c' beginnen, werden ignoriert.\n"
#: builtin/tag.c:253
@@ -8596,17 +9184,17 @@ msgid ""
"want to.\n"
msgstr ""
"\n"
-"Geben Sie eine Markierungsbeschreibung ein.\n"
+"Geben Sie eine Tag-Beschreibung ein.\n"
"Zeilen, die mit '%c' beginnen, werden behalten; Sie dürfen diese\n"
"selbst entfernen wenn Sie möchten.\n"
#: builtin/tag.c:292
msgid "unable to sign the tag"
-msgstr "konnte Markierung nicht signieren"
+msgstr "konnte Tag nicht signieren"
#: builtin/tag.c:294
msgid "unable to write tag file"
-msgstr "konnte Markierungsdatei nicht schreiben"
+msgstr "konnte Tag-Datei nicht schreiben"
#: builtin/tag.c:319
msgid "bad object type."
@@ -8614,16 +9202,16 @@ msgstr "ungültiger Objekt-Typ"
#: builtin/tag.c:332
msgid "tag header too big."
-msgstr "Markierungskopf zu groß."
+msgstr "Tag-Kopf zu groß."
#: builtin/tag.c:368
msgid "no tag message?"
-msgstr "keine Markierungsbeschreibung?"
+msgstr "keine Tag-Beschreibung?"
#: builtin/tag.c:374
#, c-format
msgid "The tag message has been left in %s\n"
-msgstr "Die Markierungsbeschreibung wurde gelassen in %s\n"
+msgstr "Die Tag-Beschreibung wurde gelassen in %s\n"
#: builtin/tag.c:423
msgid "switch 'points-at' requires an object"
@@ -8636,59 +9224,59 @@ msgstr "fehlerhafter Objekt-Name '%s'"
#: builtin/tag.c:445
msgid "list tag names"
-msgstr "listet Markierungsnamen auf"
+msgstr "listet Tagnamen auf"
#: builtin/tag.c:447
msgid "print <n> lines of each tag message"
-msgstr "zeigt <n> Zeilen jeder Markierungsbeschreibung"
+msgstr "zeigt <n> Zeilen jeder Tag-Beschreibung"
#: builtin/tag.c:449
msgid "delete tags"
-msgstr "löscht Markierungen"
+msgstr "löscht Tags"
#: builtin/tag.c:450
msgid "verify tags"
-msgstr "überprüft Markierungen"
+msgstr "überprüft Tags"
#: builtin/tag.c:452
msgid "Tag creation options"
-msgstr "Optionen für Erstellung von Markierungen"
+msgstr "Optionen für Erstellung von Tags"
#: builtin/tag.c:454
msgid "annotated tag, needs a message"
-msgstr "annotierte Markierung, benötigt eine Beschreibung"
+msgstr "annotierter Tag, benötigt eine Beschreibung"
#: builtin/tag.c:456
msgid "tag message"
-msgstr "Markierungsbeschreibung"
+msgstr "Tag-Beschreibung"
#: builtin/tag.c:458
msgid "annotated and GPG-signed tag"
-msgstr "annotierte und GPG-signierte Markierung"
+msgstr "annotierter und GPG-signierter Tag"
#: builtin/tag.c:462
msgid "use another key to sign the tag"
-msgstr "verwendet einen anderen Schlüssel um die Markierung zu signieren"
+msgstr "verwendet einen anderen Schlüssel um den Tag zu signieren"
#: builtin/tag.c:463
msgid "replace the tag if exists"
-msgstr "ersetzt die Markierung, wenn sie existiert"
+msgstr "ersetzt den Tag, wenn er existiert"
#: builtin/tag.c:464
msgid "show tag list in columns"
-msgstr "zeigt Liste der Markierungen in Spalten"
+msgstr "zeigt Liste der Tags in Spalten"
#: builtin/tag.c:466
msgid "Tag listing options"
-msgstr "Optionen für Auflistung der Markierungen"
+msgstr "Optionen für Auflistung der Tags"
#: builtin/tag.c:469
msgid "print only tags that contain the commit"
-msgstr "gibt nur Markierungen aus, die diese Version beinhalten"
+msgstr "gibt nur Tags aus, die diesen Commit beinhalten"
#: builtin/tag.c:475
msgid "print only tags of the object"
-msgstr "gibt nur Markierungen von dem Objekt aus"
+msgstr "gibt nur Tags von dem Objekt aus"
#: builtin/tag.c:504
msgid "--column and -n are incompatible"
@@ -8717,12 +9305,12 @@ msgstr "zu viele Parameter"
#: builtin/tag.c:559
#, c-format
msgid "'%s' is not a valid tag name."
-msgstr "'%s' ist kein gültiger Markierungsname."
+msgstr "'%s' ist kein gültiger Tagname."
#: builtin/tag.c:564
#, c-format
msgid "tag '%s' already exists"
-msgstr "Markierung '%s' existiert bereits"
+msgstr "Tag '%s' existiert bereits"
#: builtin/tag.c:582
#, c-format
@@ -8737,7 +9325,7 @@ msgstr "%s: kann Referenz nicht aktualisieren"
#: builtin/tag.c:586
#, c-format
msgid "Updated tag '%s' (was %s)\n"
-msgstr "Aktualisierte Markierung '%s' (war %s)\n"
+msgstr "Tag '%s' aktualisiert (war %s)\n"
#: builtin/update-index.c:401
msgid "git update-index [options] [--] [<file>...]"
@@ -8746,12 +9334,12 @@ msgstr "git update-index [Optionen] [--] [<Datei>...]"
#: builtin/update-index.c:718
msgid "continue refresh even when index needs update"
msgstr ""
-"Aktualisierung fortsetzen, auch wenn die Bereitstellung aktualisiert werden "
+"Aktualisierung fortsetzen, auch wenn die Staging-Area aktualisiert werden "
"muss"
#: builtin/update-index.c:721
msgid "refresh: ignore submodules"
-msgstr "Aktualisierung: ignoriert Unterprojekte"
+msgstr "Aktualisierung: ignoriert Submodule"
#: builtin/update-index.c:724
msgid "do not ignore new files"
@@ -8763,12 +9351,12 @@ msgstr "lässt Dateien Verzeichnisse ersetzen, und umgedreht"
#: builtin/update-index.c:728
msgid "notice files missing from worktree"
-msgstr "beachtet fehlende Dateien im Arbeitsbaum"
+msgstr "beachtet fehlende Dateien im Arbeitsverzeichnis"
#: builtin/update-index.c:730
msgid "refresh even if index contains unmerged entries"
msgstr ""
-"aktualisiert, auch wenn die Bereitstellung nicht zusammengeführte Einträge "
+"aktualisiert, auch wenn die Staging-Area nicht zusammengeführte Einträge "
"beinhaltet"
#: builtin/update-index.c:733
@@ -8785,7 +9373,7 @@ msgstr "<Modus> <Objekt> <Pfad>"
#: builtin/update-index.c:742
msgid "add the specified entry to the index"
-msgstr "stellt den angegebenen Eintrag zur Eintragung bereit"
+msgstr "merkt den angegebenen Eintrag zum Commit vor"
#: builtin/update-index.c:746
msgid "(+/-)x"
@@ -8814,12 +9402,13 @@ msgstr "löscht \"skip-worktree\"-Bit"
#: builtin/update-index.c:763
msgid "add to index only; do not add content to object database"
msgstr ""
-"fügt nur der Bereitstellung hinzu; Inhalt wird nicht der Objekt-Datenbank "
-"hinzugefügt"
+"merkt die Änderungen nur zum Commit vor; Inhalt wird nicht der Objekt-"
+"Datenbank hinzugefügt"
#: builtin/update-index.c:765
msgid "remove named paths even if present in worktree"
-msgstr "löscht benannte Pfade, auch wenn sie sich im Arbeitsbaum befinden"
+msgstr ""
+"löscht benannte Pfade, auch wenn sie sich im Arbeitsverzeichnis befinden"
#: builtin/update-index.c:767
msgid "with --stdin: input lines are terminated by null bytes"
@@ -8831,7 +9420,7 @@ msgstr "liest Liste der zu aktualisierenden Pfade von der Standard-Eingabe"
#: builtin/update-index.c:773
msgid "add entries from standard input to the index"
-msgstr "fügt Einträge von der Standard-Eingabe der Bereitstellung hinzu"
+msgstr "merkt Einträge von der Standard-Eingabe zum Commit vor"
#: builtin/update-index.c:777
msgid "repopulate stages #2 and #3 for the listed paths"
@@ -8840,12 +9429,11 @@ msgstr ""
#: builtin/update-index.c:781
msgid "only update entries that differ from HEAD"
-msgstr ""
-"aktualisiert nur Einträge, die unterschiedlich zur Zweigspitze (HEAD) sind"
+msgstr "aktualisiert nur Einträge, die unterschiedlich zu HEAD sind"
#: builtin/update-index.c:785
msgid "ignore files missing from worktree"
-msgstr "ignoriert fehlende Dateien im Arbeitsbaum"
+msgstr "ignoriert fehlende Dateien im Arbeitsverzeichnis"
#: builtin/update-index.c:788
msgid "report actions to standard output"
@@ -8857,7 +9445,7 @@ msgstr "(für Fremdprogramme) keine gespeicherten, nicht aufgelöste Konflikte"
#: builtin/update-index.c:794
msgid "write index in this format"
-msgstr "schreibt Bereitstellungsdatei in diesem Format"
+msgstr "schreibt Staging-Area-Datei in diesem Format"
#: builtin/update-ref.c:7
msgid "git update-ref [options] -d <refname> [<oldval>]"
@@ -8897,11 +9485,11 @@ msgstr "zeigt nur Statistiken"
#: builtin/verify-tag.c:17
msgid "git verify-tag [-v|--verbose] <tag>..."
-msgstr "git verify-tag [-v|--verbose] <Markierung>..."
+msgstr "git verify-tag [-v|--verbose] <Tag>..."
#: builtin/verify-tag.c:73
msgid "print tag contents"
-msgstr "gibt Markierungsinhalte aus"
+msgstr "gibt Tag-Inhalte aus"
#: builtin/write-tree.c:13
msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
@@ -8913,37 +9501,46 @@ msgstr "<Prefix>/"
#: builtin/write-tree.c:27
msgid "write tree object for a subdirectory <prefix>"
-msgstr "schreibt das Baumobjekt für ein Unterverzeichnis <Prefix>"
+msgstr "schreibt das \"Tree\"-Objekt für ein Unterverzeichnis <Prefix>"
#: builtin/write-tree.c:30
msgid "only useful for debugging"
msgstr "nur nützlich für Fehlersuche"
-#: git.c:16
-msgid "See 'git help <command>' for more information on a specific command."
+#: git.c:17
+msgid ""
+"'git help -a' and 'git help -g' lists available subcommands and some\n"
+"concept guides. See 'git help <command>' or 'git help <concept>'\n"
+"to read about a specific subcommand or concept."
msgstr ""
-"Siehe 'git help <Kommando>' für weitere Informationen zu einem spezifischen "
-"Kommando"
+"'git help -a' und 'git help -g' listet verfügbare Unterkommandos und\n"
+"einige Anleitungen zu Git-Konzepten auf. Benutzen Sie 'git help <Kommando>'\n"
+"oder 'git help <Konzept>' um mehr über ein spezifisches Kommando oder\n"
+"Konzept zu erfahren."
-#: parse-options.h:156
+#: parse-options.h:144
+msgid "expiry date"
+msgstr "Verfallsdatum"
+
+#: parse-options.h:159
msgid "no-op (backward compatibility)"
msgstr "Kein Effekt (Rückwärtskompatibilität)"
-#: parse-options.h:232
+#: parse-options.h:236
msgid "be more verbose"
msgstr "erweiterte Ausgaben"
-#: parse-options.h:234
+#: parse-options.h:238
msgid "be more quiet"
msgstr "weniger Ausgaben"
-#: parse-options.h:240
+#: parse-options.h:244
msgid "use <n> digits to display SHA-1s"
msgstr "benutze <n> Ziffern zur Anzeige von SHA-1s"
#: common-cmds.h:8
msgid "Add file contents to the index"
-msgstr "stellt Dateiinhalte zur Eintragung bereit"
+msgstr "merkt Dateiinhalte zum Commit vor"
#: common-cmds.h:9
msgid "Find by binary search the change that introduced a bug"
@@ -8952,27 +9549,28 @@ msgstr ""
#: common-cmds.h:10
msgid "List, create, or delete branches"
-msgstr "Zeigt an, erstellt oder entfernt Zweige"
+msgstr "Zeigt an, erstellt oder entfernt Branches"
#: common-cmds.h:11
msgid "Checkout a branch or paths to the working tree"
-msgstr "Checkt Zweige oder Pfade im Arbeitszweig aus"
+msgstr "Checkt Branches oder Pfade im Arbeitsverzeichnis aus"
#: common-cmds.h:12
msgid "Clone a repository into a new directory"
-msgstr "Klont ein Projektarchiv in einem neuen Verzeichnis"
+msgstr "Klont ein Repository in einem neuen Verzeichnis"
#: common-cmds.h:13
msgid "Record changes to the repository"
-msgstr "Trägt Änderungen in das Projektarchiv ein"
+msgstr "Trägt Änderungen in das Repository ein"
#: common-cmds.h:14
msgid "Show changes between commits, commit and working tree, etc"
-msgstr "Zeigt Änderungen zwischen Versionen, Version und Arbeitszweig, etc. an"
+msgstr ""
+"Zeigt Änderungen zwischen Commits, Commit und Arbeitsverzeichnis, etc. an"
#: common-cmds.h:15
msgid "Download objects and refs from another repository"
-msgstr "Lädt Objekte und Referenzen von einem anderen Projektarchiv herunter"
+msgstr "Lädt Objekte und Referenzen von einem anderen Repository herunter"
#: common-cmds.h:16
msgid "Print lines matching a pattern"
@@ -8981,11 +9579,11 @@ msgstr "Stellt Zeilen dar, die einem Muster entsprechen"
#: common-cmds.h:17
msgid "Create an empty Git repository or reinitialize an existing one"
msgstr ""
-"Erstellt ein leeres Git-Projektarchiv oder initialisiert ein bestehendes neu"
+"Erstellt ein leeres Git-Repository oder initialisiert ein bestehendes neu"
#: common-cmds.h:18
msgid "Show commit logs"
-msgstr "Zeigt Versionshistorie an"
+msgstr "Zeigt Commit-Historie an"
#: common-cmds.h:19
msgid "Join two or more development histories together"
@@ -8994,30 +9592,30 @@ msgstr "Führt zwei oder mehr Entwicklungszweige zusammen"
#: common-cmds.h:20
msgid "Move or rename a file, a directory, or a symlink"
msgstr ""
-"Verschiebt oder benennt eine Datei, ein Verzeichnis, oder eine symbolische "
-"Verknüpfung um"
+"Verschiebt oder benennt eine Datei, ein Verzeichnis, oder einen symbolischen "
+"Verweis um"
#: common-cmds.h:21
-msgid "Fetch from and merge with another repository or a local branch"
+msgid "Fetch from and integrate with another repository or a local branch"
msgstr ""
-"Fordert Objekte von einem externen Projektarchiv an und führt sie mit einem "
-"anderen Projektarchiv oder einem lokalen Zweig zusammen"
+"Fordert Objekte von einem externen Repository an und führt sie mit einem "
+"anderen Repository oder einem lokalen Branch zusammen"
#: common-cmds.h:22
msgid "Update remote refs along with associated objects"
-msgstr "Aktualisiert externe Referenzen mitsamt den verbundenen Objekten"
+msgstr "Aktualisiert Remote-Referenzen mitsamt den verbundenen Objekten"
#: common-cmds.h:23
msgid "Forward-port local commits to the updated upstream head"
-msgstr "Baut lokale Versionen auf einem aktuellerem externen Zweig neu auf"
+msgstr "Baut lokale Commits auf einem aktuellerem Upstream-Branch neu auf"
#: common-cmds.h:24
msgid "Reset current HEAD to the specified state"
-msgstr "Setzt die aktuelle Zweigspitze (HEAD) zu einem spezifizierten Zustand"
+msgstr "Setzt aktuellen HEAD zu einem spezifizierten Zustand"
#: common-cmds.h:25
msgid "Remove files from the working tree and from the index"
-msgstr "Löscht Dateien im Arbeitszweig und von der Bereitstellung"
+msgstr "Löscht Dateien im Arbeitsverzeichnis und von der Staging-Area"
#: common-cmds.h:26
msgid "Show various types of objects"
@@ -9025,54 +9623,53 @@ msgstr "Zeigt verschiedene Arten von Objekten an"
#: common-cmds.h:27
msgid "Show the working tree status"
-msgstr "Zeigt den Zustand des Arbeitszweiges an"
+msgstr "Zeigt den Zustand des Arbeitsverzeichnisses an"
#: common-cmds.h:28
msgid "Create, list, delete or verify a tag object signed with GPG"
msgstr ""
-"Erzeugt, listet auf, löscht oder verifiziert ein mit GPG signiertes "
-"Markierungsobjekt"
+"Erzeugt, listet auf, löscht oder verifiziert ein mit GPG signiertes Tag-"
+"Objekt"
#: git-am.sh:50
msgid "You need to set your committer info first"
-msgstr "Sie müssen zuerst die Informationen des Eintragenden setzen."
+msgstr "Sie müssen zuerst die Informationen zum Commit-Ersteller setzen."
#: git-am.sh:95
msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"
msgstr ""
-"Sie scheinen seit dem letzten gescheiterten 'am' die Zweigspitze (HEAD)\n"
-"geändert zu haben.\n"
+"Sie scheinen seit dem letzten gescheiterten 'am' HEAD geändert zu haben.\n"
"Keine Zurücksetzung zu ORIG_HEAD."
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"When you have resolved this problem, run \"$cmdline --continue\".\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 Sie das Problem gelöst haben, führen Sie \"$cmdline --resolved\" aus.\n"
+"Wenn Sie das Problem gelöst haben, führen Sie \"$cmdline --continue\" aus.\n"
"Falls Sie diesen Patch auslassen möchten, führen Sie stattdessen\n"
"\"$cmdline --skip\" aus.\n"
-"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der\n"
+"Um den ursprünglichen Branch wiederherzustellen und die Anwendung der\n"
"Patches abzubrechen, führen Sie \"$cmdline --abort\" aus."
#: git-am.sh:121
msgid "Cannot fall back to three-way merge."
-msgstr "Kann nicht zu 3-Wege-Zusammenführung zurückfallen."
+msgstr "Kann nicht zu 3-Wege-Merge zurückfallen."
#: git-am.sh:137
msgid "Repository lacks necessary blobs to fall back on 3-way merge."
msgstr ""
-"Dem Projektarchiv fehlen notwendige Blobs um auf eine 3-Wege-Zusammenführung "
+"Dem Repository fehlen notwendige Blobs um auf einen 3-Wege-Merge "
"zurückzufallen."
#: git-am.sh:139
msgid "Using index info to reconstruct a base tree..."
msgstr ""
-"Verwende Informationen aus der Bereitstellung um einen Basisbaum "
+"Verwende Informationen aus der Staging-Area um einen Basisverzeichnis "
"nachzustellen"
#: git-am.sh:154
@@ -9085,11 +9682,11 @@ msgstr ""
#: git-am.sh:163
msgid "Falling back to patching base and 3-way merge..."
-msgstr "Falle zurück zum Patchen der Basis und der 3-Wege-Zusammenführung..."
+msgstr "Falle zurück zum Patchen der Basis und des 3-Wege-Merges..."
#: git-am.sh:179
msgid "Failed to merge in the changes."
-msgstr "Zusammenführung der Änderungen fehlgeschlagen"
+msgstr "Merge der Änderungen fehlgeschlagen"
#: git-am.sh:274
msgid "Only one StGIT patch series can be applied at once"
@@ -9112,28 +9709,35 @@ msgstr ""
"Die -b/--binary Option hat seit Langem keinen Effekt und wird\n"
"entfernt. Bitte nicht mehr verwenden."
-#: git-am.sh:477
+#: git-am.sh:479
#, sh-format
msgid "previous rebase directory $dotest still exists but mbox given."
msgstr ""
-"Vorheriges Verzeichnis des Neuaufbaus $dotest existiert noch, aber mbox "
-"gegeben."
+"Vorheriges Rebase-Verzeichnis $dotest existiert noch, aber mbox gegeben."
-#: git-am.sh:482
+#: git-am.sh:484
msgid "Please make up your mind. --skip or --abort?"
msgstr "Bitte werden Sie sich klar. --skip oder --abort?"
-#: git-am.sh:509
+#: git-am.sh:520
+#, sh-format
+msgid ""
+"Stray $dotest directory found.\n"
+"Use \"git am --abort\" to remove it."
+msgstr ""
+"Stray $dotest Verzeichnis gefunden.\n"
+"Benutzen Sie \"git am --abort\" um es zu entfernen."
+
+#: git-am.sh:528
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:575
+#: git-am.sh:594
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
-msgstr ""
-"Unsaubere Bereitstellung: kann Patches nicht anwenden (unsauber: $files)"
+msgstr "Geänderte Staging-Area: kann Patches nicht anwenden (geändert: $files)"
-#: git-am.sh:679
+#: git-am.sh:698
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -9143,65 +9747,65 @@ msgstr ""
"Patch ist leer. Wurde er falsch aufgeteilt?\n"
"Wenn Sie diesen Patch auslassen möchten, führen Sie stattdessen\n"
"\"$cmdline --skip\" aus.\n"
-"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der "
+"Um den ursprünglichen Branch wiederherzustellen und die Anwendung der "
"Patches\n"
"abzubrechen, führen Sie \"$cmdline --abort\" aus."
-#: git-am.sh:706
+#: git-am.sh:725
msgid "Patch does not have a valid e-mail address."
msgstr "Patch enthält keine gültige Email-Adresse."
-#: git-am.sh:753
+#: git-am.sh:772
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:757
+#: git-am.sh:776
msgid "Commit Body is:"
-msgstr "Beschreibung der Eintragung ist:"
+msgstr "Commit-Beschreibung 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:764
+#: git-am.sh:783
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:800
+#: git-am.sh:819
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr "Wende an: $FIRSTLINE"
-#: git-am.sh:821
+#: git-am.sh:840
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 ""
"Keine Änderungen - haben Sie vergessen 'git add' zu benutzen?\n"
-"Wenn keine Änderungen mehr zum Bereitstellen vorhanden sind, könnten\n"
+"Wenn keine Änderungen mehr zum Commit vorzumerken sind, könnten\n"
"diese bereits anderweitig eingefügt worden sein; Sie könnten diesen Patch\n"
"auslassen."
-#: git-am.sh:829
+#: git-am.sh:848
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
msgstr ""
-"Sie haben immer noch nicht zusammengeführte Pfade in der Bereitstellung.\n"
+"Sie haben immer noch nicht zusammengeführte Pfade in der Staging-Area.\n"
"Haben Sie vergessen 'git add' zu benutzen?"
-#: git-am.sh:845
+#: git-am.sh:864
msgid "No changes -- Patch already applied."
msgstr "Keine Änderungen -- Patches bereits angewendet."
-#: git-am.sh:855
+#: git-am.sh:874
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr "Anwendung des Patches fehlgeschlagen bei $msgnum $FIRSTLINE"
-#: git-am.sh:858
+#: git-am.sh:877
#, sh-format
msgid ""
"The copy of the patch that failed is found in:\n"
@@ -9210,7 +9814,7 @@ msgstr ""
"Die Kopie des fehlgeschlagenen Patches befindet sich in:\n"
" $dotest/patch"
-#: git-am.sh:876
+#: git-am.sh:895
msgid "applying to an empty history"
msgstr "wende zu leerer Historie an"
@@ -9233,11 +9837,11 @@ msgstr "nicht erkannte Option: '$arg'"
#: git-bisect.sh:99
#, sh-format
msgid "'$arg' does not appear to be a valid revision"
-msgstr "'$arg' scheint keine gültige Revision zu sein"
+msgstr "'$arg' scheint kein gültiger Commit zu sein"
#: git-bisect.sh:117
msgid "Bad HEAD - I need a HEAD"
-msgstr "Ungültige Zweigspitze (HEAD) - Zweigspitze (HEAD) wird benötigt"
+msgstr "Ungültiger HEAD - HEAD wird benötigt"
#: git-bisect.sh:130
#, sh-format
@@ -9245,15 +9849,15 @@ msgid ""
"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
msgstr ""
"Auschecken von '$start_head' fehlgeschlagen. Versuchen Sie 'git bisect reset "
-"<gueltigerzweig>'."
+"<gueltigerbranch>'."
#: git-bisect.sh:140
msgid "won't bisect on seeked tree"
-msgstr "binäre Suche auf gesuchtem Zweig nicht möglich"
+msgstr "binäre Suche auf gesuchtem Branch nicht möglich"
#: git-bisect.sh:144
msgid "Bad HEAD - strange symbolic ref"
-msgstr "Ungültige Zweigspitze (HEAD) - merkwürdige symbolische Referenz"
+msgstr "Ungültiger HEAD - merkwürdige symbolische Referenz"
#: git-bisect.sh:189
#, sh-format
@@ -9282,7 +9886,7 @@ msgstr "'git bisect bad' kann nur ein Argument entgegennehmen."
#. this is less optimum.
#: git-bisect.sh:273
msgid "Warning: bisecting only with a bad commit."
-msgstr "Warnung: binäre Suche nur mit einer fehlerhaften Version"
+msgstr "Warnung: binäre Suche nur mit einem fehlerhaften Commit"
#. TRANSLATORS: Make sure to include [Y] and [n] in your
#. translation. The program will only accept English input
@@ -9296,7 +9900,8 @@ msgid ""
"You need to give me at least one good and one bad revisions.\n"
"(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
msgstr ""
-"Sie müssen mindestens eine korrekte und eine fehlerhafte Revision angeben.\n"
+"Sie müssen mindestens einen korrekten und einen fehlerhaften Commit "
+"angeben.\n"
"(Sie können dafür \"git bisect bad\" und \"git bisect good\" benutzen.)"
#: git-bisect.sh:292
@@ -9306,47 +9911,47 @@ msgid ""
"(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
msgstr ""
"Sie müssen mit \"git bisect start\" beginnen.\n"
-"Danach müssen Sie mindestens eine korrekte und eine fehlerhafte Revision "
+"Danach müssen Sie mindestens einen korrekten und einen fehlerhaften Commit "
"angeben.\n"
"(Sie können dafür \"git bisect bad\" und \"git bisect good\" benutzen.)"
-#: git-bisect.sh:347 git-bisect.sh:474
+#: git-bisect.sh:363 git-bisect.sh:490
msgid "We are not bisecting."
msgstr "keine binäre Suche im Gange"
-#: git-bisect.sh:354
+#: git-bisect.sh:370
#, sh-format
msgid "'$invalid' is not a valid commit"
-msgstr "'$invalid' ist keine gültige Version"
+msgstr "'$invalid' ist kein gültiger Commit"
-#: git-bisect.sh:363
+#: git-bisect.sh:379
#, sh-format
msgid ""
"Could not check out original HEAD '$branch'.\n"
"Try 'git bisect reset <commit>'."
msgstr ""
-"Konnte die ursprüngliche Zweigspitze (HEAD) '$branch' nicht auschecken.\n"
-"Versuchen Sie 'git bisect reset <Version>'."
+"Konnte den ursprünglichen HEAD '$branch' nicht auschecken.\n"
+"Versuchen Sie 'git bisect reset <Commit>'."
-#: git-bisect.sh:390
+#: git-bisect.sh:406
msgid "No logfile given"
msgstr "Keine Log-Datei gegeben"
-#: git-bisect.sh:391
+#: git-bisect.sh:407
#, sh-format
msgid "cannot read $file for replaying"
msgstr "kann $file nicht für das Abspielen lesen"
-#: git-bisect.sh:408
+#: git-bisect.sh:424
msgid "?? what are you talking about?"
msgstr "?? Was reden Sie da?"
-#: git-bisect.sh:420
+#: git-bisect.sh:436
#, sh-format
msgid "running $command"
msgstr "führe $command aus"
-#: git-bisect.sh:427
+#: git-bisect.sh:443
#, sh-format
msgid ""
"bisect run failed:\n"
@@ -9355,11 +9960,11 @@ msgstr ""
"'bisect run' fehlgeschlagen:\n"
"Rückkehrwert $res von '$command' ist < 0 oder >= 128"
-#: git-bisect.sh:453
+#: git-bisect.sh:469
msgid "bisect run cannot continue any more"
msgstr "'bisect run' kann nicht mehr fortgesetzt werden"
-#: git-bisect.sh:459
+#: git-bisect.sh:475
#, sh-format
msgid ""
"bisect run failed:\n"
@@ -9368,7 +9973,7 @@ msgstr ""
"'bisect run' fehlgeschlagen:\n"
"'bisect_state $state' wurde mit Fehlerwert $res beendet"
-#: git-bisect.sh:466
+#: git-bisect.sh:482
msgid "bisect run success"
msgstr "'bisect run' erfolgreich ausgeführt"
@@ -9379,45 +9984,44 @@ msgid ""
"as appropriate to mark resolution, or use 'git commit -a'."
msgstr ""
"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben.\n"
-"Bitte korrigieren Sie dies im Arbeitsbaum und benutzen Sie dann 'git add/rm "
-"<Datei>'\n"
-"um die Auflösung entsprechend zu markieren, oder benutzen Sie 'git commit -"
-"a'."
+"Bitte korrigieren Sie dies im Arbeitsverzeichnis und benutzen Sie dann \n"
+"'git add/rm <Datei>' um die Auflösung entsprechend zu markieren, oder\n"
+"benutzen Sie 'git commit -a'."
#: git-pull.sh:25
msgid "Pull is not possible because you have unmerged files."
msgstr ""
"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
-#: git-pull.sh:197
+#: git-pull.sh:203
msgid "updating an unborn branch with changes added to the index"
msgstr ""
-"Aktualisiere eine ungeborenen Zweig mit Änderungen, die zur Bereitstellung "
-"hinzugefügt wurden"
+"Aktualisiere einen ungeborenen Branch mit Änderungen, die zum Commit "
+"vorgemerkt sind"
#. The fetch involved updating the current branch.
#. The working tree and the index file is still based on the
#. $orig_head commit, but we are merging into $curr_head.
#. First update the working tree to match $curr_head.
-#: git-pull.sh:229
+#: git-pull.sh:235
#, sh-format
msgid ""
"Warning: fetch updated the current branch head.\n"
"Warning: fast-forwarding your working tree from\n"
"Warning: commit $orig_head."
msgstr ""
-"Warnung: Die Anforderung aktualisierte die Spitze des aktuellen Zweiges.\n"
-"Warnung: Spule Ihren Arbeitszweig von Version $orig_head vor."
+"Warnung: \"fetch\" aktualisierte die Spitze des aktuellen Branches.\n"
+"Warnung: Spule Ihr Arbeitsverzeichnis von Commit $orig_head vor."
-#: git-pull.sh:254
+#: git-pull.sh:260
msgid "Cannot merge multiple branches into empty head"
-msgstr "Kann nicht mehrere Zweige in einen ungeborenen Zweig zusammenführen"
+msgstr "Kann nicht mehrere Branches in einen ungeborenen Branch zusammenführen"
-#: git-pull.sh:258
+#: git-pull.sh:264
msgid "Cannot rebase onto multiple branches"
-msgstr "kann nicht auf mehrere Zweige neu aufbauen"
+msgstr "kann Rebase nicht auf mehrere Branches ausführen"
-#: git-rebase.sh:53
+#: git-rebase.sh:54
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"
@@ -9428,50 +10032,68 @@ msgstr ""
"aus.\n"
"Falls Sie diesen Patch auslassen möchten, führen Sie stattdessen \"git "
"rebase --skip\" aus.\n"
-"Um den ursprünglichen Zweig wiederherzustellen und den Neuaufbau "
-"abzubrechen,\n"
+"Um den ursprünglichen Branch wiederherzustellen und den Rebase abzubrechen,\n"
"führen Sie \"git rebase --abort\" aus."
+#: git-rebase.sh:156
+msgid "Applied autostash."
+msgstr "\"autostash\" angewendet."
+
+#: git-rebase.sh:159
+#, sh-format
+msgid "Cannot store $stash_sha1"
+msgstr "Kann $stash_sha1 nicht speichern."
+
#: git-rebase.sh:160
+msgid ""
+"Applying autostash resulted in conflicts.\n"
+"Your changes are safe in the stash.\n"
+"You can run \"git stash pop\" or \"git stash drop\" at any time.\n"
+msgstr ""
+"Anwendung von \"autostash\" resultierte in Konflikten.\n"
+"Ihre Änderungen sind im Stash sicher.\n"
+"Sie können jederzeit \"git stash pop\" oder \"git stash drop\" ausführen.\n"
+
+#: git-rebase.sh:190
msgid "The pre-rebase hook refused to rebase."
-msgstr "Der \"pre-rebase hook\" hat den Neuaufbau zurückgewiesen."
+msgstr "Der \"pre-rebase hook\" hat den Rebase zurückgewiesen."
-#: git-rebase.sh:165
+#: git-rebase.sh:195
msgid "It looks like git-am is in progress. Cannot rebase."
-msgstr "\"git-am\" scheint im Gange zu sein. Kann nicht neu aufbauen."
+msgstr "\"git-am\" scheint im Gange zu sein. Kann Rebase nicht durchführen."
-#: git-rebase.sh:296
+#: git-rebase.sh:329
msgid "The --exec option must be used with the --interactive option"
msgstr "Die Option --exec muss mit --interactive verwendet werden."
-#: git-rebase.sh:301
+#: git-rebase.sh:334
msgid "No rebase in progress?"
-msgstr "Kein Neuaufbau im Gange?"
+msgstr "Kein Rebase im Gange?"
-#: git-rebase.sh:312
+#: git-rebase.sh:345
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
-"Die --edit-todo Aktion kann nur während eines interaktiven Neuaufbaus "
-"verwendet werden."
+"Die --edit-todo Aktion kann nur während eines interaktiven Rebase verwendet "
+"werden."
-#: git-rebase.sh:319
+#: git-rebase.sh:352
msgid "Cannot read HEAD"
-msgstr "Kann Zweigspitze (HEAD) nicht lesen"
+msgstr "Kann HEAD nicht lesen"
-#: git-rebase.sh:322
+#: git-rebase.sh:355
msgid ""
"You must edit all merge conflicts and then\n"
"mark them as resolved using git add"
msgstr ""
-"Sie müssen alle Zusammenführungskonflikte editieren und diese dann\n"
+"Sie müssen alle Merge-Konflikte editieren und diese dann\n"
"mittels \"git add\" als aufgelöst markieren"
-#: git-rebase.sh:340
+#: git-rebase.sh:373
#, sh-format
msgid "Could not move back to $head_name"
msgstr "Konnte nicht zu $head_name zurückgehen"
-#: git-rebase.sh:359
+#: git-rebase.sh:392
#, sh-format
msgid ""
"It seems that there is already a $state_dir_base directory, and\n"
@@ -9484,7 +10106,7 @@ msgid ""
"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"
+"und es könnte ein anderer Rebase im Gange sein. Wenn das der Fall ist,\n"
"probieren Sie bitte\n"
"\t$cmd_live_rebase\n"
"Wenn das nicht der Fall ist, probieren Sie bitte\n"
@@ -9492,59 +10114,68 @@ msgstr ""
"und führen Sie dieses Kommando nochmal aus. Es wird angehalten, falls noch\n"
"etwas Schützenswertes vorhanden ist."
-#: git-rebase.sh:404
+#: git-rebase.sh:437
#, sh-format
msgid "invalid upstream $upstream_name"
-msgstr "ungültiger Übernahmezweig $upstream_name"
+msgstr "ungültiger Upstream-Branch $upstream_name"
-#: git-rebase.sh:428
+#: git-rebase.sh:461
#, sh-format
msgid "$onto_name: there are more than one merge bases"
-msgstr "$onto_name: es gibt mehr als eine Zusammenführungsbasis"
+msgstr "$onto_name: es gibt mehr als eine Merge-Basis"
-#: git-rebase.sh:431 git-rebase.sh:435
+#: git-rebase.sh:464 git-rebase.sh:468
#, sh-format
msgid "$onto_name: there is no merge base"
-msgstr "$onto_name: es gibt keine Zusammenführungsbasis"
+msgstr "$onto_name: es gibt keine Merge-Basis"
-#: git-rebase.sh:440
+#: git-rebase.sh:473
#, sh-format
msgid "Does not point to a valid commit: $onto_name"
-msgstr "$onto_name zeigt auf keine gültige Version"
+msgstr "$onto_name zeigt auf keinen gültigen Commit"
-#: git-rebase.sh:463
+#: git-rebase.sh:496
#, sh-format
msgid "fatal: no such branch: $branch_name"
-msgstr "fatal: Zweig $branch_name nicht gefunden"
+msgstr "fatal: Branch $branch_name nicht gefunden"
+
+#: git-rebase.sh:519
+msgid "Cannot autostash"
+msgstr "Kann \"autostash\" nicht ausführen."
+
+#: git-rebase.sh:524
+#, sh-format
+msgid "Created autostash: $stash_abbrev"
+msgstr "\"autostash\" erzeugt: $stash_abbrev"
-#: git-rebase.sh:483
+#: git-rebase.sh:528
msgid "Please commit or stash them."
-msgstr "Bitte tragen Sie die Änderungen ein oder benutzen Sie \"stash\"."
+msgstr "Bitte committen Sie die Änderungen oder benutzen Sie \"stash\"."
-#: git-rebase.sh:501
+#: git-rebase.sh:548
#, sh-format
msgid "Current branch $branch_name is up to date."
-msgstr "Aktueller Zweig $branch_name ist auf dem neusten Stand."
+msgstr "Aktueller Branch $branch_name ist auf dem neusten Stand."
-#: git-rebase.sh:504
+#: git-rebase.sh:552
#, 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."
+"Aktueller Branch $branch_name ist auf dem neusten Stand, Rebase erzwungen."
-#: git-rebase.sh:515
+#: git-rebase.sh:563
#, sh-format
msgid "Changes from $mb to $onto:"
msgstr "Änderungen von $mb zu $onto:"
#. Detach HEAD and reset the tree
-#: git-rebase.sh:524
+#: git-rebase.sh:572
msgid "First, rewinding head to replay your work on top of it..."
msgstr ""
-"Zunächst wird die Zweigspitze zurückgespult, um Ihre Änderungen\n"
+"Zunächst wird der Branch zurückgespult, um Ihre Änderungen\n"
"darauf neu anzuwenden..."
-#: git-rebase.sh:532
+#: git-rebase.sh:582
#, sh-format
msgid "Fast-forwarded $branch_name to $onto_name."
msgstr "$branch_name zu $onto_name vorgespult."
@@ -9555,15 +10186,15 @@ msgstr "git stash clear mit Parametern ist nicht implementiert"
#: git-stash.sh:74
msgid "You do not have the initial commit yet"
-msgstr "Sie haben bisher noch keine initiale Version"
+msgstr "Sie haben bisher noch keinen initialen Commit"
#: git-stash.sh:89
msgid "Cannot save the current index state"
-msgstr "Kann den aktuellen Zustand der Bereitstellung nicht speichern"
+msgstr "Kann den aktuellen Zustand der Staging-Area nicht speichern"
#: git-stash.sh:123 git-stash.sh:136
msgid "Cannot save the current worktree state"
-msgstr "Kann den aktuellen Zustand des Arbeitsbaumes nicht speichern"
+msgstr "Kann den aktuellen Zustand des Arbeitsverzeichnisses nicht speichern"
#: git-stash.sh:140
msgid "No changes selected"
@@ -9571,11 +10202,16 @@ msgstr "Keine Änderungen ausgewählt"
#: git-stash.sh:143
msgid "Cannot remove temporary index (can't happen)"
-msgstr "Kann temporäre Bereitstellung nicht löschen (kann nicht passieren)"
+msgstr "Kann temporäre Staging-Area nicht löschen (kann nicht passieren)"
#: git-stash.sh:156
msgid "Cannot record working tree state"
-msgstr "Kann Zustand des Arbeitsbaumes nicht aufzeichnen"
+msgstr "Kann Zustand des Arbeitsverzeichnisses nicht aufzeichnen"
+
+#: git-stash.sh:190
+#, sh-format
+msgid "Cannot update $ref_stash with $w_commit"
+msgstr "Kann $ref_stash nicht mit $w_commit aktualisieren."
#. TRANSLATORS: $option is an invalid option, like
#. `--blah-blah'. The 7 spaces at the beginning of the
@@ -9587,7 +10223,7 @@ msgstr "Kann Zustand des Arbeitsbaumes nicht aufzeichnen"
#. $ git stash save --blah-blah 2>&1 | head -n 2
#. error: unknown option for 'stash save': --blah-blah
#. To provide a message, use git stash save -- '--blah-blah'
-#: git-stash.sh:202
+#: git-stash.sh:241
#, sh-format
msgid ""
"error: unknown option for 'stash save': $option\n"
@@ -9597,122 +10233,140 @@ msgstr ""
" Um eine Beschreibung anzugeben, benutzen Sie \"git stash save -- "
"'$option'\""
-#: git-stash.sh:223
+#: git-stash.sh:262
msgid "No local changes to save"
msgstr "Keine lokalen Änderungen zum Speichern"
-#: git-stash.sh:227
+#: git-stash.sh:268
+msgid ""
+"The following untracked files would NOT be saved but need to be removed by "
+"stash save:"
+msgstr ""
+"Die folgenden unbeobachteten Dateien würden NICHT gespeichert werden,\n"
+"müssen aber durch \"stash save\" entfernt werden:"
+
+#: git-stash.sh:270
+msgid ""
+"Aborting. Consider using either the --force or --include-untracked option."
+msgstr ""
+"Abgebrochen. Benutzen Sie entweder die Option --force oder --include-"
+"untracked."
+
+#: git-stash.sh:274
msgid "Cannot initialize stash"
msgstr "Kann \"stash\" nicht initialisieren"
-#: git-stash.sh:235
+#: git-stash.sh:278
msgid "Cannot save the current status"
msgstr "Kann den aktuellen Status nicht speichern"
-#: git-stash.sh:253
+#: git-stash.sh:296
msgid "Cannot remove worktree changes"
-msgstr "Kann Änderungen am Arbeitsbaum nicht löschen"
+msgstr "Kann Änderungen im Arbeitsverzeichnis nicht löschen"
-#: git-stash.sh:352
+#: git-stash.sh:395
msgid "No stash found."
msgstr "Kein \"stash\" gefunden."
-#: git-stash.sh:359
+#: git-stash.sh:402
#, sh-format
msgid "Too many revisions specified: $REV"
-msgstr "Zu viele Revisionen angegeben: $REV"
+msgstr "Zu viele Commits angegeben: $REV"
-#: git-stash.sh:365
+#: git-stash.sh:408
#, sh-format
msgid "$reference is not valid reference"
msgstr "$reference ist keine gültige Referenz"
-#: git-stash.sh:393
+#: git-stash.sh:436
#, sh-format
msgid "'$args' is not a stash-like commit"
-msgstr "'$args' ist keine \"stash\"-artige Version"
+msgstr "'$args' ist kein \"stash\"-artiger Commit"
-#: git-stash.sh:404
+#: git-stash.sh:447
#, sh-format
msgid "'$args' is not a stash reference"
msgstr "'$args' ist keine \"stash\"-Referenz"
-#: git-stash.sh:412
+#: git-stash.sh:455
msgid "unable to refresh index"
-msgstr "unfähig die Bereitstellung zu aktualisieren"
+msgstr "unfähig die Staging-Area zu aktualisieren"
-#: git-stash.sh:416
+#: git-stash.sh:459
msgid "Cannot apply a stash in the middle of a merge"
-msgstr ""
-"Kann \"stash\" nicht anwenden, solang eine Zusammenführung im Gange ist"
+msgstr "Kann \"stash\" nicht anwenden, solang ein Merge im Gange ist"
-#: git-stash.sh:424
+#: git-stash.sh:467
msgid "Conflicts in index. Try without --index."
-msgstr "Konflikte in der Bereitstellung. Versuchen Sie es ohne --index."
+msgstr "Konflikte in der Staging-Area. Versuchen Sie es ohne --index."
-#: git-stash.sh:426
+#: git-stash.sh:469
msgid "Could not save index tree"
-msgstr "Konnte Bereitstellungsbaum nicht speichern"
+msgstr "Konnte Staging-Area-Verzeichnis nicht speichern"
-#: git-stash.sh:460
+#: git-stash.sh:503
msgid "Cannot unstage modified files"
-msgstr "Kann geänderte Dateien nicht aus der Bereitstellung herausnehmen"
+msgstr "Kann geänderte Dateien nicht aus der Staging-Area entfernen"
-#: git-stash.sh:475
+#: git-stash.sh:518
msgid "Index was not unstashed."
-msgstr "Bereitstellung wurde nicht ausgelagert."
+msgstr "Staging-Area wurde nicht aus dem Stash zurückgeladen."
-#: git-stash.sh:492
+#: git-stash.sh:535
#, sh-format
msgid "Dropped ${REV} ($s)"
msgstr "Gelöscht ${REV} ($s)"
-#: git-stash.sh:493
+#: git-stash.sh:536
#, sh-format
msgid "${REV}: Could not drop stash entry"
msgstr "${REV}: Konnte \"stash\"-Eintrag nicht löschen"
-#: git-stash.sh:500
+#: git-stash.sh:543
msgid "No branch name specified"
-msgstr "Kein Zweigname spezifiziert"
+msgstr "Kein Branchname spezifiziert"
-#: git-stash.sh:571
+#: git-stash.sh:615
msgid "(To restore them type \"git stash apply\")"
msgstr "(Zur Wiederherstellung geben Sie \"git stash apply\" ein)"
-#: git-submodule.sh:90
+#: git-submodule.sh:95
#, sh-format
msgid "cannot strip one component off url '$remoteurl'"
msgstr "Kann eine Komponente von URL '$remoteurl' nicht extrahieren"
-#: git-submodule.sh:195
+#: git-submodule.sh:237
#, 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"
+msgstr "Keine Submodul-Zuordnung in .gitmodules für Pfad '$sm_path' gefunden"
-#: git-submodule.sh:238
+#: git-submodule.sh:281
#, sh-format
msgid "Clone of '$url' into submodule path '$sm_path' failed"
-msgstr "Klonen von '$url' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen"
+msgstr "Klonen von '$url' in Submodul-Pfad '$sm_path' fehlgeschlagen"
-#: git-submodule.sh:250
+#: git-submodule.sh:293
#, sh-format
msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
+msgstr "Git-Verzeichnis '$a' ist Teil des Submodul-Pfades '$b', oder umgekehrt"
+
+#: git-submodule.sh:403
+msgid "Relative path can only be used from the toplevel of the working tree"
msgstr ""
-"Git-Verzeichnis '$a' ist Teil des Unterprojekt-Pfades '$b', oder umgekehrt"
+"Relative Pfade können nur von der obersten Ebene des Arbeitsverzeichnisses "
+"benutzt werden."
-#: git-submodule.sh:343
+#: git-submodule.sh:413
#, 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:360
+#: git-submodule.sh:430
#, sh-format
msgid "'$sm_path' already exists in the index"
-msgstr "'$sm_path' existiert bereits in der Bereitstellung"
+msgstr "'$sm_path' ist bereits zum Commit vorgemerkt"
-#: git-submodule.sh:364
+#: git-submodule.sh:434
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
@@ -9723,25 +10377,24 @@ msgstr ""
"$sm_path\n"
"Benutzen Sie -f wenn Sie diesen wirklich hinzufügen möchten."
-#: git-submodule.sh:382
+#: git-submodule.sh:452
#, 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 Repository in '$sm_path' der Staging-Area hinzu."
-#: git-submodule.sh:384
+#: git-submodule.sh:454
#, 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"
+msgstr "'$sm_path' existiert bereits und ist kein gültiges Git-Repository"
-#: git-submodule.sh:392
+#: git-submodule.sh:462
#, sh-format
msgid "A git directory for '$sm_name' is found locally with remote(s):"
msgstr ""
-"Ein Git-Verzeichnis für '$sm_name' wurde lokal gefunden mit den Fernarchiv"
-"(en):"
+"Ein Git-Verzeichnis für '$sm_name' wurde lokal gefunden mit den Remote-"
+"Repositories:"
-#: git-submodule.sh:394
+#: git-submodule.sh:464
#, sh-format
msgid ""
"If you want to reuse this local git directory instead of cloning again from"
@@ -9749,15 +10402,15 @@ msgstr ""
"Wenn Sie dieses lokale Git-Verzeichnis wiederverwenden möchtest, anstatt "
"erneut zu klonen"
-#: git-submodule.sh:396
+#: git-submodule.sh:466
#, sh-format
msgid ""
"use the '--force' option. If the local git directory is not the correct repo"
msgstr ""
"benutzen Sie die Option '--force'. Wenn das lokale Git-Verzeichnis nicht das "
-"korrekte Projektarchiv ist"
+"korrekte Repository ist"
-#: git-submodule.sh:397
+#: git-submodule.sh:467
#, sh-format
msgid ""
"or you are unsure what this means choose another name with the '--name' "
@@ -9766,156 +10419,315 @@ msgstr ""
"oder Sie sich unsicher sind, was das bedeutet, wählen Sie einen anderen "
"Namenmit der Option '--name'."
-#: git-submodule.sh:399
+#: git-submodule.sh:469
#, sh-format
msgid "Reactivating local git directory for submodule '$sm_name'."
-msgstr "Reaktiviere lokales Git-Verzeichnis für Unterprojekt '$sm_name'."
+msgstr "Reaktiviere lokales Git-Verzeichnis für Submodul '$sm_name'."
-#: git-submodule.sh:411
+#: git-submodule.sh:481
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
-msgstr "Unfähig Unterprojekt '$sm_path' auszuchecken"
+msgstr "Unfähig Submodul '$sm_path' auszuchecken"
-#: git-submodule.sh:416
+#: git-submodule.sh:486
#, sh-format
msgid "Failed to add submodule '$sm_path'"
-msgstr "Hinzufügen von Unterprojekt '$sm_path' fehlgeschlagen"
+msgstr "Hinzufügen von Submodul '$sm_path' fehlgeschlagen"
-#: git-submodule.sh:425
+#: git-submodule.sh:495
#, sh-format
msgid "Failed to register submodule '$sm_path'"
-msgstr "Registierung von Unterprojekt '$sm_path' fehlgeschlagen"
+msgstr "Fehler beim Eintragen von Submodul '$sm_path' in die Konfiguration."
-#: git-submodule.sh:468
+#: git-submodule.sh:539
#, sh-format
-msgid "Entering '$prefix$sm_path'"
-msgstr "Betrete '$prefix$sm_path'"
+msgid "Entering '$prefix$displaypath'"
+msgstr "Betrete '$prefix$displaypath'"
-#: git-submodule.sh:482
+#: git-submodule.sh:554
#, sh-format
-msgid "Stopping at '$sm_path'; script returned non-zero status."
-msgstr "Stoppe bei '$sm_path'; Skript gab nicht-Null Status zurück."
+msgid "Stopping at '$prefix$displaypath'; script returned non-zero status."
+msgstr "Stoppe bei '$prefix$displaypath'; Skript gab nicht-Null Status zurück."
-#: git-submodule.sh:526
+#: git-submodule.sh:600
#, 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"
+msgid "No url found for submodule path '$displaypath' in .gitmodules"
+msgstr "Keine URL für Submodul-Pfad '$displaypath' in .gitmodules gefunden"
-#: git-submodule.sh:535
+#: git-submodule.sh:609
#, sh-format
-msgid "Failed to register url for submodule path '$sm_path'"
-msgstr "Registrierung der URL für Unterprojekt-Pfad '$sm_path' fehlgeschlagen"
+msgid "Failed to register url for submodule path '$displaypath'"
+msgstr ""
+"Fehler beim Eintragen der URL für Submodul-Pfad '$displaypath' in die "
+"Konfiguration."
-#: git-submodule.sh:537
+#: git-submodule.sh:611
#, sh-format
-msgid "Submodule '$name' ($url) registered for path '$sm_path'"
-msgstr "Unterprojekt '$name' ($url) ist für Pfad '$sm_path' registriert"
+msgid "Submodule '$name' ($url) registered for path '$displaypath'"
+msgstr ""
+"Submodul '$name' ($url) für Pfad '$displaypath' in die Konfiguration "
+"eingetragen."
-#: git-submodule.sh:545
+#: git-submodule.sh:619
#, sh-format
-msgid "Failed to register update mode for submodule path '$sm_path'"
+msgid "Failed to register update mode for submodule path '$displaypath'"
msgstr ""
-"Registrierung des Aktualisierungsmodus für Unterprojekt-Pfad '$sm_path' "
-"fehlgeschlagen"
+"Fehler bei Änderung des Aktualisierungsmodus für Submodul-Pfad "
+"'$displaypath' in der Konfiguration."
+
+#: git-submodule.sh:656
+#, sh-format
+msgid "Use '.' if you really want to deinitialize all submodules"
+msgstr ""
+"Verwenden Sie '.' wenn Sie wirklich alle Submodule\n"
+"deinitialisieren möchten."
+
+#: git-submodule.sh:673
+#, sh-format
+msgid "Submodule work tree '$displaypath' contains a .git directory"
+msgstr ""
+"Arbeitsverzeichnis des Submoduls in '$displaypath' enthält ein .git-"
+"Verzeichnis"
+
+#: git-submodule.sh:674
+#, sh-format
+msgid ""
+"(use 'rm -rf' if you really want to remove it including all of its history)"
+msgstr ""
+"(benutzen Sie 'rm -rf' wenn Sie dieses Submodul wirklich mitsamt\n"
+"seiner Historie löschen möchten)"
+
+#: git-submodule.sh:680
+#, sh-format
+msgid ""
+"Submodule work tree '$displaypath' contains local modifications; use '-f' to "
+"discard them"
+msgstr ""
+"Arbeitsverzeichnis von Submodul in '$displaypath' enthält lokale Änderungen; "
+"verwenden Sie '-f' um diese zu verwerfen"
+
+#: git-submodule.sh:683
+#, sh-format
+msgid "Cleared directory '$displaypath'"
+msgstr "Verzeichnis '$displaypath' bereinigt."
+
+#: git-submodule.sh:684
+#, sh-format
+msgid "Could not remove submodule work tree '$displaypath'"
+msgstr ""
+"Konnte Arbeitsverzeichnis des Submoduls in '$displaypath' nicht löschen."
+
+#: git-submodule.sh:687
+#, sh-format
+msgid "Could not create empty submodule directory '$displaypath'"
+msgstr ""
+"Konnte kein leeres Verzeichnis für Submodul in '$displaypath' erstellen."
+
+#: git-submodule.sh:696
+#, sh-format
+msgid "Submodule '$name' ($url) unregistered for path '$displaypath'"
+msgstr ""
+"Submodul '$name' ($url) für Pfad '$displaypath' wurde aus der Konfiguration "
+"entfernt."
-#: git-submodule.sh:649
+#: git-submodule.sh:811
#, sh-format
msgid ""
-"Submodule path '$sm_path' not initialized\n"
+"Submodule path '$displaypath' not initialized\n"
"Maybe you want to use 'update --init'?"
msgstr ""
-"Unterprojekt-Pfad '$sm_path' ist nicht initialisiert\n"
+"Submodul-Pfad '$displaypath' ist nicht initialisiert.\n"
"Vielleicht möchten Sie 'update --init' benutzen?"
-#: git-submodule.sh:662
+#: git-submodule.sh:824
#, sh-format
-msgid "Unable to find current revision in submodule path '$sm_path'"
-msgstr "Konnte aktuelle Revision in Unterprojekt-Pfad '$sm_path' nicht finden"
+msgid "Unable to find current revision in submodule path '$displaypath'"
+msgstr "Konnte aktuellen Commit in Submodul-Pfad '$displaypath' nicht finden."
-#: git-submodule.sh:671 git-submodule.sh:695
+#: git-submodule.sh:833
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
-msgstr "Konnte in Unterprojekt-Pfad '$sm_path' nicht anfordern"
+msgstr "Konnte \"fetch\" in Submodul-Pfad '$sm_path' nicht ausführen"
+
+#: git-submodule.sh:857
+#, sh-format
+msgid "Unable to fetch in submodule path '$displaypath'"
+msgstr "Konnte \"fetch\" in Submodul-Pfad '$displaypath' nicht ausführen"
+
+#: git-submodule.sh:871
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$displaypath'"
+msgstr "Rebase auf '$sha1' in Submodul-Pfad '$displaypath' nicht möglich"
-#: git-submodule.sh:709
+#: git-submodule.sh:872
#, sh-format
-msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
-msgstr "Neuaufbau von '$sha1' in Unterprojekt-Pfad '$sm_path' nicht möglich"
+msgid "Submodule path '$displaypath': rebased into '$sha1'"
+msgstr "Submodul-Pfad '$displaypath': Rebase auf '$sha1'"
-#: git-submodule.sh:710
+#: git-submodule.sh:877
#, sh-format
-msgid "Submodule path '$sm_path': rebased into '$sha1'"
-msgstr "Unterprojekt-Pfad '$sm_path': neu aufgebaut in '$sha1'"
+msgid "Unable to merge '$sha1' in submodule path '$displaypath'"
+msgstr "Merge von '$sha1' in Submodul-Pfad '$displaypath' fehlgeschlagen"
-#: git-submodule.sh:715
+#: git-submodule.sh:878
#, sh-format
-msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
+msgid "Submodule path '$displaypath': merged in '$sha1'"
+msgstr "Submodul-Pfad '$displaypath': zusammengeführt in '$sha1'"
+
+#: git-submodule.sh:883
+#, sh-format
+msgid ""
+"Execution of '$command $sha1' failed in submodule path '$prefix$sm_path'"
msgstr ""
-"Zusammenführung von '$sha1' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen"
+"Ausführung von '$command $sha1' in Submodul-Pfad '$prefix$sm_path' "
+"fehlgeschlagen"
-#: git-submodule.sh:716
+#: git-submodule.sh:884
#, sh-format
-msgid "Submodule path '$sm_path': merged in '$sha1'"
-msgstr "Unterprojekt-Pfad '$sm_path': zusammengeführt in '$sha1'"
+msgid "Submodule path '$prefix$sm_path': '$command $sha1'"
+msgstr "Submodul-Pfad '$prefix$sm_path': '$command $sha1'"
-#: git-submodule.sh:721
+#: git-submodule.sh:889
#, sh-format
-msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
-msgstr "Konnte '$sha1' in Unterprojekt-Pfad '$sm_path' nicht auschecken."
+msgid "Unable to checkout '$sha1' in submodule path '$displaypath'"
+msgstr "Konnte '$sha1' in Submodul-Pfad '$displaypath' nicht auschecken."
-#: git-submodule.sh:722
+#: git-submodule.sh:890
#, sh-format
-msgid "Submodule path '$sm_path': checked out '$sha1'"
-msgstr "Unterprojekt-Pfad: '$sm_path': '$sha1' ausgecheckt"
+msgid "Submodule path '$displaypath': checked out '$sha1'"
+msgstr "Submodul-Pfad: '$displaypath': '$sha1' ausgecheckt"
-#: git-submodule.sh:744 git-submodule.sh:1066
+#: git-submodule.sh:917
#, sh-format
-msgid "Failed to recurse into submodule path '$sm_path'"
-msgstr "Fehler bei Rekursion in Unterprojekt-Pfad '$sm_path'"
+msgid "Failed to recurse into submodule path '$displaypath'"
+msgstr "Fehler bei Rekursion in Submodul-Pfad '$displaypath'"
-#: git-submodule.sh:852
+#: git-submodule.sh:1025
msgid "The --cached option cannot be used with the --files option"
msgstr ""
"Die Optionen --cached und --files können nicht gemeinsam verwendet werden."
#. unexpected type
-#: git-submodule.sh:892
+#: git-submodule.sh:1066
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr "unerwarteter Modus $mod_dst"
-#: git-submodule.sh:910
+#: git-submodule.sh:1086
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_src"
-msgstr " Warnung: $name beinhaltet nicht Version $sha1_src"
+msgid " Warn: $display_name doesn't contain commit $sha1_src"
+msgstr " Warnung: $display_name beinhaltet nicht Commit $sha1_src"
-#: git-submodule.sh:913
+#: git-submodule.sh:1089
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_dst"
-msgstr " Warnung: $name beinhaltet nicht Version $sha1_dst"
+msgid " Warn: $display_name doesn't contain commit $sha1_dst"
+msgstr " Warnung: $display_name beinhaltet nicht Commit $sha1_dst"
-#: git-submodule.sh:916
+#: git-submodule.sh:1092
#, sh-format
-msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgid " Warn: $display_name doesn't contain commits $sha1_src and $sha1_dst"
msgstr ""
-" Warnung: $name beinhaltet nicht die Versionen $sha1_src und $sha1_dst"
+" Warnung: $display_name beinhaltet nicht die Commits $sha1_src und $sha1_dst"
-#: git-submodule.sh:941
+#: git-submodule.sh:1117
msgid "blob"
msgstr "Blob"
-#: git-submodule.sh:979
+#: git-submodule.sh:1155
msgid "Submodules changed but not updated:"
-msgstr "Unterprojekte geändert, aber nicht aktualisiert:"
+msgstr "Submodule geändert, aber nicht aktualisiert:"
-#: git-submodule.sh:981
+#: git-submodule.sh:1157
msgid "Submodule changes to be committed:"
-msgstr "Änderungen in Unterprojekt zum Eintragen:"
+msgstr "Änderungen in Submodul zum Committen:"
+
+#: git-submodule.sh:1242
+#, sh-format
+msgid "Failed to recurse into submodule path '$sm_path'"
+msgstr "Fehler bei Rekursion in Submodul-Pfad '$sm_path'"
-#: git-submodule.sh:1129
+#: git-submodule.sh:1306
#, sh-format
-msgid "Synchronizing submodule url for '$prefix$sm_path'"
-msgstr "Synchronisiere Unterprojekt-URL für '$prefix$sm_path'"
+msgid "Synchronizing submodule url for '$displaypath'"
+msgstr "Synchronisiere Submodul-URL für '$displaypath'"
+
+#~ msgid " (fix conflicts and then run \"git am --resolved\")"
+#~ msgstr ""
+#~ " (beheben Sie die Konflikte und führen Sie dann \"git am --resolved\" "
+#~ "aus)"
+
+#~ msgid " (all conflicts fixed: run \"git commit\")"
+#~ msgstr " (alle Konflikte behoben: führen Sie \"git commit\" aus)"
+
+#~ msgid "more than %d trees given: '%s'"
+#~ msgstr "Mehr als %d \"Tree\"-Objekte angegeben: '%s'"
+
+#~ msgid "You cannot combine --no-ff with --ff-only."
+#~ msgstr "Sie können --no-ff nicht mit --ff--only kombinieren."
+
+#~ msgid ""
+#~ "submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+#~ "(use 'rm -rf' if you really want to remove it including all of its "
+#~ "history)"
+#~ msgstr ""
+#~ "Submodul '%s' (oder ein geschachteltes Submodul hiervon) verwendet\n"
+#~ "ein .git-Verzeichnis (benutzen Sie 'rm -rf' wenn Sie dieses wirklich "
+#~ "mitsamt\n"
+#~ "seiner Historie löschen möchten)"
+
+#~ msgid ""
+#~ "'%s' has changes staged in the index\n"
+#~ "(use --cached to keep the file, or -f to force removal)"
+#~ msgstr ""
+#~ "'%s' hat zum Commit vorgemerkte Änderungen\n"
+#~ "(benutzen Sie --cached um die Datei zu behalten, oder -f um die "
+#~ "Entfernung zu erzwingen)"
+
+#~ msgid "show commits where no parent comes before its children"
+#~ msgstr ""
+#~ "zeigt Commits, bei denen kein Eltern-Commit vor seinem Kind-Commit kommt"
+
+#~ msgid "show the HEAD reference"
+#~ msgstr "zeigt Referenz von HEAD"
+
+#~ msgid "Unable to fetch in submodule path '$prefix$sm_path'"
+#~ msgstr "Konnte \"fetch\" in Submodul-Pfad '$prefix$sm_path' nicht ausführen"
+
+#~ msgid "Failed to recurse into submodule path '$prefix$sm_path'"
+#~ msgstr "Fehler bei Rekursion in Submodul-Pfad '$prefix$sm_path'"
+
+#~ msgid "It took %.2f seconds to enumerate untracked files. 'status -uno'"
+#~ msgstr ""
+#~ "Es dauerte %.2f Sekunden die unbeobachteten Dateien zu bestimmen.'status -"
+#~ "uno'"
+
+#~ msgid "may speed it up, but you have to be careful not to forget to add"
+#~ msgstr "könnte das beschleunigen, aber Sie müssen darauf achten, neue"
+
+#~ msgid "new files yourself (see 'git help status')."
+#~ msgstr "Dateien selbstständig hinzuzufügen (siehe 'git help status')."
+
+#~ msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+#~ msgstr ""
+#~ "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] "
+#~ "[<Versionsidentifikation>... ]"
+
+#~ msgid "See 'git help <command>' for more information on a specific command."
+#~ msgstr ""
+#~ "Siehe 'git help <Kommando>' für weitere Informationen zu einem "
+#~ "spezifischen Kommando"
+
+#~ msgid "use any ref in .git/refs"
+#~ msgstr "verwendet alle Referenzen in .git/refs"
+
+#~ msgid "use any tag in .git/refs/tags"
+#~ msgstr "verwendet alle Markierungen in .git/refs/tags"
+
+#~ msgid "bad object %s"
+#~ msgstr "ungültiges Objekt %s"
+
+#~ msgid "bogus committer info %s"
+#~ msgstr "unechte Einreicher-Informationen %s"
#~ msgid "can't fdopen 'show' output fd"
#~ msgstr "konnte Datei-Deskriptor für Ausgabe von 'show' nicht öffnen"
diff --git a/po/fr.po b/po/fr.po
new file mode 100644
index 0000000..2cdb6f9
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,9823 @@
+# French translations for Git.
+# Copyright (C) 2013 Jean-Noël Avila <jn.avila@free.fr>
+# This file is distributed under the same license as the Git package.
+# Jean-Noël Avila <jn.avila@free.fr>, 2013.
+# Sébastien Helleu <flashcode@flashtux.org>, 2013.
+#
+# French translations of common Git words used in this file:
+#
+# English | French
+# -----------------+---------------------------------
+# #NN | n°NN
+# a commit | un commit
+# backward |
+# compatibility | rétrocompatibilité
+# bare repository | dépôt nu
+# bisect | bissection
+# blob | blob
+# bug | bogue
+# bundle | colis
+# cherry-pick | picorer
+# dangling | en suspens
+# debugging | débogage
+# fast-forward | avance rapide
+# fast-forwarded | mis à jour en avance rapide
+# glob | glob
+# hash | hachage
+# HEAD | HEAD (genre féminin)
+# hook | hook
+# hunk | section
+# merge | fusion
+# pattern | motif
+# repository | dépôt
+# remote | distante (ou serveur distant)
+# revision | révision
+# stash | remisage
+# tag | étiquette
+# template | modèle
+# to checkout | extraire
+# to commit | valider
+# to fetch | rapatrier
+# to prune | élaguer
+# to push | pousser
+# to rebase | rebaser
+# to stash | remiser
+# to track | suivre
+# to unstage | désindexer
+# tree-ish | arbre
+# upstream | amont
+# worktree / |
+# work(ing) tree | copie de travail
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: git\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
+"POT-Creation-Date: 2013-04-30 08:25+0800\n"
+"PO-Revision-Date: 2013-08-27 19:43+0200\n"
+"Last-Translator: Sébastien Helleu <flashcode@flashtux.org>\n"
+"Language-Team: Jean-Noël Avila <jn.avila@free.fr>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n<=1 ?0 : 1;\n"
+"X-Generator: Poedit 1.5.4\n"
+
+#: advice.c:53
+#, c-format
+msgid "hint: %.*s\n"
+msgstr "astuce: %.*s\n"
+
+#.
+#. * Message used both when 'git commit' fails and when
+#. * other commands doing a merge do.
+#.
+#: advice.c:83
+msgid ""
+"Fix them up in the work tree,\n"
+"and then use 'git add/rm <file>' as\n"
+"appropriate to mark resolution and make a commit,\n"
+"or use 'git commit -a'."
+msgstr ""
+"Corrigez-les dans la copie de travail,\n"
+"et utilisez 'git add/rm <fichier>' si\n"
+"nécessaire pour marquer la résolution et valider,\n"
+"ou utilisez 'git commit -a'."
+
+#: archive.c:10
+msgid "git archive [options] <tree-ish> [<path>...]"
+msgstr "git archive [options] <arbre> [<chemin>...]"
+
+#: 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 <dépôt> [--exec <commande>] [options] <arbre> [<chemin>...]"
+
+#: archive.c:13
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr "git archive --remote <dépôt> [--exec <commande>] --list"
+
+#: archive.c:323
+msgid "fmt"
+msgstr "fmt"
+
+#: archive.c:323
+msgid "archive format"
+msgstr "format d'archive"
+
+#: archive.c:324 builtin/log.c:1126
+msgid "prefix"
+msgstr "préfixe"
+
+#: archive.c:325
+msgid "prepend prefix to each pathname in the archive"
+msgstr "préfixer chaque chemin de fichier dans l'archive"
+
+#: archive.c:326 builtin/archive.c:88 builtin/blame.c:2371
+#: builtin/blame.c:2372 builtin/config.c:55 builtin/fast-export.c:665
+#: builtin/fast-export.c:667 builtin/grep.c:715 builtin/hash-object.c:77
+#: builtin/ls-files.c:490 builtin/ls-files.c:493 builtin/notes.c:536
+#: builtin/notes.c:693 builtin/read-tree.c:107 parse-options.h:149
+msgid "file"
+msgstr "fichier"
+
+#: archive.c:327 builtin/archive.c:89
+msgid "write the archive to this file"
+msgstr "écrire l'archive dans ce fichier"
+
+#: archive.c:329
+msgid "read .gitattributes in working directory"
+msgstr "lire .gitattributes dans le répertoire de travail"
+
+#: archive.c:330
+msgid "report archived files on stderr"
+msgstr "afficher les fichiers archivés sur stderr"
+
+#: archive.c:331
+msgid "store only"
+msgstr "stockage seulement"
+
+#: archive.c:332
+msgid "compress faster"
+msgstr "compression rapide"
+
+#: archive.c:340
+msgid "compress better"
+msgstr "compression efficace"
+
+#: archive.c:343
+msgid "list supported archive formats"
+msgstr "lister les formats d'archive supportés"
+
+#: archive.c:345 builtin/archive.c:90 builtin/clone.c:86
+msgid "repo"
+msgstr "dépôt"
+
+#: archive.c:346 builtin/archive.c:91
+msgid "retrieve the archive from remote repository <repo>"
+msgstr "récupérer l'archive depuis le dépôt distant <dépôt>"
+
+#: archive.c:347 builtin/archive.c:92 builtin/notes.c:615
+msgid "command"
+msgstr "commande"
+
+#: archive.c:348 builtin/archive.c:93
+msgid "path to the remote git-upload-archive command"
+msgstr "chemin vers la commande distante git-upload-archive"
+
+#: attr.c:259
+msgid ""
+"Negative patterns are ignored in git attributes\n"
+"Use '\\!' for literal leading exclamation."
+msgstr ""
+"Les motifs de négation sont ignorés dans les attributs git\n"
+"Utilisez '\\!' pour un point d'exclamation littéral."
+
+#: branch.c:60
+#, c-format
+msgid "Not setting branch %s as its own upstream."
+msgstr "La branche %s ne peut pas être sa propre branche amont."
+
+#: branch.c:82
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s by rebasing."
+msgstr "La branche %s est paramétrée pour suivre la branche distante %s de %s en rebasant."
+
+#: branch.c:83
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s."
+msgstr "La branche %s est paramétrée pour suivre la branche distante %s depuis %s."
+
+#: branch.c:87
+#, c-format
+msgid "Branch %s set up to track local branch %s by rebasing."
+msgstr "La branche %s est paramétrée pour suivre la branche locale %s en rebasant."
+
+#: branch.c:88
+#, c-format
+msgid "Branch %s set up to track local branch %s."
+msgstr "La branche %s est paramétrée pour suivre la branche locale %s."
+
+#: branch.c:92
+#, c-format
+msgid "Branch %s set up to track remote ref %s by rebasing."
+msgstr "La branche %s est paramétrée pour suivre la référence distante %s en rebasant."
+
+#: branch.c:93
+#, c-format
+msgid "Branch %s set up to track remote ref %s."
+msgstr "La branche %s est paramétrée pour suivre la référence distante %s."
+
+#: branch.c:97
+#, c-format
+msgid "Branch %s set up to track local ref %s by rebasing."
+msgstr "La branche %s est paramétrée pour suivre la référence locale %s en rebasant."
+
+#: branch.c:98
+#, c-format
+msgid "Branch %s set up to track local ref %s."
+msgstr "La branche %s est paramétrée pour suivre la référence locale %s."
+
+#: branch.c:118
+#, c-format
+msgid "Tracking not set up: name too long: %s"
+msgstr "Suivi de branche non paramétré : le nom est trop long : %s"
+
+#: branch.c:137
+#, c-format
+msgid "Not tracking: ambiguous information for ref %s"
+msgstr "Pas de suivi : information ambiguë pour la référence %s"
+
+#: branch.c:182
+#, c-format
+msgid "'%s' is not a valid branch name."
+msgstr "'%s' n'est pas un nom de branche valide."
+
+#: branch.c:187
+#, c-format
+msgid "A branch named '%s' already exists."
+msgstr "Une branche nommée '%s' existe déjà."
+
+#: branch.c:195
+msgid "Cannot force update the current branch."
+msgstr "Impossible de forcer la mise à jour de la branche courante."
+
+#: branch.c:201
+#, c-format
+msgid "Cannot setup tracking information; starting point '%s' is not a branch."
+msgstr "Impossible de paramétrer le suivi de branche ; le point de départ '%s' n'est pas une branche."
+
+#: branch.c:203
+#, c-format
+msgid "the requested upstream branch '%s' does not exist"
+msgstr "la branche amont demandée '%s' n'existe pas"
+
+#: branch.c:205
+msgid ""
+"\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push."
+msgstr ""
+"\n"
+"Si vous comptez baser votre travail sur une branche\n"
+"amont qui existe déjà sur le serveur distant, vous pourriez\n"
+"devoir lancer \"git fetch\" pour la récupérer.\n"
+"\n"
+"Si vous comptez pousser une nouvelle branche locale qui suivra\n"
+"sa jumelle distante, vous souhaiterez utiliser \"git push -u\"\n"
+"pour paramétrer le suivi distant en même temps que vous poussez."
+
+#: branch.c:250
+#, c-format
+msgid "Not a valid object name: '%s'."
+msgstr "Nom d'objet invalide : '%s'."
+
+#: branch.c:270
+#, c-format
+msgid "Ambiguous object name: '%s'."
+msgstr "Nom d'objet ambigu : '%s'."
+
+#: branch.c:275
+#, c-format
+msgid "Not a valid branch point: '%s'."
+msgstr "Point d'embranchement invalide : '%s'."
+
+#: branch.c:281
+msgid "Failed to lock ref for update"
+msgstr "Échec du verrouillage de la référence pour mise à jour"
+
+#: branch.c:299
+msgid "Failed to write ref"
+msgstr "Échec de l'écriture de la référence"
+
+#: bundle.c:36
+#, c-format
+msgid "'%s' does not look like a v2 bundle file"
+msgstr "'%s' ne semble pas être un fichier bundle v2"
+
+#: bundle.c:63
+#, c-format
+msgid "unrecognized header: %s%s (%d)"
+msgstr "en-tête non reconnu : %s%s (%d)"
+
+#: bundle.c:89 builtin/commit.c:676
+#, c-format
+msgid "could not open '%s'"
+msgstr "impossible d'ouvrir '%s'"
+
+#: bundle.c:140
+msgid "Repository lacks these prerequisite commits:"
+msgstr "Le dépôt ne dispose pas des commits prérequis :"
+
+#: bundle.c:164 sequencer.c:651 sequencer.c:1101 builtin/log.c:300
+#: builtin/log.c:770 builtin/log.c:1344 builtin/log.c:1570 builtin/merge.c:349
+#: builtin/shortlog.c:155
+msgid "revision walk setup failed"
+msgstr "échec de la préparation du parcours des révisions"
+
+#: bundle.c:186
+#, c-format
+msgid "The bundle contains this ref:"
+msgid_plural "The bundle contains these %d refs:"
+msgstr[0] "Le colis contient cette référence :"
+msgstr[1] "Le colis contient ces %d références :"
+
+#: bundle.c:193
+msgid "The bundle records a complete history."
+msgstr "Le colis enregistre l'historique complet."
+
+#: bundle.c:195
+#, c-format
+msgid "The bundle requires this ref:"
+msgid_plural "The bundle requires these %d refs:"
+msgstr[0] "Le colis exige cette référence :"
+msgstr[1] "Le colis exige ces %d références :"
+
+#: bundle.c:294
+msgid "rev-list died"
+msgstr "rev-list a disparu"
+
+#: bundle.c:300 builtin/log.c:1255 builtin/shortlog.c:258
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr "argument non reconnu : %s"
+
+#: bundle.c:335
+#, c-format
+msgid "ref '%s' is excluded by the rev-list options"
+msgstr "la référence '%s' est exclue par les options de rev-list"
+
+#: bundle.c:380
+msgid "Refusing to create empty bundle."
+msgstr "Refus de créer un colis vide."
+
+#: bundle.c:398
+msgid "Could not spawn pack-objects"
+msgstr "Impossible de créer des objets groupés"
+
+#: bundle.c:416
+msgid "pack-objects died"
+msgstr "les objets groupés ont disparu"
+
+#: bundle.c:419
+#, c-format
+msgid "cannot create '%s'"
+msgstr "impossible de créer '%s'"
+
+#: bundle.c:441
+msgid "index-pack died"
+msgstr "l'index de groupe a disparu"
+
+#: commit.c:50
+#, c-format
+msgid "could not parse %s"
+msgstr "impossible d'analyser %s"
+
+#: commit.c:52
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr "%s %s n'est pas un commit !"
+
+#: compat/obstack.c:406 compat/obstack.c:408
+msgid "memory exhausted"
+msgstr "plus de mémoire"
+
+#: connected.c:39
+msgid "Could not run 'git rev-list'"
+msgstr "Impossible de lancer 'git rev-list'"
+
+#: connected.c:48
+#, c-format
+msgid "failed write to rev-list: %s"
+msgstr "impossible d'écrire dans la rev-list : %s"
+
+#: connected.c:56
+#, c-format
+msgid "failed to close rev-list's stdin: %s"
+msgstr "impossible de fermer le stdin du rev-list : %s"
+
+#: date.c:95
+msgid "in the future"
+msgstr "dans le futur"
+
+#: date.c:101
+#, c-format
+msgid "%lu second ago"
+msgid_plural "%lu seconds ago"
+msgstr[0] "il y a %lu seconde"
+msgstr[1] "il y a %lu secondes"
+
+#: date.c:108
+#, c-format
+msgid "%lu minute ago"
+msgid_plural "%lu minutes ago"
+msgstr[0] "il y a %lu minute"
+msgstr[1] "il y a %lu minutes"
+
+#: date.c:115
+#, c-format
+msgid "%lu hour ago"
+msgid_plural "%lu hours ago"
+msgstr[0] "il y a %lu heure"
+msgstr[1] "il y a %lu heures"
+
+#: date.c:122
+#, c-format
+msgid "%lu day ago"
+msgid_plural "%lu days ago"
+msgstr[0] "il y a %lu jour"
+msgstr[1] "il y a %lu jours"
+
+#: date.c:128
+#, c-format
+msgid "%lu week ago"
+msgid_plural "%lu weeks ago"
+msgstr[0] "il y a %lu semaine"
+msgstr[1] "il y a %lu semaines"
+
+#: date.c:135
+#, c-format
+msgid "%lu month ago"
+msgid_plural "%lu months ago"
+msgstr[0] "il y a %lu mois"
+msgstr[1] "il y a %lu mois"
+
+#: date.c:146
+#, c-format
+msgid "%lu year"
+msgid_plural "%lu years"
+msgstr[0] "%lu an"
+msgstr[1] "%lu ans"
+
+#: date.c:149
+#, c-format
+msgid "%s, %lu month ago"
+msgid_plural "%s, %lu months ago"
+msgstr[0] "il y a %s et %lu mois"
+msgstr[1] "il y a %s et %lu mois"
+
+#: date.c:154 date.c:159
+#, c-format
+msgid "%lu year ago"
+msgid_plural "%lu years ago"
+msgstr[0] "il y a %lu an"
+msgstr[1] "il y a %lu ans"
+
+#: diff.c:112
+#, c-format
+msgid " Failed to parse dirstat cut-off percentage '%s'\n"
+msgstr " Impossible d'analyser le pourcentage de modification de dirstat '%s'\n"
+
+#: diff.c:117
+#, c-format
+msgid " Unknown dirstat parameter '%s'\n"
+msgstr " Paramètre dirstat inconnu '%s'\n"
+
+#: diff.c:210
+#, c-format
+msgid "Unknown value for 'diff.submodule' config variable: '%s'"
+msgstr "Valeur inconnue pour la variable de configuration 'diff.submodule' : '%s'"
+
+#: diff.c:260
+#, c-format
+msgid ""
+"Found errors in 'diff.dirstat' config variable:\n"
+"%s"
+msgstr "Erreurs dans la variable de configuration 'diff.dirstat' :\n"
+"%s"
+
+#: diff.c:3481
+#, c-format
+msgid ""
+"Failed to parse --dirstat/-X option parameter:\n"
+"%s"
+msgstr "Impossible d'analyser le paramètre de l'option --dirstat/-X :\n"
+"%s"
+
+#: diff.c:3495
+#, c-format
+msgid "Failed to parse --submodule option parameter: '%s'"
+msgstr "Impossible d'analyser le paramètre de l'option --submodule : '%s'"
+
+#: gpg-interface.c:59 gpg-interface.c:131
+msgid "could not run gpg."
+msgstr "impossible de lancer gpg."
+
+#: gpg-interface.c:71
+msgid "gpg did not accept the data"
+msgstr "gpg n'a pas accepté les données"
+
+#: gpg-interface.c:82
+msgid "gpg failed to sign the data"
+msgstr "gpg n'a pas pu signer les données"
+
+#: gpg-interface.c:115
+#, c-format
+msgid "could not create temporary file '%s': %s"
+msgstr "impossible de créer un fichier temporaire '%s' : %s"
+
+#: gpg-interface.c:118
+#, c-format
+msgid "failed writing detached signature to '%s': %s"
+msgstr "impossible d'écrire la signature détachée dans '%s' : %s"
+
+#: grep.c:1623
+#, c-format
+msgid "'%s': unable to read %s"
+msgstr "'%s' : lecture de %s impossible"
+
+#: grep.c:1640
+#, c-format
+msgid "'%s': %s"
+msgstr "'%s' : %s"
+
+#: grep.c:1651
+#, c-format
+msgid "'%s': short read %s"
+msgstr "'%s' : lecture tronquée %s"
+
+#: help.c:212
+#, c-format
+msgid "available git commands in '%s'"
+msgstr "commandes git disponibles dans '%s'"
+
+#: help.c:219
+msgid "git commands available from elsewhere on your $PATH"
+msgstr "commandes git disponibles depuis un autre endroit de votre $PATH"
+
+#: help.c:235
+msgid "The most commonly used git commands are:"
+msgstr "Les commandes git les plus utilisées sont :"
+
+#: help.c:292
+#, c-format
+msgid ""
+"'%s' appears to be a git command, but we were not\n"
+"able to execute it. Maybe git-%s is broken?"
+msgstr ""
+"'%s' semble être une commande git, mais elle n'a pas pu\n"
+"être exécutée. Peut-être git-%s est-elle cassée ?"
+
+#: help.c:349
+msgid "Uh oh. Your system reports no Git commands at all."
+msgstr "Ahem. Votre système n'indique aucune commande Git."
+
+#: help.c:371
+#, 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 "ATTENTION : vous avez invoqué une commande Git nommée '%s' qui n'existe pas.\n"
+"Poursuite en supposant que vous avez voulu dire '%s'"
+
+#: help.c:376
+#, c-format
+msgid "in %0.1f seconds automatically..."
+msgstr "dans %0.1f secondes automatiquement..."
+
+#: help.c:383
+#, c-format
+msgid "git: '%s' is not a git command. See 'git --help'."
+msgstr "git : '%s' n'est pas une commande git. Voir 'git --help'."
+
+#: help.c:387
+msgid ""
+"\n"
+"Did you mean this?"
+msgid_plural ""
+"\n"
+"Did you mean one of these?"
+msgstr[0] "\n"
+"Vouliez-vous dire cela ?"
+msgstr[1] "\nVouliez-vous dire un de ceux-là ?"
+
+#: merge.c:56
+msgid "failed to read the cache"
+msgstr "impossible de lire le cache"
+
+#: merge.c:110 builtin/checkout.c:365 builtin/checkout.c:566
+#: builtin/clone.c:645
+msgid "unable to write new index file"
+msgstr "impossible d'écrire le nouveau fichier d'index"
+
+#: merge-recursive.c:190
+#, c-format
+msgid "(bad commit)\n"
+msgstr "(mauvais commit)\n"
+
+#: merge-recursive.c:206
+#, c-format
+msgid "addinfo_cache failed for path '%s'"
+msgstr "échec de addinfo_cache pour le chemin '%s'"
+
+#: merge-recursive.c:268
+msgid "error building trees"
+msgstr "erreur de construction des arbres"
+
+#: merge-recursive.c:672
+#, c-format
+msgid "failed to create path '%s'%s"
+msgstr "impossible de créer le chemin '%s' %s"
+
+#: merge-recursive.c:683
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "Suppression de %s pour faire de la place pour le sous-répertoire\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 ": peut-être un conflit D/F ?"
+
+#: merge-recursive.c:708
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr "refus de perdre le fichier non suivi '%s'"
+
+#: merge-recursive.c:748
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr "impossible de lire l'objet %s '%s'"
+
+#: merge-recursive.c:750
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr "blob attendu pour %s '%s'"
+
+#: merge-recursive.c:773 builtin/clone.c:313
+#, c-format
+msgid "failed to open '%s'"
+msgstr "échec à l'ouverture de '%s'"
+
+#: merge-recursive.c:781
+#, c-format
+msgid "failed to symlink '%s'"
+msgstr "échec à la création du lien symbolique '%s'"
+
+#: merge-recursive.c:784
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr "ne sait pas traiter %06o %s '%s'"
+
+#: merge-recursive.c:922
+msgid "Failed to execute internal merge"
+msgstr "Échec à l'exécution de la fusion interne"
+
+#: merge-recursive.c:926
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "Impossible d'ajouter %s à la base de données"
+
+#: merge-recursive.c:942
+msgid "unsupported object type in the tree"
+msgstr "type d'objet non supporté dans l'arbre"
+
+#: 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 "CONFLIT (%s/suppression) : %s supprimé dans %s et %s dans %s. Version %s de %s laissée dans l'arbre."
+
+#: 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 "CONFLIT (%s/suppression) : %s supprimé dans %s et %s dans %s. Version %s de %s laissée dans l'arbre dans le fichier %s."
+
+#: merge-recursive.c:1081
+msgid "rename"
+msgstr "renommage"
+
+#: merge-recursive.c:1081
+msgid "renamed"
+msgstr "renommé"
+
+#: merge-recursive.c:1137
+#, c-format
+msgid "%s is a directory in %s adding as %s instead"
+msgstr "%s est un répertoire dans %s ajouté plutôt comme %s"
+
+#: merge-recursive.c:1159
+#, c-format
+msgid ""
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
+msgstr "CONFLIT (renommage/renommage) : Renommage de \"%s\"->\"%s\" dans la branche \"%s\" et renommage \"%s\"->\"%s\" dans \"%s\"%s"
+
+#: merge-recursive.c:1164
+msgid " (left unresolved)"
+msgstr " (laissé non résolu)"
+
+#: merge-recursive.c:1218
+#, c-format
+msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
+msgstr "CONFLIT (renommage/renommage) : renommage '%s'->'%s' dans %s. Renommage '%s'->'%s' dans %s"
+
+#: merge-recursive.c:1248
+#, c-format
+msgid "Renaming %s to %s and %s to %s instead"
+msgstr "Renommage de %s en %s et de %s en %s à la place"
+
+#: merge-recursive.c:1447
+#, c-format
+msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
+msgstr "CONFLIT (renommage/ajout) : Renommage de %s->%s dans %s. %s ajouté dans %s"
+
+#: merge-recursive.c:1457
+#, c-format
+msgid "Adding merged %s"
+msgstr "Ajout de %s fusionné"
+
+#: merge-recursive.c:1462 merge-recursive.c:1660
+#, c-format
+msgid "Adding as %s instead"
+msgstr "Ajout plutôt comme %s"
+
+#: merge-recursive.c:1513
+#, c-format
+msgid "cannot read object %s"
+msgstr "impossible de lire l'objet %s"
+
+#: merge-recursive.c:1516
+#, c-format
+msgid "object %s is not a blob"
+msgstr "l'objet %s n'est pas un blob"
+
+#: merge-recursive.c:1564
+msgid "modify"
+msgstr "modification"
+
+#: merge-recursive.c:1564
+msgid "modified"
+msgstr "modifié"
+
+#: merge-recursive.c:1574
+msgid "content"
+msgstr "contenu"
+
+#: merge-recursive.c:1581
+msgid "add/add"
+msgstr "ajout/ajout"
+
+#: merge-recursive.c:1615
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "%s ignoré (fusion identique à l'existant)"
+
+#: merge-recursive.c:1629
+#, c-format
+msgid "Auto-merging %s"
+msgstr "Fusion automatique de %s"
+
+#: merge-recursive.c:1633 git-submodule.sh:1029
+msgid "submodule"
+msgstr "sous-module"
+
+#: merge-recursive.c:1634
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+msgstr "CONFLIT (%s) : Conflit de fusion dans %s"
+
+#: merge-recursive.c:1724
+#, c-format
+msgid "Removing %s"
+msgstr "Suppression de %s"
+
+#: merge-recursive.c:1749
+msgid "file/directory"
+msgstr "fichier/répertoire"
+
+#: merge-recursive.c:1755
+msgid "directory/file"
+msgstr "répertoire/fichier"
+
+#: merge-recursive.c:1760
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr "CONFLIT (%s) : Il y a un répertoire nommé %s dans %s. Ajout de %s comme %s"
+
+#: merge-recursive.c:1770
+#, c-format
+msgid "Adding %s"
+msgstr "Ajout de %s"
+
+#: merge-recursive.c:1787
+msgid "Fatal merge failure, shouldn't happen."
+msgstr "Échec fatal de fusion, qui ne devrait jamais arriver."
+
+#: merge-recursive.c:1806
+msgid "Already up-to-date!"
+msgstr "Déjà à jour !"
+
+#: merge-recursive.c:1815
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "échec de fusion des arbres %s et %s"
+
+#: merge-recursive.c:1845
+#, c-format
+msgid "Unprocessed path??? %s"
+msgstr "Chemin non traité ??? %s"
+
+#: merge-recursive.c:1890
+msgid "Merging:"
+msgstr "Fusion :"
+
+#: merge-recursive.c:1903
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] "%u ancêtre commun trouvé :"
+msgstr[1] "%u ancêtres communs trouvés :"
+
+#: merge-recursive.c:1940
+msgid "merge returned no commit"
+msgstr "la fusion n'a pas retourné de commit"
+
+#: merge-recursive.c:1997
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr "Impossible d'analyser l'objet '%s'"
+
+#: merge-recursive.c:2009 builtin/merge.c:658
+msgid "Unable to write index."
+msgstr "Impossible d'écrire l'index."
+
+#: object.c:195
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "impossible d'analyser l'objet : %s"
+
+#: parse-options.c:489
+msgid "..."
+msgstr "..."
+
+#: parse-options.c:507
+#, c-format
+msgid "usage: %s"
+msgstr "usage : %s"
+
+#. TRANSLATORS: the colon here should align with the
+#. one in "usage: %s" translation
+#: parse-options.c:511
+#, c-format
+msgid " or: %s"
+msgstr " ou : %s"
+
+#: parse-options.c:514
+#, c-format
+msgid " %s"
+msgstr " %s"
+
+#: parse-options.c:548
+msgid "-NUM"
+msgstr "-NUM"
+
+#: pathspec.c:83
+#, c-format
+msgid "Path '%s' is in submodule '%.*s'"
+msgstr "Le chemin '%s' est dans le sous-module '%.*s'"
+
+#: pathspec.c:99
+#, c-format
+msgid "'%s' is beyond a symbolic link"
+msgstr "'%s' est au delà d'un lien symbolique"
+
+#: remote.c:1781
+#, 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] "Votre branche est en avance sur '%s' de %d commit.\n"
+msgstr[1] "Votre branche est en avance sur '%s' de %d commits.\n"
+
+#: remote.c:1787
+msgid " (use \"git push\" to publish your local commits)\n"
+msgstr " (utilisez \"git push\" pour publier vos commits locaux)\n"
+
+#: remote.c:1790
+#, 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] "Votre branche est en retard sur '%s' de %d commit, et peut être mise à jour en avance rapide.\n"
+msgstr[1] "Votre branche est en retard sur '%s' de %d commits, et peut être mise à jour en avance rapide.\n"
+
+#: remote.c:1798
+msgid " (use \"git pull\" to update your local branch)\n"
+msgstr " (utilisez \"git pull\" pour mettre à jour votre branche locale)\n"
+
+#: remote.c:1801
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit each, respectively.\n"
+msgid_plural ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commits each, respectively.\n"
+msgstr[0] "Votre branche et '%s' ont divergé,\n"
+"et ont %d et %d commit différent chacune respectivement.\n"
+msgstr[1] "Votre branche et '%s' ont divergé,\n"
+"et ont %d et %d commits différents chacune respectivement.\n"
+
+#: remote.c:1811
+msgid " (use \"git pull\" to merge the remote branch into yours)\n"
+msgstr " (utilisez \"git pull\" pour fusionner la branche distante dans la vôtre)\n"
+
+#: sequencer.c:206 builtin/merge.c:776 builtin/merge.c:889 builtin/merge.c:999
+#: builtin/merge.c:1009
+#, c-format
+msgid "Could not open '%s' for writing"
+msgstr "Impossible d'ouvrir '%s' en écriture"
+
+#: sequencer.c:208 builtin/merge.c:335 builtin/merge.c:779
+#: builtin/merge.c:1001 builtin/merge.c:1014
+#, c-format
+msgid "Could not write to '%s'"
+msgstr "Impossible d'écrire dans '%s'"
+
+#: sequencer.c:229
+msgid ""
+"after resolving the conflicts, mark the corrected paths\n"
+"with 'git add <paths>' or 'git rm <paths>'"
+msgstr "après résolution des conflits, marquez les chemins corrigés\n"
+"avec 'git add <chemins>' ou 'git rm <chemins>'"
+
+#: sequencer.c:232
+msgid ""
+"after resolving the conflicts, mark the corrected paths\n"
+"with 'git add <paths>' or 'git rm <paths>'\n"
+"and commit the result with 'git commit'"
+msgstr ""
+"après résolution des conflits, marquez les chemins corrigés\n"
+"avec 'git add <chemins>' ou 'git rm <chemins>'\n"
+"puis validez le résultat avec 'git commit'"
+
+#: sequencer.c:245 sequencer.c:859 sequencer.c:942
+#, c-format
+msgid "Could not write to %s"
+msgstr "Impossible d'écrire dans %s"
+
+#: sequencer.c:248
+#, c-format
+msgid "Error wrapping up %s"
+msgstr "Erreur à l'emballage de %s"
+
+#: sequencer.c:263
+msgid "Your local changes would be overwritten by cherry-pick."
+msgstr "Vos modifications locales seraient écrasées par cherry-pick."
+
+#: sequencer.c:265
+msgid "Your local changes would be overwritten by revert."
+msgstr "Vos modifications locales seraient écrasées par revert."
+
+#: sequencer.c:268
+msgid "Commit your changes or stash them to proceed."
+msgstr "Validez vos modifications ou remisez-les pour continuer."
+
+#. TRANSLATORS: %s will be "revert" or "cherry-pick"
+#: sequencer.c:319
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr "%s: Impossible d'écrire le nouveau fichier index"
+
+#: sequencer.c:350
+msgid "Could not resolve HEAD commit\n"
+msgstr "Impossible de résoudre le commit HEAD\n"
+
+#: sequencer.c:371
+msgid "Unable to update cache tree\n"
+msgstr "Impossible de mettre à jour l'arbre de cache\n"
+
+#: sequencer.c:416
+#, c-format
+msgid "Could not parse commit %s\n"
+msgstr "Impossible d'analyser le commit %s\n"
+
+#: sequencer.c:421
+#, c-format
+msgid "Could not parse parent commit %s\n"
+msgstr "Impossible d'analyser le commit parent %s\n"
+
+#: sequencer.c:487
+msgid "Your index file is unmerged."
+msgstr "Votre fichier d'index n'est pas fusionné."
+
+#: sequencer.c:506
+#, c-format
+msgid "Commit %s is a merge but no -m option was given."
+msgstr "Le commit %s est une fusion mais l'option -m n'a pas été spécifiée."
+
+#: sequencer.c:514
+#, c-format
+msgid "Commit %s does not have parent %d"
+msgstr "Le commit %s n'a pas le parent %d"
+
+#: sequencer.c:518
+#, c-format
+msgid "Mainline was specified but commit %s is not a merge."
+msgstr "Une branche principale a été spécifiée mais le commit %s n'est pas une fusion."
+
+#. TRANSLATORS: The first %s will be "revert" or
+#. "cherry-pick", the second %s a SHA1
+#: sequencer.c:531
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr "%s : impossible d'analyser le commit parent %s"
+
+#: sequencer.c:535
+#, c-format
+msgid "Cannot get commit message for %s"
+msgstr "Impossible d'obtenir un message de validation pour %s"
+
+#: sequencer.c:621
+#, c-format
+msgid "could not revert %s... %s"
+msgstr "impossible d'annuler %s... %s"
+
+#: sequencer.c:622
+#, c-format
+msgid "could not apply %s... %s"
+msgstr "impossible d'appliquer %s... %s"
+
+#: sequencer.c:654
+msgid "empty commit set passed"
+msgstr "l'ensemble de commits spéficifié est vide"
+
+#: sequencer.c:662
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr "git %s : échec à la lecture de l'index"
+
+#: sequencer.c:667
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr "git %s : échec du raffraîchissement de l'index"
+
+#: sequencer.c:725
+#, c-format
+msgid "Cannot %s during a %s"
+msgstr "Impossible de %s pendant un %s"
+
+#: sequencer.c:747
+#, c-format
+msgid "Could not parse line %d."
+msgstr "Impossible d'analyser la ligne %d."
+
+#: sequencer.c:752
+msgid "No commits parsed."
+msgstr "Aucun commit analysé."
+
+#: sequencer.c:765
+#, c-format
+msgid "Could not open %s"
+msgstr "Impossible d'ouvrir %s"
+
+#: sequencer.c:769
+#, c-format
+msgid "Could not read %s."
+msgstr "Impossible de lire %s."
+
+#: sequencer.c:776
+#, c-format
+msgid "Unusable instruction sheet: %s"
+msgstr "Feuille d'instruction inutilisable : %s"
+
+#: sequencer.c:804
+#, c-format
+msgid "Invalid key: %s"
+msgstr "Clé invalide: %s"
+
+#: sequencer.c:807
+#, c-format
+msgid "Invalid value for %s: %s"
+msgstr "Valeur invalide pour %s : %s"
+
+#: sequencer.c:819
+#, c-format
+msgid "Malformed options sheet: %s"
+msgstr "Feuille d'options malformée : %s"
+
+#: sequencer.c:840
+msgid "a cherry-pick or revert is already in progress"
+msgstr "un picorage ou un retour est déjà en cours"
+
+#: sequencer.c:841
+msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr "essayez \"git cherry-pick (--continue|--quit|-- abort)\""
+
+#: sequencer.c:845
+#, c-format
+msgid "Could not create sequencer directory %s"
+msgstr "Impossible de créer le répertoire de séquenceur %s"
+
+#: sequencer.c:861 sequencer.c:946
+#, c-format
+msgid "Error wrapping up %s."
+msgstr "Erreur lors de l'emballage de %s."
+
+#: sequencer.c:880 sequencer.c:1014
+msgid "no cherry-pick or revert in progress"
+msgstr "aucun picorage ou retour en cours"
+
+#: sequencer.c:882
+msgid "cannot resolve HEAD"
+msgstr "impossible de résoudre HEAD"
+
+#: sequencer.c:884
+msgid "cannot abort from a branch yet to be born"
+msgstr "impossible d'abandonner depuis une branche non encore créée"
+
+#: sequencer.c:906 builtin/apply.c:4060
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "impossible d'ouvrir %s : %s"
+
+#: sequencer.c:909
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "impossible de lire %s : %s"
+
+#: sequencer.c:910
+msgid "unexpected end of file"
+msgstr "fin de fichier inattendue"
+
+#: sequencer.c:916
+#, c-format
+msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
+msgstr "le fichier HEAD de préparation de picorage '%s' est corrompu"
+
+#: sequencer.c:939
+#, c-format
+msgid "Could not format %s."
+msgstr "Impossible de formater %s."
+
+#: sequencer.c:1083
+#, c-format
+msgid "%s: can't cherry-pick a %s"
+msgstr "%s : impossible de picorer un %s"
+
+#: sequencer.c:1085
+#, c-format
+msgid "%s: bad revision"
+msgstr "%s : mauvaise révision"
+
+#: sequencer.c:1119
+msgid "Can't revert as initial commit"
+msgstr "Impossible d'annuler en tant que commit initial"
+
+#: sequencer.c:1120
+msgid "Can't cherry-pick into empty head"
+msgstr "Impossible de picorer vers une HEAD vide"
+
+#: sha1_name.c:1036
+msgid "HEAD does not point to a branch"
+msgstr "HEAD ne pointe pas sur une branche"
+
+#: sha1_name.c:1039
+#, c-format
+msgid "No such branch: '%s'"
+msgstr "Branche inconnue : '%s'"
+
+#: sha1_name.c:1041
+#, c-format
+msgid "No upstream configured for branch '%s'"
+msgstr "Aucune branche amont configurée pour la branche '%s'"
+
+#: sha1_name.c:1044
+#, c-format
+msgid "Upstream branch '%s' not stored as a remote-tracking branch"
+msgstr "La branche amont '%s' n'est pas stockée comme branche de suivi"
+
+#: wrapper.c:408
+#, c-format
+msgid "unable to access '%s': %s"
+msgstr "impossible d'accéder à '%s' : %s"
+
+#: wrapper.c:423
+#, c-format
+msgid "unable to access '%s'"
+msgstr "impossible d'accéder à '%s'"
+
+#: wrapper.c:434
+#, c-format
+msgid "unable to look up current user in the passwd file: %s"
+msgstr "impossible de rechercher l'utilisateur actuel dans le fichier de mots de passe : %s"
+
+#: wrapper.c:435
+msgid "no such user"
+msgstr "utilisateur inconnu"
+
+#: wt-status.c:140
+msgid "Unmerged paths:"
+msgstr "Chemins non fusionnés :"
+
+#: wt-status.c:167 wt-status.c:194
+#, c-format
+msgid " (use \"git reset %s <file>...\" to unstage)"
+msgstr " (utilisez \"git reset %s <fichier>...\" pour désindexer)"
+
+#: wt-status.c:169 wt-status.c:196
+msgid " (use \"git rm --cached <file>...\" to unstage)"
+msgstr " (utilisez \"git rm --cached <fichier>...\" pour désindexer)"
+
+#: wt-status.c:173
+msgid " (use \"git add <file>...\" to mark resolution)"
+msgstr " (utilisez \"git add <fichier>...\" pour marquer comme résolu)"
+
+#: wt-status.c:175 wt-status.c:179
+msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
+msgstr " (utilisez \"git add/rm <fichier>...\" si nécessaire pour marquer comme résolu)"
+
+#: wt-status.c:177
+msgid " (use \"git rm <file>...\" to mark resolution)"
+msgstr " (utilisez \"git rm <fichier>...\" pour marquer comme résolu)"
+
+#: wt-status.c:188
+msgid "Changes to be committed:"
+msgstr "Modifications qui seront validées :"
+
+#: wt-status.c:206
+msgid "Changes not staged for commit:"
+msgstr "Modifications qui ne seront pas validées :"
+
+#: wt-status.c:210
+msgid " (use \"git add <file>...\" to update what will be committed)"
+msgstr " (utilisez \"git add <fichier>...\" pour mettre à jour ce qui sera validé)"
+
+#: wt-status.c:212
+msgid " (use \"git add/rm <file>...\" to update what will be committed)"
+msgstr " (utilisez \"git add/rm <fichier>...\" pour mettre à jour ce qui sera validé)"
+
+#: wt-status.c:213
+msgid ""
+" (use \"git checkout -- <file>...\" to discard changes in working directory)"
+msgstr " (utilisez \"git checkout -- <fichier>...\" pour annuler les modifications dans la copie de travail)"
+
+#: wt-status.c:215
+msgid " (commit or discard the untracked or modified content in submodules)"
+msgstr " (valider ou annuler le contenu non suivi ou modifié dans les sous-modules)"
+
+#: wt-status.c:227
+#, c-format
+msgid " (use \"git %s <file>...\" to include in what will be committed)"
+msgstr " (utilisez \"git %s <fichier>...\" pour inclure dans ce qui sera validé)"
+
+#: wt-status.c:244
+msgid "bug"
+msgstr "bogue"
+
+#: wt-status.c:249
+msgid "both deleted:"
+msgstr "supprimé des deux côtés :"
+
+#: wt-status.c:250
+msgid "added by us:"
+msgstr "ajouté par nous :"
+
+#: wt-status.c:251
+msgid "deleted by them:"
+msgstr "supprimé par eux :"
+
+#: wt-status.c:252
+msgid "added by them:"
+msgstr "ajouté par eux :"
+
+#: wt-status.c:253
+msgid "deleted by us:"
+msgstr "supprimé par nous :"
+
+#: wt-status.c:254
+msgid "both added:"
+msgstr "ajouté de deux côtés :"
+
+#: wt-status.c:255
+msgid "both modified:"
+msgstr "modifié des deux côtés :"
+
+#: wt-status.c:285
+msgid "new commits, "
+msgstr "nouveaux commits, "
+
+#: wt-status.c:287
+msgid "modified content, "
+msgstr "contenu modifié, "
+
+#: wt-status.c:289
+msgid "untracked content, "
+msgstr "contenu non suivi, "
+
+#: wt-status.c:306
+#, c-format
+msgid "new file: %s"
+msgstr "nouveau : %s"
+
+#: wt-status.c:309
+#, c-format
+msgid "copied: %s -> %s"
+msgstr "copié : %s -> %s"
+
+#: wt-status.c:312
+#, c-format
+msgid "deleted: %s"
+msgstr "supprimé : %s"
+
+#: wt-status.c:315
+#, c-format
+msgid "modified: %s"
+msgstr "modifié : %s"
+
+#: wt-status.c:318
+#, c-format
+msgid "renamed: %s -> %s"
+msgstr "renommé : %s -> %s"
+
+#: wt-status.c:321
+#, c-format
+msgid "typechange: %s"
+msgstr "nv type : %s"
+
+#: wt-status.c:324
+#, c-format
+msgid "unknown: %s"
+msgstr "inconnu : %s"
+
+#: wt-status.c:327
+#, c-format
+msgid "unmerged: %s"
+msgstr "non fus. : %s"
+
+#: wt-status.c:330
+#, c-format
+msgid "bug: unhandled diff status %c"
+msgstr "bogue : état de diff non géré %c"
+
+#: wt-status.c:803
+msgid "You have unmerged paths."
+msgstr "Vous avez des chemins non fusionnés."
+
+#: wt-status.c:806 wt-status.c:958
+msgid " (fix conflicts and run \"git commit\")"
+msgstr " (réglez les conflits et lancez \"git commit\")"
+
+#: wt-status.c:809
+msgid "All conflicts fixed but you are still merging."
+msgstr "Tous les conflits sont réglés mais la fusion n'est pas terminée."
+
+#: wt-status.c:812
+msgid " (use \"git commit\" to conclude merge)"
+msgstr " (utilisez \"git commit\" pour terminer la fusion)"
+
+#: wt-status.c:822
+msgid "You are in the middle of an am session."
+msgstr "Vous êtes au milieu d'une session am."
+
+#: wt-status.c:825
+msgid "The current patch is empty."
+msgstr "Le patch actuel est vide."
+
+#: wt-status.c:829
+msgid " (fix conflicts and then run \"git am --resolved\")"
+msgstr " (réglez les conflits puis lancez \"git am --resolved\")"
+
+#: wt-status.c:831
+msgid " (use \"git am --skip\" to skip this patch)"
+msgstr " (utilisez \"git am --skip\" pour sauter ce patch)"
+
+#: wt-status.c:833
+msgid " (use \"git am --abort\" to restore the original branch)"
+msgstr " (utilisez \"git am --abort\" pour restaurer la branche d'origine)"
+
+#: wt-status.c:893 wt-status.c:910
+#, c-format
+msgid "You are currently rebasing branch '%s' on '%s'."
+msgstr "Vous êtes en train de rebaser la branche '%s' sur '%s'."
+
+#: wt-status.c:898 wt-status.c:915
+msgid "You are currently rebasing."
+msgstr "Vous êtes en train de rebaser."
+
+#: wt-status.c:901
+msgid " (fix conflicts and then run \"git rebase --continue\")"
+msgstr " (résolvez les conflits puis lancez \"git rebase --continue\")"
+
+#: wt-status.c:903
+msgid " (use \"git rebase --skip\" to skip this patch)"
+msgstr " (utilisez \"git rebase --skip\" pour sauter ce patch)"
+
+#: wt-status.c:905
+msgid " (use \"git rebase --abort\" to check out the original branch)"
+msgstr " (utilisez \"git rebase --abort\" pour extraire la branche d'origine)"
+
+#: wt-status.c:918
+msgid " (all conflicts fixed: run \"git rebase --continue\")"
+msgstr " (tous les conflits sont résolus : lancez \"git rebase --continue\")"
+
+#: wt-status.c:922
+#, c-format
+msgid ""
+"You are currently splitting a commit while rebasing branch '%s' on '%s'."
+msgstr "Vous êtes actuellement en train de fractionner un commit pendant un rebasage de la branche '%s' sur '%s'."
+
+#: wt-status.c:927
+msgid "You are currently splitting a commit during a rebase."
+msgstr "Vous êtes actuellement en train de fractionner un commit pendant un rebasage."
+
+#: wt-status.c:930
+msgid " (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr " (Une fois la copie de travail nettoyée, lancez \"git rebase --continue\")"
+
+#: wt-status.c:934
+#, c-format
+msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
+msgstr "Vous êtes actuellement en train d'éditer un commit pendant un rebasage de la branche '%s' sur '%s'."
+
+#: wt-status.c:939
+msgid "You are currently editing a commit during a rebase."
+msgstr "Vous êtes actuellement en train d'éditer un commit pendant un rebasage."
+
+#: wt-status.c:942
+msgid " (use \"git commit --amend\" to amend the current commit)"
+msgstr " (utilisez \"git commit --amend\" pour corriger le commit actuel)"
+
+#: wt-status.c:944
+msgid ""
+" (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr " (utilisez \"git rebase --continue\" quand vous êtes satisfait de vos modifications)"
+
+#: wt-status.c:954
+msgid "You are currently cherry-picking."
+msgstr "Vous êtes actuellement en train de picorer."
+
+#: wt-status.c:961
+msgid " (all conflicts fixed: run \"git commit\")"
+msgstr " (tous les conflits sont résolus : lancez \"git commit\")"
+
+#: wt-status.c:970
+#, c-format
+msgid "You are currently reverting commit %s."
+msgstr "Vous êtes actuellement en train de rétablir le commit %s."
+
+#: wt-status.c:975
+msgid " (fix conflicts and run \"git revert --continue\")"
+msgstr " (résolvez les conflits et lancez \"git revert --continue\")"
+
+#: wt-status.c:978
+msgid " (all conflicts fixed: run \"git revert --continue\")"
+msgstr " (tous les conflits sont résolus : lancez \"git revert --continue\")"
+
+#: wt-status.c:980
+msgid " (use \"git revert --abort\" to cancel the revert operation)"
+msgstr " (utilisez \"git revert --abort\" pour annuler le rétablissement)"
+
+#: wt-status.c:991
+#, c-format
+msgid "You are currently bisecting, started from branch '%s'."
+msgstr "Vous êtes en cours de bissection, depuis la branche '%s'."
+
+#: wt-status.c:995
+msgid "You are currently bisecting."
+msgstr "Vous êtes en cours de bissection."
+
+#: wt-status.c:998
+msgid " (use \"git bisect reset\" to get back to the original branch)"
+msgstr " (utilisez \"git bisect reset\" pour revenir à la branche d'origine)"
+
+#: wt-status.c:1173
+msgid "On branch "
+msgstr "Sur la branche "
+
+#: wt-status.c:1184
+msgid "HEAD detached at "
+msgstr "HEAD détachée sur "
+
+#: wt-status.c:1186
+msgid "HEAD detached from "
+msgstr "HEAD détachée depuis "
+
+#: wt-status.c:1189
+msgid "Not currently on any branch."
+msgstr "Actuellement sur aucun branche."
+
+#: wt-status.c:1206
+msgid "Initial commit"
+msgstr "Validation initiale"
+
+#: wt-status.c:1220
+msgid "Untracked files"
+msgstr "Fichiers non suivis"
+
+#: wt-status.c:1222
+msgid "Ignored files"
+msgstr "Fichiers ignorés"
+
+#: wt-status.c:1226
+#, c-format
+msgid ""
+"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
+"may speed it up, but you have to be careful not to forget to add\n"
+"new files yourself (see 'git help status')."
+msgstr "L'énumération des fichiers non suivis a duré %.2f secondes. 'status -uno'\n"
+"peut l'accélerer, mais vous devez alors faire attention à ne pas\n"
+"oublier d'ajouter les nouveaux fichiers par vous-même (voir 'git help status')."
+
+#: wt-status.c:1232
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr "Fichiers non suivis non listés%s"
+
+#: wt-status.c:1234
+msgid " (use -u option to show untracked files)"
+msgstr " (utilisez -u pour afficher les fichiers non suivis)"
+
+#: wt-status.c:1240
+msgid "No changes"
+msgstr "Aucune modification"
+
+#: wt-status.c:1245
+#, c-format
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
+msgstr "aucune modification n'a été ajoutée à la validation (utilisez \"git add\" ou \"git commit -a\")\n"
+
+#: wt-status.c:1248
+#, c-format
+msgid "no changes added to commit\n"
+msgstr "aucune modification ajoutée à la validation\n"
+
+#: wt-status.c:1251
+#, c-format
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
+msgstr "aucune modification ajoutée à la validation mais des fichiers non suivis sont présents (utilisez \"git add\" pour les suivre)\n"
+
+#: wt-status.c:1254
+#, c-format
+msgid "nothing added to commit but untracked files present\n"
+msgstr "aucune modification ajoutée à la validation mais des fichiers non suivis sont présents\n"
+
+#: wt-status.c:1257
+#, c-format
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
+msgstr "rien à valider (créez/copiez des fichiers et utilisez \"git add\" pour les suivre)\n"
+
+#: wt-status.c:1260 wt-status.c:1265
+#, c-format
+msgid "nothing to commit\n"
+msgstr "rien à valider\n"
+
+#: wt-status.c:1263
+#, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
+msgstr "rien à valider (utilisez -u pour afficher les fichiers non suivis)\n"
+
+#: wt-status.c:1267
+#, c-format
+msgid "nothing to commit, working directory clean\n"
+msgstr "rien à valider, la copie de travail est propre\n"
+
+#: wt-status.c:1375
+msgid "HEAD (no branch)"
+msgstr "HEAD (aucune branche)"
+
+#: wt-status.c:1381
+msgid "Initial commit on "
+msgstr "Validation initiale sur "
+
+#: wt-status.c:1396
+msgid "behind "
+msgstr "derrière "
+
+#: wt-status.c:1399 wt-status.c:1402
+msgid "ahead "
+msgstr "devant "
+
+#: wt-status.c:1404
+msgid ", behind "
+msgstr ", derrière "
+
+#: compat/precompose_utf8.c:58 builtin/clone.c:352
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "echec lors de l'unlink de '%s'"
+
+#: builtin/add.c:20
+msgid "git add [options] [--] <pathspec>..."
+msgstr "git add [options] [--] <chemin>..."
+
+#.
+#. * To be consistent with "git add -p" and most Git
+#. * commands, we should default to being tree-wide, but
+#. * this is not the original behavior and can't be
+#. * changed until users trained themselves not to type
+#. * "git add -u" or "git add -A". For now, we warn and
+#. * keep the old behavior. Later, the behavior can be changed
+#. * to tree-wide, keeping the warning for a while, and
+#. * eventually we can drop the warning.
+#.
+#: builtin/add.c:58
+#, c-format
+msgid ""
+"The behavior of 'git add %s (or %s)' with no path argument from a\n"
+"subdirectory of the tree will change in Git 2.0 and should not be used "
+"anymore.\n"
+"To add content for the whole tree, run:\n"
+"\n"
+" git add %s :/\n"
+" (or git add %s :/)\n"
+"\n"
+"To restrict the command to the current directory, run:\n"
+"\n"
+" git add %s .\n"
+" (or git add %s .)\n"
+"\n"
+"With the current Git version, the command is restricted to the current "
+"directory.\n"
+msgstr ""
+"Le comportement de 'git add %s (ou %s)' sans argument de chemin depuis un\n"
+"sous-répertoire du projet va changer dans Git 2.0 et ne doit plus être utilisé.\n"
+"Pour ajouter le contenu de toute l'arborescence, lancez :\n"
+"\n"
+" git add %s :/\n"
+" (ou git add %s :/)\n"
+"\n"
+"Pour restreindre la commande au répertoire courant, lancez :\n"
+"\n"
+" git add %s .\n"
+" (ou git add %s .)\n"
+"\n"
+"Avec la version actuelle de Git, la commande est restreinte au répertoire courant.\n"
+
+#: builtin/add.c:100
+#, c-format
+msgid ""
+"You ran 'git add' with neither '-A (--all)' or '--ignore-removal',\n"
+"whose behaviour will change in Git 2.0 with respect to paths you removed.\n"
+"Paths like '%s' that are\n"
+"removed from your working tree are ignored with this version of Git.\n"
+"\n"
+"* 'git add --ignore-removal <pathspec>', which is the current default,\n"
+" ignores paths you removed from your working tree.\n"
+"\n"
+"* 'git add --all <pathspec>' will let you also record the removals.\n"
+"\n"
+"Run 'git status' to check the paths you removed from your working tree.\n"
+msgstr ""
+"Vous avez lancé 'git add' sans '-A (--all)' ni '--ignore-removal',\n"
+"dont le comportement va changer dans Git 2.0 avec le respect des chemins que vous supprimez.\n"
+"Les chemins tels que '%s' qui ont été\n"
+"retirés de votre copie de travail sont ignorés avec cette version de Git.\n"
+"\n"
+"* 'git add --ignore-removal <chemin>', qui est l'option par défaut actuelle,\n"
+" ignore les chemins que vous avez supprimés de votre copie de travail.\n"
+"\n"
+"* 'git add --all <chemin>' permet d'enregistrer aussi les suppressions.\n"
+"\n"
+"Lancez 'git status' pour vérifier les chemins que vous avez supprimés de votre copie de travail.\n"
+
+#: builtin/add.c:144
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "status de diff inattendu %c"
+
+#: builtin/add.c:149 builtin/commit.c:233
+msgid "updating files failed"
+msgstr "échec de la mise à jour des fichiers"
+
+#: builtin/add.c:163
+#, c-format
+msgid "remove '%s'\n"
+msgstr "suppression de '%s'\n"
+
+#: builtin/add.c:253
+msgid "Unstaged changes after refreshing the index:"
+msgstr "Modifications non indexées après rafraîchissement de l'index :"
+
+#: builtin/add.c:256 builtin/add.c:572 builtin/rm.c:275
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr "le chemin '%s' ne correspond à aucun fichier"
+
+#: builtin/add.c:339
+msgid "Could not read the index"
+msgstr "Impossible de lire l'index"
+
+#: builtin/add.c:349
+#, c-format
+msgid "Could not open '%s' for writing."
+msgstr "Impossible d'ouvrir '%s' en écriture."
+
+#: builtin/add.c:353
+msgid "Could not write patch"
+msgstr "Impossible d'écrire le patch"
+
+#: builtin/add.c:358
+#, c-format
+msgid "Could not stat '%s'"
+msgstr "Stat de '%s' impossible"
+
+#: builtin/add.c:360
+msgid "Empty patch. Aborted."
+msgstr "Patch vide. Abandon."
+
+#: builtin/add.c:366
+#, c-format
+msgid "Could not apply '%s'"
+msgstr "Impossible d'appliquer '%s'"
+
+#: builtin/add.c:376
+msgid "The following paths are ignored by one of your .gitignore files:\n"
+msgstr "Les chemins suivants sont ignorés par un de vos fichiers .gitignore :\n"
+
+#: builtin/add.c:393 builtin/clean.c:161 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:76 builtin/push.c:425 builtin/remote.c:1253
+#: builtin/rm.c:206
+msgid "dry run"
+msgstr "à vide"
+
+#: builtin/add.c:394 builtin/apply.c:4409 builtin/check-ignore.c:19
+#: builtin/commit.c:1152 builtin/count-objects.c:95 builtin/fsck.c:613
+#: builtin/log.c:1518 builtin/mv.c:62 builtin/read-tree.c:112
+msgid "be verbose"
+msgstr "mode verbeux"
+
+#: builtin/add.c:396
+msgid "interactive picking"
+msgstr "sélection interactive"
+
+#: builtin/add.c:397 builtin/checkout.c:1063 builtin/reset.c:258
+msgid "select hunks interactively"
+msgstr "sélection interactive des sections"
+
+#: builtin/add.c:398
+msgid "edit current diff and apply"
+msgstr "édition du diff actuel et application"
+
+#: builtin/add.c:399
+msgid "allow adding otherwise ignored files"
+msgstr "permettre l'ajout de fichiers ignorés"
+
+#: builtin/add.c:400
+msgid "update tracked files"
+msgstr "mettre à jour les fichiers suivis"
+
+#: builtin/add.c:401
+msgid "record only the fact that the path will be added later"
+msgstr "enregistrer seulement le fait que le chemin sera ajouté plus tard"
+
+#: builtin/add.c:402
+msgid "add changes from all tracked and untracked files"
+msgstr "ajouter les modifications de tous les fichiers suivis et non suivis"
+
+#. takes no arguments
+#: builtin/add.c:405
+msgid "ignore paths removed in the working tree (same as --no-all)"
+msgstr "ignorer les chemins effacés dans la copie de travail (identique à --no-all)"
+
+#: builtin/add.c:407
+msgid "don't add, only refresh the index"
+msgstr "ne pas ajouter, juste rafraîchir l'index"
+
+#: builtin/add.c:408
+msgid "just skip files which cannot be added because of errors"
+msgstr "sauter seulement les fichiers qui ne peuvent pas être ajoutés du fait d'erreurs"
+
+#: builtin/add.c:409
+msgid "check if - even missing - files are ignored in dry run"
+msgstr "vérifier si des fichiers - même manquants - sont ignorés, à vide"
+
+#: builtin/add.c:431
+#, c-format
+msgid "Use -f if you really want to add them.\n"
+msgstr "Utilisez -f si vous voulez réellement les ajouter.\n"
+
+#: builtin/add.c:432
+msgid "no files added"
+msgstr "aucun fichier ajouté"
+
+#: builtin/add.c:438
+msgid "adding files failed"
+msgstr "échec de l'ajout de fichiers"
+
+#: builtin/add.c:477
+msgid "-A and -u are mutually incompatible"
+msgstr "-A et -u sont mutuellement incompatibles"
+
+#: builtin/add.c:495
+msgid "Option --ignore-missing can only be used together with --dry-run"
+msgstr "L'option --ignore-missing ne peut être utilisée qu'en complément de --dry-run"
+
+#: builtin/add.c:525
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr "Rien de spécifié, rien n'a été ajouté.\n"
+
+#: builtin/add.c:526
+#, c-format
+msgid "Maybe you wanted to say 'git add .'?\n"
+msgstr "Vous vouliez sûrement dire 'git add .' ?\n"
+
+#: builtin/add.c:532 builtin/check-ignore.c:66 builtin/clean.c:204
+#: builtin/commit.c:293 builtin/mv.c:82 builtin/rm.c:235
+msgid "index file corrupt"
+msgstr "fichier d'index corrompu"
+
+#: builtin/add.c:604 builtin/apply.c:4505 builtin/mv.c:229 builtin/rm.c:370
+msgid "Unable to write new index file"
+msgstr "Impossible d'écrire le nouveau fichier d'index"
+
+#: builtin/apply.c:57
+msgid "git apply [options] [<patch>...]"
+msgstr "git apply [options] [<patch>...]"
+
+#: builtin/apply.c:110
+#, c-format
+msgid "unrecognized whitespace option '%s'"
+msgstr "option d'espace non reconnue '%s'"
+
+#: builtin/apply.c:125
+#, c-format
+msgid "unrecognized whitespace ignore option '%s'"
+msgstr "option d'ignorance d'espce non reconnue '%s'"
+
+#: builtin/apply.c:823
+#, c-format
+msgid "Cannot prepare timestamp regexp %s"
+msgstr "Impossible de préparer la regexp d'horodatage %s"
+
+#: builtin/apply.c:832
+#, c-format
+msgid "regexec returned %d for input: %s"
+msgstr "regexec a retourné %d pour l'entrée : %s"
+
+#: builtin/apply.c:913
+#, c-format
+msgid "unable to find filename in patch at line %d"
+msgstr "nom de fichier du patch introuvable à la ligne %d"
+
+#: builtin/apply.c:945
+#, c-format
+msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
+msgstr "git apply : mauvais format de git-diff - /dev/null attendu, %s trouvé à la ligne %d"
+
+#: builtin/apply.c:949
+#, c-format
+msgid "git apply: bad git-diff - inconsistent new filename on line %d"
+msgstr "git apply : mauvais format de git-diff - nouveau nom de fichier inconsistant à la ligne %d"
+
+#: builtin/apply.c:950
+#, c-format
+msgid "git apply: bad git-diff - inconsistent old filename on line %d"
+msgstr "git apply : mauvais format de git-diff - ancien nom de fichier inconsistant à la ligne %d"
+
+#: builtin/apply.c:957
+#, c-format
+msgid "git apply: bad git-diff - expected /dev/null on line %d"
+msgstr "git apply : mauvais format de git-diff - /dev/null attendu à la ligne %d"
+
+#: builtin/apply.c:1422
+#, c-format
+msgid "recount: unexpected line: %.*s"
+msgstr "recount : ligne inattendue : %.*s"
+
+#: builtin/apply.c:1479
+#, c-format
+msgid "patch fragment without header at line %d: %.*s"
+msgstr "fragment de patch sans en-tête à la ligne %d : %.*s"
+
+#: builtin/apply.c:1496
+#, 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] "information de nom de fichier manquante dans l'en-tête de git diff lors de la suppression de %d composant de préfixe de chemin (ligne %d)"
+msgstr[1] "information de nom de fichier manquante dans l'en-tête de git diff lors de la suppression de %d composants de préfixe de chemin (ligne %d)"
+
+#: builtin/apply.c:1656
+msgid "new file depends on old contents"
+msgstr "le nouveau fichier dépend de contenus anciens"
+
+#: builtin/apply.c:1658
+msgid "deleted file still has contents"
+msgstr "le fichier supprimé a encore du contenu"
+
+#: builtin/apply.c:1684
+#, c-format
+msgid "corrupt patch at line %d"
+msgstr "patch corrompu à la ligne %d"
+
+#: builtin/apply.c:1720
+#, c-format
+msgid "new file %s depends on old contents"
+msgstr "le nouveau fichier %s dépend de contenus anciens"
+
+#: builtin/apply.c:1722
+#, c-format
+msgid "deleted file %s still has contents"
+msgstr "le fichier supprimé %s a encore du contenu"
+
+#: builtin/apply.c:1725
+#, c-format
+msgid "** warning: file %s becomes empty but is not deleted"
+msgstr "** attention : le fichier %s devient vide mais n'est pas supprimé"
+
+#: builtin/apply.c:1871
+#, c-format
+msgid "corrupt binary patch at line %d: %.*s"
+msgstr "patch binaire corrompu à la ligne %d : %.*s"
+
+#. there has to be one hunk (forward hunk)
+#: builtin/apply.c:1900
+#, c-format
+msgid "unrecognized binary patch at line %d"
+msgstr "patch binaire non reconnu à la ligne %d"
+
+#: builtin/apply.c:1986
+#, c-format
+msgid "patch with only garbage at line %d"
+msgstr "patch totalement incompréhensible à la ligne %d"
+
+#: builtin/apply.c:2076
+#, c-format
+msgid "unable to read symlink %s"
+msgstr "lecture du lien symbolique %s impossible"
+
+#: builtin/apply.c:2080
+#, c-format
+msgid "unable to open or read %s"
+msgstr "ouverture ou lecture de %s impossible"
+
+#: builtin/apply.c:2688
+#, c-format
+msgid "invalid start of line: '%c'"
+msgstr "début de ligne invalide : '%c'"
+
+#: builtin/apply.c:2806
+#, c-format
+msgid "Hunk #%d succeeded at %d (offset %d line)."
+msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
+msgstr[0] "La section n°%d a réussi à la ligne %d (offset %d ligne)."
+msgstr[1] "La section n°%d a réussi à la ligne %d (offset %d lignes)."
+
+#: builtin/apply.c:2818
+#, c-format
+msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
+msgstr "Contexte réduit à (%ld/%ld) pour appliquer le fragment à la ligne %d"
+
+#: builtin/apply.c:2824
+#, c-format
+msgid ""
+"while searching for:\n"
+"%.*s"
+msgstr "pendant la recherche de :\n"
+"%.*s"
+
+#: builtin/apply.c:2843
+#, c-format
+msgid "missing binary patch data for '%s'"
+msgstr "données de patch binaire manquantes pour '%s'"
+
+#: builtin/apply.c:2946
+#, c-format
+msgid "binary patch does not apply to '%s'"
+msgstr "le patch binaire ne s'applique par correctement à '%s'"
+
+#: builtin/apply.c:2952
+#, c-format
+msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
+msgstr "le patch binaire sur '%s' crée un résultat incorrect (%s attendu, mais %s trouvé)"
+
+#: builtin/apply.c:2973
+#, c-format
+msgid "patch failed: %s:%ld"
+msgstr "le patch a échoué : %s:%ld"
+
+#: builtin/apply.c:3095
+#, c-format
+msgid "cannot checkout %s"
+msgstr "extraction de %s impossible"
+
+#: builtin/apply.c:3140 builtin/apply.c:3149 builtin/apply.c:3193
+#, c-format
+msgid "read of %s failed"
+msgstr "echec de la lecture de %s"
+
+#: builtin/apply.c:3173 builtin/apply.c:3395
+#, c-format
+msgid "path %s has been renamed/deleted"
+msgstr "le chemin %s a été renommé/supprimé"
+
+#: builtin/apply.c:3254 builtin/apply.c:3409
+#, c-format
+msgid "%s: does not exist in index"
+msgstr "%s : n'existe pas dans l'index"
+
+#: builtin/apply.c:3258 builtin/apply.c:3401 builtin/apply.c:3423
+#, c-format
+msgid "%s: %s"
+msgstr "%s : %s"
+
+#: builtin/apply.c:3263 builtin/apply.c:3417
+#, c-format
+msgid "%s: does not match index"
+msgstr "%s : ne correspond pas à l'index"
+
+#: builtin/apply.c:3365
+msgid "removal patch leaves file contents"
+msgstr "le patch de suppression laisse un contenu dans le fichier"
+
+#: builtin/apply.c:3434
+#, c-format
+msgid "%s: wrong type"
+msgstr "%s : type erroné"
+
+#: builtin/apply.c:3436
+#, c-format
+msgid "%s has type %o, expected %o"
+msgstr "%s est de type %o, mais %o attendu"
+
+#: builtin/apply.c:3537
+#, c-format
+msgid "%s: already exists in index"
+msgstr "%s : existe déjà dans l'index"
+
+#: builtin/apply.c:3540
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s : existe déjà dans la copie de travail"
+
+#: builtin/apply.c:3560
+#, c-format
+msgid "new mode (%o) of %s does not match old mode (%o)"
+msgstr "le nouveau mode (%o) de %s ne correspond pas à l'ancien mode (%o)"
+
+#: builtin/apply.c:3565
+#, c-format
+msgid "new mode (%o) of %s does not match old mode (%o) of %s"
+msgstr "le nouveau mode (%o) de %s ne correspond pas à l'ancien mode (%o) de %s"
+
+#: builtin/apply.c:3573
+#, c-format
+msgid "%s: patch does not apply"
+msgstr "%s : le patch ne s'applique pas"
+
+#: builtin/apply.c:3586
+#, c-format
+msgid "Checking patch %s..."
+msgstr "Vérification du patch %s..."
+
+#: builtin/apply.c:3679 builtin/checkout.c:216 builtin/reset.c:124
+#, c-format
+msgid "make_cache_entry failed for path '%s'"
+msgstr "echec de make_cache_entry pour le chemin '%s'"
+
+#: builtin/apply.c:3822
+#, c-format
+msgid "unable to remove %s from index"
+msgstr "suppression de %s dans l'index impossible"
+
+#: builtin/apply.c:3850
+#, c-format
+msgid "corrupt patch for subproject %s"
+msgstr "patch corrompu pour le sous-projet %s"
+
+#: builtin/apply.c:3854
+#, c-format
+msgid "unable to stat newly created file '%s'"
+msgstr "stat du fichier nouvellement créé '%s' impossible"
+
+#: builtin/apply.c:3859
+#, c-format
+msgid "unable to create backing store for newly created file %s"
+msgstr "création du magasin de stockage pour le fichier nouvellement créé %s impossible"
+
+#: builtin/apply.c:3862 builtin/apply.c:3970
+#, c-format
+msgid "unable to add cache entry for %s"
+msgstr "ajout de l'entrée de cache %s impossible"
+
+#: builtin/apply.c:3895
+#, c-format
+msgid "closing file '%s'"
+msgstr "fermeture du fichier '%s'"
+
+#: builtin/apply.c:3944
+#, c-format
+msgid "unable to write file '%s' mode %o"
+msgstr "écriture du fichier '%s' mode %o impossible"
+
+#: builtin/apply.c:4031
+#, c-format
+msgid "Applied patch %s cleanly."
+msgstr "Patch %s appliqué proprement."
+
+#: builtin/apply.c:4039
+msgid "internal error"
+msgstr "erreur interne"
+
+#. Say this even without --verbose
+#: builtin/apply.c:4042
+#, c-format
+msgid "Applying patch %%s with %d reject..."
+msgid_plural "Applying patch %%s with %d rejects..."
+msgstr[0] "Application du patch %%s avec %d rejet..."
+msgstr[1] "Application du patch %%s avec %d rejets..."
+
+#: builtin/apply.c:4052
+#, c-format
+msgid "truncating .rej filename to %.*s.rej"
+msgstr "troncature du nom de fichier .rej en %.*s.rej"
+
+#: builtin/apply.c:4073
+#, c-format
+msgid "Hunk #%d applied cleanly."
+msgstr "Section n°%d appliquée proprement."
+
+#: builtin/apply.c:4076
+#, c-format
+msgid "Rejected hunk #%d."
+msgstr "Section n°%d rejetée."
+
+#: builtin/apply.c:4226
+msgid "unrecognized input"
+msgstr "entrée non reconnue"
+
+#: builtin/apply.c:4237
+msgid "unable to read index file"
+msgstr "lecture du fichier d'index impossible"
+
+#: builtin/apply.c:4356 builtin/apply.c:4359 builtin/clone.c:92
+#: builtin/fetch.c:63
+msgid "path"
+msgstr "chemin"
+
+#: builtin/apply.c:4357
+msgid "don't apply changes matching the given path"
+msgstr "ne pas appliquer les modifications qui correspondent au chemin donné"
+
+#: builtin/apply.c:4360
+msgid "apply changes matching the given path"
+msgstr "appliquer les modifications qui correspondent au chemin donné"
+
+#: builtin/apply.c:4362
+msgid "num"
+msgstr "num"
+
+#: builtin/apply.c:4363
+msgid "remove <num> leading slashes from traditional diff paths"
+msgstr "supprimer <num> barres obliques des chemins traditionnels de diff"
+
+#: builtin/apply.c:4366
+msgid "ignore additions made by the patch"
+msgstr "ignorer les additions réalisées par le patch"
+
+#: builtin/apply.c:4368
+msgid "instead of applying the patch, output diffstat for the input"
+msgstr "au lieu d'appliquer le patch, afficher le diffstat de l'entrée"
+
+#: builtin/apply.c:4372
+msgid "show number of added and deleted lines in decimal notation"
+msgstr "afficher le nombre de lignes ajoutées et supprimées en notation décimale"
+
+#: builtin/apply.c:4374
+msgid "instead of applying the patch, output a summary for the input"
+msgstr "au lieu d'appliquer le patch, afficher un résumer de l'entrée"
+
+#: builtin/apply.c:4376
+msgid "instead of applying the patch, see if the patch is applicable"
+msgstr "au lieu d'appliquer le patch, voir si le patch est applicable"
+
+#: builtin/apply.c:4378
+msgid "make sure the patch is applicable to the current index"
+msgstr "s'assurer que le patch est applicable sur l'index actuel"
+
+#: builtin/apply.c:4380
+msgid "apply a patch without touching the working tree"
+msgstr "appliquer les patch sans toucher à la copie de travail"
+
+#: builtin/apply.c:4382
+msgid "also apply the patch (use with --stat/--summary/--check)"
+msgstr "appliquer aussi le patch (à utiliser avec ---stat/--summary/--check)"
+
+#: builtin/apply.c:4384
+msgid "attempt three-way merge if a patch does not apply"
+msgstr "tenter une fusion à 3 points si le patch ne s'applique pas proprement"
+
+#: builtin/apply.c:4386
+msgid "build a temporary index based on embedded index information"
+msgstr "construire un index temporaire fondé sur l'information de l'index embarqué"
+
+#: builtin/apply.c:4388 builtin/checkout-index.c:197 builtin/ls-files.c:456
+msgid "paths are separated with NUL character"
+msgstr "les chemins sont séparés par un caractère NUL"
+
+#: builtin/apply.c:4391
+msgid "ensure at least <n> lines of context match"
+msgstr "s'assurer d'au moins <n> lignes de correspondance de contexte"
+
+#: builtin/apply.c:4392
+msgid "action"
+msgstr "action"
+
+#: builtin/apply.c:4393
+msgid "detect new or modified lines that have whitespace errors"
+msgstr "détecter des lignes nouvelles ou modifiées qui contiennent des erreurs d'espace"
+
+#: builtin/apply.c:4396 builtin/apply.c:4399
+msgid "ignore changes in whitespace when finding context"
+msgstr "ignorer des modifications d'espace lors de la recherche de contexte"
+
+#: builtin/apply.c:4402
+msgid "apply the patch in reverse"
+msgstr "appliquer le patch en sens inverse"
+
+#: builtin/apply.c:4404
+msgid "don't expect at least one line of context"
+msgstr "ne pas s'attendre à au moins une ligne de contexte"
+
+#: builtin/apply.c:4406
+msgid "leave the rejected hunks in corresponding *.rej files"
+msgstr "laisser les sections rejetées dans les fichiers *.rej correspondants"
+
+#: builtin/apply.c:4408
+msgid "allow overlapping hunks"
+msgstr "accepter les recouvrements de sections"
+
+#: builtin/apply.c:4411
+msgid "tolerate incorrectly detected missing new-line at the end of file"
+msgstr "tolérer des erreurs de détection de retours chariot manquants en fin de fichier"
+
+#: builtin/apply.c:4414
+msgid "do not trust the line counts in the hunk headers"
+msgstr "ne pas se fier au compte de lignes dans les en-têtes de section"
+
+#: builtin/apply.c:4416
+msgid "root"
+msgstr "racine"
+
+#: builtin/apply.c:4417
+msgid "prepend <root> to all filenames"
+msgstr "préfixer tous les noms de fichier avec <root>"
+
+#: builtin/apply.c:4439
+msgid "--3way outside a repository"
+msgstr "--3way hors d'un dépôt"
+
+#: builtin/apply.c:4447
+msgid "--index outside a repository"
+msgstr "--index hors d'un dépôt"
+
+#: builtin/apply.c:4450
+msgid "--cached outside a repository"
+msgstr "--cached hors d'un dépôt"
+
+#: builtin/apply.c:4466
+#, c-format
+msgid "can't open patch '%s'"
+msgstr "ouverture impossible du patch '%s'"
+
+#: builtin/apply.c:4480
+#, c-format
+msgid "squelched %d whitespace error"
+msgid_plural "squelched %d whitespace errors"
+msgstr[0] "%d erreur d'espace ignorée"
+msgstr[1] "%d erreurs d'espace ignorées"
+
+#: builtin/apply.c:4486 builtin/apply.c:4496
+#, c-format
+msgid "%d line adds whitespace errors."
+msgid_plural "%d lines add whitespace errors."
+msgstr[0] "%d ligne a ajouté des erreurs d'espace."
+msgstr[1] "%d lignes ont ajouté des erreurs d'espace."
+
+#: builtin/archive.c:17
+#, c-format
+msgid "could not create archive file '%s'"
+msgstr "création impossible du fichier d'archive '%s'"
+
+#: builtin/archive.c:20
+msgid "could not redirect output"
+msgstr "impossible de rediriger la sortie"
+
+#: builtin/archive.c:37
+msgid "git archive: Remote with no URL"
+msgstr "git archive : Dépôt distant sans URL"
+
+#: builtin/archive.c:58
+msgid "git archive: expected ACK/NAK, got EOF"
+msgstr "git archive : ACK/NACK attendu, EOF reçu"
+
+#: builtin/archive.c:61
+#, c-format
+msgid "git archive: NACK %s"
+msgstr "git archive : NACK %s"
+
+#: builtin/archive.c:63
+#, c-format
+msgid "remote error: %s"
+msgstr "erreur distante : %s"
+
+#: builtin/archive.c:64
+msgid "git archive: protocol error"
+msgstr "git archive : erreur de protocole"
+
+#: builtin/archive.c:68
+msgid "git archive: expected a flush"
+msgstr "git archive : vidage attendu"
+
+#: 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 "effectuer 'git bisect next'"
+
+#: builtin/bisect--helper.c:19
+msgid "update BISECT_HEAD instead of checking out the current commit"
+msgstr "mettre à jour BISECT_HEAD au lieu d'extraire le commit actuel"
+
+#: builtin/blame.c:25
+msgid "git blame [options] [rev-opts] [rev] [--] file"
+msgstr "git blame [options] [options-de-révision] [rev] [--] fichier"
+
+#: builtin/blame.c:30
+msgid "[rev-opts] are documented in git-rev-list(1)"
+msgstr "[options-de-révision] sont documentés dans git-rev-list(1)"
+
+#: builtin/blame.c:2355
+msgid "Show blame entries as we find them, incrementally"
+msgstr "Montrer les entrée de blâme au fur et à mesure de leur découverte, de manière incrémentale"
+
+#: builtin/blame.c:2356
+msgid "Show blank SHA-1 for boundary commits (Default: off)"
+msgstr "Montrer un SHA-1 blanc pour les commits de limite (Défaut : désactivé)"
+
+#: builtin/blame.c:2357
+msgid "Do not treat root commits as boundaries (Default: off)"
+msgstr "Ne pas traiter les commits racine comme des limites (Défaut : désactivé)"
+
+#: builtin/blame.c:2358
+msgid "Show work cost statistics"
+msgstr "Montrer les statistiques de coût d'activité"
+
+#: builtin/blame.c:2359
+msgid "Show output score for blame entries"
+msgstr "Montrer le score de sortie pour les entrées de blâme"
+
+#: builtin/blame.c:2360
+msgid "Show original filename (Default: auto)"
+msgstr "Montrer les noms de fichier originaux (Défaut : auto)"
+
+#: builtin/blame.c:2361
+msgid "Show original linenumber (Default: off)"
+msgstr "Montrer les numéros de lignes originaux (Défaut : désactivé)"
+
+#: builtin/blame.c:2362
+msgid "Show in a format designed for machine consumption"
+msgstr "Afficher dans un format propice à la consommation par machine"
+
+#: builtin/blame.c:2363
+msgid "Show porcelain format with per-line commit information"
+msgstr "Afficher en format porcelaine avec l'information de commit par ligne"
+
+#: builtin/blame.c:2364
+msgid "Use the same output mode as git-annotate (Default: off)"
+msgstr "Utiliser le même mode de sortie que git-annotate (Défaut : désactivé)"
+
+#: builtin/blame.c:2365
+msgid "Show raw timestamp (Default: off)"
+msgstr "Afficher les horodatages bruts (Défaut: désactivé)"
+
+#: builtin/blame.c:2366
+msgid "Show long commit SHA1 (Default: off)"
+msgstr "Afficher les longs SHA1 de commits (Défaut : désactivé)"
+
+#: builtin/blame.c:2367
+msgid "Suppress author name and timestamp (Default: off)"
+msgstr "Supprimer le nom de l'auteur et l'horodatage (Défaut : désactivé)"
+
+#: builtin/blame.c:2368
+msgid "Show author email instead of name (Default: off)"
+msgstr "Afficher l'e-mail de l'auteur au lieu du nom (Défaut : désactivé)"
+
+#: builtin/blame.c:2369
+msgid "Ignore whitespace differences"
+msgstr "Ignorer les différences d'espace"
+
+#: builtin/blame.c:2370
+msgid "Spend extra cycles to find better match"
+msgstr "Dépenser des cycles supplémentaires pour trouver une meilleure correspondance"
+
+#: builtin/blame.c:2371
+msgid "Use revisions from <file> instead of calling git-rev-list"
+msgstr "Utiliser les révisions du fichier <fichier> au lieu d'appeler git-rev-list"
+
+#: builtin/blame.c:2372
+msgid "Use <file>'s contents as the final image"
+msgstr "Utiliser le contenu de <fichier> comme image finale"
+
+#: builtin/blame.c:2373 builtin/blame.c:2374
+msgid "score"
+msgstr "score"
+
+#: builtin/blame.c:2373
+msgid "Find line copies within and across files"
+msgstr "Trouver les copies de ligne dans et entre les fichiers"
+
+#: builtin/blame.c:2374
+msgid "Find line movements within and across files"
+msgstr "Trouver les mouvements de ligne dans et entre les fichiers"
+
+#: builtin/blame.c:2375
+msgid "n,m"
+msgstr "n,m"
+
+#: builtin/blame.c:2375
+msgid "Process only line range n,m, counting from 1"
+msgstr "Traiter seulement l'intervalle de ligne n,m en commençant le compte à 1"
+
+#: builtin/branch.c:24
+msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
+msgstr "git branch [options] [-r | -a] [--merged | --no-merged]"
+
+#: builtin/branch.c:25
+msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
+msgstr "git branch [options] [-l] [-f] <nomdebranch> [<point-de-départ>]"
+
+#: builtin/branch.c:26
+msgid "git branch [options] [-r] (-d | -D) <branchname>..."
+msgstr "git branch [options] [-r] (-d | -D) <nomdebranche>..."
+
+#: builtin/branch.c:27
+msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
+msgstr "git branch [options] (-m | -M) [<anciennebranche>] <nouvellebranche>"
+
+#: builtin/branch.c:150
+#, c-format
+msgid ""
+"deleting branch '%s' that has been merged to\n"
+" '%s', but not yet merged to HEAD."
+msgstr ""
+"suppression de la branche '%s' qui a été fusionnée dans\n"
+" '%s', mais pas dans HEAD."
+
+#: builtin/branch.c:154
+#, c-format
+msgid ""
+"not deleting branch '%s' that is not yet merged to\n"
+" '%s', even though it is merged to HEAD."
+msgstr ""
+"branche '%s' non supprimée car elle n'a pas été fusionnée dans\n"
+" '%s', même si elle est fusionnée dans HEAD."
+
+#: builtin/branch.c:168
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr "Impossible de rechercher l'objet commit pour '%s'"
+
+#: builtin/branch.c:172
+#, 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 ""
+"La branche '%s' n'est pas totalement fusionnée.\n"
+"Si vous êtes sur que vous voulez la supprimer, lancez 'git branch -D %s'."
+
+#: builtin/branch.c:185
+msgid "Update of config-file failed"
+msgstr "Échec de la mise à jour du fichier de config"
+
+#: builtin/branch.c:213
+msgid "cannot use -a with -d"
+msgstr "impossible d'utiliser -a avec -d"
+
+#: builtin/branch.c:219
+msgid "Couldn't look up commit object for HEAD"
+msgstr "Impossible de rechercher l'objet commit pour HEAD"
+
+#: builtin/branch.c:227
+#, c-format
+msgid "Cannot delete the branch '%s' which you are currently on."
+msgstr "Impossible de supprimer la branche '%s' sur laquelle vous êtes."
+
+#: builtin/branch.c:240
+#, c-format
+msgid "remote branch '%s' not found."
+msgstr "branche distante %s' non trouvée."
+
+#: builtin/branch.c:241
+#, c-format
+msgid "branch '%s' not found."
+msgstr "branche '%s' non trouvée."
+
+#: builtin/branch.c:255
+#, c-format
+msgid "Error deleting remote branch '%s'"
+msgstr "Erreur lors de la suppression de la branche distante '%s'"
+
+#: builtin/branch.c:256
+#, c-format
+msgid "Error deleting branch '%s'"
+msgstr "Erreur lors de la suppression de la branche '%s'"
+
+#: builtin/branch.c:263
+#, c-format
+msgid "Deleted remote branch %s (was %s).\n"
+msgstr "Branche distante %s supprimée (précédemment %s).\n"
+
+#: builtin/branch.c:264
+#, c-format
+msgid "Deleted branch %s (was %s).\n"
+msgstr "Branche %s supprimée (précédemment %s).\n"
+
+#: builtin/branch.c:366
+#, c-format
+msgid "branch '%s' does not point at a commit"
+msgstr "la branche '%s' ne pointe pas sur un commit"
+
+#: builtin/branch.c:453
+#, c-format
+msgid "[%s: behind %d]"
+msgstr "[%s: en retard de %d]"
+
+#: builtin/branch.c:455
+#, c-format
+msgid "[behind %d]"
+msgstr "[en retard de %d]"
+
+#: builtin/branch.c:459
+#, c-format
+msgid "[%s: ahead %d]"
+msgstr "[%s : en avance de %d]"
+
+#: builtin/branch.c:461
+#, c-format
+msgid "[ahead %d]"
+msgstr "[en avance de %d]"
+
+#: builtin/branch.c:464
+#, c-format
+msgid "[%s: ahead %d, behind %d]"
+msgstr "[%s : en avance de %d, en retard de %d]"
+
+#: builtin/branch.c:467
+#, c-format
+msgid "[ahead %d, behind %d]"
+msgstr "[en avance de %d, en retard de %d]"
+
+#: builtin/branch.c:490
+msgid " **** invalid ref ****"
+msgstr " **** référence invalide ****"
+
+#: builtin/branch.c:582
+#, c-format
+msgid "(no branch, rebasing %s)"
+msgstr "(aucune branche, rebasage de %s)"
+
+#: builtin/branch.c:585
+#, c-format
+msgid "(no branch, bisect started on %s)"
+msgstr "(aucune branche, bisect a démarré sur %s)"
+
+#: builtin/branch.c:588
+#, c-format
+msgid "(detached from %s)"
+msgstr "(détaché de %s)"
+
+#: builtin/branch.c:591
+msgid "(no branch)"
+msgstr "(aucune branche)"
+
+#: builtin/branch.c:637
+#, c-format
+msgid "object '%s' does not point to a commit"
+msgstr "l'objet '%s' ne pointe pas sur un commit"
+
+#: builtin/branch.c:669
+msgid "some refs could not be read"
+msgstr "des références n'ont pas pu être lues"
+
+#: builtin/branch.c:682
+msgid "cannot rename the current branch while not on any."
+msgstr "impossible de renommer la branche actuelle, il n'y en a pas."
+
+#: builtin/branch.c:692
+#, c-format
+msgid "Invalid branch name: '%s'"
+msgstr "Nom de branche invalide : '%s'"
+
+#: builtin/branch.c:707
+msgid "Branch rename failed"
+msgstr "Echec de renommage de la branche"
+
+#: builtin/branch.c:711
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr "Renommage d'un branche mal nommée '%s'"
+
+#: builtin/branch.c:715
+#, c-format
+msgid "Branch renamed to %s, but HEAD is not updated!"
+msgstr "La branche a été renommée en %s, mais HEAD n'est pas mise à jour !"
+
+#: builtin/branch.c:722
+msgid "Branch is renamed, but update of config-file failed"
+msgstr "La branche est renommée, mais la mise à jour du fichier de config a échoué"
+
+#: builtin/branch.c:737
+#, c-format
+msgid "malformed object name %s"
+msgstr "nom d'objet malformé %s"
+
+#: builtin/branch.c:761
+#, c-format
+msgid "could not write branch description template: %s"
+msgstr "impossible d'écrire le modèle de description de branche : %s"
+
+#: builtin/branch.c:791
+msgid "Generic options"
+msgstr "Options génériques"
+
+#: builtin/branch.c:793
+msgid "show hash and subject, give twice for upstream branch"
+msgstr "afficher le hachage et le sujet, doublé pour la branche amont"
+
+#: builtin/branch.c:794
+msgid "suppress informational messages"
+msgstr "supprimer les messages d'information"
+
+#: builtin/branch.c:795
+msgid "set up tracking mode (see git-pull(1))"
+msgstr "régler le mode de suivi (voir git-pull(1))"
+
+#: builtin/branch.c:797
+msgid "change upstream info"
+msgstr "modifier l'information amont"
+
+#: builtin/branch.c:801
+msgid "use colored output"
+msgstr "utiliser la coloration dans la sortie"
+
+#: builtin/branch.c:802
+msgid "act on remote-tracking branches"
+msgstr "agir sur les branches de suivi distantes"
+
+#: builtin/branch.c:805 builtin/branch.c:811 builtin/branch.c:832
+#: builtin/branch.c:838 builtin/commit.c:1368 builtin/commit.c:1369
+#: builtin/commit.c:1370 builtin/commit.c:1371 builtin/tag.c:468
+msgid "commit"
+msgstr "valider"
+
+#: builtin/branch.c:806 builtin/branch.c:812
+msgid "print only branches that contain the commit"
+msgstr "afficher seulement les branches qui contiennent le commit"
+
+#: builtin/branch.c:818
+msgid "Specific git-branch actions:"
+msgstr "Actions spécifiques à git-branch :"
+
+#: builtin/branch.c:819
+msgid "list both remote-tracking and local branches"
+msgstr "afficher à la fois les branches de suivi et les branches locales"
+
+#: builtin/branch.c:821
+msgid "delete fully merged branch"
+msgstr "supprimer une branche totalement fusionnée"
+
+#: builtin/branch.c:822
+msgid "delete branch (even if not merged)"
+msgstr "supprimer une branche (même non fusionnée)"
+
+#: builtin/branch.c:823
+msgid "move/rename a branch and its reflog"
+msgstr "déplacer/renommer une branche et son reflog"
+
+#: builtin/branch.c:824
+msgid "move/rename a branch, even if target exists"
+msgstr "déplacer/renommer une branche, même si la cible existe"
+
+#: builtin/branch.c:825
+msgid "list branch names"
+msgstr "afficher les noms des branches"
+
+#: builtin/branch.c:826
+msgid "create the branch's reflog"
+msgstr "créer le reflog de la branche"
+
+#: builtin/branch.c:828
+msgid "edit the description for the branch"
+msgstr "éditer la description de la branche"
+
+#: builtin/branch.c:829
+msgid "force creation (when already exists)"
+msgstr "forcer la création (même si la cible existe)"
+
+#: builtin/branch.c:832
+msgid "print only not merged branches"
+msgstr "afficher seulement les branches non fusionnées"
+
+#: builtin/branch.c:838
+msgid "print only merged branches"
+msgstr "afficher seulement les branches fusionnées"
+
+#: builtin/branch.c:842
+msgid "list branches in columns"
+msgstr "afficher les branches en colonnes"
+
+#: builtin/branch.c:855
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Échec de résolution de HEAD comme référence valide."
+
+#: builtin/branch.c:860 builtin/clone.c:619
+msgid "HEAD not found below refs/heads!"
+msgstr "HEAD non trouvée sous refs/heads !"
+
+#: builtin/branch.c:883
+msgid "--column and --verbose are incompatible"
+msgstr "--column et --verbose sont incompatibles"
+
+#: builtin/branch.c:889 builtin/branch.c:928
+msgid "branch name required"
+msgstr "le nom de branche est requis"
+
+#: builtin/branch.c:904
+msgid "Cannot give description to detached HEAD"
+msgstr "Impossible de décrire une HEAD détachée"
+
+#: builtin/branch.c:909
+msgid "cannot edit description of more than one branch"
+msgstr "impossible d'éditer la description de plus d'une branche"
+
+#: builtin/branch.c:916
+#, c-format
+msgid "No commit on branch '%s' yet."
+msgstr "Aucun commit sur la branche '%s'."
+
+#: builtin/branch.c:919
+#, c-format
+msgid "No branch named '%s'."
+msgstr "Aucune branche nommée '%s'."
+
+#: builtin/branch.c:934
+msgid "too many branches for a rename operation"
+msgstr "trop de branches pour une opération de renommage"
+
+#: builtin/branch.c:939
+msgid "too many branches to set new upstream"
+msgstr "trop de branches pour spécifier une branche amont"
+
+#: builtin/branch.c:943
+#, c-format
+msgid ""
+"could not set upstream of HEAD to %s when it does not point to any branch."
+msgstr "impossible de spécifier une branche amont de HEAD par %s qui ne pointe sur aucune branche."
+
+#: builtin/branch.c:946 builtin/branch.c:968 builtin/branch.c:990
+#, c-format
+msgid "no such branch '%s'"
+msgstr "pas de branche '%s'"
+
+#: builtin/branch.c:950
+#, c-format
+msgid "branch '%s' does not exist"
+msgstr "la branche '%s' n'existe pas"
+
+#: builtin/branch.c:962
+msgid "too many branches to unset upstream"
+msgstr "trop de branches pour désactiver un amont"
+
+#: builtin/branch.c:966
+msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgstr "impossible de désactiver une branche amont de HEAD quand elle ne pointe sur aucune branche."
+
+#: builtin/branch.c:972
+#, c-format
+msgid "Branch '%s' has no upstream information"
+msgstr "La branche '%s' n'a aucune information de branche amont"
+
+#: builtin/branch.c:987
+msgid "it does not make sense to create 'HEAD' manually"
+msgstr "créer manuellement 'HEAD' n'a aucun sens"
+
+#: builtin/branch.c:993
+msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+msgstr "les options -a et -r de 'git branch' n'ont pas de sens avec un nom de branche"
+
+#: builtin/branch.c:996
+#, c-format
+msgid ""
+"The --set-upstream flag is deprecated and will be removed. Consider using --"
+"track or --set-upstream-to\n"
+msgstr "l'option --set-upstream est obsolète et va disparaître. Utilisez plutôt --track ou --set-upstream-to\n"
+
+#: builtin/branch.c:1013
+#, c-format
+msgid ""
+"\n"
+"If you wanted to make '%s' track '%s', do this:\n"
+"\n"
+msgstr "\n"
+"Si vous vouliez que '%s' suive '%s', faîtes ceci :\n"
+"\n"
+
+#: builtin/branch.c:1014
+#, c-format
+msgid " git branch -d %s\n"
+msgstr " git branch -d %s\n"
+
+#: builtin/branch.c:1015
+#, c-format
+msgid " git branch --set-upstream-to %s\n"
+msgstr " git branch -set-upstream-to %s\n"
+
+#: builtin/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
+msgstr "%s est correct\n"
+
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
+msgstr "La création d'un colis requiert un dépôt."
+
+#: builtin/bundle.c:60
+msgid "Need a repository to unbundle."
+msgstr "Le dépaquetage d'un colis requiert un dépôt."
+
+#: builtin/cat-file.c:176
+msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
+msgstr "git cat-file (-t|-s|-e|-p|<type>|--textconv) <objet>"
+
+#: builtin/cat-file.c:177
+msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
+msgstr "git cat-file (--batch|--batch-check) < <liste_d_objets>"
+
+#: builtin/cat-file.c:195
+msgid "<type> can be one of: blob, tree, commit, tag"
+msgstr "<type> peut être : blob, tree, commit ou tag"
+
+#: builtin/cat-file.c:196
+msgid "show object type"
+msgstr "afficher le type de l'objet"
+
+#: builtin/cat-file.c:197
+msgid "show object size"
+msgstr "afficher la taille de l'objet"
+
+#: builtin/cat-file.c:199
+msgid "exit with zero when there's no error"
+msgstr "sortir avec un code d'erreur nul quand il n'y a aucune erreur"
+
+#: builtin/cat-file.c:200
+msgid "pretty-print object's content"
+msgstr "afficher avec mise en forme le contenu de l'objet"
+
+#: builtin/cat-file.c:202
+msgid "for blob objects, run textconv on object's content"
+msgstr "pour les objets blob, lancer textconv sur le contenu de l'objet"
+
+#: builtin/cat-file.c:204
+msgid "show info and content of objects fed from the standard input"
+msgstr "afficher l'information et le contenu des objets passés en entrée standard"
+
+#: builtin/cat-file.c:207
+msgid "show info about objects fed from the standard input"
+msgstr "afficher l'information des objets passés en entrée standard"
+
+#: builtin/check-attr.c:11
+msgid "git check-attr [-a | --all | attr...] [--] pathname..."
+msgstr "git check-attr [-a | --all | attr...] [--] chemin..."
+
+#: builtin/check-attr.c:12
+msgid "git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"
+msgstr "git check-attr --stdin [-z] [-a | --all | attr...] < <liste-de-chemins>"
+
+#: builtin/check-attr.c:19
+msgid "report all attributes set on file"
+msgstr "afficher tous les attributs associés au fichier"
+
+#: builtin/check-attr.c:20
+msgid "use .gitattributes only from the index"
+msgstr "utiliser .gitattributes seulement depuis l'index"
+
+#: builtin/check-attr.c:21 builtin/check-ignore.c:22 builtin/hash-object.c:75
+msgid "read file names from stdin"
+msgstr "lire les noms de fichier depuis stdin"
+
+#: builtin/check-attr.c:23 builtin/check-ignore.c:24
+msgid "input paths are terminated by a null character"
+msgstr "les chemins en entrée sont terminés par le caractère nul"
+
+#: builtin/check-ignore.c:18 builtin/checkout.c:1044 builtin/gc.c:177
+msgid "suppress progress reporting"
+msgstr "supprimer l'état d'avancement"
+
+#: builtin/check-ignore.c:146
+msgid "cannot specify pathnames with --stdin"
+msgstr "impossible de spécifier les chemins avec --stdin"
+
+#: builtin/check-ignore.c:149
+msgid "-z only makes sense with --stdin"
+msgstr "-z n'a de sens qu'avec l'option --stdin"
+
+#: builtin/check-ignore.c:151
+msgid "no path specified"
+msgstr "aucun chemin spécifié"
+
+#: builtin/check-ignore.c:155
+msgid "--quiet is only valid with a single pathname"
+msgstr "--quiet n'est valide qu'avec un seul chemin"
+
+#: builtin/check-ignore.c:157
+msgid "cannot have both --quiet and --verbose"
+msgstr "impossible d'avoir --quiet et --verbose"
+
+#: builtin/checkout-index.c:126
+msgid "git checkout-index [options] [--] [<file>...]"
+msgstr "git checkout-index [options] [--] [<fichier>...]"
+
+#: builtin/checkout-index.c:187
+msgid "check out all files in the index"
+msgstr "extraire tous les fichiers présents dans l'index"
+
+#: builtin/checkout-index.c:188
+msgid "force overwrite of existing files"
+msgstr "forcer l'écrasement des fichiers existants"
+
+#: builtin/checkout-index.c:190
+msgid "no warning for existing files and files not in index"
+msgstr "pas d'avertissement pour les fichiers existants et les fichiers absents de l'index"
+
+#: builtin/checkout-index.c:192
+msgid "don't checkout new files"
+msgstr "ne pas extraire les nouveaux fichiers"
+
+#: builtin/checkout-index.c:194
+msgid "update stat information in the index file"
+msgstr "mettre à jour l'information de stat dans le fichier d'index"
+
+#: builtin/checkout-index.c:200
+msgid "read list of paths from the standard input"
+msgstr "lire la liste des chemins depuis l'entrée standard"
+
+#: builtin/checkout-index.c:202
+msgid "write the content to temporary files"
+msgstr "écrire le contenu dans des fichiers temporaires"
+
+#: builtin/checkout-index.c:203 builtin/column.c:30
+msgid "string"
+msgstr "chaîne"
+
+#: builtin/checkout-index.c:204
+msgid "when creating files, prepend <string>"
+msgstr "lors de la création de fichiers, préfixer par <chaîne>"
+
+#: builtin/checkout-index.c:207
+msgid "copy out the files from named stage"
+msgstr "copier les fichiers depuis l'index nommé"
+
+#: builtin/checkout.c:25
+msgid "git checkout [options] <branch>"
+msgstr "git checkout [options] <branche>"
+
+#: builtin/checkout.c:26
+msgid "git checkout [options] [<branch>] -- <file>..."
+msgstr "git checkout [options] [<branche>] -- <fichier>..."
+
+#: builtin/checkout.c:117 builtin/checkout.c:150
+#, c-format
+msgid "path '%s' does not have our version"
+msgstr "le chemin '%s' n'a pas notre version"
+
+#: builtin/checkout.c:119 builtin/checkout.c:152
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr "le chemin '%s' n'a pas leur version"
+
+#: builtin/checkout.c:135
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr "le chemin '%s' n'a aucune des versions nécessaires"
+
+#: builtin/checkout.c:179
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr "le chemin '%s' n'a pas les versions nécessaires"
+
+#: builtin/checkout.c:196
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr "chemin '%s' : impossible de fusionner"
+
+#: builtin/checkout.c:213
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr "Impossible d'ajouter le résultat de fusion pour '%s'"
+
+#: builtin/checkout.c:237 builtin/checkout.c:240 builtin/checkout.c:243
+#: builtin/checkout.c:246
+#, c-format
+msgid "'%s' cannot be used with updating paths"
+msgstr "'%s' ne peut pas être utilisé avec des mises à jour de chemins"
+
+#: builtin/checkout.c:249 builtin/checkout.c:252
+#, c-format
+msgid "'%s' cannot be used with %s"
+msgstr "'%s' ne peut pas être utilisé avec %s"
+
+#: builtin/checkout.c:255
+#, c-format
+msgid "Cannot update paths and switch to branch '%s' at the same time."
+msgstr "Impossible de mettre à jour les chemins et basculer sur la branche '%s' en même temps."
+
+#: builtin/checkout.c:266 builtin/checkout.c:458
+msgid "corrupt index file"
+msgstr "fichier d'index corrompu"
+
+#: builtin/checkout.c:329 builtin/checkout.c:336
+#, c-format
+msgid "path '%s' is unmerged"
+msgstr "le chemin '%s' n'est pas fusionné"
+
+#: builtin/checkout.c:480
+msgid "you need to resolve your current index first"
+msgstr "vous devez d'abord résoudre votre index courant"
+
+#: builtin/checkout.c:601
+#, c-format
+msgid "Can not do reflog for '%s'\n"
+msgstr "Impossible de faire un reflog pour '%s'\n"
+
+#: builtin/checkout.c:634
+msgid "HEAD is now at"
+msgstr "HEAD est maintenant sur"
+
+#: builtin/checkout.c:641
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr "Remise à zéro de la branche '%s'\n"
+
+#: builtin/checkout.c:644
+#, c-format
+msgid "Already on '%s'\n"
+msgstr "Déjà sur '%s'\n"
+
+#: builtin/checkout.c:648
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr "Basculement et remise à zéro de la branche '%s'\n"
+
+#: builtin/checkout.c:650 builtin/checkout.c:987
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr "Basculement sur la nouvelle branche '%s'\n"
+
+#: builtin/checkout.c:652
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr "Basculement sur la branche '%s'\n"
+
+#: builtin/checkout.c:708
+#, c-format
+msgid " ... and %d more.\n"
+msgstr " ... et %d en plus.\n"
+
+#. The singular version
+#: builtin/checkout.c:714
+#, c-format
+msgid ""
+"Warning: you are leaving %d commit behind, not connected to\n"
+"any of your branches:\n"
+"\n"
+"%s\n"
+msgid_plural ""
+"Warning: you are leaving %d commits behind, not connected to\n"
+"any of your branches:\n"
+"\n"
+"%s\n"
+msgstr[0] ""
+"Attention : vous laissez %d commit en retard, non connectés à\n"
+"une branche :\n"
+"\n"
+"%s\n"
+msgstr[1] ""
+"Attention : vous laissez %d commits en retard, non connectés à\n"
+"une branche :\n"
+"\n"
+"%s\n"
+
+#: builtin/checkout.c:732
+#, c-format
+msgid ""
+"If you want to keep them by creating a new branch, this may be a good time\n"
+"to do so with:\n"
+"\n"
+" git branch new_branch_name %s\n"
+"\n"
+msgstr ""
+"Si vous souhaitez les garder en créant une nouvelle branche, c'est le bon moment\n"
+"de le faire avec :\n"
+"\n"
+"git branche nouvelle_branche %s\n"
+"\n"
+
+#: builtin/checkout.c:762
+msgid "internal error in revision walk"
+msgstr "erreur interne lors du parcours des révisions"
+
+#: builtin/checkout.c:766
+msgid "Previous HEAD position was"
+msgstr "La position précédente de HEAD était"
+
+#: builtin/checkout.c:793 builtin/checkout.c:982
+msgid "You are on a branch yet to be born"
+msgstr "Vous êtes sur une branche qui doit encore naître"
+
+#. case (1)
+#: builtin/checkout.c:918
+#, c-format
+msgid "invalid reference: %s"
+msgstr "référence invalide : %s"
+
+#. case (1): want a tree
+#: builtin/checkout.c:957
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr "la référence n'est pas un arbre : %s"
+
+#: builtin/checkout.c:996
+msgid "paths cannot be used with switching branches"
+msgstr "impossible d'utiliser des chemins avec un basculement de branches"
+
+#: builtin/checkout.c:999 builtin/checkout.c:1003
+#, c-format
+msgid "'%s' cannot be used with switching branches"
+msgstr "'%s' ne peut pas être utilisé avec un basculement de branches"
+
+#: builtin/checkout.c:1007 builtin/checkout.c:1010 builtin/checkout.c:1015
+#: builtin/checkout.c:1018
+#, c-format
+msgid "'%s' cannot be used with '%s'"
+msgstr "'%s' ne peut pas être utilisé avec '%s'"
+
+#: builtin/checkout.c:1023
+#, c-format
+msgid "Cannot switch branch to a non-commit '%s'"
+msgstr "Impossible de basculer de branche vers '%s' qui n'est pas un commit"
+
+#: builtin/checkout.c:1045 builtin/checkout.c:1047 builtin/clone.c:90
+#: builtin/remote.c:169 builtin/remote.c:171
+msgid "branch"
+msgstr "branche"
+
+#: builtin/checkout.c:1046
+msgid "create and checkout a new branch"
+msgstr "créer et extraire une nouvelle branche"
+
+#: builtin/checkout.c:1048
+msgid "create/reset and checkout a branch"
+msgstr "créer/réinitialiser et extraire une branche"
+
+#: builtin/checkout.c:1049
+msgid "create reflog for new branch"
+msgstr "créer un refog pour une nouvelle branche"
+
+#: builtin/checkout.c:1050
+msgid "detach the HEAD at named commit"
+msgstr "détacher la HEAD à la validation nommée"
+
+#: builtin/checkout.c:1051
+msgid "set upstream info for new branch"
+msgstr "paramétrer l'information de branche amont pour une nouvelle branche"
+
+#: builtin/checkout.c:1053
+msgid "new branch"
+msgstr "nouvelle branche"
+
+#: builtin/checkout.c:1053
+msgid "new unparented branch"
+msgstr "nouvelle branche sans parent"
+
+#: builtin/checkout.c:1054
+msgid "checkout our version for unmerged files"
+msgstr "extraire notre version pour les fichiers non fusionnés"
+
+#: builtin/checkout.c:1056
+msgid "checkout their version for unmerged files"
+msgstr "extraire leur version pour les fichiers non fusionnés"
+
+#: builtin/checkout.c:1058
+msgid "force checkout (throw away local modifications)"
+msgstr "forcer l'extraction (laisser tomber les modifications locales)"
+
+#: builtin/checkout.c:1059
+msgid "perform a 3-way merge with the new branch"
+msgstr "réaliser une fusion à 3 points avec la nouvelle branche"
+
+#: builtin/checkout.c:1060 builtin/merge.c:217
+msgid "update ignored files (default)"
+msgstr "mettre à jour les fichiers ignorés (par défaut)"
+
+#: builtin/checkout.c:1061 builtin/log.c:1158 parse-options.h:245
+msgid "style"
+msgstr "style"
+
+#: builtin/checkout.c:1062
+msgid "conflict style (merge or diff3)"
+msgstr "style de conflit (fusion ou diff3)"
+
+#: builtin/checkout.c:1065
+msgid "do not limit pathspecs to sparse entries only"
+msgstr "ne pas limiter les spécificateurs de chemins aux seules entrées creuses"
+
+#: builtin/checkout.c:1067
+msgid "second guess 'git checkout no-such-branch'"
+msgstr "deuxième chance 'git checkout branche-inexistante'"
+
+#: builtin/checkout.c:1091
+msgid "-b, -B and --orphan are mutually exclusive"
+msgstr "-b, -B et --orphan sont mutuellement exclusifs"
+
+#: builtin/checkout.c:1108
+msgid "--track needs a branch name"
+msgstr "--track requiert un nom de branche"
+
+#: builtin/checkout.c:1115
+msgid "Missing branch name; try -b"
+msgstr "Nom de branche manquant ; essayez -b"
+
+#: builtin/checkout.c:1150
+msgid "invalid path specification"
+msgstr "spécification de chemin invalide"
+
+#: builtin/checkout.c:1157
+#, c-format
+msgid ""
+"Cannot update paths and switch to branch '%s' at the same time.\n"
+"Did you intend to checkout '%s' which can not be resolved as commit?"
+msgstr ""
+"Impossible de mettre à jour les chemins et de basculer sur la branche '%s' en même temps.\n"
+"Souhaitiez-vous extraire '%s' qui ne peut être résolu comme commit ?"
+
+#: builtin/checkout.c:1162
+#, c-format
+msgid "git checkout: --detach does not take a path argument '%s'"
+msgstr "git checkout: --detach n'accepte pas un argument de chemin '%s'"
+
+#: builtin/checkout.c:1166
+msgid ""
+"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+"checking out of the index."
+msgstr ""
+"git checkout: --ours/--theirs, --force et --merge sont incompatibles lors\n"
+"de l'extraction de l'index."
+
+#: builtin/clean.c:20
+msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr "git clean [-d] [-f] [-n] [-q] [-e <motif>] [-x | -X] [--] <chemins>..."
+
+#: builtin/clean.c:24
+#, c-format
+msgid "Removing %s\n"
+msgstr "Suppression de %s\n"
+
+#: builtin/clean.c:25
+#, c-format
+msgid "Would remove %s\n"
+msgstr "Supprimerait %s\n"
+
+#: builtin/clean.c:26
+#, c-format
+msgid "Skipping repository %s\n"
+msgstr "Ignore le dépôt %s\n"
+
+#: builtin/clean.c:27
+#, c-format
+msgid "Would skip repository %s\n"
+msgstr "Ignorerait le dépôt %s\n"
+
+#: builtin/clean.c:28
+#, c-format
+msgid "failed to remove %s"
+msgstr "échec de la suppression de %s"
+
+#: builtin/clean.c:160
+msgid "do not print names of files removed"
+msgstr "ne pas afficher les noms des fichiers supprimés"
+
+#: builtin/clean.c:162
+msgid "force"
+msgstr "forcer"
+
+#: builtin/clean.c:164
+msgid "remove whole directories"
+msgstr "supprimer les répertoires entiers"
+
+#: builtin/clean.c:165 builtin/describe.c:412 builtin/grep.c:717
+#: builtin/ls-files.c:487 builtin/name-rev.c:231 builtin/show-ref.c:182
+msgid "pattern"
+msgstr "motif"
+
+#: builtin/clean.c:166
+msgid "add <pattern> to ignore rules"
+msgstr "ajouter <motif> aux règles ignore"
+
+#: builtin/clean.c:167
+msgid "remove ignored files, too"
+msgstr "supprimer les fichiers ignorés, aussi"
+
+#: builtin/clean.c:169
+msgid "remove only ignored files"
+msgstr "supprimer seulement les fichiers ignorés"
+
+#: builtin/clean.c:187
+msgid "-x and -X cannot be used together"
+msgstr "-x et -X ne peuvent pas être utilisés ensemble"
+
+#: builtin/clean.c:191
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr "clean.requireForce positionné à true et ni -n ni -f fourni ; refus de nettoyer"
+
+#: builtin/clean.c:194
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr "clean.requireForce à true par défaut et ni -n ni -f fourni ; refus de nettoyer"
+
+#: builtin/clone.c:37
+msgid "git clone [options] [--] <repo> [<dir>]"
+msgstr "git clone [options] [--] <dépôt> [<répertoire>]"
+
+#: builtin/clone.c:65 builtin/fetch.c:82 builtin/merge.c:214
+#: builtin/push.c:436
+msgid "force progress reporting"
+msgstr "forcer l'état d'avancement"
+
+#: builtin/clone.c:67
+msgid "don't create a checkout"
+msgstr "ne pas créer d'extraction"
+
+#: builtin/clone.c:68 builtin/clone.c:70 builtin/init-db.c:488
+msgid "create a bare repository"
+msgstr "créer un dépôt nu"
+
+#: builtin/clone.c:73
+msgid "create a mirror repository (implies bare)"
+msgstr "créer un dépôt miroir (implique dépôt nu)"
+
+#: builtin/clone.c:75
+msgid "to clone from a local repository"
+msgstr "pour cloner depuis un dépôt local"
+
+#: builtin/clone.c:77
+msgid "don't use local hardlinks, always copy"
+msgstr "ne pas utiliser de liens durs locaux, toujours copier"
+
+#: builtin/clone.c:79
+msgid "setup as shared repository"
+msgstr "régler comme dépôt partagé"
+
+#: builtin/clone.c:81 builtin/clone.c:83
+msgid "initialize submodules in the clone"
+msgstr "initialiser les sous-modules dans le clone"
+
+#: builtin/clone.c:84 builtin/init-db.c:485
+msgid "template-directory"
+msgstr "répertoire-modèle"
+
+#: builtin/clone.c:85 builtin/init-db.c:486
+msgid "directory from which templates will be used"
+msgstr "répertoire depuis lequel les modèles vont être utilisés"
+
+#: builtin/clone.c:87
+msgid "reference repository"
+msgstr "dépôt de référence"
+
+#: builtin/clone.c:88 builtin/column.c:26 builtin/merge-file.c:44
+msgid "name"
+msgstr "nom"
+
+#: builtin/clone.c:89
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "utiliser <nom> au lieu de 'origin' pour suivre la branche amont"
+
+#: builtin/clone.c:91
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "extraire <branche> au lieu de la HEAD du répertoire distant"
+
+#: builtin/clone.c:93
+msgid "path to git-upload-pack on the remote"
+msgstr "chemin vers git-upload-pack sur le serveur distant"
+
+#: builtin/clone.c:94 builtin/fetch.c:83 builtin/grep.c:662
+msgid "depth"
+msgstr "profondeur"
+
+#: builtin/clone.c:95
+msgid "create a shallow clone of that depth"
+msgstr "créer un clone superficiel de cette profondeur"
+
+#: builtin/clone.c:97
+msgid "clone only one branch, HEAD or --branch"
+msgstr "cloner seulement une branche, HEAD ou --branch"
+
+#: builtin/clone.c:98 builtin/init-db.c:494
+msgid "gitdir"
+msgstr "gitdir"
+
+#: builtin/clone.c:99 builtin/init-db.c:495
+msgid "separate git dir from working tree"
+msgstr "séparer le répertoire git de la copie de travail"
+
+#: builtin/clone.c:100
+msgid "key=value"
+msgstr "clé=valeur"
+
+#: builtin/clone.c:101
+msgid "set config inside the new repository"
+msgstr "régler la configuration dans le nouveau dépôt"
+
+#: builtin/clone.c:254
+#, c-format
+msgid "reference repository '%s' is not a local repository."
+msgstr "le dépôt de référence '%s' n'est pas un dépôt local."
+
+#: builtin/clone.c:317
+#, c-format
+msgid "failed to create directory '%s'"
+msgstr "échec de la création du répertoire '%s'"
+
+#: builtin/clone.c:319 builtin/diff.c:77
+#, c-format
+msgid "failed to stat '%s'"
+msgstr "échec du stat de '%s'"
+
+#: builtin/clone.c:321
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr "%s existe et n'est pas un répertoire"
+
+#: builtin/clone.c:335
+#, c-format
+msgid "failed to stat %s\n"
+msgstr "échec du stat de %s\n"
+
+#: builtin/clone.c:357
+#, c-format
+msgid "failed to create link '%s'"
+msgstr "échec de la création du lien '%s'"
+
+#: builtin/clone.c:361
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr "échec de la copie vers '%s'"
+
+#: builtin/clone.c:384
+#, c-format
+msgid "done.\n"
+msgstr "fait.\n"
+
+#: builtin/clone.c:397
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry the checkout with 'git checkout -f HEAD'\n"
+msgstr "Le clone a réussi, mais l'extraction a échoué.\n"
+"Vous pouvez inspecter ce qui a été extrait avec 'git status'\n"
+"et réessayer l'extraction avec 'git checkout -f HEAD'\n"
+
+#: builtin/clone.c:476
+#, c-format
+msgid "Could not find remote branch %s to clone."
+msgstr "Impossible de trouver la branche distante '%s' à cloner."
+
+#: builtin/clone.c:550
+msgid "remote did not send all necessary objects"
+msgstr "le serveur distant n'a pas envoyé tous les objets nécessaires"
+
+#: builtin/clone.c:610
+msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgstr "la HEAD distante réfère à une référence non existante, impossible de l'extraire.\n"
+
+#: builtin/clone.c:641
+msgid "unable to checkout working tree"
+msgstr "inpossible d'extraire la copie de travail"
+
+#: builtin/clone.c:749
+msgid "Too many arguments."
+msgstr "Trop d'arguments."
+
+#: builtin/clone.c:753
+msgid "You must specify a repository to clone."
+msgstr "Vous devez spécifier un dépôt à cloner."
+
+#: builtin/clone.c:764
+#, c-format
+msgid "--bare and --origin %s options are incompatible."
+msgstr "les options --bare et --origin %s sont incompatibles."
+
+#: builtin/clone.c:767
+msgid "--bare and --separate-git-dir are incompatible."
+msgstr "--bare et --separate-git-dir sont incompatibles."
+
+#: builtin/clone.c:780
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr "le dépôt '%s' n'existe pas"
+
+#: builtin/clone.c:785
+msgid "--depth is ignored in local clones; use file:// instead."
+msgstr "--depth est ignoré dans les clones locaux : utilisez plutôt \"file://\"."
+
+#: builtin/clone.c:795
+#, c-format
+msgid "destination path '%s' already exists and is not an empty directory."
+msgstr "le chemin de destination '%s' existe déjà et n'est pas un répertoire vide."
+
+#: builtin/clone.c:805
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr "la copie de travail '%s' existe déjà."
+
+#: builtin/clone.c:818 builtin/clone.c:830
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr "impossible de créer les répertoires de premier niveau dans '%s'"
+
+#: builtin/clone.c:821
+#, c-format
+msgid "could not create work tree dir '%s'."
+msgstr "impossible de créer le répertoire de la copie de travail '%s'."
+
+#: builtin/clone.c:840
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr "Clonage dans le dépôt nu '%s'\n"
+
+#: builtin/clone.c:842
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr "Clonage dans '%s'...\n"
+
+#: builtin/clone.c:877
+#, c-format
+msgid "Don't know how to clone %s"
+msgstr "Je ne sais pas cloner %s"
+
+#: builtin/clone.c:926
+#, c-format
+msgid "Remote branch %s not found in upstream %s"
+msgstr "La branche distante %s n'a pas été trouvée dans le dépôt amont %s"
+
+#: builtin/clone.c:933
+msgid "You appear to have cloned an empty repository."
+msgstr "Vous semblez avoir cloné un dépôt vide."
+
+#: builtin/column.c:9
+msgid "git column [options]"
+msgstr "git column [options]"
+
+#: builtin/column.c:26
+msgid "lookup config vars"
+msgstr "rechercher les variables de configuration"
+
+#: builtin/column.c:27 builtin/column.c:28
+msgid "layout to use"
+msgstr "mise en page à utiliser"
+
+#: builtin/column.c:29
+msgid "Maximum width"
+msgstr "Largeur maximale"
+
+#: builtin/column.c:30
+msgid "Padding space on left border"
+msgstr "Remplissage d'espace sur la bordure gauche"
+
+#: builtin/column.c:31
+msgid "Padding space on right border"
+msgstr "Remplissage d'espace sur le côté droit"
+
+#: builtin/column.c:32
+msgid "Padding space between columns"
+msgstr "Remplissage d'espace entre les colonnes"
+
+#: builtin/column.c:51
+msgid "--command must be the first argument"
+msgstr "--command doit être le premier argument"
+
+#: builtin/commit.c:34
+msgid "git commit [options] [--] <pathspec>..."
+msgstr "git commit [options] [--] <spécification-de-chemin>..."
+
+#: builtin/commit.c:39
+msgid "git status [options] [--] <pathspec>..."
+msgstr "git status [options] [--] <spécification-de-chemin>..."
+
+#: builtin/commit.c:44
+msgid ""
+"Your name and email address were configured automatically based\n"
+"on your username and hostname. Please check that they are accurate.\n"
+"You can suppress this message by setting them explicitly:\n"
+"\n"
+" git config --global user.name \"Your Name\"\n"
+" git config --global user.email you@example.com\n"
+"\n"
+"After doing this, you may fix the identity used for this commit with:\n"
+"\n"
+" git commit --amend --reset-author\n"
+msgstr ""
+"Votre nom et votre adresse e-mail ont été configurés automatiquement en se fondant\n"
+"sur votre nom d'utilisateur et votre nom d'ordinateur. Veuillez vérifier qu'ils sont corrects.\n"
+"Vous pouvez supprimer ce message en les paramétrant explicitement :\n"
+"\n"
+" git config --global user.name \"Votre Nom\"\n"
+" git config --global user.email vous@exemple.com\n"
+"\n"
+"Après ceci, vous pouvez corriger l'identité utilisée pour ce commit avec :\n"
+"\n"
+" git commit --amend --reset-author\n"
+
+#: builtin/commit.c:56
+msgid ""
+"You asked to amend the most recent commit, but doing so would make\n"
+"it empty. You can repeat your command with --allow-empty, or you can\n"
+"remove the commit entirely with \"git reset HEAD^\".\n"
+msgstr "Vous avez demandé de corriger le commit le plus récent, mais le faire le rendrait\n"
+"vide. Vous pouvez répéter votre commande avec --allow-empty, ou vous pouvez\n"
+"supprimer complètement le commit avec \"git reset HEAD^\".\n"
+
+#: builtin/commit.c:61
+msgid ""
+"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
+"If you wish to commit it anyway, use:\n"
+"\n"
+" git commit --allow-empty\n"
+"\n"
+"Otherwise, please use 'git reset'\n"
+msgstr ""
+"Le picorage précédent est à présent vide, vraisemblablement dû à une résolution de conflit.\n"
+"Si vous souhaitez tout de même le valider, utilisez :\n"
+"\n"
+" git commit --allow-empty\n"
+"\n"
+"Sinon, utilisez 'git reset'\n"
+
+#: builtin/commit.c:260
+msgid "failed to unpack HEAD tree object"
+msgstr "échec du dépaquetage de l'objet arbre HEAD"
+
+#: builtin/commit.c:302
+msgid "unable to create temporary index"
+msgstr "impossible de créer l'index temporaire"
+
+#: builtin/commit.c:308
+msgid "interactive add failed"
+msgstr "échec de l'ajout interactif"
+
+#: builtin/commit.c:341 builtin/commit.c:362 builtin/commit.c:412
+msgid "unable to write new_index file"
+msgstr "impossible d'écrire le fichier new_index"
+
+#: builtin/commit.c:393
+msgid "cannot do a partial commit during a merge."
+msgstr "impossible de faire une validation partielle pendant une fusion."
+
+#: builtin/commit.c:395
+msgid "cannot do a partial commit during a cherry-pick."
+msgstr "impossible de faire une validation partielle pendant un picorage."
+
+#: builtin/commit.c:405
+msgid "cannot read the index"
+msgstr "impossible de lire l'index"
+
+#: builtin/commit.c:425
+msgid "unable to write temporary index file"
+msgstr "impossible d'écrire le fichier d'index temporaire"
+
+#: builtin/commit.c:513 builtin/commit.c:519
+#, c-format
+msgid "invalid commit: %s"
+msgstr "commit invalide : %s"
+
+#: builtin/commit.c:542
+msgid "malformed --author parameter"
+msgstr "paramètre --author mal formé"
+
+#: builtin/commit.c:562
+#, c-format
+msgid "Malformed ident string: '%s'"
+msgstr "Chaîne ident mal formée : '%s'"
+
+#: builtin/commit.c:600 builtin/commit.c:633 builtin/commit.c:956
+#, c-format
+msgid "could not lookup commit %s"
+msgstr "impossible de rechercher le commit %s"
+
+#: builtin/commit.c:612 builtin/shortlog.c:270
+#, c-format
+msgid "(reading log message from standard input)\n"
+msgstr "(lecture du message de journal depuis l'entrée standard)\n"
+
+#: builtin/commit.c:614
+msgid "could not read log from standard input"
+msgstr "impossible de lire le journal depuis l'entrée standard"
+
+#: builtin/commit.c:618
+#, c-format
+msgid "could not read log file '%s'"
+msgstr "impossible de lire le fichier de journal '%s'"
+
+#: builtin/commit.c:624
+msgid "commit has empty message"
+msgstr "le commit a un message vide"
+
+#: builtin/commit.c:640
+msgid "could not read MERGE_MSG"
+msgstr "impossible de lire MERGE_MSG"
+
+#: builtin/commit.c:644
+msgid "could not read SQUASH_MSG"
+msgstr "impossible de lire SQUASH_MSG"
+
+#: builtin/commit.c:648
+#, c-format
+msgid "could not read '%s'"
+msgstr "impossible de lire '%s'"
+
+#: builtin/commit.c:709
+msgid "could not write commit template"
+msgstr "impossible d'écrire le modèle de commit"
+
+#: builtin/commit.c:720
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a merge.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+"\n"
+"Il semble que vous validiez une fusion.\n"
+"Si ce n'est pas le cas, veuillez supprimer le fichier\n"
+"\t%s\n"
+"et essayez à nouveau.\n"
+
+#: builtin/commit.c:725
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a cherry-pick.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+"\n"
+"Il semble que vous validiez un picorage.\n"
+"Si ce n'est pas le cas, veuillez supprimer le fichier\n"
+"\t%s\n"
+"et essayez à nouveau.\n"
+
+#: builtin/commit.c:737
+#, c-format
+msgid ""
+"Please enter the commit message for your changes. Lines starting\n"
+"with '%c' will be ignored, and an empty message aborts the commit.\n"
+msgstr ""
+"Veuillez saisir le message de validation pour vos modifications. Les lignes\n"
+"commençant par '%c' seront ignorées, et un message vide abandonne la validation.\n"
+
+#: builtin/commit.c:742
+#, c-format
+msgid ""
+"Please enter the commit message for your changes. Lines starting\n"
+"with '%c' will be kept; you may remove them yourself if you want to.\n"
+"An empty message aborts the commit.\n"
+msgstr ""
+"Veuillez saisir le message de validation pour vos modifications. Les lignes\n"
+"commençant par '%c' seront conservées ; vous pouvez les supprimer vous-même\n"
+"si vous le souhaitez. Un message vide abandonne la validation.\n"
+
+#: builtin/commit.c:755
+#, c-format
+msgid "%sAuthor: %s"
+msgstr "%sAuteur : %s"
+
+#: builtin/commit.c:762
+#, c-format
+msgid "%sCommitter: %s"
+msgstr "%sValidateur : %s"
+
+#: builtin/commit.c:782
+msgid "Cannot read index"
+msgstr "Impossible de lire l'index"
+
+#: builtin/commit.c:819
+msgid "Error building trees"
+msgstr "Erreur lors de la construction des arbres"
+
+#: builtin/commit.c:834 builtin/tag.c:359
+#, c-format
+msgid "Please supply the message using either -m or -F option.\n"
+msgstr "Veuillez fournir le message en utilisant l'option -m ou -F.\n"
+
+#: builtin/commit.c:931
+#, c-format
+msgid "No existing author found with '%s'"
+msgstr "Aucun auteur existant trouvé avec '%s'"
+
+#: builtin/commit.c:946 builtin/commit.c:1140
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr "Mode de fichier non suivi invalide '%s'"
+
+#: builtin/commit.c:976
+msgid "Using both --reset-author and --author does not make sense"
+msgstr "L'utilisation simultanée de --reset-author et --author n'a pas de sens"
+
+#: builtin/commit.c:987
+msgid "You have nothing to amend."
+msgstr "Il n'y a rien à corriger."
+
+#: builtin/commit.c:990
+msgid "You are in the middle of a merge -- cannot amend."
+msgstr "Vous êtes en pleine fusion -- impossible de corriger (amend)."
+
+#: builtin/commit.c:992
+msgid "You are in the middle of a cherry-pick -- cannot amend."
+msgstr "Vous êtes en plein picorage -- impossible de corriger (amend)."
+
+#: builtin/commit.c:995
+msgid "Options --squash and --fixup cannot be used together"
+msgstr "Les options --squash et --fixup ne peuvent pas être utilisées ensemble"
+
+#: builtin/commit.c:1005
+msgid "Only one of -c/-C/-F/--fixup can be used."
+msgstr "Une seule option parmi -c/-C/-F/--fixup peut être utilisée."
+
+#: builtin/commit.c:1007
+msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
+msgstr "L'option -m ne peut pas être combinée avec -c/-C/-F/--fixup."
+
+#: builtin/commit.c:1015
+msgid "--reset-author can be used only with -C, -c or --amend."
+msgstr "--reset-author ne peut être utilisé qu'avec -C, -c ou --amend."
+
+#: builtin/commit.c:1032
+msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
+msgstr "Une seule option parmi --include/--only/--all/--interactive/--patch peut être utilisée."
+
+#: builtin/commit.c:1034
+msgid "No paths with --include/--only does not make sense."
+msgstr "Aucun chemin avec les options --include/--only n'a pas de sens."
+
+#: builtin/commit.c:1036
+msgid "Clever... amending the last one with dirty index."
+msgstr "Malin... correction du dernier avec un index sale."
+
+#: builtin/commit.c:1038
+msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
+msgstr ""
+
+#: builtin/commit.c:1048 builtin/tag.c:575
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr ""
+
+#: builtin/commit.c:1053
+msgid "Paths with -a does not make sense."
+msgstr ""
+
+#: builtin/commit.c:1059 builtin/commit.c:1194
+msgid "--long and -z are incompatible"
+msgstr ""
+
+#: builtin/commit.c:1154 builtin/commit.c:1390
+msgid "show status concisely"
+msgstr ""
+
+#: builtin/commit.c:1156 builtin/commit.c:1392
+msgid "show branch information"
+msgstr ""
+
+#: builtin/commit.c:1158 builtin/commit.c:1394 builtin/push.c:426
+msgid "machine-readable output"
+msgstr ""
+
+#: builtin/commit.c:1161 builtin/commit.c:1396
+msgid "show status in long format (default)"
+msgstr ""
+
+#: builtin/commit.c:1164 builtin/commit.c:1399
+msgid "terminate entries with NUL"
+msgstr ""
+
+#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/fast-export.c:659
+#: builtin/fast-export.c:662 builtin/tag.c:459
+msgid "mode"
+msgstr ""
+
+#: builtin/commit.c:1167 builtin/commit.c:1402
+msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
+msgstr ""
+
+#: builtin/commit.c:1170
+msgid "show ignored files"
+msgstr ""
+
+#: builtin/commit.c:1171 parse-options.h:151
+msgid "when"
+msgstr ""
+
+#: builtin/commit.c:1172
+msgid ""
+"ignore changes to submodules, optional when: all, dirty, untracked. "
+"(Default: all)"
+msgstr ""
+
+#: builtin/commit.c:1174
+msgid "list untracked files in columns"
+msgstr ""
+
+#: builtin/commit.c:1248
+msgid "couldn't look up newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1250
+msgid "could not parse newly created commit"
+msgstr ""
+
+#: builtin/commit.c:1291
+msgid "detached HEAD"
+msgstr ""
+
+#: builtin/commit.c:1293
+msgid " (root-commit)"
+msgstr ""
+
+#: builtin/commit.c:1360
+msgid "suppress summary after successful commit"
+msgstr ""
+
+#: builtin/commit.c:1361
+msgid "show diff in commit message template"
+msgstr ""
+
+#: builtin/commit.c:1363
+msgid "Commit message options"
+msgstr ""
+
+#: builtin/commit.c:1364 builtin/tag.c:457
+msgid "read message from file"
+msgstr ""
+
+#: builtin/commit.c:1365
+msgid "author"
+msgstr ""
+
+#: builtin/commit.c:1365
+msgid "override author for commit"
+msgstr ""
+
+#: builtin/commit.c:1366 builtin/gc.c:178
+msgid "date"
+msgstr ""
+
+#: builtin/commit.c:1366
+msgid "override date for commit"
+msgstr ""
+
+#: builtin/commit.c:1367 builtin/merge.c:208 builtin/notes.c:533
+#: builtin/notes.c:690 builtin/tag.c:455
+msgid "message"
+msgstr ""
+
+#: builtin/commit.c:1367
+msgid "commit message"
+msgstr ""
+
+#: builtin/commit.c:1368
+msgid "reuse and edit message from specified commit"
+msgstr ""
+
+#: builtin/commit.c:1369
+msgid "reuse message from specified commit"
+msgstr ""
+
+#: builtin/commit.c:1370
+msgid "use autosquash formatted message to fixup specified commit"
+msgstr ""
+
+#: builtin/commit.c:1371
+msgid "use autosquash formatted message to squash specified commit"
+msgstr ""
+
+#: builtin/commit.c:1372
+msgid "the commit is authored by me now (used with -C/-c/--amend)"
+msgstr ""
+
+#: builtin/commit.c:1373 builtin/log.c:1113 builtin/revert.c:109
+msgid "add Signed-off-by:"
+msgstr ""
+
+#: builtin/commit.c:1374
+msgid "use specified template file"
+msgstr ""
+
+#: builtin/commit.c:1375
+msgid "force edit of commit"
+msgstr ""
+
+#: builtin/commit.c:1376
+msgid "default"
+msgstr ""
+
+#: builtin/commit.c:1376 builtin/tag.c:460
+msgid "how to strip spaces and #comments from message"
+msgstr ""
+
+#: builtin/commit.c:1377
+msgid "include status in commit message template"
+msgstr ""
+
+#: builtin/commit.c:1378 builtin/merge.c:215 builtin/tag.c:461
+msgid "key id"
+msgstr ""
+
+#: builtin/commit.c:1379 builtin/merge.c:216
+msgid "GPG sign commit"
+msgstr ""
+
+#. end commit message options
+#: builtin/commit.c:1382
+msgid "Commit contents options"
+msgstr ""
+
+#: builtin/commit.c:1383
+msgid "commit all changed files"
+msgstr ""
+
+#: builtin/commit.c:1384
+msgid "add specified files to index for commit"
+msgstr ""
+
+#: builtin/commit.c:1385
+msgid "interactively add files"
+msgstr ""
+
+#: builtin/commit.c:1386
+msgid "interactively add changes"
+msgstr ""
+
+#: builtin/commit.c:1387
+msgid "commit only specified files"
+msgstr ""
+
+#: builtin/commit.c:1388
+msgid "bypass pre-commit hook"
+msgstr ""
+
+#: builtin/commit.c:1389
+msgid "show what would be committed"
+msgstr ""
+
+#: builtin/commit.c:1400
+msgid "amend previous commit"
+msgstr ""
+
+#: builtin/commit.c:1401
+msgid "bypass post-rewrite hook"
+msgstr ""
+
+#: builtin/commit.c:1406
+msgid "ok to record an empty change"
+msgstr ""
+
+#: builtin/commit.c:1409
+msgid "ok to record a change with an empty message"
+msgstr ""
+
+#: builtin/commit.c:1441
+msgid "could not parse HEAD commit"
+msgstr ""
+
+#: builtin/commit.c:1479 builtin/merge.c:510
+#, c-format
+msgid "could not open '%s' for reading"
+msgstr ""
+
+#: builtin/commit.c:1486
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr ""
+
+#: builtin/commit.c:1493
+msgid "could not read MERGE_MODE"
+msgstr ""
+
+#: builtin/commit.c:1512
+#, c-format
+msgid "could not read commit message: %s"
+msgstr ""
+
+#: builtin/commit.c:1526
+#, c-format
+msgid "Aborting commit; you did not edit the message.\n"
+msgstr ""
+
+#: builtin/commit.c:1531
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr ""
+
+#: builtin/commit.c:1546 builtin/merge.c:847 builtin/merge.c:872
+msgid "failed to write commit object"
+msgstr ""
+
+#: builtin/commit.c:1567
+msgid "cannot lock HEAD ref"
+msgstr ""
+
+#: builtin/commit.c:1571
+msgid "cannot update HEAD ref"
+msgstr ""
+
+#: builtin/commit.c:1582
+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:51
+msgid "Config file location"
+msgstr ""
+
+#: builtin/config.c:52
+msgid "use global config file"
+msgstr ""
+
+#: builtin/config.c:53
+msgid "use system config file"
+msgstr ""
+
+#: builtin/config.c:54
+msgid "use repository config file"
+msgstr ""
+
+#: builtin/config.c:55
+msgid "use given config file"
+msgstr ""
+
+#: builtin/config.c:56
+msgid "Action"
+msgstr ""
+
+#: builtin/config.c:57
+msgid "get value: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:58
+msgid "get all values: key [value-regex]"
+msgstr ""
+
+#: builtin/config.c:59
+msgid "get values for regexp: name-regex [value-regex]"
+msgstr ""
+
+#: builtin/config.c:60
+msgid "replace all matching variables: name value [value_regex]"
+msgstr ""
+
+#: builtin/config.c:61
+msgid "add a new variable: name value"
+msgstr ""
+
+#: builtin/config.c:62
+msgid "remove a variable: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:63
+msgid "remove all matches: name [value-regex]"
+msgstr ""
+
+#: builtin/config.c:64
+msgid "rename section: old-name new-name"
+msgstr ""
+
+#: builtin/config.c:65
+msgid "remove a section: name"
+msgstr ""
+
+#: builtin/config.c:66
+msgid "list all"
+msgstr ""
+
+#: builtin/config.c:67
+msgid "open an editor"
+msgstr ""
+
+#: builtin/config.c:68 builtin/config.c:69
+msgid "slot"
+msgstr ""
+
+#: builtin/config.c:68
+msgid "find the color configured: [default]"
+msgstr ""
+
+#: builtin/config.c:69
+msgid "find the color setting: [stdout-is-tty]"
+msgstr ""
+
+#: builtin/config.c:70
+msgid "Type"
+msgstr ""
+
+#: builtin/config.c:71
+msgid "value is \"true\" or \"false\""
+msgstr ""
+
+#: builtin/config.c:72
+msgid "value is decimal number"
+msgstr ""
+
+#: builtin/config.c:73
+msgid "value is --bool or --int"
+msgstr ""
+
+#: builtin/config.c:74
+msgid "value is a path (file or directory name)"
+msgstr ""
+
+#: builtin/config.c:75
+msgid "Other"
+msgstr ""
+
+#: builtin/config.c:76
+msgid "terminate values with NUL byte"
+msgstr ""
+
+#: builtin/config.c:77
+msgid "respect include directives on lookup"
+msgstr ""
+
+#: builtin/count-objects.c:82
+msgid "git count-objects [-v] [-H | --human-readable]"
+msgstr ""
+
+#: builtin/count-objects.c:97
+msgid "print sizes in human readable format"
+msgstr ""
+
+#: builtin/describe.c:15
+msgid "git describe [options] <committish>*"
+msgstr ""
+
+#: builtin/describe.c:16
+msgid "git describe [options] --dirty"
+msgstr ""
+
+#: builtin/describe.c:233
+#, c-format
+msgid "annotated tag %s not available"
+msgstr ""
+
+#: builtin/describe.c:237
+#, c-format
+msgid "annotated tag %s has no embedded name"
+msgstr ""
+
+#: builtin/describe.c:239
+#, c-format
+msgid "tag '%s' is really '%s' here"
+msgstr ""
+
+#: builtin/describe.c:266
+#, c-format
+msgid "Not a valid object name %s"
+msgstr ""
+
+#: builtin/describe.c:269
+#, c-format
+msgid "%s is not a valid '%s' object"
+msgstr "%s n'est pas un objet '%s' valide"
+
+#: builtin/describe.c:286
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr ""
+
+#: builtin/describe.c:288
+#, c-format
+msgid "searching to describe %s\n"
+msgstr ""
+
+#: builtin/describe.c:328
+#, c-format
+msgid "finished search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:352
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
+msgstr ""
+
+#: builtin/describe.c:356
+#, c-format
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
+msgstr ""
+
+#: builtin/describe.c:377
+#, c-format
+msgid "traversed %lu commits\n"
+msgstr ""
+
+#: builtin/describe.c:380
+#, c-format
+msgid ""
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
+msgstr ""
+
+#: builtin/describe.c:402
+msgid "find the tag that comes after the commit"
+msgstr ""
+
+#: builtin/describe.c:403
+msgid "debug search strategy on stderr"
+msgstr ""
+
+#: builtin/describe.c:404
+msgid "use any ref"
+msgstr ""
+
+#: builtin/describe.c:405
+msgid "use any tag, even unannotated"
+msgstr ""
+
+#: builtin/describe.c:406
+msgid "always use long format"
+msgstr ""
+
+#: builtin/describe.c:409
+msgid "only output exact matches"
+msgstr ""
+
+#: builtin/describe.c:411
+msgid "consider <n> most recent tags (default: 10)"
+msgstr ""
+
+#: builtin/describe.c:413
+msgid "only consider tags matching <pattern>"
+msgstr ""
+
+#: builtin/describe.c:415 builtin/name-rev.c:238
+msgid "show abbreviated commit object as fallback"
+msgstr ""
+
+#: builtin/describe.c:416
+msgid "mark"
+msgstr ""
+
+#: builtin/describe.c:417
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
+msgstr ""
+
+#: builtin/describe.c:435
+msgid "--long is incompatible with --abbrev=0"
+msgstr ""
+
+#: builtin/describe.c:461
+msgid "No names found, cannot describe anything."
+msgstr ""
+
+#: builtin/describe.c:481
+msgid "--dirty is incompatible with committishes"
+msgstr ""
+
+#: builtin/diff.c:79
+#, c-format
+msgid "'%s': not a regular file or symlink"
+msgstr ""
+
+#: builtin/diff.c:228
+#, c-format
+msgid "invalid option: %s"
+msgstr ""
+
+#: builtin/diff.c:305
+msgid "Not a git repository"
+msgstr ""
+
+#: builtin/diff.c:348
+#, c-format
+msgid "invalid object '%s' given."
+msgstr ""
+
+#: builtin/diff.c:353
+#, c-format
+msgid "more than %d trees given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:363
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr ""
+
+#: builtin/diff.c:371
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr ""
+
+#: builtin/fast-export.c:22
+msgid "git fast-export [rev-list-opts]"
+msgstr ""
+
+#: builtin/fast-export.c:658
+msgid "show progress after <n> objects"
+msgstr ""
+
+#: builtin/fast-export.c:660
+msgid "select handling of signed tags"
+msgstr ""
+
+#: builtin/fast-export.c:663
+msgid "select handling of tags that tag filtered objects"
+msgstr ""
+
+#: builtin/fast-export.c:666
+msgid "Dump marks to this file"
+msgstr ""
+
+#: builtin/fast-export.c:668
+msgid "Import marks from this file"
+msgstr ""
+
+#: builtin/fast-export.c:670
+msgid "Fake a tagger when tags lack one"
+msgstr ""
+
+#: builtin/fast-export.c:672
+msgid "Output full tree for each commit"
+msgstr ""
+
+#: builtin/fast-export.c:674
+msgid "Use the done feature to terminate the stream"
+msgstr ""
+
+#: builtin/fast-export.c:675
+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:86
+msgid "convert to a complete repository"
+msgstr ""
+
+#: builtin/fetch.c:88 builtin/log.c:1130
+msgid "dir"
+msgstr ""
+
+#: builtin/fetch.c:89
+msgid "prepend this to submodule path output"
+msgstr ""
+
+#: builtin/fetch.c:92
+msgid "default mode for recursion"
+msgstr ""
+
+#: builtin/fetch.c:204
+msgid "Couldn't find remote ref HEAD"
+msgstr ""
+
+#: builtin/fetch.c:257
+#, c-format
+msgid "object %s not found"
+msgstr ""
+
+#: builtin/fetch.c:262
+msgid "[up to date]"
+msgstr ""
+
+#: builtin/fetch.c:276
+#, c-format
+msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
+msgstr ""
+
+#: builtin/fetch.c:277 builtin/fetch.c:363
+msgid "[rejected]"
+msgstr ""
+
+#: builtin/fetch.c:288
+msgid "[tag update]"
+msgstr ""
+
+#: builtin/fetch.c:290 builtin/fetch.c:325 builtin/fetch.c:343
+msgid " (unable to update local ref)"
+msgstr ""
+
+#: builtin/fetch.c:308
+msgid "[new tag]"
+msgstr ""
+
+#: builtin/fetch.c:311
+msgid "[new branch]"
+msgstr ""
+
+#: builtin/fetch.c:314
+msgid "[new ref]"
+msgstr ""
+
+#: builtin/fetch.c:359
+msgid "unable to update local ref"
+msgstr ""
+
+#: builtin/fetch.c:359
+msgid "forced update"
+msgstr ""
+
+#: builtin/fetch.c:365
+msgid "(non-fast-forward)"
+msgstr ""
+
+#: builtin/fetch.c:396 builtin/fetch.c:688
+#, c-format
+msgid "cannot open %s: %s\n"
+msgstr "impossible d'ouvrir %s : %s\n"
+
+#: builtin/fetch.c:405
+#, c-format
+msgid "%s did not send all necessary objects\n"
+msgstr "%s n'a pas envoyé tous les objets nécessaires\n"
+
+#: builtin/fetch.c:491
+#, c-format
+msgid "From %.*s\n"
+msgstr ""
+
+#: builtin/fetch.c:502
+#, 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:552
+#, c-format
+msgid " (%s will become dangling)"
+msgstr ""
+
+#: builtin/fetch.c:553
+#, c-format
+msgid " (%s has become dangling)"
+msgstr ""
+
+#: builtin/fetch.c:560
+msgid "[deleted]"
+msgstr ""
+
+#: builtin/fetch.c:561 builtin/remote.c:1055
+msgid "(none)"
+msgstr ""
+
+#: builtin/fetch.c:678
+#, c-format
+msgid "Refusing to fetch into current branch %s of non-bare repository"
+msgstr ""
+
+#: builtin/fetch.c:712
+#, c-format
+msgid "Don't know how to fetch from %s"
+msgstr ""
+
+#: builtin/fetch.c:789
+#, c-format
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
+msgstr ""
+
+#: builtin/fetch.c:792
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
+msgstr ""
+
+#: builtin/fetch.c:894
+#, c-format
+msgid "Fetching %s\n"
+msgstr ""
+
+#: builtin/fetch.c:896 builtin/remote.c:100
+#, c-format
+msgid "Could not fetch %s"
+msgstr ""
+
+#: builtin/fetch.c:915
+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:935
+msgid "You need to specify a tag name."
+msgstr ""
+
+#: builtin/fetch.c:981
+msgid "--depth and --unshallow cannot be used together"
+msgstr ""
+
+#: builtin/fetch.c:983
+msgid "--unshallow on a complete repository does not make sense"
+msgstr ""
+
+#: builtin/fetch.c:1002
+msgid "fetch --all does not take a repository argument"
+msgstr ""
+
+#: builtin/fetch.c:1004
+msgid "fetch --all does not make sense with refspecs"
+msgstr ""
+
+#: builtin/fetch.c:1015
+#, c-format
+msgid "No such remote or remote group: %s"
+msgstr ""
+
+#: builtin/fetch.c:1023
+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:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:701
+#: builtin/merge.c:188 builtin/show-branch.c:655 builtin/show-ref.c:175
+#: builtin/tag.c:446 parse-options.h:133 parse-options.h:239
+msgid "n"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:664
+msgid "populate log with at most <n> entries from shortlog"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:667
+msgid "alias for --log (deprecated)"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:670
+msgid "text"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:671
+msgid "use <text> as start of message"
+msgstr ""
+
+#: builtin/fmt-merge-msg.c:672
+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'"
+msgstr ""
+
+#: builtin/gc.c:90
+#, c-format
+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:222
+#, c-format
+msgid ""
+"Auto packing the repository for optimum performance. You may also\n"
+"run \"git gc\" manually. See \"git help gc\" for more information.\n"
+msgstr ""
+
+#: builtin/gc.c:249
+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:217
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr ""
+
+#: builtin/grep.c:365
+#, c-format
+msgid "Failed to chdir: %s"
+msgstr ""
+
+#: builtin/grep.c:443 builtin/grep.c:478
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr ""
+
+#: builtin/grep.c:493
+#, c-format
+msgid "unable to grep from object of type %s"
+msgstr ""
+
+#: builtin/grep.c:551
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr ""
+
+#: builtin/grep.c:568
+#, c-format
+msgid "cannot open '%s'"
+msgstr ""
+
+#: builtin/grep.c:643
+msgid "search in index instead of in the work tree"
+msgstr ""
+
+#: builtin/grep.c:645
+msgid "find in contents not managed by git"
+msgstr ""
+
+#: builtin/grep.c:647
+msgid "search in both tracked and untracked files"
+msgstr ""
+
+#: builtin/grep.c:649
+msgid "search also in ignored files"
+msgstr ""
+
+#: builtin/grep.c:652
+msgid "show non-matching lines"
+msgstr ""
+
+#: builtin/grep.c:654
+msgid "case insensitive matching"
+msgstr ""
+
+#: builtin/grep.c:656
+msgid "match patterns only at word boundaries"
+msgstr ""
+
+#: builtin/grep.c:658
+msgid "process binary files as text"
+msgstr ""
+
+#: builtin/grep.c:660
+msgid "don't match patterns in binary files"
+msgstr ""
+
+#: builtin/grep.c:663
+msgid "descend at most <depth> levels"
+msgstr ""
+
+#: builtin/grep.c:667
+msgid "use extended POSIX regular expressions"
+msgstr ""
+
+#: builtin/grep.c:670
+msgid "use basic POSIX regular expressions (default)"
+msgstr ""
+
+#: builtin/grep.c:673
+msgid "interpret patterns as fixed strings"
+msgstr ""
+
+#: builtin/grep.c:676
+msgid "use Perl-compatible regular expressions"
+msgstr ""
+
+#: builtin/grep.c:679
+msgid "show line numbers"
+msgstr ""
+
+#: builtin/grep.c:680
+msgid "don't show filenames"
+msgstr ""
+
+#: builtin/grep.c:681
+msgid "show filenames"
+msgstr ""
+
+#: builtin/grep.c:683
+msgid "show filenames relative to top directory"
+msgstr ""
+
+#: builtin/grep.c:685
+msgid "show only filenames instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:687
+msgid "synonym for --files-with-matches"
+msgstr ""
+
+#: builtin/grep.c:690
+msgid "show only the names of files without match"
+msgstr ""
+
+#: builtin/grep.c:692
+msgid "print NUL after filenames"
+msgstr ""
+
+#: builtin/grep.c:694
+msgid "show the number of matches instead of matching lines"
+msgstr ""
+
+#: builtin/grep.c:695
+msgid "highlight matches"
+msgstr ""
+
+#: builtin/grep.c:697
+msgid "print empty line between matches from different files"
+msgstr ""
+
+#: builtin/grep.c:699
+msgid "show filename only once above matches from same file"
+msgstr ""
+
+#: builtin/grep.c:702
+msgid "show <n> context lines before and after matches"
+msgstr ""
+
+#: builtin/grep.c:705
+msgid "show <n> context lines before matches"
+msgstr ""
+
+#: builtin/grep.c:707
+msgid "show <n> context lines after matches"
+msgstr ""
+
+#: builtin/grep.c:708
+msgid "shortcut for -C NUM"
+msgstr ""
+
+#: builtin/grep.c:711
+msgid "show a line with the function name before matches"
+msgstr ""
+
+#: builtin/grep.c:713
+msgid "show the surrounding function"
+msgstr ""
+
+#: builtin/grep.c:716
+msgid "read patterns from file"
+msgstr ""
+
+#: builtin/grep.c:718
+msgid "match <pattern>"
+msgstr ""
+
+#: builtin/grep.c:720
+msgid "combine patterns specified with -e"
+msgstr ""
+
+#: builtin/grep.c:732
+msgid "indicate hit with exit status without output"
+msgstr ""
+
+#: builtin/grep.c:734
+msgid "show only matches from files that match all patterns"
+msgstr ""
+
+#: builtin/grep.c:736
+msgid "show parse tree for grep expression"
+msgstr ""
+
+#: builtin/grep.c:740
+msgid "pager"
+msgstr ""
+
+#: builtin/grep.c:740
+msgid "show matching files in the pager"
+msgstr ""
+
+#: builtin/grep.c:743
+msgid "allow calling of grep(1) (ignored by this build)"
+msgstr ""
+
+#: builtin/grep.c:744 builtin/show-ref.c:184
+msgid "show usage"
+msgstr ""
+
+#: builtin/grep.c:811
+msgid "no pattern given."
+msgstr ""
+
+#: builtin/grep.c:866
+msgid "--open-files-in-pager only works on the worktree"
+msgstr ""
+
+#: builtin/grep.c:889
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr ""
+
+#: builtin/grep.c:894
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr ""
+
+#: builtin/grep.c:897
+msgid "--[no-]exclude-standard cannot be used for tracked contents."
+msgstr ""
+
+#: builtin/grep.c:905
+msgid "both --cached and trees are given."
+msgstr ""
+
+#: builtin/hash-object.c:60
+msgid ""
+"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
+"<file>..."
+msgstr ""
+
+#: builtin/hash-object.c:61
+msgid "git hash-object --stdin-paths < <list-of-paths>"
+msgstr ""
+
+#: builtin/hash-object.c:72
+msgid "type"
+msgstr ""
+
+#: builtin/hash-object.c:72
+msgid "object type"
+msgstr ""
+
+#: builtin/hash-object.c:73
+msgid "write the object into the object database"
+msgstr ""
+
+#: builtin/hash-object.c:74
+msgid "read the object from stdin"
+msgstr ""
+
+#: builtin/hash-object.c:76
+msgid "store file as is without filters"
+msgstr ""
+
+#: builtin/hash-object.c:77
+msgid "process file as it were from this path"
+msgstr ""
+
+#: builtin/help.c:43
+msgid "print all available commands"
+msgstr ""
+
+#: builtin/help.c:44
+msgid "print list of useful guides"
+msgstr ""
+
+#: builtin/help.c:45
+msgid "show man page"
+msgstr ""
+
+#: builtin/help.c:46
+msgid "show manual in web browser"
+msgstr ""
+
+#: builtin/help.c:48
+msgid "show info page"
+msgstr ""
+
+#: builtin/help.c:54
+msgid "git help [--all] [--guides] [--man|--web|--info] [command]"
+msgstr ""
+
+#: builtin/help.c:66
+#, c-format
+msgid "unrecognized help format '%s'"
+msgstr ""
+
+#: builtin/help.c:94
+msgid "Failed to start emacsclient."
+msgstr ""
+
+#: builtin/help.c:107
+msgid "Failed to parse emacsclient version."
+msgstr ""
+
+#: builtin/help.c:115
+#, c-format
+msgid "emacsclient version '%d' too old (< 22)."
+msgstr ""
+
+#: builtin/help.c:133 builtin/help.c:161 builtin/help.c:170 builtin/help.c:178
+#, c-format
+msgid "failed to exec '%s': %s"
+msgstr ""
+
+#: builtin/help.c:218
+#, c-format
+msgid ""
+"'%s': path for unsupported man viewer.\n"
+"Please consider using 'man.<tool>.cmd' instead."
+msgstr ""
+
+#: builtin/help.c:230
+#, c-format
+msgid ""
+"'%s': cmd for supported man viewer.\n"
+"Please consider using 'man.<tool>.path' instead."
+msgstr ""
+
+#: builtin/help.c:351
+#, c-format
+msgid "'%s': unknown man viewer."
+msgstr ""
+
+#: builtin/help.c:368
+msgid "no man viewer handled the request"
+msgstr ""
+
+#: builtin/help.c:376
+msgid "no info viewer handled the request"
+msgstr ""
+
+#: builtin/help.c:422
+msgid "Defining attributes per path"
+msgstr ""
+
+#: builtin/help.c:423
+msgid "A Git glossary"
+msgstr ""
+
+#: builtin/help.c:424
+msgid "Specifies intentionally untracked files to ignore"
+msgstr ""
+
+#: builtin/help.c:425
+msgid "Defining submodule properties"
+msgstr ""
+
+#: builtin/help.c:426
+msgid "Specifying revisions and ranges for Git"
+msgstr ""
+
+#: builtin/help.c:427
+msgid "A tutorial introduction to Git (for version 1.5.1 or newer)"
+msgstr ""
+
+#: builtin/help.c:428
+msgid "An overview of recommended workflows with Git"
+msgstr ""
+
+#: builtin/help.c:440
+msgid "The common Git guides are:\n"
+msgstr ""
+
+#: builtin/help.c:462 builtin/help.c:478
+#, c-format
+msgid "usage: %s%s"
+msgstr ""
+
+#: builtin/help.c:494
+#, c-format
+msgid "`git %s' is aliased to `%s'"
+msgstr ""
+
+#: builtin/index-pack.c:182
+#, c-format
+msgid "object type mismatch at %s"
+msgstr ""
+
+#: builtin/index-pack.c:202
+msgid "object of unexpected type"
+msgstr ""
+
+#: builtin/index-pack.c:239
+#, c-format
+msgid "cannot fill %d byte"
+msgid_plural "cannot fill %d bytes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/index-pack.c:249
+msgid "early EOF"
+msgstr ""
+
+#: builtin/index-pack.c:250
+msgid "read error on input"
+msgstr ""
+
+#: builtin/index-pack.c:262
+msgid "used more bytes than were available"
+msgstr ""
+
+#: builtin/index-pack.c:269
+msgid "pack too large for current definition of off_t"
+msgstr ""
+
+#: builtin/index-pack.c:285
+#, c-format
+msgid "unable to create '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:290
+#, c-format
+msgid "cannot open packfile '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:304
+msgid "pack signature mismatch"
+msgstr ""
+
+#: builtin/index-pack.c:306
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr ""
+
+#: builtin/index-pack.c:324
+#, c-format
+msgid "pack has bad object at offset %lu: %s"
+msgstr ""
+
+#: builtin/index-pack.c:446
+#, c-format
+msgid "inflate returned %d"
+msgstr ""
+
+#: builtin/index-pack.c:495
+msgid "offset value overflow for delta base object"
+msgstr ""
+
+#: builtin/index-pack.c:503
+msgid "delta base offset is out of bound"
+msgstr ""
+
+#: builtin/index-pack.c:511
+#, c-format
+msgid "unknown object type %d"
+msgstr ""
+
+#: builtin/index-pack.c:542
+msgid "cannot pread pack file"
+msgstr ""
+
+#: builtin/index-pack.c:544
+#, 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:570
+msgid "serious inflate inconsistency"
+msgstr ""
+
+#: builtin/index-pack.c:661 builtin/index-pack.c:667 builtin/index-pack.c:690
+#: builtin/index-pack.c:724 builtin/index-pack.c:733
+#, c-format
+msgid "SHA1 COLLISION FOUND WITH %s !"
+msgstr ""
+
+#: builtin/index-pack.c:664 builtin/pack-objects.c:170
+#: builtin/pack-objects.c:262
+#, c-format
+msgid "unable to read %s"
+msgstr ""
+
+#: builtin/index-pack.c:730
+#, c-format
+msgid "cannot read existing object %s"
+msgstr ""
+
+#: builtin/index-pack.c:744
+#, c-format
+msgid "invalid blob object %s"
+msgstr ""
+
+#: builtin/index-pack.c:759
+#, c-format
+msgid "invalid %s"
+msgstr ""
+
+#: builtin/index-pack.c:761
+msgid "Error in object"
+msgstr ""
+
+#: builtin/index-pack.c:763
+#, c-format
+msgid "Not all child objects of %s are reachable"
+msgstr ""
+
+#: builtin/index-pack.c:833 builtin/index-pack.c:863
+msgid "failed to apply delta"
+msgstr ""
+
+#: builtin/index-pack.c:1004
+msgid "Receiving objects"
+msgstr ""
+
+#: builtin/index-pack.c:1004
+msgid "Indexing objects"
+msgstr ""
+
+#: builtin/index-pack.c:1030
+msgid "pack is corrupted (SHA1 mismatch)"
+msgstr ""
+
+#: builtin/index-pack.c:1035
+msgid "cannot fstat packfile"
+msgstr ""
+
+#: builtin/index-pack.c:1038
+msgid "pack has junk at the end"
+msgstr ""
+
+#: builtin/index-pack.c:1049
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr ""
+
+#: builtin/index-pack.c:1072
+msgid "Resolving deltas"
+msgstr ""
+
+#: builtin/index-pack.c:1082
+#, c-format
+msgid "unable to create thread: %s"
+msgstr ""
+
+#: builtin/index-pack.c:1124
+msgid "confusion beyond insanity"
+msgstr ""
+
+#: builtin/index-pack.c:1132
+#, c-format
+msgid "completed with %d local objects"
+msgstr ""
+
+#: builtin/index-pack.c:1142
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr ""
+
+#: builtin/index-pack.c:1146
+#, c-format
+msgid "pack has %d unresolved delta"
+msgid_plural "pack has %d unresolved deltas"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/index-pack.c:1171
+#, c-format
+msgid "unable to deflate appended object (%d)"
+msgstr ""
+
+#: builtin/index-pack.c:1250
+#, c-format
+msgid "local object %s is corrupt"
+msgstr ""
+
+#: builtin/index-pack.c:1274
+msgid "error while closing pack file"
+msgstr ""
+
+#: builtin/index-pack.c:1287
+#, c-format
+msgid "cannot write keep file '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:1295
+#, c-format
+msgid "cannot close written keep file '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:1308
+msgid "cannot store pack file"
+msgstr ""
+
+#: builtin/index-pack.c:1319
+msgid "cannot store index file"
+msgstr ""
+
+#: builtin/index-pack.c:1352
+#, c-format
+msgid "bad pack.indexversion=%<PRIu32>"
+msgstr ""
+
+#: builtin/index-pack.c:1358
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr ""
+
+#: builtin/index-pack.c:1362 builtin/index-pack.c:1535
+#, c-format
+msgid "no threads support, ignoring %s"
+msgstr ""
+
+#: builtin/index-pack.c:1420
+#, c-format
+msgid "Cannot open existing pack file '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:1422
+#, c-format
+msgid "Cannot open existing pack idx file for '%s'"
+msgstr ""
+
+#: builtin/index-pack.c:1469
+#, c-format
+msgid "non delta: %d object"
+msgid_plural "non delta: %d objects"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/index-pack.c:1476
+#, c-format
+msgid "chain length = %d: %lu object"
+msgid_plural "chain length = %d: %lu objects"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/index-pack.c:1503
+msgid "Cannot come back to cwd"
+msgstr ""
+
+#: builtin/index-pack.c:1547 builtin/index-pack.c:1550
+#: builtin/index-pack.c:1562 builtin/index-pack.c:1566
+#, c-format
+msgid "bad %s"
+msgstr ""
+
+#: builtin/index-pack.c:1580
+msgid "--fix-thin cannot be used without --stdin"
+msgstr ""
+
+#: builtin/index-pack.c:1584 builtin/index-pack.c:1594
+#, c-format
+msgid "packfile name '%s' does not end with '.pack'"
+msgstr ""
+
+#: builtin/index-pack.c:1603
+msgid "--verify with no packfile name given"
+msgstr ""
+
+#: builtin/init-db.c:35
+#, c-format
+msgid "Could not make %s writable by group"
+msgstr ""
+
+#: builtin/init-db.c:62
+#, c-format
+msgid "insanely long template name %s"
+msgstr ""
+
+#: builtin/init-db.c:67
+#, c-format
+msgid "cannot stat '%s'"
+msgstr ""
+
+#: builtin/init-db.c:73
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr ""
+
+#: builtin/init-db.c:80
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr ""
+
+#: builtin/init-db.c:97
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr ""
+
+#: builtin/init-db.c:99
+#, c-format
+msgid "insanely long symlink %s"
+msgstr ""
+
+#: builtin/init-db.c:102
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr ""
+
+#: builtin/init-db.c:106
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr ""
+
+#: builtin/init-db.c:110
+#, c-format
+msgid "ignoring template %s"
+msgstr ""
+
+#: builtin/init-db.c:133
+#, c-format
+msgid "insanely long template path %s"
+msgstr ""
+
+#: builtin/init-db.c:141
+#, c-format
+msgid "templates not found %s"
+msgstr ""
+
+#: builtin/init-db.c:154
+#, c-format
+msgid "not copying templates of a wrong format version %d from '%s'"
+msgstr ""
+
+#: builtin/init-db.c:192
+#, c-format
+msgid "insane git directory %s"
+msgstr ""
+
+#: builtin/init-db.c:323 builtin/init-db.c:326
+#, c-format
+msgid "%s already exists"
+msgstr "%s existe déjà"
+
+#: builtin/init-db.c:355
+#, c-format
+msgid "unable to handle file type %d"
+msgstr ""
+
+#: builtin/init-db.c:358
+#, c-format
+msgid "unable to move %s to %s"
+msgstr ""
+
+#: builtin/init-db.c:363
+#, c-format
+msgid "Could not create git link %s"
+msgstr ""
+
+#.
+#. * TRANSLATORS: The first '%s' is either "Reinitialized
+#. * existing" or "Initialized empty", the second " shared" or
+#. * "", and the last '%s%s' is the verbatim directory name.
+#.
+#: builtin/init-db.c:420
+#, c-format
+msgid "%s%s Git repository in %s%s\n"
+msgstr "%s%s Dépôt git dans %s%s\n"
+
+#: builtin/init-db.c:421
+msgid "Reinitialized existing"
+msgstr ""
+
+#: builtin/init-db.c:421
+msgid "Initialized empty"
+msgstr ""
+
+#: builtin/init-db.c:422
+msgid " shared"
+msgstr ""
+
+#: builtin/init-db.c:441
+msgid "cannot tell cwd"
+msgstr ""
+
+#: builtin/init-db.c:467
+msgid ""
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--"
+"shared[=<permissions>]] [directory]"
+msgstr ""
+
+#: builtin/init-db.c:490
+msgid "permissions"
+msgstr ""
+
+#: builtin/init-db.c:491
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr ""
+
+#: builtin/init-db.c:493 builtin/prune-packed.c:77
+msgid "be quiet"
+msgstr ""
+
+#: builtin/init-db.c:522 builtin/init-db.c:529
+#, c-format
+msgid "cannot mkdir %s"
+msgstr ""
+
+#: builtin/init-db.c:533
+#, c-format
+msgid "cannot chdir to %s"
+msgstr ""
+
+#: builtin/init-db.c:555
+#, c-format
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+
+#: builtin/init-db.c:579
+msgid "Cannot access current working directory"
+msgstr ""
+
+#: builtin/init-db.c:586
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr ""
+
+#: builtin/log.c:40
+msgid "git log [<options>] [<revision range>] [[--] <path>...]\n"
+msgstr ""
+
+#: builtin/log.c:41
+msgid " or: git show [options] <object>..."
+msgstr ""
+
+#: builtin/log.c:103
+msgid "suppress diff output"
+msgstr ""
+
+#: builtin/log.c:104
+msgid "show source"
+msgstr ""
+
+#: builtin/log.c:105
+msgid "Use mail map file"
+msgstr ""
+
+#: builtin/log.c:106
+msgid "decorate options"
+msgstr ""
+
+#: builtin/log.c:199
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr ""
+
+#: builtin/log.c:422 builtin/log.c:514
+#, c-format
+msgid "Could not read object %s"
+msgstr ""
+
+#: builtin/log.c:538
+#, c-format
+msgid "Unknown type: %d"
+msgstr ""
+
+#: builtin/log.c:638
+msgid "format.headers without value"
+msgstr ""
+
+#: builtin/log.c:720
+msgid "name of output directory is too long"
+msgstr ""
+
+#: builtin/log.c:736
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr ""
+
+#: builtin/log.c:750
+msgid "Need exactly one range."
+msgstr ""
+
+#: builtin/log.c:758
+msgid "Not a range."
+msgstr ""
+
+#: builtin/log.c:860
+msgid "Cover letter needs email format"
+msgstr ""
+
+#: builtin/log.c:936
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr ""
+
+#: builtin/log.c:964
+msgid "git format-patch [options] [<since> | <revision range>]"
+msgstr ""
+
+#: builtin/log.c:1009
+msgid "Two output directories?"
+msgstr ""
+
+#: builtin/log.c:1108
+msgid "use [PATCH n/m] even with a single patch"
+msgstr ""
+
+#: builtin/log.c:1111
+msgid "use [PATCH] even with multiple patches"
+msgstr ""
+
+#: builtin/log.c:1115
+msgid "print patches to standard out"
+msgstr ""
+
+#: builtin/log.c:1117
+msgid "generate a cover letter"
+msgstr ""
+
+#: builtin/log.c:1119
+msgid "use simple number sequence for output file names"
+msgstr ""
+
+#: builtin/log.c:1120
+msgid "sfx"
+msgstr ""
+
+#: builtin/log.c:1121
+msgid "use <sfx> instead of '.patch'"
+msgstr ""
+
+#: builtin/log.c:1123
+msgid "start numbering patches at <n> instead of 1"
+msgstr ""
+
+#: builtin/log.c:1125
+msgid "mark the series as Nth re-roll"
+msgstr ""
+
+#: builtin/log.c:1127
+msgid "Use [<prefix>] instead of [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1130
+msgid "store resulting files in <dir>"
+msgstr ""
+
+#: builtin/log.c:1133
+msgid "don't strip/add [PATCH]"
+msgstr ""
+
+#: builtin/log.c:1136
+msgid "don't output binary diffs"
+msgstr ""
+
+#: builtin/log.c:1138
+msgid "don't include a patch matching a commit upstream"
+msgstr ""
+
+#: builtin/log.c:1140
+msgid "show patch format instead of default (patch + stat)"
+msgstr ""
+
+#: builtin/log.c:1142
+msgid "Messaging"
+msgstr ""
+
+#: builtin/log.c:1143
+msgid "header"
+msgstr ""
+
+#: builtin/log.c:1144
+msgid "add email header"
+msgstr ""
+
+#: builtin/log.c:1145 builtin/log.c:1147
+msgid "email"
+msgstr ""
+
+#: builtin/log.c:1145
+msgid "add To: header"
+msgstr ""
+
+#: builtin/log.c:1147
+msgid "add Cc: header"
+msgstr ""
+
+#: builtin/log.c:1149
+msgid "message-id"
+msgstr ""
+
+#: builtin/log.c:1150
+msgid "make first mail a reply to <message-id>"
+msgstr ""
+
+#: builtin/log.c:1151 builtin/log.c:1154
+msgid "boundary"
+msgstr ""
+
+#: builtin/log.c:1152
+msgid "attach the patch"
+msgstr ""
+
+#: builtin/log.c:1155
+msgid "inline the patch"
+msgstr ""
+
+#: builtin/log.c:1159
+msgid "enable message threading, styles: shallow, deep"
+msgstr ""
+
+#: builtin/log.c:1161
+msgid "signature"
+msgstr ""
+
+#: builtin/log.c:1162
+msgid "add a signature"
+msgstr ""
+
+#: builtin/log.c:1164
+msgid "don't print the patch filenames"
+msgstr ""
+
+#: builtin/log.c:1248
+msgid "-n and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1250
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr ""
+
+#: builtin/log.c:1258
+msgid "--name-only does not make sense"
+msgstr ""
+
+#: builtin/log.c:1260
+msgid "--name-status does not make sense"
+msgstr ""
+
+#: builtin/log.c:1262
+msgid "--check does not make sense"
+msgstr ""
+
+#: builtin/log.c:1285
+msgid "standard output, or directory, which one?"
+msgstr ""
+
+#: builtin/log.c:1287
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr ""
+
+#: builtin/log.c:1435
+msgid "Failed to create output files"
+msgstr ""
+
+#: builtin/log.c:1484
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+msgstr ""
+
+#: builtin/log.c:1539
+#, c-format
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr ""
+
+#: builtin/log.c:1552 builtin/log.c:1554 builtin/log.c:1566
+#, c-format
+msgid "Unknown commit %s"
+msgstr ""
+
+#: builtin/ls-files.c:402
+msgid "git ls-files [options] [<file>...]"
+msgstr ""
+
+#: builtin/ls-files.c:459
+msgid "identify the file status with tags"
+msgstr ""
+
+#: builtin/ls-files.c:461
+msgid "use lowercase letters for 'assume unchanged' files"
+msgstr ""
+
+#: builtin/ls-files.c:463
+msgid "show cached files in the output (default)"
+msgstr ""
+
+#: builtin/ls-files.c:465
+msgid "show deleted files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:467
+msgid "show modified files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:469
+msgid "show other files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:471
+msgid "show ignored files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:474
+msgid "show staged contents' object name in the output"
+msgstr ""
+
+#: builtin/ls-files.c:476
+msgid "show files on the filesystem that need to be removed"
+msgstr ""
+
+#: builtin/ls-files.c:478
+msgid "show 'other' directories' name only"
+msgstr ""
+
+#: builtin/ls-files.c:481
+msgid "don't show empty directories"
+msgstr ""
+
+#: builtin/ls-files.c:484
+msgid "show unmerged files in the output"
+msgstr ""
+
+#: builtin/ls-files.c:486
+msgid "show resolve-undo information"
+msgstr ""
+
+#: builtin/ls-files.c:488
+msgid "skip files matching pattern"
+msgstr ""
+
+#: builtin/ls-files.c:491
+msgid "exclude patterns are read from <file>"
+msgstr ""
+
+#: builtin/ls-files.c:494
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr ""
+
+#: builtin/ls-files.c:496
+msgid "add the standard git exclusions"
+msgstr ""
+
+#: builtin/ls-files.c:499
+msgid "make the output relative to the project top directory"
+msgstr ""
+
+#: builtin/ls-files.c:502
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr ""
+
+#: builtin/ls-files.c:503
+msgid "tree-ish"
+msgstr ""
+
+#: builtin/ls-files.c:504
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr ""
+
+#: builtin/ls-files.c:506
+msgid "show debugging data"
+msgstr ""
+
+#: builtin/ls-tree.c:27
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr ""
+
+#: builtin/ls-tree.c:125
+msgid "only show trees"
+msgstr ""
+
+#: builtin/ls-tree.c:127
+msgid "recurse into subtrees"
+msgstr ""
+
+#: builtin/ls-tree.c:129
+msgid "show trees when recursing"
+msgstr ""
+
+#: builtin/ls-tree.c:132
+msgid "terminate entries with NUL byte"
+msgstr ""
+
+#: builtin/ls-tree.c:133
+msgid "include object size"
+msgstr ""
+
+#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
+msgid "list only filenames"
+msgstr ""
+
+#: builtin/ls-tree.c:140
+msgid "use full path names"
+msgstr ""
+
+#: builtin/ls-tree.c:142
+msgid "list entire tree; not just current directory (implies --full-name)"
+msgstr ""
+
+#: builtin/merge.c:43
+msgid "git merge [options] [<commit>...]"
+msgstr ""
+
+#: builtin/merge.c:44
+msgid "git merge [options] <msg> HEAD <commit>"
+msgstr ""
+
+#: builtin/merge.c:45
+msgid "git merge --abort"
+msgstr ""
+
+#: builtin/merge.c:90
+msgid "switch `m' requires a value"
+msgstr ""
+
+#: builtin/merge.c:127
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr ""
+
+#: builtin/merge.c:128
+#, c-format
+msgid "Available strategies are:"
+msgstr ""
+
+#: builtin/merge.c:133
+#, c-format
+msgid "Available custom strategies are:"
+msgstr ""
+
+#: builtin/merge.c:183
+msgid "do not show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:186
+msgid "show a diffstat at the end of the merge"
+msgstr ""
+
+#: builtin/merge.c:187
+msgid "(synonym to --stat)"
+msgstr ""
+
+#: builtin/merge.c:189
+msgid "add (at most <n>) entries from shortlog to merge commit message"
+msgstr ""
+
+#: builtin/merge.c:192
+msgid "create a single commit instead of doing a merge"
+msgstr ""
+
+#: builtin/merge.c:194
+msgid "perform a commit if the merge succeeds (default)"
+msgstr ""
+
+#: builtin/merge.c:196
+msgid "edit message before committing"
+msgstr ""
+
+#: builtin/merge.c:198
+msgid "allow fast-forward (default)"
+msgstr ""
+
+#: builtin/merge.c:200
+msgid "abort if fast-forward is not possible"
+msgstr ""
+
+#: builtin/merge.c:203
+msgid "Verify that the named commit has a valid GPG signature"
+msgstr ""
+
+#: builtin/merge.c:204 builtin/notes.c:866 builtin/revert.c:112
+msgid "strategy"
+msgstr ""
+
+#: builtin/merge.c:205
+msgid "merge strategy to use"
+msgstr ""
+
+#: builtin/merge.c:206
+msgid "option=value"
+msgstr ""
+
+#: builtin/merge.c:207
+msgid "option for selected merge strategy"
+msgstr ""
+
+#: builtin/merge.c:209
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr ""
+
+#: builtin/merge.c:213
+msgid "abort the current in-progress merge"
+msgstr ""
+
+#: builtin/merge.c:242
+msgid "could not run stash."
+msgstr ""
+
+#: builtin/merge.c:247
+msgid "stash failed"
+msgstr ""
+
+#: builtin/merge.c:252
+#, c-format
+msgid "not a valid object: %s"
+msgstr ""
+
+#: builtin/merge.c:271 builtin/merge.c:288
+msgid "read-tree failed"
+msgstr ""
+
+#: builtin/merge.c:318
+msgid " (nothing to squash)"
+msgstr " (rien à compresser)"
+
+#: builtin/merge.c:331
+#, c-format
+msgid "Squash commit -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:363
+msgid "Writing SQUASH_MSG"
+msgstr ""
+
+#: builtin/merge.c:365
+msgid "Finishing SQUASH_MSG"
+msgstr ""
+
+#: builtin/merge.c:388
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr ""
+
+#: builtin/merge.c:438
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr ""
+
+#: builtin/merge.c:550
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr ""
+
+#: builtin/merge.c:643
+msgid "git write-tree failed to write a tree"
+msgstr ""
+
+#: builtin/merge.c:671
+msgid "Not handling anything other than two heads merge."
+msgstr ""
+
+#: builtin/merge.c:685
+#, c-format
+msgid "Unknown option for merge-recursive: -X%s"
+msgstr ""
+
+#: builtin/merge.c:699
+#, c-format
+msgid "unable to write %s"
+msgstr ""
+
+#: builtin/merge.c:788
+#, c-format
+msgid "Could not read from '%s'"
+msgstr ""
+
+#: builtin/merge.c:797
+#, c-format
+msgid "Not committing merge; use 'git commit' to complete the merge.\n"
+msgstr ""
+
+#: builtin/merge.c:803
+#, c-format
+msgid ""
+"Please enter a commit message to explain why this merge is necessary,\n"
+"especially if it merges an updated upstream into a topic branch.\n"
+"\n"
+"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"the commit.\n"
+msgstr ""
+
+#: builtin/merge.c:827
+msgid "Empty commit message."
+msgstr ""
+
+#: builtin/merge.c:839
+#, c-format
+msgid "Wonderful.\n"
+msgstr ""
+
+#: builtin/merge.c:904
+#, c-format
+msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+msgstr ""
+
+#: builtin/merge.c:920
+#, c-format
+msgid "'%s' is not a commit"
+msgstr ""
+
+#: builtin/merge.c:961
+msgid "No current branch."
+msgstr ""
+
+#: builtin/merge.c:963
+msgid "No remote for the current branch."
+msgstr ""
+
+#: builtin/merge.c:965
+msgid "No default upstream defined for the current branch."
+msgstr ""
+
+#: builtin/merge.c:970
+#, c-format
+msgid "No remote tracking branch for %s from %s"
+msgstr ""
+
+#: builtin/merge.c:1057 builtin/merge.c:1214
+#, c-format
+msgid "%s - not something we can merge"
+msgstr ""
+
+#: builtin/merge.c:1125
+msgid "There is no merge to abort (MERGE_HEAD missing)."
+msgstr ""
+
+#: builtin/merge.c:1141 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:1144 git-pull.sh:34
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1148
+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:1151
+msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
+msgstr ""
+
+#: builtin/merge.c:1160
+msgid "You cannot combine --squash with --no-ff."
+msgstr ""
+
+#: builtin/merge.c:1165
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr ""
+
+#: builtin/merge.c:1172
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr ""
+
+#: builtin/merge.c:1204
+msgid "Can merge only exactly one commit into empty head"
+msgstr ""
+
+#: builtin/merge.c:1207
+msgid "Squash commit into empty head not supported yet"
+msgstr ""
+
+#: builtin/merge.c:1209
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr ""
+
+#: builtin/merge.c:1265
+#, c-format
+msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
+msgstr ""
+
+#: builtin/merge.c:1268
+#, c-format
+msgid "Commit %s has a bad GPG signature allegedly by %s."
+msgstr ""
+
+#. 'N'
+#: builtin/merge.c:1271
+#, c-format
+msgid "Commit %s does not have a GPG signature."
+msgstr ""
+
+#: builtin/merge.c:1274
+#, c-format
+msgid "Commit %s has a good GPG signature by %s\n"
+msgstr ""
+
+#: builtin/merge.c:1358
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr ""
+
+#: builtin/merge.c:1397
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr ""
+
+#: builtin/merge.c:1404
+#, c-format
+msgid "Nope.\n"
+msgstr ""
+
+#: builtin/merge.c:1436
+msgid "Not possible to fast-forward, aborting."
+msgstr ""
+
+#: builtin/merge.c:1459 builtin/merge.c:1538
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr ""
+
+#: builtin/merge.c:1463
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr ""
+
+#: builtin/merge.c:1529
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr ""
+
+#: builtin/merge.c:1531
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr ""
+
+#: builtin/merge.c:1540
+#, c-format
+msgid "Using the %s to prepare resolving by hand.\n"
+msgstr ""
+
+#: builtin/merge.c:1552
+#, c-format
+msgid "Automatic merge went well; stopped before committing as requested\n"
+msgstr ""
+
+#: builtin/merge-base.c:26
+msgid "git merge-base [-a|--all] <commit> <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:27
+msgid "git merge-base [-a|--all] --octopus <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:28
+msgid "git merge-base --independent <commit>..."
+msgstr ""
+
+#: builtin/merge-base.c:29
+msgid "git merge-base --is-ancestor <commit> <commit>"
+msgstr ""
+
+#: builtin/merge-base.c:98
+msgid "output all common ancestors"
+msgstr ""
+
+#: builtin/merge-base.c:99
+msgid "find ancestors for a single n-way merge"
+msgstr ""
+
+#: builtin/merge-base.c:100
+msgid "list revs not reachable from others"
+msgstr ""
+
+#: builtin/merge-base.c:102
+msgid "is the first one ancestor of the other?"
+msgstr ""
+
+#: builtin/merge-file.c:8
+msgid ""
+"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
+"file2"
+msgstr ""
+
+#: builtin/merge-file.c:33
+msgid "send results to standard output"
+msgstr ""
+
+#: builtin/merge-file.c:34
+msgid "use a diff3 based merge"
+msgstr ""
+
+#: builtin/merge-file.c:35
+msgid "for conflicts, use our version"
+msgstr ""
+
+#: builtin/merge-file.c:37
+msgid "for conflicts, use their version"
+msgstr ""
+
+#: builtin/merge-file.c:39
+msgid "for conflicts, use a union version"
+msgstr ""
+
+#: builtin/merge-file.c:42
+msgid "for conflicts, use this marker size"
+msgstr ""
+
+#: builtin/merge-file.c:43
+msgid "do not warn about conflicts"
+msgstr ""
+
+#: builtin/merge-file.c:45
+msgid "set labels for file1/orig_file/file2"
+msgstr ""
+
+#: builtin/mktree.c:67
+msgid "git mktree [-z] [--missing] [--batch]"
+msgstr ""
+
+#: builtin/mktree.c:153
+msgid "input is NUL terminated"
+msgstr ""
+
+#: builtin/mktree.c:154 builtin/write-tree.c:24
+msgid "allow missing objects"
+msgstr ""
+
+#: builtin/mktree.c:155
+msgid "allow creation of more than one tree"
+msgstr ""
+
+#: builtin/mv.c:14
+msgid "git mv [options] <source>... <destination>"
+msgstr ""
+
+#: builtin/mv.c:64
+msgid "force move/rename even if target exists"
+msgstr ""
+
+#: builtin/mv.c:65
+msgid "skip move/rename errors"
+msgstr ""
+
+#: builtin/mv.c:108
+#, c-format
+msgid "Checking rename of '%s' to '%s'\n"
+msgstr ""
+
+#: builtin/mv.c:112
+msgid "bad source"
+msgstr ""
+
+#: builtin/mv.c:115
+msgid "can not move directory into itself"
+msgstr ""
+
+#: builtin/mv.c:118
+msgid "cannot move directory over file"
+msgstr ""
+
+#: builtin/mv.c:128
+#, c-format
+msgid "Huh? %.*s is in index?"
+msgstr ""
+
+#: builtin/mv.c:140
+msgid "source directory is empty"
+msgstr ""
+
+#: builtin/mv.c:171
+msgid "not under version control"
+msgstr ""
+
+#: builtin/mv.c:173
+msgid "destination exists"
+msgstr ""
+
+#: builtin/mv.c:181
+#, c-format
+msgid "overwriting '%s'"
+msgstr ""
+
+#: builtin/mv.c:184
+msgid "Cannot overwrite"
+msgstr ""
+
+#: builtin/mv.c:187
+msgid "multiple sources for the same target"
+msgstr ""
+
+#: builtin/mv.c:202
+#, c-format
+msgid "%s, source=%s, destination=%s"
+msgstr "%s, source=%s, destination=%s"
+
+#: builtin/mv.c:212
+#, c-format
+msgid "Renaming %s to %s\n"
+msgstr ""
+
+#: builtin/mv.c:215 builtin/remote.c:731
+#, c-format
+msgid "renaming '%s' failed"
+msgstr ""
+
+#: builtin/name-rev.c:175
+msgid "git name-rev [options] <commit>..."
+msgstr ""
+
+#: builtin/name-rev.c:176
+msgid "git name-rev [options] --all"
+msgstr ""
+
+#: builtin/name-rev.c:177
+msgid "git name-rev [options] --stdin"
+msgstr ""
+
+#: builtin/name-rev.c:229
+msgid "print only names (no SHA-1)"
+msgstr ""
+
+#: builtin/name-rev.c:230
+msgid "only use tags to name the commits"
+msgstr ""
+
+#: builtin/name-rev.c:232
+msgid "only use refs matching <pattern>"
+msgstr ""
+
+#: builtin/name-rev.c:234
+msgid "list all commits reachable from all refs"
+msgstr ""
+
+#: builtin/name-rev.c:235
+msgid "read from stdin"
+msgstr ""
+
+#: builtin/name-rev.c:236
+msgid "allow to print `undefined` names"
+msgstr ""
+
+#: builtin/notes.c:26
+msgid "git notes [--ref <notes_ref>] [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:27
+msgid ""
+"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:28
+msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:29
+msgid ""
+"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:30
+msgid "git notes [--ref <notes_ref>] edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:31
+msgid "git notes [--ref <notes_ref>] show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:32
+msgid ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:33
+msgid "git notes merge --commit [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:34
+msgid "git notes merge --abort [-v | -q]"
+msgstr ""
+
+#: builtin/notes.c:35
+msgid "git notes [--ref <notes_ref>] remove [<object>...]"
+msgstr ""
+
+#: builtin/notes.c:36
+msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
+msgstr ""
+
+#: builtin/notes.c:37
+msgid "git notes [--ref <notes_ref>] get-ref"
+msgstr ""
+
+#: builtin/notes.c:42
+msgid "git notes [list [<object>]]"
+msgstr ""
+
+#: builtin/notes.c:47
+msgid "git notes add [<options>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:52
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr ""
+
+#: builtin/notes.c:53
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr ""
+
+#: builtin/notes.c:58
+msgid "git notes append [<options>] [<object>]"
+msgstr ""
+
+#: builtin/notes.c:63
+msgid "git notes edit [<object>]"
+msgstr ""
+
+#: builtin/notes.c:68
+msgid "git notes show [<object>]"
+msgstr ""
+
+#: builtin/notes.c:73
+msgid "git notes merge [<options>] <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:74
+msgid "git notes merge --commit [<options>]"
+msgstr ""
+
+#: builtin/notes.c:75
+msgid "git notes merge --abort [<options>]"
+msgstr ""
+
+#: builtin/notes.c:80
+msgid "git notes remove [<object>]"
+msgstr ""
+
+#: builtin/notes.c:85
+msgid "git notes prune [<options>]"
+msgstr ""
+
+#: builtin/notes.c:90
+msgid "git notes get-ref"
+msgstr ""
+
+#: builtin/notes.c:139
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:143
+msgid "could not read 'show' output"
+msgstr ""
+
+#: builtin/notes.c:151
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr ""
+
+#: builtin/notes.c:169 builtin/tag.c:341
+#, c-format
+msgid "could not create file '%s'"
+msgstr ""
+
+#: builtin/notes.c:188
+msgid "Please supply the note contents using either -m or -F option"
+msgstr ""
+
+#: builtin/notes.c:209 builtin/notes.c:972
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:214
+msgid "unable to write note object"
+msgstr ""
+
+#: builtin/notes.c:216
+#, c-format
+msgid "The note contents has been left in %s"
+msgstr ""
+
+#: builtin/notes.c:250 builtin/tag.c:540
+#, c-format
+msgid "cannot read '%s'"
+msgstr ""
+
+#: builtin/notes.c:252 builtin/tag.c:543
+#, c-format
+msgid "could not open or read '%s'"
+msgstr ""
+
+#: builtin/notes.c:271 builtin/notes.c:444 builtin/notes.c:446
+#: builtin/notes.c:506 builtin/notes.c:560 builtin/notes.c:643
+#: builtin/notes.c:648 builtin/notes.c:723 builtin/notes.c:765
+#: builtin/notes.c:967 builtin/tag.c:556
+#, c-format
+msgid "Failed to resolve '%s' as a valid ref."
+msgstr ""
+
+#: builtin/notes.c:274
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr ""
+
+#: builtin/notes.c:298
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr ""
+
+#: builtin/notes.c:339
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:349
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr ""
+
+#. TRANSLATORS: The first %s is the name of the
+#. environment variable, the second %s is its value
+#: builtin/notes.c:376
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr ""
+
+#: builtin/notes.c:440
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr ""
+
+#: builtin/notes.c:455
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+msgstr ""
+
+#: builtin/notes.c:499 builtin/notes.c:553 builtin/notes.c:626
+#: builtin/notes.c:638 builtin/notes.c:711 builtin/notes.c:758
+#: builtin/notes.c:1032
+msgid "too many parameters"
+msgstr ""
+
+#: builtin/notes.c:512 builtin/notes.c:771
+#, c-format
+msgid "No note found for object %s."
+msgstr ""
+
+#: builtin/notes.c:534 builtin/notes.c:691
+msgid "note contents as a string"
+msgstr ""
+
+#: builtin/notes.c:537 builtin/notes.c:694
+msgid "note contents in a file"
+msgstr ""
+
+#: builtin/notes.c:539 builtin/notes.c:542 builtin/notes.c:696
+#: builtin/notes.c:699 builtin/tag.c:474
+msgid "object"
+msgstr ""
+
+#: builtin/notes.c:540 builtin/notes.c:697
+msgid "reuse and edit specified note object"
+msgstr ""
+
+#: builtin/notes.c:543 builtin/notes.c:700
+msgid "reuse specified note object"
+msgstr ""
+
+#: builtin/notes.c:545 builtin/notes.c:613
+msgid "replace existing notes"
+msgstr ""
+
+#: builtin/notes.c:579
+#, c-format
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:584 builtin/notes.c:661
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr ""
+
+#: builtin/notes.c:614
+msgid "read objects from stdin"
+msgstr ""
+
+#: builtin/notes.c:616
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr ""
+
+#: builtin/notes.c:634
+msgid "too few parameters"
+msgstr ""
+
+#: builtin/notes.c:655
+#, c-format
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr ""
+
+#: builtin/notes.c:667
+#, c-format
+msgid "Missing notes on source object %s. Cannot copy."
+msgstr ""
+
+#: builtin/notes.c:716
+#, c-format
+msgid ""
+"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
+"Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
+msgstr ""
+
+#: builtin/notes.c:863
+msgid "General options"
+msgstr ""
+
+#: builtin/notes.c:865
+msgid "Merge options"
+msgstr ""
+
+#: builtin/notes.c:867
+msgid ""
+"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+msgstr ""
+
+#: builtin/notes.c:869
+msgid "Committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:871
+msgid "finalize notes merge by committing unmerged notes"
+msgstr ""
+
+#: builtin/notes.c:873
+msgid "Aborting notes merge resolution"
+msgstr ""
+
+#: builtin/notes.c:875
+msgid "abort notes merge"
+msgstr ""
+
+#: builtin/notes.c:970
+#, c-format
+msgid "Object %s has no note\n"
+msgstr ""
+
+#: builtin/notes.c:982
+msgid "attempt to remove non-existent note is not an error"
+msgstr ""
+
+#: builtin/notes.c:985
+msgid "read object names from the standard input"
+msgstr ""
+
+#: builtin/notes.c:1066
+msgid "notes_ref"
+msgstr ""
+
+#: builtin/notes.c:1067
+msgid "use notes from <notes_ref>"
+msgstr ""
+
+#: builtin/notes.c:1102 builtin/remote.c:1598
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr ""
+
+#: builtin/pack-objects.c:23
+msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:24
+msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
+msgstr ""
+
+#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
+#, c-format
+msgid "deflate error (%d)"
+msgstr ""
+
+#: builtin/pack-objects.c:2397
+#, c-format
+msgid "unsupported index version %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2401
+#, c-format
+msgid "bad index version '%s'"
+msgstr ""
+
+#: builtin/pack-objects.c:2424
+#, c-format
+msgid "option %s does not accept negative form"
+msgstr ""
+
+#: builtin/pack-objects.c:2428
+#, c-format
+msgid "unable to parse value '%s' for option %s"
+msgstr ""
+
+#: builtin/pack-objects.c:2447
+msgid "do not show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2449
+msgid "show progress meter"
+msgstr ""
+
+#: builtin/pack-objects.c:2451
+msgid "show progress meter during object writing phase"
+msgstr ""
+
+#: builtin/pack-objects.c:2454
+msgid "similar to --all-progress when progress meter is shown"
+msgstr ""
+
+#: builtin/pack-objects.c:2455
+msgid "version[,offset]"
+msgstr ""
+
+#: builtin/pack-objects.c:2456
+msgid "write the pack index file in the specified idx format version"
+msgstr ""
+
+#: builtin/pack-objects.c:2459
+msgid "maximum size of each output pack file"
+msgstr ""
+
+#: builtin/pack-objects.c:2461
+msgid "ignore borrowed objects from alternate object store"
+msgstr ""
+
+#: builtin/pack-objects.c:2463
+msgid "ignore packed objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2465
+msgid "limit pack window by objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2467
+msgid "limit pack window by memory in addition to object limit"
+msgstr ""
+
+#: builtin/pack-objects.c:2469
+msgid "maximum length of delta chain allowed in the resulting pack"
+msgstr ""
+
+#: builtin/pack-objects.c:2471
+msgid "reuse existing deltas"
+msgstr ""
+
+#: builtin/pack-objects.c:2473
+msgid "reuse existing objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2475
+msgid "use OFS_DELTA objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2477
+msgid "use threads when searching for best delta matches"
+msgstr ""
+
+#: builtin/pack-objects.c:2479
+msgid "do not create an empty pack output"
+msgstr ""
+
+#: builtin/pack-objects.c:2481
+msgid "read revision arguments from standard input"
+msgstr ""
+
+#: builtin/pack-objects.c:2483
+msgid "limit the objects to those that are not yet packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2486
+msgid "include objects reachable from any reference"
+msgstr ""
+
+#: builtin/pack-objects.c:2489
+msgid "include objects referred by reflog entries"
+msgstr ""
+
+#: builtin/pack-objects.c:2492
+msgid "output pack to stdout"
+msgstr ""
+
+#: builtin/pack-objects.c:2494
+msgid "include tag objects that refer to objects to be packed"
+msgstr ""
+
+#: builtin/pack-objects.c:2496
+msgid "keep unreachable objects"
+msgstr ""
+
+#: builtin/pack-objects.c:2497 parse-options.h:141
+msgid "time"
+msgstr ""
+
+#: builtin/pack-objects.c:2498
+msgid "unpack unreachable objects newer than <time>"
+msgstr ""
+
+#: builtin/pack-objects.c:2501
+msgid "create thin packs"
+msgstr ""
+
+#: builtin/pack-objects.c:2503
+msgid "ignore packs that have companion .keep file"
+msgstr ""
+
+#: builtin/pack-objects.c:2505
+msgid "pack compression level"
+msgstr ""
+
+#: builtin/pack-objects.c:2507
+msgid "do not hide commits by grafts"
+msgstr ""
+
+#: builtin/pack-refs.c:6
+msgid "git pack-refs [options]"
+msgstr ""
+
+#: builtin/pack-refs.c:14
+msgid "pack everything"
+msgstr ""
+
+#: builtin/pack-refs.c:15
+msgid "prune loose refs (default)"
+msgstr ""
+
+#: builtin/prune-packed.c:7
+msgid "git prune-packed [-n|--dry-run] [-q|--quiet]"
+msgstr ""
+
+#: builtin/prune.c:12
+msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
+msgstr ""
+
+#: builtin/prune.c:132
+msgid "do not remove, show only"
+msgstr ""
+
+#: builtin/prune.c:133
+msgid "report pruned objects"
+msgstr ""
+
+#: builtin/prune.c:136
+msgid "expire objects older than <time>"
+msgstr ""
+
+#: builtin/push.c:14
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr ""
+
+#: builtin/push.c:45
+msgid "tag shorthand without <tag>"
+msgstr ""
+
+#: builtin/push.c:64
+msgid "--delete only accepts plain target ref names"
+msgstr ""
+
+#: builtin/push.c:99
+msgid ""
+"\n"
+"To choose either option permanently, see push.default in 'git help config'."
+msgstr ""
+
+#: builtin/push.c:102
+#, c-format
+msgid ""
+"The upstream branch of your current branch does not match\n"
+"the name of your current branch. To push to the upstream branch\n"
+"on the remote, use\n"
+"\n"
+" git push %s HEAD:%s\n"
+"\n"
+"To push to the branch of the same name on the remote, use\n"
+"\n"
+" git push %s %s\n"
+"%s"
+msgstr ""
+
+#: builtin/push.c:121
+#, c-format
+msgid ""
+"You are not currently on a branch.\n"
+"To push the history leading to the current (detached HEAD)\n"
+"state now, use\n"
+"\n"
+" git push %s HEAD:<name-of-remote-branch>\n"
+msgstr ""
+
+#: builtin/push.c:128
+#, c-format
+msgid ""
+"The current branch %s has no upstream branch.\n"
+"To push the current branch and set the remote as upstream, use\n"
+"\n"
+" git push --set-upstream %s %s\n"
+msgstr ""
+
+#: builtin/push.c:136
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr ""
+
+#: builtin/push.c:139
+#, c-format
+msgid ""
+"You are pushing to remote '%s', which is not the upstream of\n"
+"your current branch '%s', without telling me what to push\n"
+"to update which remote branch."
+msgstr ""
+
+#: builtin/push.c:151
+msgid ""
+"push.default is unset; its implicit value is changing in\n"
+"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+"and maintain the current behavior after the default changes, use:\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"To squelch this message and adopt the new behavior now, use:\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"See 'git help config' and search for 'push.default' for further "
+"information.\n"
+"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+"'current' instead of 'simple' if you sometimes use older versions of Git)"
+msgstr ""
+
+#: builtin/push.c:199
+msgid ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr ""
+
+#: builtin/push.c:206
+msgid ""
+"Updates were rejected because the tip of your current branch is behind\n"
+"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
+"before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
+msgstr ""
+
+#: builtin/push.c:212
+msgid ""
+"Updates were rejected because a pushed branch tip is behind its remote\n"
+"counterpart. If you did not intend to push that branch, you may want to\n"
+"specify branches to push or set the 'push.default' configuration variable\n"
+"to 'simple', 'current' or 'upstream' to push only the current branch."
+msgstr ""
+
+#: builtin/push.c:218
+msgid ""
+"Updates were rejected because a pushed branch tip is behind its remote\n"
+"counterpart. Check out this branch and merge the remote changes\n"
+"(e.g. 'git pull') before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
+msgstr ""
+
+#: builtin/push.c:224
+msgid ""
+"Updates were rejected because the remote contains work that you do\n"
+"not have locally. This is usually caused by another repository pushing\n"
+"to the same ref. You may want to first merge the remote changes (e.g.,\n"
+"'git pull') before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
+msgstr ""
+
+#: builtin/push.c:231
+msgid "Updates were rejected because the tag already exists in the remote."
+msgstr ""
+
+#: builtin/push.c:234
+msgid ""
+"You cannot update a remote ref that points at a non-commit object,\n"
+"or update a remote ref to make it point at a non-commit object,\n"
+"without using the '--force' option.\n"
+msgstr ""
+
+#: builtin/push.c:294
+#, c-format
+msgid "Pushing to %s\n"
+msgstr ""
+
+#: builtin/push.c:298
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr ""
+
+#: builtin/push.c:331
+#, c-format
+msgid "bad repository '%s'"
+msgstr ""
+
+#: builtin/push.c:332
+msgid ""
+"No configured push destination.\n"
+"Either specify the URL from the command-line or configure a remote "
+"repository using\n"
+"\n"
+" git remote add <name> <url>\n"
+"\n"
+"and then push using the remote name\n"
+"\n"
+" git push <name>\n"
+msgstr ""
+
+#: builtin/push.c:347
+msgid "--all and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:348
+msgid "--all can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:353
+msgid "--mirror and --tags are incompatible"
+msgstr ""
+
+#: builtin/push.c:354
+msgid "--mirror can't be combined with refspecs"
+msgstr ""
+
+#: builtin/push.c:359
+msgid "--all and --mirror are incompatible"
+msgstr ""
+
+#: builtin/push.c:419
+msgid "repository"
+msgstr ""
+
+#: builtin/push.c:420
+msgid "push all refs"
+msgstr ""
+
+#: builtin/push.c:421
+msgid "mirror all refs"
+msgstr ""
+
+#: builtin/push.c:423
+msgid "delete refs"
+msgstr ""
+
+#: builtin/push.c:424
+msgid "push tags (can't be used with --all or --mirror)"
+msgstr ""
+
+#: builtin/push.c:427
+msgid "force updates"
+msgstr ""
+
+#: builtin/push.c:428
+msgid "check"
+msgstr ""
+
+#: builtin/push.c:429
+msgid "control recursive pushing of submodules"
+msgstr ""
+
+#: builtin/push.c:431
+msgid "use thin pack"
+msgstr ""
+
+#: builtin/push.c:432 builtin/push.c:433
+msgid "receive pack program"
+msgstr ""
+
+#: builtin/push.c:434
+msgid "set upstream for git pull/status"
+msgstr ""
+
+#: builtin/push.c:437
+msgid "prune locally removed refs"
+msgstr ""
+
+#: builtin/push.c:439
+msgid "bypass pre-push hook"
+msgstr ""
+
+#: builtin/push.c:440
+msgid "push missing but relevant tags"
+msgstr ""
+
+#: builtin/push.c:450
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr ""
+
+#: builtin/push.c:452
+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 "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 <branche>] [-m <maîtresse>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <nom> <URL>"
+
+#: builtin/remote.c:13 builtin/remote.c:32
+msgid "git remote rename <old> <new>"
+msgstr "git remote rename <ancienne> <nouvelle>"
+
+#: builtin/remote.c:14 builtin/remote.c:37
+msgid "git remote remove <name>"
+msgstr "git remote remove <nom>"
+
+#: builtin/remote.c:15 builtin/remote.c:42
+msgid "git remote set-head <name> (-a | -d | <branch>)"
+msgstr "git remote set-head <nom> (-a | -d | <branche>)"
+
+#: builtin/remote.c:16
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr "git remote [-v | --verbose] show [-n] <nom>"
+
+#: builtin/remote.c:17
+msgid "git remote prune [-n | --dry-run] <name>"
+msgstr "git remote prune [-n | --dry-run] <nom>"
+
+#: builtin/remote.c:18
+msgid ""
+"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
+msgstr "git remote [-v | --verbose] update [-p | --prune] [(<groupe> | <distante>)...]"
+
+#: builtin/remote.c:19
+msgid "git remote set-branches [--add] <name> <branch>..."
+msgstr "git remote set-branches [--add] <nom> <branche>..."
+
+#: builtin/remote.c:20 builtin/remote.c:68
+msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
+msgstr "git remote set-url [--push] <nom> <nouvelle-URL> [<ancienne-URL>]"
+
+#: builtin/remote.c:21 builtin/remote.c:69
+msgid "git remote set-url --add <name> <newurl>"
+msgstr "git remote set-url --add <nom> <nouvelle-URL>"
+
+#: builtin/remote.c:22 builtin/remote.c:70
+msgid "git remote set-url --delete <name> <url>"
+msgstr "git remote set-url --delete <nom> <URL>"
+
+#: builtin/remote.c:27
+msgid "git remote add [<options>] <name> <url>"
+msgstr "git remote add [<options>] <nom> <URL>"
+
+#: builtin/remote.c:47
+msgid "git remote set-branches <name> <branch>..."
+msgstr "git remote set-branches <nom> <branche>..."
+
+#: builtin/remote.c:48
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr "git remote set-branches --add <nom> <branche>..."
+
+#: builtin/remote.c:53
+msgid "git remote show [<options>] <name>"
+msgstr "git remote show [<options>] <nom>"
+
+#: builtin/remote.c:58
+msgid "git remote prune [<options>] <name>"
+msgstr "git remote prune [<options>] <nom>"
+
+#: builtin/remote.c:63
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr "git remote update [<options>] [<groupe> | <distante>]..."
+
+#: builtin/remote.c:98
+#, c-format
+msgid "Updating %s"
+msgstr "Mise à jour de %s"
+
+#: builtin/remote.c:130
+msgid ""
+"--mirror is dangerous and deprecated; please\n"
+"\t use --mirror=fetch or --mirror=push instead"
+msgstr ""
+"--mirror est dangereux et obsolète ; merci\n"
+"\t d'utiliser --mirror=fetch ou --mirror=push à la place"
+
+#: builtin/remote.c:147
+#, c-format
+msgid "unknown mirror argument: %s"
+msgstr "argument miroir inconnu : %s"
+
+#: builtin/remote.c:163
+msgid "fetch the remote branches"
+msgstr "rapatrier les branches distantes"
+
+#: builtin/remote.c:165
+msgid "import all tags and associated objects when fetching"
+msgstr "importer toutes les étiquettes et les objets associés lors du rapatriement"
+
+#: builtin/remote.c:168
+msgid "or do not fetch any tag at all (--no-tags)"
+msgstr "ou ne rapatrier aucune étiquette (--no-tags)"
+
+#: builtin/remote.c:170
+msgid "branch(es) to track"
+msgstr "branche(s) à suivre"
+
+#: builtin/remote.c:171
+msgid "master branch"
+msgstr "branche maîtresse"
+
+#: 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 "paramétrer la distante comme miroir pour pousser ou pour rapatrier depuis"
+
+#: builtin/remote.c:185
+msgid "specifying a master branch makes no sense with --mirror"
+msgstr "spécifier une branche maîtresse n'a pas de sens avec --mirror"
+
+#: builtin/remote.c:187
+msgid "specifying branches to track makes sense only with fetch mirrors"
+msgstr "spécifier les branches à suivre n'a de sens qu'avec des miroirs de rapatriement"
+
+#: builtin/remote.c:195 builtin/remote.c:646
+#, c-format
+msgid "remote %s already exists."
+msgstr "la distante %s existe déjà."
+
+#: builtin/remote.c:199 builtin/remote.c:650
+#, c-format
+msgid "'%s' is not a valid remote name"
+msgstr "'%s' n'est pas un nom valide de distante"
+
+#: builtin/remote.c:243
+#, c-format
+msgid "Could not setup master '%s'"
+msgstr "Impossible de paramétrer la maîtresse '%s'"
+
+#: builtin/remote.c:299
+#, c-format
+msgid "more than one %s"
+msgstr "plus d'un %s"
+
+#: builtin/remote.c:339
+#, c-format
+msgid "Could not get fetch map for refspec %s"
+msgstr ""
+
+#: builtin/remote.c:440 builtin/remote.c:448
+msgid "(matching)"
+msgstr "(correspond)"
+
+#: builtin/remote.c:452
+msgid "(delete)"
+msgstr "(supprimer)"
+
+#: builtin/remote.c:595 builtin/remote.c:601 builtin/remote.c:607
+#, c-format
+msgid "Could not append '%s' to '%s'"
+msgstr "Impossible d'ajouter '%s' à '%s'"
+
+#: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890
+#, c-format
+msgid "No such remote: %s"
+msgstr "Distante inconnue : %s"
+
+#: builtin/remote.c:656
+#, c-format
+msgid "Could not rename config section '%s' to '%s'"
+msgstr "Impossible de renommer la section de configuration '%s' en '%s'"
+
+#: builtin/remote.c:662 builtin/remote.c:799
+#, c-format
+msgid "Could not remove config section '%s'"
+msgstr "Impossible de supprimer la section de configuration '%s'"
+
+#: builtin/remote.c:677
+#, c-format
+msgid ""
+"Not updating non-default fetch refspec\n"
+"\t%s\n"
+"\tPlease update the configuration manually if necessary."
+msgstr ""
+"Pas de mise à jour du refspec de rapatriement qui n'est pas par défaut\n"
+"\t%s\n"
+"\tMerci de mettre à jour la configuration si nécessaire."
+
+#: builtin/remote.c:683
+#, c-format
+msgid "Could not append '%s'"
+msgstr "Impossible d'ajouter '%s'"
+
+#: builtin/remote.c:694
+#, c-format
+msgid "Could not set '%s'"
+msgstr "Impossible de définir '%s'"
+
+#: builtin/remote.c:716
+#, c-format
+msgid "deleting '%s' failed"
+msgstr "échec de suppression de '%s'"
+
+#: builtin/remote.c:750
+#, c-format
+msgid "creating '%s' failed"
+msgstr "échec de création de '%s'"
+
+#: builtin/remote.c:764
+#, c-format
+msgid "Could not remove branch %s"
+msgstr "Impossible de supprimer la branche %s"
+
+#: builtin/remote.c:834
+msgid ""
+"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
+"to delete it, use:"
+msgid_plural ""
+"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
+"to delete them, use:"
+msgstr[0] ""
+"Note : Une branche en dehors de refs/remotes/ n'a pas été supprimée ;\n"
+"pour la supprimer, utilisez :"
+msgstr[1] ""
+"Note : Plusieurs branches en dehors de refs/remotes/ n'ont pas été supprimées ;\n"
+"pour les supprimer, utilisez :"
+
+#: builtin/remote.c:943
+#, c-format
+msgid " new (next fetch will store in remotes/%s)"
+msgstr " nouveau (le prochain rapatriement (fetch) stockera dans remotes/%s)"
+
+#: builtin/remote.c:946
+msgid " tracked"
+msgstr " suivi"
+
+#: builtin/remote.c:948
+msgid " stale (use 'git remote prune' to remove)"
+msgstr " dépassé (utilisez 'git remote prune' pour supprimer)"
+
+#: builtin/remote.c:950
+msgid " ???"
+msgstr " ???"
+
+#: builtin/remote.c:991
+#, c-format
+msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
+msgstr "branch.%s.merge invalide ; ne peut pas rebaser sur plus d'une branche"
+
+#: builtin/remote.c:998
+#, c-format
+msgid "rebases onto remote %s"
+msgstr "rebase sur la distante %s"
+
+#: builtin/remote.c:1001
+#, c-format
+msgid " merges with remote %s"
+msgstr " fusionne avec la distante %s"
+
+#: builtin/remote.c:1002
+msgid " and with remote"
+msgstr " et avec la distante"
+
+#: builtin/remote.c:1004
+#, c-format
+msgid "merges with remote %s"
+msgstr "fusionne avec la distante %s"
+
+#: builtin/remote.c:1005
+msgid " and with remote"
+msgstr " et avec la distante"
+
+#: builtin/remote.c:1051
+msgid "create"
+msgstr "créer"
+
+#: builtin/remote.c:1054
+msgid "delete"
+msgstr "supprimer"
+
+#: builtin/remote.c:1058
+msgid "up to date"
+msgstr "à jour"
+
+#: builtin/remote.c:1061
+msgid "fast-forwardable"
+msgstr "peut être mis à jour en avance rapide"
+
+#: builtin/remote.c:1064
+msgid "local out of date"
+msgstr "le local n'est pas à jour"
+
+#: builtin/remote.c:1071
+#, c-format
+msgid " %-*s forces to %-*s (%s)"
+msgstr " %-*s force vers %-*s (%s)"
+
+#: builtin/remote.c:1074
+#, c-format
+msgid " %-*s pushes to %-*s (%s)"
+msgstr " %-*s pousse vers %-*s (%s)"
+
+#: builtin/remote.c:1078
+#, c-format
+msgid " %-*s forces to %s"
+msgstr " %-*s force vers %s"
+
+#: builtin/remote.c:1081
+#, c-format
+msgid " %-*s pushes to %s"
+msgstr " %-*s pousse vers %s"
+
+#: builtin/remote.c:1091
+msgid "do not query remotes"
+msgstr "ne pas interroger les distantes"
+
+#: builtin/remote.c:1118
+#, c-format
+msgid "* remote %s"
+msgstr "* distante %s"
+
+#: builtin/remote.c:1119
+#, c-format
+msgid " Fetch URL: %s"
+msgstr " URL de rapatriement : %s"
+
+#: builtin/remote.c:1120 builtin/remote.c:1285
+msgid "(no URL)"
+msgstr "(pas d'URL)"
+
+#: builtin/remote.c:1129 builtin/remote.c:1131
+#, c-format
+msgid " Push URL: %s"
+msgstr " URL push : %s"
+
+#: builtin/remote.c:1133 builtin/remote.c:1135 builtin/remote.c:1137
+#, c-format
+msgid " HEAD branch: %s"
+msgstr " Branche HEAD : %s"
+
+#: builtin/remote.c:1139
+#, c-format
+msgid ""
+" HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
+msgstr " Branche HEAD (la HEAD distante est ambiguë, peut être l'une des suivantes) :\n"
+
+#: builtin/remote.c:1151
+#, c-format
+msgid " Remote branch:%s"
+msgid_plural " Remote branches:%s"
+msgstr[0] " Branche distante :%s"
+msgstr[1] " Branches distantes :%s"
+
+#: builtin/remote.c:1154 builtin/remote.c:1181
+msgid " (status not queried)"
+msgstr " (statut non demandé)"
+
+#: builtin/remote.c:1163
+msgid " Local branch configured for 'git pull':"
+msgid_plural " Local branches configured for 'git pull':"
+msgstr[0] " Branche locale configurée pour 'git pull' :"
+msgstr[1] " Branches locales configurées pour 'git pull' :"
+
+#: builtin/remote.c:1171
+msgid " Local refs will be mirrored by 'git push'"
+msgstr " Les références locales seront reflétées par 'git push'"
+
+#: builtin/remote.c:1178
+#, c-format
+msgid " Local ref configured for 'git push'%s:"
+msgid_plural " Local refs configured for 'git push'%s:"
+msgstr[0] " Référence locale configurée pour 'git push'%s :"
+msgstr[1] " Références locales configurées pour 'git push'%s :"
+
+#: builtin/remote.c:1199
+msgid "set refs/remotes/<name>/HEAD according to remote"
+msgstr "définir refs/remotes/<nom>/HEAD selon la distante"
+
+#: builtin/remote.c:1201
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr "supprimer refs/remotes/<nom>/HEAD"
+
+#: builtin/remote.c:1216
+msgid "Cannot determine remote HEAD"
+msgstr "Impossible de déterminer la HEAD distante"
+
+#: builtin/remote.c:1218
+msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
+msgstr "Il y a de multiples branches HEAD distantes. Merci d'en choisir une explicitement avec :"
+
+#: builtin/remote.c:1228
+#, c-format
+msgid "Could not delete %s"
+msgstr "Impossible de supprimer %s"
+
+#: builtin/remote.c:1236
+#, c-format
+msgid "Not a valid ref: %s"
+msgstr "Référence non valide : %s"
+
+#: builtin/remote.c:1238
+#, c-format
+msgid "Could not setup %s"
+msgstr "Impossible de paramétrer %s"
+
+#: builtin/remote.c:1274
+#, c-format
+msgid " %s will become dangling!"
+msgstr " %s deviendra en suspens !"
+
+#: builtin/remote.c:1275
+#, c-format
+msgid " %s has become dangling!"
+msgstr " %s est devenu en suspens !"
+
+#: builtin/remote.c:1281
+#, c-format
+msgid "Pruning %s"
+msgstr "Élagage de %s"
+
+#: builtin/remote.c:1282
+#, c-format
+msgid "URL: %s"
+msgstr "URL : %s"
+
+#: builtin/remote.c:1295
+#, c-format
+msgid " * [would prune] %s"
+msgstr " * [serait élagué] %s"
+
+#: builtin/remote.c:1298
+#, c-format
+msgid " * [pruned] %s"
+msgstr " * [élagué] %s"
+
+#: builtin/remote.c:1321
+msgid "prune remotes after fetching"
+msgstr "élaguer les distants après le rapatriement"
+
+#: builtin/remote.c:1387 builtin/remote.c:1461
+#, c-format
+msgid "No such remote '%s'"
+msgstr "Pas de serveur remote '%s'"
+
+#: builtin/remote.c:1407
+msgid "add branch"
+msgstr "ajouter une branche"
+
+#: builtin/remote.c:1414
+msgid "no remote specified"
+msgstr "pas de serveur distant spécifié"
+
+#: builtin/remote.c:1436
+msgid "manipulate push URLs"
+msgstr "manipuler les URLs push"
+
+#: builtin/remote.c:1438
+msgid "add URL"
+msgstr "ajouter une URL"
+
+#: builtin/remote.c:1440
+msgid "delete URLs"
+msgstr "supprimer des URLs"
+
+#: builtin/remote.c:1447
+msgid "--add --delete doesn't make sense"
+msgstr "--add --delete n'a aucun sens"
+
+#: builtin/remote.c:1487
+#, c-format
+msgid "Invalid old URL pattern: %s"
+msgstr "Motif d'URL ancien invalide : %s"
+
+#: builtin/remote.c:1495
+#, c-format
+msgid "No such URL found: %s"
+msgstr "Pas d'URL trouvée : %s"
+
+#: builtin/remote.c:1497
+msgid "Will not delete all non-push URLs"
+msgstr ""
+
+#: builtin/remote.c:1569
+msgid "be verbose; must be placed before a subcommand"
+msgstr "être verbeux : doit être placé avant une sous-commande"
+
+#: builtin/replace.c:17
+msgid "git replace [-f] <object> <replacement>"
+msgstr "git replace [-f] <objet> <remplacement>"
+
+#: builtin/replace.c:18
+msgid "git replace -d <object>..."
+msgstr "git replace -d <objet>..."
+
+#: builtin/replace.c:19
+msgid "git replace -l [<pattern>]"
+msgstr "git replace -l [<motif>]"
+
+#: builtin/replace.c:121
+msgid "list replace refs"
+msgstr "afficher les références de remplacement"
+
+#: builtin/replace.c:122
+msgid "delete replace refs"
+msgstr "supprimer les références de remplacement"
+
+#: builtin/replace.c:123
+msgid "replace the ref if it exists"
+msgstr "remplacer la référence si elle existe"
+
+#: builtin/rerere.c:11
+msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
+msgstr "git rerere [clear | forget chemin... | status | remaining | diff | gc]"
+
+#: builtin/rerere.c:56
+msgid "register clean resolutions in index"
+msgstr "enregistrer des résolutions propres dans l'index"
+
+#: builtin/reset.c:25
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+
+#: builtin/reset.c:26
+msgid "git reset [-q] <tree-ish> [--] <paths>..."
+msgstr "git reset [-q] <arbre> [--] <chemins>..."
+
+#: builtin/reset.c:27
+msgid "git reset --patch [<tree-ish>] [--] [<paths>...]"
+msgstr "git reset --patch [<arbre>] [--] [<chemins>...]"
+
+#: builtin/reset.c:33
+msgid "mixed"
+msgstr "mixed"
+
+#: builtin/reset.c:33
+msgid "soft"
+msgstr "soft"
+
+#: builtin/reset.c:33
+msgid "hard"
+msgstr "hard"
+
+#: builtin/reset.c:33
+msgid "merge"
+msgstr "merge"
+
+#: builtin/reset.c:33
+msgid "keep"
+msgstr "keep"
+
+#: builtin/reset.c:73
+msgid "You do not have a valid HEAD."
+msgstr "Vous n'avez pas une HEAD valide."
+
+#: builtin/reset.c:75
+msgid "Failed to find tree of HEAD."
+msgstr "Impossible de trouver l'arbre pour HEAD."
+
+#: builtin/reset.c:81
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr "Impossible de trouver l'arbre pour %s."
+
+#: builtin/reset.c:98
+#, c-format
+msgid "HEAD is now at %s"
+msgstr "HEAD est maintenant à %s"
+
+#: builtin/reset.c:169
+#, c-format
+msgid "Cannot do a %s reset in the middle of a merge."
+msgstr "Impossible de faire un \"reset %s\" au milieu d'une fusion."
+
+#: builtin/reset.c:248
+msgid "be quiet, only report errors"
+msgstr "être silencieux, afficher seulement les erreurs"
+
+#: builtin/reset.c:250
+msgid "reset HEAD and index"
+msgstr "réinitialiser HEAD et l'index"
+
+#: builtin/reset.c:251
+msgid "reset only HEAD"
+msgstr "réinitialiser seulement HEAD"
+
+#: builtin/reset.c:253 builtin/reset.c:255
+msgid "reset HEAD, index and working tree"
+msgstr "réinitialiser HEAD, l'index et la copie de travail"
+
+#: builtin/reset.c:257
+msgid "reset HEAD but keep local changes"
+msgstr "réinitialiser HEAD mais garder les changements locaux"
+
+#: builtin/reset.c:275
+#, c-format
+msgid "Failed to resolve '%s' as a valid revision."
+msgstr "Échec de résolution de '%s' comme une révision valide."
+
+#: builtin/reset.c:278 builtin/reset.c:286
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr "Impossible d'analyser l'objet '%s'."
+
+#: builtin/reset.c:283
+#, c-format
+msgid "Failed to resolve '%s' as a valid tree."
+msgstr "Échec de résolution de '%s' comme un arbre valide."
+
+#: builtin/reset.c:292
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr "--patch est incompatible avec --{hard,mixed,soft}"
+
+#: builtin/reset.c:301
+msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+msgstr "--mixed avec des chemins est obsolète ; utilisez 'git reset -- <paths>' à la place."
+
+#: builtin/reset.c:303
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr "Impossible de faire un \"%s reset\" avec des chemins."
+
+#: builtin/reset.c:313
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+msgstr "Le \"%s reset\" n'est pas permis dans un dépôt nu"
+
+#: builtin/reset.c:333
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr "Impossible de réinitialiser le fichier d'index à la révision '%s'."
+
+#: builtin/reset.c:339
+msgid "Unstaged changes after reset:"
+msgstr "Modifications non indexées après reset :"
+
+#: builtin/reset.c:344
+msgid "Could not write new index file."
+msgstr "Impossible d'écrire le nouveau fichier d'index."
+
+#: builtin/rev-parse.c:339
+msgid "git rev-parse --parseopt [options] -- [<args>...]"
+msgstr "git rev-parse --parseopt [options] -- [<arguments>...]"
+
+#: builtin/rev-parse.c:344
+msgid "keep the `--` passed as an arg"
+msgstr "garder le `--` passé en argument"
+
+#: builtin/rev-parse.c:346
+msgid "stop parsing after the first non-option argument"
+msgstr "arrêt de l'analyse après le premier argument qui n'est pas une option"
+
+#: 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 [options] -- [<arguments>...]\n"
+" ou : git rev-parse --sq-quote [<argument>...]\n"
+" ou : git rev-parse [options] [<argument>...]\n"
+"\n"
+"Lancez \"git rev-parse --parseopt -h\" pour plus d'information sur l'utilisation principale."
+
+#: builtin/revert.c:22
+msgid "git revert [options] <commit-ish>..."
+msgstr "git revert [options] <commit>..."
+
+#: builtin/revert.c:23
+msgid "git revert <subcommand>"
+msgstr "git revert <sous-commande>"
+
+#: builtin/revert.c:28
+msgid "git cherry-pick [options] <commit-ish>..."
+msgstr "git cherry-pick [options] <commit>..."
+
+#: builtin/revert.c:29
+msgid "git cherry-pick <subcommand>"
+msgstr "git cherry-pick <sous-commande>"
+
+#: builtin/revert.c:70 builtin/revert.c:92
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr "%s : %s ne peut pas être utilisé avec %s"
+
+#: builtin/revert.c:103
+msgid "end revert or cherry-pick sequence"
+msgstr "mettre fin au retour ou picorage"
+
+#: builtin/revert.c:104
+msgid "resume revert or cherry-pick sequence"
+msgstr "reprendre le retour ou picorage"
+
+#: builtin/revert.c:105
+msgid "cancel revert or cherry-pick sequence"
+msgstr "annuler le retour ou picorage"
+
+#: builtin/revert.c:106
+msgid "don't automatically commit"
+msgstr "ne pas valider automatiquement"
+
+#: builtin/revert.c:107
+msgid "edit the commit message"
+msgstr "éditer le message de validation"
+
+#: builtin/revert.c:110
+msgid "parent number"
+msgstr "numéro de parent"
+
+#: builtin/revert.c:112
+msgid "merge strategy"
+msgstr "stratégie de fusion"
+
+#: builtin/revert.c:113
+msgid "option"
+msgstr "option"
+
+#: builtin/revert.c:114
+msgid "option for merge strategy"
+msgstr "option pour la stratégie de fusion"
+
+#: builtin/revert.c:125
+msgid "append commit name"
+msgstr "ajouter le nom de validation"
+
+#: builtin/revert.c:126
+msgid "allow fast-forward"
+msgstr "autoriser l'avance rapide"
+
+#: builtin/revert.c:127
+msgid "preserve initially empty commits"
+msgstr "préserver les validations vides initialement"
+
+#: builtin/revert.c:128
+msgid "allow commits with empty messages"
+msgstr "autoriser les validations avec des messages vides"
+
+#: builtin/revert.c:129
+msgid "keep redundant, empty commits"
+msgstr "garder les validations redondantes, vides"
+
+#: builtin/revert.c:133
+msgid "program error"
+msgstr "erreur du programme"
+
+#: builtin/revert.c:223
+msgid "revert failed"
+msgstr "revert a échoué"
+
+#: builtin/revert.c:238
+msgid "cherry-pick failed"
+msgstr "le picorage a échoué"
+
+#: builtin/rm.c:15
+msgid "git rm [options] [--] <file>..."
+msgstr "git rm [options] [--] <fichier>..."
+
+#: builtin/rm.c:64 builtin/rm.c:186
+#, c-format
+msgid ""
+"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"(use 'rm -rf' if you really want to remove it including all of its history)"
+msgstr ""
+"le sous-module '%s' (ou un des sous-modules imbriqués) utilise un répertoire .git\n"
+"(utilisez 'rm -rf' si vous souhaitez vraiment le supprimer avec tout son historique)"
+
+#: builtin/rm.c:174
+#, c-format
+msgid ""
+"'%s' has staged content different from both the file and the HEAD\n"
+"(use -f to force removal)"
+msgstr ""
+"'%s' a du contenu indexé différent du fichier et de HEAD\n"
+"(utilisez -f pour forcer la suppression)"
+
+#: builtin/rm.c:180
+#, c-format
+msgid ""
+"'%s' has changes staged in the index\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+"'%s' a des changements dans l'index\n"
+"(utilisez --cached pour garder le fichier, ou -f pour forcer la suppression)"
+
+#: builtin/rm.c:191
+#, c-format
+msgid ""
+"'%s' has local modifications\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+"'%s' a des modifications locales\n"
+"(utilisez --cached pour garder le fichier, ou -f pour forcer la suppression)"
+
+#: builtin/rm.c:207
+msgid "do not list removed files"
+msgstr "ne pas afficher les fichiers supprimés"
+
+#: builtin/rm.c:208
+msgid "only remove from the index"
+msgstr "supprimer seulement de l'index"
+
+#: builtin/rm.c:209
+msgid "override the up-to-date check"
+msgstr "outrepasser la vérification des fichiers à jour"
+
+#: builtin/rm.c:210
+msgid "allow recursive removal"
+msgstr "autoriser la suppression récursive"
+
+#: builtin/rm.c:212
+msgid "exit with a zero status even if nothing matched"
+msgstr "sortir avec un statut zéro même si rien ne correspondait"
+
+#: builtin/rm.c:283
+#, c-format
+msgid "not removing '%s' recursively without -r"
+msgstr "pas de suppression récursive de '%s' sans -r"
+
+#: builtin/rm.c:322
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr "git rm : impossible de supprimer %s"
+
+#: builtin/shortlog.c:13
+msgid "git shortlog [<options>] [<revision range>] [[--] [<path>...]]"
+msgstr "git shortlog [<options>] [<intervalle révisions>] [[--] [<chemin>...]]"
+
+#: builtin/shortlog.c:131
+#, c-format
+msgid "Missing author: %s"
+msgstr "Auteur manquant : %s"
+
+#: builtin/shortlog.c:227
+msgid "sort output according to the number of commits per author"
+msgstr "trier la sortie sur le nombre de validations par auteur"
+
+#: builtin/shortlog.c:229
+msgid "Suppress commit descriptions, only provides commit count"
+msgstr "Supprimer les descriptions de validation, fournit seulement le nombre de validations"
+
+#: builtin/shortlog.c:231
+msgid "Show the email address of each author"
+msgstr "Afficher l'adresse e-mail de chaque auteur"
+
+#: builtin/shortlog.c:232
+msgid "w[,i1[,i2]]"
+msgstr "w[,i1[,i2]]"
+
+#: builtin/shortlog.c:233
+msgid "Linewrap output"
+msgstr "Couper les lignes"
+
+#: 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[=<quand>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<révision> | <glob>)...]"
+
+#: builtin/show-branch.c:10
+msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
+msgstr "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<référence>]"
+
+#: builtin/show-branch.c:650
+msgid "show remote-tracking and local branches"
+msgstr "afficher les branches de suivi distantes et les branches locales"
+
+#: builtin/show-branch.c:652
+msgid "show remote-tracking branches"
+msgstr "afficher les branches de suivi distantes"
+
+#: builtin/show-branch.c:654
+msgid "color '*!+-' corresponding to the branch"
+msgstr "couleur '*!+-' correspondant à la branche"
+
+#: builtin/show-branch.c:656
+msgid "show <n> more commits after the common ancestor"
+msgstr "afficher <n> validations de plus après l'ancêtre commun"
+
+#: builtin/show-branch.c:658
+msgid "synonym to more=-1"
+msgstr "synonyme de more=-1"
+
+#: builtin/show-branch.c:659
+msgid "suppress naming strings"
+msgstr ""
+
+#: builtin/show-branch.c:661
+msgid "include the current branch"
+msgstr "inclure la branche courante"
+
+#: builtin/show-branch.c:663
+msgid "name commits with their object names"
+msgstr "nommer les validations avec leurs noms d'objet"
+
+#: builtin/show-branch.c:665
+msgid "show possible merge bases"
+msgstr "afficher les bases possibles de fusion"
+
+#: builtin/show-branch.c:667
+msgid "show refs unreachable from any other ref"
+msgstr "afficher les références non accessibles depuis toute autre référence"
+
+#: builtin/show-branch.c:669
+msgid "show commits in topological order"
+msgstr "afficher les validations dans l'ordre topologique"
+
+#: builtin/show-branch.c:671
+msgid "show only commits not on the first branch"
+msgstr "afficher seulement les validations qui ne sont pas sur la première branche"
+
+#: builtin/show-branch.c:673
+msgid "show merges reachable from only one tip"
+msgstr "afficher les fusions accessibles depuis une seule pointe"
+
+#: builtin/show-branch.c:675
+msgid "show commits where no parent comes before its children"
+msgstr "afficher les validations où aucun parent ne vient avant ses enfants"
+
+#: builtin/show-branch.c:677
+msgid "<n>[,<base>]"
+msgstr "<n>[,<base>]"
+
+#: builtin/show-branch.c:678
+msgid "show <n> most recent ref-log entries starting at base"
+msgstr "afficher les <n> plus récentes entrées de ref-log en commençant à la base"
+
+#: builtin/show-ref.c:10
+msgid ""
+"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--"
+"hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "
+msgstr "git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [motif*] "
+
+#: builtin/show-ref.c:11
+msgid "git show-ref --exclude-existing[=pattern] < ref-list"
+msgstr "git show-ref --exclude-existing[=motif] < liste-références"
+
+#: builtin/show-ref.c:165
+msgid "only show tags (can be combined with heads)"
+msgstr "afficher seulement les étiquettes (peut être combiné avec des têtes)"
+
+#: builtin/show-ref.c:166
+msgid "only show heads (can be combined with tags)"
+msgstr "afficher seulement les têtes (peut être combiné avec des étiquettes)"
+
+#: builtin/show-ref.c:167
+msgid "stricter reference checking, requires exact ref path"
+msgstr "vérification de référence plus stricte, requiert un chemin de référence exact"
+
+#: builtin/show-ref.c:170 builtin/show-ref.c:172
+msgid "show the HEAD reference"
+msgstr "afficher la référence HEAD"
+
+#: builtin/show-ref.c:174
+msgid "dereference tags into object IDs"
+msgstr "déréférencer les étiquettes en IDs d'objet"
+
+#: builtin/show-ref.c:176
+msgid "only show SHA1 hash using <n> digits"
+msgstr "afficher seulement le hachage SHA1 en utilisant <n> chiffres"
+
+#: builtin/show-ref.c:180
+msgid "do not print results to stdout (useful with --verify)"
+msgstr "ne pas afficher les résultats sur la sortie standard (pratique avec --verify)"
+
+#: builtin/show-ref.c:182
+msgid "show refs from stdin that aren't in local repository"
+msgstr "afficher les références de l'entrée standard qui ne sont pas dans le dépôt local"
+
+#: builtin/symbolic-ref.c:7
+msgid "git symbolic-ref [options] name [ref]"
+msgstr "git symbolic-ref [options] nom [référence]"
+
+#: builtin/symbolic-ref.c:8
+msgid "git symbolic-ref -d [-q] name"
+msgstr "git symbolic-ref -d [-q] nom"
+
+#: builtin/symbolic-ref.c:40
+msgid "suppress error message for non-symbolic (detached) refs"
+msgstr "supprimer le message d'erreur pour une référence non symbolique (détachée)"
+
+#: builtin/symbolic-ref.c:41
+msgid "delete symbolic ref"
+msgstr "supprimer la référence symbolique"
+
+#: builtin/symbolic-ref.c:42
+msgid "shorten ref output"
+msgstr "raccourcir l'affichage de la référence"
+
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
+msgid "reason"
+msgstr "raison"
+
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
+msgid "reason of the update"
+msgstr "raison de la mise à jour"
+
+#: 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 <id-clé>] [-f] [-m <msg>|-F <file>] <nométiquette> [<head>]"
+
+#: builtin/tag.c:23
+msgid "git tag -d <tagname>..."
+msgstr "git tag -d <nométiquette>..."
+
+#: builtin/tag.c:24
+msgid ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
+"\t\t[<pattern>...]"
+msgstr ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <objet>] \n"
+"\t\t[<motif>...]"
+
+#: builtin/tag.c:26
+msgid "git tag -v <tagname>..."
+msgstr "git tag -v <nométiquette>..."
+
+#: builtin/tag.c:60
+#, c-format
+msgid "malformed object at '%s'"
+msgstr "objet malformé à '%s'"
+
+#: builtin/tag.c:207
+#, c-format
+msgid "tag name too long: %.*s..."
+msgstr "nom d'étiquette trop long : %.*s..."
+
+#: builtin/tag.c:212
+#, c-format
+msgid "tag '%s' not found."
+msgstr "étiquette '%s' non trouvée."
+
+#: builtin/tag.c:227
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr "Étiquette '%s' supprimée (elle était %s)\n"
+
+#: builtin/tag.c:239
+#, c-format
+msgid "could not verify the tag '%s'"
+msgstr "impossible de vérifier l'étiquette '%s'"
+
+#: builtin/tag.c:249
+#, c-format
+msgid ""
+"\n"
+"Write a tag message\n"
+"Lines starting with '%c' will be ignored.\n"
+msgstr ""
+"\n"
+"Écrire un message pour l'étiquette\n"
+"Les lignes commençant par '%c' seront ignorées.\n"
+
+#: builtin/tag.c:253
+#, c-format
+msgid ""
+"\n"
+"Write a tag message\n"
+"Lines starting with '%c' will be kept; you may remove them yourself if you "
+"want to.\n"
+msgstr ""
+"\n"
+"Écrire un message pour l'étiquette\n"
+"Les lignes commençant par '%c' seront gardées ; vous pouvez les retirer vous-même si vous le souhaitez.\n"
+
+#: builtin/tag.c:292
+msgid "unable to sign the tag"
+msgstr "impossible de signer l'étiquette"
+
+#: builtin/tag.c:294
+msgid "unable to write tag file"
+msgstr "impossible d'écrire le fichier d'étiquettes"
+
+#: builtin/tag.c:319
+msgid "bad object type."
+msgstr "mauvais type d'objet."
+
+#: builtin/tag.c:332
+msgid "tag header too big."
+msgstr "en-tête d'étiquette trop gros."
+
+#: builtin/tag.c:368
+msgid "no tag message?"
+msgstr "pas de message pour l'étiquette ?"
+
+#: builtin/tag.c:374
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr "Le message pour l'étiquette a été laissé dans %s\n"
+
+#: builtin/tag.c:423
+msgid "switch 'points-at' requires an object"
+msgstr "le commutateur 'points-at' requiert un objet"
+
+#: builtin/tag.c:425
+#, c-format
+msgid "malformed object name '%s'"
+msgstr "nom d'objet malformé '%s'"
+
+#: builtin/tag.c:445
+msgid "list tag names"
+msgstr "afficher les noms des étiquettes"
+
+#: builtin/tag.c:447
+msgid "print <n> lines of each tag message"
+msgstr "affiche <n> lignes de chaque message d'étiquette"
+
+#: builtin/tag.c:449
+msgid "delete tags"
+msgstr "supprimer des étiquettes"
+
+#: builtin/tag.c:450
+msgid "verify tags"
+msgstr "vérifier des étiquettes"
+
+#: builtin/tag.c:452
+msgid "Tag creation options"
+msgstr "Options de création de l'étiquette"
+
+#: builtin/tag.c:454
+msgid "annotated tag, needs a message"
+msgstr "étiquette annotée, nécessite un message"
+
+#: builtin/tag.c:456
+msgid "tag message"
+msgstr "message pour l'étiquette"
+
+#: builtin/tag.c:458
+msgid "annotated and GPG-signed tag"
+msgstr "étiquette annotée et signée avec GPG"
+
+#: builtin/tag.c:462
+msgid "use another key to sign the tag"
+msgstr "utiliser une autre clé pour signer l'étiquette"
+
+#: builtin/tag.c:463
+msgid "replace the tag if exists"
+msgstr "remplacer l'étiquette si elle existe"
+
+#: builtin/tag.c:464
+msgid "show tag list in columns"
+msgstr "afficher la liste des étiquettes sous forme de colonnes"
+
+#: builtin/tag.c:466
+msgid "Tag listing options"
+msgstr "Options d'affichage des étiquettes"
+
+#: builtin/tag.c:469
+msgid "print only tags that contain the commit"
+msgstr "afficher seulement les étiquettes qui contiennent la validation"
+
+#: builtin/tag.c:475
+msgid "print only tags of the object"
+msgstr "afficher seulement les étiquettes de l'objet"
+
+#: builtin/tag.c:504
+msgid "--column and -n are incompatible"
+msgstr "--column et -n sont incompatibles"
+
+#: builtin/tag.c:521
+msgid "-n option is only allowed with -l."
+msgstr "l'option -n est autorisée seulement avec -l."
+
+#: builtin/tag.c:523
+msgid "--contains option is only allowed with -l."
+msgstr "l'option --contains est autorisée seulement avec -l."
+
+#: builtin/tag.c:525
+msgid "--points-at option is only allowed with -l."
+msgstr "l'option --points-at est autorisée seulement avec -l."
+
+#: builtin/tag.c:533
+msgid "only one -F or -m option is allowed."
+msgstr "une seule option -F ou -m est autorisée."
+
+#: builtin/tag.c:553
+msgid "too many params"
+msgstr "trop de paramètres"
+
+#: builtin/tag.c:559
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr "'%s' n'est pas un nom d'étiquette valide."
+
+#: builtin/tag.c:564
+#, c-format
+msgid "tag '%s' already exists"
+msgstr "l'étiquette '%s' existe déjà"
+
+#: builtin/tag.c:582
+#, c-format
+msgid "%s: cannot lock the ref"
+msgstr "%s : impossible de verrouiller la référence"
+
+#: builtin/tag.c:584
+#, c-format
+msgid "%s: cannot update the ref"
+msgstr "%s : impossible de mettre à jour la référence"
+
+#: builtin/tag.c:586
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+msgstr "Étiquette '%s' mise à jour (elle était %s)\n"
+
+#: builtin/update-index.c:401
+msgid "git update-index [options] [--] [<file>...]"
+msgstr "git update-index [options] [--] [<fichier>...]"
+
+#: builtin/update-index.c:718
+msgid "continue refresh even when index needs update"
+msgstr "continuer de rafraîchir même si l'index a besoin d'une mise à jour"
+
+#: builtin/update-index.c:721
+msgid "refresh: ignore submodules"
+msgstr "rafraîchir : ignorer les sous-modules"
+
+#: builtin/update-index.c:724
+msgid "do not ignore new files"
+msgstr "ne pas ignorer les nouveaux fichiers"
+
+#: builtin/update-index.c:726
+msgid "let files replace directories and vice-versa"
+msgstr "laisser les fichiers remplacer des répertoires et vice-versa"
+
+#: builtin/update-index.c:728
+msgid "notice files missing from worktree"
+msgstr "aviser des fichiers manquants dans la copie de travail"
+
+#: builtin/update-index.c:730
+msgid "refresh even if index contains unmerged entries"
+msgstr "rafraîchir même si l'index contient des entrées non fusionnées"
+
+#: builtin/update-index.c:733
+msgid "refresh stat information"
+msgstr "rafraîchir l'information de stat"
+
+#: builtin/update-index.c:737
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr "comme --refresh, mais en ignorant l'option assume-unchanged"
+
+#: builtin/update-index.c:741
+msgid "<mode> <object> <path>"
+msgstr "<mode> <objet> <chemin>"
+
+#: builtin/update-index.c:742
+msgid "add the specified entry to the index"
+msgstr "ajouter l'entrée spécifiée dans l'index"
+
+#: builtin/update-index.c:746
+msgid "(+/-)x"
+msgstr "(+/-)x"
+
+#: builtin/update-index.c:747
+msgid "override the executable bit of the listed files"
+msgstr "outrepasser le bit exécutable pour les fichiers listés"
+
+#: builtin/update-index.c:751
+msgid "mark files as \"not changing\""
+msgstr "marquer les fichiers comme \"non changeants\""
+
+#: builtin/update-index.c:754
+msgid "clear assumed-unchanged bit"
+msgstr ""
+
+#: builtin/update-index.c:757
+msgid "mark files as \"index-only\""
+msgstr "marquer les fichiers comme \"index seulement\""
+
+#: builtin/update-index.c:760
+msgid "clear skip-worktree bit"
+msgstr ""
+
+#: builtin/update-index.c:763
+msgid "add to index only; do not add content to object database"
+msgstr "ajouter seulement à l'index ; ne pas ajouter le contenu dans la base de données des objets"
+
+#: builtin/update-index.c:765
+msgid "remove named paths even if present in worktree"
+msgstr "supprimer les chemins nommés même s'ils sont présents dans la copie de travail"
+
+#: builtin/update-index.c:767
+msgid "with --stdin: input lines are terminated by null bytes"
+msgstr "avec --stdin : les lignes en entrée sont terminées par des octets nuls"
+
+#: builtin/update-index.c:769
+msgid "read list of paths to be updated from standard input"
+msgstr "lire la liste des chemins à mettre à jour depuis l'entrée standard"
+
+#: builtin/update-index.c:773
+msgid "add entries from standard input to the index"
+msgstr "ajouter les entrées depuis l'entrée standard à l'index"
+
+#: builtin/update-index.c:777
+msgid "repopulate stages #2 and #3 for the listed paths"
+msgstr "repeupler les étapes n°2 et n°3 pour les chemins listés"
+
+#: builtin/update-index.c:781
+msgid "only update entries that differ from HEAD"
+msgstr "mettre à jour seulement les entrées qui diffèrent de HEAD"
+
+#: builtin/update-index.c:785
+msgid "ignore files missing from worktree"
+msgstr "ignorer les fichiers manquants dans la copie de travail"
+
+#: builtin/update-index.c:788
+msgid "report actions to standard output"
+msgstr "afficher les actions sur la sortie standard"
+
+#: builtin/update-index.c:790
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr "(pour porcelaines) oublier les conflits sauvés et non résolus"
+
+#: builtin/update-index.c:794
+msgid "write index in this format"
+msgstr "écrire l'index dans ce format"
+
+#: builtin/update-ref.c:7
+msgid "git update-ref [options] -d <refname> [<oldval>]"
+msgstr "git update-ref [options] -d <nomréférence> [<anciennevaleur>]"
+
+#: builtin/update-ref.c:8
+msgid "git update-ref [options] <refname> <newval> [<oldval>]"
+msgstr "git update-ref [options] <nomréférence> <nouvellevaleur> [<anciennevaleur>]"
+
+#: builtin/update-ref.c:19
+msgid "delete the reference"
+msgstr "supprimer la référence"
+
+#: 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 "git update-server-info [--force]"
+
+#: builtin/update-server-info.c:14
+msgid "update the info files from scratch"
+msgstr "mettre à jour les fichiers d'information à partir de zéro"
+
+#: builtin/verify-pack.c:56
+msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
+msgstr "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
+
+#: builtin/verify-pack.c:66
+msgid "verbose"
+msgstr "verbeux"
+
+#: builtin/verify-pack.c:68
+msgid "show statistics only"
+msgstr "afficher seulement les statistiques"
+
+#: builtin/verify-tag.c:17
+msgid "git verify-tag [-v|--verbose] <tag>..."
+msgstr "git verify-tag [-v|--verbose] <étiquette>..."
+
+#: builtin/verify-tag.c:73
+msgid "print tag contents"
+msgstr "afficher le contenu de l'étiquette"
+
+#: builtin/write-tree.c:13
+msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+msgstr "git write-tree [--missing-ok] [--prefix=<préfixe>/]"
+
+#: builtin/write-tree.c:26
+msgid "<prefix>/"
+msgstr "<préfixe>/"
+
+#: builtin/write-tree.c:27
+msgid "write tree object for a subdirectory <prefix>"
+msgstr "écrire l'objet arbre pour un sous-répertoire <préfixe>"
+
+#: builtin/write-tree.c:30
+msgid "only useful for debugging"
+msgstr "seulement utile pour le débogage"
+
+#: git.c:16
+msgid ""
+"'git help -a' and 'git help -g' lists available subcommands and some\n"
+"concept guides. See 'git help <command>' or 'git help <concept>'\n"
+"to read about a specific subcommand or concept."
+msgstr ""
+"'git help -a' et 'git help -g' listent les sous-commandes disponibles et\n"
+"quelques concepts. Voir 'git help <command>' ou 'git help <concept>'\n"
+"pour en lire plus à propos d'une commande spécifique ou d'un concept."
+
+#: parse-options.h:156
+msgid "no-op (backward compatibility)"
+msgstr "sans action (rétrocompatibilité)"
+
+#: parse-options.h:232
+msgid "be more verbose"
+msgstr "être plus verbeux"
+
+#: parse-options.h:234
+msgid "be more quiet"
+msgstr "être plus silencieux"
+
+#: parse-options.h:240
+msgid "use <n> digits to display SHA-1s"
+msgstr "utiliser <n> chiffres pour afficher les SHA-1s"
+
+#: common-cmds.h:8
+msgid "Add file contents to the index"
+msgstr "Ajouter le contenu du fichier dans l'index"
+
+#: common-cmds.h:9
+msgid "Find by binary search the change that introduced a bug"
+msgstr "Rechercher de manière binaire le changement qui a introduit un bogue"
+
+#: common-cmds.h:10
+msgid "List, create, or delete branches"
+msgstr "Lister, créer ou supprimer des branches"
+
+#: common-cmds.h:11
+msgid "Checkout a branch or paths to the working tree"
+msgstr "Extraire une branche ou des chemins dans la copie de travail"
+
+#: common-cmds.h:12
+msgid "Clone a repository into a new directory"
+msgstr "Cloner un dépôt dans un nouveau répertoire"
+
+#: common-cmds.h:13
+msgid "Record changes to the repository"
+msgstr "Enregistrer les changements dans le dépôt"
+
+#: common-cmds.h:14
+msgid "Show changes between commits, commit and working tree, etc"
+msgstr "Afficher les changements entre les validations, entre validation et copie de travail, etc"
+
+#: common-cmds.h:15
+msgid "Download objects and refs from another repository"
+msgstr "Télécharger les objets et références depuis un autre dépôt"
+
+#: common-cmds.h:16
+msgid "Print lines matching a pattern"
+msgstr "Afficher les lignes correspondant à un motif"
+
+#: common-cmds.h:17
+msgid "Create an empty Git repository or reinitialize an existing one"
+msgstr "Créer un dépôt Git vide ou réinitialiser un existant"
+
+#: common-cmds.h:18
+msgid "Show commit logs"
+msgstr "Afficher l'historique des validations"
+
+#: common-cmds.h:19
+msgid "Join two or more development histories together"
+msgstr "Joindre deux ou plusieurs historiques de développement ensemble"
+
+#: common-cmds.h:20
+msgid "Move or rename a file, a directory, or a symlink"
+msgstr "Déplacer ou renommer un fichier, un répertoire, ou un lien symbolique"
+
+#: common-cmds.h:21
+msgid "Fetch from and merge with another repository or a local branch"
+msgstr "Rapatrier et fusionner avec un autre dépôt ou une branche locale"
+
+#: common-cmds.h:22
+msgid "Update remote refs along with associated objects"
+msgstr "Mettre à jour les références distantes ainsi que les objets associés"
+
+#: common-cmds.h:23
+msgid "Forward-port local commits to the updated upstream head"
+msgstr "Reporter en avant les validations locales dans la tête en amont mise à jour"
+
+#: common-cmds.h:24
+msgid "Reset current HEAD to the specified state"
+msgstr "Réinitialiser la HEAD courante à l'état spécifié"
+
+#: common-cmds.h:25
+msgid "Remove files from the working tree and from the index"
+msgstr "Supprimer les fichiers de la copie de travail et de l'index"
+
+#: common-cmds.h:26
+msgid "Show various types of objects"
+msgstr "Afficher différents types d'objects"
+
+#: common-cmds.h:27
+msgid "Show the working tree status"
+msgstr "Afficher le statut de la copie de travail"
+
+#: common-cmds.h:28
+msgid "Create, list, delete or verify a tag object signed with GPG"
+msgstr "Créer, lister, supprimer ou vérifier un objet d'étiquette signé avec GPG"
+
+#: git-am.sh:50
+msgid "You need to set your committer info first"
+msgstr "Vous devez d'abord définir vos informations de validateur"
+
+#: git-am.sh:95
+msgid ""
+"You seem to have moved HEAD since the last 'am' failure.\n"
+"Not rewinding to ORIG_HEAD"
+msgstr ""
+"Vous semblez avoir déplacé la HEAD depuis le dernier échec de 'am'.\n"
+"Pas de retour à ORIG_HEAD"
+
+#: git-am.sh:105
+#, sh-format
+msgid ""
+"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 ""
+"Lorsque vous aurez résolu ce problème, lancez \"$cmdline --resolved\".\n"
+"Si vous préférez sauter ce patch, lancez \"$cmdline --skip\" à la place.\n"
+"Pour restaurer la branche d'origine et stopper le patchage, lancez \"$cmdline --abort\"."
+
+#: git-am.sh:121
+msgid "Cannot fall back to three-way merge."
+msgstr "Impossible de retourner à une fusion 3-way."
+
+#: git-am.sh:137
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr "Le dépôt n'a pas les blobs nécessaires pour un retour à une fusion 3-way."
+
+#: git-am.sh:139
+msgid "Using index info to reconstruct a base tree..."
+msgstr "Utilisation de l'information de l'index pour reconstruire un arbre de base..."
+
+#: git-am.sh:154
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+"Avez-vous édité le patch à la main ?\n"
+"Il ne s'applique pas aux blobs enregistrés dans son index."
+
+#: git-am.sh:163
+msgid "Falling back to patching base and 3-way merge..."
+msgstr "Retour à un patch de la base et fusion 3-way..."
+
+#: git-am.sh:179
+msgid "Failed to merge in the changes."
+msgstr "Échec de fusion dans les changements."
+
+#: git-am.sh:274
+msgid "Only one StGIT patch series can be applied at once"
+msgstr "Seulement une série de patches StGIT peut être appliquée à la fois"
+
+#: git-am.sh:361
+#, sh-format
+msgid "Patch format $patch_format is not supported."
+msgstr "Le format de patch $patch_format n'est pas supporté."
+
+#: git-am.sh:363
+msgid "Patch format detection failed."
+msgstr "Échec de détection du format du patch."
+
+#: 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 ""
+"L'option -b/--binary ne fait plus rien depuis longtemps,\n"
+"et elle sera supprimée. Merci de ne plus l'utiliser."
+
+#: git-am.sh:477
+#, sh-format
+msgid "previous rebase directory $dotest still exists but mbox given."
+msgstr "le répertoire précédent de rebasage $dotest existe toujours mais mbox donnée."
+
+#: git-am.sh:482
+msgid "Please make up your mind. --skip or --abort?"
+msgstr "Décidez-vous. --skip ou --abort ?"
+
+#: git-am.sh:509
+msgid "Resolve operation not in progress, we are not resuming."
+msgstr "Pas de résolution de l'opération en cours, nous ne sommes pas dans une reprise."
+
+#: git-am.sh:575
+#, sh-format
+msgid "Dirty index: cannot apply patches (dirty: $files)"
+msgstr "Index sale : impossible d'appliquer des patches (sales : $files)"
+
+#: git-am.sh:679
+#, sh-format
+msgid ""
+"Patch is empty. Was it split wrong?\n"
+"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n"
+"To restore the original branch and stop patching run \"$cmdline --abort\"."
+msgstr ""
+"Le patch est vide. Était-il mal découpé ?\n"
+"Si vous préférez sauter ce patch, lancez plutôt \"$cmdline --skip\".\n"
+"Pour restaurer la branche d'origine et stopper le patchage, lancez \"$cmdline --abort\"."
+
+#: git-am.sh:706
+msgid "Patch does not have a valid e-mail address."
+msgstr "Le patch n'a pas d'adresse e-mail valide."
+
+#: git-am.sh:753
+msgid "cannot be interactive without stdin connected to a terminal."
+msgstr "impossible d'être interactif sans entrée standard connectée à un terminal."
+
+#: git-am.sh:757
+msgid "Commit Body is:"
+msgstr "Le corps de la validation est :"
+
+#. 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:764
+msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
+msgstr "Appliquer ? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
+
+#: git-am.sh:800
+#, sh-format
+msgid "Applying: $FIRSTLINE"
+msgstr "Application : $FIRSTLINE"
+
+#: 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:829
+msgid ""
+"You still have unmerged paths in your index\n"
+"did you forget to use 'git add'?"
+msgstr ""
+"Vous avez toujours des chemins non fusionnés dans votre index\n"
+"auriez-vous oublié de faire 'git add' ?"
+
+#: git-am.sh:845
+msgid "No changes -- Patch already applied."
+msgstr "Pas de changement -- Patch déjà appliqué."
+
+#: git-am.sh:855
+#, sh-format
+msgid "Patch failed at $msgnum $FIRSTLINE"
+msgstr "Le patch a échoué à $msgnum $FIRSTLINE"
+
+#: git-am.sh:858
+#, sh-format
+msgid ""
+"The copy of the patch that failed is found in:\n"
+" $dotest/patch"
+msgstr ""
+"La copie du patch qui a échoué se trouve dans :\n"
+" $dotest/patch"
+
+#: git-am.sh:876
+msgid "applying to an empty history"
+msgstr "application à un historique vide"
+
+#: git-bisect.sh:48
+msgid "You need to start by \"git bisect start\""
+msgstr "Vous devez démarrer avec \"git bisect start\""
+
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:54
+msgid "Do you want me to do it for you [Y/n]? "
+msgstr "Souhaitez-vous que je le fasse pour vous [Y/n] ? "
+
+#: git-bisect.sh:95
+#, sh-format
+msgid "unrecognised option: '$arg'"
+msgstr "option inconnue : '$arg'"
+
+#: git-bisect.sh:99
+#, sh-format
+msgid "'$arg' does not appear to be a valid revision"
+msgstr "'$arg' ne semble être une révision valide"
+
+#: git-bisect.sh:117
+msgid "Bad HEAD - I need a HEAD"
+msgstr "Mauvaise HEAD - j'ai besoin d'une HEAD"
+
+#: git-bisect.sh:130
+#, sh-format
+msgid ""
+"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr "L'extraction de '$start_head' a échoué. Essayez 'git bisect reset <branchevalide>'."
+
+#: git-bisect.sh:140
+msgid "won't bisect on seeked tree"
+msgstr ""
+
+#: git-bisect.sh:144
+msgid "Bad HEAD - strange symbolic ref"
+msgstr "Mauvaise HEAD - référence symbolique douteuse"
+
+#: git-bisect.sh:189
+#, sh-format
+msgid "Bad bisect_write argument: $state"
+msgstr "Mauvais argument pour bisect_write : $state"
+
+#: git-bisect.sh:218
+#, sh-format
+msgid "Bad rev input: $arg"
+msgstr "Mauvaise révision en entrée : $arg"
+
+#: git-bisect.sh:232
+msgid "Please call 'bisect_state' with at least one argument."
+msgstr "Merci d'appeler 'bisect_state' avec au moins un argument."
+
+#: git-bisect.sh:244
+#, sh-format
+msgid "Bad rev input: $rev"
+msgstr "Mauvaise révision en entrée : $rev"
+
+#: git-bisect.sh:250
+msgid "'git bisect bad' can take only one argument."
+msgstr "'git bisect bad' n'accepte qu'un seul argument."
+
+#. have bad but not good. we could bisect although
+#. this is less optimum.
+#: git-bisect.sh:273
+msgid "Warning: bisecting only with a bad commit."
+msgstr "Attention : bissection avec seulement une mauvaise validation."
+
+#. 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 "Êtes-vous sûr [Y/n] ? "
+
+#: git-bisect.sh:289
+msgid ""
+"You need to give me at least one good and one bad revisions.\n"
+"(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
+msgstr ""
+"Vous devez me donner au moins une bonne et une mauvaise révision.\n"
+"(Vous pouvez utiliser \"git bisect bad\" et \"git bisect good\" pour cela.)"
+
+#: git-bisect.sh:292
+msgid ""
+"You need to start by \"git bisect start\".\n"
+"You then need to give me at least one good and one bad revisions.\n"
+"(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
+msgstr ""
+"Vous devez démarrer avec \"git bisect start\".\n"
+"Puis vous devez me donner au moins une bonne et une mauvaise révision.\n"
+"(Vous pouvez utiliser \"git bisect bad\" et \"git bisect good\" pour cela.)"
+
+#: git-bisect.sh:363 git-bisect.sh:490
+msgid "We are not bisecting."
+msgstr "Pas de bissection en cours."
+
+#: git-bisect.sh:370
+#, sh-format
+msgid "'$invalid' is not a valid commit"
+msgstr "'$invalid' n'est pas une validation valide"
+
+#: git-bisect.sh:379
+#, sh-format
+msgid ""
+"Could not check out original HEAD '$branch'.\n"
+"Try 'git bisect reset <commit>'."
+msgstr ""
+"Échec d'extraction de la HEAD d'origine '$branch'.\n"
+"Essayez 'git bisect reset <commit>'."
+
+#: git-bisect.sh:406
+msgid "No logfile given"
+msgstr "Pas de fichier de log donné"
+
+#: git-bisect.sh:407
+#, sh-format
+msgid "cannot read $file for replaying"
+msgstr "impossible de lire $file pour rejouer"
+
+#: git-bisect.sh:424
+msgid "?? what are you talking about?"
+msgstr "?? de quoi parlez-vous ?"
+
+#: git-bisect.sh:436
+#, sh-format
+msgid "running $command"
+msgstr "lancement de $command"
+
+#: git-bisect.sh:443
+#, sh-format
+msgid ""
+"bisect run failed:\n"
+"exit code $res from '$command' is < 0 or >= 128"
+msgstr ""
+"la bissection a échoué :\n"
+"le code retour $res de '$command' est < 0 ou >= 128"
+
+#: git-bisect.sh:469
+msgid "bisect run cannot continue any more"
+msgstr "la bissection ne peut plus continuer"
+
+#: git-bisect.sh:475
+#, sh-format
+msgid ""
+"bisect run failed:\n"
+"'bisect_state $state' exited with error code $res"
+msgstr ""
+"la bissection a échoué :\n"
+"'bisect_state $state' a retourné le code erreur $res"
+
+#: git-bisect.sh:482
+msgid "bisect run success"
+msgstr "succès de la bissection"
+
+#: git-pull.sh:21
+msgid ""
+"Pull is not possible because you have unmerged files.\n"
+"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
+"as appropriate to mark resolution, or use 'git commit -a'."
+msgstr ""
+"Le pull n'est pas possible car vous avez des fichiers non fusionnés.\n"
+"Merci de corriger dans votre copie de travail, et utilisez alors 'git add/rm <file>'\n"
+"si nécessaire pour marquer comme résolu, ou utilisez 'git commit -a'."
+
+#: git-pull.sh:25
+msgid "Pull is not possible because you have unmerged files."
+msgstr "Le pull n'est pas possible car vous avez des fichiers non fusionnés."
+
+#: git-pull.sh:203
+msgid "updating an unborn branch with changes added to the index"
+msgstr "mise à jour d'une branche non encore créée avec les changements ajoutés dans l'index"
+
+#. The fetch involved updating the current branch.
+#. The working tree and the index file is still based on the
+#. $orig_head commit, but we are merging into $curr_head.
+#. First update the working tree to match $curr_head.
+#: git-pull.sh:235
+#, sh-format
+msgid ""
+"Warning: fetch updated the current branch head.\n"
+"Warning: fast-forwarding your working tree from\n"
+"Warning: commit $orig_head."
+msgstr ""
+"Attention : fetch a mis à jour la tête de la branche courante.\n"
+"Attention : mise à jour en avance rapide de votre copie de travail\n"
+"Attention : depuis la validation $orig_head."
+
+#: git-pull.sh:260
+msgid "Cannot merge multiple branches into empty head"
+msgstr "Impossible de fusionner de multiples branches sur une tête vide"
+
+#: git-pull.sh:264
+msgid "Cannot rebase onto multiple branches"
+msgstr "Impossible de rebaser sur de multiples branches"
+
+#: git-rebase.sh:53
+msgid ""
+"When you have resolved this problem, run \"git rebase --continue\".\n"
+"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
+"To check out the original branch and stop rebasing, run \"git rebase --abort"
+"\"."
+msgstr ""
+"Lorsque vous aurez résolu ce problème, lancez \"git rebase --continue\".\n"
+"Si vous préférez sauter ce patch, lancez \"git rebase --skip\" à la place.\n"
+"Pour extraire la branche d'origine et stopper le rebasage, lancez \"git rebase --abort\"."
+
+#: git-rebase.sh:160
+msgid "The pre-rebase hook refused to rebase."
+msgstr "Le hook pre-rebase a refusé de rebaser."
+
+#: git-rebase.sh:165
+msgid "It looks like git-am is in progress. Cannot rebase."
+msgstr "Il semble que git-am soit en cours. Impossible de rebaser."
+
+#: git-rebase.sh:296
+msgid "The --exec option must be used with the --interactive option"
+msgstr "L'option --exec doit être utilisée avec l'option --interactive"
+
+#: git-rebase.sh:301
+msgid "No rebase in progress?"
+msgstr "Pas de rebasage en cours ?"
+
+#: git-rebase.sh:312
+msgid "The --edit-todo action can only be used during interactive rebase."
+msgstr "L'action --edit-todo peut seulement être utilisée lors d'un rebasage interactif."
+
+#: git-rebase.sh:319
+msgid "Cannot read HEAD"
+msgstr "Impossible de lire HEAD"
+
+#: git-rebase.sh:322
+msgid ""
+"You must edit all merge conflicts and then\n"
+"mark them as resolved using git add"
+msgstr ""
+"Vous devez éditer tous les conflits de fusion et\n"
+"les marquer comme résolus avec git add"
+
+#: git-rebase.sh:340
+#, sh-format
+msgid "Could not move back to $head_name"
+msgstr "Impossible de revenir à $head_name"
+
+#: git-rebase.sh:359
+#, sh-format
+msgid ""
+"It seems that there is already a $state_dir_base directory, and\n"
+"I wonder if you are in the middle of another rebase. If that is the\n"
+"case, please try\n"
+"\t$cmd_live_rebase\n"
+"If that is not the case, please\n"
+"\t$cmd_clear_stale_rebase\n"
+"and run me again. I am stopping in case you still have something\n"
+"valuable there."
+msgstr ""
+"Il semble qu'il y ait déjà un répertoire $state_dir_base, et je me demande\n"
+"si vous n'êtes pas au milieu d'un autre rebasage. Si c'est le cas,\n"
+"merci d'essayer\n"
+"\t$cmd_live_rebase\n"
+"Si ça n'est pas le cas, merci de\n"
+"\t$cmd_clear_stale_rebase\n"
+"et relancer à nouveau. Je m'arrête au cas où vous auriez quelque chose\n"
+"d'important ici."
+
+#: git-rebase.sh:404
+#, sh-format
+msgid "invalid upstream $upstream_name"
+msgstr "invalide $upstream_name en amont"
+
+#: git-rebase.sh:428
+#, sh-format
+msgid "$onto_name: there are more than one merge bases"
+msgstr "$onto_name : il y a plus d'une base de fusion"
+
+#: git-rebase.sh:431 git-rebase.sh:435
+#, sh-format
+msgid "$onto_name: there is no merge base"
+msgstr "$onto_name : il n'y a pas de base de fusion"
+
+#: git-rebase.sh:440
+#, sh-format
+msgid "Does not point to a valid commit: $onto_name"
+msgstr "Ne pointe pas sur une validation valide : $onto_name"
+
+#: git-rebase.sh:463
+#, sh-format
+msgid "fatal: no such branch: $branch_name"
+msgstr "fatal : pas de branche : $branch_name"
+
+#: git-rebase.sh:483
+msgid "Please commit or stash them."
+msgstr "Merci de les valider ou de les remiser."
+
+#: git-rebase.sh:501
+#, sh-format
+msgid "Current branch $branch_name is up to date."
+msgstr "La branche courante $branch_name est à jour."
+
+#: git-rebase.sh:504
+#, sh-format
+msgid "Current branch $branch_name is up to date, rebase forced."
+msgstr "La branche courante $branch_name est à jour, rebasage forcé."
+
+#: git-rebase.sh:515
+#, sh-format
+msgid "Changes from $mb to $onto:"
+msgstr "Changements de $mb sur $onto :"
+
+#. Detach HEAD and reset the tree
+#: git-rebase.sh:524
+msgid "First, rewinding head to replay your work on top of it..."
+msgstr "Premièrement, retour de head pour rejouer votre travail par-dessus..."
+
+#: git-rebase.sh:532
+#, sh-format
+msgid "Fast-forwarded $branch_name to $onto_name."
+msgstr "$branch_name mise à jour en avance rapide sur $onto_name."
+
+#: git-stash.sh:51
+msgid "git stash clear with parameters is unimplemented"
+msgstr "git stash clear avec des paramètres n'est pas implémenté"
+
+#: git-stash.sh:74
+msgid "You do not have the initial commit yet"
+msgstr "Vous n'avez pas encore la validation initiale"
+
+#: git-stash.sh:89
+msgid "Cannot save the current index state"
+msgstr "Impossible de sauver l'état courant de l'index"
+
+#: git-stash.sh:123 git-stash.sh:136
+msgid "Cannot save the current worktree state"
+msgstr "Impossible de sauver l'état courant de la copie de travail"
+
+#: git-stash.sh:140
+msgid "No changes selected"
+msgstr "Aucun changement sélectionné"
+
+#: git-stash.sh:143
+msgid "Cannot remove temporary index (can't happen)"
+msgstr "Impossible de supprimer l'index temporaire (ne peut pas se produire)"
+
+#: git-stash.sh:156
+msgid "Cannot record working tree state"
+msgstr "Impossible d'enregistrer l'état de la copie de travail"
+
+#. TRANSLATORS: $option is an invalid option, like
+#. `--blah-blah'. The 7 spaces at the beginning of the
+#. second line correspond to "error: ". So you should line
+#. up the second line with however many characters the
+#. translation of "error: " takes in your language. E.g. in
+#. English this is:
+#.
+#. $ git stash save --blah-blah 2>&1 | head -n 2
+#. error: unknown option for 'stash save': --blah-blah
+#. To provide a message, use git stash save -- '--blah-blah'
+#: git-stash.sh:202
+#, sh-format
+msgid ""
+"error: unknown option for 'stash save': $option\n"
+" To provide a message, use git stash save -- '$option'"
+msgstr ""
+"erreur: option inconnue pour 'stash save': $option\n"
+" Pour fournir un message, utilisez git stash save -- '$option'"
+
+#: git-stash.sh:223
+msgid "No local changes to save"
+msgstr "Pas de changements en local à sauver"
+
+#: git-stash.sh:227
+msgid "Cannot initialize stash"
+msgstr "Impossible d'initialiser le remisage"
+
+#: git-stash.sh:235
+msgid "Cannot save the current status"
+msgstr "Impossible de sauver le statut courant"
+
+#: git-stash.sh:253
+msgid "Cannot remove worktree changes"
+msgstr "Impossible de supprimer les changements de la copie de travail"
+
+#: git-stash.sh:352
+msgid "No stash found."
+msgstr "Pas de remisage trouvé."
+
+#: git-stash.sh:359
+#, sh-format
+msgid "Too many revisions specified: $REV"
+msgstr "Trop de révisions spécifiées : $REV"
+
+#: git-stash.sh:365
+#, sh-format
+msgid "$reference is not valid reference"
+msgstr "$reference n'est pas une référence valide"
+
+#: git-stash.sh:393
+#, sh-format
+msgid "'$args' is not a stash-like commit"
+msgstr "'$args' n'est pas une validation de type remisage"
+
+#: git-stash.sh:404
+#, sh-format
+msgid "'$args' is not a stash reference"
+msgstr "'$args' n'est pas une référence de remisage"
+
+#: git-stash.sh:412
+msgid "unable to refresh index"
+msgstr "impossible de rafraîchir l'index"
+
+#: git-stash.sh:416
+msgid "Cannot apply a stash in the middle of a merge"
+msgstr "Impossible d'appliquer un remisage au milieu d'une fusion"
+
+#: git-stash.sh:424
+msgid "Conflicts in index. Try without --index."
+msgstr "Conflits dans l'index. Essayez sans --index."
+
+#: git-stash.sh:426
+msgid "Could not save index tree"
+msgstr "Impossible de sauver l'arbre d'index"
+
+#: git-stash.sh:460
+msgid "Cannot unstage modified files"
+msgstr "Impossible de désindexer les fichiers modifiés"
+
+#: git-stash.sh:475
+msgid "Index was not unstashed."
+msgstr ""
+
+#: git-stash.sh:492
+#, sh-format
+msgid "Dropped ${REV} ($s)"
+msgstr "${REV} supprimé ($s)"
+
+#: git-stash.sh:493
+#, sh-format
+msgid "${REV}: Could not drop stash entry"
+msgstr "${REV}: Impossible de supprimer l'entrée de stash"
+
+#: git-stash.sh:500
+msgid "No branch name specified"
+msgstr "Aucune branche spécifiée"
+
+#: git-stash.sh:571
+msgid "(To restore them type \"git stash apply\")"
+msgstr "(Pour les restaurer tapez \"git stash apply\")"
+
+#: git-submodule.sh:91
+#, sh-format
+msgid "cannot strip one component off url '$remoteurl'"
+msgstr "impossible de supprimer un composant de l'URL '$remoteurl'"
+
+#: git-submodule.sh:196
+#, sh-format
+msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
+msgstr "Pas de mappage du sous-module trouvé dans .gitmodules pour le chemin '$sm_path'"
+
+#: git-submodule.sh:239
+#, sh-format
+msgid "Clone of '$url' into submodule path '$sm_path' failed"
+msgstr "Le clonage de '$url' dans le chemin de sous-module '$sm_path' a échoué"
+
+#: git-submodule.sh:251
+#, sh-format
+msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
+msgstr "Le répertoire Git '$a' fait partie du chemin de sous-module '$b' ou vice-versa"
+
+#: git-submodule.sh:349
+#, sh-format
+msgid "repo URL: '$repo' must be absolute or begin with ./|../"
+msgstr "L'URL de dépôt '$repo' doit être absolu ou commencer par ./|../"
+
+#: git-submodule.sh:366
+#, sh-format
+msgid "'$sm_path' already exists in the index"
+msgstr "'$sm_path' existe déjà dans l'index"
+
+#: git-submodule.sh:370
+#, 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 ""
+"Le chemin suivant est ignoré par un de vos fichiers .gitignore :\n"
+"$sm_path\n"
+"Utilisez -f si vous voulez vraiment l'ajouter."
+
+#: git-submodule.sh:388
+#, sh-format
+msgid "Adding existing repo at '$sm_path' to the index"
+msgstr "Ajout du dépôt existant à '$sm_path' dans l'index"
+
+#: git-submodule.sh:390
+#, sh-format
+msgid "'$sm_path' already exists and is not a valid git repo"
+msgstr "'$sm_path' existe déjà et n'est pas un dépôt git valide"
+
+#: git-submodule.sh:398
+#, sh-format
+msgid "A git directory for '$sm_name' is found locally with remote(s):"
+msgstr "Un répertoire git pour '$sm_name' est trouvé en local avec le(s) serveur(s) distant(s) :"
+
+#: git-submodule.sh:400
+#, sh-format
+msgid ""
+"If you want to reuse this local git directory instead of cloning again from"
+msgstr "Si vous voulez réutiliser ce répertoire git local au lieu de cloner à nouveau depuis"
+
+#: git-submodule.sh:402
+#, sh-format
+msgid ""
+"use the '--force' option. If the local git directory is not the correct repo"
+msgstr "utilisez l'option '--force'. Si le répertoire local git n'est pas le dépôt correct"
+
+#: git-submodule.sh:403
+#, sh-format
+msgid ""
+"or you are unsure what this means choose another name with the '--name' "
+"option."
+msgstr "ou vous ne savez pas ce que cela signifie de choisir un autre nom avec l'option '--name'."
+
+#: git-submodule.sh:405
+#, sh-format
+msgid "Reactivating local git directory for submodule '$sm_name'."
+msgstr "Réactivation du répertoire git local pour le sous-module '$sm_name'."
+
+#: git-submodule.sh:417
+#, sh-format
+msgid "Unable to checkout submodule '$sm_path'"
+msgstr "Impossible d'extraire le sous-module '$sm_path'"
+
+#: git-submodule.sh:422
+#, sh-format
+msgid "Failed to add submodule '$sm_path'"
+msgstr "Échec d'ajout du sous-module '$sm_path'"
+
+#: git-submodule.sh:431
+#, sh-format
+msgid "Failed to register submodule '$sm_path'"
+msgstr "Échec d'enregistrement du sous-module '$sm_path'"
+
+#: git-submodule.sh:474
+#, sh-format
+msgid "Entering '$prefix$sm_path'"
+msgstr "Entrée dans '$prefix$sm_path'"
+
+#: git-submodule.sh:488
+#, sh-format
+msgid "Stopping at '$sm_path'; script returned non-zero status."
+msgstr "Arrêt sur '$sm_path' ; le script a retourné un statut non nul."
+
+#: git-submodule.sh:532
+#, sh-format
+msgid "No url found for submodule path '$sm_path' in .gitmodules"
+msgstr "URL non trouvé pour le chemin de sous-module '$sm_path' dans .gitmodules"
+
+#: git-submodule.sh:541
+#, sh-format
+msgid "Failed to register url for submodule path '$sm_path'"
+msgstr "Échec d'enregistrement de l'URL pour le chemin de sous-module '$sm_path'"
+
+#: git-submodule.sh:543
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$sm_path'"
+msgstr "Sous-module '$name' ($url) enregistré pour le chemin '$sm_path'"
+
+#: git-submodule.sh:551
+#, sh-format
+msgid "Failed to register update mode for submodule path '$sm_path'"
+msgstr "Échec d'enregistrement du mode de mise à jour pour le chemin de sous-module '$sm_path'"
+
+#: git-submodule.sh:588
+#, sh-format
+msgid "Use '.' if you really want to deinitialize all submodules"
+msgstr "Utilisez '.' si vous voulez vraiment réinitialiser tous les sous-modules"
+
+#: git-submodule.sh:603
+#, sh-format
+msgid "Submodule work tree '$sm_path' contains a .git directory"
+msgstr "La copie de travail du sous-module '$sm_path' contient un répertoire .git"
+
+#: git-submodule.sh:604
+#, sh-format
+msgid ""
+"(use 'rm -rf' if you really want to remove it including all of its history)"
+msgstr "(utilisez 'rm -rf' si vous voulez vraiment le supprimer en incluant tout son historique)"
+
+#: git-submodule.sh:610
+#, sh-format
+msgid ""
+"Submodule work tree '$sm_path' contains local modifications; use '-f' to "
+"discard them"
+msgstr "La copie de travail du sous-module '$sm_path' contient des modifications locales; utilisez '-f' pour les annuler"
+
+#: git-submodule.sh:613
+#, sh-format
+msgid "Cleared directory '$sm_path'"
+msgstr "Répertoire '$sm_path' nettoyé"
+
+#: git-submodule.sh:614
+#, sh-format
+msgid "Could not remove submodule work tree '$sm_path'"
+msgstr "Impossible de supprimer la copie de travail du sous-module '$sm_path'"
+
+#: git-submodule.sh:617
+#, sh-format
+msgid "Could not create empty submodule directory '$sm_path'"
+msgstr "Impossible de créer le répertoire vide du sous-module '$sm_path'"
+
+#: git-submodule.sh:626
+#, sh-format
+msgid "Submodule '$name' ($url) unregistered for path '$sm_path'"
+msgstr "Le sous-module '$name' ($url) n'est pas enregistré pour le chemin '$sm_path'"
+
+#: git-submodule.sh:731
+#, sh-format
+msgid ""
+"Submodule path '$prefix$sm_path' not initialized\n"
+"Maybe you want to use 'update --init'?"
+msgstr ""
+"Chemin de sous-module '$prefix$sm_path' non initialisé\n"
+"Peut-être souhaitez-vous utiliser 'update --init' ?"
+
+#: git-submodule.sh:744
+#, sh-format
+msgid "Unable to find current revision in submodule path '$prefix$sm_path'"
+msgstr "Impossible de trouver la révision courante dans le chemin de sous-module '$prefix$sm_path'"
+
+#: git-submodule.sh:753
+#, sh-format
+msgid "Unable to fetch in submodule path '$sm_path'"
+msgstr "Impossible de rapatrier dans le chemin de sous-module '$sm_path'"
+
+#: git-submodule.sh:777
+#, sh-format
+msgid "Unable to fetch in submodule path '$prefix$sm_path'"
+msgstr "Impossible de rapatrier dans le chemin de sous-module '$prefix$sm_path'"
+
+#: git-submodule.sh:791
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$prefix$sm_path'"
+msgstr "Impossible de rebaser '$sha1' dans le chemin de sous-module '$prefix$sm_path'"
+
+#: git-submodule.sh:792
+#, sh-format
+msgid "Submodule path '$prefix$sm_path': rebased into '$sha1'"
+msgstr "Chemin de sous-module '$prefix$sm_path' : rebasé dans '$sha1'"
+
+#: git-submodule.sh:797
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$prefix$sm_path'"
+msgstr "Impossible de fusionner '$sha1' dans le chemin de sous-module '$prefix$sm_path'"
+
+#: git-submodule.sh:798
+#, sh-format
+msgid "Submodule path '$prefix$sm_path': merged in '$sha1'"
+msgstr "Chemin de sous-module '$prefix$sm_path' : fusionné dans '$sha1'"
+
+#: git-submodule.sh:803
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$prefix$sm_path'"
+msgstr "Impossible d'extraire '$sha1' dans le chemin de sous-module '$prefix$sm_path'"
+
+#: git-submodule.sh:804
+#, sh-format
+msgid "Submodule path '$prefix$sm_path': checked out '$sha1'"
+msgstr "Chemin de sous-module '$prefix$sm_path' : '$sha1' extrait"
+
+#: git-submodule.sh:831
+#, sh-format
+msgid "Failed to recurse into submodule path '$prefix$sm_path'"
+msgstr "Échec de parcours dans le chemin du sous-module '$prefix$sm_path'"
+
+#: git-submodule.sh:939
+msgid "The --cached option cannot be used with the --files option"
+msgstr "L'option --cached ne peut pas être utilisée avec l'option --files"
+
+#. unexpected type
+#: git-submodule.sh:979
+#, sh-format
+msgid "unexpected mode $mod_dst"
+msgstr "mode $mod_dst inattendu"
+
+#: git-submodule.sh:997
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_src"
+msgstr " Attention : $name ne contient pas la validation $sha1_src"
+
+#: git-submodule.sh:1000
+#, sh-format
+msgid " Warn: $name doesn't contain commit $sha1_dst"
+msgstr " Attention : $name ne contient pas la validation $sha1_dst"
+
+#: git-submodule.sh:1003
+#, sh-format
+msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgstr " Attention : $name ne contient pas les validations $sha1_src et $sha1_dst"
+
+#: git-submodule.sh:1028
+msgid "blob"
+msgstr "blob"
+
+#: git-submodule.sh:1066
+msgid "Submodules changed but not updated:"
+msgstr "Sous-modules modifiés mais non mis à jour :"
+
+#: git-submodule.sh:1068
+msgid "Submodule changes to be committed:"
+msgstr "Changements du sous-module à valider :"
+
+#: git-submodule.sh:1153
+#, sh-format
+msgid "Failed to recurse into submodule path '$sm_path'"
+msgstr "Échec de parcours dans le chemin du sous-module '$sm_path'"
+
+#: git-submodule.sh:1216
+#, sh-format
+msgid "Synchronizing submodule url for '$prefix$sm_path'"
+msgstr "Synchronisation de l'URL sous-module pour '$prefix$sm_path'"
diff --git a/po/git.pot b/po/git.pot
index a826dcb..cf1e446 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: 2013-03-05 12:36+0800\n"
+"POT-Creation-Date: 2013-08-06 14:10+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"
@@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
-#: advice.c:49
+#: advice.c:57
#, c-format
msgid "hint: %.*s\n"
msgstr ""
@@ -27,7 +27,7 @@ msgstr ""
#. * Message used both when 'git commit' fails and when
#. * other commands doing a merge do.
#.
-#: advice.c:79
+#: advice.c:87
msgid ""
"Fix them up in the work tree,\n"
"and then use 'git add/rm <file>' as\n"
@@ -60,7 +60,7 @@ msgstr ""
msgid "archive format"
msgstr ""
-#: archive.c:324 builtin/log.c:1115
+#: archive.c:324 builtin/log.c:1173
msgid "prefix"
msgstr ""
@@ -68,15 +68,15 @@ msgstr ""
msgid "prepend prefix to each pathname in the archive"
msgstr ""
-#: archive.c:326 builtin/archive.c:91 builtin/blame.c:2366
-#: builtin/blame.c:2367 builtin/config.c:55 builtin/fast-export.c:653
-#: builtin/fast-export.c:655 builtin/grep.c:715 builtin/hash-object.c:77
-#: builtin/ls-files.c:497 builtin/ls-files.c:500 builtin/notes.c:536
-#: builtin/notes.c:693 builtin/read-tree.c:107 parse-options.h:149
+#: archive.c:326 builtin/archive.c:88 builtin/blame.c:2292
+#: builtin/blame.c:2293 builtin/config.c:56 builtin/fast-export.c:673
+#: builtin/fast-export.c:675 builtin/grep.c:714 builtin/hash-object.c:77
+#: builtin/ls-files.c:496 builtin/ls-files.c:499 builtin/notes.c:408
+#: builtin/notes.c:565 builtin/read-tree.c:108 parse-options.h:152
msgid "file"
msgstr ""
-#: archive.c:327 builtin/archive.c:92
+#: archive.c:327 builtin/archive.c:89
msgid "write the archive to this file"
msgstr ""
@@ -104,19 +104,19 @@ msgstr ""
msgid "list supported archive formats"
msgstr ""
-#: archive.c:345 builtin/archive.c:93 builtin/clone.c:85
+#: archive.c:345 builtin/archive.c:90 builtin/clone.c:85
msgid "repo"
msgstr ""
-#: archive.c:346 builtin/archive.c:94
+#: archive.c:346 builtin/archive.c:91
msgid "retrieve the archive from remote repository <repo>"
msgstr ""
-#: archive.c:347 builtin/archive.c:95 builtin/notes.c:615
+#: archive.c:347 builtin/archive.c:92 builtin/notes.c:487
msgid "command"
msgstr ""
-#: archive.c:348 builtin/archive.c:96
+#: archive.c:348 builtin/archive.c:93
msgid "path to the remote git-upload-archive command"
msgstr ""
@@ -126,6 +126,120 @@ msgid ""
"Use '\\!' for literal leading exclamation."
msgstr ""
+#: branch.c:60
+#, c-format
+msgid "Not setting branch %s as its own upstream."
+msgstr ""
+
+#: branch.c:82
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s by rebasing."
+msgstr ""
+
+#: branch.c:83
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s."
+msgstr ""
+
+#: branch.c:87
+#, c-format
+msgid "Branch %s set up to track local branch %s by rebasing."
+msgstr ""
+
+#: branch.c:88
+#, c-format
+msgid "Branch %s set up to track local branch %s."
+msgstr ""
+
+#: branch.c:92
+#, c-format
+msgid "Branch %s set up to track remote ref %s by rebasing."
+msgstr ""
+
+#: branch.c:93
+#, c-format
+msgid "Branch %s set up to track remote ref %s."
+msgstr ""
+
+#: branch.c:97
+#, c-format
+msgid "Branch %s set up to track local ref %s by rebasing."
+msgstr ""
+
+#: branch.c:98
+#, c-format
+msgid "Branch %s set up to track local ref %s."
+msgstr ""
+
+#: branch.c:118
+#, c-format
+msgid "Tracking not set up: name too long: %s"
+msgstr ""
+
+#: branch.c:137
+#, c-format
+msgid "Not tracking: ambiguous information for ref %s"
+msgstr ""
+
+#: branch.c:182
+#, c-format
+msgid "'%s' is not a valid branch name."
+msgstr ""
+
+#: branch.c:187
+#, c-format
+msgid "A branch named '%s' already exists."
+msgstr ""
+
+#: branch.c:195
+msgid "Cannot force update the current branch."
+msgstr ""
+
+#: branch.c:216
+#, c-format
+msgid "Cannot setup tracking information; starting point '%s' is not a branch."
+msgstr ""
+
+#: branch.c:218
+#, c-format
+msgid "the requested upstream branch '%s' does not exist"
+msgstr ""
+
+#: branch.c:220
+msgid ""
+"\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push."
+msgstr ""
+
+#: branch.c:265
+#, c-format
+msgid "Not a valid object name: '%s'."
+msgstr ""
+
+#: branch.c:285
+#, c-format
+msgid "Ambiguous object name: '%s'."
+msgstr ""
+
+#: branch.c:290
+#, c-format
+msgid "Not a valid branch point: '%s'."
+msgstr ""
+
+#: branch.c:296
+msgid "Failed to lock ref for update"
+msgstr ""
+
+#: branch.c:314
+msgid "Failed to write ref"
+msgstr ""
+
#: bundle.c:36
#, c-format
msgid "'%s' does not look like a v2 bundle file"
@@ -136,7 +250,7 @@ msgstr ""
msgid "unrecognized header: %s%s (%d)"
msgstr ""
-#: bundle.c:89 builtin/commit.c:674
+#: bundle.c:89 builtin/commit.c:697
#, c-format
msgid "could not open '%s'"
msgstr ""
@@ -145,27 +259,27 @@ msgstr ""
msgid "Repository lacks these prerequisite commits:"
msgstr ""
-#: bundle.c:164 sequencer.c:566 sequencer.c:998 builtin/log.c:299
-#: builtin/log.c:751 builtin/log.c:1358 builtin/log.c:1574 builtin/merge.c:347
-#: builtin/shortlog.c:157
+#: bundle.c:164 sequencer.c:661 sequencer.c:1111 builtin/log.c:331
+#: builtin/log.c:801 builtin/log.c:1399 builtin/log.c:1625 builtin/merge.c:364
+#: builtin/shortlog.c:156
msgid "revision walk setup failed"
msgstr ""
#: bundle.c:186
#, c-format
-msgid "The bundle contains %d ref"
-msgid_plural "The bundle contains %d refs"
+msgid "The bundle contains this ref:"
+msgid_plural "The bundle contains these %d refs:"
msgstr[0] ""
msgstr[1] ""
-#: bundle.c:192
+#: bundle.c:193
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"
+msgid "The bundle requires this ref:"
+msgid_plural "The bundle requires these %d refs:"
msgstr[0] ""
msgstr[1] ""
@@ -173,7 +287,7 @@ msgstr[1] ""
msgid "rev-list died"
msgstr ""
-#: bundle.c:300 builtin/log.c:1254 builtin/shortlog.c:260
+#: bundle.c:300 builtin/log.c:1310 builtin/shortlog.c:259
#, c-format
msgid "unrecognized argument: %s"
msgstr ""
@@ -204,12 +318,12 @@ msgstr ""
msgid "index-pack died"
msgstr ""
-#: commit.c:50
+#: commit.c:53
#, c-format
msgid "could not parse %s"
msgstr ""
-#: commit.c:52
+#: commit.c:55
#, c-format
msgid "%s %s is not a commit!"
msgstr ""
@@ -218,16 +332,16 @@ msgstr ""
msgid "memory exhausted"
msgstr ""
-#: connected.c:39
+#: connected.c:60
msgid "Could not run 'git rev-list'"
msgstr ""
-#: connected.c:48
+#: connected.c:80
#, c-format
msgid "failed write to rev-list: %s"
msgstr ""
-#: connected.c:56
+#: connected.c:88
#, c-format
msgid "failed to close rev-list's stdin: %s"
msgstr ""
@@ -321,19 +435,19 @@ msgid ""
"%s"
msgstr ""
-#: diff.c:3468
+#: diff.c:3487
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
"%s"
msgstr ""
-#: diff.c:3482
+#: diff.c:3501
#, c-format
msgid "Failed to parse --submodule option parameter: '%s'"
msgstr ""
-#: gpg-interface.c:59 gpg-interface.c:127
+#: gpg-interface.c:59 gpg-interface.c:131
msgid "could not run gpg."
msgstr ""
@@ -345,73 +459,73 @@ msgstr ""
msgid "gpg failed to sign the data"
msgstr ""
-#: gpg-interface.c:112
+#: gpg-interface.c:115
#, c-format
msgid "could not create temporary file '%s': %s"
msgstr ""
-#: gpg-interface.c:115
+#: gpg-interface.c:118
#, c-format
msgid "failed writing detached signature to '%s': %s"
msgstr ""
-#: grep.c:1622
+#: grep.c:1623
#, c-format
msgid "'%s': unable to read %s"
msgstr ""
-#: grep.c:1639
+#: grep.c:1640
#, c-format
msgid "'%s': %s"
msgstr ""
-#: grep.c:1650
+#: grep.c:1651
#, c-format
msgid "'%s': short read %s"
msgstr ""
-#: help.c:212
+#: help.c:210
#, c-format
msgid "available git commands in '%s'"
msgstr ""
-#: help.c:219
+#: help.c:217
msgid "git commands available from elsewhere on your $PATH"
msgstr ""
-#: help.c:235
+#: help.c:233
msgid "The most commonly used git commands are:"
msgstr ""
-#: help.c:292
+#: help.c:290
#, 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:349
+#: help.c:347
msgid "Uh oh. Your system reports no Git commands at all."
msgstr ""
-#: help.c:371
+#: help.c:369
#, 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:376
+#: help.c:374
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr ""
-#: help.c:383
+#: help.c:381
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
msgstr ""
-#: help.c:387
+#: help.c:385 help.c:444
msgid ""
"\n"
"Did you mean this?"
@@ -421,12 +535,17 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
+#: help.c:440
+#, c-format
+msgid "%s: %s - %s"
+msgstr ""
+
#: merge.c:56
msgid "failed to read the cache"
msgstr ""
-#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534
-#: builtin/clone.c:586
+#: merge.c:110 builtin/checkout.c:365 builtin/checkout.c:566
+#: builtin/clone.c:656
msgid "unable to write new index file"
msgstr ""
@@ -440,242 +559,268 @@ msgstr ""
msgid "addinfo_cache failed for path '%s'"
msgstr ""
-#: merge-recursive.c:268
+#: merge-recursive.c:269
msgid "error building trees"
msgstr ""
-#: merge-recursive.c:672
+#: merge-recursive.c:673
#, c-format
msgid "failed to create path '%s'%s"
msgstr ""
-#: merge-recursive.c:683
+#: merge-recursive.c:684
#, 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
+#: merge-recursive.c:698 merge-recursive.c:719
msgid ": perhaps a D/F conflict?"
msgstr ""
-#: merge-recursive.c:708
+#: merge-recursive.c:709
#, c-format
msgid "refusing to lose untracked file at '%s'"
msgstr ""
-#: merge-recursive.c:748
+#: merge-recursive.c:749
#, c-format
msgid "cannot read object %s '%s'"
msgstr ""
-#: merge-recursive.c:750
+#: merge-recursive.c:751
#, c-format
msgid "blob expected for %s '%s'"
msgstr ""
-#: merge-recursive.c:773 builtin/clone.c:302
+#: merge-recursive.c:774 builtin/clone.c:312
#, c-format
msgid "failed to open '%s'"
msgstr ""
-#: merge-recursive.c:781
+#: merge-recursive.c:782
#, c-format
msgid "failed to symlink '%s'"
msgstr ""
-#: merge-recursive.c:784
+#: merge-recursive.c:785
#, c-format
msgid "do not know what to do with %06o %s '%s'"
msgstr ""
-#: merge-recursive.c:922
+#: merge-recursive.c:923
msgid "Failed to execute internal merge"
msgstr ""
-#: merge-recursive.c:926
+#: merge-recursive.c:927
#, c-format
msgid "Unable to add %s to database"
msgstr ""
-#: merge-recursive.c:942
+#: merge-recursive.c:943
msgid "unsupported object type in the tree"
msgstr ""
-#: merge-recursive.c:1021 merge-recursive.c:1035
+#: merge-recursive.c:1022 merge-recursive.c:1036
#, 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
+#: merge-recursive.c:1028 merge-recursive.c:1041
#, 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
+#: merge-recursive.c:1082
msgid "rename"
msgstr ""
-#: merge-recursive.c:1081
+#: merge-recursive.c:1082
msgid "renamed"
msgstr ""
-#: merge-recursive.c:1137
+#: merge-recursive.c:1138
#, c-format
msgid "%s is a directory in %s adding as %s instead"
msgstr ""
-#: merge-recursive.c:1159
+#: merge-recursive.c:1160
#, c-format
msgid ""
"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
"\"->\"%s\" in \"%s\"%s"
msgstr ""
-#: merge-recursive.c:1164
+#: merge-recursive.c:1165
msgid " (left unresolved)"
msgstr ""
-#: merge-recursive.c:1218
+#: merge-recursive.c:1219
#, c-format
msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
msgstr ""
-#: merge-recursive.c:1248
+#: merge-recursive.c:1249
#, c-format
msgid "Renaming %s to %s and %s to %s instead"
msgstr ""
-#: merge-recursive.c:1447
+#: merge-recursive.c:1448
#, c-format
msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
msgstr ""
-#: merge-recursive.c:1457
+#: merge-recursive.c:1458
#, c-format
msgid "Adding merged %s"
msgstr ""
-#: merge-recursive.c:1462 merge-recursive.c:1660
+#: merge-recursive.c:1463 merge-recursive.c:1661
#, c-format
msgid "Adding as %s instead"
msgstr ""
-#: merge-recursive.c:1513
+#: merge-recursive.c:1514
#, c-format
msgid "cannot read object %s"
msgstr ""
-#: merge-recursive.c:1516
+#: merge-recursive.c:1517
#, c-format
msgid "object %s is not a blob"
msgstr ""
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modify"
msgstr ""
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modified"
msgstr ""
-#: merge-recursive.c:1574
+#: merge-recursive.c:1575
msgid "content"
msgstr ""
-#: merge-recursive.c:1581
+#: merge-recursive.c:1582
msgid "add/add"
msgstr ""
-#: merge-recursive.c:1615
+#: merge-recursive.c:1616
#, c-format
msgid "Skipped %s (merged same as existing)"
msgstr ""
-#: merge-recursive.c:1629
+#: merge-recursive.c:1630
#, c-format
msgid "Auto-merging %s"
msgstr ""
-#: merge-recursive.c:1633 git-submodule.sh:942
+#: merge-recursive.c:1634 git-submodule.sh:1118
msgid "submodule"
msgstr ""
-#: merge-recursive.c:1634
+#: merge-recursive.c:1635
#, c-format
msgid "CONFLICT (%s): Merge conflict in %s"
msgstr ""
-#: merge-recursive.c:1724
+#: merge-recursive.c:1725
#, c-format
msgid "Removing %s"
msgstr ""
-#: merge-recursive.c:1749
+#: merge-recursive.c:1750
msgid "file/directory"
msgstr ""
-#: merge-recursive.c:1755
+#: merge-recursive.c:1756
msgid "directory/file"
msgstr ""
-#: merge-recursive.c:1760
+#: merge-recursive.c:1761
#, c-format
msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
msgstr ""
-#: merge-recursive.c:1770
+#: merge-recursive.c:1771
#, c-format
msgid "Adding %s"
msgstr ""
-#: merge-recursive.c:1787
+#: merge-recursive.c:1788
msgid "Fatal merge failure, shouldn't happen."
msgstr ""
-#: merge-recursive.c:1806
+#: merge-recursive.c:1807
msgid "Already up-to-date!"
msgstr ""
-#: merge-recursive.c:1815
+#: merge-recursive.c:1816
#, c-format
msgid "merging of trees %s and %s failed"
msgstr ""
-#: merge-recursive.c:1845
+#: merge-recursive.c:1846
#, c-format
msgid "Unprocessed path??? %s"
msgstr ""
-#: merge-recursive.c:1890
+#: merge-recursive.c:1891
msgid "Merging:"
msgstr ""
-#: merge-recursive.c:1903
+#: merge-recursive.c:1904
#, c-format
msgid "found %u common ancestor:"
msgid_plural "found %u common ancestors:"
msgstr[0] ""
msgstr[1] ""
-#: merge-recursive.c:1940
+#: merge-recursive.c:1941
msgid "merge returned no commit"
msgstr ""
-#: merge-recursive.c:1997
+#: merge-recursive.c:1998
#, c-format
msgid "Could not parse object '%s'"
msgstr ""
-#: merge-recursive.c:2009 builtin/merge.c:643
+#: merge-recursive.c:2010 builtin/merge.c:672
msgid "Unable to write index."
msgstr ""
+#: notes-utils.c:40
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr ""
+
+#: notes-utils.c:81
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr ""
+
+#: notes-utils.c:91
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr ""
+
+#. TRANSLATORS: The first %s is the name of the
+#. environment variable, the second %s is its value
+#: notes-utils.c:118
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr ""
+
+#: object.c:204
+#, c-format
+msgid "unable to parse object: %s"
+msgstr ""
+
#: parse-options.c:489
msgid "..."
msgstr ""
@@ -711,18 +856,18 @@ msgstr ""
msgid "'%s' is beyond a symbolic link"
msgstr ""
-#: remote.c:1653
+#: remote.c:1788
#, 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:1659
+#: remote.c:1794
msgid " (use \"git push\" to publish your local commits)\n"
msgstr ""
-#: remote.c:1662
+#: remote.c:1797
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -730,11 +875,11 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: remote.c:1670
+#: remote.c:1805
msgid " (use \"git pull\" to update your local branch)\n"
msgstr ""
-#: remote.c:1673
+#: remote.c:1808
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -745,257 +890,289 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: remote.c:1683
+#: remote.c:1818
msgid " (use \"git pull\" to merge the remote branch into yours)\n"
msgstr ""
-#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
-#: builtin/merge.c:994
+#: run-command.c:80
+msgid "open /dev/null failed"
+msgstr ""
+
+#: run-command.c:82
+#, c-format
+msgid "dup2(%d,%d) failed"
+msgstr ""
+
+#: sequencer.c:206 builtin/merge.c:790 builtin/merge.c:903
+#: builtin/merge.c:1013 builtin/merge.c:1023
#, c-format
msgid "Could not open '%s' for writing"
msgstr ""
-#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986
-#: builtin/merge.c:999
+#: sequencer.c:208 builtin/merge.c:350 builtin/merge.c:793
+#: builtin/merge.c:1015 builtin/merge.c:1028
#, c-format
msgid "Could not write to '%s'"
msgstr ""
-#: sequencer.c:146
+#: sequencer.c:229
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
-#: sequencer.c:149
+#: sequencer.c:232
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'\n"
"and commit the result with 'git commit'"
msgstr ""
-#: sequencer.c:162 sequencer.c:774 sequencer.c:857
+#: sequencer.c:245 sequencer.c:869 sequencer.c:952
#, c-format
msgid "Could not write to %s"
msgstr ""
-#: sequencer.c:165
+#: sequencer.c:248
#, c-format
msgid "Error wrapping up %s"
msgstr ""
-#: sequencer.c:180
+#: sequencer.c:263
msgid "Your local changes would be overwritten by cherry-pick."
msgstr ""
-#: sequencer.c:182
+#: sequencer.c:265
msgid "Your local changes would be overwritten by revert."
msgstr ""
-#: sequencer.c:185
+#: sequencer.c:268
msgid "Commit your changes or stash them to proceed."
msgstr ""
#. TRANSLATORS: %s will be "revert" or "cherry-pick"
-#: sequencer.c:236
+#: sequencer.c:324
#, c-format
msgid "%s: Unable to write new index file"
msgstr ""
-#: sequencer.c:267
+#: sequencer.c:355
msgid "Could not resolve HEAD commit\n"
msgstr ""
-#: sequencer.c:288
+#: sequencer.c:377
msgid "Unable to update cache tree\n"
msgstr ""
-#: sequencer.c:333
+#: sequencer.c:422
#, c-format
msgid "Could not parse commit %s\n"
msgstr ""
-#: sequencer.c:338
+#: sequencer.c:427
#, c-format
msgid "Could not parse parent commit %s\n"
msgstr ""
-#: sequencer.c:404
+#: sequencer.c:493
msgid "Your index file is unmerged."
msgstr ""
-#: sequencer.c:423
+#: sequencer.c:512
#, c-format
msgid "Commit %s is a merge but no -m option was given."
msgstr ""
-#: sequencer.c:431
+#: sequencer.c:520
#, c-format
msgid "Commit %s does not have parent %d"
msgstr ""
-#: sequencer.c:435
+#: sequencer.c:524
#, 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:448
+#: sequencer.c:537
#, c-format
msgid "%s: cannot parse parent commit %s"
msgstr ""
-#: sequencer.c:452
+#: sequencer.c:541
#, c-format
msgid "Cannot get commit message for %s"
msgstr ""
-#: sequencer.c:536
+#: sequencer.c:627
#, c-format
msgid "could not revert %s... %s"
msgstr ""
-#: sequencer.c:537
+#: sequencer.c:628
#, c-format
msgid "could not apply %s... %s"
msgstr ""
-#: sequencer.c:569
+#: sequencer.c:664
msgid "empty commit set passed"
msgstr ""
-#: sequencer.c:577
+#: sequencer.c:672
#, c-format
msgid "git %s: failed to read the index"
msgstr ""
-#: sequencer.c:582
+#: sequencer.c:677
#, c-format
msgid "git %s: failed to refresh the index"
msgstr ""
-#: sequencer.c:640
+#: sequencer.c:735
#, c-format
msgid "Cannot %s during a %s"
msgstr ""
-#: sequencer.c:662
+#: sequencer.c:757
#, c-format
msgid "Could not parse line %d."
msgstr ""
-#: sequencer.c:667
+#: sequencer.c:762
msgid "No commits parsed."
msgstr ""
-#: sequencer.c:680
+#: sequencer.c:775
#, c-format
msgid "Could not open %s"
msgstr ""
-#: sequencer.c:684
+#: sequencer.c:779
#, c-format
msgid "Could not read %s."
msgstr ""
-#: sequencer.c:691
+#: sequencer.c:786
#, c-format
msgid "Unusable instruction sheet: %s"
msgstr ""
-#: sequencer.c:719
+#: sequencer.c:814
#, c-format
msgid "Invalid key: %s"
msgstr ""
-#: sequencer.c:722
+#: sequencer.c:817
#, c-format
msgid "Invalid value for %s: %s"
msgstr ""
-#: sequencer.c:734
+#: sequencer.c:829
#, c-format
msgid "Malformed options sheet: %s"
msgstr ""
-#: sequencer.c:755
+#: sequencer.c:850
msgid "a cherry-pick or revert is already in progress"
msgstr ""
-#: sequencer.c:756
+#: sequencer.c:851
msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
msgstr ""
-#: sequencer.c:760
+#: sequencer.c:855
#, c-format
msgid "Could not create sequencer directory %s"
msgstr ""
-#: sequencer.c:776 sequencer.c:861
+#: sequencer.c:871 sequencer.c:956
#, c-format
msgid "Error wrapping up %s."
msgstr ""
-#: sequencer.c:795 sequencer.c:929
+#: sequencer.c:890 sequencer.c:1024
msgid "no cherry-pick or revert in progress"
msgstr ""
-#: sequencer.c:797
+#: sequencer.c:892
msgid "cannot resolve HEAD"
msgstr ""
-#: sequencer.c:799
+#: sequencer.c:894
msgid "cannot abort from a branch yet to be born"
msgstr ""
-#: sequencer.c:821 builtin/apply.c:4056
+#: sequencer.c:916 builtin/apply.c:4061
#, c-format
msgid "cannot open %s: %s"
msgstr ""
-#: sequencer.c:824
+#: sequencer.c:919
#, c-format
msgid "cannot read %s: %s"
msgstr ""
-#: sequencer.c:825
+#: sequencer.c:920
msgid "unexpected end of file"
msgstr ""
-#: sequencer.c:831
+#: sequencer.c:926
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
msgstr ""
-#: sequencer.c:854
+#: sequencer.c:949
#, c-format
msgid "Could not format %s."
msgstr ""
-#: sequencer.c:1016
+#: sequencer.c:1092
+#, c-format
+msgid "%s: can't cherry-pick a %s"
+msgstr ""
+
+#: sequencer.c:1095
+#, c-format
+msgid "%s: bad revision"
+msgstr ""
+
+#: sequencer.c:1129
msgid "Can't revert as initial commit"
msgstr ""
-#: sequencer.c:1017
+#: sequencer.c:1130
msgid "Can't cherry-pick into empty head"
msgstr ""
-#: sha1_name.c:1044
+#: sha1_name.c:440
+msgid ""
+"Git normally never creates a ref that ends with 40 hex characters\n"
+"because it will be ignored when you just specify 40-hex. These refs\n"
+"may be created by mistake. For example,\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
+"examine these refs and maybe delete them. Turn this message off by\n"
+"running \"git config advice.objectNameWarning false\""
+msgstr ""
+
+#: sha1_name.c:1097
msgid "HEAD does not point to a branch"
msgstr ""
-#: sha1_name.c:1047
+#: sha1_name.c:1100
#, c-format
msgid "No such branch: '%s'"
msgstr ""
-#: sha1_name.c:1049
+#: sha1_name.c:1102
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr ""
-#: sha1_name.c:1052
+#: sha1_name.c:1106
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr ""
@@ -1005,374 +1182,419 @@ msgstr ""
msgid "unable to access '%s': %s"
msgstr ""
-#: wrapper.c:423
+#: wrapper.c:429
#, c-format
msgid "unable to access '%s'"
msgstr ""
-#: wrapper.c:434
+#: wrapper.c:440
#, c-format
msgid "unable to look up current user in the passwd file: %s"
msgstr ""
-#: wrapper.c:435
+#: wrapper.c:441
msgid "no such user"
msgstr ""
-#: wt-status.c:140
+#: wt-status.c:141
msgid "Unmerged paths:"
msgstr ""
-#: wt-status.c:167 wt-status.c:194
+#: wt-status.c:168 wt-status.c:195
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr ""
-#: wt-status.c:169 wt-status.c:196
+#: wt-status.c:170 wt-status.c:197
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr ""
-#: wt-status.c:173
+#: wt-status.c:174
msgid " (use \"git add <file>...\" to mark resolution)"
msgstr ""
-#: wt-status.c:175 wt-status.c:179
+#: wt-status.c:176 wt-status.c:180
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr ""
-#: wt-status.c:177
+#: wt-status.c:178
msgid " (use \"git rm <file>...\" to mark resolution)"
msgstr ""
-#: wt-status.c:188
+#: wt-status.c:189
msgid "Changes to be committed:"
msgstr ""
-#: wt-status.c:206
+#: wt-status.c:207
msgid "Changes not staged for commit:"
msgstr ""
-#: wt-status.c:210
+#: wt-status.c:211
msgid " (use \"git add <file>...\" to update what will be committed)"
msgstr ""
-#: wt-status.c:212
+#: wt-status.c:213
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr ""
-#: wt-status.c:213
+#: wt-status.c:214
msgid ""
" (use \"git checkout -- <file>...\" to discard changes in working directory)"
msgstr ""
-#: wt-status.c:215
+#: wt-status.c:216
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr ""
-#: wt-status.c:227
+#: wt-status.c:228
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr ""
-#: wt-status.c:244
+#: wt-status.c:245
msgid "bug"
msgstr ""
-#: wt-status.c:249
+#: wt-status.c:250
msgid "both deleted:"
msgstr ""
-#: wt-status.c:250
+#: wt-status.c:251
msgid "added by us:"
msgstr ""
-#: wt-status.c:251
+#: wt-status.c:252
msgid "deleted by them:"
msgstr ""
-#: wt-status.c:252
+#: wt-status.c:253
msgid "added by them:"
msgstr ""
-#: wt-status.c:253
+#: wt-status.c:254
msgid "deleted by us:"
msgstr ""
-#: wt-status.c:254
+#: wt-status.c:255
msgid "both added:"
msgstr ""
-#: wt-status.c:255
+#: wt-status.c:256
msgid "both modified:"
msgstr ""
-#: wt-status.c:285
+#: wt-status.c:286
msgid "new commits, "
msgstr ""
-#: wt-status.c:287
+#: wt-status.c:288
msgid "modified content, "
msgstr ""
-#: wt-status.c:289
+#: wt-status.c:290
msgid "untracked content, "
msgstr ""
-#: wt-status.c:303
+#: wt-status.c:307
#, c-format
msgid "new file: %s"
msgstr ""
-#: wt-status.c:306
+#: wt-status.c:310
#, c-format
msgid "copied: %s -> %s"
msgstr ""
-#: wt-status.c:309
+#: wt-status.c:313
#, c-format
msgid "deleted: %s"
msgstr ""
-#: wt-status.c:312
+#: wt-status.c:316
#, c-format
msgid "modified: %s"
msgstr ""
-#: wt-status.c:315
+#: wt-status.c:319
#, c-format
msgid "renamed: %s -> %s"
msgstr ""
-#: wt-status.c:318
+#: wt-status.c:322
#, c-format
msgid "typechange: %s"
msgstr ""
-#: wt-status.c:321
+#: wt-status.c:325
#, c-format
msgid "unknown: %s"
msgstr ""
-#: wt-status.c:324
+#: wt-status.c:328
#, c-format
msgid "unmerged: %s"
msgstr ""
-#: wt-status.c:327
+#: wt-status.c:331
#, c-format
msgid "bug: unhandled diff status %c"
msgstr ""
-#: wt-status.c:789
+#: wt-status.c:803
msgid "You have unmerged paths."
msgstr ""
-#: wt-status.c:792 wt-status.c:944
+#: wt-status.c:806
msgid " (fix conflicts and run \"git commit\")"
msgstr ""
-#: wt-status.c:795
+#: wt-status.c:809
msgid "All conflicts fixed but you are still merging."
msgstr ""
-#: wt-status.c:798
+#: wt-status.c:812
msgid " (use \"git commit\" to conclude merge)"
msgstr ""
-#: wt-status.c:808
+#: wt-status.c:822
msgid "You are in the middle of an am session."
msgstr ""
-#: wt-status.c:811
+#: wt-status.c:825
msgid "The current patch is empty."
msgstr ""
-#: wt-status.c:815
-msgid " (fix conflicts and then run \"git am --resolved\")"
+#: wt-status.c:829
+msgid " (fix conflicts and then run \"git am --continue\")"
msgstr ""
-#: wt-status.c:817
+#: wt-status.c:831
msgid " (use \"git am --skip\" to skip this patch)"
msgstr ""
-#: wt-status.c:819
+#: wt-status.c:833
msgid " (use \"git am --abort\" to restore the original branch)"
msgstr ""
-#: wt-status.c:879 wt-status.c:896
+#: wt-status.c:893 wt-status.c:910
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
msgstr ""
-#: wt-status.c:884 wt-status.c:901
+#: wt-status.c:898 wt-status.c:915
msgid "You are currently rebasing."
msgstr ""
-#: wt-status.c:887
+#: wt-status.c:901
msgid " (fix conflicts and then run \"git rebase --continue\")"
msgstr ""
-#: wt-status.c:889
+#: wt-status.c:903
msgid " (use \"git rebase --skip\" to skip this patch)"
msgstr ""
-#: wt-status.c:891
+#: wt-status.c:905
msgid " (use \"git rebase --abort\" to check out the original branch)"
msgstr ""
-#: wt-status.c:904
+#: wt-status.c:918
msgid " (all conflicts fixed: run \"git rebase --continue\")"
msgstr ""
-#: wt-status.c:908
+#: wt-status.c:922
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
msgstr ""
-#: wt-status.c:913
+#: wt-status.c:927
msgid "You are currently splitting a commit during a rebase."
msgstr ""
-#: wt-status.c:916
+#: wt-status.c:930
msgid " (Once your working directory is clean, run \"git rebase --continue\")"
msgstr ""
-#: wt-status.c:920
+#: wt-status.c:934
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr ""
-#: wt-status.c:925
+#: wt-status.c:939
msgid "You are currently editing a commit during a rebase."
msgstr ""
-#: wt-status.c:928
+#: wt-status.c:942
msgid " (use \"git commit --amend\" to amend the current commit)"
msgstr ""
-#: wt-status.c:930
+#: wt-status.c:944
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
msgstr ""
-#: wt-status.c:940
+#: wt-status.c:954
msgid "You are currently cherry-picking."
msgstr ""
-#: wt-status.c:947
-msgid " (all conflicts fixed: run \"git commit\")"
+#: wt-status.c:958
+msgid " (fix conflicts and run \"git cherry-pick --continue\")"
msgstr ""
-#: wt-status.c:958
+#: wt-status.c:961
+msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
+msgstr ""
+
+#: wt-status.c:963
+msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
+msgstr ""
+
+#: wt-status.c:972
+#, c-format
+msgid "You are currently reverting commit %s."
+msgstr ""
+
+#: wt-status.c:977
+msgid " (fix conflicts and run \"git revert --continue\")"
+msgstr ""
+
+#: wt-status.c:980
+msgid " (all conflicts fixed: run \"git revert --continue\")"
+msgstr ""
+
+#: wt-status.c:982
+msgid " (use \"git revert --abort\" to cancel the revert operation)"
+msgstr ""
+
+#: wt-status.c:993
#, c-format
-msgid "You are currently bisecting branch '%s'."
+msgid "You are currently bisecting, started from branch '%s'."
msgstr ""
-#: wt-status.c:962
+#: wt-status.c:997
msgid "You are currently bisecting."
msgstr ""
-#: wt-status.c:965
+#: wt-status.c:1000
msgid " (use \"git bisect reset\" to get back to the original branch)"
msgstr ""
-#: wt-status.c:1064
+#: wt-status.c:1173
msgid "On branch "
msgstr ""
-#: wt-status.c:1071
+#: wt-status.c:1180
+msgid "rebase in progress; onto "
+msgstr ""
+
+#: wt-status.c:1187
+msgid "HEAD detached at "
+msgstr ""
+
+#: wt-status.c:1189
+msgid "HEAD detached from "
+msgstr ""
+
+#: wt-status.c:1192
msgid "Not currently on any branch."
msgstr ""
-#: wt-status.c:1083
+#: wt-status.c:1209
msgid "Initial commit"
msgstr ""
-#: wt-status.c:1097
+#: wt-status.c:1223
msgid "Untracked files"
msgstr ""
-#: wt-status.c:1099
+#: wt-status.c:1225
msgid "Ignored files"
msgstr ""
-#: wt-status.c:1101
+#: wt-status.c:1229
+#, c-format
+msgid ""
+"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
+"may speed it up, but you have to be careful not to forget to add\n"
+"new files yourself (see 'git help status')."
+msgstr ""
+
+#: wt-status.c:1235
#, c-format
msgid "Untracked files not listed%s"
msgstr ""
-#: wt-status.c:1103
+#: wt-status.c:1237
msgid " (use -u option to show untracked files)"
msgstr ""
-#: wt-status.c:1109
+#: wt-status.c:1243
msgid "No changes"
msgstr ""
-#: wt-status.c:1114
+#: wt-status.c:1248
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr ""
-#: wt-status.c:1117
+#: wt-status.c:1251
#, c-format
msgid "no changes added to commit\n"
msgstr ""
-#: wt-status.c:1120
+#: wt-status.c:1254
#, c-format
msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
"track)\n"
msgstr ""
-#: wt-status.c:1123
+#: wt-status.c:1257
#, c-format
msgid "nothing added to commit but untracked files present\n"
msgstr ""
-#: wt-status.c:1126
+#: wt-status.c:1260
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
msgstr ""
-#: wt-status.c:1129 wt-status.c:1134
+#: wt-status.c:1263 wt-status.c:1268
#, c-format
msgid "nothing to commit\n"
msgstr ""
-#: wt-status.c:1132
+#: wt-status.c:1266
#, c-format
msgid "nothing to commit (use -u to show untracked files)\n"
msgstr ""
-#: wt-status.c:1136
+#: wt-status.c:1270
#, c-format
msgid "nothing to commit, working directory clean\n"
msgstr ""
-#: wt-status.c:1244
+#: wt-status.c:1378
msgid "HEAD (no branch)"
msgstr ""
-#: wt-status.c:1250
+#: wt-status.c:1384
msgid "Initial commit on "
msgstr ""
-#: wt-status.c:1265
+#: wt-status.c:1399
msgid "behind "
msgstr ""
-#: wt-status.c:1268 wt-status.c:1271
+#: wt-status.c:1402 wt-status.c:1405
msgid "ahead "
msgstr ""
-#: wt-status.c:1273
+#: wt-status.c:1407
msgid ", behind "
msgstr ""
-#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#: compat/precompose_utf8.c:58 builtin/clone.c:351
#, c-format
msgid "failed to unlink '%s'"
msgstr ""
@@ -1381,179 +1603,200 @@ msgstr ""
msgid "git add [options] [--] <pathspec>..."
msgstr ""
-#: builtin/add.c:63
+#.
+#. * To be consistent with "git add -p" and most Git
+#. * commands, we should default to being tree-wide, but
+#. * this is not the original behavior and can't be
+#. * changed until users trained themselves not to type
+#. * "git add -u" or "git add -A". For now, we warn and
+#. * keep the old behavior. Later, the behavior can be changed
+#. * to tree-wide, keeping the warning for a while, and
+#. * eventually we can drop the warning.
+#.
+#: builtin/add.c:58
+#, c-format
+msgid ""
+"The behavior of 'git add %s (or %s)' with no path argument from a\n"
+"subdirectory of the tree will change in Git 2.0 and should not be used "
+"anymore.\n"
+"To add content for the whole tree, run:\n"
+"\n"
+" git add %s :/\n"
+" (or git add %s :/)\n"
+"\n"
+"To restrict the command to the current directory, run:\n"
+"\n"
+" git add %s .\n"
+" (or git add %s .)\n"
+"\n"
+"With the current Git version, the command is restricted to the current "
+"directory.\n"
+msgstr ""
+
+#: builtin/add.c:100
+#, c-format
+msgid ""
+"You ran 'git add' with neither '-A (--all)' or '--ignore-removal',\n"
+"whose behaviour will change in Git 2.0 with respect to paths you removed.\n"
+"Paths like '%s' that are\n"
+"removed from your working tree are ignored with this version of Git.\n"
+"\n"
+"* 'git add --ignore-removal <pathspec>', which is the current default,\n"
+" ignores paths you removed from your working tree.\n"
+"\n"
+"* 'git add --all <pathspec>' will let you also record the removals.\n"
+"\n"
+"Run 'git status' to check the paths you removed from your working tree.\n"
+msgstr ""
+
+#: builtin/add.c:144
#, c-format
msgid "unexpected diff status %c"
msgstr ""
-#: builtin/add.c:68 builtin/commit.c:231
+#: builtin/add.c:149 builtin/commit.c:252
msgid "updating files failed"
msgstr ""
-#: builtin/add.c:78
+#: builtin/add.c:163
#, c-format
msgid "remove '%s'\n"
msgstr ""
-#: builtin/add.c:148
+#: builtin/add.c:253
msgid "Unstaged changes after refreshing the index:"
msgstr ""
-#: builtin/add.c:151 builtin/add.c:460 builtin/rm.c:275
+#: builtin/add.c:256 builtin/add.c:573 builtin/rm.c:337
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr ""
-#: builtin/add.c:234
+#: builtin/add.c:339
msgid "Could not read the index"
msgstr ""
-#: builtin/add.c:244
+#: builtin/add.c:350
#, c-format
msgid "Could not open '%s' for writing."
msgstr ""
-#: builtin/add.c:248
+#: builtin/add.c:354
msgid "Could not write patch"
msgstr ""
-#: builtin/add.c:253
+#: builtin/add.c:359
#, c-format
msgid "Could not stat '%s'"
msgstr ""
-#: builtin/add.c:255
+#: builtin/add.c:361
msgid "Empty patch. Aborted."
msgstr ""
-#: builtin/add.c:261
+#: builtin/add.c:367
#, c-format
msgid "Could not apply '%s'"
msgstr ""
-#: builtin/add.c:271
+#: builtin/add.c:377
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr ""
-#: builtin/add.c:277 builtin/clean.c:161 builtin/fetch.c:78 builtin/mv.c:63
-#: builtin/prune-packed.c:76 builtin/push.c:425 builtin/remote.c:1253
-#: builtin/rm.c:206
+#: builtin/add.c:394 builtin/clean.c:875 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:73 builtin/push.c:451 builtin/remote.c:1253
+#: builtin/rm.c:268
msgid "dry run"
msgstr ""
-#: builtin/add.c:278 builtin/apply.c:4405 builtin/check-ignore.c:19
-#: builtin/commit.c:1150 builtin/count-objects.c:82 builtin/fsck.c:613
-#: builtin/log.c:1522 builtin/mv.c:62 builtin/read-tree.c:112
+#: builtin/add.c:395 builtin/apply.c:4410 builtin/check-ignore.c:19
+#: builtin/commit.c:1220 builtin/count-objects.c:95 builtin/fsck.c:613
+#: builtin/log.c:1573 builtin/mv.c:62 builtin/read-tree.c:113
msgid "be verbose"
msgstr ""
-#: builtin/add.c:280
+#: builtin/add.c:397
msgid "interactive picking"
msgstr ""
-#: builtin/add.c:281 builtin/checkout.c:1031 builtin/reset.c:258
+#: builtin/add.c:398 builtin/checkout.c:1073 builtin/reset.c:261
msgid "select hunks interactively"
msgstr ""
-#: builtin/add.c:282
+#: builtin/add.c:399
msgid "edit current diff and apply"
msgstr ""
-#: builtin/add.c:283
+#: builtin/add.c:400
msgid "allow adding otherwise ignored files"
msgstr ""
-#: builtin/add.c:284
+#: builtin/add.c:401
msgid "update tracked files"
msgstr ""
-#: builtin/add.c:285
+#: builtin/add.c:402
msgid "record only the fact that the path will be added later"
msgstr ""
-#: builtin/add.c:286
+#: builtin/add.c:403
msgid "add changes from all tracked and untracked files"
msgstr ""
-#: builtin/add.c:287
+#. takes no arguments
+#: builtin/add.c:406
+msgid "ignore paths removed in the working tree (same as --no-all)"
+msgstr ""
+
+#: builtin/add.c:408
msgid "don't add, only refresh the index"
msgstr ""
-#: builtin/add.c:288
+#: builtin/add.c:409
msgid "just skip files which cannot be added because of errors"
msgstr ""
-#: builtin/add.c:289
+#: builtin/add.c:410
msgid "check if - even missing - files are ignored in dry run"
msgstr ""
-#: builtin/add.c:311
+#: builtin/add.c:432
#, c-format
msgid "Use -f if you really want to add them.\n"
msgstr ""
-#: builtin/add.c:312
+#: builtin/add.c:433
msgid "no files added"
msgstr ""
-#: builtin/add.c:318
+#: builtin/add.c:439
msgid "adding files failed"
msgstr ""
-#.
-#. * To be consistent with "git add -p" and most Git
-#. * commands, we should default to being tree-wide, but
-#. * this is not the original behavior and can't be
-#. * changed until users trained themselves not to type
-#. * "git add -u" or "git add -A". For now, we warn and
-#. * keep the old behavior. Later, this warning can be
-#. * turned into a die(...), and eventually we may
-#. * reallow the command with a new behavior.
-#.
-#: builtin/add.c:335
-#, c-format
-msgid ""
-"The behavior of 'git add %s (or %s)' with no path argument from a\n"
-"subdirectory of the tree will change in Git 2.0 and should not be used "
-"anymore.\n"
-"To add content for the whole tree, run:\n"
-"\n"
-" git add %s :/\n"
-" (or git add %s :/)\n"
-"\n"
-"To restrict the command to the current directory, run:\n"
-"\n"
-" git add %s .\n"
-" (or git add %s .)\n"
-"\n"
-"With the current Git version, the command is restricted to the current "
-"directory."
-msgstr ""
-
-#: builtin/add.c:381
+#: builtin/add.c:478
msgid "-A and -u are mutually incompatible"
msgstr ""
-#: builtin/add.c:383
+#: builtin/add.c:496
msgid "Option --ignore-missing can only be used together with --dry-run"
msgstr ""
-#: builtin/add.c:414
+#: builtin/add.c:526
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr ""
-#: builtin/add.c:415
+#: builtin/add.c:527
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr ""
-#: builtin/add.c:421 builtin/check-ignore.c:67 builtin/clean.c:204
-#: builtin/commit.c:291 builtin/mv.c:82 builtin/rm.c:235
+#: builtin/add.c:533 builtin/check-ignore.c:161 builtin/clean.c:919
+#: builtin/commit.c:312 builtin/mv.c:82 builtin/rm.c:297
msgid "index file corrupt"
msgstr ""
-#: builtin/add.c:481 builtin/apply.c:4501 builtin/mv.c:229 builtin/rm.c:370
+#: builtin/add.c:605 builtin/apply.c:4506 builtin/mv.c:229 builtin/rm.c:432
msgid "Unable to write new index file"
msgstr ""
@@ -1681,342 +1924,342 @@ msgstr ""
msgid "unable to open or read %s"
msgstr ""
-#: builtin/apply.c:2684
+#: builtin/apply.c:2688
#, c-format
msgid "invalid start of line: '%c'"
msgstr ""
-#: builtin/apply.c:2802
+#: builtin/apply.c:2806
#, 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:2814
+#: builtin/apply.c:2818
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
msgstr ""
-#: builtin/apply.c:2820
+#: builtin/apply.c:2824
#, c-format
msgid ""
"while searching for:\n"
"%.*s"
msgstr ""
-#: builtin/apply.c:2839
+#: builtin/apply.c:2843
#, c-format
msgid "missing binary patch data for '%s'"
msgstr ""
-#: builtin/apply.c:2942
+#: builtin/apply.c:2946
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr ""
-#: builtin/apply.c:2948
+#: builtin/apply.c:2952
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
msgstr ""
-#: builtin/apply.c:2969
+#: builtin/apply.c:2973
#, c-format
msgid "patch failed: %s:%ld"
msgstr ""
-#: builtin/apply.c:3091
+#: builtin/apply.c:3095
#, c-format
msgid "cannot checkout %s"
msgstr ""
-#: builtin/apply.c:3136 builtin/apply.c:3145 builtin/apply.c:3189
+#: builtin/apply.c:3140 builtin/apply.c:3149 builtin/apply.c:3194
#, c-format
msgid "read of %s failed"
msgstr ""
-#: builtin/apply.c:3169 builtin/apply.c:3391
+#: builtin/apply.c:3174 builtin/apply.c:3396
#, c-format
msgid "path %s has been renamed/deleted"
msgstr ""
-#: builtin/apply.c:3250 builtin/apply.c:3405
+#: builtin/apply.c:3255 builtin/apply.c:3410
#, c-format
msgid "%s: does not exist in index"
msgstr ""
-#: builtin/apply.c:3254 builtin/apply.c:3397 builtin/apply.c:3419
+#: builtin/apply.c:3259 builtin/apply.c:3402 builtin/apply.c:3424
#, c-format
msgid "%s: %s"
msgstr ""
-#: builtin/apply.c:3259 builtin/apply.c:3413
+#: builtin/apply.c:3264 builtin/apply.c:3418
#, c-format
msgid "%s: does not match index"
msgstr ""
-#: builtin/apply.c:3361
+#: builtin/apply.c:3366
msgid "removal patch leaves file contents"
msgstr ""
-#: builtin/apply.c:3430
+#: builtin/apply.c:3435
#, c-format
msgid "%s: wrong type"
msgstr ""
-#: builtin/apply.c:3432
+#: builtin/apply.c:3437
#, c-format
msgid "%s has type %o, expected %o"
msgstr ""
-#: builtin/apply.c:3533
+#: builtin/apply.c:3538
#, c-format
msgid "%s: already exists in index"
msgstr ""
-#: builtin/apply.c:3536
+#: builtin/apply.c:3541
#, c-format
msgid "%s: already exists in working directory"
msgstr ""
-#: builtin/apply.c:3556
+#: builtin/apply.c:3561
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr ""
-#: builtin/apply.c:3561
+#: builtin/apply.c:3566
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
msgstr ""
-#: builtin/apply.c:3569
+#: builtin/apply.c:3574
#, c-format
msgid "%s: patch does not apply"
msgstr ""
-#: builtin/apply.c:3582
+#: builtin/apply.c:3587
#, c-format
msgid "Checking patch %s..."
msgstr ""
-#: builtin/apply.c:3675 builtin/checkout.c:215 builtin/reset.c:124
+#: builtin/apply.c:3680 builtin/checkout.c:216 builtin/reset.c:127
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr ""
-#: builtin/apply.c:3818
+#: builtin/apply.c:3823
#, c-format
msgid "unable to remove %s from index"
msgstr ""
-#: builtin/apply.c:3846
+#: builtin/apply.c:3851
#, c-format
-msgid "corrupt patch for subproject %s"
+msgid "corrupt patch for submodule %s"
msgstr ""
-#: builtin/apply.c:3850
+#: builtin/apply.c:3855
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr ""
-#: builtin/apply.c:3855
+#: builtin/apply.c:3860
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr ""
-#: builtin/apply.c:3858 builtin/apply.c:3966
+#: builtin/apply.c:3863 builtin/apply.c:3971
#, c-format
msgid "unable to add cache entry for %s"
msgstr ""
-#: builtin/apply.c:3891
+#: builtin/apply.c:3896
#, c-format
msgid "closing file '%s'"
msgstr ""
-#: builtin/apply.c:3940
+#: builtin/apply.c:3945
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr ""
-#: builtin/apply.c:4027
+#: builtin/apply.c:4032
#, c-format
msgid "Applied patch %s cleanly."
msgstr ""
-#: builtin/apply.c:4035
+#: builtin/apply.c:4040
msgid "internal error"
msgstr ""
#. Say this even without --verbose
-#: builtin/apply.c:4038
+#: builtin/apply.c:4043
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
msgstr[0] ""
msgstr[1] ""
-#: builtin/apply.c:4048
+#: builtin/apply.c:4053
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr ""
-#: builtin/apply.c:4069
+#: builtin/apply.c:4074
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr ""
-#: builtin/apply.c:4072
+#: builtin/apply.c:4077
#, c-format
msgid "Rejected hunk #%d."
msgstr ""
-#: builtin/apply.c:4222
+#: builtin/apply.c:4227
msgid "unrecognized input"
msgstr ""
-#: builtin/apply.c:4233
+#: builtin/apply.c:4238
msgid "unable to read index file"
msgstr ""
-#: builtin/apply.c:4352 builtin/apply.c:4355 builtin/clone.c:91
+#: builtin/apply.c:4357 builtin/apply.c:4360 builtin/clone.c:91
#: builtin/fetch.c:63
msgid "path"
msgstr ""
-#: builtin/apply.c:4353
+#: builtin/apply.c:4358
msgid "don't apply changes matching the given path"
msgstr ""
-#: builtin/apply.c:4356
+#: builtin/apply.c:4361
msgid "apply changes matching the given path"
msgstr ""
-#: builtin/apply.c:4358
+#: builtin/apply.c:4363
msgid "num"
msgstr ""
-#: builtin/apply.c:4359
+#: builtin/apply.c:4364
msgid "remove <num> leading slashes from traditional diff paths"
msgstr ""
-#: builtin/apply.c:4362
+#: builtin/apply.c:4367
msgid "ignore additions made by the patch"
msgstr ""
-#: builtin/apply.c:4364
+#: builtin/apply.c:4369
msgid "instead of applying the patch, output diffstat for the input"
msgstr ""
-#: builtin/apply.c:4368
+#: builtin/apply.c:4373
msgid "show number of added and deleted lines in decimal notation"
msgstr ""
-#: builtin/apply.c:4370
+#: builtin/apply.c:4375
msgid "instead of applying the patch, output a summary for the input"
msgstr ""
-#: builtin/apply.c:4372
+#: builtin/apply.c:4377
msgid "instead of applying the patch, see if the patch is applicable"
msgstr ""
-#: builtin/apply.c:4374
+#: builtin/apply.c:4379
msgid "make sure the patch is applicable to the current index"
msgstr ""
-#: builtin/apply.c:4376
+#: builtin/apply.c:4381
msgid "apply a patch without touching the working tree"
msgstr ""
-#: builtin/apply.c:4378
+#: builtin/apply.c:4383
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr ""
-#: builtin/apply.c:4380
+#: builtin/apply.c:4385
msgid "attempt three-way merge if a patch does not apply"
msgstr ""
-#: builtin/apply.c:4382
+#: builtin/apply.c:4387
msgid "build a temporary index based on embedded index information"
msgstr ""
-#: builtin/apply.c:4384 builtin/checkout-index.c:197 builtin/ls-files.c:463
+#: builtin/apply.c:4389 builtin/checkout-index.c:197 builtin/ls-files.c:462
msgid "paths are separated with NUL character"
msgstr ""
-#: builtin/apply.c:4387
+#: builtin/apply.c:4392
msgid "ensure at least <n> lines of context match"
msgstr ""
-#: builtin/apply.c:4388
+#: builtin/apply.c:4393
msgid "action"
msgstr ""
-#: builtin/apply.c:4389
+#: builtin/apply.c:4394
msgid "detect new or modified lines that have whitespace errors"
msgstr ""
-#: builtin/apply.c:4392 builtin/apply.c:4395
+#: builtin/apply.c:4397 builtin/apply.c:4400
msgid "ignore changes in whitespace when finding context"
msgstr ""
-#: builtin/apply.c:4398
+#: builtin/apply.c:4403
msgid "apply the patch in reverse"
msgstr ""
-#: builtin/apply.c:4400
+#: builtin/apply.c:4405
msgid "don't expect at least one line of context"
msgstr ""
-#: builtin/apply.c:4402
+#: builtin/apply.c:4407
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr ""
-#: builtin/apply.c:4404
+#: builtin/apply.c:4409
msgid "allow overlapping hunks"
msgstr ""
-#: builtin/apply.c:4407
+#: builtin/apply.c:4412
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr ""
-#: builtin/apply.c:4410
+#: builtin/apply.c:4415
msgid "do not trust the line counts in the hunk headers"
msgstr ""
-#: builtin/apply.c:4412
+#: builtin/apply.c:4417
msgid "root"
msgstr ""
-#: builtin/apply.c:4413
+#: builtin/apply.c:4418
msgid "prepend <root> to all filenames"
msgstr ""
-#: builtin/apply.c:4435
+#: builtin/apply.c:4440
msgid "--3way outside a repository"
msgstr ""
-#: builtin/apply.c:4443
+#: builtin/apply.c:4448
msgid "--index outside a repository"
msgstr ""
-#: builtin/apply.c:4446
+#: builtin/apply.c:4451
msgid "--cached outside a repository"
msgstr ""
-#: builtin/apply.c:4462
+#: builtin/apply.c:4467
#, c-format
msgid "can't open patch '%s'"
msgstr ""
-#: builtin/apply.c:4476
+#: builtin/apply.c:4481
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] ""
msgstr[1] ""
-#: builtin/apply.c:4482 builtin/apply.c:4492
+#: builtin/apply.c:4487 builtin/apply.c:4497
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -2040,21 +2283,21 @@ msgstr ""
msgid "git archive: expected ACK/NAK, got EOF"
msgstr ""
-#: builtin/archive.c:63
+#: builtin/archive.c:61
#, c-format
msgid "git archive: NACK %s"
msgstr ""
-#: builtin/archive.c:65
+#: builtin/archive.c:63
#, c-format
msgid "remote error: %s"
msgstr ""
-#: builtin/archive.c:66
+#: builtin/archive.c:64
msgid "git archive: protocol error"
msgstr ""
-#: builtin/archive.c:71
+#: builtin/archive.c:68
msgid "git archive: expected a flush"
msgstr ""
@@ -2070,434 +2313,476 @@ msgstr ""
msgid "update BISECT_HEAD instead of checking out the current commit"
msgstr ""
-#: builtin/blame.c:25
+#: builtin/blame.c:26
msgid "git blame [options] [rev-opts] [rev] [--] file"
msgstr ""
-#: builtin/blame.c:30 builtin/shortlog.c:15
+#: builtin/blame.c:31
msgid "[rev-opts] are documented in git-rev-list(1)"
msgstr ""
-#: builtin/blame.c:2350
+#: builtin/blame.c:2276
msgid "Show blame entries as we find them, incrementally"
msgstr ""
-#: builtin/blame.c:2351
+#: builtin/blame.c:2277
msgid "Show blank SHA-1 for boundary commits (Default: off)"
msgstr ""
-#: builtin/blame.c:2352
+#: builtin/blame.c:2278
msgid "Do not treat root commits as boundaries (Default: off)"
msgstr ""
-#: builtin/blame.c:2353
+#: builtin/blame.c:2279
msgid "Show work cost statistics"
msgstr ""
-#: builtin/blame.c:2354
+#: builtin/blame.c:2280
msgid "Show output score for blame entries"
msgstr ""
-#: builtin/blame.c:2355
+#: builtin/blame.c:2281
msgid "Show original filename (Default: auto)"
msgstr ""
-#: builtin/blame.c:2356
+#: builtin/blame.c:2282
msgid "Show original linenumber (Default: off)"
msgstr ""
-#: builtin/blame.c:2357
+#: builtin/blame.c:2283
msgid "Show in a format designed for machine consumption"
msgstr ""
-#: builtin/blame.c:2358
+#: builtin/blame.c:2284
msgid "Show porcelain format with per-line commit information"
msgstr ""
-#: builtin/blame.c:2359
+#: builtin/blame.c:2285
msgid "Use the same output mode as git-annotate (Default: off)"
msgstr ""
-#: builtin/blame.c:2360
+#: builtin/blame.c:2286
msgid "Show raw timestamp (Default: off)"
msgstr ""
-#: builtin/blame.c:2361
+#: builtin/blame.c:2287
msgid "Show long commit SHA1 (Default: off)"
msgstr ""
-#: builtin/blame.c:2362
+#: builtin/blame.c:2288
msgid "Suppress author name and timestamp (Default: off)"
msgstr ""
-#: builtin/blame.c:2363
+#: builtin/blame.c:2289
msgid "Show author email instead of name (Default: off)"
msgstr ""
-#: builtin/blame.c:2364
+#: builtin/blame.c:2290
msgid "Ignore whitespace differences"
msgstr ""
-#: builtin/blame.c:2365
+#: builtin/blame.c:2291
msgid "Spend extra cycles to find better match"
msgstr ""
-#: builtin/blame.c:2366
+#: builtin/blame.c:2292
msgid "Use revisions from <file> instead of calling git-rev-list"
msgstr ""
-#: builtin/blame.c:2367
+#: builtin/blame.c:2293
msgid "Use <file>'s contents as the final image"
msgstr ""
-#: builtin/blame.c:2368 builtin/blame.c:2369
+#: builtin/blame.c:2294 builtin/blame.c:2295
msgid "score"
msgstr ""
-#: builtin/blame.c:2368
+#: builtin/blame.c:2294
msgid "Find line copies within and across files"
msgstr ""
-#: builtin/blame.c:2369
+#: builtin/blame.c:2295
msgid "Find line movements within and across files"
msgstr ""
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
msgid "n,m"
msgstr ""
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
msgid "Process only line range n,m, counting from 1"
msgstr ""
-#: builtin/branch.c:23
+#: builtin/branch.c:24
msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
msgstr ""
-#: builtin/branch.c:24
+#: builtin/branch.c:25
msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
msgstr ""
-#: builtin/branch.c:25
+#: builtin/branch.c:26
msgid "git branch [options] [-r] (-d | -D) <branchname>..."
msgstr ""
-#: builtin/branch.c:26
+#: builtin/branch.c:27
msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
msgstr ""
-#: builtin/branch.c:145
+#: builtin/branch.c:150
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
" '%s', but not yet merged to HEAD."
msgstr ""
-#: builtin/branch.c:149
+#: builtin/branch.c:154
#, 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:163
+#: builtin/branch.c:168
#, c-format
msgid "Couldn't look up commit object for '%s'"
msgstr ""
-#: builtin/branch.c:167
+#: builtin/branch.c:172
#, c-format
msgid ""
"The branch '%s' is not fully merged.\n"
"If you are sure you want to delete it, run 'git branch -D %s'."
msgstr ""
-#: builtin/branch.c:180
+#: builtin/branch.c:185
msgid "Update of config-file failed"
msgstr ""
-#: builtin/branch.c:208
+#: builtin/branch.c:213
msgid "cannot use -a with -d"
msgstr ""
-#: builtin/branch.c:214
+#: builtin/branch.c:219
msgid "Couldn't look up commit object for HEAD"
msgstr ""
-#: builtin/branch.c:222
+#: builtin/branch.c:227
#, c-format
msgid "Cannot delete the branch '%s' which you are currently on."
msgstr ""
-#: builtin/branch.c:235
+#: builtin/branch.c:240
#, c-format
msgid "remote branch '%s' not found."
msgstr ""
-#: builtin/branch.c:236
+#: builtin/branch.c:241
#, c-format
msgid "branch '%s' not found."
msgstr ""
-#: builtin/branch.c:250
+#: builtin/branch.c:255
#, c-format
msgid "Error deleting remote branch '%s'"
msgstr ""
-#: builtin/branch.c:251
+#: builtin/branch.c:256
#, c-format
msgid "Error deleting branch '%s'"
msgstr ""
-#: builtin/branch.c:258
+#: builtin/branch.c:263
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
msgstr ""
-#: builtin/branch.c:259
+#: builtin/branch.c:264
#, c-format
msgid "Deleted branch %s (was %s).\n"
msgstr ""
-#: builtin/branch.c:361
+#: builtin/branch.c:366
#, c-format
msgid "branch '%s' does not point at a commit"
msgstr ""
-#: builtin/branch.c:433
+#: builtin/branch.c:453
#, c-format
msgid "[%s: behind %d]"
msgstr ""
-#: builtin/branch.c:435
+#: builtin/branch.c:455
#, c-format
msgid "[behind %d]"
msgstr ""
-#: builtin/branch.c:439
+#: builtin/branch.c:459
#, c-format
msgid "[%s: ahead %d]"
msgstr ""
-#: builtin/branch.c:441
+#: builtin/branch.c:461
#, c-format
msgid "[ahead %d]"
msgstr ""
-#: builtin/branch.c:444
+#: builtin/branch.c:464
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr ""
-#: builtin/branch.c:447
+#: builtin/branch.c:467
#, c-format
msgid "[ahead %d, behind %d]"
msgstr ""
-#: builtin/branch.c:469
+#: builtin/branch.c:490
msgid " **** invalid ref ****"
msgstr ""
-#: builtin/branch.c:560
+#: builtin/branch.c:582
+#, c-format
+msgid "(no branch, rebasing %s)"
+msgstr ""
+
+#: builtin/branch.c:585
+#, c-format
+msgid "(no branch, bisect started on %s)"
+msgstr ""
+
+#: builtin/branch.c:588
+#, c-format
+msgid "(detached from %s)"
+msgstr ""
+
+#: builtin/branch.c:591
msgid "(no branch)"
msgstr ""
-#: builtin/branch.c:593
+#: builtin/branch.c:637
#, c-format
msgid "object '%s' does not point to a commit"
msgstr ""
-#: builtin/branch.c:625
+#: builtin/branch.c:669
msgid "some refs could not be read"
msgstr ""
-#: builtin/branch.c:638
+#: builtin/branch.c:682
msgid "cannot rename the current branch while not on any."
msgstr ""
-#: builtin/branch.c:648
+#: builtin/branch.c:692
#, c-format
msgid "Invalid branch name: '%s'"
msgstr ""
-#: builtin/branch.c:663
+#: builtin/branch.c:707
msgid "Branch rename failed"
msgstr ""
-#: builtin/branch.c:667
+#: builtin/branch.c:711
#, c-format
msgid "Renamed a misnamed branch '%s' away"
msgstr ""
-#: builtin/branch.c:671
+#: builtin/branch.c:715
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
msgstr ""
-#: builtin/branch.c:678
+#: builtin/branch.c:722
msgid "Branch is renamed, but update of config-file failed"
msgstr ""
-#: builtin/branch.c:693
+#: builtin/branch.c:737
#, c-format
msgid "malformed object name %s"
msgstr ""
-#: builtin/branch.c:717
+#: builtin/branch.c:761
#, c-format
msgid "could not write branch description template: %s"
msgstr ""
-#: builtin/branch.c:747
+#: builtin/branch.c:791
msgid "Generic options"
msgstr ""
-#: builtin/branch.c:749
+#: builtin/branch.c:793
msgid "show hash and subject, give twice for upstream branch"
msgstr ""
-#: builtin/branch.c:750
+#: builtin/branch.c:794
msgid "suppress informational messages"
msgstr ""
-#: builtin/branch.c:751
+#: builtin/branch.c:795
msgid "set up tracking mode (see git-pull(1))"
msgstr ""
-#: builtin/branch.c:753
+#: builtin/branch.c:797
msgid "change upstream info"
msgstr ""
-#: builtin/branch.c:757
+#: builtin/branch.c:801
msgid "use colored output"
msgstr ""
-#: builtin/branch.c:758
+#: builtin/branch.c:802
msgid "act on remote-tracking branches"
msgstr ""
-#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788
-#: builtin/branch.c:794 builtin/commit.c:1366 builtin/commit.c:1367
-#: builtin/commit.c:1368 builtin/commit.c:1369 builtin/tag.c:468
+#: builtin/branch.c:805 builtin/branch.c:811 builtin/branch.c:832
+#: builtin/branch.c:838 builtin/commit.c:1433 builtin/commit.c:1434
+#: builtin/commit.c:1435 builtin/commit.c:1436 builtin/tag.c:468
msgid "commit"
msgstr ""
-#: builtin/branch.c:762 builtin/branch.c:768
+#: builtin/branch.c:806 builtin/branch.c:812
msgid "print only branches that contain the commit"
msgstr ""
-#: builtin/branch.c:774
+#: builtin/branch.c:818
msgid "Specific git-branch actions:"
msgstr ""
-#: builtin/branch.c:775
+#: builtin/branch.c:819
msgid "list both remote-tracking and local branches"
msgstr ""
-#: builtin/branch.c:777
+#: builtin/branch.c:821
msgid "delete fully merged branch"
msgstr ""
-#: builtin/branch.c:778
+#: builtin/branch.c:822
msgid "delete branch (even if not merged)"
msgstr ""
-#: builtin/branch.c:779
+#: builtin/branch.c:823
msgid "move/rename a branch and its reflog"
msgstr ""
-#: builtin/branch.c:780
+#: builtin/branch.c:824
msgid "move/rename a branch, even if target exists"
msgstr ""
-#: builtin/branch.c:781
+#: builtin/branch.c:825
msgid "list branch names"
msgstr ""
-#: builtin/branch.c:782
+#: builtin/branch.c:826
msgid "create the branch's reflog"
msgstr ""
-#: builtin/branch.c:784
+#: builtin/branch.c:828
msgid "edit the description for the branch"
msgstr ""
-#: builtin/branch.c:785
+#: builtin/branch.c:829
msgid "force creation (when already exists)"
msgstr ""
-#: builtin/branch.c:788
+#: builtin/branch.c:832
msgid "print only not merged branches"
msgstr ""
-#: builtin/branch.c:794
+#: builtin/branch.c:838
msgid "print only merged branches"
msgstr ""
-#: builtin/branch.c:798
+#: builtin/branch.c:842
msgid "list branches in columns"
msgstr ""
-#: builtin/branch.c:811
+#: builtin/branch.c:855
msgid "Failed to resolve HEAD as a valid ref."
msgstr ""
-#: builtin/branch.c:816 builtin/clone.c:561
+#: builtin/branch.c:860 builtin/clone.c:630
msgid "HEAD not found below refs/heads!"
msgstr ""
-#: builtin/branch.c:839
+#: builtin/branch.c:883
msgid "--column and --verbose are incompatible"
msgstr ""
-#: builtin/branch.c:845
+#: builtin/branch.c:889 builtin/branch.c:928
msgid "branch name required"
msgstr ""
-#: builtin/branch.c:860
+#: builtin/branch.c:904
msgid "Cannot give description to detached HEAD"
msgstr ""
-#: builtin/branch.c:865
+#: builtin/branch.c:909
msgid "cannot edit description of more than one branch"
msgstr ""
-#: builtin/branch.c:872
+#: builtin/branch.c:916
#, c-format
msgid "No commit on branch '%s' yet."
msgstr ""
-#: builtin/branch.c:875
+#: builtin/branch.c:919
#, c-format
msgid "No branch named '%s'."
msgstr ""
-#: builtin/branch.c:888
+#: builtin/branch.c:934
msgid "too many branches for a rename operation"
msgstr ""
-#: builtin/branch.c:893
+#: builtin/branch.c:939
+msgid "too many branches to set new upstream"
+msgstr ""
+
+#: builtin/branch.c:943
+#, c-format
+msgid ""
+"could not set upstream of HEAD to %s when it does not point to any branch."
+msgstr ""
+
+#: builtin/branch.c:946 builtin/branch.c:968 builtin/branch.c:990
+#, c-format
+msgid "no such branch '%s'"
+msgstr ""
+
+#: builtin/branch.c:950
#, c-format
msgid "branch '%s' does not exist"
msgstr ""
-#: builtin/branch.c:905
+#: builtin/branch.c:962
+msgid "too many branches to unset upstream"
+msgstr ""
+
+#: builtin/branch.c:966
+msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgstr ""
+
+#: builtin/branch.c:972
#, c-format
msgid "Branch '%s' has no upstream information"
msgstr ""
-#: builtin/branch.c:920
+#: builtin/branch.c:987
+msgid "it does not make sense to create 'HEAD' manually"
+msgstr ""
+
+#: builtin/branch.c:993
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
msgstr ""
-#: builtin/branch.c:923
+#: builtin/branch.c:996
#, 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:940
+#: builtin/branch.c:1013
#, c-format
msgid ""
"\n"
@@ -2505,12 +2790,12 @@ msgid ""
"\n"
msgstr ""
-#: builtin/branch.c:941
+#: builtin/branch.c:1014
#, c-format
msgid " git branch -d %s\n"
msgstr ""
-#: builtin/branch.c:942
+#: builtin/branch.c:1015
#, c-format
msgid " git branch --set-upstream-to %s\n"
msgstr ""
@@ -2528,43 +2813,43 @@ msgstr ""
msgid "Need a repository to unbundle."
msgstr ""
-#: builtin/cat-file.c:247
+#: builtin/cat-file.c:285
msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
msgstr ""
-#: builtin/cat-file.c:248
+#: builtin/cat-file.c:286
msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
msgstr ""
-#: builtin/cat-file.c:266
+#: builtin/cat-file.c:323
msgid "<type> can be one of: blob, tree, commit, tag"
msgstr ""
-#: builtin/cat-file.c:267
+#: builtin/cat-file.c:324
msgid "show object type"
msgstr ""
-#: builtin/cat-file.c:268
+#: builtin/cat-file.c:325
msgid "show object size"
msgstr ""
-#: builtin/cat-file.c:270
+#: builtin/cat-file.c:327
msgid "exit with zero when there's no error"
msgstr ""
-#: builtin/cat-file.c:271
+#: builtin/cat-file.c:328
msgid "pretty-print object's content"
msgstr ""
-#: builtin/cat-file.c:273
+#: builtin/cat-file.c:330
msgid "for blob objects, run textconv on object's content"
msgstr ""
-#: builtin/cat-file.c:275
+#: builtin/cat-file.c:332
msgid "show info and content of objects fed from the standard input"
msgstr ""
-#: builtin/cat-file.c:278
+#: builtin/cat-file.c:335
msgid "show info about objects fed from the standard input"
msgstr ""
@@ -2592,30 +2877,55 @@ msgstr ""
msgid "input paths are terminated by a null character"
msgstr ""
-#: builtin/check-ignore.c:18 builtin/checkout.c:1012 builtin/gc.c:177
+#: builtin/check-ignore.c:18 builtin/checkout.c:1054 builtin/gc.c:177
msgid "suppress progress reporting"
msgstr ""
-#: builtin/check-ignore.c:151
+#: builtin/check-ignore.c:26
+msgid "show non-matching input paths"
+msgstr ""
+
+#: builtin/check-ignore.c:143
msgid "cannot specify pathnames with --stdin"
msgstr ""
-#: builtin/check-ignore.c:154
+#: builtin/check-ignore.c:146
msgid "-z only makes sense with --stdin"
msgstr ""
-#: builtin/check-ignore.c:156
+#: builtin/check-ignore.c:148
msgid "no path specified"
msgstr ""
-#: builtin/check-ignore.c:160
+#: builtin/check-ignore.c:152
msgid "--quiet is only valid with a single pathname"
msgstr ""
-#: builtin/check-ignore.c:162
+#: builtin/check-ignore.c:154
msgid "cannot have both --quiet and --verbose"
msgstr ""
+#: builtin/check-ignore.c:157
+msgid "--non-matching is only valid with --verbose"
+msgstr ""
+
+#: builtin/check-mailmap.c:8
+msgid "git check-mailmap [options] <contact>..."
+msgstr ""
+
+#: builtin/check-mailmap.c:13
+msgid "also read contacts from stdin"
+msgstr ""
+
+#: builtin/check-mailmap.c:24
+#, c-format
+msgid "unable to parse contact: %s"
+msgstr ""
+
+#: builtin/check-mailmap.c:47
+msgid "no contacts specified"
+msgstr ""
+
#: builtin/checkout-index.c:126
msgid "git checkout-index [options] [--] [<file>...]"
msgstr ""
@@ -2668,106 +2978,106 @@ msgstr ""
msgid "git checkout [options] [<branch>] -- <file>..."
msgstr ""
-#: builtin/checkout.c:116 builtin/checkout.c:149
+#: builtin/checkout.c:117 builtin/checkout.c:150
#, c-format
msgid "path '%s' does not have our version"
msgstr ""
-#: builtin/checkout.c:118 builtin/checkout.c:151
+#: builtin/checkout.c:119 builtin/checkout.c:152
#, c-format
msgid "path '%s' does not have their version"
msgstr ""
-#: builtin/checkout.c:134
+#: builtin/checkout.c:135
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr ""
-#: builtin/checkout.c:178
+#: builtin/checkout.c:179
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr ""
-#: builtin/checkout.c:195
+#: builtin/checkout.c:196
#, c-format
msgid "path '%s': cannot merge"
msgstr ""
-#: builtin/checkout.c:212
+#: builtin/checkout.c:213
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr ""
-#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
-#: builtin/checkout.c:245
+#: builtin/checkout.c:237 builtin/checkout.c:240 builtin/checkout.c:243
+#: builtin/checkout.c:246
#, c-format
msgid "'%s' cannot be used with updating paths"
msgstr ""
-#: builtin/checkout.c:248 builtin/checkout.c:251
+#: builtin/checkout.c:249 builtin/checkout.c:252
#, c-format
msgid "'%s' cannot be used with %s"
msgstr ""
-#: builtin/checkout.c:254
+#: builtin/checkout.c:255
#, c-format
msgid "Cannot update paths and switch to branch '%s' at the same time."
msgstr ""
-#: builtin/checkout.c:265 builtin/checkout.c:426
+#: builtin/checkout.c:266 builtin/checkout.c:458
msgid "corrupt index file"
msgstr ""
-#: builtin/checkout.c:295 builtin/checkout.c:302
+#: builtin/checkout.c:329 builtin/checkout.c:336
#, c-format
msgid "path '%s' is unmerged"
msgstr ""
-#: builtin/checkout.c:448
+#: builtin/checkout.c:480
msgid "you need to resolve your current index first"
msgstr ""
-#: builtin/checkout.c:569
+#: builtin/checkout.c:601
#, c-format
msgid "Can not do reflog for '%s'\n"
msgstr ""
-#: builtin/checkout.c:602
+#: builtin/checkout.c:639
msgid "HEAD is now at"
msgstr ""
-#: builtin/checkout.c:609
+#: builtin/checkout.c:646
#, c-format
msgid "Reset branch '%s'\n"
msgstr ""
-#: builtin/checkout.c:612
+#: builtin/checkout.c:649
#, c-format
msgid "Already on '%s'\n"
msgstr ""
-#: builtin/checkout.c:616
+#: builtin/checkout.c:653
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr ""
-#: builtin/checkout.c:618 builtin/checkout.c:955
+#: builtin/checkout.c:655 builtin/checkout.c:997
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr ""
-#: builtin/checkout.c:620
+#: builtin/checkout.c:657
#, c-format
msgid "Switched to branch '%s'\n"
msgstr ""
-#: builtin/checkout.c:676
+#: builtin/checkout.c:713
#, c-format
msgid " ... and %d more.\n"
msgstr ""
#. The singular version
-#: builtin/checkout.c:682
+#: builtin/checkout.c:719
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -2782,7 +3092,7 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: builtin/checkout.c:700
+#: builtin/checkout.c:737
#, c-format
msgid ""
"If you want to keep them by creating a new branch, this may be a good time\n"
@@ -2792,228 +3102,315 @@ msgid ""
"\n"
msgstr ""
-#: builtin/checkout.c:730
+#: builtin/checkout.c:767
msgid "internal error in revision walk"
msgstr ""
-#: builtin/checkout.c:734
+#: builtin/checkout.c:771
msgid "Previous HEAD position was"
msgstr ""
-#: builtin/checkout.c:761 builtin/checkout.c:950
+#: builtin/checkout.c:798 builtin/checkout.c:992
msgid "You are on a branch yet to be born"
msgstr ""
#. case (1)
-#: builtin/checkout.c:886
+#: builtin/checkout.c:928
#, c-format
msgid "invalid reference: %s"
msgstr ""
#. case (1): want a tree
-#: builtin/checkout.c:925
+#: builtin/checkout.c:967
#, c-format
msgid "reference is not a tree: %s"
msgstr ""
-#: builtin/checkout.c:964
+#: builtin/checkout.c:1006
msgid "paths cannot be used with switching branches"
msgstr ""
-#: builtin/checkout.c:967 builtin/checkout.c:971
+#: builtin/checkout.c:1009 builtin/checkout.c:1013
#, c-format
msgid "'%s' cannot be used with switching branches"
msgstr ""
-#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983
-#: builtin/checkout.c:986
+#: builtin/checkout.c:1017 builtin/checkout.c:1020 builtin/checkout.c:1025
+#: builtin/checkout.c:1028
#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr ""
-#: builtin/checkout.c:991
+#: builtin/checkout.c:1033
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
msgstr ""
-#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89
+#: builtin/checkout.c:1055 builtin/checkout.c:1057 builtin/clone.c:89
#: builtin/remote.c:169 builtin/remote.c:171
msgid "branch"
msgstr ""
-#: builtin/checkout.c:1014
+#: builtin/checkout.c:1056
msgid "create and checkout a new branch"
msgstr ""
-#: builtin/checkout.c:1016
+#: builtin/checkout.c:1058
msgid "create/reset and checkout a branch"
msgstr ""
-#: builtin/checkout.c:1017
+#: builtin/checkout.c:1059
msgid "create reflog for new branch"
msgstr ""
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1060
msgid "detach the HEAD at named commit"
msgstr ""
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1061
msgid "set upstream info for new branch"
msgstr ""
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new branch"
msgstr ""
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new unparented branch"
msgstr ""
-#: builtin/checkout.c:1022
+#: builtin/checkout.c:1064
msgid "checkout our version for unmerged files"
msgstr ""
-#: builtin/checkout.c:1024
+#: builtin/checkout.c:1066
msgid "checkout their version for unmerged files"
msgstr ""
-#: builtin/checkout.c:1026
+#: builtin/checkout.c:1068
msgid "force checkout (throw away local modifications)"
msgstr ""
-#: builtin/checkout.c:1027
+#: builtin/checkout.c:1069
msgid "perform a 3-way merge with the new branch"
msgstr ""
-#: builtin/checkout.c:1028 builtin/merge.c:215
+#: builtin/checkout.c:1070 builtin/merge.c:232
msgid "update ignored files (default)"
msgstr ""
-#: builtin/checkout.c:1029 builtin/log.c:1147 parse-options.h:245
+#: builtin/checkout.c:1071 builtin/log.c:1208 parse-options.h:249
msgid "style"
msgstr ""
-#: builtin/checkout.c:1030
+#: builtin/checkout.c:1072
msgid "conflict style (merge or diff3)"
msgstr ""
-#: builtin/checkout.c:1033
+#: builtin/checkout.c:1075
+msgid "do not limit pathspecs to sparse entries only"
+msgstr ""
+
+#: builtin/checkout.c:1077
msgid "second guess 'git checkout no-such-branch'"
msgstr ""
-#: builtin/checkout.c:1057
+#: builtin/checkout.c:1101
msgid "-b, -B and --orphan are mutually exclusive"
msgstr ""
-#: builtin/checkout.c:1074
+#: builtin/checkout.c:1118
msgid "--track needs a branch name"
msgstr ""
-#: builtin/checkout.c:1081
+#: builtin/checkout.c:1125
msgid "Missing branch name; try -b"
msgstr ""
-#: builtin/checkout.c:1116
+#: builtin/checkout.c:1160
msgid "invalid path specification"
msgstr ""
-#: builtin/checkout.c:1123
+#: builtin/checkout.c:1167
#, c-format
msgid ""
"Cannot update paths and switch to branch '%s' at the same time.\n"
"Did you intend to checkout '%s' which can not be resolved as commit?"
msgstr ""
-#: builtin/checkout.c:1128
+#: builtin/checkout.c:1172
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
msgstr ""
-#: builtin/checkout.c:1132
+#: builtin/checkout.c:1176
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
msgstr ""
-#: builtin/clean.c:20
-msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+#: builtin/clean.c:25
+msgid ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
msgstr ""
-#: builtin/clean.c:24
+#: builtin/clean.c:29
#, c-format
msgid "Removing %s\n"
msgstr ""
-#: builtin/clean.c:25
+#: builtin/clean.c:30
#, c-format
msgid "Would remove %s\n"
msgstr ""
-#: builtin/clean.c:26
+#: builtin/clean.c:31
#, c-format
msgid "Skipping repository %s\n"
msgstr ""
-#: builtin/clean.c:27
+#: builtin/clean.c:32
#, c-format
msgid "Would skip repository %s\n"
msgstr ""
-#: builtin/clean.c:28
+#: builtin/clean.c:33
#, c-format
msgid "failed to remove %s"
msgstr ""
-#: builtin/clean.c:160
+#: builtin/clean.c:293
+msgid ""
+"Prompt help:\n"
+"1 - select a numbered item\n"
+"foo - select item based on unique prefix\n"
+" - (empty) select nothing"
+msgstr ""
+
+#: builtin/clean.c:297
+msgid ""
+"Prompt help:\n"
+"1 - select a single item\n"
+"3-5 - select a range of items\n"
+"2-3,6-9 - select multiple ranges\n"
+"foo - select item based on unique prefix\n"
+"-... - unselect specified items\n"
+"* - choose all items\n"
+" - (empty) finish selecting"
+msgstr ""
+
+#: builtin/clean.c:515
+#, c-format
+msgid "Huh (%s)?"
+msgstr ""
+
+#: builtin/clean.c:658
+#, c-format
+msgid "Input ignore patterns>> "
+msgstr ""
+
+#: builtin/clean.c:695
+#, c-format
+msgid "WARNING: Cannot find items matched by: %s"
+msgstr ""
+
+#: builtin/clean.c:716
+msgid "Select items to delete"
+msgstr ""
+
+#: builtin/clean.c:756
+#, c-format
+msgid "remove %s? "
+msgstr ""
+
+#: builtin/clean.c:781
+msgid "Bye."
+msgstr ""
+
+#: builtin/clean.c:789
+msgid ""
+"clean - start cleaning\n"
+"filter by pattern - exclude items from deletion\n"
+"select by numbers - select items to be deleted by numbers\n"
+"ask each - confirm each deletion (like \"rm -i\")\n"
+"quit - stop cleaning\n"
+"help - this screen\n"
+"? - help for prompt selection"
+msgstr ""
+
+#: builtin/clean.c:816
+msgid "*** Commands ***"
+msgstr ""
+
+#: builtin/clean.c:817
+msgid "What now"
+msgstr ""
+
+#: builtin/clean.c:825
+msgid "Would remove the following item:"
+msgid_plural "Would remove the following items:"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/clean.c:842
+msgid "No more files to clean, exiting."
+msgstr ""
+
+#: builtin/clean.c:874
msgid "do not print names of files removed"
msgstr ""
-#: builtin/clean.c:162
+#: builtin/clean.c:876
msgid "force"
msgstr ""
-#: builtin/clean.c:164
+#: builtin/clean.c:877
+msgid "interactive cleaning"
+msgstr ""
+
+#: builtin/clean.c:879
msgid "remove whole directories"
msgstr ""
-#: builtin/clean.c:165 builtin/describe.c:413 builtin/grep.c:717
-#: builtin/ls-files.c:494 builtin/name-rev.c:231 builtin/show-ref.c:182
+#: builtin/clean.c:880 builtin/describe.c:420 builtin/grep.c:716
+#: builtin/ls-files.c:493 builtin/name-rev.c:315 builtin/show-ref.c:186
msgid "pattern"
msgstr ""
-#: builtin/clean.c:166
+#: builtin/clean.c:881
msgid "add <pattern> to ignore rules"
msgstr ""
-#: builtin/clean.c:167
+#: builtin/clean.c:882
msgid "remove ignored files, too"
msgstr ""
-#: builtin/clean.c:169
+#: builtin/clean.c:884
msgid "remove only ignored files"
msgstr ""
-#: builtin/clean.c:187
+#: builtin/clean.c:902
msgid "-x and -X cannot be used together"
msgstr ""
-#: builtin/clean.c:191
+#: builtin/clean.c:906
msgid ""
-"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+"clean.requireForce set to true and neither -i, -n nor -f given; refusing to "
+"clean"
msgstr ""
-#: builtin/clean.c:194
+#: builtin/clean.c:909
msgid ""
-"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
-"clean"
+"clean.requireForce defaults to true and neither -i, -n nor -f given; "
+"refusing to clean"
msgstr ""
#: 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:436
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:229
+#: builtin/push.c:462
msgid "force progress reporting"
msgstr ""
@@ -3073,7 +3470,7 @@ msgstr ""
msgid "path to git-upload-pack on the remote"
msgstr ""
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:661
msgid "depth"
msgstr ""
@@ -3101,122 +3498,151 @@ msgstr ""
msgid "set config inside the new repository"
msgstr ""
-#: builtin/clone.c:243
+#: builtin/clone.c:253
#, c-format
-msgid "reference repository '%s' is not a local directory."
+msgid "reference repository '%s' is not a local repository."
msgstr ""
-#: builtin/clone.c:306
+#: builtin/clone.c:316
#, c-format
msgid "failed to create directory '%s'"
msgstr ""
-#: builtin/clone.c:308 builtin/diff.c:77
+#: builtin/clone.c:318 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
msgstr ""
-#: builtin/clone.c:310
+#: builtin/clone.c:320
#, c-format
msgid "%s exists and is not a directory"
msgstr ""
-#: builtin/clone.c:324
+#: builtin/clone.c:334
#, c-format
msgid "failed to stat %s\n"
msgstr ""
-#: builtin/clone.c:346
+#: builtin/clone.c:356
#, c-format
msgid "failed to create link '%s'"
msgstr ""
-#: builtin/clone.c:350
+#: builtin/clone.c:360
#, c-format
msgid "failed to copy file to '%s'"
msgstr ""
-#: builtin/clone.c:373
+#: builtin/clone.c:383
#, c-format
msgid "done.\n"
msgstr ""
-#: builtin/clone.c:443
+#: builtin/clone.c:396
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry the checkout with 'git checkout -f HEAD'\n"
+msgstr ""
+
+#: builtin/clone.c:475
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr ""
-#: builtin/clone.c:552
+#: builtin/clone.c:555
+#, c-format
+msgid "Checking connectivity... "
+msgstr ""
+
+#: builtin/clone.c:558
+msgid "remote did not send all necessary objects"
+msgstr ""
+
+#: builtin/clone.c:560
+#, c-format
+msgid "done\n"
+msgstr ""
+
+#: builtin/clone.c:621
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
msgstr ""
-#: builtin/clone.c:690
+#: builtin/clone.c:652
+msgid "unable to checkout working tree"
+msgstr ""
+
+#: builtin/clone.c:760
msgid "Too many arguments."
msgstr ""
-#: builtin/clone.c:694
+#: builtin/clone.c:764
msgid "You must specify a repository to clone."
msgstr ""
-#: builtin/clone.c:705
+#: builtin/clone.c:775
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr ""
-#: builtin/clone.c:708
+#: builtin/clone.c:778
msgid "--bare and --separate-git-dir are incompatible."
msgstr ""
-#: builtin/clone.c:721
+#: builtin/clone.c:791
#, c-format
msgid "repository '%s' does not exist"
msgstr ""
-#: builtin/clone.c:726
+#: builtin/clone.c:796
msgid "--depth is ignored in local clones; use file:// instead."
msgstr ""
-#: builtin/clone.c:736
+#: builtin/clone.c:798
+msgid "--local is ignored"
+msgstr ""
+
+#: builtin/clone.c:808
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr ""
-#: builtin/clone.c:746
+#: builtin/clone.c:818
#, c-format
msgid "working tree '%s' already exists."
msgstr ""
-#: builtin/clone.c:759 builtin/clone.c:771
+#: builtin/clone.c:831 builtin/clone.c:843
#, c-format
msgid "could not create leading directories of '%s'"
msgstr ""
-#: builtin/clone.c:762
+#: builtin/clone.c:834
#, c-format
msgid "could not create work tree dir '%s'."
msgstr ""
-#: builtin/clone.c:781
+#: builtin/clone.c:853
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr ""
-#: builtin/clone.c:783
+#: builtin/clone.c:855
#, c-format
msgid "Cloning into '%s'...\n"
msgstr ""
-#: builtin/clone.c:818
+#: builtin/clone.c:890
#, c-format
msgid "Don't know how to clone %s"
msgstr ""
-#: builtin/clone.c:867
+#: builtin/clone.c:942
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr ""
-#: builtin/clone.c:874
+#: builtin/clone.c:949
msgid "You appear to have cloned an empty repository."
msgstr ""
@@ -3252,15 +3678,15 @@ msgstr ""
msgid "--command must be the first argument"
msgstr ""
-#: builtin/commit.c:34
+#: builtin/commit.c:35
msgid "git commit [options] [--] <pathspec>..."
msgstr ""
-#: builtin/commit.c:39
+#: builtin/commit.c:40
msgid "git status [options] [--] <pathspec>..."
msgstr ""
-#: builtin/commit.c:44
+#: builtin/commit.c:45
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
@@ -3274,110 +3700,123 @@ msgid ""
" git commit --amend --reset-author\n"
msgstr ""
-#: builtin/commit.c:56
+#: builtin/commit.c:57
msgid ""
"You asked to amend the most recent commit, but doing so would make\n"
"it empty. You can repeat your command with --allow-empty, or you can\n"
"remove the commit entirely with \"git reset HEAD^\".\n"
msgstr ""
-#: builtin/commit.c:61
+#: builtin/commit.c:62
msgid ""
"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
"If you wish to commit it anyway, use:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Otherwise, please use 'git reset'\n"
msgstr ""
-#: builtin/commit.c:258
+#: builtin/commit.c:69
+msgid "Otherwise, please use 'git reset'\n"
+msgstr ""
+
+#: builtin/commit.c:72
+msgid ""
+"If you wish to skip this commit, use:\n"
+"\n"
+" git reset\n"
+"\n"
+"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
+"the remaining commits.\n"
+msgstr ""
+
+#: builtin/commit.c:279
msgid "failed to unpack HEAD tree object"
msgstr ""
-#: builtin/commit.c:300
+#: builtin/commit.c:321
msgid "unable to create temporary index"
msgstr ""
-#: builtin/commit.c:306
+#: builtin/commit.c:327
msgid "interactive add failed"
msgstr ""
-#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410
+#: builtin/commit.c:360 builtin/commit.c:381 builtin/commit.c:431
msgid "unable to write new_index file"
msgstr ""
-#: builtin/commit.c:391
+#: builtin/commit.c:412
msgid "cannot do a partial commit during a merge."
msgstr ""
-#: builtin/commit.c:393
+#: builtin/commit.c:414
msgid "cannot do a partial commit during a cherry-pick."
msgstr ""
-#: builtin/commit.c:403
+#: builtin/commit.c:424
msgid "cannot read the index"
msgstr ""
-#: builtin/commit.c:423
+#: builtin/commit.c:444
msgid "unable to write temporary index file"
msgstr ""
-#: builtin/commit.c:511 builtin/commit.c:517
+#: builtin/commit.c:535 builtin/commit.c:541
#, c-format
msgid "invalid commit: %s"
msgstr ""
-#: builtin/commit.c:540
+#: builtin/commit.c:563
msgid "malformed --author parameter"
msgstr ""
-#: builtin/commit.c:560
+#: builtin/commit.c:583
#, c-format
msgid "Malformed ident string: '%s'"
msgstr ""
-#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954
+#: builtin/commit.c:621 builtin/commit.c:654 builtin/commit.c:982
#, c-format
msgid "could not lookup commit %s"
msgstr ""
-#: builtin/commit.c:610 builtin/shortlog.c:272
+#: builtin/commit.c:633 builtin/shortlog.c:271
#, c-format
msgid "(reading log message from standard input)\n"
msgstr ""
-#: builtin/commit.c:612
+#: builtin/commit.c:635
msgid "could not read log from standard input"
msgstr ""
-#: builtin/commit.c:616
+#: builtin/commit.c:639
#, c-format
msgid "could not read log file '%s'"
msgstr ""
-#: builtin/commit.c:622
+#: builtin/commit.c:645
msgid "commit has empty message"
msgstr ""
-#: builtin/commit.c:638
+#: builtin/commit.c:661
msgid "could not read MERGE_MSG"
msgstr ""
-#: builtin/commit.c:642
+#: builtin/commit.c:665
msgid "could not read SQUASH_MSG"
msgstr ""
-#: builtin/commit.c:646
+#: builtin/commit.c:669
#, c-format
msgid "could not read '%s'"
msgstr ""
-#: builtin/commit.c:707
+#: builtin/commit.c:730
msgid "could not write commit template"
msgstr ""
-#: builtin/commit.c:718
+#: builtin/commit.c:741
#, c-format
msgid ""
"\n"
@@ -3387,7 +3826,7 @@ msgid ""
"and try again.\n"
msgstr ""
-#: builtin/commit.c:723
+#: builtin/commit.c:746
#, c-format
msgid ""
"\n"
@@ -3397,14 +3836,14 @@ msgid ""
"and try again.\n"
msgstr ""
-#: builtin/commit.c:735
+#: builtin/commit.c:758
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '%c' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
-#: builtin/commit.c:740
+#: builtin/commit.c:763
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
@@ -3412,351 +3851,351 @@ msgid ""
"An empty message aborts the commit.\n"
msgstr ""
-#: builtin/commit.c:753
+#: builtin/commit.c:776
#, c-format
msgid "%sAuthor: %s"
msgstr ""
-#: builtin/commit.c:760
+#: builtin/commit.c:783
#, c-format
msgid "%sCommitter: %s"
msgstr ""
-#: builtin/commit.c:780
+#: builtin/commit.c:803
msgid "Cannot read index"
msgstr ""
-#: builtin/commit.c:817
+#: builtin/commit.c:845
msgid "Error building trees"
msgstr ""
-#: builtin/commit.c:832 builtin/tag.c:359
+#: builtin/commit.c:860 builtin/tag.c:359
#, c-format
msgid "Please supply the message using either -m or -F option.\n"
msgstr ""
-#: builtin/commit.c:929
+#: builtin/commit.c:957
#, c-format
msgid "No existing author found with '%s'"
msgstr ""
-#: builtin/commit.c:944 builtin/commit.c:1138
+#: builtin/commit.c:972 builtin/commit.c:1208
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr ""
-#: builtin/commit.c:974
+#: builtin/commit.c:1009
+msgid "--long and -z are incompatible"
+msgstr ""
+
+#: builtin/commit.c:1039
msgid "Using both --reset-author and --author does not make sense"
msgstr ""
-#: builtin/commit.c:985
+#: builtin/commit.c:1050
msgid "You have nothing to amend."
msgstr ""
-#: builtin/commit.c:988
+#: builtin/commit.c:1053
msgid "You are in the middle of a merge -- cannot amend."
msgstr ""
-#: builtin/commit.c:990
+#: builtin/commit.c:1055
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr ""
-#: builtin/commit.c:993
+#: builtin/commit.c:1058
msgid "Options --squash and --fixup cannot be used together"
msgstr ""
-#: builtin/commit.c:1003
+#: builtin/commit.c:1068
msgid "Only one of -c/-C/-F/--fixup can be used."
msgstr ""
-#: builtin/commit.c:1005
+#: builtin/commit.c:1070
msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
msgstr ""
-#: builtin/commit.c:1013
+#: builtin/commit.c:1078
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr ""
-#: builtin/commit.c:1030
+#: builtin/commit.c:1095
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
msgstr ""
-#: builtin/commit.c:1032
+#: builtin/commit.c:1097
msgid "No paths with --include/--only does not make sense."
msgstr ""
-#: builtin/commit.c:1034
+#: builtin/commit.c:1099
msgid "Clever... amending the last one with dirty index."
msgstr ""
-#: builtin/commit.c:1036
+#: builtin/commit.c:1101
msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
msgstr ""
-#: builtin/commit.c:1046 builtin/tag.c:575
+#: builtin/commit.c:1111 builtin/tag.c:575
#, c-format
msgid "Invalid cleanup mode %s"
msgstr ""
-#: builtin/commit.c:1051
+#: builtin/commit.c:1116
msgid "Paths with -a does not make sense."
msgstr ""
-#: builtin/commit.c:1057 builtin/commit.c:1192
-msgid "--long and -z are incompatible"
-msgstr ""
-
-#: builtin/commit.c:1152 builtin/commit.c:1388
+#: builtin/commit.c:1222 builtin/commit.c:1455
msgid "show status concisely"
msgstr ""
-#: builtin/commit.c:1154 builtin/commit.c:1390
+#: builtin/commit.c:1224 builtin/commit.c:1457
msgid "show branch information"
msgstr ""
-#: builtin/commit.c:1156 builtin/commit.c:1392 builtin/push.c:426
+#: builtin/commit.c:1226 builtin/commit.c:1459 builtin/push.c:452
msgid "machine-readable output"
msgstr ""
-#: builtin/commit.c:1159 builtin/commit.c:1394
+#: builtin/commit.c:1229 builtin/commit.c:1461
msgid "show status in long format (default)"
msgstr ""
-#: builtin/commit.c:1162 builtin/commit.c:1397
+#: builtin/commit.c:1232 builtin/commit.c:1464
msgid "terminate entries with NUL"
msgstr ""
-#: builtin/commit.c:1164 builtin/commit.c:1400 builtin/fast-export.c:647
-#: builtin/fast-export.c:650 builtin/tag.c:459
+#: builtin/commit.c:1234 builtin/commit.c:1467 builtin/fast-export.c:667
+#: builtin/fast-export.c:670 builtin/tag.c:459
msgid "mode"
msgstr ""
-#: builtin/commit.c:1165 builtin/commit.c:1400
+#: builtin/commit.c:1235 builtin/commit.c:1467
msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
msgstr ""
-#: builtin/commit.c:1168
+#: builtin/commit.c:1238
msgid "show ignored files"
msgstr ""
-#: builtin/commit.c:1169 parse-options.h:151
+#: builtin/commit.c:1239 parse-options.h:154
msgid "when"
msgstr ""
-#: builtin/commit.c:1170
+#: builtin/commit.c:1240
msgid ""
"ignore changes to submodules, optional when: all, dirty, untracked. "
"(Default: all)"
msgstr ""
-#: builtin/commit.c:1172
+#: builtin/commit.c:1242
msgid "list untracked files in columns"
msgstr ""
-#: builtin/commit.c:1246
+#: builtin/commit.c:1313
msgid "couldn't look up newly created commit"
msgstr ""
-#: builtin/commit.c:1248
+#: builtin/commit.c:1315
msgid "could not parse newly created commit"
msgstr ""
-#: builtin/commit.c:1289
+#: builtin/commit.c:1356
msgid "detached HEAD"
msgstr ""
-#: builtin/commit.c:1291
+#: builtin/commit.c:1358
msgid " (root-commit)"
msgstr ""
-#: builtin/commit.c:1358
+#: builtin/commit.c:1425
msgid "suppress summary after successful commit"
msgstr ""
-#: builtin/commit.c:1359
+#: builtin/commit.c:1426
msgid "show diff in commit message template"
msgstr ""
-#: builtin/commit.c:1361
+#: builtin/commit.c:1428
msgid "Commit message options"
msgstr ""
-#: builtin/commit.c:1362 builtin/tag.c:457
+#: builtin/commit.c:1429 builtin/tag.c:457
msgid "read message from file"
msgstr ""
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "author"
msgstr ""
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "override author for commit"
msgstr ""
-#: builtin/commit.c:1364 builtin/gc.c:178
+#: builtin/commit.c:1431 builtin/gc.c:178
msgid "date"
msgstr ""
-#: builtin/commit.c:1364
+#: builtin/commit.c:1431
msgid "override date for commit"
msgstr ""
-#: builtin/commit.c:1365 builtin/merge.c:206 builtin/notes.c:533
-#: builtin/notes.c:690 builtin/tag.c:455
+#: builtin/commit.c:1432 builtin/merge.c:223 builtin/notes.c:405
+#: builtin/notes.c:562 builtin/tag.c:455
msgid "message"
msgstr ""
-#: builtin/commit.c:1365
+#: builtin/commit.c:1432
msgid "commit message"
msgstr ""
-#: builtin/commit.c:1366
+#: builtin/commit.c:1433
msgid "reuse and edit message from specified commit"
msgstr ""
-#: builtin/commit.c:1367
+#: builtin/commit.c:1434
msgid "reuse message from specified commit"
msgstr ""
-#: builtin/commit.c:1368
+#: builtin/commit.c:1435
msgid "use autosquash formatted message to fixup specified commit"
msgstr ""
-#: builtin/commit.c:1369
+#: builtin/commit.c:1436
msgid "use autosquash formatted message to squash specified commit"
msgstr ""
-#: builtin/commit.c:1370
+#: builtin/commit.c:1437
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr ""
-#: builtin/commit.c:1371 builtin/log.c:1102 builtin/revert.c:109
+#: builtin/commit.c:1438 builtin/log.c:1160 builtin/revert.c:111
msgid "add Signed-off-by:"
msgstr ""
-#: builtin/commit.c:1372
+#: builtin/commit.c:1439
msgid "use specified template file"
msgstr ""
-#: builtin/commit.c:1373
+#: builtin/commit.c:1440
msgid "force edit of commit"
msgstr ""
-#: builtin/commit.c:1374
+#: builtin/commit.c:1441
msgid "default"
msgstr ""
-#: builtin/commit.c:1374 builtin/tag.c:460
+#: builtin/commit.c:1441 builtin/tag.c:460
msgid "how to strip spaces and #comments from message"
msgstr ""
-#: builtin/commit.c:1375
+#: builtin/commit.c:1442
msgid "include status in commit message template"
msgstr ""
-#: builtin/commit.c:1376 builtin/merge.c:213 builtin/tag.c:461
+#: builtin/commit.c:1443 builtin/merge.c:230 builtin/tag.c:461
msgid "key id"
msgstr ""
-#: builtin/commit.c:1377 builtin/merge.c:214
+#: builtin/commit.c:1444 builtin/merge.c:231
msgid "GPG sign commit"
msgstr ""
#. end commit message options
-#: builtin/commit.c:1380
+#: builtin/commit.c:1447
msgid "Commit contents options"
msgstr ""
-#: builtin/commit.c:1381
+#: builtin/commit.c:1448
msgid "commit all changed files"
msgstr ""
-#: builtin/commit.c:1382
+#: builtin/commit.c:1449
msgid "add specified files to index for commit"
msgstr ""
-#: builtin/commit.c:1383
+#: builtin/commit.c:1450
msgid "interactively add files"
msgstr ""
-#: builtin/commit.c:1384
+#: builtin/commit.c:1451
msgid "interactively add changes"
msgstr ""
-#: builtin/commit.c:1385
+#: builtin/commit.c:1452
msgid "commit only specified files"
msgstr ""
-#: builtin/commit.c:1386
+#: builtin/commit.c:1453
msgid "bypass pre-commit hook"
msgstr ""
-#: builtin/commit.c:1387
+#: builtin/commit.c:1454
msgid "show what would be committed"
msgstr ""
-#: builtin/commit.c:1398
+#: builtin/commit.c:1465
msgid "amend previous commit"
msgstr ""
-#: builtin/commit.c:1399
+#: builtin/commit.c:1466
msgid "bypass post-rewrite hook"
msgstr ""
-#: builtin/commit.c:1404
+#: builtin/commit.c:1471
msgid "ok to record an empty change"
msgstr ""
-#: builtin/commit.c:1407
+#: builtin/commit.c:1474
msgid "ok to record a change with an empty message"
msgstr ""
-#: builtin/commit.c:1439
+#: builtin/commit.c:1507
msgid "could not parse HEAD commit"
msgstr ""
-#: builtin/commit.c:1477 builtin/merge.c:508
+#: builtin/commit.c:1545 builtin/merge.c:525
#, c-format
msgid "could not open '%s' for reading"
msgstr ""
-#: builtin/commit.c:1484
+#: builtin/commit.c:1552
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr ""
-#: builtin/commit.c:1491
+#: builtin/commit.c:1559
msgid "could not read MERGE_MODE"
msgstr ""
-#: builtin/commit.c:1510
+#: builtin/commit.c:1578
#, c-format
msgid "could not read commit message: %s"
msgstr ""
-#: builtin/commit.c:1524
+#: builtin/commit.c:1592
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr ""
-#: builtin/commit.c:1529
+#: builtin/commit.c:1597
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr ""
-#: builtin/commit.c:1544 builtin/merge.c:832 builtin/merge.c:857
+#: builtin/commit.c:1612 builtin/merge.c:861 builtin/merge.c:886
msgid "failed to write commit object"
msgstr ""
-#: builtin/commit.c:1565
+#: builtin/commit.c:1633
msgid "cannot lock HEAD ref"
msgstr ""
-#: builtin/commit.c:1569
+#: builtin/commit.c:1637
msgid "cannot update HEAD ref"
msgstr ""
-#: builtin/commit.c:1580
+#: builtin/commit.c:1648
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
@@ -3767,249 +4206,265 @@ msgstr ""
msgid "git config [options]"
msgstr ""
-#: builtin/config.c:51
+#: builtin/config.c:52
msgid "Config file location"
msgstr ""
-#: builtin/config.c:52
+#: builtin/config.c:53
msgid "use global config file"
msgstr ""
-#: builtin/config.c:53
+#: builtin/config.c:54
msgid "use system config file"
msgstr ""
-#: builtin/config.c:54
+#: builtin/config.c:55
msgid "use repository config file"
msgstr ""
-#: builtin/config.c:55
+#: builtin/config.c:56
msgid "use given config file"
msgstr ""
-#: builtin/config.c:56
-msgid "Action"
+#: builtin/config.c:57
+msgid "blob-id"
msgstr ""
#: builtin/config.c:57
-msgid "get value: name [value-regex]"
+msgid "read config from given blob object"
msgstr ""
#: builtin/config.c:58
-msgid "get all values: key [value-regex]"
+msgid "Action"
msgstr ""
#: builtin/config.c:59
-msgid "get values for regexp: name-regex [value-regex]"
+msgid "get value: name [value-regex]"
msgstr ""
#: builtin/config.c:60
-msgid "replace all matching variables: name value [value_regex]"
+msgid "get all values: key [value-regex]"
msgstr ""
#: builtin/config.c:61
-msgid "add a new variable: name value"
+msgid "get values for regexp: name-regex [value-regex]"
msgstr ""
#: builtin/config.c:62
-msgid "remove a variable: name [value-regex]"
+msgid "replace all matching variables: name value [value_regex]"
msgstr ""
#: builtin/config.c:63
-msgid "remove all matches: name [value-regex]"
+msgid "add a new variable: name value"
msgstr ""
#: builtin/config.c:64
-msgid "rename section: old-name new-name"
+msgid "remove a variable: name [value-regex]"
msgstr ""
#: builtin/config.c:65
-msgid "remove a section: name"
+msgid "remove all matches: name [value-regex]"
msgstr ""
#: builtin/config.c:66
-msgid "list all"
+msgid "rename section: old-name new-name"
msgstr ""
#: builtin/config.c:67
+msgid "remove a section: name"
+msgstr ""
+
+#: builtin/config.c:68
+msgid "list all"
+msgstr ""
+
+#: builtin/config.c:69
msgid "open an editor"
msgstr ""
-#: builtin/config.c:68 builtin/config.c:69
+#: builtin/config.c:70 builtin/config.c:71
msgid "slot"
msgstr ""
-#: builtin/config.c:68
+#: builtin/config.c:70
msgid "find the color configured: [default]"
msgstr ""
-#: builtin/config.c:69
+#: builtin/config.c:71
msgid "find the color setting: [stdout-is-tty]"
msgstr ""
-#: builtin/config.c:70
+#: builtin/config.c:72
msgid "Type"
msgstr ""
-#: builtin/config.c:71
+#: builtin/config.c:73
msgid "value is \"true\" or \"false\""
msgstr ""
-#: builtin/config.c:72
+#: builtin/config.c:74
msgid "value is decimal number"
msgstr ""
-#: builtin/config.c:73
+#: builtin/config.c:75
msgid "value is --bool or --int"
msgstr ""
-#: builtin/config.c:74
+#: builtin/config.c:76
msgid "value is a path (file or directory name)"
msgstr ""
-#: builtin/config.c:75
+#: builtin/config.c:77
msgid "Other"
msgstr ""
-#: builtin/config.c:76
+#: builtin/config.c:78
msgid "terminate values with NUL byte"
msgstr ""
-#: builtin/config.c:77
+#: builtin/config.c:79
msgid "respect include directives on lookup"
msgstr ""
-#: builtin/count-objects.c:69
-msgid "git count-objects [-v]"
+#: builtin/count-objects.c:82
+msgid "git count-objects [-v] [-H | --human-readable]"
msgstr ""
-#: builtin/describe.c:15
-msgid "git describe [options] <committish>*"
+#: builtin/count-objects.c:97
+msgid "print sizes in human readable format"
msgstr ""
#: builtin/describe.c:16
+msgid "git describe [options] <committish>*"
+msgstr ""
+
+#: builtin/describe.c:17
msgid "git describe [options] --dirty"
msgstr ""
-#: builtin/describe.c:234
+#: builtin/describe.c:237
#, c-format
msgid "annotated tag %s not available"
msgstr ""
-#: builtin/describe.c:238
+#: builtin/describe.c:241
#, c-format
msgid "annotated tag %s has no embedded name"
msgstr ""
-#: builtin/describe.c:240
+#: builtin/describe.c:243
#, c-format
msgid "tag '%s' is really '%s' here"
msgstr ""
-#: builtin/describe.c:267
+#: builtin/describe.c:270
#, c-format
msgid "Not a valid object name %s"
msgstr ""
-#: builtin/describe.c:270
+#: builtin/describe.c:273
#, c-format
msgid "%s is not a valid '%s' object"
msgstr ""
-#: builtin/describe.c:287
+#: builtin/describe.c:290
#, c-format
msgid "no tag exactly matches '%s'"
msgstr ""
-#: builtin/describe.c:289
+#: builtin/describe.c:292
#, c-format
msgid "searching to describe %s\n"
msgstr ""
-#: builtin/describe.c:329
+#: builtin/describe.c:332
#, c-format
msgid "finished search at %s\n"
msgstr ""
-#: builtin/describe.c:353
+#: builtin/describe.c:359
#, c-format
msgid ""
"No annotated tags can describe '%s'.\n"
"However, there were unannotated tags: try --tags."
msgstr ""
-#: builtin/describe.c:357
+#: builtin/describe.c:363
#, c-format
msgid ""
"No tags can describe '%s'.\n"
"Try --always, or create some tags."
msgstr ""
-#: builtin/describe.c:378
+#: builtin/describe.c:384
#, c-format
msgid "traversed %lu commits\n"
msgstr ""
-#: builtin/describe.c:381
+#: builtin/describe.c:387
#, c-format
msgid ""
"more than %i tags found; listed %i most recent\n"
"gave up search at %s\n"
msgstr ""
-#: builtin/describe.c:403
+#: builtin/describe.c:409
msgid "find the tag that comes after the commit"
msgstr ""
-#: builtin/describe.c:404
+#: builtin/describe.c:410
msgid "debug search strategy on stderr"
msgstr ""
-#: builtin/describe.c:405
-msgid "use any ref in .git/refs"
+#: builtin/describe.c:411
+msgid "use any ref"
msgstr ""
-#: builtin/describe.c:406
-msgid "use any tag in .git/refs/tags"
+#: builtin/describe.c:412
+msgid "use any tag, even unannotated"
msgstr ""
-#: builtin/describe.c:407
+#: builtin/describe.c:413
msgid "always use long format"
msgstr ""
-#: builtin/describe.c:410
+#: builtin/describe.c:414
+msgid "only follow first parent"
+msgstr ""
+
+#: builtin/describe.c:417
msgid "only output exact matches"
msgstr ""
-#: builtin/describe.c:412
+#: builtin/describe.c:419
msgid "consider <n> most recent tags (default: 10)"
msgstr ""
-#: builtin/describe.c:414
+#: builtin/describe.c:421
msgid "only consider tags matching <pattern>"
msgstr ""
-#: builtin/describe.c:416 builtin/name-rev.c:238
+#: builtin/describe.c:423 builtin/name-rev.c:322
msgid "show abbreviated commit object as fallback"
msgstr ""
-#: builtin/describe.c:417
+#: builtin/describe.c:424
msgid "mark"
msgstr ""
-#: builtin/describe.c:418
+#: builtin/describe.c:425
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
msgstr ""
-#: builtin/describe.c:436
+#: builtin/describe.c:443
msgid "--long is incompatible with --abbrev=0"
msgstr ""
-#: builtin/describe.c:462
+#: builtin/describe.c:469
msgid "No names found, cannot describe anything."
msgstr ""
-#: builtin/describe.c:482
+#: builtin/describe.c:489
msgid "--dirty is incompatible with committishes"
msgstr ""
@@ -4018,31 +4473,26 @@ msgstr ""
msgid "'%s': not a regular file or symlink"
msgstr ""
-#: builtin/diff.c:228
+#: builtin/diff.c:230
#, c-format
msgid "invalid option: %s"
msgstr ""
-#: builtin/diff.c:305
+#: builtin/diff.c:307
msgid "Not a git repository"
msgstr ""
-#: builtin/diff.c:348
+#: builtin/diff.c:350
#, c-format
msgid "invalid object '%s' given."
msgstr ""
-#: builtin/diff.c:353
-#, c-format
-msgid "more than %d trees given: '%s'"
-msgstr ""
-
-#: builtin/diff.c:363
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
msgstr ""
-#: builtin/diff.c:371
+#: builtin/diff.c:366
#, c-format
msgid "unhandled object '%s' given."
msgstr ""
@@ -4051,39 +4501,39 @@ msgstr ""
msgid "git fast-export [rev-list-opts]"
msgstr ""
-#: builtin/fast-export.c:646
+#: builtin/fast-export.c:666
msgid "show progress after <n> objects"
msgstr ""
-#: builtin/fast-export.c:648
+#: builtin/fast-export.c:668
msgid "select handling of signed tags"
msgstr ""
-#: builtin/fast-export.c:651
+#: builtin/fast-export.c:671
msgid "select handling of tags that tag filtered objects"
msgstr ""
-#: builtin/fast-export.c:654
+#: builtin/fast-export.c:674
msgid "Dump marks to this file"
msgstr ""
-#: builtin/fast-export.c:656
+#: builtin/fast-export.c:676
msgid "Import marks from this file"
msgstr ""
-#: builtin/fast-export.c:658
+#: builtin/fast-export.c:678
msgid "Fake a tagger when tags lack one"
msgstr ""
-#: builtin/fast-export.c:660
+#: builtin/fast-export.c:680
msgid "Output full tree for each commit"
msgstr ""
-#: builtin/fast-export.c:662
+#: builtin/fast-export.c:682
msgid "Use the done feature to terminate the stream"
msgstr ""
-#: builtin/fast-export.c:663
+#: builtin/fast-export.c:683
msgid "Skip output of blob data"
msgstr ""
@@ -4159,7 +4609,7 @@ msgstr ""
msgid "convert to a complete repository"
msgstr ""
-#: builtin/fetch.c:88 builtin/log.c:1119
+#: builtin/fetch.c:88 builtin/log.c:1177
msgid "dir"
msgstr ""
@@ -4171,162 +4621,162 @@ msgstr ""
msgid "default mode for recursion"
msgstr ""
-#: builtin/fetch.c:204
+#: builtin/fetch.c:220
msgid "Couldn't find remote ref HEAD"
msgstr ""
-#: builtin/fetch.c:257
+#: builtin/fetch.c:273
#, c-format
msgid "object %s not found"
msgstr ""
-#: builtin/fetch.c:262
+#: builtin/fetch.c:278
msgid "[up to date]"
msgstr ""
-#: builtin/fetch.c:276
+#: builtin/fetch.c:292
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
msgstr ""
-#: builtin/fetch.c:277 builtin/fetch.c:363
+#: builtin/fetch.c:293 builtin/fetch.c:379
msgid "[rejected]"
msgstr ""
-#: builtin/fetch.c:288
+#: builtin/fetch.c:304
msgid "[tag update]"
msgstr ""
-#: builtin/fetch.c:290 builtin/fetch.c:325 builtin/fetch.c:343
+#: builtin/fetch.c:306 builtin/fetch.c:341 builtin/fetch.c:359
msgid " (unable to update local ref)"
msgstr ""
-#: builtin/fetch.c:308
+#: builtin/fetch.c:324
msgid "[new tag]"
msgstr ""
-#: builtin/fetch.c:311
+#: builtin/fetch.c:327
msgid "[new branch]"
msgstr ""
-#: builtin/fetch.c:314
+#: builtin/fetch.c:330
msgid "[new ref]"
msgstr ""
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "unable to update local ref"
msgstr ""
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "forced update"
msgstr ""
-#: builtin/fetch.c:365
+#: builtin/fetch.c:381
msgid "(non-fast-forward)"
msgstr ""
-#: builtin/fetch.c:396 builtin/fetch.c:688
+#: builtin/fetch.c:412 builtin/fetch.c:718
#, c-format
msgid "cannot open %s: %s\n"
msgstr ""
-#: builtin/fetch.c:405
+#: builtin/fetch.c:421
#, c-format
msgid "%s did not send all necessary objects\n"
msgstr ""
-#: builtin/fetch.c:491
+#: builtin/fetch.c:520
#, c-format
msgid "From %.*s\n"
msgstr ""
-#: builtin/fetch.c:502
+#: builtin/fetch.c:531
#, 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:552
+#: builtin/fetch.c:581
#, c-format
msgid " (%s will become dangling)"
msgstr ""
-#: builtin/fetch.c:553
+#: builtin/fetch.c:582
#, c-format
msgid " (%s has become dangling)"
msgstr ""
-#: builtin/fetch.c:560
+#: builtin/fetch.c:589
msgid "[deleted]"
msgstr ""
-#: builtin/fetch.c:561 builtin/remote.c:1055
+#: builtin/fetch.c:590 builtin/remote.c:1055
msgid "(none)"
msgstr ""
-#: builtin/fetch.c:678
+#: builtin/fetch.c:708
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
msgstr ""
-#: builtin/fetch.c:712
+#: builtin/fetch.c:742
#, c-format
msgid "Don't know how to fetch from %s"
msgstr ""
-#: builtin/fetch.c:789
+#: builtin/fetch.c:823
#, c-format
msgid "Option \"%s\" value \"%s\" is not valid for %s"
msgstr ""
-#: builtin/fetch.c:792
+#: builtin/fetch.c:826
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr ""
-#: builtin/fetch.c:894
+#: builtin/fetch.c:928
#, c-format
msgid "Fetching %s\n"
msgstr ""
-#: builtin/fetch.c:896 builtin/remote.c:100
+#: builtin/fetch.c:930 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
msgstr ""
-#: builtin/fetch.c:915
+#: builtin/fetch.c:949
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:935
+#: builtin/fetch.c:969
msgid "You need to specify a tag name."
msgstr ""
-#: builtin/fetch.c:981
+#: builtin/fetch.c:1015
msgid "--depth and --unshallow cannot be used together"
msgstr ""
-#: builtin/fetch.c:983
+#: builtin/fetch.c:1017
msgid "--unshallow on a complete repository does not make sense"
msgstr ""
-#: builtin/fetch.c:1002
+#: builtin/fetch.c:1036
msgid "fetch --all does not take a repository argument"
msgstr ""
-#: builtin/fetch.c:1004
+#: builtin/fetch.c:1038
msgid "fetch --all does not make sense with refspecs"
msgstr ""
-#: builtin/fetch.c:1015
+#: builtin/fetch.c:1049
#, c-format
msgid "No such remote or remote group: %s"
msgstr ""
-#: builtin/fetch.c:1023
+#: builtin/fetch.c:1057
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr ""
@@ -4334,29 +4784,29 @@ msgstr ""
msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
msgstr ""
-#: builtin/fmt-merge-msg.c:659 builtin/fmt-merge-msg.c:662 builtin/grep.c:701
-#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175
-#: builtin/tag.c:446 parse-options.h:133 parse-options.h:239
+#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:700
+#: builtin/merge.c:203 builtin/show-branch.c:655 builtin/show-ref.c:179
+#: builtin/tag.c:446 parse-options.h:133 parse-options.h:243
msgid "n"
msgstr ""
-#: builtin/fmt-merge-msg.c:660
+#: builtin/fmt-merge-msg.c:664
msgid "populate log with at most <n> entries from shortlog"
msgstr ""
-#: builtin/fmt-merge-msg.c:663
+#: builtin/fmt-merge-msg.c:667
msgid "alias for --log (deprecated)"
msgstr ""
-#: builtin/fmt-merge-msg.c:666
+#: builtin/fmt-merge-msg.c:670
msgid "text"
msgstr ""
-#: builtin/fmt-merge-msg.c:667
+#: builtin/fmt-merge-msg.c:671
msgid "use <text> as start of message"
msgstr ""
-#: builtin/fmt-merge-msg.c:668
+#: builtin/fmt-merge-msg.c:672
msgid "file to read from"
msgstr ""
@@ -4491,225 +4941,220 @@ msgstr ""
msgid "grep: failed to create thread: %s"
msgstr ""
-#: builtin/grep.c:365
+#: builtin/grep.c:364
#, c-format
msgid "Failed to chdir: %s"
msgstr ""
-#: builtin/grep.c:443 builtin/grep.c:478
+#: builtin/grep.c:442 builtin/grep.c:477
#, c-format
msgid "unable to read tree (%s)"
msgstr ""
-#: builtin/grep.c:493
+#: builtin/grep.c:492
#, c-format
msgid "unable to grep from object of type %s"
msgstr ""
-#: builtin/grep.c:551
+#: builtin/grep.c:550
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr ""
-#: builtin/grep.c:568
+#: builtin/grep.c:567
#, c-format
msgid "cannot open '%s'"
msgstr ""
-#: builtin/grep.c:643
+#: builtin/grep.c:642
msgid "search in index instead of in the work tree"
msgstr ""
-#: builtin/grep.c:645
+#: builtin/grep.c:644
msgid "find in contents not managed by git"
msgstr ""
-#: builtin/grep.c:647
+#: builtin/grep.c:646
msgid "search in both tracked and untracked files"
msgstr ""
-#: builtin/grep.c:649
+#: builtin/grep.c:648
msgid "search also in ignored files"
msgstr ""
-#: builtin/grep.c:652
+#: builtin/grep.c:651
msgid "show non-matching lines"
msgstr ""
-#: builtin/grep.c:654
+#: builtin/grep.c:653
msgid "case insensitive matching"
msgstr ""
-#: builtin/grep.c:656
+#: builtin/grep.c:655
msgid "match patterns only at word boundaries"
msgstr ""
-#: builtin/grep.c:658
+#: builtin/grep.c:657
msgid "process binary files as text"
msgstr ""
-#: builtin/grep.c:660
+#: builtin/grep.c:659
msgid "don't match patterns in binary files"
msgstr ""
-#: builtin/grep.c:663
+#: builtin/grep.c:662
msgid "descend at most <depth> levels"
msgstr ""
-#: builtin/grep.c:667
+#: builtin/grep.c:666
msgid "use extended POSIX regular expressions"
msgstr ""
-#: builtin/grep.c:670
+#: builtin/grep.c:669
msgid "use basic POSIX regular expressions (default)"
msgstr ""
-#: builtin/grep.c:673
+#: builtin/grep.c:672
msgid "interpret patterns as fixed strings"
msgstr ""
-#: builtin/grep.c:676
+#: builtin/grep.c:675
msgid "use Perl-compatible regular expressions"
msgstr ""
-#: builtin/grep.c:679
+#: builtin/grep.c:678
msgid "show line numbers"
msgstr ""
-#: builtin/grep.c:680
+#: builtin/grep.c:679
msgid "don't show filenames"
msgstr ""
-#: builtin/grep.c:681
+#: builtin/grep.c:680
msgid "show filenames"
msgstr ""
-#: builtin/grep.c:683
+#: builtin/grep.c:682
msgid "show filenames relative to top directory"
msgstr ""
-#: builtin/grep.c:685
+#: builtin/grep.c:684
msgid "show only filenames instead of matching lines"
msgstr ""
-#: builtin/grep.c:687
+#: builtin/grep.c:686
msgid "synonym for --files-with-matches"
msgstr ""
-#: builtin/grep.c:690
+#: builtin/grep.c:689
msgid "show only the names of files without match"
msgstr ""
-#: builtin/grep.c:692
+#: builtin/grep.c:691
msgid "print NUL after filenames"
msgstr ""
-#: builtin/grep.c:694
+#: builtin/grep.c:693
msgid "show the number of matches instead of matching lines"
msgstr ""
-#: builtin/grep.c:695
+#: builtin/grep.c:694
msgid "highlight matches"
msgstr ""
-#: builtin/grep.c:697
+#: builtin/grep.c:696
msgid "print empty line between matches from different files"
msgstr ""
-#: builtin/grep.c:699
+#: builtin/grep.c:698
msgid "show filename only once above matches from same file"
msgstr ""
-#: builtin/grep.c:702
+#: builtin/grep.c:701
msgid "show <n> context lines before and after matches"
msgstr ""
-#: builtin/grep.c:705
+#: builtin/grep.c:704
msgid "show <n> context lines before matches"
msgstr ""
-#: builtin/grep.c:707
+#: builtin/grep.c:706
msgid "show <n> context lines after matches"
msgstr ""
-#: builtin/grep.c:708
+#: builtin/grep.c:707
msgid "shortcut for -C NUM"
msgstr ""
-#: builtin/grep.c:711
+#: builtin/grep.c:710
msgid "show a line with the function name before matches"
msgstr ""
-#: builtin/grep.c:713
+#: builtin/grep.c:712
msgid "show the surrounding function"
msgstr ""
-#: builtin/grep.c:716
+#: builtin/grep.c:715
msgid "read patterns from file"
msgstr ""
-#: builtin/grep.c:718
+#: builtin/grep.c:717
msgid "match <pattern>"
msgstr ""
-#: builtin/grep.c:720
+#: builtin/grep.c:719
msgid "combine patterns specified with -e"
msgstr ""
-#: builtin/grep.c:732
+#: builtin/grep.c:731
msgid "indicate hit with exit status without output"
msgstr ""
-#: builtin/grep.c:734
+#: builtin/grep.c:733
msgid "show only matches from files that match all patterns"
msgstr ""
-#: builtin/grep.c:736
+#: builtin/grep.c:735
msgid "show parse tree for grep expression"
msgstr ""
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "pager"
msgstr ""
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "show matching files in the pager"
msgstr ""
-#: builtin/grep.c:743
+#: builtin/grep.c:742
msgid "allow calling of grep(1) (ignored by this build)"
msgstr ""
-#: builtin/grep.c:744 builtin/show-ref.c:184
+#: builtin/grep.c:743 builtin/show-ref.c:188
msgid "show usage"
msgstr ""
-#: builtin/grep.c:811
+#: builtin/grep.c:810
msgid "no pattern given."
msgstr ""
-#: builtin/grep.c:825
-#, c-format
-msgid "bad object %s"
-msgstr ""
-
-#: builtin/grep.c:868
+#: builtin/grep.c:865
msgid "--open-files-in-pager only works on the worktree"
msgstr ""
-#: builtin/grep.c:891
+#: builtin/grep.c:888
msgid "--cached or --untracked cannot be used with --no-index."
msgstr ""
-#: builtin/grep.c:896
+#: builtin/grep.c:893
msgid "--no-index or --untracked cannot be used with revs."
msgstr ""
-#: builtin/grep.c:899
+#: builtin/grep.c:896
msgid "--[no-]exclude-standard cannot be used for tracked contents."
msgstr ""
-#: builtin/grep.c:907
+#: builtin/grep.c:904
msgid "both --cached and trees are given."
msgstr ""
@@ -4747,10 +5192,14 @@ msgstr ""
msgid "process file as it were from this path"
msgstr ""
-#: builtin/help.c:42
+#: builtin/help.c:41
msgid "print all available commands"
msgstr ""
+#: builtin/help.c:42
+msgid "print list of useful guides"
+msgstr ""
+
#: builtin/help.c:43
msgid "show man page"
msgstr ""
@@ -4764,7 +5213,7 @@ msgid "show info page"
msgstr ""
#: builtin/help.c:52
-msgid "git help [--all] [--man|--web|--info] [command]"
+msgid "git help [--all] [--guides] [--man|--web|--info] [command]"
msgstr ""
#: builtin/help.c:64
@@ -4817,290 +5266,322 @@ msgstr ""
msgid "no info viewer handled the request"
msgstr ""
-#: builtin/help.c:429 builtin/help.c:436
+#: builtin/help.c:420
+msgid "Defining attributes per path"
+msgstr ""
+
+#: builtin/help.c:421
+msgid "A Git glossary"
+msgstr ""
+
+#: builtin/help.c:422
+msgid "Specifies intentionally untracked files to ignore"
+msgstr ""
+
+#: builtin/help.c:423
+msgid "Defining submodule properties"
+msgstr ""
+
+#: builtin/help.c:424
+msgid "Specifying revisions and ranges for Git"
+msgstr ""
+
+#: builtin/help.c:425
+msgid "A tutorial introduction to Git (for version 1.5.1 or newer)"
+msgstr ""
+
+#: builtin/help.c:426
+msgid "An overview of recommended workflows with Git"
+msgstr ""
+
+#: builtin/help.c:438
+msgid "The common Git guides are:\n"
+msgstr ""
+
+#: builtin/help.c:460 builtin/help.c:476
#, c-format
msgid "usage: %s%s"
msgstr ""
-#: builtin/help.c:452
+#: builtin/help.c:492
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr ""
-#: builtin/index-pack.c:170
+#: builtin/index-pack.c:184
#, c-format
msgid "object type mismatch at %s"
msgstr ""
-#: builtin/index-pack.c:190
+#: builtin/index-pack.c:204
msgid "object of unexpected type"
msgstr ""
-#: builtin/index-pack.c:227
+#: builtin/index-pack.c:244
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:254
msgid "early EOF"
msgstr ""
-#: builtin/index-pack.c:238
+#: builtin/index-pack.c:255
msgid "read error on input"
msgstr ""
-#: builtin/index-pack.c:250
+#: builtin/index-pack.c:267
msgid "used more bytes than were available"
msgstr ""
-#: builtin/index-pack.c:257
+#: builtin/index-pack.c:274
msgid "pack too large for current definition of off_t"
msgstr ""
-#: builtin/index-pack.c:273
+#: builtin/index-pack.c:290
#, c-format
msgid "unable to create '%s'"
msgstr ""
-#: builtin/index-pack.c:278
+#: builtin/index-pack.c:295
#, c-format
msgid "cannot open packfile '%s'"
msgstr ""
-#: builtin/index-pack.c:292
+#: builtin/index-pack.c:309
msgid "pack signature mismatch"
msgstr ""
-#: builtin/index-pack.c:294
+#: builtin/index-pack.c:311
#, c-format
msgid "pack version %<PRIu32> unsupported"
msgstr ""
-#: builtin/index-pack.c:312
+#: builtin/index-pack.c:329
#, c-format
msgid "pack has bad object at offset %lu: %s"
msgstr ""
-#: builtin/index-pack.c:434
+#: builtin/index-pack.c:451
#, c-format
msgid "inflate returned %d"
msgstr ""
-#: builtin/index-pack.c:483
+#: builtin/index-pack.c:500
msgid "offset value overflow for delta base object"
msgstr ""
-#: builtin/index-pack.c:491
+#: builtin/index-pack.c:508
msgid "delta base offset is out of bound"
msgstr ""
-#: builtin/index-pack.c:499
+#: builtin/index-pack.c:516
#, c-format
msgid "unknown object type %d"
msgstr ""
-#: builtin/index-pack.c:530
+#: builtin/index-pack.c:547
msgid "cannot pread pack file"
msgstr ""
-#: builtin/index-pack.c:532
+#: builtin/index-pack.c:549
#, c-format
msgid "premature end of pack file, %lu byte missing"
msgid_plural "premature end of pack file, %lu bytes missing"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:558
+#: builtin/index-pack.c:575
msgid "serious inflate inconsistency"
msgstr ""
-#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
-#: builtin/index-pack.c:712 builtin/index-pack.c:721
+#: builtin/index-pack.c:666 builtin/index-pack.c:672 builtin/index-pack.c:695
+#: builtin/index-pack.c:729 builtin/index-pack.c:738
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr ""
-#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/index-pack.c:669 builtin/pack-objects.c:170
#: builtin/pack-objects.c:262
#, c-format
msgid "unable to read %s"
msgstr ""
-#: builtin/index-pack.c:718
+#: builtin/index-pack.c:735
#, c-format
msgid "cannot read existing object %s"
msgstr ""
-#: builtin/index-pack.c:732
+#: builtin/index-pack.c:749
#, c-format
msgid "invalid blob object %s"
msgstr ""
-#: builtin/index-pack.c:747
+#: builtin/index-pack.c:763
#, c-format
msgid "invalid %s"
msgstr ""
-#: builtin/index-pack.c:749
+#: builtin/index-pack.c:766
msgid "Error in object"
msgstr ""
-#: builtin/index-pack.c:751
+#: builtin/index-pack.c:768
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr ""
-#: builtin/index-pack.c:821 builtin/index-pack.c:847
+#: builtin/index-pack.c:838 builtin/index-pack.c:868
msgid "failed to apply delta"
msgstr ""
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Receiving objects"
msgstr ""
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Indexing objects"
msgstr ""
-#: builtin/index-pack.c:1012
+#: builtin/index-pack.c:1035
msgid "pack is corrupted (SHA1 mismatch)"
msgstr ""
-#: builtin/index-pack.c:1017
+#: builtin/index-pack.c:1040
msgid "cannot fstat packfile"
msgstr ""
-#: builtin/index-pack.c:1020
+#: builtin/index-pack.c:1043
msgid "pack has junk at the end"
msgstr ""
-#: builtin/index-pack.c:1031
+#: builtin/index-pack.c:1054
msgid "confusion beyond insanity in parse_pack_objects()"
msgstr ""
-#: builtin/index-pack.c:1054
+#: builtin/index-pack.c:1077
msgid "Resolving deltas"
msgstr ""
-#: builtin/index-pack.c:1064
+#: builtin/index-pack.c:1087
#, c-format
msgid "unable to create thread: %s"
msgstr ""
-#: builtin/index-pack.c:1106
+#: builtin/index-pack.c:1129
msgid "confusion beyond insanity"
msgstr ""
-#: builtin/index-pack.c:1112
+#: builtin/index-pack.c:1137
#, c-format
msgid "completed with %d local objects"
msgstr ""
-#: builtin/index-pack.c:1121
+#: builtin/index-pack.c:1147
#, c-format
msgid "Unexpected tail checksum for %s (disk corruption?)"
msgstr ""
-#: builtin/index-pack.c:1125
+#: builtin/index-pack.c:1151
#, c-format
msgid "pack has %d unresolved delta"
msgid_plural "pack has %d unresolved deltas"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:1150
+#: builtin/index-pack.c:1176
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr ""
-#: builtin/index-pack.c:1229
+#: builtin/index-pack.c:1255
#, c-format
msgid "local object %s is corrupt"
msgstr ""
-#: builtin/index-pack.c:1253
+#: builtin/index-pack.c:1279
msgid "error while closing pack file"
msgstr ""
-#: builtin/index-pack.c:1266
+#: builtin/index-pack.c:1292
#, c-format
msgid "cannot write keep file '%s'"
msgstr ""
-#: builtin/index-pack.c:1274
+#: builtin/index-pack.c:1300
#, c-format
msgid "cannot close written keep file '%s'"
msgstr ""
-#: builtin/index-pack.c:1287
+#: builtin/index-pack.c:1313
msgid "cannot store pack file"
msgstr ""
-#: builtin/index-pack.c:1298
+#: builtin/index-pack.c:1324
msgid "cannot store index file"
msgstr ""
-#: builtin/index-pack.c:1331
+#: builtin/index-pack.c:1357
#, c-format
msgid "bad pack.indexversion=%<PRIu32>"
msgstr ""
-#: builtin/index-pack.c:1337
+#: builtin/index-pack.c:1363
#, c-format
msgid "invalid number of threads specified (%d)"
msgstr ""
-#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#: builtin/index-pack.c:1367 builtin/index-pack.c:1545
#, c-format
msgid "no threads support, ignoring %s"
msgstr ""
-#: builtin/index-pack.c:1399
+#: builtin/index-pack.c:1425
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr ""
-#: builtin/index-pack.c:1401
+#: builtin/index-pack.c:1427
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
msgstr ""
-#: builtin/index-pack.c:1448
+#: builtin/index-pack.c:1474
#, c-format
msgid "non delta: %d object"
msgid_plural "non delta: %d objects"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:1455
+#: builtin/index-pack.c:1481
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
msgstr[0] ""
msgstr[1] ""
-#: builtin/index-pack.c:1482
+#: builtin/index-pack.c:1509
msgid "Cannot come back to cwd"
msgstr ""
-#: builtin/index-pack.c:1526 builtin/index-pack.c:1529
-#: builtin/index-pack.c:1541 builtin/index-pack.c:1545
+#: builtin/index-pack.c:1557 builtin/index-pack.c:1560
+#: builtin/index-pack.c:1572 builtin/index-pack.c:1576
#, c-format
msgid "bad %s"
msgstr ""
-#: builtin/index-pack.c:1559
+#: builtin/index-pack.c:1590
msgid "--fix-thin cannot be used without --stdin"
msgstr ""
-#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
+#: builtin/index-pack.c:1594 builtin/index-pack.c:1604
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr ""
-#: builtin/index-pack.c:1582
+#: builtin/index-pack.c:1613
msgid "--verify with no packfile name given"
msgstr ""
@@ -5234,7 +5715,7 @@ msgstr ""
msgid "specify that the git repository is to be shared amongst several users"
msgstr ""
-#: builtin/init-db.c:493 builtin/prune-packed.c:77
+#: builtin/init-db.c:493 builtin/prune-packed.c:75
msgid "be quiet"
msgstr ""
@@ -5264,345 +5745,353 @@ msgstr ""
msgid "Cannot access work tree '%s'"
msgstr ""
-#: builtin/log.c:39
-msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
+#: builtin/log.c:41
+msgid "git log [<options>] [<revision range>] [[--] <path>...]\n"
msgstr ""
-#: builtin/log.c:40
+#: builtin/log.c:42
msgid " or: git show [options] <object>..."
msgstr ""
-#: builtin/log.c:102
+#: builtin/log.c:124
msgid "suppress diff output"
msgstr ""
-#: builtin/log.c:103
+#: builtin/log.c:125
msgid "show source"
msgstr ""
-#: builtin/log.c:104
+#: builtin/log.c:126
msgid "Use mail map file"
msgstr ""
-#: builtin/log.c:105
+#: builtin/log.c:127
msgid "decorate options"
msgstr ""
-#: builtin/log.c:198
+#: builtin/log.c:230
#, c-format
msgid "Final output: %d %s\n"
msgstr ""
-#: builtin/log.c:419 builtin/log.c:511
+#: builtin/log.c:453 builtin/log.c:545
#, c-format
msgid "Could not read object %s"
msgstr ""
-#: builtin/log.c:535
+#: builtin/log.c:569
#, c-format
msgid "Unknown type: %d"
msgstr ""
-#: builtin/log.c:627
+#: builtin/log.c:669
msgid "format.headers without value"
msgstr ""
-#: builtin/log.c:701
+#: builtin/log.c:751
msgid "name of output directory is too long"
msgstr ""
-#: builtin/log.c:717
+#: builtin/log.c:767
#, c-format
msgid "Cannot open patch file %s"
msgstr ""
-#: builtin/log.c:731
+#: builtin/log.c:781
msgid "Need exactly one range."
msgstr ""
-#: builtin/log.c:739
+#: builtin/log.c:789
msgid "Not a range."
msgstr ""
-#: builtin/log.c:812
+#: builtin/log.c:891
msgid "Cover letter needs email format"
msgstr ""
-#: builtin/log.c:885
+#: builtin/log.c:967
#, c-format
msgid "insane in-reply-to: %s"
msgstr ""
-#: builtin/log.c:913
+#: builtin/log.c:995
msgid "git format-patch [options] [<since> | <revision range>]"
msgstr ""
-#: builtin/log.c:958
+#: builtin/log.c:1040
msgid "Two output directories?"
msgstr ""
-#: builtin/log.c:1097
+#: builtin/log.c:1155
msgid "use [PATCH n/m] even with a single patch"
msgstr ""
-#: builtin/log.c:1100
+#: builtin/log.c:1158
msgid "use [PATCH] even with multiple patches"
msgstr ""
-#: builtin/log.c:1104
+#: builtin/log.c:1162
msgid "print patches to standard out"
msgstr ""
-#: builtin/log.c:1106
+#: builtin/log.c:1164
msgid "generate a cover letter"
msgstr ""
-#: builtin/log.c:1108
+#: builtin/log.c:1166
msgid "use simple number sequence for output file names"
msgstr ""
-#: builtin/log.c:1109
+#: builtin/log.c:1167
msgid "sfx"
msgstr ""
-#: builtin/log.c:1110
+#: builtin/log.c:1168
msgid "use <sfx> instead of '.patch'"
msgstr ""
-#: builtin/log.c:1112
+#: builtin/log.c:1170
msgid "start numbering patches at <n> instead of 1"
msgstr ""
-#: builtin/log.c:1114
+#: builtin/log.c:1172
msgid "mark the series as Nth re-roll"
msgstr ""
-#: builtin/log.c:1116
+#: builtin/log.c:1174
msgid "Use [<prefix>] instead of [PATCH]"
msgstr ""
-#: builtin/log.c:1119
+#: builtin/log.c:1177
msgid "store resulting files in <dir>"
msgstr ""
-#: builtin/log.c:1122
+#: builtin/log.c:1180
msgid "don't strip/add [PATCH]"
msgstr ""
-#: builtin/log.c:1125
+#: builtin/log.c:1183
msgid "don't output binary diffs"
msgstr ""
-#: builtin/log.c:1127
+#: builtin/log.c:1185
msgid "don't include a patch matching a commit upstream"
msgstr ""
-#: builtin/log.c:1129
+#: builtin/log.c:1187
msgid "show patch format instead of default (patch + stat)"
msgstr ""
-#: builtin/log.c:1131
+#: builtin/log.c:1189
msgid "Messaging"
msgstr ""
-#: builtin/log.c:1132
+#: builtin/log.c:1190
msgid "header"
msgstr ""
-#: builtin/log.c:1133
+#: builtin/log.c:1191
msgid "add email header"
msgstr ""
-#: builtin/log.c:1134 builtin/log.c:1136
+#: builtin/log.c:1192 builtin/log.c:1194
msgid "email"
msgstr ""
-#: builtin/log.c:1134
+#: builtin/log.c:1192
msgid "add To: header"
msgstr ""
-#: builtin/log.c:1136
+#: builtin/log.c:1194
msgid "add Cc: header"
msgstr ""
-#: builtin/log.c:1138
+#: builtin/log.c:1196
+msgid "ident"
+msgstr ""
+
+#: builtin/log.c:1197
+msgid "set From address to <ident> (or committer ident if absent)"
+msgstr ""
+
+#: builtin/log.c:1199
msgid "message-id"
msgstr ""
-#: builtin/log.c:1139
+#: builtin/log.c:1200
msgid "make first mail a reply to <message-id>"
msgstr ""
-#: builtin/log.c:1140 builtin/log.c:1143
+#: builtin/log.c:1201 builtin/log.c:1204
msgid "boundary"
msgstr ""
-#: builtin/log.c:1141
+#: builtin/log.c:1202
msgid "attach the patch"
msgstr ""
-#: builtin/log.c:1144
+#: builtin/log.c:1205
msgid "inline the patch"
msgstr ""
-#: builtin/log.c:1148
+#: builtin/log.c:1209
msgid "enable message threading, styles: shallow, deep"
msgstr ""
-#: builtin/log.c:1150
+#: builtin/log.c:1211
msgid "signature"
msgstr ""
-#: builtin/log.c:1151
+#: builtin/log.c:1212
msgid "add a signature"
msgstr ""
-#: builtin/log.c:1153
+#: builtin/log.c:1214
msgid "don't print the patch filenames"
msgstr ""
-#: builtin/log.c:1202
+#: builtin/log.c:1288
#, c-format
-msgid "bogus committer info %s"
+msgid "invalid ident line: %s"
msgstr ""
-#: builtin/log.c:1247
+#: builtin/log.c:1303
msgid "-n and -k are mutually exclusive."
msgstr ""
-#: builtin/log.c:1249
+#: builtin/log.c:1305
msgid "--subject-prefix and -k are mutually exclusive."
msgstr ""
-#: builtin/log.c:1257
+#: builtin/log.c:1313
msgid "--name-only does not make sense"
msgstr ""
-#: builtin/log.c:1259
+#: builtin/log.c:1315
msgid "--name-status does not make sense"
msgstr ""
-#: builtin/log.c:1261
+#: builtin/log.c:1317
msgid "--check does not make sense"
msgstr ""
-#: builtin/log.c:1284
+#: builtin/log.c:1340
msgid "standard output, or directory, which one?"
msgstr ""
-#: builtin/log.c:1286
+#: builtin/log.c:1342
#, c-format
msgid "Could not create directory '%s'"
msgstr ""
-#: builtin/log.c:1439
+#: builtin/log.c:1490
msgid "Failed to create output files"
msgstr ""
-#: builtin/log.c:1488
+#: builtin/log.c:1539
msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
msgstr ""
-#: builtin/log.c:1543
+#: builtin/log.c:1594
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
msgstr ""
-#: builtin/log.c:1556 builtin/log.c:1558 builtin/log.c:1570
+#: builtin/log.c:1607 builtin/log.c:1609 builtin/log.c:1621
#, c-format
msgid "Unknown commit %s"
msgstr ""
-#: builtin/ls-files.c:409
+#: builtin/ls-files.c:408
msgid "git ls-files [options] [<file>...]"
msgstr ""
-#: builtin/ls-files.c:466
+#: builtin/ls-files.c:465
msgid "identify the file status with tags"
msgstr ""
-#: builtin/ls-files.c:468
+#: builtin/ls-files.c:467
msgid "use lowercase letters for 'assume unchanged' files"
msgstr ""
-#: builtin/ls-files.c:470
+#: builtin/ls-files.c:469
msgid "show cached files in the output (default)"
msgstr ""
-#: builtin/ls-files.c:472
+#: builtin/ls-files.c:471
msgid "show deleted files in the output"
msgstr ""
-#: builtin/ls-files.c:474
+#: builtin/ls-files.c:473
msgid "show modified files in the output"
msgstr ""
-#: builtin/ls-files.c:476
+#: builtin/ls-files.c:475
msgid "show other files in the output"
msgstr ""
-#: builtin/ls-files.c:478
+#: builtin/ls-files.c:477
msgid "show ignored files in the output"
msgstr ""
-#: builtin/ls-files.c:481
+#: builtin/ls-files.c:480
msgid "show staged contents' object name in the output"
msgstr ""
-#: builtin/ls-files.c:483
+#: builtin/ls-files.c:482
msgid "show files on the filesystem that need to be removed"
msgstr ""
-#: builtin/ls-files.c:485
+#: builtin/ls-files.c:484
msgid "show 'other' directories' name only"
msgstr ""
-#: builtin/ls-files.c:488
+#: builtin/ls-files.c:487
msgid "don't show empty directories"
msgstr ""
-#: builtin/ls-files.c:491
+#: builtin/ls-files.c:490
msgid "show unmerged files in the output"
msgstr ""
-#: builtin/ls-files.c:493
+#: builtin/ls-files.c:492
msgid "show resolve-undo information"
msgstr ""
-#: builtin/ls-files.c:495
+#: builtin/ls-files.c:494
msgid "skip files matching pattern"
msgstr ""
-#: builtin/ls-files.c:498
+#: builtin/ls-files.c:497
msgid "exclude patterns are read from <file>"
msgstr ""
-#: builtin/ls-files.c:501
+#: builtin/ls-files.c:500
msgid "read additional per-directory exclude patterns in <file>"
msgstr ""
-#: builtin/ls-files.c:503
+#: builtin/ls-files.c:502
msgid "add the standard git exclusions"
msgstr ""
-#: builtin/ls-files.c:506
+#: builtin/ls-files.c:505
msgid "make the output relative to the project top directory"
msgstr ""
-#: builtin/ls-files.c:509
+#: builtin/ls-files.c:508
msgid "if any <file> is not in the index, treat this as an error"
msgstr ""
-#: builtin/ls-files.c:510
+#: builtin/ls-files.c:509
msgid "tree-ish"
msgstr ""
-#: builtin/ls-files.c:511
+#: builtin/ls-files.c:510
msgid "pretend that paths removed since <tree-ish> are still present"
msgstr ""
-#: builtin/ls-files.c:513
+#: builtin/ls-files.c:512
msgid "show debugging data"
msgstr ""
@@ -5654,163 +6143,167 @@ msgstr ""
msgid "git merge --abort"
msgstr ""
-#: builtin/merge.c:90
+#: builtin/merge.c:98
msgid "switch `m' requires a value"
msgstr ""
-#: builtin/merge.c:127
+#: builtin/merge.c:135
#, c-format
msgid "Could not find merge strategy '%s'.\n"
msgstr ""
-#: builtin/merge.c:128
+#: builtin/merge.c:136
#, c-format
msgid "Available strategies are:"
msgstr ""
-#: builtin/merge.c:133
+#: builtin/merge.c:141
#, c-format
msgid "Available custom strategies are:"
msgstr ""
-#: builtin/merge.c:183
+#: builtin/merge.c:198
msgid "do not show a diffstat at the end of the merge"
msgstr ""
-#: builtin/merge.c:186
+#: builtin/merge.c:201
msgid "show a diffstat at the end of the merge"
msgstr ""
-#: builtin/merge.c:187
+#: builtin/merge.c:202
msgid "(synonym to --stat)"
msgstr ""
-#: builtin/merge.c:189
+#: builtin/merge.c:204
msgid "add (at most <n>) entries from shortlog to merge commit message"
msgstr ""
-#: builtin/merge.c:192
+#: builtin/merge.c:207
msgid "create a single commit instead of doing a merge"
msgstr ""
-#: builtin/merge.c:194
+#: builtin/merge.c:209
msgid "perform a commit if the merge succeeds (default)"
msgstr ""
-#: builtin/merge.c:196
+#: builtin/merge.c:211
msgid "edit message before committing"
msgstr ""
-#: builtin/merge.c:198
+#: builtin/merge.c:212
msgid "allow fast-forward (default)"
msgstr ""
-#: builtin/merge.c:200
+#: builtin/merge.c:214
msgid "abort if fast-forward is not possible"
msgstr ""
-#: builtin/merge.c:202 builtin/notes.c:866 builtin/revert.c:112
+#: builtin/merge.c:218
+msgid "Verify that the named commit has a valid GPG signature"
+msgstr ""
+
+#: builtin/merge.c:219 builtin/notes.c:738 builtin/revert.c:114
msgid "strategy"
msgstr ""
-#: builtin/merge.c:203
+#: builtin/merge.c:220
msgid "merge strategy to use"
msgstr ""
-#: builtin/merge.c:204
+#: builtin/merge.c:221
msgid "option=value"
msgstr ""
-#: builtin/merge.c:205
+#: builtin/merge.c:222
msgid "option for selected merge strategy"
msgstr ""
-#: builtin/merge.c:207
+#: builtin/merge.c:224
msgid "merge commit message (for a non-fast-forward merge)"
msgstr ""
-#: builtin/merge.c:211
+#: builtin/merge.c:228
msgid "abort the current in-progress merge"
msgstr ""
-#: builtin/merge.c:240
+#: builtin/merge.c:257
msgid "could not run stash."
msgstr ""
-#: builtin/merge.c:245
+#: builtin/merge.c:262
msgid "stash failed"
msgstr ""
-#: builtin/merge.c:250
+#: builtin/merge.c:267
#, c-format
msgid "not a valid object: %s"
msgstr ""
-#: builtin/merge.c:269 builtin/merge.c:286
+#: builtin/merge.c:286 builtin/merge.c:303
msgid "read-tree failed"
msgstr ""
-#: builtin/merge.c:316
+#: builtin/merge.c:333
msgid " (nothing to squash)"
msgstr ""
-#: builtin/merge.c:329
+#: builtin/merge.c:346
#, c-format
msgid "Squash commit -- not updating HEAD\n"
msgstr ""
-#: builtin/merge.c:361
+#: builtin/merge.c:378
msgid "Writing SQUASH_MSG"
msgstr ""
-#: builtin/merge.c:363
+#: builtin/merge.c:380
msgid "Finishing SQUASH_MSG"
msgstr ""
-#: builtin/merge.c:386
+#: builtin/merge.c:403
#, c-format
msgid "No merge message -- not updating HEAD\n"
msgstr ""
-#: builtin/merge.c:436
+#: builtin/merge.c:453
#, c-format
msgid "'%s' does not point to a commit"
msgstr ""
-#: builtin/merge.c:535
+#: builtin/merge.c:565
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr ""
-#: builtin/merge.c:628
+#: builtin/merge.c:657
msgid "git write-tree failed to write a tree"
msgstr ""
-#: builtin/merge.c:656
+#: builtin/merge.c:685
msgid "Not handling anything other than two heads merge."
msgstr ""
-#: builtin/merge.c:670
+#: builtin/merge.c:699
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr ""
-#: builtin/merge.c:684
+#: builtin/merge.c:713
#, c-format
msgid "unable to write %s"
msgstr ""
-#: builtin/merge.c:773
+#: builtin/merge.c:802
#, c-format
msgid "Could not read from '%s'"
msgstr ""
-#: builtin/merge.c:782
+#: builtin/merge.c:811
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
-#: builtin/merge.c:788
+#: builtin/merge.c:817
#, c-format
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
@@ -5820,140 +6313,157 @@ msgid ""
"the commit.\n"
msgstr ""
-#: builtin/merge.c:812
+#: builtin/merge.c:841
msgid "Empty commit message."
msgstr ""
-#: builtin/merge.c:824
+#: builtin/merge.c:853
#, c-format
msgid "Wonderful.\n"
msgstr ""
-#: builtin/merge.c:889
+#: builtin/merge.c:918
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr ""
-#: builtin/merge.c:905
+#: builtin/merge.c:934
#, c-format
msgid "'%s' is not a commit"
msgstr ""
-#: builtin/merge.c:946
+#: builtin/merge.c:975
msgid "No current branch."
msgstr ""
-#: builtin/merge.c:948
+#: builtin/merge.c:977
msgid "No remote for the current branch."
msgstr ""
-#: builtin/merge.c:950
+#: builtin/merge.c:979
msgid "No default upstream defined for the current branch."
msgstr ""
-#: builtin/merge.c:955
+#: builtin/merge.c:984
#, c-format
-msgid "No remote tracking branch for %s from %s"
+msgid "No remote-tracking branch for %s from %s"
msgstr ""
-#: builtin/merge.c:1042 builtin/merge.c:1199
-#, c-format
-msgid "%s - not something we can merge"
-msgstr ""
-
-#: builtin/merge.c:1110
+#: builtin/merge.c:1140
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr ""
-#: builtin/merge.c:1126 git-pull.sh:31
+#: builtin/merge.c:1156 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:1129 git-pull.sh:34
+#: builtin/merge.c:1159 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr ""
-#: builtin/merge.c:1133
+#: builtin/merge.c:1163
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:1136
+#: builtin/merge.c:1166
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr ""
-#: builtin/merge.c:1145
+#: builtin/merge.c:1175
msgid "You cannot combine --squash with --no-ff."
msgstr ""
-#: builtin/merge.c:1150
-msgid "You cannot combine --no-ff with --ff-only."
-msgstr ""
-
-#: builtin/merge.c:1157
+#: builtin/merge.c:1184
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr ""
-#: builtin/merge.c:1189
+#: builtin/merge.c:1216
msgid "Can merge only exactly one commit into empty head"
msgstr ""
-#: builtin/merge.c:1192
+#: builtin/merge.c:1219
msgid "Squash commit into empty head not supported yet"
msgstr ""
-#: builtin/merge.c:1194
+#: builtin/merge.c:1221
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr ""
-#: builtin/merge.c:1310
+#: builtin/merge.c:1226
+#, c-format
+msgid "%s - not something we can merge"
+msgstr ""
+
+#: builtin/merge.c:1277
+#, c-format
+msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
+msgstr ""
+
+#: builtin/merge.c:1280
+#, c-format
+msgid "Commit %s has a bad GPG signature allegedly by %s."
+msgstr ""
+
+#. 'N'
+#: builtin/merge.c:1283
+#, c-format
+msgid "Commit %s does not have a GPG signature."
+msgstr ""
+
+#: builtin/merge.c:1286
+#, c-format
+msgid "Commit %s has a good GPG signature by %s\n"
+msgstr ""
+
+#: builtin/merge.c:1370
#, c-format
msgid "Updating %s..%s\n"
msgstr ""
-#: builtin/merge.c:1349
+#: builtin/merge.c:1409
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr ""
-#: builtin/merge.c:1356
+#: builtin/merge.c:1416
#, c-format
msgid "Nope.\n"
msgstr ""
-#: builtin/merge.c:1388
+#: builtin/merge.c:1448
msgid "Not possible to fast-forward, aborting."
msgstr ""
-#: builtin/merge.c:1411 builtin/merge.c:1490
+#: builtin/merge.c:1471 builtin/merge.c:1550
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr ""
-#: builtin/merge.c:1415
+#: builtin/merge.c:1475
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr ""
-#: builtin/merge.c:1481
+#: builtin/merge.c:1541
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr ""
-#: builtin/merge.c:1483
+#: builtin/merge.c:1543
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr ""
-#: builtin/merge.c:1492
+#: builtin/merge.c:1552
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr ""
-#: builtin/merge.c:1504
+#: builtin/merge.c:1564
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
@@ -6118,369 +6628,352 @@ msgstr ""
msgid "renaming '%s' failed"
msgstr ""
-#: builtin/name-rev.c:175
+#: builtin/name-rev.c:259
msgid "git name-rev [options] <commit>..."
msgstr ""
-#: builtin/name-rev.c:176
+#: builtin/name-rev.c:260
msgid "git name-rev [options] --all"
msgstr ""
-#: builtin/name-rev.c:177
+#: builtin/name-rev.c:261
msgid "git name-rev [options] --stdin"
msgstr ""
-#: builtin/name-rev.c:229
+#: builtin/name-rev.c:313
msgid "print only names (no SHA-1)"
msgstr ""
-#: builtin/name-rev.c:230
+#: builtin/name-rev.c:314
msgid "only use tags to name the commits"
msgstr ""
-#: builtin/name-rev.c:232
+#: builtin/name-rev.c:316
msgid "only use refs matching <pattern>"
msgstr ""
-#: builtin/name-rev.c:234
+#: builtin/name-rev.c:318
msgid "list all commits reachable from all refs"
msgstr ""
-#: builtin/name-rev.c:235
+#: builtin/name-rev.c:319
msgid "read from stdin"
msgstr ""
-#: builtin/name-rev.c:236
+#: builtin/name-rev.c:320
msgid "allow to print `undefined` names"
msgstr ""
-#: builtin/notes.c:26
+#: builtin/name-rev.c:326
+msgid "dereference tags in the input (internal use)"
+msgstr ""
+
+#: builtin/notes.c:24
msgid "git notes [--ref <notes_ref>] [list [<object>]]"
msgstr ""
-#: builtin/notes.c:27
+#: builtin/notes.c:25
msgid ""
"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
msgstr ""
-#: builtin/notes.c:28
+#: builtin/notes.c:26
msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
msgstr ""
-#: builtin/notes.c:29
+#: builtin/notes.c:27
msgid ""
"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
msgstr ""
-#: builtin/notes.c:30
+#: builtin/notes.c:28
msgid "git notes [--ref <notes_ref>] edit [<object>]"
msgstr ""
-#: builtin/notes.c:31
+#: builtin/notes.c:29
msgid "git notes [--ref <notes_ref>] show [<object>]"
msgstr ""
-#: builtin/notes.c:32
+#: builtin/notes.c:30
msgid ""
"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
msgstr ""
-#: builtin/notes.c:33
+#: builtin/notes.c:31
msgid "git notes merge --commit [-v | -q]"
msgstr ""
-#: builtin/notes.c:34
+#: builtin/notes.c:32
msgid "git notes merge --abort [-v | -q]"
msgstr ""
-#: builtin/notes.c:35
+#: builtin/notes.c:33
msgid "git notes [--ref <notes_ref>] remove [<object>...]"
msgstr ""
-#: builtin/notes.c:36
+#: builtin/notes.c:34
msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
msgstr ""
-#: builtin/notes.c:37
+#: builtin/notes.c:35
msgid "git notes [--ref <notes_ref>] get-ref"
msgstr ""
-#: builtin/notes.c:42
+#: builtin/notes.c:40
msgid "git notes [list [<object>]]"
msgstr ""
-#: builtin/notes.c:47
+#: builtin/notes.c:45
msgid "git notes add [<options>] [<object>]"
msgstr ""
-#: builtin/notes.c:52
+#: builtin/notes.c:50
msgid "git notes copy [<options>] <from-object> <to-object>"
msgstr ""
-#: builtin/notes.c:53
+#: builtin/notes.c:51
msgid "git notes copy --stdin [<from-object> <to-object>]..."
msgstr ""
-#: builtin/notes.c:58
+#: builtin/notes.c:56
msgid "git notes append [<options>] [<object>]"
msgstr ""
-#: builtin/notes.c:63
+#: builtin/notes.c:61
msgid "git notes edit [<object>]"
msgstr ""
-#: builtin/notes.c:68
+#: builtin/notes.c:66
msgid "git notes show [<object>]"
msgstr ""
-#: builtin/notes.c:73
+#: builtin/notes.c:71
msgid "git notes merge [<options>] <notes_ref>"
msgstr ""
-#: builtin/notes.c:74
+#: builtin/notes.c:72
msgid "git notes merge --commit [<options>]"
msgstr ""
-#: builtin/notes.c:75
+#: builtin/notes.c:73
msgid "git notes merge --abort [<options>]"
msgstr ""
-#: builtin/notes.c:80
+#: builtin/notes.c:78
msgid "git notes remove [<object>]"
msgstr ""
-#: builtin/notes.c:85
+#: builtin/notes.c:83
msgid "git notes prune [<options>]"
msgstr ""
-#: builtin/notes.c:90
+#: builtin/notes.c:88
msgid "git notes get-ref"
msgstr ""
-#: builtin/notes.c:139
+#: builtin/notes.c:137
#, c-format
msgid "unable to start 'show' for object '%s'"
msgstr ""
-#: builtin/notes.c:143
+#: builtin/notes.c:141
msgid "could not read 'show' output"
msgstr ""
-#: builtin/notes.c:151
+#: builtin/notes.c:149
#, c-format
msgid "failed to finish 'show' for object '%s'"
msgstr ""
-#: builtin/notes.c:169 builtin/tag.c:341
+#: builtin/notes.c:167 builtin/tag.c:341
#, c-format
msgid "could not create file '%s'"
msgstr ""
-#: builtin/notes.c:188
+#: builtin/notes.c:186
msgid "Please supply the note contents using either -m or -F option"
msgstr ""
-#: builtin/notes.c:209 builtin/notes.c:972
+#: builtin/notes.c:207 builtin/notes.c:844
#, c-format
msgid "Removing note for object %s\n"
msgstr ""
-#: builtin/notes.c:214
+#: builtin/notes.c:212
msgid "unable to write note object"
msgstr ""
-#: builtin/notes.c:216
+#: builtin/notes.c:214
#, c-format
msgid "The note contents has been left in %s"
msgstr ""
-#: builtin/notes.c:250 builtin/tag.c:540
+#: builtin/notes.c:248 builtin/tag.c:540
#, c-format
msgid "cannot read '%s'"
msgstr ""
-#: builtin/notes.c:252 builtin/tag.c:543
+#: builtin/notes.c:250 builtin/tag.c:543
#, c-format
msgid "could not open or read '%s'"
msgstr ""
-#: builtin/notes.c:271 builtin/notes.c:444 builtin/notes.c:446
-#: builtin/notes.c:506 builtin/notes.c:560 builtin/notes.c:643
-#: builtin/notes.c:648 builtin/notes.c:723 builtin/notes.c:765
-#: builtin/notes.c:967 builtin/tag.c:556
+#: builtin/notes.c:269 builtin/notes.c:316 builtin/notes.c:318
+#: builtin/notes.c:378 builtin/notes.c:432 builtin/notes.c:515
+#: builtin/notes.c:520 builtin/notes.c:595 builtin/notes.c:637
+#: builtin/notes.c:839 builtin/tag.c:556
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
msgstr ""
-#: builtin/notes.c:274
+#: builtin/notes.c:272
#, c-format
msgid "Failed to read object '%s'."
msgstr ""
-#: builtin/notes.c:298
-msgid "Cannot commit uninitialized/unreferenced notes tree"
-msgstr ""
-
-#: builtin/notes.c:339
-#, c-format
-msgid "Bad notes.rewriteMode value: '%s'"
-msgstr ""
-
-#: builtin/notes.c:349
-#, c-format
-msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
-msgstr ""
-
-#. TRANSLATORS: The first %s is the name of the
-#. environment variable, the second %s is its value
-#: builtin/notes.c:376
-#, c-format
-msgid "Bad %s value: '%s'"
-msgstr ""
-
-#: builtin/notes.c:440
+#: builtin/notes.c:312
#, c-format
msgid "Malformed input line: '%s'."
msgstr ""
-#: builtin/notes.c:455
+#: builtin/notes.c:327
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
msgstr ""
-#: builtin/notes.c:499 builtin/notes.c:553 builtin/notes.c:626
-#: builtin/notes.c:638 builtin/notes.c:711 builtin/notes.c:758
-#: builtin/notes.c:1032
+#: builtin/notes.c:371 builtin/notes.c:425 builtin/notes.c:498
+#: builtin/notes.c:510 builtin/notes.c:583 builtin/notes.c:630
+#: builtin/notes.c:904
msgid "too many parameters"
msgstr ""
-#: builtin/notes.c:512 builtin/notes.c:771
+#: builtin/notes.c:384 builtin/notes.c:643
#, c-format
msgid "No note found for object %s."
msgstr ""
-#: builtin/notes.c:534 builtin/notes.c:691
+#: builtin/notes.c:406 builtin/notes.c:563
msgid "note contents as a string"
msgstr ""
-#: builtin/notes.c:537 builtin/notes.c:694
+#: builtin/notes.c:409 builtin/notes.c:566
msgid "note contents in a file"
msgstr ""
-#: builtin/notes.c:539 builtin/notes.c:542 builtin/notes.c:696
-#: builtin/notes.c:699 builtin/tag.c:474
+#: builtin/notes.c:411 builtin/notes.c:414 builtin/notes.c:568
+#: builtin/notes.c:571 builtin/tag.c:474
msgid "object"
msgstr ""
-#: builtin/notes.c:540 builtin/notes.c:697
+#: builtin/notes.c:412 builtin/notes.c:569
msgid "reuse and edit specified note object"
msgstr ""
-#: builtin/notes.c:543 builtin/notes.c:700
+#: builtin/notes.c:415 builtin/notes.c:572
msgid "reuse specified note object"
msgstr ""
-#: builtin/notes.c:545 builtin/notes.c:613
+#: builtin/notes.c:417 builtin/notes.c:485
msgid "replace existing notes"
msgstr ""
-#: builtin/notes.c:579
+#: builtin/notes.c:451
#, c-format
msgid ""
"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
"existing notes"
msgstr ""
-#: builtin/notes.c:584 builtin/notes.c:661
+#: builtin/notes.c:456 builtin/notes.c:533
#, c-format
msgid "Overwriting existing notes for object %s\n"
msgstr ""
-#: builtin/notes.c:614
+#: builtin/notes.c:486
msgid "read objects from stdin"
msgstr ""
-#: builtin/notes.c:616
+#: builtin/notes.c:488
msgid "load rewriting config for <command> (implies --stdin)"
msgstr ""
-#: builtin/notes.c:634
+#: builtin/notes.c:506
msgid "too few parameters"
msgstr ""
-#: builtin/notes.c:655
+#: builtin/notes.c:527
#, c-format
msgid ""
"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
"existing notes"
msgstr ""
-#: builtin/notes.c:667
+#: builtin/notes.c:539
#, c-format
msgid "Missing notes on source object %s. Cannot copy."
msgstr ""
-#: builtin/notes.c:716
+#: builtin/notes.c:588
#, c-format
msgid ""
"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
"Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
msgstr ""
-#: builtin/notes.c:863
+#: builtin/notes.c:735
msgid "General options"
msgstr ""
-#: builtin/notes.c:865
+#: builtin/notes.c:737
msgid "Merge options"
msgstr ""
-#: builtin/notes.c:867
+#: builtin/notes.c:739
msgid ""
"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
"cat_sort_uniq)"
msgstr ""
-#: builtin/notes.c:869
+#: builtin/notes.c:741
msgid "Committing unmerged notes"
msgstr ""
-#: builtin/notes.c:871
+#: builtin/notes.c:743
msgid "finalize notes merge by committing unmerged notes"
msgstr ""
-#: builtin/notes.c:873
+#: builtin/notes.c:745
msgid "Aborting notes merge resolution"
msgstr ""
-#: builtin/notes.c:875
+#: builtin/notes.c:747
msgid "abort notes merge"
msgstr ""
-#: builtin/notes.c:970
+#: builtin/notes.c:842
#, c-format
msgid "Object %s has no note\n"
msgstr ""
-#: builtin/notes.c:982
+#: builtin/notes.c:854
msgid "attempt to remove non-existent note is not an error"
msgstr ""
-#: builtin/notes.c:985
+#: builtin/notes.c:857
msgid "read object names from the standard input"
msgstr ""
-#: builtin/notes.c:1066
+#: builtin/notes.c:938
msgid "notes_ref"
msgstr ""
-#: builtin/notes.c:1067
+#: builtin/notes.c:939
msgid "use notes from <notes_ref>"
msgstr ""
-#: builtin/notes.c:1102 builtin/remote.c:1598
+#: builtin/notes.c:974 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
msgstr ""
@@ -6703,7 +7196,7 @@ msgid ""
"%s"
msgstr ""
-#: builtin/push.c:121
+#: builtin/push.c:117
#, c-format
msgid ""
"You are not currently on a branch.\n"
@@ -6713,7 +7206,7 @@ msgid ""
" git push %s HEAD:<name-of-remote-branch>\n"
msgstr ""
-#: builtin/push.c:128
+#: builtin/push.c:131
#, c-format
msgid ""
"The current branch %s has no upstream branch.\n"
@@ -6722,12 +7215,12 @@ msgid ""
" git push --set-upstream %s %s\n"
msgstr ""
-#: builtin/push.c:136
+#: builtin/push.c:139
#, c-format
msgid "The current branch %s has multiple upstream branches, refusing to push."
msgstr ""
-#: builtin/push.c:139
+#: builtin/push.c:142
#, c-format
msgid ""
"You are pushing to remote '%s', which is not the upstream of\n"
@@ -6735,7 +7228,7 @@ msgid ""
"to update which remote branch."
msgstr ""
-#: builtin/push.c:151
+#: builtin/push.c:165
msgid ""
"push.default is unset; its implicit value is changing in\n"
"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
@@ -6753,20 +7246,20 @@ msgid ""
"'current' instead of 'simple' if you sometimes use older versions of Git)"
msgstr ""
-#: builtin/push.c:199
+#: builtin/push.c:225
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
-#: builtin/push.c:206
+#: builtin/push.c:232
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
-"before pushing again.\n"
+"its remote counterpart. Integrate the remote changes (e.g.\n"
+"'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-#: builtin/push.c:212
+#: builtin/push.c:238
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"
@@ -6774,50 +7267,50 @@ msgid ""
"to 'simple', 'current' or 'upstream' to push only the current branch."
msgstr ""
-#: builtin/push.c:218
+#: builtin/push.c:244
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and merge the remote changes\n"
-"(e.g. 'git pull') before pushing again.\n"
+"counterpart. Check out this branch and integrate the remote changes\n"
+"(e.g. 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-#: builtin/push.c:224
+#: builtin/push.c:250
msgid ""
"Updates were rejected because the remote contains work that you do\n"
"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first merge the remote changes (e.g.,\n"
-"'git pull') before pushing again.\n"
+"to the same ref. You may want to first integrate the remote changes\n"
+"(e.g., 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-#: builtin/push.c:231
+#: builtin/push.c:257
msgid "Updates were rejected because the tag already exists in the remote."
msgstr ""
-#: builtin/push.c:234
+#: builtin/push.c:260
msgid ""
"You cannot update a remote ref that points at a non-commit object,\n"
"or update a remote ref to make it point at a non-commit object,\n"
"without using the '--force' option.\n"
msgstr ""
-#: builtin/push.c:294
+#: builtin/push.c:320
#, c-format
msgid "Pushing to %s\n"
msgstr ""
-#: builtin/push.c:298
+#: builtin/push.c:324
#, c-format
msgid "failed to push some refs to '%s'"
msgstr ""
-#: builtin/push.c:331
+#: builtin/push.c:357
#, c-format
msgid "bad repository '%s'"
msgstr ""
-#: builtin/push.c:332
+#: builtin/push.c:358
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -6830,83 +7323,87 @@ msgid ""
" git push <name>\n"
msgstr ""
-#: builtin/push.c:347
+#: builtin/push.c:373
msgid "--all and --tags are incompatible"
msgstr ""
-#: builtin/push.c:348
+#: builtin/push.c:374
msgid "--all can't be combined with refspecs"
msgstr ""
-#: builtin/push.c:353
+#: builtin/push.c:379
msgid "--mirror and --tags are incompatible"
msgstr ""
-#: builtin/push.c:354
+#: builtin/push.c:380
msgid "--mirror can't be combined with refspecs"
msgstr ""
-#: builtin/push.c:359
+#: builtin/push.c:385
msgid "--all and --mirror are incompatible"
msgstr ""
-#: builtin/push.c:419
+#: builtin/push.c:445
msgid "repository"
msgstr ""
-#: builtin/push.c:420
+#: builtin/push.c:446
msgid "push all refs"
msgstr ""
-#: builtin/push.c:421
+#: builtin/push.c:447
msgid "mirror all refs"
msgstr ""
-#: builtin/push.c:423
+#: builtin/push.c:449
msgid "delete refs"
msgstr ""
-#: builtin/push.c:424
+#: builtin/push.c:450
msgid "push tags (can't be used with --all or --mirror)"
msgstr ""
-#: builtin/push.c:427
+#: builtin/push.c:453
msgid "force updates"
msgstr ""
-#: builtin/push.c:428
+#: builtin/push.c:454
msgid "check"
msgstr ""
-#: builtin/push.c:429
+#: builtin/push.c:455
msgid "control recursive pushing of submodules"
msgstr ""
-#: builtin/push.c:431
+#: builtin/push.c:457
msgid "use thin pack"
msgstr ""
-#: builtin/push.c:432 builtin/push.c:433
+#: builtin/push.c:458 builtin/push.c:459
msgid "receive pack program"
msgstr ""
-#: builtin/push.c:434
+#: builtin/push.c:460
msgid "set upstream for git pull/status"
msgstr ""
-#: builtin/push.c:437
+#: builtin/push.c:463
msgid "prune locally removed refs"
msgstr ""
-#: builtin/push.c:439
+#: builtin/push.c:465
msgid "bypass pre-push hook"
msgstr ""
-#: builtin/push.c:448
+#: builtin/push.c:466
+msgid "push missing but relevant tags"
+msgstr ""
+
+#: builtin/push.c:476
msgid "--delete is incompatible with --all, --mirror and --tags"
msgstr ""
-#: builtin/push.c:450
+#: builtin/push.c:478
msgid "--delete doesn't make sense without any refs"
msgstr ""
@@ -6917,70 +7414,80 @@ msgid ""
"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
msgstr ""
-#: builtin/read-tree.c:108
+#: builtin/read-tree.c:109
msgid "write resulting index to <file>"
msgstr ""
-#: builtin/read-tree.c:111
+#: builtin/read-tree.c:112
msgid "only empty the index"
msgstr ""
-#: builtin/read-tree.c:113
+#: builtin/read-tree.c:114
msgid "Merging"
msgstr ""
-#: builtin/read-tree.c:115
+#: builtin/read-tree.c:116
msgid "perform a merge in addition to a read"
msgstr ""
-#: builtin/read-tree.c:117
+#: builtin/read-tree.c:118
msgid "3-way merge if no file level merging required"
msgstr ""
-#: builtin/read-tree.c:119
+#: builtin/read-tree.c:120
msgid "3-way merge in presence of adds and removes"
msgstr ""
-#: builtin/read-tree.c:121
+#: builtin/read-tree.c:122
msgid "same as -m, but discard unmerged entries"
msgstr ""
-#: builtin/read-tree.c:122
+#: builtin/read-tree.c:123
msgid "<subdirectory>/"
msgstr ""
-#: builtin/read-tree.c:123
+#: builtin/read-tree.c:124
msgid "read the tree into the index under <subdirectory>/"
msgstr ""
-#: builtin/read-tree.c:126
+#: builtin/read-tree.c:127
msgid "update working tree with merge result"
msgstr ""
-#: builtin/read-tree.c:128
+#: builtin/read-tree.c:129
msgid "gitignore"
msgstr ""
-#: builtin/read-tree.c:129
+#: builtin/read-tree.c:130
msgid "allow explicitly ignored files to be overwritten"
msgstr ""
-#: builtin/read-tree.c:132
+#: builtin/read-tree.c:133
msgid "don't check the working tree after merging"
msgstr ""
-#: builtin/read-tree.c:133
+#: builtin/read-tree.c:134
msgid "don't update the index or the work tree"
msgstr ""
-#: builtin/read-tree.c:135
+#: builtin/read-tree.c:136
msgid "skip applying sparse checkout filter"
msgstr ""
-#: builtin/read-tree.c:137
+#: builtin/read-tree.c:138
msgid "debug unpack-trees"
msgstr ""
+#: builtin/reflog.c:500
+#, c-format
+msgid "%s' for '%s' is not a valid timestamp"
+msgstr ""
+
+#: builtin/reflog.c:616 builtin/reflog.c:621
+#, c-format
+msgid "'%s' is not a valid timestamp"
+msgstr ""
+
#: builtin/remote.c:11
msgid "git remote [-v | --verbose]"
msgstr ""
@@ -7541,95 +8048,95 @@ msgstr ""
msgid "Failed to find tree of %s."
msgstr ""
-#: builtin/reset.c:98
+#: builtin/reset.c:99
#, c-format
msgid "HEAD is now at %s"
msgstr ""
-#: builtin/reset.c:169
+#: builtin/reset.c:172
#, c-format
msgid "Cannot do a %s reset in the middle of a merge."
msgstr ""
-#: builtin/reset.c:248
+#: builtin/reset.c:251
msgid "be quiet, only report errors"
msgstr ""
-#: builtin/reset.c:250
+#: builtin/reset.c:253
msgid "reset HEAD and index"
msgstr ""
-#: builtin/reset.c:251
+#: builtin/reset.c:254
msgid "reset only HEAD"
msgstr ""
-#: builtin/reset.c:253 builtin/reset.c:255
+#: builtin/reset.c:256 builtin/reset.c:258
msgid "reset HEAD, index and working tree"
msgstr ""
-#: builtin/reset.c:257
+#: builtin/reset.c:260
msgid "reset HEAD but keep local changes"
msgstr ""
-#: builtin/reset.c:275
+#: builtin/reset.c:278
#, c-format
msgid "Failed to resolve '%s' as a valid revision."
msgstr ""
-#: builtin/reset.c:278 builtin/reset.c:286
+#: builtin/reset.c:281 builtin/reset.c:289
#, c-format
msgid "Could not parse object '%s'."
msgstr ""
-#: builtin/reset.c:283
+#: builtin/reset.c:286
#, c-format
msgid "Failed to resolve '%s' as a valid tree."
msgstr ""
-#: builtin/reset.c:292
+#: builtin/reset.c:295
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr ""
-#: builtin/reset.c:301
+#: builtin/reset.c:304
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
-#: builtin/reset.c:303
+#: builtin/reset.c:306
#, c-format
msgid "Cannot do %s reset with paths."
msgstr ""
-#: builtin/reset.c:313
+#: builtin/reset.c:316
#, c-format
msgid "%s reset is not allowed in a bare repository"
msgstr ""
-#: builtin/reset.c:333
+#: builtin/reset.c:336
#, c-format
msgid "Could not reset index file to revision '%s'."
msgstr ""
-#: builtin/reset.c:339
+#: builtin/reset.c:342
msgid "Unstaged changes after reset:"
msgstr ""
-#: builtin/reset.c:344
+#: builtin/reset.c:347
msgid "Could not write new index file."
msgstr ""
-#: builtin/rev-parse.c:339
+#: builtin/rev-parse.c:345
msgid "git rev-parse --parseopt [options] -- [<args>...]"
msgstr ""
-#: builtin/rev-parse.c:344
+#: builtin/rev-parse.c:350
msgid "keep the `--` passed as an arg"
msgstr ""
-#: builtin/rev-parse.c:346
+#: builtin/rev-parse.c:352
msgid "stop parsing after the first non-option argument"
msgstr ""
-#: builtin/rev-parse.c:464
+#: builtin/rev-parse.c:470
msgid ""
"git rev-parse --parseopt [options] -- [<args>...]\n"
" or: git rev-parse --sq-quote [<arg>...]\n"
@@ -7639,7 +8146,7 @@ msgid ""
msgstr ""
#: builtin/revert.c:22
-msgid "git revert [options] <commit-ish>"
+msgid "git revert [options] <commit-ish>..."
msgstr ""
#: builtin/revert.c:23
@@ -7647,174 +8154,196 @@ msgid "git revert <subcommand>"
msgstr ""
#: builtin/revert.c:28
-msgid "git cherry-pick [options] <commit-ish>"
+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
+#: builtin/revert.c:71 builtin/revert.c:94
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr ""
-#: builtin/revert.c:103
+#: builtin/revert.c:105
msgid "end revert or cherry-pick sequence"
msgstr ""
-#: builtin/revert.c:104
+#: builtin/revert.c:106
msgid "resume revert or cherry-pick sequence"
msgstr ""
-#: builtin/revert.c:105
+#: builtin/revert.c:107
msgid "cancel revert or cherry-pick sequence"
msgstr ""
-#: builtin/revert.c:106
+#: builtin/revert.c:108
msgid "don't automatically commit"
msgstr ""
-#: builtin/revert.c:107
+#: builtin/revert.c:109
msgid "edit the commit message"
msgstr ""
-#: builtin/revert.c:110
+#: builtin/revert.c:112
msgid "parent number"
msgstr ""
-#: builtin/revert.c:112
+#: builtin/revert.c:114
msgid "merge strategy"
msgstr ""
-#: builtin/revert.c:113
+#: builtin/revert.c:115
msgid "option"
msgstr ""
-#: builtin/revert.c:114
+#: builtin/revert.c:116
msgid "option for merge strategy"
msgstr ""
-#: builtin/revert.c:125
+#: builtin/revert.c:127
msgid "append commit name"
msgstr ""
-#: builtin/revert.c:126
+#: builtin/revert.c:128
msgid "allow fast-forward"
msgstr ""
-#: builtin/revert.c:127
+#: builtin/revert.c:129
msgid "preserve initially empty commits"
msgstr ""
-#: builtin/revert.c:128
+#: builtin/revert.c:130
msgid "allow commits with empty messages"
msgstr ""
-#: builtin/revert.c:129
+#: builtin/revert.c:131
msgid "keep redundant, empty commits"
msgstr ""
-#: builtin/revert.c:133
+#: builtin/revert.c:135
msgid "program error"
msgstr ""
-#: builtin/revert.c:223
+#: builtin/revert.c:225
msgid "revert failed"
msgstr ""
-#: builtin/revert.c:238
+#: builtin/revert.c:240
msgid "cherry-pick failed"
msgstr ""
-#: builtin/rm.c:15
+#: builtin/rm.c:16
msgid "git rm [options] [--] <file>..."
msgstr ""
-#: builtin/rm.c:64 builtin/rm.c:186
-#, c-format
+#: builtin/rm.c:64
msgid ""
-"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"the following submodule (or one of its nested submodules)\n"
+"uses a .git directory:"
+msgid_plural ""
+"the following submodules (or one of its nested submodules)\n"
+"use a .git directory:"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/rm.c:70
+msgid ""
+"\n"
"(use 'rm -rf' if you really want to remove it including all of its history)"
msgstr ""
-#: builtin/rm.c:174
-#, c-format
+#: builtin/rm.c:230
msgid ""
-"'%s' has staged content different from both the file and the HEAD\n"
-"(use -f to force removal)"
-msgstr ""
+"the following file has staged content different from both the\n"
+"file and the HEAD:"
+msgid_plural ""
+"the following files have staged content different from both the\n"
+"file and the HEAD:"
+msgstr[0] ""
+msgstr[1] ""
-#: builtin/rm.c:180
-#, c-format
+#: builtin/rm.c:235
msgid ""
-"'%s' has changes staged in the index\n"
-"(use --cached to keep the file, or -f to force removal)"
+"\n"
+"(use -f to force removal)"
msgstr ""
-#: builtin/rm.c:191
-#, c-format
+#: builtin/rm.c:239
+msgid "the following file has changes staged in the index:"
+msgid_plural "the following files have changes staged in the index:"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/rm.c:243 builtin/rm.c:254
msgid ""
-"'%s' has local modifications\n"
+"\n"
"(use --cached to keep the file, or -f to force removal)"
msgstr ""
-#: builtin/rm.c:207
+#: builtin/rm.c:251
+msgid "the following file has local modifications:"
+msgid_plural "the following files have local modifications:"
+msgstr[0] ""
+msgstr[1] ""
+
+#: builtin/rm.c:269
msgid "do not list removed files"
msgstr ""
-#: builtin/rm.c:208
+#: builtin/rm.c:270
msgid "only remove from the index"
msgstr ""
-#: builtin/rm.c:209
+#: builtin/rm.c:271
msgid "override the up-to-date check"
msgstr ""
-#: builtin/rm.c:210
+#: builtin/rm.c:272
msgid "allow recursive removal"
msgstr ""
-#: builtin/rm.c:212
+#: builtin/rm.c:274
msgid "exit with a zero status even if nothing matched"
msgstr ""
-#: builtin/rm.c:283
+#: builtin/rm.c:345
#, c-format
msgid "not removing '%s' recursively without -r"
msgstr ""
-#: builtin/rm.c:322
+#: builtin/rm.c:384
#, c-format
msgid "git rm: unable to remove %s"
msgstr ""
#: builtin/shortlog.c:13
-msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+msgid "git shortlog [<options>] [<revision range>] [[--] [<path>...]]"
msgstr ""
-#: builtin/shortlog.c:133
+#: builtin/shortlog.c:131
#, c-format
msgid "Missing author: %s"
msgstr ""
-#: builtin/shortlog.c:229
+#: builtin/shortlog.c:228
msgid "sort output according to the number of commits per author"
msgstr ""
-#: builtin/shortlog.c:231
+#: builtin/shortlog.c:230
msgid "Suppress commit descriptions, only provides commit count"
msgstr ""
-#: builtin/shortlog.c:233
+#: builtin/shortlog.c:232
msgid "Show the email address of each author"
msgstr ""
-#: builtin/shortlog.c:234
+#: builtin/shortlog.c:233
msgid "w[,i1[,i2]]"
msgstr ""
-#: builtin/shortlog.c:235
+#: builtin/shortlog.c:234
msgid "Linewrap output"
msgstr ""
@@ -7830,47 +8359,47 @@ msgstr ""
msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
msgstr ""
-#: builtin/show-branch.c:651
+#: builtin/show-branch.c:650
msgid "show remote-tracking and local branches"
msgstr ""
-#: builtin/show-branch.c:653
+#: builtin/show-branch.c:652
msgid "show remote-tracking branches"
msgstr ""
-#: builtin/show-branch.c:655
+#: builtin/show-branch.c:654
msgid "color '*!+-' corresponding to the branch"
msgstr ""
-#: builtin/show-branch.c:657
+#: builtin/show-branch.c:656
msgid "show <n> more commits after the common ancestor"
msgstr ""
-#: builtin/show-branch.c:659
+#: builtin/show-branch.c:658
msgid "synonym to more=-1"
msgstr ""
-#: builtin/show-branch.c:660
+#: builtin/show-branch.c:659
msgid "suppress naming strings"
msgstr ""
-#: builtin/show-branch.c:662
+#: builtin/show-branch.c:661
msgid "include the current branch"
msgstr ""
-#: builtin/show-branch.c:664
+#: builtin/show-branch.c:663
msgid "name commits with their object names"
msgstr ""
-#: builtin/show-branch.c:666
+#: builtin/show-branch.c:665
msgid "show possible merge bases"
msgstr ""
-#: builtin/show-branch.c:668
+#: builtin/show-branch.c:667
msgid "show refs unreachable from any other ref"
msgstr ""
-#: builtin/show-branch.c:670
+#: builtin/show-branch.c:669
msgid "show commits in topological order"
msgstr ""
@@ -7883,14 +8412,14 @@ msgid "show merges reachable from only one tip"
msgstr ""
#: builtin/show-branch.c:676
-msgid "show commits where no parent comes before its children"
+msgid "topologically sort, maintaining date order where possible"
msgstr ""
-#: builtin/show-branch.c:678
+#: builtin/show-branch.c:679
msgid "<n>[,<base>]"
msgstr ""
-#: builtin/show-branch.c:679
+#: builtin/show-branch.c:680
msgid "show <n> most recent ref-log entries starting at base"
msgstr ""
@@ -7904,35 +8433,35 @@ msgstr ""
msgid "git show-ref --exclude-existing[=pattern] < ref-list"
msgstr ""
-#: builtin/show-ref.c:165
+#: builtin/show-ref.c:168
msgid "only show tags (can be combined with heads)"
msgstr ""
-#: builtin/show-ref.c:166
+#: builtin/show-ref.c:169
msgid "only show heads (can be combined with tags)"
msgstr ""
-#: builtin/show-ref.c:167
+#: builtin/show-ref.c:170
msgid "stricter reference checking, requires exact ref path"
msgstr ""
-#: builtin/show-ref.c:170 builtin/show-ref.c:172
-msgid "show the HEAD reference"
+#: builtin/show-ref.c:173 builtin/show-ref.c:176
+msgid "show the HEAD reference, even if it would be filtered out"
msgstr ""
-#: builtin/show-ref.c:174
+#: builtin/show-ref.c:178
msgid "dereference tags into object IDs"
msgstr ""
-#: builtin/show-ref.c:176
+#: builtin/show-ref.c:180
msgid "only show SHA1 hash using <n> digits"
msgstr ""
-#: builtin/show-ref.c:180
+#: builtin/show-ref.c:184
msgid "do not print results to stdout (useful with --verify)"
msgstr ""
-#: builtin/show-ref.c:182
+#: builtin/show-ref.c:186
msgid "show refs from stdin that aren't in local repository"
msgstr ""
@@ -8336,23 +8865,30 @@ msgstr ""
msgid "only useful for debugging"
msgstr ""
-#: git.c:16
-msgid "See 'git help <command>' for more information on a specific command."
+#: git.c:17
+msgid ""
+"'git help -a' and 'git help -g' lists available subcommands and some\n"
+"concept guides. See 'git help <command>' or 'git help <concept>'\n"
+"to read about a specific subcommand or concept."
+msgstr ""
+
+#: parse-options.h:144
+msgid "expiry date"
msgstr ""
-#: parse-options.h:156
+#: parse-options.h:159
msgid "no-op (backward compatibility)"
msgstr ""
-#: parse-options.h:232
+#: parse-options.h:236
msgid "be more verbose"
msgstr ""
-#: parse-options.h:234
+#: parse-options.h:238
msgid "be more quiet"
msgstr ""
-#: parse-options.h:240
+#: parse-options.h:244
msgid "use <n> digits to display SHA-1s"
msgstr ""
@@ -8409,7 +8945,7 @@ msgid "Move or rename a file, a directory, or a symlink"
msgstr ""
#: common-cmds.h:21
-msgid "Fetch from and merge with another repository or a local branch"
+msgid "Fetch from and integrate with another repository or a local branch"
msgstr ""
#: common-cmds.h:22
@@ -8453,7 +8989,7 @@ msgstr ""
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"When you have resolved this problem, run \"$cmdline --continue\".\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 ""
@@ -8503,25 +9039,32 @@ msgid ""
"it will be removed. Please do not use it anymore."
msgstr ""
-#: git-am.sh:477
+#: git-am.sh:479
#, sh-format
msgid "previous rebase directory $dotest still exists but mbox given."
msgstr ""
-#: git-am.sh:482
+#: git-am.sh:484
msgid "Please make up your mind. --skip or --abort?"
msgstr ""
-#: git-am.sh:509
+#: git-am.sh:520
+#, sh-format
+msgid ""
+"Stray $dotest directory found.\n"
+"Use \"git am --abort\" to remove it."
+msgstr ""
+
+#: git-am.sh:528
msgid "Resolve operation not in progress, we are not resuming."
msgstr ""
-#: git-am.sh:575
+#: git-am.sh:594
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
msgstr ""
-#: git-am.sh:679
+#: git-am.sh:698
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -8529,60 +9072,60 @@ msgid ""
"To restore the original branch and stop patching run \"$cmdline --abort\"."
msgstr ""
-#: git-am.sh:706
+#: git-am.sh:725
msgid "Patch does not have a valid e-mail address."
msgstr ""
-#: git-am.sh:753
+#: git-am.sh:772
msgid "cannot be interactive without stdin connected to a terminal."
msgstr ""
-#: git-am.sh:757
+#: git-am.sh:776
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:764
+#: git-am.sh:783
msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
msgstr ""
-#: git-am.sh:800
+#: git-am.sh:819
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr ""
-#: git-am.sh:821
+#: git-am.sh:840
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:829
+#: git-am.sh:848
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
msgstr ""
-#: git-am.sh:845
+#: git-am.sh:864
msgid "No changes -- Patch already applied."
msgstr ""
-#: git-am.sh:855
+#: git-am.sh:874
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr ""
-#: git-am.sh:858
+#: git-am.sh:877
#, sh-format
msgid ""
"The copy of the patch that failed is found in:\n"
" $dotest/patch"
msgstr ""
-#: git-am.sh:876
+#: git-am.sh:895
msgid "applying to an empty history"
msgstr ""
@@ -8674,59 +9217,59 @@ msgid ""
"(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
msgstr ""
-#: git-bisect.sh:347 git-bisect.sh:474
+#: git-bisect.sh:363 git-bisect.sh:490
msgid "We are not bisecting."
msgstr ""
-#: git-bisect.sh:354
+#: git-bisect.sh:370
#, sh-format
msgid "'$invalid' is not a valid commit"
msgstr ""
-#: git-bisect.sh:363
+#: git-bisect.sh:379
#, sh-format
msgid ""
"Could not check out original HEAD '$branch'.\n"
"Try 'git bisect reset <commit>'."
msgstr ""
-#: git-bisect.sh:390
+#: git-bisect.sh:406
msgid "No logfile given"
msgstr ""
-#: git-bisect.sh:391
+#: git-bisect.sh:407
#, sh-format
msgid "cannot read $file for replaying"
msgstr ""
-#: git-bisect.sh:408
+#: git-bisect.sh:424
msgid "?? what are you talking about?"
msgstr ""
-#: git-bisect.sh:420
+#: git-bisect.sh:436
#, sh-format
msgid "running $command"
msgstr ""
-#: git-bisect.sh:427
+#: git-bisect.sh:443
#, sh-format
msgid ""
"bisect run failed:\n"
"exit code $res from '$command' is < 0 or >= 128"
msgstr ""
-#: git-bisect.sh:453
+#: git-bisect.sh:469
msgid "bisect run cannot continue any more"
msgstr ""
-#: git-bisect.sh:459
+#: git-bisect.sh:475
#, sh-format
msgid ""
"bisect run failed:\n"
"'bisect_state $state' exited with error code $res"
msgstr ""
-#: git-bisect.sh:466
+#: git-bisect.sh:482
msgid "bisect run success"
msgstr ""
@@ -8741,7 +9284,7 @@ msgstr ""
msgid "Pull is not possible because you have unmerged files."
msgstr ""
-#: git-pull.sh:197
+#: git-pull.sh:203
msgid "updating an unborn branch with changes added to the index"
msgstr ""
@@ -8749,7 +9292,7 @@ msgstr ""
#. The working tree and the index file is still based on the
#. $orig_head commit, but we are merging into $curr_head.
#. First update the working tree to match $curr_head.
-#: git-pull.sh:229
+#: git-pull.sh:235
#, sh-format
msgid ""
"Warning: fetch updated the current branch head.\n"
@@ -8757,15 +9300,15 @@ msgid ""
"Warning: commit $orig_head."
msgstr ""
-#: git-pull.sh:254
+#: git-pull.sh:260
msgid "Cannot merge multiple branches into empty head"
msgstr ""
-#: git-pull.sh:258
+#: git-pull.sh:264
msgid "Cannot rebase onto multiple branches"
msgstr ""
-#: git-rebase.sh:53
+#: git-rebase.sh:54
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"
@@ -8773,42 +9316,58 @@ msgid ""
"\"."
msgstr ""
+#: git-rebase.sh:156
+msgid "Applied autostash."
+msgstr ""
+
+#: git-rebase.sh:159
+#, sh-format
+msgid "Cannot store $stash_sha1"
+msgstr ""
+
#: git-rebase.sh:160
+msgid ""
+"Applying autostash resulted in conflicts.\n"
+"Your changes are safe in the stash.\n"
+"You can run \"git stash pop\" or \"git stash drop\" at any time.\n"
+msgstr ""
+
+#: git-rebase.sh:190
msgid "The pre-rebase hook refused to rebase."
msgstr ""
-#: git-rebase.sh:165
+#: git-rebase.sh:195
msgid "It looks like git-am is in progress. Cannot rebase."
msgstr ""
-#: git-rebase.sh:296
+#: git-rebase.sh:329
msgid "The --exec option must be used with the --interactive option"
msgstr ""
-#: git-rebase.sh:301
+#: git-rebase.sh:334
msgid "No rebase in progress?"
msgstr ""
-#: git-rebase.sh:312
+#: git-rebase.sh:345
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
-#: git-rebase.sh:319
+#: git-rebase.sh:352
msgid "Cannot read HEAD"
msgstr ""
-#: git-rebase.sh:322
+#: git-rebase.sh:355
msgid ""
"You must edit all merge conflicts and then\n"
"mark them as resolved using git add"
msgstr ""
-#: git-rebase.sh:340
+#: git-rebase.sh:373
#, sh-format
msgid "Could not move back to $head_name"
msgstr ""
-#: git-rebase.sh:359
+#: git-rebase.sh:392
#, sh-format
msgid ""
"It seems that there is already a $state_dir_base directory, and\n"
@@ -8821,56 +9380,65 @@ msgid ""
"valuable there."
msgstr ""
-#: git-rebase.sh:404
+#: git-rebase.sh:437
#, sh-format
msgid "invalid upstream $upstream_name"
msgstr ""
-#: git-rebase.sh:428
+#: git-rebase.sh:461
#, sh-format
msgid "$onto_name: there are more than one merge bases"
msgstr ""
-#: git-rebase.sh:431 git-rebase.sh:435
+#: git-rebase.sh:464 git-rebase.sh:468
#, sh-format
msgid "$onto_name: there is no merge base"
msgstr ""
-#: git-rebase.sh:440
+#: git-rebase.sh:473
#, sh-format
msgid "Does not point to a valid commit: $onto_name"
msgstr ""
-#: git-rebase.sh:463
+#: git-rebase.sh:496
#, sh-format
msgid "fatal: no such branch: $branch_name"
msgstr ""
-#: git-rebase.sh:483
+#: git-rebase.sh:519
+msgid "Cannot autostash"
+msgstr ""
+
+#: git-rebase.sh:524
+#, sh-format
+msgid "Created autostash: $stash_abbrev"
+msgstr ""
+
+#: git-rebase.sh:528
msgid "Please commit or stash them."
msgstr ""
-#: git-rebase.sh:501
+#: git-rebase.sh:548
#, sh-format
msgid "Current branch $branch_name is up to date."
msgstr ""
-#: git-rebase.sh:504
+#: git-rebase.sh:552
#, sh-format
msgid "Current branch $branch_name is up to date, rebase forced."
msgstr ""
-#: git-rebase.sh:515
+#: git-rebase.sh:563
#, sh-format
msgid "Changes from $mb to $onto:"
msgstr ""
#. Detach HEAD and reset the tree
-#: git-rebase.sh:524
+#: git-rebase.sh:572
msgid "First, rewinding head to replay your work on top of it..."
msgstr ""
-#: git-rebase.sh:532
+#: git-rebase.sh:582
#, sh-format
msgid "Fast-forwarded $branch_name to $onto_name."
msgstr ""
@@ -8903,6 +9471,11 @@ msgstr ""
msgid "Cannot record working tree state"
msgstr ""
+#: git-stash.sh:190
+#, sh-format
+msgid "Cannot update $ref_stash with $w_commit"
+msgstr ""
+
#. TRANSLATORS: $option is an invalid option, like
#. `--blah-blah'. The 7 spaces at the beginning of the
#. second line correspond to "error: ". So you should line
@@ -8913,126 +9486,141 @@ msgstr ""
#. $ git stash save --blah-blah 2>&1 | head -n 2
#. error: unknown option for 'stash save': --blah-blah
#. To provide a message, use git stash save -- '--blah-blah'
-#: git-stash.sh:202
+#: git-stash.sh:241
#, sh-format
msgid ""
"error: unknown option for 'stash save': $option\n"
" To provide a message, use git stash save -- '$option'"
msgstr ""
-#: git-stash.sh:223
+#: git-stash.sh:262
msgid "No local changes to save"
msgstr ""
-#: git-stash.sh:227
+#: git-stash.sh:268
+msgid ""
+"The following untracked files would NOT be saved but need to be removed by "
+"stash save:"
+msgstr ""
+
+#: git-stash.sh:270
+msgid ""
+"Aborting. Consider using either the --force or --include-untracked option."
+msgstr ""
+
+#: git-stash.sh:274
msgid "Cannot initialize stash"
msgstr ""
-#: git-stash.sh:235
+#: git-stash.sh:278
msgid "Cannot save the current status"
msgstr ""
-#: git-stash.sh:253
+#: git-stash.sh:296
msgid "Cannot remove worktree changes"
msgstr ""
-#: git-stash.sh:352
+#: git-stash.sh:395
msgid "No stash found."
msgstr ""
-#: git-stash.sh:359
+#: git-stash.sh:402
#, sh-format
msgid "Too many revisions specified: $REV"
msgstr ""
-#: git-stash.sh:365
+#: git-stash.sh:408
#, sh-format
msgid "$reference is not valid reference"
msgstr ""
-#: git-stash.sh:393
+#: git-stash.sh:436
#, sh-format
msgid "'$args' is not a stash-like commit"
msgstr ""
-#: git-stash.sh:404
+#: git-stash.sh:447
#, sh-format
msgid "'$args' is not a stash reference"
msgstr ""
-#: git-stash.sh:412
+#: git-stash.sh:455
msgid "unable to refresh index"
msgstr ""
-#: git-stash.sh:416
+#: git-stash.sh:459
msgid "Cannot apply a stash in the middle of a merge"
msgstr ""
-#: git-stash.sh:424
+#: git-stash.sh:467
msgid "Conflicts in index. Try without --index."
msgstr ""
-#: git-stash.sh:426
+#: git-stash.sh:469
msgid "Could not save index tree"
msgstr ""
-#: git-stash.sh:460
+#: git-stash.sh:503
msgid "Cannot unstage modified files"
msgstr ""
-#: git-stash.sh:475
+#: git-stash.sh:518
msgid "Index was not unstashed."
msgstr ""
-#: git-stash.sh:492
+#: git-stash.sh:535
#, sh-format
msgid "Dropped ${REV} ($s)"
msgstr ""
-#: git-stash.sh:493
+#: git-stash.sh:536
#, sh-format
msgid "${REV}: Could not drop stash entry"
msgstr ""
-#: git-stash.sh:500
+#: git-stash.sh:543
msgid "No branch name specified"
msgstr ""
-#: git-stash.sh:571
+#: git-stash.sh:615
msgid "(To restore them type \"git stash apply\")"
msgstr ""
-#: git-submodule.sh:90
+#: git-submodule.sh:95
#, sh-format
msgid "cannot strip one component off url '$remoteurl'"
msgstr ""
-#: git-submodule.sh:195
+#: git-submodule.sh:237
#, sh-format
msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
msgstr ""
-#: git-submodule.sh:238
+#: git-submodule.sh:281
#, sh-format
msgid "Clone of '$url' into submodule path '$sm_path' failed"
msgstr ""
-#: git-submodule.sh:250
+#: git-submodule.sh:293
#, sh-format
msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
msgstr ""
-#: git-submodule.sh:343
+#: git-submodule.sh:403
+msgid "Relative path can only be used from the toplevel of the working tree"
+msgstr ""
+
+#: git-submodule.sh:413
#, sh-format
msgid "repo URL: '$repo' must be absolute or begin with ./|../"
msgstr ""
-#: git-submodule.sh:360
+#: git-submodule.sh:430
#, sh-format
msgid "'$sm_path' already exists in the index"
msgstr ""
-#: git-submodule.sh:364
+#: git-submodule.sh:434
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
@@ -9040,180 +9628,244 @@ msgid ""
"Use -f if you really want to add it."
msgstr ""
-#: git-submodule.sh:382
+#: git-submodule.sh:452
#, sh-format
msgid "Adding existing repo at '$sm_path' to the index"
msgstr ""
-#: git-submodule.sh:384
+#: git-submodule.sh:454
#, sh-format
msgid "'$sm_path' already exists and is not a valid git repo"
msgstr ""
-#: git-submodule.sh:392
+#: git-submodule.sh:462
#, sh-format
msgid "A git directory for '$sm_name' is found locally with remote(s):"
msgstr ""
-#: git-submodule.sh:394
+#: git-submodule.sh:464
#, sh-format
msgid ""
"If you want to reuse this local git directory instead of cloning again from"
msgstr ""
-#: git-submodule.sh:396
+#: git-submodule.sh:466
#, sh-format
msgid ""
"use the '--force' option. If the local git directory is not the correct repo"
msgstr ""
-#: git-submodule.sh:397
+#: git-submodule.sh:467
#, sh-format
msgid ""
"or you are unsure what this means choose another name with the '--name' "
"option."
msgstr ""
-#: git-submodule.sh:399
+#: git-submodule.sh:469
#, sh-format
msgid "Reactivating local git directory for submodule '$sm_name'."
msgstr ""
-#: git-submodule.sh:411
+#: git-submodule.sh:481
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
msgstr ""
-#: git-submodule.sh:416
+#: git-submodule.sh:486
#, sh-format
msgid "Failed to add submodule '$sm_path'"
msgstr ""
-#: git-submodule.sh:425
+#: git-submodule.sh:495
#, sh-format
msgid "Failed to register submodule '$sm_path'"
msgstr ""
-#: git-submodule.sh:468
+#: git-submodule.sh:539
+#, sh-format
+msgid "Entering '$prefix$displaypath'"
+msgstr ""
+
+#: git-submodule.sh:554
#, sh-format
-msgid "Entering '$prefix$sm_path'"
+msgid "Stopping at '$prefix$displaypath'; script returned non-zero status."
msgstr ""
-#: git-submodule.sh:482
+#: git-submodule.sh:600
#, sh-format
-msgid "Stopping at '$sm_path'; script returned non-zero status."
+msgid "No url found for submodule path '$displaypath' in .gitmodules"
msgstr ""
-#: git-submodule.sh:526
+#: git-submodule.sh:609
#, sh-format
-msgid "No url found for submodule path '$sm_path' in .gitmodules"
+msgid "Failed to register url for submodule path '$displaypath'"
msgstr ""
-#: git-submodule.sh:535
+#: git-submodule.sh:611
#, sh-format
-msgid "Failed to register url for submodule path '$sm_path'"
+msgid "Submodule '$name' ($url) registered for path '$displaypath'"
msgstr ""
-#: git-submodule.sh:537
+#: git-submodule.sh:619
#, sh-format
-msgid "Submodule '$name' ($url) registered for path '$sm_path'"
+msgid "Failed to register update mode for submodule path '$displaypath'"
msgstr ""
-#: git-submodule.sh:545
+#: git-submodule.sh:656
#, sh-format
-msgid "Failed to register update mode for submodule path '$sm_path'"
+msgid "Use '.' if you really want to deinitialize all submodules"
+msgstr ""
+
+#: git-submodule.sh:673
+#, sh-format
+msgid "Submodule work tree '$displaypath' contains a .git directory"
+msgstr ""
+
+#: git-submodule.sh:674
+#, sh-format
+msgid ""
+"(use 'rm -rf' if you really want to remove it including all of its history)"
msgstr ""
-#: git-submodule.sh:649
+#: git-submodule.sh:680
#, sh-format
msgid ""
-"Submodule path '$sm_path' not initialized\n"
+"Submodule work tree '$displaypath' contains local modifications; use '-f' to "
+"discard them"
+msgstr ""
+
+#: git-submodule.sh:683
+#, sh-format
+msgid "Cleared directory '$displaypath'"
+msgstr ""
+
+#: git-submodule.sh:684
+#, sh-format
+msgid "Could not remove submodule work tree '$displaypath'"
+msgstr ""
+
+#: git-submodule.sh:687
+#, sh-format
+msgid "Could not create empty submodule directory '$displaypath'"
+msgstr ""
+
+#: git-submodule.sh:696
+#, sh-format
+msgid "Submodule '$name' ($url) unregistered for path '$displaypath'"
+msgstr ""
+
+#: git-submodule.sh:811
+#, sh-format
+msgid ""
+"Submodule path '$displaypath' not initialized\n"
"Maybe you want to use 'update --init'?"
msgstr ""
-#: git-submodule.sh:662
+#: git-submodule.sh:824
#, sh-format
-msgid "Unable to find current revision in submodule path '$sm_path'"
+msgid "Unable to find current revision in submodule path '$displaypath'"
msgstr ""
-#: git-submodule.sh:671 git-submodule.sh:695
+#: git-submodule.sh:833
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
msgstr ""
-#: git-submodule.sh:709
+#: git-submodule.sh:857
#, sh-format
-msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
+msgid "Unable to fetch in submodule path '$displaypath'"
msgstr ""
-#: git-submodule.sh:710
+#: git-submodule.sh:871
#, sh-format
-msgid "Submodule path '$sm_path': rebased into '$sha1'"
+msgid "Unable to rebase '$sha1' in submodule path '$displaypath'"
msgstr ""
-#: git-submodule.sh:715
+#: git-submodule.sh:872
#, sh-format
-msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
+msgid "Submodule path '$displaypath': rebased into '$sha1'"
msgstr ""
-#: git-submodule.sh:716
+#: git-submodule.sh:877
#, sh-format
-msgid "Submodule path '$sm_path': merged in '$sha1'"
+msgid "Unable to merge '$sha1' in submodule path '$displaypath'"
msgstr ""
-#: git-submodule.sh:721
+#: git-submodule.sh:878
#, sh-format
-msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
+msgid "Submodule path '$displaypath': merged in '$sha1'"
msgstr ""
-#: git-submodule.sh:722
+#: git-submodule.sh:883
#, sh-format
-msgid "Submodule path '$sm_path': checked out '$sha1'"
+msgid ""
+"Execution of '$command $sha1' failed in submodule path '$prefix$sm_path'"
msgstr ""
-#: git-submodule.sh:744 git-submodule.sh:1066
+#: git-submodule.sh:884
#, sh-format
-msgid "Failed to recurse into submodule path '$sm_path'"
+msgid "Submodule path '$prefix$sm_path': '$command $sha1'"
+msgstr ""
+
+#: git-submodule.sh:889
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$displaypath'"
msgstr ""
-#: git-submodule.sh:852
+#: git-submodule.sh:890
+#, sh-format
+msgid "Submodule path '$displaypath': checked out '$sha1'"
+msgstr ""
+
+#: git-submodule.sh:917
+#, sh-format
+msgid "Failed to recurse into submodule path '$displaypath'"
+msgstr ""
+
+#: git-submodule.sh:1025
msgid "The --cached option cannot be used with the --files option"
msgstr ""
#. unexpected type
-#: git-submodule.sh:892
+#: git-submodule.sh:1066
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr ""
-#: git-submodule.sh:910
+#: git-submodule.sh:1086
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_src"
+msgid " Warn: $display_name doesn't contain commit $sha1_src"
msgstr ""
-#: git-submodule.sh:913
+#: git-submodule.sh:1089
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_dst"
+msgid " Warn: $display_name doesn't contain commit $sha1_dst"
msgstr ""
-#: git-submodule.sh:916
+#: git-submodule.sh:1092
#, sh-format
-msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgid " Warn: $display_name doesn't contain commits $sha1_src and $sha1_dst"
msgstr ""
-#: git-submodule.sh:941
+#: git-submodule.sh:1117
msgid "blob"
msgstr ""
-#: git-submodule.sh:979
+#: git-submodule.sh:1155
msgid "Submodules changed but not updated:"
msgstr ""
-#: git-submodule.sh:981
+#: git-submodule.sh:1157
msgid "Submodule changes to be committed:"
msgstr ""
-#: git-submodule.sh:1129
+#: git-submodule.sh:1242
+#, sh-format
+msgid "Failed to recurse into submodule path '$sm_path'"
+msgstr ""
+
+#: git-submodule.sh:1306
#, sh-format
-msgid "Synchronizing submodule url for '$prefix$sm_path'"
+msgid "Synchronizing submodule url for '$displaypath'"
msgstr ""
diff --git a/po/sv.po b/po/sv.po
index 15f1aa8..12dfca9 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: git 1.8.2\n"
+"Project-Id-Version: git 1.8.4\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2013-03-05 12:36+0800\n"
-"PO-Revision-Date: 2013-03-05 09:17+0100\n"
+"POT-Creation-Date: 2013-08-06 14:10+0800\n"
+"PO-Revision-Date: 2013-08-06 12:37+0100\n"
"Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"Language: sv\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: advice.c:49
+#: advice.c:57
#, c-format
msgid "hint: %.*s\n"
msgstr "tips: %.*s\n"
@@ -26,7 +26,7 @@ msgstr "tips: %.*s\n"
#. * Message used both when 'git commit' fails and when
#. * other commands doing a merge do.
#.
-#: advice.c:79
+#: advice.c:87
msgid ""
"Fix them up in the work tree,\n"
"and then use 'git add/rm <file>' as\n"
@@ -65,7 +65,7 @@ msgstr "fmt"
msgid "archive format"
msgstr "arkivformat"
-#: archive.c:324 builtin/log.c:1115
+#: archive.c:324 builtin/log.c:1173
msgid "prefix"
msgstr "prefix"
@@ -73,15 +73,15 @@ msgstr "prefix"
msgid "prepend prefix to each pathname in the archive"
msgstr "lägg till prefix till varje sökväg i arkivet"
-#: archive.c:326 builtin/archive.c:91 builtin/blame.c:2366
-#: builtin/blame.c:2367 builtin/config.c:55 builtin/fast-export.c:653
-#: builtin/fast-export.c:655 builtin/grep.c:715 builtin/hash-object.c:77
-#: builtin/ls-files.c:497 builtin/ls-files.c:500 builtin/notes.c:536
-#: builtin/notes.c:693 builtin/read-tree.c:107 parse-options.h:149
+#: archive.c:326 builtin/archive.c:88 builtin/blame.c:2292
+#: builtin/blame.c:2293 builtin/config.c:56 builtin/fast-export.c:673
+#: builtin/fast-export.c:675 builtin/grep.c:714 builtin/hash-object.c:77
+#: builtin/ls-files.c:496 builtin/ls-files.c:499 builtin/notes.c:408
+#: builtin/notes.c:565 builtin/read-tree.c:108 parse-options.h:152
msgid "file"
msgstr "fil"
-#: archive.c:327 builtin/archive.c:92
+#: archive.c:327 builtin/archive.c:89
msgid "write the archive to this file"
msgstr "skriv arkivet till filen"
@@ -109,19 +109,19 @@ msgstr "komprimera bättre"
msgid "list supported archive formats"
msgstr "visa understödda arkivformat"
-#: archive.c:345 builtin/archive.c:93 builtin/clone.c:85
+#: archive.c:345 builtin/archive.c:90 builtin/clone.c:85
msgid "repo"
msgstr "arkiv"
-#: archive.c:346 builtin/archive.c:94
+#: archive.c:346 builtin/archive.c:91
msgid "retrieve the archive from remote repository <repo>"
msgstr "hämta arkivet från fjärrarkivet <arkiv>"
-#: archive.c:347 builtin/archive.c:95 builtin/notes.c:615
+#: archive.c:347 builtin/archive.c:92 builtin/notes.c:487
msgid "command"
msgstr "kommando"
-#: archive.c:348 builtin/archive.c:96
+#: archive.c:348 builtin/archive.c:93
msgid "path to the remote git-upload-archive command"
msgstr "sökväg till kommandot git-upload-archive på fjärren"
@@ -133,6 +133,130 @@ msgstr ""
"Negativa mönster ignoreras i git-attribut\n"
"Använd '\\!' för att inleda med ett utropstecken."
+#: branch.c:60
+#, c-format
+msgid "Not setting branch %s as its own upstream."
+msgstr "Ställer inte in grenen %s som sin egen uppströmsgren."
+
+#: branch.c:82
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s by rebasing."
+msgstr ""
+"Grenen %s ställdes in att spåra fjärrgrenen %s från %s genom ombasering."
+
+#: branch.c:83
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s."
+msgstr "Grenen %s ställdes in att spåra fjärrgrenen %s från %s."
+
+#: branch.c:87
+#, c-format
+msgid "Branch %s set up to track local branch %s by rebasing."
+msgstr "Grenen %s ställdes in att spåra den lokala grenen %s genom ombasering."
+
+#: branch.c:88
+#, c-format
+msgid "Branch %s set up to track local branch %s."
+msgstr "Grenen %s ställdes in att spåra den lokala grenen %s."
+
+#: branch.c:92
+#, c-format
+msgid "Branch %s set up to track remote ref %s by rebasing."
+msgstr "Grenen %s ställdes in att spåra fjärreferensen %s genom ombasering."
+
+#: branch.c:93
+#, c-format
+msgid "Branch %s set up to track remote ref %s."
+msgstr "Grenen %s ställdes in att spåra fjärreferensen %s."
+
+#: branch.c:97
+#, c-format
+msgid "Branch %s set up to track local ref %s by rebasing."
+msgstr ""
+"Grenen %s ställdes in att spåra den lokala referensen %s genom ombasering."
+
+#: branch.c:98
+#, c-format
+msgid "Branch %s set up to track local ref %s."
+msgstr "Grenen %s ställdes in att spåra den lokala referensen %s."
+
+#: branch.c:118
+#, c-format
+msgid "Tracking not set up: name too long: %s"
+msgstr "Spårning har inte ställts in: namnet för långt: %s"
+
+#: branch.c:137
+#, c-format
+msgid "Not tracking: ambiguous information for ref %s"
+msgstr "Spårar inte: tvetydig information för referensen %s"
+
+#: branch.c:182
+#, c-format
+msgid "'%s' is not a valid branch name."
+msgstr "\"%s\" är inte ett giltigt grennamn."
+
+#: branch.c:187
+#, c-format
+msgid "A branch named '%s' already exists."
+msgstr "Det finns redan en gren som heter \"%s\""
+
+#: branch.c:195
+msgid "Cannot force update the current branch."
+msgstr "Kan inte tvinga uppdatering av aktuell gren."
+
+#: branch.c:216
+#, c-format
+msgid "Cannot setup tracking information; starting point '%s' is not a branch."
+msgstr "Kan inte ställa in spårning; startpunkten \"%s\" är inte en gren."
+
+#: branch.c:218
+#, c-format
+msgid "the requested upstream branch '%s' does not exist"
+msgstr "den efterfrågade uppströmsgrenen \"%s\" finns inte"
+
+#: branch.c:220
+msgid ""
+"\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push."
+msgstr ""
+"\n"
+"Om du har tänkt basera ditt arbete på en uppströmsgren\n"
+"som redan finns på fjärren kan du behöva köra \"git fetch\"\n"
+"för att hämta den.\n"
+"\n"
+"Om du har tänkt sända in en ny lokal gren som skall\n"
+"spåra dess fjärrmotsvarighet kan du använda \"git push -u\"\n"
+"för att ställa in uppströmskonfigurationen när du sänder in."
+
+#: branch.c:265
+#, c-format
+msgid "Not a valid object name: '%s'."
+msgstr "Objektnamnet är inte giltigt: \"%s\"."
+
+#: branch.c:285
+#, c-format
+msgid "Ambiguous object name: '%s'."
+msgstr "Objektnamnet är tvetydigt: \"%s\"."
+
+#: branch.c:290
+#, c-format
+msgid "Not a valid branch point: '%s'."
+msgstr "Avgreningspunkten är inte giltig: \"%s\""
+
+#: branch.c:296
+msgid "Failed to lock ref for update"
+msgstr "Misslyckades låsa referens för uppdatering"
+
+#: branch.c:314
+msgid "Failed to write ref"
+msgstr "Misslyckades skriva referens"
+
#: bundle.c:36
#, c-format
msgid "'%s' does not look like a v2 bundle file"
@@ -143,7 +267,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:674
+#: bundle.c:89 builtin/commit.c:697
#, c-format
msgid "could not open '%s'"
msgstr "kunde inte öppna \"%s\""
@@ -152,35 +276,35 @@ msgstr "kunde inte öppna \"%s\""
msgid "Repository lacks these prerequisite commits:"
msgstr "Arkivet saknar dessa nödvändiga incheckningar:"
-#: bundle.c:164 sequencer.c:566 sequencer.c:998 builtin/log.c:299
-#: builtin/log.c:751 builtin/log.c:1358 builtin/log.c:1574 builtin/merge.c:347
-#: builtin/shortlog.c:157
+#: bundle.c:164 sequencer.c:661 sequencer.c:1111 builtin/log.c:331
+#: builtin/log.c:801 builtin/log.c:1399 builtin/log.c:1625 builtin/merge.c:364
+#: builtin/shortlog.c:156
msgid "revision walk setup failed"
msgstr "misslyckades skapa revisionstraversering"
#: bundle.c:186
#, c-format
-msgid "The bundle contains %d ref"
-msgid_plural "The bundle contains %d refs"
-msgstr[0] "Paketet (bundlen) innehåller %d referens"
-msgstr[1] "Paketet (bundlen) innehåller %d referenser"
+msgid "The bundle contains this ref:"
+msgid_plural "The bundle contains these %d refs:"
+msgstr[0] "Paketet (bundlen) denna referens:"
+msgstr[1] "Paketet (bundlen) dessa %d referenser:"
-#: bundle.c:192
+#: bundle.c:193
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"
+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:294
msgid "rev-list died"
msgstr "rev-list dog"
-#: bundle.c:300 builtin/log.c:1254 builtin/shortlog.c:260
+#: bundle.c:300 builtin/log.c:1310 builtin/shortlog.c:259
#, c-format
msgid "unrecognized argument: %s"
msgstr "okänt argument: %s"
@@ -211,12 +335,12 @@ msgstr "kan inte skapa \"%s\""
msgid "index-pack died"
msgstr "index-pack dog"
-#: commit.c:50
+#: commit.c:53
#, c-format
msgid "could not parse %s"
msgstr "kunde inte tolka %s"
-#: commit.c:52
+#: commit.c:55
#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s är inte en incheckning!"
@@ -225,16 +349,16 @@ msgstr "%s %s är inte en incheckning!"
msgid "memory exhausted"
msgstr "minnet slut"
-#: connected.c:39
+#: connected.c:60
msgid "Could not run 'git rev-list'"
msgstr "Kunde inte köra \"git rev-list\""
-#: connected.c:48
+#: connected.c:80
#, c-format
msgid "failed write to rev-list: %s"
msgstr "kunde inte skriva till rev-list: %s"
-#: connected.c:56
+#: connected.c:88
#, c-format
msgid "failed to close rev-list's stdin: %s"
msgstr "kunde inte stänga rev-list:s standard in: %s"
@@ -330,7 +454,7 @@ msgstr ""
"Hittade fel i konfigurationsvariabeln \"diff.dirstat\":\n"
"%s"
-#: diff.c:3468
+#: diff.c:3487
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -339,12 +463,12 @@ msgstr ""
"Misslyckades tolka argument till flaggan --dirstat/-X;\n"
"%s"
-#: diff.c:3482
+#: diff.c:3501
#, c-format
msgid "Failed to parse --submodule option parameter: '%s'"
msgstr "Misslyckades tolka argument till flaggan --submodule: \"%s\""
-#: gpg-interface.c:59 gpg-interface.c:127
+#: gpg-interface.c:59 gpg-interface.c:131
msgid "could not run gpg."
msgstr "kunde inte köra gpg."
@@ -356,45 +480,45 @@ msgstr "gpg godtog inte data"
msgid "gpg failed to sign the data"
msgstr "gpg misslyckades signera data"
-#: gpg-interface.c:112
+#: gpg-interface.c:115
#, c-format
msgid "could not create temporary file '%s': %s"
msgstr "kunde inte skapa temporära filen \"%s\": %s"
-#: gpg-interface.c:115
+#: gpg-interface.c:118
#, c-format
msgid "failed writing detached signature to '%s': %s"
msgstr "misslyckades skriva fristående signatur till \"%s\": %s"
-#: grep.c:1622
+#: grep.c:1623
#, c-format
msgid "'%s': unable to read %s"
msgstr "\"%s\" kunde inte läsa %s"
-#: grep.c:1639
+#: grep.c:1640
#, c-format
msgid "'%s': %s"
msgstr "\"%s\": %s"
-#: grep.c:1650
+#: grep.c:1651
#, c-format
msgid "'%s': short read %s"
msgstr "\"%s\": kort läsning %s"
-#: help.c:212
+#: help.c:210
#, c-format
msgid "available git commands in '%s'"
msgstr "git-kommandon tillgängliga i \"%s\""
-#: help.c:219
+#: help.c:217
msgid "git commands available from elsewhere on your $PATH"
msgstr "git-kommandon från andra platser i din $PATH"
-#: help.c:235
+#: help.c:233
msgid "The most commonly used git commands are:"
msgstr "De mest använda git-kommandona är:"
-#: help.c:292
+#: help.c:290
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -403,11 +527,11 @@ msgstr ""
"\"%s\" verkar vara ett git-kommando, men vi kan inte\n"
"köra det. Kanske git-%s är trasigt?"
-#: help.c:349
+#: help.c:347
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "Oj då. Ditt system rapporterar inga Git-kommandon alls."
-#: help.c:371
+#: help.c:369
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -416,17 +540,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:376
+#: help.c:374
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr "automatiskt om %0.1f sekunder..."
-#: help.c:383
+#: help.c:381
#, 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:387
+#: help.c:385 help.c:444
msgid ""
"\n"
"Did you mean this?"
@@ -440,12 +564,17 @@ msgstr[1] ""
"\n"
"Menade du ett av dessa?"
+#: help.c:440
+#, c-format
+msgid "%s: %s - %s"
+msgstr "%s: %s - %s"
+
#: merge.c:56
msgid "failed to read the cache"
msgstr "misslyckads läsa cachen"
-#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534
-#: builtin/clone.c:586
+#: merge.c:110 builtin/checkout.c:365 builtin/checkout.c:566
+#: builtin/clone.c:656
msgid "unable to write new index file"
msgstr "kunde inte skriva ny indexfil"
@@ -459,70 +588,70 @@ msgstr "(felaktig incheckning)\n"
msgid "addinfo_cache failed for path '%s'"
msgstr "addinfo_cache misslyckades för sökvägen \"%s\""
-#: merge-recursive.c:268
+#: merge-recursive.c:269
msgid "error building trees"
msgstr "fel vid byggande av träd"
-#: merge-recursive.c:672
+#: merge-recursive.c:673
#, c-format
msgid "failed to create path '%s'%s"
msgstr "misslyckades skapa sökvägen \"%s\"%s"
-#: merge-recursive.c:683
+#: merge-recursive.c:684
#, 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
+#: merge-recursive.c:698 merge-recursive.c:719
msgid ": perhaps a D/F conflict?"
msgstr ": kanske en K/F-konflikt?"
-#: merge-recursive.c:708
+#: merge-recursive.c:709
#, c-format
msgid "refusing to lose untracked file at '%s'"
msgstr "vägrar förlora ospårad fil vid \"%s\""
-#: merge-recursive.c:748
+#: merge-recursive.c:749
#, c-format
msgid "cannot read object %s '%s'"
msgstr "kan inte läsa objektet %s: \"%s\""
-#: merge-recursive.c:750
+#: merge-recursive.c:751
#, 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
+#: merge-recursive.c:774 builtin/clone.c:312
#, c-format
msgid "failed to open '%s'"
msgstr "misslyckades öppna \"%s\""
-#: merge-recursive.c:781
+#: merge-recursive.c:782
#, c-format
msgid "failed to symlink '%s'"
msgstr "misslyckades ta skapa symboliska länken \"%s\""
-#: merge-recursive.c:784
+#: merge-recursive.c:785
#, 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
+#: merge-recursive.c:923
msgid "Failed to execute internal merge"
msgstr "Misslyckades exekvera intern sammanslagning"
-#: merge-recursive.c:926
+#: merge-recursive.c:927
#, c-format
msgid "Unable to add %s to database"
msgstr "Kunde inte lägga till %s till databasen"
-#: merge-recursive.c:942
+#: merge-recursive.c:943
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
+#: merge-recursive.c:1022 merge-recursive.c:1036
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -531,7 +660,7 @@ 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
+#: merge-recursive.c:1028 merge-recursive.c:1041
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -540,20 +669,20 @@ 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
+#: merge-recursive.c:1082
msgid "rename"
msgstr "namnbyte"
-#: merge-recursive.c:1081
+#: merge-recursive.c:1082
msgid "renamed"
msgstr "namnbytt"
-#: merge-recursive.c:1137
+#: merge-recursive.c:1138
#, 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
+#: merge-recursive.c:1160
#, c-format
msgid ""
"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
@@ -562,147 +691,173 @@ msgstr ""
"KONFLIKT (namnbyte/namnbyte): Namnbyte \"%s\"->\"%s\" på grenen \"%s\" "
"namnbyte \"%s\"->\"%s\" i \"%s\"%s"
-#: merge-recursive.c:1164
+#: merge-recursive.c:1165
msgid " (left unresolved)"
msgstr " (lämnad olöst)"
-#: merge-recursive.c:1218
+#: merge-recursive.c:1219
#, 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
+#: merge-recursive.c:1249
#, 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
+#: merge-recursive.c:1448
#, 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
+#: merge-recursive.c:1458
#, c-format
msgid "Adding merged %s"
msgstr "Lägger till sammanslagen %s"
-#: merge-recursive.c:1462 merge-recursive.c:1660
+#: merge-recursive.c:1463 merge-recursive.c:1661
#, c-format
msgid "Adding as %s instead"
msgstr "Lägger till som %s iställer"
-#: merge-recursive.c:1513
+#: merge-recursive.c:1514
#, c-format
msgid "cannot read object %s"
msgstr "kan inte läsa objektet %s"
-#: merge-recursive.c:1516
+#: merge-recursive.c:1517
#, c-format
msgid "object %s is not a blob"
msgstr "objektet %s är inte en blob"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modify"
msgstr "ändra"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modified"
msgstr "ändrad"
-#: merge-recursive.c:1574
+#: merge-recursive.c:1575
msgid "content"
msgstr "innehåll"
-#: merge-recursive.c:1581
+#: merge-recursive.c:1582
msgid "add/add"
msgstr "tillägg/tillägg"
-#: merge-recursive.c:1615
+#: merge-recursive.c:1616
#, c-format
msgid "Skipped %s (merged same as existing)"
msgstr "Hoppade över %s (sammanslagen samma som befintlig)"
-#: merge-recursive.c:1629
+#: merge-recursive.c:1630
#, c-format
msgid "Auto-merging %s"
msgstr "Slår ihop %s automatiskt"
-#: merge-recursive.c:1633 git-submodule.sh:942
+#: merge-recursive.c:1634 git-submodule.sh:1118
msgid "submodule"
msgstr "undermodul"
-#: merge-recursive.c:1634
+#: merge-recursive.c:1635
#, c-format
msgid "CONFLICT (%s): Merge conflict in %s"
msgstr "KONFLIKT (%s): Sammanslagningskonflikt i %s"
-#: merge-recursive.c:1724
+#: merge-recursive.c:1725
#, c-format
msgid "Removing %s"
msgstr "Tar bort %s"
-#: merge-recursive.c:1749
+#: merge-recursive.c:1750
msgid "file/directory"
msgstr "fil/katalog"
-#: merge-recursive.c:1755
+#: merge-recursive.c:1756
msgid "directory/file"
msgstr "katalog/fil"
-#: merge-recursive.c:1760
+#: merge-recursive.c:1761
#, 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
+#: merge-recursive.c:1771
#, c-format
msgid "Adding %s"
msgstr "Lägger till %s"
-#: merge-recursive.c:1787
+#: merge-recursive.c:1788
msgid "Fatal merge failure, shouldn't happen."
msgstr "Ödesdigert sammanslagningsfel, borde inte inträffa."
-#: merge-recursive.c:1806
+#: merge-recursive.c:1807
msgid "Already up-to-date!"
msgstr "Redan à jour!"
-#: merge-recursive.c:1815
+#: merge-recursive.c:1816
#, c-format
msgid "merging of trees %s and %s failed"
msgstr "sammanslagning av träden %s och %s misslyckades"
-#: merge-recursive.c:1845
+#: merge-recursive.c:1846
#, c-format
msgid "Unprocessed path??? %s"
msgstr "Obehandlad sökväg??? %s"
-#: merge-recursive.c:1890
+#: merge-recursive.c:1891
msgid "Merging:"
msgstr "Slår ihop:"
-#: merge-recursive.c:1903
+#: merge-recursive.c:1904
#, 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
+#: merge-recursive.c:1941
msgid "merge returned no commit"
msgstr "sammanslagningen returnerade ingen incheckning"
-#: merge-recursive.c:1997
+#: merge-recursive.c:1998
#, c-format
msgid "Could not parse object '%s'"
msgstr "Kunde inte tolka objektet \"%s\""
-#: merge-recursive.c:2009 builtin/merge.c:643
+#: merge-recursive.c:2010 builtin/merge.c:672
msgid "Unable to write index."
msgstr "Kunde inte skriva indexet."
+#: notes-utils.c:40
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr "Kan inte checka in oinitierat/orefererat anteckningsträd"
+
+#: notes-utils.c:81
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "Felaktigt värde för notes.rewriteMode: '%s'"
+
+#: notes-utils.c:91
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr "Vägrar skriva över anteckningar i %s (utanför refs/notes/)"
+
+#. TRANSLATORS: The first %s is the name of the
+#. environment variable, the second %s is its value
+#: notes-utils.c:118
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr "Felaktigt värde på %s: \"%s\""
+
+#: object.c:204
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "kunde inte tolka objektet: %s"
+
#: parse-options.c:489
msgid "..."
msgstr "..."
@@ -738,18 +893,18 @@ msgstr "Sökvägen \"%s\" är i undermodulen \"%.*s\""
msgid "'%s' is beyond a symbolic link"
msgstr "\"%s\" är på andra sidan av en symbolisk länk"
-#: remote.c:1653
+#: remote.c:1788
#, 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:1659
+#: remote.c:1794
msgid " (use \"git push\" to publish your local commits)\n"
msgstr " (använd \"git push\" för att publicera dina lokala incheckningar)\n"
-#: remote.c:1662
+#: remote.c:1797
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -759,11 +914,11 @@ msgstr[0] ""
msgstr[1] ""
"Din gren ligger efter \"%s\" med %d incheckningar, och kan snabbspolas.\n"
-#: remote.c:1670
+#: remote.c:1805
msgid " (use \"git pull\" to update your local branch)\n"
msgstr " (använd \"git pull\" för att uppdatera din lokala gren)\n"
-#: remote.c:1673
+#: remote.c:1808
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -778,23 +933,32 @@ msgstr[1] ""
"Din gren och \"%s\" har divergerat,\n"
"och har %d respektive %d olika incheckningar.\n"
-#: remote.c:1683
+#: remote.c:1818
msgid " (use \"git pull\" to merge the remote branch into yours)\n"
msgstr " (använd \"git pull\" för att slå ihop fjärrgrenen med din egen)\n"
-#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
-#: builtin/merge.c:994
+#: run-command.c:80
+msgid "open /dev/null failed"
+msgstr "misslyckades öppna /dev/null"
+
+#: run-command.c:82
+#, c-format
+msgid "dup2(%d,%d) failed"
+msgstr "dup2(%d,%d) misslyckades"
+
+#: sequencer.c:206 builtin/merge.c:790 builtin/merge.c:903
+#: builtin/merge.c:1013 builtin/merge.c:1023
#, c-format
msgid "Could not open '%s' for writing"
msgstr "Kunde inte öppna \"%s\" för skrivning"
-#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986
-#: builtin/merge.c:999
+#: sequencer.c:208 builtin/merge.c:350 builtin/merge.c:793
+#: builtin/merge.c:1015 builtin/merge.c:1028
#, c-format
msgid "Could not write to '%s'"
msgstr "Kunde inte skriva till \"%s\""
-#: sequencer.c:146
+#: sequencer.c:229
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
@@ -802,7 +966,7 @@ msgstr ""
"efter att ha löst konflikterna, markera de rättade sökvägarna\n"
"med \"git add <sökvägar>\" eller \"git rm <sökvägar>\""
-#: sequencer.c:149
+#: sequencer.c:232
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'\n"
@@ -812,228 +976,260 @@ msgstr ""
"med \"git add <sökvägar>\" eller \"git rm <sökvägar>\"\n"
"och checka in resultatet med \"git commit\""
-#: sequencer.c:162 sequencer.c:774 sequencer.c:857
+#: sequencer.c:245 sequencer.c:869 sequencer.c:952
#, c-format
msgid "Could not write to %s"
msgstr "Kunde inte skriva till %s"
-#: sequencer.c:165
+#: sequencer.c:248
#, c-format
msgid "Error wrapping up %s"
msgstr "Fel vid ombrytning av %s"
-#: sequencer.c:180
+#: sequencer.c:263
msgid "Your local changes would be overwritten by cherry-pick."
msgstr "Dina lokala ändringar skulle skrivas över av \"cherry-pick\"."
-#: sequencer.c:182
+#: sequencer.c:265
msgid "Your local changes would be overwritten by revert."
msgstr "Dina lokala ändringar skulle skrivas över av \"revert\"."
-#: sequencer.c:185
+#: sequencer.c:268
msgid "Commit your changes or stash them to proceed."
msgstr "Checka in dina ändringar eller använd \"stash\" för att fortsätta."
#. TRANSLATORS: %s will be "revert" or "cherry-pick"
-#: sequencer.c:236
+#: sequencer.c:324
#, c-format
msgid "%s: Unable to write new index file"
msgstr "%s: Kunde inte skriva ny indexfil"
-#: sequencer.c:267
+#: sequencer.c:355
msgid "Could not resolve HEAD commit\n"
msgstr "Kunde inte bestämma HEAD:s incheckning\n"
-#: sequencer.c:288
+#: sequencer.c:377
msgid "Unable to update cache tree\n"
msgstr "Kan inte uppdatera cacheträd\n"
-#: sequencer.c:333
+#: sequencer.c:422
#, c-format
msgid "Could not parse commit %s\n"
msgstr "Kunde inte tolka incheckningen %s\n"
-#: sequencer.c:338
+#: sequencer.c:427
#, c-format
msgid "Could not parse parent commit %s\n"
msgstr "Kunde inte tolka föräldraincheckningen %s\n"
-#: sequencer.c:404
+#: sequencer.c:493
msgid "Your index file is unmerged."
msgstr "Din indexfil har inte slagits ihop."
-#: sequencer.c:423
+#: sequencer.c:512
#, 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:431
+#: sequencer.c:520
#, c-format
msgid "Commit %s does not have parent %d"
msgstr "Incheckning %s har inte förälder %d"
-#: sequencer.c:435
+#: sequencer.c:524
#, 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:448
+#: sequencer.c:537
#, c-format
msgid "%s: cannot parse parent commit %s"
msgstr "%s: kan inte tolka föräldraincheckningen %s"
-#: sequencer.c:452
+#: sequencer.c:541
#, c-format
msgid "Cannot get commit message for %s"
msgstr "Kan inte hämta incheckningsmeddelande för %s"
-#: sequencer.c:536
+#: sequencer.c:627
#, c-format
msgid "could not revert %s... %s"
msgstr "kunde inte ångra %s... %s"
-#: sequencer.c:537
+#: sequencer.c:628
#, c-format
msgid "could not apply %s... %s"
msgstr "kunde inte tillämpa %s... %s"
-#: sequencer.c:569
+#: sequencer.c:664
msgid "empty commit set passed"
msgstr "den angivna uppsättningen incheckningar är tom"
-#: sequencer.c:577
+#: sequencer.c:672
#, c-format
msgid "git %s: failed to read the index"
msgstr "git %s: misslyckades läsa indexet"
-#: sequencer.c:582
+#: sequencer.c:677
#, c-format
msgid "git %s: failed to refresh the index"
msgstr "git %s: misslyckades uppdatera indexet"
-#: sequencer.c:640
+#: sequencer.c:735
#, c-format
msgid "Cannot %s during a %s"
msgstr "kan inte %s under en %s"
-#: sequencer.c:662
+#: sequencer.c:757
#, c-format
msgid "Could not parse line %d."
msgstr "Kan inte tolka rad %d."
-#: sequencer.c:667
+#: sequencer.c:762
msgid "No commits parsed."
msgstr "Inga incheckningar lästes."
-#: sequencer.c:680
+#: sequencer.c:775
#, c-format
msgid "Could not open %s"
msgstr "Kunde inte öppna %s"
-#: sequencer.c:684
+#: sequencer.c:779
#, c-format
msgid "Could not read %s."
msgstr "kunde inte läsa %s."
-#: sequencer.c:691
+#: sequencer.c:786
#, c-format
msgid "Unusable instruction sheet: %s"
msgstr "Oanvändbart manus: %s"
-#: sequencer.c:719
+#: sequencer.c:814
#, c-format
msgid "Invalid key: %s"
msgstr "Felaktig nyckel: %s"
-#: sequencer.c:722
+#: sequencer.c:817
#, c-format
msgid "Invalid value for %s: %s"
msgstr "Felaktigt värde för %s: %s"
-#: sequencer.c:734
+#: sequencer.c:829
#, c-format
msgid "Malformed options sheet: %s"
msgstr "Trasigt manus: %s"
-#: sequencer.c:755
+#: sequencer.c:850
msgid "a cherry-pick or revert is already in progress"
msgstr "en \"cherry-pick\" eller \"revert\" pågår redan"
-#: sequencer.c:756
+#: sequencer.c:851
msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
msgstr "testa \"git cherry-pick (--continue | --quit | --abort)\""
-#: sequencer.c:760
+#: sequencer.c:855
#, c-format
msgid "Could not create sequencer directory %s"
msgstr "Kunde inte skapa \"sequencer\"-katalogen \"%s\""
-#: sequencer.c:776 sequencer.c:861
+#: sequencer.c:871 sequencer.c:956
#, c-format
msgid "Error wrapping up %s."
msgstr "Fel vid ombrytning av %s."
-#: sequencer.c:795 sequencer.c:929
+#: sequencer.c:890 sequencer.c:1024
msgid "no cherry-pick or revert in progress"
msgstr "ingen \"cherry-pick\" eller \"revert\" pågår"
-#: sequencer.c:797
+#: sequencer.c:892
msgid "cannot resolve HEAD"
msgstr "kan inte bestämma HEAD"
-#: sequencer.c:799
+#: sequencer.c:894
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:821 builtin/apply.c:4056
+#: sequencer.c:916 builtin/apply.c:4061
#, c-format
msgid "cannot open %s: %s"
msgstr "kan inte öppna %s: %s"
-#: sequencer.c:824
+#: sequencer.c:919
#, c-format
msgid "cannot read %s: %s"
msgstr "kan inte läsa %s: %s"
-#: sequencer.c:825
+#: sequencer.c:920
msgid "unexpected end of file"
msgstr "oväntat filslut"
-#: sequencer.c:831
+#: sequencer.c:926
#, 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:854
+#: sequencer.c:949
#, c-format
msgid "Could not format %s."
msgstr "Kunde inte formatera %s."
-#: sequencer.c:1016
+#: sequencer.c:1092
+#, c-format
+msgid "%s: can't cherry-pick a %s"
+msgstr "%s: kan inte göra \"cherry-pick\" på typen \"%s\""
+
+#: sequencer.c:1095
+#, c-format
+msgid "%s: bad revision"
+msgstr "%s: felaktig revision"
+
+#: sequencer.c:1129
msgid "Can't revert as initial commit"
msgstr "Kan inte ångra som första incheckning"
-#: sequencer.c:1017
+#: sequencer.c:1130
msgid "Can't cherry-pick into empty head"
msgstr "Kan inte göra \"cherry-pick\" i ett tomt huvud"
-#: sha1_name.c:1044
+#: sha1_name.c:440
+msgid ""
+"Git normally never creates a ref that ends with 40 hex characters\n"
+"because it will be ignored when you just specify 40-hex. These refs\n"
+"may be created by mistake. For example,\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
+"examine these refs and maybe delete them. Turn this message off by\n"
+"running \"git config advice.objectNameWarning false\""
+msgstr ""
+"Git skapar normalt aldrig referenser som slutar med 40 hexadecimala\n"
+"tecken, då detta ignoreras när du anger 40-hex enbart. Dessa\n"
+"referenser kan skapas av misstag. Till exempel, för\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"där \"$br\" på något sätt blivit tomt och en 40-hex-referens skapats.\n"
+"Undersök referenserna och ta kanske bort dem. Stäng av meddelandet\n"
+"genom att köra \"git config advice.objectNameWarning false\""
+
+#: sha1_name.c:1097
msgid "HEAD does not point to a branch"
msgstr "HEAD pekar inte på en gren"
-#: sha1_name.c:1047
+#: sha1_name.c:1100
#, c-format
msgid "No such branch: '%s'"
msgstr "Okänd gren: \"%s\""
-#: sha1_name.c:1049
+#: sha1_name.c:1102
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "Ingen standarduppström angiven för grenen \"%s\""
-#: sha1_name.c:1052
+#: sha1_name.c:1106
#, 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"
@@ -1043,232 +1239,232 @@ msgstr "Uppströmsgrenen \"%s\" är inte lagrad som en fjärrspårande gren"
msgid "unable to access '%s': %s"
msgstr "kan inte komma åt \"%s\": %s"
-#: wrapper.c:423
+#: wrapper.c:429
#, c-format
msgid "unable to access '%s'"
msgstr "kan inte komma åt \"%s\""
-#: wrapper.c:434
+#: wrapper.c:440
#, 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:435
+#: wrapper.c:441
msgid "no such user"
msgstr "okänd användare"
-#: wt-status.c:140
+#: wt-status.c:141
msgid "Unmerged paths:"
msgstr "Ej sammanslagna sökvägar:"
-#: wt-status.c:167 wt-status.c:194
+#: wt-status.c:168 wt-status.c:195
#, 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:169 wt-status.c:196
+#: wt-status.c:170 wt-status.c:197
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:173
+#: wt-status.c:174
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
+#: wt-status.c:176 wt-status.c:180
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:177
+#: wt-status.c:178
msgid " (use \"git rm <file>...\" to mark resolution)"
msgstr " (använd \"git rm <fil>...\" för att ange lösning)"
-#: wt-status.c:188
+#: wt-status.c:189
msgid "Changes to be committed:"
msgstr "Ändringar att checka in:"
-#: wt-status.c:206
+#: wt-status.c:207
msgid "Changes not staged for commit:"
msgstr "Ändringar ej i incheckningskön:"
-#: wt-status.c:210
+#: wt-status.c:211
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:212
+#: wt-status.c:213
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:213
+#: wt-status.c:214
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:215
+#: wt-status.c:216
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)"
-#: wt-status.c:227
+#: wt-status.c:228
#, 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 det som skall checkas in)"
-#: wt-status.c:244
+#: wt-status.c:245
msgid "bug"
msgstr "programfel"
-#: wt-status.c:249
+#: wt-status.c:250
msgid "both deleted:"
msgstr "borttaget av bägge:"
-#: wt-status.c:250
+#: wt-status.c:251
msgid "added by us:"
msgstr "tillagt av oss:"
-#: wt-status.c:251
+#: wt-status.c:252
msgid "deleted by them:"
msgstr "borttaget av dem:"
-#: wt-status.c:252
+#: wt-status.c:253
msgid "added by them:"
msgstr "tillagt av dem:"
-#: wt-status.c:253
+#: wt-status.c:254
msgid "deleted by us:"
msgstr "borttaget av oss:"
-#: wt-status.c:254
+#: wt-status.c:255
msgid "both added:"
msgstr "tillagt av bägge:"
-#: wt-status.c:255
+#: wt-status.c:256
msgid "both modified:"
msgstr "ändrat av bägge:"
-#: wt-status.c:285
+#: wt-status.c:286
msgid "new commits, "
msgstr "nya incheckningar, "
-#: wt-status.c:287
+#: wt-status.c:288
msgid "modified content, "
msgstr "ändrat innehåll, "
-#: wt-status.c:289
+#: wt-status.c:290
msgid "untracked content, "
msgstr "ospårat innehåll, "
-#: wt-status.c:303
+#: wt-status.c:307
#, c-format
msgid "new file: %s"
msgstr "ny fil: %s"
-#: wt-status.c:306
+#: wt-status.c:310
#, c-format
msgid "copied: %s -> %s"
msgstr "kopierad: %s -> %s"
-#: wt-status.c:309
+#: wt-status.c:313
#, c-format
msgid "deleted: %s"
msgstr "borttagen: %s"
-#: wt-status.c:312
+#: wt-status.c:316
#, c-format
msgid "modified: %s"
msgstr "ändrad: %s"
-#: wt-status.c:315
+#: wt-status.c:319
#, c-format
msgid "renamed: %s -> %s"
msgstr "namnbyte: %s -> %s"
-#: wt-status.c:318
+#: wt-status.c:322
#, c-format
msgid "typechange: %s"
msgstr "typbyte: %s"
-#: wt-status.c:321
+#: wt-status.c:325
#, c-format
msgid "unknown: %s"
msgstr "okänd: %s"
-#: wt-status.c:324
+#: wt-status.c:328
#, c-format
msgid "unmerged: %s"
msgstr "osammansl.: %s"
-#: wt-status.c:327
+#: wt-status.c:331
#, c-format
msgid "bug: unhandled diff status %c"
msgstr "programfel: diff-status %c ej hanterad"
-#: wt-status.c:789
+#: wt-status.c:803
msgid "You have unmerged paths."
msgstr "Du har ej sammanslagna sökvägar."
-#: wt-status.c:792 wt-status.c:944
+#: wt-status.c:806
msgid " (fix conflicts and run \"git commit\")"
msgstr " (rätta konflikter och kör \"git commit\")"
-#: wt-status.c:795
+#: wt-status.c:809
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:798
+#: wt-status.c:812
msgid " (use \"git commit\" to conclude merge)"
msgstr " (använd \"git commit\" för att slutföra sammanslagningen)"
-#: wt-status.c:808
+#: wt-status.c:822
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:811
+#: wt-status.c:825
msgid "The current patch is empty."
msgstr "Aktuell patch är tom."
-#: wt-status.c:815
-msgid " (fix conflicts and then run \"git am --resolved\")"
-msgstr " (rätta konflikter och kör sedan \"git am --resolved\")"
+#: wt-status.c:829
+msgid " (fix conflicts and then run \"git am --continue\")"
+msgstr " (rätta konflikter och kör sedan \"git am --continue\")"
-#: wt-status.c:817
+#: wt-status.c:831
msgid " (use \"git am --skip\" to skip this patch)"
msgstr " (använd \"git am --skip\" för att hoppa över patchen)"
-#: wt-status.c:819
+#: wt-status.c:833
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:879 wt-status.c:896
+#: wt-status.c:893 wt-status.c:910
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
msgstr "Du håller på att ombasera grenen \"%s\" ovanpå \"%s\"."
-#: wt-status.c:884 wt-status.c:901
+#: wt-status.c:898 wt-status.c:915
msgid "You are currently rebasing."
msgstr "Du håller på med en ombasering."
-#: wt-status.c:887
+#: wt-status.c:901
msgid " (fix conflicts and then run \"git rebase --continue\")"
msgstr " (rätta konflikter och kör sedan \"git rebase --continue\")"
-#: wt-status.c:889
+#: wt-status.c:903
msgid " (use \"git rebase --skip\" to skip this patch)"
msgstr " (använd \"git rebase --skip\" för att hoppa över patchen)"
-#: wt-status.c:891
+#: wt-status.c:905
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:904
+#: wt-status.c:918
msgid " (all conflicts fixed: run \"git rebase --continue\")"
msgstr " (alla konflikter rättade: kör \"git rebase --continue\")"
-#: wt-status.c:908
+#: wt-status.c:922
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
@@ -1276,104 +1472,154 @@ msgstr ""
"Du håller på att dela upp en incheckning medan du ombaserar grenen \"%s\" "
"ovanpå \"%s\"."
-#: wt-status.c:913
+#: wt-status.c:927
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:916
+#: wt-status.c:930
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:920
+#: wt-status.c:934
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr ""
"Du håller på att redigera en incheckning medan du ombaserar grenen \"%s\" "
"ovanpå \"%s\"."
-#: wt-status.c:925
+#: wt-status.c:939
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:928
+#: wt-status.c:942
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:930
+#: wt-status.c:944
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:940
+#: wt-status.c:954
msgid "You are currently cherry-picking."
msgstr "Du håller på med en \"cherry-pick\"."
-#: wt-status.c:947
-msgid " (all conflicts fixed: run \"git commit\")"
-msgstr " (alla konflikter har rättats: kör \"git commit\")"
-
#: wt-status.c:958
+msgid " (fix conflicts and run \"git cherry-pick --continue\")"
+msgstr " (rätta konflikter och kör sedan \"git cherry-pick --continue\")"
+
+#: wt-status.c:961
+msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
+msgstr " (alla konflikter rättade: kör \"git cherry-pick --continue\")"
+
+#: wt-status.c:963
+msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
+msgstr ""
+" (använd \"git cherry-pick --abort\" för att avbryta \"cherry-pick\"-"
+"operationen)"
+
+#: wt-status.c:972
#, c-format
-msgid "You are currently bisecting branch '%s'."
-msgstr "Du håller på med en \"bisect\" på grenen \"%s\"."
+msgid "You are currently reverting commit %s."
+msgstr "Du håller på med att ångra incheckningen %s."
-#: wt-status.c:962
+#: wt-status.c:977
+msgid " (fix conflicts and run \"git revert --continue\")"
+msgstr " (rätta konflikter och kör sedan \"git revert --continue\")"
+
+#: wt-status.c:980
+msgid " (all conflicts fixed: run \"git revert --continue\")"
+msgstr " (alla konflikter rättade: kör \"git revert --continue\")"
+
+#: wt-status.c:982
+msgid " (use \"git revert --abort\" to cancel the revert operation)"
+msgstr " (använd \"git revert --abort\" för att avbryta ångrandet)"
+
+#: wt-status.c:993
+#, c-format
+msgid "You are currently bisecting, started from branch '%s'."
+msgstr "Du håller på med en \"bisect\", startad från grenen \"%s\"."
+
+#: wt-status.c:997
msgid "You are currently bisecting."
msgstr "Du håller på med en \"bisect\"."
-#: wt-status.c:965
+#: wt-status.c:1000
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:1064
+#: wt-status.c:1173
msgid "On branch "
msgstr "PÃ¥ grenen "
-#: wt-status.c:1071
+#: wt-status.c:1180
+msgid "rebase in progress; onto "
+msgstr "ombasering pågår; ovanpå"
+
+#: wt-status.c:1187
+msgid "HEAD detached at "
+msgstr "HEAD frånkopplad vid "
+
+#: wt-status.c:1189
+msgid "HEAD detached from "
+msgstr "HEAD frånkopplad från "
+
+#: wt-status.c:1192
msgid "Not currently on any branch."
msgstr "Inte på någon gren för närvarande."
-#: wt-status.c:1083
+#: wt-status.c:1209
msgid "Initial commit"
msgstr "Första incheckning"
-#: wt-status.c:1097
+#: wt-status.c:1223
msgid "Untracked files"
msgstr "Ospårade filer"
-#: wt-status.c:1099
+#: wt-status.c:1225
msgid "Ignored files"
msgstr "Ignorerade filer"
+#: wt-status.c:1229
+#, c-format
+msgid ""
+"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
+"may speed it up, but you have to be careful not to forget to add\n"
+"new files yourself (see 'git help status')."
+msgstr ""
+"Det tog %.2f sekunder att räkna upp ospårade filer. \"status -uno\"\n"
+"kan gå snabbare, men du måste vara försiktig så du inte glömmer\n"
+"lägga till nya filer själv (se \"git help status\")."
+
# %s är nästa sträng eller tom.
-#: wt-status.c:1101
+#: wt-status.c:1235
#, c-format
msgid "Untracked files not listed%s"
msgstr "Ospårade filer visas ej%s"
-#: wt-status.c:1103
+#: wt-status.c:1237
msgid " (use -u option to show untracked files)"
msgstr " (använd flaggan -u för att visa ospårade filer)"
-#: wt-status.c:1109
+#: wt-status.c:1243
msgid "No changes"
msgstr "Inga ändringar"
-#: wt-status.c:1114
+#: wt-status.c:1248
#, c-format
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:1117
+#: wt-status.c:1251
#, c-format
msgid "no changes added to commit\n"
msgstr "inga ändringar att checka in\n"
-#: wt-status.c:1120
+#: wt-status.c:1254
#, c-format
msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
@@ -1382,52 +1628,52 @@ msgstr ""
"inget köat för incheckning, men ospårade filer finns (spåra med \"git add"
"\")\n"
-#: wt-status.c:1123
+#: wt-status.c:1257
#, 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:1126
+#: wt-status.c:1260
#, c-format
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:1129 wt-status.c:1134
+#: wt-status.c:1263 wt-status.c:1268
#, c-format
msgid "nothing to commit\n"
msgstr "inget att checka in\n"
-#: wt-status.c:1132
+#: wt-status.c:1266
#, 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:1136
+#: wt-status.c:1270
#, c-format
msgid "nothing to commit, working directory clean\n"
msgstr "inget att checka in, arbetskatalogen ren\n"
-#: wt-status.c:1244
+#: wt-status.c:1378
msgid "HEAD (no branch)"
msgstr "HEAD (ingen gren)"
-#: wt-status.c:1250
+#: wt-status.c:1384
msgid "Initial commit on "
msgstr "Första incheckning på "
-#: wt-status.c:1265
+#: wt-status.c:1399
msgid "behind "
msgstr "efter "
-#: wt-status.c:1268 wt-status.c:1271
+#: wt-status.c:1402 wt-status.c:1405
msgid "ahead "
msgstr "före "
-#: wt-status.c:1273
+#: wt-status.c:1407
msgid ", behind "
msgstr ", efter "
-#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#: compat/precompose_utf8.c:58 builtin/clone.c:351
#, c-format
msgid "failed to unlink '%s'"
msgstr "misslyckades ta bort länken \"%s\""
@@ -1436,193 +1682,226 @@ msgstr "misslyckades ta bort länken \"%s\""
msgid "git add [options] [--] <pathspec>..."
msgstr "git add [flaggor] [--] <sökväg>..."
-#: builtin/add.c:63
+#.
+#. * To be consistent with "git add -p" and most Git
+#. * commands, we should default to being tree-wide, but
+#. * this is not the original behavior and can't be
+#. * changed until users trained themselves not to type
+#. * "git add -u" or "git add -A". For now, we warn and
+#. * keep the old behavior. Later, the behavior can be changed
+#. * to tree-wide, keeping the warning for a while, and
+#. * eventually we can drop the warning.
+#.
+#: builtin/add.c:58
+#, c-format
+msgid ""
+"The behavior of 'git add %s (or %s)' with no path argument from a\n"
+"subdirectory of the tree will change in Git 2.0 and should not be used "
+"anymore.\n"
+"To add content for the whole tree, run:\n"
+"\n"
+" git add %s :/\n"
+" (or git add %s :/)\n"
+"\n"
+"To restrict the command to the current directory, run:\n"
+"\n"
+" git add %s .\n"
+" (or git add %s .)\n"
+"\n"
+"With the current Git version, the command is restricted to the current "
+"directory.\n"
+msgstr ""
+"Beteendet för \"git add %s (eller %s)\" utan sökvägsargument från en\n"
+"underkatalog i ett träd kommer ändras i Git 2.0 och bör inte längre "
+"användas.\n"
+"För att lägga till innehållet för hela trädet, använd:\n"
+"\n"
+" git add %s :/\n"
+" (eller git add %s :/)\n"
+"\n"
+"För att begränsa kommandot till aktuell katalog, använd:\n"
+"\n"
+" git add %s .\n"
+" (eller git add %s .)\n"
+"\n"
+"I nuvarande version av Git begränsas kommandot till aktuell katalog.\n"
+
+#: builtin/add.c:100
+#, c-format
+msgid ""
+"You ran 'git add' with neither '-A (--all)' or '--ignore-removal',\n"
+"whose behaviour will change in Git 2.0 with respect to paths you removed.\n"
+"Paths like '%s' that are\n"
+"removed from your working tree are ignored with this version of Git.\n"
+"\n"
+"* 'git add --ignore-removal <pathspec>', which is the current default,\n"
+" ignores paths you removed from your working tree.\n"
+"\n"
+"* 'git add --all <pathspec>' will let you also record the removals.\n"
+"\n"
+"Run 'git status' to check the paths you removed from your working tree.\n"
+msgstr ""
+"Du körde \"git add\" utan varken \"-A (--all)\" eller \"--ignore-removal\".\n"
+"Beteendet kommer ändras i Git 2.0 vad gäller sökvägar du tagit bort.\n"
+"Sökvägar som \"%s\", som har\n"
+"tagits bort från din arbetskatalog ignoreras i den här versionen av Git.\n"
+"\n"
+"* \"git add --ignore-removal <sökväg>\", som är förvalet just nu,\n"
+" ignorerar sökvägar du har tagit bort från arbetskatalogen.\n"
+"\n"
+"* \"git add --all <sökväg>\" låter dig även registrera borttagningarna.\n"
+"\n"
+"Kör \"git status\" för att kontrollera sökvägarna du tagit bort från\n"
+"arbetskatalogen.\n"
+
+#: builtin/add.c:144
#, c-format
msgid "unexpected diff status %c"
msgstr "diff-status %c förväntades inte"
-#: builtin/add.c:68 builtin/commit.c:231
+#: builtin/add.c:149 builtin/commit.c:252
msgid "updating files failed"
msgstr "misslyckades uppdatera filer"
-#: builtin/add.c:78
+#: builtin/add.c:163
#, c-format
msgid "remove '%s'\n"
msgstr "ta bort \"%s\"\n"
-#: builtin/add.c:148
+#: builtin/add.c:253
msgid "Unstaged changes after refreshing the index:"
msgstr "Ospårade ändringar efter att ha uppdaterat indexet:"
-#: builtin/add.c:151 builtin/add.c:460 builtin/rm.c:275
+#: builtin/add.c:256 builtin/add.c:573 builtin/rm.c:337
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "sökvägsangivelsen \"%s\" motsvarade inte några filer"
-#: builtin/add.c:234
+#: builtin/add.c:339
msgid "Could not read the index"
msgstr "Kunde inte läsa indexet"
-#: builtin/add.c:244
+#: builtin/add.c:350
#, c-format
msgid "Could not open '%s' for writing."
msgstr "Kunde inte öppna \"%s\" för skrivning"
-#: builtin/add.c:248
+#: builtin/add.c:354
msgid "Could not write patch"
msgstr "Kunde inte skriva patch"
-#: builtin/add.c:253
+#: builtin/add.c:359
#, c-format
msgid "Could not stat '%s'"
msgstr "Kunde inte ta status på \"%s\""
-#: builtin/add.c:255
+#: builtin/add.c:361
msgid "Empty patch. Aborted."
msgstr "Tom patch. Avbryter."
-#: builtin/add.c:261
+#: builtin/add.c:367
#, c-format
msgid "Could not apply '%s'"
msgstr "Kunde inte tillämpa \"%s\""
-#: builtin/add.c:271
+#: builtin/add.c:377
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:277 builtin/clean.c:161 builtin/fetch.c:78 builtin/mv.c:63
-#: builtin/prune-packed.c:76 builtin/push.c:425 builtin/remote.c:1253
-#: builtin/rm.c:206
+#: builtin/add.c:394 builtin/clean.c:875 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:73 builtin/push.c:451 builtin/remote.c:1253
+#: builtin/rm.c:268
msgid "dry run"
msgstr "testkörning"
-#: builtin/add.c:278 builtin/apply.c:4405 builtin/check-ignore.c:19
-#: builtin/commit.c:1150 builtin/count-objects.c:82 builtin/fsck.c:613
-#: builtin/log.c:1522 builtin/mv.c:62 builtin/read-tree.c:112
+#: builtin/add.c:395 builtin/apply.c:4410 builtin/check-ignore.c:19
+#: builtin/commit.c:1220 builtin/count-objects.c:95 builtin/fsck.c:613
+#: builtin/log.c:1573 builtin/mv.c:62 builtin/read-tree.c:113
msgid "be verbose"
msgstr "var pratsam"
-#: builtin/add.c:280
+#: builtin/add.c:397
msgid "interactive picking"
msgstr "plocka interaktivt"
-#: builtin/add.c:281 builtin/checkout.c:1031 builtin/reset.c:258
+#: builtin/add.c:398 builtin/checkout.c:1073 builtin/reset.c:261
msgid "select hunks interactively"
msgstr "välj stycken interaktivt"
-#: builtin/add.c:282
+#: builtin/add.c:399
msgid "edit current diff and apply"
msgstr "redigera aktuell diff och applicera"
-#: builtin/add.c:283
+#: builtin/add.c:400
msgid "allow adding otherwise ignored files"
msgstr "tillåt lägga till annars ignorerade filer"
-#: builtin/add.c:284
+#: builtin/add.c:401
msgid "update tracked files"
msgstr "uppdatera spårade filer"
-#: builtin/add.c:285
+#: builtin/add.c:402
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:286
+#: builtin/add.c:403
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:287
+#. takes no arguments
+#: builtin/add.c:406
+msgid "ignore paths removed in the working tree (same as --no-all)"
+msgstr "ignorera sökvägar borttagna i arbetskatalogen (samma som --no-all)"
+
+#: builtin/add.c:408
msgid "don't add, only refresh the index"
msgstr "lägg inte till, uppdatera endast indexet"
-#: builtin/add.c:288
+#: builtin/add.c:409
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:289
+#: builtin/add.c:410
msgid "check if - even missing - files are ignored in dry run"
msgstr "se om - även saknade - filer ignoreras i testkörning"
-#: builtin/add.c:311
+#: builtin/add.c:432
#, 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:312
+#: builtin/add.c:433
msgid "no files added"
msgstr "inga filer har lagts till"
-#: builtin/add.c:318
+#: builtin/add.c:439
msgid "adding files failed"
msgstr "misslyckades lägga till filer"
-#.
-#. * To be consistent with "git add -p" and most Git
-#. * commands, we should default to being tree-wide, but
-#. * this is not the original behavior and can't be
-#. * changed until users trained themselves not to type
-#. * "git add -u" or "git add -A". For now, we warn and
-#. * keep the old behavior. Later, this warning can be
-#. * turned into a die(...), and eventually we may
-#. * reallow the command with a new behavior.
-#.
-#: builtin/add.c:335
-#, c-format
-msgid ""
-"The behavior of 'git add %s (or %s)' with no path argument from a\n"
-"subdirectory of the tree will change in Git 2.0 and should not be used "
-"anymore.\n"
-"To add content for the whole tree, run:\n"
-"\n"
-" git add %s :/\n"
-" (or git add %s :/)\n"
-"\n"
-"To restrict the command to the current directory, run:\n"
-"\n"
-" git add %s .\n"
-" (or git add %s .)\n"
-"\n"
-"With the current Git version, the command is restricted to the current "
-"directory."
-msgstr ""
-"Beteendet för \"git add %s (eller %s)\" utan sökvägsargument från en\n"
-"underkatalog i ett träd kommer ändras i Git 2.0 och bör inte längre "
-"användas.\n"
-"För att lägga till innehållet för hela trädet, använd:\n"
-"\n"
-" git add %s :/\n"
-" (eller git add %s :/)\n"
-"\n"
-"För att begränsa kommandot till aktuell katalog, använd:\n"
-"\n"
-" git add %s .\n"
-" (eller git add %s .)\n"
-"\n"
-"I nuvarande version av Git begränsas kommandot till aktuell katalog."
-
-#: builtin/add.c:381
+#: builtin/add.c:478
msgid "-A and -u are mutually incompatible"
msgstr "-A och -u är ömsesidigt inkompatibla"
-#: builtin/add.c:383
+#: builtin/add.c:496
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:414
+#: builtin/add.c:526
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr "Inget angivet, inget tillagt.\n"
-#: builtin/add.c:415
+#: builtin/add.c:527
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "Kanske menade du att skriva \"git add .\"?\n"
-#: builtin/add.c:421 builtin/check-ignore.c:67 builtin/clean.c:204
-#: builtin/commit.c:291 builtin/mv.c:82 builtin/rm.c:235
+#: builtin/add.c:533 builtin/check-ignore.c:161 builtin/clean.c:919
+#: builtin/commit.c:312 builtin/mv.c:82 builtin/rm.c:297
msgid "index file corrupt"
msgstr "indexfilen trasig"
-#: builtin/add.c:481 builtin/apply.c:4501 builtin/mv.c:229 builtin/rm.c:370
+#: builtin/add.c:605 builtin/apply.c:4506 builtin/mv.c:229 builtin/rm.c:432
msgid "Unable to write new index file"
msgstr "Kunde inte skriva ny indexfil"
@@ -1755,24 +2034,24 @@ msgstr "kunde inte läsa symboliska länken %s"
msgid "unable to open or read %s"
msgstr "kunde inte öppna eller läsa %s"
-#: builtin/apply.c:2684
+#: builtin/apply.c:2688
#, c-format
msgid "invalid start of line: '%c'"
msgstr "felaktig inledning på rad: \"%c\""
-#: builtin/apply.c:2802
+#: builtin/apply.c:2806
#, 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:2814
+#: builtin/apply.c:2818
#, 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:2820
+#: builtin/apply.c:2824
#, c-format
msgid ""
"while searching for:\n"
@@ -1781,318 +2060,318 @@ msgstr ""
"vid sökning efter:\n"
"%.*s"
-#: builtin/apply.c:2839
+#: builtin/apply.c:2843
#, c-format
msgid "missing binary patch data for '%s'"
msgstr "saknar binära patchdata för \"%s\""
-#: builtin/apply.c:2942
+#: builtin/apply.c:2946
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr "binärpatchen kan inte tillämpas på \"%s\""
-#: builtin/apply.c:2948
+#: builtin/apply.c:2952
#, 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:2969
+#: builtin/apply.c:2973
#, c-format
msgid "patch failed: %s:%ld"
msgstr "patch misslyckades: %s:%ld"
-#: builtin/apply.c:3091
+#: builtin/apply.c:3095
#, c-format
msgid "cannot checkout %s"
msgstr "kan inte checka ut %s"
-#: builtin/apply.c:3136 builtin/apply.c:3145 builtin/apply.c:3189
+#: builtin/apply.c:3140 builtin/apply.c:3149 builtin/apply.c:3194
#, c-format
msgid "read of %s failed"
msgstr "misslyckades läsa %s"
-#: builtin/apply.c:3169 builtin/apply.c:3391
+#: builtin/apply.c:3174 builtin/apply.c:3396
#, c-format
msgid "path %s has been renamed/deleted"
msgstr "sökvägen %s har ändrat namn/tagits bort"
-#: builtin/apply.c:3250 builtin/apply.c:3405
+#: builtin/apply.c:3255 builtin/apply.c:3410
#, c-format
msgid "%s: does not exist in index"
msgstr "%s: finns inte i indexet"
-#: builtin/apply.c:3254 builtin/apply.c:3397 builtin/apply.c:3419
+#: builtin/apply.c:3259 builtin/apply.c:3402 builtin/apply.c:3424
#, c-format
msgid "%s: %s"
msgstr "%s: %s"
-#: builtin/apply.c:3259 builtin/apply.c:3413
+#: builtin/apply.c:3264 builtin/apply.c:3418
#, c-format
msgid "%s: does not match index"
msgstr "%s: motsvarar inte indexet"
-#: builtin/apply.c:3361
+#: builtin/apply.c:3366
msgid "removal patch leaves file contents"
msgstr "patch för borttagning lämnar kvar filinnehåll"
-#: builtin/apply.c:3430
+#: builtin/apply.c:3435
#, c-format
msgid "%s: wrong type"
msgstr "%s: fel typ"
-#: builtin/apply.c:3432
+#: builtin/apply.c:3437
#, c-format
msgid "%s has type %o, expected %o"
msgstr "%s har typen %o, förväntade %o"
-#: builtin/apply.c:3533
+#: builtin/apply.c:3538
#, c-format
msgid "%s: already exists in index"
msgstr "%s: finns redan i indexet"
-#: builtin/apply.c:3536
+#: builtin/apply.c:3541
#, c-format
msgid "%s: already exists in working directory"
msgstr "%s: finns redan i arbetskatalogen"
-#: builtin/apply.c:3556
+#: builtin/apply.c:3561
#, 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:3561
+#: builtin/apply.c:3566
#, 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:3569
+#: builtin/apply.c:3574
#, c-format
msgid "%s: patch does not apply"
msgstr "%s: patchen kan inte tillämpas"
-#: builtin/apply.c:3582
+#: builtin/apply.c:3587
#, c-format
msgid "Checking patch %s..."
msgstr "Kontrollerar patchen %s..."
-#: builtin/apply.c:3675 builtin/checkout.c:215 builtin/reset.c:124
+#: builtin/apply.c:3680 builtin/checkout.c:216 builtin/reset.c:127
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "make_cache_entry misslyckades för sökvägen \"%s\""
-#: builtin/apply.c:3818
+#: builtin/apply.c:3823
#, c-format
msgid "unable to remove %s from index"
msgstr "kan inte ta bort %s från indexet"
-#: builtin/apply.c:3846
+#: builtin/apply.c:3851
#, c-format
-msgid "corrupt patch for subproject %s"
-msgstr "trasig patch för underprojektet %s"
+msgid "corrupt patch for submodule %s"
+msgstr "trasig patch för undermodulen %s"
-#: builtin/apply.c:3850
+#: builtin/apply.c:3855
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr "kan inte ta status på nyligen skapade filen \"%s\""
-#: builtin/apply.c:3855
+#: builtin/apply.c:3860
#, 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:3858 builtin/apply.c:3966
+#: builtin/apply.c:3863 builtin/apply.c:3971
#, c-format
msgid "unable to add cache entry for %s"
msgstr "kan inte lägga till cachepost för %s"
-#: builtin/apply.c:3891
+#: builtin/apply.c:3896
#, c-format
msgid "closing file '%s'"
msgstr "stänger filen \"%s\""
-#: builtin/apply.c:3940
+#: builtin/apply.c:3945
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "kan inte skriva filen \"%s\" läge %o"
-#: builtin/apply.c:4027
+#: builtin/apply.c:4032
#, c-format
msgid "Applied patch %s cleanly."
msgstr "Tillämpade patchen %s rent."
-#: builtin/apply.c:4035
+#: builtin/apply.c:4040
msgid "internal error"
msgstr "internt fel"
#. Say this even without --verbose
-#: builtin/apply.c:4038
+#: builtin/apply.c:4043
#, 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:4048
+#: builtin/apply.c:4053
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "trunkerar .rej-filnamnet till %.*s.rej"
-#: builtin/apply.c:4069
+#: builtin/apply.c:4074
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "Stycke %d tillämpades rent."
-#: builtin/apply.c:4072
+#: builtin/apply.c:4077
#, c-format
msgid "Rejected hunk #%d."
msgstr "Refuserar stycke %d."
-#: builtin/apply.c:4222
+#: builtin/apply.c:4227
msgid "unrecognized input"
msgstr "indata känns inte igen"
-#: builtin/apply.c:4233
+#: builtin/apply.c:4238
msgid "unable to read index file"
msgstr "kan inte läsa indexfilen"
-#: builtin/apply.c:4352 builtin/apply.c:4355 builtin/clone.c:91
+#: builtin/apply.c:4357 builtin/apply.c:4360 builtin/clone.c:91
#: builtin/fetch.c:63
msgid "path"
msgstr "sökväg"
-#: builtin/apply.c:4353
+#: builtin/apply.c:4358
msgid "don't apply changes matching the given path"
msgstr "tillämpa inte ändringar som motsvarar given sökväg"
-#: builtin/apply.c:4356
+#: builtin/apply.c:4361
msgid "apply changes matching the given path"
msgstr "tillämpa ändringar som motsvarar given sökväg"
-#: builtin/apply.c:4358
+#: builtin/apply.c:4363
msgid "num"
msgstr "antal"
-#: builtin/apply.c:4359
+#: builtin/apply.c:4364
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:4362
+#: builtin/apply.c:4367
msgid "ignore additions made by the patch"
msgstr "ignorera tillägg gjorda av patchen"
-#: builtin/apply.c:4364
+#: builtin/apply.c:4369
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:4368
+#: builtin/apply.c:4373
msgid "show number of added and deleted lines in decimal notation"
msgstr "visa antal tillagda och borttagna rader decimalt"
-#: builtin/apply.c:4370
+#: builtin/apply.c:4375
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:4372
+#: builtin/apply.c:4377
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:4374
+#: builtin/apply.c:4379
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:4376
+#: builtin/apply.c:4381
msgid "apply a patch without touching the working tree"
msgstr "tillämpa en patch utan att röra arbetskatalogen"
-#: builtin/apply.c:4378
+#: builtin/apply.c:4383
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr "tillämpa också patchen (använd med --stat/--summary/--check)"
-#: builtin/apply.c:4380
+#: builtin/apply.c:4385
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:4382
+#: builtin/apply.c:4387
msgid "build a temporary index based on embedded index information"
msgstr "bygg ett temporärt index baserat på inbyggd indexinformation"
-#: builtin/apply.c:4384 builtin/checkout-index.c:197 builtin/ls-files.c:463
+#: builtin/apply.c:4389 builtin/checkout-index.c:197 builtin/ls-files.c:462
msgid "paths are separated with NUL character"
msgstr "sökvägar avdelas med NUL-tecken"
-#: builtin/apply.c:4387
+#: builtin/apply.c:4392
msgid "ensure at least <n> lines of context match"
msgstr "se till att åtminstone <n> rader sammanhang är lika"
-#: builtin/apply.c:4388
+#: builtin/apply.c:4393
msgid "action"
msgstr "åtgärd"
-#: builtin/apply.c:4389
+#: builtin/apply.c:4394
msgid "detect new or modified lines that have whitespace errors"
msgstr "detektera nya eller ändrade rader som har fel i blanktecken"
-#: builtin/apply.c:4392 builtin/apply.c:4395
+#: builtin/apply.c:4397 builtin/apply.c:4400
msgid "ignore changes in whitespace when finding context"
msgstr "ignorera ändringar i blanktecken för sammanhang"
-#: builtin/apply.c:4398
+#: builtin/apply.c:4403
msgid "apply the patch in reverse"
msgstr "tillämpa patchen baklänges"
-#: builtin/apply.c:4400
+#: builtin/apply.c:4405
msgid "don't expect at least one line of context"
msgstr "förvänta inte minst en rad sammanhang"
-#: builtin/apply.c:4402
+#: builtin/apply.c:4407
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr "lämna refuserade stycken i motsvarande *.rej-filer"
-#: builtin/apply.c:4404
+#: builtin/apply.c:4409
msgid "allow overlapping hunks"
msgstr "tillåt överlappande stycken"
-#: builtin/apply.c:4407
+#: builtin/apply.c:4412
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr "tolerera felaktigt detekterade saknade nyradstecken vid filslut"
-#: builtin/apply.c:4410
+#: builtin/apply.c:4415
msgid "do not trust the line counts in the hunk headers"
msgstr "lite inte på antalet linjer i styckehuvuden"
-#: builtin/apply.c:4412
+#: builtin/apply.c:4417
msgid "root"
msgstr "rot"
-#: builtin/apply.c:4413
+#: builtin/apply.c:4418
msgid "prepend <root> to all filenames"
msgstr "lägg till <rot> i alla filnamn"
-#: builtin/apply.c:4435
+#: builtin/apply.c:4440
msgid "--3way outside a repository"
msgstr "--3way utanför arkiv"
-#: builtin/apply.c:4443
+#: builtin/apply.c:4448
msgid "--index outside a repository"
msgstr "--index utanför arkiv"
-#: builtin/apply.c:4446
+#: builtin/apply.c:4451
msgid "--cached outside a repository"
msgstr "--cached utanför arkiv"
-#: builtin/apply.c:4462
+#: builtin/apply.c:4467
#, c-format
msgid "can't open patch '%s'"
msgstr "kan inte öppna patchen \"%s\""
-#: builtin/apply.c:4476
+#: builtin/apply.c:4481
#, 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:4482 builtin/apply.c:4492
+#: builtin/apply.c:4487 builtin/apply.c:4497
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -2116,21 +2395,21 @@ msgstr "git archive: Fjärr utan URL"
msgid "git archive: expected ACK/NAK, got EOF"
msgstr "git archive: förväntade ACK/NAK, fick EOF"
-#: builtin/archive.c:63
+#: builtin/archive.c:61
#, c-format
msgid "git archive: NACK %s"
msgstr "git archive: NACK %s"
-#: builtin/archive.c:65
+#: builtin/archive.c:63
#, c-format
msgid "remote error: %s"
msgstr "fjärrfel: %s"
-#: builtin/archive.c:66
+#: builtin/archive.c:64
msgid "git archive: protocol error"
msgstr "git archive: protokollfel"
-#: builtin/archive.c:71
+#: builtin/archive.c:68
msgid "git archive: expected a flush"
msgstr "git archive: förväntade en tömning (flush)"
@@ -2146,123 +2425,123 @@ msgstr "utför 'git bisect next'"
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
+#: builtin/blame.c:26
msgid "git blame [options] [rev-opts] [rev] [--] file"
msgstr "git blame [flaggor] [rev-flaggor] [rev] [--] fil"
-#: builtin/blame.c:30 builtin/shortlog.c:15
+#: builtin/blame.c:31
msgid "[rev-opts] are documented in git-rev-list(1)"
msgstr "[rev-flaggor] dokumenteras i git-rev-list(1)"
-#: builtin/blame.c:2350
+#: builtin/blame.c:2276
msgid "Show blame entries as we find them, incrementally"
msgstr "Visa klandringsposter när vi hittar dem, interaktivt"
-#: builtin/blame.c:2351
+#: builtin/blame.c:2277
msgid "Show blank SHA-1 for boundary commits (Default: off)"
msgstr "Visa blank SHA-1 för gränsincheckningar (Standard: av)"
-#: builtin/blame.c:2352
+#: builtin/blame.c:2278
msgid "Do not treat root commits as boundaries (Default: off)"
msgstr "Behandla inte rotincheckningar som gränser (Standard: av)"
-#: builtin/blame.c:2353
+#: builtin/blame.c:2279
msgid "Show work cost statistics"
msgstr "Visa statistik över arbetskostnad"
-#: builtin/blame.c:2354
+#: builtin/blame.c:2280
msgid "Show output score for blame entries"
msgstr "Visa utdatapoäng för klandringsposter"
-#: builtin/blame.c:2355
+#: builtin/blame.c:2281
msgid "Show original filename (Default: auto)"
msgstr "Visa originalfilnamn (Standard: auto)"
-#: builtin/blame.c:2356
+#: builtin/blame.c:2282
msgid "Show original linenumber (Default: off)"
msgstr "Visa ursprungligt radnummer (Standard: av)"
-#: builtin/blame.c:2357
+#: builtin/blame.c:2283
msgid "Show in a format designed for machine consumption"
msgstr "Visa i ett format avsett för maskinkonsumtion"
-#: builtin/blame.c:2358
+#: builtin/blame.c:2284
msgid "Show porcelain format with per-line commit information"
msgstr "Visa porslinsformat med per-rad-incheckningsinformation"
-#: builtin/blame.c:2359
+#: builtin/blame.c:2285
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:2360
+#: builtin/blame.c:2286
msgid "Show raw timestamp (Default: off)"
msgstr "Visa rå tidsstämpel (Standard: av)"
-#: builtin/blame.c:2361
+#: builtin/blame.c:2287
msgid "Show long commit SHA1 (Default: off)"
msgstr "Visa lång inchecknings-SHA1 (Standard: av)"
-#: builtin/blame.c:2362
+#: builtin/blame.c:2288
msgid "Suppress author name and timestamp (Default: off)"
msgstr "Undertryck författarnamn och tidsstämpel (Standard: av)"
-#: builtin/blame.c:2363
+#: builtin/blame.c:2289
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:2364
+#: builtin/blame.c:2290
msgid "Ignore whitespace differences"
msgstr "Ignorera ändringar i blanksteg"
-#: builtin/blame.c:2365
+#: builtin/blame.c:2291
msgid "Spend extra cycles to find better match"
msgstr "Slösa extra cykler med att hitta bättre träff"
-#: builtin/blame.c:2366
+#: builtin/blame.c:2292
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:2367
+#: builtin/blame.c:2293
msgid "Use <file>'s contents as the final image"
msgstr "Använd <fil>s innehåll som slutgiltig bild"
-#: builtin/blame.c:2368 builtin/blame.c:2369
+#: builtin/blame.c:2294 builtin/blame.c:2295
msgid "score"
msgstr "poäng"
-#: builtin/blame.c:2368
+#: builtin/blame.c:2294
msgid "Find line copies within and across files"
msgstr "Hitta kopierade rader inuti och mellan filer"
-#: builtin/blame.c:2369
+#: builtin/blame.c:2295
msgid "Find line movements within and across files"
msgstr "Hitta flyttade rader inuti och mellan filer"
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
msgid "n,m"
msgstr "n,m"
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
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
+#: builtin/branch.c:24
msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
msgstr "git branch [flaggor] [-r | -a] [--merged | --no-merged]"
-#: builtin/branch.c:24
+#: builtin/branch.c:25
msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
msgstr "git branch [flaggor] [-l] [-f] <grennamn> [<startpunkt>]"
-#: builtin/branch.c:25
+#: builtin/branch.c:26
msgid "git branch [options] [-r] (-d | -D) <branchname>..."
msgstr "git branch [flaggor] [-r] (-d | -D) <grennamn>..."
-#: builtin/branch.c:26
+#: builtin/branch.c:27
msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
msgstr "git branch [flaggor] (-m | -M) [<gammal_gren>] <ny_gren>"
-#: builtin/branch.c:145
+#: builtin/branch.c:150
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
@@ -2271,7 +2550,7 @@ msgstr ""
"tar bort grenen \"%s\" som har slagits ihop med\n"
" \"%s\", men ännu inte slagits ihop med HEAD."
-#: builtin/branch.c:149
+#: builtin/branch.c:154
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
@@ -2280,12 +2559,12 @@ 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:163
+#: builtin/branch.c:168
#, c-format
msgid "Couldn't look up commit object for '%s'"
msgstr "Kunde inte slå upp incheckningsobjekt för \"%s\""
-#: builtin/branch.c:167
+#: builtin/branch.c:172
#, c-format
msgid ""
"The branch '%s' is not fully merged.\n"
@@ -2294,288 +2573,332 @@ msgstr ""
"Grenen \"%s\" har inte slagits samman i sin helhet.\n"
"Om du är säker på att du vill ta bort den, kör \"git branch -D %s\"."
-#: builtin/branch.c:180
+#: builtin/branch.c:185
msgid "Update of config-file failed"
msgstr "Misslyckades uppdatera konfigurationsfil"
-#: builtin/branch.c:208
+#: builtin/branch.c:213
msgid "cannot use -a with -d"
msgstr "kan inte ange -a med -d"
-#: builtin/branch.c:214
+#: builtin/branch.c:219
msgid "Couldn't look up commit object for HEAD"
msgstr "Kunde inte slå upp incheckningsobjekt för HEAD"
-#: builtin/branch.c:222
+#: builtin/branch.c:227
#, 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:235
+#: builtin/branch.c:240
#, c-format
msgid "remote branch '%s' not found."
msgstr "fjärrgrenen \"%s\" hittades inte."
-#: builtin/branch.c:236
+#: builtin/branch.c:241
#, c-format
msgid "branch '%s' not found."
msgstr "grenen \"%s\" hittades inte."
-#: builtin/branch.c:250
+#: builtin/branch.c:255
#, c-format
msgid "Error deleting remote branch '%s'"
msgstr "Fel vid borttagning av fjärrgrenen \"%s\""
-#: builtin/branch.c:251
+#: builtin/branch.c:256
#, c-format
msgid "Error deleting branch '%s'"
msgstr "Fel vid borttagning av grenen \"%s\""
-#: builtin/branch.c:258
+#: builtin/branch.c:263
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
msgstr "Tog bort fjärrgrenen %s (var %s).\n"
-#: builtin/branch.c:259
+#: builtin/branch.c:264
#, c-format
msgid "Deleted branch %s (was %s).\n"
msgstr "Tog bort grenen %s (var %s).\n"
-#: builtin/branch.c:361
+#: builtin/branch.c:366
#, c-format
msgid "branch '%s' does not point at a commit"
msgstr "grenen \"%s\" pekar inte på en incheckning"
-#: builtin/branch.c:433
+#: builtin/branch.c:453
#, c-format
msgid "[%s: behind %d]"
msgstr "[%s: bakom %d] "
-#: builtin/branch.c:435
+#: builtin/branch.c:455
#, c-format
msgid "[behind %d]"
msgstr "[bakom %d] "
-#: builtin/branch.c:439
+#: builtin/branch.c:459
#, c-format
msgid "[%s: ahead %d]"
msgstr "[%s: före %d] "
-#: builtin/branch.c:441
+#: builtin/branch.c:461
#, c-format
msgid "[ahead %d]"
msgstr "[före %d] "
-#: builtin/branch.c:444
+#: builtin/branch.c:464
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr "[%s: före %d, bakom %d] "
-#: builtin/branch.c:447
+#: builtin/branch.c:467
#, c-format
msgid "[ahead %d, behind %d]"
msgstr "[före %d, bakom %d] "
-#: builtin/branch.c:469
+#: builtin/branch.c:490
msgid " **** invalid ref ****"
msgstr " **** ogiltig ref ****"
-#: builtin/branch.c:560
+#: builtin/branch.c:582
+#, c-format
+msgid "(no branch, rebasing %s)"
+msgstr "(ingen gren, ombaserar %s)"
+
+#: builtin/branch.c:585
+#, c-format
+msgid "(no branch, bisect started on %s)"
+msgstr "(ingen gren, \"bisect\" startad på %s)"
+
+#: builtin/branch.c:588
+#, c-format
+msgid "(detached from %s)"
+msgstr "(frånkopplad från %s)"
+
+#: builtin/branch.c:591
msgid "(no branch)"
msgstr "(ingen gren)"
-#: builtin/branch.c:593
+#: builtin/branch.c:637
#, c-format
msgid "object '%s' does not point to a commit"
msgstr "objektet \"%s\" pekar på en incheckning"
-#: builtin/branch.c:625
+#: builtin/branch.c:669
msgid "some refs could not be read"
msgstr "vissa referenser kunde inte läsas"
-#: builtin/branch.c:638
+#: builtin/branch.c:682
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:648
+#: builtin/branch.c:692
#, c-format
msgid "Invalid branch name: '%s'"
msgstr "Felaktigt namn på gren: \"%s\""
-#: builtin/branch.c:663
+#: builtin/branch.c:707
msgid "Branch rename failed"
msgstr "Misslyckades byta namn på gren"
-#: builtin/branch.c:667
+#: builtin/branch.c:711
#, c-format
msgid "Renamed a misnamed branch '%s' away"
msgstr "Bytte bort namn på en felaktigt namngiven gren \"%s\""
-#: builtin/branch.c:671
+#: builtin/branch.c:715
#, 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:678
+#: builtin/branch.c:722
msgid "Branch is renamed, but update of config-file failed"
msgstr "Grenen namnbytt, men misslyckades uppdatera konfigurationsfilen"
-#: builtin/branch.c:693
+#: builtin/branch.c:737
#, c-format
msgid "malformed object name %s"
msgstr "felformat objektnamn %s"
-#: builtin/branch.c:717
+#: builtin/branch.c:761
#, c-format
msgid "could not write branch description template: %s"
msgstr "kunde inte skriva grenbeskrivningsmall: %s"
-#: builtin/branch.c:747
+#: builtin/branch.c:791
msgid "Generic options"
msgstr "Allmänna flaggor"
-#: builtin/branch.c:749
+#: builtin/branch.c:793
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:750
+#: builtin/branch.c:794
msgid "suppress informational messages"
msgstr "undertryck informationsmeddelanden"
-#: builtin/branch.c:751
+#: builtin/branch.c:795
msgid "set up tracking mode (see git-pull(1))"
msgstr "ställ in spårningsläge (se git-pull(1))"
-#: builtin/branch.c:753
+#: builtin/branch.c:797
msgid "change upstream info"
msgstr "ändra uppströmsinformation"
-#: builtin/branch.c:757
+#: builtin/branch.c:801
msgid "use colored output"
msgstr "använd färgad utdata"
-#: builtin/branch.c:758
+#: builtin/branch.c:802
msgid "act on remote-tracking branches"
msgstr "arbeta på fjärrspårande grenar"
-#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788
-#: builtin/branch.c:794 builtin/commit.c:1366 builtin/commit.c:1367
-#: builtin/commit.c:1368 builtin/commit.c:1369 builtin/tag.c:468
+#: builtin/branch.c:805 builtin/branch.c:811 builtin/branch.c:832
+#: builtin/branch.c:838 builtin/commit.c:1433 builtin/commit.c:1434
+#: builtin/commit.c:1435 builtin/commit.c:1436 builtin/tag.c:468
msgid "commit"
msgstr "incheckning"
-#: builtin/branch.c:762 builtin/branch.c:768
+#: builtin/branch.c:806 builtin/branch.c:812
msgid "print only branches that contain the commit"
msgstr "visa endast grenar som innehåller incheckningen"
-#: builtin/branch.c:774
+#: builtin/branch.c:818
msgid "Specific git-branch actions:"
msgstr "Specifika git-branch-åtgärder:"
-#: builtin/branch.c:775
+#: builtin/branch.c:819
msgid "list both remote-tracking and local branches"
msgstr "visa både fjärrspårande och lokala grenar"
-#: builtin/branch.c:777
+#: builtin/branch.c:821
msgid "delete fully merged branch"
msgstr "ta bort helt sammanslagen gren"
-#: builtin/branch.c:778
+#: builtin/branch.c:822
msgid "delete branch (even if not merged)"
msgstr "ta bort gren (även om inte helt sammanslagen)"
-#: builtin/branch.c:779
+#: builtin/branch.c:823
msgid "move/rename a branch and its reflog"
msgstr "flytta/ta bort en gren och dess reflogg"
-#: builtin/branch.c:780
+#: builtin/branch.c:824
msgid "move/rename a branch, even if target exists"
msgstr "flytta/ta bort en gren, även om målet finns"
-#: builtin/branch.c:781
+#: builtin/branch.c:825
msgid "list branch names"
msgstr "lista namn på grenar"
-#: builtin/branch.c:782
+#: builtin/branch.c:826
msgid "create the branch's reflog"
msgstr "skapa grenens reflogg"
-#: builtin/branch.c:784
+#: builtin/branch.c:828
msgid "edit the description for the branch"
msgstr "redigera beskrivning för grenen"
-#: builtin/branch.c:785
+#: builtin/branch.c:829
msgid "force creation (when already exists)"
msgstr "tvinga skapande (när den redan finns)"
-#: builtin/branch.c:788
+#: builtin/branch.c:832
msgid "print only not merged branches"
msgstr "visa endast ej sammanslagna grenar"
-#: builtin/branch.c:794
+#: builtin/branch.c:838
msgid "print only merged branches"
msgstr "visa endast sammanslagna grenar"
-#: builtin/branch.c:798
+#: builtin/branch.c:842
msgid "list branches in columns"
msgstr "visa grenar i spalter"
-#: builtin/branch.c:811
+#: builtin/branch.c:855
msgid "Failed to resolve HEAD as a valid ref."
msgstr "Misslyckades slå upp HEAD som giltig referens"
-#: builtin/branch.c:816 builtin/clone.c:561
+#: builtin/branch.c:860 builtin/clone.c:630
msgid "HEAD not found below refs/heads!"
msgstr "HEAD hittades inte under refs/heads!"
-#: builtin/branch.c:839
+#: builtin/branch.c:883
msgid "--column and --verbose are incompatible"
msgstr "--column och --verbose är inkompatibla"
-#: builtin/branch.c:845
+#: builtin/branch.c:889 builtin/branch.c:928
msgid "branch name required"
msgstr "grennamn krävs"
-#: builtin/branch.c:860
+#: builtin/branch.c:904
msgid "Cannot give description to detached HEAD"
msgstr "Kan inte beskriva frånkopplad HEAD"
-#: builtin/branch.c:865
+#: builtin/branch.c:909
msgid "cannot edit description of more than one branch"
msgstr "kan inte redigera beskrivning för mer än en gren"
-#: builtin/branch.c:872
+#: builtin/branch.c:916
#, c-format
msgid "No commit on branch '%s' yet."
msgstr "Inga incheckningar på grenen \"%s\" ännu"
-#: builtin/branch.c:875
+#: builtin/branch.c:919
#, c-format
msgid "No branch named '%s'."
msgstr "Ingen gren vid namnet \"%s\"."
-#: builtin/branch.c:888
+#: builtin/branch.c:934
msgid "too many branches for a rename operation"
msgstr "för många grenar för namnbyte"
-#: builtin/branch.c:893
+#: builtin/branch.c:939
+msgid "too many branches to set new upstream"
+msgstr "för många grenar för att byta uppström"
+
+#: builtin/branch.c:943
+#, c-format
+msgid ""
+"could not set upstream of HEAD to %s when it does not point to any branch."
+msgstr ""
+"kunde inte sätta uppström för HEAD till %s när det inte pekar mot någon gren."
+
+#: builtin/branch.c:946 builtin/branch.c:968 builtin/branch.c:990
+#, c-format
+msgid "no such branch '%s'"
+msgstr "okänd gren \"%s\""
+
+#: builtin/branch.c:950
#, c-format
msgid "branch '%s' does not exist"
msgstr "grenen \"%s\" finns inte"
-#: builtin/branch.c:905
+#: builtin/branch.c:962
+msgid "too many branches to unset upstream"
+msgstr "för många grenar för att ta bort uppström"
+
+#: builtin/branch.c:966
+msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgstr ""
+"kunde inte ta bort uppström för HEAD när det inte pekar mot någon gren."
+
+#: builtin/branch.c:972
#, c-format
msgid "Branch '%s' has no upstream information"
msgstr "Grenen \"%s\" har ingen uppströmsinformation"
-#: builtin/branch.c:920
+#: builtin/branch.c:987
+msgid "it does not make sense to create 'HEAD' manually"
+msgstr "kan inte skapa \"HEAD\" manuellt"
+
+#: builtin/branch.c:993
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:923
+#: builtin/branch.c:996
#, c-format
msgid ""
"The --set-upstream flag is deprecated and will be removed. Consider using --"
@@ -2584,7 +2907,7 @@ msgstr ""
"Flaggan --set-upstream rekommenderas ej och kommer tas bort. Använd --track "
"eller --set-upstream-to\n"
-#: builtin/branch.c:940
+#: builtin/branch.c:1013
#, c-format
msgid ""
"\n"
@@ -2595,12 +2918,12 @@ msgstr ""
"Om du vill göra så att \"%s\" spårar \"%s\" gör du så här:\n"
"\n"
-#: builtin/branch.c:941
+#: builtin/branch.c:1014
#, c-format
msgid " git branch -d %s\n"
msgstr " git branch -d %s\n"
-#: builtin/branch.c:942
+#: builtin/branch.c:1015
#, c-format
msgid " git branch --set-upstream-to %s\n"
msgstr " git branch --set-upstream-to %s\n"
@@ -2618,43 +2941,43 @@ 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/cat-file.c:247
+#: builtin/cat-file.c:285
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
+#: builtin/cat-file.c:286
msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
msgstr "git cat-file (--batch|--batch-check) < <objektlista>"
-#: builtin/cat-file.c:266
+#: builtin/cat-file.c:323
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
+#: builtin/cat-file.c:324
msgid "show object type"
msgstr "visa objekttyp"
-#: builtin/cat-file.c:268
+#: builtin/cat-file.c:325
msgid "show object size"
msgstr "visa objektstorlek"
-#: builtin/cat-file.c:270
+#: builtin/cat-file.c:327
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
+#: builtin/cat-file.c:328
msgid "pretty-print object's content"
msgstr "visa objektets innehåll snyggt"
-#: builtin/cat-file.c:273
+#: builtin/cat-file.c:330
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
+#: builtin/cat-file.c:332
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
+#: builtin/cat-file.c:335
msgid "show info about objects fed from the standard input"
msgstr "visa information för objekt som listas på standard in"
@@ -2682,30 +3005,55 @@ msgstr "läs filnamn från standard in"
msgid "input paths are terminated by a null character"
msgstr "sökvägar avdelas med null-tecken"
-#: builtin/check-ignore.c:18 builtin/checkout.c:1012 builtin/gc.c:177
+#: builtin/check-ignore.c:18 builtin/checkout.c:1054 builtin/gc.c:177
msgid "suppress progress reporting"
msgstr "undertryck förloppsrapportering"
-#: builtin/check-ignore.c:151
+#: builtin/check-ignore.c:26
+msgid "show non-matching input paths"
+msgstr "visa indatasökvägar som inte träffas"
+
+#: builtin/check-ignore.c:143
msgid "cannot specify pathnames with --stdin"
msgstr "kan inte ange sökvägsnamn med --stdin"
-#: builtin/check-ignore.c:154
+#: builtin/check-ignore.c:146
msgid "-z only makes sense with --stdin"
msgstr "-z kan endast användas tillsammans med --stdin"
-#: builtin/check-ignore.c:156
+#: builtin/check-ignore.c:148
msgid "no path specified"
msgstr "ingen sökväg angavs"
-#: builtin/check-ignore.c:160
+#: builtin/check-ignore.c:152
msgid "--quiet is only valid with a single pathname"
msgstr "--quiet kan endast användas med ett enkelt sökvägsnamn"
-#: builtin/check-ignore.c:162
+#: builtin/check-ignore.c:154
msgid "cannot have both --quiet and --verbose"
msgstr "kan inte använda både --quiet och --verbose"
+#: builtin/check-ignore.c:157
+msgid "--non-matching is only valid with --verbose"
+msgstr "--non-matching är endast giltig med --verbose"
+
+#: builtin/check-mailmap.c:8
+msgid "git check-mailmap [options] <contact>..."
+msgstr "git check-mailmap [flaggor] <kontakt>..."
+
+#: builtin/check-mailmap.c:13
+msgid "also read contacts from stdin"
+msgstr "läs även kontakter från standard in"
+
+#: builtin/check-mailmap.c:24
+#, c-format
+msgid "unable to parse contact: %s"
+msgstr "kunde inte tolka kontakt: %s"
+
+#: builtin/check-mailmap.c:47
+msgid "no contacts specified"
+msgstr "inga kontakter angavs"
+
#: builtin/checkout-index.c:126
msgid "git checkout-index [options] [--] [<file>...]"
msgstr "git checkout-index [flaggor] [--] [<fil>...]"
@@ -2758,106 +3106,106 @@ msgstr "git checkout [flaggor] <gren>"
msgid "git checkout [options] [<branch>] -- <file>..."
msgstr "git checkout [flaggor] [<gren>] -- <fil>..."
-#: builtin/checkout.c:116 builtin/checkout.c:149
+#: builtin/checkout.c:117 builtin/checkout.c:150
#, c-format
msgid "path '%s' does not have our version"
msgstr "sökvägen \"%s\" har inte vår version"
-#: builtin/checkout.c:118 builtin/checkout.c:151
+#: builtin/checkout.c:119 builtin/checkout.c:152
#, c-format
msgid "path '%s' does not have their version"
msgstr "sökvägen \"%s\" har inte deras version"
-#: builtin/checkout.c:134
+#: builtin/checkout.c:135
#, 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:178
+#: builtin/checkout.c:179
#, 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:195
+#: builtin/checkout.c:196
#, c-format
msgid "path '%s': cannot merge"
msgstr "sökväg \"%s\": kan inte slå ihop"
-#: builtin/checkout.c:212
+#: builtin/checkout.c:213
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr "Kunde inte lägga till sammanslagningsresultat för \"%s\""
-#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
-#: builtin/checkout.c:245
+#: builtin/checkout.c:237 builtin/checkout.c:240 builtin/checkout.c:243
+#: builtin/checkout.c:246
#, 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
+#: builtin/checkout.c:249 builtin/checkout.c:252
#, c-format
msgid "'%s' cannot be used with %s"
msgstr "\"%s\" kan inte användas med %s"
-#: builtin/checkout.c:254
+#: builtin/checkout.c:255
#, 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
+#: builtin/checkout.c:266 builtin/checkout.c:458
msgid "corrupt index file"
msgstr "indexfilen är trasig"
-#: builtin/checkout.c:295 builtin/checkout.c:302
+#: builtin/checkout.c:329 builtin/checkout.c:336
#, c-format
msgid "path '%s' is unmerged"
msgstr "sökvägen \"%s\" har inte slagits ihop"
-#: builtin/checkout.c:448
+#: builtin/checkout.c:480
msgid "you need to resolve your current index first"
msgstr "du måste lösa ditt befintliga index först"
-#: builtin/checkout.c:569
+#: builtin/checkout.c:601
#, c-format
msgid "Can not do reflog for '%s'\n"
msgstr "Kan inte skapa referenslog för \"%s\"\n"
-#: builtin/checkout.c:602
+#: builtin/checkout.c:639
msgid "HEAD is now at"
msgstr "HEAD är nu på"
-#: builtin/checkout.c:609
+#: builtin/checkout.c:646
#, c-format
msgid "Reset branch '%s'\n"
msgstr "Återställ gren \"%s\"\n"
-#: builtin/checkout.c:612
+#: builtin/checkout.c:649
#, c-format
msgid "Already on '%s'\n"
msgstr "Redan på \"%s\"\n"
-#: builtin/checkout.c:616
+#: builtin/checkout.c:653
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr "Växlade till och nollställde grenen \"%s\"\n"
-#: builtin/checkout.c:618 builtin/checkout.c:955
+#: builtin/checkout.c:655 builtin/checkout.c:997
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr "Växlade till en ny gren \"%s\"\n"
-#: builtin/checkout.c:620
+#: builtin/checkout.c:657
#, c-format
msgid "Switched to branch '%s'\n"
msgstr "Växlade till grenen \"%s\"\n"
-#: builtin/checkout.c:676
+#: builtin/checkout.c:713
#, c-format
msgid " ... and %d more.\n"
msgstr " ... och %d till.\n"
#. The singular version
-#: builtin/checkout.c:682
+#: builtin/checkout.c:719
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -2880,7 +3228,7 @@ msgstr[1] ""
"\n"
"%s\n"
-#: builtin/checkout.c:700
+#: builtin/checkout.c:737
#, c-format
msgid ""
"If you want to keep them by creating a new branch, this may be a good time\n"
@@ -2895,132 +3243,136 @@ msgstr ""
" git branch nytt_grennamn %s\n"
"\n"
-#: builtin/checkout.c:730
+#: builtin/checkout.c:767
msgid "internal error in revision walk"
msgstr "internt fel vid genomgång av revisioner (revision walk)"
-#: builtin/checkout.c:734
+#: builtin/checkout.c:771
msgid "Previous HEAD position was"
msgstr "Tidigare position för HEAD var"
-#: builtin/checkout.c:761 builtin/checkout.c:950
+#: builtin/checkout.c:798 builtin/checkout.c:992
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:886
+#: builtin/checkout.c:928
#, c-format
msgid "invalid reference: %s"
msgstr "felaktig referens: %s"
#. case (1): want a tree
-#: builtin/checkout.c:925
+#: builtin/checkout.c:967
#, c-format
msgid "reference is not a tree: %s"
msgstr "referensen är inte ett träd: %s"
-#: builtin/checkout.c:964
+#: builtin/checkout.c:1006
msgid "paths cannot be used with switching branches"
msgstr "sökvägar kan inte användas vid byte av gren"
-#: builtin/checkout.c:967 builtin/checkout.c:971
+#: builtin/checkout.c:1009 builtin/checkout.c:1013
#, c-format
msgid "'%s' cannot be used with switching branches"
msgstr "\"%s\" kan inte användas vid byte av gren"
-#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983
-#: builtin/checkout.c:986
+#: builtin/checkout.c:1017 builtin/checkout.c:1020 builtin/checkout.c:1025
+#: builtin/checkout.c:1028
#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "\"%s\" kan inte användas med \"%s\""
-#: builtin/checkout.c:991
+#: builtin/checkout.c:1033
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
msgstr "Kan inte växla gren till icke-incheckningen \"%s\""
-#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89
+#: builtin/checkout.c:1055 builtin/checkout.c:1057 builtin/clone.c:89
#: builtin/remote.c:169 builtin/remote.c:171
msgid "branch"
msgstr "gren"
-#: builtin/checkout.c:1014
+#: builtin/checkout.c:1056
msgid "create and checkout a new branch"
msgstr "skapa och checka ut en ny gren"
-#: builtin/checkout.c:1016
+#: builtin/checkout.c:1058
msgid "create/reset and checkout a branch"
msgstr "skapa/nollställ och checka ut en gren"
-#: builtin/checkout.c:1017
+#: builtin/checkout.c:1059
msgid "create reflog for new branch"
msgstr "skapa reflogg för ny gren"
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1060
msgid "detach the HEAD at named commit"
msgstr "koppla från HEAD vid namngiven incheckning"
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1061
msgid "set upstream info for new branch"
msgstr "sätt uppströmsinformation för ny gren"
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new branch"
msgstr "ny gren"
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new unparented branch"
msgstr "ny gren utan förälder"
-#: builtin/checkout.c:1022
+#: builtin/checkout.c:1064
msgid "checkout our version for unmerged files"
msgstr "checka ut vår version för ej sammanslagna filer"
-#: builtin/checkout.c:1024
+#: builtin/checkout.c:1066
msgid "checkout their version for unmerged files"
msgstr "checka ut deras version för ej sammanslagna filer"
-#: builtin/checkout.c:1026
+#: builtin/checkout.c:1068
msgid "force checkout (throw away local modifications)"
msgstr "tvinga utcheckning (kasta bort lokala ändringar)"
-#: builtin/checkout.c:1027
+#: builtin/checkout.c:1069
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:1028 builtin/merge.c:215
+#: builtin/checkout.c:1070 builtin/merge.c:232
msgid "update ignored files (default)"
msgstr "uppdatera ignorerade filer (standard)"
-#: builtin/checkout.c:1029 builtin/log.c:1147 parse-options.h:245
+#: builtin/checkout.c:1071 builtin/log.c:1208 parse-options.h:249
msgid "style"
msgstr "stil"
-#: builtin/checkout.c:1030
+#: builtin/checkout.c:1072
msgid "conflict style (merge or diff3)"
msgstr "konfliktstil (merge eller diff3)"
-#: builtin/checkout.c:1033
+#: builtin/checkout.c:1075
+msgid "do not limit pathspecs to sparse entries only"
+msgstr "begränsa inte sökvägar till endast glesa poster"
+
+#: builtin/checkout.c:1077
msgid "second guess 'git checkout no-such-branch'"
msgstr "förutspå \"git checkout gren-saknas\""
-#: builtin/checkout.c:1057
+#: builtin/checkout.c:1101
msgid "-b, -B and --orphan are mutually exclusive"
msgstr "-b, -B och --orphan är ömsesidigt uteslutande"
-#: builtin/checkout.c:1074
+#: builtin/checkout.c:1118
msgid "--track needs a branch name"
msgstr "--track behöver ett namn på en gren"
-#: builtin/checkout.c:1081
+#: builtin/checkout.c:1125
msgid "Missing branch name; try -b"
msgstr "Grennamn saknas; försök med -b"
-#: builtin/checkout.c:1116
+#: builtin/checkout.c:1160
msgid "invalid path specification"
msgstr "felaktig sökvägsangivelse"
-#: builtin/checkout.c:1123
+#: builtin/checkout.c:1167
#, c-format
msgid ""
"Cannot update paths and switch to branch '%s' at the same time.\n"
@@ -3029,12 +3381,12 @@ msgstr ""
"Kan inte uppdatera sökvägar och växla till grenen \"%s\" samtidigt.\n"
"Ville du checka ut \"%s\" som inte kan lösas som en utcheckning?"
-#: builtin/checkout.c:1128
+#: builtin/checkout.c:1172
#, 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:1132
+#: builtin/checkout.c:1176
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
@@ -3042,90 +3394,193 @@ msgstr ""
"git checkout: --ours/--theirs, --force och --merge är inkompatibla när\n"
"du checkar ut från indexet."
-#: builtin/clean.c:20
-msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+#: builtin/clean.c:25
+msgid ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
msgstr ""
-"git clean [-d] [-f] [-n] [-q] [-e <mönster>] [-x | -X] [--] <sökvägar>..."
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <mönster>] [-x | -X] [--] "
+"<sökvägar>..."
-#: builtin/clean.c:24
+#: builtin/clean.c:29
#, c-format
msgid "Removing %s\n"
msgstr "Tar bort %s\n"
-#: builtin/clean.c:25
+#: builtin/clean.c:30
#, c-format
msgid "Would remove %s\n"
msgstr "Skulle ta bort %s\n"
-#: builtin/clean.c:26
+#: builtin/clean.c:31
#, c-format
msgid "Skipping repository %s\n"
msgstr "Hoppar över arkivet %s\n"
-#: builtin/clean.c:27
+#: builtin/clean.c:32
#, c-format
msgid "Would skip repository %s\n"
msgstr "Skulle hoppa över arkivet %s\n"
-#: builtin/clean.c:28
+#: builtin/clean.c:33
#, c-format
msgid "failed to remove %s"
msgstr "misslyckades ta bort %s"
-#: builtin/clean.c:160
+#: builtin/clean.c:293
+msgid ""
+"Prompt help:\n"
+"1 - select a numbered item\n"
+"foo - select item based on unique prefix\n"
+" - (empty) select nothing"
+msgstr ""
+"Kommandohjälp:\n"
+"1 - markera en numrerad post\n"
+"foo - markera post baserad på unikt prefix\n"
+" - (tomt) markera ingenting"
+
+#: builtin/clean.c:297
+msgid ""
+"Prompt help:\n"
+"1 - select a single item\n"
+"3-5 - select a range of items\n"
+"2-3,6-9 - select multiple ranges\n"
+"foo - select item based on unique prefix\n"
+"-... - unselect specified items\n"
+"* - choose all items\n"
+" - (empty) finish selecting"
+msgstr ""
+"Kommandohjälp:\n"
+"1 - markera en ensam post\n"
+"3-5 - markera ett intervall med poster\n"
+"2-3,6-9 - markera flera intervall\n"
+"foo - markera post baserad på unikt prefix\n"
+"-... - avmarkera specifika poster\n"
+"* - välj alla poster\n"
+" - (tomt) avsluta markering"
+
+#: builtin/clean.c:515
+#, c-format
+msgid "Huh (%s)?"
+msgstr "Vadå (%s)?"
+
+#: builtin/clean.c:658
+#, c-format
+msgid "Input ignore patterns>> "
+msgstr "Ange ignoreringsmönster>>"
+
+#: builtin/clean.c:695
+#, c-format
+msgid "WARNING: Cannot find items matched by: %s"
+msgstr "VARNING: Hittar inte poster som motsvarar: %s"
+
+#: builtin/clean.c:716
+msgid "Select items to delete"
+msgstr "Välj poster att ta bort"
+
+#: builtin/clean.c:756
+#, c-format
+msgid "remove %s? "
+msgstr "ta bort %s?"
+
+#: builtin/clean.c:781
+msgid "Bye."
+msgstr "Hej då."
+
+#: builtin/clean.c:789
+msgid ""
+"clean - start cleaning\n"
+"filter by pattern - exclude items from deletion\n"
+"select by numbers - select items to be deleted by numbers\n"
+"ask each - confirm each deletion (like \"rm -i\")\n"
+"quit - stop cleaning\n"
+"help - this screen\n"
+"? - help for prompt selection"
+msgstr ""
+"clean - börja städa\n"
+"filter by pattern - uteslut poster från borttagning\n"
+"select by numbers - markera poster som ska tas bort med siffror\n"
+"ask each - bekräfta varje borttagning (som \"rm -i\")\n"
+"quit - sluta städa\n"
+"help - denna skärm\n"
+"? - hjälp för kommandoval"
+
+#: builtin/clean.c:816
+msgid "*** Commands ***"
+msgstr "*** Kommandon ***"
+
+#: builtin/clean.c:817
+msgid "What now"
+msgstr "Vad nu"
+
+#: builtin/clean.c:825
+msgid "Would remove the following item:"
+msgid_plural "Would remove the following items:"
+msgstr[0] "Skulle ta bort följande post:"
+msgstr[1] "Skulle ta bort följande poster:"
+
+#: builtin/clean.c:842
+msgid "No more files to clean, exiting."
+msgstr "Inga fler filer att städa, avslutar."
+
+#: builtin/clean.c:874
msgid "do not print names of files removed"
msgstr "skriv inte ut namn på borttagna filer"
-#: builtin/clean.c:162
+#: builtin/clean.c:876
msgid "force"
msgstr "tvinga"
-#: builtin/clean.c:164
+#: builtin/clean.c:877
+msgid "interactive cleaning"
+msgstr "städa interaktivt"
+
+#: builtin/clean.c:879
msgid "remove whole directories"
msgstr "ta bort hela kataloger"
-#: builtin/clean.c:165 builtin/describe.c:413 builtin/grep.c:717
-#: builtin/ls-files.c:494 builtin/name-rev.c:231 builtin/show-ref.c:182
+#: builtin/clean.c:880 builtin/describe.c:420 builtin/grep.c:716
+#: builtin/ls-files.c:493 builtin/name-rev.c:315 builtin/show-ref.c:186
msgid "pattern"
msgstr "mönster"
-#: builtin/clean.c:166
+#: builtin/clean.c:881
msgid "add <pattern> to ignore rules"
msgstr "lägg till <mönster> till ignoreringsregler"
-#: builtin/clean.c:167
+#: builtin/clean.c:882
msgid "remove ignored files, too"
msgstr "ta även bort ignorerade filer"
-#: builtin/clean.c:169
+#: builtin/clean.c:884
msgid "remove only ignored files"
msgstr "ta endast bort ignorerade filer"
-#: builtin/clean.c:187
+#: builtin/clean.c:902
msgid "-x and -X cannot be used together"
msgstr "-x och -X kan inte användas samtidigt"
-#: builtin/clean.c:191
+#: builtin/clean.c:906
msgid ""
-"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+"clean.requireForce set to true and neither -i, -n nor -f given; refusing to "
+"clean"
msgstr ""
-"clean.requireForce satt till true, men varken -n eller -f angavs; vägrar "
+"clean.requireForce satt till true, men varken -i, -n eller -f angavs; vägrar "
"städa"
-#: builtin/clean.c:194
+#: builtin/clean.c:909
msgid ""
-"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
-"clean"
+"clean.requireForce defaults to true and neither -i, -n nor -f given; "
+"refusing to clean"
msgstr ""
-"clean.requireForce har standardvärdet true, men varken -n eller -f angavs; "
-"vägrar städa"
+"clean.requireForce har standardvärdet true och varken -i, -n eller -f "
+"angavs; vägrar städa"
#: 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:436
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:229
+#: builtin/push.c:462
msgid "force progress reporting"
msgstr "tvinga förloppsrapportering"
@@ -3185,7 +3640,7 @@ msgstr "checka ut <gren> istället för fjärrens HEAD"
msgid "path to git-upload-pack on the remote"
msgstr "sökväg till git-upload-pack på fjärren"
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:661
msgid "depth"
msgstr "djup"
@@ -3213,123 +3668,155 @@ msgstr "nyckel=värde"
msgid "set config inside the new repository"
msgstr "ställ in konfiguration i det nya arkivet"
-#: builtin/clone.c:243
+#: builtin/clone.c:253
#, c-format
-msgid "reference repository '%s' is not a local directory."
-msgstr "referensarkivet \"%s\" är inte en lokal katalog."
+msgid "reference repository '%s' is not a local repository."
+msgstr "referensarkivet \"%s\" är inte ett lokalt arkiv."
-#: builtin/clone.c:306
+#: builtin/clone.c:316
#, c-format
msgid "failed to create directory '%s'"
msgstr "misslyckades skapa katalogen \"%s\""
-#: builtin/clone.c:308 builtin/diff.c:77
+#: builtin/clone.c:318 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
msgstr "misslyckades ta status på \"%s\""
-#: builtin/clone.c:310
+#: builtin/clone.c:320
#, c-format
msgid "%s exists and is not a directory"
msgstr "%s finns och är ingen katalog"
-#: builtin/clone.c:324
+#: builtin/clone.c:334
#, c-format
msgid "failed to stat %s\n"
msgstr "misslyckades ta status på %s\n"
-#: builtin/clone.c:346
+#: builtin/clone.c:356
#, c-format
msgid "failed to create link '%s'"
msgstr "misslyckades skapa länken \"%s\""
-#: builtin/clone.c:350
+#: builtin/clone.c:360
#, c-format
msgid "failed to copy file to '%s'"
msgstr "misslyckades kopiera filen till \"%s\""
-#: builtin/clone.c:373
+#: builtin/clone.c:383
#, c-format
msgid "done.\n"
msgstr "klart.\n"
-#: builtin/clone.c:443
+#: builtin/clone.c:396
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry the checkout with 'git checkout -f HEAD'\n"
+msgstr ""
+"Klonen lyckades, men utcheckningen misslyckades.\n"
+"Du kan inspektera det som checkades ut med \"git status\"\n"
+"och försöka checka ut igen med \"git checkout -f HEAD\"\n"
+
+#: builtin/clone.c:475
#, 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:552
+#: builtin/clone.c:555
+#, c-format
+msgid "Checking connectivity... "
+msgstr "Kontrollerar anslutning..."
+
+#: builtin/clone.c:558
+msgid "remote did not send all necessary objects"
+msgstr "fjärren sände inte alla nödvändiga objekt"
+
+#: builtin/clone.c:560
+#, c-format
+msgid "done\n"
+msgstr "klart\n"
+
+#: builtin/clone.c:621
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:690
+#: builtin/clone.c:652
+msgid "unable to checkout working tree"
+msgstr "kunde inte checka ut arbetskatalogen"
+
+#: builtin/clone.c:760
msgid "Too many arguments."
msgstr "För många argument."
-#: builtin/clone.c:694
+#: builtin/clone.c:764
msgid "You must specify a repository to clone."
msgstr "Du måste ange ett arkiv att klona."
-#: builtin/clone.c:705
+#: builtin/clone.c:775
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr "flaggorna --bare och --origin %s är inkompatibla."
-#: builtin/clone.c:708
+#: builtin/clone.c:778
msgid "--bare and --separate-git-dir are incompatible."
msgstr "flaggorna --bare och --separate-git-dir är inkompatibla."
-#: builtin/clone.c:721
+#: builtin/clone.c:791
#, c-format
msgid "repository '%s' does not exist"
msgstr "arkivet \"%s\" finns inte"
-#: builtin/clone.c:726
+#: builtin/clone.c:796
msgid "--depth is ignored in local clones; use file:// instead."
msgstr "--depth ignoreras i lokala kloningar; använd file:// istället"
-#: builtin/clone.c:736
+#: builtin/clone.c:798
+msgid "--local is ignored"
+msgstr "--local ignoreras"
+
+#: builtin/clone.c:808
#, 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:746
+#: builtin/clone.c:818
#, c-format
msgid "working tree '%s' already exists."
msgstr "arbetsträdet \"%s\" finns redan."
-#: builtin/clone.c:759 builtin/clone.c:771
+#: builtin/clone.c:831 builtin/clone.c:843
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "kunde inte skapa inledande kataloger för \"%s\""
-#: builtin/clone.c:762
+#: builtin/clone.c:834
#, c-format
msgid "could not create work tree dir '%s'."
msgstr "kunde inte skapa arbetskatalogen \"%s\""
-#: builtin/clone.c:781
+#: builtin/clone.c:853
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "Klonar till ett naket arkiv \"%s\"...\n"
-#: builtin/clone.c:783
+#: builtin/clone.c:855
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "Klonar till \"%s\"...\n"
-#: builtin/clone.c:818
+#: builtin/clone.c:890
#, c-format
msgid "Don't know how to clone %s"
msgstr "Vet inte hur man klonar %s"
-#: builtin/clone.c:867
+#: builtin/clone.c:942
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "Fjärrgrenen %s hittades inte i uppströmsarkivet %s"
-#: builtin/clone.c:874
+#: builtin/clone.c:949
msgid "You appear to have cloned an empty repository."
msgstr "Du verkar ha klonat ett tomt arkiv."
@@ -3365,15 +3852,15 @@ msgstr "Spaltfyllnad mellan spalter"
msgid "--command must be the first argument"
msgstr "--command måste vara första argument"
-#: builtin/commit.c:34
+#: builtin/commit.c:35
msgid "git commit [options] [--] <pathspec>..."
msgstr "git commit [flaggor] [--] <sökväg>..."
-#: builtin/commit.c:39
+#: builtin/commit.c:40
msgid "git status [options] [--] <pathspec>..."
msgstr "git status [flaggor] [--] <sökväg>..."
-#: builtin/commit.c:44
+#: builtin/commit.c:45
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
@@ -3398,7 +3885,7 @@ msgstr ""
"\n"
" git commit --amend --reset-author\n"
-#: builtin/commit.c:56
+#: builtin/commit.c:57
msgid ""
"You asked to amend the most recent commit, but doing so would make\n"
"it empty. You can repeat your command with --allow-empty, or you can\n"
@@ -3408,109 +3895,127 @@ msgstr ""
"blir den tom. Du kan köra kommandot på nytt med --allow-empty, eller\n"
"så kan du ta bort incheckningen helt med \"git reset HEAD^\".\n"
-#: builtin/commit.c:61
+#: builtin/commit.c:62
msgid ""
"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
"If you wish to commit it anyway, use:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Otherwise, please use 'git reset'\n"
msgstr ""
"Den tidigare \"cherry-pick\":en är nu tom, kanske på grund av en löst\n"
"konflikt. Om du vill checka in den ändå använder du:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Annars använder du \"git reset\"\n"
-#: builtin/commit.c:258
+#: builtin/commit.c:69
+msgid "Otherwise, please use 'git reset'\n"
+msgstr "Använd annars \"git reset\"\n"
+
+#: builtin/commit.c:72
+msgid ""
+"If you wish to skip this commit, use:\n"
+"\n"
+" git reset\n"
+"\n"
+"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
+"the remaining commits.\n"
+msgstr ""
+"Om du vill hoppa över incheckningen, använd:\n"
+"\n"
+" git reset\n"
+"\n"
+"\"git cherry-pick --continue\" kommer därefter att återuppta\n"
+"cherry-pick för återstående incheckningar.\n"
+
+#: builtin/commit.c:279
msgid "failed to unpack HEAD tree object"
msgstr "misslyckades packa upp HEAD:s trädobjekt"
-#: builtin/commit.c:300
+#: builtin/commit.c:321
msgid "unable to create temporary index"
msgstr "kunde inte skapa temporär indexfil"
-#: builtin/commit.c:306
+#: builtin/commit.c:327
msgid "interactive add failed"
msgstr "interaktiv tilläggning misslyckades"
-#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410
+#: builtin/commit.c:360 builtin/commit.c:381 builtin/commit.c:431
msgid "unable to write new_index file"
msgstr "kunde inte skriva filen new_index"
-#: builtin/commit.c:391
+#: builtin/commit.c:412
msgid "cannot do a partial commit during a merge."
msgstr "kan inte utföra en delvis incheckning under en sammanslagning."
-#: builtin/commit.c:393
+#: builtin/commit.c:414
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:403
+#: builtin/commit.c:424
msgid "cannot read the index"
msgstr "kan inte läsa indexet"
-#: builtin/commit.c:423
+#: builtin/commit.c:444
msgid "unable to write temporary index file"
msgstr "kunde inte skriva temporär indexfil"
-#: builtin/commit.c:511 builtin/commit.c:517
+#: builtin/commit.c:535 builtin/commit.c:541
#, c-format
msgid "invalid commit: %s"
msgstr "felaktig incheckning: %s"
-#: builtin/commit.c:540
+#: builtin/commit.c:563
msgid "malformed --author parameter"
msgstr "felformad \"--author\"-flagga"
-#: builtin/commit.c:560
+#: builtin/commit.c:583
#, c-format
msgid "Malformed ident string: '%s'"
msgstr "Felaktig indragningssträng: \"%s\""
-#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954
+#: builtin/commit.c:621 builtin/commit.c:654 builtin/commit.c:982
#, c-format
msgid "could not lookup commit %s"
msgstr "kunde inte slå upp incheckningen %s"
-#: builtin/commit.c:610 builtin/shortlog.c:272
+#: builtin/commit.c:633 builtin/shortlog.c:271
#, c-format
msgid "(reading log message from standard input)\n"
msgstr "(läser loggmeddelande från standard in)\n"
-#: builtin/commit.c:612
+#: builtin/commit.c:635
msgid "could not read log from standard input"
msgstr "kunde inte läsa logg från standard in"
-#: builtin/commit.c:616
+#: builtin/commit.c:639
#, c-format
msgid "could not read log file '%s'"
msgstr "kunde inte läsa loggfilen \"%s\""
-#: builtin/commit.c:622
+#: builtin/commit.c:645
msgid "commit has empty message"
msgstr "incheckningen har ett tomt meddelande"
-#: builtin/commit.c:638
+#: builtin/commit.c:661
msgid "could not read MERGE_MSG"
msgstr "kunde inte läsa MERGE_MSG"
-#: builtin/commit.c:642
+#: builtin/commit.c:665
msgid "could not read SQUASH_MSG"
msgstr "kunde inte läsa SQUASH_MSG"
-#: builtin/commit.c:646
+#: builtin/commit.c:669
#, c-format
msgid "could not read '%s'"
msgstr "kunde inte läsa \"%s\""
-#: builtin/commit.c:707
+#: builtin/commit.c:730
msgid "could not write commit template"
msgstr "kunde inte skriva incheckningsmall"
-#: builtin/commit.c:718
+#: builtin/commit.c:741
#, c-format
msgid ""
"\n"
@@ -3525,7 +4030,7 @@ msgstr ""
"\t%s\n"
"och försöker igen.\n"
-#: builtin/commit.c:723
+#: builtin/commit.c:746
#, c-format
msgid ""
"\n"
@@ -3540,7 +4045,7 @@ msgstr ""
"\t%s\n"
"och försöker igen.\n"
-#: builtin/commit.c:735
+#: builtin/commit.c:758
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
@@ -3550,7 +4055,7 @@ msgstr ""
"med \"%c\" kommer ignoreras, och ett tomt meddelande avbryter "
"incheckningen.\n"
-#: builtin/commit.c:740
+#: builtin/commit.c:763
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
@@ -3561,139 +4066,139 @@ msgstr ""
"med \"%c\" kommer behållas; du kan själv ta bort dem om du vill.\n"
"Ett tomt meddelande avbryter incheckningen.\n"
-#: builtin/commit.c:753
+#: builtin/commit.c:776
#, c-format
msgid "%sAuthor: %s"
msgstr "%sFörfattare: %s"
-#: builtin/commit.c:760
+#: builtin/commit.c:783
#, c-format
msgid "%sCommitter: %s"
msgstr "%sIncheckare: %s"
-#: builtin/commit.c:780
+#: builtin/commit.c:803
msgid "Cannot read index"
msgstr "Kan inte läsa indexet"
-#: builtin/commit.c:817
+#: builtin/commit.c:845
msgid "Error building trees"
msgstr "Fel vid byggande av träd"
-#: builtin/commit.c:832 builtin/tag.c:359
+#: builtin/commit.c:860 builtin/tag.c:359
#, 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:929
+#: builtin/commit.c:957
#, c-format
msgid "No existing author found with '%s'"
msgstr "Hittade ingen befintlig författare med \"%s\""
-#: builtin/commit.c:944 builtin/commit.c:1138
+#: builtin/commit.c:972 builtin/commit.c:1208
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr "Ogiltigt läge för ospårade filer: \"%s\""
-#: builtin/commit.c:974
+#: builtin/commit.c:1009
+msgid "--long and -z are incompatible"
+msgstr "--long och -z är inkompatibla"
+
+#: builtin/commit.c:1039
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:985
+#: builtin/commit.c:1050
msgid "You have nothing to amend."
msgstr "Du har inget att utöka."
-#: builtin/commit.c:988
+#: builtin/commit.c:1053
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:990
+#: builtin/commit.c:1055
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:993
+#: builtin/commit.c:1058
msgid "Options --squash and --fixup cannot be used together"
msgstr "Flaggorna --squash och --fixup kan inte användas samtidigt"
-#: builtin/commit.c:1003
+#: builtin/commit.c:1068
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:1005
+#: builtin/commit.c:1070
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:1013
+#: builtin/commit.c:1078
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:1030
+#: builtin/commit.c:1095
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:1032
+#: builtin/commit.c:1097
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:1034
+#: builtin/commit.c:1099
msgid "Clever... amending the last one with dirty index."
msgstr "Smart... utöka den senaste med smutsigt index."
-#: builtin/commit.c:1036
+#: builtin/commit.c:1101
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:1046 builtin/tag.c:575
+#: builtin/commit.c:1111 builtin/tag.c:575
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "Felaktigt städningsläge %s"
-#: builtin/commit.c:1051
+#: builtin/commit.c:1116
msgid "Paths with -a does not make sense."
msgstr "Kan inte ange sökvägar med -a."
-#: builtin/commit.c:1057 builtin/commit.c:1192
-msgid "--long and -z are incompatible"
-msgstr "--long och -z är inkompatibla"
-
-#: builtin/commit.c:1152 builtin/commit.c:1388
+#: builtin/commit.c:1222 builtin/commit.c:1455
msgid "show status concisely"
-msgstr "vis koncis status"
+msgstr "visa koncis status"
-#: builtin/commit.c:1154 builtin/commit.c:1390
+#: builtin/commit.c:1224 builtin/commit.c:1457
msgid "show branch information"
msgstr "visa information om gren"
-#: builtin/commit.c:1156 builtin/commit.c:1392 builtin/push.c:426
+#: builtin/commit.c:1226 builtin/commit.c:1459 builtin/push.c:452
msgid "machine-readable output"
msgstr "maskinläsbar utdata"
-#: builtin/commit.c:1159 builtin/commit.c:1394
+#: builtin/commit.c:1229 builtin/commit.c:1461
msgid "show status in long format (default)"
msgstr "visa status i långt format (standard)"
-#: builtin/commit.c:1162 builtin/commit.c:1397
+#: builtin/commit.c:1232 builtin/commit.c:1464
msgid "terminate entries with NUL"
msgstr "terminera poster med NUL"
-#: builtin/commit.c:1164 builtin/commit.c:1400 builtin/fast-export.c:647
-#: builtin/fast-export.c:650 builtin/tag.c:459
+#: builtin/commit.c:1234 builtin/commit.c:1467 builtin/fast-export.c:667
+#: builtin/fast-export.c:670 builtin/tag.c:459
msgid "mode"
msgstr "läge"
-#: builtin/commit.c:1165 builtin/commit.c:1400
+#: builtin/commit.c:1235 builtin/commit.c:1467
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:1168
+#: builtin/commit.c:1238
msgid "show ignored files"
msgstr "visa ignorerade filer"
-#: builtin/commit.c:1169 parse-options.h:151
+#: builtin/commit.c:1239 parse-options.h:154
msgid "when"
msgstr "när"
-#: builtin/commit.c:1170
+#: builtin/commit.c:1240
msgid ""
"ignore changes to submodules, optional when: all, dirty, untracked. "
"(Default: all)"
@@ -3701,217 +4206,217 @@ msgstr ""
"ignorera ändringar i undermoduler, valfritt när: all, dirty, untracked. "
"(Default: all)"
-#: builtin/commit.c:1172
+#: builtin/commit.c:1242
msgid "list untracked files in columns"
msgstr "visa ospårade filer i spalter"
-#: builtin/commit.c:1246
+#: builtin/commit.c:1313
msgid "couldn't look up newly created commit"
msgstr "kunde inte slå upp en precis skapad incheckning"
-#: builtin/commit.c:1248
+#: builtin/commit.c:1315
msgid "could not parse newly created commit"
msgstr "kunde inte tolka en precis skapad incheckning"
-#: builtin/commit.c:1289
+#: builtin/commit.c:1356
msgid "detached HEAD"
msgstr "frånkopplad HEAD"
-#: builtin/commit.c:1291
+#: builtin/commit.c:1358
msgid " (root-commit)"
msgstr " (rotincheckning)"
-#: builtin/commit.c:1358
+#: builtin/commit.c:1425
msgid "suppress summary after successful commit"
msgstr "undertryck sammanfattning efter framgångsrik incheckning"
-#: builtin/commit.c:1359
+#: builtin/commit.c:1426
msgid "show diff in commit message template"
msgstr "visa diff i mallen för incheckningsmeddelandet"
-#: builtin/commit.c:1361
+#: builtin/commit.c:1428
msgid "Commit message options"
msgstr "Alternativ för incheckningsmeddelande"
-#: builtin/commit.c:1362 builtin/tag.c:457
+#: builtin/commit.c:1429 builtin/tag.c:457
msgid "read message from file"
msgstr "läs meddelande från fil"
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "author"
msgstr "författare"
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "override author for commit"
msgstr "överstyr författare för incheckningen"
-#: builtin/commit.c:1364 builtin/gc.c:178
+#: builtin/commit.c:1431 builtin/gc.c:178
msgid "date"
msgstr "datum"
-#: builtin/commit.c:1364
+#: builtin/commit.c:1431
msgid "override date for commit"
msgstr "överstyr datum för inchecknignen"
-#: builtin/commit.c:1365 builtin/merge.c:206 builtin/notes.c:533
-#: builtin/notes.c:690 builtin/tag.c:455
+#: builtin/commit.c:1432 builtin/merge.c:223 builtin/notes.c:405
+#: builtin/notes.c:562 builtin/tag.c:455
msgid "message"
msgstr "meddelande"
-#: builtin/commit.c:1365
+#: builtin/commit.c:1432
msgid "commit message"
msgstr "incheckningsmeddelande"
-#: builtin/commit.c:1366
+#: builtin/commit.c:1433
msgid "reuse and edit message from specified commit"
msgstr "återanvänd och redigera meddelande från angiven incheckning"
-#: builtin/commit.c:1367
+#: builtin/commit.c:1434
msgid "reuse message from specified commit"
msgstr "återanvänd meddelande från angiven incheckning"
-#: builtin/commit.c:1368
+#: builtin/commit.c:1435
msgid "use autosquash formatted message to fixup specified commit"
msgstr ""
"använd autosquash-formaterat meddelande för att fixa angiven incheckning"
-#: builtin/commit.c:1369
+#: builtin/commit.c:1436
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:1370
+#: builtin/commit.c:1437
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:1371 builtin/log.c:1102 builtin/revert.c:109
+#: builtin/commit.c:1438 builtin/log.c:1160 builtin/revert.c:111
msgid "add Signed-off-by:"
msgstr "lägg till Signed-off-by:"
-#: builtin/commit.c:1372
+#: builtin/commit.c:1439
msgid "use specified template file"
msgstr "använd angiven mallfil"
-#: builtin/commit.c:1373
+#: builtin/commit.c:1440
msgid "force edit of commit"
msgstr "tvinga redigering av incheckning"
-#: builtin/commit.c:1374
+#: builtin/commit.c:1441
msgid "default"
msgstr "standard"
-#: builtin/commit.c:1374 builtin/tag.c:460
+#: builtin/commit.c:1441 builtin/tag.c:460
msgid "how to strip spaces and #comments from message"
msgstr "hur blanksteg och #kommentarer skall tas bort från meddelande"
-#: builtin/commit.c:1375
+#: builtin/commit.c:1442
msgid "include status in commit message template"
msgstr "inkludera status i mallen för incheckningsmeddelandet"
-#: builtin/commit.c:1376 builtin/merge.c:213 builtin/tag.c:461
+#: builtin/commit.c:1443 builtin/merge.c:230 builtin/tag.c:461
msgid "key id"
msgstr "nyckel-id"
-#: builtin/commit.c:1377 builtin/merge.c:214
+#: builtin/commit.c:1444 builtin/merge.c:231
msgid "GPG sign commit"
msgstr "GPG-signera incheckning"
#. end commit message options
-#: builtin/commit.c:1380
+#: builtin/commit.c:1447
msgid "Commit contents options"
msgstr "Alternativ för incheckningens innehåll"
-#: builtin/commit.c:1381
+#: builtin/commit.c:1448
msgid "commit all changed files"
msgstr "checka in alla ändrade filer"
-#: builtin/commit.c:1382
+#: builtin/commit.c:1449
msgid "add specified files to index for commit"
msgstr "lägg till angivna filer till indexet för incheckning"
-#: builtin/commit.c:1383
+#: builtin/commit.c:1450
msgid "interactively add files"
msgstr "lägg till filer interaktivt"
-#: builtin/commit.c:1384
+#: builtin/commit.c:1451
msgid "interactively add changes"
msgstr "lägg till ändringar interaktivt"
-#: builtin/commit.c:1385
+#: builtin/commit.c:1452
msgid "commit only specified files"
msgstr "checka endast in angivna filer"
-#: builtin/commit.c:1386
+#: builtin/commit.c:1453
msgid "bypass pre-commit hook"
msgstr "förbigå pre-commit-krok"
-#: builtin/commit.c:1387
+#: builtin/commit.c:1454
msgid "show what would be committed"
msgstr "visa vad som skulle checkas in"
-#: builtin/commit.c:1398
+#: builtin/commit.c:1465
msgid "amend previous commit"
msgstr "lägg till föregående incheckning"
-#: builtin/commit.c:1399
+#: builtin/commit.c:1466
msgid "bypass post-rewrite hook"
msgstr "förbigå post-rewrite-krok"
-#: builtin/commit.c:1404
+#: builtin/commit.c:1471
msgid "ok to record an empty change"
msgstr "ok att registrera en tom ändring"
-#: builtin/commit.c:1407
+#: builtin/commit.c:1474
msgid "ok to record a change with an empty message"
msgstr "ok att registrera en ändring med tomt meddelande"
-#: builtin/commit.c:1439
+#: builtin/commit.c:1507
msgid "could not parse HEAD commit"
msgstr "kunde inte tolka HEAD:s incheckning"
-#: builtin/commit.c:1477 builtin/merge.c:508
+#: builtin/commit.c:1545 builtin/merge.c:525
#, c-format
msgid "could not open '%s' for reading"
msgstr "kunde inte öppna \"%s\" för läsning"
-#: builtin/commit.c:1484
+#: builtin/commit.c:1552
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "Trasig MERGE_HEAD-fil (%s)"
-#: builtin/commit.c:1491
+#: builtin/commit.c:1559
msgid "could not read MERGE_MODE"
msgstr "kunde inte läsa MERGE_MODE"
-#: builtin/commit.c:1510
+#: builtin/commit.c:1578
#, c-format
msgid "could not read commit message: %s"
msgstr "kunde inte läsa incheckningsmeddelande: %s"
-#: builtin/commit.c:1524
+#: builtin/commit.c:1592
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr "Avbryter incheckning; meddelandet inte redigerat.\n"
-#: builtin/commit.c:1529
+#: builtin/commit.c:1597
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr "Avbryter på grund av tomt incheckningsmeddelande.\n"
-#: builtin/commit.c:1544 builtin/merge.c:832 builtin/merge.c:857
+#: builtin/commit.c:1612 builtin/merge.c:861 builtin/merge.c:886
msgid "failed to write commit object"
msgstr "kunde inte skriva incheckningsobjekt"
-#: builtin/commit.c:1565
+#: builtin/commit.c:1633
msgid "cannot lock HEAD ref"
msgstr "kunde inte låsa HEAD-referens"
-#: builtin/commit.c:1569
+#: builtin/commit.c:1637
msgid "cannot update HEAD ref"
msgstr "kunde inte uppdatera HEAD-referens"
-#: builtin/commit.c:1580
+#: builtin/commit.c:1648
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
@@ -3926,171 +4431,183 @@ msgstr ""
msgid "git config [options]"
msgstr "git config [flaggor]"
-#: builtin/config.c:51
+#: builtin/config.c:52
msgid "Config file location"
msgstr "Konfigurationsfilens plats"
-#: builtin/config.c:52
+#: builtin/config.c:53
msgid "use global config file"
msgstr "använd global konfigurationsfil"
-#: builtin/config.c:53
+#: builtin/config.c:54
msgid "use system config file"
msgstr "använd systemets konfigurationsfil"
-#: builtin/config.c:54
+#: builtin/config.c:55
msgid "use repository config file"
msgstr "använd arkivets konfigurationsfil"
-#: builtin/config.c:55
+#: builtin/config.c:56
msgid "use given config file"
msgstr "använd angiven konfigurationsil"
-#: builtin/config.c:56
+#: builtin/config.c:57
+msgid "blob-id"
+msgstr "blob-id"
+
+#: builtin/config.c:57
+msgid "read config from given blob object"
+msgstr "läs konfiguration från givet blob-objekt"
+
+#: builtin/config.c:58
msgid "Action"
msgstr "Åtgärd"
-#: builtin/config.c:57
+#: builtin/config.c:59
msgid "get value: name [value-regex]"
msgstr "hämta värde: namn [värde-reguttr]"
-#: builtin/config.c:58
+#: builtin/config.c:60
msgid "get all values: key [value-regex]"
msgstr "hämta alla värden: nyckel [värde-reguttr]"
-#: builtin/config.c:59
+#: builtin/config.c:61
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:60
+#: builtin/config.c:62
msgid "replace all matching variables: name value [value_regex]"
msgstr "ersätt alla motsvarande variabler: namn värde [värde-reguttr]"
-#: builtin/config.c:61
+#: builtin/config.c:63
msgid "add a new variable: name value"
msgstr "lägg till en ny variabel: namn värde"
-#: builtin/config.c:62
+#: builtin/config.c:64
msgid "remove a variable: name [value-regex]"
msgstr "ta bort en variabel: namn [värde-reguttr]"
-#: builtin/config.c:63
+#: builtin/config.c:65
msgid "remove all matches: name [value-regex]"
msgstr "ta bort alla träffar: namn [värde-reguttr]"
-#: builtin/config.c:64
+#: builtin/config.c:66
msgid "rename section: old-name new-name"
msgstr "byt namn på sektion: gammalt-namn nytt-namn"
-#: builtin/config.c:65
+#: builtin/config.c:67
msgid "remove a section: name"
msgstr "ta bort en sektion: namn"
-#: builtin/config.c:66
+#: builtin/config.c:68
msgid "list all"
msgstr "visa alla"
-#: builtin/config.c:67
+#: builtin/config.c:69
msgid "open an editor"
msgstr "öppna textredigeringsprogram"
-#: builtin/config.c:68 builtin/config.c:69
+#: builtin/config.c:70 builtin/config.c:71
msgid "slot"
msgstr "plats"
-#: builtin/config.c:68
+#: builtin/config.c:70
msgid "find the color configured: [default]"
msgstr "hitta den inställda färgen: [default]"
-#: builtin/config.c:69
+#: builtin/config.c:71
msgid "find the color setting: [stdout-is-tty]"
msgstr "hitta färginställningen: [stdout-is-tty]"
-#: builtin/config.c:70
+#: builtin/config.c:72
msgid "Type"
msgstr "Typ"
-#: builtin/config.c:71
+#: builtin/config.c:73
msgid "value is \"true\" or \"false\""
msgstr "värdet är \"true\" eller \"false\""
-#: builtin/config.c:72
+#: builtin/config.c:74
msgid "value is decimal number"
msgstr "värdet är ett decimalt tal"
-#: builtin/config.c:73
+#: builtin/config.c:75
msgid "value is --bool or --int"
msgstr "värdet är --bool eller --int"
-#: builtin/config.c:74
+#: builtin/config.c:76
msgid "value is a path (file or directory name)"
msgstr "värdet är en sökväg (fil- eller katalognamn)"
-#: builtin/config.c:75
+#: builtin/config.c:77
msgid "Other"
msgstr "Andra"
-#: builtin/config.c:76
+#: builtin/config.c:78
msgid "terminate values with NUL byte"
msgstr "terminera värden med NUL-byte"
-#: builtin/config.c:77
+#: builtin/config.c:79
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/count-objects.c:82
+msgid "git count-objects [-v] [-H | --human-readable]"
+msgstr "git count-objects [-v] [-H | --human-readable]"
+
+#: builtin/count-objects.c:97
+msgid "print sizes in human readable format"
+msgstr "skriv storlekar i människoläsbart format"
-#: builtin/describe.c:15
+#: builtin/describe.c:16
msgid "git describe [options] <committish>*"
msgstr "git describe [flaggor] <incheckning-igt>*"
-#: builtin/describe.c:16
+#: builtin/describe.c:17
msgid "git describe [options] --dirty"
msgstr "git describe [flaggor] --dirty"
-#: builtin/describe.c:234
+#: builtin/describe.c:237
#, c-format
msgid "annotated tag %s not available"
msgstr "den annoterade taggen %s inte tillgänglig"
-#: builtin/describe.c:238
+#: builtin/describe.c:241
#, c-format
msgid "annotated tag %s has no embedded name"
msgstr "den annoterade taggen %s har inget inbäddat namn"
-#: builtin/describe.c:240
+#: builtin/describe.c:243
#, c-format
msgid "tag '%s' is really '%s' here"
msgstr "taggen \"%s\" är i verkligheten \"%s\" här"
-#: builtin/describe.c:267
+#: builtin/describe.c:270
#, c-format
msgid "Not a valid object name %s"
msgstr "Objektnamnet är inte giltigt: %s"
-#: builtin/describe.c:270
+#: builtin/describe.c:273
#, c-format
msgid "%s is not a valid '%s' object"
msgstr "%s är inte ett giltigt \"%s\"-objekt"
-#: builtin/describe.c:287
+#: builtin/describe.c:290
#, c-format
msgid "no tag exactly matches '%s'"
msgstr "ingen tagg motsvarar \"%s\" exakt"
-#: builtin/describe.c:289
+#: builtin/describe.c:292
#, c-format
msgid "searching to describe %s\n"
msgstr "söker för att beskriva %s\n"
-#: builtin/describe.c:329
+#: builtin/describe.c:332
#, c-format
msgid "finished search at %s\n"
msgstr "avslutade sökning på %s\n"
-#: builtin/describe.c:353
+#: builtin/describe.c:359
#, c-format
msgid ""
"No annotated tags can describe '%s'.\n"
@@ -4099,7 +4616,7 @@ msgstr ""
"Inga annoterade taggar kan beskriva \"%s\".\n"
"Det finns dock oannoterade taggar: testa --tags."
-#: builtin/describe.c:357
+#: builtin/describe.c:363
#, c-format
msgid ""
"No tags can describe '%s'.\n"
@@ -4108,12 +4625,12 @@ msgstr ""
"Inga taggar kan beskriva \"%s\".\n"
"Testa --always, eller skapa några taggar."
-#: builtin/describe.c:378
+#: builtin/describe.c:384
#, c-format
msgid "traversed %lu commits\n"
msgstr "traverserade %lu incheckningar\n"
-#: builtin/describe.c:381
+#: builtin/describe.c:387
#, c-format
msgid ""
"more than %i tags found; listed %i most recent\n"
@@ -4122,59 +4639,63 @@ msgstr ""
"mer än %i taggar hittades; listar de %i senaste\n"
"gav upp sökningen vid %s\n"
-#: builtin/describe.c:403
+#: builtin/describe.c:409
msgid "find the tag that comes after the commit"
msgstr "hitta taggen som kommer efter incheckningen"
-#: builtin/describe.c:404
+#: builtin/describe.c:410
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:411
+msgid "use any ref"
+msgstr "använd alla referenser"
-#: builtin/describe.c:406
-msgid "use any tag in .git/refs/tags"
-msgstr "använd alla taggar i .git/refs/tags"
+#: builtin/describe.c:412
+msgid "use any tag, even unannotated"
+msgstr "använd alla taggar, även oannoterade"
-#: builtin/describe.c:407
+#: builtin/describe.c:413
msgid "always use long format"
msgstr "använd alltid långt format"
-#: builtin/describe.c:410
+#: builtin/describe.c:414
+msgid "only follow first parent"
+msgstr "följ endast första föräldern"
+
+#: builtin/describe.c:417
msgid "only output exact matches"
msgstr "skriv endast ut exakta träffar"
-#: builtin/describe.c:412
+#: builtin/describe.c:419
msgid "consider <n> most recent tags (default: 10)"
msgstr "överväg de <n> nyaste taggarna (standard: 10)"
-#: builtin/describe.c:414
+#: builtin/describe.c:421
msgid "only consider tags matching <pattern>"
msgstr "överväg endast taggar som motsvarar <mönster>"
-#: builtin/describe.c:416 builtin/name-rev.c:238
+#: builtin/describe.c:423 builtin/name-rev.c:322
msgid "show abbreviated commit object as fallback"
msgstr "visa förkortade incheckningsobjekt som standard"
-#: builtin/describe.c:417
+#: builtin/describe.c:424
msgid "mark"
msgstr "märke"
-#: builtin/describe.c:418
+#: builtin/describe.c:425
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
+#: builtin/describe.c:443
msgid "--long is incompatible with --abbrev=0"
msgstr "--long är inkompatibel med --abbrev=0"
-#: builtin/describe.c:462
+#: builtin/describe.c:469
msgid "No names found, cannot describe anything."
msgstr "Inga namn hittades, kan inte beskriva något."
-#: builtin/describe.c:482
+#: builtin/describe.c:489
msgid "--dirty is incompatible with committishes"
msgstr "--dirty är inkompatibelt med \"committish\"-värden"
@@ -4183,31 +4704,26 @@ msgstr "--dirty är inkompatibelt med \"committish\"-värden"
msgid "'%s': not a regular file or symlink"
msgstr "\"%s\": inte en normal fil eller symbolisk länk"
-#: builtin/diff.c:228
+#: builtin/diff.c:230
#, c-format
msgid "invalid option: %s"
msgstr "ogiltig flagga: %s"
-#: builtin/diff.c:305
+#: builtin/diff.c:307
msgid "Not a git repository"
msgstr "Inte ett git-arkiv"
-#: builtin/diff.c:348
+#: builtin/diff.c:350
#, c-format
msgid "invalid object '%s' given."
msgstr "objektet \"%s\" som angavs är felaktigt."
-#: builtin/diff.c:353
-#, c-format
-msgid "more than %d trees given: '%s'"
-msgstr "mer än %d träd angavs: \"%s\""
-
-#: builtin/diff.c:363
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
msgstr "mer än två blobbar angavs: \"%s\""
-#: builtin/diff.c:371
+#: builtin/diff.c:366
#, c-format
msgid "unhandled object '%s' given."
msgstr "ej hanterat objekt \"%s\" angavs."
@@ -4216,39 +4732,39 @@ msgstr "ej hanterat objekt \"%s\" angavs."
msgid "git fast-export [rev-list-opts]"
msgstr "git fast-export [rev-list-flaggor]"
-#: builtin/fast-export.c:646
+#: builtin/fast-export.c:666
msgid "show progress after <n> objects"
msgstr "visa förlopp efter <n> objekt"
-#: builtin/fast-export.c:648
+#: builtin/fast-export.c:668
msgid "select handling of signed tags"
msgstr "välj hantering av signerade taggar"
-#: builtin/fast-export.c:651
+#: builtin/fast-export.c:671
msgid "select handling of tags that tag filtered objects"
msgstr "välj hantering av taggar som har taggfiltrerade objekt"
-#: builtin/fast-export.c:654
+#: builtin/fast-export.c:674
msgid "Dump marks to this file"
msgstr "Dump märken till filen"
-#: builtin/fast-export.c:656
+#: builtin/fast-export.c:676
msgid "Import marks from this file"
msgstr "Importera märken från filen"
-#: builtin/fast-export.c:658
+#: builtin/fast-export.c:678
msgid "Fake a tagger when tags lack one"
msgstr "Fejka taggare när taggen saknar en"
-#: builtin/fast-export.c:660
+#: builtin/fast-export.c:680
msgid "Output full tree for each commit"
msgstr "Skriv ut hela trädet för varje incheckning"
-#: builtin/fast-export.c:662
+#: builtin/fast-export.c:682
msgid "Use the done feature to terminate the stream"
msgstr "Använd done-funktionen för att avsluta strömmen"
-#: builtin/fast-export.c:663
+#: builtin/fast-export.c:683
msgid "Skip output of blob data"
msgstr "Hoppa över skrivning av blob-data"
@@ -4324,7 +4840,7 @@ msgstr "fördjupa historik för grund klon"
msgid "convert to a complete repository"
msgstr "konvertera till komplett arkiv"
-#: builtin/fetch.c:88 builtin/log.c:1119
+#: builtin/fetch.c:88 builtin/log.c:1177
msgid "dir"
msgstr "kat"
@@ -4336,76 +4852,76 @@ msgstr "lägg till i början av undermodulens sökvägsutdata"
msgid "default mode for recursion"
msgstr "standardläge för rekursion"
-#: builtin/fetch.c:204
+#: builtin/fetch.c:220
msgid "Couldn't find remote ref HEAD"
msgstr "Kunde inte hitta fjärr-referensen HEAD"
-#: builtin/fetch.c:257
+#: builtin/fetch.c:273
#, c-format
msgid "object %s not found"
msgstr "objektet %s hittades inte"
-#: builtin/fetch.c:262
+#: builtin/fetch.c:278
msgid "[up to date]"
msgstr "[àjour]"
-#: builtin/fetch.c:276
+#: builtin/fetch.c:292
#, 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:277 builtin/fetch.c:363
+#: builtin/fetch.c:293 builtin/fetch.c:379
msgid "[rejected]"
msgstr "[refuserad]"
-#: builtin/fetch.c:288
+#: builtin/fetch.c:304
msgid "[tag update]"
msgstr "[uppdaterad tagg]"
-#: builtin/fetch.c:290 builtin/fetch.c:325 builtin/fetch.c:343
+#: builtin/fetch.c:306 builtin/fetch.c:341 builtin/fetch.c:359
msgid " (unable to update local ref)"
msgstr " (kunde inte uppdatera lokal ref)"
-#: builtin/fetch.c:308
+#: builtin/fetch.c:324
msgid "[new tag]"
msgstr "[ny tagg]"
-#: builtin/fetch.c:311
+#: builtin/fetch.c:327
msgid "[new branch]"
msgstr "[ny gren]"
-#: builtin/fetch.c:314
+#: builtin/fetch.c:330
msgid "[new ref]"
msgstr "[ny ref]"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "unable to update local ref"
msgstr "kunde inte uppdatera lokal ref"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "forced update"
msgstr "tvingad uppdatering"
-#: builtin/fetch.c:365
+#: builtin/fetch.c:381
msgid "(non-fast-forward)"
msgstr "(ej snabbspolad)"
-#: builtin/fetch.c:396 builtin/fetch.c:688
+#: builtin/fetch.c:412 builtin/fetch.c:718
#, c-format
msgid "cannot open %s: %s\n"
msgstr "kan inte öppna %s: %s\n"
-#: builtin/fetch.c:405
+#: builtin/fetch.c:421
#, 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:491
+#: builtin/fetch.c:520
#, c-format
msgid "From %.*s\n"
msgstr "Från %.*s\n"
-#: builtin/fetch.c:502
+#: builtin/fetch.c:531
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
@@ -4414,55 +4930,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:552
+#: builtin/fetch.c:581
#, c-format
msgid " (%s will become dangling)"
msgstr " (%s kommer bli dinglande)"
-#: builtin/fetch.c:553
+#: builtin/fetch.c:582
#, c-format
msgid " (%s has become dangling)"
msgstr " (%s har blivit dinglande)"
-#: builtin/fetch.c:560
+#: builtin/fetch.c:589
msgid "[deleted]"
msgstr "[borttagen]"
-#: builtin/fetch.c:561 builtin/remote.c:1055
+#: builtin/fetch.c:590 builtin/remote.c:1055
msgid "(none)"
msgstr "(ingen)"
-#: builtin/fetch.c:678
+#: builtin/fetch.c:708
#, 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:712
+#: builtin/fetch.c:742
#, c-format
msgid "Don't know how to fetch from %s"
msgstr "Vet inte hur man hämtar från %s"
-#: builtin/fetch.c:789
+#: builtin/fetch.c:823
#, 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:792
+#: builtin/fetch.c:826
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr "Flaggan \"%s\" ignoreras för %s\n"
-#: builtin/fetch.c:894
+#: builtin/fetch.c:928
#, c-format
msgid "Fetching %s\n"
msgstr "Hämtar %s\n"
-#: builtin/fetch.c:896 builtin/remote.c:100
+#: builtin/fetch.c:930 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
msgstr "Kunde inte hämta %s"
-#: builtin/fetch.c:915
+#: builtin/fetch.c:949
msgid ""
"No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."
@@ -4470,32 +4986,32 @@ 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:935
+#: builtin/fetch.c:969
msgid "You need to specify a tag name."
msgstr "Du måste ange namnet på en tagg."
-#: builtin/fetch.c:981
+#: builtin/fetch.c:1015
msgid "--depth and --unshallow cannot be used together"
msgstr "--depth och --unshallow kan inte användas samtidigt"
-#: builtin/fetch.c:983
+#: builtin/fetch.c:1017
msgid "--unshallow on a complete repository does not make sense"
msgstr "--unshallow kan inte användas på ett komplett arkiv"
-#: builtin/fetch.c:1002
+#: builtin/fetch.c:1036
msgid "fetch --all does not take a repository argument"
msgstr "fetch --all tar inte namnet på ett arkiv som argument"
-#: builtin/fetch.c:1004
+#: builtin/fetch.c:1038
msgid "fetch --all does not make sense with refspecs"
msgstr "fetch --all kan inte anges med referensspecifikationer"
-#: builtin/fetch.c:1015
+#: builtin/fetch.c:1049
#, c-format
msgid "No such remote or remote group: %s"
msgstr "Fjärren eller fjärrgruppen finns inte: %s"
-#: builtin/fetch.c:1023
+#: builtin/fetch.c:1057
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr "Kan inte hämta från grupp och ange referensspecifikationer"
@@ -4504,29 +5020,29 @@ 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:659 builtin/fmt-merge-msg.c:662 builtin/grep.c:701
-#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175
-#: builtin/tag.c:446 parse-options.h:133 parse-options.h:239
+#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:700
+#: builtin/merge.c:203 builtin/show-branch.c:655 builtin/show-ref.c:179
+#: builtin/tag.c:446 parse-options.h:133 parse-options.h:243
msgid "n"
msgstr "n"
-#: builtin/fmt-merge-msg.c:660
+#: builtin/fmt-merge-msg.c:664
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:663
+#: builtin/fmt-merge-msg.c:667
msgid "alias for --log (deprecated)"
msgstr "alias för --log (avråds)"
-#: builtin/fmt-merge-msg.c:666
+#: builtin/fmt-merge-msg.c:670
msgid "text"
msgstr "text"
-#: builtin/fmt-merge-msg.c:667
+#: builtin/fmt-merge-msg.c:671
msgid "use <text> as start of message"
msgstr "inled meddelande med <text>"
-#: builtin/fmt-merge-msg.c:668
+#: builtin/fmt-merge-msg.c:672
msgid "file to read from"
msgstr "fil att läsa från"
@@ -4665,225 +5181,220 @@ msgstr "git grep [flaggor] [-e] <mönster> [<rev>...] [[--] <sökväg>...]"
msgid "grep: failed to create thread: %s"
msgstr "grep: misslyckades skapa tråd. %s"
-#: builtin/grep.c:365
+#: builtin/grep.c:364
#, c-format
msgid "Failed to chdir: %s"
msgstr "Kunde inte byta katalog (chdir): %s"
-#: builtin/grep.c:443 builtin/grep.c:478
+#: builtin/grep.c:442 builtin/grep.c:477
#, c-format
msgid "unable to read tree (%s)"
msgstr "kunde inte läsa träd (%s)"
-#: builtin/grep.c:493
+#: builtin/grep.c:492
#, c-format
msgid "unable to grep from object of type %s"
msgstr "Kunde inte \"grep\" från objekt av typen %s"
-#: builtin/grep.c:551
+#: builtin/grep.c:550
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr "flaggan \"%c\" antar ett numeriskt värde"
-#: builtin/grep.c:568
+#: builtin/grep.c:567
#, c-format
msgid "cannot open '%s'"
msgstr "kan inte öppna \"%s\""
-#: builtin/grep.c:643
+#: builtin/grep.c:642
msgid "search in index instead of in the work tree"
msgstr "sök i indexet istället för i arbetskatalogen"
-#: builtin/grep.c:645
+#: builtin/grep.c:644
msgid "find in contents not managed by git"
msgstr "sök i innehål som inte hanteras av git"
-#: builtin/grep.c:647
+#: builtin/grep.c:646
msgid "search in both tracked and untracked files"
msgstr "sök i både spårade och ospårade filer"
-#: builtin/grep.c:649
+#: builtin/grep.c:648
msgid "search also in ignored files"
msgstr "sök även i ignorerade filer"
-#: builtin/grep.c:652
+#: builtin/grep.c:651
msgid "show non-matching lines"
-msgstr "vis rader som inte träffas"
+msgstr "visa rader som inte träffas"
-#: builtin/grep.c:654
+#: builtin/grep.c:653
msgid "case insensitive matching"
msgstr "skiftlägesokänslig sökning"
-#: builtin/grep.c:656
+#: builtin/grep.c:655
msgid "match patterns only at word boundaries"
msgstr "matcha endast mönster vid ordgränser"
-#: builtin/grep.c:658
+#: builtin/grep.c:657
msgid "process binary files as text"
msgstr "hantera binärfiler som text"
-#: builtin/grep.c:660
+#: builtin/grep.c:659
msgid "don't match patterns in binary files"
msgstr "träffa inte mönster i binärfiler"
-#: builtin/grep.c:663
+#: builtin/grep.c:662
msgid "descend at most <depth> levels"
msgstr "gå som mest ned <djup> nivåer"
-#: builtin/grep.c:667
+#: builtin/grep.c:666
msgid "use extended POSIX regular expressions"
msgstr "använd utökade POSIX-reguljära uttryck"
-#: builtin/grep.c:670
+#: builtin/grep.c:669
msgid "use basic POSIX regular expressions (default)"
msgstr "använd grundläggande POSIX-reguljära uttryck (standard)"
-#: builtin/grep.c:673
+#: builtin/grep.c:672
msgid "interpret patterns as fixed strings"
msgstr "tolka mönster som fixerade strängar"
-#: builtin/grep.c:676
+#: builtin/grep.c:675
msgid "use Perl-compatible regular expressions"
msgstr "använd Perlkompatibla reguljära uttryck"
-#: builtin/grep.c:679
+#: builtin/grep.c:678
msgid "show line numbers"
msgstr "visa radnummer"
-#: builtin/grep.c:680
+#: builtin/grep.c:679
msgid "don't show filenames"
msgstr "visa inte filnamn"
-#: builtin/grep.c:681
+#: builtin/grep.c:680
msgid "show filenames"
msgstr "visa filnamn"
-#: builtin/grep.c:683
+#: builtin/grep.c:682
msgid "show filenames relative to top directory"
msgstr "visa filnamn relativa till toppkatalogen"
-#: builtin/grep.c:685
+#: builtin/grep.c:684
msgid "show only filenames instead of matching lines"
msgstr "visa endast filnamn istället för träffade rader"
-#: builtin/grep.c:687
+#: builtin/grep.c:686
msgid "synonym for --files-with-matches"
msgstr "synonym för --files-with-matches"
-#: builtin/grep.c:690
+#: builtin/grep.c:689
msgid "show only the names of files without match"
msgstr "visa endast namn på filer utan träffar"
-#: builtin/grep.c:692
+#: builtin/grep.c:691
msgid "print NUL after filenames"
msgstr "skriv NUL efter filnamn"
-#: builtin/grep.c:694
+#: builtin/grep.c:693
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:695
+#: builtin/grep.c:694
msgid "highlight matches"
msgstr "ljusmarkera träffar"
-#: builtin/grep.c:697
+#: builtin/grep.c:696
msgid "print empty line between matches from different files"
msgstr "skriv tomma rader mellan träffar från olika filer"
-#: builtin/grep.c:699
+#: builtin/grep.c:698
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:702
+#: builtin/grep.c:701
msgid "show <n> context lines before and after matches"
msgstr "visa <n> rader sammanhang före och efter träffar"
-#: builtin/grep.c:705
+#: builtin/grep.c:704
msgid "show <n> context lines before matches"
msgstr "visa <n> rader sammanhang före träffar"
-#: builtin/grep.c:707
+#: builtin/grep.c:706
msgid "show <n> context lines after matches"
msgstr "visa <n> rader sammanhang efter träffar"
-#: builtin/grep.c:708
+#: builtin/grep.c:707
msgid "shortcut for -C NUM"
msgstr "genväg för -C NUM"
-#: builtin/grep.c:711
+#: builtin/grep.c:710
msgid "show a line with the function name before matches"
msgstr "visa en rad med funktionsnamnet före träffen"
-#: builtin/grep.c:713
+#: builtin/grep.c:712
msgid "show the surrounding function"
msgstr "visa den omkringliggande funktionen"
-#: builtin/grep.c:716
+#: builtin/grep.c:715
msgid "read patterns from file"
msgstr "läs mönster från fil"
-#: builtin/grep.c:718
+#: builtin/grep.c:717
msgid "match <pattern>"
msgstr "träffa <mönster>"
-#: builtin/grep.c:720
+#: builtin/grep.c:719
msgid "combine patterns specified with -e"
msgstr "kombinera mönster som anges med -e"
-#: builtin/grep.c:732
+#: builtin/grep.c:731
msgid "indicate hit with exit status without output"
msgstr "ange träff med slutstatuskod utan utdata"
-#: builtin/grep.c:734
+#: builtin/grep.c:733
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:736
+#: builtin/grep.c:735
msgid "show parse tree for grep expression"
msgstr "visa analysträd för grep-uttryck"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "pager"
msgstr "bläddrare"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "show matching files in the pager"
msgstr "visa träffade filer i filbläddraren"
-#: builtin/grep.c:743
+#: builtin/grep.c:742
msgid "allow calling of grep(1) (ignored by this build)"
msgstr "tillåt anropa grep(1) (ignoreras av detta bygge)"
-#: builtin/grep.c:744 builtin/show-ref.c:184
+#: builtin/grep.c:743 builtin/show-ref.c:188
msgid "show usage"
msgstr "visa användning"
-#: builtin/grep.c:811
+#: builtin/grep.c:810
msgid "no pattern given."
msgstr "inget mönster angavs."
-#: builtin/grep.c:825
-#, c-format
-msgid "bad object %s"
-msgstr "felaktigt objekt %s"
-
-#: builtin/grep.c:868
+#: builtin/grep.c:865
msgid "--open-files-in-pager only works on the worktree"
msgstr "--open-files-in-pager fungerar endast i arbetskatalogen"
-#: builtin/grep.c:891
+#: builtin/grep.c:888
msgid "--cached or --untracked cannot be used with --no-index."
msgstr "--cached och --untracked kan inte användas med --no-index."
-#: builtin/grep.c:896
+#: builtin/grep.c:893
msgid "--no-index or --untracked cannot be used with revs."
msgstr "--no-index och --untracked kan inte användas med revisioner."
-#: builtin/grep.c:899
+#: builtin/grep.c:896
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:907
+#: builtin/grep.c:904
msgid "both --cached and trees are given."
msgstr "både --cached och träd angavs."
@@ -4923,10 +5434,14 @@ msgstr "spara filen som den är utan filer"
msgid "process file as it were from this path"
msgstr "hantera filen som om den kom från sökvägen"
-#: builtin/help.c:42
+#: builtin/help.c:41
msgid "print all available commands"
msgstr "visa alla tillgängliga kommandon"
+#: builtin/help.c:42
+msgid "print list of useful guides"
+msgstr "lista användbara vägledningar"
+
#: builtin/help.c:43
msgid "show man page"
msgstr "visa manualsida"
@@ -4940,8 +5455,8 @@ msgid "show info page"
msgstr "visa info-sida"
#: builtin/help.c:52
-msgid "git help [--all] [--man|--web|--info] [command]"
-msgstr "git help [--all] [--man|--web|--info] [kommando]"
+msgid "git help [--all] [--guides] [--man|--web|--info] [command]"
+msgstr "git help [--all] [--guides] [--man|--web|--info] [kommando]"
#: builtin/help.c:64
#, c-format
@@ -4997,290 +5512,322 @@ msgstr "ingen man-visare hanterade förfrågan"
msgid "no info viewer handled the request"
msgstr "ingen info-visare hanterade förfrågan"
-#: builtin/help.c:429 builtin/help.c:436
+#: builtin/help.c:420
+msgid "Defining attributes per path"
+msgstr "Definierar attribut per sökväg"
+
+#: builtin/help.c:421
+msgid "A Git glossary"
+msgstr "En Git-ordlista"
+
+#: builtin/help.c:422
+msgid "Specifies intentionally untracked files to ignore"
+msgstr "Ange avsiktligen ospårade filer att ignorera"
+
+#: builtin/help.c:423
+msgid "Defining submodule properties"
+msgstr "Ange egenskaper för undermoduler"
+
+#: builtin/help.c:424
+msgid "Specifying revisions and ranges for Git"
+msgstr "Ange versioner och intervall i Git"
+
+#: builtin/help.c:425
+msgid "A tutorial introduction to Git (for version 1.5.1 or newer)"
+msgstr "Introduktion till Git (för version 1.5.1 och senare)"
+
+#: builtin/help.c:426
+msgid "An overview of recommended workflows with Git"
+msgstr "Översikt över rekommenderade arbetsflöden med Git"
+
+#: builtin/help.c:438
+msgid "The common Git guides are:\n"
+msgstr "De vanliga Git-vägledningarna är:\n"
+
+#: builtin/help.c:460 builtin/help.c:476
#, c-format
msgid "usage: %s%s"
msgstr "användning: %s%s"
-#: builtin/help.c:452
+#: builtin/help.c:492
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr "\"git %s\" är ett alias för \"%s\""
-#: builtin/index-pack.c:170
+#: builtin/index-pack.c:184
#, c-format
msgid "object type mismatch at %s"
msgstr "objekttyp stämmer inte överens vid %s"
-#: builtin/index-pack.c:190
+#: builtin/index-pack.c:204
msgid "object of unexpected type"
msgstr "objekt av oväntad typ"
-#: builtin/index-pack.c:227
+#: builtin/index-pack.c:244
#, 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:237
+#: builtin/index-pack.c:254
msgid "early EOF"
msgstr "tidigt filslut"
-#: builtin/index-pack.c:238
+#: builtin/index-pack.c:255
msgid "read error on input"
msgstr "indataläsfel"
-#: builtin/index-pack.c:250
+#: builtin/index-pack.c:267
msgid "used more bytes than were available"
msgstr "använde fler byte än tillgängligt"
-#: builtin/index-pack.c:257
+#: builtin/index-pack.c:274
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:273
+#: builtin/index-pack.c:290
#, c-format
msgid "unable to create '%s'"
msgstr "kunde inte skapa \"%s\""
-#: builtin/index-pack.c:278
+#: builtin/index-pack.c:295
#, c-format
msgid "cannot open packfile '%s'"
msgstr "kan inte öppna paketfilen \"%s\""
-#: builtin/index-pack.c:292
+#: builtin/index-pack.c:309
msgid "pack signature mismatch"
msgstr "paketsignatur stämmer inte överens"
-#: builtin/index-pack.c:294
+#: builtin/index-pack.c:311
#, c-format
msgid "pack version %<PRIu32> unsupported"
msgstr "paketversion %<PRIu32> stöds ej"
-#: builtin/index-pack.c:312
+#: builtin/index-pack.c:329
#, c-format
msgid "pack has bad object at offset %lu: %s"
msgstr "paketet har felaktigt objekt vid index %lu: %s"
-#: builtin/index-pack.c:434
+#: builtin/index-pack.c:451
#, c-format
msgid "inflate returned %d"
msgstr "inflate returnerade %d"
-#: builtin/index-pack.c:483
+#: builtin/index-pack.c:500
msgid "offset value overflow for delta base object"
msgstr "indexvärdespill för deltabasobjekt"
-#: builtin/index-pack.c:491
+#: builtin/index-pack.c:508
msgid "delta base offset is out of bound"
msgstr "deltabasindex utanför gränsen"
-#: builtin/index-pack.c:499
+#: builtin/index-pack.c:516
#, c-format
msgid "unknown object type %d"
msgstr "okänd objekttyp %d"
-#: builtin/index-pack.c:530
+#: builtin/index-pack.c:547
msgid "cannot pread pack file"
msgstr "kan inte utföra \"pread\" på paketfil"
-#: builtin/index-pack.c:532
+#: builtin/index-pack.c:549
#, 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:558
+#: builtin/index-pack.c:575
msgid "serious inflate inconsistency"
msgstr "allvarlig inflate-inkonsekvens"
-#: 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
+#: builtin/index-pack.c:666 builtin/index-pack.c:672 builtin/index-pack.c:695
+#: builtin/index-pack.c:729 builtin/index-pack.c:738
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "SHA1-KOLLISION UPPTÄCKT VID %s !"
-#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/index-pack.c:669 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
+#: builtin/index-pack.c:735
#, c-format
msgid "cannot read existing object %s"
msgstr "kan inte läsa befintligt objekt %s"
-#: builtin/index-pack.c:732
+#: builtin/index-pack.c:749
#, c-format
msgid "invalid blob object %s"
msgstr "ogiltigt blob-objekt %s"
-#: builtin/index-pack.c:747
+#: builtin/index-pack.c:763
#, c-format
msgid "invalid %s"
msgstr "ogiltigt %s"
-#: builtin/index-pack.c:749
+#: builtin/index-pack.c:766
msgid "Error in object"
msgstr "Fel i objekt"
-#: builtin/index-pack.c:751
+#: builtin/index-pack.c:768
#, 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:821 builtin/index-pack.c:847
+#: builtin/index-pack.c:838 builtin/index-pack.c:868
msgid "failed to apply delta"
msgstr "misslyckades tillämpa delta"
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Receiving objects"
msgstr "Tar emot objekt"
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Indexing objects"
msgstr "Skapar index för objekt"
-#: builtin/index-pack.c:1012
+#: builtin/index-pack.c:1035
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "paketet är trasigt (SHA1 stämmer inte)"
-#: builtin/index-pack.c:1017
+#: builtin/index-pack.c:1040
msgid "cannot fstat packfile"
msgstr "kan inte utföra \"fstat\" på paketfil"
-#: builtin/index-pack.c:1020
+#: builtin/index-pack.c:1043
msgid "pack has junk at the end"
msgstr "paket har skräp i slutet"
-#: builtin/index-pack.c:1031
+#: builtin/index-pack.c:1054
msgid "confusion beyond insanity in parse_pack_objects()"
msgstr "förvirrad bortom vanvett i parse_pack_objects()"
-#: builtin/index-pack.c:1054
+#: builtin/index-pack.c:1077
msgid "Resolving deltas"
msgstr "Analyserar delta"
-#: builtin/index-pack.c:1064
+#: builtin/index-pack.c:1087
#, c-format
msgid "unable to create thread: %s"
msgstr "kunde inte skapa tråd: %s"
-#: builtin/index-pack.c:1106
+#: builtin/index-pack.c:1129
msgid "confusion beyond insanity"
msgstr "förvirrad bortom vanvett"
-#: builtin/index-pack.c:1112
+#: builtin/index-pack.c:1137
#, c-format
msgid "completed with %d local objects"
msgstr "slutfördes med %d lokala objekt"
-#: builtin/index-pack.c:1121
+#: builtin/index-pack.c:1147
#, c-format
msgid "Unexpected tail checksum for %s (disk corruption?)"
msgstr "Oväntad svanschecksumma för %s (trasig disk?)"
-#: builtin/index-pack.c:1125
+#: builtin/index-pack.c:1151
#, 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:1150
+#: builtin/index-pack.c:1176
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr "kunde inte utföra \"deflate\" på tillagt objekt (%d)"
-#: builtin/index-pack.c:1229
+#: builtin/index-pack.c:1255
#, c-format
msgid "local object %s is corrupt"
msgstr "lokalt objekt %s är trasigt"
-#: builtin/index-pack.c:1253
+#: builtin/index-pack.c:1279
msgid "error while closing pack file"
msgstr "fel vid stängning av paketfil"
-#: builtin/index-pack.c:1266
+#: builtin/index-pack.c:1292
#, c-format
msgid "cannot write keep file '%s'"
msgstr "kan inte ta skriva \"keep\"-fil \"%s\""
-#: builtin/index-pack.c:1274
+#: builtin/index-pack.c:1300
#, c-format
msgid "cannot close written keep file '%s'"
msgstr "akn inte stänga skriven \"keep\"-fil \"%s\""
-#: builtin/index-pack.c:1287
+#: builtin/index-pack.c:1313
msgid "cannot store pack file"
msgstr "kan inte spara paketfil"
-#: builtin/index-pack.c:1298
+#: builtin/index-pack.c:1324
msgid "cannot store index file"
msgstr "kan inte spara indexfil"
-#: builtin/index-pack.c:1331
+#: builtin/index-pack.c:1357
#, c-format
msgid "bad pack.indexversion=%<PRIu32>"
msgstr "felaktig pack.indexversion=%<PRIu32>"
-#: builtin/index-pack.c:1337
+#: builtin/index-pack.c:1363
#, 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
+#: builtin/index-pack.c:1367 builtin/index-pack.c:1545
#, c-format
msgid "no threads support, ignoring %s"
msgstr "trådstöd saknas, ignorerar %s"
-#: builtin/index-pack.c:1399
+#: builtin/index-pack.c:1425
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr "Kan inte öppna befintlig paketfil \"%s\""
-#: builtin/index-pack.c:1401
+#: builtin/index-pack.c:1427
#, 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:1448
+#: builtin/index-pack.c:1474
#, 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:1455
+#: builtin/index-pack.c:1481
#, 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:1482
+#: builtin/index-pack.c:1509
msgid "Cannot come back to cwd"
msgstr "Kan inte gå tillbaka till arbetskatalogen (cwd)"
-#: builtin/index-pack.c:1526 builtin/index-pack.c:1529
-#: builtin/index-pack.c:1541 builtin/index-pack.c:1545
+#: builtin/index-pack.c:1557 builtin/index-pack.c:1560
+#: builtin/index-pack.c:1572 builtin/index-pack.c:1576
#, c-format
msgid "bad %s"
msgstr "felaktig %s"
-#: builtin/index-pack.c:1559
+#: builtin/index-pack.c:1590
msgid "--fix-thin cannot be used without --stdin"
msgstr "--fix-thin kan inte användas med --stdin"
-#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
+#: builtin/index-pack.c:1594 builtin/index-pack.c:1604
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr "paketfilnamnet \"%s\" slutar inte med \".pack\""
-#: builtin/index-pack.c:1582
+#: builtin/index-pack.c:1613
msgid "--verify with no packfile name given"
msgstr "--verify angavs utan paketfilnamn"
@@ -5416,7 +5963,7 @@ msgstr "behörigheter"
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
+#: builtin/init-db.c:493 builtin/prune-packed.c:75
msgid "be quiet"
msgstr "var tyst"
@@ -5448,345 +5995,353 @@ msgstr "Kan inte komma åt aktuell arbetskatalog"
msgid "Cannot access work tree '%s'"
msgstr "Kan inte komma åt arbetskatalogen \"%s\""
-#: builtin/log.c:39
-msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
-msgstr "git log [<flaggor>] [<sedan>..<till>] [[--] <sökväg>...]\n"
+#: builtin/log.c:41
+msgid "git log [<options>] [<revision range>] [[--] <path>...]\n"
+msgstr "git log [<flaggor>] [<versionsintervall>] [[--] <sökväg>...]\n"
-#: builtin/log.c:40
+#: builtin/log.c:42
msgid " or: git show [options] <object>..."
msgstr " eller: git show [flaggor] <objekt>..."
-#: builtin/log.c:102
+#: builtin/log.c:124
msgid "suppress diff output"
msgstr "undertryck diff-utdata"
-#: builtin/log.c:103
+#: builtin/log.c:125
msgid "show source"
msgstr "visa källkod"
-#: builtin/log.c:104
+#: builtin/log.c:126
msgid "Use mail map file"
msgstr "Använd e-postmappningsfil"
-#: builtin/log.c:105
+#: builtin/log.c:127
msgid "decorate options"
msgstr "dekoreringsflaggor"
-#: builtin/log.c:198
+#: builtin/log.c:230
#, c-format
msgid "Final output: %d %s\n"
msgstr "Slututdata: %d %s\n"
-#: builtin/log.c:419 builtin/log.c:511
+#: builtin/log.c:453 builtin/log.c:545
#, c-format
msgid "Could not read object %s"
msgstr "Kunde inte läsa objektet %s"
-#: builtin/log.c:535
+#: builtin/log.c:569
#, c-format
msgid "Unknown type: %d"
msgstr "Okänd typ: %d"
-#: builtin/log.c:627
+#: builtin/log.c:669
msgid "format.headers without value"
msgstr "format.headers utan värde"
-#: builtin/log.c:701
+#: builtin/log.c:751
msgid "name of output directory is too long"
msgstr "namnet på utdatakatalogen är för långt"
-#: builtin/log.c:717
+#: builtin/log.c:767
#, c-format
msgid "Cannot open patch file %s"
msgstr "Kan inte öppna patchfilen %s"
-#: builtin/log.c:731
+#: builtin/log.c:781
msgid "Need exactly one range."
msgstr "Behöver precis ett intervall."
-#: builtin/log.c:739
+#: builtin/log.c:789
msgid "Not a range."
msgstr "Inte ett intervall."
-#: builtin/log.c:812
+#: builtin/log.c:891
msgid "Cover letter needs email format"
msgstr "Omslagsbrevet behöver e-postformat"
-#: builtin/log.c:885
+#: builtin/log.c:967
#, c-format
msgid "insane in-reply-to: %s"
msgstr "tokigt in-reply-to: %s"
-#: builtin/log.c:913
+#: builtin/log.c:995
msgid "git format-patch [options] [<since> | <revision range>]"
msgstr "git format-patch [flaggor] [<sedan> | <revisionsintervall>]"
-#: builtin/log.c:958
+#: builtin/log.c:1040
msgid "Two output directories?"
msgstr "Två utdatakataloger?"
-#: builtin/log.c:1097
+#: builtin/log.c:1155
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:1100
+#: builtin/log.c:1158
msgid "use [PATCH] even with multiple patches"
msgstr "använd [PATCH] även för flera patchar"
-#: builtin/log.c:1104
+#: builtin/log.c:1162
msgid "print patches to standard out"
msgstr "skriv patcharna på stnadard ut"
-#: builtin/log.c:1106
+#: builtin/log.c:1164
msgid "generate a cover letter"
msgstr "generera ett följebrev"
-#: builtin/log.c:1108
+#: builtin/log.c:1166
msgid "use simple number sequence for output file names"
msgstr "använd enkel nummersekvens för utdatafilnamn"
-#: builtin/log.c:1109
+#: builtin/log.c:1167
msgid "sfx"
msgstr "sfx"
-#: builtin/log.c:1110
+#: builtin/log.c:1168
msgid "use <sfx> instead of '.patch'"
msgstr "använd <sfx> istället för \".patch\""
-#: builtin/log.c:1112
+#: builtin/log.c:1170
msgid "start numbering patches at <n> instead of 1"
msgstr "börja numrera patchar på <n> istället för 1"
-#: builtin/log.c:1114
+#: builtin/log.c:1172
msgid "mark the series as Nth re-roll"
msgstr "markera serien som N:te försök"
-#: builtin/log.c:1116
+#: builtin/log.c:1174
msgid "Use [<prefix>] instead of [PATCH]"
msgstr "Använd [<prefix>] istället för [PATCH]"
-#: builtin/log.c:1119
+#: builtin/log.c:1177
msgid "store resulting files in <dir>"
msgstr "spara filerna i <katalog>"
-#: builtin/log.c:1122
+#: builtin/log.c:1180
msgid "don't strip/add [PATCH]"
msgstr "ta inte bort eller lägg till [PATCH]"
-#: builtin/log.c:1125
+#: builtin/log.c:1183
msgid "don't output binary diffs"
msgstr "skriv inte binära diffar"
-#: builtin/log.c:1127
+#: builtin/log.c:1185
msgid "don't include a patch matching a commit upstream"
msgstr "ta inte med patchar som motsvarar en uppströmsincheckning"
-#: builtin/log.c:1129
+#: builtin/log.c:1187
msgid "show patch format instead of default (patch + stat)"
msgstr "visa patchformat istället för standard (patch + stat)"
-#: builtin/log.c:1131
+#: builtin/log.c:1189
msgid "Messaging"
msgstr "E-post"
-#: builtin/log.c:1132
+#: builtin/log.c:1190
msgid "header"
msgstr "huvud"
-#: builtin/log.c:1133
+#: builtin/log.c:1191
msgid "add email header"
msgstr "lägg till e-posthuvud"
-#: builtin/log.c:1134 builtin/log.c:1136
+#: builtin/log.c:1192 builtin/log.c:1194
msgid "email"
msgstr "epost"
-#: builtin/log.c:1134
+#: builtin/log.c:1192
msgid "add To: header"
msgstr "Lägg till mottagarhuvud (\"To:\")"
-#: builtin/log.c:1136
+#: builtin/log.c:1194
msgid "add Cc: header"
msgstr "Lägg till kopiehuvud (\"Cc:\")"
-#: builtin/log.c:1138
+#: builtin/log.c:1196
+msgid "ident"
+msgstr "ident"
+
+#: builtin/log.c:1197
+msgid "set From address to <ident> (or committer ident if absent)"
+msgstr "sätt Från-adress till <ident> (eller incheckare om ident saknas)"
+
+#: builtin/log.c:1199
msgid "message-id"
msgstr "meddelande-id"
-#: builtin/log.c:1139
+#: builtin/log.c:1200
msgid "make first mail a reply to <message-id>"
msgstr "Gör det första brevet ett svar till <meddelande-id>"
-#: builtin/log.c:1140 builtin/log.c:1143
+#: builtin/log.c:1201 builtin/log.c:1204
msgid "boundary"
msgstr "gräns"
-#: builtin/log.c:1141
+#: builtin/log.c:1202
msgid "attach the patch"
msgstr "bifoga patchen"
-#: builtin/log.c:1144
+#: builtin/log.c:1205
msgid "inline the patch"
msgstr "gör patchen ett inline-objekt"
-#: builtin/log.c:1148
+#: builtin/log.c:1209
msgid "enable message threading, styles: shallow, deep"
msgstr "aktivera brevtrådning, typer: shallow, deep"
-#: builtin/log.c:1150
+#: builtin/log.c:1211
msgid "signature"
msgstr "signatur"
-#: builtin/log.c:1151
+#: builtin/log.c:1212
msgid "add a signature"
msgstr "lägg till signatur"
-#: builtin/log.c:1153
+#: builtin/log.c:1214
msgid "don't print the patch filenames"
msgstr "visa inte filnamn för patchar"
-#: builtin/log.c:1202
+#: builtin/log.c:1288
#, c-format
-msgid "bogus committer info %s"
-msgstr "felaktig incheckarinformation %s"
+msgid "invalid ident line: %s"
+msgstr "ogiltig ident-rad: %s"
-#: builtin/log.c:1247
+#: builtin/log.c:1303
msgid "-n and -k are mutually exclusive."
msgstr "-n och -k kan inte användas samtidigt."
-#: builtin/log.c:1249
+#: builtin/log.c:1305
msgid "--subject-prefix and -k are mutually exclusive."
msgstr "--subject-prefix och -k kan inte användas samtidigt."
-#: builtin/log.c:1257
+#: builtin/log.c:1313
msgid "--name-only does not make sense"
msgstr "kan inte använda --name-only"
-#: builtin/log.c:1259
+#: builtin/log.c:1315
msgid "--name-status does not make sense"
msgstr "kan inte använda --name-status"
-#: builtin/log.c:1261
+#: builtin/log.c:1317
msgid "--check does not make sense"
msgstr "kan inte använda --check"
-#: builtin/log.c:1284
+#: builtin/log.c:1340
msgid "standard output, or directory, which one?"
msgstr "standard ut, eller katalog, vilken skall det vara?"
-#: builtin/log.c:1286
+#: builtin/log.c:1342
#, c-format
msgid "Could not create directory '%s'"
msgstr "Kunde inte skapa katalogen \"%s\""
-#: builtin/log.c:1439
+#: builtin/log.c:1490
msgid "Failed to create output files"
msgstr "Misslyckades skapa utdatafiler"
-#: builtin/log.c:1488
+#: builtin/log.c:1539
msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
msgstr "git cherry [-v] [<uppström> [<huvud> [<gräns>]]]"
-#: builtin/log.c:1543
+#: builtin/log.c:1594
#, 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:1556 builtin/log.c:1558 builtin/log.c:1570
+#: builtin/log.c:1607 builtin/log.c:1609 builtin/log.c:1621
#, c-format
msgid "Unknown commit %s"
msgstr "Okänd incheckning %s"
-#: builtin/ls-files.c:409
+#: builtin/ls-files.c:408
msgid "git ls-files [options] [<file>...]"
msgstr "git ls-files [flaggor] [<fil>...]"
-#: builtin/ls-files.c:466
+#: builtin/ls-files.c:465
msgid "identify the file status with tags"
msgstr "identifiera filstatus med taggar"
-#: builtin/ls-files.c:468
+#: builtin/ls-files.c:467
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:470
+#: builtin/ls-files.c:469
msgid "show cached files in the output (default)"
msgstr "visa cachade filer i utdata (standard)"
-#: builtin/ls-files.c:472
+#: builtin/ls-files.c:471
msgid "show deleted files in the output"
msgstr "visa borttagna filer i utdata"
-#: builtin/ls-files.c:474
+#: builtin/ls-files.c:473
msgid "show modified files in the output"
msgstr "visa modifierade filer i utdata"
-#: builtin/ls-files.c:476
+#: builtin/ls-files.c:475
msgid "show other files in the output"
msgstr "visa andra filer i utdata"
-#: builtin/ls-files.c:478
+#: builtin/ls-files.c:477
msgid "show ignored files in the output"
msgstr "visa ignorerade filer i utdata"
-#: builtin/ls-files.c:481
+#: builtin/ls-files.c:480
msgid "show staged contents' object name in the output"
msgstr "visa köat innehålls objektnamn i utdata"
-#: builtin/ls-files.c:483
+#: builtin/ls-files.c:482
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:485
+#: builtin/ls-files.c:484
msgid "show 'other' directories' name only"
msgstr "visa endast namn för \"andra\" kataloger"
-#: builtin/ls-files.c:488
+#: builtin/ls-files.c:487
msgid "don't show empty directories"
msgstr "visa inte tomma kataloger"
-#: builtin/ls-files.c:491
+#: builtin/ls-files.c:490
msgid "show unmerged files in the output"
msgstr "visa ej sammanslagna filer i utdata"
-#: builtin/ls-files.c:493
+#: builtin/ls-files.c:492
msgid "show resolve-undo information"
msgstr "visa \"resolve-undo\"-information"
-#: builtin/ls-files.c:495
+#: builtin/ls-files.c:494
msgid "skip files matching pattern"
msgstr "hoppa över filer som motsvarar mönster"
-#: builtin/ls-files.c:498
+#: builtin/ls-files.c:497
msgid "exclude patterns are read from <file>"
msgstr "exkludera mönster som läses från <fil>"
-#: builtin/ls-files.c:501
+#: builtin/ls-files.c:500
msgid "read additional per-directory exclude patterns in <file>"
msgstr "läs ytterligare per-katalog-exkluderingsmönster från <fil>"
-#: builtin/ls-files.c:503
+#: builtin/ls-files.c:502
msgid "add the standard git exclusions"
msgstr "lägg till git:s standardexkluderingar"
-#: builtin/ls-files.c:506
+#: builtin/ls-files.c:505
msgid "make the output relative to the project top directory"
msgstr "gör utdata relativ till projektets toppkatalog"
-#: builtin/ls-files.c:509
+#: builtin/ls-files.c:508
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:510
+#: builtin/ls-files.c:509
msgid "tree-ish"
msgstr "träd-igt"
-#: builtin/ls-files.c:511
+#: builtin/ls-files.c:510
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:513
+#: builtin/ls-files.c:512
msgid "show debugging data"
msgstr "visa felsökningsutdata"
@@ -5838,166 +6393,170 @@ msgstr "git merge [flaggor] <meddelande> HEAD <incheckning>"
msgid "git merge --abort"
msgstr "git merge --abort"
-#: builtin/merge.c:90
+#: builtin/merge.c:98
msgid "switch `m' requires a value"
msgstr "flaggan \"m\" behöver ett värde"
-#: builtin/merge.c:127
+#: builtin/merge.c:135
#, c-format
msgid "Could not find merge strategy '%s'.\n"
msgstr "Kunde inte hitta sammanslagningsstrategin \"%s\".\n"
-#: builtin/merge.c:128
+#: builtin/merge.c:136
#, c-format
msgid "Available strategies are:"
msgstr "Tillgängliga strategier är:"
-#: builtin/merge.c:133
+#: builtin/merge.c:141
#, c-format
msgid "Available custom strategies are:"
msgstr "Tillgängliga skräddarsydda strategier är:"
-#: builtin/merge.c:183
+#: builtin/merge.c:198
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
+#: builtin/merge.c:201
msgid "show a diffstat at the end of the merge"
msgstr "visa en diffstat när sammanslagningen är färdig"
-#: builtin/merge.c:187
+#: builtin/merge.c:202
msgid "(synonym to --stat)"
msgstr "(synonym till --stat)"
-#: builtin/merge.c:189
+#: builtin/merge.c:204
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
+#: builtin/merge.c:207
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
+#: builtin/merge.c:209
msgid "perform a commit if the merge succeeds (default)"
msgstr "utför en incheckning om sammanslagningen lyckades (standard)"
-#: builtin/merge.c:196
+#: builtin/merge.c:211
msgid "edit message before committing"
msgstr "redigera meddelande innan incheckning"
-#: builtin/merge.c:198
+#: builtin/merge.c:212
msgid "allow fast-forward (default)"
msgstr "tillåt snabbspolning (standard)"
-#: builtin/merge.c:200
+#: builtin/merge.c:214
msgid "abort if fast-forward is not possible"
msgstr "avbryt om snabbspolning inte är möjlig"
-#: builtin/merge.c:202 builtin/notes.c:866 builtin/revert.c:112
+#: builtin/merge.c:218
+msgid "Verify that the named commit has a valid GPG signature"
+msgstr "Bekräfta att den namngivna incheckningen har en giltig GPG-signatur"
+
+#: builtin/merge.c:219 builtin/notes.c:738 builtin/revert.c:114
msgid "strategy"
msgstr "strategi"
-#: builtin/merge.c:203
+#: builtin/merge.c:220
msgid "merge strategy to use"
msgstr "sammanslagninsstrategi att använda"
-#: builtin/merge.c:204
+#: builtin/merge.c:221
msgid "option=value"
msgstr "alternativ=värde"
-#: builtin/merge.c:205
+#: builtin/merge.c:222
msgid "option for selected merge strategy"
msgstr "alternativ för vald sammanslagningsstrategi"
-#: builtin/merge.c:207
+#: builtin/merge.c:224
msgid "merge commit message (for a non-fast-forward merge)"
msgstr "incheckningsmeddelande för (icke snabbspolande) sammanslagning"
-#: builtin/merge.c:211
+#: builtin/merge.c:228
msgid "abort the current in-progress merge"
msgstr "avbryt den pågående sammanslagningen"
-#: builtin/merge.c:240
+#: builtin/merge.c:257
msgid "could not run stash."
msgstr "kunde köra stash."
-#: builtin/merge.c:245
+#: builtin/merge.c:262
msgid "stash failed"
msgstr "stash misslyckades"
-#: builtin/merge.c:250
+#: builtin/merge.c:267
#, c-format
msgid "not a valid object: %s"
msgstr "inte ett giltigt objekt: %s"
-#: builtin/merge.c:269 builtin/merge.c:286
+#: builtin/merge.c:286 builtin/merge.c:303
msgid "read-tree failed"
msgstr "read-tree misslyckades"
-#: builtin/merge.c:316
+#: builtin/merge.c:333
msgid " (nothing to squash)"
msgstr " (inget att platta till)"
-#: builtin/merge.c:329
+#: builtin/merge.c:346
#, c-format
msgid "Squash commit -- not updating HEAD\n"
msgstr "Tillplattningsincheckning -- uppdaterar inte HEAD\n"
-#: builtin/merge.c:361
+#: builtin/merge.c:378
msgid "Writing SQUASH_MSG"
msgstr "Skriver SQUASH_MSG"
-#: builtin/merge.c:363
+#: builtin/merge.c:380
msgid "Finishing SQUASH_MSG"
msgstr "Avslutar SQUASH_MSG"
-#: builtin/merge.c:386
+#: builtin/merge.c:403
#, c-format
msgid "No merge message -- not updating HEAD\n"
msgstr "Inget sammanslagningsmeddelande -- uppdaterar inte HEAD\n"
-#: builtin/merge.c:436
+#: builtin/merge.c:453
#, c-format
msgid "'%s' does not point to a commit"
msgstr "\"%s\" verkar inte peka på en incheckning"
-#: builtin/merge.c:535
+#: builtin/merge.c:565
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Felaktig branch.%s.mergeoptions-sträng: %s"
-#: builtin/merge.c:628
+#: builtin/merge.c:657
msgid "git write-tree failed to write a tree"
msgstr "git write-tree misslyckades skriva ett träd"
-#: builtin/merge.c:656
+#: builtin/merge.c:685
msgid "Not handling anything other than two heads merge."
msgstr "Hanterar inte något annat än en sammanslagning av två huvuden."
-#: builtin/merge.c:670
+#: builtin/merge.c:699
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr "Felaktig flagga för merge-recursive: -X%s"
-#: builtin/merge.c:684
+#: builtin/merge.c:713
#, c-format
msgid "unable to write %s"
msgstr "kunde inte skriva %s"
-#: builtin/merge.c:773
+#: builtin/merge.c:802
#, c-format
msgid "Could not read from '%s'"
msgstr "Kunde inte läsa från \"%s\""
-#: builtin/merge.c:782
+#: builtin/merge.c:811
#, 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:788
+#: builtin/merge.c:817
#, c-format
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
@@ -6013,53 +6572,48 @@ msgstr ""
"Rader som inleds med \"%c\" kommer ignoreras, och ett tomt meddelande\n"
"avbryter incheckningen.\n"
-#: builtin/merge.c:812
+#: builtin/merge.c:841
msgid "Empty commit message."
msgstr "Tomt incheckningsmeddelande."
-#: builtin/merge.c:824
+#: builtin/merge.c:853
#, c-format
msgid "Wonderful.\n"
msgstr "Underbart.\n"
-#: builtin/merge.c:889
+#: builtin/merge.c:918
#, 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:905
+#: builtin/merge.c:934
#, c-format
msgid "'%s' is not a commit"
msgstr "\"%s\" är inte en incheckning"
-#: builtin/merge.c:946
+#: builtin/merge.c:975
msgid "No current branch."
msgstr "Inte på någon gren."
-#: builtin/merge.c:948
+#: builtin/merge.c:977
msgid "No remote for the current branch."
msgstr "Ingen fjärr för aktuell gren."
-#: builtin/merge.c:950
+#: builtin/merge.c:979
msgid "No default upstream defined for the current branch."
msgstr "Ingen standarduppström angiven för aktuell gren."
-#: builtin/merge.c:955
+#: builtin/merge.c:984
#, c-format
-msgid "No remote tracking branch for %s from %s"
+msgid "No remote-tracking branch for %s from %s"
msgstr "Ingen fjärrspårande gren för %s från %s"
-#: builtin/merge.c:1042 builtin/merge.c:1199
-#, c-format
-msgid "%s - not something we can merge"
-msgstr "%s - inte något vi kan slå ihop"
-
-#: builtin/merge.c:1110
+#: builtin/merge.c:1140
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr "Det finns ingen sammanslagning att avbryta (MERGE_HEAD saknas)."
-#: builtin/merge.c:1126 git-pull.sh:31
+#: builtin/merge.c:1156 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -6067,11 +6621,11 @@ msgstr ""
"Du har inte avslutat sammanslagningen (MERGE_HEAD finns).\n"
"Checka in dina ändringar innan du kan slå ihop."
-#: builtin/merge.c:1129 git-pull.sh:34
+#: builtin/merge.c:1159 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:1133
+#: builtin/merge.c:1163
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -6079,79 +6633,103 @@ 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:1136
+#: builtin/merge.c:1166
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:1145
+#: builtin/merge.c:1175
msgid "You cannot combine --squash with --no-ff."
msgstr "Du kan inte kombinera --squash med --no-ff."
-#: builtin/merge.c:1150
-msgid "You cannot combine --no-ff with --ff-only."
-msgstr "Du kan inte kombinera --no-ff med --ff-only."
-
-#: builtin/merge.c:1157
+#: builtin/merge.c:1184
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr "Ingen incheckning angiven och merge.defaultToUpstream är ej satt."
-#: builtin/merge.c:1189
+#: builtin/merge.c:1216
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:1192
+#: builtin/merge.c:1219
msgid "Squash commit into empty head not supported yet"
msgstr "Stöder inte en tillplattningsincheckning på ett tomt huvud ännu"
-#: builtin/merge.c:1194
+#: builtin/merge.c:1221
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:1310
+#: builtin/merge.c:1226
+#, c-format
+msgid "%s - not something we can merge"
+msgstr "%s - inte något vi kan slå ihop"
+
+#: builtin/merge.c:1277
+#, c-format
+msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
+msgstr ""
+"Incheckningen %s har en obetrodd GPG-signatur som påstås vara gjord av %s."
+
+#: builtin/merge.c:1280
+#, c-format
+msgid "Commit %s has a bad GPG signature allegedly by %s."
+msgstr ""
+"Incheckningen %s har en felaktig GPG-signatur som påstås vara gjord av %s."
+
+#. 'N'
+#: builtin/merge.c:1283
+#, c-format
+msgid "Commit %s does not have a GPG signature."
+msgstr "Incheckning %s har inte någon GPG-signatur."
+
+#: builtin/merge.c:1286
+#, c-format
+msgid "Commit %s has a good GPG signature by %s\n"
+msgstr "Incheckningen %s har en korrekt GPG-signatur av %s\n"
+
+#: builtin/merge.c:1370
#, c-format
msgid "Updating %s..%s\n"
msgstr "Uppdaterar %s..%s\n"
-#: builtin/merge.c:1349
+#: builtin/merge.c:1409
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr "Försöker riktigt enkel sammanslagning i indexet...\n"
-#: builtin/merge.c:1356
+#: builtin/merge.c:1416
#, c-format
msgid "Nope.\n"
msgstr "Nej.\n"
-#: builtin/merge.c:1388
+#: builtin/merge.c:1448
msgid "Not possible to fast-forward, aborting."
msgstr "Kan inte snabbspola, avbryter."
-#: builtin/merge.c:1411 builtin/merge.c:1490
+#: builtin/merge.c:1471 builtin/merge.c:1550
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr "Återspolar trädet till orört...\n"
-#: builtin/merge.c:1415
+#: builtin/merge.c:1475
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "Försöker sammanslagninsstrategin %s...\n"
-#: builtin/merge.c:1481
+#: builtin/merge.c:1541
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr "Ingen sammanslagningsstrategi hanterade sammanslagningen.\n"
-#: builtin/merge.c:1483
+#: builtin/merge.c:1543
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr "Sammanslagning med strategin %s misslyckades.\n"
-#: builtin/merge.c:1492
+#: builtin/merge.c:1552
#, 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:1504
+#: builtin/merge.c:1564
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
@@ -6318,47 +6896,51 @@ msgstr "Byter namn på %s till %s\n"
msgid "renaming '%s' failed"
msgstr "misslyckades byta namn på \"%s\""
-#: builtin/name-rev.c:175
+#: builtin/name-rev.c:259
msgid "git name-rev [options] <commit>..."
msgstr "git name-rev [flaggor] <incheckning>..."
-#: builtin/name-rev.c:176
+#: builtin/name-rev.c:260
msgid "git name-rev [options] --all"
msgstr "git name-rev [flaggor] --all"
-#: builtin/name-rev.c:177
+#: builtin/name-rev.c:261
msgid "git name-rev [options] --stdin"
msgstr "git name-rev [flaggor] --stdin"
-#: builtin/name-rev.c:229
+#: builtin/name-rev.c:313
msgid "print only names (no SHA-1)"
msgstr "skriv endast namn (ingen SHA-1)"
-#: builtin/name-rev.c:230
+#: builtin/name-rev.c:314
msgid "only use tags to name the commits"
msgstr "använd endast taggar för att namnge incheckningar"
-#: builtin/name-rev.c:232
+#: builtin/name-rev.c:316
msgid "only use refs matching <pattern>"
msgstr "använd endast referenser som motsvarar <mönster>"
-#: builtin/name-rev.c:234
+#: builtin/name-rev.c:318
msgid "list all commits reachable from all refs"
msgstr "lista alla incheckningar som kan nås alla referenser"
-#: builtin/name-rev.c:235
+#: builtin/name-rev.c:319
msgid "read from stdin"
msgstr "läs från standard in"
-#: builtin/name-rev.c:236
+#: builtin/name-rev.c:320
msgid "allow to print `undefined` names"
msgstr "tillåt att skriva \"odefinierade\" namn"
-#: builtin/notes.c:26
+#: builtin/name-rev.c:326
+msgid "dereference tags in the input (internal use)"
+msgstr "avreferera taggar i indata (används internt)"
+
+#: builtin/notes.c:24
msgid "git notes [--ref <notes_ref>] [list [<object>]]"
msgstr "git notes [--ref <anteckningsref>] [list [<objekt>]]"
-#: builtin/notes.c:27
+#: builtin/notes.c:25
msgid ""
"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
@@ -6366,12 +6948,12 @@ msgstr ""
"git notes [--ref <anteckningsref>] add [-f] [-m <medd> | -F <fil> | (-c | -"
"C) <objekt>] [<objekt>]"
-#: builtin/notes.c:28
+#: builtin/notes.c:26
msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
msgstr ""
"git notes [--ref <anteckningsref>] copy [-f] <från-objekt> <till-objekt>"
-#: builtin/notes.c:29
+#: builtin/notes.c:27
msgid ""
"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
@@ -6379,221 +6961,200 @@ msgstr ""
"git notes [--ref <anteckningsref>] append [-m <medd> | -F <fil> | (-c | -C) "
"<objekt>] [<objekt>]"
-#: builtin/notes.c:30
+#: builtin/notes.c:28
msgid "git notes [--ref <notes_ref>] edit [<object>]"
msgstr "git notes [--ref <anteckningsref>] edit [<objekt>]"
-#: builtin/notes.c:31
+#: builtin/notes.c:29
msgid "git notes [--ref <notes_ref>] show [<object>]"
msgstr "git notes [--ref <anteckningsref>] show [<objekt>]"
-#: builtin/notes.c:32
+#: builtin/notes.c:30
msgid ""
"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
msgstr ""
"git notes [--ref <anteckningsref>] merge [-v | -q] [-s <strategi> ] "
"<anteckningsref>"
-#: builtin/notes.c:33
+#: builtin/notes.c:31
msgid "git notes merge --commit [-v | -q]"
msgstr "git notes merge --commit [-v | -q]"
-#: builtin/notes.c:34
+#: builtin/notes.c:32
msgid "git notes merge --abort [-v | -q]"
msgstr "git notes merge --abort [-v | -q]"
-#: builtin/notes.c:35
+#: builtin/notes.c:33
msgid "git notes [--ref <notes_ref>] remove [<object>...]"
msgstr "git notes [--ref <anteckningsref>] remove [<objekt>...]"
-#: builtin/notes.c:36
+#: builtin/notes.c:34
msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
msgstr "git notes [--ref <anteckningsref>] prune [-n | -v]"
-#: builtin/notes.c:37
+#: builtin/notes.c:35
msgid "git notes [--ref <notes_ref>] get-ref"
msgstr "git notes [--ref <anteckningsref>] get-ref"
-#: builtin/notes.c:42
+#: builtin/notes.c:40
msgid "git notes [list [<object>]]"
msgstr "git notes [list [<objekt>]]"
-#: builtin/notes.c:47
+#: builtin/notes.c:45
msgid "git notes add [<options>] [<object>]"
msgstr "git notes add [<flaggor>] [<objekt>]"
-#: builtin/notes.c:52
+#: builtin/notes.c:50
msgid "git notes copy [<options>] <from-object> <to-object>"
msgstr "git notes copy [<flaggor>] <från-objekt> <till-objekt>"
-#: builtin/notes.c:53
+#: builtin/notes.c:51
msgid "git notes copy --stdin [<from-object> <to-object>]..."
msgstr "git notes copy --stdin [<från-objekt> <till-objekt>]..."
-#: builtin/notes.c:58
+#: builtin/notes.c:56
msgid "git notes append [<options>] [<object>]"
msgstr "git notes append [<flaggor>] [<objekt>]"
-#: builtin/notes.c:63
+#: builtin/notes.c:61
msgid "git notes edit [<object>]"
msgstr "git notes edit [<objekt>]"
-#: builtin/notes.c:68
+#: builtin/notes.c:66
msgid "git notes show [<object>]"
msgstr "git notes show [<objekt>]"
-#: builtin/notes.c:73
+#: builtin/notes.c:71
msgid "git notes merge [<options>] <notes_ref>"
msgstr "git notes merge [<flaggor>] <anteckningsref>"
-#: builtin/notes.c:74
+#: builtin/notes.c:72
msgid "git notes merge --commit [<options>]"
msgstr "git notes merge --commit [<flaggor>]"
-#: builtin/notes.c:75
+#: builtin/notes.c:73
msgid "git notes merge --abort [<options>]"
msgstr "git notes merge --abort [<flaggor>]"
-#: builtin/notes.c:80
+#: builtin/notes.c:78
msgid "git notes remove [<object>]"
msgstr "git notes remove [<objekt>]"
-#: builtin/notes.c:85
+#: builtin/notes.c:83
msgid "git notes prune [<options>]"
msgstr "git notes prune [<flaggor>]"
-#: builtin/notes.c:90
+#: builtin/notes.c:88
msgid "git notes get-ref"
msgstr "git notes get-ref"
-#: builtin/notes.c:139
+#: builtin/notes.c:137
#, c-format
msgid "unable to start 'show' for object '%s'"
msgstr "kunde inte starta \"show\" för objektet \"%s\""
-#: builtin/notes.c:143
+#: builtin/notes.c:141
msgid "could not read 'show' output"
msgstr "kunde inte läsa utdata från \"show\""
-#: builtin/notes.c:151
+#: builtin/notes.c:149
#, c-format
msgid "failed to finish 'show' for object '%s'"
msgstr "kunde inte avsluta \"show\" för objektet \"%s\""
-#: builtin/notes.c:169 builtin/tag.c:341
+#: builtin/notes.c:167 builtin/tag.c:341
#, c-format
msgid "could not create file '%s'"
msgstr "kunde inte skapa filen \"%s\""
-#: builtin/notes.c:188
+#: builtin/notes.c:186
msgid "Please supply the note contents using either -m or -F option"
msgstr "Ange innehåll för anteckningen med antingen -m eller -F"
-#: builtin/notes.c:209 builtin/notes.c:972
+#: builtin/notes.c:207 builtin/notes.c:844
#, c-format
msgid "Removing note for object %s\n"
msgstr "Tar bort anteckning för objektet %s\n"
-#: builtin/notes.c:214
+#: builtin/notes.c:212
msgid "unable to write note object"
msgstr "kunde inte skriva anteckningsobjekt"
-#: builtin/notes.c:216
+#: builtin/notes.c:214
#, c-format
msgid "The note contents has been left in %s"
msgstr "Anteckningens innehåll har lämnats kvar i %s"
-#: builtin/notes.c:250 builtin/tag.c:540
+#: builtin/notes.c:248 builtin/tag.c:540
#, c-format
msgid "cannot read '%s'"
msgstr "kunde inte läsa \"%s\""
-#: builtin/notes.c:252 builtin/tag.c:543
+#: builtin/notes.c:250 builtin/tag.c:543
#, c-format
msgid "could not open or read '%s'"
msgstr "kunde inte öppna eller läsa \"%s\""
-#: builtin/notes.c:271 builtin/notes.c:444 builtin/notes.c:446
-#: builtin/notes.c:506 builtin/notes.c:560 builtin/notes.c:643
-#: builtin/notes.c:648 builtin/notes.c:723 builtin/notes.c:765
-#: builtin/notes.c:967 builtin/tag.c:556
+#: builtin/notes.c:269 builtin/notes.c:316 builtin/notes.c:318
+#: builtin/notes.c:378 builtin/notes.c:432 builtin/notes.c:515
+#: builtin/notes.c:520 builtin/notes.c:595 builtin/notes.c:637
+#: builtin/notes.c:839 builtin/tag.c:556
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
msgstr "Kunde inte slå upp \"%s\" som en giltig referens."
-#: builtin/notes.c:274
+#: builtin/notes.c:272
#, c-format
msgid "Failed to read object '%s'."
msgstr "Kunde inte läsa objektet \"%s\"."
-#: builtin/notes.c:298
-msgid "Cannot commit uninitialized/unreferenced notes tree"
-msgstr "Kan inte checka in oinitierat/orefererat anteckningsträd"
-
-#: builtin/notes.c:339
-#, c-format
-msgid "Bad notes.rewriteMode value: '%s'"
-msgstr "Felaktigt värde för notes.rewriteMode: '%s'"
-
-#: builtin/notes.c:349
-#, c-format
-msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
-msgstr "Vägrar skriva över anteckningar i %s (utanför refs/notes/)"
-
-#. TRANSLATORS: The first %s is the name of the
-#. environment variable, the second %s is its value
-#: builtin/notes.c:376
-#, c-format
-msgid "Bad %s value: '%s'"
-msgstr "Felaktigt värde på %s: \"%s\""
-
-#: builtin/notes.c:440
+#: builtin/notes.c:312
#, c-format
msgid "Malformed input line: '%s'."
msgstr "Felaktig indatarad: \"%s\"."
-#: builtin/notes.c:455
+#: builtin/notes.c:327
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
msgstr "Misslyckades kopiera anteckningar från \"%s\" till \"%s\""
-#: builtin/notes.c:499 builtin/notes.c:553 builtin/notes.c:626
-#: builtin/notes.c:638 builtin/notes.c:711 builtin/notes.c:758
-#: builtin/notes.c:1032
+#: builtin/notes.c:371 builtin/notes.c:425 builtin/notes.c:498
+#: builtin/notes.c:510 builtin/notes.c:583 builtin/notes.c:630
+#: builtin/notes.c:904
msgid "too many parameters"
msgstr "för många parametrar"
-#: builtin/notes.c:512 builtin/notes.c:771
+#: builtin/notes.c:384 builtin/notes.c:643
#, c-format
msgid "No note found for object %s."
msgstr "Inga anteckningar hittades för objektet %s."
-#: builtin/notes.c:534 builtin/notes.c:691
+#: builtin/notes.c:406 builtin/notes.c:563
msgid "note contents as a string"
msgstr "anteckningsinnehåll som sträng"
-#: builtin/notes.c:537 builtin/notes.c:694
+#: builtin/notes.c:409 builtin/notes.c:566
msgid "note contents in a file"
msgstr "anteckningsinnehåll i en fil"
-#: builtin/notes.c:539 builtin/notes.c:542 builtin/notes.c:696
-#: builtin/notes.c:699 builtin/tag.c:474
+#: builtin/notes.c:411 builtin/notes.c:414 builtin/notes.c:568
+#: builtin/notes.c:571 builtin/tag.c:474
msgid "object"
msgstr "objekt"
-#: builtin/notes.c:540 builtin/notes.c:697
+#: builtin/notes.c:412 builtin/notes.c:569
msgid "reuse and edit specified note object"
msgstr "återanvänd och redigera angivet anteckningsobjekt"
-#: builtin/notes.c:543 builtin/notes.c:700
+#: builtin/notes.c:415 builtin/notes.c:572
msgid "reuse specified note object"
msgstr "återanvänd angivet anteckningsobjekt"
-#: builtin/notes.c:545 builtin/notes.c:613
+#: builtin/notes.c:417 builtin/notes.c:485
msgid "replace existing notes"
msgstr "ersätt befintliga anteckningar"
-#: builtin/notes.c:579
+#: builtin/notes.c:451
#, c-format
msgid ""
"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6602,24 +7163,24 @@ msgstr ""
"Kan inte lägga till anteckningar. Hittade befintliga anteckningar för "
"objektet %s. Använd \"-f\" för att skriva över befintliga anteckningar"
-#: builtin/notes.c:584 builtin/notes.c:661
+#: builtin/notes.c:456 builtin/notes.c:533
#, c-format
msgid "Overwriting existing notes for object %s\n"
msgstr "Skriver över befintliga anteckningar för objektet %s\n"
-#: builtin/notes.c:614
+#: builtin/notes.c:486
msgid "read objects from stdin"
msgstr "läs objekt från standard in"
-#: builtin/notes.c:616
+#: builtin/notes.c:488
msgid "load rewriting config for <command> (implies --stdin)"
msgstr "läs omskrivningsinställning för <kommando> (implicerar --stdin)"
-#: builtin/notes.c:634
+#: builtin/notes.c:506
msgid "too few parameters"
msgstr "för få parametrar"
-#: builtin/notes.c:655
+#: builtin/notes.c:527
#, c-format
msgid ""
"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6628,12 +7189,12 @@ msgstr ""
"Kan inte kopiera anteckningar. Hittade befintliga anteckningar för objektet "
"%s. Använd \"-f\" för att skriva över befintliga anteckningar"
-#: builtin/notes.c:667
+#: builtin/notes.c:539
#, c-format
msgid "Missing notes on source object %s. Cannot copy."
msgstr "Anteckningar på källobjektet %s saknas. Kan inte kopiera."
-#: builtin/notes.c:716
+#: builtin/notes.c:588
#, c-format
msgid ""
"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
@@ -6642,15 +7203,15 @@ 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:863
+#: builtin/notes.c:735
msgid "General options"
msgstr "Allmänna flaggor"
-#: builtin/notes.c:865
+#: builtin/notes.c:737
msgid "Merge options"
msgstr "Flaggor för sammanslagning"
-#: builtin/notes.c:867
+#: builtin/notes.c:739
msgid ""
"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
"cat_sort_uniq)"
@@ -6658,46 +7219,46 @@ msgstr ""
"läs konflikter i anteckningar med angiven strategi (manual/ours/theirs/union/"
"cat_sort_uniq)"
-#: builtin/notes.c:869
+#: builtin/notes.c:741
msgid "Committing unmerged notes"
msgstr "Checkar in ej sammanslagna anteckningar"
-#: builtin/notes.c:871
+#: builtin/notes.c:743
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:873
+#: builtin/notes.c:745
msgid "Aborting notes merge resolution"
msgstr "Avbryt lösning av sammanslagning av anteckningar"
-#: builtin/notes.c:875
+#: builtin/notes.c:747
msgid "abort notes merge"
msgstr "avbryt sammanslagning av anteckningar"
-#: builtin/notes.c:970
+#: builtin/notes.c:842
#, c-format
msgid "Object %s has no note\n"
msgstr "Objektet %s har ingen anteckning\n"
-#: builtin/notes.c:982
+#: builtin/notes.c:854
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:985
+#: builtin/notes.c:857
msgid "read object names from the standard input"
msgstr "läs objektnamn från standard in"
-#: builtin/notes.c:1066
+#: builtin/notes.c:938
msgid "notes_ref"
msgstr "anteckningar-ref"
-#: builtin/notes.c:1067
+#: builtin/notes.c:939
msgid "use notes from <notes_ref>"
msgstr "använd anteckningar från <anteckningsref>"
-#: builtin/notes.c:1102 builtin/remote.c:1598
+#: builtin/notes.c:974 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
msgstr "Okänt underkommando: %s"
@@ -6933,7 +7494,7 @@ msgstr ""
" git push %s %s\n"
"%s"
-#: builtin/push.c:121
+#: builtin/push.c:117
#, c-format
msgid ""
"You are not currently on a branch.\n"
@@ -6948,7 +7509,7 @@ msgstr ""
"\n"
" git push %s HEAD:<namn-på-fjärrgren>\n"
-#: builtin/push.c:128
+#: builtin/push.c:131
#, c-format
msgid ""
"The current branch %s has no upstream branch.\n"
@@ -6961,12 +7522,12 @@ msgstr ""
"\n"
" git push --set-upstream %s %s\n"
-#: builtin/push.c:136
+#: builtin/push.c:139
#, c-format
msgid "The current branch %s has multiple upstream branches, refusing to push."
msgstr "Den aktuella grenen %s har flera uppströmsgrenar, vägrar sända."
-#: builtin/push.c:139
+#: builtin/push.c:142
#, c-format
msgid ""
"You are pushing to remote '%s', which is not the upstream of\n"
@@ -6977,7 +7538,7 @@ 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:151
+#: builtin/push.c:165
msgid ""
"push.default is unset; its implicit value is changing in\n"
"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
@@ -7011,26 +7572,26 @@ msgstr ""
"liknande läget \"current\" istället för \"simple\" om du ibland använder\n"
"äldre versioner av Git.)"
-#: builtin/push.c:199
+#: builtin/push.c:225
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:206
+#: builtin/push.c:232
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
-"before pushing again.\n"
+"its remote counterpart. Integrate the remote changes (e.g.\n"
+"'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"Uppdateringar avvisades då änden på din befintliga gren är bakom\n"
-"dess fjärrmotsvarighet. Slå ihop fjärrändringarna (t.ex. \"git pull\")\n"
-"innan du sänder igen.\n"
+"dess fjärrmotsvarighet. Integrera fjärrändringarna (t.ex\n"
+"\"git pull ....\") innan du sänder igen.\n"
"Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
-#: builtin/push.c:212
+#: builtin/push.c:238
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"
@@ -7044,37 +7605,37 @@ msgstr ""
"endast\n"
"sända aktuell gren."
-#: builtin/push.c:218
+#: builtin/push.c:244
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and merge the remote changes\n"
-"(e.g. 'git pull') before pushing again.\n"
+"counterpart. Check out this branch and integrate the remote changes\n"
+"(e.g. 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"Uppdateringar avvisades då änden på en gren som sänds in är bakom dess\n"
-"fjärrmotsvarighet. Checka ut grenen och slå ihop fjärrändringarna (t.ex.\n"
-"\"git pull\") innan du sänder igen.\n"
+"fjärrmotsvarighet. Checka ut grenen och integrera fjärrändringarna (t.ex.\n"
+"\"git pull ...\") innan du sänder igen.\n"
"Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
-#: builtin/push.c:224
+#: builtin/push.c:250
msgid ""
"Updates were rejected because the remote contains work that you do\n"
"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first merge the remote changes (e.g.,\n"
-"'git pull') before pushing again.\n"
+"to the same ref. You may want to first integrate the remote changes\n"
+"(e.g., 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"Uppdateringar avvisades då fjärren innehåller ändringar som du inte\n"
"har lokalt. Det beror oftast på att ett annat arkiv har sänt in samma\n"
-"referenser. Det kan vara en idé att först slå ihop fjärrändringarna\n"
-"(t.ex. \"git pull\") innan du sänder igen.\n"
+"referenser. Det kan vara en idé att först integrera fjärrändringarna\n"
+"(t.ex. \"git pull ...\") innan du sänder igen.\n"
"Se avsnittet \"Note about fast-forwards\" i \"git push --help\" för detaljer."
-#: builtin/push.c:231
+#: builtin/push.c:257
msgid "Updates were rejected because the tag already exists in the remote."
msgstr "Uppdateringarna avvisades eftersom taggen redan finns på fjärren."
-#: builtin/push.c:234
+#: builtin/push.c:260
msgid ""
"You cannot update a remote ref that points at a non-commit object,\n"
"or update a remote ref to make it point at a non-commit object,\n"
@@ -7085,22 +7646,22 @@ msgstr ""
"pekar på något som inte är en incheckning, utan att använda flaggan\n"
"\"--force\".\n"
-#: builtin/push.c:294
+#: builtin/push.c:320
#, c-format
msgid "Pushing to %s\n"
msgstr "Sänder till %s\n"
-#: builtin/push.c:298
+#: builtin/push.c:324
#, c-format
msgid "failed to push some refs to '%s'"
msgstr "misslyckades sända vissa referenser till \"%s\""
-#: builtin/push.c:331
+#: builtin/push.c:357
#, c-format
msgid "bad repository '%s'"
msgstr "felaktigt arkiv \"%s\""
-#: builtin/push.c:332
+#: builtin/push.c:358
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -7121,83 +7682,87 @@ msgstr ""
"\n"
" git push <namn>\n"
-#: builtin/push.c:347
+#: builtin/push.c:373
msgid "--all and --tags are incompatible"
msgstr "--all och --tags är inkompatibla"
-#: builtin/push.c:348
+#: builtin/push.c:374
msgid "--all can't be combined with refspecs"
msgstr "--all kan inte kombineras med referensspecifikationer"
-#: builtin/push.c:353
+#: builtin/push.c:379
msgid "--mirror and --tags are incompatible"
msgstr "--mirror och --tags är inkompatibla"
-#: builtin/push.c:354
+#: builtin/push.c:380
msgid "--mirror can't be combined with refspecs"
msgstr "--mirror kan inte kombineras med referensspecifikationer"
-#: builtin/push.c:359
+#: builtin/push.c:385
msgid "--all and --mirror are incompatible"
msgstr "--all och --mirror är inkompatibla"
-#: builtin/push.c:419
+#: builtin/push.c:445
msgid "repository"
msgstr "arkiv"
-#: builtin/push.c:420
+#: builtin/push.c:446
msgid "push all refs"
msgstr "sänd alla referenser"
-#: builtin/push.c:421
+#: builtin/push.c:447
msgid "mirror all refs"
msgstr "spegla alla referenser"
-#: builtin/push.c:423
+#: builtin/push.c:449
msgid "delete refs"
msgstr "ta bort referenser"
-#: builtin/push.c:424
+#: builtin/push.c:450
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:427
+#: builtin/push.c:453
msgid "force updates"
msgstr "tvinga uppdateringar"
-#: builtin/push.c:428
+#: builtin/push.c:454
msgid "check"
msgstr "kontrollera"
-#: builtin/push.c:429
+#: builtin/push.c:455
msgid "control recursive pushing of submodules"
msgstr "styr rekursiv insändning av undermoduler"
-#: builtin/push.c:431
+#: builtin/push.c:457
msgid "use thin pack"
msgstr "använd tunna paket"
-#: builtin/push.c:432 builtin/push.c:433
+#: builtin/push.c:458 builtin/push.c:459
msgid "receive pack program"
msgstr "program för att ta emot paket"
-#: builtin/push.c:434
+#: builtin/push.c:460
msgid "set upstream for git pull/status"
msgstr "ställ in uppström för git pull/status"
-#: builtin/push.c:437
+#: builtin/push.c:463
msgid "prune locally removed refs"
msgstr "ta bort lokalt borttagna referenser"
-#: builtin/push.c:439
+#: builtin/push.c:465
msgid "bypass pre-push hook"
msgstr "förbigå pre-push-krok"
-#: builtin/push.c:448
+#: builtin/push.c:466
+msgid "push missing but relevant tags"
+msgstr "sänd in saknade men relevanta taggar"
+
+#: builtin/push.c:476
msgid "--delete is incompatible with --all, --mirror and --tags"
msgstr "--delete är imkompatibel med --all, --mirror och --tags"
-#: builtin/push.c:450
+#: builtin/push.c:478
msgid "--delete doesn't make sense without any refs"
msgstr "--delete kan inte användas utan referenser"
@@ -7211,70 +7776,80 @@ msgstr ""
"[-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
+#: builtin/read-tree.c:109
msgid "write resulting index to <file>"
msgstr "skriv resulterande index till <fil>"
-#: builtin/read-tree.c:111
+#: builtin/read-tree.c:112
msgid "only empty the index"
msgstr "töm bara indexet"
-#: builtin/read-tree.c:113
+#: builtin/read-tree.c:114
msgid "Merging"
msgstr "Sammanslagning"
-#: builtin/read-tree.c:115
+#: builtin/read-tree.c:116
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
+#: builtin/read-tree.c:118
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
+#: builtin/read-tree.c:120
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
+#: builtin/read-tree.c:122
msgid "same as -m, but discard unmerged entries"
msgstr "som -m, men kasta bort ej sammanslagna poster"
-#: builtin/read-tree.c:122
+#: builtin/read-tree.c:123
msgid "<subdirectory>/"
msgstr "<underkatalog>/"
-#: builtin/read-tree.c:123
+#: builtin/read-tree.c:124
msgid "read the tree into the index under <subdirectory>/"
msgstr "läs in trädet i indexet under <underkatalog>/"
-#: builtin/read-tree.c:126
+#: builtin/read-tree.c:127
msgid "update working tree with merge result"
msgstr "uppdatera arbetskatalogen med resultatet från sammanslagningen"
-#: builtin/read-tree.c:128
+#: builtin/read-tree.c:129
msgid "gitignore"
msgstr "gitignore"
-#: builtin/read-tree.c:129
+#: builtin/read-tree.c:130
msgid "allow explicitly ignored files to be overwritten"
msgstr "tillåt explicit ignorerade filer att skrivas över"
-#: builtin/read-tree.c:132
+#: builtin/read-tree.c:133
msgid "don't check the working tree after merging"
msgstr "kontrollera inte arbetskatalogen efter sammanslagning"
-#: builtin/read-tree.c:133
+#: builtin/read-tree.c:134
msgid "don't update the index or the work tree"
msgstr "uppdatera inte indexet eller arbetskatalogen"
-#: builtin/read-tree.c:135
+#: builtin/read-tree.c:136
msgid "skip applying sparse checkout filter"
msgstr "hoppa över att applicera filter för gles utcheckning"
-#: builtin/read-tree.c:137
+#: builtin/read-tree.c:138
msgid "debug unpack-trees"
msgstr "felsök unpack-trees"
+#: builtin/reflog.c:500
+#, c-format
+msgid "%s' for '%s' is not a valid timestamp"
+msgstr "\"%s\" för \"%s\" är inte en giltig tidsstämpel"
+
+#: builtin/reflog.c:616 builtin/reflog.c:621
+#, c-format
+msgid "'%s' is not a valid timestamp"
+msgstr "\"%s\" är inte en giltig tidsstämpel"
+
#: builtin/remote.c:11
msgid "git remote [-v | --verbose]"
msgstr "git remote [-v | --verbose]"
@@ -7848,96 +8423,96 @@ msgstr "Kunde inte hitta träder för HEAD."
msgid "Failed to find tree of %s."
msgstr "Kunde inte hitta träder för %s."
-#: builtin/reset.c:98
+#: builtin/reset.c:99
#, c-format
msgid "HEAD is now at %s"
msgstr "HEAD är nu på %s"
-#: builtin/reset.c:169
+#: builtin/reset.c:172
#, c-format
msgid "Cannot do a %s reset in the middle of a merge."
msgstr "Kan inte utföra en %s återställning mitt i en sammanslagning."
-#: builtin/reset.c:248
+#: builtin/reset.c:251
msgid "be quiet, only report errors"
msgstr "var tyst, rapportera endast fel"
-#: builtin/reset.c:250
+#: builtin/reset.c:253
msgid "reset HEAD and index"
msgstr "återställ HEAD och index"
-#: builtin/reset.c:251
+#: builtin/reset.c:254
msgid "reset only HEAD"
msgstr "återställ endast HEAD"
-#: builtin/reset.c:253 builtin/reset.c:255
+#: builtin/reset.c:256 builtin/reset.c:258
msgid "reset HEAD, index and working tree"
msgstr "återställ HEAD, index och arbetskatalog"
-#: builtin/reset.c:257
+#: builtin/reset.c:260
msgid "reset HEAD but keep local changes"
msgstr "återställ HEAD men behåll lokala ändringar"
-#: builtin/reset.c:275
+#: builtin/reset.c:278
#, c-format
msgid "Failed to resolve '%s' as a valid revision."
msgstr "Kunde inte slå upp \"%s\" som en giltig revision."
-#: builtin/reset.c:278 builtin/reset.c:286
+#: builtin/reset.c:281 builtin/reset.c:289
#, c-format
msgid "Could not parse object '%s'."
msgstr "Kan inte tolka objektet \"%s\""
-#: builtin/reset.c:283
+#: builtin/reset.c:286
#, c-format
msgid "Failed to resolve '%s' as a valid tree."
msgstr "Kunde inte slå upp \"%s\" som ett giltigt träd."
-#: builtin/reset.c:292
+#: builtin/reset.c:295
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr "--patch är inkompatibel med --{hard,mixed,soft}"
-#: builtin/reset.c:301
+#: builtin/reset.c:304
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:303
+#: builtin/reset.c:306
#, c-format
msgid "Cannot do %s reset with paths."
msgstr "Kan inte göra %s återställning med sökvägar."
-#: builtin/reset.c:313
+#: builtin/reset.c:316
#, 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:333
+#: builtin/reset.c:336
#, c-format
msgid "Could not reset index file to revision '%s'."
msgstr "Kunde inte återställa indexfilen till versionen \"%s\"."
-#: builtin/reset.c:339
+#: builtin/reset.c:342
msgid "Unstaged changes after reset:"
msgstr "Oköade ändringar efter återställning:"
-#: builtin/reset.c:344
+#: builtin/reset.c:347
msgid "Could not write new index file."
msgstr "Kunde inte skriva ny indexfil."
-#: builtin/rev-parse.c:339
+#: builtin/rev-parse.c:345
msgid "git rev-parse --parseopt [options] -- [<args>...]"
msgstr "git rev-parse --parseopt [options] -- [<argument>...]"
-#: builtin/rev-parse.c:344
+#: builtin/rev-parse.c:350
msgid "keep the `--` passed as an arg"
msgstr "behåll \"--\" sänt som argument"
-#: builtin/rev-parse.c:346
+#: builtin/rev-parse.c:352
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
+#: builtin/rev-parse.c:470
msgid ""
"git rev-parse --parseopt [options] -- [<args>...]\n"
" or: git rev-parse --sq-quote [<arg>...]\n"
@@ -7953,192 +8528,216 @@ msgstr ""
"varianten."
#: builtin/revert.c:22
-msgid "git revert [options] <commit-ish>"
-msgstr "git revert [flaggor] <incheckning-igt>"
+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>"
+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
+#: builtin/revert.c:71 builtin/revert.c:94
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr "%s: %s kan inte användas med %s"
-#: builtin/revert.c:103
+#: builtin/revert.c:105
msgid "end revert or cherry-pick sequence"
msgstr "avsluta revert- eller cherry-pick-sekvens"
-#: builtin/revert.c:104
+#: builtin/revert.c:106
msgid "resume revert or cherry-pick sequence"
msgstr "Ã¥teruppta revert- eller cherry-pick-sekvens"
-#: builtin/revert.c:105
+#: builtin/revert.c:107
msgid "cancel revert or cherry-pick sequence"
msgstr "avbryt revert- eller cherry-pick-sekvens"
-#: builtin/revert.c:106
+#: builtin/revert.c:108
msgid "don't automatically commit"
msgstr "checka inte in automatiskt"
-#: builtin/revert.c:107
+#: builtin/revert.c:109
msgid "edit the commit message"
msgstr "redigera incheckningsmeddelandet"
-#: builtin/revert.c:110
+#: builtin/revert.c:112
msgid "parent number"
msgstr "nummer på förälder"
-#: builtin/revert.c:112
+#: builtin/revert.c:114
msgid "merge strategy"
msgstr "sammanslagninsstrategi"
-#: builtin/revert.c:113
+#: builtin/revert.c:115
msgid "option"
msgstr "alternativ"
-#: builtin/revert.c:114
+#: builtin/revert.c:116
msgid "option for merge strategy"
msgstr "alternativ för sammanslagningsstrategi"
-#: builtin/revert.c:125
+#: builtin/revert.c:127
msgid "append commit name"
msgstr "lägg till incheckningsnamn"
-#: builtin/revert.c:126
+#: builtin/revert.c:128
msgid "allow fast-forward"
msgstr "tillåt snabbspolning"
-#: builtin/revert.c:127
+#: builtin/revert.c:129
msgid "preserve initially empty commits"
msgstr "behåll incheckningar som börjar som tomma"
-#: builtin/revert.c:128
+#: builtin/revert.c:130
msgid "allow commits with empty messages"
msgstr "tillåt incheckningar med tomt meddelande"
-#: builtin/revert.c:129
+#: builtin/revert.c:131
msgid "keep redundant, empty commits"
msgstr "behåll redundanta, tomma incheckningar"
-#: builtin/revert.c:133
+#: builtin/revert.c:135
msgid "program error"
msgstr "programfel"
-#: builtin/revert.c:223
+#: builtin/revert.c:225
msgid "revert failed"
msgstr "\"revert\" misslyckades"
-#: builtin/revert.c:238
+#: builtin/revert.c:240
msgid "cherry-pick failed"
msgstr "\"cherry-pick\" misslyckades"
-#: builtin/rm.c:15
+#: builtin/rm.c:16
msgid "git rm [options] [--] <file>..."
msgstr "git rm [flaggor] [--] <fil>..."
-#: builtin/rm.c:64 builtin/rm.c:186
-#, c-format
+#: builtin/rm.c:64
msgid ""
-"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"the following submodule (or one of its nested submodules)\n"
+"uses a .git directory:"
+msgid_plural ""
+"the following submodules (or one of its nested submodules)\n"
+"use a .git directory:"
+msgstr[0] ""
+"följande undermodul (eller en av dess nästlade undermoduler)\n"
+"använder en .git-katalog:"
+msgstr[1] ""
+"följande undermoduler (eller en av deras nästlade undermoduler)\n"
+"använder en .git-katalog:"
+
+#: builtin/rm.c:70
+msgid ""
+"\n"
"(use 'rm -rf' if you really want to remove it including all of its history)"
msgstr ""
-"undermodulen \"%s\" (eller en av dess undermoduler) använder en .git-"
-"katalog\n"
+"\n"
"(använd \"rm -rf\" om du verkligen vill ta bort den och all dess historik)"
-#: builtin/rm.c:174
-#, c-format
+#: builtin/rm.c:230
msgid ""
-"'%s' has staged content different from both the file and the HEAD\n"
+"the following file has staged content different from both the\n"
+"file and the HEAD:"
+msgid_plural ""
+"the following files have staged content different from both the\n"
+"file and the HEAD:"
+msgstr[0] ""
+"följande fil har köat innehåll som skiljer sig både från filen och HEAD:"
+msgstr[1] ""
+"följande filer har köat innehåll som skiljer sig både från filen och HEAD:"
+
+#: builtin/rm.c:235
+msgid ""
+"\n"
"(use -f to force removal)"
msgstr ""
-"\"%s\" har köat ändringar som skiljer sig både från filen och HEAD\n"
+"\n"
"(använd -f för att tvinga borttagning)"
-#: builtin/rm.c:180
-#, c-format
-msgid ""
-"'%s' has changes staged in the index\n"
-"(use --cached to keep the file, or -f to force removal)"
-msgstr ""
-"\"%s\" har köade ändringar i indexet\n"
-"(använd --cached för att behålla filen eller -f för att tvinga borttagning)"
+#: builtin/rm.c:239
+msgid "the following file has changes staged in the index:"
+msgid_plural "the following files have changes staged in the index:"
+msgstr[0] "följande fil har ändringar köade i indexet:"
+msgstr[1] "följande filer har ändringar köade i indexet:"
-#: builtin/rm.c:191
-#, c-format
+#: builtin/rm.c:243 builtin/rm.c:254
msgid ""
-"'%s' has local modifications\n"
+"\n"
"(use --cached to keep the file, or -f to force removal)"
msgstr ""
-"\"%s\" har lokala ändringar\n"
+"\n"
"(använd --cached för att behålla filen eller -f för att tvinga borttagning)"
-#: builtin/rm.c:207
+#: builtin/rm.c:251
+msgid "the following file has local modifications:"
+msgid_plural "the following files have local modifications:"
+msgstr[0] "följande fil har lokala ändringar:"
+msgstr[1] "följande filer har lokala ändringar:"
+
+#: builtin/rm.c:269
msgid "do not list removed files"
msgstr "lista inte borttagna filer"
-#: builtin/rm.c:208
+#: builtin/rm.c:270
msgid "only remove from the index"
msgstr "ta bara bort från indexet"
-#: builtin/rm.c:209
+#: builtin/rm.c:271
msgid "override the up-to-date check"
msgstr "överstyr àjour-testet"
-#: builtin/rm.c:210
+#: builtin/rm.c:272
msgid "allow recursive removal"
msgstr "tillåt rekursiv borttagning"
-#: builtin/rm.c:212
+#: builtin/rm.c:274
msgid "exit with a zero status even if nothing matched"
msgstr "avsluta med nollstatus även om inget träffades"
-#: builtin/rm.c:283
+#: builtin/rm.c:345
#, c-format
msgid "not removing '%s' recursively without -r"
msgstr "tar inte bort \"%s\" rekursivt utan -r"
-#: builtin/rm.c:322
+#: builtin/rm.c:384
#, c-format
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>... ]"
+msgid "git shortlog [<options>] [<revision range>] [[--] [<path>...]]"
+msgstr "git shortlog [<flaggor>] [<versionsintervall>] [[--] <sökväg>...]"
-#: builtin/shortlog.c:133
+#: builtin/shortlog.c:131
#, c-format
msgid "Missing author: %s"
msgstr "Författare saknas: %s"
-#: builtin/shortlog.c:229
+#: builtin/shortlog.c:228
msgid "sort output according to the number of commits per author"
msgstr "sortera utdata enligt antal incheckningar per författare"
-#: builtin/shortlog.c:231
+#: builtin/shortlog.c:230
msgid "Suppress commit descriptions, only provides commit count"
msgstr "Undertryck beskrivningar, visa bara antal incheckningar"
-#: builtin/shortlog.c:233
+#: builtin/shortlog.c:232
msgid "Show the email address of each author"
msgstr "Visa e-postadress för varje författare"
-#: builtin/shortlog.c:234
+#: builtin/shortlog.c:233
msgid "w[,i1[,i2]]"
msgstr "w[,i1[,i2]]"
-#: builtin/shortlog.c:235
+#: builtin/shortlog.c:234
msgid "Linewrap output"
msgstr "Radbryt utdata"
@@ -8158,47 +8757,47 @@ msgstr ""
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
+#: builtin/show-branch.c:650
msgid "show remote-tracking and local branches"
msgstr "visa fjärrspårande och lokala grenar"
-#: builtin/show-branch.c:653
+#: builtin/show-branch.c:652
msgid "show remote-tracking branches"
msgstr "visa fjärrspårande grenar"
-#: builtin/show-branch.c:655
+#: builtin/show-branch.c:654
msgid "color '*!+-' corresponding to the branch"
msgstr "färga \"*!+-\" enligt grenen"
-#: builtin/show-branch.c:657
+#: builtin/show-branch.c:656
msgid "show <n> more commits after the common ancestor"
msgstr "visa <n> ytterligare incheckningar efter gemensam anfader"
-#: builtin/show-branch.c:659
+#: builtin/show-branch.c:658
msgid "synonym to more=-1"
msgstr "synonym till more=-1"
-#: builtin/show-branch.c:660
+#: builtin/show-branch.c:659
msgid "suppress naming strings"
msgstr "undertyck namnsträngar"
-#: builtin/show-branch.c:662
+#: builtin/show-branch.c:661
msgid "include the current branch"
msgstr "inkludera aktuell gren"
-#: builtin/show-branch.c:664
+#: builtin/show-branch.c:663
msgid "name commits with their object names"
msgstr "namnge incheckningar med deras objektnamn"
-#: builtin/show-branch.c:666
+#: builtin/show-branch.c:665
msgid "show possible merge bases"
msgstr "visa möjliga sammanslaningsbaser"
-#: builtin/show-branch.c:668
+#: builtin/show-branch.c:667
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
+#: builtin/show-branch.c:669
msgid "show commits in topological order"
msgstr "visa incheckningar i topologisk ordning"
@@ -8211,14 +8810,14 @@ 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"
+msgid "topologically sort, maintaining date order where possible"
+msgstr "sortera topologiskt, behåll datumordning när möjligt"
-#: builtin/show-branch.c:678
+#: builtin/show-branch.c:679
msgid "<n>[,<base>]"
msgstr "<n>[,<bas>]"
-#: builtin/show-branch.c:679
+#: builtin/show-branch.c:680
msgid "show <n> most recent ref-log entries starting at base"
msgstr "visa <n> nyaste refloggposter med början på bas"
@@ -8234,35 +8833,35 @@ msgstr ""
msgid "git show-ref --exclude-existing[=pattern] < ref-list"
msgstr "git show-ref --exclude-existing[=mönster] < reflista"
-#: builtin/show-ref.c:165
+#: builtin/show-ref.c:168
msgid "only show tags (can be combined with heads)"
msgstr "visa endast taggar (kan kombineras med huvuden)"
-#: builtin/show-ref.c:166
+#: builtin/show-ref.c:169
msgid "only show heads (can be combined with tags)"
msgstr "visa endast huvuden (kan kombineras med taggar)"
-#: builtin/show-ref.c:167
+#: builtin/show-ref.c:170
msgid "stricter reference checking, requires exact ref path"
msgstr "striktare referenskontroll, kräver exakt referenssökväg"
-#: builtin/show-ref.c:170 builtin/show-ref.c:172
-msgid "show the HEAD reference"
-msgstr "visa HEAD-referensen"
+#: builtin/show-ref.c:173 builtin/show-ref.c:176
+msgid "show the HEAD reference, even if it would be filtered out"
+msgstr "visa HEAD-refrens, även när den skulle filtreras ut"
-#: builtin/show-ref.c:174
+#: builtin/show-ref.c:178
msgid "dereference tags into object IDs"
msgstr "avreferera taggar till objekt-id"
-#: builtin/show-ref.c:176
+#: builtin/show-ref.c:180
msgid "only show SHA1 hash using <n> digits"
msgstr "visa SHA1-hash endast med <n> siffror"
-#: builtin/show-ref.c:180
+#: builtin/show-ref.c:184
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:182
+#: builtin/show-ref.c:186
msgid "show refs from stdin that aren't in local repository"
msgstr "visa referenser från standard in som inte finns i lokalt arkiv"
@@ -8677,24 +9276,33 @@ msgstr "visa trädobjekt för underkatalogen <prefix>"
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."
+#: git.c:17
+msgid ""
+"'git help -a' and 'git help -g' lists available subcommands and some\n"
+"concept guides. See 'git help <command>' or 'git help <concept>'\n"
+"to read about a specific subcommand or concept."
msgstr ""
-"Se \"git help <kommando>\" för mer information om ett specifikt kommando."
+"\"git help -a\" och \"git help -g\" visar tillgängliga underkommandon och\n"
+"några konceptvägledningar. Se \"git help <kommando>\" eller \"git help\n"
+"<koncept>\" för att läsa mer om specifika underkommandon och koncept."
+
+#: parse-options.h:144
+msgid "expiry date"
+msgstr "giltig till"
-#: parse-options.h:156
+#: parse-options.h:159
msgid "no-op (backward compatibility)"
msgstr "ingen funktion (bakåtkompatibilitet)"
-#: parse-options.h:232
+#: parse-options.h:236
msgid "be more verbose"
msgstr "var mer pratsam"
-#: parse-options.h:234
+#: parse-options.h:238
msgid "be more quiet"
msgstr "var mer tyst"
-#: parse-options.h:240
+#: parse-options.h:244
msgid "use <n> digits to display SHA-1s"
msgstr "använd <n> siffror för att visa SHA-1:or"
@@ -8751,8 +9359,8 @@ msgid "Move or rename a file, a directory, or a symlink"
msgstr "Flytta eller byt namn på en fil, katalog eller symbolisk länk"
#: common-cmds.h:21
-msgid "Fetch from and merge with another repository or a local branch"
-msgstr "Hämta från och slå ihop med annat arkiv eller en lokal gren"
+msgid "Fetch from and integrate with another repository or a local branch"
+msgstr "Hämta från och integrera med annat arkiv eller en lokal gren"
#: common-cmds.h:22
msgid "Update remote refs along with associated objects"
@@ -8797,11 +9405,11 @@ msgstr ""
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"When you have resolved this problem, run \"$cmdline --continue\".\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"
+"När du har löst problemet kör du \"$cmdline --continue\".\n"
"Om du vill hoppa över patchen kör du istället \"$cmdline --skip\".\n"
"För att återställa originalgrenen och avbryta kör du \"$cmdline --abort\"."
@@ -8857,25 +9465,34 @@ 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:477
+#: git-am.sh:479
#, 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:482
+#: git-am.sh:484
msgid "Please make up your mind. --skip or --abort?"
msgstr "Bestäm dig. --skip eller --abort?"
-#: git-am.sh:509
+#: git-am.sh:520
+#, sh-format
+msgid ""
+"Stray $dotest directory found.\n"
+"Use \"git am --abort\" to remove it."
+msgstr ""
+"Kvarbliven katalog $dotest hittades.\n"
+"Använd \"git am --abort\" för att ta bort den."
+
+#: git-am.sh:528
msgid "Resolve operation not in progress, we are not resuming."
msgstr "Lösningsoperation pågår inte, vi återupptar inte."
-#: git-am.sh:575
+#: git-am.sh:594
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
msgstr "Smutsigt index: kan inte tillämpa patchar (smutsiga: $files)"
-#: git-am.sh:679
+#: git-am.sh:698
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -8886,32 +9503,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:706
+#: git-am.sh:725
msgid "Patch does not have a valid e-mail address."
msgstr "Patchen har inte någon giltig e-postadress."
-#: git-am.sh:753
+#: git-am.sh:772
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:757
+#: git-am.sh:776
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:764
+#: git-am.sh:783
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:800
+#: git-am.sh:819
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr "Tillämpar: $FIRSTLINE"
-#: git-am.sh:821
+#: git-am.sh:840
msgid ""
"No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
@@ -8921,7 +9538,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:829
+#: git-am.sh:848
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
@@ -8929,16 +9546,16 @@ 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:845
+#: git-am.sh:864
msgid "No changes -- Patch already applied."
msgstr "Inga ändringar -- Patchen har redan tillämpats."
-#: git-am.sh:855
+#: git-am.sh:874
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr "Patchen misslyckades vid $msgnum $FIRSTLINE"
-#: git-am.sh:858
+#: git-am.sh:877
#, sh-format
msgid ""
"The copy of the patch that failed is found in:\n"
@@ -8947,7 +9564,7 @@ msgstr ""
"En kopia av patchen som misslyckades finns i:\n"
" $dotest/patch"
-#: git-am.sh:876
+#: git-am.sh:895
msgid "applying to an empty history"
msgstr "tillämpar på en tom historik"
@@ -9047,16 +9664,16 @@ msgstr ""
"Du måste sedan ange åtminstone en bra och en dålig version.\n"
"(Du kan använda \"git bisect bad\" och \"git bisect good\" för detta.)"
-#: git-bisect.sh:347 git-bisect.sh:474
+#: git-bisect.sh:363 git-bisect.sh:490
msgid "We are not bisecting."
msgstr "Vi utför ingen bisect för tillfället."
-#: git-bisect.sh:354
+#: git-bisect.sh:370
#, sh-format
msgid "'$invalid' is not a valid commit"
msgstr "\"$invalid\" är inte en giltig incheckning"
-#: git-bisect.sh:363
+#: git-bisect.sh:379
#, sh-format
msgid ""
"Could not check out original HEAD '$branch'.\n"
@@ -9065,25 +9682,25 @@ msgstr ""
"Kunde inte checka ut original-HEAD \"$branch\".\n"
"Försök \"git bisect reset <incheckning>\"."
-#: git-bisect.sh:390
+#: git-bisect.sh:406
msgid "No logfile given"
msgstr "Ingen loggfil angiven"
-#: git-bisect.sh:391
+#: git-bisect.sh:407
#, sh-format
msgid "cannot read $file for replaying"
msgstr "kan inte läsa $file för uppspelning"
-#: git-bisect.sh:408
+#: git-bisect.sh:424
msgid "?? what are you talking about?"
msgstr "?? vad menar du?"
-#: git-bisect.sh:420
+#: git-bisect.sh:436
#, sh-format
msgid "running $command"
msgstr "kör $command"
-#: git-bisect.sh:427
+#: git-bisect.sh:443
#, sh-format
msgid ""
"bisect run failed:\n"
@@ -9092,11 +9709,11 @@ msgstr ""
"\"bisect\"-körningen misslyckades:\n"
"felkod $res från \"$command\" är < 0 eller >= 128"
-#: git-bisect.sh:453
+#: git-bisect.sh:469
msgid "bisect run cannot continue any more"
msgstr "\"bisect\"-körningen kan inte fortsätta längre"
-#: git-bisect.sh:459
+#: git-bisect.sh:475
#, sh-format
msgid ""
"bisect run failed:\n"
@@ -9105,7 +9722,7 @@ msgstr ""
"\"bisect\"-körningen misslyckades:\n"
"\"bisect_state $state\" avslutades med felkoden $res"
-#: git-bisect.sh:466
+#: git-bisect.sh:482
msgid "bisect run success"
msgstr "\"bisect\"-körningen lyckades"
@@ -9123,7 +9740,7 @@ msgstr ""
msgid "Pull is not possible because you have unmerged files."
msgstr "Du kan inte göra en \"pull\" då du har ändringar som inte checkats in."
-#: git-pull.sh:197
+#: git-pull.sh:203
msgid "updating an unborn branch with changes added to the index"
msgstr "uppdaterar en ofödd gren med ändringar som lagts till i indexet"
@@ -9131,7 +9748,7 @@ msgstr "uppdaterar en ofödd gren med ändringar som lagts till i indexet"
#. The working tree and the index file is still based on the
#. $orig_head commit, but we are merging into $curr_head.
#. First update the working tree to match $curr_head.
-#: git-pull.sh:229
+#: git-pull.sh:235
#, sh-format
msgid ""
"Warning: fetch updated the current branch head.\n"
@@ -9142,15 +9759,15 @@ msgstr ""
"Varning: snabbspolar din arbetskatalog från\n"
"Varning: incheckningen $orig_head."
-#: git-pull.sh:254
+#: git-pull.sh:260
msgid "Cannot merge multiple branches into empty head"
msgstr "Kan inte slå ihop flera grenar i ett tomt huvud."
-#: git-pull.sh:258
+#: git-pull.sh:264
msgid "Cannot rebase onto multiple branches"
msgstr "Kan inte utföra en \"rebase\" ovanpå flera grenar"
-#: git-rebase.sh:53
+#: git-rebase.sh:54
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"
@@ -9161,31 +9778,50 @@ msgstr ""
"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:156
+msgid "Applied autostash."
+msgstr "Tillämpade autostash."
+
+#: git-rebase.sh:159
+#, sh-format
+msgid "Cannot store $stash_sha1"
+msgstr "Kan inte spara $stash_sha1"
+
#: git-rebase.sh:160
+msgid ""
+"Applying autostash resulted in conflicts.\n"
+"Your changes are safe in the stash.\n"
+"You can run \"git stash pop\" or \"git stash drop\" at any time.\n"
+msgstr ""
+"Tillämpning av autostash gav konflikter.\n"
+"Dina ändringar är säkra i stashen.\n"
+"Du kan när som helst använda \"git stash pop\" eller \"git stash drop\".\n"
+
+#: git-rebase.sh:190
msgid "The pre-rebase hook refused to rebase."
msgstr "Kroken pre-rebase vägrade ombaseringen."
-#: git-rebase.sh:165
+#: git-rebase.sh:195
msgid "It looks like git-am is in progress. Cannot rebase."
msgstr "Det verkar som en git-am körs. Kan inte ombasera."
-#: git-rebase.sh:296
+#: git-rebase.sh:329
msgid "The --exec option must be used with the --interactive option"
msgstr "Flaggan --exec måste användas tillsammans med flaggan --interactive"
-#: git-rebase.sh:301
+#: git-rebase.sh:334
msgid "No rebase in progress?"
msgstr "Ingen ombasering pågår?"
-#: git-rebase.sh:312
+#: git-rebase.sh:345
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr "Åtgärden --edit-todo kan endast användas under interaktiv ombasering."
-#: git-rebase.sh:319
+#: git-rebase.sh:352
msgid "Cannot read HEAD"
msgstr "Kan inte läsa HEAD"
-#: git-rebase.sh:322
+#: git-rebase.sh:355
msgid ""
"You must edit all merge conflicts and then\n"
"mark them as resolved using git add"
@@ -9193,12 +9829,12 @@ msgstr ""
"Du måste redigera alla sammanslagningskonflikter och\n"
"därefter markera dem som lösta med git add"
-#: git-rebase.sh:340
+#: git-rebase.sh:373
#, sh-format
msgid "Could not move back to $head_name"
msgstr "Kunde inte flytta tillbaka till $head_name"
-#: git-rebase.sh:359
+#: git-rebase.sh:392
#, sh-format
msgid ""
"It seems that there is already a $state_dir_base directory, and\n"
@@ -9219,57 +9855,66 @@ msgstr ""
"och kör programmet igen. Jag avslutar ifall du fortfarande har\n"
"något av värde där."
-#: git-rebase.sh:404
+#: git-rebase.sh:437
#, sh-format
msgid "invalid upstream $upstream_name"
msgstr "ogiltig uppström $upstream_name"
-#: git-rebase.sh:428
+#: git-rebase.sh:461
#, sh-format
msgid "$onto_name: there are more than one merge bases"
msgstr "$onto_name: mer än en sammanslagningsbas finns"
-#: git-rebase.sh:431 git-rebase.sh:435
+#: git-rebase.sh:464 git-rebase.sh:468
#, sh-format
msgid "$onto_name: there is no merge base"
msgstr "$onto_name: ingen sammanslagningsbas finns"
-#: git-rebase.sh:440
+#: git-rebase.sh:473
#, sh-format
msgid "Does not point to a valid commit: $onto_name"
msgstr "Peka på en giltig incheckning: $onto_name"
-#: git-rebase.sh:463
+#: git-rebase.sh:496
#, sh-format
msgid "fatal: no such branch: $branch_name"
msgstr "ödesdigert: ingen sådan gren: $branch_name"
-#: git-rebase.sh:483
+#: git-rebase.sh:519
+msgid "Cannot autostash"
+msgstr "Kan inte utföra \"autostash\""
+
+#: git-rebase.sh:524
+#, sh-format
+msgid "Created autostash: $stash_abbrev"
+msgstr "Skapade autostash: $stash_abbrev"
+
+#: git-rebase.sh:528
msgid "Please commit or stash them."
msgstr "Checka in eller använd \"stash\" på dem."
-#: git-rebase.sh:501
+#: git-rebase.sh:548
#, sh-format
msgid "Current branch $branch_name is up to date."
msgstr "Aktuell gren $branch_name är à jour."
-#: git-rebase.sh:504
+#: git-rebase.sh:552
#, sh-format
msgid "Current branch $branch_name is up to date, rebase forced."
msgstr "Aktuell gren $branch_name är à jour, ombasering framtvingad."
-#: git-rebase.sh:515
+#: git-rebase.sh:563
#, sh-format
msgid "Changes from $mb to $onto:"
msgstr "Ändringar från $mb till $onto:"
#. Detach HEAD and reset the tree
-#: git-rebase.sh:524
+#: git-rebase.sh:572
msgid "First, rewinding head to replay your work on top of it..."
msgstr ""
"Först, spolar tillbaka huvudet för att spela av ditt arbete ovanpå det..."
-#: git-rebase.sh:532
+#: git-rebase.sh:582
#, sh-format
msgid "Fast-forwarded $branch_name to $onto_name."
msgstr "Snabbspolade $branch_name till $onto_name."
@@ -9302,6 +9947,11 @@ msgstr "Kan inte ta bort temporärt index (kan inte inträffa)"
msgid "Cannot record working tree state"
msgstr "Kan inte registrera tillstånd för arbetskatalog"
+#: git-stash.sh:190
+#, sh-format
+msgid "Cannot update $ref_stash with $w_commit"
+msgstr "Kan inte uppdatera $ref_stash med $w_commit"
+
#. TRANSLATORS: $option is an invalid option, like
#. `--blah-blah'. The 7 spaces at the beginning of the
#. second line correspond to "error: ". So you should line
@@ -9312,7 +9962,7 @@ msgstr "Kan inte registrera tillstånd för arbetskatalog"
#. $ git stash save --blah-blah 2>&1 | head -n 2
#. error: unknown option for 'stash save': --blah-blah
#. To provide a message, use git stash save -- '--blah-blah'
-#: git-stash.sh:202
+#: git-stash.sh:241
#, sh-format
msgid ""
"error: unknown option for 'stash save': $option\n"
@@ -9321,120 +9971,139 @@ msgstr ""
"fel: felaktig flagga för \"stash save\": $option\n"
" För att ange ett meddelande, använd git stash save -- \"$option\""
-#: git-stash.sh:223
+#: git-stash.sh:262
msgid "No local changes to save"
msgstr "Inga lokala ändringar att spara"
-#: git-stash.sh:227
+#: git-stash.sh:268
+msgid ""
+"The following untracked files would NOT be saved but need to be removed by "
+"stash save:"
+msgstr ""
+"Följande ospårade ändringar skulle INTE sparas utan måste tas bort med "
+"\"stash save\":"
+
+#: git-stash.sh:270
+msgid ""
+"Aborting. Consider using either the --force or --include-untracked option."
+msgstr ""
+"Avbryter. Överväg att använda antingen flaggan --force eller --include-"
+"untracked."
+
+#: git-stash.sh:274
msgid "Cannot initialize stash"
msgstr "Kan inte initiera \"stash\""
-#: git-stash.sh:235
+#: git-stash.sh:278
msgid "Cannot save the current status"
msgstr "Kan inte spara aktuell status"
-#: git-stash.sh:253
+#: git-stash.sh:296
msgid "Cannot remove worktree changes"
msgstr "Kan inte ta bort ändringar i arbetskatalogen"
-#: git-stash.sh:352
+#: git-stash.sh:395
msgid "No stash found."
msgstr "Ingen \"stash\" hittades."
-#: git-stash.sh:359
+#: git-stash.sh:402
#, sh-format
msgid "Too many revisions specified: $REV"
msgstr "För många revisioner angivna: $REV"
-#: git-stash.sh:365
+#: git-stash.sh:408
#, sh-format
msgid "$reference is not valid reference"
msgstr "$reference är inte en giltig referens."
-#: git-stash.sh:393
+#: git-stash.sh:436
#, sh-format
msgid "'$args' is not a stash-like commit"
msgstr "\"$args\" är inte en \"stash\"-liknande incheckning"
-#: git-stash.sh:404
+#: git-stash.sh:447
#, sh-format
msgid "'$args' is not a stash reference"
msgstr "\"$args\" är inte en \"stash\"-referens"
-#: git-stash.sh:412
+#: git-stash.sh:455
msgid "unable to refresh index"
msgstr "kan inte uppdatera indexet"
-#: git-stash.sh:416
+#: git-stash.sh:459
msgid "Cannot apply a stash in the middle of a merge"
msgstr "Kan inte tillämpa en \"stash\" mitt i en sammanslagning"
-#: git-stash.sh:424
+#: git-stash.sh:467
msgid "Conflicts in index. Try without --index."
msgstr "Konflikter i indexet. Testa utan --index."
-#: git-stash.sh:426
+#: git-stash.sh:469
msgid "Could not save index tree"
msgstr "Kunde inte spara indexträd"
-#: git-stash.sh:460
+#: git-stash.sh:503
msgid "Cannot unstage modified files"
msgstr "Kan inte ta bort ändrade filer ur kön"
-#: git-stash.sh:475
+#: git-stash.sh:518
msgid "Index was not unstashed."
msgstr "Indexet har inte tagits ur kön."
-#: git-stash.sh:492
+#: git-stash.sh:535
#, sh-format
msgid "Dropped ${REV} ($s)"
msgstr "Kastade ${REV} ($s)"
-#: git-stash.sh:493
+#: git-stash.sh:536
#, sh-format
msgid "${REV}: Could not drop stash entry"
msgstr "${REV}: Kunde inte kasta \"stash\"-post"
-#: git-stash.sh:500
+#: git-stash.sh:543
msgid "No branch name specified"
msgstr "Inget grennamn angavs"
-#: git-stash.sh:571
+#: git-stash.sh:615
msgid "(To restore them type \"git stash apply\")"
msgstr "(För att återställa dem, skriv \"git stash apply\")"
-#: git-submodule.sh:90
+#: git-submodule.sh:95
#, 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:195
+#: git-submodule.sh:237
#, 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:238
+#: git-submodule.sh:281
#, 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:250
+#: git-submodule.sh:293
#, 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"
+msgstr "Gitkatalog \"$a\" ingår i undermodulsökvägen \"$b\" eller omvänt"
+
+#: git-submodule.sh:403
+msgid "Relative path can only be used from the toplevel of the working tree"
+msgstr "Relativ sökväg kan enfast användas från arbetskatalogens toppnivå"
-#: git-submodule.sh:343
+#: git-submodule.sh:413
#, 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:360
+#: git-submodule.sh:430
#, sh-format
msgid "'$sm_path' already exists in the index"
msgstr "\"$sm_path\" finns redan i indexet"
-#: git-submodule.sh:364
+#: git-submodule.sh:434
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
@@ -9445,22 +10114,22 @@ msgstr ""
"$sm_path\n"
"Använd -f om du verkligen vill lägga till den"
-#: git-submodule.sh:382
+#: git-submodule.sh:452
#, 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:384
+#: git-submodule.sh:454
#, 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:392
+#: git-submodule.sh:462
#, sh-format
msgid "A git directory for '$sm_name' is found locally with remote(s):"
msgstr "En git-katalog för \"$sm_name\" hittades lokalt med fjärr(ar):"
-#: git-submodule.sh:394
+#: git-submodule.sh:464
#, sh-format
msgid ""
"If you want to reuse this local git directory instead of cloning again from"
@@ -9468,14 +10137,14 @@ msgstr ""
"För att återanvända den lokala git-katalogen istället för att på nytt klona "
"från"
-#: git-submodule.sh:396
+#: git-submodule.sh:466
#, sh-format
msgid ""
"use the '--force' option. If the local git directory is not the correct repo"
msgstr ""
"använd flaggan \"--force\". Om den lokala git-katalogen inte är riktigt arkiv"
-#: git-submodule.sh:397
+#: git-submodule.sh:467
#, sh-format
msgid ""
"or you are unsure what this means choose another name with the '--name' "
@@ -9484,153 +10153,299 @@ msgstr ""
"eller om du är osäker på vad det innebär, välj nytt namn med flaggan \"--name"
"\"."
-#: git-submodule.sh:399
+#: git-submodule.sh:469
#, sh-format
msgid "Reactivating local git directory for submodule '$sm_name'."
msgstr "Aktiverar lokal git-katalog för undermodulen \"$sm_name\" på nytt."
-#: git-submodule.sh:411
+#: git-submodule.sh:481
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
msgstr "Kan inte checka ut undermodulen \"$sm_path\""
-#: git-submodule.sh:416
+#: git-submodule.sh:486
#, sh-format
msgid "Failed to add submodule '$sm_path'"
msgstr "Misslyckades lägga till undermodulen \"$sm_path\""
-#: git-submodule.sh:425
+#: git-submodule.sh:495
#, sh-format
msgid "Failed to register submodule '$sm_path'"
msgstr "Misslyckades registrera undermodulen \"$sm_path\""
-#: git-submodule.sh:468
+#: git-submodule.sh:539
+#, sh-format
+msgid "Entering '$prefix$displaypath'"
+msgstr "GÃ¥r in i \"$prefix$displaypath\""
+
+#: git-submodule.sh:554
+#, sh-format
+msgid "Stopping at '$prefix$displaypath'; script returned non-zero status."
+msgstr ""
+"Stoppar på \"$prefix$displaypath\"; skriptet returnerade en status skild "
+"från noll."
+
+#: git-submodule.sh:600
#, sh-format
-msgid "Entering '$prefix$sm_path'"
-msgstr "GÃ¥r in i \"$prefix$sm_path\""
+msgid "No url found for submodule path '$displaypath' in .gitmodules"
+msgstr ""
+"Hittade ingen url för undermodulsökvägen \"$displaypath\" i .gitmodules"
+
+#: git-submodule.sh:609
+#, sh-format
+msgid "Failed to register url for submodule path '$displaypath'"
+msgstr "Misslyckades registrera url för undermodulsökväg \"$displaypath\""
+
+#: git-submodule.sh:611
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$displaypath'"
+msgstr ""
+"Undermodulen \"$name\" ($url) registrerad för sökvägen \"$displaypath\""
+
+#: git-submodule.sh:619
+#, sh-format
+msgid "Failed to register update mode for submodule path '$displaypath'"
+msgstr ""
+"Misslyckades registrera uppdateringsläge för undermodulsökväg \"$displaypath"
+"\""
+
+#: git-submodule.sh:656
+#, sh-format
+msgid "Use '.' if you really want to deinitialize all submodules"
+msgstr "Använd \".\" om du verkligen vill avinitiera alla undermoduler"
-#: git-submodule.sh:482
+#: git-submodule.sh:673
#, sh-format
-msgid "Stopping at '$sm_path'; script returned non-zero status."
+msgid "Submodule work tree '$displaypath' contains a .git directory"
msgstr ""
-"Stoppar på \"$sm_path\"; skriptet returnerade en status skild från noll."
+"Undermodulens arbetskatalog \"$displaypath\" innehåller katalogen \".git\""
-#: git-submodule.sh:526
+#: git-submodule.sh:674
#, 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"
+msgid ""
+"(use 'rm -rf' if you really want to remove it including all of its history)"
+msgstr ""
+"(använd \"rm -rf\" om du verkligen vill ta bort den och all dess historik)"
-#: git-submodule.sh:535
+#: git-submodule.sh:680
#, sh-format
-msgid "Failed to register url for submodule path '$sm_path'"
-msgstr "Misslyckades registrera url för underkatalogsökväg \"$sm_path\""
+msgid ""
+"Submodule work tree '$displaypath' contains local modifications; use '-f' to "
+"discard them"
+msgstr ""
+"Undermodulens arbetskatalog \"$displaypath\" har lokala ändringar; \"-f\" "
+"kastar bort dem"
-#: git-submodule.sh:537
+#: git-submodule.sh:683
#, sh-format
-msgid "Submodule '$name' ($url) registered for path '$sm_path'"
-msgstr "Undermodulen \"$name\" ($url) registrerad för sökvägen \"$sm_path\""
+msgid "Cleared directory '$displaypath'"
+msgstr "Rensade katalogen \"$displaypath\""
-#: git-submodule.sh:545
+#: git-submodule.sh:684
#, sh-format
-msgid "Failed to register update mode for submodule path '$sm_path'"
+msgid "Could not remove submodule work tree '$displaypath'"
+msgstr "Kunde inte ta bort undermodulens arbetskatalog \"$displaypath\""
+
+#: git-submodule.sh:687
+#, sh-format
+msgid "Could not create empty submodule directory '$displaypath'"
+msgstr "Kunde inte skapa tom undermodulskatalog \"$displaypath\""
+
+#: git-submodule.sh:696
+#, sh-format
+msgid "Submodule '$name' ($url) unregistered for path '$displaypath'"
msgstr ""
-"Misslyckades registrera uppdateringsläge för undermodulsökväg \"$sm_path\""
+"Undermodulen \"$name\" ($url) avregistrerad för sökvägen \"$displaypath\""
-#: git-submodule.sh:649
+#: git-submodule.sh:811
#, sh-format
msgid ""
-"Submodule path '$sm_path' not initialized\n"
+"Submodule path '$displaypath' not initialized\n"
"Maybe you want to use 'update --init'?"
msgstr ""
-"Undermodulen \"$sm_path\" har inte initierats\n"
+"Undermodulen \"$displaypath\" har inte initierats\n"
"Kanske du vill köra \"update --init\"?"
-#: git-submodule.sh:662
+#: git-submodule.sh:824
#, 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\""
+msgid "Unable to find current revision in submodule path '$displaypath'"
+msgstr "Kan inte hitta aktuell revision i undermodulsökvägen \"$displaypath\""
-#: git-submodule.sh:671 git-submodule.sh:695
+#: git-submodule.sh:833
#, 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:709
+#: git-submodule.sh:857
#, sh-format
-msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
-msgstr "Kan inte ombasera \"$sha1\" i undermodulsökväg \"$sm_path\""
+msgid "Unable to fetch in submodule path '$displaypath'"
+msgstr "Kan inte hämta i undermodulsökväg \"$displaypath\""
-#: git-submodule.sh:710
+#: git-submodule.sh:871
#, sh-format
-msgid "Submodule path '$sm_path': rebased into '$sha1'"
-msgstr "Undermodulsökvägen \"$sm_path\": ombaserade in i \"$sha1\""
+msgid "Unable to rebase '$sha1' in submodule path '$displaypath'"
+msgstr "Kan inte ombasera \"$sha1\" i undermodulsökvägen \"$displaypath\""
-#: git-submodule.sh:715
+#: git-submodule.sh:872
#, sh-format
-msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
-msgstr "Kan inte slå ihop \"$sha1\" i undermodulsökvägen \"$sm_path\""
+msgid "Submodule path '$displaypath': rebased into '$sha1'"
+msgstr "Undermodulsökvägen \"$displaypath\": ombaserade in i \"$sha1\""
-#: git-submodule.sh:716
+#: git-submodule.sh:877
#, sh-format
-msgid "Submodule path '$sm_path': merged in '$sha1'"
-msgstr "Undermodulsökvägen \"$sm_path\": sammanslagen i \"$sha1\""
+msgid "Unable to merge '$sha1' in submodule path '$displaypath'"
+msgstr "Kan inte slå ihop \"$sha1\" i undermodulsökvägen \"$displaypath\""
-#: git-submodule.sh:721
+#: git-submodule.sh:878
#, sh-format
-msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
-msgstr "Kan inte checka ut \"$sha1\" i undermodulsökvägen \"$sm_path\""
+msgid "Submodule path '$displaypath': merged in '$sha1'"
+msgstr "Undermodulsökvägen \"$displaypath\": sammanslagen i \"$sha1\""
-#: git-submodule.sh:722
+#: git-submodule.sh:883
#, sh-format
-msgid "Submodule path '$sm_path': checked out '$sha1'"
-msgstr "Undermodulsökvägen \"$sm_path\": checkade ut \"$sha1\""
+msgid ""
+"Execution of '$command $sha1' failed in submodule path '$prefix$sm_path'"
+msgstr ""
+"Misslyckades köra \"$command $sha1\" i undermodulsökvägen \"$prefix$sm_path\""
-#: git-submodule.sh:744 git-submodule.sh:1066
+#: git-submodule.sh:884
#, sh-format
-msgid "Failed to recurse into submodule path '$sm_path'"
-msgstr "Misslyckades rekursera in i undermodulsökvägen \"$sm_path\""
+msgid "Submodule path '$prefix$sm_path': '$command $sha1'"
+msgstr "Undermodulsökvägen \"$prefix$sm_path\": \"$command $sha1\""
-#: git-submodule.sh:852
+#: git-submodule.sh:889
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$displaypath'"
+msgstr "Kan inte checka ut \"$sha1\" i undermodulsökvägen \"$displaypath\""
+
+#: git-submodule.sh:890
+#, sh-format
+msgid "Submodule path '$displaypath': checked out '$sha1'"
+msgstr "Undermodulsökvägen \"$displaypath\": checkade ut \"$sha1\""
+
+#: git-submodule.sh:917
+#, sh-format
+msgid "Failed to recurse into submodule path '$displaypath'"
+msgstr "Misslyckades rekursera in i undermodulsökvägen \"$displaypath\""
+
+#: git-submodule.sh:1025
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:892
+#: git-submodule.sh:1066
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr "oväntat läge $mod_dst"
-#: git-submodule.sh:910
+#: git-submodule.sh:1086
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_src"
-msgstr " Varning: $name innehåller inte incheckning $sha1_src"
+msgid " Warn: $display_name doesn't contain commit $sha1_src"
+msgstr " Varning: $display_name innehåller inte incheckningen $sha1_src"
-#: git-submodule.sh:913
+#: git-submodule.sh:1089
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_dst"
-msgstr " Varning: $name innehåller inte incheckning $sha1_dst"
+msgid " Warn: $display_name doesn't contain commit $sha1_dst"
+msgstr " Varning: $display_name innehåller inte incheckningen $sha1_dst"
-#: git-submodule.sh:916
+#: git-submodule.sh:1092
#, 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"
+msgid " Warn: $display_name doesn't contain commits $sha1_src and $sha1_dst"
+msgstr ""
+" Varning: $display_name innehåller inte incheckningarna $sha1_src och "
+"$sha1_dst"
-#: git-submodule.sh:941
+#: git-submodule.sh:1117
msgid "blob"
msgstr "blob"
-#: git-submodule.sh:979
+#: git-submodule.sh:1155
msgid "Submodules changed but not updated:"
msgstr "Undermoduler ändrade men inte uppdaterade:"
-#: git-submodule.sh:981
+#: git-submodule.sh:1157
msgid "Submodule changes to be committed:"
msgstr "Undermodulers ändringar att checka in:"
-#: git-submodule.sh:1129
+#: git-submodule.sh:1242
#, sh-format
-msgid "Synchronizing submodule url for '$prefix$sm_path'"
-msgstr "Synkroniserar undermodul-url för \"$prefix$sm_path\""
+msgid "Failed to recurse into submodule path '$sm_path'"
+msgstr "Misslyckades rekursera in i undermodulsökvägen \"$sm_path\""
+
+#: git-submodule.sh:1306
+#, sh-format
+msgid "Synchronizing submodule url for '$displaypath'"
+msgstr "Synkroniserar undermodul-url för \"$displaypath\""
+
+#~ msgid " (fix conflicts and then run \"git am --resolved\")"
+#~ msgstr " (rätta konflikter och kör sedan \"git am --resolved\")"
+
+#~ msgid " (all conflicts fixed: run \"git commit\")"
+#~ msgstr " (alla konflikter har rättats: kör \"git commit\")"
+
+#~ msgid "more than %d trees given: '%s'"
+#~ msgstr "mer än %d träd angavs: \"%s\""
+
+#~ msgid "You cannot combine --no-ff with --ff-only."
+#~ msgstr "Du kan inte kombinera --no-ff med --ff-only."
+
+#~ msgid ""
+#~ "submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+#~ "(use 'rm -rf' if you really want to remove it including all of its "
+#~ "history)"
+#~ msgstr ""
+#~ "undermodulen \"%s\" (eller en av dess undermoduler) använder en .git-"
+#~ "katalog\n"
+#~ "(använd \"rm -rf\" om du verkligen vill ta bort den och all dess historik)"
+
+#~ msgid ""
+#~ "'%s' has changes staged in the index\n"
+#~ "(use --cached to keep the file, or -f to force removal)"
+#~ msgstr ""
+#~ "\"%s\" har köade ändringar i indexet\n"
+#~ "(använd --cached för att behålla filen eller -f för att tvinga "
+#~ "borttagning)"
+
+#~ msgid "show commits where no parent comes before its children"
+#~ msgstr "visa incheckningar där ingen förälder kommer före dess barn"
+
+#~ msgid "show the HEAD reference"
+#~ msgstr "visa HEAD-referensen"
+
+#~ msgid "Unable to fetch in submodule path '$prefix$sm_path'"
+#~ msgstr "Kan inte hämta i undermodulsökväg \"$prefix$sm_path\""
+
+#~ msgid "Failed to recurse into submodule path '$prefix$sm_path'"
+#~ msgstr "Misslyckades rekursera in i undermodulsökvägen \"$prefix$sm_path\""
+
+#~ msgid "It took %.2f seconds to enumerate untracked files. 'status -uno'"
+#~ msgstr "Det tog %.2f sekunder att räkna ospårade filer. \"status -uno\""
+
+#~ msgid "may speed it up, but you have to be careful not to forget to add"
+#~ msgstr "kanske gör det snabbare, men du måste vara försiktig så att du"
+
+#~ msgid "new files yourself (see 'git help status')."
+#~ msgstr "inte glömmer lägga till filer själv (se \"git help status\")"
+
+#~ msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+#~ msgstr ""
+#~ "git shortlog [-n] [-s] [-e] [-w] [rev-flaggor] [--] [<incheckning-id>... ]"
+
+#~ 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."
+
+#~ msgid "use any ref in .git/refs"
+#~ msgstr "använd alla referenser i .git/refs"
+
+#~ msgid "use any tag in .git/refs/tags"
+#~ msgstr "använd alla taggar i .git/refs/tags"
+
+#~ msgid "bad object %s"
+#~ msgstr "felaktigt objekt %s"
+
+#~ msgid "bogus committer info %s"
+#~ msgstr "felaktig incheckarinformation %s"
#~ msgid "can't fdopen 'show' output fd"
#~ msgstr "kunde inte öppna (fdopen) \"show\"-utdata-filhandtag"
@@ -9739,9 +10554,6 @@ msgstr "Synkroniserar undermodul-url för \"$prefix$sm_path\""
#~ msgid "# Changed but not updated:"
#~ msgstr "# Ändrade men inte uppdaterade:"
-#~ msgid "A branch named '%s' already exists."
-#~ msgstr "Det finns redan en gren som heter \"%s\""
-
#~ msgid "path '%s' does not have all 3 versions"
#~ msgstr "sökvägen \"%s\" har inte alla 3 versionerna"
@@ -9765,73 +10577,3 @@ msgstr "Synkroniserar undermodul-url för \"$prefix$sm_path\""
#~ msgid "Failed to write current notes tree to database"
#~ msgstr "Kunde inte skriva aktuellt anteckningsträd till 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 "add"
-#~ msgstr "add"
-
-#~ msgid "copy"
-#~ msgstr "copy"
-
-#~ msgid "show"
-#~ msgstr "show"
-
-#~ msgid "remove"
-#~ msgstr "remove"
-
-#~ msgid "prune"
-#~ msgstr "prune"
-
-#~ msgid "The current branch %s is not tracking anything."
-#~ msgstr "Den aktuella grenen %s spårar ingenting."
-
-#~ msgid "No destination configured to push to."
-#~ msgstr "Har inte ställt in någon destination att sända till."
-
-#~ msgid "Reflog action message too long: %.*s..."
-#~ msgstr "Reflog-händelsemeddelande för långt: %.*s..."
-
-#~ msgid "Could not read commit message of %s"
-#~ msgstr "Kunde inte läsa incheckningsmeddelandet för %s"
-
-#~ msgid "Could not extract author email from %s"
-#~ msgstr "Kunde inte hämta författarens e-postadress från %s"
-
-#~ msgid "Could not extract author time from %s"
-#~ msgstr "Kunde inte hämta författartid från %s"
-
-#~ msgid "No author information found in %s"
-#~ msgstr "Hittade ingen författarinformation i %s"
-
-#~ msgid "cherry-pick --ff cannot be used with --signoff"
-#~ msgstr "cherry-pick --ff kan inte användas med --signoff"
-
-#~ msgid "cherry-pick --ff cannot be used with --no-commit"
-#~ msgstr "cherry-pick --ff kan inte användas med --no-commit"
-
-#~ msgid "cherry-pick --ff cannot be used with -x"
-#~ msgstr "cherry-pick --ff kan inte användas med -x"
-
-#~ msgid "cherry-pick --ff cannot be used with --edit"
-#~ msgstr "cherry-pick --ff kan inte användas med --edit"
-
-#~ msgid "committer info too long."
-#~ msgstr "incheckarinformation för lång."
-
-#~ msgid ""
-#~ "\n"
-#~ "#\n"
-#~ "# Write a tag message\n"
-#~ "#\n"
-#~ msgstr ""
-#~ "\n"
-#~ "#\n"
-#~ "# Skriv ett taggmeddelande\n"
-#~ "#\n"
-
-#~ msgid "signing key value too long (%.10s...)"
-#~ msgstr "signeringsnyckelvärdet för långt (%.10s...)"
diff --git a/po/vi.po b/po/vi.po
index 7d9d05d..dd2d2a7 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -1,15 +1,14 @@
# Vietnamese translation for GIT-CORE.
-# Copyright (C) 2012-2013 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-2013.
# Nguyá»…n Thái Ngá»c Duy <pclouds@gmail.com>, 2012.
#
msgid ""
msgstr ""
-"Project-Id-Version: git-v1.8.2-rc2-4-g77995\n"
+"Project-Id-Version: git-v1.8.4-rc1-22-gb8ecf23\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2013-03-05 12:36+0800\n"
-"PO-Revision-Date: 2013-03-06 13:55+0700\n"
+"POT-Creation-Date: 2013-08-06 14:10+0800\n"
+"PO-Revision-Date: 2013-08-06 14:28+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"
@@ -20,8 +19,9 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=1;\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-Basepath: ../\n"
+"X-Generator: Poedit 1.5.5\n"
-#: advice.c:49
+#: advice.c:57
#, c-format
msgid "hint: %.*s\n"
msgstr "gợi ý: %.*s\n"
@@ -30,7 +30,7 @@ msgstr "gợi ý: %.*s\n"
#. * Message used both when 'git commit' fails and when
#. * other commands doing a merge do.
#.
-#: advice.c:79
+#: advice.c:87
msgid ""
"Fix them up in the work tree,\n"
"and then use 'git add/rm <file>' as\n"
@@ -38,9 +38,9 @@ msgid ""
"or use 'git commit -a'."
msgstr ""
"Sửa chúng trong cây làm việc,\n"
-"và sau đó dùng lệnh “git add/rm <tập-tin>†dành riêng\n"
+"và sau đó dùng lệnh \"git add/rm <tập-tin>\" dành riêng\n"
"cho việc đánh dấu tập tin cần giải quyết và tạo lần chuyển giao,\n"
-"hoặc là dùng lệnh “git commit -aâ€."
+"hoặc là dùng lệnh \"git commit -a\"."
#: archive.c:10
msgid "git archive [options] <tree-ish> [<path>...]"
@@ -69,7 +69,7 @@ msgstr "fmt"
msgid "archive format"
msgstr "định dạng lưu trữ"
-#: archive.c:324 builtin/log.c:1115
+#: archive.c:324 builtin/log.c:1173
msgid "prefix"
msgstr "tiá»n tố"
@@ -77,15 +77,15 @@ msgstr "tiá»n tố"
msgid "prepend prefix to each pathname in the archive"
msgstr "nối thêm tiá»n tố vào từng Ä‘Æ°á»ng dẫn tập tin trong kho lÆ°u"
-#: archive.c:326 builtin/archive.c:91 builtin/blame.c:2366
-#: builtin/blame.c:2367 builtin/config.c:55 builtin/fast-export.c:653
-#: builtin/fast-export.c:655 builtin/grep.c:715 builtin/hash-object.c:77
-#: builtin/ls-files.c:497 builtin/ls-files.c:500 builtin/notes.c:536
-#: builtin/notes.c:693 builtin/read-tree.c:107 parse-options.h:149
+#: archive.c:326 builtin/archive.c:88 builtin/blame.c:2292
+#: builtin/blame.c:2293 builtin/config.c:56 builtin/fast-export.c:673
+#: builtin/fast-export.c:675 builtin/grep.c:714 builtin/hash-object.c:77
+#: builtin/ls-files.c:496 builtin/ls-files.c:499 builtin/notes.c:408
+#: builtin/notes.c:565 builtin/read-tree.c:108 parse-options.h:152
msgid "file"
msgstr "tập-tin"
-#: archive.c:327 builtin/archive.c:92
+#: archive.c:327 builtin/archive.c:89
msgid "write the archive to this file"
msgstr "ghi kho lưu vào tập tin này"
@@ -95,7 +95,7 @@ msgstr "Ä‘á»c .gitattributes trong thÆ° mục làm việc"
#: archive.c:330
msgid "report archived files on stderr"
-msgstr "liệt kê các tập tin được lưu trữ vào stderr (đầu ra lỗi chuẩn)"
+msgstr "liệt kê các tập tin được lưu trữ vào stderr (đầu ra lỗi tiêu chuẩn)"
#: archive.c:331
msgid "store only"
@@ -113,19 +113,19 @@ msgstr "nén nhỠhơn"
msgid "list supported archive formats"
msgstr "liệt kê các kiểu nén được hỗ trợ"
-#: archive.c:345 builtin/archive.c:93 builtin/clone.c:85
+#: archive.c:345 builtin/archive.c:90 builtin/clone.c:85
msgid "repo"
msgstr "kho"
-#: archive.c:346 builtin/archive.c:94
+#: archive.c:346 builtin/archive.c:91
msgid "retrieve the archive from remote repository <repo>"
msgstr "nhận kho lưu từ kho chứa <kho> trên máy chủ"
-#: archive.c:347 builtin/archive.c:95 builtin/notes.c:615
+#: archive.c:347 builtin/archive.c:92 builtin/notes.c:487
msgid "command"
msgstr "lệnh"
-#: archive.c:348 builtin/archive.c:96
+#: archive.c:348 builtin/archive.c:93
msgid "path to the remote git-upload-archive command"
msgstr "Ä‘Æ°á»ng dẫn đến lệnh git-upload-pack trên máy chủ"
@@ -137,6 +137,132 @@ msgstr ""
"Các mẫu dạng phủ định bị cấm dùng cho các thuộc tính của git\n"
"Dùng “\\!†cho các chuỗi văn bản có dấu chấm than dẫn đầu."
+#: branch.c:60
+#, c-format
+msgid "Not setting branch %s as its own upstream."
+msgstr "Chưa cài đặt nhánh %s như là thượng nguồn (upstream) của nó."
+
+#: branch.c:82
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s by rebasing."
+msgstr ""
+"Nhánh %s cài đặt để theo dõi vết nhánh máy chủ %s từ %s bằng cách rebase."
+
+#: branch.c:83
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s."
+msgstr "Nhánh %s cài đặt để theo vết nhánh máy chủ %s từ %s."
+
+#: branch.c:87
+#, c-format
+msgid "Branch %s set up to track local branch %s by rebasing."
+msgstr "Nhánh %s cài đặt để theo vết nhánh nội bộ %s bằng cách rebase."
+
+#: branch.c:88
+#, c-format
+msgid "Branch %s set up to track local branch %s."
+msgstr "Nhánh %s cài đặt để theo vết nhánh nội bộ %s."
+
+#: branch.c:92
+#, c-format
+msgid "Branch %s set up to track remote ref %s by rebasing."
+msgstr "Nhánh %s cài đặt để theo vết nhánh máy chủ %s bằng cách rebase."
+
+#: branch.c:93
+#, c-format
+msgid "Branch %s set up to track remote ref %s."
+msgstr "Nhánh %s cài đặt để theo vết tham chiếu máy chủ %s."
+
+#: branch.c:97
+#, c-format
+msgid "Branch %s set up to track local ref %s by rebasing."
+msgstr ""
+"Nhánh %s cài đặt để theo dõi vết tham chiếu nội bộ %s bằng cách rebase."
+
+#: branch.c:98
+#, c-format
+msgid "Branch %s set up to track local ref %s."
+msgstr "Nhánh %s cài đặt để theo dõi tham chiếu nội bộ %s."
+
+#: branch.c:118
+#, c-format
+msgid "Tracking not set up: name too long: %s"
+msgstr "Theo vết chưa được cài đặt: tên quá dài: %s"
+
+#: branch.c:137
+#, c-format
+msgid "Not tracking: ambiguous information for ref %s"
+msgstr "Không theo vết: thông tin chưa rõ ràng cho tham chiếu %s"
+
+#: branch.c:182
+#, c-format
+msgid "'%s' is not a valid branch name."
+msgstr "“%s†không phải là một tên nhánh hợp lệ."
+
+#: branch.c:187
+#, c-format
+msgid "A branch named '%s' already exists."
+msgstr "Äã có nhánh mang tên “%sâ€."
+
+#: branch.c:195
+msgid "Cannot force update the current branch."
+msgstr "Không thể ép buộc cập nhật nhánh hiện hành."
+
+#: branch.c:216
+#, c-format
+msgid "Cannot setup tracking information; starting point '%s' is not a branch."
+msgstr ""
+"Không thể cài đặt thông tin theo vết; điểm bắt đầu “%s†không phải là một "
+"nhánh."
+
+#: branch.c:218
+#, c-format
+msgid "the requested upstream branch '%s' does not exist"
+msgstr "nhánh dòng ngược đã yêu cầu “%s†chưa sẵn có"
+
+#: branch.c:220
+msgid ""
+"\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push."
+msgstr ""
+"\n"
+"Nếu bạn có ý định trên cơ sở công việc của bạn trên nhánh dòng ngược\n"
+"(upstream) cái mà đã sẵn có trên máy chủ, bạn cần chạy\n"
+"lệnh \"git fetch\" để lấy nó vá».\n"
+"\n"
+"Nếu bạn có ý định push lênh một nhánh nội bộ mới cái mà\n"
+"sẽ theo dõi bản đối chiếu máy chủ của nó, bạn cần dùng lệnh\n"
+"\"git push -u\" để đặt cấu hình dòng ngược bạn muốn push."
+
+#: branch.c:265
+#, c-format
+msgid "Not a valid object name: '%s'."
+msgstr "Không phải tên đối tượng hợp lệ: “%sâ€."
+
+#: branch.c:285
+#, c-format
+msgid "Ambiguous object name: '%s'."
+msgstr "Tên đối tượng chÆ°a rõ ràng: “%sâ€."
+
+#: branch.c:290
+#, c-format
+msgid "Not a valid branch point: '%s'."
+msgstr "Nhánh không hợp lệ: “%sâ€."
+
+#: branch.c:296
+msgid "Failed to lock ref for update"
+msgstr "Gặp lỗi khi khóa tham chiếu (ref) để cập nhật"
+
+#: branch.c:314
+msgid "Failed to write ref"
+msgstr "Gặp lỗi khi ghi tham chiếu (ref)"
+
#: bundle.c:36
#, c-format
msgid "'%s' does not look like a v2 bundle file"
@@ -147,7 +273,7 @@ msgstr "“%s†không giống nhÆ° tập tin v2 bundle (định dạng dump cá
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:674
+#: bundle.c:89 builtin/commit.c:697
#, c-format
msgid "could not open '%s'"
msgstr "không thể mở “%sâ€"
@@ -156,35 +282,35 @@ msgstr "không thể mở “%sâ€"
msgid "Repository lacks these prerequisite commits:"
msgstr "Kho 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:566 sequencer.c:998 builtin/log.c:299
-#: builtin/log.c:751 builtin/log.c:1358 builtin/log.c:1574 builtin/merge.c:347
-#: builtin/shortlog.c:157
+#: bundle.c:164 sequencer.c:661 sequencer.c:1111 builtin/log.c:331
+#: builtin/log.c:801 builtin/log.c:1399 builtin/log.c:1625 builtin/merge.c:364
+#: builtin/shortlog.c:156
msgid "revision walk setup failed"
-msgstr "cài đặt việc di chuyển qua các điểm xét lại gặp lỗi"
+msgstr "cài đặt việc di chuyển qua các điểm xét duyệt gặp lỗi"
#: bundle.c:186
#, c-format
-msgid "The bundle contains %d ref"
-msgid_plural "The bundle contains %d refs"
-msgstr[0] "Bundle chứa %d tham chiếu (refs)"
-msgstr[1] "Bundle chứa %d tham chiếu (refs)"
+msgid "The bundle contains this ref:"
+msgid_plural "The bundle contains these %d refs:"
+msgstr[0] "Bundle chứa tham chiếu (ref) này:"
+msgstr[1] "Bundle chứa %d tham chiếu (ref):"
-#: bundle.c:192
+#: bundle.c:193
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"
+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 này:"
+msgstr[1] "Lệnh bundle yêu cầu %d tham chiếu (refs) này:"
#: bundle.c:294
msgid "rev-list died"
msgstr "rev-list đã chết"
-#: bundle.c:300 builtin/log.c:1254 builtin/shortlog.c:260
+#: bundle.c:300 builtin/log.c:1310 builtin/shortlog.c:259
#, c-format
msgid "unrecognized argument: %s"
msgstr "đối số không được thừa nhận: %s"
@@ -215,12 +341,12 @@ msgstr "không thể tạo “%sâ€"
msgid "index-pack died"
msgstr "index-pack đã chết"
-#: commit.c:50
+#: commit.c:53
#, c-format
msgid "could not parse %s"
-msgstr "không thể phân tích %s"
+msgstr "không thể phân tích cú pháp %s"
-#: commit.c:52
+#: commit.c:55
#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s không phải là một lần commit!"
@@ -229,16 +355,16 @@ msgstr "%s %s không phải là một lần commit!"
msgid "memory exhausted"
msgstr "hết bộ nhớ"
-#: connected.c:39
+#: connected.c:60
msgid "Could not run 'git rev-list'"
msgstr "Không thể chạy “git rev-listâ€"
-#: connected.c:48
+#: connected.c:80
#, c-format
msgid "failed write to rev-list: %s"
msgstr "gặp lỗi khi ghi vào rev-list: %s"
-#: connected.c:56
+#: connected.c:88
#, c-format
msgid "failed to close rev-list's stdin: %s"
msgstr "gặp lỗi khi đóng đầu vào chuẩn stdin của rev-list: %s"
@@ -334,7 +460,7 @@ msgstr ""
"Tìm thấy các lá»—i trong biến cấu hình “diff.dirstatâ€:\n"
"%s"
-#: diff.c:3468
+#: diff.c:3487
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -343,12 +469,12 @@ msgstr ""
"Gặp lá»—i khi phân tích đối số tùy chá»n --dirstat/-X:\n"
"%s"
-#: diff.c:3482
+#: diff.c:3501
#, c-format
msgid "Failed to parse --submodule option parameter: '%s'"
msgstr "Gặp lá»—i khi phân tích đối số tùy chá»n --submodule: “%sâ€"
-#: gpg-interface.c:59 gpg-interface.c:127
+#: gpg-interface.c:59 gpg-interface.c:131
msgid "could not run gpg."
msgstr "không thể chạy gpg."
@@ -360,45 +486,45 @@ msgstr "gpg đã không chấp nhận dữ liệu"
msgid "gpg failed to sign the data"
msgstr "gpg gặp lỗi khi ký dữ liệu"
-#: gpg-interface.c:112
+#: gpg-interface.c:115
#, c-format
msgid "could not create temporary file '%s': %s"
msgstr "không thể tạo tập tin tạm thá»i “%sâ€: %s"
-#: gpg-interface.c:115
+#: gpg-interface.c:118
#, c-format
msgid "failed writing detached signature to '%s': %s"
msgstr "gặp lá»—i khi ghi chữ ký đính kèm vào “%sâ€: %s"
-#: grep.c:1622
+#: grep.c:1623
#, c-format
msgid "'%s': unable to read %s"
msgstr "“%sâ€: không thể Ä‘á»c %s"
-#: grep.c:1639
+#: grep.c:1640
#, c-format
msgid "'%s': %s"
msgstr "“%sâ€: %s"
-#: grep.c:1650
+#: grep.c:1651
#, c-format
msgid "'%s': short read %s"
msgstr "“%sâ€: Ä‘á»c ngắn %s"
-#: help.c:212
+#: help.c:210
#, c-format
msgid "available git commands in '%s'"
-msgstr "các lệnh git sẵn sàng để dùng trong “%sâ€"
+msgstr "các lệnh git sẵn có trong thÆ° mục “%sâ€:"
-#: help.c:219
+#: help.c:217
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:235
+#: help.c:233
msgid "The most commonly used git commands are:"
msgstr "Những lệnh git hay được sử dụng nhất là:"
-#: help.c:292
+#: help.c:290
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -407,11 +533,11 @@ 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:349
+#: help.c:347
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:371
+#: help.c:369
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -420,17 +546,17 @@ msgstr ""
"CẢNH BÃO: Bạn đã gá»i lệnh Git có tên “%sâ€, mà nó lại không có sẵn.\n"
"Giả định rằng ý bạn là “%sâ€"
-#: help.c:376
+#: help.c:374
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr "trong %0.1f giây một cách tự động..."
-#: help.c:383
+#: help.c:381
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
msgstr "git: “%s†không phải là má»™t lệnh của git. Xem “git --helpâ€."
-#: help.c:387
+#: help.c:385 help.c:444
msgid ""
"\n"
"Did you mean this?"
@@ -444,12 +570,17 @@ msgstr[1] ""
"\n"
"Có phải ý bạn là một trong số những cái này không?"
+#: help.c:440
+#, c-format
+msgid "%s: %s - %s"
+msgstr "%s: %s - %s"
+
#: merge.c:56
msgid "failed to read the cache"
msgstr "gặp lá»—i khi Ä‘á»c bá»™ nhá»› tạm"
-#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534
-#: builtin/clone.c:586
+#: merge.c:110 builtin/checkout.c:365 builtin/checkout.c:566
+#: builtin/clone.c:656
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"
@@ -463,70 +594,70 @@ msgstr "(commit sai)\n"
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
+#: merge-recursive.c:269
msgid "error building trees"
msgstr "gặp lỗi khi xây dựng cây"
-#: merge-recursive.c:672
+#: merge-recursive.c:673
#, 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
+#: merge-recursive.c:684
#, 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
+#: merge-recursive.c:698 merge-recursive.c:719
msgid ": perhaps a D/F conflict?"
msgstr ": có lẽ là một xung đột D/F?"
-#: merge-recursive.c:708
+#: merge-recursive.c:709
#, 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
+#: merge-recursive.c:749
#, c-format
msgid "cannot read object %s '%s'"
msgstr "không thể Ä‘á»c đối tượng %s “%sâ€"
-#: merge-recursive.c:750
+#: merge-recursive.c:751
#, 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
+#: merge-recursive.c:774 builtin/clone.c:312
#, c-format
msgid "failed to open '%s'"
msgstr "gặp lá»—i khi mở “%sâ€"
-#: merge-recursive.c:781
+#: merge-recursive.c:782
#, 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
+#: merge-recursive.c:785
#, c-format
msgid "do not know what to do with %06o %s '%s'"
msgstr "không hiểu phải làm gì vá»›i %06o %s “%sâ€"
-#: merge-recursive.c:922
+#: merge-recursive.c:923
msgid "Failed to execute internal merge"
msgstr "Gặp lỗi khi thực hiện trộn nội bộ"
-#: merge-recursive.c:926
+#: merge-recursive.c:927
#, c-format
msgid "Unable to add %s to database"
msgstr "Không thể thêm %s vào cơ sở dữ liệu"
-#: merge-recursive.c:942
+#: merge-recursive.c:943
msgid "unsupported object type in the tree"
msgstr "kiểu đối tượng không được hỗ trợ trong cây (tree)"
-#: merge-recursive.c:1021 merge-recursive.c:1035
+#: merge-recursive.c:1022 merge-recursive.c:1036
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -535,7 +666,7 @@ msgstr ""
"XUNG ÄỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s của %s "
"còn lại trong cây (tree)."
-#: merge-recursive.c:1027 merge-recursive.c:1040
+#: merge-recursive.c:1028 merge-recursive.c:1041
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -544,20 +675,20 @@ msgstr ""
"XUNG ÄỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s của %s "
"còn lại trong cây (tree) tại %s."
-#: merge-recursive.c:1081
+#: merge-recursive.c:1082
msgid "rename"
msgstr "đổi tên"
-#: merge-recursive.c:1081
+#: merge-recursive.c:1082
msgid "renamed"
msgstr "đã đổi tên"
-#: merge-recursive.c:1137
+#: merge-recursive.c:1138
#, c-format
msgid "%s is a directory in %s adding as %s instead"
msgstr "%s là một thư mục trong %s thay vào đó thêm vào như là %s"
-#: merge-recursive.c:1159
+#: merge-recursive.c:1160
#, c-format
msgid ""
"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
@@ -566,149 +697,177 @@ msgstr ""
"XUNG ÄỘT (đổi-tên/đổi-tên): Äổi tên \"%s\"->\"%s\" trong nhánh \"%s\" đổi "
"tên \"%s\"->\"%s\" trong \"%s\"%s"
-#: merge-recursive.c:1164
+#: merge-recursive.c:1165
msgid " (left unresolved)"
msgstr " (cần giải quyết)"
-#: merge-recursive.c:1218
+#: merge-recursive.c:1219
#, c-format
msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
msgstr ""
"XUNG ÄỘT (đổi-tên/đổi-tên): Äổi tên %s->%s trong %s. Äổi tên %s->%s trong %s"
-#: merge-recursive.c:1248
+#: merge-recursive.c:1249
#, c-format
msgid "Renaming %s to %s and %s to %s instead"
msgstr "Äang đổi tên %s thành %s thay vì %s thành %s"
-#: merge-recursive.c:1447
+#: merge-recursive.c:1448
#, c-format
msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
msgstr ""
"XUNG ÄỘT (đổi-tên/thêm): Äổi tên %s->%s trong %s. %s được thêm vào trong %s"
-#: merge-recursive.c:1457
+#: merge-recursive.c:1458
#, c-format
msgid "Adding merged %s"
msgstr "Thêm hòa trộn %s"
-#: merge-recursive.c:1462 merge-recursive.c:1660
+#: merge-recursive.c:1463 merge-recursive.c:1661
#, c-format
msgid "Adding as %s instead"
msgstr "Thay vào đó thêm vào %s"
-#: merge-recursive.c:1513
+#: merge-recursive.c:1514
#, c-format
msgid "cannot read object %s"
msgstr "không thể Ä‘á»c đối tượng %s"
-#: merge-recursive.c:1516
+#: merge-recursive.c:1517
#, c-format
msgid "object %s is not a blob"
msgstr "đối tượng %s không phải là một blob"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modify"
msgstr "sửa đổi"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modified"
msgstr "đã sửa"
-#: merge-recursive.c:1574
+#: merge-recursive.c:1575
msgid "content"
msgstr "ná»™i dung"
-#: merge-recursive.c:1581
+#: merge-recursive.c:1582
msgid "add/add"
msgstr "thêm/thêm"
-#: merge-recursive.c:1615
+#: merge-recursive.c:1616
#, c-format
msgid "Skipped %s (merged same as existing)"
msgstr "Äã bá» qua %s (đã có sẵn lần hòa trá»™n này)"
-#: merge-recursive.c:1629
+#: merge-recursive.c:1630
#, c-format
msgid "Auto-merging %s"
msgstr "Tự-động-hòa-trộn %s"
-#: merge-recursive.c:1633 git-submodule.sh:942
+#: merge-recursive.c:1634 git-submodule.sh:1118
msgid "submodule"
msgstr "mô-đun-con"
-#: merge-recursive.c:1634
+#: merge-recursive.c:1635
#, c-format
msgid "CONFLICT (%s): Merge conflict in %s"
msgstr "XUNG ÄỘT (%s): Xung Ä‘á»™t hòa trá»™n trong %s"
-#: merge-recursive.c:1724
+#: merge-recursive.c:1725
#, c-format
msgid "Removing %s"
msgstr "Äang xóa %s"
-#: merge-recursive.c:1749
+#: merge-recursive.c:1750
msgid "file/directory"
msgstr "tập-tin/thư-mục"
-#: merge-recursive.c:1755
+#: merge-recursive.c:1756
msgid "directory/file"
msgstr "thư-mục/tập tin"
-#: merge-recursive.c:1760
+#: merge-recursive.c:1761
#, c-format
msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
msgstr ""
"XUNG ÄỘT (%s): Ở đây không có thÆ° mục nào có tên %s trong %s. Thêm %s nhÆ° là "
"%s"
-#: merge-recursive.c:1770
+#: merge-recursive.c:1771
#, c-format
msgid "Adding %s"
msgstr "Thêm \"%s\""
-#: merge-recursive.c:1787
+#: merge-recursive.c:1788
msgid "Fatal merge failure, shouldn't happen."
msgstr "Việc hòa trá»™n há»ng nghiêm trá»ng, không nên để xảy ra."
-#: merge-recursive.c:1806
+#: merge-recursive.c:1807
msgid "Already up-to-date!"
msgstr "Äã cập nhật rồi!"
-#: merge-recursive.c:1815
+#: merge-recursive.c:1816
#, c-format
msgid "merging of trees %s and %s failed"
msgstr "hòa trộn cây (tree) %s và %s gặp lỗi"
-#: merge-recursive.c:1845
+#: merge-recursive.c:1846
#, c-format
msgid "Unprocessed path??? %s"
msgstr "ÄÆ°á»ng dẫn chÆ°a được xá»­ lý??? %s"
-#: merge-recursive.c:1890
+#: merge-recursive.c:1891
msgid "Merging:"
msgstr "Äang trá»™n:"
-#: merge-recursive.c:1903
+#: merge-recursive.c:1904
#, c-format
msgid "found %u common ancestor:"
msgid_plural "found %u common ancestors:"
msgstr[0] "tìm thấy %u tổ tiên chung:"
msgstr[1] "tìm thấy %u tổ tiên chung:"
-#: merge-recursive.c:1940
+#: merge-recursive.c:1941
msgid "merge returned no commit"
msgstr "hòa trộn không trả vỠlần chuyển giao (commit) nào"
-#: merge-recursive.c:1997
+#: merge-recursive.c:1998
#, c-format
msgid "Could not parse object '%s'"
msgstr "Không thể phân tích đối tượng “%sâ€"
-#: merge-recursive.c:2009 builtin/merge.c:643
+#: merge-recursive.c:2010 builtin/merge.c:672
msgid "Unable to write index."
msgstr "Không thể ghi bảng mục lục"
+#: notes-utils.c:40
+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ú"
+
+#: notes-utils.c:81
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "Giá trị notes.rewriteMode sai: “%sâ€"
+
+#: notes-utils.c:91
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr "Từ chối ghi đè ghi chú trong %s (nằm ngoài của refs/notes/)"
+
+#. TRANSLATORS: The first %s is the name of the
+#. environment variable, the second %s is its value
+#: notes-utils.c:118
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr "Giá trị %s sai: “%sâ€"
+
+#: object.c:204
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "không thể phân tích đối tượng: “%sâ€"
+
#: parse-options.c:489
msgid "..."
msgstr "..."
@@ -744,18 +903,18 @@ msgstr "ÄÆ°á»ng dẫn “%s†thì ở trong mô-Ä‘un-con “%.*sâ€"
msgid "'%s' is beyond a symbolic link"
msgstr "“%s†nằm ngoài một liên kết tượng trưng"
-#: remote.c:1653
+#: remote.c:1788
#, 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:1659
+#: remote.c:1794
msgid " (use \"git push\" to publish your local commits)\n"
msgstr " (dùng \"git push\" để xuất bản các lần chuyển giao nội bộ của bạn)\n"
-#: remote.c:1662
+#: remote.c:1797
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -767,11 +926,11 @@ 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:1670
+#: remote.c:1805
msgid " (use \"git pull\" to update your local branch)\n"
msgstr " (dùng \"git pull\" để cập nhật nhánh nội bộ của bạn)\n"
-#: remote.c:1673
+#: remote.c:1808
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -787,25 +946,34 @@ msgstr[1] ""
"Your branch and “%s†have diverged,\n"
"and have %d and %d different commit each, respectively.\n"
-#: remote.c:1683
+#: remote.c:1818
msgid " (use \"git pull\" to merge the remote branch into yours)\n"
msgstr ""
" (dùng \"git pull\" để hòa trộn nhánh trên máy chủ vào trong nhánh của "
"bạn)\n"
-#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
-#: builtin/merge.c:994
+#: run-command.c:80
+msgid "open /dev/null failed"
+msgstr "gặp lỗi khi mở /dev/null"
+
+#: run-command.c:82
+#, c-format
+msgid "dup2(%d,%d) failed"
+msgstr "dup2(%d,%d) gặp lỗi"
+
+#: sequencer.c:206 builtin/merge.c:790 builtin/merge.c:903
+#: builtin/merge.c:1013 builtin/merge.c:1023
#, c-format
msgid "Could not open '%s' for writing"
msgstr "Không thể mở “%s†để ghi"
-#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986
-#: builtin/merge.c:999
+#: sequencer.c:208 builtin/merge.c:350 builtin/merge.c:793
+#: builtin/merge.c:1015 builtin/merge.c:1028
#, c-format
msgid "Could not write to '%s'"
msgstr "Không thể ghi vào “%sâ€"
-#: sequencer.c:146
+#: sequencer.c:229
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
@@ -813,7 +981,7 @@ msgstr ""
"sau khi giải quyết các xung Ä‘á»™t, đánh dấu Ä‘Æ°á»ng dẫn đã sá»­a\n"
"vá»›i lệnh “git add <Ä‘Æ°á»ng_dẫn>†hoặc “git rm <Ä‘Æ°á»ng_dẫn>â€"
-#: sequencer.c:149
+#: sequencer.c:232
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'\n"
@@ -823,232 +991,266 @@ 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:162 sequencer.c:774 sequencer.c:857
+#: sequencer.c:245 sequencer.c:869 sequencer.c:952
#, c-format
msgid "Could not write to %s"
msgstr "Không thể ghi vào %s"
-#: sequencer.c:165
+#: sequencer.c:248
#, c-format
msgid "Error wrapping up %s"
msgstr "Lá»—i bao bá»c %s"
-#: sequencer.c:180
+#: sequencer.c:263
msgid "Your local changes would be overwritten by cherry-pick."
msgstr "Các thay đổi nội bộ của bạn có thể bị ghi đè bởi lệnh cherry-pick."
-#: sequencer.c:182
+#: sequencer.c:265
msgid "Your local changes would be overwritten by revert."
msgstr "Các thay đổi nội bộ của bạn có thể bị ghi đè bởi lệnh revert."
-#: sequencer.c:185
+#: sequencer.c:268
msgid "Commit your changes or stash them to proceed."
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:236
+#: sequencer.c:324
#, c-format
msgid "%s: Unable to write new index file"
msgstr "%s: Không thể ghi tập tin lưu bảng mục lục mới"
-#: sequencer.c:267
+#: sequencer.c:355
msgid "Could not resolve HEAD commit\n"
msgstr "Không thể phân giải commit (lần chuyển giao) HEAD\n"
-#: sequencer.c:288
+#: sequencer.c:377
msgid "Unable to update cache tree\n"
msgstr "Không thể cập nhật cây bộ nhớ đệm\n"
-#: sequencer.c:333
+#: sequencer.c:422
#, c-format
msgid "Could not parse commit %s\n"
msgstr "Không thể phân tích commit (lần chuyển giao) %s\n"
-#: sequencer.c:338
+#: sequencer.c:427
#, c-format
msgid "Could not parse parent commit %s\n"
msgstr "Không thể phân tích commit (lần chuyển giao) cha mẹ %s\n"
-#: sequencer.c:404
+#: sequencer.c:493
msgid "Your index file is unmerged."
msgstr "Tập tin lưu mục lục của bạn không được hòa trộn."
-#: sequencer.c:423
+#: sequencer.c:512
#, 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."
-#: sequencer.c:431
+#: sequencer.c:520
#, c-format
msgid "Commit %s does not have parent %d"
msgstr "Lần chuyển giao (commit) %s không có cha mẹ %d"
-#: sequencer.c:435
+#: sequencer.c:524
#, c-format
msgid "Mainline was specified but commit %s is not a merge."
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."
+"Luồng chính đã được chỉ ra nhưng lần chuyển giao (commit) %s không phải là "
+"một lần hòa trộn."
#. TRANSLATORS: The first %s will be "revert" or
#. "cherry-pick", the second %s a SHA1
-#: sequencer.c:448
+#: sequencer.c:537
#, c-format
msgid "%s: cannot parse parent commit %s"
msgstr "%s: không thể phân tích lần chuyển giao mẹ của %s"
-#: sequencer.c:452
+#: sequencer.c:541
#, c-format
msgid "Cannot get commit message for %s"
msgstr "Không thể lấy thông điệp lần chuyển giao (commit) cho %s"
-#: sequencer.c:536
+#: sequencer.c:627
#, c-format
msgid "could not revert %s... %s"
msgstr "không thể revert %s... %s"
-#: sequencer.c:537
+#: sequencer.c:628
#, c-format
msgid "could not apply %s... %s"
msgstr "không thể apply (áp dụng miếng vá) %s... %s"
-#: sequencer.c:569
+#: sequencer.c:664
msgid "empty commit set passed"
msgstr "lần chuyển giao (commit) trống rỗng đặt là hợp quy cách"
-#: sequencer.c:577
+#: sequencer.c:672
#, c-format
msgid "git %s: failed to read the index"
msgstr "git %s: gặp lá»—i Ä‘á»c bảng mục lục"
-#: sequencer.c:582
+#: sequencer.c:677
#, c-format
msgid "git %s: failed to refresh the index"
msgstr "git %s: gặp lỗi khi làm tươi mới bảng mục lục"
-#: sequencer.c:640
+#: sequencer.c:735
#, c-format
msgid "Cannot %s during a %s"
msgstr "Không thể %s trong khi %s"
-#: sequencer.c:662
+#: sequencer.c:757
#, c-format
msgid "Could not parse line %d."
msgstr "Không phân tích được dòng %d."
-#: sequencer.c:667
+#: sequencer.c:762
msgid "No commits parsed."
msgstr "Không có lần chuyển giao (commit) nào được phân tích."
-#: sequencer.c:680
+#: sequencer.c:775
#, c-format
msgid "Could not open %s"
msgstr "Không thể mở %s"
-#: sequencer.c:684
+#: sequencer.c:779
#, c-format
msgid "Could not read %s."
msgstr "Không thể Ä‘á»c %s."
-#: sequencer.c:691
+#: sequencer.c:786
#, c-format
msgid "Unusable instruction sheet: %s"
msgstr "Bảng chỉ thị không thể dùng được: %s"
-#: sequencer.c:719
+#: sequencer.c:814
#, c-format
msgid "Invalid key: %s"
msgstr "Khóa không đúng: %s"
-#: sequencer.c:722
+#: sequencer.c:817
#, c-format
msgid "Invalid value for %s: %s"
msgstr "Giá trị không hợp lệ %s: %s"
-#: sequencer.c:734
+#: sequencer.c:829
#, c-format
msgid "Malformed options sheet: %s"
msgstr "Bảng tùy chá»n dị hình: %s"
-#: sequencer.c:755
+#: sequencer.c:850
msgid "a cherry-pick or revert is already in progress"
msgstr "một thao tác cherry-pick hoặc revert đang được thực hiện"
-#: sequencer.c:756
+#: sequencer.c:851
msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
msgstr "hãy thử \"git cherry-pick (--continue | --quit | --abort)\""
-#: sequencer.c:760
+#: sequencer.c:855
#, c-format
msgid "Could not create sequencer directory %s"
msgstr "Không thể tạo thư mục xếp dãy %s"
-#: sequencer.c:776 sequencer.c:861
+#: sequencer.c:871 sequencer.c:956
#, c-format
msgid "Error wrapping up %s."
msgstr "Lá»—i bao bá»c %s."
-#: sequencer.c:795 sequencer.c:929
+#: sequencer.c:890 sequencer.c:1024
msgid "no cherry-pick or revert in progress"
msgstr "không cherry-pick hay revert trong tiến trình"
-#: sequencer.c:797
+#: sequencer.c:892
msgid "cannot resolve HEAD"
msgstr "không thể phân giải HEAD"
-#: sequencer.c:799
+#: sequencer.c:894
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:821 builtin/apply.c:4056
+#: sequencer.c:916 builtin/apply.c:4061
#, c-format
msgid "cannot open %s: %s"
msgstr "không thể mở %s: %s"
-#: sequencer.c:824
+#: sequencer.c:919
#, c-format
msgid "cannot read %s: %s"
msgstr "không thể Ä‘á»c %s: %s"
-#: sequencer.c:825
+#: sequencer.c:920
msgid "unexpected end of file"
msgstr "kết thúc tập tin đột xuất"
-#: sequencer.c:831
+#: sequencer.c:926
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
msgstr "tập tin HEAD “pre-cherry-pick†đã lÆ°u “%s†bị há»ng"
-#: sequencer.c:854
+#: sequencer.c:949
#, c-format
msgid "Could not format %s."
msgstr "Không thể định dạng %s."
-#: sequencer.c:1016
+#: sequencer.c:1092
+#, c-format
+msgid "%s: can't cherry-pick a %s"
+msgstr "%s: không thể cherry-pick một %s"
+
+#: sequencer.c:1095
+#, c-format
+msgid "%s: bad revision"
+msgstr "%s: điểm xét duyệt sai"
+
+#: sequencer.c:1129
msgid "Can't revert as initial commit"
msgstr "Không thể revert một lần chuyển giao (commit) khởi tạo"
-#: sequencer.c:1017
+#: sequencer.c:1130
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:1044
+#: sha1_name.c:440
+msgid ""
+"Git normally never creates a ref that ends with 40 hex characters\n"
+"because it will be ignored when you just specify 40-hex. These refs\n"
+"may be created by mistake. For example,\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
+"examine these refs and maybe delete them. Turn this message off by\n"
+"running \"git config advice.objectNameWarning false\""
+msgstr ""
+"Git thÆ°á»ng không bao giá» tạo tham chiếu mà nó kết thúc vá»›i 40 ký tá»± hex\n"
+"bởi vì nó sẽ bị bỠqua khi bạn chỉ định 40-hex. Những tham chiếu này\n"
+"có lẽ được tạo ra bởi một sai sót nào đó. Ví dụ,\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"với \"$br\" không hiểu lý do vì sao trống rỗng và một tham chiếu 40-hex được "
+"tạo ra.\n"
+"Xin hãy kiểm tra những tham chiếu này và có thể xóa chúng Ä‘i. Tắt lá»i nhắn "
+"này\n"
+"bằng cách chạy lệnh \"git config advice.objectNameWarning false\""
+
+#: sha1_name.c:1097
msgid "HEAD does not point to a branch"
msgstr "HEAD không chỉ đến một nhánh nào cả"
-#: sha1_name.c:1047
+#: sha1_name.c:1100
#, c-format
msgid "No such branch: '%s'"
msgstr "Không có nhánh nào nhÆ° thế: “%sâ€"
-#: sha1_name.c:1049
+#: sha1_name.c:1102
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "Không có thượng nguồn (upstream) được cấu hình cho nhánh “%sâ€"
-#: sha1_name.c:1052
+#: sha1_name.c:1106
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr ""
@@ -1060,239 +1262,239 @@ msgstr ""
msgid "unable to access '%s': %s"
msgstr "không thể truy cập “%sâ€: %s"
-#: wrapper.c:423
+#: wrapper.c:429
#, c-format
msgid "unable to access '%s'"
msgstr "không thể truy cập “%sâ€"
-#: wrapper.c:434
+#: wrapper.c:440
#, c-format
msgid "unable to look up current user in the passwd file: %s"
msgstr "không tìm thấy ngÆ°á»i dùng hiện tại trong tập tin passwd: %s"
-#: wrapper.c:435
+#: wrapper.c:441
msgid "no such user"
msgstr "không có ngÆ°á»i dùng nhÆ° vậy"
-#: wt-status.c:140
+#: wt-status.c:141
msgid "Unmerged paths:"
msgstr "Những Ä‘Æ°á»ng dẫn chÆ°a được hòa trá»™n:"
-#: wt-status.c:167 wt-status.c:194
+#: wt-status.c:168 wt-status.c:195
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr " (dùng \"git reset %s <tập-tin>...\" để bỠmột stage (trạng thái))"
-#: wt-status.c:169 wt-status.c:196
+#: wt-status.c:170 wt-status.c:197
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr " (dùng \"git rm --cached <tập-tin>...\" để bỠtrạng thái (stage))"
-#: wt-status.c:173
+#: wt-status.c:174
msgid " (use \"git add <file>...\" to mark resolution)"
msgstr " (dùng \"git add <tập-tin>...\" để đánh dấu là cần giải quyết)"
-#: wt-status.c:175 wt-status.c:179
+#: wt-status.c:176 wt-status.c:180
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
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:177
+#: wt-status.c:178
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
+#: wt-status.c:189
msgid "Changes to be committed:"
msgstr "Những thay đổi sẽ được chuyển giao:"
-#: wt-status.c:206
+#: wt-status.c:207
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):"
-#: wt-status.c:210
+#: wt-status.c:211
msgid " (use \"git add <file>...\" to update what will be committed)"
msgstr ""
" (dùng \"git add <tập-tin>...\" để cập nhật những gì cần chuyển giao "
"(commit))"
-#: wt-status.c:212
+#: wt-status.c:213
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr ""
" (dùng \"git add/rm <tập-tin>...\" để cập nhật những gì sẽ được chuyển giao)"
-#: wt-status.c:213
+#: wt-status.c:214
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:215
+#: wt-status.c:216
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr ""
" (chuyển giao (commit) hoặc là loại bỠcác nội dung không-bị-theo-vết hay "
"đã bị chỉnh sửa trong mô-đun-con)"
-#: wt-status.c:227
+#: wt-status.c:228
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr ""
" (dùng \"git %s <tập-tin>...\" để thêm vào những gì cần chuyển giao "
"(commit))"
-#: wt-status.c:244
+#: wt-status.c:245
msgid "bug"
msgstr "lá»—i"
-#: wt-status.c:249
+#: wt-status.c:250
msgid "both deleted:"
msgstr "bị xóa bởi cả hai:"
-#: wt-status.c:250
+#: wt-status.c:251
msgid "added by us:"
msgstr "được thêm vào bởi chúng ta:"
-#: wt-status.c:251
+#: wt-status.c:252
msgid "deleted by them:"
msgstr "bị xóa Ä‘i bởi há»:"
-#: wt-status.c:252
+#: wt-status.c:253
msgid "added by them:"
msgstr "được thêm vào bởi há»:"
-#: wt-status.c:253
+#: wt-status.c:254
msgid "deleted by us:"
msgstr "bị xóa bởi chúng ta:"
-#: wt-status.c:254
+#: wt-status.c:255
msgid "both added:"
msgstr "được thêm vào bởi cả hai:"
-#: wt-status.c:255
+#: wt-status.c:256
msgid "both modified:"
msgstr "bị sửa bởi cả hai:"
-#: wt-status.c:285
+#: wt-status.c:286
msgid "new commits, "
msgstr "lần chuyển giao (commit) mới, "
-#: wt-status.c:287
+#: wt-status.c:288
msgid "modified content, "
msgstr "nội dung bị sửa đổi, "
-#: wt-status.c:289
+#: wt-status.c:290
msgid "untracked content, "
msgstr "nội dung chưa được theo dõi, "
-#: wt-status.c:303
+#: wt-status.c:307
#, c-format
msgid "new file: %s"
msgstr "tập tin mới: %s"
-#: wt-status.c:306
+#: wt-status.c:310
#, c-format
msgid "copied: %s -> %s"
msgstr "đã sao chép: %s -> %s"
-#: wt-status.c:309
+#: wt-status.c:313
#, c-format
msgid "deleted: %s"
msgstr "đã xóa: %s"
-#: wt-status.c:312
+#: wt-status.c:316
#, c-format
msgid "modified: %s"
msgstr "đã sửa đổi: %s"
-#: wt-status.c:315
+#: wt-status.c:319
#, c-format
msgid "renamed: %s -> %s"
msgstr "đã đổi tên: %s -> %s"
-#: wt-status.c:318
+#: wt-status.c:322
#, c-format
msgid "typechange: %s"
msgstr "đổi-kiểu: %s"
-#: wt-status.c:321
+#: wt-status.c:325
#, c-format
msgid "unknown: %s"
msgstr "không hiểu: %s"
-#: wt-status.c:324
+#: wt-status.c:328
#, c-format
msgid "unmerged: %s"
msgstr "chưa hòa trộn: %s"
-#: wt-status.c:327
+#: wt-status.c:331
#, 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:789
+#: wt-status.c:803
msgid "You have unmerged paths."
msgstr "Bạn có những Ä‘Æ°á»ng dẫn chÆ°a được hòa trá»™n."
-#: wt-status.c:792 wt-status.c:944
+#: wt-status.c:806
msgid " (fix conflicts and run \"git commit\")"
msgstr " (sửa các xung đột sau đó chạy \"git commit\")"
-#: wt-status.c:795
+#: wt-status.c:809
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:798
+#: wt-status.c:812
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:808
+#: wt-status.c:822
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:811
+#: wt-status.c:825
msgid "The current patch is empty."
msgstr "Miếng vá hiện tại bị trống rỗng."
-#: wt-status.c:815
-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:829
+msgid " (fix conflicts and then run \"git am --continue\")"
+msgstr " (sửa các xung đột và sau đó chạy lệnh \"git am --continue\")"
-#: wt-status.c:817
+#: wt-status.c:831
msgid " (use \"git am --skip\" to skip this patch)"
msgstr " (dùng \"git am --skip\" để bỠqua miếng vá này)"
-#: wt-status.c:819
+#: wt-status.c:833
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:879 wt-status.c:896
+#: wt-status.c:893 wt-status.c:910
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
msgstr "Bạn hiện nay Ä‘ang thá»±c hiện việc rebase nhánh “%s†trên “%sâ€."
-#: wt-status.c:884 wt-status.c:901
+#: wt-status.c:898 wt-status.c:915
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:887
+#: wt-status.c:901
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:889
+#: wt-status.c:903
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:891
+#: wt-status.c:905
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:904
+#: wt-status.c:918
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:908
+#: wt-status.c:922
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
@@ -1300,110 +1502,163 @@ msgstr ""
"Bạn hiện nay đang thực hiện việc chia tách một lần chuyển giao (commit) "
"trong khi Ä‘ang rebase nhánh “%s†trên “%sâ€."
-#: wt-status.c:913
+#: wt-status.c:927
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:916
+#: wt-status.c:930
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:920
+#: wt-status.c:934
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr ""
"Bạn hiện nay đang thực hiện việc sửa chữa một lần chuyển giao (commit) trong "
"khi Ä‘ang rebase nhánh “%s†trên “%sâ€."
-#: wt-status.c:925
+#: wt-status.c:939
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:928
+#: wt-status.c:942
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:930
+#: wt-status.c:944
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:940
+#: wt-status.c:954
msgid "You are currently cherry-picking."
msgstr "Bạn hiện nay đang thực hiện việc cherry-pick."
-#: wt-status.c:947
-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:958
+msgid " (fix conflicts and run \"git cherry-pick --continue\")"
+msgstr ""
+" (sửa các xung đột và sau đó chạy lệnh \"git cherry-pick --continue\")"
+
+#: wt-status.c:961
+msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
+msgstr ""
+" (khi tất cả các xung đột đã sửa xong: chạy lệnh \"git cherry-pick --"
+"continue\")"
+
+#: wt-status.c:963
+msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
+msgstr " (dùng \"git cherry-pick --abort\" để hủy bỠthao tác cherry-pick)"
+
+#: wt-status.c:972
#, c-format
-msgid "You are currently bisecting branch '%s'."
+msgid "You are currently reverting commit %s."
+msgstr "Bạn hiện nay Ä‘ang thá»±c hiện thao tác revert lần chuyển giao “%sâ€."
+
+#: wt-status.c:977
+msgid " (fix conflicts and run \"git revert --continue\")"
+msgstr " (sửa các xung đột và sau đó chạy lệnh \"git revert --continue\")"
+
+#: wt-status.c:980
+msgid " (all conflicts fixed: run \"git revert --continue\")"
msgstr ""
-"Bạn hiện nay đang thực hiện thao tác di chuyển nửa bước (bisect) trên nhánh "
-"“%sâ€."
+" (khi tất cả các xung đột đã sửa xong: chạy lệnh \"git revert --continue\")"
+
+#: wt-status.c:982
+msgid " (use \"git revert --abort\" to cancel the revert operation)"
+msgstr " (dùng \"git revert --abort\" để hủy bỠthao tác revert)"
-#: wt-status.c:962
+#: wt-status.c:993
+#, c-format
+msgid "You are currently bisecting, started from branch '%s'."
+msgstr ""
+"Bạn hiện nay đang thực hiện thao tác di chuyển nửa bước (bisect), bắt đầu từ "
+"nhánh “%sâ€."
+
+#: wt-status.c:997
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:965
+#: wt-status.c:1000
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:1064
+#: wt-status.c:1173
msgid "On branch "
msgstr "Trên nhánh "
-#: wt-status.c:1071
+#: wt-status.c:1180
+msgid "rebase in progress; onto "
+msgstr "rebase đang được thực hiện: lên trên"
+
+#: wt-status.c:1187
+msgid "HEAD detached at "
+msgstr "HEAD được tách rá»i tại"
+
+#: wt-status.c:1189
+msgid "HEAD detached from "
+msgstr "HEAD được tách rá»i từ"
+
+#: wt-status.c:1192
msgid "Not currently on any branch."
msgstr "Hiện tại chẳng ở nhánh nào cả."
-#: wt-status.c:1083
+#: wt-status.c:1209
msgid "Initial commit"
msgstr "Lần chuyển giao (commit) khởi đầu"
-#: wt-status.c:1097
+#: wt-status.c:1223
msgid "Untracked files"
msgstr "Những tập tin chưa được theo dõi"
-#: wt-status.c:1099
+#: wt-status.c:1225
msgid "Ignored files"
msgstr "Những tập tin bị lỠđi"
-#: wt-status.c:1101
+#: wt-status.c:1229
+#, c-format
+msgid ""
+"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
+"may speed it up, but you have to be careful not to forget to add\n"
+"new files yourself (see 'git help status')."
+msgstr ""
+"Cần %.2f giây để liệt kê tất cả các tập tin chưa được theo dõi. “status -"
+"unoâ€\n"
+"có lẽ làm nó nhanh hơn, nhưng bạn phải cẩn thận đừng quên mình phải\n"
+"tá»± thêm các tập tin má»›i (xem “git help statusâ€.."
+
+#: wt-status.c:1235
#, 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:1103
+#: wt-status.c:1237
msgid " (use -u option to show untracked files)"
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:1109
+#: wt-status.c:1243
msgid "No changes"
msgstr "Không có thay đổi nào"
-#: wt-status.c:1114
+#: wt-status.c:1248
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr ""
"không có thay đổi nào được thêm vào commit (dùng \"git add\" và/hoặc \"git "
"commit -a\")\n"
-#: wt-status.c:1117
+#: wt-status.c:1251
#, c-format
msgid "no changes added to commit\n"
msgstr "không có thay đổi nào được thêm vào lần chuyển giao (commit)\n"
-#: wt-status.c:1120
+#: wt-status.c:1254
#, c-format
msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
@@ -1412,58 +1667,58 @@ msgstr ""
"không có gì được thêm vào lần chuyển giao (commit) nhưng có những tập tin "
"không được theo dấu vết hiện diện (dùng \"git add\" để đưa vào theo dõi)\n"
-#: wt-status.c:1123
+#: wt-status.c:1257
#, c-format
msgid "nothing added to commit but untracked files present\n"
msgstr ""
"không có gì được thêm vào lần chuyển giao (commit) nhưng có những tập tin "
"không được theo dấu vết hiện diện\n"
-#: wt-status.c:1126
+#: wt-status.c:1260
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
msgstr ""
" không có gì để commit (tạo/sao-chép các tập tin và dùng \"git add\" để theo "
"dõi dấu vết)\n"
-#: wt-status.c:1129 wt-status.c:1134
+#: wt-status.c:1263 wt-status.c:1268
#, c-format
msgid "nothing to commit\n"
msgstr "không có gì để chuyển giao (commit)\n"
-#: wt-status.c:1132
+#: wt-status.c:1266
#, c-format
msgid "nothing to commit (use -u to show untracked files)\n"
msgstr ""
"không có gì để chuyển giao (commit) (dùng -u để bỠcác tập tin cần theo dấu "
"vết)\n"
-#: wt-status.c:1136
+#: wt-status.c:1270
#, c-format
msgid "nothing to commit, working directory clean\n"
msgstr "không có gì để chuyển giao (commit), thư mục làm việc sạch sẽ\n"
-#: wt-status.c:1244
+#: wt-status.c:1378
msgid "HEAD (no branch)"
msgstr "HEAD (không nhánh)"
-#: wt-status.c:1250
+#: wt-status.c:1384
msgid "Initial commit on "
msgstr "Lần chuyển giao (commit) khởi tạo trên "
-#: wt-status.c:1265
+#: wt-status.c:1399
msgid "behind "
msgstr "đằng sau "
-#: wt-status.c:1268 wt-status.c:1271
+#: wt-status.c:1402 wt-status.c:1405
msgid "ahead "
msgstr "phía trước "
-#: wt-status.c:1273
+#: wt-status.c:1407
msgid ", behind "
msgstr ", đằng sau "
-#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#: compat/precompose_utf8.c:58 builtin/clone.c:351
#, c-format
msgid "failed to unlink '%s'"
msgstr "bỠliên kết (unlink) %s không thành công"
@@ -1472,200 +1727,235 @@ msgstr "bỠliên kết (unlink) %s không thành công"
msgid "git add [options] [--] <pathspec>..."
msgstr "git add [các-tùy-chá»n] [--] <pathspec>..."
-#: builtin/add.c:63
+#.
+#. * To be consistent with "git add -p" and most Git
+#. * commands, we should default to being tree-wide, but
+#. * this is not the original behavior and can't be
+#. * changed until users trained themselves not to type
+#. * "git add -u" or "git add -A". For now, we warn and
+#. * keep the old behavior. Later, the behavior can be changed
+#. * to tree-wide, keeping the warning for a while, and
+#. * eventually we can drop the warning.
+#.
+#: builtin/add.c:58
+#, c-format
+msgid ""
+"The behavior of 'git add %s (or %s)' with no path argument from a\n"
+"subdirectory of the tree will change in Git 2.0 and should not be used "
+"anymore.\n"
+"To add content for the whole tree, run:\n"
+"\n"
+" git add %s :/\n"
+" (or git add %s :/)\n"
+"\n"
+"To restrict the command to the current directory, run:\n"
+"\n"
+" git add %s .\n"
+" (or git add %s .)\n"
+"\n"
+"With the current Git version, the command is restricted to the current "
+"directory.\n"
+msgstr ""
+"Cách ứng xá»­ của lệnh “git add %s (hay %s)†khi không có tham số Ä‘Æ°á»ng dẫn "
+"từ\n"
+"thư-mục con của cây sẽ thay đổi kể từ Git 2.0 và không thể sử dụng như thế "
+"nữa.\n"
+"Äể thêm ná»™i dung cho toàn bá»™ cây, chạy:\n"
+"\n"
+" git add %s :/\n"
+" (hay git add %s :/)\n"
+"\n"
+"Äể hạn chế lệnh cho thÆ°-mục hiện tại, chạy:\n"
+"\n"
+" git add %s .\n"
+" (hay git add %s .)\n"
+"\n"
+"Với phiên bản hiện tại của Git, lệnh bị hạn chế cho thư-mục hiện tại.\n"
+
+#: builtin/add.c:100
+#, c-format
+msgid ""
+"You ran 'git add' with neither '-A (--all)' or '--ignore-removal',\n"
+"whose behaviour will change in Git 2.0 with respect to paths you removed.\n"
+"Paths like '%s' that are\n"
+"removed from your working tree are ignored with this version of Git.\n"
+"\n"
+"* 'git add --ignore-removal <pathspec>', which is the current default,\n"
+" ignores paths you removed from your working tree.\n"
+"\n"
+"* 'git add --all <pathspec>' will let you also record the removals.\n"
+"\n"
+"Run 'git status' to check the paths you removed from your working tree.\n"
+msgstr ""
+"Bạn chạy “git add†mà không có “-A (--all)†cÅ©ng không “--ignore-removalâ€,\n"
+"cách ứng xá»­ của nó sẽ thay đổi kể từ Git 2.0: nó quan tâm đến các Ä‘Æ°á»ng dẫn "
+"mà\n"
+"bạn đã gỡ bá». Các Ä‘Æ°á»ng dẫn nhÆ° là “%s†cái mà\n"
+"bị gỡ bỠtừ cây làm việc của bạn thì bị bỠqua với phiên bản này của Git.\n"
+"\n"
+"* “git add --ignore-removal <pathspec>â€, cái hiện tại là mặc định,\n"
+" bá» qua các Ä‘Æ°á»ng dẫn bạn đã gỡ bá» từ cây làm việc của bạn.\n"
+"\n"
+"* “git add --all <pathspec>†sẽ đồng thá»i giúp bạn ghi lại việc dá»i Ä‘i.\n"
+"\n"
+"Chạy “git status†để kiểm tra các Ä‘Æ°á»ng dẫn bạn đã gỡ bá» từ cây làm việc của "
+"bạn.\n"
+
+#: builtin/add.c:144
#, c-format
msgid "unexpected diff status %c"
msgstr "trạng thái lệnh diff không như mong đợi %c"
-#: builtin/add.c:68 builtin/commit.c:231
+#: builtin/add.c:149 builtin/commit.c:252
msgid "updating files failed"
msgstr "Cập nhật tập tin gặp lỗi"
-#: builtin/add.c:78
+#: builtin/add.c:163
#, c-format
msgid "remove '%s'\n"
msgstr "gỡ bỠ“%sâ€\n"
-#: builtin/add.c:148
+#: builtin/add.c:253
msgid "Unstaged changes after refreshing the index:"
msgstr ""
"Các thay đổi không được lưu trạng thái sau khi làm tươi mới lại bảng mục lục:"
-#: builtin/add.c:151 builtin/add.c:460 builtin/rm.c:275
+#: builtin/add.c:256 builtin/add.c:573 builtin/rm.c:337
#, 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"
-#: builtin/add.c:234
+#: builtin/add.c:339
msgid "Could not read the index"
msgstr "Không thể Ä‘á»c bảng mục lục"
-#: builtin/add.c:244
+#: builtin/add.c:350
#, c-format
msgid "Could not open '%s' for writing."
msgstr "Không thể mở “%s†để ghi."
-#: builtin/add.c:248
+#: builtin/add.c:354
msgid "Could not write patch"
msgstr "Không thể ghi ra miếng vá"
-#: builtin/add.c:253
+#: builtin/add.c:359
#, c-format
msgid "Could not stat '%s'"
msgstr "không thể lấy trạng thái vỠ“%sâ€"
-#: builtin/add.c:255
+#: builtin/add.c:361
msgid "Empty patch. Aborted."
msgstr "Miếng vá trống rá»—ng. Äã bá» qua."
-#: builtin/add.c:261
+#: builtin/add.c:367
#, c-format
msgid "Could not apply '%s'"
msgstr "Không thể apply (áp dụng miếng vá) “%sâ€"
-#: builtin/add.c:271
+#: builtin/add.c:377
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"
-#: builtin/add.c:277 builtin/clean.c:161 builtin/fetch.c:78 builtin/mv.c:63
-#: builtin/prune-packed.c:76 builtin/push.c:425 builtin/remote.c:1253
-#: builtin/rm.c:206
+#: builtin/add.c:394 builtin/clean.c:875 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:73 builtin/push.c:451 builtin/remote.c:1253
+#: builtin/rm.c:268
msgid "dry run"
msgstr "chạy thử"
-#: builtin/add.c:278 builtin/apply.c:4405 builtin/check-ignore.c:19
-#: builtin/commit.c:1150 builtin/count-objects.c:82 builtin/fsck.c:613
-#: builtin/log.c:1522 builtin/mv.c:62 builtin/read-tree.c:112
+#: builtin/add.c:395 builtin/apply.c:4410 builtin/check-ignore.c:19
+#: builtin/commit.c:1220 builtin/count-objects.c:95 builtin/fsck.c:613
+#: builtin/log.c:1573 builtin/mv.c:62 builtin/read-tree.c:113
msgid "be verbose"
msgstr "chi tiết"
-#: builtin/add.c:280
+#: builtin/add.c:397
msgid "interactive picking"
msgstr "sửa bằng cách tương tác"
-#: builtin/add.c:281 builtin/checkout.c:1031 builtin/reset.c:258
+#: builtin/add.c:398 builtin/checkout.c:1073 builtin/reset.c:261
msgid "select hunks interactively"
msgstr "chá»n “hunks†má»™t cách tÆ°Æ¡ng tác"
-#: builtin/add.c:282
+#: builtin/add.c:399
msgid "edit current diff and apply"
msgstr "sửa diff hiện nay và áp dụng nó"
-#: builtin/add.c:283
+#: builtin/add.c:400
msgid "allow adding otherwise ignored files"
msgstr "cho phép thêm các tập tin bị bỠqua khác"
-#: builtin/add.c:284
+#: builtin/add.c:401
msgid "update tracked files"
msgstr "cập nhật các tập tin được theo vết"
-#: builtin/add.c:285
+#: builtin/add.c:402
msgid "record only the fact that the path will be added later"
msgstr "chỉ ghi lại sá»± việc mà Ä‘Æ°á»ng dẫn sẽ được thêm vào sau"
-#: builtin/add.c:286
+#: builtin/add.c:403
msgid "add changes from all tracked and untracked files"
msgstr ""
"thêm các thay đổi từ tất cả các tập tin có cũng như không được theo dõi dấu "
"vết"
-#: builtin/add.c:287
+#. takes no arguments
+#: builtin/add.c:406
+msgid "ignore paths removed in the working tree (same as --no-all)"
+msgstr ""
+"lá» Ä‘i các Ä‘Æ°á»ng dẫn bị gỡ bá» trong cây thÆ° mục làm việc (giống vá»›i --no-all)"
+
+#: builtin/add.c:408
msgid "don't add, only refresh the index"
msgstr "không thêm, chỉ làm tươi mới bảng mục lục"
-#: builtin/add.c:288
+#: builtin/add.c:409
msgid "just skip files which cannot be added because of errors"
msgstr "chie bỠqua những tập tin mà nó không thể được thêm vào bởi vì gặp lỗi"
-#: builtin/add.c:289
+#: builtin/add.c:410
msgid "check if - even missing - files are ignored in dry run"
msgstr ""
"kiểm tra xem - thậm chí thiếu - tập tin bị bỠqua trong quá trình chạy thử"
-#: builtin/add.c:311
+#: builtin/add.c:432
#, c-format
msgid "Use -f if you really want to add them.\n"
msgstr "Sá»­ dụng tùy chá»n -f nếu bạn thá»±c sá»± muốn thêm chúng vào.\n"
-#: builtin/add.c:312
+#: builtin/add.c:433
msgid "no files added"
msgstr "chưa có tập tin nào được thêm vào"
-#: builtin/add.c:318
+#: builtin/add.c:439
msgid "adding files failed"
msgstr "thêm tập tin gặp lỗi"
-#.
-#. * To be consistent with "git add -p" and most Git
-#. * commands, we should default to being tree-wide, but
-#. * this is not the original behavior and can't be
-#. * changed until users trained themselves not to type
-#. * "git add -u" or "git add -A". For now, we warn and
-#. * keep the old behavior. Later, this warning can be
-#. * turned into a die(...), and eventually we may
-#. * reallow the command with a new behavior.
-#.
-#: builtin/add.c:335
-#, c-format
-msgid ""
-"The behavior of 'git add %s (or %s)' with no path argument from a\n"
-"subdirectory of the tree will change in Git 2.0 and should not be used "
-"anymore.\n"
-"To add content for the whole tree, run:\n"
-"\n"
-" git add %s :/\n"
-" (or git add %s :/)\n"
-"\n"
-"To restrict the command to the current directory, run:\n"
-"\n"
-" git add %s .\n"
-" (or git add %s .)\n"
-"\n"
-"With the current Git version, the command is restricted to the current "
-"directory."
-msgstr ""
-"Cách ứng xá»­ của lệnh “git add %s (hay %s)†khi không có tham số Ä‘Æ°á»ng dẫn "
-"từ\n"
-"thư-mục con của cây sẽ thay đổi kể từ Git 2.0 và không thể sử dụng như thế "
-"nữa.\n"
-"Äể thêm ná»™i dung cho toàn bá»™ cây, chạy:\n"
-"\n"
-" git add %s :/\n"
-" (hay git add %s :/)\n"
-"\n"
-"Äể hạn chế lệnh cho thÆ°-mục hiện tại, chạy:\n"
-"\n"
-" git add %s .\n"
-" (hay git add %s .)\n"
-"\n"
-"Với phiên bản hiện tại của Git, lệnh bị hạn chế cho thư-mục hiện tại."
-
-#: builtin/add.c:381
+#: builtin/add.c:478
msgid "-A and -u are mutually incompatible"
msgstr "-A và -u xung khắc nhau"
-#: builtin/add.c:383
+#: builtin/add.c:496
msgid "Option --ignore-missing can only be used together with --dry-run"
msgstr "Tùy chá»n --ignore-missing chỉ có thể được dùng cùng vá»›i --dry-run"
-#: builtin/add.c:414
+#: builtin/add.c:526
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr "Không có gì được chỉ ra, không có gì được thêm vào.\n"
-#: builtin/add.c:415
+#: builtin/add.c:527
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "Có lẽ bạn muốn là “git add .†phải không?\n"
-#: builtin/add.c:421 builtin/check-ignore.c:67 builtin/clean.c:204
-#: builtin/commit.c:291 builtin/mv.c:82 builtin/rm.c:235
+#: builtin/add.c:533 builtin/check-ignore.c:161 builtin/clean.c:919
+#: builtin/commit.c:312 builtin/mv.c:82 builtin/rm.c:297
msgid "index file corrupt"
msgstr "tập tin ghi bảng mục lục bị há»ng"
-#: builtin/add.c:481 builtin/apply.c:4501 builtin/mv.c:229 builtin/rm.c:370
+#: builtin/add.c:605 builtin/apply.c:4506 builtin/mv.c:229 builtin/rm.c:432
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"
@@ -1799,24 +2089,24 @@ msgstr "không thể Ä‘á»c liên kết tượng trÆ°ng %s"
msgid "unable to open or read %s"
msgstr "không thể mở hay Ä‘á»c %s"
-#: builtin/apply.c:2684
+#: builtin/apply.c:2688
#, c-format
msgid "invalid start of line: '%c'"
msgstr "sai khởi đầu dòng: “%câ€"
-#: builtin/apply.c:2802
+#: builtin/apply.c:2806
#, 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:2814
+#: builtin/apply.c:2818
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %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:2820
+#: builtin/apply.c:2824
#, c-format
msgid ""
"while searching for:\n"
@@ -1825,325 +2115,325 @@ msgstr ""
"Trong khi đang tìm kiếm cho:\n"
"%.*s"
-#: builtin/apply.c:2839
+#: builtin/apply.c:2843
#, 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:2942
+#: builtin/apply.c:2946
#, 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:2948
+#: builtin/apply.c:2952
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
msgstr ""
"vá nhị phân cho “%s†tạo ra kết quả không chính xác (mong chỠ%s, lại nhận "
"%s)"
-#: builtin/apply.c:2969
+#: builtin/apply.c:2973
#, c-format
msgid "patch failed: %s:%ld"
msgstr "vá gặp lỗi: %s:%ld"
-#: builtin/apply.c:3091
+#: builtin/apply.c:3095
#, c-format
msgid "cannot checkout %s"
msgstr "không thể \"checkout\" %s"
-#: builtin/apply.c:3136 builtin/apply.c:3145 builtin/apply.c:3189
+#: builtin/apply.c:3140 builtin/apply.c:3149 builtin/apply.c:3194
#, c-format
msgid "read of %s failed"
msgstr "Ä‘á»c %s gặp lá»—i"
-#: builtin/apply.c:3169 builtin/apply.c:3391
+#: builtin/apply.c:3174 builtin/apply.c:3396
#, c-format
msgid "path %s has been renamed/deleted"
msgstr "Ä‘Æ°á»ng dẫn %s đã bị xóa/đổi tên"
-#: builtin/apply.c:3250 builtin/apply.c:3405
+#: builtin/apply.c:3255 builtin/apply.c:3410
#, 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:3254 builtin/apply.c:3397 builtin/apply.c:3419
+#: builtin/apply.c:3259 builtin/apply.c:3402 builtin/apply.c:3424
#, c-format
msgid "%s: %s"
msgstr "%s: %s"
-#: builtin/apply.c:3259 builtin/apply.c:3413
+#: builtin/apply.c:3264 builtin/apply.c:3418
#, c-format
msgid "%s: does not match index"
msgstr "%s: không khớp trong mục lục"
-#: builtin/apply.c:3361
+#: builtin/apply.c:3366
msgid "removal patch leaves file contents"
msgstr "loại bỠmiếng vá để lại nội dung tập tin"
-#: builtin/apply.c:3430
+#: builtin/apply.c:3435
#, c-format
msgid "%s: wrong type"
msgstr "%s: sai kiểu"
-#: builtin/apply.c:3432
+#: builtin/apply.c:3437
#, c-format
msgid "%s has type %o, expected %o"
msgstr "%s có kiểu %o, mong chỠ%o"
-#: builtin/apply.c:3533
+#: builtin/apply.c:3538
#, c-format
msgid "%s: already exists in index"
msgstr "%s: đã có từ trước trong bảng mục lục"
-#: builtin/apply.c:3536
+#: builtin/apply.c:3541
#, 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:3556
+#: builtin/apply.c:3561
#, 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:3561
+#: builtin/apply.c:3566
#, 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:3569
+#: builtin/apply.c:3574
#, c-format
msgid "%s: patch does not apply"
msgstr "%s: miếng vá không được áp dụng"
-#: builtin/apply.c:3582
+#: builtin/apply.c:3587
#, c-format
msgid "Checking patch %s..."
msgstr "Äang kiểm tra miếng vá %s..."
-#: builtin/apply.c:3675 builtin/checkout.c:215 builtin/reset.c:124
+#: builtin/apply.c:3680 builtin/checkout.c:216 builtin/reset.c:127
#, 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:3818
+#: builtin/apply.c:3823
#, c-format
msgid "unable to remove %s from index"
msgstr "không thể gỡ bỠ%s từ mục lục"
-#: builtin/apply.c:3846
+#: builtin/apply.c:3851
#, c-format
-msgid "corrupt patch for subproject %s"
-msgstr "miếng vá sai há»ng cho dá»± án con (subproject) %s"
+msgid "corrupt patch for submodule %s"
+msgstr "miếng vá sai há»ng cho mô-Ä‘un-con (subproject) %s"
-#: builtin/apply.c:3850
+#: builtin/apply.c:3855
#, 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:3855
+#: builtin/apply.c:3860
#, 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:3858 builtin/apply.c:3966
+#: builtin/apply.c:3863 builtin/apply.c:3971
#, 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:3891
+#: builtin/apply.c:3896
#, c-format
msgid "closing file '%s'"
msgstr "Ä‘ang đóng tập tin “%sâ€"
-#: builtin/apply.c:3940
+#: builtin/apply.c:3945
#, 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:4027
+#: builtin/apply.c:4032
#, 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:4035
+#: builtin/apply.c:4040
msgid "internal error"
msgstr "lá»—i ná»™i bá»™"
#. Say this even without --verbose
-#: builtin/apply.c:4038
+#: builtin/apply.c:4043
#, 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:4048
+#: builtin/apply.c:4053
#, 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:4069
+#: builtin/apply.c:4074
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "Khối nhá»› #%d được áp dụng gá»n gàng."
-#: builtin/apply.c:4072
+#: builtin/apply.c:4077
#, c-format
msgid "Rejected hunk #%d."
msgstr "hunk #%d bị từ chối."
-#: builtin/apply.c:4222
+#: builtin/apply.c:4227
msgid "unrecognized input"
msgstr "không thừa nhận đầu vào"
-#: builtin/apply.c:4233
+#: builtin/apply.c:4238
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:4352 builtin/apply.c:4355 builtin/clone.c:91
+#: builtin/apply.c:4357 builtin/apply.c:4360 builtin/clone.c:91
#: builtin/fetch.c:63
msgid "path"
msgstr "Ä‘Æ°á»ng-dẫn"
-#: builtin/apply.c:4353
+#: builtin/apply.c:4358
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:4356
+#: builtin/apply.c:4361
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:4358
+#: builtin/apply.c:4363
msgid "num"
msgstr "số"
-#: builtin/apply.c:4359
+#: builtin/apply.c:4364
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:4362
+#: builtin/apply.c:4367
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:4364
+#: builtin/apply.c:4369
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"
-#: builtin/apply.c:4368
+#: builtin/apply.c:4373
msgid "show number of added and deleted lines in decimal notation"
msgstr ""
"hiển thị số lượng các dòng được thêm vào và xóa đi theo ký hiệu thập phân"
-#: builtin/apply.c:4370
+#: builtin/apply.c:4375
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:4372
+#: builtin/apply.c:4377
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:4374
+#: builtin/apply.c:4379
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:4376
+#: builtin/apply.c:4381
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:4378
+#: builtin/apply.c:4383
msgid "also apply the patch (use with --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:4380
+#: builtin/apply.c:4385
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:4382
+#: builtin/apply.c:4387
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"
-#: builtin/apply.c:4384 builtin/checkout-index.c:197 builtin/ls-files.c:463
+#: builtin/apply.c:4389 builtin/checkout-index.c:197 builtin/ls-files.c:462
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:4387
+#: builtin/apply.c:4392
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:4388
+#: builtin/apply.c:4393
msgid "action"
msgstr "hành động"
-#: builtin/apply.c:4389
+#: builtin/apply.c:4394
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:4392 builtin/apply.c:4395
+#: builtin/apply.c:4397 builtin/apply.c:4400
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:4398
+#: builtin/apply.c:4403
msgid "apply the patch in reverse"
msgstr "áp dụng miếng vá theo chiá»u ngược"
-#: builtin/apply.c:4400
+#: builtin/apply.c:4405
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:4402
+#: builtin/apply.c:4407
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:4404
+#: builtin/apply.c:4409
msgid "allow overlapping hunks"
msgstr "cho phép chồng khối nhớ"
-#: builtin/apply.c:4407
+#: builtin/apply.c:4412
msgid "tolerate incorrectly detected missing new-line at the end of file"
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:4410
+#: builtin/apply.c:4415
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:4412
+#: builtin/apply.c:4417
msgid "root"
msgstr "root"
-#: builtin/apply.c:4413
+#: builtin/apply.c:4418
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:4435
+#: builtin/apply.c:4440
msgid "--3way outside a repository"
msgstr "--3way ở ngoài một kho chứa"
-#: builtin/apply.c:4443
+#: builtin/apply.c:4448
msgid "--index outside a repository"
msgstr "--index ở ngoài một kho chứa"
-#: builtin/apply.c:4446
+#: builtin/apply.c:4451
msgid "--cached outside a repository"
msgstr "--cached ở ngoài một kho chứa"
-#: builtin/apply.c:4462
+#: builtin/apply.c:4467
#, c-format
msgid "can't open patch '%s'"
msgstr "không thể mở miếng vá “%sâ€"
-#: builtin/apply.c:4476
+#: builtin/apply.c:4481
#, 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:4482 builtin/apply.c:4492
+#: builtin/apply.c:4487 builtin/apply.c:4497
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -2167,21 +2457,21 @@ msgstr "git archive: Máy chủ không có địa chỉ URL"
msgid "git archive: expected ACK/NAK, got EOF"
msgstr "git archive: mong đợi ACK/NAK, nhận EOF"
-#: builtin/archive.c:63
+#: builtin/archive.c:61
#, c-format
msgid "git archive: NACK %s"
msgstr "git archive: NACK %s"
-#: builtin/archive.c:65
+#: builtin/archive.c:63
#, c-format
msgid "remote error: %s"
msgstr "lỗi máy chủ: %s"
-#: builtin/archive.c:66
+#: builtin/archive.c:64
msgid "git archive: protocol error"
msgstr "git archive: lỗi giao thức"
-#: builtin/archive.c:71
+#: builtin/archive.c:68
msgid "git archive: expected a flush"
msgstr "git archive: đã mong chỠmột flush"
@@ -2199,125 +2489,125 @@ msgstr ""
"cập nhật BISECT_HEAD thay vì lấy ra (checking out) lần chuyển giao (commit) "
"hiện hành"
-#: builtin/blame.c:25
+#: builtin/blame.c:26
msgid "git blame [options] [rev-opts] [rev] [--] file"
msgstr "git blame [các-tùy-chá»n] [rev-opts] [rev] [--] tập-tin"
-#: builtin/blame.c:30 builtin/shortlog.c:15
+#: builtin/blame.c:31
msgid "[rev-opts] are documented in git-rev-list(1)"
msgstr "[rev-opts] được mô tả trong git-rev-list(1)"
-#: builtin/blame.c:2350
+#: builtin/blame.c:2276
msgid "Show blame entries as we find them, incrementally"
msgstr "Hiển thị các mục “blame†như là chúng ta thấy chúng, tăng dần"
-#: builtin/blame.c:2351
+#: builtin/blame.c:2277
msgid "Show blank SHA-1 for boundary commits (Default: off)"
msgstr ""
"Hiển thị SHA-1 trắng cho những lần chuyển giao biên giới (Mặc định: off)"
-#: builtin/blame.c:2352
+#: builtin/blame.c:2278
msgid "Do not treat root commits as boundaries (Default: off)"
msgstr "Không coi các lần chuyển giao gốc là giới hạn (Mặc định: off)"
-#: builtin/blame.c:2353
+#: builtin/blame.c:2279
msgid "Show work cost statistics"
msgstr "Hiển thị thống kê công sức làm việc"
-#: builtin/blame.c:2354
+#: builtin/blame.c:2280
msgid "Show output score for blame entries"
msgstr "Hiển thị kết xuất Ä‘iểm số có các mục tin “blameâ€"
-#: builtin/blame.c:2355
+#: builtin/blame.c:2281
msgid "Show original filename (Default: auto)"
msgstr "Hiển thị tên tập tin gốc (Mặc định: auto)"
-#: builtin/blame.c:2356
+#: builtin/blame.c:2282
msgid "Show original linenumber (Default: off)"
msgstr "Hiển thị số dòng gốc (Mặc định: off)"
-#: builtin/blame.c:2357
+#: builtin/blame.c:2283
msgid "Show in a format designed for machine consumption"
msgstr "Hiển thị ở định dạng đã thiết kế cho sự tiêu dùng bằng máy"
-#: builtin/blame.c:2358
+#: builtin/blame.c:2284
msgid "Show porcelain format with per-line commit information"
msgstr "Hiển thị định dạng “porcelain†với thông tin chuyển giao mỗi dòng"
-#: builtin/blame.c:2359
+#: builtin/blame.c:2285
msgid "Use the same output mode as git-annotate (Default: off)"
msgstr "Dùng cùng chế độ xuất ra vóigit-annotate (Mặc định: off)"
-#: builtin/blame.c:2360
+#: builtin/blame.c:2286
msgid "Show raw timestamp (Default: off)"
msgstr "Hiển thị dấu vết thá»i gian dạng thô (Mặc định: off)"
-#: builtin/blame.c:2361
+#: builtin/blame.c:2287
msgid "Show long commit SHA1 (Default: off)"
msgstr "Hiển thị SHA1 của lần chuyển giao (commit) dạng dài (Mặc định: off)"
-#: builtin/blame.c:2362
+#: builtin/blame.c:2288
msgid "Suppress author name and timestamp (Default: off)"
msgstr "Không hiển thị tên tác giả và dấu vết thá»i gian (Mặc định: off)"
-#: builtin/blame.c:2363
+#: builtin/blame.c:2289
msgid "Show author email instead of name (Default: off)"
msgstr "Hiển thị thư điện tử của tác giả thay vì tên (Mặc định: off)"
-#: builtin/blame.c:2364
+#: builtin/blame.c:2290
msgid "Ignore whitespace differences"
msgstr "BỠqua các khác biệt do khoảng trắng gây ra"
-#: builtin/blame.c:2365
+#: builtin/blame.c:2291
msgid "Spend extra cycles to find better match"
msgstr "Tiêu thụ thêm năng tài nguyên máy móc để tìm kiếm tốt hơn nữa"
-#: builtin/blame.c:2366
+#: builtin/blame.c:2292
msgid "Use revisions from <file> instead of calling git-rev-list"
msgstr ""
"Sá»­ dụng Ä‘iểm xét duyệt (revision) từ <tập tin> thay vì gá»i “git-rev-listâ€"
-#: builtin/blame.c:2367
+#: builtin/blame.c:2293
msgid "Use <file>'s contents as the final image"
msgstr "Sử dụng nội dung của <tập tin> như là ảnh cuối cùng"
-#: builtin/blame.c:2368 builtin/blame.c:2369
+#: builtin/blame.c:2294 builtin/blame.c:2295
msgid "score"
msgstr "điểm số"
-#: builtin/blame.c:2368
+#: builtin/blame.c:2294
msgid "Find line copies within and across files"
msgstr "Tìm các bản sao chép dòng trong và ngang qua tập tin"
-#: builtin/blame.c:2369
+#: builtin/blame.c:2295
msgid "Find line movements within and across files"
msgstr "Tìm các di chuyển dòng trong và ngang qua tập tin"
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
msgid "n,m"
msgstr "n,m"
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
msgid "Process only line range n,m, counting from 1"
msgstr "Xử lý chỉ dòng vùng n,m, tính từ 1"
-#: builtin/branch.c:23
+#: builtin/branch.c:24
msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
msgstr "git branch [các-tùy-chá»n] [-r | -a] [--merged | --no-merged]"
-#: builtin/branch.c:24
+#: builtin/branch.c:25
msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
msgstr "git branch [các-tùy-chá»n] [-l] [-f] <tên-nhánh> [<Ä‘iểm-đầu>]"
-#: builtin/branch.c:25
+#: builtin/branch.c:26
msgid "git branch [options] [-r] (-d | -D) <branchname>..."
msgstr "git branch [các-tùy-chá»n] [-r] (-d | -D) <tên-nhánh> ..."
-#: builtin/branch.c:26
+#: builtin/branch.c:27
msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
msgstr "git branch [các-tùy-chá»n] (-m | -M) [<nhánh-cÅ©>] <nhánh-má»›i>"
-#: builtin/branch.c:145
+#: builtin/branch.c:150
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
@@ -2326,7 +2616,7 @@ msgstr ""
"đang xóa nhánh “%s†mà nó lại đã được hòa trộn vào\n"
" “%sâ€, nhÆ°ng vẫn chÆ°a được hòa trá»™n vào HEAD."
-#: builtin/branch.c:149
+#: builtin/branch.c:154
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
@@ -2335,12 +2625,12 @@ msgstr ""
"không xóa nhánh “%s†cái mà chưa được hòa trộn vào\n"
" “%sâ€, cho dù là nó đã được hòa trá»™n vào HEAD."
-#: builtin/branch.c:163
+#: builtin/branch.c:168
#, c-format
msgid "Couldn't look up commit object for '%s'"
msgstr "Không thể tìm kiếm đối tượng chuyển giao (commit) cho “%sâ€"
-#: builtin/branch.c:167
+#: builtin/branch.c:172
#, c-format
msgid ""
"The branch '%s' is not fully merged.\n"
@@ -2349,287 +2639,333 @@ msgstr ""
"Nhánh “%s†không được trộn một cách đầy đủ.\n"
"Nếu bạn thá»±c sá»± muốn xóa nó, thì chạy lệnh “git branch -D %sâ€."
-#: builtin/branch.c:180
+#: builtin/branch.c:185
msgid "Update of config-file failed"
msgstr "Cập nhật tập tin cấu hình gặp lỗi"
-#: builtin/branch.c:208
+#: builtin/branch.c:213
msgid "cannot use -a with -d"
msgstr "không thể dùng tùy chá»n -a vá»›i -d"
-#: builtin/branch.c:214
+#: builtin/branch.c:219
msgid "Couldn't look up commit object for HEAD"
msgstr "Không thể tìm kiếm đối tượng chuyển giao (commit) cho HEAD"
-#: builtin/branch.c:222
+#: builtin/branch.c:227
#, c-format
msgid "Cannot delete the branch '%s' which you are currently on."
msgstr "Không thể xóa nhánh “%s†cái mà bạn hiện nay đang ở."
-#: builtin/branch.c:235
+#: builtin/branch.c:240
#, c-format
msgid "remote branch '%s' not found."
msgstr "không tìm thấy nhánh máy chủ “%sâ€."
-#: builtin/branch.c:236
+#: builtin/branch.c:241
#, c-format
msgid "branch '%s' not found."
msgstr "không tìm thấy nhánh “%sâ€."
-#: builtin/branch.c:250
+#: builtin/branch.c:255
#, c-format
msgid "Error deleting remote branch '%s'"
msgstr "Gặp lá»—i khi Ä‘ang xóa nhánh trên máy chủ “%sâ€"
-#: builtin/branch.c:251
+#: builtin/branch.c:256
#, c-format
msgid "Error deleting branch '%s'"
msgstr "Lá»—i khi xoá bá» nhánh “%sâ€"
-#: builtin/branch.c:258
+#: builtin/branch.c:263
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
msgstr "Nhánh trên máy chủ \"%s\" đã bị xóa (từng là %s).\n"
-#: builtin/branch.c:259
+#: builtin/branch.c:264
#, c-format
msgid "Deleted branch %s (was %s).\n"
msgstr "Nhánh “%s†đã bị xóa (từng là %s)\n"
-#: builtin/branch.c:361
+#: builtin/branch.c:366
#, c-format
msgid "branch '%s' does not point at a commit"
msgstr "nhánh “%s†không chỉ đến một lần chuyển giao (commit) nào cả"
-#: builtin/branch.c:433
+#: builtin/branch.c:453
#, c-format
msgid "[%s: behind %d]"
msgstr "[%s: đằng sau %d]"
-#: builtin/branch.c:435
+#: builtin/branch.c:455
#, c-format
msgid "[behind %d]"
msgstr "[đằng sau %d]"
-#: builtin/branch.c:439
+#: builtin/branch.c:459
#, c-format
msgid "[%s: ahead %d]"
msgstr "[%s: phía trước %d]"
-#: builtin/branch.c:441
+#: builtin/branch.c:461
#, c-format
msgid "[ahead %d]"
msgstr "[phía trước %d]"
-#: builtin/branch.c:444
+#: builtin/branch.c:464
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr "[%s: trÆ°á»›c %d, sau %d]"
-#: builtin/branch.c:447
+#: builtin/branch.c:467
#, c-format
msgid "[ahead %d, behind %d]"
msgstr "[trÆ°á»›c %d, sau %d]"
-#: builtin/branch.c:469
+#: builtin/branch.c:490
msgid " **** invalid ref ****"
msgstr " **** tham chiếu sai ****"
-#: builtin/branch.c:560
+#: builtin/branch.c:582
+#, c-format
+msgid "(no branch, rebasing %s)"
+msgstr "(không nhánh, đang rebase %s)"
+
+#: builtin/branch.c:585
+#, c-format
+msgid "(no branch, bisect started on %s)"
+msgstr "(không nhánh, bisect được bắt đầu tại %s)"
+
+#: builtin/branch.c:588
+#, c-format
+msgid "(detached from %s)"
+msgstr "(được tách rá»i từ %s)"
+
+#: builtin/branch.c:591
msgid "(no branch)"
msgstr "(không nhánh)"
-#: builtin/branch.c:593
+#: builtin/branch.c:637
#, c-format
msgid "object '%s' does not point to a commit"
msgstr "đối tượng “%s†không chỉ đến một lần chuyển giao (commit) nào cả"
-#: builtin/branch.c:625
+#: builtin/branch.c:669
msgid "some refs could not be read"
msgstr "má»™t số tham chiếu đã không thể Ä‘á»c được"
-#: builtin/branch.c:638
+#: builtin/branch.c:682
msgid "cannot rename the current branch while not on any."
msgstr "không thể đổi tên nhánh hiện hành trong khi nó chẳng ở đâu cả."
-#: builtin/branch.c:648
+#: builtin/branch.c:692
#, c-format
msgid "Invalid branch name: '%s'"
msgstr "Sai tên nhánh: “%sâ€"
-#: builtin/branch.c:663
+#: builtin/branch.c:707
msgid "Branch rename failed"
msgstr "Äổi tên nhánh gặp lá»—i"
-#: builtin/branch.c:667
+#: builtin/branch.c:711
#, c-format
msgid "Renamed a misnamed branch '%s' away"
msgstr "Äã đổi tên nhánh khuyết danh “%s†đi"
-#: builtin/branch.c:671
+#: builtin/branch.c:715
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
msgstr "Nhánh bị đổi tên thành %s, nhưng HEAD lại không được cập nhật!"
-#: builtin/branch.c:678
+#: builtin/branch.c:722
msgid "Branch is renamed, but update of config-file failed"
msgstr "Nhánh bị đổi tên, nhưng cập nhật tập tin cấu hình gặp lỗi"
-#: builtin/branch.c:693
+#: builtin/branch.c:737
#, c-format
msgid "malformed object name %s"
msgstr "tên đối tượng dị hình %s"
-#: builtin/branch.c:717
+#: builtin/branch.c:761
#, c-format
msgid "could not write branch description template: %s"
msgstr "không thể ghi vào mẫu mô tả nhánh: %s"
-#: builtin/branch.c:747
+#: builtin/branch.c:791
msgid "Generic options"
msgstr "Tùy chá»n chung"
-#: builtin/branch.c:749
+#: builtin/branch.c:793
msgid "show hash and subject, give twice for upstream branch"
msgstr "hiển thị mã băm và chủ Ä‘á», Ä‘Æ°a ra hai lần cho nhánh thượng nguồn"
-#: builtin/branch.c:750
+#: builtin/branch.c:794
msgid "suppress informational messages"
msgstr "Thu hồi các thông điệp thông tin"
-#: builtin/branch.c:751
+#: builtin/branch.c:795
msgid "set up tracking mode (see git-pull(1))"
msgstr "cài đặt chế độ theo vết (xem git-pull(1))"
-#: builtin/branch.c:753
+#: builtin/branch.c:797
msgid "change upstream info"
msgstr "thay đổi thông tin thượng nguồn (upstream)"
-#: builtin/branch.c:757
+#: builtin/branch.c:801
msgid "use colored output"
msgstr "sử dụng kết xuất có tô màu"
-#: builtin/branch.c:758
+#: builtin/branch.c:802
msgid "act on remote-tracking branches"
msgstr "thao tác trên nhánh “remote-trackingâ€"
-#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788
-#: builtin/branch.c:794 builtin/commit.c:1366 builtin/commit.c:1367
-#: builtin/commit.c:1368 builtin/commit.c:1369 builtin/tag.c:468
+#: builtin/branch.c:805 builtin/branch.c:811 builtin/branch.c:832
+#: builtin/branch.c:838 builtin/commit.c:1433 builtin/commit.c:1434
+#: builtin/commit.c:1435 builtin/commit.c:1436 builtin/tag.c:468
msgid "commit"
msgstr "commit"
-#: builtin/branch.c:762 builtin/branch.c:768
+#: builtin/branch.c:806 builtin/branch.c:812
msgid "print only branches that contain the commit"
msgstr "chỉ hiển thị những nhánh mà nó chứa lần chuyển giao"
-#: builtin/branch.c:774
+#: builtin/branch.c:818
msgid "Specific git-branch actions:"
msgstr "Hành động git-branch:"
-#: builtin/branch.c:775
+#: builtin/branch.c:819
msgid "list both remote-tracking and local branches"
msgstr "liệt kê cả nhánh “remote-tracking†và nội bộ"
-#: builtin/branch.c:777
+#: builtin/branch.c:821
msgid "delete fully merged branch"
msgstr "xóa một cách đầy đủ nhánh đã hòa trộn"
-#: builtin/branch.c:778
+#: builtin/branch.c:822
msgid "delete branch (even if not merged)"
msgstr "xoá nhánh (cho dù là chưa được hòa trộn)"
-#: builtin/branch.c:779
+#: builtin/branch.c:823
msgid "move/rename a branch and its reflog"
msgstr "di chuyển hay đổi tên một nhánh và reflog của nó"
-#: builtin/branch.c:780
+#: builtin/branch.c:824
msgid "move/rename a branch, even if target exists"
msgstr "di chuyển hoặc đổi tên một nhánh, thậm chí cả khi đích đã có sẵn"
-#: builtin/branch.c:781
+#: builtin/branch.c:825
msgid "list branch names"
msgstr "liệt kê các tên nhánh"
-#: builtin/branch.c:782
+#: builtin/branch.c:826
msgid "create the branch's reflog"
msgstr "tạo reflog của nhánh"
-#: builtin/branch.c:784
+#: builtin/branch.c:828
msgid "edit the description for the branch"
msgstr "sửa mô tả cho nhánh"
-#: builtin/branch.c:785
+#: builtin/branch.c:829
msgid "force creation (when already exists)"
msgstr "ép buộc tạo (khi đã sẵn tồn tại rồi)"
-#: builtin/branch.c:788
+#: builtin/branch.c:832
msgid "print only not merged branches"
msgstr "chỉ hiển thị các nhánh chưa được hòa trộn"
-#: builtin/branch.c:794
+#: builtin/branch.c:838
msgid "print only merged branches"
msgstr "chỉ hiển thị các nhánh được hòa trộn"
-#: builtin/branch.c:798
+#: builtin/branch.c:842
msgid "list branches in columns"
msgstr "liệt kê các nhánh trong các cột"
-#: builtin/branch.c:811
+#: builtin/branch.c:855
msgid "Failed to resolve HEAD as a valid ref."
msgstr "Gặp lỗi khi phân giải HEAD như là một tham chiếu (ref) hợp lệ."
-#: builtin/branch.c:816 builtin/clone.c:561
+#: builtin/branch.c:860 builtin/clone.c:630
msgid "HEAD not found below refs/heads!"
msgstr "không tìm thấy HEAD ở dưới refs/heads!"
-#: builtin/branch.c:839
+#: builtin/branch.c:883
msgid "--column and --verbose are incompatible"
msgstr "--column và --verbose xung khắc nhau"
-#: builtin/branch.c:845
+#: builtin/branch.c:889 builtin/branch.c:928
msgid "branch name required"
msgstr "cần tên nhánh"
-#: builtin/branch.c:860
+#: builtin/branch.c:904
msgid "Cannot give description to detached HEAD"
msgstr "Không thể Ä‘Æ°a ra mô tả HEAD đã tách rá»i"
-#: builtin/branch.c:865
+#: builtin/branch.c:909
msgid "cannot edit description of more than one branch"
msgstr "không thể sá»­a mô tả cho nhiá»u hÆ¡n má»™t nhánh"
-#: builtin/branch.c:872
+#: builtin/branch.c:916
#, c-format
msgid "No commit on branch '%s' yet."
msgstr "Vẫn chÆ°a chuyển giao trên nhánh “%sâ€."
-#: builtin/branch.c:875
+#: builtin/branch.c:919
#, c-format
msgid "No branch named '%s'."
msgstr "Không có nhánh nào có tên “%sâ€."
-#: builtin/branch.c:888
+#: builtin/branch.c:934
msgid "too many branches for a rename operation"
msgstr "quá nhiá»u nhánh dành cho thao tác đổi tên"
-#: builtin/branch.c:893
+#: builtin/branch.c:939
+msgid "too many branches to set new upstream"
+msgstr "quá nhiá»u nhánh được đặt cho dòng ngược (upstream) má»›i"
+
+#: builtin/branch.c:943
+#, c-format
+msgid ""
+"could not set upstream of HEAD to %s when it does not point to any branch."
+msgstr ""
+"không thể đặt dòng ngược (upstream) của HEAD thành %s khi mà nó chẳng chỉ "
+"đến nhánh nào cả."
+
+#: builtin/branch.c:946 builtin/branch.c:968 builtin/branch.c:990
+#, c-format
+msgid "no such branch '%s'"
+msgstr "không có nhánh nào nhÆ° thế “%sâ€"
+
+#: builtin/branch.c:950
#, c-format
msgid "branch '%s' does not exist"
msgstr "nhánh “%s†chưa sẵn có"
-#: builtin/branch.c:905
+#: builtin/branch.c:962
+msgid "too many branches to unset upstream"
+msgstr "quá nhiá»u nhánh để bỠđặt ngược dòng (upstream)"
+
+#: builtin/branch.c:966
+msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgstr ""
+"không thể bỠđặt ngược dòng (upstream) của HEAD không chỉ đến một nhánh nào "
+"cả."
+
+#: builtin/branch.c:972
#, c-format
msgid "Branch '%s' has no upstream information"
msgstr "Nhánh “%s†không có thông tin thượng nguồn (upstream)"
-#: builtin/branch.c:920
+#: builtin/branch.c:987
+msgid "it does not make sense to create 'HEAD' manually"
+msgstr "không hợp lý khi tạo “HEAD†thủ công "
+
+#: builtin/branch.c:993
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"
-#: builtin/branch.c:923
+#: builtin/branch.c:996
#, c-format
msgid ""
"The --set-upstream flag is deprecated and will be removed. Consider using --"
@@ -2638,7 +2974,7 @@ msgstr ""
"Cá» --set-upstream bị phản đối và sẽ bị xóa bá». Nên dùng --track hoặc --set-"
"upstream-to\n"
-#: builtin/branch.c:940
+#: builtin/branch.c:1013
#, c-format
msgid ""
"\n"
@@ -2649,12 +2985,12 @@ msgstr ""
"Nếu bạn muốn “%s†theo dõi “%sâ€, thá»±c hiện lệnh sau:\n"
"\n"
-#: builtin/branch.c:941
+#: builtin/branch.c:1014
#, c-format
msgid " git branch -d %s\n"
msgstr " git branch -d %s\n"
-#: builtin/branch.c:942
+#: builtin/branch.c:1015
#, c-format
msgid " git branch --set-upstream-to %s\n"
msgstr " git branch --set-upstream-to %s\n"
@@ -2672,44 +3008,44 @@ 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/cat-file.c:247
+#: builtin/cat-file.c:285
msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
msgstr "git cat-file (-t|-s|-e|-p|<kiểu>|--textconv) <đối tượng>"
-#: builtin/cat-file.c:248
+#: builtin/cat-file.c:286
msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
msgstr "git cat-file (--batch|--batch-check) < <danh-sách-đối-tượng>"
-#: builtin/cat-file.c:266
+#: builtin/cat-file.c:323
msgid "<type> can be one of: blob, tree, commit, tag"
msgstr "<kiểu> là một trong số: blob, tree, commit, tag"
-#: builtin/cat-file.c:267
+#: builtin/cat-file.c:324
msgid "show object type"
msgstr "hiển thị kiểu đối tượng"
-#: builtin/cat-file.c:268
+#: builtin/cat-file.c:325
msgid "show object size"
msgstr "hiển thị kích thước đối tượng"
-#: builtin/cat-file.c:270
+#: builtin/cat-file.c:327
msgid "exit with zero when there's no error"
msgstr "thoát với 0 khi không có lỗi"
-#: builtin/cat-file.c:271
+#: builtin/cat-file.c:328
msgid "pretty-print object's content"
msgstr "in ná»™i dung đối tượng dạng dá»… Ä‘á»c"
-#: builtin/cat-file.c:273
+#: builtin/cat-file.c:330
msgid "for blob objects, run textconv on object's content"
msgstr "với đối tượng blob, chạy lệnh textconv trên nội dung của đối tượng"
-#: builtin/cat-file.c:275
+#: builtin/cat-file.c:332
msgid "show info and content of objects fed from the standard input"
msgstr ""
"hiển thị thông tin và nội dung của các đối tượng lấy từ đầu vào tiêu chuẩn"
-#: builtin/cat-file.c:278
+#: builtin/cat-file.c:335
msgid "show info about objects fed from the standard input"
msgstr "hiển thị các thông tin vỠđối tượng fed từ đầu vào tiêu chuẩn"
@@ -2738,30 +3074,55 @@ msgstr "Ä‘á»c tên tập tin từ đầu vào tiêu chuẩn"
msgid "input paths are terminated by a null character"
msgstr "các Ä‘Æ°á»ng dẫn được ngăn cách bởi ký tá»± null"
-#: builtin/check-ignore.c:18 builtin/checkout.c:1012 builtin/gc.c:177
+#: builtin/check-ignore.c:18 builtin/checkout.c:1054 builtin/gc.c:177
msgid "suppress progress reporting"
msgstr "chặn các báo cáo tiến trình hoạt động"
-#: builtin/check-ignore.c:151
+#: builtin/check-ignore.c:26
+msgid "show non-matching input paths"
+msgstr "hiển thị những Ä‘Æ°á»ng dẫn đầu vào không khá»›p vá»›i mẫu"
+
+#: builtin/check-ignore.c:143
msgid "cannot specify pathnames with --stdin"
msgstr "không thể chỉ định các tên Ä‘Æ°á»ng dẫn vá»›i --stdin"
-#: builtin/check-ignore.c:154
+#: builtin/check-ignore.c:146
msgid "-z only makes sense with --stdin"
msgstr "-z chỉ hợp lý với --stdin"
-#: builtin/check-ignore.c:156
+#: builtin/check-ignore.c:148
msgid "no path specified"
msgstr "chÆ°a ghi rõ Ä‘Æ°á»ng dẫn"
-#: builtin/check-ignore.c:160
+#: builtin/check-ignore.c:152
msgid "--quiet is only valid with a single pathname"
msgstr "--quiet chỉ hợp lệ vá»›i tên Ä‘Æ°á»ng dẫn Ä‘Æ¡n"
-#: builtin/check-ignore.c:162
+#: builtin/check-ignore.c:154
msgid "cannot have both --quiet and --verbose"
msgstr "không thể dùng cả hai tùy chá»n --quiet và --verbose"
+#: builtin/check-ignore.c:157
+msgid "--non-matching is only valid with --verbose"
+msgstr "tùy-chá»n --non-matching chỉ hợp lệ khi dùng vá»›i --verbose"
+
+#: builtin/check-mailmap.c:8
+msgid "git check-mailmap [options] <contact>..."
+msgstr "git check-mailmap [các-tùy-chá»n] <danh-bạ>..."
+
+#: builtin/check-mailmap.c:13
+msgid "also read contacts from stdin"
+msgstr "đồng thá»i Ä‘á»c các danh bạ từ đầu vào tiêu chuẩn"
+
+#: builtin/check-mailmap.c:24
+#, c-format
+msgid "unable to parse contact: %s"
+msgstr "không thể phân tích danh bạ: “%sâ€"
+
+#: builtin/check-mailmap.c:47
+msgid "no contacts specified"
+msgstr "chưa chỉ ra danh bạ"
+
#: builtin/checkout-index.c:126
msgid "git checkout-index [options] [--] [<file>...]"
msgstr "git checkout-index [các-tùy-chá»n] [--] [<tập-tin>...]"
@@ -2815,107 +3176,107 @@ msgstr "git checkout [các-tùy-chá»n] <nhánh>"
msgid "git checkout [options] [<branch>] -- <file>..."
msgstr "git checkout [các-tùy-chá»n] [<nhánh>] -- <tập-tin>..."
-#: builtin/checkout.c:116 builtin/checkout.c:149
+#: builtin/checkout.c:117 builtin/checkout.c:150
#, 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:118 builtin/checkout.c:151
+#: builtin/checkout.c:119 builtin/checkout.c:152
#, 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:134
+#: builtin/checkout.c:135
#, 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:178
+#: builtin/checkout.c:179
#, 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:195
+#: builtin/checkout.c:196
#, c-format
msgid "path '%s': cannot merge"
msgstr "Ä‘Æ°á»ng dẫn “%sâ€: không thể hòa trá»™n"
-#: builtin/checkout.c:212
+#: builtin/checkout.c:213
#, 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:236 builtin/checkout.c:239 builtin/checkout.c:242
-#: builtin/checkout.c:245
+#: builtin/checkout.c:237 builtin/checkout.c:240 builtin/checkout.c:243
+#: builtin/checkout.c:246
#, c-format
msgid "'%s' cannot be used with updating paths"
msgstr "“%s†không thể được sá»­ dụng vá»›i các Ä‘Æ°á»ng dẫn cập nhật"
-#: builtin/checkout.c:248 builtin/checkout.c:251
+#: builtin/checkout.c:249 builtin/checkout.c:252
#, c-format
msgid "'%s' cannot be used with %s"
msgstr "“%s†không thể được sử dụng với %s"
-#: builtin/checkout.c:254
+#: builtin/checkout.c:255
#, c-format
msgid "Cannot update paths and switch to branch '%s' at the same time."
msgstr ""
"Không thể cập nhật các Ä‘Æ°á»ng dẫn và chuyển đến nhánh “%s†cùng má»™t lúc."
-#: builtin/checkout.c:265 builtin/checkout.c:426
+#: builtin/checkout.c:266 builtin/checkout.c:458
msgid "corrupt index file"
msgstr "tập tin ghi bảng mục lục bị há»ng"
-#: builtin/checkout.c:295 builtin/checkout.c:302
+#: builtin/checkout.c:329 builtin/checkout.c:336
#, c-format
msgid "path '%s' is unmerged"
msgstr "Ä‘Æ°á»ng dẫn “%s†không được hòa trá»™n"
-#: builtin/checkout.c:448
+#: builtin/checkout.c:480
msgid "you need to resolve your current index first"
msgstr "bạn cần phải phân giải bảng mục lục hiện tại của bạn trước đã"
-#: builtin/checkout.c:569
+#: builtin/checkout.c:601
#, c-format
msgid "Can not do reflog for '%s'\n"
msgstr "Không thể thá»±c hiện reflog cho “%sâ€\n"
-#: builtin/checkout.c:602
+#: builtin/checkout.c:639
msgid "HEAD is now at"
msgstr "HEAD hiện giỠtại"
-#: builtin/checkout.c:609
+#: builtin/checkout.c:646
#, c-format
msgid "Reset branch '%s'\n"
msgstr "Äặt lại nhánh “%sâ€\n"
-#: builtin/checkout.c:612
+#: builtin/checkout.c:649
#, c-format
msgid "Already on '%s'\n"
msgstr "Äã sẵn sàng trên “%sâ€\n"
-#: builtin/checkout.c:616
+#: builtin/checkout.c:653
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr "Äã chuyển tá»›i và reset nhánh “%sâ€\n"
-#: builtin/checkout.c:618 builtin/checkout.c:955
+#: builtin/checkout.c:655 builtin/checkout.c:997
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr "Äã chuyển đến nhánh má»›i “%sâ€\n"
-#: builtin/checkout.c:620
+#: builtin/checkout.c:657
#, c-format
msgid "Switched to branch '%s'\n"
msgstr "Äã chuyển đến nhánh “%sâ€\n"
-#: builtin/checkout.c:676
+#: builtin/checkout.c:713
#, c-format
msgid " ... and %d more.\n"
msgstr " ... và nhiá»u hÆ¡n %d.\n"
#. The singular version
-#: builtin/checkout.c:682
+#: builtin/checkout.c:719
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -2940,7 +3301,7 @@ msgstr[1] ""
"\n"
"%s\n"
-#: builtin/checkout.c:700
+#: builtin/checkout.c:737
#, c-format
msgid ""
"If you want to keep them by creating a new branch, this may be a good time\n"
@@ -2956,134 +3317,138 @@ msgstr ""
" git branch tên_nhánh_mới %s\n"
"\n"
-#: builtin/checkout.c:730
+#: builtin/checkout.c:767
msgid "internal error in revision walk"
-msgstr "lỗi nội bộ trong khi di chuyển qua các điểm xét lại"
+msgstr "lỗi nội bộ trong khi di chuyển qua các điểm xét duyệt"
-#: builtin/checkout.c:734
+#: builtin/checkout.c:771
msgid "Previous HEAD position was"
msgstr "Vị trí kế trước của HEAD là"
-#: builtin/checkout.c:761 builtin/checkout.c:950
+#: builtin/checkout.c:798 builtin/checkout.c:992
msgid "You are on a branch yet to be born"
msgstr "Bạn tại nhánh mà nó chưa hỠđược sinh ra"
#. case (1)
-#: builtin/checkout.c:886
+#: builtin/checkout.c:928
#, c-format
msgid "invalid reference: %s"
msgstr "tham chiếu sai: %s"
#. case (1): want a tree
-#: builtin/checkout.c:925
+#: builtin/checkout.c:967
#, c-format
msgid "reference is not a tree: %s"
msgstr "tham chiếu không phải là một cây (tree):%s"
-#: builtin/checkout.c:964
+#: builtin/checkout.c:1006
msgid "paths cannot be used with switching branches"
msgstr "các Ä‘Æ°á»ng dẫn không thể dùng cùng vá»›i các nhánh chuyển"
-#: builtin/checkout.c:967 builtin/checkout.c:971
+#: builtin/checkout.c:1009 builtin/checkout.c:1013
#, c-format
msgid "'%s' cannot be used with switching branches"
msgstr "“%s†không thể được sử dụng với các nhánh chuyển"
-#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983
-#: builtin/checkout.c:986
+#: builtin/checkout.c:1017 builtin/checkout.c:1020 builtin/checkout.c:1025
+#: builtin/checkout.c:1028
#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "“%s†không thể được sá»­ dụng vá»›i “%sâ€"
-#: builtin/checkout.c:991
+#: builtin/checkout.c:1033
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
msgstr "Không thể chuyển nhánh đến má»™t non-commit “%sâ€"
-#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89
+#: builtin/checkout.c:1055 builtin/checkout.c:1057 builtin/clone.c:89
#: builtin/remote.c:169 builtin/remote.c:171
msgid "branch"
msgstr "nhánh"
-#: builtin/checkout.c:1014
+#: builtin/checkout.c:1056
msgid "create and checkout a new branch"
msgstr "tạo và checkout một nhánh mới"
-#: builtin/checkout.c:1016
+#: builtin/checkout.c:1058
msgid "create/reset and checkout a branch"
msgstr "create/reset và checkout một nhánh"
-#: builtin/checkout.c:1017
+#: builtin/checkout.c:1059
msgid "create reflog for new branch"
msgstr "tạo reflog cho nhánh mới"
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1060
msgid "detach the HEAD at named commit"
msgstr "rá»i bá» HEAD tại lần chuyển giao danh nghÄ©a"
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1061
msgid "set upstream info for new branch"
msgstr "đặt thông tin thượng nguồn (upstream) cho nhánh mới"
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new branch"
msgstr "nhánh mới"
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new unparented branch"
msgstr "nhánh mồ côi mới"
-#: builtin/checkout.c:1022
+#: builtin/checkout.c:1064
msgid "checkout our version for unmerged files"
msgstr ""
"lấy ra (checkout) phiên bản của chúng ta cho các tập tin chưa được hòa trộn"
-#: builtin/checkout.c:1024
+#: builtin/checkout.c:1066
msgid "checkout their version for unmerged files"
msgstr ""
"lấy ra (checkout) phiên bản của chúng hỠcho các tập tin chưa được hòa trộn"
-#: builtin/checkout.c:1026
+#: builtin/checkout.c:1068
msgid "force checkout (throw away local modifications)"
msgstr "ép buộc lấy ra (checkout) (bỠđi những thay đổi nội bộ)"
-#: builtin/checkout.c:1027
+#: builtin/checkout.c:1069
msgid "perform a 3-way merge with the new branch"
msgstr "thực hiện hòa trộn kiểu 3-way với nhánh mới"
-#: builtin/checkout.c:1028 builtin/merge.c:215
+#: builtin/checkout.c:1070 builtin/merge.c:232
msgid "update ignored files (default)"
msgstr "cập nhật các tập tin bị bỠqua (mặc định)"
-#: builtin/checkout.c:1029 builtin/log.c:1147 parse-options.h:245
+#: builtin/checkout.c:1071 builtin/log.c:1208 parse-options.h:249
msgid "style"
msgstr "kiểu"
-#: builtin/checkout.c:1030
+#: builtin/checkout.c:1072
msgid "conflict style (merge or diff3)"
msgstr "xung đột kiểu (hòa trộn hay diff3)"
-#: builtin/checkout.c:1033
+#: builtin/checkout.c:1075
+msgid "do not limit pathspecs to sparse entries only"
+msgstr "không giới hạn pathspecs chỉ thành các mục thưa thớt"
+
+#: builtin/checkout.c:1077
msgid "second guess 'git checkout no-such-branch'"
msgstr "gợi ý thứ hai “git checkout không-nhánh-nào-nhÆ°-vậyâ€"
-#: builtin/checkout.c:1057
+#: builtin/checkout.c:1101
msgid "-b, -B and --orphan are mutually exclusive"
msgstr "Tùy chá»n -b|-B và --orphan loại từ lẫn nhau"
-#: builtin/checkout.c:1074
+#: builtin/checkout.c:1118
msgid "--track needs a branch name"
msgstr "--track cần tên một nhánh"
-#: builtin/checkout.c:1081
+#: builtin/checkout.c:1125
msgid "Missing branch name; try -b"
msgstr "Thiếu tên nhánh; hãy thử -b"
-#: builtin/checkout.c:1116
+#: builtin/checkout.c:1160
msgid "invalid path specification"
msgstr "Ä‘Æ°á»ng dẫn đã cho không hợp lệ"
-#: builtin/checkout.c:1123
+#: builtin/checkout.c:1167
#, c-format
msgid ""
"Cannot update paths and switch to branch '%s' at the same time.\n"
@@ -3093,12 +3458,12 @@ msgstr ""
"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:1128
+#: builtin/checkout.c:1172
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
msgstr "git checkout: --detach không nhận má»™t đối số Ä‘Æ°á»ng dẫn “%sâ€"
-#: builtin/checkout.c:1132
+#: builtin/checkout.c:1176
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
@@ -3106,89 +3471,192 @@ msgstr ""
"git checkout: --ours/--theirs, --force và --merge là xung khắc với nhau khi\n"
"checkout bảng mục lục (index)."
-#: builtin/clean.c:20
-msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
-msgstr "git clean [-d] [-f] [-n] [-q] [-e <mẫu>] [-x | -X] [--] <Ä‘Æ°á»ng-dẫn>..."
+#: builtin/clean.c:25
+msgid ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <mẫu>] [-x | -X] [--] <Ä‘Æ°á»ng-dẫn>..."
-#: builtin/clean.c:24
+#: builtin/clean.c:29
#, c-format
msgid "Removing %s\n"
msgstr "Äang gỡ bá» %s\n"
-#: builtin/clean.c:25
+#: builtin/clean.c:30
#, c-format
msgid "Would remove %s\n"
msgstr "Có thể gỡ bỠ%s\n"
-#: builtin/clean.c:26
+#: builtin/clean.c:31
#, c-format
msgid "Skipping repository %s\n"
msgstr "Äang bá» qua kho chứa %s\n"
-#: builtin/clean.c:27
+#: builtin/clean.c:32
#, c-format
msgid "Would skip repository %s\n"
msgstr "Nên bỠqua kho chứa %s\n"
-#: builtin/clean.c:28
+#: builtin/clean.c:33
#, c-format
msgid "failed to remove %s"
msgstr "gặp lỗi khi gỡ bỠ%s"
-#: builtin/clean.c:160
+#: builtin/clean.c:293
+msgid ""
+"Prompt help:\n"
+"1 - select a numbered item\n"
+"foo - select item based on unique prefix\n"
+" - (empty) select nothing"
+msgstr ""
+"Trợ giúp vỠnhắc:\n"
+"1 - chá»n má»™t mục được đánh số\n"
+"foo - chá»n mục trên cÆ¡ sở tiá»n tố duy nhất\n"
+" - (trống rá»—ng) không chá»n gì cả"
+
+#: builtin/clean.c:297
+msgid ""
+"Prompt help:\n"
+"1 - select a single item\n"
+"3-5 - select a range of items\n"
+"2-3,6-9 - select multiple ranges\n"
+"foo - select item based on unique prefix\n"
+"-... - unselect specified items\n"
+"* - choose all items\n"
+" - (empty) finish selecting"
+msgstr ""
+"Trợ giúp vỠnhắc:\n"
+"1 - chá»n má»™t mục Ä‘Æ¡n\n"
+"3-5 - chá»n má»™t vùng\n"
+"2-3,6-9 - chá»n nhiá»u vùng\n"
+"foo - chá»n mục dá»±a trên tiá»n tố duy nhất\n"
+"-... - không chá»n các mục đã chỉ ra\n"
+"* - chá»n tất\n"
+" - (trống rá»—ng) kết thúc việc chá»n"
+
+#: builtin/clean.c:515
+#, c-format
+msgid "Huh (%s)?"
+msgstr "Hả (%s)?"
+
+#: builtin/clean.c:658
+#, c-format
+msgid "Input ignore patterns>> "
+msgstr "Mẫu để lá»c các tập tin cần lá» Ä‘i đầu vào>>"
+
+#: builtin/clean.c:695
+#, c-format
+msgid "WARNING: Cannot find items matched by: %s"
+msgstr "CẢNH BÃO: Không tìm thấy các mục được khá»›p bởi: %s"
+
+#: builtin/clean.c:716
+msgid "Select items to delete"
+msgstr "Chá»n mục muốn xóa"
+
+#: builtin/clean.c:756
+#, c-format
+msgid "remove %s? "
+msgstr "gỡ bỠ“%s�"
+
+#: builtin/clean.c:781
+msgid "Bye."
+msgstr "Tạm biệt."
+
+#: builtin/clean.c:789
+msgid ""
+"clean - start cleaning\n"
+"filter by pattern - exclude items from deletion\n"
+"select by numbers - select items to be deleted by numbers\n"
+"ask each - confirm each deletion (like \"rm -i\")\n"
+"quit - stop cleaning\n"
+"help - this screen\n"
+"? - help for prompt selection"
+msgstr ""
+"clean - bắt đầu dá»n dẹp\n"
+"filter by pattern - loại trừ các mục khá»i việc xóa\n"
+"select by numbers - chá»n các mục cần xóa bằng số\n"
+"ask each - xác nhận trước mỗi lần xóa (giống như \"rm -i\")\n"
+"quit - dừng việc dá»n dẹp lại\n"
+"help - hiển thị chính trợ giúp này\n"
+"? - trợ giúp dành cho chá»n bằng cách nhắc"
+
+#: builtin/clean.c:816
+msgid "*** Commands ***"
+msgstr "*** Lệnh ***"
+
+#: builtin/clean.c:817
+msgid "What now"
+msgstr "GiỠthì sao"
+
+#: builtin/clean.c:825
+msgid "Would remove the following item:"
+msgid_plural "Would remove the following items:"
+msgstr[0] "Có muốn gỡ bỠmục sau đây không:"
+msgstr[1] "Có muốn gỡ bỠcác mục sau đây không:"
+
+#: builtin/clean.c:842
+msgid "No more files to clean, exiting."
+msgstr "Không còn tập-tin nào để dá»n dẹp, Ä‘ang thoát ra."
+
+#: builtin/clean.c:874
msgid "do not print names of files removed"
msgstr "không hiển thị tên của các tập tin đã gỡ bá»"
-#: builtin/clean.c:162
+#: builtin/clean.c:876
msgid "force"
msgstr "ép buộc"
-#: builtin/clean.c:164
+#: builtin/clean.c:877
+msgid "interactive cleaning"
+msgstr "sửa bằng cách tương tác"
+
+#: builtin/clean.c:879
msgid "remove whole directories"
msgstr "gỡ bỠtoàn bộ thư mục"
-#: builtin/clean.c:165 builtin/describe.c:413 builtin/grep.c:717
-#: builtin/ls-files.c:494 builtin/name-rev.c:231 builtin/show-ref.c:182
+#: builtin/clean.c:880 builtin/describe.c:420 builtin/grep.c:716
+#: builtin/ls-files.c:493 builtin/name-rev.c:315 builtin/show-ref.c:186
msgid "pattern"
msgstr "mẫu"
-#: builtin/clean.c:166
+#: builtin/clean.c:881
msgid "add <pattern> to ignore rules"
msgstr "thêm <mẫu> vào trong qui tắc bỠqua"
-#: builtin/clean.c:167
+#: builtin/clean.c:882
msgid "remove ignored files, too"
msgstr "đồng thá»i gỡ bá» cả các tập tin bị bá» qua"
-#: builtin/clean.c:169
+#: builtin/clean.c:884
msgid "remove only ignored files"
msgstr "chỉ gỡ bỠnhững tập tin bị bỠqua"
-#: builtin/clean.c:187
+#: builtin/clean.c:902
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:191
+#: builtin/clean.c:906
msgid ""
-"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+"clean.requireForce set to true and neither -i, -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 "
+"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:194
+#: builtin/clean.c:909
msgid ""
-"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
-"clean"
+"clean.requireForce defaults to true and neither -i, -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)"
+"clean.requireForce mặc định được đặt là 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/clone.c:36
msgid "git clone [options] [--] <repo> [<dir>]"
msgstr "git clone [các-tùy-chá»n] [--] <kho> [<t.mục>]"
-#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
-#: builtin/push.c:436
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:229
+#: builtin/push.c:462
msgid "force progress reporting"
msgstr "ép buộc báo cáo tiến trình"
@@ -3248,7 +3716,7 @@ msgstr "lấy ra nhánh (checkout <nhánh>) thay vì HEAD của máy chủ"
msgid "path to git-upload-pack on the remote"
msgstr "Ä‘Æ°á»ng dẫn đến git-upload-pack trên máy chủ"
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:661
msgid "depth"
msgstr "độ sâu"
@@ -3276,122 +3744,154 @@ msgstr "khóa=giá trị"
msgid "set config inside the new repository"
msgstr "đặt cấu hình bên trong một kho chứa mới"
-#: builtin/clone.c:243
+#: builtin/clone.c:253
#, c-format
-msgid "reference repository '%s' is not a local directory."
-msgstr "kho tham chiếu “%s†không phải là một thư mục nội bộ."
+msgid "reference repository '%s' is not a local repository."
+msgstr "kho tham chiếu “%s†không phải là một kho nội bộ."
-#: builtin/clone.c:306
+#: builtin/clone.c:316
#, 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:77
+#: builtin/clone.c:318 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â€"
-#: builtin/clone.c:310
+#: builtin/clone.c:320
#, c-format
msgid "%s exists and is not a directory"
msgstr "%s tồn tại nhưng không phải là một thư mục"
-#: builtin/clone.c:324
+#: builtin/clone.c:334
#, c-format
msgid "failed to stat %s\n"
msgstr "lá»—i stat (lấy trạng thái vá») %s\n"
-#: builtin/clone.c:346
+#: builtin/clone.c:356
#, c-format
msgid "failed to create link '%s'"
msgstr "gặp lá»—i khi tạo được liên kết má»m %s"
-#: builtin/clone.c:350
+#: builtin/clone.c:360
#, c-format
msgid "failed to copy file to '%s'"
msgstr "gặp lá»—i khi chép tập tin tá»›i “%sâ€"
-#: builtin/clone.c:373
+#: builtin/clone.c:383
#, c-format
msgid "done.\n"
msgstr "hoàn tất.\n"
-#: builtin/clone.c:443
+#: builtin/clone.c:396
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry the checkout with 'git checkout -f HEAD'\n"
+msgstr ""
+"Việc nhân bản thành công, nhưng checkout gặp lỗi.\n"
+"Bạn kiểm tra kỹ xem cái gì được lấy ra bằng lệnh “git statusâ€\n"
+"và thá»­ checkout vá»›i lệnh “git checkout -f HEADâ€\n"
+
+#: builtin/clone.c:475
#, 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:552
+#: builtin/clone.c:555
+#, c-format
+msgid "Checking connectivity... "
+msgstr "Äang kiểm tra kết nối..."
+
+#: builtin/clone.c:558
+msgid "remote did not send all necessary objects"
+msgstr "máy chủ đã không gửi tất cả các đối tượng cần thiết"
+
+#: builtin/clone.c:560
+#, c-format
+msgid "done\n"
+msgstr "xong.\n"
+
+#: builtin/clone.c:621
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:690
+#: builtin/clone.c:652
+msgid "unable to checkout working tree"
+msgstr "không thể lấy ra (checkout) cây làm việc"
+
+#: builtin/clone.c:760
msgid "Too many arguments."
msgstr "Có quá nhiá»u đối số."
-#: builtin/clone.c:694
+#: builtin/clone.c:764
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:705
+#: builtin/clone.c:775
#, 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:708
+#: builtin/clone.c:778
msgid "--bare and --separate-git-dir are incompatible."
msgstr "tùy chá»n --bare và --separate-git-dir xung khắc nhau."
-#: builtin/clone.c:721
+#: builtin/clone.c:791
#, c-format
msgid "repository '%s' does not exist"
msgstr "kho chứa “%s†chưa tồn tại"
-#: builtin/clone.c:726
+#: builtin/clone.c:796
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:736
+#: builtin/clone.c:798
+msgid "--local is ignored"
+msgstr "--local bị lỠđi"
+
+#: builtin/clone.c:808
#, 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:746
+#: builtin/clone.c:818
#, 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:759 builtin/clone.c:771
+#: builtin/clone.c:831 builtin/clone.c:843
#, 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:762
+#: builtin/clone.c:834
#, 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:781
+#: builtin/clone.c:853
#, 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:783
+#: builtin/clone.c:855
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "Äang nhân bản thành “%sâ€...\n"
-#: builtin/clone.c:818
+#: builtin/clone.c:890
#, 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:867
+#: builtin/clone.c:942
#, 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 thượng nguồn (upstream) %s"
-#: builtin/clone.c:874
+#: builtin/clone.c:949
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."
@@ -3427,15 +3927,15 @@ msgstr "Chèn thêm khoảng trắng giữa các cột"
msgid "--command must be the first argument"
msgstr "--command phải là đối số đầu tiên"
-#: builtin/commit.c:34
+#: builtin/commit.c:35
msgid "git commit [options] [--] <pathspec>..."
msgstr "git commit [các-tùy-chá»n] [--] <pathspec>..."
-#: builtin/commit.c:39
+#: builtin/commit.c:40
msgid "git status [options] [--] <pathspec>..."
msgstr "git status [các-tùy-chá»n] [--] <pathspec>..."
-#: builtin/commit.c:44
+#: builtin/commit.c:45
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
@@ -3463,7 +3963,7 @@ msgstr ""
"\n"
" git commit --amend --reset-author\n"
-#: builtin/commit.c:56
+#: builtin/commit.c:57
msgid ""
"You asked to amend the most recent commit, but doing so would make\n"
"it empty. You can repeat your command with --allow-empty, or you can\n"
@@ -3476,114 +3976,132 @@ msgstr ""
"hoặc là bạn gỡ bỠcác lần chuyển giao một cách hoàn toàn bằng lệnh:\n"
"\"git reset HEAD^\".\n"
-#: builtin/commit.c:61
+#: builtin/commit.c:62
msgid ""
"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
"If you wish to commit it anyway, use:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Otherwise, please use 'git reset'\n"
msgstr ""
"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ếu bạn vẫ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á»­ dùng “git resetâ€\n"
-#: builtin/commit.c:258
+#: builtin/commit.c:69
+msgid "Otherwise, please use 'git reset'\n"
+msgstr "Nếu không được thì dùng lệnh \"git reset\"\n"
+
+#: builtin/commit.c:72
+msgid ""
+"If you wish to skip this commit, use:\n"
+"\n"
+" git reset\n"
+"\n"
+"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
+"the remaining commits.\n"
+msgstr ""
+"Nếu bạn muốn bỠqua lần chuyển giao này thì dùng:\n"
+"\n"
+" git reset\n"
+"\n"
+"Thế thì \"git cherry-pick --continue\" sẽ phục hồi lại việc cherry-pick\n"
+"những lần chuyển giao còn lại.\n"
+
+#: builtin/commit.c:279
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:300
+#: builtin/commit.c:321
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:306
+#: builtin/commit.c:327
msgid "interactive add failed"
msgstr "việc thêm tương tác gặp lỗi"
-#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410
+#: builtin/commit.c:360 builtin/commit.c:381 builtin/commit.c:431
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:391
+#: builtin/commit.c:412
msgid "cannot do a partial commit during a merge."
msgstr ""
"không thể thực hiện việc chuyển giao (commit) cục bộ trong khi đang được hòa "
"trá»™n."
-#: builtin/commit.c:393
+#: builtin/commit.c:414
msgid "cannot do a partial commit during a cherry-pick."
msgstr ""
"không thể thực hiện việc chuyển giao (commit) bộ phận trong khi đang cherry-"
"pick."
-#: builtin/commit.c:403
+#: builtin/commit.c:424
msgid "cannot read the index"
msgstr "không Ä‘á»c được bảng mục lục"
-#: builtin/commit.c:423
+#: builtin/commit.c:444
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:511 builtin/commit.c:517
+#: builtin/commit.c:535 builtin/commit.c:541
#, c-format
msgid "invalid commit: %s"
msgstr "lần chuyển giao (commit) không hợp lệ: %s"
-#: builtin/commit.c:540
+#: builtin/commit.c:563
msgid "malformed --author parameter"
msgstr "đối số --author bị dị hình"
-#: builtin/commit.c:560
+#: builtin/commit.c:583
#, c-format
msgid "Malformed ident string: '%s'"
msgstr "Chuá»—i thụt lỠđầu dòng dị hình: “%sâ€"
-#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954
+#: builtin/commit.c:621 builtin/commit.c:654 builtin/commit.c:982
#, 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:610 builtin/shortlog.c:272
+#: builtin/commit.c:633 builtin/shortlog.c:271
#, 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:612
+#: builtin/commit.c:635
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:616
+#: builtin/commit.c:639
#, c-format
msgid "could not read log file '%s'"
msgstr "không Ä‘á»c được tệp nhật ký “%sâ€"
-#: builtin/commit.c:622
+#: builtin/commit.c:645
msgid "commit has empty message"
msgstr "lần chuyển giao (commit) có ghi chú trống rỗng"
-#: builtin/commit.c:638
+#: builtin/commit.c:661
msgid "could not read MERGE_MSG"
msgstr "không thể Ä‘á»c MERGE_MSG"
-#: builtin/commit.c:642
+#: builtin/commit.c:665
msgid "could not read SQUASH_MSG"
msgstr "không thể Ä‘á»c SQUASH_MSG"
-#: builtin/commit.c:646
+#: builtin/commit.c:669
#, c-format
msgid "could not read '%s'"
msgstr "Không thể Ä‘á»c “%sâ€."
-#: builtin/commit.c:707
+#: builtin/commit.c:730
msgid "could not write commit template"
msgstr "không thể ghi mẫu commit"
-#: builtin/commit.c:718
+#: builtin/commit.c:741
#, c-format
msgid ""
"\n"
@@ -3598,7 +4116,7 @@ msgstr ""
"\t%s\n"
"và thử lại.\n"
-#: builtin/commit.c:723
+#: builtin/commit.c:746
#, c-format
msgid ""
"\n"
@@ -3613,7 +4131,7 @@ msgstr ""
"\t%s\n"
"và thử lại.\n"
-#: builtin/commit.c:735
+#: builtin/commit.c:758
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
@@ -3624,7 +4142,7 @@ msgstr ""
"bắt đầu bằng “%c†sẽ được bỠqua, nếu phần chú thích rỗng sẽ hủy bỠlần "
"chuyển giao (commit).\n"
-#: builtin/commit.c:740
+#: builtin/commit.c:763
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
@@ -3636,372 +4154,372 @@ msgstr ""
"bắt đầu bằng “%c†sẽ được bỠqua; bạn có thể xóa chúng đi nếu muốn thế.\n"
"Phần chú thích này nếu trống rỗng sẽ hủy bỠlần chuyển giao (commit).\n"
-#: builtin/commit.c:753
+#: builtin/commit.c:776
#, c-format
msgid "%sAuthor: %s"
msgstr "%sTác giả: %s"
-#: builtin/commit.c:760
+#: builtin/commit.c:783
#, c-format
msgid "%sCommitter: %s"
msgstr "%sNgÆ°á»i chuyển giao (commit): %s"
-#: builtin/commit.c:780
+#: builtin/commit.c:803
msgid "Cannot read index"
msgstr "không Ä‘á»c được bảng mục lục"
-#: builtin/commit.c:817
+#: builtin/commit.c:845
msgid "Error building trees"
msgstr "Gặp lỗi khi xây dựng cây"
-#: builtin/commit.c:832 builtin/tag.c:359
+#: builtin/commit.c:860 builtin/tag.c:359
#, 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:929
+#: builtin/commit.c:957
#, c-format
msgid "No existing author found with '%s'"
msgstr "Không tìm thấy tác giả có sẵn vá»›i “%sâ€"
-#: builtin/commit.c:944 builtin/commit.c:1138
+#: builtin/commit.c:972 builtin/commit.c:1208
#, 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:974
+#: builtin/commit.c:1009
+msgid "--long and -z are incompatible"
+msgstr "hai tùy chá»n -long và -z không tÆ°Æ¡ng thích vá»›i nhau"
+
+#: builtin/commit.c:1039
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:985
+#: builtin/commit.c:1050
msgid "You have nothing to amend."
msgstr "Không có gì để amend (tu bổ) cả."
-#: builtin/commit.c:988
+#: builtin/commit.c:1053
msgid "You are in the middle of a merge -- cannot amend."
msgstr ""
"Bạn đang ở giữa của quá trình hòa trộn -- không thể thực hiện amend (tu bổ)."
-#: builtin/commit.c:990
+#: builtin/commit.c:1055
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr ""
"Bạn đang ở giữa của quá trình cherry-pick -- không thể thực hiện amend (tu "
"bổ)."
-#: builtin/commit.c:993
+#: builtin/commit.c:1058
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:1003
+#: builtin/commit.c:1068
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:1005
+#: builtin/commit.c:1070
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:1013
+#: builtin/commit.c:1078
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr ""
"--reset-author chỉ có thể được sá»­ dụng vá»›i tùy chá»n -C, -c hay --amend."
-#: builtin/commit.c:1030
+#: builtin/commit.c:1095
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
msgstr ""
"Chỉ má»™t trong các tùy chá»n --include/--only/--all/--interactive/--patch được "
"sử dụng."
-#: builtin/commit.c:1032
+#: builtin/commit.c:1097
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:1034
+#: builtin/commit.c:1099
msgid "Clever... amending the last one with dirty index."
msgstr "Giá»i... tu bổ cái cuối vá»›i bảng mục lục phi nghÄ©a."
-#: builtin/commit.c:1036
+#: builtin/commit.c:1101
msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
msgstr ""
"Những Ä‘Æ°á»ng dẫn rõ ràng được chỉ ra không có tùy chá»n -i cÅ©ng không -o; Ä‘ang "
"giả định --only những-Ä‘Æ°á»ng-dẫn..."
-#: builtin/commit.c:1046 builtin/tag.c:575
+#: builtin/commit.c:1111 builtin/tag.c:575
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "Chế Ä‘á»™ dá»n dẹp không hợp lệ %s"
-#: builtin/commit.c:1051
+#: builtin/commit.c:1116
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:1057 builtin/commit.c:1192
-msgid "--long and -z are incompatible"
-msgstr "hai tùy chá»n -long và -z không tÆ°Æ¡ng thích vá»›i nhau"
-
-#: builtin/commit.c:1152 builtin/commit.c:1388
+#: builtin/commit.c:1222 builtin/commit.c:1455
msgid "show status concisely"
msgstr "hiển thị trạng thái ở dạng súc tích"
-#: builtin/commit.c:1154 builtin/commit.c:1390
+#: builtin/commit.c:1224 builtin/commit.c:1457
msgid "show branch information"
msgstr "hiển thị thông tin nhánh"
-#: builtin/commit.c:1156 builtin/commit.c:1392 builtin/push.c:426
+#: builtin/commit.c:1226 builtin/commit.c:1459 builtin/push.c:452
msgid "machine-readable output"
msgstr "kết xuất dạng máy-có-thể-Ä‘á»c"
-#: builtin/commit.c:1159 builtin/commit.c:1394
+#: builtin/commit.c:1229 builtin/commit.c:1461
msgid "show status in long format (default)"
msgstr "hiển thị trạng thái ở định dạng dài (mặc định)"
-#: builtin/commit.c:1162 builtin/commit.c:1397
+#: builtin/commit.c:1232 builtin/commit.c:1464
msgid "terminate entries with NUL"
msgstr "chấm dứt các mục bằng NUL"
-#: builtin/commit.c:1164 builtin/commit.c:1400 builtin/fast-export.c:647
-#: builtin/fast-export.c:650 builtin/tag.c:459
+#: builtin/commit.c:1234 builtin/commit.c:1467 builtin/fast-export.c:667
+#: builtin/fast-export.c:670 builtin/tag.c:459
msgid "mode"
msgstr "chế độ"
-#: builtin/commit.c:1165 builtin/commit.c:1400
+#: builtin/commit.c:1235 builtin/commit.c:1467
msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
msgstr ""
"hiển thị các tập tin chÆ°a được theo dõi dấu vết, các chế Ä‘á»™ tùy chá»n: all, "
"normal, no. (Mặc định: all)"
-#: builtin/commit.c:1168
+#: builtin/commit.c:1238
msgid "show ignored files"
msgstr "hiển thị các tập tin ẩn"
-#: builtin/commit.c:1169 parse-options.h:151
+#: builtin/commit.c:1239 parse-options.h:154
msgid "when"
msgstr "khi"
-#: builtin/commit.c:1170
+#: builtin/commit.c:1240
msgid ""
"ignore changes to submodules, optional when: all, dirty, untracked. "
"(Default: all)"
msgstr ""
-"bá» qua các thay đổi trong mô-Ä‘un con, tùy chá»n khi: all, dirty, untracked. "
+"bá» qua các thay đổi trong mô-Ä‘un-con, tùy chá»n khi: all, dirty, untracked. "
"(Mặc định: all)"
-#: builtin/commit.c:1172
+#: builtin/commit.c:1242
msgid "list untracked files in columns"
msgstr "hiển thị danh sách các tập-tin chưa được theo dõi trong các cột"
-#: builtin/commit.c:1246
+#: builtin/commit.c:1313
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:1248
+#: builtin/commit.c:1315
msgid "could not parse newly created commit"
msgstr ""
"không thể phân tích cú pháp của đối tượng chuyển giao mới hơn đã được tạo"
-#: builtin/commit.c:1289
+#: builtin/commit.c:1356
msgid "detached HEAD"
msgstr "đã rá»i khá»i HEAD"
-#: builtin/commit.c:1291
+#: builtin/commit.c:1358
msgid " (root-commit)"
msgstr " (root-commit)"
-#: builtin/commit.c:1358
+#: builtin/commit.c:1425
msgid "suppress summary after successful commit"
msgstr "không hiển thị tổng kết sau khi chuyển giao thành công"
-#: builtin/commit.c:1359
+#: builtin/commit.c:1426
msgid "show diff in commit message template"
msgstr "hiển thị sự khác biệt trong mẫu tin nhắn chuyển giao"
-#: builtin/commit.c:1361
+#: builtin/commit.c:1428
msgid "Commit message options"
msgstr "Các tùy chá»n ghi chú commit"
-#: builtin/commit.c:1362 builtin/tag.c:457
+#: builtin/commit.c:1429 builtin/tag.c:457
msgid "read message from file"
msgstr "Ä‘á»c chú thích từ tập tin"
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "author"
msgstr "tác giả"
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "override author for commit"
msgstr "ghi đè tác giả cho commit"
-#: builtin/commit.c:1364 builtin/gc.c:178
+#: builtin/commit.c:1431 builtin/gc.c:178
msgid "date"
msgstr "ngày tháng"
-#: builtin/commit.c:1364
+#: builtin/commit.c:1431
msgid "override date for commit"
msgstr "ghi đè ngày tháng cho commit"
-#: builtin/commit.c:1365 builtin/merge.c:206 builtin/notes.c:533
-#: builtin/notes.c:690 builtin/tag.c:455
+#: builtin/commit.c:1432 builtin/merge.c:223 builtin/notes.c:405
+#: builtin/notes.c:562 builtin/tag.c:455
msgid "message"
msgstr "thông điệp"
-#: builtin/commit.c:1365
+#: builtin/commit.c:1432
msgid "commit message"
msgstr "chú thích của lần commit"
-#: builtin/commit.c:1366
+#: builtin/commit.c:1433
msgid "reuse and edit message from specified commit"
msgstr ""
"dùng lại các ghi chú từ lần chuyển giao (commit) đã cho nhưng có cho sửa chữa"
-#: builtin/commit.c:1367
+#: builtin/commit.c:1434
msgid "reuse message from specified commit"
msgstr "dùng lại các ghi chú từ lần chuyển giao (commit) đã cho"
-#: builtin/commit.c:1368
+#: builtin/commit.c:1435
msgid "use autosquash formatted message to fixup specified commit"
msgstr ""
"dùng ghi chú có định dạng autosquash để sửa chữa lần chuyển giao đã chỉ ra"
-#: builtin/commit.c:1369
+#: builtin/commit.c:1436
msgid "use autosquash formatted message to squash specified commit"
msgstr ""
"dùng lá»i nhắn có định dạng tá»± Ä‘á»™ng nén để nén lại các lần chuyển giao đã chỉ "
"ra"
-#: builtin/commit.c:1370
+#: builtin/commit.c:1437
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr ""
"lần chuyển giao nhận tôi là tác giả (được dùng vá»›i tùy chá»n -C/-c/--amend)"
-#: builtin/commit.c:1371 builtin/log.c:1102 builtin/revert.c:109
+#: builtin/commit.c:1438 builtin/log.c:1160 builtin/revert.c:111
msgid "add Signed-off-by:"
msgstr "thêm dòng Signed-off-by:"
-#: builtin/commit.c:1372
+#: builtin/commit.c:1439
msgid "use specified template file"
msgstr "sử dụng tập tin mẫu đã cho"
-#: builtin/commit.c:1373
+#: builtin/commit.c:1440
msgid "force edit of commit"
msgstr "ép buộc sửa lần commit"
-#: builtin/commit.c:1374
+#: builtin/commit.c:1441
msgid "default"
msgstr "mặc định"
-#: builtin/commit.c:1374 builtin/tag.c:460
+#: builtin/commit.c:1441 builtin/tag.c:460
msgid "how to strip spaces and #comments from message"
msgstr "làm thế nào để cắt bỠkhoảng trắng và #ghichú từ mẩu tin nhắn"
-#: builtin/commit.c:1375
+#: builtin/commit.c:1442
msgid "include status in commit message template"
msgstr "bao gồm các trạng thái ghi mẫu ghi chú chuyển giao (commit)"
-#: builtin/commit.c:1376 builtin/merge.c:213 builtin/tag.c:461
+#: builtin/commit.c:1443 builtin/merge.c:230 builtin/tag.c:461
msgid "key id"
msgstr "id khóa"
-#: builtin/commit.c:1377 builtin/merge.c:214
+#: builtin/commit.c:1444 builtin/merge.c:231
msgid "GPG sign commit"
msgstr "ký lần commit dùng GPG"
#. end commit message options
-#: builtin/commit.c:1380
+#: builtin/commit.c:1447
msgid "Commit contents options"
msgstr "Các tùy nội dung ghi chú commit"
-#: builtin/commit.c:1381
+#: builtin/commit.c:1448
msgid "commit all changed files"
msgstr "chuyển giao tất cả các tập tin có thay đổi"
-#: builtin/commit.c:1382
+#: builtin/commit.c:1449
msgid "add specified files to index for commit"
msgstr "thêm các tập tin đã chỉ ra vào bảng mục lục để chuyển giao (commit)"
-#: builtin/commit.c:1383
+#: builtin/commit.c:1450
msgid "interactively add files"
msgstr "thêm các tập-tin bằng tương tác"
-#: builtin/commit.c:1384
+#: builtin/commit.c:1451
msgid "interactively add changes"
msgstr "thêm các thay đổi bằng tương tác"
-#: builtin/commit.c:1385
+#: builtin/commit.c:1452
msgid "commit only specified files"
msgstr "chỉ chuyển giao các tập tin đã chỉ ra"
-#: builtin/commit.c:1386
+#: builtin/commit.c:1453
msgid "bypass pre-commit hook"
msgstr "vòng qua móc (hook) pre-commit"
-#: builtin/commit.c:1387
+#: builtin/commit.c:1454
msgid "show what would be committed"
msgstr "hiển thị xem cái gì có thể được chuyển giao"
-#: builtin/commit.c:1398
+#: builtin/commit.c:1465
msgid "amend previous commit"
msgstr "tu bổ (amend) lần commit trước"
-#: builtin/commit.c:1399
+#: builtin/commit.c:1466
msgid "bypass post-rewrite hook"
msgstr "vòng qua móc (hook) post-rewrite"
-#: builtin/commit.c:1404
+#: builtin/commit.c:1471
msgid "ok to record an empty change"
msgstr "ok để ghi lại một thay đổi trống rỗng"
-#: builtin/commit.c:1407
+#: builtin/commit.c:1474
msgid "ok to record a change with an empty message"
msgstr "ok để ghi các thay đổi vá»›i lá»i nhắn trống rá»—ng"
-#: builtin/commit.c:1439
+#: builtin/commit.c:1507
msgid "could not parse HEAD commit"
msgstr "không thể phân tích commit (lần chuyển giao) HEAD"
-#: builtin/commit.c:1477 builtin/merge.c:508
+#: builtin/commit.c:1545 builtin/merge.c:525
#, c-format
msgid "could not open '%s' for reading"
msgstr "không thể mở “%s†để Ä‘á»c"
-#: builtin/commit.c:1484
+#: builtin/commit.c:1552
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "Tập tin MERGE_HEAD sai há»ng (%s)"
-#: builtin/commit.c:1491
+#: builtin/commit.c:1559
msgid "could not read MERGE_MODE"
msgstr "không thể Ä‘á»c MERGE_MODE"
-#: builtin/commit.c:1510
+#: builtin/commit.c:1578
#, 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:1524
+#: builtin/commit.c:1592
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr ""
"Äang bá» qua việc chuyển giao (commit); bạn đã không biên soạn thông Ä‘iệp "
"(message).\n"
-#: builtin/commit.c:1529
+#: builtin/commit.c:1597
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr ""
"Äang bá» qua lần chuyển giao (commit) bởi vì thông Ä‘iệp của nó trống rá»—ng.\n"
-#: builtin/commit.c:1544 builtin/merge.c:832 builtin/merge.c:857
+#: builtin/commit.c:1612 builtin/merge.c:861 builtin/merge.c:886
msgid "failed to write commit object"
msgstr "gặp lỗi khi ghi đối tượng chuyển giao (commit)"
-#: builtin/commit.c:1565
+#: builtin/commit.c:1633
msgid "cannot lock HEAD ref"
msgstr "không thể khóa HEAD ref (tham chiếu)"
-#: builtin/commit.c:1569
+#: builtin/commit.c:1637
msgid "cannot update HEAD ref"
msgstr "không thể cập nhật ref (tham chiếu) HEAD"
-#: builtin/commit.c:1580
+#: builtin/commit.c:1648
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
@@ -4016,171 +4534,183 @@ msgstr ""
msgid "git config [options]"
msgstr "git config [các-tùy-chá»n]"
-#: builtin/config.c:51
+#: builtin/config.c:52
msgid "Config file location"
msgstr "Vị trí tập tin cấu hình"
-#: builtin/config.c:52
+#: builtin/config.c:53
msgid "use global config file"
msgstr "đặt tập tin cấu hình cần toàn cục"
-#: builtin/config.c:53
+#: builtin/config.c:54
msgid "use system config file"
msgstr "sử dụng tập tin cấu hình hệ thống"
-#: builtin/config.c:54
+#: builtin/config.c:55
msgid "use repository config file"
msgstr "dùng tập tin cấu hình của kho"
-#: builtin/config.c:55
+#: builtin/config.c:56
msgid "use given config file"
msgstr "sử dụng tập tin cấu hình đã cho"
-#: builtin/config.c:56
+#: builtin/config.c:57
+msgid "blob-id"
+msgstr "blob-id"
+
+#: builtin/config.c:57
+msgid "read config from given blob object"
+msgstr "Ä‘á»c cấu hình từ đối tượng blob đã cho"
+
+#: builtin/config.c:58
msgid "Action"
msgstr "Hành động"
-#: builtin/config.c:57
+#: builtin/config.c:59
msgid "get value: name [value-regex]"
msgstr "lấy giá-trị: tên [value-regex]"
-#: builtin/config.c:58
+#: builtin/config.c:60
msgid "get all values: key [value-regex]"
msgstr "lấy tất cả giá-trị: khóa [value-regex]"
-#: builtin/config.c:59
+#: builtin/config.c:61
msgid "get values for regexp: name-regex [value-regex]"
msgstr "lấy giá trị cho regexp: name-regex [value-regex]"
-#: builtin/config.c:60
+#: builtin/config.c:62
msgid "replace all matching variables: name value [value_regex]"
msgstr "thay thế tất cả các biến khớp mẫu: tên giá-trị [value_regex]"
-#: builtin/config.c:61
+#: builtin/config.c:63
msgid "add a new variable: name value"
msgstr "thêm biến mới: tên giá-trị"
-#: builtin/config.c:62
+#: builtin/config.c:64
msgid "remove a variable: name [value-regex]"
msgstr "gỡ bỠbiến: tên [value-regex]"
-#: builtin/config.c:63
+#: builtin/config.c:65
msgid "remove all matches: name [value-regex]"
msgstr "gỡ bá» má»i cái khá»›p: tên [value-regex]"
-#: builtin/config.c:64
+#: builtin/config.c:66
msgid "rename section: old-name new-name"
msgstr "đổi tên chương: tên-cũ tên-mới"
-#: builtin/config.c:65
+#: builtin/config.c:67
msgid "remove a section: name"
msgstr "gỡ bỠchương: tên"
-#: builtin/config.c:66
+#: builtin/config.c:68
msgid "list all"
msgstr "liệt kê tất"
-#: builtin/config.c:67
+#: builtin/config.c:69
msgid "open an editor"
msgstr "mở một trình biên soạn"
-#: builtin/config.c:68 builtin/config.c:69
+#: builtin/config.c:70 builtin/config.c:71
msgid "slot"
msgstr "khe"
-#: builtin/config.c:68
+#: builtin/config.c:70
msgid "find the color configured: [default]"
msgstr "tìm cấu hình màu sắc: [mặc định]"
-#: builtin/config.c:69
+#: builtin/config.c:71
msgid "find the color setting: [stdout-is-tty]"
msgstr "tìm các cài đặt vỠmàu sắc: [stdout-là-tty]"
-#: builtin/config.c:70
+#: builtin/config.c:72
msgid "Type"
msgstr "Kiểu"
-#: builtin/config.c:71
+#: builtin/config.c:73
msgid "value is \"true\" or \"false\""
msgstr "giá trị là \"true\" hoặc \"false\""
-#: builtin/config.c:72
+#: builtin/config.c:74
msgid "value is decimal number"
msgstr "giá trị ở dạng số thập phân"
-#: builtin/config.c:73
+#: builtin/config.c:75
msgid "value is --bool or --int"
msgstr "giá trị là --bool hoặc --int"
-#: builtin/config.c:74
+#: builtin/config.c:76
msgid "value is a path (file or directory name)"
msgstr "giá trị là Ä‘Æ°á»ng dẫn (tên tập tin hay thÆ° mục)"
-#: builtin/config.c:75
+#: builtin/config.c:77
msgid "Other"
msgstr "Khác"
-#: builtin/config.c:76
+#: builtin/config.c:78
msgid "terminate values with NUL byte"
msgstr "chấm dứt giá trị với byte NUL"
-#: builtin/config.c:77
+#: builtin/config.c:79
msgid "respect include directives on lookup"
msgstr "tôn trá»ng kể cà các hÆ°á»›ng trong tìm kiếm"
-#: builtin/count-objects.c:69
-msgid "git count-objects [-v]"
-msgstr "git count-objects [-v]"
+#: builtin/count-objects.c:82
+msgid "git count-objects [-v] [-H | --human-readable]"
+msgstr "git count-objects [-v] [-H | --human-readable]"
+
+#: builtin/count-objects.c:97
+msgid "print sizes in human readable format"
+msgstr "hiển thị kích cỡ theo định dạng dành cho ngÆ°á»i Ä‘á»c"
-#: builtin/describe.c:15
+#: builtin/describe.c:16
msgid "git describe [options] <committish>*"
msgstr "git describe [các-tùy-chá»n] <committish>*"
-#: builtin/describe.c:16
+#: builtin/describe.c:17
msgid "git describe [options] --dirty"
msgstr "git describe [các-tùy-chá»n] --dirty"
-#: builtin/describe.c:234
+#: builtin/describe.c:237
#, c-format
msgid "annotated tag %s not available"
msgstr "thẻ đã được ghi chú %s không sẵn để dùng"
-#: builtin/describe.c:238
+#: builtin/describe.c:241
#, c-format
msgid "annotated tag %s has no embedded name"
msgstr "thẻ được chú giải %s không có tên nhúng"
-#: builtin/describe.c:240
+#: builtin/describe.c:243
#, c-format
msgid "tag '%s' is really '%s' here"
msgstr "thẻ “%s†đã thực sự ở đây “%s†rồi"
-#: builtin/describe.c:267
+#: builtin/describe.c:270
#, c-format
msgid "Not a valid object name %s"
msgstr "Không phải tên đối tượng %s hợp lệ"
-#: builtin/describe.c:270
+#: builtin/describe.c:273
#, c-format
msgid "%s is not a valid '%s' object"
msgstr "%s không phải là một đối tượng “%s†hợp lệ"
-#: builtin/describe.c:287
+#: builtin/describe.c:290
#, c-format
msgid "no tag exactly matches '%s'"
msgstr "không có thẻ nào khá»›p chính xác vá»›i “%sâ€"
-#: builtin/describe.c:289
+#: builtin/describe.c:292
#, c-format
msgid "searching to describe %s\n"
msgstr "Äang tìm kiếm để mô tả %s\n"
-#: builtin/describe.c:329
+#: builtin/describe.c:332
#, c-format
msgid "finished search at %s\n"
msgstr "việc tìm kiếm đã kết thúc tại %s\n"
-#: builtin/describe.c:353
+#: builtin/describe.c:359
#, c-format
msgid ""
"No annotated tags can describe '%s'.\n"
@@ -4189,7 +4719,7 @@ msgstr ""
"Không có thẻ được chú giải nào được mô tả là “%sâ€.\n"
"Tuy nhiên, ở đây có những thẻ không được chú giải: hãy thử --tags."
-#: builtin/describe.c:357
+#: builtin/describe.c:363
#, c-format
msgid ""
"No tags can describe '%s'.\n"
@@ -4198,12 +4728,12 @@ msgstr ""
"Không có thẻ (tag) có thể mô tả “%sâ€.\n"
"Hãy thử --always, hoặt tạo một số thẻ."
-#: builtin/describe.c:378
+#: builtin/describe.c:384
#, c-format
msgid "traversed %lu commits\n"
msgstr "đã xuyên %lu qua lần chuyển giao (commit)\n"
-#: builtin/describe.c:381
+#: builtin/describe.c:387
#, c-format
msgid ""
"more than %i tags found; listed %i most recent\n"
@@ -4212,59 +4742,63 @@ msgstr ""
"tìm thấy nhiá»u hÆ¡n %i thẻ (tag); đã liệt kê %i gần đây nhất\n"
"bỠđi tìm kiếm tại %s\n"
-#: builtin/describe.c:403
+#: builtin/describe.c:409
msgid "find the tag that comes after the commit"
msgstr "tìm các thẻ mà nó đến trước lần chuyển giao"
-#: builtin/describe.c:404
+#: builtin/describe.c:410
msgid "debug search strategy on stderr"
msgstr "chiến lược tìm kiếm trên đầu ra lỗi chuẩn stderr"
-#: builtin/describe.c:405
-msgid "use any ref in .git/refs"
-msgstr "sử dụng bất kỳ ref nào trong .git/refs"
+#: builtin/describe.c:411
+msgid "use any ref"
+msgstr "dùng ref bất kỳ"
-#: builtin/describe.c:406
-msgid "use any tag in .git/refs/tags"
-msgstr "sử dụng bất kỳ thẻ nào trong .git/refs/tags"
+#: builtin/describe.c:412
+msgid "use any tag, even unannotated"
+msgstr "dùng thẻ bất kỳ, cả khi “unannotatedâ€"
-#: builtin/describe.c:407
+#: builtin/describe.c:413
msgid "always use long format"
msgstr "luôn dùng định dạng dài"
-#: builtin/describe.c:410
+#: builtin/describe.c:414
+msgid "only follow first parent"
+msgstr "chỉ theo cha mẹ đầu tiên"
+
+#: builtin/describe.c:417
msgid "only output exact matches"
msgstr "chỉ xuất những gì khớp chính xác"
-#: builtin/describe.c:412
+#: builtin/describe.c:419
msgid "consider <n> most recent tags (default: 10)"
msgstr "coi như <n> thẻ gần đây nhất (mặc định: 10)"
-#: builtin/describe.c:414
+#: builtin/describe.c:421
msgid "only consider tags matching <pattern>"
msgstr "chỉ cân nhắc đến những thẻ khớp với <mẫu>"
-#: builtin/describe.c:416 builtin/name-rev.c:238
+#: builtin/describe.c:423 builtin/name-rev.c:322
msgid "show abbreviated commit object as fallback"
msgstr "hiển thị đối tượng chuyển giao vắn tắt như là fallback"
-#: builtin/describe.c:417
+#: builtin/describe.c:424
msgid "mark"
msgstr "dấu"
-#: builtin/describe.c:418
+#: builtin/describe.c:425
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
msgstr "thêm <dấu> trên cây thư mục làm việc bẩn (mặc định \"-dirty\")"
-#: builtin/describe.c:436
+#: builtin/describe.c:443
msgid "--long is incompatible with --abbrev=0"
msgstr "--long là xung khắc vá»›i tùy chá»n --abbrev=0"
-#: builtin/describe.c:462
+#: builtin/describe.c:469
msgid "No names found, cannot describe anything."
msgstr "Không tìm thấy các tên, không thể mô tả gì cả."
-#: builtin/describe.c:482
+#: builtin/describe.c:489
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)"
@@ -4273,31 +4807,26 @@ msgstr "--dirty là xung khắc vá»›i các tùy chá»n dành cho chuyển giao (
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:228
+#: builtin/diff.c:230
#, c-format
msgid "invalid option: %s"
msgstr "tùy chá»n sai: %s"
-#: builtin/diff.c:305
+#: builtin/diff.c:307
msgid "Not a git repository"
msgstr "Không phải là kho git"
-#: builtin/diff.c:348
+#: builtin/diff.c:350
#, c-format
msgid "invalid object '%s' given."
msgstr "đối tượng đã cho “%s†không hợp lệ."
-#: builtin/diff.c:353
-#, c-format
-msgid "more than %d trees given: '%s'"
-msgstr "đã chỉ ra nhiá»u hÆ¡n %d cây (tree): “%sâ€"
-
-#: builtin/diff.c:363
+#: 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:371
+#: builtin/diff.c:366
#, c-format
msgid "unhandled object '%s' given."
msgstr "đã cho đối tượng không thể nắm giữ “%sâ€."
@@ -4306,39 +4835,39 @@ msgstr "đã cho đối tượng không thể nắm giữ “%sâ€."
msgid "git fast-export [rev-list-opts]"
msgstr "git fast-export [rev-list-opts]"
-#: builtin/fast-export.c:646
+#: builtin/fast-export.c:666
msgid "show progress after <n> objects"
msgstr "hiển thị tiến triển sau <n> đối tượng"
-#: builtin/fast-export.c:648
+#: builtin/fast-export.c:668
msgid "select handling of signed tags"
msgstr "chá»n Ä‘iá»u khiển của thẻ đã ký"
-#: builtin/fast-export.c:651
+#: builtin/fast-export.c:671
msgid "select handling of tags that tag filtered objects"
msgstr "chá»n sá»± xá»­ lý của các thẻ, cái mà đánh thẻ các đối tượng được lá»c ra"
-#: builtin/fast-export.c:654
+#: builtin/fast-export.c:674
msgid "Dump marks to this file"
msgstr "Äổ các đánh dấu này vào tập-tin"
-#: builtin/fast-export.c:656
+#: builtin/fast-export.c:676
msgid "Import marks from this file"
msgstr "nhập vào đánh dấu từ tập tin này"
-#: builtin/fast-export.c:658
+#: builtin/fast-export.c:678
msgid "Fake a tagger when tags lack one"
msgstr "Làm giả một cái thẻ khi thẻ bị thiếu một cái"
-#: builtin/fast-export.c:660
+#: builtin/fast-export.c:680
msgid "Output full tree for each commit"
msgstr "Xuất ra toàn bộ cây cho mỗi lần chuyển giao"
-#: builtin/fast-export.c:662
+#: builtin/fast-export.c:682
msgid "Use the done feature to terminate the stream"
msgstr "Sử dụng tính năng done để chấm dứt luồng dữ liệu"
-#: builtin/fast-export.c:663
+#: builtin/fast-export.c:683
msgid "Skip output of blob data"
msgstr "BỠqua kết xuất của dữ liệu blob"
@@ -4360,7 +4889,7 @@ msgstr "git fetch --all [<các-tùy-chá»n>]"
#: builtin/fetch.c:60
msgid "fetch from all remotes"
-msgstr "fetch từ tất cả các máy chủ"
+msgstr "lấy vỠtừ tất cả các máy chủ"
#: builtin/fetch.c:62
msgid "append to .git/FETCH_HEAD instead of overwriting"
@@ -4376,15 +4905,15 @@ msgstr "ép buộc ghi đè lên nhánh nội bộ"
#: builtin/fetch.c:67
msgid "fetch from multiple remotes"
-msgstr "fetch từ nhiá»u máy chủ cùng lúc"
+msgstr "lấy từ nhiá»u máy chủ cùng lúc"
#: builtin/fetch.c:69
msgid "fetch all tags and associated objects"
-msgstr "lấy (fetch) tất cả các thẻ cùng với các đối tượng liên quan đến nó"
+msgstr "lấy tất cả các thẻ cùng với các đối tượng liên quan đến nó"
#: builtin/fetch.c:71
msgid "do not fetch all tags (--no-tags)"
-msgstr "không lấy (fetch) tất cả các thẻ (--no-tags)"
+msgstr "không lấy tất cả các thẻ (--no-tags)"
#: builtin/fetch.c:73
msgid "prune remote-tracking branches no longer on remote"
@@ -4398,7 +4927,7 @@ msgstr "khi-cần"
#: builtin/fetch.c:75
msgid "control recursive fetching of submodules"
-msgstr "Ä‘iá»u khiển việc lấy vá» (fetch) đệ quy trong các mô-Ä‘un-con"
+msgstr "Ä‘iá»u khiển việc lấy vỠđệ quy trong các mô-Ä‘un-con"
#: builtin/fetch.c:79
msgid "keep downloaded pack"
@@ -4406,7 +4935,7 @@ msgstr "giữ các gói đã tải vá»"
#: builtin/fetch.c:81
msgid "allow updating of HEAD ref"
-msgstr "cho phép cập nhật ref (tham chiếu) HEAD"
+msgstr "cho phép cập nhật th.chiếu HEAD"
#: builtin/fetch.c:84
msgid "deepen history of shallow clone"
@@ -4416,7 +4945,7 @@ msgstr "làm sâu hơn lịch sử của bản sao"
msgid "convert to a complete repository"
msgstr "chuyển đổi hoàn toàn sang kho git"
-#: builtin/fetch.c:88 builtin/log.c:1119
+#: builtin/fetch.c:88 builtin/log.c:1177
msgid "dir"
msgstr "tmục"
@@ -4428,76 +4957,76 @@ msgstr "soạn sẵn cái này cho kết xuất Ä‘Æ°á»ng dẫn mô-Ä‘un-con"
msgid "default mode for recursion"
msgstr "chế độ mặc định cho đệ qui"
-#: builtin/fetch.c:204
+#: builtin/fetch.c:220
msgid "Couldn't find remote ref HEAD"
msgstr "Không thể tìm thấy máy chủ cho tham chiếu HEAD"
-#: builtin/fetch.c:257
+#: builtin/fetch.c:273
#, c-format
msgid "object %s not found"
msgstr "Không tìm thấy đối tượng %s"
-#: builtin/fetch.c:262
+#: builtin/fetch.c:278
msgid "[up to date]"
msgstr "[đã cập nhật]"
-#: builtin/fetch.c:276
+#: builtin/fetch.c:292
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
msgstr "! %-*s %-*s -> %s (không thể fetch (lấy) vỠnhánh hiện hành)"
-#: builtin/fetch.c:277 builtin/fetch.c:363
+#: builtin/fetch.c:293 builtin/fetch.c:379
msgid "[rejected]"
msgstr "[Bị từ chối]"
-#: builtin/fetch.c:288
+#: builtin/fetch.c:304
msgid "[tag update]"
msgstr "[cập nhật thẻ]"
-#: builtin/fetch.c:290 builtin/fetch.c:325 builtin/fetch.c:343
+#: builtin/fetch.c:306 builtin/fetch.c:341 builtin/fetch.c:359
msgid " (unable to update local ref)"
msgstr " (không thể cập nhật tham chiếu (ref) nội bộ)"
-#: builtin/fetch.c:308
+#: builtin/fetch.c:324
msgid "[new tag]"
msgstr "[thẻ mới]"
-#: builtin/fetch.c:311
+#: builtin/fetch.c:327
msgid "[new branch]"
msgstr "[nhánh mới]"
-#: builtin/fetch.c:314
+#: builtin/fetch.c:330
msgid "[new ref]"
msgstr "[ref (tham chiếu) mới]"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "unable to update local ref"
msgstr "không thể cập nhật tham chiếu (ref) nội bộ"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "forced update"
msgstr "cưỡng bức cập nhật"
-#: builtin/fetch.c:365
+#: builtin/fetch.c:381
msgid "(non-fast-forward)"
msgstr "(non-fast-forward)"
-#: builtin/fetch.c:396 builtin/fetch.c:688
+#: builtin/fetch.c:412 builtin/fetch.c:718
#, c-format
msgid "cannot open %s: %s\n"
msgstr "không thể mở %s: %s\n"
-#: builtin/fetch.c:405
+#: builtin/fetch.c:421
#, c-format
msgid "%s did not send all necessary objects\n"
msgstr "%s đã không gửi tất cả các đối tượng cần thiết\n"
-#: builtin/fetch.c:491
+#: builtin/fetch.c:520
#, c-format
msgid "From %.*s\n"
msgstr "Từ %.*s\n"
-#: builtin/fetch.c:502
+#: builtin/fetch.c:531
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
@@ -4506,57 +5035,57 @@ msgstr ""
"một số tham chiếu (refs) nội bộ không thể được cập nhật; hãy thử chạy\n"
" “git remote prune %s†để bỠđi những nhánh cũ, hay bị xung đột"
-#: builtin/fetch.c:552
+#: builtin/fetch.c:581
#, c-format
msgid " (%s will become dangling)"
msgstr " (%s sẽ trở thành không đầu (không được quản lý))"
-#: builtin/fetch.c:553
+#: builtin/fetch.c:582
#, c-format
msgid " (%s has become dangling)"
msgstr " (%s đã trở thành không đầu (không được quản lý))"
-#: builtin/fetch.c:560
+#: builtin/fetch.c:589
msgid "[deleted]"
msgstr "[đã xóa]"
-#: builtin/fetch.c:561 builtin/remote.c:1055
+#: builtin/fetch.c:590 builtin/remote.c:1055
msgid "(none)"
msgstr "(không)"
-#: builtin/fetch.c:678
+#: builtin/fetch.c:708
#, 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)"
-#: builtin/fetch.c:712
+#: builtin/fetch.c:742
#, c-format
msgid "Don't know how to fetch from %s"
-msgstr "Không biết làm cách nào để lấy vỠ(fetch) từ %s"
+msgstr "Không biết làm cách nào để lấy vỠtừ %s"
-#: builtin/fetch.c:789
+#: builtin/fetch.c:823
#, c-format
msgid "Option \"%s\" value \"%s\" is not valid for %s"
msgstr "Tùy chá»n \"%s\" có giá trị \"%s\" là không hợp lệ cho %s"
-#: builtin/fetch.c:792
+#: builtin/fetch.c:826
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr "Tùy chá»n \"%s\" bị bá» qua vá»›i %s\n"
-#: builtin/fetch.c:894
+#: builtin/fetch.c:928
#, c-format
msgid "Fetching %s\n"
-msgstr "Äang lấy (fetch) %s\n"
+msgstr "Äang lấy vá» %s\n"
-#: builtin/fetch.c:896 builtin/remote.c:100
+#: builtin/fetch.c:930 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
-msgstr "không thể fetch (lấy) %s"
+msgstr "không thể lấy vỠ%s"
-#: builtin/fetch.c:915
+#: builtin/fetch.c:949
msgid ""
"No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."
@@ -4564,32 +5093,32 @@ msgstr ""
"Chưa chỉ ra kho chứa máy chủ. Xin hãy chỉ định hoặc là URL hoặc\n"
"tên máy chủ từ cái mà những Ä‘iểm xét duyệt má»›i có thể được fetch (lấy vá»)."
-#: builtin/fetch.c:935
+#: builtin/fetch.c:969
msgid "You need to specify a tag name."
msgstr "Bạn phải định rõ tên thẻ."
-#: builtin/fetch.c:981
+#: builtin/fetch.c:1015
msgid "--depth and --unshallow cannot be used together"
msgstr "tùy chá»n --depth và --unshallow không thể sá»­ dụng cùng vá»›i nhau"
-#: builtin/fetch.c:983
+#: builtin/fetch.c:1017
msgid "--unshallow on a complete repository does not make sense"
msgstr "--unshallow trên kho hoàn chỉnh là không hợp lý"
-#: builtin/fetch.c:1002
+#: builtin/fetch.c:1036
msgid "fetch --all does not take a repository argument"
msgstr "lệnh lấy vỠ\"fetch --all\" không lấy đối số kho chứa"
-#: builtin/fetch.c:1004
+#: builtin/fetch.c:1038
msgid "fetch --all does not make sense with refspecs"
msgstr "lệnh lấy vỠ\"fetch --all\" không hợp lý với refspecs"
-#: builtin/fetch.c:1015
+#: builtin/fetch.c:1049
#, c-format
msgid "No such remote or remote group: %s"
msgstr "không có nhóm máy chủ hay máy chủ như thế: %s"
-#: builtin/fetch.c:1023
+#: builtin/fetch.c:1057
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr "Việc lấy vỠcả một nhóm và chỉ định refspecs không hợp lý"
@@ -4598,29 +5127,29 @@ msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
msgstr ""
"git fmt-merge-msg [-m <thông điệp>] [--log[=<n>]|--no-log] [--file <tập-tin>]"
-#: builtin/fmt-merge-msg.c:659 builtin/fmt-merge-msg.c:662 builtin/grep.c:701
-#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175
-#: builtin/tag.c:446 parse-options.h:133 parse-options.h:239
+#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:700
+#: builtin/merge.c:203 builtin/show-branch.c:655 builtin/show-ref.c:179
+#: builtin/tag.c:446 parse-options.h:133 parse-options.h:243
msgid "n"
msgstr "n"
-#: builtin/fmt-merge-msg.c:660
+#: builtin/fmt-merge-msg.c:664
msgid "populate log with at most <n> entries from shortlog"
msgstr "gắn nhật ký vá»›i ít nhất <n> mục từ lệnh “shortlogâ€"
-#: builtin/fmt-merge-msg.c:663
+#: builtin/fmt-merge-msg.c:667
msgid "alias for --log (deprecated)"
msgstr "bí danh cho --log (không được dùng)"
-#: builtin/fmt-merge-msg.c:666
+#: builtin/fmt-merge-msg.c:670
msgid "text"
msgstr "văn bản"
-#: builtin/fmt-merge-msg.c:667
+#: builtin/fmt-merge-msg.c:671
msgid "use <text> as start of message"
msgstr "dùng <văn bản thÆ°á»ng> để bắt đầu ghi chú"
-#: builtin/fmt-merge-msg.c:668
+#: builtin/fmt-merge-msg.c:672
msgid "file to read from"
msgstr "tập tin để Ä‘á»c dữ liệu từ đó"
@@ -4760,228 +5289,223 @@ msgstr "git grep [các-tùy-chá»n] [-e] <mẫu> [<rev>...] [[--] <Ä‘Æ°á»ng-dáº
msgid "grep: failed to create thread: %s"
msgstr "grep: gặp lỗi tạo tuyến (thread): %s"
-#: builtin/grep.c:365
+#: builtin/grep.c:364
#, c-format
msgid "Failed to chdir: %s"
msgstr "Gặp lỗi với lệnh chdir: %s"
-#: builtin/grep.c:443 builtin/grep.c:478
+#: builtin/grep.c:442 builtin/grep.c:477
#, c-format
msgid "unable to read tree (%s)"
msgstr "không thể Ä‘á»c cây (%s)"
-#: builtin/grep.c:493
+#: builtin/grep.c:492
#, 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:551
+#: builtin/grep.c:550
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr "chuyển đến “%c†cần một giá trị bằng số"
-#: builtin/grep.c:568
+#: builtin/grep.c:567
#, c-format
msgid "cannot open '%s'"
msgstr "không mở được “%sâ€"
-#: builtin/grep.c:643
+#: builtin/grep.c:642
msgid "search in index instead of in the work tree"
msgstr "tìm trong bảng mục lục thay vì trong cây làm việc"
-#: builtin/grep.c:645
+#: builtin/grep.c:644
msgid "find in contents not managed by git"
msgstr "tìm trong nội dung không được quản lý bởi git"
-#: builtin/grep.c:647
+#: builtin/grep.c:646
msgid "search in both tracked and untracked files"
msgstr "tìm kiếm các tập tin được và chưa được theo dõi dấu vết"
-#: builtin/grep.c:649
+#: builtin/grep.c:648
msgid "search also in ignored files"
msgstr "tìm cả trong các tập tin đã bị lỠđi"
-#: builtin/grep.c:652
+#: builtin/grep.c:651
msgid "show non-matching lines"
msgstr "hiển thị những dòng không khớp với mẫu"
-#: builtin/grep.c:654
+#: builtin/grep.c:653
msgid "case insensitive matching"
msgstr "phân biệt chữ hoa/thÆ°á»ng"
-#: builtin/grep.c:656
+#: builtin/grep.c:655
msgid "match patterns only at word boundaries"
msgstr "chỉ khá»›p mẫu tại Ä‘Æ°á»ng ranh giá»›i từ"
-#: builtin/grep.c:658
+#: builtin/grep.c:657
msgid "process binary files as text"
msgstr "xá»­ lý tập tin nhị phân nhÆ° là dạng văn bản thÆ°á»ng"
-#: builtin/grep.c:660
+#: builtin/grep.c:659
msgid "don't match patterns in binary files"
msgstr "không khớp mẫu trong các tập tin nhị phân"
-#: builtin/grep.c:663
+#: builtin/grep.c:662
msgid "descend at most <depth> levels"
msgstr "giảm xuống ít nhất mức <sâu>"
-#: builtin/grep.c:667
+#: builtin/grep.c:666
msgid "use extended POSIX regular expressions"
msgstr "dùng biểu thức chính qui POSIX có mở rộng"
-#: builtin/grep.c:670
+#: builtin/grep.c:669
msgid "use basic POSIX regular expressions (default)"
msgstr "sử dụng biểu thức chính quy kiểu POSIX (mặc định)"
-#: builtin/grep.c:673
+#: builtin/grep.c:672
msgid "interpret patterns as fixed strings"
msgstr "diễn dịch các mẫu như là chuỗi cố định"
-#: builtin/grep.c:676
+#: builtin/grep.c:675
msgid "use Perl-compatible regular expressions"
msgstr "sử dụng biểu thức chính quy tương thích Perl"
-#: builtin/grep.c:679
+#: builtin/grep.c:678
msgid "show line numbers"
msgstr "hiển thị số của dòng"
-#: builtin/grep.c:680
+#: builtin/grep.c:679
msgid "don't show filenames"
msgstr "không hiển thị tên tập tin"
-#: builtin/grep.c:681
+#: builtin/grep.c:680
msgid "show filenames"
msgstr "hiển thị các tên tập tin"
-#: builtin/grep.c:683
+#: builtin/grep.c:682
msgid "show filenames relative to top directory"
msgstr "hiển thị tên tập tin tương đối với thư mục đỉnh (top)"
-#: builtin/grep.c:685
+#: builtin/grep.c:684
msgid "show only filenames instead of matching lines"
msgstr "chỉ hiển thị tên tập tin thay vì những dòng khớp với mẫu"
-#: builtin/grep.c:687
+#: builtin/grep.c:686
msgid "synonym for --files-with-matches"
msgstr "đồng nghĩa với --files-with-matches"
-#: builtin/grep.c:690
+#: builtin/grep.c:689
msgid "show only the names of files without match"
msgstr "chỉ hiển thị tên cho những tập tin không khớp với mẫu"
-#: builtin/grep.c:692
+#: builtin/grep.c:691
msgid "print NUL after filenames"
msgstr "thêm NUL vào sau tên tập tin"
-#: builtin/grep.c:694
+#: builtin/grep.c:693
msgid "show the number of matches instead of matching lines"
msgstr "hiển thị số lượng khớp thay vì những dòng khớp với mẫu"
-#: builtin/grep.c:695
+#: builtin/grep.c:694
msgid "highlight matches"
msgstr "tô sáng cái khớp"
-#: builtin/grep.c:697
+#: builtin/grep.c:696
msgid "print empty line between matches from different files"
msgstr "hiển thị dòng trống giữa các lần khớp từ các tập tin khác biệt"
-#: builtin/grep.c:699
+#: builtin/grep.c:698
msgid "show filename only once above matches from same file"
msgstr ""
"hiển thị tên tập tin một lần phía trên các lần khớp từ cùng một tập tin"
-#: builtin/grep.c:702
+#: builtin/grep.c:701
msgid "show <n> context lines before and after matches"
msgstr "hiển thị <n> dòng nội dung phía trước và sau các lần khớp"
-#: builtin/grep.c:705
+#: builtin/grep.c:704
msgid "show <n> context lines before matches"
msgstr "hiển thị <n> dòng nội dung trước khớp"
-#: builtin/grep.c:707
+#: builtin/grep.c:706
msgid "show <n> context lines after matches"
msgstr "hiển thị <n> dòng nội dung sau khớp"
-#: builtin/grep.c:708
+#: builtin/grep.c:707
msgid "shortcut for -C NUM"
msgstr "Dạng tắt cho -C Sá»"
-#: builtin/grep.c:711
+#: builtin/grep.c:710
msgid "show a line with the function name before matches"
msgstr "hiển thị dòng vói tên hàm trước các lần khớp"
-#: builtin/grep.c:713
+#: builtin/grep.c:712
msgid "show the surrounding function"
msgstr "hiển thị hàm bao quanh"
-#: builtin/grep.c:716
+#: builtin/grep.c:715
msgid "read patterns from file"
msgstr "Ä‘á»c mẫu từ tập-tin"
-#: builtin/grep.c:718
+#: builtin/grep.c:717
msgid "match <pattern>"
msgstr "match <mẫu>"
-#: builtin/grep.c:720
+#: builtin/grep.c:719
msgid "combine patterns specified with -e"
msgstr "tổ hợp mẫu được chỉ ra vá»›i tùy chá»n -e"
-#: builtin/grep.c:732
+#: builtin/grep.c:731
msgid "indicate hit with exit status without output"
msgstr "đưa ra gợi ý với trạng thái thoát mà không có kết xuất"
-#: builtin/grep.c:734
+#: builtin/grep.c:733
msgid "show only matches from files that match all patterns"
msgstr "chỉ hiển thị những cái khớp từ tập tin mà nó khớp toàn bộ các mẫu"
-#: builtin/grep.c:736
+#: builtin/grep.c:735
msgid "show parse tree for grep expression"
msgstr "hiển thị cây phân tích cú pháp cho biểu thức “grep†(tìm kiếm)"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "pager"
msgstr "trang giấy"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "show matching files in the pager"
msgstr "hiển thị các tập tin khớp trong trang giấy"
-#: builtin/grep.c:743
+#: builtin/grep.c:742
msgid "allow calling of grep(1) (ignored by this build)"
msgstr "cho phép gá»i grep(1) (bị bá» qua bởi lần dịch này)"
-#: builtin/grep.c:744 builtin/show-ref.c:184
+#: builtin/grep.c:743 builtin/show-ref.c:188
msgid "show usage"
msgstr "hiển thị cách dùng"
-#: builtin/grep.c:811
+#: builtin/grep.c:810
msgid "no pattern given."
msgstr "chưa chỉ ra mẫu."
-#: builtin/grep.c:825
-#, c-format
-msgid "bad object %s"
-msgstr "đối tượng sai %s"
-
-#: builtin/grep.c:868
+#: builtin/grep.c:865
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:891
+#: builtin/grep.c:888
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:896
+#: builtin/grep.c:893
msgid "--no-index or --untracked cannot be used with revs."
msgstr ""
"--no-index hay --untracked không được sá»­ dụng cùng vá»›i các tùy chá»n liên "
"quan đến revs."
-#: builtin/grep.c:899
+#: builtin/grep.c:896
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:907
+#: builtin/grep.c:904
msgid "both --cached and trees are given."
msgstr "cả hai --cached và các cây phải được chỉ ra."
@@ -5021,10 +5545,14 @@ msgstr "lÆ°u các tập tin mà nó không có các bá»™ lá»c"
msgid "process file as it were from this path"
msgstr "xử lý tập tin như là nó đang ở thư mục này"
-#: builtin/help.c:42
+#: builtin/help.c:41
msgid "print all available commands"
msgstr "hiển thị danh sách các câu lệnh ngÆ°á»i dùng có thể sá»­ dụng"
+#: builtin/help.c:42
+msgid "print list of useful guides"
+msgstr "hiển thị danh sách các hướng dẫn hữu dụng"
+
#: builtin/help.c:43
msgid "show man page"
msgstr "hiển thị trang man"
@@ -5038,8 +5566,8 @@ msgid "show info page"
msgstr "hiện trang info"
#: builtin/help.c:52
-msgid "git help [--all] [--man|--web|--info] [command]"
-msgstr "git help [--all] [--man|--web|--info] [lệnh]"
+msgid "git help [--all] [--guides] [--man|--web|--info] [command]"
+msgstr "git help [--all] [--guides] [--man|--web|--info] [lệnh]"
#: builtin/help.c:64
#, c-format
@@ -5095,290 +5623,322 @@ msgstr "không có trình xem trợ giúp dạng manpage tiếp hợp với yêu
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:429 builtin/help.c:436
+#: builtin/help.c:420
+msgid "Defining attributes per path"
+msgstr "Äịnh nghÄ©a các thuá»™c tính cho má»—i Ä‘Æ°á»ng dẫn"
+
+#: builtin/help.c:421
+msgid "A Git glossary"
+msgstr "Thuật ngữ chuyên môn Git"
+
+#: builtin/help.c:422
+msgid "Specifies intentionally untracked files to ignore"
+msgstr "Chỉ định các tập tin không cần theo dõi"
+
+#: builtin/help.c:423
+msgid "Defining submodule properties"
+msgstr "Äịnh nghÄ©a thuá»™c tính mô-Ä‘un-con"
+
+#: builtin/help.c:424
+msgid "Specifying revisions and ranges for Git"
+msgstr "Chỉ định điểm xét duyệt và vùng cho Git"
+
+#: builtin/help.c:425
+msgid "A tutorial introduction to Git (for version 1.5.1 or newer)"
+msgstr "Hướng dẫn cách dùng Git ở mức cơ bản (bản 1.5.1 hay mới hơn)"
+
+#: builtin/help.c:426
+msgid "An overview of recommended workflows with Git"
+msgstr "Tổng quan vỠluồng công việc khuyến nghị nên dùng với Git."
+
+#: builtin/help.c:438
+msgid "The common Git guides are:\n"
+msgstr "Các chỉ dẫn chung vỠcách dùng Git là:\n"
+
+#: builtin/help.c:460 builtin/help.c:476
#, c-format
msgid "usage: %s%s"
msgstr "cách sử dụng: %s%s"
-#: builtin/help.c:452
+#: builtin/help.c:492
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr "“git %s†được đặt bí danh thành “%sâ€"
-#: builtin/index-pack.c:170
+#: builtin/index-pack.c:184
#, 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:190
+#: builtin/index-pack.c:204
msgid "object of unexpected type"
msgstr "đối tượng của kiểu không mong đợi"
-#: builtin/index-pack.c:227
+#: builtin/index-pack.c:244
#, 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:237
+#: builtin/index-pack.c:254
msgid "early EOF"
msgstr "vừa đúng lúc EOF"
-#: builtin/index-pack.c:238
+#: builtin/index-pack.c:255
msgid "read error on input"
msgstr "lá»—i Ä‘á»c ở đầu vào"
-#: builtin/index-pack.c:250
+#: builtin/index-pack.c:267
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:257
+#: builtin/index-pack.c:274
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:273
+#: builtin/index-pack.c:290
#, c-format
msgid "unable to create '%s'"
msgstr "không thể tạo “%sâ€"
-#: builtin/index-pack.c:278
+#: builtin/index-pack.c:295
#, c-format
msgid "cannot open packfile '%s'"
msgstr "không thể mở packfile “%sâ€"
-#: builtin/index-pack.c:292
+#: builtin/index-pack.c:309
msgid "pack signature mismatch"
msgstr "chữ ký cho pack không khớp"
-#: builtin/index-pack.c:294
+#: builtin/index-pack.c:311
#, c-format
msgid "pack version %<PRIu32> unsupported"
msgstr "không hỗ trợ phiên bản pack %<PRIu32>"
-#: builtin/index-pack.c:312
+#: builtin/index-pack.c:329
#, 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:434
+#: builtin/index-pack.c:451
#, c-format
msgid "inflate returned %d"
msgstr "xả nén trả vỠ%d"
-#: builtin/index-pack.c:483
+#: builtin/index-pack.c:500
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:491
+#: builtin/index-pack.c:508
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:499
+#: builtin/index-pack.c:516
#, c-format
msgid "unknown object type %d"
msgstr "không hiểu kiểu đối tượng %d"
-#: builtin/index-pack.c:530
+#: builtin/index-pack.c:547
msgid "cannot pread pack file"
msgstr "không thể chạy hàm pread cho tập tin pack"
-#: builtin/index-pack.c:532
+#: builtin/index-pack.c:549
#, 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:558
+#: builtin/index-pack.c:575
msgid "serious inflate inconsistency"
msgstr "sá»± mâu thuẫn xả nén nghiêm trá»ng"
-#: 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
+#: builtin/index-pack.c:666 builtin/index-pack.c:672 builtin/index-pack.c:695
+#: builtin/index-pack.c:729 builtin/index-pack.c:738
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "Sá»° VA CHẠM SHA1 ÄÃ XẢY RA VỚI %s!"
-#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/index-pack.c:669 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
+#: builtin/index-pack.c:735
#, 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
+#: builtin/index-pack.c:749
#, c-format
msgid "invalid blob object %s"
msgstr "đối tượng blob không hợp lệ %s"
-#: builtin/index-pack.c:747
+#: builtin/index-pack.c:763
#, c-format
msgid "invalid %s"
msgstr "%s không hợp lệ"
-#: builtin/index-pack.c:749
+#: builtin/index-pack.c:766
msgid "Error in object"
msgstr "Lỗi trong đối tượng"
-#: builtin/index-pack.c:751
+#: builtin/index-pack.c:768
#, 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:821 builtin/index-pack.c:847
+#: builtin/index-pack.c:838 builtin/index-pack.c:868
msgid "failed to apply delta"
msgstr "gặp lỗi khi áp dụng delta"
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Receiving objects"
msgstr "Äang nhận vá» các đối tượng"
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Indexing objects"
msgstr "Các đối tượng bảng mục lục"
-#: builtin/index-pack.c:1012
+#: builtin/index-pack.c:1035
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "pack bị sai há»ng (SHA1 không khá»›p)"
-#: builtin/index-pack.c:1017
+#: builtin/index-pack.c:1040
msgid "cannot fstat packfile"
msgstr "không thể fstat packfile"
-#: builtin/index-pack.c:1020
+#: builtin/index-pack.c:1043
msgid "pack has junk at the end"
msgstr "pack có phần thừa ở cuối"
-#: builtin/index-pack.c:1031
+#: builtin/index-pack.c:1054
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
+#: builtin/index-pack.c:1077
msgid "Resolving deltas"
msgstr "Äang phân giải các delta"
-#: builtin/index-pack.c:1064
+#: builtin/index-pack.c:1087
#, c-format
msgid "unable to create thread: %s"
msgstr "không thể tạo tuyến: %s"
-#: builtin/index-pack.c:1106
+#: builtin/index-pack.c:1129
msgid "confusion beyond insanity"
msgstr "lộn xộn hơn cả điên rồ"
-#: builtin/index-pack.c:1112
+#: builtin/index-pack.c:1137
#, c-format
msgid "completed with %d local objects"
msgstr "đầy đủ với %d đối tượng nội bộ"
-#: builtin/index-pack.c:1121
+#: builtin/index-pack.c:1147
#, c-format
msgid "Unexpected tail checksum for %s (disk corruption?)"
msgstr "Tổng kiểm tra tail không nhÆ° mong đợi cho %s (Ä‘Ä©a há»ng?)"
-#: builtin/index-pack.c:1125
+#: builtin/index-pack.c:1151
#, 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:1150
+#: builtin/index-pack.c:1176
#, 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:1229
+#: builtin/index-pack.c:1255
#, c-format
msgid "local object %s is corrupt"
msgstr "đối tượng ná»™i bá»™ %s bị há»ng"
-#: builtin/index-pack.c:1253
+#: builtin/index-pack.c:1279
msgid "error while closing pack file"
msgstr "gặp lỗi trong khi đóng tập tin pack"
-#: builtin/index-pack.c:1266
+#: builtin/index-pack.c:1292
#, c-format
msgid "cannot write keep file '%s'"
msgstr "không thể ghi tập tin giữ lại “%sâ€"
-#: builtin/index-pack.c:1274
+#: builtin/index-pack.c:1300
#, 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:1287
+#: builtin/index-pack.c:1313
msgid "cannot store pack file"
msgstr "không thể lưu tập tin pack"
-#: builtin/index-pack.c:1298
+#: builtin/index-pack.c:1324
msgid "cannot store index file"
msgstr "không thể lưu trữ tập tin ghi mục lục"
-#: builtin/index-pack.c:1331
+#: builtin/index-pack.c:1357
#, c-format
msgid "bad pack.indexversion=%<PRIu32>"
msgstr "sai pack.indexversion=%<PRIu32>"
-#: builtin/index-pack.c:1337
+#: builtin/index-pack.c:1363
#, c-format
msgid "invalid number of threads specified (%d)"
msgstr "số tuyến chỉ ra không hợp lệ (%d)"
-#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#: builtin/index-pack.c:1367 builtin/index-pack.c:1545
#, c-format
msgid "no threads support, ignoring %s"
msgstr "không hỗ trợ đa tuyến, bỠqua %s"
-#: builtin/index-pack.c:1399
+#: builtin/index-pack.c:1425
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr "Không thể mở tập tin pack đã sẵn có “%sâ€"
-#: builtin/index-pack.c:1401
+#: builtin/index-pack.c:1427
#, 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:1448
+#: builtin/index-pack.c:1474
#, 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:1455
+#: builtin/index-pack.c:1481
#, 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:1482
+#: builtin/index-pack.c:1509
msgid "Cannot come back to cwd"
msgstr "Không thể quay lại cwd"
-#: builtin/index-pack.c:1526 builtin/index-pack.c:1529
-#: builtin/index-pack.c:1541 builtin/index-pack.c:1545
+#: builtin/index-pack.c:1557 builtin/index-pack.c:1560
+#: builtin/index-pack.c:1572 builtin/index-pack.c:1576
#, c-format
msgid "bad %s"
msgstr "%s sai"
-#: builtin/index-pack.c:1559
+#: builtin/index-pack.c:1590
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:1563 builtin/index-pack.c:1573
+#: builtin/index-pack.c:1594 builtin/index-pack.c:1604
#, 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:1582
+#: builtin/index-pack.c:1613
msgid "--verify with no packfile name given"
msgstr "dùng tùy chá»n --verify mà không Ä‘Æ°a ra tên packfile"
@@ -5514,7 +6074,7 @@ msgstr "các quyá»n"
msgid "specify that the git repository is to be shared amongst several users"
msgstr "chỉ ra cái mà kho git được chia sẻ giữa nhiá»u ngÆ°á»i dùng"
-#: builtin/init-db.c:493 builtin/prune-packed.c:77
+#: builtin/init-db.c:493 builtin/prune-packed.c:75
msgid "be quiet"
msgstr "im lặng"
@@ -5546,246 +6106,255 @@ msgstr "Không thể truy cập thư mục làm việc hiện hành"
msgid "Cannot access work tree '%s'"
msgstr "không thể truy cập cây (tree) làm việc “%sâ€"
-#: builtin/log.c:39
-msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
-msgstr "git log [<các-tùy-chá»n>] [<kể-từ>..<cho-đến>] [[--] <Ä‘Æ°á»ng-dẫn>...]\n"
+#: builtin/log.c:41
+msgid "git log [<options>] [<revision range>] [[--] <path>...]\n"
+msgstr "git log [<các-tùy-chá»n>] [<vùng xem xét>] [[--] <Ä‘Æ°á»ng-dẫn>...]\n"
-#: builtin/log.c:40
+#: builtin/log.c:42
msgid " or: git show [options] <object>..."
-msgstr " or: git show [các-tùy-chá»n] <đối-tượng>..."
+msgstr " hay: git show [các-tùy-chá»n] <đối-tượng>..."
-#: builtin/log.c:102
+#: builtin/log.c:124
msgid "suppress diff output"
msgstr "chặn má»i kết xuất từ diff"
-#: builtin/log.c:103
+#: builtin/log.c:125
msgid "show source"
msgstr "hiển thị mã nguồn"
-#: builtin/log.c:104
+#: builtin/log.c:126
msgid "Use mail map file"
msgstr "Sử dụng tập tin ánh xạ thư"
-#: builtin/log.c:105
+#: builtin/log.c:127
msgid "decorate options"
msgstr "các tùy chá»n trang trí"
-#: builtin/log.c:198
+#: builtin/log.c:230
#, c-format
msgid "Final output: %d %s\n"
msgstr "Kết xuất cuối cùng: %d %s\n"
-#: builtin/log.c:419 builtin/log.c:511
+#: builtin/log.c:453 builtin/log.c:545
#, c-format
msgid "Could not read object %s"
msgstr "Không thể Ä‘á»c đối tượng %s"
-#: builtin/log.c:535
+#: builtin/log.c:569
#, c-format
msgid "Unknown type: %d"
msgstr "Không nhận ra kiểu: %d"
-#: builtin/log.c:627
+#: builtin/log.c:669
msgid "format.headers without value"
msgstr "format.headers không có giá trị cụ thể"
-#: builtin/log.c:701
+#: builtin/log.c:751
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:717
+#: builtin/log.c:767
#, c-format
msgid "Cannot open patch file %s"
msgstr "Không thể mở tập tin miếng vá: %s"
-#: builtin/log.c:731
+#: builtin/log.c:781
msgid "Need exactly one range."
msgstr "Cần chính xác một vùng."
-#: builtin/log.c:739
+#: builtin/log.c:789
msgid "Not a range."
msgstr "Không phải là một vùng."
-#: builtin/log.c:812
+#: builtin/log.c:891
msgid "Cover letter needs email format"
msgstr "â€Cover letter†cần cho định dạng thÆ°"
-#: builtin/log.c:885
+#: builtin/log.c:967
#, c-format
msgid "insane in-reply-to: %s"
msgstr "in-reply-to điên rồ: %s"
-#: builtin/log.c:913
+#: builtin/log.c:995
msgid "git format-patch [options] [<since> | <revision range>]"
msgstr "git format-patch [các-tùy-chá»n] [<kể-từ> | <vùng-xem-xét>]"
-#: builtin/log.c:958
+#: builtin/log.c:1040
msgid "Two output directories?"
msgstr "Hai thư mục kết xuất?"
-#: builtin/log.c:1097
+#: builtin/log.c:1155
msgid "use [PATCH n/m] even with a single patch"
msgstr "dùng [PATCH n/m] ngay cả với miếng vá đơn"
-#: builtin/log.c:1100
+#: builtin/log.c:1158
msgid "use [PATCH] even with multiple patches"
msgstr "dùng [VÃ] ngay cả vá»›i các miếng vá phức tạp"
-#: builtin/log.c:1104
+#: builtin/log.c:1162
msgid "print patches to standard out"
msgstr "hiển thị miếng vá ra đầu ra chuẩn"
-#: builtin/log.c:1106
+#: builtin/log.c:1164
msgid "generate a cover letter"
msgstr "tạo bì thư"
-#: builtin/log.c:1108
+#: builtin/log.c:1166
msgid "use simple number sequence for output file names"
msgstr "sử dụng chỗi dãy số dạng đơn giản cho tên tập-tin xuất ra"
-#: builtin/log.c:1109
+#: builtin/log.c:1167
msgid "sfx"
msgstr "sfx"
-#: builtin/log.c:1110
+#: builtin/log.c:1168
msgid "use <sfx> instead of '.patch'"
msgstr "sá»­ dụng <sfx> thay cho “.patchâ€"
-#: builtin/log.c:1112
+#: builtin/log.c:1170
msgid "start numbering patches at <n> instead of 1"
msgstr "bắt đầu đánh số miếng vá từ <n> thay vì 1"
-#: builtin/log.c:1114
+#: builtin/log.c:1172
msgid "mark the series as Nth re-roll"
msgstr "đánh dấu chuỗi nối tiếp dạng thứ-N re-roll"
-#: builtin/log.c:1116
+#: builtin/log.c:1174
msgid "Use [<prefix>] instead of [PATCH]"
msgstr "Dùng [<tiá»n-tố>] thay cho [VÃ]"
-#: builtin/log.c:1119
+#: builtin/log.c:1177
msgid "store resulting files in <dir>"
msgstr "lưu các tập tin kết quả trong <t.mục>"
-#: builtin/log.c:1122
+#: builtin/log.c:1180
msgid "don't strip/add [PATCH]"
msgstr "không strip/add [VÃ]"
-#: builtin/log.c:1125
+#: builtin/log.c:1183
msgid "don't output binary diffs"
msgstr "không kết xuất diff (những khác biệt) nhị phân"
-#: builtin/log.c:1127
+#: builtin/log.c:1185
msgid "don't include a patch matching a commit upstream"
msgstr "không bao gồm miếng vá khớp với một lần chuyển giao thượng nguồn"
-#: builtin/log.c:1129
+#: builtin/log.c:1187
msgid "show patch format instead of default (patch + stat)"
msgstr "hiển thị định dạng miếng vá thay vì mặc định (miếng vá + thống kê)"
-#: builtin/log.c:1131
+#: builtin/log.c:1189
msgid "Messaging"
msgstr "Lá»i nhắn"
-#: builtin/log.c:1132
+#: builtin/log.c:1190
msgid "header"
msgstr "đầu đỠthư"
-#: builtin/log.c:1133
+#: builtin/log.c:1191
msgid "add email header"
msgstr "thêm đầu đỠthư"
-#: builtin/log.c:1134 builtin/log.c:1136
+#: builtin/log.c:1192 builtin/log.c:1194
msgid "email"
msgstr "thư điện tử"
-#: builtin/log.c:1134
+#: builtin/log.c:1192
msgid "add To: header"
msgstr "thêm To: đầu đỠthư"
-#: builtin/log.c:1136
+#: builtin/log.c:1194
msgid "add Cc: header"
msgstr "thêm Cc: đầu đỠthư"
-#: builtin/log.c:1138
+#: builtin/log.c:1196
+msgid "ident"
+msgstr "thụt lá»"
+
+#: builtin/log.c:1197
+msgid "set From address to <ident> (or committer ident if absent)"
+msgstr ""
+"đặt `Äịa chỉ gá»­i' thành <thụ lá»> (hoặc thụt lá» ngÆ°á»i commit nếu bá» quên)"
+
+#: builtin/log.c:1199
msgid "message-id"
msgstr "message-id"
-#: builtin/log.c:1139
+#: builtin/log.c:1200
msgid "make first mail a reply to <message-id>"
msgstr "dùng thÆ° đầu tiên để trả lá»i <message-id>"
-#: builtin/log.c:1140 builtin/log.c:1143
+#: builtin/log.c:1201 builtin/log.c:1204
msgid "boundary"
msgstr "ranh giá»›i"
-#: builtin/log.c:1141
+#: builtin/log.c:1202
msgid "attach the patch"
msgstr "đính kèm miếng vá"
-#: builtin/log.c:1144
+#: builtin/log.c:1205
msgid "inline the patch"
msgstr "dùng miếng vá làm nội dung"
-#: builtin/log.c:1148
+#: builtin/log.c:1209
msgid "enable message threading, styles: shallow, deep"
msgstr "cho phép luồng lá»i nhắn, kiểu: “shallowâ€, “deepâ€"
-#: builtin/log.c:1150
+#: builtin/log.c:1211
msgid "signature"
msgstr "chữ ký"
-#: builtin/log.c:1151
+#: builtin/log.c:1212
msgid "add a signature"
msgstr "thêm chữ ký"
-#: builtin/log.c:1153
+#: builtin/log.c:1214
msgid "don't print the patch filenames"
msgstr "không hiển thị các tên tập tin của miếng vá"
-#: builtin/log.c:1202
+#: builtin/log.c:1288
#, c-format
-msgid "bogus committer info %s"
-msgstr "thông tin ngÆ°á»i chuyển giao không có thá»±c %s"
+msgid "invalid ident line: %s"
+msgstr "dòng thụt lỠkhông hợp lệ: %s"
-#: builtin/log.c:1247
+#: builtin/log.c:1303
msgid "-n and -k are mutually exclusive."
msgstr "-n và -k loại từ lẫn nhau."
-#: builtin/log.c:1249
+#: builtin/log.c:1305
msgid "--subject-prefix and -k are mutually exclusive."
msgstr "--subject-prefix và -k xung khắc nhau."
-#: builtin/log.c:1257
+#: builtin/log.c:1313
msgid "--name-only does not make sense"
msgstr "--name-only không hợp lý"
-#: builtin/log.c:1259
+#: builtin/log.c:1315
msgid "--name-status does not make sense"
msgstr "--name-status không hợp lý"
-#: builtin/log.c:1261
+#: builtin/log.c:1317
msgid "--check does not make sense"
msgstr "--check không hợp lý"
-#: builtin/log.c:1284
+#: builtin/log.c:1340
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:1286
+#: builtin/log.c:1342
#, c-format
msgid "Could not create directory '%s'"
msgstr "Không thể tạo thÆ° mục “%sâ€"
-#: builtin/log.c:1439
+#: builtin/log.c:1490
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:1488
+#: builtin/log.c:1539
msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
msgstr "git cherry [-v] [<thượng-nguồn> [<head> [<giới-hạn>]]]"
-#: builtin/log.c:1543
+#: builtin/log.c:1594
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
@@ -5793,103 +6362,103 @@ msgstr ""
"Không tìm thấy nhánh mạng bị theo vết, hãy chỉ định <thượng-nguồn> một cách "
"thủ công.\n"
-#: builtin/log.c:1556 builtin/log.c:1558 builtin/log.c:1570
+#: builtin/log.c:1607 builtin/log.c:1609 builtin/log.c:1621
#, c-format
msgid "Unknown commit %s"
msgstr "Không hiểu lần chuyển giao (commit) %s"
-#: builtin/ls-files.c:409
+#: builtin/ls-files.c:408
msgid "git ls-files [options] [<file>...]"
msgstr "git ls-files [các-tùy-chá»n] [<tập-tin>...]"
-#: builtin/ls-files.c:466
+#: builtin/ls-files.c:465
msgid "identify the file status with tags"
msgstr "nhận dạng các trạng thái tập tin với thẻ"
-#: builtin/ls-files.c:468
+#: builtin/ls-files.c:467
msgid "use lowercase letters for 'assume unchanged' files"
msgstr ""
"dùng chữ cái viết thÆ°á»ng cho các tập tin “assume unchanged†(giả định không "
"thay đổi)"
-#: builtin/ls-files.c:470
+#: builtin/ls-files.c:469
msgid "show cached files in the output (default)"
msgstr "hiển thị các tập tin được nhớ tạm vào đầu ra (mặc định)"
-#: builtin/ls-files.c:472
+#: builtin/ls-files.c:471
msgid "show deleted files in the output"
msgstr "hiển thị các tập tin đã xóa trong kết xuất"
-#: builtin/ls-files.c:474
+#: builtin/ls-files.c:473
msgid "show modified files in the output"
msgstr "hiển thị các tập tin đã bị sửa đổi ra kết xuất"
-#: builtin/ls-files.c:476
+#: builtin/ls-files.c:475
msgid "show other files in the output"
msgstr "hiển thị các tập tin khác trong kết xuất"
-#: builtin/ls-files.c:478
+#: builtin/ls-files.c:477
msgid "show ignored files in the output"
msgstr "hiển thị các tập tin bị bỠqua trong kết xuất"
-#: builtin/ls-files.c:481
+#: builtin/ls-files.c:480
msgid "show staged contents' object name in the output"
msgstr "hiển thị tên đối tượng của nội dung được lưu trạng thái ở kết xuất"
-#: builtin/ls-files.c:483
+#: builtin/ls-files.c:482
msgid "show files on the filesystem that need to be removed"
msgstr "hiển thị các tập tin trên hệ thống tập tin mà nó cần được gỡ bá»"
-#: builtin/ls-files.c:485
+#: builtin/ls-files.c:484
msgid "show 'other' directories' name only"
msgstr "chỉ hiển thị tên của các thÆ° mục “khácâ€"
-#: builtin/ls-files.c:488
+#: builtin/ls-files.c:487
msgid "don't show empty directories"
msgstr "không hiển thị thư mục rỗng"
-#: builtin/ls-files.c:491
+#: builtin/ls-files.c:490
msgid "show unmerged files in the output"
msgstr "hiển thị các tập tin chưa hòa trộn trong kết xuất"
-#: builtin/ls-files.c:493
+#: builtin/ls-files.c:492
msgid "show resolve-undo information"
msgstr "hiển thị thông tin resolve-undo"
-#: builtin/ls-files.c:495
+#: builtin/ls-files.c:494
msgid "skip files matching pattern"
msgstr "bỠqua những tập tin khớp với một mẫu"
-#: builtin/ls-files.c:498
+#: builtin/ls-files.c:497
msgid "exclude patterns are read from <file>"
msgstr "mẫu loại trừ được Ä‘á»c từ <tập tin>"
-#: builtin/ls-files.c:501
+#: builtin/ls-files.c:500
msgid "read additional per-directory exclude patterns in <file>"
msgstr "Ä‘á»c thêm các mẫu ngoại trừ má»—i thÆ° mục trong <tập tin>"
-#: builtin/ls-files.c:503
+#: builtin/ls-files.c:502
msgid "add the standard git exclusions"
msgstr "thêm loại trừ tiêu chuẩn kiểu git"
-#: builtin/ls-files.c:506
+#: builtin/ls-files.c:505
msgid "make the output relative to the project top directory"
msgstr "làm cho kết xuất liên quan đến thư mục ở mức cao nhất (gốc) của dự án"
-#: builtin/ls-files.c:509
+#: builtin/ls-files.c:508
msgid "if any <file> is not in the index, treat this as an error"
msgstr "nếu <tập tin> bất kỳ không ở trong bảng mục lục, xử lý nó như một lỗi"
-#: builtin/ls-files.c:510
+#: builtin/ls-files.c:509
msgid "tree-ish"
msgstr "tree-ish"
-#: builtin/ls-files.c:511
+#: builtin/ls-files.c:510
msgid "pretend that paths removed since <tree-ish> are still present"
msgstr ""
"giả định rằng các Ä‘Æ°á»ng dẫn đã bị gỡ bá» kể từ <tree-ish> nay vẫn hiện diện"
-#: builtin/ls-files.c:513
+#: builtin/ls-files.c:512
msgid "show debugging data"
msgstr "hiển thị dữ liệu gỡ lỗi"
@@ -5941,166 +6510,170 @@ msgstr "git merge [các-tùy-chá»n] <tin-nhắn> HEAD <commit>"
msgid "git merge --abort"
msgstr "git merge --abort"
-#: builtin/merge.c:90
+#: builtin/merge.c:98
msgid "switch `m' requires a value"
msgstr "switch “m†yêu cầu một giá trị"
-#: builtin/merge.c:127
+#: builtin/merge.c:135
#, c-format
msgid "Could not find merge strategy '%s'.\n"
msgstr "Không tìm thấy chiến lược hòa trá»™n “%sâ€.\n"
-#: builtin/merge.c:128
+#: builtin/merge.c:136
#, c-format
msgid "Available strategies are:"
msgstr "Các chiến lược sẵn sàng là:"
-#: builtin/merge.c:133
+#: builtin/merge.c:141
#, c-format
msgid "Available custom strategies are:"
msgstr "Các chiến lược tùy chỉnh sẵn sàng là:"
-#: builtin/merge.c:183
+#: builtin/merge.c:198
msgid "do not show a diffstat at the end of the merge"
msgstr "không hiển thị thống kê khác biệt tại cuối của lần hòa trộn"
-#: builtin/merge.c:186
+#: builtin/merge.c:201
msgid "show a diffstat at the end of the merge"
msgstr "hiển thị thống kê khác biệt tại cuối của hòa trộn"
-#: builtin/merge.c:187
+#: builtin/merge.c:202
msgid "(synonym to --stat)"
msgstr "(đồng nghĩa với --stat)"
-#: builtin/merge.c:189
+#: builtin/merge.c:204
msgid "add (at most <n>) entries from shortlog to merge commit message"
msgstr "thêm (ít nhất <n>) mục từ shortlog cho ghi chú chuyển giao hòa trộn"
-#: builtin/merge.c:192
+#: builtin/merge.c:207
msgid "create a single commit instead of doing a merge"
msgstr "tạo một lần chuyển giao (commit) đưon thay vì thực hiện việc hòa trộn"
-#: builtin/merge.c:194
+#: builtin/merge.c:209
msgid "perform a commit if the merge succeeds (default)"
msgstr "thực hiện chuyển giao nếu hòa trộn thành công (mặc định)"
-#: builtin/merge.c:196
+#: builtin/merge.c:211
msgid "edit message before committing"
msgstr "sửa chú thích trước khi chuyển giao (commit)"
-#: builtin/merge.c:198
+#: builtin/merge.c:212
msgid "allow fast-forward (default)"
msgstr "cho phép fast-forward (mặc định)"
-#: builtin/merge.c:200
+#: builtin/merge.c:214
msgid "abort if fast-forward is not possible"
msgstr "bỠqua nếu fast-forward không thể được"
-#: builtin/merge.c:202 builtin/notes.c:866 builtin/revert.c:112
+#: builtin/merge.c:218
+msgid "Verify that the named commit has a valid GPG signature"
+msgstr "Thẩm tra xem lần chuyển giao có tên đó có chữ ký GPG hợp lệ hay không"
+
+#: builtin/merge.c:219 builtin/notes.c:738 builtin/revert.c:114
msgid "strategy"
msgstr "chiến lược"
-#: builtin/merge.c:203
+#: builtin/merge.c:220
msgid "merge strategy to use"
msgstr "chiến lược hòa trộn sẽ dùng"
-#: builtin/merge.c:204
+#: builtin/merge.c:221
msgid "option=value"
msgstr "tùy_chá»n=giá_trị"
-#: builtin/merge.c:205
+#: builtin/merge.c:222
msgid "option for selected merge strategy"
msgstr "tùy chá»n cho chiến lược hòa trá»™n đã chá»n"
-#: builtin/merge.c:207
+#: builtin/merge.c:224
msgid "merge commit message (for a non-fast-forward merge)"
msgstr ""
"hòa trộn ghi chú của lần chuyển giao (dành cho hòa trộn non-fast-forward)"
-#: builtin/merge.c:211
+#: builtin/merge.c:228
msgid "abort the current in-progress merge"
msgstr "bãi bỠquá trình hòa trộn hiện tại đang thực hiện"
-#: builtin/merge.c:240
+#: builtin/merge.c:257
msgid "could not run stash."
msgstr "không thể chạy stash."
-#: builtin/merge.c:245
+#: builtin/merge.c:262
msgid "stash failed"
msgstr "stash gặp lỗi"
-#: builtin/merge.c:250
+#: builtin/merge.c:267
#, c-format
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:286 builtin/merge.c:303
msgid "read-tree failed"
msgstr "read-tree gặp lỗi"
-#: builtin/merge.c:316
+#: builtin/merge.c:333
msgid " (nothing to squash)"
msgstr " (không có gì để squash)"
-#: builtin/merge.c:329
+#: builtin/merge.c:346
#, c-format
msgid "Squash commit -- not updating HEAD\n"
msgstr "Squash commit -- không cập nhật HEAD\n"
-#: builtin/merge.c:361
+#: builtin/merge.c:378
msgid "Writing SQUASH_MSG"
msgstr "Äang ghi SQUASH_MSG"
-#: builtin/merge.c:363
+#: builtin/merge.c:380
msgid "Finishing SQUASH_MSG"
msgstr "Hoàn thành SQUASH_MSG"
-#: builtin/merge.c:386
+#: builtin/merge.c:403
#, c-format
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:436
+#: builtin/merge.c:453
#, 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:535
+#: builtin/merge.c:565
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Chuá»—i branch.%s.mergeoptions sai: %s"
-#: builtin/merge.c:628
+#: builtin/merge.c:657
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:656
+#: builtin/merge.c:685
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:670
+#: builtin/merge.c:699
#, 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:684
+#: builtin/merge.c:713
#, c-format
msgid "unable to write %s"
msgstr "không thể ghi %s"
-#: builtin/merge.c:773
+#: builtin/merge.c:802
#, c-format
msgid "Could not read from '%s'"
msgstr "Không thể Ä‘á»c từ “%sâ€"
-#: builtin/merge.c:782
+#: builtin/merge.c:811
#, 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"
-#: builtin/merge.c:788
+#: builtin/merge.c:817
#, c-format
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
@@ -6118,55 +6691,50 @@ msgstr ""
"rá»—ng\n"
"sẽ hủy bỠlần chuyển giao (commit).\n"
-#: builtin/merge.c:812
+#: builtin/merge.c:841
msgid "Empty commit message."
msgstr "Chú thích của lần commit (chuyển giao) bị trống rỗng."
-#: builtin/merge.c:824
+#: builtin/merge.c:853
#, c-format
msgid "Wonderful.\n"
msgstr "Thần kỳ.\n"
-#: builtin/merge.c:889
+#: builtin/merge.c:918
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr ""
"Việc tự động hòa trộn gặp lỗi; hãy sửa các xung đột sau đó chuyển giao "
"(commit) kết quả.\n"
-#: builtin/merge.c:905
+#: builtin/merge.c:934
#, 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:946
+#: builtin/merge.c:975
msgid "No current branch."
msgstr "không phải nhánh hiện hành"
-#: builtin/merge.c:948
+#: builtin/merge.c:977
msgid "No remote for the current branch."
msgstr "Không có máy chủ cho nhánh hiện hành."
-#: builtin/merge.c:950
+#: builtin/merge.c:979
msgid "No default upstream defined for the current branch."
msgstr "Không có thượng nguồn mặc định được định nghĩa cho nhánh hiện hành."
-#: builtin/merge.c:955
+#: builtin/merge.c:984
#, c-format
-msgid "No remote tracking branch for %s from %s"
+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:1042 builtin/merge.c:1199
-#, c-format
-msgid "%s - not something we can merge"
-msgstr "%s - không phải là một số thứ chúng tôi có thể hòa trộn"
-
-#: builtin/merge.c:1110
+#: builtin/merge.c:1140
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr ""
"Ở đây không có lần hòa trộn nào được hủy bỠgiữa chừng cả (thiếu MERGE_HEAD)."
-#: builtin/merge.c:1126 git-pull.sh:31
+#: builtin/merge.c:1156 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -6174,11 +6742,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:1129 git-pull.sh:34
+#: builtin/merge.c:1159 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:1133
+#: builtin/merge.c:1163
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -6186,85 +6754,108 @@ 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:1136
+#: builtin/merge.c:1166
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:1145
+#: builtin/merge.c:1175
msgid "You cannot combine --squash with --no-ff."
msgstr "Bạn không thể kết hợp --squash với --no-ff."
-#: builtin/merge.c:1150
-msgid "You cannot combine --no-ff with --ff-only."
-msgstr "Bạn không thể kết hợp --no-ff với --ff-only."
-
-#: builtin/merge.c:1157
+#: builtin/merge.c:1184
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr ""
"Không chỉ ra lần chuyển giao (commit) và merge.defaultToUpstream chưa được "
"đặt."
-#: builtin/merge.c:1189
+#: builtin/merge.c:1216
msgid "Can merge only exactly one commit into empty head"
msgstr ""
"Không thể hòa trộn một cách đúng đắn một lần chuyển giao (commit) vào một "
"head rá»—ng"
-#: builtin/merge.c:1192
+#: builtin/merge.c:1219
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:1194
+#: builtin/merge.c:1221
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr ""
"Chuyển giao (commit) không-fast-forward không hợp lý ở trong một head trống "
"rá»—ng"
-#: builtin/merge.c:1310
+#: builtin/merge.c:1226
+#, 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:1277
+#, c-format
+msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
+msgstr ""
+"Lần chuyển giao %s có một chữ ký GPG không đáng tin, được cho là bởi %s."
+
+#: builtin/merge.c:1280
+#, c-format
+msgid "Commit %s has a bad GPG signature allegedly by %s."
+msgstr "Lần chuyển giao %s có một chữ ký GPG sai, được cho là bởi %s."
+
+#. 'N'
+#: builtin/merge.c:1283
+#, c-format
+msgid "Commit %s does not have a GPG signature."
+msgstr "Lần chuyển giao (commit) %s không có chữ ký GPG."
+
+#: builtin/merge.c:1286
+#, c-format
+msgid "Commit %s has a good GPG signature by %s\n"
+msgstr "Lần chuyển giao %s có một chữ ký GPG tốt bởi %s\n"
+
+#: builtin/merge.c:1370
#, c-format
msgid "Updating %s..%s\n"
msgstr "Äang cập nhật %s..%s\n"
-#: builtin/merge.c:1349
+#: builtin/merge.c:1409
#, 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:1356
+#: builtin/merge.c:1416
#, c-format
msgid "Nope.\n"
msgstr "Không.\n"
-#: builtin/merge.c:1388
+#: builtin/merge.c:1448
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:1411 builtin/merge.c:1490
+#: builtin/merge.c:1471 builtin/merge.c:1550
#, 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:1415
+#: builtin/merge.c:1475
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "Äang thá»­ chiến lược hòa trá»™n %s...\n"
-#: builtin/merge.c:1481
+#: builtin/merge.c:1541
#, 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:1483
+#: builtin/merge.c:1543
#, 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:1492
+#: builtin/merge.c:1552
#, 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:1504
+#: builtin/merge.c:1564
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
@@ -6433,48 +7024,52 @@ msgstr "Äổi tên %s thành %s\n"
msgid "renaming '%s' failed"
msgstr "đổi tên %s gặp lỗi"
-#: builtin/name-rev.c:175
+#: builtin/name-rev.c:259
msgid "git name-rev [options] <commit>..."
msgstr "git name-rev [các-tùy-chá»n] <commit>..."
-#: builtin/name-rev.c:176
+#: builtin/name-rev.c:260
msgid "git name-rev [options] --all"
msgstr "git name-rev [các-tùy-chá»n] --all"
-#: builtin/name-rev.c:177
+#: builtin/name-rev.c:261
msgid "git name-rev [options] --stdin"
msgstr "git name-rev [các-tùy-chá»n] --stdin"
-#: builtin/name-rev.c:229
+#: builtin/name-rev.c:313
msgid "print only names (no SHA-1)"
msgstr "chỉ hiển thị tên (không SHA-1)"
-#: builtin/name-rev.c:230
+#: builtin/name-rev.c:314
msgid "only use tags to name the commits"
msgstr "chỉ dùng các thẻ để đặt tên cho các lần chuyển giao"
-#: builtin/name-rev.c:232
+#: builtin/name-rev.c:316
msgid "only use refs matching <pattern>"
msgstr "chỉ sử dụng các tham chiếu (refs) khớp với <mẫu>"
-#: builtin/name-rev.c:234
+#: builtin/name-rev.c:318
msgid "list all commits reachable from all refs"
msgstr ""
"liệt kê tất cả các lần chuyển giao có thể Ä‘á»c được từ tất cả các tham chiếu"
-#: builtin/name-rev.c:235
+#: builtin/name-rev.c:319
msgid "read from stdin"
msgstr "Ä‘á»c từ đầu vào tiêu chuẩn"
-#: builtin/name-rev.c:236
+#: builtin/name-rev.c:320
msgid "allow to print `undefined` names"
msgstr "cho phép hiển thị các tên “chưa định nghĩa“"
-#: builtin/notes.c:26
+#: builtin/name-rev.c:326
+msgid "dereference tags in the input (internal use)"
+msgstr "bãi bỠtham chiếu các thẻ trong đầu vào (dùng nội bộ)"
+
+#: builtin/notes.c:24
msgid "git notes [--ref <notes_ref>] [list [<object>]]"
msgstr "git notes [--ref <notes_ref>] [list [<đối-tượng>]]"
-#: builtin/notes.c:27
+#: builtin/notes.c:25
msgid ""
"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
@@ -6482,11 +7077,11 @@ msgstr ""
"git notes [--ref <notes_ref>] add [-f] [-m <lá»i-nhắn> | -F <tập-tin> | (-c | "
"-C) <đối-tượng>] [<đối-tượng>]"
-#: builtin/notes.c:28
+#: builtin/notes.c:26
msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
msgstr "git notes [--ref <notes_ref>] copy [-f] <từ-đối-tượng> <đến-đối-tượng>"
-#: builtin/notes.c:29
+#: builtin/notes.c:27
msgid ""
"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
@@ -6494,223 +7089,200 @@ msgstr ""
"git notes [--ref <notes_ref>] append [-m <lá»i-nhắn> | -F <tập-tin> | (-c | -"
"C) <đối-tượng>] [<đối-tượng>]"
-#: builtin/notes.c:30
+#: builtin/notes.c:28
msgid "git notes [--ref <notes_ref>] edit [<object>]"
msgstr "git notes [--ref <notes_ref>] edit [<đối-tượng>]"
-#: builtin/notes.c:31
+#: builtin/notes.c:29
msgid "git notes [--ref <notes_ref>] show [<object>]"
msgstr "git notes [--ref <notes_ref>] show [<đối-tượng>]"
-#: builtin/notes.c:32
+#: builtin/notes.c:30
msgid ""
"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
msgstr ""
"git notes [--ref <notes_ref>] merge [-v | -q] [-s <chiến-lược> ] <notes_ref>"
-#: builtin/notes.c:33
+#: builtin/notes.c:31
msgid "git notes merge --commit [-v | -q]"
msgstr "git notes merge --commit [-v | -q]"
-#: builtin/notes.c:34
+#: builtin/notes.c:32
msgid "git notes merge --abort [-v | -q]"
msgstr "git notes merge --abort [-v | -q]"
-#: builtin/notes.c:35
+#: builtin/notes.c:33
msgid "git notes [--ref <notes_ref>] remove [<object>...]"
msgstr "git notes [--ref <notes_ref>] remove [<đối-tượng>...]"
-#: builtin/notes.c:36
+#: builtin/notes.c:34
msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
msgstr "git notes [--ref <notes_ref>] prune [-n | -v]"
-#: builtin/notes.c:37
+#: builtin/notes.c:35
msgid "git notes [--ref <notes_ref>] get-ref"
msgstr "git notes [--ref <notes_ref>] get-ref"
-#: builtin/notes.c:42
+#: builtin/notes.c:40
msgid "git notes [list [<object>]]"
msgstr "git notes [list [<đối tượng>]]"
-#: builtin/notes.c:47
+#: builtin/notes.c:45
msgid "git notes add [<options>] [<object>]"
msgstr "git notes add [<các-tùy-chá»n>] [<đối-tượng>]"
-#: builtin/notes.c:52
+#: builtin/notes.c:50
msgid "git notes copy [<options>] <from-object> <to-object>"
msgstr "git notes copy [<các-tùy-chá»n>] <từ-đối-tượng> <đến-đối-tượng>"
-#: builtin/notes.c:53
+#: builtin/notes.c:51
msgid "git notes copy --stdin [<from-object> <to-object>]..."
msgstr "git notes copy --stdin [<từ-đối-tượng> <đến-đối-tượng>]..."
-#: builtin/notes.c:58
+#: builtin/notes.c:56
msgid "git notes append [<options>] [<object>]"
msgstr "git notes append [<các-tùy-chá»n>] [<đối-tượng>]"
-#: builtin/notes.c:63
+#: builtin/notes.c:61
msgid "git notes edit [<object>]"
msgstr "git notes edit [<đối tượng>]"
-#: builtin/notes.c:68
+#: builtin/notes.c:66
msgid "git notes show [<object>]"
msgstr "git notes show [<đối tượng>]"
-#: builtin/notes.c:73
+#: builtin/notes.c:71
msgid "git notes merge [<options>] <notes_ref>"
msgstr "git notes merge [<các-tùy-chá»n>] <notes_ref>"
-#: builtin/notes.c:74
+#: builtin/notes.c:72
msgid "git notes merge --commit [<options>]"
msgstr "git notes merge --commit [<các-tùy-chá»n>]"
-#: builtin/notes.c:75
+#: builtin/notes.c:73
msgid "git notes merge --abort [<options>]"
msgstr "git notes merge --abort [<các-tùy-chá»n>]"
-#: builtin/notes.c:80
+#: builtin/notes.c:78
msgid "git notes remove [<object>]"
msgstr "git notes remove [<đối tượng>]"
-#: builtin/notes.c:85
+#: builtin/notes.c:83
msgid "git notes prune [<options>]"
msgstr "git notes prune [<các-tùy-chá»n>]"
-#: builtin/notes.c:90
+#: builtin/notes.c:88
msgid "git notes get-ref"
msgstr "git notes get-ref"
-#: builtin/notes.c:139
+#: builtin/notes.c:137
#, c-format
msgid "unable to start 'show' for object '%s'"
msgstr "không thể khởi chạy “show†cho đối tượng “%sâ€"
-#: builtin/notes.c:143
+#: builtin/notes.c:141
msgid "could not read 'show' output"
msgstr "không thể Ä‘á»c kết xuất “showâ€"
-#: builtin/notes.c:151
+#: builtin/notes.c:149
#, c-format
msgid "failed to finish 'show' for object '%s'"
msgstr "gặp lá»—i khi hoàn thành “show†cho đối tượng “%sâ€"
-#: builtin/notes.c:169 builtin/tag.c:341
+#: builtin/notes.c:167 builtin/tag.c:341
#, c-format
msgid "could not create file '%s'"
msgstr "không thể tạo tập tin “%sâ€"
-#: builtin/notes.c:188
+#: builtin/notes.c:186
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"
-#: builtin/notes.c:209 builtin/notes.c:972
+#: builtin/notes.c:207 builtin/notes.c:844
#, c-format
msgid "Removing note for object %s\n"
msgstr "Äang gỡ bá» ghi chú (note) cho đối tượng %s\n"
-#: builtin/notes.c:214
+#: builtin/notes.c:212
msgid "unable to write note object"
msgstr "không thể ghi đối tượng ghi chú (note)"
-#: builtin/notes.c:216
+#: builtin/notes.c:214
#, c-format
msgid "The note contents has been left in %s"
msgstr "Nội dung ghi chú còn lại %s"
-#: builtin/notes.c:250 builtin/tag.c:540
+#: builtin/notes.c:248 builtin/tag.c:540
#, c-format
msgid "cannot read '%s'"
msgstr "không thể Ä‘á»c “%sâ€"
-#: builtin/notes.c:252 builtin/tag.c:543
+#: builtin/notes.c:250 builtin/tag.c:543
#, c-format
msgid "could not open or read '%s'"
msgstr "không thể mở hay Ä‘á»c “%sâ€"
-#: builtin/notes.c:271 builtin/notes.c:444 builtin/notes.c:446
-#: builtin/notes.c:506 builtin/notes.c:560 builtin/notes.c:643
-#: builtin/notes.c:648 builtin/notes.c:723 builtin/notes.c:765
-#: builtin/notes.c:967 builtin/tag.c:556
+#: builtin/notes.c:269 builtin/notes.c:316 builtin/notes.c:318
+#: builtin/notes.c:378 builtin/notes.c:432 builtin/notes.c:515
+#: builtin/notes.c:520 builtin/notes.c:595 builtin/notes.c:637
+#: builtin/notes.c:839 builtin/tag.c:556
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
msgstr "Gặp lỗi khi phân giải “%s†như là một tham chiếu (ref) hợp lệ."
-#: builtin/notes.c:274
+#: builtin/notes.c:272
#, c-format
msgid "Failed to read object '%s'."
msgstr "Gặp lá»—i khi Ä‘á»c đối tượng “%sâ€."
-#: builtin/notes.c:298
-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ú"
-
-#: builtin/notes.c:339
-#, c-format
-msgid "Bad notes.rewriteMode value: '%s'"
-msgstr "Giá trị notes.rewriteMode sai: “%sâ€"
-
-#: builtin/notes.c:349
-#, c-format
-msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
-msgstr "Từ chối ghi đè ghi chú trong %s (nằm ngoài của refs/notes/)"
-
-#. TRANSLATORS: The first %s is the name of the
-#. environment variable, the second %s is its value
-#: builtin/notes.c:376
-#, c-format
-msgid "Bad %s value: '%s'"
-msgstr "Giá trị %s sai: “%sâ€"
-
-#: builtin/notes.c:440
+#: builtin/notes.c:312
#, c-format
msgid "Malformed input line: '%s'."
msgstr "Dòng nhập vào dị hình: “%sâ€."
-#: builtin/notes.c:455
+#: builtin/notes.c:327
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
msgstr "Gặp lá»—i khi sao chép ghi chú (note) từ “%s†tá»›i “%sâ€"
-#: builtin/notes.c:499 builtin/notes.c:553 builtin/notes.c:626
-#: builtin/notes.c:638 builtin/notes.c:711 builtin/notes.c:758
-#: builtin/notes.c:1032
+#: builtin/notes.c:371 builtin/notes.c:425 builtin/notes.c:498
+#: builtin/notes.c:510 builtin/notes.c:583 builtin/notes.c:630
+#: builtin/notes.c:904
msgid "too many parameters"
msgstr "quá nhiá»u đối số"
-#: builtin/notes.c:512 builtin/notes.c:771
+#: builtin/notes.c:384 builtin/notes.c:643
#, c-format
msgid "No note found for object %s."
msgstr "không tìm thấy ghi chú cho đối tượng %s."
-#: builtin/notes.c:534 builtin/notes.c:691
+#: builtin/notes.c:406 builtin/notes.c:563
msgid "note contents as a string"
msgstr "nội dung ghi chú (note) nằm trong một chuỗi"
-#: builtin/notes.c:537 builtin/notes.c:694
+#: builtin/notes.c:409 builtin/notes.c:566
msgid "note contents in a file"
msgstr "nội dung ghi chú (note) nằm trong một tập tin"
-#: builtin/notes.c:539 builtin/notes.c:542 builtin/notes.c:696
-#: builtin/notes.c:699 builtin/tag.c:474
+#: builtin/notes.c:411 builtin/notes.c:414 builtin/notes.c:568
+#: builtin/notes.c:571 builtin/tag.c:474
msgid "object"
msgstr "đối tượng"
-#: builtin/notes.c:540 builtin/notes.c:697
+#: builtin/notes.c:412 builtin/notes.c:569
msgid "reuse and edit specified note object"
msgstr "dùng lại nhưng có sửa chữa đối tượng note đã chỉ ra"
-#: builtin/notes.c:543 builtin/notes.c:700
+#: builtin/notes.c:415 builtin/notes.c:572
msgid "reuse specified note object"
msgstr "dùng lại đối tượng ghi chú (note) đã chỉ ra"
-#: builtin/notes.c:545 builtin/notes.c:613
+#: builtin/notes.c:417 builtin/notes.c:485
msgid "replace existing notes"
msgstr "thay thế ghi chú trước"
-#: builtin/notes.c:579
+#: builtin/notes.c:451
#, c-format
msgid ""
"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6719,24 +7291,24 @@ 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:584 builtin/notes.c:661
+#: builtin/notes.c:456 builtin/notes.c:533
#, c-format
msgid "Overwriting existing notes for object %s\n"
msgstr "Äang ghi đè lên ghi chú cÅ© cho đối tượng %s\n"
-#: builtin/notes.c:614
+#: builtin/notes.c:486
msgid "read objects from stdin"
msgstr "Ä‘á»c các đối tượng từ đầu vào tiêu chuẩn"
-#: builtin/notes.c:616
+#: builtin/notes.c:488
msgid "load rewriting config for <command> (implies --stdin)"
msgstr "tải cấu hình chép lại cho <lệnh> (ngầm định là --stdin)"
-#: builtin/notes.c:634
+#: builtin/notes.c:506
msgid "too few parameters"
msgstr "quá ít đối số"
-#: builtin/notes.c:655
+#: builtin/notes.c:527
#, c-format
msgid ""
"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6745,12 +7317,12 @@ 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:667
+#: builtin/notes.c:539
#, c-format
msgid "Missing notes on source object %s. Cannot copy."
msgstr "Thiếu ghi chú trên đối tượng nguốn %s. Không thể sao chép."
-#: builtin/notes.c:716
+#: builtin/notes.c:588
#, c-format
msgid ""
"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
@@ -6759,15 +7331,15 @@ msgstr ""
"Các tùy chá»n -m/-F/-c/-C đã cổ không còn dùng nữa cho lệnh con “editâ€.\n"
"Xin hãy sá»­ dụng lệnh sau để thay thế: “git notes add -f -m/-F/-c/-Câ€.\n"
-#: builtin/notes.c:863
+#: builtin/notes.c:735
msgid "General options"
msgstr "Tùy chá»n chung"
-#: builtin/notes.c:865
+#: builtin/notes.c:737
msgid "Merge options"
msgstr "Tùy chá»n vá» hòa trá»™n"
-#: builtin/notes.c:867
+#: builtin/notes.c:739
msgid ""
"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
"cat_sort_uniq)"
@@ -6775,46 +7347,46 @@ msgstr ""
"phân giải các xung đột “notes†sử dụng chiến lược đã đưa ra (manual/ours/"
"theirs/union/cat_sort_uniq)"
-#: builtin/notes.c:869
+#: builtin/notes.c:741
msgid "Committing unmerged notes"
msgstr "Chuyển giao các note chưa được hòa trộn"
-#: builtin/notes.c:871
+#: builtin/notes.c:743
msgid "finalize notes merge by committing unmerged notes"
msgstr ""
"các note cuối cùng được hòa trộn bởi các note chưa hòa trộn của lần chuyển "
"giao"
-#: builtin/notes.c:873
+#: builtin/notes.c:745
msgid "Aborting notes merge resolution"
msgstr "Hủy bỠphân giải ghi chú (note) hòa trộn"
-#: builtin/notes.c:875
+#: builtin/notes.c:747
msgid "abort notes merge"
msgstr "bỠqua hòa trộn các ghi chú (note)"
-#: builtin/notes.c:970
+#: builtin/notes.c:842
#, c-format
msgid "Object %s has no note\n"
msgstr "Äối tượng %s không có ghi chú (note)\n"
-#: builtin/notes.c:982
+#: builtin/notes.c:854
msgid "attempt to remove non-existent note is not an error"
msgstr "cố gắng gỡ bỠmột note chưa từng tồn tại không phải là một lỗi"
-#: builtin/notes.c:985
+#: builtin/notes.c:857
msgid "read object names from the standard input"
msgstr "Ä‘á»c tên đối tượng từ thiết bị nhập chuẩn"
-#: builtin/notes.c:1066
+#: builtin/notes.c:938
msgid "notes_ref"
msgstr "notes_ref"
-#: builtin/notes.c:1067
+#: builtin/notes.c:939
msgid "use notes from <notes_ref>"
msgstr "dùng “notes†từ <notes_ref>"
-#: builtin/notes.c:1102 builtin/remote.c:1598
+#: builtin/notes.c:974 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
msgstr "Không hiểu câu lệnh con: %s"
@@ -7055,7 +7627,7 @@ msgstr ""
" git push %s %s\n"
"%s"
-#: builtin/push.c:121
+#: builtin/push.c:117
#, c-format
msgid ""
"You are not currently on a branch.\n"
@@ -7070,7 +7642,7 @@ msgstr ""
"\n"
" git push %s HEAD:<tên-của-nhánh-máy-chủ>\n"
-#: builtin/push.c:128
+#: builtin/push.c:131
#, c-format
msgid ""
"The current branch %s has no upstream branch.\n"
@@ -7084,12 +7656,12 @@ msgstr ""
"\n"
" git push --set-upstream %s %s\n"
-#: builtin/push.c:136
+#: builtin/push.c:139
#, c-format
msgid "The current branch %s has multiple upstream branches, refusing to push."
msgstr "Nhánh hiện tại %s có đa nhánh thượng nguồn (upstream), từ chối push."
-#: builtin/push.c:139
+#: builtin/push.c:142
#, c-format
msgid ""
"You are pushing to remote '%s', which is not the upstream of\n"
@@ -7101,7 +7673,7 @@ msgstr ""
"nhánh hiện tại “%s†của bạn, mà không báo cho tôi biết là cái gì được push\n"
"để cập nhật nhánh máy chủ nào."
-#: builtin/push.c:151
+#: builtin/push.c:165
msgid ""
"push.default is unset; its implicit value is changing in\n"
"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
@@ -7134,28 +7706,28 @@ msgstr ""
"tá»±\n"
"“current†thay vì “simple†nếu bạn thỉnh thoảng phải sử dụng bản Git cũ)"
-#: builtin/push.c:199
+#: builtin/push.c:225
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
+#: builtin/push.c:232
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
-"before pushing again.\n"
+"its remote counterpart. Integrate the remote changes (e.g.\n"
+"'git pull ...') before pushing again.\n"
"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"
+"pull...â€)\n"
"trước khi lại push lần nữa.\n"
-"Xem trong phần “Note about fast-forwards†từ lệnh “git push --help†để có "
-"thông tin chi tiết."
+"Xem “Note about fast-forwards†từ lệnh “git push --help†để có thông tin chi "
+"tiết."
-#: builtin/push.c:212
+#: builtin/push.c:238
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"
@@ -7170,41 +7742,40 @@ msgstr ""
"thành “simpleâ€, “current†hoặc “upstream†để chỉ push nhánh hiện hành mà "
"thôi."
-#: builtin/push.c:218
+#: builtin/push.c:244
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and merge the remote changes\n"
-"(e.g. 'git pull') before pushing again.\n"
+"counterpart. Check out this branch and integrate the remote changes\n"
+"(e.g. 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"Việc cập nhật bị từ chối bởi vì đầu mút của nhánh được push nằm đằng sau bộ\n"
"phận tương ứng của máy chủ. Checkou nhánh này và hòa trộn với các thay đổi "
"từ máy chủ\n"
-"(v.d. “git pullâ€) trÆ°á»›c khi lại push lần nữa.\n"
-"Xem trong phần “Note about fast-forwards†từ lệnh “git push --help†để có "
-"thông tin chi tiết."
+"(v.d. “git pull ...â€) trÆ°á»›c khi lại push lần nữa.\n"
+"Xem “Note about fast-forwards†từ lệnh “git push --help†để có thông tin chi "
+"tiết."
-#: builtin/push.c:224
+#: builtin/push.c:250
msgid ""
"Updates were rejected because the remote contains work that you do\n"
"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first merge the remote changes (e.g.,\n"
-"'git pull') before pushing again.\n"
+"to the same ref. You may want to first integrate the remote changes\n"
+"(e.g., 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"Việc cập nhật bị từ chối bởi vì máy chủ có chứa công việc mà bạn không\n"
-"có ở máy ná»™i bá»™ của mình. Lá»—i này thÆ°á»ng có nguyên nhân bởi kho khác đẩy dữ "
-"liệu lên\n"
-"cùng một tham chiếu. Bạn có lẽ muốn hòa trộn với các thay đổi từ máy chủ\n"
-"(v.d. “git pullâ€) trÆ°á»›c khi lại push lần nữa.\n"
-"Xem trong phần “Note about fast-forwards†từ lệnh “git push --help†để có "
-"thông tin chi tiết."
-
-#: builtin/push.c:231
+"có ở máy ná»™i bá»™ của mình. Lá»—i này thÆ°á»ng có nguyên nhân bởi kho khác đẩy\n"
+"dữ liệu lên cùng một tham chiếu. Bạn có lẽ muốn hòa trộn với các thay đổi\n"
+"từ máy chủ(v.d. “git pull...â€) trÆ°á»›c khi lại push lần nữa.\n"
+"Xem “Note about fast-forwards†từ lệnh “git push --help†để có thông tin chi "
+"tiết."
+
+#: builtin/push.c:257
msgid "Updates were rejected because the tag already exists in the remote."
msgstr "Việc cập nhật bị từ chối bởi vì thẻ đã sẵn có từ trước trên máy chủ."
-#: builtin/push.c:234
+#: builtin/push.c:260
msgid ""
"You cannot update a remote ref that points at a non-commit object,\n"
"or update a remote ref to make it point at a non-commit object,\n"
@@ -7216,22 +7787,22 @@ msgstr ""
"tượng\n"
"không phải chuyển giao, mà không sá»­ dụng tùy chá»n “--forceâ€.\n"
-#: builtin/push.c:294
+#: builtin/push.c:320
#, c-format
msgid "Pushing to %s\n"
msgstr "Äang push (đẩy) lên %s\n"
-#: builtin/push.c:298
+#: builtin/push.c:324
#, 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:331
+#: builtin/push.c:357
#, c-format
msgid "bad repository '%s'"
msgstr "repository (kho) sai “%sâ€"
-#: builtin/push.c:332
+#: builtin/push.c:358
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -7252,84 +7823,88 @@ msgstr ""
"\n"
" git push <tên>\n"
-#: builtin/push.c:347
+#: builtin/push.c:373
msgid "--all and --tags are incompatible"
msgstr "--all và --tags xung khắc nhau"
-#: builtin/push.c:348
+#: builtin/push.c:374
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:353
+#: builtin/push.c:379
msgid "--mirror and --tags are incompatible"
msgstr "--mirror và --tags xung khắc nhau"
-#: builtin/push.c:354
+#: builtin/push.c:380
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:359
+#: builtin/push.c:385
msgid "--all and --mirror are incompatible"
msgstr "--all và --mirror xung khắc nhau"
-#: builtin/push.c:419
+#: builtin/push.c:445
msgid "repository"
msgstr "kho"
-#: builtin/push.c:420
+#: builtin/push.c:446
msgid "push all refs"
msgstr "push tất cả refs"
-#: builtin/push.c:421
+#: builtin/push.c:447
msgid "mirror all refs"
msgstr "mirror tất cả refs"
-#: builtin/push.c:423
+#: builtin/push.c:449
msgid "delete refs"
msgstr "xóa refs"
-#: builtin/push.c:424
+#: builtin/push.c:450
msgid "push tags (can't be used with --all or --mirror)"
msgstr ""
"các thẻ push (không thể sá»­ dụng cùng vá»›i các tùy chá»n --all hay --mirror)"
-#: builtin/push.c:427
+#: builtin/push.c:453
msgid "force updates"
msgstr "ép buộc cập nhật"
-#: builtin/push.c:428
+#: builtin/push.c:454
msgid "check"
msgstr "kiểm tra"
-#: builtin/push.c:429
+#: builtin/push.c:455
msgid "control recursive pushing of submodules"
msgstr "Ä‘iá»u khiển việc đẩy lên (push) đệ qui của mô-Ä‘un-con"
-#: builtin/push.c:431
+#: builtin/push.c:457
msgid "use thin pack"
msgstr "tạo gói nhẹ"
-#: builtin/push.c:432 builtin/push.c:433
+#: builtin/push.c:458 builtin/push.c:459
msgid "receive pack program"
msgstr "nhận vỠchương trình pack"
-#: builtin/push.c:434
+#: builtin/push.c:460
msgid "set upstream for git pull/status"
msgstr "đặt thượng nguồn (upstream) cho git pull/status"
-#: builtin/push.c:437
+#: builtin/push.c:463
msgid "prune locally removed refs"
msgstr "prune (cắt cụt) những tham chiếu (refs) bị gỡ bá»"
-#: builtin/push.c:439
+#: builtin/push.c:465
msgid "bypass pre-push hook"
msgstr "vòng qua “pre-push hookâ€"
-#: builtin/push.c:448
+#: builtin/push.c:466
+msgid "push missing but relevant tags"
+msgstr "push bị trượt nhưng các thẻ thích hợp"
+
+#: builtin/push.c:476
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:450
+#: builtin/push.c:478
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"
@@ -7344,71 +7919,81 @@ msgstr ""
"[--index-output=<tập-tin>] (--empty | <tree-ish1> [<tree-ish2> [<tree-"
"ish3>]])"
-#: builtin/read-tree.c:108
+#: builtin/read-tree.c:109
msgid "write resulting index to <file>"
msgstr "ghi mục lục kết quả vào <tập-tin>"
-#: builtin/read-tree.c:111
+#: builtin/read-tree.c:112
msgid "only empty the index"
msgstr "chỉ với bảng mục lục trống rỗng"
-#: builtin/read-tree.c:113
+#: builtin/read-tree.c:114
msgid "Merging"
msgstr "Hòa trộn"
-#: builtin/read-tree.c:115
+#: builtin/read-tree.c:116
msgid "perform a merge in addition to a read"
msgstr "thá»±c hiện má»™t hòa trá»™n thêm vào việc Ä‘á»c"
-#: builtin/read-tree.c:117
+#: builtin/read-tree.c:118
msgid "3-way merge if no file level merging required"
msgstr ""
"hòa trộn kiểu “3-way†nếu không có tập tin mức hòa trộn nào được yêu cầu "
-#: builtin/read-tree.c:119
+#: builtin/read-tree.c:120
msgid "3-way merge in presence of adds and removes"
msgstr "hòa trá»™n 3-way trong sá»± hiện diện của “adds†và “removesâ€"
-#: builtin/read-tree.c:121
+#: builtin/read-tree.c:122
msgid "same as -m, but discard unmerged entries"
msgstr "giống với -m, nhưng bỠqua các mục chưa được hòa trộn"
-#: builtin/read-tree.c:122
+#: builtin/read-tree.c:123
msgid "<subdirectory>/"
msgstr "<thư-mục-con>/"
-#: builtin/read-tree.c:123
+#: builtin/read-tree.c:124
msgid "read the tree into the index under <subdirectory>/"
msgstr "Ä‘á»c cây vào trong bảng mục lục dÆ°á»›i <thÆ°_mục_con>/"
-#: builtin/read-tree.c:126
+#: builtin/read-tree.c:127
msgid "update working tree with merge result"
msgstr "cập nhật cây làm việc với kết quả hòa trộn"
-#: builtin/read-tree.c:128
+#: builtin/read-tree.c:129
msgid "gitignore"
msgstr "gitignore"
-#: builtin/read-tree.c:129
+#: builtin/read-tree.c:130
msgid "allow explicitly ignored files to be overwritten"
msgstr "cho phép các tập tin rõ ràng bị lỠđi được ghi đè"
-#: builtin/read-tree.c:132
+#: builtin/read-tree.c:133
msgid "don't check the working tree after merging"
msgstr "không kiểm tra cây làm việc sau hòa trộn"
-#: builtin/read-tree.c:133
+#: builtin/read-tree.c:134
msgid "don't update the index or the work tree"
msgstr "không cập nhật bảng mục lục hay cây làm việc"
-#: builtin/read-tree.c:135
+#: builtin/read-tree.c:136
msgid "skip applying sparse checkout filter"
msgstr "bá» qua áp dụng bá»™ lá»c lấy ra (checkout) thÆ°a thá»›t"
-#: builtin/read-tree.c:137
+#: builtin/read-tree.c:138
msgid "debug unpack-trees"
msgstr "gỡ lỗi unpack-trees"
+#: builtin/reflog.c:500
+#, c-format
+msgid "%s' for '%s' is not a valid timestamp"
+msgstr "%s' cho '%s' không phải là dấu thá»i gian hợp lệ"
+
+#: builtin/reflog.c:616 builtin/reflog.c:621
+#, c-format
+msgid "'%s' is not a valid timestamp"
+msgstr "“%s†không phải là dấu thá»i gian hợp lệ"
+
#: builtin/remote.c:11
msgid "git remote [-v | --verbose]"
msgstr "git remote [-v | --verbose]"
@@ -7852,7 +8437,7 @@ msgstr " * [nên xén bớt] %s"
#: builtin/remote.c:1298
#, c-format
msgid " * [pruned] %s"
-msgstr " *[đã xén bớ] %s"
+msgstr " *[đã bị xén] %s"
#: builtin/remote.c:1321
msgid "prune remotes after fetching"
@@ -7984,97 +8569,97 @@ msgstr "Gặp lỗi khi tìm cây của HEAD."
msgid "Failed to find tree of %s."
msgstr "Gặp lỗi khi tìm cây của %s."
-#: builtin/reset.c:98
+#: builtin/reset.c:99
#, c-format
msgid "HEAD is now at %s"
msgstr "HEAD hiện giỠtại %s"
-#: builtin/reset.c:169
+#: builtin/reset.c:172
#, c-format
msgid "Cannot do a %s reset in the middle of a merge."
msgstr "Không thể thực hiện một %s reset ở giữa của quá trình hòa trộn."
-#: builtin/reset.c:248
+#: builtin/reset.c:251
msgid "be quiet, only report errors"
msgstr "làm việc ở chế độ im lặng, chỉ hiển thị khi có lỗi"
-#: builtin/reset.c:250
+#: builtin/reset.c:253
msgid "reset HEAD and index"
msgstr "đặt lại (reset) HEAD và bảng mục lục"
-#: builtin/reset.c:251
+#: builtin/reset.c:254
msgid "reset only HEAD"
msgstr "chỉ đặt lại (reset) HEAD"
-#: builtin/reset.c:253 builtin/reset.c:255
+#: builtin/reset.c:256 builtin/reset.c:258
msgid "reset HEAD, index and working tree"
msgstr "đặt lại HEAD, bảng mục lục và cây làm việc"
-#: builtin/reset.c:257
+#: builtin/reset.c:260
msgid "reset HEAD but keep local changes"
msgstr "đặt lại HEAD nhưng giữ lại các thay đổi nội bộ"
-#: builtin/reset.c:275
+#: builtin/reset.c:278
#, c-format
msgid "Failed to resolve '%s' as a valid revision."
msgstr "Gặp lỗi khi phân giải “%s†như là điểm xét duyệt hợp lệ."
-#: builtin/reset.c:278 builtin/reset.c:286
+#: builtin/reset.c:281 builtin/reset.c:289
#, c-format
msgid "Could not parse object '%s'."
msgstr "không thể phân tích đối tượng “%sâ€."
-#: builtin/reset.c:283
+#: builtin/reset.c:286
#, c-format
msgid "Failed to resolve '%s' as a valid tree."
msgstr "Gặp lỗi khi phân giải “%s†như là một cây (tree) hợp lệ."
-#: builtin/reset.c:292
+#: builtin/reset.c:295
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr "--patch xung khắc với --{hard,mixed,soft}"
-#: builtin/reset.c:301
+#: builtin/reset.c:304
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
"--mixed vá»›i các Ä‘Æ°á»ng dẫn không còn dùng nữa; hãy thay thế bằng lệnh “git "
"reset -- <Ä‘Æ°á»ng_dẫn>â€."
-#: builtin/reset.c:303
+#: builtin/reset.c:306
#, 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:313
+#: builtin/reset.c:316
#, 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:333
+#: builtin/reset.c:336
#, c-format
msgid "Could not reset index file to revision '%s'."
-msgstr "Không thể đặt lại (reset) bảng mục lục thành Ä‘iểm xét lại “%sâ€."
+msgstr "Không thể đặt lại (reset) bảng mục lục thành Ä‘iểm xét duyệt “%sâ€."
-#: builtin/reset.c:339
+#: builtin/reset.c:342
msgid "Unstaged changes after reset:"
msgstr "Những thay đổi bị bỠtrạng thái (stage) sau khi reset:"
-#: builtin/reset.c:344
+#: builtin/reset.c:347
msgid "Could not write new index file."
msgstr "Không thể ghi tập tin lưu bảng mục lục mới."
-#: builtin/rev-parse.c:339
+#: builtin/rev-parse.c:345
msgid "git rev-parse --parseopt [options] -- [<args>...]"
msgstr "git rev-parse --parseopt [các-tùy-chá»n] -- [<th.số>...]"
-#: builtin/rev-parse.c:344
+#: builtin/rev-parse.c:350
msgid "keep the `--` passed as an arg"
msgstr "giữ “--“ chuyển qua làm tham số"
-#: builtin/rev-parse.c:346
+#: builtin/rev-parse.c:352
msgid "stop parsing after the first non-option argument"
msgstr "dừng phân tích sau đối số đầu tiên không có tùy chá»n"
-#: builtin/rev-parse.c:464
+#: builtin/rev-parse.c:470
msgid ""
"git rev-parse --parseopt [options] -- [<args>...]\n"
" or: git rev-parse --sq-quote [<arg>...]\n"
@@ -8089,191 +8674,219 @@ msgstr ""
"Chạy lệnh \"git rev-parse --parseopt -h\" để có thêm thông tin vỠcách dùng."
#: builtin/revert.c:22
-msgid "git revert [options] <commit-ish>"
-msgstr "git revert [các-tùy-chá»n] <commit-ish>"
+msgid "git revert [options] <commit-ish>..."
+msgstr "git revert [các-tùy-chá»n] <commit-ish>..."
#: builtin/revert.c:23
msgid "git revert <subcommand>"
msgstr "git revert <lệnh-con>"
#: builtin/revert.c:28
-msgid "git cherry-pick [options] <commit-ish>"
-msgstr "git cherry-pick [các-tùy-chá»n] <commit-ish>"
+msgid "git cherry-pick [options] <commit-ish>..."
+msgstr "git cherry-pick [các-tùy-chá»n] <commit-ish>..."
#: builtin/revert.c:29
msgid "git cherry-pick <subcommand>"
msgstr "git cherry-pick <lệnh-con>"
-#: builtin/revert.c:70 builtin/revert.c:92
+#: builtin/revert.c:71 builtin/revert.c:94
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr "%s: %s không thể được sử dụng với %s"
-#: builtin/revert.c:103
+#: builtin/revert.c:105
msgid "end revert or cherry-pick sequence"
msgstr "kết thúc cherry-pick hay revert liên tiếp nhau"
-#: builtin/revert.c:104
+#: builtin/revert.c:106
msgid "resume revert or cherry-pick sequence"
msgstr "phục hồi lại cherry-pick hay revert liên tiếp nhau"
-#: builtin/revert.c:105
+#: builtin/revert.c:107
msgid "cancel revert or cherry-pick sequence"
msgstr "không cherry-pick hay revert liên tiếp nhau"
-#: builtin/revert.c:106
+#: builtin/revert.c:108
msgid "don't automatically commit"
msgstr "không commit một cách tự động."
-#: builtin/revert.c:107
+#: builtin/revert.c:109
msgid "edit the commit message"
msgstr "sửa lại chú thích cho commit"
-#: builtin/revert.c:110
+#: builtin/revert.c:112
msgid "parent number"
msgstr "số của cha mẹ"
-#: builtin/revert.c:112
+#: builtin/revert.c:114
msgid "merge strategy"
msgstr "chiến lược hòa trộn"
-#: builtin/revert.c:113
+#: builtin/revert.c:115
msgid "option"
msgstr "tùy chá»n"
-#: builtin/revert.c:114
+#: builtin/revert.c:116
msgid "option for merge strategy"
msgstr "tùy chá»n cho chiến lược hòa trá»™n"
-#: builtin/revert.c:125
+#: builtin/revert.c:127
msgid "append commit name"
msgstr "nối thêm tên lần chuyển giao (commit)"
-#: builtin/revert.c:126
+#: builtin/revert.c:128
msgid "allow fast-forward"
msgstr "cho phép fast-forward"
-#: builtin/revert.c:127
+#: builtin/revert.c:129
msgid "preserve initially empty commits"
msgstr "cấm khởi tạo lần chuyển giao trống rỗng"
-#: builtin/revert.c:128
+#: builtin/revert.c:130
msgid "allow commits with empty messages"
msgstr "chấp nhận chuyển giao (commit) mà không ghi chú gì"
-#: builtin/revert.c:129
+#: builtin/revert.c:131
msgid "keep redundant, empty commits"
msgstr "giữ lại các lần chuyển giao dư thừa, rỗng"
-#: builtin/revert.c:133
+#: builtin/revert.c:135
msgid "program error"
msgstr "lỗi chương trình"
-#: builtin/revert.c:223
+#: builtin/revert.c:225
msgid "revert failed"
msgstr "revert gặp lỗi"
-#: builtin/revert.c:238
+#: builtin/revert.c:240
msgid "cherry-pick failed"
msgstr "cherry-pick gặp lỗi"
-#: builtin/rm.c:15
+#: builtin/rm.c:16
msgid "git rm [options] [--] <file>..."
msgstr "git rm [các-tùy-chá»n] [--] <tập-tin>..."
-#: builtin/rm.c:64 builtin/rm.c:186
-#, c-format
+#: builtin/rm.c:64
+msgid ""
+"the following submodule (or one of its nested submodules)\n"
+"uses a .git directory:"
+msgid_plural ""
+"the following submodules (or one of its nested submodules)\n"
+"use a .git directory:"
+msgstr[0] ""
+"mô-đun-con sau đây (hay một trong số mô-đun-con bên trong của nó)\n"
+"dùng một thư mục .git:"
+msgstr[1] ""
+"các mô-đun-con sau đây (hay một trong số mô-đun-con bên trong của nó)\n"
+"dùng một thư mục .git:"
+
+#: builtin/rm.c:70
msgid ""
-"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"\n"
"(use 'rm -rf' if you really want to remove it including all of its history)"
msgstr ""
-"mô-đun-con “%s†(hoặc cái nằm trong các mô-đun-con) dùng thư mục .git\n"
-"(dùng “rm -rf†nếu bạn thực sự muốn gỡ bỠnó cùng với tất cả lịch sử của "
+"\n"
+"(dùng /\"rm -rf/\" nếu bạn thực sự muốn gỡ bỠnó cùng với tất cả lịch sử của "
"chúng)"
-#: builtin/rm.c:174
-#, c-format
+#: builtin/rm.c:230
msgid ""
-"'%s' has staged content different from both the file and the HEAD\n"
-"(use -f to force removal)"
-msgstr ""
-"“%s†có nội dung được lưu trạng thái khác biệt từ cả tập tin và cả HEAD\n"
-"(dùng tùy chá»n -f để ép buá»™c gỡ bá»)"
+"the following file has staged content different from both the\n"
+"file and the HEAD:"
+msgid_plural ""
+"the following files have staged content different from both the\n"
+"file and the HEAD:"
+msgstr[0] ""
+"tập tin sau đây có trạng thái khác biệt nội dung từ cả tập tin\n"
+"và cả HEAD:"
+msgstr[1] ""
+"các tập tin sau đây có trạng thái khác biệt nội dung từ cả tập tin\n"
+"và cả HEAD:"
-#: builtin/rm.c:180
-#, c-format
+#: builtin/rm.c:235
msgid ""
-"'%s' has changes staged in the index\n"
-"(use --cached to keep the file, or -f to force removal)"
+"\n"
+"(use -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"
-"(dùng tùy chá»n --cached để giữ tập tin, hoặc -f để ép buá»™c gỡ bá»)"
+"\n"
+"(dùng -f để buá»™c gỡ bá»)"
-#: builtin/rm.c:191
-#, c-format
+#: builtin/rm.c:239
+msgid "the following file has changes staged in the index:"
+msgid_plural "the following files have changes staged in the index:"
+msgstr[0] "tập tin sau đây có thay đổi trạng thái trong bảng mục lục:"
+msgstr[1] "các tập tin sau đây có thay đổi trạng thái trong bảng mục lục:"
+
+#: builtin/rm.c:243 builtin/rm.c:254
msgid ""
-"'%s' has local modifications\n"
+"\n"
"(use --cached to keep the file, or -f to force removal)"
msgstr ""
-"“%s†có các thay đổi nội bộ\n"
+"\n"
"(dùng tùy chá»n --cached để giữ tập tin, hoặc -f để ép buá»™c gỡ bá»)"
-#: builtin/rm.c:207
+#: builtin/rm.c:251
+msgid "the following file has local modifications:"
+msgid_plural "the following files have local modifications:"
+msgstr[0] "tập tin sau đây có những thay đổi nội bộ:"
+msgstr[1] "những tập tin sau đây có những thay đổi nội bộ:"
+
+#: builtin/rm.c:269
msgid "do not list removed files"
msgstr "không liệt kê các tập tin đã gỡ bá»"
-#: builtin/rm.c:208
+#: builtin/rm.c:270
msgid "only remove from the index"
msgstr "chỉ gỡ bỠtừ mục lục"
-#: builtin/rm.c:209
+#: builtin/rm.c:271
msgid "override the up-to-date check"
msgstr "ghi đè lên kiểm tra cập nhật"
-#: builtin/rm.c:210
+#: builtin/rm.c:272
msgid "allow recursive removal"
msgstr "cho phép gỡ bỠđệ qui"
-#: builtin/rm.c:212
+#: builtin/rm.c:274
msgid "exit with a zero status even if nothing matched"
msgstr "thoát ra với trạng thái khác không thậm chí nếu không có gì khớp"
-#: builtin/rm.c:283
+#: builtin/rm.c:345
#, c-format
msgid "not removing '%s' recursively without -r"
msgstr "không thể gỡ bỠ“%s†má»™t cách đệ qui mà không có tùy chá»n -r"
-#: builtin/rm.c:322
+#: builtin/rm.c:384
#, c-format
msgid "git rm: unable to remove %s"
msgstr "git rm: không thể gỡ bỠ%s"
#: builtin/shortlog.c:13
-msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
-msgstr "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+msgid "git shortlog [<options>] [<revision range>] [[--] [<path>...]]"
+msgstr "git shortlog [các-tùy-chá»n] [<vùng-xét-duyệt>] [[--] [<Ä‘Æ°á»ng-dẫn>...]]"
-#: builtin/shortlog.c:133
+#: builtin/shortlog.c:131
#, c-format
msgid "Missing author: %s"
msgstr "Thiếu tên tác giả: %s"
-#: builtin/shortlog.c:229
+#: builtin/shortlog.c:228
msgid "sort output according to the number of commits per author"
msgstr "sắp xếp kết xuất tuân theo số lượng chuyển giao trên mỗi tác giả"
-#: builtin/shortlog.c:231
+#: builtin/shortlog.c:230
msgid "Suppress commit descriptions, only provides commit count"
msgstr "Chặn má»i mô tả lần chuyển giao, chỉ Ä‘Æ°a ra số lượng lần chuyển giao"
-#: builtin/shortlog.c:233
+#: builtin/shortlog.c:232
msgid "Show the email address of each author"
msgstr "Hiển thị thư điện tử cho từng tác giả"
-#: builtin/shortlog.c:234
+#: builtin/shortlog.c:233
msgid "w[,i1[,i2]]"
msgstr "w[,i1[,i2]]"
-#: builtin/shortlog.c:235
+#: builtin/shortlog.c:234
msgid "Linewrap output"
msgstr "Ngắt dòng khi quá dài"
@@ -8293,47 +8906,47 @@ msgstr ""
msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
msgstr "git show-branch (-g|--reflog)[=<n>[,<ná»n>]] [--list] [<ref>]"
-#: builtin/show-branch.c:651
+#: builtin/show-branch.c:650
msgid "show remote-tracking and local branches"
msgstr "hiển thị các nhánh remote-tracking và nội bộ"
-#: builtin/show-branch.c:653
+#: builtin/show-branch.c:652
msgid "show remote-tracking branches"
msgstr "hiển thị các nhánh remote-tracking"
-#: builtin/show-branch.c:655
+#: builtin/show-branch.c:654
msgid "color '*!+-' corresponding to the branch"
msgstr "màu “*!+-†tương ứng với nhánh"
-#: builtin/show-branch.c:657
+#: builtin/show-branch.c:656
msgid "show <n> more commits after the common ancestor"
msgstr "hiển thị thêm <n> lần chuyển giao sau cha mẹ chung"
-#: builtin/show-branch.c:659
+#: builtin/show-branch.c:658
msgid "synonym to more=-1"
msgstr "đồng nghĩa với more=-1"
-#: builtin/show-branch.c:660
+#: builtin/show-branch.c:659
msgid "suppress naming strings"
msgstr "chặn các chuỗi đặt tên"
-#: builtin/show-branch.c:662
+#: builtin/show-branch.c:661
msgid "include the current branch"
msgstr "bao gồm nhánh hiện hành"
-#: builtin/show-branch.c:664
+#: builtin/show-branch.c:663
msgid "name commits with their object names"
msgstr "đặt tên các lần chuyển giao bằng các tên của đối tượng của chúng"
-#: builtin/show-branch.c:666
+#: builtin/show-branch.c:665
msgid "show possible merge bases"
msgstr "hiển thị má»i cÆ¡ sở có thể dùng để hòa trá»™n"
-#: builtin/show-branch.c:668
+#: builtin/show-branch.c:667
msgid "show refs unreachable from any other ref"
msgstr "hiển thị các tham chiếu không thể được Ä‘á»c bởi bất kỳ tham chiếu khác"
-#: builtin/show-branch.c:670
+#: builtin/show-branch.c:669
msgid "show commits in topological order"
msgstr "hiển thị các lần chuyển giao theo thứ tự tôpô"
@@ -8346,14 +8959,14 @@ msgid "show merges reachable from only one tip"
msgstr "hiển thị các lần hòa trá»™n có thể Ä‘á»c được chỉ từ má»™t đầu mút"
#: builtin/show-branch.c:676
-msgid "show commits where no parent comes before its children"
-msgstr "hiển thị các lần chuyển giao nơi mà cha mẹ đến trước con của nó"
+msgid "topologically sort, maintaining date order where possible"
+msgstr "sắp xếp hình thái há»c, bảo trì thứ tá»± ngày nếu có thể"
-#: builtin/show-branch.c:678
+#: builtin/show-branch.c:679
msgid "<n>[,<base>]"
msgstr "<n>[,<cơ sở>]"
-#: builtin/show-branch.c:679
+#: builtin/show-branch.c:680
msgid "show <n> most recent ref-log entries starting at base"
msgstr "hiển thị <n> các mục “ref-log†gần nhất kể từ ná»n (base)"
@@ -8369,38 +8982,38 @@ msgstr ""
msgid "git show-ref --exclude-existing[=pattern] < ref-list"
msgstr "git show-ref --exclude-existing[=mẫu] < ref-list"
-#: builtin/show-ref.c:165
+#: builtin/show-ref.c:168
msgid "only show tags (can be combined with heads)"
msgstr "chỉ hiển thị thẻ (có thể tổ hợp cùng với đầu)"
-#: builtin/show-ref.c:166
+#: builtin/show-ref.c:169
msgid "only show heads (can be combined with tags)"
msgstr "chỉ hiển thị đầu (có thể tổ hợp cùng với thẻ)"
-#: builtin/show-ref.c:167
+#: builtin/show-ref.c:170
msgid "stricter reference checking, requires exact ref path"
msgstr ""
"việc kiểm tra tham chiếu chính xác, đòi há»i chính xác Ä‘Æ°á»ng dẫn tham chiếu "
"(ref)"
-#: builtin/show-ref.c:170 builtin/show-ref.c:172
-msgid "show the HEAD reference"
-msgstr "hiển thị tham chiếu của HEAD"
+#: builtin/show-ref.c:173 builtin/show-ref.c:176
+msgid "show the HEAD reference, even if it would be filtered out"
+msgstr "hiển thị tham chiếu HEAD, ngay cả khi nó đã được lá»c ra"
-#: builtin/show-ref.c:174
+#: builtin/show-ref.c:178
msgid "dereference tags into object IDs"
msgstr "bãi bỠtham chiếu các thẻ thành ra các ID đối tượng"
-#: builtin/show-ref.c:176
+#: builtin/show-ref.c:180
msgid "only show SHA1 hash using <n> digits"
msgstr "chỉ hiển thị mã băm SHA1 sử dụng <n> chữ số"
-#: builtin/show-ref.c:180
+#: builtin/show-ref.c:184
msgid "do not print results to stdout (useful with --verify)"
msgstr ""
"không hiển thị kết quả ra đầu ra chuẩn (stdout) (chỉ hữu dụng với --verify)"
-#: builtin/show-ref.c:182
+#: builtin/show-ref.c:186
msgid "show refs from stdin that aren't in local repository"
msgstr ""
"hiển thị các tham chiếu (refs) từ đầu vào tiêu chuẩn (stdin) cái mà không ở "
@@ -8821,24 +9434,33 @@ msgstr "ghi đối tượng cây (tree) cho <tiá»n tố> thÆ° mục con"
msgid "only useful for debugging"
msgstr "chỉ hữu ích khi cần gỡ lỗi"
-#: git.c:16
-msgid "See 'git help <command>' for more information on a specific command."
+#: git.c:17
+msgid ""
+"'git help -a' and 'git help -g' lists available subcommands and some\n"
+"concept guides. See 'git help <command>' or 'git help <concept>'\n"
+"to read about a specific subcommand or concept."
msgstr ""
-"Chạy lệnh “git help <tên-lệnh>†để có thêm thông tin vỠlệnh được chỉ ra."
+"“git help -a†và “git help -g†liệt kê các câu lệnh con sẵn có và một số\n"
+"hÆ°á»›ng dẫn vá» khái niệm. Xem “git help <lệnh>†hay “git help <khái-niệm>â€\n"
+"để xem các đặc tả cho lệnh hay khái niệm cụ thể."
-#: parse-options.h:156
+#: parse-options.h:144
+msgid "expiry date"
+msgstr "ngày hết hạn"
+
+#: parse-options.h:159
msgid "no-op (backward compatibility)"
msgstr "no-op (tương thích ngược)"
-#: parse-options.h:232
+#: parse-options.h:236
msgid "be more verbose"
msgstr "chi tiết hơn nữa"
-#: parse-options.h:234
+#: parse-options.h:238
msgid "be more quiet"
msgstr "im lặng hơn nữa"
-#: parse-options.h:240
+#: parse-options.h:244
msgid "use <n> digits to display SHA-1s"
msgstr "sử dụng <n> chữ số để hiển thị SHA-1s"
@@ -8856,7 +9478,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 "Lấy ra (checkout) má»™t nhánh hay các Ä‘Æ°á»ng dẫn tá»›i cây làm việc"
+msgstr "Lấy ra 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"
@@ -8869,12 +9491,12 @@ 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.."
+"Xem các thay đổi giữa những lần chuyển giao,\n"
+" giữa một lần chuyển giao và cây làm việc, v.v.."
#: common-cmds.h:15
msgid "Download objects and refs from another repository"
-msgstr "Các đối tượng và tham chiếu được tải vỠtừ kho chứa khác"
+msgstr "Tải vỠcác đối tượng và tham chiếu từ kho chứa khác"
#: common-cmds.h:16
msgid "Print lines matching a pattern"
@@ -8882,40 +9504,37 @@ 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 mới 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"
-msgstr "Hiển thị nhật ký các lần chuyển giao (commit)"
+msgstr "Hiển thị nhật ký các lần 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"
#: common-cmds.h:20
msgid "Move or rename a file, a directory, or a symlink"
-msgstr "Di chuyển, đổi tên một tập tin, thư mục hay liên kết tượng trưng"
+msgstr "Di chuyển hay đổi tên má»™t tập tin, thÆ° mục hoặc liên kết má»m"
#: common-cmds.h:21
-msgid "Fetch from and merge with another repository or a local branch"
-msgstr "Lấy vỠ(fetch) và hòa trộn với kho khác hay nhánh nội bộ"
+msgid "Fetch from and integrate with another repository or a local branch"
+msgstr "Lấy vỠvà hợp nhất với kho khác hay một 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 th.chiếu 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 thượng nguồn đã cập nhật"
+"Chuyển tiếp những lần chuyển giao nội bộ\n"
+" tới head thượng nguồn đã cập nhật"
#: common-cmds.h:24
msgid "Reset current HEAD to the specified state"
-msgstr "Äặt lại HEAD hiện hành thành má»™t trạng thái được chỉ ra"
+msgstr "Äặt lại HEAD hiện hành thành trạng thái đã cho"
#: common-cmds.h:25
msgid "Remove files from the working tree and from the index"
@@ -8931,9 +9550,7 @@ 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ẻ được ký bằng GPG"
#: git-am.sh:50
msgid "You need to set your committer info first"
@@ -8950,11 +9567,11 @@ msgstr ""
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"When you have resolved this problem, run \"$cmdline --continue\".\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"
+"Khi bạn cần giải quyết vấn đỠnày hãy chạy lệnh \"$cmdline --continue\".\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 thủy và dừng việc vá lại thì chạy "
@@ -9010,25 +9627,34 @@ 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:477
+#: git-am.sh:479
#, 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:482
+#: git-am.sh:484
msgid "Please make up your mind. --skip or --abort?"
msgstr "Xin hãy rõ ràng. --skip hay --abort?"
-#: git-am.sh:509
+#: git-am.sh:520
+#, sh-format
+msgid ""
+"Stray $dotest directory found.\n"
+"Use \"git am --abort\" to remove it."
+msgstr ""
+"Tìm thấy thư mục lạc $dotest.\n"
+"Dùng \"git am --abort\" để loại bỠnó đi."
+
+#: git-am.sh:528
msgid "Resolve operation not in progress, we are not resuming."
msgstr "Thao tác phân giải không được tiến hành, chúng ta không phục hồi lại."
-#: git-am.sh:575
+#: git-am.sh:594
#, 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:679
+#: git-am.sh:698
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -9041,34 +9667,34 @@ msgstr ""
"Äể 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:706
+#: git-am.sh:725
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:753
+#: git-am.sh:772
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"
-#: git-am.sh:757
+#: git-am.sh:776
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:764
+#: git-am.sh:783
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] "
-#: git-am.sh:800
+#: git-am.sh:819
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr "Äang áp dụng (miếng vá): $FIRSTLINE"
-#: git-am.sh:821
+#: git-am.sh:840
msgid ""
"No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
@@ -9079,7 +9705,7 @@ msgstr ""
"đã 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:829
+#: git-am.sh:848
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
@@ -9087,16 +9713,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:845
+#: git-am.sh:864
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:855
+#: git-am.sh:874
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr "Vá gặp lỗi tại $msgnum $FIRSTLINE"
-#: git-am.sh:858
+#: git-am.sh:877
#, sh-format
msgid ""
"The copy of the patch that failed is found in:\n"
@@ -9105,7 +9731,7 @@ msgstr ""
"Bản sao chép của miếng vá mà nó gặp lỗi thì được tìm thấy trong:\n"
" $dotest/patch"
-#: git-am.sh:876
+#: git-am.sh:895
msgid "applying to an empty history"
msgstr "áp dụng vào một lịch sử trống rỗng"
@@ -9128,7 +9754,7 @@ msgstr "không công nhận tùy chá»n: “$argâ€"
#: git-bisect.sh:99
#, sh-format
msgid "'$arg' does not appear to be a valid revision"
-msgstr "â€$arg†không có vẻ nhÆ° là má»™t sá»± xét lại hợp lệ"
+msgstr "â€$arg†không có vẻ nhÆ° là má»™t Ä‘iểm xét duyệt hợp lệ"
#: git-bisect.sh:117
msgid "Bad HEAD - I need a HEAD"
@@ -9206,16 +9832,16 @@ msgstr ""
"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:363 git-bisect.sh:490
msgid "We are not bisecting."
msgstr "Chúng tôi không bisect."
-#: git-bisect.sh:354
+#: git-bisect.sh:370
#, sh-format
msgid "'$invalid' is not a valid commit"
msgstr "â€$invalid†không phải là lần chuyển giao (commit) hợp lệ"
-#: git-bisect.sh:363
+#: git-bisect.sh:379
#, sh-format
msgid ""
"Could not check out original HEAD '$branch'.\n"
@@ -9224,25 +9850,25 @@ msgstr ""
"Không thể check-out HEAD nguyên thủy của “$branchâ€.\n"
"Hãy thá»­ “git bisect reset <lần-chuyển-giao>â€."
-#: git-bisect.sh:390
+#: git-bisect.sh:406
msgid "No logfile given"
msgstr "Chưa chỉ ra tập tin ghi nhật ký"
-#: git-bisect.sh:391
+#: git-bisect.sh:407
#, sh-format
msgid "cannot read $file for replaying"
msgstr "không thể Ä‘á»c $file để thao diá»…n lại"
-#: git-bisect.sh:408
+#: git-bisect.sh:424
msgid "?? what are you talking about?"
msgstr "?? bạn đang nói gì thế?"
-#: git-bisect.sh:420
+#: git-bisect.sh:436
#, sh-format
msgid "running $command"
msgstr "đang chạy lệnh $command"
-#: git-bisect.sh:427
+#: git-bisect.sh:443
#, sh-format
msgid ""
"bisect run failed:\n"
@@ -9251,11 +9877,11 @@ msgstr ""
"chạy bisect gặp lỗi:\n"
"mã trả vỠ$res từ lệnh “$command†là < 0 hoặc >= 128"
-#: git-bisect.sh:453
+#: git-bisect.sh:469
msgid "bisect run cannot continue any more"
msgstr "bisect không thể tiếp tục thêm được nữa"
-#: git-bisect.sh:459
+#: git-bisect.sh:475
#, sh-format
msgid ""
"bisect run failed:\n"
@@ -9264,7 +9890,7 @@ msgstr ""
"chạy bisect gặp lỗi:\n"
"â€bisect_state $state†đã thoát ra vá»›i mã lá»—i $res"
-#: git-bisect.sh:466
+#: git-bisect.sh:482
msgid "bisect run success"
msgstr "bisect chạy thành công"
@@ -9284,7 +9910,7 @@ 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."
-#: git-pull.sh:197
+#: git-pull.sh:203
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 "
@@ -9294,7 +9920,7 @@ msgstr ""
#. The working tree and the index file is still based on the
#. $orig_head commit, but we are merging into $curr_head.
#. First update the working tree to match $curr_head.
-#: git-pull.sh:229
+#: git-pull.sh:235
#, sh-format
msgid ""
"Warning: fetch updated the current branch head.\n"
@@ -9305,15 +9931,15 @@ msgstr ""
"Cảnh báo: đang fast-forward cây làm việc của bạn từ\n"
"Cảnh báo: commit $orig_head."
-#: git-pull.sh:254
+#: git-pull.sh:260
msgid "Cannot merge multiple branches into empty head"
msgstr "Không thể hòa trá»™n nhiá»u nhánh và trong má»™t head trống rá»—ng"
-#: git-pull.sh:258
+#: git-pull.sh:264
msgid "Cannot rebase onto multiple branches"
msgstr "Không thể thá»±c hiện lệnh rebase (cÆ¡ cấu lại) trên nhiá»u nhánh"
-#: git-rebase.sh:53
+#: git-rebase.sh:54
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"
@@ -9326,35 +9952,55 @@ msgstr ""
"Äể 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:156
+msgid "Applied autostash."
+msgstr "Äã áp dụng autostash."
+
+#: git-rebase.sh:159
+#, sh-format
+msgid "Cannot store $stash_sha1"
+msgstr "Không thể lưu $stash_sha1"
+
#: git-rebase.sh:160
+msgid ""
+"Applying autostash resulted in conflicts.\n"
+"Your changes are safe in the stash.\n"
+"You can run \"git stash pop\" or \"git stash drop\" at any time.\n"
+msgstr ""
+"Ãp dụng autostash có hiệu quả trong các xung Ä‘á»™t.\n"
+"Các thay đổi của bạn an toàn trong stash (tạm cất đi).\n"
+"Bạn có thể chạy lệnh \"git stash pop\" hay \"git stash drop\" bất kỳ lúc "
+"nào.\n"
+
+#: git-rebase.sh:190
msgid "The pre-rebase hook refused to rebase."
msgstr "Móc (hook) pre-rebase từ chối rebase."
-#: git-rebase.sh:165
+#: git-rebase.sh:195
msgid "It looks like git-am is in progress. Cannot rebase."
msgstr ""
"Hình như đang trong quá trình thực hiện lệnh git-am. Không thể chạy lệnh "
"rebase."
-#: git-rebase.sh:296
+#: git-rebase.sh:329
msgid "The --exec option must be used with the --interactive option"
msgstr "Tùy chá»n --exec phải được sá»­ dụng cùng vá»›i tùy chá»n --interactive"
-#: git-rebase.sh:301
+#: git-rebase.sh:334
msgid "No rebase in progress?"
msgstr "Không có tiến trình rebase nào phải không?"
-#: git-rebase.sh:312
+#: git-rebase.sh:345
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
"Hành động “--edit-todo†chỉ có thể dùng trong quá trình “rebase†(sửa lịch "
"sử) tương tác."
-#: git-rebase.sh:319
+#: git-rebase.sh:352
msgid "Cannot read HEAD"
msgstr "Không thể Ä‘á»c HEAD"
-#: git-rebase.sh:322
+#: git-rebase.sh:355
msgid ""
"You must edit all merge conflicts and then\n"
"mark them as resolved using git add"
@@ -9362,12 +10008,12 @@ msgstr ""
"Bạn phải sửa tất cả các lần hòa trộn xung đột và sau\n"
"đó đánh dấu chúng là cần xử lý sử dụng lệnh git add"
-#: git-rebase.sh:340
+#: git-rebase.sh:373
#, sh-format
msgid "Could not move back to $head_name"
msgstr "Không thể quay trở lại $head_name"
-#: git-rebase.sh:359
+#: git-rebase.sh:392
#, sh-format
msgid ""
"It seems that there is already a $state_dir_base directory, and\n"
@@ -9390,57 +10036,66 @@ msgstr ""
"\n"
"TÔI: là lệnh bạn vừa gá»i!"
-#: git-rebase.sh:404
+#: git-rebase.sh:437
#, sh-format
msgid "invalid upstream $upstream_name"
msgstr "thượng nguồn không hợp lệ $upstream_name"
-#: git-rebase.sh:428
+#: git-rebase.sh:461
#, sh-format
msgid "$onto_name: there are more than one merge bases"
msgstr "$onto_name: ở đây có nhiá»u hÆ¡n má»™t ná»n móng hòa trá»™n"
-#: git-rebase.sh:431 git-rebase.sh:435
+#: git-rebase.sh:464 git-rebase.sh:468
#, sh-format
msgid "$onto_name: there is no merge base"
msgstr "$onto_name: ở đây không có ná»n móng hòa trá»™n nào"
-#: git-rebase.sh:440
+#: git-rebase.sh:473
#, sh-format
msgid "Does not point to a valid commit: $onto_name"
msgstr "Không chỉ đến một lần chuyển giao (commit) không hợp lệ: $onto_name"
-#: git-rebase.sh:463
+#: git-rebase.sh:496
#, sh-format
msgid "fatal: no such branch: $branch_name"
msgstr "nghiêm trá»ng: không có nhánh nhÆ° thế: $branch_name"
-#: git-rebase.sh:483
+#: git-rebase.sh:519
+msgid "Cannot autostash"
+msgstr "Không thể autostash"
+
+#: git-rebase.sh:524
+#, sh-format
+msgid "Created autostash: $stash_abbrev"
+msgstr "Äã tạo autostash: $stash_abbrev"
+
+#: git-rebase.sh:528
msgid "Please commit or stash them."
msgstr "Xin hãy commit hoặc tạm cất (stash) chúng."
-#: git-rebase.sh:501
+#: git-rebase.sh:548
#, sh-format
msgid "Current branch $branch_name is up to date."
msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi."
-#: git-rebase.sh:504
+#: git-rebase.sh:552
#, sh-format
msgid "Current branch $branch_name is up to date, rebase forced."
msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi, lệnh rebase ép buộc."
-#: git-rebase.sh:515
+#: git-rebase.sh:563
#, sh-format
msgid "Changes from $mb to $onto:"
msgstr "Thay đổi từ $mb thành $onto:"
#. Detach HEAD and reset the tree
-#: git-rebase.sh:524
+#: git-rebase.sh:572
msgid "First, rewinding head to replay your work on top of it..."
msgstr ""
"Trước tiên, di chuyển head để xem lại các công việc trên đỉnh của nó..."
-#: git-rebase.sh:532
+#: git-rebase.sh:582
#, sh-format
msgid "Fast-forwarded $branch_name to $onto_name."
msgstr "Fast-forward $branch_name thành $onto_name."
@@ -9474,6 +10129,11 @@ msgstr "Không thể gỡ bá» bảng mục lục tạm thá»i (không thể xáº
msgid "Cannot record working tree state"
msgstr "Không thể ghi lại trạng thái cây làm việc hiện hành"
+#: git-stash.sh:190
+#, sh-format
+msgid "Cannot update $ref_stash with $w_commit"
+msgstr "Không thể cập nhật $ref_stash với $w_commit"
+
#. TRANSLATORS: $option is an invalid option, like
#. `--blah-blah'. The 7 spaces at the beginning of the
#. second line correspond to "error: ". So you should line
@@ -9484,132 +10144,153 @@ msgstr "Không thể ghi lại trạng thái cây làm việc hiện hành"
#. $ git stash save --blah-blah 2>&1 | head -n 2
#. error: unknown option for 'stash save': --blah-blah
#. To provide a message, use git stash save -- '--blah-blah'
-#: git-stash.sh:202
+#: git-stash.sh:241
#, sh-format
msgid ""
"error: unknown option for 'stash save': $option\n"
" To provide a message, use git stash save -- '$option'"
msgstr ""
"lá»—i: không hiểu tùy chá»n cho “stash saveâ€: $option\n"
-" Äể cung cấp má»™t thông Ä‘iệp, sá»­ dụng git stash save -- “$optionâ€"
+" Äể dùng thông Ä‘iệp có chứa -- ở đầu, sá»­ dụng git stash save -- \"$option"
+"\""
-#: git-stash.sh:223
+#: git-stash.sh:262
msgid "No local changes to save"
msgstr "Không có thay đổi nội bộ nào được ghi lại"
-#: git-stash.sh:227
+#: git-stash.sh:268
+msgid ""
+"The following untracked files would NOT be saved but need to be removed by "
+"stash save:"
+msgstr ""
+"Các tập tin chưa được theo dõi sau đây KHÔNG được ghi lại nhưng cần được gỡ "
+"bỠbởi việc ghi lại stash:"
+
+#: git-stash.sh:270
+msgid ""
+"Aborting. Consider using either the --force or --include-untracked option."
+msgstr ""
+"Bãi bá». Cân nhắc dùng má»™t trong hai tùy chá»n --force và --include-untracked."
+
+#: git-stash.sh:274
msgid "Cannot initialize stash"
msgstr "Không thể khởi tạo stash"
-#: git-stash.sh:235
+#: git-stash.sh:278
msgid "Cannot save the current status"
msgstr "Không thể ghi lại trạng thái hiện hành"
-#: git-stash.sh:253
+#: git-stash.sh:296
msgid "Cannot remove worktree changes"
msgstr "Không thể gỡ bỠcác thay đổi cây-làm-việc"
-#: git-stash.sh:352
+#: git-stash.sh:395
msgid "No stash found."
msgstr "Không tìm thấy stash nào."
-#: git-stash.sh:359
+#: git-stash.sh:402
#, sh-format
msgid "Too many revisions specified: $REV"
-msgstr "Chỉ ra quá nhiá»u Ä‘iểm xét lại: $REV"
+msgstr "Chỉ ra quá nhiá»u Ä‘iểm xét duyệt: $REV"
-#: git-stash.sh:365
+#: git-stash.sh:408
#, sh-format
msgid "$reference is not valid reference"
msgstr "$reference không phải là tham chiếu hợp lệ"
-#: git-stash.sh:393
+#: git-stash.sh:436
#, sh-format
msgid "'$args' is not a stash-like commit"
msgstr "â€$args†không phải là lần chuyển giao (commit) giống-stash"
-#: git-stash.sh:404
+#: git-stash.sh:447
#, sh-format
msgid "'$args' is not a stash reference"
msgstr "â€$args†không phải tham chiếu đến stash"
-#: git-stash.sh:412
+#: git-stash.sh:455
msgid "unable to refresh index"
msgstr "không thể làm tươi mới bảng mục lục"
-#: git-stash.sh:416
+#: git-stash.sh:459
msgid "Cannot apply a stash in the middle of a merge"
msgstr "Không thể áp dụng một stash ở giữa của quá trình hòa trộn"
-#: git-stash.sh:424
+#: git-stash.sh:467
msgid "Conflicts in index. Try without --index."
msgstr "Xung Ä‘á»™t trong bảng mục lục. Hãy thá»­ mà không dùng tùy chá»n --index."
-#: git-stash.sh:426
+#: git-stash.sh:469
msgid "Could not save index tree"
msgstr "Không thể ghi lại cây chỉ mục"
-#: git-stash.sh:460
+#: git-stash.sh:503
msgid "Cannot unstage modified files"
msgstr "Không thể bỠtrạng thía của các tập tin đã được sửa chữa"
-#: git-stash.sh:475
+#: git-stash.sh:518
msgid "Index was not unstashed."
msgstr "Bảng mục lục đã không được bỠstash."
-#: git-stash.sh:492
+#: git-stash.sh:535
#, sh-format
msgid "Dropped ${REV} ($s)"
-msgstr "Äã hạ xuống ${REV} ($s)"
+msgstr "Äã xóa ${REV} ($s)"
-#: git-stash.sh:493
+#: git-stash.sh:536
#, sh-format
msgid "${REV}: Could not drop stash entry"
msgstr "${REV}: Không thể xóa bỠmục stash"
-#: git-stash.sh:500
+#: git-stash.sh:543
msgid "No branch name specified"
msgstr "Chưa chỉ ra tên của nhánh"
-#: git-stash.sh:571
+#: git-stash.sh:615
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:90
+#: git-submodule.sh:95
#, 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 “$remoteurl†url"
-#: git-submodule.sh:195
+#: git-submodule.sh:237
#, 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â€"
-#: git-submodule.sh:238
+#: git-submodule.sh:281
#, 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:250
+#: git-submodule.sh:293
#, 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\""
-#: git-submodule.sh:343
+#: git-submodule.sh:403
+msgid "Relative path can only be used from the toplevel of the working tree"
+msgstr ""
+"ÄÆ°á»ng dẫn tÆ°Æ¡ng đối chỉ có thể dùng từ thÆ° mục ở mức cao nhất của cây làm "
+"việc"
+
+#: git-submodule.sh:413
#, 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 ./|../"
-#: git-submodule.sh:360
+#: git-submodule.sh:430
#, 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:364
+#: git-submodule.sh:434
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
@@ -9621,36 +10302,36 @@ msgstr ""
"$sm_path\n"
"Sử dụng -f nếu bạn thực sự muốn thêm nó vào."
-#: git-submodule.sh:382
+#: git-submodule.sh:452
#, 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:384
+#: git-submodule.sh:454
#, 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:392
+#: git-submodule.sh:462
#, sh-format
msgid "A git directory for '$sm_name' is found locally with remote(s):"
msgstr ""
"Thư mục git cho “$sm_name†được tìm thấy một cách cục bộ với các máy chủ:"
-#: git-submodule.sh:394
+#: git-submodule.sh:464
#, sh-format
msgid ""
"If you want to reuse this local git directory instead of cloning again from"
msgstr "Nếu bạn muốn dùng lại thư mục git nội bộ này thay vì nhân bản từ nó"
-#: git-submodule.sh:396
+#: git-submodule.sh:466
#, sh-format
msgid ""
"use the '--force' option. If the local git directory is not the correct repo"
msgstr ""
"dùng tùy chá»n “--forceâ€. Nếu thÆ° mục git ná»™i bá»™ không phải là repo (kho) đúng"
-#: git-submodule.sh:397
+#: git-submodule.sh:467
#, sh-format
msgid ""
"or you are unsure what this means choose another name with the '--name' "
@@ -9659,158 +10340,302 @@ msgstr ""
"hay bạn không chắc chắn Ä‘iá»u đó có nghÄ©a gì chá»n tên khác vá»›i tùy chá»n “--"
"nameâ€."
-#: git-submodule.sh:399
+#: git-submodule.sh:469
#, sh-format
msgid "Reactivating local git directory for submodule '$sm_name'."
msgstr ""
"Phục hồi sá»± hoạt Ä‘á»™ng của thÆ° mục git ná»™i bá»™ cho mô-Ä‘un-con “$sm_nameâ€."
-#: git-submodule.sh:411
+#: git-submodule.sh:481
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
-msgstr "Không thể checkout mô-Ä‘un con “$sm_pathâ€"
+msgstr "Không thể checkout mô-Ä‘un-con “$sm_pathâ€"
-#: git-submodule.sh:416
+#: git-submodule.sh:486
#, sh-format
msgid "Failed to add submodule '$sm_path'"
-msgstr "Gặp lá»—i khi thêm mô-Ä‘un con “$sm_pathâ€"
+msgstr "Gặp lá»—i khi thêm mô-Ä‘un-con “$sm_pathâ€"
-#: git-submodule.sh:425
+#: git-submodule.sh:495
#, sh-format
msgid "Failed to register submodule '$sm_path'"
-msgstr "Gặp lá»—i khi đăng ký vá»›i hệ thống mô-Ä‘un con “$sm_pathâ€"
+msgstr "Gặp lá»—i khi đăng ký vá»›i hệ thống mô-Ä‘un-con “$sm_pathâ€"
+
+#: git-submodule.sh:539
+#, sh-format
+msgid "Entering '$prefix$displaypath'"
+msgstr "Äang vào “$prefix$displaypathâ€"
+
+#: git-submodule.sh:554
+#, sh-format
+msgid "Stopping at '$prefix$displaypath'; script returned non-zero status."
+msgstr ""
+"Dừng lại tại “$prefix$displaypathâ€; script trả vá» trạng thái khác không."
+
+#: git-submodule.sh:600
+#, sh-format
+msgid "No url found for submodule path '$displaypath' in .gitmodules"
+msgstr ""
+"Không tìm thấy url cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypath†trong .gitmodules"
-#: git-submodule.sh:468
+#: git-submodule.sh:609
#, sh-format
-msgid "Entering '$prefix$sm_path'"
-msgstr "Äang nhập “$prefix$sm_pathâ€"
+msgid "Failed to register url for submodule path '$displaypath'"
+msgstr "Gặp lá»—i khi đăng ký url cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€"
-#: git-submodule.sh:482
+#: git-submodule.sh:611
#, 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."
+msgid "Submodule '$name' ($url) registered for path '$displaypath'"
+msgstr "Mô-Ä‘un-con “$name†($url) được đăng ký cho Ä‘Æ°á»ng dẫn “$displaypathâ€"
-#: git-submodule.sh:526
+#: git-submodule.sh:619
#, sh-format
-msgid "No url found for submodule path '$sm_path' in .gitmodules"
+msgid "Failed to register update mode for submodule path '$displaypath'"
msgstr ""
-"Không tìm thấy url cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$sm_path†trong .gitmodules"
+"Gặp lá»—i khi đăng ký chế Ä‘á»™ cập nhật cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€"
-#: git-submodule.sh:535
+#: git-submodule.sh:656
#, 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â€"
+msgid "Use '.' if you really want to deinitialize all submodules"
+msgstr "Dùng “.†nếu bạn thá»±c sá»± muốn gỡ bá» má»i mô-Ä‘un-con"
-#: git-submodule.sh:537
+#: git-submodule.sh:673
#, 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â€"
+msgid "Submodule work tree '$displaypath' contains a .git directory"
+msgstr "Cây làm việc mô-đun-con “$displaypath†có chứa thư mục .git"
-#: git-submodule.sh:545
+#: git-submodule.sh:674
#, sh-format
-msgid "Failed to register update mode for submodule path '$sm_path'"
+msgid ""
+"(use 'rm -rf' if you really want to remove it including all of its history)"
msgstr ""
-"Gặp lá»—i khi đăng ký chế Ä‘á»™ cập nhật cho Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$sm_pathâ€"
+"(dùng “rm -rf†nếu bạn thực sự muốn gỡ bỠnó cùng với tất cả lịch sử của "
+"chúng)"
+
+#: git-submodule.sh:680
+#, sh-format
+msgid ""
+"Submodule work tree '$displaypath' contains local modifications; use '-f' to "
+"discard them"
+msgstr ""
+"Cây làm việc mô-đun-con “$displaypath†chứa các thay đổi nội bộ; hãy dùng “-"
+"f†để loại bỠchúng đi"
+
+#: git-submodule.sh:683
+#, sh-format
+msgid "Cleared directory '$displaypath'"
+msgstr "Äã tạo thÆ° mục '$displaypath'"
+
+#: git-submodule.sh:684
+#, sh-format
+msgid "Could not remove submodule work tree '$displaypath'"
+msgstr "Không thể gỡ bá» cây làm việc mô-Ä‘un-con “$displaypathâ€"
+
+#: git-submodule.sh:687
+#, sh-format
+msgid "Could not create empty submodule directory '$displaypath'"
+msgstr "Không thể tạo thÆ° mục mô-Ä‘un-con rá»—ng “$displaypathâ€"
+
+#: git-submodule.sh:696
+#, sh-format
+msgid "Submodule '$name' ($url) unregistered for path '$displaypath'"
+msgstr "Mô-Ä‘un-con “$name†($url) được bỠđăng ký cho Ä‘Æ°á»ng dẫn “$displaypathâ€"
-#: git-submodule.sh:649
+#: git-submodule.sh:811
#, sh-format
msgid ""
-"Submodule path '$sm_path' not initialized\n"
+"Submodule path '$displaypath' not initialized\n"
"Maybe you want to use 'update --init'?"
msgstr ""
-"ÄÆ°á»ng dẫn mô-Ä‘un-con “$sm_path†chÆ°a được khởi tạo\n"
+"ÄÆ°á»ng dẫn mô-Ä‘un-con “$displaypath†chÆ°a được khởi tạo.\n"
"Có lẽ bạn muốn sử dụng lệnh “update --init�"
-#: git-submodule.sh:662
+#: git-submodule.sh:824
#, sh-format
-msgid "Unable to find current revision in submodule path '$sm_path'"
+msgid "Unable to find current revision in submodule path '$displaypath'"
msgstr ""
-"Không tìm thấy Ä‘iểm xét lại hiện hành trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$sm_pathâ€"
+"Không tìm thấy Ä‘iểm xét duyệt hiện hành trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con "
+"“$displaypathâ€"
-#: git-submodule.sh:671 git-submodule.sh:695
+#: git-submodule.sh:833
#, 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:709
+#: git-submodule.sh:857
#, 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â€"
+msgid "Unable to fetch in submodule path '$displaypath'"
+msgstr "Không thể lấy vá» (fetch) trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€"
-#: git-submodule.sh:710
+#: git-submodule.sh:871
#, 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â€"
+msgid "Unable to rebase '$sha1' in submodule path '$displaypath'"
+msgstr "Không thể rebase “$sha1†trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€"
-#: git-submodule.sh:715
+#: git-submodule.sh:872
#, sh-format
-msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
+msgid "Submodule path '$displaypath': rebased into '$sha1'"
+msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€: được rebase vào trong “$sha1â€"
+
+#: git-submodule.sh:877
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$displaypath'"
msgstr ""
-"Không thể hòa trá»™n (merge) “$sha1†trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$sm_pathâ€"
+"Không thể hòa trá»™n (merge) “$sha1†trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€"
-#: git-submodule.sh:716
+#: git-submodule.sh:878
#, 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â€"
+msgid "Submodule path '$displaypath': merged in '$sha1'"
+msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€: được hòa trá»™n vào “$sha1â€"
-#: git-submodule.sh:721
+#: git-submodule.sh:883
#, 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â€"
+msgid ""
+"Execution of '$command $sha1' failed in submodule path '$prefix$sm_path'"
+msgstr ""
+"Thá»±c hiện không thành công lệnh “$command $sha1†trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con "
+"“$prefix$sm_pathâ€"
-#: git-submodule.sh:722
+#: git-submodule.sh:884
#, sh-format
-msgid "Submodule path '$sm_path': checked out '$sha1'"
-msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “$sm_pathâ€: được checkout “$sha1â€"
+msgid "Submodule path '$prefix$sm_path': '$command $sha1'"
+msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “$prefix$sm_pathâ€: “$command $sha1â€"
-#: git-submodule.sh:744 git-submodule.sh:1066
+#: git-submodule.sh:889
#, 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â€"
+msgid "Unable to checkout '$sha1' in submodule path '$displaypath'"
+msgstr "Không thể checkout “$sha1†trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€"
-#: git-submodule.sh:852
+#: git-submodule.sh:890
+#, sh-format
+msgid "Submodule path '$displaypath': checked out '$sha1'"
+msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€: đã checkout “$sha1â€"
+
+#: git-submodule.sh:917
+#, sh-format
+msgid "Failed to recurse into submodule path '$displaypath'"
+msgstr "Gặp lá»—i khi đệ quy vào trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$displaypathâ€"
+
+#: git-submodule.sh:1025
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:892
+#: git-submodule.sh:1066
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr "chế độ không như mong chỠ$mod_dst"
-#: git-submodule.sh:910
+#: git-submodule.sh:1086
#, 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"
+msgid " Warn: $display_name doesn't contain commit $sha1_src"
+msgstr ""
+" Cảnh báo: $display_name không chứa lần chuyển giao (commit) $sha1_src"
-#: git-submodule.sh:913
+#: git-submodule.sh:1089
#, 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"
+msgid " Warn: $display_name doesn't contain commit $sha1_dst"
+msgstr ""
+" Cảnh báo: $display_name không chứa lần chuyển giao (commit) $sha1_dst"
-#: git-submodule.sh:916
+#: git-submodule.sh:1092
#, sh-format
-msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgid " Warn: $display_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"
+" Cảnh báo: $display_name không chứa những lần chuyển giao (commit) "
+"$sha1_src và $sha1_dst"
-#: git-submodule.sh:941
+#: git-submodule.sh:1117
msgid "blob"
msgstr "blob"
-#: git-submodule.sh:979
+#: git-submodule.sh:1155
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:981
+#: git-submodule.sh:1157
msgid "Submodule changes to be committed:"
msgstr "Những mô-đun-con thay đổi đã được chuyển giao (commit):"
-#: git-submodule.sh:1129
+#: git-submodule.sh:1242
+#, 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:1306
#, sh-format
-msgid "Synchronizing submodule url for '$prefix$sm_path'"
-msgstr "Url Mô-Ä‘un-con đồng bá»™ hóa cho “$prefix$sm_pathâ€"
+msgid "Synchronizing submodule url for '$displaypath'"
+msgstr "Url Mô-Ä‘un-con đồng bá»™ hóa cho “$displaypathâ€"
+
+#~ 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\")"
+
+#~ 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\")"
+
+#~ msgid "more than %d trees given: '%s'"
+#~ msgstr "đã chỉ ra nhiá»u hÆ¡n %d cây (tree): “%sâ€"
+
+#~ msgid "You cannot combine --no-ff with --ff-only."
+#~ msgstr "Bạn không thể kết hợp --no-ff với --ff-only."
+
+#~ msgid ""
+#~ "submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+#~ "(use 'rm -rf' if you really want to remove it including all of its "
+#~ "history)"
+#~ msgstr ""
+#~ "mô-đun-con “%s†(hoặc cái nằm trong các mô-đun-con) dùng thư mục .git\n"
+#~ "(dùng “rm -rf†nếu bạn thực sự muốn gỡ bỠnó cùng với tất cả lịch sử của "
+#~ "chúng)"
+
+#~ msgid ""
+#~ "'%s' has changes staged in the index\n"
+#~ "(use --cached to keep the file, or -f to force removal)"
+#~ msgstr ""
+#~ "“%s†có các thay đổi được lưu trạng thái trong bảng mục lục\n"
+#~ "(dùng tùy chá»n --cached để giữ tập tin, hoặc -f để ép buá»™c gỡ bá»)"
+
+#~ msgid "show commits where no parent comes before its children"
+#~ msgstr "hiển thị các lần chuyển giao nơi mà cha mẹ đến trước con của nó"
+
+#~ msgid "show the HEAD reference"
+#~ msgstr "hiển thị tham chiếu của HEAD"
+
+#~ msgid "Unable to fetch in submodule path '$prefix$sm_path'"
+#~ msgstr ""
+#~ "Không thể lấy vá» (fetch) trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$prefix$sm_pathâ€"
+
+#~ msgid "Failed to recurse into submodule path '$prefix$sm_path'"
+#~ msgstr "Gặp lá»—i khi đệ quy vào trong Ä‘Æ°á»ng dẫn mô-Ä‘un-con “$prefix$sm_pathâ€"
+
+#~ msgid "It took %.2f seconds to enumerate untracked files. 'status -uno'"
+#~ msgstr "Cần %.2f giây để đếm các tập tin chÆ°a được theo vết. “status -unoâ€"
+
+#~ msgid "may speed it up, but you have to be careful not to forget to add"
+#~ msgstr ""
+#~ "có thể làm nó nhanh lên, nhÆ°ng bạn phải cẩn trá»ng đừng quên thêm nó vào"
+
+#~ msgid "new files yourself (see 'git help status')."
+#~ msgstr "tập tin má»›i của chính bạn (xem “git help statusâ€.."
+
+#~ msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+#~ msgstr "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+
+#~ 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."
+
+#~ msgid "use any ref in .git/refs"
+#~ msgstr "sử dụng bất kỳ ref nào trong .git/refs"
+
+#~ msgid "use any tag in .git/refs/tags"
+#~ msgstr "sử dụng bất kỳ thẻ nào trong .git/refs/tags"
+
+#~ msgid "bad object %s"
+#~ msgstr "đối tượng sai %s"
+
+#~ msgid "bogus committer info %s"
+#~ msgstr "thông tin ngÆ°á»i chuyển giao không có thá»±c %s"
#~ msgid "can't fdopen 'show' output fd"
#~ msgstr "không thể fdopen “show†(lệnh hiển thị) mô tả tập tin (fd) kết xuất"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index c48ae10..b7b46f1 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: 2013-03-05 12:36+0800\n"
-"PO-Revision-Date: 2013-03-05 13:07+0800\n"
+"POT-Creation-Date: 2013-08-06 14:10+0800\n"
+"PO-Revision-Date: 2013-08-06 14:45+0800\n"
"Last-Translator: Jiang Xin <worldhello.net@gmail.com>\n"
"Language-Team: GitHub <https://github.com/gotgit/git/>\n"
"Language: zh_CN\n"
@@ -22,7 +22,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: advice.c:49
+#: advice.c:57
#, c-format
msgid "hint: %.*s\n"
msgstr "æ示:%.*s\n"
@@ -31,7 +31,7 @@ msgstr "æ示:%.*s\n"
#. * Message used both when 'git commit' fails and when
#. * other commands doing a merge do.
#.
-#: advice.c:79
+#: advice.c:87
msgid ""
"Fix them up in the work tree,\n"
"and then use 'git add/rm <file>' as\n"
@@ -68,7 +68,7 @@ msgstr "æ ¼å¼"
msgid "archive format"
msgstr "归档格å¼"
-#: archive.c:324 builtin/log.c:1115
+#: archive.c:324 builtin/log.c:1173
msgid "prefix"
msgstr "å‰ç¼€"
@@ -76,15 +76,15 @@ msgstr "å‰ç¼€"
msgid "prepend prefix to each pathname in the archive"
msgstr "为归档中æ¯ä¸ªè·¯å¾„å加上å‰ç¼€"
-#: archive.c:326 builtin/archive.c:91 builtin/blame.c:2366
-#: builtin/blame.c:2367 builtin/config.c:55 builtin/fast-export.c:653
-#: builtin/fast-export.c:655 builtin/grep.c:715 builtin/hash-object.c:77
-#: builtin/ls-files.c:497 builtin/ls-files.c:500 builtin/notes.c:536
-#: builtin/notes.c:693 builtin/read-tree.c:107 parse-options.h:149
+#: archive.c:326 builtin/archive.c:88 builtin/blame.c:2292
+#: builtin/blame.c:2293 builtin/config.c:56 builtin/fast-export.c:673
+#: builtin/fast-export.c:675 builtin/grep.c:714 builtin/hash-object.c:77
+#: builtin/ls-files.c:496 builtin/ls-files.c:499 builtin/notes.c:408
+#: builtin/notes.c:565 builtin/read-tree.c:108 parse-options.h:152
msgid "file"
msgstr "文件"
-#: archive.c:327 builtin/archive.c:92
+#: archive.c:327 builtin/archive.c:89
msgid "write the archive to this file"
msgstr "归档写入此文件"
@@ -112,19 +112,19 @@ msgstr "压缩效果更好"
msgid "list supported archive formats"
msgstr "列出支æŒçš„归档格å¼"
-#: archive.c:345 builtin/archive.c:93 builtin/clone.c:85
+#: archive.c:345 builtin/archive.c:90 builtin/clone.c:85
msgid "repo"
msgstr "版本库"
-#: archive.c:346 builtin/archive.c:94
+#: archive.c:346 builtin/archive.c:91
msgid "retrieve the archive from remote repository <repo>"
msgstr "从远程版本库(<版本库>)æå–归档文件"
-#: archive.c:347 builtin/archive.c:95 builtin/notes.c:615
+#: archive.c:347 builtin/archive.c:92 builtin/notes.c:487
msgid "command"
msgstr "命令"
-#: archive.c:348 builtin/archive.c:96
+#: archive.c:348 builtin/archive.c:93
msgid "path to the remote git-upload-archive command"
msgstr "远程 git-upload-archive 命令的路径"
@@ -136,6 +136,126 @@ msgstr ""
"负值模版在 git attributes 中被忽略\n"
"当字符串确实è¦ä»¥æ„Ÿå¹å·å¼€å§‹æ—¶ï¼Œä½¿ç”¨ '\\!'。"
+#: branch.c:60
+#, c-format
+msgid "Not setting branch %s as its own upstream."
+msgstr "未设置分支 %s 作为它自己的上游。"
+
+#: branch.c:82
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s by rebasing."
+msgstr "分支 %1$s 设置为使用å˜åŸºæ¥è·Ÿè¸ªæ¥è‡ª %3$s 的远程分支 %2$s。"
+
+#: branch.c:83
+#, c-format
+msgid "Branch %s set up to track remote branch %s from %s."
+msgstr "分支 %1$s 设置为跟踪æ¥è‡ª %3$s 的远程分支 %2$s。"
+
+#: branch.c:87
+#, c-format
+msgid "Branch %s set up to track local branch %s by rebasing."
+msgstr "分支 %s 设置为使用å˜åŸºæ¥è·Ÿè¸ªæœ¬åœ°åˆ†æ”¯ %s。"
+
+#: branch.c:88
+#, c-format
+msgid "Branch %s set up to track local branch %s."
+msgstr "分支 %s 设置为跟踪本地分支 %s。"
+
+#: branch.c:92
+#, c-format
+msgid "Branch %s set up to track remote ref %s by rebasing."
+msgstr "分支 %s 设置为使用å˜åŸºæ¥è·Ÿè¸ªè¿œç¨‹å¼•ç”¨ %s。"
+
+#: branch.c:93
+#, c-format
+msgid "Branch %s set up to track remote ref %s."
+msgstr "分支 %s 设置为跟踪远程引用 %s。"
+
+#: branch.c:97
+#, c-format
+msgid "Branch %s set up to track local ref %s by rebasing."
+msgstr "分支 %s 设置为使用å˜åŸºæ¥è·Ÿè¸ªæœ¬åœ°å¼•ç”¨ %s。"
+
+#: branch.c:98
+#, c-format
+msgid "Branch %s set up to track local ref %s."
+msgstr "分支 %s 设置为跟踪本地引用 %s。"
+
+#: branch.c:118
+#, c-format
+msgid "Tracking not set up: name too long: %s"
+msgstr "跟踪未设置:å字太长:%s"
+
+#: branch.c:137
+#, c-format
+msgid "Not tracking: ambiguous information for ref %s"
+msgstr "未跟踪:引用 %s 有歧义"
+
+#: branch.c:182
+#, c-format
+msgid "'%s' is not a valid branch name."
+msgstr "'%s' ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„分支å称。"
+
+#: branch.c:187
+#, c-format
+msgid "A branch named '%s' already exists."
+msgstr "一个分支å '%s' å·²ç»å­˜åœ¨ã€‚"
+
+#: branch.c:195
+msgid "Cannot force update the current branch."
+msgstr "无法强制更新当å‰åˆ†æ”¯ã€‚"
+
+#: branch.c:216
+#, c-format
+msgid "Cannot setup tracking information; starting point '%s' is not a branch."
+msgstr "无法设置跟踪信æ¯ï¼›èµ·å§‹ç‚¹ '%s' ä¸æ˜¯ä¸€ä¸ªåˆ†æ”¯ã€‚"
+
+#: branch.c:218
+#, c-format
+msgid "the requested upstream branch '%s' does not exist"
+msgstr "请求的上游分支 '%s' ä¸å­˜åœ¨"
+
+#: branch.c:220
+msgid ""
+"\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push."
+msgstr ""
+"\n"
+"如果您正计划基于远程一个现存的上游分支开始你的工作,\n"
+"您å¯èƒ½éœ€è¦æ‰§è¡Œ \"git fetch\" æ¥èŽ·å–分支。\n"
+"\n"
+"如果您正计划推é€ä¸€ä¸ªèƒ½ä¸Žå¯¹åº”远程分支建立跟踪的新的本地分支,\n"
+"您å¯èƒ½éœ€è¦ä½¿ç”¨ \"git push -u\" 推é€åˆ†æ”¯å¹¶é…置和上游的关è”。"
+
+#: branch.c:265
+#, c-format
+msgid "Not a valid object name: '%s'."
+msgstr "ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„对象å:'%s'。"
+
+#: branch.c:285
+#, c-format
+msgid "Ambiguous object name: '%s'."
+msgstr "歧义的对象å:'%s'。"
+
+#: branch.c:290
+#, c-format
+msgid "Not a valid branch point: '%s'."
+msgstr "无效的分支点:'%s'。"
+
+#: branch.c:296
+msgid "Failed to lock ref for update"
+msgstr "无法为更新é”定引用"
+
+#: branch.c:314
+msgid "Failed to write ref"
+msgstr "ä¸èƒ½å†™å¼•ç”¨"
+
#: bundle.c:36
#, c-format
msgid "'%s' does not look like a v2 bundle file"
@@ -146,7 +266,7 @@ msgstr "'%s' ä¸åƒæ˜¯ä¸€ä¸ª v2 版本的包文件"
msgid "unrecognized header: %s%s (%d)"
msgstr "未能识别的包头:%s%s (%d)"
-#: bundle.c:89 builtin/commit.c:674
+#: bundle.c:89 builtin/commit.c:697
#, c-format
msgid "could not open '%s'"
msgstr "ä¸èƒ½æ‰“å¼€ '%s'"
@@ -155,35 +275,35 @@ msgstr "ä¸èƒ½æ‰“å¼€ '%s'"
msgid "Repository lacks these prerequisite commits:"
msgstr "版本库缺少这些必备的æ交:"
-#: bundle.c:164 sequencer.c:566 sequencer.c:998 builtin/log.c:299
-#: builtin/log.c:751 builtin/log.c:1358 builtin/log.c:1574 builtin/merge.c:347
-#: builtin/shortlog.c:157
+#: bundle.c:164 sequencer.c:661 sequencer.c:1111 builtin/log.c:331
+#: builtin/log.c:801 builtin/log.c:1399 builtin/log.c:1625 builtin/merge.c:364
+#: builtin/shortlog.c:156
msgid "revision walk setup failed"
msgstr "版本é历设置失败"
#: bundle.c:186
#, c-format
-msgid "The bundle contains %d ref"
-msgid_plural "The bundle contains %d refs"
-msgstr[0] "这个包中å«æœ‰ %d 个引用"
-msgstr[1] "这个包中å«æœ‰ %d 个引用"
+msgid "The bundle contains this ref:"
+msgid_plural "The bundle contains these %d refs:"
+msgstr[0] "这个包中å«æœ‰è¿™ä¸ªå¼•ç”¨ï¼š"
+msgstr[1] "这个包中å«æœ‰ %d 个引用:"
-#: bundle.c:192
+#: bundle.c:193
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 个这些引用"
+msgid "The bundle requires this ref:"
+msgid_plural "The bundle requires these %d refs:"
+msgstr[0] "这个包需è¦è¿™ä¸ªå¼•ç”¨ï¼š"
+msgstr[1] "è¿™ä¸ªåŒ…éœ€è¦ %d 个引用:"
#: bundle.c:294
msgid "rev-list died"
msgstr "rev-list 终止"
-#: bundle.c:300 builtin/log.c:1254 builtin/shortlog.c:260
+#: bundle.c:300 builtin/log.c:1310 builtin/shortlog.c:259
#, c-format
msgid "unrecognized argument: %s"
msgstr "未能识别的å‚数:%s"
@@ -214,12 +334,12 @@ msgstr "ä¸èƒ½åˆ›å»º '%s'"
msgid "index-pack died"
msgstr "index-pack 终止"
-#: commit.c:50
+#: commit.c:53
#, c-format
msgid "could not parse %s"
msgstr "ä¸èƒ½è§£æž %s"
-#: commit.c:52
+#: commit.c:55
#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s ä¸æ˜¯ä¸€ä¸ªæ交!"
@@ -228,16 +348,16 @@ msgstr "%s %s ä¸æ˜¯ä¸€ä¸ªæ交!"
msgid "memory exhausted"
msgstr "内存耗尽"
-#: connected.c:39
+#: connected.c:60
msgid "Could not run 'git rev-list'"
msgstr "ä¸èƒ½æ‰§è¡Œ 'git rev-list'"
-#: connected.c:48
+#: connected.c:80
#, c-format
msgid "failed write to rev-list: %s"
msgstr "无法写入 rev-list:%s"
-#: connected.c:56
+#: connected.c:88
#, c-format
msgid "failed to close rev-list's stdin: %s"
msgstr "无法关闭 rev-list 的标准输入:%s"
@@ -335,7 +455,7 @@ msgstr ""
"å‘现é…ç½®å˜é‡ 'diff.dirstat' 中的错误:\n"
"%s"
-#: diff.c:3468
+#: diff.c:3487
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -344,12 +464,12 @@ msgstr ""
"æ— æ³•è§£æž --dirstat/-X 选项的å‚数:\n"
"%s"
-#: diff.c:3482
+#: diff.c:3501
#, c-format
msgid "Failed to parse --submodule option parameter: '%s'"
msgstr "æ— æ³•è§£æž --submodule 选项的å‚数:'%s'"
-#: gpg-interface.c:59 gpg-interface.c:127
+#: gpg-interface.c:59 gpg-interface.c:131
msgid "could not run gpg."
msgstr "ä¸èƒ½æ‰§è¡Œ gpg。"
@@ -361,45 +481,45 @@ msgstr "gpg 没有接å—æ•°æ®"
msgid "gpg failed to sign the data"
msgstr "gpg 无法为数æ®ç­¾å"
-#: gpg-interface.c:112
+#: gpg-interface.c:115
#, c-format
msgid "could not create temporary file '%s': %s"
msgstr "ä¸èƒ½åˆ›å»ºä¸´æ—¶æ–‡ä»¶ '%s':%s"
-#: gpg-interface.c:115
+#: gpg-interface.c:118
#, c-format
msgid "failed writing detached signature to '%s': %s"
msgstr "无法将分离å¼ç­¾å写入 '%s':%s"
-#: grep.c:1622
+#: grep.c:1623
#, c-format
msgid "'%s': unable to read %s"
msgstr "'%s'ï¼šæ— æ³•è¯»å– %s"
-#: grep.c:1639
+#: grep.c:1640
#, c-format
msgid "'%s': %s"
msgstr "'%s':%s"
-#: grep.c:1650
+#: grep.c:1651
#, c-format
msgid "'%s': short read %s"
msgstr "'%s':读å–ä¸å®Œæ•´ %s"
-#: help.c:212
+#: help.c:210
#, c-format
msgid "available git commands in '%s'"
msgstr "在 '%s' 下å¯ç”¨çš„ git 命令"
-#: help.c:219
+#: help.c:217
msgid "git commands available from elsewhere on your $PATH"
msgstr "在 $PATH 路径中的其他地方å¯ç”¨çš„ git 命令"
-#: help.c:235
+#: help.c:233
msgid "The most commonly used git commands are:"
msgstr "最常用的 git 命令有:"
-#: help.c:292
+#: help.c:290
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -408,11 +528,11 @@ msgstr ""
"'%s' åƒæ˜¯ä¸€ä¸ª git 命令,但å´æ— æ³•è¿è¡Œã€‚\n"
"å¯èƒ½æ˜¯ git-%s å—æŸï¼Ÿ"
-#: help.c:349
+#: help.c:347
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "唉呀,您的系统中未å‘现 Git 命令。"
-#: help.c:371
+#: help.c:369
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -421,17 +541,17 @@ msgstr ""
"警告:您è¿è¡Œä¸€ä¸ªä¸å­˜åœ¨çš„ Git 命令 '%s'。继续执行å‡å®šæ‚¨è¦è¦è¿è¡Œçš„\n"
"是 '%s'"
-#: help.c:376
+#: help.c:374
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr "在 %0.1f 秒钟åŽè‡ªåŠ¨è¿è¡Œ..."
-#: help.c:383
+#: help.c:381
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
msgstr "git:'%s' ä¸æ˜¯ä¸€ä¸ª git 命令。å‚è§ 'git --help'。"
-#: help.c:387
+#: help.c:385 help.c:444
msgid ""
"\n"
"Did you mean this?"
@@ -445,12 +565,17 @@ msgstr[1] ""
"\n"
"您指的是这其中的æŸä¸€ä¸ªä¹ˆï¼Ÿ"
+#: help.c:440
+#, c-format
+msgid "%s: %s - %s"
+msgstr "%s:%s - %s"
+
#: merge.c:56
msgid "failed to read the cache"
msgstr "无法读å–缓存"
-#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534
-#: builtin/clone.c:586
+#: merge.c:110 builtin/checkout.c:365 builtin/checkout.c:566
+#: builtin/clone.c:656
msgid "unable to write new index file"
msgstr "无法写新的索引文件"
@@ -464,70 +589,70 @@ msgstr "(åæ交)\n"
msgid "addinfo_cache failed for path '%s'"
msgstr "为路径 '%s' addinfo_cache 失败"
-#: merge-recursive.c:268
+#: merge-recursive.c:269
msgid "error building trees"
msgstr "无法创建树"
-#: merge-recursive.c:672
+#: merge-recursive.c:673
#, c-format
msgid "failed to create path '%s'%s"
msgstr "无法创建路径 '%s'%s"
-#: merge-recursive.c:683
+#: merge-recursive.c:684
#, 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
+#: merge-recursive.c:698 merge-recursive.c:719
msgid ": perhaps a D/F conflict?"
msgstr ":å¯èƒ½æ˜¯ä¸€ä¸ªç›®å½•/文件冲çªï¼Ÿ"
-#: merge-recursive.c:708
+#: merge-recursive.c:709
#, c-format
msgid "refusing to lose untracked file at '%s'"
msgstr "æ‹’ç»ä¸¢å¼ƒ '%s' 中的未跟踪文件"
-#: merge-recursive.c:748
+#: merge-recursive.c:749
#, c-format
msgid "cannot read object %s '%s'"
msgstr "ä¸èƒ½è¯»å–对象 %s '%s'"
-#: merge-recursive.c:750
+#: merge-recursive.c:751
#, c-format
msgid "blob expected for %s '%s'"
msgstr "%s '%s' 应为数æ®ï¼ˆblob)对象"
-#: merge-recursive.c:773 builtin/clone.c:302
+#: merge-recursive.c:774 builtin/clone.c:312
#, c-format
msgid "failed to open '%s'"
msgstr "无法打开 '%s'"
-#: merge-recursive.c:781
+#: merge-recursive.c:782
#, c-format
msgid "failed to symlink '%s'"
msgstr "无法创建符å·é“¾æŽ¥ '%s'"
-#: merge-recursive.c:784
+#: merge-recursive.c:785
#, c-format
msgid "do not know what to do with %06o %s '%s'"
msgstr "ä¸çŸ¥é“å¦‚ä½•å¤„ç† %06o %s '%s'"
-#: merge-recursive.c:922
+#: merge-recursive.c:923
msgid "Failed to execute internal merge"
msgstr "无法执行内部åˆå¹¶"
-#: merge-recursive.c:926
+#: merge-recursive.c:927
#, c-format
msgid "Unable to add %s to database"
msgstr "ä¸èƒ½æ·»åŠ  %s 至对象库"
-#: merge-recursive.c:942
+#: merge-recursive.c:943
msgid "unsupported object type in the tree"
msgstr "在树中有ä¸æ”¯æŒçš„对象类型"
-#: merge-recursive.c:1021 merge-recursive.c:1035
+#: merge-recursive.c:1022 merge-recursive.c:1036
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -536,7 +661,7 @@ msgstr ""
"冲çªï¼ˆ%1$s/删除):%2$s 在 %3$s 中被删除,在 %5$s 中被 %4$s。%7$s 在 %6$s 中"
"的版本被ä¿ç•™ã€‚"
-#: merge-recursive.c:1027 merge-recursive.c:1040
+#: merge-recursive.c:1028 merge-recursive.c:1041
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -545,20 +670,20 @@ msgstr ""
"冲çªï¼ˆ%1$s/删除):%2$s 在 %3$s 中被删除,在 %5$s 中被 %4$s。%7$s 在 %6$s 中"
"的版本ä¿ç•™äºŽ %8$s 中。"
-#: merge-recursive.c:1081
+#: merge-recursive.c:1082
msgid "rename"
msgstr "é‡å‘½å"
-#: merge-recursive.c:1081
+#: merge-recursive.c:1082
msgid "renamed"
msgstr "é‡å‘½å"
-#: merge-recursive.c:1137
+#: merge-recursive.c:1138
#, c-format
msgid "%s is a directory in %s adding as %s instead"
msgstr "%s 是 %s 中的一个目录而以 %s 为å被添加"
-#: merge-recursive.c:1159
+#: merge-recursive.c:1160
#, c-format
msgid ""
"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
@@ -567,147 +692,173 @@ msgstr ""
"冲çªï¼ˆé‡å‘½å/é‡å‘½å):在分支 \"%3$s\" 中é‡å‘½å \"%1$s\"->\"%2$s\",在分支 "
"\"%6$s\" 中é‡å‘½å \"%4$s\"->\"%5$s\"%7$s"
-#: merge-recursive.c:1164
+#: merge-recursive.c:1165
msgid " (left unresolved)"
msgstr "(留下未解决)"
-#: merge-recursive.c:1218
+#: merge-recursive.c:1219
#, 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
+#: merge-recursive.c:1249
#, c-format
msgid "Renaming %s to %s and %s to %s instead"
msgstr "而是é‡å‘½å %s 至 %sï¼Œä»¥åŠ %s 至 %s"
-#: merge-recursive.c:1447
+#: merge-recursive.c:1448
#, 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
+#: merge-recursive.c:1458
#, c-format
msgid "Adding merged %s"
msgstr "添加åˆå¹¶åŽçš„ %s"
-#: merge-recursive.c:1462 merge-recursive.c:1660
+#: merge-recursive.c:1463 merge-recursive.c:1661
#, c-format
msgid "Adding as %s instead"
msgstr "而是以 %s 为å添加"
-#: merge-recursive.c:1513
+#: merge-recursive.c:1514
#, c-format
msgid "cannot read object %s"
msgstr "ä¸èƒ½è¯»å–对象 %s"
-#: merge-recursive.c:1516
+#: merge-recursive.c:1517
#, c-format
msgid "object %s is not a blob"
msgstr "对象 %s ä¸æ˜¯ä¸€ä¸ªæ•°æ®ï¼ˆblob)对象"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modify"
msgstr "修改"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modified"
msgstr "修改"
-#: merge-recursive.c:1574
+#: merge-recursive.c:1575
msgid "content"
msgstr "内容"
-#: merge-recursive.c:1581
+#: merge-recursive.c:1582
msgid "add/add"
msgstr "添加/添加"
-#: merge-recursive.c:1615
+#: merge-recursive.c:1616
#, c-format
msgid "Skipped %s (merged same as existing)"
msgstr "略过 %s(已ç»åšè¿‡ç›¸åŒåˆå¹¶ï¼‰"
-#: merge-recursive.c:1629
+#: merge-recursive.c:1630
#, c-format
msgid "Auto-merging %s"
msgstr "自动åˆå¹¶ %s"
-#: merge-recursive.c:1633 git-submodule.sh:942
+#: merge-recursive.c:1634 git-submodule.sh:1118
msgid "submodule"
msgstr "å­æ¨¡ç»„"
-#: merge-recursive.c:1634
+#: merge-recursive.c:1635
#, c-format
msgid "CONFLICT (%s): Merge conflict in %s"
msgstr "冲çªï¼ˆ%s):åˆå¹¶å†²çªäºŽ %s"
-#: merge-recursive.c:1724
+#: merge-recursive.c:1725
#, c-format
msgid "Removing %s"
msgstr "删除 %s"
-#: merge-recursive.c:1749
+#: merge-recursive.c:1750
msgid "file/directory"
msgstr "文件/目录"
-#: merge-recursive.c:1755
+#: merge-recursive.c:1756
msgid "directory/file"
msgstr "目录/文件"
-#: merge-recursive.c:1760
+#: merge-recursive.c:1761
#, 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
+#: merge-recursive.c:1771
#, c-format
msgid "Adding %s"
msgstr "添加 %s"
-#: merge-recursive.c:1787
+#: merge-recursive.c:1788
msgid "Fatal merge failure, shouldn't happen."
msgstr "严é‡çš„åˆå¹¶é”™è¯¯ï¼Œä¸åº”å‘生。"
-#: merge-recursive.c:1806
+#: merge-recursive.c:1807
msgid "Already up-to-date!"
msgstr "å·²ç»æ˜¯æœ€æ–°çš„ï¼"
-#: merge-recursive.c:1815
+#: merge-recursive.c:1816
#, c-format
msgid "merging of trees %s and %s failed"
msgstr "无法åˆå¹¶æ ‘ %s å’Œ %s"
-#: merge-recursive.c:1845
+#: merge-recursive.c:1846
#, c-format
msgid "Unprocessed path??? %s"
msgstr "未处ç†çš„路径??? %s"
-#: merge-recursive.c:1890
+#: merge-recursive.c:1891
msgid "Merging:"
msgstr "åˆå¹¶ï¼š"
-#: merge-recursive.c:1903
+#: merge-recursive.c:1904
#, c-format
msgid "found %u common ancestor:"
msgid_plural "found %u common ancestors:"
msgstr[0] "å‘现 %u 个共åŒç¥–先:"
msgstr[1] "å‘现 %u 个共åŒç¥–先:"
-#: merge-recursive.c:1940
+#: merge-recursive.c:1941
msgid "merge returned no commit"
msgstr "åˆå¹¶æœªè¿”回æ交"
-#: merge-recursive.c:1997
+#: merge-recursive.c:1998
#, c-format
msgid "Could not parse object '%s'"
msgstr "ä¸èƒ½è§£æžå¯¹è±¡ '%s'"
-#: merge-recursive.c:2009 builtin/merge.c:643
+#: merge-recursive.c:2010 builtin/merge.c:672
msgid "Unable to write index."
msgstr "ä¸èƒ½å†™å…¥ç´¢å¼•ã€‚"
+#: notes-utils.c:40
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr "ä¸èƒ½æ交未åˆå§‹åŒ–/未引用的注解树"
+
+#: notes-utils.c:81
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "åçš„ notes.rewriteMode 值:'%s'"
+
+#: notes-utils.c:91
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr "æ‹’ç»å‘ %s(在 refs/notes/ 之外)写入注解"
+
+#. TRANSLATORS: The first %s is the name of the
+#. environment variable, the second %s is its value
+#: notes-utils.c:118
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr "åçš„ %s 值:'%s'"
+
+#: object.c:204
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "ä¸èƒ½è§£æžå¯¹è±¡ï¼š%s"
+
#: parse-options.c:489
msgid "..."
msgstr "..."
@@ -744,18 +895,18 @@ msgstr "路径 '%s' 属于模组 '%.*s'"
msgid "'%s' is beyond a symbolic link"
msgstr "'%s' ä½äºŽç¬¦å·é“¾æŽ¥ä¸­"
-#: remote.c:1653
+#: remote.c:1788
#, 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:1659
+#: remote.c:1794
msgid " (use \"git push\" to publish your local commits)\n"
msgstr " (使用 \"git push\" æ¥å‘布您的本地æ交)\n"
-#: remote.c:1662
+#: remote.c:1797
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -764,11 +915,11 @@ msgstr[0] "您的分支è½åŽ '%s' å…± %d 个æ交,并且å¯ä»¥å¿«è¿›ã€‚\n"
msgstr[1] "您的分支è½åŽ '%s' å…± %d 个æ交,并且å¯ä»¥å¿«è¿›ã€‚\n"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: remote.c:1670
+#: remote.c:1805
msgid " (use \"git pull\" to update your local branch)\n"
msgstr " (使用 \"git pull\" æ¥æ›´æ–°æ‚¨çš„本地分支)\n"
-#: remote.c:1673
+#: remote.c:1808
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -784,23 +935,32 @@ msgstr[1] ""
"并且分别有 %d å’Œ %d 处ä¸åŒçš„æ交。\n"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: remote.c:1683
+#: remote.c:1818
msgid " (use \"git pull\" to merge the remote branch into yours)\n"
msgstr " (使用 \"git pull\" æ¥åˆå¹¶è¿œç¨‹åˆ†æ”¯ï¼‰\n"
-#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
-#: builtin/merge.c:994
+#: run-command.c:80
+msgid "open /dev/null failed"
+msgstr "ä¸èƒ½æ‰“å¼€ /dev/null"
+
+#: run-command.c:82
+#, c-format
+msgid "dup2(%d,%d) failed"
+msgstr "ä¸èƒ½è°ƒç”¨ dup2(%d,%d)"
+
+#: sequencer.c:206 builtin/merge.c:790 builtin/merge.c:903
+#: builtin/merge.c:1013 builtin/merge.c:1023
#, c-format
msgid "Could not open '%s' for writing"
msgstr "ä¸èƒ½ä¸ºå†™å…¥æ‰“å¼€ '%s'"
-#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986
-#: builtin/merge.c:999
+#: sequencer.c:208 builtin/merge.c:350 builtin/merge.c:793
+#: builtin/merge.c:1015 builtin/merge.c:1028
#, c-format
msgid "Could not write to '%s'"
msgstr "ä¸èƒ½å†™å…¥ '%s'"
-#: sequencer.c:146
+#: sequencer.c:229
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
@@ -808,7 +968,7 @@ msgstr ""
"冲çªè§£å†³å®Œæ¯•åŽï¼Œç”¨ 'git add <paths>' 或 'git rm <paths>'\n"
"命令标记修正åŽçš„文件"
-#: sequencer.c:149
+#: sequencer.c:232
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'\n"
@@ -817,228 +977,259 @@ msgstr ""
"冲çªè§£å†³å®Œæ¯•åŽï¼Œç”¨ 'git add <paths>' 或 'git rm <paths>'\n"
"对修正åŽçš„文件åšæ ‡è®°ï¼Œç„¶åŽç”¨ 'git commit' æ交"
-#: sequencer.c:162 sequencer.c:774 sequencer.c:857
+#: sequencer.c:245 sequencer.c:869 sequencer.c:952
#, c-format
msgid "Could not write to %s"
msgstr "ä¸èƒ½å†™å…¥ %s"
-#: sequencer.c:165
+#: sequencer.c:248
#, c-format
msgid "Error wrapping up %s"
msgstr "错误收尾 %s"
-#: sequencer.c:180
+#: sequencer.c:263
msgid "Your local changes would be overwritten by cherry-pick."
msgstr "您的本地修改将被拣选æ“作覆盖。"
-#: sequencer.c:182
+#: sequencer.c:265
msgid "Your local changes would be overwritten by revert."
msgstr "您的本地修改将被还原æ“作覆盖。"
-#: sequencer.c:185
+#: sequencer.c:268
msgid "Commit your changes or stash them to proceed."
msgstr "æ交您的修改或ä¿å­˜è¿›åº¦åŽå†ç»§ç»­ã€‚"
#. TRANSLATORS: %s will be "revert" or "cherry-pick"
-#: sequencer.c:236
+#: sequencer.c:324
#, c-format
msgid "%s: Unable to write new index file"
msgstr "%s:无法写入新索引文件"
-#: sequencer.c:267
+#: sequencer.c:355
msgid "Could not resolve HEAD commit\n"
msgstr "ä¸èƒ½è§£æž HEAD æ交\n"
-#: sequencer.c:288
+#: sequencer.c:377
msgid "Unable to update cache tree\n"
msgstr "ä¸èƒ½æ›´æ–°ç¼“å­˜\n"
-#: sequencer.c:333
+#: sequencer.c:422
#, c-format
msgid "Could not parse commit %s\n"
msgstr "ä¸èƒ½è§£æžæ交 %s\n"
-#: sequencer.c:338
+#: sequencer.c:427
#, c-format
msgid "Could not parse parent commit %s\n"
msgstr "ä¸èƒ½è§£æžçˆ¶æ交 %s\n"
-#: sequencer.c:404
+#: sequencer.c:493
msgid "Your index file is unmerged."
msgstr "您的索引文件未完æˆåˆå¹¶ã€‚"
-#: sequencer.c:423
+#: sequencer.c:512
#, c-format
msgid "Commit %s is a merge but no -m option was given."
msgstr "æ交 %s 是一个åˆå¹¶æ交但未æä¾› -m 选项。"
-#: sequencer.c:431
+#: sequencer.c:520
#, c-format
msgid "Commit %s does not have parent %d"
msgstr "æ交 %s 没有父æ交 %d"
-#: sequencer.c:435
+#: sequencer.c:524
#, 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:448
+#: sequencer.c:537
#, c-format
msgid "%s: cannot parse parent commit %s"
msgstr "%s:ä¸èƒ½è§£æžçˆ¶æ交 %s"
-#: sequencer.c:452
+#: sequencer.c:541
#, c-format
msgid "Cannot get commit message for %s"
msgstr "ä¸èƒ½å¾—到 %s çš„æ交说明"
-#: sequencer.c:536
+#: sequencer.c:627
#, c-format
msgid "could not revert %s... %s"
msgstr "ä¸èƒ½è¿˜åŽŸ %s... %s"
-#: sequencer.c:537
+#: sequencer.c:628
#, c-format
msgid "could not apply %s... %s"
msgstr "ä¸èƒ½åº”用 %s... %s"
-#: sequencer.c:569
+#: sequencer.c:664
msgid "empty commit set passed"
msgstr "æ供了空的æ交集"
-#: sequencer.c:577
+#: sequencer.c:672
#, c-format
msgid "git %s: failed to read the index"
msgstr "git %s:无法读å–索引"
-#: sequencer.c:582
+#: sequencer.c:677
#, c-format
msgid "git %s: failed to refresh the index"
msgstr "git %s:无法刷新索引"
-#: sequencer.c:640
+#: sequencer.c:735
#, c-format
msgid "Cannot %s during a %s"
msgstr "无法 %s 在一个 %s 过程中"
-#: sequencer.c:662
+#: sequencer.c:757
#, c-format
msgid "Could not parse line %d."
msgstr "ä¸èƒ½è§£æžç¬¬ %d 行。"
-#: sequencer.c:667
+#: sequencer.c:762
msgid "No commits parsed."
msgstr "没有æ交被解æžã€‚"
-#: sequencer.c:680
+#: sequencer.c:775
#, c-format
msgid "Could not open %s"
msgstr "ä¸èƒ½æ‰“å¼€ %s"
-#: sequencer.c:684
+#: sequencer.c:779
#, c-format
msgid "Could not read %s."
msgstr "ä¸èƒ½è¯»å– %s。"
-#: sequencer.c:691
+#: sequencer.c:786
#, c-format
msgid "Unusable instruction sheet: %s"
msgstr "无用的指令表å•ï¼š%s"
-#: sequencer.c:719
+#: sequencer.c:814
#, c-format
msgid "Invalid key: %s"
msgstr "无效键å:%s"
-#: sequencer.c:722
+#: sequencer.c:817
#, c-format
msgid "Invalid value for %s: %s"
msgstr "%s 的值无效:%s"
-#: sequencer.c:734
+#: sequencer.c:829
#, c-format
msgid "Malformed options sheet: %s"
msgstr "éžæ³•çš„选项表å•ï¼š%s"
-#: sequencer.c:755
+#: sequencer.c:850
msgid "a cherry-pick or revert is already in progress"
msgstr "一个拣选或还原æ“作已在进行"
-#: sequencer.c:756
+#: sequencer.c:851
msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
msgstr "å°è¯• \"git cherry-pick (--continue | --quit | --abort)\""
-#: sequencer.c:760
+#: sequencer.c:855
#, c-format
msgid "Could not create sequencer directory %s"
msgstr "ä¸èƒ½åˆ›å»ºåºåˆ—目录 %s"
-#: sequencer.c:776 sequencer.c:861
+#: sequencer.c:871 sequencer.c:956
#, c-format
msgid "Error wrapping up %s."
msgstr "错误收尾 %s。"
-#: sequencer.c:795 sequencer.c:929
+#: sequencer.c:890 sequencer.c:1024
msgid "no cherry-pick or revert in progress"
msgstr "拣选或还原æ“作并未进行"
-#: sequencer.c:797
+#: sequencer.c:892
msgid "cannot resolve HEAD"
msgstr "ä¸èƒ½è§£æž HEAD"
-#: sequencer.c:799
+#: sequencer.c:894
msgid "cannot abort from a branch yet to be born"
msgstr "ä¸èƒ½ä»Žå°šæœªå»ºç«‹çš„分支终止"
-#: sequencer.c:821 builtin/apply.c:4056
+#: sequencer.c:916 builtin/apply.c:4061
#, c-format
msgid "cannot open %s: %s"
msgstr "ä¸èƒ½æ‰“å¼€ %s:%s"
-#: sequencer.c:824
+#: sequencer.c:919
#, c-format
msgid "cannot read %s: %s"
msgstr "ä¸èƒ½è¯»å– %s:%s"
-#: sequencer.c:825
+#: sequencer.c:920
msgid "unexpected end of file"
msgstr "æ„外的文件结æŸ"
-#: sequencer.c:831
+#: sequencer.c:926
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
msgstr "ä¿å­˜æ‹£é€‰æ交å‰çš„ HEAD 文件 '%s' æŸå"
-#: sequencer.c:854
+#: sequencer.c:949
#, c-format
msgid "Could not format %s."
msgstr "ä¸èƒ½æ ¼å¼åŒ– %s。"
-#: sequencer.c:1016
+#: sequencer.c:1092
+#, c-format
+msgid "%s: can't cherry-pick a %s"
+msgstr "%s:ä¸èƒ½æ‹£é€‰ä¸€ä¸ª%s"
+
+#: sequencer.c:1095
+#, c-format
+msgid "%s: bad revision"
+msgstr "%s:错误的版本"
+
+#: sequencer.c:1129
msgid "Can't revert as initial commit"
msgstr "ä¸èƒ½ä½œä¸ºåˆå§‹æ交还原"
-#: sequencer.c:1017
+#: sequencer.c:1130
msgid "Can't cherry-pick into empty head"
msgstr "ä¸èƒ½æ‹£é€‰åˆ°ç©ºåˆ†æ”¯"
-#: sha1_name.c:1044
+#: sha1_name.c:440
+msgid ""
+"Git normally never creates a ref that ends with 40 hex characters\n"
+"because it will be ignored when you just specify 40-hex. These refs\n"
+"may be created by mistake. For example,\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
+"examine these refs and maybe delete them. Turn this message off by\n"
+"running \"git config advice.objectNameWarning false\""
+msgstr ""
+"Git 通常ä¸ä¼šåˆ›å»ºä¸€ä¸ªä»¥40ä½å六进制字符命å的引用,因为当你æä¾›40ä½\n"
+"å六进制字符时将被忽略。ä¸è¿‡è¿™äº›å¼•ç”¨ä¹Ÿå¯èƒ½è¢«é”™è¯¯åœ°åˆ›å»ºã€‚例如:\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"当 \"$br\" 空白时一个40ä½å六进制的引用将被创建。请检查这些引用,\n"
+"å¯èƒ½éœ€è¦åˆ é™¤å®ƒä»¬ã€‚用 \"git config advice.objectNameWarning false\"\n"
+"命令关闭本消æ¯é€šçŸ¥ã€‚"
+
+#: sha1_name.c:1097
msgid "HEAD does not point to a branch"
msgstr "HEAD 没有指å‘一个分支"
-#: sha1_name.c:1047
+#: sha1_name.c:1100
#, c-format
msgid "No such branch: '%s'"
msgstr "没有此分支:'%s'"
-#: sha1_name.c:1049
+#: sha1_name.c:1102
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "尚未给分支 '%s' 设置上游"
-#: sha1_name.c:1052
+#: sha1_name.c:1106
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr "上游分支 '%s' 没有存储为一个远程跟踪分支"
@@ -1048,418 +1239,469 @@ msgstr "上游分支 '%s' 没有存储为一个远程跟踪分支"
msgid "unable to access '%s': %s"
msgstr "ä¸èƒ½è®¿é—® '%s':%s"
-#: wrapper.c:423
+#: wrapper.c:429
#, c-format
msgid "unable to access '%s'"
msgstr "ä¸èƒ½è®¿é—® '%s'"
-#: wrapper.c:434
+#: wrapper.c:440
#, c-format
msgid "unable to look up current user in the passwd file: %s"
msgstr "无法在å£ä»¤æ–‡ä»¶ä¸­æŸ¥è¯¢åˆ°å½“å‰ç”¨æˆ·ï¼š%s"
-#: wrapper.c:435
+#: wrapper.c:441
msgid "no such user"
msgstr "无此用户"
-#: wt-status.c:140
+#: wt-status.c:141
msgid "Unmerged paths:"
msgstr "未åˆå¹¶çš„路径:"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:167 wt-status.c:194
+#: wt-status.c:168 wt-status.c:195
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr " (使用 \"git reset %s <file>...\" 撤出暂存区)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:169 wt-status.c:196
+#: wt-status.c:170 wt-status.c:197
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr " (使用 \"git rm --cached <file>...\" 撤出暂存区)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:173
+#: wt-status.c:174
msgid " (use \"git add <file>...\" to mark resolution)"
msgstr " (使用 \"git add <file>...\" 标记解决方案)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:175 wt-status.c:179
+#: wt-status.c:176 wt-status.c:180
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr " (酌情使用 \"git add/rm <file>...\" 标记解决方案)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:177
+#: wt-status.c:178
msgid " (use \"git rm <file>...\" to mark resolution)"
msgstr " (使用 \"git rm <file>...\" 标记解决方案)"
-#: wt-status.c:188
+#: wt-status.c:189
msgid "Changes to be committed:"
msgstr "è¦æ交的å˜æ›´ï¼š"
-#: wt-status.c:206
+#: wt-status.c:207
msgid "Changes not staged for commit:"
msgstr "尚未暂存以备æ交的å˜æ›´ï¼š"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:210
+#: wt-status.c:211
msgid " (use \"git add <file>...\" to update what will be committed)"
msgstr " (使用 \"git add <file>...\" æ›´æ–°è¦æ交的内容)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:212
+#: wt-status.c:213
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr " (使用 \"git add/rm <file>...\" æ›´æ–°è¦æ交的内容)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:213
+#: wt-status.c:214
msgid ""
" (use \"git checkout -- <file>...\" to discard changes in working directory)"
msgstr " (使用 \"git checkout -- <file>...\" 丢弃工作区的改动)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:215
+#: wt-status.c:216
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr " (æ交或丢弃å­æ¨¡ç»„中未跟踪或修改的内容)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:227
+#: wt-status.c:228
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr " (使用 \"git %s <file>...\" 以包å«è¦æ交的内容)"
-#: wt-status.c:244
+#: wt-status.c:245
msgid "bug"
msgstr "bug"
-#: wt-status.c:249
+#: wt-status.c:250
msgid "both deleted:"
msgstr "åŒæ–¹åˆ é™¤ï¼š"
-#: wt-status.c:250
+#: wt-status.c:251
msgid "added by us:"
msgstr "由我们添加:"
-#: wt-status.c:251
+#: wt-status.c:252
msgid "deleted by them:"
msgstr "由他们删除:"
-#: wt-status.c:252
+#: wt-status.c:253
msgid "added by them:"
msgstr "由他们添加:"
-#: wt-status.c:253
+#: wt-status.c:254
msgid "deleted by us:"
msgstr "由我们删除:"
-#: wt-status.c:254
+#: wt-status.c:255
msgid "both added:"
msgstr "åŒæ–¹æ·»åŠ ï¼š"
-#: wt-status.c:255
+#: wt-status.c:256
msgid "both modified:"
msgstr "åŒæ–¹ä¿®æ”¹ï¼š"
# 译者:末尾两个字节å¯èƒ½è¢«åˆ å‡ï¼Œå¦‚果翻译为中文标点会出现åŠä¸ªæ±‰å­—
-#: wt-status.c:285
+#: wt-status.c:286
msgid "new commits, "
msgstr "æ–°æ交, "
# 译者:末尾两个字节å¯èƒ½è¢«åˆ å‡ï¼Œå¦‚果翻译为中文标点会出现åŠä¸ªæ±‰å­—
-#: wt-status.c:287
+#: wt-status.c:288
msgid "modified content, "
msgstr "修改的内容, "
# 译者:末尾两个字节å¯èƒ½è¢«åˆ å‡ï¼Œå¦‚果翻译为中文标点会出现åŠä¸ªæ±‰å­—
-#: wt-status.c:289
+#: wt-status.c:290
msgid "untracked content, "
msgstr "未跟踪的内容, "
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:303
+#: wt-status.c:307
#, c-format
msgid "new file: %s"
msgstr "新文件: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:306
+#: wt-status.c:310
#, c-format
msgid "copied: %s -> %s"
msgstr "æ‹·è´ï¼š %s -> %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:309
+#: wt-status.c:313
#, c-format
msgid "deleted: %s"
msgstr "删除: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:312
+#: wt-status.c:316
#, c-format
msgid "modified: %s"
msgstr "修改: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:315
+#: wt-status.c:319
#, c-format
msgid "renamed: %s -> %s"
msgstr "é‡å‘½å: %s -> %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:318
+#: wt-status.c:322
#, c-format
msgid "typechange: %s"
msgstr "类型å˜æ›´ï¼š %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:321
+#: wt-status.c:325
#, c-format
msgid "unknown: %s"
msgstr "未知: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: wt-status.c:324
+#: wt-status.c:328
#, c-format
msgid "unmerged: %s"
msgstr "未åˆå¹¶ï¼š %s"
-#: wt-status.c:327
+#: wt-status.c:331
#, c-format
msgid "bug: unhandled diff status %c"
msgstr "bug:未处ç†çš„å·®å¼‚çŠ¶æ€ %c"
-#: wt-status.c:789
+#: wt-status.c:803
msgid "You have unmerged paths."
msgstr "您有尚未åˆå¹¶çš„路径。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:792 wt-status.c:944
+#: wt-status.c:806
msgid " (fix conflicts and run \"git commit\")"
msgstr " (解决冲çªå¹¶è¿è¡Œ \"git commit\")"
-#: wt-status.c:795
+#: wt-status.c:809
msgid "All conflicts fixed but you are still merging."
msgstr "所有冲çªå·²è§£å†³ä½†æ‚¨ä»å¤„于åˆå¹¶ä¸­ã€‚"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:798
+#: wt-status.c:812
msgid " (use \"git commit\" to conclude merge)"
msgstr " (使用 \"git commit\" 结æŸåˆå¹¶ï¼‰"
-#: wt-status.c:808
+#: wt-status.c:822
msgid "You are in the middle of an am session."
msgstr "您正处于一个 am 过程中。"
-#: wt-status.c:811
+#: wt-status.c:825
msgid "The current patch is empty."
msgstr "当å‰çš„è¡¥ä¸ä¸ºç©ºã€‚"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:815
-msgid " (fix conflicts and then run \"git am --resolved\")"
-msgstr " (解决冲çªï¼Œç„¶åŽè¿è¡Œ \"git am --resolved\")"
+#: wt-status.c:829
+msgid " (fix conflicts and then run \"git am --continue\")"
+msgstr " (解决冲çªï¼Œç„¶åŽè¿è¡Œ \"git am --continue\")"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:817
+#: wt-status.c:831
msgid " (use \"git am --skip\" to skip this patch)"
msgstr " (使用 \"git am --skip\" 跳过此补ä¸ï¼‰"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:819
+#: wt-status.c:833
msgid " (use \"git am --abort\" to restore the original branch)"
msgstr " (使用 \"git am --abort\" æ¢å¤åŽŸæœ‰åˆ†æ”¯ï¼‰"
-#: wt-status.c:879 wt-status.c:896
+#: wt-status.c:893 wt-status.c:910
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
msgstr "您正在将分支 '%s' å˜åŸºåˆ° '%s'。"
-#: wt-status.c:884 wt-status.c:901
+#: wt-status.c:898 wt-status.c:915
msgid "You are currently rebasing."
msgstr "您正在å˜åŸºã€‚"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:887
+#: wt-status.c:901
msgid " (fix conflicts and then run \"git rebase --continue\")"
msgstr " (解决冲çªï¼Œç„¶åŽè¿è¡Œ \"git rebase --continue\")"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:889
+#: wt-status.c:903
msgid " (use \"git rebase --skip\" to skip this patch)"
msgstr " (使用 \"git rebase --skip\" 跳过此补ä¸ï¼‰"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:891
+#: wt-status.c:905
msgid " (use \"git rebase --abort\" to check out the original branch)"
msgstr " (使用 \"git rebase --abort\" 以检出原有分支)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:904
+#: wt-status.c:918
msgid " (all conflicts fixed: run \"git rebase --continue\")"
msgstr " (所有冲çªå·²è§£å†³ï¼šè¿è¡Œ \"git rebase --continue\")"
-#: wt-status.c:908
+#: wt-status.c:922
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
msgstr "您正在将分支 '%s' å˜åŸºåˆ° '%s' 过程中拆分一个æ交。"
-#: wt-status.c:913
+#: wt-status.c:927
msgid "You are currently splitting a commit during a rebase."
msgstr "您正在å˜åŸºè¿‡ç¨‹ä¸­æ‹†åˆ†ä¸€ä¸ªæ交。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:916
+#: wt-status.c:930
msgid " (Once your working directory is clean, run \"git rebase --continue\")"
msgstr " (一旦您工作目录æ交干净åŽï¼Œè¿è¡Œ \"git rebase --continue\")"
-#: wt-status.c:920
+#: wt-status.c:934
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr "您正在将分支 '%s' å˜åŸºåˆ° '%s' 过程中编辑一个æ交。"
-#: wt-status.c:925
+#: wt-status.c:939
msgid "You are currently editing a commit during a rebase."
msgstr "您正在å˜åŸºè¿‡ç¨‹ä¸­ç¼–辑一个æ交。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:928
+#: wt-status.c:942
msgid " (use \"git commit --amend\" to amend the current commit)"
msgstr " (使用 \"git commit --amend\" 修补当å‰æ交)"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:930
+#: wt-status.c:944
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
msgstr " (当您对您的修改满æ„åŽæ‰§è¡Œ \"git rebase --continue\")"
-#: wt-status.c:940
+#: wt-status.c:954
msgid "You are currently cherry-picking."
msgstr "您正在åšæ‹£é€‰æ“作。"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:947
-msgid " (all conflicts fixed: run \"git commit\")"
-msgstr " (解决所有冲çªåŽï¼Œæ‰§è¡Œ \"git commit\")"
-
#: wt-status.c:958
+msgid " (fix conflicts and run \"git cherry-pick --continue\")"
+msgstr " (解决冲çªå¹¶è¿è¡Œ \"git cherry-pick --continue\")"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:961
+msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
+msgstr " (所有冲çªå·²è§£å†³ï¼šè¿è¡Œ \"git cherry-pick --continue\")"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:963
+msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
+msgstr " (使用 \"git cherry-pick --abort\" 以å–消拣选æ“作)"
+
+#: wt-status.c:972
+#, c-format
+msgid "You are currently reverting commit %s."
+msgstr "您正在å转æ交 %s 。"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:977
+msgid " (fix conflicts and run \"git revert --continue\")"
+msgstr " (解决冲çªå¹¶è¿è¡Œ \"git revert --continue\")"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:980
+msgid " (all conflicts fixed: run \"git revert --continue\")"
+msgstr " (所有冲çªå·²è§£å†³ï¼šè¿è¡Œ \"git revert --continue\")"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#: wt-status.c:982
+msgid " (use \"git revert --abort\" to cancel the revert operation)"
+msgstr " (使用 \"git revert --abort\" 以å–消å转æ交æ“作)"
+
+#: wt-status.c:993
#, c-format
-msgid "You are currently bisecting branch '%s'."
-msgstr "您正在分支 '%s' 中åšäºŒåˆ†æŸ¥æ‰¾ã€‚"
+msgid "You are currently bisecting, started from branch '%s'."
+msgstr "您正在从分支 '%s' 开始åšäºŒåˆ†æŸ¥æ‰¾ã€‚"
-#: wt-status.c:962
+#: wt-status.c:997
msgid "You are currently bisecting."
msgstr "您正在åšäºŒåˆ†æŸ¥æ‰¾ã€‚"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: wt-status.c:965
+#: wt-status.c:1000
msgid " (use \"git bisect reset\" to get back to the original branch)"
msgstr " (使用 \"git bisect reset\" 以回到原有分支)"
-#: wt-status.c:1064
+#: wt-status.c:1173
msgid "On branch "
msgstr "ä½äºŽåˆ†æ”¯ "
-#: wt-status.c:1071
+#: wt-status.c:1180
+msgid "rebase in progress; onto "
+msgstr "å˜åŸºæ­£åœ¨è¿›è¡Œä¸­ï¼›è‡³ "
+
+#: wt-status.c:1187
+msgid "HEAD detached at "
+msgstr "头指针分离于 "
+
+#: wt-status.c:1189
+msgid "HEAD detached from "
+msgstr "头指针分离自 "
+
+#: wt-status.c:1192
msgid "Not currently on any branch."
msgstr "当å‰ä¸åœ¨ä»»ä½•åˆ†æ”¯ä¸Šã€‚"
-#: wt-status.c:1083
+#: wt-status.c:1209
msgid "Initial commit"
msgstr "åˆå§‹æ交"
-#: wt-status.c:1097
+#: wt-status.c:1223
msgid "Untracked files"
msgstr "未跟踪的文件"
-#: wt-status.c:1099
+#: wt-status.c:1225
msgid "Ignored files"
msgstr "忽略的文件"
-#: wt-status.c:1101
+#: wt-status.c:1229
+#, c-format
+msgid ""
+"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
+"may speed it up, but you have to be careful not to forget to add\n"
+"new files yourself (see 'git help status')."
+msgstr ""
+"耗费了 %.2f 秒以枚举未跟踪的文件。'status -uno' 也许能æ高速度,\n"
+"但您需è¦å°å¿ƒä¸è¦å¿˜äº†æ·»åŠ æ–°æ–‡ä»¶ï¼ˆå‚è§ 'git help status')。"
+
+#: wt-status.c:1235
#, c-format
msgid "Untracked files not listed%s"
msgstr "未跟踪的文件没有列出%s"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:1103
+#: wt-status.c:1237
msgid " (use -u option to show untracked files)"
msgstr "(使用 -u å‚数显示未跟踪的文件)"
-#: wt-status.c:1109
+#: wt-status.c:1243
msgid "No changes"
msgstr "没有修改"
-# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:1114
+#: wt-status.c:1248
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr "修改尚未加入æ交(使用 \"git add\" å’Œ/或 \"git commit -a\")\n"
-#: wt-status.c:1117
+#: wt-status.c:1251
#, c-format
msgid "no changes added to commit\n"
msgstr "修改尚未加入æ交\n"
-#: wt-status.c:1120
+#: wt-status.c:1254
#, c-format
msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
"track)\n"
msgstr "æ交为空,但是存在尚未跟踪的文件(使用 \"git add\" 建立跟踪)\n"
-#: wt-status.c:1123
+#: wt-status.c:1257
#, c-format
msgid "nothing added to commit but untracked files present\n"
msgstr "æ交为空,但是存在尚未跟踪的文件\n"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:1126
+#: wt-status.c:1260
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
msgstr "无文件è¦æ交(创建/æ‹·è´æ–‡ä»¶å¹¶ä½¿ç”¨ \"git add\" 建立跟踪)\n"
-#: wt-status.c:1129 wt-status.c:1134
+#: wt-status.c:1263 wt-status.c:1268
#, c-format
msgid "nothing to commit\n"
msgstr "无文件è¦æ交\n"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:1132
+#: wt-status.c:1266
#, c-format
msgid "nothing to commit (use -u to show untracked files)\n"
msgstr "无文件è¦æ交(使用 -u 显示未跟踪的文件)\n"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: wt-status.c:1136
+#: wt-status.c:1270
#, c-format
msgid "nothing to commit, working directory clean\n"
msgstr "无文件è¦æ交,干净的工作区\n"
-#: wt-status.c:1244
+#: wt-status.c:1378
msgid "HEAD (no branch)"
msgstr "HEAD(éžåˆ†æ”¯ï¼‰"
# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼
-#: wt-status.c:1250
+#: wt-status.c:1384
msgid "Initial commit on "
msgstr "åˆå§‹æ交于 "
# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼
-#: wt-status.c:1265
+#: wt-status.c:1399
msgid "behind "
msgstr "è½åŽ "
# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼
-#: wt-status.c:1268 wt-status.c:1271
+#: wt-status.c:1402 wt-status.c:1405
msgid "ahead "
msgstr "领先 "
# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼
-#: wt-status.c:1273
+#: wt-status.c:1407
msgid ", behind "
msgstr ",è½åŽ "
-#: compat/precompose_utf8.c:58 builtin/clone.c:341
+#: compat/precompose_utf8.c:58 builtin/clone.c:351
#, c-format
msgid "failed to unlink '%s'"
msgstr "无法删除 '%s'"
@@ -1468,193 +1710,225 @@ msgstr "无法删除 '%s'"
msgid "git add [options] [--] <pathspec>..."
msgstr "git add [选项] [--] <路径匹é…>..."
-#: builtin/add.c:63
+# 译者:字符串首行行首è¦æ·»åŠ â€œwarning: â€å­—串,故此首行è¦è¾ƒå…¶ä½™è¡ŒçŸ­
+#.
+#. * To be consistent with "git add -p" and most Git
+#. * commands, we should default to being tree-wide, but
+#. * this is not the original behavior and can't be
+#. * changed until users trained themselves not to type
+#. * "git add -u" or "git add -A". For now, we warn and
+#. * keep the old behavior. Later, the behavior can be changed
+#. * to tree-wide, keeping the warning for a while, and
+#. * eventually we can drop the warning.
+#.
+#: builtin/add.c:58
+#, c-format
+msgid ""
+"The behavior of 'git add %s (or %s)' with no path argument from a\n"
+"subdirectory of the tree will change in Git 2.0 and should not be used "
+"anymore.\n"
+"To add content for the whole tree, run:\n"
+"\n"
+" git add %s :/\n"
+" (or git add %s :/)\n"
+"\n"
+"To restrict the command to the current directory, run:\n"
+"\n"
+" git add %s .\n"
+" (or git add %s .)\n"
+"\n"
+"With the current Git version, the command is restricted to the current "
+"directory.\n"
+msgstr ""
+"在 Git 2.0 版本,ä½äºŽä¸€ä¸ªå­ç›®å½•ä¸‹ä¸å¸¦ä»»ä½•è·¯å¾„å‚数地执行命令\n"
+"'git add %s (或 %s)' 的行为将被改å˜ï¼Œä¸è¦å†ç»§ç»­ä½¿ç”¨äº†ã€‚\n"
+"如果è¦æ·»åŠ æ•´ä¸ªç›®å½•æ ‘的内容,执行:\n"
+"\n"
+" git add %s :/\n"
+" (或 git add %s :/)\n"
+"\n"
+"如果è¦é™åˆ¶è¯¥å‘½ä»¤åªä½œç”¨äºŽå½“å‰ç›®å½•ï¼Œæ‰§è¡Œï¼š\n"
+"\n"
+" git add %s .\n"
+" (或 git add %s .)\n"
+"\n"
+"对于当å‰ç‰ˆæœ¬çš„ Git,这æ¡å‘½ä»¤åªä½œç”¨äºŽå½“å‰ç›®å½•ã€‚\n"
+
+#: builtin/add.c:100
+#, c-format
+msgid ""
+"You ran 'git add' with neither '-A (--all)' or '--ignore-removal',\n"
+"whose behaviour will change in Git 2.0 with respect to paths you removed.\n"
+"Paths like '%s' that are\n"
+"removed from your working tree are ignored with this version of Git.\n"
+"\n"
+"* 'git add --ignore-removal <pathspec>', which is the current default,\n"
+" ignores paths you removed from your working tree.\n"
+"\n"
+"* 'git add --all <pathspec>' will let you also record the removals.\n"
+"\n"
+"Run 'git status' to check the paths you removed from your working tree.\n"
+msgstr ""
+"您在è¿è¡Œ 'git add' 时没有指定 '-A (--all)' 或 '--ignore-removal',\n"
+"针对其中本地移除路径的行为将在 Git 2.0 版本库å‘生å˜åŒ–。\n"
+"åƒæœ¬åœ°å·¥ä½œåŒºç§»é™¤çš„路径 '%s'\n"
+"在此版本的 Git 中被忽略。\n"
+"\n"
+"* 'git add --ignore-removal <pathspec>',是当å‰ç‰ˆæœ¬çš„默认æ“作,\n"
+" 忽略您本地工作区中移除的文件。\n"
+"\n"
+"* 'git add --all <pathspec>' 将让您åŒæ—¶å¯¹åˆ é™¤æ“作进行记录。\n"
+"\n"
+"è¿è¡Œ 'git status' æ¥æ£€æŸ¥æ‚¨æœ¬åœ°å·¥ä½œåŒºä¸­ç§»é™¤çš„路径。\n"
+
+#: builtin/add.c:144
#, c-format
msgid "unexpected diff status %c"
msgstr "æ„å¤–çš„å·®å¼‚çŠ¶æ€ %c"
-#: builtin/add.c:68 builtin/commit.c:231
+#: builtin/add.c:149 builtin/commit.c:252
msgid "updating files failed"
msgstr "更新文件失败"
-#: builtin/add.c:78
+#: builtin/add.c:163
#, c-format
msgid "remove '%s'\n"
msgstr "删除 '%s'\n"
-#: builtin/add.c:148
+#: builtin/add.c:253
msgid "Unstaged changes after refreshing the index:"
msgstr "刷新索引之åŽå°šæœªè¢«æš‚存的å˜æ›´ï¼š"
-#: builtin/add.c:151 builtin/add.c:460 builtin/rm.c:275
+#: builtin/add.c:256 builtin/add.c:573 builtin/rm.c:337
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "路径 '%s' 未匹é…任何文件"
-#: builtin/add.c:234
+#: builtin/add.c:339
msgid "Could not read the index"
msgstr "ä¸èƒ½è¯»å–索引"
-#: builtin/add.c:244
+#: builtin/add.c:350
#, c-format
msgid "Could not open '%s' for writing."
msgstr "ä¸èƒ½æ‰“å¼€ '%s' 以写入。"
-#: builtin/add.c:248
+#: builtin/add.c:354
msgid "Could not write patch"
msgstr "ä¸èƒ½ç”Ÿæˆè¡¥ä¸"
-#: builtin/add.c:253
+#: builtin/add.c:359
#, c-format
msgid "Could not stat '%s'"
msgstr "ä¸èƒ½æŸ¥çœ‹æ–‡ä»¶çŠ¶æ€ '%s'"
-#: builtin/add.c:255
+#: builtin/add.c:361
msgid "Empty patch. Aborted."
msgstr "空补ä¸ã€‚异常终止。"
-#: builtin/add.c:261
+#: builtin/add.c:367
#, c-format
msgid "Could not apply '%s'"
msgstr "ä¸èƒ½åº”用 '%s'"
-#: builtin/add.c:271
+#: builtin/add.c:377
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr "下列路径根æ®æ‚¨çš„一个 .gitignore 文件而被忽略:\n"
-#: builtin/add.c:277 builtin/clean.c:161 builtin/fetch.c:78 builtin/mv.c:63
-#: builtin/prune-packed.c:76 builtin/push.c:425 builtin/remote.c:1253
-#: builtin/rm.c:206
+#: builtin/add.c:394 builtin/clean.c:875 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:73 builtin/push.c:451 builtin/remote.c:1253
+#: builtin/rm.c:268
msgid "dry run"
msgstr "演习"
-#: builtin/add.c:278 builtin/apply.c:4405 builtin/check-ignore.c:19
-#: builtin/commit.c:1150 builtin/count-objects.c:82 builtin/fsck.c:613
-#: builtin/log.c:1522 builtin/mv.c:62 builtin/read-tree.c:112
+#: builtin/add.c:395 builtin/apply.c:4410 builtin/check-ignore.c:19
+#: builtin/commit.c:1220 builtin/count-objects.c:95 builtin/fsck.c:613
+#: builtin/log.c:1573 builtin/mv.c:62 builtin/read-tree.c:113
msgid "be verbose"
msgstr "冗长输出"
-#: builtin/add.c:280
+#: builtin/add.c:397
msgid "interactive picking"
msgstr "交互å¼æ‹£é€‰"
-#: builtin/add.c:281 builtin/checkout.c:1031 builtin/reset.c:258
+#: builtin/add.c:398 builtin/checkout.c:1073 builtin/reset.c:261
msgid "select hunks interactively"
msgstr "交互å¼æŒ‘选数æ®å—"
-#: builtin/add.c:282
+#: builtin/add.c:399
msgid "edit current diff and apply"
msgstr "编辑当å‰å·®å¼‚并应用"
-#: builtin/add.c:283
+#: builtin/add.c:400
msgid "allow adding otherwise ignored files"
msgstr "å…许添加忽略的文件"
-#: builtin/add.c:284
+#: builtin/add.c:401
msgid "update tracked files"
msgstr "更新已跟踪的文件"
-#: builtin/add.c:285
+#: builtin/add.c:402
msgid "record only the fact that the path will be added later"
msgstr "åªè®°å½•ï¼Œè¯¥è·¯å¾„ç¨åŽå†æ·»åŠ "
-#: builtin/add.c:286
+#: builtin/add.c:403
msgid "add changes from all tracked and untracked files"
msgstr "添加所有改å˜çš„已跟踪文件和未跟踪文件"
-#: builtin/add.c:287
+#. takes no arguments
+#: builtin/add.c:406
+msgid "ignore paths removed in the working tree (same as --no-all)"
+msgstr "忽略工作区中移除的路径(和 --no-all 相åŒï¼‰"
+
+#: builtin/add.c:408
msgid "don't add, only refresh the index"
msgstr "ä¸æ·»åŠ ï¼Œåªåˆ·æ–°ç´¢å¼•"
-#: builtin/add.c:288
+#: builtin/add.c:409
msgid "just skip files which cannot be added because of errors"
msgstr "跳过因出错ä¸èƒ½æ·»åŠ çš„文件"
-#: builtin/add.c:289
+#: builtin/add.c:410
msgid "check if - even missing - files are ignored in dry run"
msgstr "检查在演习模å¼ä¸‹æ–‡ä»¶ï¼ˆå³ä½¿ä¸å­˜åœ¨ï¼‰æ˜¯å¦è¢«å¿½ç•¥"
-#: builtin/add.c:311
+#: builtin/add.c:432
#, c-format
msgid "Use -f if you really want to add them.\n"
msgstr "使用 -f å‚数如果您确实è¦æ·»åŠ å®ƒä»¬ã€‚\n"
-#: builtin/add.c:312
+#: builtin/add.c:433
msgid "no files added"
msgstr "没有文件被添加"
-#: builtin/add.c:318
+#: builtin/add.c:439
msgid "adding files failed"
msgstr "添加文件失败"
-# 译者:字符串首行行首è¦æ·»åŠ â€œwarning: â€å­—串,故此首行è¦è¾ƒå…¶ä½™è¡ŒçŸ­
-#.
-#. * To be consistent with "git add -p" and most Git
-#. * commands, we should default to being tree-wide, but
-#. * this is not the original behavior and can't be
-#. * changed until users trained themselves not to type
-#. * "git add -u" or "git add -A". For now, we warn and
-#. * keep the old behavior. Later, this warning can be
-#. * turned into a die(...), and eventually we may
-#. * reallow the command with a new behavior.
-#.
-#: builtin/add.c:335
-#, c-format
-msgid ""
-"The behavior of 'git add %s (or %s)' with no path argument from a\n"
-"subdirectory of the tree will change in Git 2.0 and should not be used "
-"anymore.\n"
-"To add content for the whole tree, run:\n"
-"\n"
-" git add %s :/\n"
-" (or git add %s :/)\n"
-"\n"
-"To restrict the command to the current directory, run:\n"
-"\n"
-" git add %s .\n"
-" (or git add %s .)\n"
-"\n"
-"With the current Git version, the command is restricted to the current "
-"directory."
-msgstr ""
-"在 Git 2.0 版本,将ä¸å†å…许在一个å­ç›®å½•ä¸‹ä¸å¸¦ä»»ä½•è·¯å¾„å‚数地执行\n"
-"命令 'git add %s (或 %s)'。所以ä¸è¦å†ç»§ç»­ä½¿ç”¨äº†ã€‚\n"
-"如果è¦æ·»åŠ æ•´ä¸ªç›®å½•æ ‘的内容,执行:\n"
-"\n"
-" git add %s :/\n"
-" (或 git add %s :/)\n"
-"\n"
-"如果è¦é™åˆ¶è¯¥å‘½ä»¤åªä½œç”¨äºŽå½“å‰ç›®å½•ï¼Œæ‰§è¡Œï¼š\n"
-"\n"
-" git add %s .\n"
-" (或 git add %s .)\n"
-"\n"
-"对于当å‰ç‰ˆæœ¬çš„ Git,这æ¡å‘½ä»¤åªä½œç”¨äºŽå½“å‰ç›®å½•ã€‚"
-
-#: builtin/add.c:381
+#: builtin/add.c:478
msgid "-A and -u are mutually incompatible"
msgstr "-A 和 -u 选项互斥"
-#: builtin/add.c:383
+#: builtin/add.c:496
msgid "Option --ignore-missing can only be used together with --dry-run"
msgstr "选项 --ignore-missing åªèƒ½å’Œ --dry-run åŒæ—¶ä½¿ç”¨"
-#: builtin/add.c:414
+#: builtin/add.c:526
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr "没有指定文件,也没有文件被添加。\n"
-#: builtin/add.c:415
+#: builtin/add.c:527
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "也许您想è¦æ‰§è¡Œ 'git add .'?\n"
-#: builtin/add.c:421 builtin/check-ignore.c:67 builtin/clean.c:204
-#: builtin/commit.c:291 builtin/mv.c:82 builtin/rm.c:235
+#: builtin/add.c:533 builtin/check-ignore.c:161 builtin/clean.c:919
+#: builtin/commit.c:312 builtin/mv.c:82 builtin/rm.c:297
msgid "index file corrupt"
msgstr "索引文件æŸå"
-#: builtin/add.c:481 builtin/apply.c:4501 builtin/mv.c:229 builtin/rm.c:370
+#: builtin/add.c:605 builtin/apply.c:4506 builtin/mv.c:229 builtin/rm.c:432
msgid "Unable to write new index file"
msgstr "无法写入新索引文件"
@@ -1782,24 +2056,24 @@ msgstr "无法读å–符å·é“¾æŽ¥ %s"
msgid "unable to open or read %s"
msgstr "ä¸èƒ½æ‰“å¼€æˆ–è¯»å– %s"
-#: builtin/apply.c:2684
+#: builtin/apply.c:2688
#, c-format
msgid "invalid start of line: '%c'"
msgstr "无效的行首字符:'%c'"
-#: builtin/apply.c:2802
+#: builtin/apply.c:2806
#, 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:2814
+#: builtin/apply.c:2818
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
msgstr "上下文å‡å°‘到(%ld/%ld)以在第 %d 行应用补ä¸ç‰‡æ®µ"
-#: builtin/apply.c:2820
+#: builtin/apply.c:2824
#, c-format
msgid ""
"while searching for:\n"
@@ -1808,318 +2082,318 @@ msgstr ""
"当查询:\n"
"%.*s"
-#: builtin/apply.c:2839
+#: builtin/apply.c:2843
#, c-format
msgid "missing binary patch data for '%s'"
msgstr "缺失 '%s' 的二进制补ä¸æ•°æ®"
-#: builtin/apply.c:2942
+#: builtin/apply.c:2946
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr "二进制补ä¸æœªåº”用到 '%s'"
-#: builtin/apply.c:2948
+#: builtin/apply.c:2952
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
msgstr "到 '%s' 的二进制补ä¸äº§ç”Ÿäº†ä¸æ­£ç¡®çš„结果(应为 %s,å´ä¸º %s)"
-#: builtin/apply.c:2969
+#: builtin/apply.c:2973
#, c-format
msgid "patch failed: %s:%ld"
msgstr "打补ä¸å¤±è´¥ï¼š%s:%ld"
-#: builtin/apply.c:3091
+#: builtin/apply.c:3095
#, c-format
msgid "cannot checkout %s"
msgstr "ä¸èƒ½æ£€å‡º %s"
-#: builtin/apply.c:3136 builtin/apply.c:3145 builtin/apply.c:3189
+#: builtin/apply.c:3140 builtin/apply.c:3149 builtin/apply.c:3194
#, c-format
msgid "read of %s failed"
msgstr "è¯»å– %s 失败"
-#: builtin/apply.c:3169 builtin/apply.c:3391
+#: builtin/apply.c:3174 builtin/apply.c:3396
#, c-format
msgid "path %s has been renamed/deleted"
msgstr "路径 %s å·²ç»è¢«é‡å‘½å/删除"
-#: builtin/apply.c:3250 builtin/apply.c:3405
+#: builtin/apply.c:3255 builtin/apply.c:3410
#, c-format
msgid "%s: does not exist in index"
msgstr "%s:ä¸å­˜åœ¨äºŽç´¢å¼•ä¸­"
-#: builtin/apply.c:3254 builtin/apply.c:3397 builtin/apply.c:3419
+#: builtin/apply.c:3259 builtin/apply.c:3402 builtin/apply.c:3424
#, c-format
msgid "%s: %s"
msgstr "%s:%s"
-#: builtin/apply.c:3259 builtin/apply.c:3413
+#: builtin/apply.c:3264 builtin/apply.c:3418
#, c-format
msgid "%s: does not match index"
msgstr "%s:和索引ä¸åŒ¹é…"
-#: builtin/apply.c:3361
+#: builtin/apply.c:3366
msgid "removal patch leaves file contents"
msgstr "移除补ä¸ä»ç•™ä¸‹äº†æ–‡ä»¶å†…容"
-#: builtin/apply.c:3430
+#: builtin/apply.c:3435
#, c-format
msgid "%s: wrong type"
msgstr "%s:错误类型"
-#: builtin/apply.c:3432
+#: builtin/apply.c:3437
#, c-format
msgid "%s has type %o, expected %o"
msgstr "%s 的类型是 %o,应为 %o"
-#: builtin/apply.c:3533
+#: builtin/apply.c:3538
#, c-format
msgid "%s: already exists in index"
msgstr "%s:已ç»å­˜åœ¨äºŽç´¢å¼•ä¸­"
-#: builtin/apply.c:3536
+#: builtin/apply.c:3541
#, c-format
msgid "%s: already exists in working directory"
msgstr "%s:已ç»å­˜åœ¨äºŽå·¥ä½œåŒºä¸­"
-#: builtin/apply.c:3556
+#: builtin/apply.c:3561
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr "%2$s 的新模å¼ï¼ˆ%1$o)和旧模å¼ï¼ˆ%3$o)ä¸åŒ¹é…"
-#: builtin/apply.c:3561
+#: builtin/apply.c:3566
#, 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:3569
+#: builtin/apply.c:3574
#, c-format
msgid "%s: patch does not apply"
msgstr "%s:补ä¸æœªåº”用"
-#: builtin/apply.c:3582
+#: builtin/apply.c:3587
#, c-format
msgid "Checking patch %s..."
msgstr "æ£€æŸ¥è¡¥ä¸ %s..."
-#: builtin/apply.c:3675 builtin/checkout.c:215 builtin/reset.c:124
+#: builtin/apply.c:3680 builtin/checkout.c:216 builtin/reset.c:127
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "对路径 '%s' çš„ make_cache_entry æ“作失败"
-#: builtin/apply.c:3818
+#: builtin/apply.c:3823
#, c-format
msgid "unable to remove %s from index"
msgstr "ä¸èƒ½ä»Žç´¢å¼•ä¸­ç§»é™¤ %s"
-#: builtin/apply.c:3846
+#: builtin/apply.c:3851
#, c-format
-msgid "corrupt patch for subproject %s"
-msgstr "å­é¡¹ç›® %s æŸåçš„è¡¥ä¸"
+msgid "corrupt patch for submodule %s"
+msgstr "å­æ¨¡ç»„ %s æŸåçš„è¡¥ä¸"
-#: builtin/apply.c:3850
+#: builtin/apply.c:3855
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr "ä¸èƒ½æžšä¸¾æ–°å»ºæ–‡ä»¶ '%s' 的状æ€"
-#: builtin/apply.c:3855
+#: builtin/apply.c:3860
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr "ä¸èƒ½ä¸ºæ–°å»ºæ–‡ä»¶ %s 创建åŽç«¯å­˜å‚¨"
-#: builtin/apply.c:3858 builtin/apply.c:3966
+#: builtin/apply.c:3863 builtin/apply.c:3971
#, c-format
msgid "unable to add cache entry for %s"
msgstr "无法为 %s 添加缓存æ¡ç›®"
-#: builtin/apply.c:3891
+#: builtin/apply.c:3896
#, c-format
msgid "closing file '%s'"
msgstr "关闭文件 '%s'"
-#: builtin/apply.c:3940
+#: builtin/apply.c:3945
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "ä¸èƒ½å†™æ–‡ä»¶ '%s' æƒé™ %o"
-#: builtin/apply.c:4027
+#: builtin/apply.c:4032
#, c-format
msgid "Applied patch %s cleanly."
msgstr "æˆåŠŸåº”ç”¨è¡¥ä¸ %s。"
-#: builtin/apply.c:4035
+#: builtin/apply.c:4040
msgid "internal error"
msgstr "内部错误"
#. Say this even without --verbose
-#: builtin/apply.c:4038
+#: builtin/apply.c:4043
#, 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 个被拒ç»..."
-#: builtin/apply.c:4048
+#: builtin/apply.c:4053
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "截短 .rej 文件å为 %.*s.rej"
-#: builtin/apply.c:4069
+#: builtin/apply.c:4074
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "第 #%d 个片段æˆåŠŸåº”用。"
-#: builtin/apply.c:4072
+#: builtin/apply.c:4077
#, c-format
msgid "Rejected hunk #%d."
msgstr "æ‹’ç»ç¬¬ #%d 个片段。"
-#: builtin/apply.c:4222
+#: builtin/apply.c:4227
msgid "unrecognized input"
msgstr "未能识别的输入"
-#: builtin/apply.c:4233
+#: builtin/apply.c:4238
msgid "unable to read index file"
msgstr "无法读å–索引文件"
-#: builtin/apply.c:4352 builtin/apply.c:4355 builtin/clone.c:91
+#: builtin/apply.c:4357 builtin/apply.c:4360 builtin/clone.c:91
#: builtin/fetch.c:63
msgid "path"
msgstr "路径"
-#: builtin/apply.c:4353
+#: builtin/apply.c:4358
msgid "don't apply changes matching the given path"
msgstr "ä¸è¦åº”用与给出路径å‘匹é…çš„å˜æ›´"
-#: builtin/apply.c:4356
+#: builtin/apply.c:4361
msgid "apply changes matching the given path"
msgstr "应用与给出路径å‘匹é…çš„å˜æ›´"
-#: builtin/apply.c:4358
+#: builtin/apply.c:4363
msgid "num"
msgstr "æ•°å­—"
-#: builtin/apply.c:4359
+#: builtin/apply.c:4364
msgid "remove <num> leading slashes from traditional diff paths"
msgstr "从传统的 diff 路径中移除指定数é‡çš„å‰å¯¼æ–œçº¿"
-#: builtin/apply.c:4362
+#: builtin/apply.c:4367
msgid "ignore additions made by the patch"
msgstr "忽略补ä¸ä¸­çš„添加的文件"
-#: builtin/apply.c:4364
+#: builtin/apply.c:4369
msgid "instead of applying the patch, output diffstat for the input"
msgstr "ä¸åº”用补ä¸ï¼Œè€Œæ˜¯æ˜¾ç¤ºè¾“入的差异统计(diffstat)"
-#: builtin/apply.c:4368
+#: builtin/apply.c:4373
msgid "show number of added and deleted lines in decimal notation"
msgstr "以å进制数显示添加和删除的行数"
-#: builtin/apply.c:4370
+#: builtin/apply.c:4375
msgid "instead of applying the patch, output a summary for the input"
msgstr "ä¸åº”用补ä¸ï¼Œè€Œæ˜¯æ˜¾ç¤ºè¾“入的概è¦"
-#: builtin/apply.c:4372
+#: builtin/apply.c:4377
msgid "instead of applying the patch, see if the patch is applicable"
msgstr "ä¸åº”用补ä¸ï¼Œè€Œæ˜¯æŸ¥çœ‹è¡¥ä¸æ˜¯å¦å¯åº”用"
-#: builtin/apply.c:4374
+#: builtin/apply.c:4379
msgid "make sure the patch is applicable to the current index"
msgstr "确认补ä¸å¯ä»¥åº”用到当å‰ç´¢å¼•"
-#: builtin/apply.c:4376
+#: builtin/apply.c:4381
msgid "apply a patch without touching the working tree"
msgstr "应用补ä¸è€Œä¸ä¿®æ”¹å·¥ä½œåŒº"
-#: builtin/apply.c:4378
+#: builtin/apply.c:4383
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr "还应用此补ä¸ï¼ˆä¸Ž --stat/--summary/--check 选项åŒæ—¶ä½¿ç”¨ï¼‰"
-#: builtin/apply.c:4380
+#: builtin/apply.c:4385
msgid "attempt three-way merge if a patch does not apply"
msgstr "如果一个补ä¸ä¸èƒ½åº”用则å°è¯•ä¸‰è·¯åˆå¹¶"
-#: builtin/apply.c:4382
+#: builtin/apply.c:4387
msgid "build a temporary index based on embedded index information"
msgstr "创建一个临时索引基于嵌入的索引信æ¯"
-#: builtin/apply.c:4384 builtin/checkout-index.c:197 builtin/ls-files.c:463
+#: builtin/apply.c:4389 builtin/checkout-index.c:197 builtin/ls-files.c:462
msgid "paths are separated with NUL character"
msgstr "路径以 NUL 字符分隔"
-#: builtin/apply.c:4387
+#: builtin/apply.c:4392
msgid "ensure at least <n> lines of context match"
msgstr "ç¡®ä¿è‡³å°‘åŒ¹é… <n> 行上下文"
-#: builtin/apply.c:4388
+#: builtin/apply.c:4393
msgid "action"
msgstr "动作"
-#: builtin/apply.c:4389
+#: builtin/apply.c:4394
msgid "detect new or modified lines that have whitespace errors"
msgstr "检查新增和修改的行中间的空白字符滥用"
-#: builtin/apply.c:4392 builtin/apply.c:4395
+#: builtin/apply.c:4397 builtin/apply.c:4400
msgid "ignore changes in whitespace when finding context"
msgstr "查找上下文时忽略空白字符的å˜æ›´"
-#: builtin/apply.c:4398
+#: builtin/apply.c:4403
msgid "apply the patch in reverse"
msgstr "åå‘应用补ä¸"
-#: builtin/apply.c:4400
+#: builtin/apply.c:4405
msgid "don't expect at least one line of context"
msgstr "无需至少一行上下文"
-#: builtin/apply.c:4402
+#: builtin/apply.c:4407
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr "将拒ç»çš„è¡¥ä¸ç‰‡æ®µä¿å­˜åœ¨å¯¹åº”çš„ *.rej 文件中"
-#: builtin/apply.c:4404
+#: builtin/apply.c:4409
msgid "allow overlapping hunks"
msgstr "å…许é‡å çš„è¡¥ä¸ç‰‡æ®µ"
-#: builtin/apply.c:4407
+#: builtin/apply.c:4412
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr "å…许ä¸æ­£ç¡®çš„文件末尾æ¢è¡Œç¬¦"
-#: builtin/apply.c:4410
+#: builtin/apply.c:4415
msgid "do not trust the line counts in the hunk headers"
msgstr "ä¸ä¿¡ä»»è¡¥ä¸ç‰‡æ®µçš„头信æ¯ä¸­çš„è¡Œå·"
-#: builtin/apply.c:4412
+#: builtin/apply.c:4417
msgid "root"
msgstr "根目录"
-#: builtin/apply.c:4413
+#: builtin/apply.c:4418
msgid "prepend <root> to all filenames"
msgstr "为所有文件åå‰æ·»åŠ  <根目录>"
-#: builtin/apply.c:4435
+#: builtin/apply.c:4440
msgid "--3way outside a repository"
msgstr "--3way 在一个版本库之外"
-#: builtin/apply.c:4443
+#: builtin/apply.c:4448
msgid "--index outside a repository"
msgstr "--index 在一个版本库之外"
-#: builtin/apply.c:4446
+#: builtin/apply.c:4451
msgid "--cached outside a repository"
msgstr "--cached 在一个版本库之外"
-#: builtin/apply.c:4462
+#: builtin/apply.c:4467
#, c-format
msgid "can't open patch '%s'"
msgstr "ä¸èƒ½æ‰“å¼€è¡¥ä¸ '%s'"
-#: builtin/apply.c:4476
+#: builtin/apply.c:4481
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] "抑制下ä»æœ‰ %d 个空白字符误用"
msgstr[1] "抑制下ä»æœ‰ %d 个空白字符误用"
-#: builtin/apply.c:4482 builtin/apply.c:4492
+#: builtin/apply.c:4487 builtin/apply.c:4497
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -2143,21 +2417,21 @@ msgstr "git archive:未æ供远程URL"
msgid "git archive: expected ACK/NAK, got EOF"
msgstr "git archive:应为ACK/NACK,å´å¾—到EOF"
-#: builtin/archive.c:63
+#: builtin/archive.c:61
#, c-format
msgid "git archive: NACK %s"
msgstr "git archive:NACK %s"
-#: builtin/archive.c:65
+#: builtin/archive.c:63
#, c-format
msgid "remote error: %s"
msgstr "远程错误:%s"
-#: builtin/archive.c:66
+#: builtin/archive.c:64
msgid "git archive: protocol error"
msgstr "git archive:å议错误"
-#: builtin/archive.c:71
+#: builtin/archive.c:68
msgid "git archive: expected a flush"
msgstr "git archive:应为刷新"
@@ -2173,124 +2447,124 @@ msgstr "执行 'git bisect next'"
msgid "update BISECT_HEAD instead of checking out the current commit"
msgstr "æ›´æ–° BISECT_HEAD 而éžæ£€å‡ºå½“å‰æ交"
-#: builtin/blame.c:25
+#: builtin/blame.c:26
msgid "git blame [options] [rev-opts] [rev] [--] file"
msgstr "git blame [选项] [版本选项] [版本] [--] 文件"
-#: builtin/blame.c:30 builtin/shortlog.c:15
+#: builtin/blame.c:31
msgid "[rev-opts] are documented in git-rev-list(1)"
msgstr "[版本选项] 的文档记录在 git-rev-list(1) 中"
-#: builtin/blame.c:2350
+#: builtin/blame.c:2276
msgid "Show blame entries as we find them, incrementally"
msgstr "增é‡å¼åœ°æ˜¾ç¤ºå‘现的 blame æ¡ç›®"
-#: builtin/blame.c:2351
+#: builtin/blame.c:2277
msgid "Show blank SHA-1 for boundary commits (Default: off)"
msgstr "边界æ交显示空的 SHA-1(默认:关闭)"
-#: builtin/blame.c:2352
+#: builtin/blame.c:2278
msgid "Do not treat root commits as boundaries (Default: off)"
msgstr "ä¸æŠŠæ ¹æ交作为边界(默认:关闭)"
-#: builtin/blame.c:2353
+#: builtin/blame.c:2279
msgid "Show work cost statistics"
msgstr "显示命令消耗统计"
-#: builtin/blame.c:2354
+#: builtin/blame.c:2280
msgid "Show output score for blame entries"
msgstr "显示判断 blame æ¡ç›®ä½ç§»çš„得分诊断信æ¯"
-#: builtin/blame.c:2355
+#: builtin/blame.c:2281
msgid "Show original filename (Default: auto)"
msgstr "显示原始文件å(默认:自动)"
-#: builtin/blame.c:2356
+#: builtin/blame.c:2282
msgid "Show original linenumber (Default: off)"
msgstr "显示原始的行å·ï¼ˆé»˜è®¤ï¼šå…³é—­ï¼‰"
-#: builtin/blame.c:2357
+#: builtin/blame.c:2283
msgid "Show in a format designed for machine consumption"
msgstr "显示为一个适åˆæœºå™¨è¯»å–çš„æ ¼å¼"
-#: builtin/blame.c:2358
+#: builtin/blame.c:2284
msgid "Show porcelain format with per-line commit information"
msgstr "为æ¯ä¸€è¡Œæ˜¾ç¤ºæœºå™¨é€‚用的æ交信æ¯"
-#: builtin/blame.c:2359
+#: builtin/blame.c:2285
msgid "Use the same output mode as git-annotate (Default: off)"
msgstr "使用和 git-annotate 相åŒçš„输出模å¼ï¼ˆé»˜è®¤ï¼šå…³é—­ï¼‰"
-#: builtin/blame.c:2360
+#: builtin/blame.c:2286
msgid "Show raw timestamp (Default: off)"
msgstr "显示原始时间戳(默认:关闭)"
-#: builtin/blame.c:2361
+#: builtin/blame.c:2287
msgid "Show long commit SHA1 (Default: off)"
msgstr "显示长的SHA1æ交å·ï¼ˆé»˜è®¤ï¼šå…³é—­ï¼‰"
-#: builtin/blame.c:2362
+#: builtin/blame.c:2288
msgid "Suppress author name and timestamp (Default: off)"
msgstr "éšè—作者å字和时间戳(默认:关闭)"
-#: builtin/blame.c:2363
+#: builtin/blame.c:2289
msgid "Show author email instead of name (Default: off)"
msgstr "显示作者的邮箱而ä¸æ˜¯å字(默认:关闭)"
-#: builtin/blame.c:2364
+#: builtin/blame.c:2290
msgid "Ignore whitespace differences"
msgstr "忽略空白差异"
-#: builtin/blame.c:2365
+#: builtin/blame.c:2291
msgid "Spend extra cycles to find better match"
msgstr "花费é¢å¤–的循环æ¥æ‰¾åˆ°æ›´å¥½çš„匹é…"
-#: builtin/blame.c:2366
+#: builtin/blame.c:2292
msgid "Use revisions from <file> instead of calling git-rev-list"
msgstr "使用æ¥è‡ª <file> 的修订集而ä¸æ˜¯è°ƒç”¨ git-rev-list"
-#: builtin/blame.c:2367
+#: builtin/blame.c:2293
msgid "Use <file>'s contents as the final image"
msgstr "使用 <file> 的内容作为最终的图片"
-#: builtin/blame.c:2368 builtin/blame.c:2369
+#: builtin/blame.c:2294 builtin/blame.c:2295
msgid "score"
msgstr "得分"
-#: builtin/blame.c:2368
+#: builtin/blame.c:2294
msgid "Find line copies within and across files"
msgstr "找到文件内åŠè·¨æ–‡ä»¶çš„行拷è´"
-#: builtin/blame.c:2369
+#: builtin/blame.c:2295
msgid "Find line movements within and across files"
msgstr "找到文件内åŠè·¨æ–‡ä»¶çš„行移动"
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
msgid "n,m"
msgstr "n,m"
-#: builtin/blame.c:2370
+#: builtin/blame.c:2296
msgid "Process only line range n,m, counting from 1"
msgstr "åªå¤„ç†è¡ŒèŒƒå›´åœ¨ n å’Œ m 之间的,从 1 开始"
-#: builtin/branch.c:23
+#: builtin/branch.c:24
msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
msgstr "git branch [选项] [-r | -a] [--merged | --no-merged]"
-#: builtin/branch.c:24
+#: builtin/branch.c:25
msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
msgstr "git branch [选项] [-l] [-f] <分支å> [<起始点>]"
-#: builtin/branch.c:25
+#: builtin/branch.c:26
msgid "git branch [options] [-r] (-d | -D) <branchname>..."
msgstr "git branch [选项] [-r] (-d | -D) <分支å>..."
-#: builtin/branch.c:26
+#: builtin/branch.c:27
msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
msgstr "git branch [选项] (-m | -M) [<旧分支>] <新分支>"
# 译者:ä¿æŒåŽŸæ¢è¡Œæ ¼å¼ï¼Œåœ¨è¾“出时 %s 的替代内容会让字符串å˜é•¿
-#: builtin/branch.c:145
+#: builtin/branch.c:150
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
@@ -2300,7 +2574,7 @@ msgstr ""
" '%s',但未åˆå¹¶åˆ° HEAD。"
# 译者:ä¿æŒåŽŸæ¢è¡Œæ ¼å¼ï¼Œåœ¨è¾“出时 %s 的替代内容会让字符串å˜é•¿
-#: builtin/branch.c:149
+#: builtin/branch.c:154
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
@@ -2309,12 +2583,12 @@ msgstr ""
"并未删除分支 '%s', 虽然它已ç»åˆå¹¶åˆ° HEAD,\n"
" 然而å´å°šæœªè¢«åˆå¹¶åˆ°åˆ†æ”¯ '%s' 。"
-#: builtin/branch.c:163
+#: builtin/branch.c:168
#, c-format
msgid "Couldn't look up commit object for '%s'"
msgstr "无法查询 '%s' 指å‘çš„æ交对象"
-#: builtin/branch.c:167
+#: builtin/branch.c:172
#, c-format
msgid ""
"The branch '%s' is not fully merged.\n"
@@ -2323,285 +2597,327 @@ msgstr ""
"分支 '%s' 没有完全åˆå¹¶ã€‚\n"
"如果您确认è¦åˆ é™¤å®ƒï¼Œæ‰§è¡Œ 'git branch -D %s'。"
-#: builtin/branch.c:180
+#: builtin/branch.c:185
msgid "Update of config-file failed"
msgstr "无法更新 config 文件"
-#: builtin/branch.c:208
+#: builtin/branch.c:213
msgid "cannot use -a with -d"
msgstr "ä¸èƒ½å°† -a å’Œ -d åŒæ—¶ä½¿ç”¨"
-#: builtin/branch.c:214
+#: builtin/branch.c:219
msgid "Couldn't look up commit object for HEAD"
msgstr "无法查询 HEAD 指å‘çš„æ交对象"
-#: builtin/branch.c:222
+#: builtin/branch.c:227
#, c-format
msgid "Cannot delete the branch '%s' which you are currently on."
msgstr "无法删除您当å‰æ‰€åœ¨çš„分支 '%s'。"
-#: builtin/branch.c:235
+#: builtin/branch.c:240
#, c-format
msgid "remote branch '%s' not found."
msgstr "远程分支 '%s' 未å‘现。"
-#: builtin/branch.c:236
+#: builtin/branch.c:241
#, c-format
msgid "branch '%s' not found."
msgstr "分支 '%s' 未å‘现。"
-#: builtin/branch.c:250
+#: builtin/branch.c:255
#, c-format
msgid "Error deleting remote branch '%s'"
msgstr "删除远程分支 '%s' 时出错"
-#: builtin/branch.c:251
+#: builtin/branch.c:256
#, c-format
msgid "Error deleting branch '%s'"
msgstr "删除分支 '%s' 时出错"
-#: builtin/branch.c:258
+#: builtin/branch.c:263
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
msgstr "已删除远程分支 %s(曾为 %s)。\n"
-#: builtin/branch.c:259
+#: builtin/branch.c:264
#, c-format
msgid "Deleted branch %s (was %s).\n"
msgstr "已删除分支 %s(曾为 %s)。\n"
-#: builtin/branch.c:361
+#: builtin/branch.c:366
#, c-format
msgid "branch '%s' does not point at a commit"
msgstr "分支 '%s' 未指å‘一个æ交"
-#: builtin/branch.c:433
+#: builtin/branch.c:453
#, c-format
msgid "[%s: behind %d]"
msgstr "[%s:è½åŽ %d]"
-#: builtin/branch.c:435
+#: builtin/branch.c:455
#, c-format
msgid "[behind %d]"
msgstr "[è½åŽ %d]"
-#: builtin/branch.c:439
+#: builtin/branch.c:459
#, c-format
msgid "[%s: ahead %d]"
msgstr "[%s:领先 %d]"
-#: builtin/branch.c:441
+#: builtin/branch.c:461
#, c-format
msgid "[ahead %d]"
msgstr "[领先 %d]"
-#: builtin/branch.c:444
+#: builtin/branch.c:464
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr "[%s:领先 %d,è½åŽ %d]"
-#: builtin/branch.c:447
+#: builtin/branch.c:467
#, c-format
msgid "[ahead %d, behind %d]"
msgstr "[领先 %d,è½åŽ %d]"
-#: builtin/branch.c:469
+#: builtin/branch.c:490
msgid " **** invalid ref ****"
msgstr " **** 无效引用 ****"
-#: builtin/branch.c:560
+#: builtin/branch.c:582
+#, c-format
+msgid "(no branch, rebasing %s)"
+msgstr "(éžåˆ†æ”¯ï¼Œæ­£å˜åŸº %s)"
+
+#: builtin/branch.c:585
+#, c-format
+msgid "(no branch, bisect started on %s)"
+msgstr "(éžåˆ†æ”¯ï¼ŒäºŒåˆ†æŸ¥æ‰¾å¼€å§‹äºŽ %s)"
+
+#: builtin/branch.c:588
+#, c-format
+msgid "(detached from %s)"
+msgstr "(分离自 %s)"
+
+#: builtin/branch.c:591
msgid "(no branch)"
msgstr "(éžåˆ†æ”¯ï¼‰"
-#: builtin/branch.c:593
+#: builtin/branch.c:637
#, c-format
msgid "object '%s' does not point to a commit"
msgstr "对象 '%s' 没有指å‘一个æ交"
-#: builtin/branch.c:625
+#: builtin/branch.c:669
msgid "some refs could not be read"
msgstr "一些引用ä¸èƒ½è¯»å–"
-#: builtin/branch.c:638
+#: builtin/branch.c:682
msgid "cannot rename the current branch while not on any."
msgstr "无法é‡å‘½å当å‰åˆ†æ”¯å› ä¸ºä¸å¤„于任何分支上。"
-#: builtin/branch.c:648
+#: builtin/branch.c:692
#, c-format
msgid "Invalid branch name: '%s'"
msgstr "无效的分支å:'%s'"
-#: builtin/branch.c:663
+#: builtin/branch.c:707
msgid "Branch rename failed"
msgstr "分支é‡å‘½å失败"
-#: builtin/branch.c:667
+#: builtin/branch.c:711
#, c-format
msgid "Renamed a misnamed branch '%s' away"
msgstr "é‡å‘½å掉一个错误命å的旧分支 '%s'"
-#: builtin/branch.c:671
+#: builtin/branch.c:715
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
msgstr "分支é‡å‘½å为 %s,但 HEAD 没有更新ï¼"
-#: builtin/branch.c:678
+#: builtin/branch.c:722
msgid "Branch is renamed, but update of config-file failed"
msgstr "分支被é‡å‘½å,但更新 config 文件失败"
-#: builtin/branch.c:693
+#: builtin/branch.c:737
#, c-format
msgid "malformed object name %s"
msgstr "éžæ³•çš„对象å %s"
-#: builtin/branch.c:717
+#: builtin/branch.c:761
#, c-format
msgid "could not write branch description template: %s"
msgstr "ä¸èƒ½å†™åˆ†æ”¯æ述模版:%s"
-#: builtin/branch.c:747
+#: builtin/branch.c:791
msgid "Generic options"
msgstr "通用选项"
-#: builtin/branch.c:749
+#: builtin/branch.c:793
msgid "show hash and subject, give twice for upstream branch"
msgstr "显示哈希值和主题,若å‚数出现两次则显示上游分支"
-#: builtin/branch.c:750
+#: builtin/branch.c:794
msgid "suppress informational messages"
msgstr "ä¸æ˜¾ç¤ºä¿¡æ¯"
-#: builtin/branch.c:751
+#: builtin/branch.c:795
msgid "set up tracking mode (see git-pull(1))"
msgstr "设置跟踪模å¼ï¼ˆå‚è§ git-pull(1))"
-#: builtin/branch.c:753
+#: builtin/branch.c:797
msgid "change upstream info"
msgstr "改å˜ä¸Šæ¸¸ä¿¡æ¯"
-#: builtin/branch.c:757
+#: builtin/branch.c:801
msgid "use colored output"
msgstr "使用彩色输出"
-#: builtin/branch.c:758
+#: builtin/branch.c:802
msgid "act on remote-tracking branches"
msgstr "作用于远程跟踪分支"
-#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788
-#: builtin/branch.c:794 builtin/commit.c:1366 builtin/commit.c:1367
-#: builtin/commit.c:1368 builtin/commit.c:1369 builtin/tag.c:468
+#: builtin/branch.c:805 builtin/branch.c:811 builtin/branch.c:832
+#: builtin/branch.c:838 builtin/commit.c:1433 builtin/commit.c:1434
+#: builtin/commit.c:1435 builtin/commit.c:1436 builtin/tag.c:468
msgid "commit"
msgstr "æ交"
-#: builtin/branch.c:762 builtin/branch.c:768
+#: builtin/branch.c:806 builtin/branch.c:812
msgid "print only branches that contain the commit"
msgstr "åªæ‰“å°åŒ…å«è¯¥æ交的分支"
-#: builtin/branch.c:774
+#: builtin/branch.c:818
msgid "Specific git-branch actions:"
msgstr "具体的 git-branch 动作:"
-#: builtin/branch.c:775
+#: builtin/branch.c:819
msgid "list both remote-tracking and local branches"
msgstr "列出远程跟踪åŠæœ¬åœ°åˆ†æ”¯"
-#: builtin/branch.c:777
+#: builtin/branch.c:821
msgid "delete fully merged branch"
msgstr "删除完全åˆå¹¶çš„分支"
-#: builtin/branch.c:778
+#: builtin/branch.c:822
msgid "delete branch (even if not merged)"
msgstr "删除分支(å³ä½¿æ²¡æœ‰åˆå¹¶ï¼‰"
-#: builtin/branch.c:779
+#: builtin/branch.c:823
msgid "move/rename a branch and its reflog"
msgstr "移动/é‡å‘½å一个分支,以åŠå®ƒçš„引用日志"
-#: builtin/branch.c:780
+#: builtin/branch.c:824
msgid "move/rename a branch, even if target exists"
msgstr "移动/é‡å‘½å一个分支,å³ä½¿ç›®æ ‡å·²å­˜åœ¨"
-#: builtin/branch.c:781
+#: builtin/branch.c:825
msgid "list branch names"
msgstr "列出分支å"
-#: builtin/branch.c:782
+#: builtin/branch.c:826
msgid "create the branch's reflog"
msgstr "创建分支的引用日志"
-#: builtin/branch.c:784
+#: builtin/branch.c:828
msgid "edit the description for the branch"
msgstr "标记分支的æè¿°"
-#: builtin/branch.c:785
+#: builtin/branch.c:829
msgid "force creation (when already exists)"
msgstr "强制创建(当已ç»å­˜åœ¨ï¼‰"
-#: builtin/branch.c:788
+#: builtin/branch.c:832
msgid "print only not merged branches"
msgstr "åªæ‰“å°æ²¡æœ‰åˆå¹¶çš„分支"
-#: builtin/branch.c:794
+#: builtin/branch.c:838
msgid "print only merged branches"
msgstr "åªæ‰“å°åˆå¹¶çš„分支"
-#: builtin/branch.c:798
+#: builtin/branch.c:842
msgid "list branches in columns"
msgstr "以列的方å¼æ˜¾ç¤ºåˆ†æ”¯"
-#: builtin/branch.c:811
+#: builtin/branch.c:855
msgid "Failed to resolve HEAD as a valid ref."
msgstr "无法将 HEAD 解æžä¸ºæœ‰æ•ˆå¼•ç”¨ã€‚"
-#: builtin/branch.c:816 builtin/clone.c:561
+#: builtin/branch.c:860 builtin/clone.c:630
msgid "HEAD not found below refs/heads!"
msgstr "HEAD 没有ä½äºŽ /refs/heads 之下ï¼"
-#: builtin/branch.c:839
+#: builtin/branch.c:883
msgid "--column and --verbose are incompatible"
msgstr "--column å’Œ --verbose ä¸å…¼å®¹"
-#: builtin/branch.c:845
+#: builtin/branch.c:889 builtin/branch.c:928
msgid "branch name required"
msgstr "å¿…é¡»æ供分支å"
-#: builtin/branch.c:860
+#: builtin/branch.c:904
msgid "Cannot give description to detached HEAD"
msgstr "ä¸èƒ½å‘分离头指针æä¾›æè¿°"
-#: builtin/branch.c:865
+#: builtin/branch.c:909
msgid "cannot edit description of more than one branch"
msgstr "ä¸èƒ½ä¸ºä¸€ä¸ªä»¥ä¸Šçš„分支编辑æè¿°"
-#: builtin/branch.c:872
+#: builtin/branch.c:916
#, c-format
msgid "No commit on branch '%s' yet."
msgstr "分支 '%s' å°šæ— æ交。"
-#: builtin/branch.c:875
+#: builtin/branch.c:919
#, c-format
msgid "No branch named '%s'."
msgstr "没有分支 '%s'。"
-#: builtin/branch.c:888
+#: builtin/branch.c:934
msgid "too many branches for a rename operation"
msgstr "为é‡å‘½åæ“作æ供了太多的分支å"
-#: builtin/branch.c:893
+#: builtin/branch.c:939
+msgid "too many branches to set new upstream"
+msgstr "为设置新上游æ供了太多的分支å"
+
+#: builtin/branch.c:943
+#, c-format
+msgid ""
+"could not set upstream of HEAD to %s when it does not point to any branch."
+msgstr "无法设置 HEAD 的上游为 %s,因为 HEAD 没有指å‘任何分支。"
+
+#: builtin/branch.c:946 builtin/branch.c:968 builtin/branch.c:990
+#, c-format
+msgid "no such branch '%s'"
+msgstr "没有此分支 '%s'"
+
+#: builtin/branch.c:950
#, c-format
msgid "branch '%s' does not exist"
msgstr "分支 '%s' ä¸å­˜åœ¨"
-#: builtin/branch.c:905
+#: builtin/branch.c:962
+msgid "too many branches to unset upstream"
+msgstr "为å–消上游设置æ“作æ供了太多的分支å"
+
+#: builtin/branch.c:966
+msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgstr "无法å–消 HEAD 的上游设置因为它没有指å‘一个分支"
+
+#: builtin/branch.c:972
#, c-format
msgid "Branch '%s' has no upstream information"
msgstr "分支 '%s' 没有上游信æ¯"
-#: builtin/branch.c:920
+#: builtin/branch.c:987
+msgid "it does not make sense to create 'HEAD' manually"
+msgstr "手工创建 'HEAD' 没有æ„义"
+
+#: builtin/branch.c:993
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
msgstr "'git branch' çš„ -a å’Œ -r 选项带一个分支åå‚数没有æ„义"
-#: builtin/branch.c:923
+#: builtin/branch.c:996
#, c-format
msgid ""
"The --set-upstream flag is deprecated and will be removed. Consider using --"
@@ -2609,7 +2925,7 @@ msgid ""
msgstr ""
"选项 --set-upstream 已弃用并将被移除。考虑使用 --track 或 --set-upstream-to\n"
-#: builtin/branch.c:940
+#: builtin/branch.c:1013
#, c-format
msgid ""
"\n"
@@ -2620,12 +2936,12 @@ msgstr ""
"如果你想用 '%s' 跟踪 '%s', 这么åšï¼š\n"
"\n"
-#: builtin/branch.c:941
+#: builtin/branch.c:1014
#, c-format
msgid " git branch -d %s\n"
msgstr " git branch -d %s\n"
-#: builtin/branch.c:942
+#: builtin/branch.c:1015
#, c-format
msgid " git branch --set-upstream-to %s\n"
msgstr " git branch --set-upstream-to %s\n"
@@ -2643,43 +2959,43 @@ msgstr "需è¦ä¸€ä¸ªç‰ˆæœ¬åº“æ¥åˆ›å»ºåŒ…。"
msgid "Need a repository to unbundle."
msgstr "需è¦ä¸€ä¸ªç‰ˆæœ¬åº“æ¥è§£åŒ…。"
-#: builtin/cat-file.c:247
+#: builtin/cat-file.c:285
msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
msgstr "git cat-file (-t|-s|-e|-p|<类型>|--textconv) <对象>"
-#: builtin/cat-file.c:248
+#: builtin/cat-file.c:286
msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
msgstr "git cat-file (--batch|--batch-check) < <对象列表>"
-#: builtin/cat-file.c:266
+#: builtin/cat-file.c:323
msgid "<type> can be one of: blob, tree, commit, tag"
msgstr "<类型> å¯ä»¥æ˜¯å…¶ä¸­ä¹‹ä¸€ï¼šblobã€treeã€commitã€tag"
-#: builtin/cat-file.c:267
+#: builtin/cat-file.c:324
msgid "show object type"
msgstr "显示对象类型"
-#: builtin/cat-file.c:268
+#: builtin/cat-file.c:325
msgid "show object size"
msgstr "显示对象大å°"
-#: builtin/cat-file.c:270
+#: builtin/cat-file.c:327
msgid "exit with zero when there's no error"
msgstr "当没有错误时退出并返回零"
-#: builtin/cat-file.c:271
+#: builtin/cat-file.c:328
msgid "pretty-print object's content"
msgstr "美观地打å°å¯¹è±¡çš„内容"
-#: builtin/cat-file.c:273
+#: builtin/cat-file.c:330
msgid "for blob objects, run textconv on object's content"
msgstr "对于数æ®ï¼ˆblob)对象,对其内容执行 textconv"
-#: builtin/cat-file.c:275
+#: builtin/cat-file.c:332
msgid "show info and content of objects fed from the standard input"
msgstr "显示从标准输入æ供的对象的信æ¯å’Œå†…容"
-#: builtin/cat-file.c:278
+#: builtin/cat-file.c:335
msgid "show info about objects fed from the standard input"
msgstr "显示从标准输入æ供的对象的信æ¯"
@@ -2707,30 +3023,55 @@ msgstr "从标准输入读出文件å"
msgid "input paths are terminated by a null character"
msgstr "输入路径以null字符终止"
-#: builtin/check-ignore.c:18 builtin/checkout.c:1012 builtin/gc.c:177
+#: builtin/check-ignore.c:18 builtin/checkout.c:1054 builtin/gc.c:177
msgid "suppress progress reporting"
msgstr "ä¸æ˜¾ç¤ºè¿›åº¦æŠ¥å‘Š"
-#: builtin/check-ignore.c:151
+#: builtin/check-ignore.c:26
+msgid "show non-matching input paths"
+msgstr "显示未匹é…的输入路径"
+
+#: builtin/check-ignore.c:143
msgid "cannot specify pathnames with --stdin"
msgstr "ä¸èƒ½åŒæ—¶æä¾›è·¯å¾„åŠ --stdin å‚æ•°"
-#: builtin/check-ignore.c:154
+#: builtin/check-ignore.c:146
msgid "-z only makes sense with --stdin"
msgstr "-z 需è¦å’Œ --stdin å‚数共用æ‰æœ‰æ„义"
-#: builtin/check-ignore.c:156
+#: builtin/check-ignore.c:148
msgid "no path specified"
msgstr "未指定路径"
-#: builtin/check-ignore.c:160
+#: builtin/check-ignore.c:152
msgid "--quiet is only valid with a single pathname"
msgstr "å‚æ•° --quiet åªåœ¨æ供一个路径å时有效"
-#: builtin/check-ignore.c:162
+#: builtin/check-ignore.c:154
msgid "cannot have both --quiet and --verbose"
msgstr "ä¸èƒ½åŒæ—¶æä¾› --quiet å’Œ --verbose å‚æ•°"
+#: builtin/check-ignore.c:157
+msgid "--non-matching is only valid with --verbose"
+msgstr "--non-matching 选项åªåœ¨ä½¿ç”¨ --verbose 时有效"
+
+#: builtin/check-mailmap.c:8
+msgid "git check-mailmap [options] <contact>..."
+msgstr "git check-mailmap [选项] <è”系地å€>..."
+
+#: builtin/check-mailmap.c:13
+msgid "also read contacts from stdin"
+msgstr "还从标准输入读å–è”系地å€"
+
+#: builtin/check-mailmap.c:24
+#, c-format
+msgid "unable to parse contact: %s"
+msgstr "ä¸èƒ½è§£æžè”系地å€ï¼š%s"
+
+#: builtin/check-mailmap.c:47
+msgid "no contacts specified"
+msgstr "未指定è”系地å€"
+
#: builtin/checkout-index.c:126
msgid "git checkout-index [options] [--] [<file>...]"
msgstr "git checkout-index [选项] [--] [<文件>...]"
@@ -2783,107 +3124,107 @@ msgstr "git checkout [选项] <分支>"
msgid "git checkout [options] [<branch>] -- <file>..."
msgstr "git checkout [选项] [<分支>] -- <文件>..."
-#: builtin/checkout.c:116 builtin/checkout.c:149
+#: builtin/checkout.c:117 builtin/checkout.c:150
#, c-format
msgid "path '%s' does not have our version"
msgstr "路径 '%s' 没有我们的版本"
-#: builtin/checkout.c:118 builtin/checkout.c:151
+#: builtin/checkout.c:119 builtin/checkout.c:152
#, c-format
msgid "path '%s' does not have their version"
msgstr "路径 '%s' 没有他们的版本"
-#: builtin/checkout.c:134
+#: builtin/checkout.c:135
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr "路径 '%s' 没有全部必须的版本"
-#: builtin/checkout.c:178
+#: builtin/checkout.c:179
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr "路径 '%s' 没有必须的版本"
-#: builtin/checkout.c:195
+#: builtin/checkout.c:196
#, c-format
msgid "path '%s': cannot merge"
msgstr "path '%s':无法åˆå¹¶"
-#: builtin/checkout.c:212
+#: builtin/checkout.c:213
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr "无法为 '%s' 添加åˆå¹¶ç»“æžœ"
-#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
-#: builtin/checkout.c:245
+#: builtin/checkout.c:237 builtin/checkout.c:240 builtin/checkout.c:243
+#: builtin/checkout.c:246
#, c-format
msgid "'%s' cannot be used with updating paths"
msgstr "'%s' ä¸èƒ½åœ¨æ›´æ–°è·¯å¾„时使用"
-#: builtin/checkout.c:248 builtin/checkout.c:251
+#: builtin/checkout.c:249 builtin/checkout.c:252
#, c-format
msgid "'%s' cannot be used with %s"
msgstr "'%s' ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨"
-#: builtin/checkout.c:254
+#: builtin/checkout.c:255
#, c-format
msgid "Cannot update paths and switch to branch '%s' at the same time."
msgstr "ä¸èƒ½åŒæ—¶æ›´æ–°è·¯å¾„并切æ¢åˆ°åˆ†æ”¯'%s'。"
-#: builtin/checkout.c:265 builtin/checkout.c:426
+#: builtin/checkout.c:266 builtin/checkout.c:458
msgid "corrupt index file"
msgstr "æŸå的索引文件"
-#: builtin/checkout.c:295 builtin/checkout.c:302
+#: builtin/checkout.c:329 builtin/checkout.c:336
#, c-format
msgid "path '%s' is unmerged"
msgstr "路径 '%s' 未åˆå¹¶"
-#: builtin/checkout.c:448
+#: builtin/checkout.c:480
msgid "you need to resolve your current index first"
msgstr "您需è¦å…ˆè§£å†³å½“å‰ç´¢å¼•çš„冲çª"
-#: builtin/checkout.c:569
+#: builtin/checkout.c:601
#, c-format
msgid "Can not do reflog for '%s'\n"
msgstr "ä¸èƒ½å¯¹ '%s' 执行 reflog æ“作\n"
-#: builtin/checkout.c:602
+#: builtin/checkout.c:639
msgid "HEAD is now at"
msgstr "HEAD ç›®å‰ä½äºŽ"
-#: builtin/checkout.c:609
+#: builtin/checkout.c:646
#, c-format
msgid "Reset branch '%s'\n"
msgstr "é‡ç½®åˆ†æ”¯ '%s'\n"
-#: builtin/checkout.c:612
+#: builtin/checkout.c:649
#, c-format
msgid "Already on '%s'\n"
msgstr "å·²ç»ä½äºŽ '%s'\n"
-#: builtin/checkout.c:616
+#: builtin/checkout.c:653
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr "切æ¢å¹¶é‡ç½®åˆ†æ”¯ '%s'\n"
-#: builtin/checkout.c:618 builtin/checkout.c:955
+#: builtin/checkout.c:655 builtin/checkout.c:997
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr "切æ¢åˆ°ä¸€ä¸ªæ–°åˆ†æ”¯ '%s'\n"
-#: builtin/checkout.c:620
+#: builtin/checkout.c:657
#, c-format
msgid "Switched to branch '%s'\n"
msgstr "切æ¢åˆ°åˆ†æ”¯ '%s'\n"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: builtin/checkout.c:676
+#: builtin/checkout.c:713
#, c-format
msgid " ... and %d more.\n"
msgstr " ... åŠå…¶å®ƒ %d 个。\n"
#. The singular version
-#: builtin/checkout.c:682
+#: builtin/checkout.c:719
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -2904,7 +3245,7 @@ msgstr[1] ""
"\n"
"%s\n"
-#: builtin/checkout.c:700
+#: builtin/checkout.c:737
#, c-format
msgid ""
"If you want to keep them by creating a new branch, this may be a good time\n"
@@ -2919,132 +3260,136 @@ msgstr ""
" git branch new_branch_name %s\n"
"\n"
-#: builtin/checkout.c:730
+#: builtin/checkout.c:767
msgid "internal error in revision walk"
msgstr "在版本é历时é‡åˆ°å†…部错误"
-#: builtin/checkout.c:734
+#: builtin/checkout.c:771
msgid "Previous HEAD position was"
msgstr "之å‰çš„ HEAD ä½ç½®æ˜¯"
-#: builtin/checkout.c:761 builtin/checkout.c:950
+#: builtin/checkout.c:798 builtin/checkout.c:992
msgid "You are on a branch yet to be born"
msgstr "您ä½äºŽä¸€ä¸ªå°šæœªåˆå§‹åŒ–的分支"
#. case (1)
-#: builtin/checkout.c:886
+#: builtin/checkout.c:928
#, c-format
msgid "invalid reference: %s"
msgstr "无效引用:%s"
#. case (1): want a tree
-#: builtin/checkout.c:925
+#: builtin/checkout.c:967
#, c-format
msgid "reference is not a tree: %s"
msgstr "引用ä¸æ˜¯ä¸€ä¸ªæ ‘:%s"
-#: builtin/checkout.c:964
+#: builtin/checkout.c:1006
msgid "paths cannot be used with switching branches"
msgstr "路径ä¸èƒ½å’Œåˆ‡æ¢åˆ†æ”¯åŒæ—¶ä½¿ç”¨"
-#: builtin/checkout.c:967 builtin/checkout.c:971
+#: builtin/checkout.c:1009 builtin/checkout.c:1013
#, c-format
msgid "'%s' cannot be used with switching branches"
msgstr "'%s' ä¸èƒ½å’Œåˆ‡æ¢åˆ†æ”¯åŒæ—¶ä½¿ç”¨"
-#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983
-#: builtin/checkout.c:986
+#: builtin/checkout.c:1017 builtin/checkout.c:1020 builtin/checkout.c:1025
+#: builtin/checkout.c:1028
#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "'%s' ä¸èƒ½å’Œ '%s' åŒæ—¶ä½¿ç”¨"
-#: builtin/checkout.c:991
+#: builtin/checkout.c:1033
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
msgstr "ä¸èƒ½åˆ‡æ¢åˆ†æ”¯åˆ°ä¸€ä¸ªéžæ交 '%s'"
-#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89
+#: builtin/checkout.c:1055 builtin/checkout.c:1057 builtin/clone.c:89
#: builtin/remote.c:169 builtin/remote.c:171
msgid "branch"
msgstr "分支"
-#: builtin/checkout.c:1014
+#: builtin/checkout.c:1056
msgid "create and checkout a new branch"
msgstr "创建并检出一个新的分支"
-#: builtin/checkout.c:1016
+#: builtin/checkout.c:1058
msgid "create/reset and checkout a branch"
msgstr "创建/é‡ç½®å¹¶æ£€å‡ºä¸€ä¸ªåˆ†æ”¯"
-#: builtin/checkout.c:1017
+#: builtin/checkout.c:1059
msgid "create reflog for new branch"
msgstr "为新的分支创建引用日志"
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1060
msgid "detach the HEAD at named commit"
msgstr "æˆä¸ºæŒ‡å‘该æ交的分离头指针"
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1061
msgid "set upstream info for new branch"
msgstr "为新的分支设置上游信æ¯"
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new branch"
msgstr "新分支"
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1063
msgid "new unparented branch"
msgstr "新的没有父æ交的分支"
-#: builtin/checkout.c:1022
+#: builtin/checkout.c:1064
msgid "checkout our version for unmerged files"
msgstr "对尚未åˆå¹¶çš„文件检出我们的版本"
-#: builtin/checkout.c:1024
+#: builtin/checkout.c:1066
msgid "checkout their version for unmerged files"
msgstr "对尚未åˆå¹¶çš„文件检出他们的版本"
-#: builtin/checkout.c:1026
+#: builtin/checkout.c:1068
msgid "force checkout (throw away local modifications)"
msgstr "强制检出(丢弃本地修改)"
-#: builtin/checkout.c:1027
+#: builtin/checkout.c:1069
msgid "perform a 3-way merge with the new branch"
msgstr "和新的分支执行三路åˆå¹¶"
-#: builtin/checkout.c:1028 builtin/merge.c:215
+#: builtin/checkout.c:1070 builtin/merge.c:232
msgid "update ignored files (default)"
msgstr "更新忽略的文件(默认)"
-#: builtin/checkout.c:1029 builtin/log.c:1147 parse-options.h:245
+#: builtin/checkout.c:1071 builtin/log.c:1208 parse-options.h:249
msgid "style"
msgstr "风格"
-#: builtin/checkout.c:1030
+#: builtin/checkout.c:1072
msgid "conflict style (merge or diff3)"
msgstr "冲çªè¾“出风格(merge 或 diff3)"
-#: builtin/checkout.c:1033
+#: builtin/checkout.c:1075
+msgid "do not limit pathspecs to sparse entries only"
+msgstr "对路径ä¸åšç¨€ç–检出的é™åˆ¶"
+
+#: builtin/checkout.c:1077
msgid "second guess 'git checkout no-such-branch'"
msgstr "å†è€…猜测'git checkout no-such-branch'"
-#: builtin/checkout.c:1057
+#: builtin/checkout.c:1101
msgid "-b, -B and --orphan are mutually exclusive"
msgstr "-bã€-B å’Œ --orphan 是互斥的"
-#: builtin/checkout.c:1074
+#: builtin/checkout.c:1118
msgid "--track needs a branch name"
msgstr "--track 需è¦ä¸€ä¸ªåˆ†æ”¯å"
-#: builtin/checkout.c:1081
+#: builtin/checkout.c:1125
msgid "Missing branch name; try -b"
msgstr "缺少分支åï¼›å°è¯• -b"
-#: builtin/checkout.c:1116
+#: builtin/checkout.c:1160
msgid "invalid path specification"
msgstr "无效的路径规格"
-#: builtin/checkout.c:1123
+#: builtin/checkout.c:1167
#, c-format
msgid ""
"Cannot update paths and switch to branch '%s' at the same time.\n"
@@ -3053,99 +3398,202 @@ msgstr ""
"ä¸èƒ½åŒæ—¶æ›´æ–°è·¯å¾„并切æ¢åˆ°åˆ†æ”¯'%s'。\n"
"您是想è¦æ£€å‡º '%s' 但其未能解æžä¸ºæ交么?"
-#: builtin/checkout.c:1128
+#: builtin/checkout.c:1172
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
msgstr "git checkout:--detach ä¸èƒ½æŽ¥æ”¶è·¯å¾„å‚æ•° '%s'"
-#: builtin/checkout.c:1132
+#: builtin/checkout.c:1176
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/clean.c:20
-msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
-msgstr "git clean [-d] [-f] [-n] [-q] [-e <模å¼>] [-x | -X] [--] <路径>..."
+#: builtin/clean.c:25
+msgid ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <模å¼>] [-x | -X] [--] <路径>..."
-#: builtin/clean.c:24
+#: builtin/clean.c:29
#, c-format
msgid "Removing %s\n"
msgstr "正删除 %s\n"
-#: builtin/clean.c:25
+#: builtin/clean.c:30
#, c-format
msgid "Would remove %s\n"
msgstr "将删除 %s\n"
-#: builtin/clean.c:26
+#: builtin/clean.c:31
#, c-format
msgid "Skipping repository %s\n"
msgstr "忽略版本库 %s\n"
-#: builtin/clean.c:27
+#: builtin/clean.c:32
#, c-format
msgid "Would skip repository %s\n"
msgstr "将忽略版本库 %s\n"
-#: builtin/clean.c:28
+#: builtin/clean.c:33
#, c-format
msgid "failed to remove %s"
msgstr "无法删除 %s"
-#: builtin/clean.c:160
+#: builtin/clean.c:293
+msgid ""
+"Prompt help:\n"
+"1 - select a numbered item\n"
+"foo - select item based on unique prefix\n"
+" - (empty) select nothing"
+msgstr ""
+"帮助:\n"
+"1 - 通过编å·é€‰æ‹©ä¸€ä¸ªé€‰é¡¹\n"
+"foo - 通过标题选择一个选项\n"
+" - (空)什么也ä¸é€‰æ‹©"
+
+#: builtin/clean.c:297
+msgid ""
+"Prompt help:\n"
+"1 - select a single item\n"
+"3-5 - select a range of items\n"
+"2-3,6-9 - select multiple ranges\n"
+"foo - select item based on unique prefix\n"
+"-... - unselect specified items\n"
+"* - choose all items\n"
+" - (empty) finish selecting"
+msgstr ""
+"帮助:\n"
+"1 - 选择一个选项\n"
+"3-5 - 选择一个范围内的所有选项\n"
+"2-3,6-9 - 选择多个范围内的所有选项\n"
+"foo - 通过标题选择一个选项\n"
+"-... - å选特定的选项\n"
+"* - 选择所有选项\n"
+" - (空)结æŸé€‰æ‹©"
+
+#: builtin/clean.c:515
+#, c-format
+msgid "Huh (%s)?"
+msgstr "嗯(%s)?"
+
+#: builtin/clean.c:658
+#, c-format
+msgid "Input ignore patterns>> "
+msgstr "输入模版以排除æ¡ç›®>> "
+
+#: builtin/clean.c:695
+#, c-format
+msgid "WARNING: Cannot find items matched by: %s"
+msgstr "警告:无法找到和 %s 匹é…çš„æ¡ç›®"
+
+#: builtin/clean.c:716
+msgid "Select items to delete"
+msgstr "选择è¦åˆ é™¤çš„æ¡ç›®"
+
+#: builtin/clean.c:756
+#, c-format
+msgid "remove %s? "
+msgstr "删除 %s?"
+
+#: builtin/clean.c:781
+msgid "Bye."
+msgstr "å†è§ã€‚"
+
+#: builtin/clean.c:789
+msgid ""
+"clean - start cleaning\n"
+"filter by pattern - exclude items from deletion\n"
+"select by numbers - select items to be deleted by numbers\n"
+"ask each - confirm each deletion (like \"rm -i\")\n"
+"quit - stop cleaning\n"
+"help - this screen\n"
+"? - help for prompt selection"
+msgstr ""
+"clean - 开始清ç†\n"
+"filter by pattern - 通过模版排除è¦åˆ é™¤çš„æ¡ç›®\n"
+"select by numbers - 通过数字选择è¦åˆ é™¤çš„æ¡ç›®\n"
+"ask each - 针对删除é€ä¸€è¯¢é—®ï¼ˆå°±åƒ \"rm -i\")\n"
+"quit - åœæ­¢åˆ é™¤å¹¶é€€å‡º\n"
+"help - 显示本帮助\n"
+"? - 显示如何在æ示符下选择的帮助"
+
+#: builtin/clean.c:816
+msgid "*** Commands ***"
+msgstr "*** 命令 ***"
+
+#: builtin/clean.c:817
+msgid "What now"
+msgstr "请选择"
+
+#: builtin/clean.c:825
+msgid "Would remove the following item:"
+msgid_plural "Would remove the following items:"
+msgstr[0] "将删除如下æ¡ç›®ï¼š"
+msgstr[1] "将删除如下æ¡ç›®ï¼š"
+
+#: builtin/clean.c:842
+msgid "No more files to clean, exiting."
+msgstr "没有è¦æ¸…ç†çš„文件,退出。"
+
+#: builtin/clean.c:874
msgid "do not print names of files removed"
msgstr "ä¸æ‰“å°åˆ é™¤æ–‡ä»¶çš„å称"
-#: builtin/clean.c:162
+#: builtin/clean.c:876
msgid "force"
msgstr "强制"
-#: builtin/clean.c:164
+#: builtin/clean.c:877
+msgid "interactive cleaning"
+msgstr "交互å¼æ¸…除"
+
+#: builtin/clean.c:879
msgid "remove whole directories"
msgstr "删除整个目录"
-#: builtin/clean.c:165 builtin/describe.c:413 builtin/grep.c:717
-#: builtin/ls-files.c:494 builtin/name-rev.c:231 builtin/show-ref.c:182
+#: builtin/clean.c:880 builtin/describe.c:420 builtin/grep.c:716
+#: builtin/ls-files.c:493 builtin/name-rev.c:315 builtin/show-ref.c:186
msgid "pattern"
msgstr "模å¼"
-#: builtin/clean.c:166
+#: builtin/clean.c:881
msgid "add <pattern> to ignore rules"
msgstr "添加<模å¼>到忽略规则"
-#: builtin/clean.c:167
+#: builtin/clean.c:882
msgid "remove ignored files, too"
msgstr "也删除忽略的文件"
-#: builtin/clean.c:169
+#: builtin/clean.c:884
msgid "remove only ignored files"
msgstr "åªåˆ é™¤å¿½ç•¥çš„文件"
-#: builtin/clean.c:187
+#: builtin/clean.c:902
msgid "-x and -X cannot be used together"
msgstr "-x å’Œ -X ä¸èƒ½åŒæ—¶ä½¿ç”¨"
-#: builtin/clean.c:191
+#: builtin/clean.c:906
msgid ""
-"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+"clean.requireForce set to true and neither -i, -n nor -f given; refusing to "
+"clean"
msgstr ""
-"clean.requireForce 设置为 true 且未æä¾› -n 或 -f 选项,拒ç»æ‰§è¡Œæ¸…ç†åŠ¨ä½œ"
+"clean.requireForce 设置为 true 且未æä¾› -iã€-n 或 -f 选项,拒ç»æ‰§è¡Œæ¸…ç†åŠ¨ä½œ"
-#: builtin/clean.c:194
+#: builtin/clean.c:909
msgid ""
-"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
-"clean"
+"clean.requireForce defaults to true and neither -i, -n nor -f given; "
+"refusing to clean"
msgstr ""
-"clean.requireForce 默认为 true 且未æä¾› -n 或 -f 选项,拒ç»æ‰§è¡Œæ¸…ç†åŠ¨ä½œ"
+"clean.requireForce 默认为 true 且未æä¾› -iã€-n 或 -f 选项,拒ç»æ‰§è¡Œæ¸…ç†åŠ¨ä½œ"
#: builtin/clone.c:36
msgid "git clone [options] [--] <repo> [<dir>]"
msgstr "git clone [选项] [--] <版本库> [<路径>]"
-#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
-#: builtin/push.c:436
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:229
+#: builtin/push.c:462
msgid "force progress reporting"
msgstr "强制显示进度报告"
@@ -3205,7 +3653,7 @@ msgstr "检出<分支>而ä¸æ˜¯è¿œç¨‹HEAD"
msgid "path to git-upload-pack on the remote"
msgstr "远程 git-upload-pack 路径"
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:661
msgid "depth"
msgstr "深度"
@@ -3233,122 +3681,154 @@ msgstr "key=value"
msgid "set config inside the new repository"
msgstr "在新版本库中设置é…置信æ¯"
-#: builtin/clone.c:243
+#: builtin/clone.c:253
#, c-format
-msgid "reference repository '%s' is not a local directory."
-msgstr "引用版本库 '%s' ä¸æ˜¯ä¸€ä¸ªæœ¬åœ°ç›®å½•ã€‚"
+msgid "reference repository '%s' is not a local repository."
+msgstr "引用版本库 '%s' ä¸æ˜¯ä¸€ä¸ªæœ¬åœ°ç‰ˆæœ¬åº“。"
-#: builtin/clone.c:306
+#: builtin/clone.c:316
#, c-format
msgid "failed to create directory '%s'"
msgstr "无法创建目录 '%s'"
-#: builtin/clone.c:308 builtin/diff.c:77
+#: builtin/clone.c:318 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
msgstr "无法枚举 '%s' 状æ€"
-#: builtin/clone.c:310
+#: builtin/clone.c:320
#, c-format
msgid "%s exists and is not a directory"
msgstr "%s 存在且ä¸æ˜¯ä¸€ä¸ªç›®å½•"
-#: builtin/clone.c:324
+#: builtin/clone.c:334
#, c-format
msgid "failed to stat %s\n"
msgstr "无法枚举 %s 状æ€\n"
-#: builtin/clone.c:346
+#: builtin/clone.c:356
#, c-format
msgid "failed to create link '%s'"
msgstr "无法创建链接 '%s'"
-#: builtin/clone.c:350
+#: builtin/clone.c:360
#, c-format
msgid "failed to copy file to '%s'"
msgstr "无法拷è´æ–‡ä»¶è‡³ '%s'"
-#: builtin/clone.c:373
+#: builtin/clone.c:383
#, c-format
msgid "done.\n"
msgstr "完æˆã€‚\n"
-#: builtin/clone.c:443
+#: builtin/clone.c:396
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry the checkout with 'git checkout -f HEAD'\n"
+msgstr ""
+"克隆æˆåŠŸï¼Œä½†æ˜¯æ£€å‡ºå¤±è´¥ã€‚\n"
+"您å¯ä»¥é€šè¿‡ 'git status' 检查哪些已被检出,然åŽä½¿ç”¨å‘½ä»¤\n"
+"'git checkout -f HEAD' é‡è¯•\n"
+
+#: builtin/clone.c:475
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr "ä¸èƒ½å‘现è¦å…‹éš†çš„远程分支 %s。"
-#: builtin/clone.c:552
+#: builtin/clone.c:555
+#, c-format
+msgid "Checking connectivity... "
+msgstr "检查连接... "
+
+#: builtin/clone.c:558
+msgid "remote did not send all necessary objects"
+msgstr "远程没有å‘é€æ‰€æœ‰å¿…须的对象"
+
+#: builtin/clone.c:560
+#, c-format
+msgid "done\n"
+msgstr "完æˆ\n"
+
+#: builtin/clone.c:621
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
msgstr "远程 HEAD 指å‘一个ä¸å­˜åœ¨çš„引用,无法检出。\n"
-#: builtin/clone.c:690
+#: builtin/clone.c:652
+msgid "unable to checkout working tree"
+msgstr "ä¸èƒ½æ£€å‡ºå·¥ä½œåŒº"
+
+#: builtin/clone.c:760
msgid "Too many arguments."
msgstr "太多å‚数。"
-#: builtin/clone.c:694
+#: builtin/clone.c:764
msgid "You must specify a repository to clone."
msgstr "您必须指定一个版本库æ¥å…‹éš†ã€‚"
-#: builtin/clone.c:705
+#: builtin/clone.c:775
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr "--bare å’Œ --origin %s 选项ä¸å…¼å®¹ã€‚"
-#: builtin/clone.c:708
+#: builtin/clone.c:778
msgid "--bare and --separate-git-dir are incompatible."
msgstr "--bare å’Œ --separate-git-dir 选项ä¸å…¼å®¹ã€‚"
-#: builtin/clone.c:721
+#: builtin/clone.c:791
#, c-format
msgid "repository '%s' does not exist"
msgstr "版本库 '%s' ä¸å­˜åœ¨"
-#: builtin/clone.c:726
+#: builtin/clone.c:796
msgid "--depth is ignored in local clones; use file:// instead."
msgstr "--depth 在本地克隆被忽略,改为 file:// å议试试。"
-#: builtin/clone.c:736
+#: builtin/clone.c:798
+msgid "--local is ignored"
+msgstr "--local 被忽略"
+
+#: builtin/clone.c:808
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr "目标路径 '%s' å·²ç»å­˜åœ¨ï¼Œå¹¶ä¸”ä¸æ˜¯ä¸€ä¸ªç©ºç›®å½•ã€‚"
-#: builtin/clone.c:746
+#: builtin/clone.c:818
#, c-format
msgid "working tree '%s' already exists."
msgstr "工作区 '%s' å·²ç»å­˜åœ¨ã€‚"
-#: builtin/clone.c:759 builtin/clone.c:771
+#: builtin/clone.c:831 builtin/clone.c:843
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "ä¸èƒ½ä¸º '%s' 创建先导目录"
-#: builtin/clone.c:762
+#: builtin/clone.c:834
#, c-format
msgid "could not create work tree dir '%s'."
msgstr "ä¸èƒ½ä¸º '%s' 创建工作区目录。"
-#: builtin/clone.c:781
+#: builtin/clone.c:853
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "克隆到裸版本库 '%s'...\n"
-#: builtin/clone.c:783
+#: builtin/clone.c:855
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "正克隆到 '%s'...\n"
-#: builtin/clone.c:818
+#: builtin/clone.c:890
#, c-format
msgid "Don't know how to clone %s"
msgstr "ä¸çŸ¥é“如何克隆 %s"
-#: builtin/clone.c:867
+#: builtin/clone.c:942
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "远程分支 %s 在上游 %s 未å‘现"
-#: builtin/clone.c:874
+#: builtin/clone.c:949
msgid "You appear to have cloned an empty repository."
msgstr "您似乎克隆了一个空版本库。"
@@ -3384,15 +3864,15 @@ msgstr "两列之间的填充空间"
msgid "--command must be the first argument"
msgstr "--command 必须是第一个å‚æ•°"
-#: builtin/commit.c:34
+#: builtin/commit.c:35
msgid "git commit [options] [--] <pathspec>..."
msgstr "git commit [选项] [--] <路径匹é…>..."
-#: builtin/commit.c:39
+#: builtin/commit.c:40
msgid "git status [options] [--] <pathspec>..."
msgstr "git status [选项] [--] <路径匹é…>..."
-#: builtin/commit.c:44
+#: builtin/commit.c:45
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
@@ -3415,7 +3895,7 @@ msgstr ""
"\n"
" git commit --amend --reset-author\n"
-#: builtin/commit.c:56
+#: builtin/commit.c:57
msgid ""
"You asked to amend the most recent commit, but doing so would make\n"
"it empty. You can repeat your command with --allow-empty, or you can\n"
@@ -3424,109 +3904,127 @@ msgstr ""
"您è¦ä¿®è¡¥æœ€è¿‘çš„æ交,但这么åšä¼šè®©å®ƒæˆä¸ºç©ºæ交。您å¯ä»¥é‡å¤æ‚¨çš„命令并带上\n"
"--allow-empty 选项,或者您å¯ç”¨å‘½ä»¤ \"git reset HEAD^\" 整个删除该æ交。\n"
-#: builtin/commit.c:61
+#: builtin/commit.c:62
msgid ""
"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
"If you wish to commit it anyway, use:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Otherwise, please use 'git reset'\n"
msgstr ""
"之å‰çš„拣选æ“作现在是一个空æ交,å¯èƒ½æ˜¯ç”±å†²çªè§£å†³å¯¼è‡´çš„。如果您无论如何\n"
"也è¦æ交,使用命令:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"å¦åˆ™ï¼Œè¯·ä½¿ç”¨å‘½ä»¤ 'git reset'\n"
-#: builtin/commit.c:258
+#: builtin/commit.c:69
+msgid "Otherwise, please use 'git reset'\n"
+msgstr "å¦åˆ™ï¼Œè¯·ä½¿ç”¨å‘½ä»¤ 'git reset'\n"
+
+#: builtin/commit.c:72
+msgid ""
+"If you wish to skip this commit, use:\n"
+"\n"
+" git reset\n"
+"\n"
+"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
+"the remaining commits.\n"
+msgstr ""
+"如果您想跳过这个æ交,使用命令:\n"
+"\n"
+" git reset\n"
+"\n"
+"然åŽæ‰§è¡Œ \"git cherry-pick --continue\" 继续对其余æ交执行拣选\n"
+"æ“作。\n"
+
+#: builtin/commit.c:279
msgid "failed to unpack HEAD tree object"
msgstr "无法解包 HEAD 树对象"
-#: builtin/commit.c:300
+#: builtin/commit.c:321
msgid "unable to create temporary index"
msgstr "ä¸èƒ½åˆ›å»ºä¸´æ—¶ç´¢å¼•"
-#: builtin/commit.c:306
+#: builtin/commit.c:327
msgid "interactive add failed"
msgstr "交互å¼æ·»åŠ å¤±è´¥"
-#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410
+#: builtin/commit.c:360 builtin/commit.c:381 builtin/commit.c:431
msgid "unable to write new_index file"
msgstr "无法写 new_index 文件"
-#: builtin/commit.c:391
+#: builtin/commit.c:412
msgid "cannot do a partial commit during a merge."
msgstr "在åˆå¹¶è¿‡ç¨‹ä¸­ä¸èƒ½åšéƒ¨åˆ†æ交。"
-#: builtin/commit.c:393
+#: builtin/commit.c:414
msgid "cannot do a partial commit during a cherry-pick."
msgstr "在拣选过程中ä¸èƒ½åšéƒ¨åˆ†æ交。"
-#: builtin/commit.c:403
+#: builtin/commit.c:424
msgid "cannot read the index"
msgstr "无法读å–索引"
-#: builtin/commit.c:423
+#: builtin/commit.c:444
msgid "unable to write temporary index file"
msgstr "无法写临时索引文件"
-#: builtin/commit.c:511 builtin/commit.c:517
+#: builtin/commit.c:535 builtin/commit.c:541
#, c-format
msgid "invalid commit: %s"
msgstr "无效的æ交:%s"
-#: builtin/commit.c:540
+#: builtin/commit.c:563
msgid "malformed --author parameter"
msgstr "éžæ³•çš„ --author å‚æ•°"
-#: builtin/commit.c:560
+#: builtin/commit.c:583
#, c-format
msgid "Malformed ident string: '%s'"
msgstr "éžæ³•çš„身份字符串:'%s'"
-#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954
+#: builtin/commit.c:621 builtin/commit.c:654 builtin/commit.c:982
#, c-format
msgid "could not lookup commit %s"
msgstr "ä¸èƒ½æŸ¥è¯¢æ交 %s"
-#: builtin/commit.c:610 builtin/shortlog.c:272
+#: builtin/commit.c:633 builtin/shortlog.c:271
#, c-format
msgid "(reading log message from standard input)\n"
msgstr "(正从标准输入中读å–日志信æ¯ï¼‰\n"
-#: builtin/commit.c:612
+#: builtin/commit.c:635
msgid "could not read log from standard input"
msgstr "ä¸èƒ½ä»Žæ ‡å‡†è¾“入中读å–日志信æ¯"
-#: builtin/commit.c:616
+#: builtin/commit.c:639
#, c-format
msgid "could not read log file '%s'"
msgstr "ä¸èƒ½è¯»å–日志文件 '%s'"
-#: builtin/commit.c:622
+#: builtin/commit.c:645
msgid "commit has empty message"
msgstr "æ交说明为空"
-#: builtin/commit.c:638
+#: builtin/commit.c:661
msgid "could not read MERGE_MSG"
msgstr "ä¸èƒ½è¯»å– MERGE_MSG"
-#: builtin/commit.c:642
+#: builtin/commit.c:665
msgid "could not read SQUASH_MSG"
msgstr "ä¸èƒ½è¯»å– SQUASH_MSG"
-#: builtin/commit.c:646
+#: builtin/commit.c:669
#, c-format
msgid "could not read '%s'"
msgstr "ä¸èƒ½è¯»å– '%s'"
-#: builtin/commit.c:707
+#: builtin/commit.c:730
msgid "could not write commit template"
msgstr "ä¸èƒ½å†™æ交模版"
-#: builtin/commit.c:718
+#: builtin/commit.c:741
#, c-format
msgid ""
"\n"
@@ -3540,7 +4038,7 @@ msgstr ""
"\t%s\n"
"然åŽé‡è¯•ã€‚\n"
-#: builtin/commit.c:723
+#: builtin/commit.c:746
#, c-format
msgid ""
"\n"
@@ -3554,7 +4052,7 @@ msgstr ""
"\t%s\n"
"然åŽé‡è¯•ã€‚\n"
-#: builtin/commit.c:735
+#: builtin/commit.c:758
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
@@ -3563,7 +4061,7 @@ msgstr ""
"请为您的å˜æ›´è¾“å…¥æ交说明。以 '%c' 开始的行将被忽略,而一个空的æ交\n"
"说明将会终止æ交。\n"
-#: builtin/commit.c:740
+#: builtin/commit.c:763
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
@@ -3574,355 +4072,355 @@ msgstr ""
"也å¯ä»¥åˆ é™¤å®ƒä»¬ã€‚一个空的æ交说明将会终止æ交。\n"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: builtin/commit.c:753
+#: builtin/commit.c:776
#, c-format
msgid "%sAuthor: %s"
msgstr "%s作者: %s"
# 译者:为ä¿è¯åœ¨è¾“出中对é½ï¼Œæ³¨æ„调整å¥ä¸­ç©ºæ ¼ï¼
-#: builtin/commit.c:760
+#: builtin/commit.c:783
#, c-format
msgid "%sCommitter: %s"
msgstr "%sæ交者: %s"
-#: builtin/commit.c:780
+#: builtin/commit.c:803
msgid "Cannot read index"
msgstr "无法读å–索引"
-#: builtin/commit.c:817
+#: builtin/commit.c:845
msgid "Error building trees"
msgstr "无法创建树对象"
-#: builtin/commit.c:832 builtin/tag.c:359
+#: builtin/commit.c:860 builtin/tag.c:359
#, c-format
msgid "Please supply the message using either -m or -F option.\n"
msgstr "请使用 -m 或 -F 选项æä¾›æ交说明。\n"
-#: builtin/commit.c:929
+#: builtin/commit.c:957
#, c-format
msgid "No existing author found with '%s'"
msgstr "æ²¡æœ‰æ‰¾åˆ°åŒ¹é… '%s' 的作者"
-#: builtin/commit.c:944 builtin/commit.c:1138
+#: builtin/commit.c:972 builtin/commit.c:1208
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr "无效的未追踪文件å‚æ•° '%s'"
-#: builtin/commit.c:974
+#: builtin/commit.c:1009
+msgid "--long and -z are incompatible"
+msgstr "--long å’Œ -z 选项ä¸å…¼å®¹"
+
+#: builtin/commit.c:1039
msgid "Using both --reset-author and --author does not make sense"
msgstr "åŒæ—¶ä½¿ç”¨ --reset-author å’Œ --author 没有æ„义"
-#: builtin/commit.c:985
+#: builtin/commit.c:1050
msgid "You have nothing to amend."
msgstr "您没有å¯ä¿®è¡¥çš„æ交。"
-#: builtin/commit.c:988
+#: builtin/commit.c:1053
msgid "You are in the middle of a merge -- cannot amend."
msgstr "您正处于一个åˆå¹¶è¿‡ç¨‹ä¸­ -- 无法修补æ交。"
-#: builtin/commit.c:990
+#: builtin/commit.c:1055
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr "您正处于一个拣选过程中 -- 无法修补æ交。"
-#: builtin/commit.c:993
+#: builtin/commit.c:1058
msgid "Options --squash and --fixup cannot be used together"
msgstr "选项 --squash å’Œ --fixup ä¸èƒ½åŒæ—¶ä½¿ç”¨"
-#: builtin/commit.c:1003
+#: builtin/commit.c:1068
msgid "Only one of -c/-C/-F/--fixup can be used."
msgstr "åªèƒ½ç”¨ä¸€ä¸ª -c/-C/-F/--fixup 选项。"
-#: builtin/commit.c:1005
+#: builtin/commit.c:1070
msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
msgstr "选项 -m ä¸èƒ½å’Œ -c/-C/-F/--fixup åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/commit.c:1013
+#: builtin/commit.c:1078
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr "--reset-author åªèƒ½å’Œ -Cã€-c 或 --amend åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/commit.c:1030
+#: builtin/commit.c:1095
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
msgstr "åªèƒ½ç”¨ä¸€ä¸ª --include/--only/--all/--interactive/--patch 选项。"
-#: builtin/commit.c:1032
+#: builtin/commit.c:1097
msgid "No paths with --include/--only does not make sense."
msgstr "å‚æ•° --include/--only ä¸è·Ÿè·¯å¾„没有æ„义。"
-#: builtin/commit.c:1034
+#: builtin/commit.c:1099
msgid "Clever... amending the last one with dirty index."
msgstr "èªæ˜Ž... 在索引ä¸å¹²å‡€ä¸‹ä¿®è¡¥æœ€åŽçš„æ交。"
-#: builtin/commit.c:1036
+#: builtin/commit.c:1101
msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
msgstr "指定了明确的路径而没有使用 -i 或 -o 选项;认为是 --only paths..."
-#: builtin/commit.c:1046 builtin/tag.c:575
+#: builtin/commit.c:1111 builtin/tag.c:575
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "无效的清ç†æ¨¡å¼ %s"
-#: builtin/commit.c:1051
+#: builtin/commit.c:1116
msgid "Paths with -a does not make sense."
msgstr "路径和 -a 选项åŒæ—¶ä½¿ç”¨æ²¡æœ‰æ„义。"
-#: builtin/commit.c:1057 builtin/commit.c:1192
-msgid "--long and -z are incompatible"
-msgstr "--long å’Œ -z 选项ä¸å…¼å®¹"
-
-#: builtin/commit.c:1152 builtin/commit.c:1388
+#: builtin/commit.c:1222 builtin/commit.c:1455
msgid "show status concisely"
msgstr "以简æ´çš„æ ¼å¼æ˜¾ç¤ºçŠ¶æ€"
-#: builtin/commit.c:1154 builtin/commit.c:1390
+#: builtin/commit.c:1224 builtin/commit.c:1457
msgid "show branch information"
msgstr "显示分支信æ¯"
-#: builtin/commit.c:1156 builtin/commit.c:1392 builtin/push.c:426
+#: builtin/commit.c:1226 builtin/commit.c:1459 builtin/push.c:452
msgid "machine-readable output"
msgstr "机器å¯è¯»çš„输出"
-#: builtin/commit.c:1159 builtin/commit.c:1394
+#: builtin/commit.c:1229 builtin/commit.c:1461
msgid "show status in long format (default)"
msgstr "以长格å¼æ˜¾ç¤ºçŠ¶æ€ï¼ˆé»˜è®¤ï¼‰"
-#: builtin/commit.c:1162 builtin/commit.c:1397
+#: builtin/commit.c:1232 builtin/commit.c:1464
msgid "terminate entries with NUL"
msgstr "æ¡ç›®ä»¥NUL字符结尾"
-#: builtin/commit.c:1164 builtin/commit.c:1400 builtin/fast-export.c:647
-#: builtin/fast-export.c:650 builtin/tag.c:459
+#: builtin/commit.c:1234 builtin/commit.c:1467 builtin/fast-export.c:667
+#: builtin/fast-export.c:670 builtin/tag.c:459
msgid "mode"
msgstr "模å¼"
-#: builtin/commit.c:1165 builtin/commit.c:1400
+#: builtin/commit.c:1235 builtin/commit.c:1467
msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
msgstr "显示未跟踪的文件,“模å¼â€çš„å¯é€‰å‚数:allã€normalã€no。(默认:all)"
-#: builtin/commit.c:1168
+#: builtin/commit.c:1238
msgid "show ignored files"
msgstr "显示忽略的文件"
-#: builtin/commit.c:1169 parse-options.h:151
+#: builtin/commit.c:1239 parse-options.h:154
msgid "when"
msgstr "何时"
-#: builtin/commit.c:1170
+#: builtin/commit.c:1240
msgid ""
"ignore changes to submodules, optional when: all, dirty, untracked. "
"(Default: all)"
msgstr ""
"忽略å­æ¨¡ç»„的更改,“何时â€çš„å¯é€‰å‚数:allã€dirtyã€untracked。(默认:all)"
-#: builtin/commit.c:1172
+#: builtin/commit.c:1242
msgid "list untracked files in columns"
msgstr "以列的方å¼æ˜¾ç¤ºæœªè·Ÿè¸ªçš„文件"
-#: builtin/commit.c:1246
+#: builtin/commit.c:1313
msgid "couldn't look up newly created commit"
msgstr "无法找到新创建的æ交"
-#: builtin/commit.c:1248
+#: builtin/commit.c:1315
msgid "could not parse newly created commit"
msgstr "ä¸èƒ½è§£æžæ–°åˆ›å»ºçš„æ交"
-#: builtin/commit.c:1289
+#: builtin/commit.c:1356
msgid "detached HEAD"
msgstr "分离头指针"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: builtin/commit.c:1291
+#: builtin/commit.c:1358
msgid " (root-commit)"
msgstr "(根æ交)"
-#: builtin/commit.c:1358
+#: builtin/commit.c:1425
msgid "suppress summary after successful commit"
msgstr "æ交æˆåŠŸåŽä¸æ˜¾ç¤ºæ¦‚è¿°ä¿¡æ¯"
-#: builtin/commit.c:1359
+#: builtin/commit.c:1426
msgid "show diff in commit message template"
msgstr "在æ交说明模æ¿é‡Œæ˜¾ç¤ºå·®å¼‚"
-#: builtin/commit.c:1361
+#: builtin/commit.c:1428
msgid "Commit message options"
msgstr "æ交说明选项"
-#: builtin/commit.c:1362 builtin/tag.c:457
+#: builtin/commit.c:1429 builtin/tag.c:457
msgid "read message from file"
msgstr "从文件中读å–æ交说明"
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "author"
msgstr "作者"
-#: builtin/commit.c:1363
+#: builtin/commit.c:1430
msgid "override author for commit"
msgstr "æ交时覆盖作者"
-#: builtin/commit.c:1364 builtin/gc.c:178
+#: builtin/commit.c:1431 builtin/gc.c:178
msgid "date"
msgstr "日期"
-#: builtin/commit.c:1364
+#: builtin/commit.c:1431
msgid "override date for commit"
msgstr "æ交时覆盖日期"
-#: builtin/commit.c:1365 builtin/merge.c:206 builtin/notes.c:533
-#: builtin/notes.c:690 builtin/tag.c:455
+#: builtin/commit.c:1432 builtin/merge.c:223 builtin/notes.c:405
+#: builtin/notes.c:562 builtin/tag.c:455
msgid "message"
msgstr "说明"
-#: builtin/commit.c:1365
+#: builtin/commit.c:1432
msgid "commit message"
msgstr "æ交说明"
-#: builtin/commit.c:1366
+#: builtin/commit.c:1433
msgid "reuse and edit message from specified commit"
msgstr "é‡ç”¨å¹¶ç¼–辑指定æ交的æ交说明"
-#: builtin/commit.c:1367
+#: builtin/commit.c:1434
msgid "reuse message from specified commit"
msgstr "é‡ç”¨æŒ‡å®šæ交的æ交说明"
-#: builtin/commit.c:1368
+#: builtin/commit.c:1435
msgid "use autosquash formatted message to fixup specified commit"
msgstr "使用 autosquash æ ¼å¼çš„æ交说明用以修正指定的æ交"
-#: builtin/commit.c:1369
+#: builtin/commit.c:1436
msgid "use autosquash formatted message to squash specified commit"
msgstr "使用 autosquash æ ¼å¼çš„æ交说明用以压缩至指定的æ交"
-#: builtin/commit.c:1370
+#: builtin/commit.c:1437
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr "现在将该æ交的作者改为我(和 -C/-c/--amend å‚数共用)"
-#: builtin/commit.c:1371 builtin/log.c:1102 builtin/revert.c:109
+#: builtin/commit.c:1438 builtin/log.c:1160 builtin/revert.c:111
msgid "add Signed-off-by:"
msgstr "添加 Signed-off-by: ç­¾å"
-#: builtin/commit.c:1372
+#: builtin/commit.c:1439
msgid "use specified template file"
msgstr "使用指定的模æ¿æ–‡ä»¶"
-#: builtin/commit.c:1373
+#: builtin/commit.c:1440
msgid "force edit of commit"
msgstr "强制编辑æ交"
# 译者:å¯é€‰å€¼ï¼Œä¸èƒ½ç¿»è¯‘(或是原文中笔误,应为 mode)
-#: builtin/commit.c:1374
+#: builtin/commit.c:1441
msgid "default"
msgstr "default"
-#: builtin/commit.c:1374 builtin/tag.c:460
+#: builtin/commit.c:1441 builtin/tag.c:460
msgid "how to strip spaces and #comments from message"
msgstr "设置如何删除æ交说明里的空格和#注释"
-#: builtin/commit.c:1375
+#: builtin/commit.c:1442
msgid "include status in commit message template"
msgstr "在æ交说明模æ¿é‡ŒåŒ…å«çŠ¶æ€ä¿¡æ¯"
-#: builtin/commit.c:1376 builtin/merge.c:213 builtin/tag.c:461
+#: builtin/commit.c:1443 builtin/merge.c:230 builtin/tag.c:461
msgid "key id"
msgstr "key id"
-#: builtin/commit.c:1377 builtin/merge.c:214
+#: builtin/commit.c:1444 builtin/merge.c:231
msgid "GPG sign commit"
msgstr "GPG æ交签å"
#. end commit message options
-#: builtin/commit.c:1380
+#: builtin/commit.c:1447
msgid "Commit contents options"
msgstr "æ交内容选项"
-#: builtin/commit.c:1381
+#: builtin/commit.c:1448
msgid "commit all changed files"
msgstr "æ交所有改动的文件"
-#: builtin/commit.c:1382
+#: builtin/commit.c:1449
msgid "add specified files to index for commit"
msgstr "添加指定的文件到索引区等待æ交"
-#: builtin/commit.c:1383
+#: builtin/commit.c:1450
msgid "interactively add files"
msgstr "交互å¼æ·»åŠ æ–‡ä»¶"
-#: builtin/commit.c:1384
+#: builtin/commit.c:1451
msgid "interactively add changes"
msgstr "交互å¼æ·»åŠ å˜æ›´"
-#: builtin/commit.c:1385
+#: builtin/commit.c:1452
msgid "commit only specified files"
msgstr "åªæ交指定的文件"
-#: builtin/commit.c:1386
+#: builtin/commit.c:1453
msgid "bypass pre-commit hook"
msgstr "绕过 pre-commit é’©å­"
-#: builtin/commit.c:1387
+#: builtin/commit.c:1454
msgid "show what would be committed"
msgstr "显示将è¦æ交的内容"
-#: builtin/commit.c:1398
+#: builtin/commit.c:1465
msgid "amend previous commit"
msgstr "修改先å‰çš„æ交"
-#: builtin/commit.c:1399
+#: builtin/commit.c:1466
msgid "bypass post-rewrite hook"
msgstr "绕过 post-rewrite é’©å­"
-#: builtin/commit.c:1404
+#: builtin/commit.c:1471
msgid "ok to record an empty change"
msgstr "å…许一个空æ交"
-#: builtin/commit.c:1407
+#: builtin/commit.c:1474
msgid "ok to record a change with an empty message"
msgstr "å…许空的æ交说明"
-#: builtin/commit.c:1439
+#: builtin/commit.c:1507
msgid "could not parse HEAD commit"
msgstr "ä¸èƒ½è§£æž HEAD æ交"
-#: builtin/commit.c:1477 builtin/merge.c:508
+#: builtin/commit.c:1545 builtin/merge.c:525
#, c-format
msgid "could not open '%s' for reading"
msgstr "ä¸èƒ½ä¸ºè¯»å…¥æ‰“å¼€ '%s'"
-#: builtin/commit.c:1484
+#: builtin/commit.c:1552
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "æŸåçš„ MERGE_HEAD 文件(%s)"
-#: builtin/commit.c:1491
+#: builtin/commit.c:1559
msgid "could not read MERGE_MODE"
msgstr "ä¸èƒ½è¯»å– MERGE_MODE"
-#: builtin/commit.c:1510
+#: builtin/commit.c:1578
#, c-format
msgid "could not read commit message: %s"
msgstr "ä¸èƒ½è¯»å–æ交说明:%s"
-#: builtin/commit.c:1524
+#: builtin/commit.c:1592
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr "终止æ交;您未更改æ¥è‡ªæ¨¡ç‰ˆçš„æ交说明。\n"
-#: builtin/commit.c:1529
+#: builtin/commit.c:1597
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr "终止æ交因为æ交说明为空。\n"
-#: builtin/commit.c:1544 builtin/merge.c:832 builtin/merge.c:857
+#: builtin/commit.c:1612 builtin/merge.c:861 builtin/merge.c:886
msgid "failed to write commit object"
msgstr "无法写æ交对象"
-#: builtin/commit.c:1565
+#: builtin/commit.c:1633
msgid "cannot lock HEAD ref"
msgstr "无法é”定 HEAD 引用"
-#: builtin/commit.c:1569
+#: builtin/commit.c:1637
msgid "cannot update HEAD ref"
msgstr "无法更新 HEAD 引用"
-#: builtin/commit.c:1580
+#: builtin/commit.c:1648
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full or quota is\n"
@@ -3935,171 +4433,183 @@ msgstr ""
msgid "git config [options]"
msgstr "git config [选项]"
-#: builtin/config.c:51
+#: builtin/config.c:52
msgid "Config file location"
msgstr "é…置文件ä½ç½®"
-#: builtin/config.c:52
+#: builtin/config.c:53
msgid "use global config file"
msgstr "使用全局é…置文件"
-#: builtin/config.c:53
+#: builtin/config.c:54
msgid "use system config file"
msgstr "使用系统级é…置文件"
-#: builtin/config.c:54
+#: builtin/config.c:55
msgid "use repository config file"
msgstr "使用版本库级é…置文件"
-#: builtin/config.c:55
+#: builtin/config.c:56
msgid "use given config file"
msgstr "使用指定的é…置文件"
-#: builtin/config.c:56
+#: builtin/config.c:57
+msgid "blob-id"
+msgstr "æ•°æ®å¯¹è±¡ID"
+
+#: builtin/config.c:57
+msgid "read config from given blob object"
+msgstr "从给定的数æ®å¯¹è±¡è¯»å–é…ç½®"
+
+#: builtin/config.c:58
msgid "Action"
msgstr "æ“作"
-#: builtin/config.c:57
+#: builtin/config.c:59
msgid "get value: name [value-regex]"
msgstr "获å–值:name [value-regex]"
-#: builtin/config.c:58
+#: builtin/config.c:60
msgid "get all values: key [value-regex]"
msgstr "获得所有的值:key [value-regex]"
-#: builtin/config.c:59
+#: builtin/config.c:61
msgid "get values for regexp: name-regex [value-regex]"
msgstr "æ ¹æ®æ­£åˆ™è¡¨è¾¾å¼èŽ·å¾—值:name-regex [value-regex]"
-#: builtin/config.c:60
+#: builtin/config.c:62
msgid "replace all matching variables: name value [value_regex]"
msgstr "替æ¢æ‰€æœ‰åŒ¹é…çš„å˜é‡ï¼šname value [value_regex]"
-#: builtin/config.c:61
+#: builtin/config.c:63
msgid "add a new variable: name value"
msgstr "添加一个新的å˜é‡ï¼šname value"
-#: builtin/config.c:62
+#: builtin/config.c:64
msgid "remove a variable: name [value-regex]"
msgstr "删除一个å˜é‡ï¼šname [value-regex]"
-#: builtin/config.c:63
+#: builtin/config.c:65
msgid "remove all matches: name [value-regex]"
msgstr "删除所有匹é…项:name [value-regex]"
-#: builtin/config.c:64
+#: builtin/config.c:66
msgid "rename section: old-name new-name"
msgstr "é‡å‘½åå°èŠ‚:old-name new-name"
-#: builtin/config.c:65
+#: builtin/config.c:67
msgid "remove a section: name"
msgstr "删除一个å°èŠ‚:name"
-#: builtin/config.c:66
+#: builtin/config.c:68
msgid "list all"
msgstr "列出所有"
-#: builtin/config.c:67
+#: builtin/config.c:69
msgid "open an editor"
msgstr "打开一个编辑器"
-#: builtin/config.c:68 builtin/config.c:69
+#: builtin/config.c:70 builtin/config.c:71
msgid "slot"
msgstr "slot"
-#: builtin/config.c:68
+#: builtin/config.c:70
msgid "find the color configured: [default]"
msgstr "找到é…置的颜色:[默认]"
-#: builtin/config.c:69
+#: builtin/config.c:71
msgid "find the color setting: [stdout-is-tty]"
msgstr "找到颜色设置:[stdout-is-tty]"
-#: builtin/config.c:70
+#: builtin/config.c:72
msgid "Type"
msgstr "类型"
-#: builtin/config.c:71
+#: builtin/config.c:73
msgid "value is \"true\" or \"false\""
msgstr "值是 \"true\" 或 \"false\""
-#: builtin/config.c:72
+#: builtin/config.c:74
msgid "value is decimal number"
msgstr "值是å进制数"
-#: builtin/config.c:73
+#: builtin/config.c:75
msgid "value is --bool or --int"
msgstr "值是 --bool or --int"
-#: builtin/config.c:74
+#: builtin/config.c:76
msgid "value is a path (file or directory name)"
msgstr "值是一个路径(文件或目录å)"
-#: builtin/config.c:75
+#: builtin/config.c:77
msgid "Other"
msgstr "其它"
-#: builtin/config.c:76
+#: builtin/config.c:78
msgid "terminate values with NUL byte"
msgstr "终止值是NUL字节"
-#: builtin/config.c:77
+#: builtin/config.c:79
msgid "respect include directives on lookup"
msgstr "查询时å‚ç…§ include 指令递归查找"
-#: builtin/count-objects.c:69
-msgid "git count-objects [-v]"
-msgstr "git count-objects [-v]"
+#: builtin/count-objects.c:82
+msgid "git count-objects [-v] [-H | --human-readable]"
+msgstr "git count-objects [-v] [-H | --human-readable]"
-#: builtin/describe.c:15
+#: builtin/count-objects.c:97
+msgid "print sizes in human readable format"
+msgstr "以用户å¯è¯»çš„æ ¼å¼æ˜¾ç¤ºå¤§å°"
+
+#: builtin/describe.c:16
msgid "git describe [options] <committish>*"
msgstr "git describe [选项] <æ交å·>*"
-#: builtin/describe.c:16
+#: builtin/describe.c:17
msgid "git describe [options] --dirty"
msgstr "git describe [选项] --dirty"
-#: builtin/describe.c:234
+#: builtin/describe.c:237
#, c-format
msgid "annotated tag %s not available"
msgstr "注释 tag %s 无效"
-#: builtin/describe.c:238
+#: builtin/describe.c:241
#, c-format
msgid "annotated tag %s has no embedded name"
msgstr "注释 tag %s 没有嵌入å称"
-#: builtin/describe.c:240
+#: builtin/describe.c:243
#, c-format
msgid "tag '%s' is really '%s' here"
msgstr "tag '%s' 的确是在 '%s'"
-#: builtin/describe.c:267
+#: builtin/describe.c:270
#, c-format
msgid "Not a valid object name %s"
msgstr "ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„对象å %s"
-#: builtin/describe.c:270
+#: builtin/describe.c:273
#, c-format
msgid "%s is not a valid '%s' object"
msgstr "%s ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„ '%s' 对象"
-#: builtin/describe.c:287
+#: builtin/describe.c:290
#, c-format
msgid "no tag exactly matches '%s'"
msgstr "没有 tag å‡†ç¡®åŒ¹é… '%s'"
-#: builtin/describe.c:289
+#: builtin/describe.c:292
#, c-format
msgid "searching to describe %s\n"
msgstr "æœç´¢æè¿° %s\n"
-#: builtin/describe.c:329
+#: builtin/describe.c:332
#, c-format
msgid "finished search at %s\n"
msgstr "完æˆæœç´¢ %s\n"
-#: builtin/describe.c:353
+#: builtin/describe.c:359
#, c-format
msgid ""
"No annotated tags can describe '%s'.\n"
@@ -4108,7 +4618,7 @@ msgstr ""
"没有注释 tag 能æè¿° '%s'。\n"
"然而,有éžæ³¨é‡Š tag:å°è¯• --tags。"
-#: builtin/describe.c:357
+#: builtin/describe.c:363
#, c-format
msgid ""
"No tags can describe '%s'.\n"
@@ -4117,12 +4627,12 @@ msgstr ""
"没有注释 tag 能æè¿° '%s'。\n"
"å°è¯• --always,或者创建一些 tag。"
-#: builtin/describe.c:378
+#: builtin/describe.c:384
#, c-format
msgid "traversed %lu commits\n"
msgstr "å·²é历 %lu 个æ交\n"
-#: builtin/describe.c:381
+#: builtin/describe.c:387
#, c-format
msgid ""
"more than %i tags found; listed %i most recent\n"
@@ -4131,59 +4641,63 @@ msgstr ""
"å‘现多于 %i 个 tag,列出最近的 %i 个\n"
"在 %s 放弃æœç´¢\n"
-#: builtin/describe.c:403
+#: builtin/describe.c:409
msgid "find the tag that comes after the commit"
msgstr "寻找æ交之åŽçš„ tag(用于æè¿°æ交)"
-#: builtin/describe.c:404
+#: builtin/describe.c:410
msgid "debug search strategy on stderr"
msgstr "在标准错误上调试æœç´¢ç­–ç•¥"
-#: builtin/describe.c:405
-msgid "use any ref in .git/refs"
-msgstr "使用 .git/refs 里的任æ„引用"
+#: builtin/describe.c:411
+msgid "use any ref"
+msgstr "使用任æ„引用"
-#: builtin/describe.c:406
-msgid "use any tag in .git/refs/tags"
-msgstr "使用 .git/refs/tags é‡Œçš„ä»»æ„ tag"
+#: builtin/describe.c:412
+msgid "use any tag, even unannotated"
+msgstr "ä½¿ç”¨ä»»æ„ tag,å³ä½¿æœªå¸¦æ³¨è§£"
-#: builtin/describe.c:407
+#: builtin/describe.c:413
msgid "always use long format"
msgstr "始终使用长æ交å·æ ¼å¼"
-#: builtin/describe.c:410
+#: builtin/describe.c:414
+msgid "only follow first parent"
+msgstr "åªè·Ÿéšç¬¬ä¸€ä¸ªçˆ¶æ交"
+
+#: builtin/describe.c:417
msgid "only output exact matches"
msgstr "åªè¾“出精确匹é…"
-#: builtin/describe.c:412
+#: builtin/describe.c:419
msgid "consider <n> most recent tags (default: 10)"
msgstr "考虑最近 <n> 个 tags(默认:10)"
-#: builtin/describe.c:414
+#: builtin/describe.c:421
msgid "only consider tags matching <pattern>"
msgstr "åªè€ƒè™‘åŒ¹é… <模å¼> çš„ tags"
-#: builtin/describe.c:416 builtin/name-rev.c:238
+#: builtin/describe.c:423 builtin/name-rev.c:322
msgid "show abbreviated commit object as fallback"
msgstr "显示简写的æ交å·ä½œä¸ºåŽå¤‡"
-#: builtin/describe.c:417
+#: builtin/describe.c:424
msgid "mark"
msgstr "标记"
-#: builtin/describe.c:418
+#: builtin/describe.c:425
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
msgstr "若工作区è„(有å˜æ›´ï¼‰åœ¨ç»“尾添加 <标记>(默认:\"-dirty\")"
-#: builtin/describe.c:436
+#: builtin/describe.c:443
msgid "--long is incompatible with --abbrev=0"
msgstr "--long 与 --abbrev=0 ä¸å…¼å®¹"
-#: builtin/describe.c:462
+#: builtin/describe.c:469
msgid "No names found, cannot describe anything."
msgstr "没有å‘现å称,无法æ述任何东西。"
-#: builtin/describe.c:482
+#: builtin/describe.c:489
msgid "--dirty is incompatible with committishes"
msgstr "--dirty ä¸èƒ½ä¸Žæ交åŒæ—¶ä½¿ç”¨"
@@ -4192,31 +4706,26 @@ msgstr "--dirty ä¸èƒ½ä¸Žæ交åŒæ—¶ä½¿ç”¨"
msgid "'%s': not a regular file or symlink"
msgstr "'%s':ä¸æ˜¯ä¸€ä¸ªæ­£è§„文件或符å·é“¾æŽ¥"
-#: builtin/diff.c:228
+#: builtin/diff.c:230
#, c-format
msgid "invalid option: %s"
msgstr "无效选项:%s"
-#: builtin/diff.c:305
+#: builtin/diff.c:307
msgid "Not a git repository"
msgstr "ä¸æ˜¯ä¸€ä¸ª git 版本库"
-#: builtin/diff.c:348
+#: builtin/diff.c:350
#, c-format
msgid "invalid object '%s' given."
msgstr "æ供了无效对象 '%s'。"
-#: builtin/diff.c:353
-#, c-format
-msgid "more than %d trees given: '%s'"
-msgstr "æ供了超过 %d 个树对象:'%s'"
-
-#: builtin/diff.c:363
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
msgstr "æ供了超过两个数æ®ï¼ˆblob)对象:'%s'"
-#: builtin/diff.c:371
+#: builtin/diff.c:366
#, c-format
msgid "unhandled object '%s' given."
msgstr "æ供了无法处ç†çš„对象 '%s'。"
@@ -4225,39 +4734,39 @@ msgstr "æ供了无法处ç†çš„对象 '%s'。"
msgid "git fast-export [rev-list-opts]"
msgstr "git fast-export [rev-list-opts]"
-#: builtin/fast-export.c:646
+#: builtin/fast-export.c:666
msgid "show progress after <n> objects"
msgstr "在 <n> 个对象之åŽæ˜¾ç¤ºè¿›åº¦"
-#: builtin/fast-export.c:648
+#: builtin/fast-export.c:668
msgid "select handling of signed tags"
msgstr "选择如何处ç†ç­¾å tags"
-#: builtin/fast-export.c:651
+#: builtin/fast-export.c:671
msgid "select handling of tags that tag filtered objects"
msgstr "选择当 tag 指å‘被过滤时 tags 的处ç†æ–¹å¼"
-#: builtin/fast-export.c:654
+#: builtin/fast-export.c:674
msgid "Dump marks to this file"
msgstr "把标记存储到这个文件"
-#: builtin/fast-export.c:656
+#: builtin/fast-export.c:676
msgid "Import marks from this file"
msgstr "从这个文件导入标记"
-#: builtin/fast-export.c:658
+#: builtin/fast-export.c:678
msgid "Fake a tagger when tags lack one"
msgstr "当 tags 缺少标记者字段时,å‡è£…æ供一个"
-#: builtin/fast-export.c:660
+#: builtin/fast-export.c:680
msgid "Output full tree for each commit"
msgstr "æ¯æ¬¡æ交都输出整个树"
-#: builtin/fast-export.c:662
+#: builtin/fast-export.c:682
msgid "Use the done feature to terminate the stream"
msgstr "使用 done 功能æ¥ç»ˆæ­¢æµ"
-#: builtin/fast-export.c:663
+#: builtin/fast-export.c:683
msgid "Skip output of blob data"
msgstr "跳过数æ®å¯¹è±¡çš„输出"
@@ -4334,7 +4843,7 @@ msgstr "深化浅克隆的历å²"
msgid "convert to a complete repository"
msgstr "转æ¢ä¸ºä¸€ä¸ªå®Œæ•´çš„版本库"
-#: builtin/fetch.c:88 builtin/log.c:1119
+#: builtin/fetch.c:88 builtin/log.c:1177
msgid "dir"
msgstr "目录"
@@ -4346,77 +4855,77 @@ msgstr "在å­æ¨¡ç»„路径输出的å‰é¢åŠ ä¸Šæ­¤ç›®å½•"
msgid "default mode for recursion"
msgstr "递归的默认模å¼"
-#: builtin/fetch.c:204
+#: builtin/fetch.c:220
msgid "Couldn't find remote ref HEAD"
msgstr "无法å‘现远程 HEAD 引用"
-#: builtin/fetch.c:257
+#: builtin/fetch.c:273
#, c-format
msgid "object %s not found"
msgstr "对象 %s 未å‘现"
-#: builtin/fetch.c:262
+#: builtin/fetch.c:278
msgid "[up to date]"
msgstr "[最新]"
-#: builtin/fetch.c:276
+#: builtin/fetch.c:292
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
msgstr "! %-*s %-*s -> %s (在当å‰åˆ†æ”¯ä¸‹ä¸èƒ½èŽ·å–)"
-#: builtin/fetch.c:277 builtin/fetch.c:363
+#: builtin/fetch.c:293 builtin/fetch.c:379
msgid "[rejected]"
msgstr "[已拒ç»]"
-#: builtin/fetch.c:288
+#: builtin/fetch.c:304
msgid "[tag update]"
msgstr "[tagæ›´æ–°]"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: builtin/fetch.c:290 builtin/fetch.c:325 builtin/fetch.c:343
+#: builtin/fetch.c:306 builtin/fetch.c:341 builtin/fetch.c:359
msgid " (unable to update local ref)"
msgstr " (ä¸èƒ½æ›´æ–°æœ¬åœ°å¼•ç”¨ï¼‰"
-#: builtin/fetch.c:308
+#: builtin/fetch.c:324
msgid "[new tag]"
msgstr "[æ–°tag]"
-#: builtin/fetch.c:311
+#: builtin/fetch.c:327
msgid "[new branch]"
msgstr "[新分支]"
-#: builtin/fetch.c:314
+#: builtin/fetch.c:330
msgid "[new ref]"
msgstr "[新引用]"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "unable to update local ref"
msgstr "ä¸èƒ½æ›´æ–°æœ¬åœ°å¼•ç”¨"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "forced update"
msgstr "强制更新"
-#: builtin/fetch.c:365
+#: builtin/fetch.c:381
msgid "(non-fast-forward)"
msgstr "(éžå¿«è¿›å¼ï¼‰"
-#: builtin/fetch.c:396 builtin/fetch.c:688
+#: builtin/fetch.c:412 builtin/fetch.c:718
#, c-format
msgid "cannot open %s: %s\n"
msgstr "无法打开 %s:%s\n"
-#: builtin/fetch.c:405
+#: builtin/fetch.c:421
#, c-format
msgid "%s did not send all necessary objects\n"
msgstr "%s 未å‘é€æ‰€æœ‰å¿…须的对象\n"
-#: builtin/fetch.c:491
+#: builtin/fetch.c:520
#, c-format
msgid "From %.*s\n"
msgstr "æ¥è‡ª %.*s\n"
-#: builtin/fetch.c:502
+#: builtin/fetch.c:531
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
@@ -4426,87 +4935,87 @@ msgstr ""
" 'git remote prune %s' æ¥åˆ é™¤æ—§çš„ã€æœ‰å†²çªçš„分支"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: builtin/fetch.c:552
+#: builtin/fetch.c:581
#, c-format
msgid " (%s will become dangling)"
msgstr " (%s å°†æˆä¸ºæ‘‡æ‘†çŠ¶æ€ï¼‰"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: builtin/fetch.c:553
+#: builtin/fetch.c:582
#, c-format
msgid " (%s has become dangling)"
msgstr " (%s å·²æˆä¸ºæ‘‡æ‘†çŠ¶æ€ï¼‰"
-#: builtin/fetch.c:560
+#: builtin/fetch.c:589
msgid "[deleted]"
msgstr "[已删除]"
-#: builtin/fetch.c:561 builtin/remote.c:1055
+#: builtin/fetch.c:590 builtin/remote.c:1055
msgid "(none)"
msgstr "(无)"
-#: builtin/fetch.c:678
+#: builtin/fetch.c:708
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
msgstr "æ‹’ç»èŽ·å–到éžè£¸ç‰ˆæœ¬åº“的当å‰åˆ†æ”¯ %s"
-#: builtin/fetch.c:712
+#: builtin/fetch.c:742
#, c-format
msgid "Don't know how to fetch from %s"
msgstr "ä¸çŸ¥é“如何从 %s 获å–"
-#: builtin/fetch.c:789
+#: builtin/fetch.c:823
#, c-format
msgid "Option \"%s\" value \"%s\" is not valid for %s"
msgstr "选项 \"%s\" 的值 \"%s\" 对于 %s 是无效的"
-#: builtin/fetch.c:792
+#: builtin/fetch.c:826
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr "选项 \"%s\" 为 %s 所忽略\n"
-#: builtin/fetch.c:894
+#: builtin/fetch.c:928
#, c-format
msgid "Fetching %s\n"
msgstr "æ­£åœ¨èŽ·å– %s\n"
-#: builtin/fetch.c:896 builtin/remote.c:100
+#: builtin/fetch.c:930 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
msgstr "ä¸èƒ½èŽ·å– %s"
-#: builtin/fetch.c:915
+#: builtin/fetch.c:949
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:935
+#: builtin/fetch.c:969
msgid "You need to specify a tag name."
msgstr "您需è¦æŒ‡å®šä¸€ä¸ª tag å称。"
-#: builtin/fetch.c:981
+#: builtin/fetch.c:1015
msgid "--depth and --unshallow cannot be used together"
msgstr "--depth å’Œ --unshallow ä¸èƒ½åŒæ—¶ä½¿ç”¨"
-#: builtin/fetch.c:983
+#: builtin/fetch.c:1017
msgid "--unshallow on a complete repository does not make sense"
msgstr "对于一个完整的版本库,å‚æ•° --unshallow 没有æ„义"
-#: builtin/fetch.c:1002
+#: builtin/fetch.c:1036
msgid "fetch --all does not take a repository argument"
msgstr "fetch --all ä¸èƒ½å¸¦ä¸€ä¸ªç‰ˆæœ¬åº“å‚æ•°"
-#: builtin/fetch.c:1004
+#: builtin/fetch.c:1038
msgid "fetch --all does not make sense with refspecs"
msgstr "fetch --all 带引用表达å¼æ²¡æœ‰ä»»ä½•æ„义"
-#: builtin/fetch.c:1015
+#: builtin/fetch.c:1049
#, c-format
msgid "No such remote or remote group: %s"
msgstr "没有这样的远程或远程组:%s"
-#: builtin/fetch.c:1023
+#: builtin/fetch.c:1057
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr "获å–组并指定引用表达å¼æ²¡æœ‰æ„义"
@@ -4515,29 +5024,29 @@ msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
msgstr ""
"git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
-#: builtin/fmt-merge-msg.c:659 builtin/fmt-merge-msg.c:662 builtin/grep.c:701
-#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175
-#: builtin/tag.c:446 parse-options.h:133 parse-options.h:239
+#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:700
+#: builtin/merge.c:203 builtin/show-branch.c:655 builtin/show-ref.c:179
+#: builtin/tag.c:446 parse-options.h:133 parse-options.h:243
msgid "n"
msgstr "n"
-#: builtin/fmt-merge-msg.c:660
+#: builtin/fmt-merge-msg.c:664
msgid "populate log with at most <n> entries from shortlog"
msgstr "å‘æ交说明中最多å¤åˆ¶æŒ‡å®šæ¡ç›®ï¼ˆåˆå¹¶è€Œæ¥çš„æ交)的简短说明"
-#: builtin/fmt-merge-msg.c:663
+#: builtin/fmt-merge-msg.c:667
msgid "alias for --log (deprecated)"
msgstr "å‚æ•° --log 的别å(已弃用)"
-#: builtin/fmt-merge-msg.c:666
+#: builtin/fmt-merge-msg.c:670
msgid "text"
msgstr "文本"
-#: builtin/fmt-merge-msg.c:667
+#: builtin/fmt-merge-msg.c:671
msgid "use <text> as start of message"
msgstr "使用 <文本> 作为æ交说明的开始"
-#: builtin/fmt-merge-msg.c:668
+#: builtin/fmt-merge-msg.c:672
msgid "file to read from"
msgstr "从文件中读å–"
@@ -4674,226 +5183,221 @@ msgstr "git grep [选项] [-e] <模å¼> [<修订>...] [[--] <路径>...]"
msgid "grep: failed to create thread: %s"
msgstr "grep:无法创建线程:%s"
-#: builtin/grep.c:365
+#: builtin/grep.c:364
#, c-format
msgid "Failed to chdir: %s"
msgstr "无法切æ¢ç›®å½•ï¼š%s"
-#: builtin/grep.c:443 builtin/grep.c:478
+#: builtin/grep.c:442 builtin/grep.c:477
#, c-format
msgid "unable to read tree (%s)"
msgstr "无法读å–树(%s)"
-#: builtin/grep.c:493
+#: builtin/grep.c:492
#, c-format
msgid "unable to grep from object of type %s"
msgstr "无法抓å–æ¥è‡ªäºŽ %s 类型的对象"
-#: builtin/grep.c:551
+#: builtin/grep.c:550
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr "开关 `%c' 期望一个数字值"
-#: builtin/grep.c:568
+#: builtin/grep.c:567
#, c-format
msgid "cannot open '%s'"
msgstr "ä¸èƒ½æ‰“å¼€ '%s'"
-#: builtin/grep.c:643
+#: builtin/grep.c:642
msgid "search in index instead of in the work tree"
msgstr "在索引区æœç´¢è€Œä¸æ˜¯åœ¨å·¥ä½œåŒº"
-#: builtin/grep.c:645
+#: builtin/grep.c:644
msgid "find in contents not managed by git"
msgstr "在未被 git 管ç†çš„内容中查找"
# 译者:中文字符串拼接,å¯åˆ é™¤å‰å¯¼ç©ºæ ¼
-#: builtin/grep.c:647
+#: builtin/grep.c:646
msgid "search in both tracked and untracked files"
msgstr "在跟踪和未跟踪的文件中æœç´¢"
-#: builtin/grep.c:649
+#: builtin/grep.c:648
msgid "search also in ignored files"
msgstr "也在忽略的文件中æœç´¢"
-#: builtin/grep.c:652
+#: builtin/grep.c:651
msgid "show non-matching lines"
msgstr "显示未匹é…çš„è¡Œ"
-#: builtin/grep.c:654
+#: builtin/grep.c:653
msgid "case insensitive matching"
msgstr "ä¸åŒºåˆ†å¤§å°å†™åŒ¹é…"
-#: builtin/grep.c:656
+#: builtin/grep.c:655
msgid "match patterns only at word boundaries"
msgstr "åªåœ¨å•è¯è¾¹ç•ŒåŒ¹é…模å¼"
-#: builtin/grep.c:658
+#: builtin/grep.c:657
msgid "process binary files as text"
msgstr "把二进制文件当åšæ–‡æœ¬å¤„ç†"
-#: builtin/grep.c:660
+#: builtin/grep.c:659
msgid "don't match patterns in binary files"
msgstr "ä¸åœ¨äºŒè¿›åˆ¶æ–‡ä»¶ä¸­åŒ¹é…模å¼"
-#: builtin/grep.c:663
+#: builtin/grep.c:662
msgid "descend at most <depth> levels"
msgstr "最多以指定的深度å‘下寻找"
-#: builtin/grep.c:667
+#: builtin/grep.c:666
msgid "use extended POSIX regular expressions"
msgstr "使用扩展的 POSIX 正则表达å¼"
-#: builtin/grep.c:670
+#: builtin/grep.c:669
msgid "use basic POSIX regular expressions (default)"
msgstr "使用基本的 POSIX 正则表达å¼ï¼ˆé»˜è®¤ï¼‰"
-#: builtin/grep.c:673
+#: builtin/grep.c:672
msgid "interpret patterns as fixed strings"
msgstr "把模å¼è§£æžä¸ºå›ºå®šçš„字符串"
-#: builtin/grep.c:676
+#: builtin/grep.c:675
msgid "use Perl-compatible regular expressions"
msgstr "使用 Perl 兼容的正则表达å¼"
-#: builtin/grep.c:679
+#: builtin/grep.c:678
msgid "show line numbers"
msgstr "显示行å·"
-#: builtin/grep.c:680
+#: builtin/grep.c:679
msgid "don't show filenames"
msgstr "ä¸æ˜¾ç¤ºæ–‡ä»¶å"
-#: builtin/grep.c:681
+#: builtin/grep.c:680
msgid "show filenames"
msgstr "显示文件å"
-#: builtin/grep.c:683
+#: builtin/grep.c:682
msgid "show filenames relative to top directory"
msgstr "显示相对于顶级目录的文件å"
-#: builtin/grep.c:685
+#: builtin/grep.c:684
msgid "show only filenames instead of matching lines"
msgstr "åªæ˜¾ç¤ºæ–‡ä»¶å而ä¸æ˜¾ç¤ºåŒ¹é…çš„è¡Œ"
-#: builtin/grep.c:687
+#: builtin/grep.c:686
msgid "synonym for --files-with-matches"
msgstr "å’Œ --files-with-matches åŒä¹‰"
-#: builtin/grep.c:690
+#: builtin/grep.c:689
msgid "show only the names of files without match"
msgstr "åªæ˜¾ç¤ºæœªåŒ¹é…的文件å"
-#: builtin/grep.c:692
+#: builtin/grep.c:691
msgid "print NUL after filenames"
msgstr "在文件ååŽè¾“出 NUL 字符"
-#: builtin/grep.c:694
+#: builtin/grep.c:693
msgid "show the number of matches instead of matching lines"
msgstr "显示总匹é…行数,而ä¸æ˜¾ç¤ºåŒ¹é…çš„è¡Œ"
-#: builtin/grep.c:695
+#: builtin/grep.c:694
msgid "highlight matches"
msgstr "高亮显示匹é…项"
-#: builtin/grep.c:697
+#: builtin/grep.c:696
msgid "print empty line between matches from different files"
msgstr "在ä¸åŒæ–‡ä»¶çš„匹é…项之间打å°ç©ºè¡Œ"
-#: builtin/grep.c:699
+#: builtin/grep.c:698
msgid "show filename only once above matches from same file"
msgstr "åªåœ¨åŒä¸€æ–‡ä»¶çš„匹é…项的上é¢æ˜¾ç¤ºä¸€æ¬¡æ–‡ä»¶å"
-#: builtin/grep.c:702
+#: builtin/grep.c:701
msgid "show <n> context lines before and after matches"
msgstr "显示匹é…项å‰åŽçš„ <n> 行上下文"
-#: builtin/grep.c:705
+#: builtin/grep.c:704
msgid "show <n> context lines before matches"
msgstr "显示匹é…é¡¹å‰ <n> 行上下文"
-#: builtin/grep.c:707
+#: builtin/grep.c:706
msgid "show <n> context lines after matches"
msgstr "显示匹é…é¡¹åŽ <n> 行上下文"
-#: builtin/grep.c:708
+#: builtin/grep.c:707
msgid "shortcut for -C NUM"
msgstr "å¿«æ·é”® -C æ•°å­—"
-#: builtin/grep.c:711
+#: builtin/grep.c:710
msgid "show a line with the function name before matches"
msgstr "在匹é…çš„å‰é¢æ˜¾ç¤ºä¸€è¡Œå‡½æ•°å"
-#: builtin/grep.c:713
+#: builtin/grep.c:712
msgid "show the surrounding function"
msgstr "显示所在函数的å‰åŽå†…容"
-#: builtin/grep.c:716
+#: builtin/grep.c:715
msgid "read patterns from file"
msgstr "从文件读å–模å¼"
-#: builtin/grep.c:718
+#: builtin/grep.c:717
msgid "match <pattern>"
msgstr "åŒ¹é… <模å¼>"
-#: builtin/grep.c:720
+#: builtin/grep.c:719
msgid "combine patterns specified with -e"
msgstr "组åˆç”¨ -e å‚数设定的模å¼"
-#: builtin/grep.c:732
+#: builtin/grep.c:731
msgid "indicate hit with exit status without output"
msgstr "ä¸è¾“出,而用退出ç æ ‡è¯†å‘½ä¸­çŠ¶æ€"
-#: builtin/grep.c:734
+#: builtin/grep.c:733
msgid "show only matches from files that match all patterns"
msgstr "åªæ˜¾ç¤ºåŒ¹é…所有模å¼çš„文件中的匹é…"
-#: builtin/grep.c:736
+#: builtin/grep.c:735
msgid "show parse tree for grep expression"
msgstr "显示 grep 表达å¼çš„解æžæ ‘"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "pager"
msgstr "分页"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "show matching files in the pager"
msgstr "分页显示匹é…的文件"
-#: builtin/grep.c:743
+#: builtin/grep.c:742
msgid "allow calling of grep(1) (ignored by this build)"
msgstr "å…许调用 grep(1)(本次构建忽略)"
-#: builtin/grep.c:744 builtin/show-ref.c:184
+#: builtin/grep.c:743 builtin/show-ref.c:188
msgid "show usage"
msgstr "显示用法"
-#: builtin/grep.c:811
+#: builtin/grep.c:810
msgid "no pattern given."
msgstr "未æ供模å¼åŒ¹é…。"
-#: builtin/grep.c:825
-#, c-format
-msgid "bad object %s"
-msgstr "å对象 %s"
-
-#: builtin/grep.c:868
+#: builtin/grep.c:865
msgid "--open-files-in-pager only works on the worktree"
msgstr "--open-files-in-pager 仅用于工作区"
-#: builtin/grep.c:891
+#: builtin/grep.c:888
msgid "--cached or --untracked cannot be used with --no-index."
msgstr "--cached 或 --untracked ä¸èƒ½ä¸Ž --no-index åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/grep.c:896
+#: builtin/grep.c:893
msgid "--no-index or --untracked cannot be used with revs."
msgstr "--no-index 或 --untracked ä¸èƒ½å’Œç‰ˆæœ¬åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/grep.c:899
+#: builtin/grep.c:896
msgid "--[no-]exclude-standard cannot be used for tracked contents."
msgstr "--[no-]exclude-standard ä¸èƒ½ç”¨äºŽå·²è·Ÿè¸ªå†…容。"
-#: builtin/grep.c:907
+#: builtin/grep.c:904
msgid "both --cached and trees are given."
msgstr "åŒæ—¶ç»™å‡ºäº† --cached 和树对象。"
@@ -4933,10 +5437,14 @@ msgstr "原样存储文件ä¸ä½¿ç”¨è¿‡æ»¤å™¨"
msgid "process file as it were from this path"
msgstr "处ç†æ–‡ä»¶å¹¶å‡è®¾å…¶æ¥è‡ªäºŽæ­¤è·¯å¾„"
-#: builtin/help.c:42
+#: builtin/help.c:41
msgid "print all available commands"
msgstr "打å°æ‰€æœ‰å¯ç”¨çš„命令"
+#: builtin/help.c:42
+msgid "print list of useful guides"
+msgstr "显示有用的指å—列表"
+
#: builtin/help.c:43
msgid "show man page"
msgstr "显示 man 手册"
@@ -4950,8 +5458,8 @@ msgid "show info page"
msgstr "显示 info 手册"
#: builtin/help.c:52
-msgid "git help [--all] [--man|--web|--info] [command]"
-msgstr "git help [--all] [--man|--web|--info] [命令]"
+msgid "git help [--all] [--guides] [--man|--web|--info] [command]"
+msgstr "git help [--all] [--guides] [--man|--web|--info] [命令]"
#: builtin/help.c:64
#, c-format
@@ -5007,290 +5515,322 @@ msgstr "没有 man 查看器处ç†æ­¤è¯·æ±‚"
msgid "no info viewer handled the request"
msgstr "没有 info 查看器处ç†æ­¤è¯·æ±‚"
-#: builtin/help.c:429 builtin/help.c:436
+#: builtin/help.c:420
+msgid "Defining attributes per path"
+msgstr "定义路径的属性"
+
+#: builtin/help.c:421
+msgid "A Git glossary"
+msgstr "Git è¯æ±‡è¡¨"
+
+#: builtin/help.c:422
+msgid "Specifies intentionally untracked files to ignore"
+msgstr "忽略指定的未跟踪文件"
+
+#: builtin/help.c:423
+msgid "Defining submodule properties"
+msgstr "定义å­æ¨¡ç»„属性"
+
+#: builtin/help.c:424
+msgid "Specifying revisions and ranges for Git"
+msgstr "指定 Git 的版本和版本范围"
+
+#: builtin/help.c:425
+msgid "A tutorial introduction to Git (for version 1.5.1 or newer)"
+msgstr "一个 Git 教程(针对 1.5.1 或更新版本)"
+
+#: builtin/help.c:426
+msgid "An overview of recommended workflows with Git"
+msgstr "Git 推è的工作æµæ¦‚览"
+
+#: builtin/help.c:438
+msgid "The common Git guides are:\n"
+msgstr "最常用的 Git å‘导有:\n"
+
+#: builtin/help.c:460 builtin/help.c:476
#, c-format
msgid "usage: %s%s"
msgstr "用法:%s%s"
-#: builtin/help.c:452
+#: builtin/help.c:492
#, c-format
msgid "`git %s' is aliased to `%s'"
msgstr "`git %s' 是 `%s' 的别å"
-#: builtin/index-pack.c:170
+#: builtin/index-pack.c:184
#, c-format
msgid "object type mismatch at %s"
msgstr "%s 的对象类型ä¸åŒ¹é…"
-#: builtin/index-pack.c:190
+#: builtin/index-pack.c:204
msgid "object of unexpected type"
msgstr "æ„外的类型的对象"
-#: builtin/index-pack.c:227
+#: builtin/index-pack.c:244
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
msgstr[0] "无法填充 %d 字节"
msgstr[1] "无法填充 %d 字节"
-#: builtin/index-pack.c:237
+#: builtin/index-pack.c:254
msgid "early EOF"
msgstr "过早的文件结æŸç¬¦ï¼ˆEOF)"
-#: builtin/index-pack.c:238
+#: builtin/index-pack.c:255
msgid "read error on input"
msgstr "输入上的读错误"
-#: builtin/index-pack.c:250
+#: builtin/index-pack.c:267
msgid "used more bytes than were available"
msgstr "用掉了超过å¯ç”¨çš„字节"
-#: builtin/index-pack.c:257
+#: builtin/index-pack.c:274
msgid "pack too large for current definition of off_t"
msgstr "åŒ…å¤ªå¤§è¶…è¿‡äº†å½“å‰ off_t 的定义"
-#: builtin/index-pack.c:273
+#: builtin/index-pack.c:290
#, c-format
msgid "unable to create '%s'"
msgstr "ä¸èƒ½åˆ›å»º '%s'"
-#: builtin/index-pack.c:278
+#: builtin/index-pack.c:295
#, c-format
msgid "cannot open packfile '%s'"
msgstr "无法打开包文件 '%s'"
-#: builtin/index-pack.c:292
+#: builtin/index-pack.c:309
msgid "pack signature mismatch"
msgstr "包签åä¸åŒ¹é…"
-#: builtin/index-pack.c:294
+#: builtin/index-pack.c:311
#, c-format
msgid "pack version %<PRIu32> unsupported"
msgstr "ä¸æ”¯æŒåŒ…版本 %<PRIu32>"
-#: builtin/index-pack.c:312
+#: builtin/index-pack.c:329
#, c-format
msgid "pack has bad object at offset %lu: %s"
msgstr "包中有错误的对象ä½äºŽ %lu:%s"
-#: builtin/index-pack.c:434
+#: builtin/index-pack.c:451
#, c-format
msgid "inflate returned %d"
msgstr "解压缩返回 %d"
-#: builtin/index-pack.c:483
+#: builtin/index-pack.c:500
msgid "offset value overflow for delta base object"
msgstr "å移值覆盖了 delta 基准对象"
-#: builtin/index-pack.c:491
+#: builtin/index-pack.c:508
msgid "delta base offset is out of bound"
msgstr "delta 基准å移越界"
-#: builtin/index-pack.c:499
+#: builtin/index-pack.c:516
#, c-format
msgid "unknown object type %d"
msgstr "未知对象类型 %d"
-#: builtin/index-pack.c:530
+#: builtin/index-pack.c:547
msgid "cannot pread pack file"
msgstr "无法读å–包文件"
-#: builtin/index-pack.c:532
+#: builtin/index-pack.c:549
#, 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:558
+#: builtin/index-pack.c:575
msgid "serious inflate inconsistency"
msgstr "解压缩严é‡çš„ä¸ä¸€è‡´"
-#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678
-#: builtin/index-pack.c:712 builtin/index-pack.c:721
+#: builtin/index-pack.c:666 builtin/index-pack.c:672 builtin/index-pack.c:695
+#: builtin/index-pack.c:729 builtin/index-pack.c:738
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "å‘现 %s 出现 SHA1 冲çªï¼"
-#: builtin/index-pack.c:652 builtin/pack-objects.c:170
+#: builtin/index-pack.c:669 builtin/pack-objects.c:170
#: builtin/pack-objects.c:262
#, c-format
msgid "unable to read %s"
msgstr "ä¸èƒ½è¯» %s"
-#: builtin/index-pack.c:718
+#: builtin/index-pack.c:735
#, c-format
msgid "cannot read existing object %s"
msgstr "ä¸èƒ½è¯»å–现存对象 %s"
-#: builtin/index-pack.c:732
+#: builtin/index-pack.c:749
#, c-format
msgid "invalid blob object %s"
msgstr "无效的数æ®ï¼ˆblob)对象 %s"
-#: builtin/index-pack.c:747
+#: builtin/index-pack.c:763
#, c-format
msgid "invalid %s"
msgstr "无效的 %s"
-#: builtin/index-pack.c:749
+#: builtin/index-pack.c:766
msgid "Error in object"
msgstr "对象中出错"
-#: builtin/index-pack.c:751
+#: builtin/index-pack.c:768
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr "%s 的所有å­å¯¹è±¡å¹¶éžéƒ½å¯è¾¾"
-#: builtin/index-pack.c:821 builtin/index-pack.c:847
+#: builtin/index-pack.c:838 builtin/index-pack.c:868
msgid "failed to apply delta"
msgstr "无法应用 delta"
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Receiving objects"
msgstr "接收对象中"
-#: builtin/index-pack.c:986
+#: builtin/index-pack.c:1009
msgid "Indexing objects"
msgstr "索引对象中"
-#: builtin/index-pack.c:1012
+#: builtin/index-pack.c:1035
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "包冲çªï¼ˆSHA1 ä¸åŒ¹é…)"
-#: builtin/index-pack.c:1017
+#: builtin/index-pack.c:1040
msgid "cannot fstat packfile"
msgstr "ä¸èƒ½æžšä¸¾åŒ…文件状æ€"
-#: builtin/index-pack.c:1020
+#: builtin/index-pack.c:1043
msgid "pack has junk at the end"
msgstr "包的结尾有垃圾数æ®"
-#: builtin/index-pack.c:1031
+#: builtin/index-pack.c:1054
msgid "confusion beyond insanity in parse_pack_objects()"
msgstr "parse_pack_objects() 中é‡åˆ°ä¸å¯ç†å–»çš„问题"
-#: builtin/index-pack.c:1054
+#: builtin/index-pack.c:1077
msgid "Resolving deltas"
msgstr "å¤„ç† delta 中"
-#: builtin/index-pack.c:1064
+#: builtin/index-pack.c:1087
#, c-format
msgid "unable to create thread: %s"
msgstr "ä¸èƒ½åˆ›å»ºçº¿ç¨‹ï¼š%s"
-#: builtin/index-pack.c:1106
+#: builtin/index-pack.c:1129
msgid "confusion beyond insanity"
msgstr "ä¸å¯ç†å–»"
-#: builtin/index-pack.c:1112
+#: builtin/index-pack.c:1137
#, c-format
msgid "completed with %d local objects"
msgstr "å®Œæˆ %d 个本地对象"
-#: builtin/index-pack.c:1121
+#: builtin/index-pack.c:1147
#, c-format
msgid "Unexpected tail checksum for %s (disk corruption?)"
msgstr "对 %s 的尾部校验出现æ„外(ç£ç›˜æŸå?)"
-#: builtin/index-pack.c:1125
+#: builtin/index-pack.c:1151
#, 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:1150
+#: builtin/index-pack.c:1176
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr "ä¸èƒ½åŽ‹ç¼©é™„加对象(%d)"
-#: builtin/index-pack.c:1229
+#: builtin/index-pack.c:1255
#, c-format
msgid "local object %s is corrupt"
msgstr "本地对象 %s å·²æŸå"
-#: builtin/index-pack.c:1253
+#: builtin/index-pack.c:1279
msgid "error while closing pack file"
msgstr "关闭包文件时出错"
-#: builtin/index-pack.c:1266
+#: builtin/index-pack.c:1292
#, c-format
msgid "cannot write keep file '%s'"
msgstr "无法写ä¿ç•™æ–‡ä»¶ '%s'"
-#: builtin/index-pack.c:1274
+#: builtin/index-pack.c:1300
#, c-format
msgid "cannot close written keep file '%s'"
msgstr "无法关闭ä¿ç•™æ–‡ä»¶ '%s'"
-#: builtin/index-pack.c:1287
+#: builtin/index-pack.c:1313
msgid "cannot store pack file"
msgstr "无法存储包文件"
-#: builtin/index-pack.c:1298
+#: builtin/index-pack.c:1324
msgid "cannot store index file"
msgstr "无法存储索引文件"
-#: builtin/index-pack.c:1331
+#: builtin/index-pack.c:1357
#, c-format
msgid "bad pack.indexversion=%<PRIu32>"
msgstr "åçš„ pack.indexversion=%<PRIu32>"
-#: builtin/index-pack.c:1337
+#: builtin/index-pack.c:1363
#, c-format
msgid "invalid number of threads specified (%d)"
msgstr "指定的线程数无效(%d)"
-#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#: builtin/index-pack.c:1367 builtin/index-pack.c:1545
#, c-format
msgid "no threads support, ignoring %s"
msgstr "没有线程支æŒï¼Œå¿½ç•¥ %s"
-#: builtin/index-pack.c:1399
+#: builtin/index-pack.c:1425
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr "无法打开现存包文件 '%s'"
-#: builtin/index-pack.c:1401
+#: builtin/index-pack.c:1427
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
msgstr "无法为 %s 打开包索引文件"
-#: builtin/index-pack.c:1448
+#: builtin/index-pack.c:1474
#, 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:1455
+#: builtin/index-pack.c:1481
#, 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:1482
+#: builtin/index-pack.c:1509
msgid "Cannot come back to cwd"
msgstr "无法返回当å‰å·¥ä½œç›®å½•"
-#: builtin/index-pack.c:1526 builtin/index-pack.c:1529
-#: builtin/index-pack.c:1541 builtin/index-pack.c:1545
+#: builtin/index-pack.c:1557 builtin/index-pack.c:1560
+#: builtin/index-pack.c:1572 builtin/index-pack.c:1576
#, c-format
msgid "bad %s"
msgstr "错误选项 %s"
-#: builtin/index-pack.c:1559
+#: builtin/index-pack.c:1590
msgid "--fix-thin cannot be used without --stdin"
msgstr "--fix-thin ä¸èƒ½å’Œ --stdin åŒæ—¶ä½¿ç”¨"
-#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
+#: builtin/index-pack.c:1594 builtin/index-pack.c:1604
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr "包å '%s' 没有以 '.pack' 结尾"
-#: builtin/index-pack.c:1582
+#: builtin/index-pack.c:1613
msgid "--verify with no packfile name given"
msgstr "--verify 没有æ供包åå‚æ•°"
@@ -5427,7 +5967,7 @@ msgstr "æƒé™"
msgid "specify that the git repository is to be shared amongst several users"
msgstr "指定 git 版本库是多个用户之间共享的"
-#: builtin/init-db.c:493 builtin/prune-packed.c:77
+#: builtin/init-db.c:493 builtin/prune-packed.c:75
msgid "be quiet"
msgstr "ä¿æŒå®‰é™"
@@ -5459,345 +5999,353 @@ msgstr "ä¸èƒ½è®¿é—®å½“å‰å·¥ä½œç›®å½•"
msgid "Cannot access work tree '%s'"
msgstr "ä¸èƒ½è®¿é—®å·¥ä½œåŒº '%s'"
-#: builtin/log.c:39
-msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
-msgstr "git log [<选项>] [<从>..<到>] [[--] <路径>...]\n"
+#: builtin/log.c:41
+msgid "git log [<options>] [<revision range>] [[--] <path>...]\n"
+msgstr "git log [<选项>] [<版本范围>] [[--] <路径>...]\n"
-#: builtin/log.c:40
+#: builtin/log.c:42
msgid " or: git show [options] <object>..."
msgstr " 或者:git show [选项] <对象>..."
-#: builtin/log.c:102
+#: builtin/log.c:124
msgid "suppress diff output"
msgstr "ä¸æ˜¾ç¤ºå·®å¼‚输出"
-#: builtin/log.c:103
+#: builtin/log.c:125
msgid "show source"
msgstr "显示æº"
-#: builtin/log.c:104
+#: builtin/log.c:126
msgid "Use mail map file"
msgstr "使用邮件映射文件"
-#: builtin/log.c:105
+#: builtin/log.c:127
msgid "decorate options"
msgstr "修饰选项"
-#: builtin/log.c:198
+#: builtin/log.c:230
#, c-format
msgid "Final output: %d %s\n"
msgstr "最终输出:%d %s\n"
-#: builtin/log.c:419 builtin/log.c:511
+#: builtin/log.c:453 builtin/log.c:545
#, c-format
msgid "Could not read object %s"
msgstr "ä¸èƒ½è¯»å–对象 %s"
-#: builtin/log.c:535
+#: builtin/log.c:569
#, c-format
msgid "Unknown type: %d"
msgstr "未知类型:%d"
-#: builtin/log.c:627
+#: builtin/log.c:669
msgid "format.headers without value"
msgstr "format.headers 没有值"
-#: builtin/log.c:701
+#: builtin/log.c:751
msgid "name of output directory is too long"
msgstr "输出目录å太长"
-#: builtin/log.c:717
+#: builtin/log.c:767
#, c-format
msgid "Cannot open patch file %s"
msgstr "无法打开补ä¸æ–‡ä»¶ %s"
-#: builtin/log.c:731
+#: builtin/log.c:781
msgid "Need exactly one range."
msgstr "åªéœ€è¦ä¸€ä¸ªèŒƒå›´ã€‚"
-#: builtin/log.c:739
+#: builtin/log.c:789
msgid "Not a range."
msgstr "ä¸æ˜¯ä¸€ä¸ªèŒƒå›´ã€‚"
-#: builtin/log.c:812
+#: builtin/log.c:891
msgid "Cover letter needs email format"
msgstr "ä¿¡å°éœ€è¦é‚®ä»¶åœ°å€æ ¼å¼"
-#: builtin/log.c:885
+#: builtin/log.c:967
#, c-format
msgid "insane in-reply-to: %s"
msgstr "ä¸æ­£å¸¸çš„ in-reply-to:%s"
-#: builtin/log.c:913
+#: builtin/log.c:995
msgid "git format-patch [options] [<since> | <revision range>]"
msgstr "git format-patch [选项] [<从> | <修订集范围>]"
-#: builtin/log.c:958
+#: builtin/log.c:1040
msgid "Two output directories?"
msgstr "两个输出目录?"
-#: builtin/log.c:1097
+#: builtin/log.c:1155
msgid "use [PATCH n/m] even with a single patch"
msgstr "使用 [PATCH n/m],å³ä½¿åªæœ‰ä¸€ä¸ªè¡¥ä¸"
-#: builtin/log.c:1100
+#: builtin/log.c:1158
msgid "use [PATCH] even with multiple patches"
msgstr "使用 [PATCH],å³ä½¿æœ‰å¤šä¸ªè¡¥ä¸"
-#: builtin/log.c:1104
+#: builtin/log.c:1162
msgid "print patches to standard out"
msgstr "打å°è¡¥ä¸åˆ°æ ‡å‡†è¾“出"
-#: builtin/log.c:1106
+#: builtin/log.c:1164
msgid "generate a cover letter"
msgstr "生æˆä¸€å°é™„ä¿¡"
-#: builtin/log.c:1108
+#: builtin/log.c:1166
msgid "use simple number sequence for output file names"
msgstr "使用简å•çš„æ•°å­—åºåˆ—作为输出文件å"
-#: builtin/log.c:1109
+#: builtin/log.c:1167
msgid "sfx"
msgstr "åŽç¼€"
-#: builtin/log.c:1110
+#: builtin/log.c:1168
msgid "use <sfx> instead of '.patch'"
msgstr "使用 <åŽç¼€> 代替 '.patch'"
-#: builtin/log.c:1112
+#: builtin/log.c:1170
msgid "start numbering patches at <n> instead of 1"
msgstr "è¡¥ä¸ä»¥ <n> 开始编å·ï¼Œè€Œä¸æ˜¯1"
-#: builtin/log.c:1114
+#: builtin/log.c:1172
msgid "mark the series as Nth re-roll"
msgstr "标记补ä¸ç³»åˆ—是第几次é‡åˆ¶"
-#: builtin/log.c:1116
+#: builtin/log.c:1174
msgid "Use [<prefix>] instead of [PATCH]"
msgstr "使用 [<å‰ç¼€>] 代替 [PATCH]"
-#: builtin/log.c:1119
+#: builtin/log.c:1177
msgid "store resulting files in <dir>"
msgstr "把结果文件存储在 <dir>"
-#: builtin/log.c:1122
+#: builtin/log.c:1180
msgid "don't strip/add [PATCH]"
msgstr "ä¸åˆ é™¤/添加 [PATCH]"
-#: builtin/log.c:1125
+#: builtin/log.c:1183
msgid "don't output binary diffs"
msgstr "ä¸è¾“出二进制差异"
-#: builtin/log.c:1127
+#: builtin/log.c:1185
msgid "don't include a patch matching a commit upstream"
msgstr "ä¸åŒ…å«å·²åœ¨ä¸Šæ¸¸æ交中的补ä¸"
-#: builtin/log.c:1129
+#: builtin/log.c:1187
msgid "show patch format instead of default (patch + stat)"
msgstr "显示纯补ä¸æ ¼å¼è€Œéžé»˜è®¤çš„(补ä¸+状æ€ï¼‰"
-#: builtin/log.c:1131
+#: builtin/log.c:1189
msgid "Messaging"
msgstr "邮件å‘é€"
-#: builtin/log.c:1132
+#: builtin/log.c:1190
msgid "header"
msgstr "header"
-#: builtin/log.c:1133
+#: builtin/log.c:1191
msgid "add email header"
msgstr "添加邮件头"
-#: builtin/log.c:1134 builtin/log.c:1136
+#: builtin/log.c:1192 builtin/log.c:1194
msgid "email"
msgstr "邮件地å€"
-#: builtin/log.c:1134
+#: builtin/log.c:1192
msgid "add To: header"
msgstr "添加收件人"
-#: builtin/log.c:1136
+#: builtin/log.c:1194
msgid "add Cc: header"
msgstr "添加抄é€"
-#: builtin/log.c:1138
+#: builtin/log.c:1196
+msgid "ident"
+msgstr "ident"
+
+#: builtin/log.c:1197
+msgid "set From address to <ident> (or committer ident if absent)"
+msgstr "设置 From 地å€ä¸º <ident>(如若ä¸æ供,用æ交者IDåšä¸ºåœ°å€ï¼‰"
+
+#: builtin/log.c:1199
msgid "message-id"
msgstr "message-id"
-#: builtin/log.c:1139
+#: builtin/log.c:1200
msgid "make first mail a reply to <message-id>"
msgstr "使第一å°é‚®ä»¶ä½œä¸ºå¯¹ <message-id> 的回å¤"
-#: builtin/log.c:1140 builtin/log.c:1143
+#: builtin/log.c:1201 builtin/log.c:1204
msgid "boundary"
msgstr "边界"
-#: builtin/log.c:1141
+#: builtin/log.c:1202
msgid "attach the patch"
msgstr "附件方å¼æ·»åŠ è¡¥ä¸"
-#: builtin/log.c:1144
+#: builtin/log.c:1205
msgid "inline the patch"
msgstr "内è”显示补ä¸"
-#: builtin/log.c:1148
+#: builtin/log.c:1209
msgid "enable message threading, styles: shallow, deep"
msgstr "å¯ç”¨é‚®ä»¶çº¿ç´¢ï¼Œé£Žæ ¼ï¼šæµ…,深"
-#: builtin/log.c:1150
+#: builtin/log.c:1211
msgid "signature"
msgstr "ç­¾å"
-#: builtin/log.c:1151
+#: builtin/log.c:1212
msgid "add a signature"
msgstr "添加一个签å"
-#: builtin/log.c:1153
+#: builtin/log.c:1214
msgid "don't print the patch filenames"
msgstr "ä¸è¦æ‰“å°è¡¥ä¸æ–‡ä»¶å"
-#: builtin/log.c:1202
+#: builtin/log.c:1288
#, c-format
-msgid "bogus committer info %s"
-msgstr "虚å‡çš„æäº¤è€…ä¿¡æ¯ %s"
+msgid "invalid ident line: %s"
+msgstr "包å«æ— æ•ˆçš„身份标识:%s"
-#: builtin/log.c:1247
+#: builtin/log.c:1303
msgid "-n and -k are mutually exclusive."
msgstr "-n 和 -k 互斥。"
-#: builtin/log.c:1249
+#: builtin/log.c:1305
msgid "--subject-prefix and -k are mutually exclusive."
msgstr "--subject-prefix 和 -k 互斥。"
-#: builtin/log.c:1257
+#: builtin/log.c:1313
msgid "--name-only does not make sense"
msgstr "--name-only æ— æ„义"
-#: builtin/log.c:1259
+#: builtin/log.c:1315
msgid "--name-status does not make sense"
msgstr "--name-status æ— æ„义"
-#: builtin/log.c:1261
+#: builtin/log.c:1317
msgid "--check does not make sense"
msgstr "--check æ— æ„义"
-#: builtin/log.c:1284
+#: builtin/log.c:1340
msgid "standard output, or directory, which one?"
msgstr "标准输出或目录,哪一个?"
-#: builtin/log.c:1286
+#: builtin/log.c:1342
#, c-format
msgid "Could not create directory '%s'"
msgstr "ä¸èƒ½åˆ›å»ºç›®å½• '%s'"
-#: builtin/log.c:1439
+#: builtin/log.c:1490
msgid "Failed to create output files"
msgstr "无法创建输出文件"
-#: builtin/log.c:1488
+#: builtin/log.c:1539
msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
msgstr "git cherry [-v] [<上游> [<头> [<é™åˆ¶>]]]"
-#: builtin/log.c:1543
+#: builtin/log.c:1594
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
msgstr "ä¸èƒ½æ‰¾åˆ°è·Ÿè¸ªçš„远程分支,请手工指定 <upstream>。\n"
-#: builtin/log.c:1556 builtin/log.c:1558 builtin/log.c:1570
+#: builtin/log.c:1607 builtin/log.c:1609 builtin/log.c:1621
#, c-format
msgid "Unknown commit %s"
msgstr "未知æ交 %s"
-#: builtin/ls-files.c:409
+#: builtin/ls-files.c:408
msgid "git ls-files [options] [<file>...]"
msgstr "git ls-files [选项] [<文件>...]"
-#: builtin/ls-files.c:466
+#: builtin/ls-files.c:465
msgid "identify the file status with tags"
msgstr "用标签标识文件的状æ€"
-#: builtin/ls-files.c:468
+#: builtin/ls-files.c:467
msgid "use lowercase letters for 'assume unchanged' files"
msgstr "使用å°å†™å­—æ¯è¡¨ç¤º 'å‡è®¾æœªæ”¹å˜çš„' 文件"
-#: builtin/ls-files.c:470
+#: builtin/ls-files.c:469
msgid "show cached files in the output (default)"
msgstr "显示缓存的文件(默认)"
-#: builtin/ls-files.c:472
+#: builtin/ls-files.c:471
msgid "show deleted files in the output"
msgstr "显示已删除的文件"
-#: builtin/ls-files.c:474
+#: builtin/ls-files.c:473
msgid "show modified files in the output"
msgstr "显示已修改的文件"
-#: builtin/ls-files.c:476
+#: builtin/ls-files.c:475
msgid "show other files in the output"
msgstr "显示其它文件"
-#: builtin/ls-files.c:478
+#: builtin/ls-files.c:477
msgid "show ignored files in the output"
msgstr "显示忽略的文件"
-#: builtin/ls-files.c:481
+#: builtin/ls-files.c:480
msgid "show staged contents' object name in the output"
msgstr "显示暂存区内容的对象å称"
-#: builtin/ls-files.c:483
+#: builtin/ls-files.c:482
msgid "show files on the filesystem that need to be removed"
msgstr "显示文件系统需è¦åˆ é™¤çš„文件"
-#: builtin/ls-files.c:485
+#: builtin/ls-files.c:484
msgid "show 'other' directories' name only"
msgstr "åªæ˜¾ç¤ºâ€œå…¶ä»–â€ç›®å½•çš„å称"
-#: builtin/ls-files.c:488
+#: builtin/ls-files.c:487
msgid "don't show empty directories"
msgstr "ä¸æ˜¾ç¤ºç©ºç›®å½•"
-#: builtin/ls-files.c:491
+#: builtin/ls-files.c:490
msgid "show unmerged files in the output"
msgstr "显示未åˆå¹¶çš„文件"
-#: builtin/ls-files.c:493
+#: builtin/ls-files.c:492
msgid "show resolve-undo information"
msgstr "显示 resolve-undo ä¿¡æ¯"
-#: builtin/ls-files.c:495
+#: builtin/ls-files.c:494
msgid "skip files matching pattern"
msgstr "匹é…排除文件的模å¼"
-#: builtin/ls-files.c:498
+#: builtin/ls-files.c:497
msgid "exclude patterns are read from <file>"
msgstr "从 <文件> 中读å–排除模å¼"
-#: builtin/ls-files.c:501
+#: builtin/ls-files.c:500
msgid "read additional per-directory exclude patterns in <file>"
msgstr "从 <文件> 读å–é¢å¤–çš„æ¯ä¸ªç›®å½•çš„排除模å¼"
-#: builtin/ls-files.c:503
+#: builtin/ls-files.c:502
msgid "add the standard git exclusions"
msgstr "添加标准的 git 排除"
-#: builtin/ls-files.c:506
+#: builtin/ls-files.c:505
msgid "make the output relative to the project top directory"
msgstr "显示相对于顶级目录的文件å"
-#: builtin/ls-files.c:509
+#: builtin/ls-files.c:508
msgid "if any <file> is not in the index, treat this as an error"
msgstr "如果任何 <文件> 都ä¸åœ¨ç´¢å¼•åŒºï¼Œè§†ä¸ºé”™è¯¯"
-#: builtin/ls-files.c:510
+#: builtin/ls-files.c:509
msgid "tree-ish"
msgstr "树或æ交"
-#: builtin/ls-files.c:511
+#: builtin/ls-files.c:510
msgid "pretend that paths removed since <tree-ish> are still present"
msgstr "å‡è£…自从 <树或æ交> 之åŽåˆ é™¤çš„路径ä»ç„¶å­˜åœ¨"
-#: builtin/ls-files.c:513
+#: builtin/ls-files.c:512
msgid "show debugging data"
msgstr "显示调试数æ®"
@@ -5849,164 +6397,168 @@ msgstr "git merge [选项] <说明> HEAD <æ交>"
msgid "git merge --abort"
msgstr "git merge --abort"
-#: builtin/merge.c:90
+#: builtin/merge.c:98
msgid "switch `m' requires a value"
msgstr "开关 `m' 需è¦ä¸€ä¸ªå€¼"
-#: builtin/merge.c:127
+#: builtin/merge.c:135
#, c-format
msgid "Could not find merge strategy '%s'.\n"
msgstr "ä¸èƒ½æ‰¾åˆ°åˆå¹¶ç­–ç•¥ '%s'。\n"
-#: builtin/merge.c:128
+#: builtin/merge.c:136
#, c-format
msgid "Available strategies are:"
msgstr "å¯ç”¨çš„策略有:"
-#: builtin/merge.c:133
+#: builtin/merge.c:141
#, c-format
msgid "Available custom strategies are:"
msgstr "å¯ç”¨çš„自定义策略有:"
-#: builtin/merge.c:183
+#: builtin/merge.c:198
msgid "do not show a diffstat at the end of the merge"
msgstr "在åˆå¹¶çš„最åŽä¸æ˜¾ç¤ºå·®å¼‚统计"
-#: builtin/merge.c:186
+#: builtin/merge.c:201
msgid "show a diffstat at the end of the merge"
msgstr "在åˆå¹¶çš„最åŽæ˜¾ç¤ºå·®å¼‚统计"
-#: builtin/merge.c:187
+#: builtin/merge.c:202
msgid "(synonym to --stat)"
msgstr "(和 --stat åŒä¹‰ï¼‰"
-#: builtin/merge.c:189
+#: builtin/merge.c:204
msgid "add (at most <n>) entries from shortlog to merge commit message"
msgstr "在åˆå¹¶æ交信æ¯ä¸­æ·»åŠ ï¼ˆæœ€å¤š <n> æ¡ï¼‰ç²¾ç®€æ交记录"
-#: builtin/merge.c:192
+#: builtin/merge.c:207
msgid "create a single commit instead of doing a merge"
msgstr "创建一个å•ç‹¬çš„æ交而ä¸æ˜¯åšä¸€æ¬¡åˆå¹¶"
-#: builtin/merge.c:194
+#: builtin/merge.c:209
msgid "perform a commit if the merge succeeds (default)"
msgstr "如果åˆå¹¶æˆåŠŸï¼Œæ‰§è¡Œä¸€æ¬¡æ交(默认)"
-#: builtin/merge.c:196
+#: builtin/merge.c:211
msgid "edit message before committing"
msgstr "在æ交å‰ç¼–辑æ交说明"
-#: builtin/merge.c:198
+#: builtin/merge.c:212
msgid "allow fast-forward (default)"
msgstr "å…许快进(默认)"
-#: builtin/merge.c:200
+#: builtin/merge.c:214
msgid "abort if fast-forward is not possible"
msgstr "如果ä¸èƒ½å¿«è¿›å°±æ”¾å¼ƒåˆå¹¶"
-#: builtin/merge.c:202 builtin/notes.c:866 builtin/revert.c:112
+#: builtin/merge.c:218
+msgid "Verify that the named commit has a valid GPG signature"
+msgstr "验è¯æŒ‡å®šçš„æ交是å¦åŒ…å«ä¸€ä¸ªæœ‰æ•ˆçš„ GPG ç­¾å"
+
+#: builtin/merge.c:219 builtin/notes.c:738 builtin/revert.c:114
msgid "strategy"
msgstr "ç­–ç•¥"
-#: builtin/merge.c:203
+#: builtin/merge.c:220
msgid "merge strategy to use"
msgstr "è¦ä½¿ç”¨çš„åˆå¹¶ç­–ç•¥"
-#: builtin/merge.c:204
+#: builtin/merge.c:221
msgid "option=value"
msgstr "option=value"
-#: builtin/merge.c:205
+#: builtin/merge.c:222
msgid "option for selected merge strategy"
msgstr "所选的åˆå¹¶ç­–略的选项"
-#: builtin/merge.c:207
+#: builtin/merge.c:224
msgid "merge commit message (for a non-fast-forward merge)"
msgstr "åˆå¹¶çš„æ交说明(针对éžå¿«è¿›å¼åˆå¹¶ï¼‰"
-#: builtin/merge.c:211
+#: builtin/merge.c:228
msgid "abort the current in-progress merge"
msgstr "放弃当å‰æ­£åœ¨è¿›è¡Œçš„åˆå¹¶"
-#: builtin/merge.c:240
+#: builtin/merge.c:257
msgid "could not run stash."
msgstr "ä¸èƒ½è¿›è¡Œè¿›åº¦ä¿å­˜ã€‚"
-#: builtin/merge.c:245
+#: builtin/merge.c:262
msgid "stash failed"
msgstr "进度ä¿å­˜å¤±è´¥"
-#: builtin/merge.c:250
+#: builtin/merge.c:267
#, c-format
msgid "not a valid object: %s"
msgstr "ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆå¯¹è±¡ï¼š%s"
-#: builtin/merge.c:269 builtin/merge.c:286
+#: builtin/merge.c:286 builtin/merge.c:303
msgid "read-tree failed"
msgstr "读å–树失败"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: builtin/merge.c:316
+#: builtin/merge.c:333
msgid " (nothing to squash)"
msgstr " (无å¯åŽ‹ç¼©ï¼‰"
-#: builtin/merge.c:329
+#: builtin/merge.c:346
#, c-format
msgid "Squash commit -- not updating HEAD\n"
msgstr "压缩æ交 -- 未更新 HEAD\n"
-#: builtin/merge.c:361
+#: builtin/merge.c:378
msgid "Writing SQUASH_MSG"
msgstr "写入 SQUASH_MSG"
-#: builtin/merge.c:363
+#: builtin/merge.c:380
msgid "Finishing SQUASH_MSG"
msgstr "å®Œæˆ SQUASH_MSG"
-#: builtin/merge.c:386
+#: builtin/merge.c:403
#, c-format
msgid "No merge message -- not updating HEAD\n"
msgstr "æ— åˆå¹¶ä¿¡æ¯ -- 未更新 HEAD\n"
-#: builtin/merge.c:436
+#: builtin/merge.c:453
#, c-format
msgid "'%s' does not point to a commit"
msgstr "'%s' 没有指å‘一个æ交"
-#: builtin/merge.c:535
+#: builtin/merge.c:565
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "åçš„ branch.%s.mergeoptions 字符串:%s"
-#: builtin/merge.c:628
+#: builtin/merge.c:657
msgid "git write-tree failed to write a tree"
msgstr "git write-tree 无法写入一树对象"
-#: builtin/merge.c:656
+#: builtin/merge.c:685
msgid "Not handling anything other than two heads merge."
msgstr "ä¸èƒ½å¤„ç†ä¸¤ä¸ªå¤´åˆå¹¶ä¹‹å¤–的任何æ“作。"
-#: builtin/merge.c:670
+#: builtin/merge.c:699
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr "merge-recursive 的未知选项:-X%s"
-#: builtin/merge.c:684
+#: builtin/merge.c:713
#, c-format
msgid "unable to write %s"
msgstr "ä¸èƒ½å†™ %s"
-#: builtin/merge.c:773
+#: builtin/merge.c:802
#, c-format
msgid "Could not read from '%s'"
msgstr "ä¸èƒ½ä»Ž '%s' 读å–"
-#: builtin/merge.c:782
+#: builtin/merge.c:811
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr "未æ交åˆå¹¶ï¼Œä½¿ç”¨ 'git commit' 完æˆæ­¤æ¬¡åˆå¹¶ã€‚\n"
-#: builtin/merge.c:788
+#: builtin/merge.c:817
#, c-format
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
@@ -6020,52 +6572,47 @@ msgstr ""
"\n"
"以 '%c' 开头的行将被忽略,而且空æ交说明将会终止æ交。\n"
-#: builtin/merge.c:812
+#: builtin/merge.c:841
msgid "Empty commit message."
msgstr "空æ交信æ¯ã€‚"
-#: builtin/merge.c:824
+#: builtin/merge.c:853
#, c-format
msgid "Wonderful.\n"
msgstr "太棒了。\n"
-#: builtin/merge.c:889
+#: builtin/merge.c:918
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr "自动åˆå¹¶å¤±è´¥ï¼Œä¿®æ­£å†²çªç„¶åŽæ交修正的结果。\n"
-#: builtin/merge.c:905
+#: builtin/merge.c:934
#, c-format
msgid "'%s' is not a commit"
msgstr "'%s' ä¸æ˜¯ä¸€ä¸ªæ交"
-#: builtin/merge.c:946
+#: builtin/merge.c:975
msgid "No current branch."
msgstr "没有当å‰åˆ†æ”¯ã€‚"
-#: builtin/merge.c:948
+#: builtin/merge.c:977
msgid "No remote for the current branch."
msgstr "当å‰åˆ†æ”¯æ²¡æœ‰å¯¹åº”的远程版本库。"
-#: builtin/merge.c:950
+#: builtin/merge.c:979
msgid "No default upstream defined for the current branch."
msgstr "当å‰åˆ†æ”¯æ²¡æœ‰å®šä¹‰é»˜è®¤çš„上游分支。"
-#: builtin/merge.c:955
+#: builtin/merge.c:984
#, c-format
-msgid "No remote tracking branch for %s from %s"
-msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支"
-
-#: builtin/merge.c:1042 builtin/merge.c:1199
-#, c-format
-msgid "%s - not something we can merge"
-msgstr "%s - ä¸èƒ½è¢«åˆå¹¶"
+msgid "No remote-tracking branch for %s from %s"
+msgstr "对于 %s 没有æ¥è‡ª %s 的远程跟踪分支"
-#: builtin/merge.c:1110
+#: builtin/merge.c:1140
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr "没有è¦ç»ˆæ­¢çš„åˆå¹¶ï¼ˆMERGE_HEAD 丢失)。"
-#: builtin/merge.c:1126 git-pull.sh:31
+#: builtin/merge.c:1156 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -6073,11 +6620,11 @@ msgstr ""
"您尚未结æŸæ‚¨çš„åˆå¹¶ï¼ˆå­˜åœ¨ MERGE_HEAD)。\n"
"请在åˆå¹¶å‰å…ˆæ交您的修改。"
-#: builtin/merge.c:1129 git-pull.sh:34
+#: builtin/merge.c:1159 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "您尚未结æŸæ‚¨çš„åˆå¹¶ï¼ˆå­˜åœ¨ MERGE_HEAD)。"
-#: builtin/merge.c:1133
+#: builtin/merge.c:1163
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
@@ -6085,79 +6632,101 @@ msgstr ""
"您尚未结æŸæ‚¨çš„拣选(存在 CHERRY_PICK_HEAD)。\n"
"请在åˆå¹¶å‰å…ˆæ交您的修改。"
-#: builtin/merge.c:1136
+#: builtin/merge.c:1166
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr "您尚未结æŸæ‚¨çš„拣选(存在 CHERRY_PICK_HEAD)。"
-#: builtin/merge.c:1145
+#: builtin/merge.c:1175
msgid "You cannot combine --squash with --no-ff."
msgstr "您ä¸èƒ½å°† --squash 与 --no-ff åŒæ—¶ä½¿ç”¨ã€‚"
-#: builtin/merge.c:1150
-msgid "You cannot combine --no-ff with --ff-only."
-msgstr "您ä¸èƒ½å°† --no-ff 与 --ff-only åŒæ—¶ä½¿ç”¨ã€‚"
-
-#: builtin/merge.c:1157
+#: builtin/merge.c:1184
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr "未指定æ交并且 merge.defaultToUpstream 未设置。"
-#: builtin/merge.c:1189
+#: builtin/merge.c:1216
msgid "Can merge only exactly one commit into empty head"
msgstr "åªèƒ½å°†ä¸€ä¸ªæ交åˆå¹¶åˆ°ç©ºåˆ†æ”¯ä¸Š"
-#: builtin/merge.c:1192
+#: builtin/merge.c:1219
msgid "Squash commit into empty head not supported yet"
msgstr "å°šä¸æ”¯æŒåˆ°ç©ºåˆ†æ”¯çš„压缩æ交"
-#: builtin/merge.c:1194
+#: builtin/merge.c:1221
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr "到空分支的éžå¿«è¿›å¼æ交没有æ„义"
-#: builtin/merge.c:1310
+#: builtin/merge.c:1226
+#, c-format
+msgid "%s - not something we can merge"
+msgstr "%s - ä¸èƒ½è¢«åˆå¹¶"
+
+#: builtin/merge.c:1277
+#, c-format
+msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
+msgstr "æ交 %s 有一个éžå¯ä¿¡çš„声称æ¥è‡ª %s çš„ GPG ç­¾å。"
+
+#: builtin/merge.c:1280
+#, c-format
+msgid "Commit %s has a bad GPG signature allegedly by %s."
+msgstr "æ交 %s 有一个错误的声称æ¥è‡ª %s çš„ GPG ç­¾å。"
+
+#. 'N'
+#: builtin/merge.c:1283
+#, c-format
+msgid "Commit %s does not have a GPG signature."
+msgstr "æ交 %s 没有一个 GPG ç­¾å。"
+
+#: builtin/merge.c:1286
+#, c-format
+msgid "Commit %s has a good GPG signature by %s\n"
+msgstr "æ交 %s 有一个æ¥è‡ª %s 的好的 GPG ç­¾å。\n"
+
+#: builtin/merge.c:1370
#, c-format
msgid "Updating %s..%s\n"
msgstr "æ›´æ–° %s..%s\n"
-#: builtin/merge.c:1349
+#: builtin/merge.c:1409
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr "å°è¯•éžå¸¸å°çš„索引内åˆå¹¶...\n"
-#: builtin/merge.c:1356
+#: builtin/merge.c:1416
#, c-format
msgid "Nope.\n"
msgstr "无。\n"
-#: builtin/merge.c:1388
+#: builtin/merge.c:1448
msgid "Not possible to fast-forward, aborting."
msgstr "无法快进,终止。"
-#: builtin/merge.c:1411 builtin/merge.c:1490
+#: builtin/merge.c:1471 builtin/merge.c:1550
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr "将树回滚至原始状æ€...\n"
-#: builtin/merge.c:1415
+#: builtin/merge.c:1475
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "å°è¯•åˆå¹¶ç­–ç•¥ %s...\n"
-#: builtin/merge.c:1481
+#: builtin/merge.c:1541
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr "没有åˆå¹¶ç­–略处ç†æ­¤åˆå¹¶ã€‚\n"
-#: builtin/merge.c:1483
+#: builtin/merge.c:1543
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr "使用策略 %s åˆå¹¶å¤±è´¥ã€‚\n"
-#: builtin/merge.c:1492
+#: builtin/merge.c:1552
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr "使用 %s 以准备手工解决。\n"
-#: builtin/merge.c:1504
+#: builtin/merge.c:1564
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr "自动åˆå¹¶è¿›å±•é¡ºåˆ©ï¼ŒæŒ‰è¦æ±‚在æ交å‰åœæ­¢\n"
@@ -6323,47 +6892,51 @@ msgstr "é‡å‘½å %s 至 %s\n"
msgid "renaming '%s' failed"
msgstr "é‡å‘½å '%s' 失败"
-#: builtin/name-rev.c:175
+#: builtin/name-rev.c:259
msgid "git name-rev [options] <commit>..."
msgstr "git name-rev [选项] <æ交>..."
-#: builtin/name-rev.c:176
+#: builtin/name-rev.c:260
msgid "git name-rev [options] --all"
msgstr "git name-rev [选项] --all"
-#: builtin/name-rev.c:177
+#: builtin/name-rev.c:261
msgid "git name-rev [options] --stdin"
msgstr "git name-rev [选项] --stdin"
-#: builtin/name-rev.c:229
+#: builtin/name-rev.c:313
msgid "print only names (no SHA-1)"
msgstr "åªæ‰“å°å称(无 SHA-1)"
-#: builtin/name-rev.c:230
+#: builtin/name-rev.c:314
msgid "only use tags to name the commits"
msgstr "åªä½¿ç”¨ tags æ¥å‘½åæ交"
-#: builtin/name-rev.c:232
+#: builtin/name-rev.c:316
msgid "only use refs matching <pattern>"
msgstr "åªä½¿ç”¨å’Œ <模å¼> 相匹é…的引用"
-#: builtin/name-rev.c:234
+#: builtin/name-rev.c:318
msgid "list all commits reachable from all refs"
msgstr "列出å¯ä»¥ä»Žæ‰€æœ‰å¼•ç”¨è®¿é—®çš„æ交"
-#: builtin/name-rev.c:235
+#: builtin/name-rev.c:319
msgid "read from stdin"
msgstr "从标准输入读å–"
-#: builtin/name-rev.c:236
+#: builtin/name-rev.c:320
msgid "allow to print `undefined` names"
msgstr "å…è®¸æ‰“å° `未定义` çš„å称"
-#: builtin/notes.c:26
+#: builtin/name-rev.c:326
+msgid "dereference tags in the input (internal use)"
+msgstr "åå‘解æžè¾“入中的 tags(内部使用)"
+
+#: builtin/notes.c:24
msgid "git notes [--ref <notes_ref>] [list [<object>]]"
msgstr "git notes [--ref <注解引用>] [list [<对象>]]"
-#: builtin/notes.c:27
+#: builtin/notes.c:25
msgid ""
"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
@@ -6371,11 +6944,11 @@ msgstr ""
"git notes [--ref <注解引用>] add [-f] [-m <说明> | -F <文件> | (-c | -C) <对"
"象>] [<对象>]"
-#: builtin/notes.c:28
+#: builtin/notes.c:26
msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
msgstr "git notes [--ref <注解引用>] copy [-f] <æºå¯¹è±¡> <目标对象>"
-#: builtin/notes.c:29
+#: builtin/notes.c:27
msgid ""
"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
@@ -6383,255 +6956,234 @@ msgstr ""
"git notes [--ref <注解引用>] append [-m <说明> | -F <文件> | (-c | -C) <对象"
">] [<对象>]"
-#: builtin/notes.c:30
+#: builtin/notes.c:28
msgid "git notes [--ref <notes_ref>] edit [<object>]"
msgstr "git notes [--ref <注解引用>] edit [<对象>]"
-#: builtin/notes.c:31
+#: builtin/notes.c:29
msgid "git notes [--ref <notes_ref>] show [<object>]"
msgstr "git notes [--ref <注解引用>] show [<对象>]"
-#: builtin/notes.c:32
+#: builtin/notes.c:30
msgid ""
"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
msgstr "git notes [--ref <注解引用>] merge [-v | -q] [-s <策略> ] <注解引用>"
-#: builtin/notes.c:33
+#: builtin/notes.c:31
msgid "git notes merge --commit [-v | -q]"
msgstr "git notes merge --commit [-v | -q]"
-#: builtin/notes.c:34
+#: builtin/notes.c:32
msgid "git notes merge --abort [-v | -q]"
msgstr "git notes merge --abort [-v | -q]"
-#: builtin/notes.c:35
+#: builtin/notes.c:33
msgid "git notes [--ref <notes_ref>] remove [<object>...]"
msgstr "git notes [--ref <注解引用>] remove [<对象>...]"
-#: builtin/notes.c:36
+#: builtin/notes.c:34
msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
msgstr "git notes [--ref <注解引用>] prune [-n | -v]"
-#: builtin/notes.c:37
+#: builtin/notes.c:35
msgid "git notes [--ref <notes_ref>] get-ref"
msgstr "git notes [--ref <注解引用>] get-ref"
-#: builtin/notes.c:42
+#: builtin/notes.c:40
msgid "git notes [list [<object>]]"
msgstr "git notes [list [<对象>]]"
-#: builtin/notes.c:47
+#: builtin/notes.c:45
msgid "git notes add [<options>] [<object>]"
msgstr "git notes add [<选项>] [<对象>]"
-#: builtin/notes.c:52
+#: builtin/notes.c:50
msgid "git notes copy [<options>] <from-object> <to-object>"
msgstr "git notes copy [<选项>] <æºå¯¹è±¡> <目标对象>"
-#: builtin/notes.c:53
+#: builtin/notes.c:51
msgid "git notes copy --stdin [<from-object> <to-object>]..."
msgstr "git notes copy --stdin [<æºå¯¹è±¡> <目标对象>]..."
-#: builtin/notes.c:58
+#: builtin/notes.c:56
msgid "git notes append [<options>] [<object>]"
msgstr "git notes append [<选项>] [<对象>]"
-#: builtin/notes.c:63
+#: builtin/notes.c:61
msgid "git notes edit [<object>]"
msgstr "git notes edit [<对象>]"
-#: builtin/notes.c:68
+#: builtin/notes.c:66
msgid "git notes show [<object>]"
msgstr "git notes show [<对象>]"
-#: builtin/notes.c:73
+#: builtin/notes.c:71
msgid "git notes merge [<options>] <notes_ref>"
msgstr "git notes merge [<选项>] <注解引用>"
-#: builtin/notes.c:74
+#: builtin/notes.c:72
msgid "git notes merge --commit [<options>]"
msgstr "git notes merge --commit [<选项>]"
-#: builtin/notes.c:75
+#: builtin/notes.c:73
msgid "git notes merge --abort [<options>]"
msgstr "git notes merge --abort [<选项>]"
-#: builtin/notes.c:80
+#: builtin/notes.c:78
msgid "git notes remove [<object>]"
msgstr "git notes remove [<对象>]"
-#: builtin/notes.c:85
+#: builtin/notes.c:83
msgid "git notes prune [<options>]"
msgstr "git notes prune [<选项>]"
-#: builtin/notes.c:90
+#: builtin/notes.c:88
msgid "git notes get-ref"
msgstr "git notes get-ref"
-#: builtin/notes.c:139
+#: builtin/notes.c:137
#, c-format
msgid "unable to start 'show' for object '%s'"
msgstr "ä¸èƒ½ä¸ºå¯¹è±¡ '%s' 开始 'show'"
-#: builtin/notes.c:143
+#: builtin/notes.c:141
msgid "could not read 'show' output"
msgstr "ä¸èƒ½è¯»å– 'show' 的输出"
-#: builtin/notes.c:151
+#: builtin/notes.c:149
#, c-format
msgid "failed to finish 'show' for object '%s'"
msgstr "无法为对象 '%s' å®Œæˆ 'show'"
-#: builtin/notes.c:169 builtin/tag.c:341
+#: builtin/notes.c:167 builtin/tag.c:341
#, c-format
msgid "could not create file '%s'"
msgstr "ä¸èƒ½åˆ›å»ºæ–‡ä»¶ '%s'"
-#: builtin/notes.c:188
+#: builtin/notes.c:186
msgid "Please supply the note contents using either -m or -F option"
msgstr "请通过 -m 或 -F 选项为注解æ供内容"
-#: builtin/notes.c:209 builtin/notes.c:972
+#: builtin/notes.c:207 builtin/notes.c:844
#, c-format
msgid "Removing note for object %s\n"
msgstr "删除对象 %s 的注解\n"
-#: builtin/notes.c:214
+#: builtin/notes.c:212
msgid "unable to write note object"
msgstr "ä¸èƒ½å†™æ³¨è§£å¯¹è±¡"
-#: builtin/notes.c:216
+#: builtin/notes.c:214
#, c-format
msgid "The note contents has been left in %s"
msgstr "注解内容被留在文件 %s 中"
-#: builtin/notes.c:250 builtin/tag.c:540
+#: builtin/notes.c:248 builtin/tag.c:540
#, c-format
msgid "cannot read '%s'"
msgstr "ä¸èƒ½è¯»å– '%s'"
-#: builtin/notes.c:252 builtin/tag.c:543
+#: builtin/notes.c:250 builtin/tag.c:543
#, c-format
msgid "could not open or read '%s'"
msgstr "ä¸èƒ½æ‰“å¼€æˆ–è¯»å– '%s'"
-#: builtin/notes.c:271 builtin/notes.c:444 builtin/notes.c:446
-#: builtin/notes.c:506 builtin/notes.c:560 builtin/notes.c:643
-#: builtin/notes.c:648 builtin/notes.c:723 builtin/notes.c:765
-#: builtin/notes.c:967 builtin/tag.c:556
+#: builtin/notes.c:269 builtin/notes.c:316 builtin/notes.c:318
+#: builtin/notes.c:378 builtin/notes.c:432 builtin/notes.c:515
+#: builtin/notes.c:520 builtin/notes.c:595 builtin/notes.c:637
+#: builtin/notes.c:839 builtin/tag.c:556
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
msgstr "æ— æ³•è§£æž '%s' 为一个有效引用。"
-#: builtin/notes.c:274
+#: builtin/notes.c:272
#, c-format
msgid "Failed to read object '%s'."
msgstr "无法读å–对象 '%s'。"
-#: builtin/notes.c:298
-msgid "Cannot commit uninitialized/unreferenced notes tree"
-msgstr "ä¸èƒ½æ交未åˆå§‹åŒ–/未引用的注解树"
-
-#: builtin/notes.c:339
-#, c-format
-msgid "Bad notes.rewriteMode value: '%s'"
-msgstr "åçš„ notes.rewriteMode 值:'%s'"
-
-#: builtin/notes.c:349
-#, c-format
-msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
-msgstr "æ‹’ç»å‘ %s(在 refs/notes/ 之外)写入注解"
-
-#. TRANSLATORS: The first %s is the name of the
-#. environment variable, the second %s is its value
-#: builtin/notes.c:376
-#, c-format
-msgid "Bad %s value: '%s'"
-msgstr "åçš„ %s 值:'%s'"
-
-#: builtin/notes.c:440
+#: builtin/notes.c:312
#, c-format
msgid "Malformed input line: '%s'."
msgstr "éžæ³•çš„输入行:'%s'。"
-#: builtin/notes.c:455
+#: builtin/notes.c:327
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
msgstr "无法从 '%s' 到 '%s' æ‹·è´æ³¨è§£"
-#: builtin/notes.c:499 builtin/notes.c:553 builtin/notes.c:626
-#: builtin/notes.c:638 builtin/notes.c:711 builtin/notes.c:758
-#: builtin/notes.c:1032
+#: builtin/notes.c:371 builtin/notes.c:425 builtin/notes.c:498
+#: builtin/notes.c:510 builtin/notes.c:583 builtin/notes.c:630
+#: builtin/notes.c:904
msgid "too many parameters"
msgstr "å‚数太多"
-#: builtin/notes.c:512 builtin/notes.c:771
+#: builtin/notes.c:384 builtin/notes.c:643
#, c-format
msgid "No note found for object %s."
msgstr "未å‘现对象 %s 的注解。"
-#: builtin/notes.c:534 builtin/notes.c:691
+#: builtin/notes.c:406 builtin/notes.c:563
msgid "note contents as a string"
msgstr "注解内容作为一个字符串"
-#: builtin/notes.c:537 builtin/notes.c:694
+#: builtin/notes.c:409 builtin/notes.c:566
msgid "note contents in a file"
msgstr "注解内容到一个文件中"
-#: builtin/notes.c:539 builtin/notes.c:542 builtin/notes.c:696
-#: builtin/notes.c:699 builtin/tag.c:474
+#: builtin/notes.c:411 builtin/notes.c:414 builtin/notes.c:568
+#: builtin/notes.c:571 builtin/tag.c:474
msgid "object"
msgstr "对象"
-#: builtin/notes.c:540 builtin/notes.c:697
+#: builtin/notes.c:412 builtin/notes.c:569
msgid "reuse and edit specified note object"
msgstr "é‡ç”¨å’Œç¼–辑指定的注解对象"
-#: builtin/notes.c:543 builtin/notes.c:700
+#: builtin/notes.c:415 builtin/notes.c:572
msgid "reuse specified note object"
msgstr "é‡ç”¨æŒ‡å®šçš„注解对象"
-#: builtin/notes.c:545 builtin/notes.c:613
+#: builtin/notes.c:417 builtin/notes.c:485
msgid "replace existing notes"
msgstr "替æ¢å·²å­˜åœ¨çš„注解"
-#: builtin/notes.c:579
+#: builtin/notes.c:451
#, c-format
msgid ""
"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
"existing notes"
msgstr "ä¸èƒ½æ·»åŠ æ³¨è§£ã€‚å‘现对象 %s 已存在注解。使用 '-f' 覆盖现存注解"
-#: builtin/notes.c:584 builtin/notes.c:661
+#: builtin/notes.c:456 builtin/notes.c:533
#, c-format
msgid "Overwriting existing notes for object %s\n"
msgstr "覆盖对象 %s 现存注解\n"
-#: builtin/notes.c:614
+#: builtin/notes.c:486
msgid "read objects from stdin"
msgstr "从标准输入读å–对象"
-#: builtin/notes.c:616
+#: builtin/notes.c:488
msgid "load rewriting config for <command> (implies --stdin)"
msgstr "é‡æ–°åŠ è½½ <命令> çš„é…置(éšå« --stdin)"
-#: builtin/notes.c:634
+#: builtin/notes.c:506
msgid "too few parameters"
msgstr "å‚数太少"
-#: builtin/notes.c:655
+#: builtin/notes.c:527
#, c-format
msgid ""
"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
"existing notes"
msgstr "ä¸èƒ½æ‹·è´æ³¨è§£ã€‚å‘现对象 %s 已存在注解。使用 '-f' 覆盖现存注解"
-#: builtin/notes.c:667
+#: builtin/notes.c:539
#, c-format
msgid "Missing notes on source object %s. Cannot copy."
msgstr "æºå¯¹è±¡ %s 缺少注解。ä¸èƒ½æ‹·è´ã€‚"
-#: builtin/notes.c:716
+#: builtin/notes.c:588
#, c-format
msgid ""
"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
@@ -6640,58 +7192,58 @@ msgstr ""
"å­å‘½ä»¤ 'edit' 的选项 -m/-F/-c/-C 已弃用。\n"
"请æ¢ç”¨ 'git notes add -f -m/-F/-c/-C'。\n"
-#: builtin/notes.c:863
+#: builtin/notes.c:735
msgid "General options"
msgstr "通用选项"
-#: builtin/notes.c:865
+#: builtin/notes.c:737
msgid "Merge options"
msgstr "åˆå¹¶é€‰é¡¹"
-#: builtin/notes.c:867
+#: builtin/notes.c:739
msgid ""
"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
"cat_sort_uniq)"
msgstr "ä½¿ç”¨æŒ‡å®šçš„ç­–ç•¥è§£å†³æ³¨è§£å†²çª (manual/ours/theirs/union/cat_sort_uniq)"
-#: builtin/notes.c:869
+#: builtin/notes.c:741
msgid "Committing unmerged notes"
msgstr "æ交未åˆå¹¶çš„注解"
-#: builtin/notes.c:871
+#: builtin/notes.c:743
msgid "finalize notes merge by committing unmerged notes"
msgstr "通过æ交未åˆå¹¶çš„注解æ¥å®Œæˆæ³¨è§£åˆå¹¶"
-#: builtin/notes.c:873
+#: builtin/notes.c:745
msgid "Aborting notes merge resolution"
msgstr "中止注解åˆå¹¶çš„方案"
-#: builtin/notes.c:875
+#: builtin/notes.c:747
msgid "abort notes merge"
msgstr "中止注解åˆå¹¶"
-#: builtin/notes.c:970
+#: builtin/notes.c:842
#, c-format
msgid "Object %s has no note\n"
msgstr "对象 %s 没有注解\n"
-#: builtin/notes.c:982
+#: builtin/notes.c:854
msgid "attempt to remove non-existent note is not an error"
msgstr "å°è¯•åˆ é™¤ä¸å­˜åœ¨çš„注解ä¸æ˜¯ä¸€ä¸ªé”™è¯¯"
-#: builtin/notes.c:985
+#: builtin/notes.c:857
msgid "read object names from the standard input"
msgstr "从标准输入读å–对象å称"
-#: builtin/notes.c:1066
+#: builtin/notes.c:938
msgid "notes_ref"
msgstr "注解引用"
-#: builtin/notes.c:1067
+#: builtin/notes.c:939
msgid "use notes from <notes_ref>"
msgstr "从 <注解引用> 使用注解"
-#: builtin/notes.c:1102 builtin/remote.c:1598
+#: builtin/notes.c:974 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
msgstr "未知å­å‘½ä»¤ï¼š%s"
@@ -6925,7 +7477,7 @@ msgstr ""
" git push %s %s\n"
"%s"
-#: builtin/push.c:121
+#: builtin/push.c:117
#, c-format
msgid ""
"You are not currently on a branch.\n"
@@ -6939,7 +7491,7 @@ msgstr ""
"\n"
" git push %s HEAD:<name-of-remote-branch>\n"
-#: builtin/push.c:128
+#: builtin/push.c:131
#, c-format
msgid ""
"The current branch %s has no upstream branch.\n"
@@ -6952,12 +7504,12 @@ msgstr ""
"\n"
" git push --set-upstream %s %s\n"
-#: builtin/push.c:136
+#: builtin/push.c:139
#, c-format
msgid "The current branch %s has multiple upstream branches, refusing to push."
msgstr "当å‰åˆ†æ”¯ %s 有多个上游分支,拒ç»æŽ¨é€ã€‚"
-#: builtin/push.c:139
+#: builtin/push.c:142
#, c-format
msgid ""
"You are pushing to remote '%s', which is not the upstream of\n"
@@ -6968,7 +7520,7 @@ msgstr ""
"而没有告诉我è¦æŽ¨é€ä»€ä¹ˆã€æ›´æ–°å“ªä¸ªè¿œç¨‹åˆ†æ”¯ã€‚"
# 译者:字符串首行行首è¦æ·»åŠ â€œwarning: â€å­—串,故此首行è¦è¾ƒå…¶ä½™è¡ŒçŸ­
-#: builtin/push.c:151
+#: builtin/push.c:165
msgid ""
"push.default is unset; its implicit value is changing in\n"
"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
@@ -6999,23 +7551,23 @@ msgstr ""
"('simple' 模å¼ç”± Git 1.7.11 版本引入。如果您有时è¦ä½¿ç”¨è€ç‰ˆæœ¬çš„ Git,\n"
"为ä¿æŒå…¼å®¹ï¼Œè¯·ç”¨ 'current' 代替 'simple' 模å¼ï¼‰"
-#: builtin/push.c:199
+#: builtin/push.c:225
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr "您没有为推é€æŒ‡å®šä»»ä½•å¼•ç”¨è¡¨è¾¾å¼ï¼Œå¹¶ä¸” push.default 为 \"nothing\"。"
-#: builtin/push.c:206
+#: builtin/push.c:232
msgid ""
"Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
-"before pushing again.\n"
+"its remote counterpart. Integrate the remote changes (e.g.\n"
+"'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"更新被拒ç»ï¼Œå› ä¸ºæ‚¨å½“å‰åˆ†æ”¯çš„最新æ交è½åŽäºŽå…¶å¯¹åº”的远程分支。\n"
-"å†æ¬¡æŽ¨é€å‰ï¼Œå…ˆä¸Žè¿œç¨‹å˜æ›´åˆå¹¶ï¼ˆå¦‚ 'git pull')。详è§\n"
+"å†æ¬¡æŽ¨é€å‰ï¼Œå…ˆä¸Žè¿œç¨‹å˜æ›´åˆå¹¶ï¼ˆå¦‚ 'git pull ...')。详è§\n"
"'git push --help' 中的 'Note about fast-forwards' å°èŠ‚。"
-#: builtin/push.c:212
+#: builtin/push.c:238
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"
@@ -7027,35 +7579,35 @@ msgstr ""
"é…ç½®å˜é‡ 'push.default' 设置为 'simple'ã€'current' 或 'upstream'\n"
"以便åªæŽ¨é€å½“å‰åˆ†æ”¯ã€‚"
-#: builtin/push.c:218
+#: builtin/push.c:244
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and merge the remote changes\n"
-"(e.g. 'git pull') before pushing again.\n"
+"counterpart. Check out this branch and integrate the remote changes\n"
+"(e.g. 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"更新被拒ç»ï¼Œå› ä¸ºæŽ¨é€çš„一个分支的最新æ交è½åŽäºŽå…¶å¯¹åº”的远程分支。\n"
-"检出该分支并与远程å˜æ›´åˆå¹¶ï¼ˆå¦‚ 'git pull'),然åŽå†æŽ¨é€ã€‚详è§\n"
+"检出该分支并整åˆè¿œç¨‹å˜æ›´ï¼ˆå¦‚ 'git pull ...'),然åŽå†æŽ¨é€ã€‚详è§\n"
"'git push --help' 中的 'Note about fast-forwards' å°èŠ‚。"
-#: builtin/push.c:224
+#: builtin/push.c:250
msgid ""
"Updates were rejected because the remote contains work that you do\n"
"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first merge the remote changes (e.g.,\n"
-"'git pull') before pushing again.\n"
+"to the same ref. You may want to first integrate the remote changes\n"
+"(e.g., 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"更新被拒ç»ï¼Œå› ä¸ºè¿œç¨‹ç‰ˆæœ¬åº“包å«æ‚¨æœ¬åœ°å°šä¸å­˜åœ¨çš„æ交。这通常是因为å¦å¤–\n"
-"一个版本库已推é€äº†ç›¸åŒçš„引用。å†æ¬¡æŽ¨é€å‰ï¼Œæ‚¨å¯èƒ½éœ€è¦å…ˆåˆå¹¶è¿œç¨‹å˜æ›´\n"
-"(如 'git pull')。\n"
+"一个版本库已å‘该引用进行了推é€ã€‚å†æ¬¡æŽ¨é€å‰ï¼Œæ‚¨å¯èƒ½éœ€è¦å…ˆæ•´åˆè¿œç¨‹å˜æ›´\n"
+"(如 'git pull ...')。\n"
"è¯¦è§ 'git push --help' 中的 'Note about fast-forwards' å°èŠ‚。"
-#: builtin/push.c:231
+#: builtin/push.c:257
msgid "Updates were rejected because the tag already exists in the remote."
msgstr "更新被拒ç»å› ä¸º tag 在远程已ç»å­˜åœ¨ã€‚"
-#: builtin/push.c:234
+#: builtin/push.c:260
msgid ""
"You cannot update a remote ref that points at a non-commit object,\n"
"or update a remote ref to make it point at a non-commit object,\n"
@@ -7064,22 +7616,22 @@ msgstr ""
"如果ä¸ä½¿ç”¨ '--force' å‚数,您ä¸èƒ½æ›´æ–°ä¸€ä¸ªæŒ‡å‘éžæ交对象的远程引用,\n"
"也ä¸èƒ½æ›´æ–°è¿œç¨‹å¼•ç”¨è®©å…¶æŒ‡å‘一个éžæ交对象。\n"
-#: builtin/push.c:294
+#: builtin/push.c:320
#, c-format
msgid "Pushing to %s\n"
msgstr "推é€åˆ° %s\n"
-#: builtin/push.c:298
+#: builtin/push.c:324
#, c-format
msgid "failed to push some refs to '%s'"
msgstr "无法推é€ä¸€äº›å¼•ç”¨åˆ° '%s'"
-#: builtin/push.c:331
+#: builtin/push.c:357
#, c-format
msgid "bad repository '%s'"
msgstr "å的版本库 '%s'"
-#: builtin/push.c:332
+#: builtin/push.c:358
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -7100,83 +7652,87 @@ msgstr ""
"\n"
" git push <name>\n"
-#: builtin/push.c:347
+#: builtin/push.c:373
msgid "--all and --tags are incompatible"
msgstr "--all å’Œ --tags ä¸å…¼å®¹"
-#: builtin/push.c:348
+#: builtin/push.c:374
msgid "--all can't be combined with refspecs"
msgstr "--all ä¸èƒ½å’Œå¼•ç”¨è¡¨è¾¾å¼åŒæ—¶ä½¿ç”¨"
-#: builtin/push.c:353
+#: builtin/push.c:379
msgid "--mirror and --tags are incompatible"
msgstr "--mirror å’Œ --tags ä¸å…¼å®¹"
-#: builtin/push.c:354
+#: builtin/push.c:380
msgid "--mirror can't be combined with refspecs"
msgstr "--mirror ä¸èƒ½å’Œå¼•ç”¨è¡¨è¾¾å¼åŒæ—¶ä½¿ç”¨"
-#: builtin/push.c:359
+#: builtin/push.c:385
msgid "--all and --mirror are incompatible"
msgstr "--all å’Œ --mirror ä¸å…¼å®¹"
-#: builtin/push.c:419
+#: builtin/push.c:445
msgid "repository"
msgstr "版本库"
-#: builtin/push.c:420
+#: builtin/push.c:446
msgid "push all refs"
msgstr "推é€æ‰€æœ‰å¼•ç”¨"
-#: builtin/push.c:421
+#: builtin/push.c:447
msgid "mirror all refs"
msgstr "é•œåƒæ‰€æœ‰å¼•ç”¨"
-#: builtin/push.c:423
+#: builtin/push.c:449
msgid "delete refs"
msgstr "删除引用"
-#: builtin/push.c:424
+#: builtin/push.c:450
msgid "push tags (can't be used with --all or --mirror)"
msgstr "æŽ¨é€ tags(ä¸èƒ½ä½¿ç”¨ --all or --mirror)"
-#: builtin/push.c:427
+#: builtin/push.c:453
msgid "force updates"
msgstr "强制更新"
-#: builtin/push.c:428
+#: builtin/push.c:454
msgid "check"
msgstr "检查"
-#: builtin/push.c:429
+#: builtin/push.c:455
msgid "control recursive pushing of submodules"
msgstr "控制å­æ¨¡ç»„的递归推é€"
-#: builtin/push.c:431
+#: builtin/push.c:457
msgid "use thin pack"
msgstr "使用精简打包"
-#: builtin/push.c:432 builtin/push.c:433
+#: builtin/push.c:458 builtin/push.c:459
msgid "receive pack program"
msgstr "接收包程åº"
-#: builtin/push.c:434
+#: builtin/push.c:460
msgid "set upstream for git pull/status"
msgstr "设置 git pull/status 的上游"
-#: builtin/push.c:437
+#: builtin/push.c:463
msgid "prune locally removed refs"
msgstr "清除本地删除的引用"
-#: builtin/push.c:439
+#: builtin/push.c:465
msgid "bypass pre-push hook"
msgstr "绕过 pre-push é’©å­"
-#: builtin/push.c:448
+#: builtin/push.c:466
+msgid "push missing but relevant tags"
+msgstr "推é€ç¼ºå¤±çš„有关的 tags"
+
+#: builtin/push.c:476
msgid "--delete is incompatible with --all, --mirror and --tags"
msgstr "--delete 与 --allã€--mirror åŠ --tags ä¸å…¼å®¹"
-#: builtin/push.c:450
+#: builtin/push.c:478
msgid "--delete doesn't make sense without any refs"
msgstr "--delete 未接任何引用没有æ„义"
@@ -7190,70 +7746,80 @@ msgstr ""
"u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
"index-output=<文件>] (--empty | <树或æ交1> [<树或æ交2> [<树或æ交3>]])"
-#: builtin/read-tree.c:108
+#: builtin/read-tree.c:109
msgid "write resulting index to <file>"
msgstr "将索引结果写入 <file>"
-#: builtin/read-tree.c:111
+#: builtin/read-tree.c:112
msgid "only empty the index"
msgstr "åªæ˜¯æ¸…空索引"
-#: builtin/read-tree.c:113
+#: builtin/read-tree.c:114
msgid "Merging"
msgstr "åˆå¹¶"
-#: builtin/read-tree.c:115
+#: builtin/read-tree.c:116
msgid "perform a merge in addition to a read"
msgstr "读å–之余å†æ‰§è¡Œä¸€ä¸ªåˆå¹¶"
-#: builtin/read-tree.c:117
+#: builtin/read-tree.c:118
msgid "3-way merge if no file level merging required"
msgstr "如果没有文件级åˆå¹¶éœ€è¦ï¼Œæ‰§è¡Œä¸‰è·¯åˆå¹¶"
-#: builtin/read-tree.c:119
+#: builtin/read-tree.c:120
msgid "3-way merge in presence of adds and removes"
msgstr "存在添加和删除时,也执行三路åˆå¹¶"
-#: builtin/read-tree.c:121
+#: builtin/read-tree.c:122
msgid "same as -m, but discard unmerged entries"
msgstr "类似于 -m,但丢弃未åˆå¹¶çš„æ¡ç›®"
-#: builtin/read-tree.c:122
+#: builtin/read-tree.c:123
msgid "<subdirectory>/"
msgstr "<å­ç›®å½•>/"
-#: builtin/read-tree.c:123
+#: builtin/read-tree.c:124
msgid "read the tree into the index under <subdirectory>/"
msgstr "读å–树对象到索引的 <å­ç›®å½•>/ 下"
-#: builtin/read-tree.c:126
+#: builtin/read-tree.c:127
msgid "update working tree with merge result"
msgstr "用åˆå¹¶çš„结果更新工作区"
-#: builtin/read-tree.c:128
+#: builtin/read-tree.c:129
msgid "gitignore"
msgstr "gitignore"
-#: builtin/read-tree.c:129
+#: builtin/read-tree.c:130
msgid "allow explicitly ignored files to be overwritten"
msgstr "å…许忽略文件中设定的文件å¯ä»¥è¢«è¦†ç›–"
-#: builtin/read-tree.c:132
+#: builtin/read-tree.c:133
msgid "don't check the working tree after merging"
msgstr "åˆå¹¶åŽä¸æ£€æŸ¥å·¥ä½œåŒº"
-#: builtin/read-tree.c:133
+#: builtin/read-tree.c:134
msgid "don't update the index or the work tree"
msgstr "ä¸æ›´æ–°ç´¢å¼•åŒºå’Œå·¥ä½œåŒº"
-#: builtin/read-tree.c:135
+#: builtin/read-tree.c:136
msgid "skip applying sparse checkout filter"
msgstr "跳过应用稀ç–检出过滤器"
-#: builtin/read-tree.c:137
+#: builtin/read-tree.c:138
msgid "debug unpack-trees"
msgstr "调试 unpack-trees"
+#: builtin/reflog.c:500
+#, c-format
+msgid "%s' for '%s' is not a valid timestamp"
+msgstr "'%2$s' 的值 '%1$s' ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„时间戳"
+
+#: builtin/reflog.c:616 builtin/reflog.c:621
+#, c-format
+msgid "'%s' is not a valid timestamp"
+msgstr "'%s' ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„时间戳"
+
#: builtin/remote.c:11
msgid "git remote [-v | --verbose]"
msgstr "git remote [-v | --verbose]"
@@ -7824,98 +8390,98 @@ msgstr "无法找到 HEAD 指å‘的树。"
msgid "Failed to find tree of %s."
msgstr "无法找到 %s 指å‘的树。"
-#: builtin/reset.c:98
+#: builtin/reset.c:99
#, c-format
msgid "HEAD is now at %s"
msgstr "HEAD 现在ä½äºŽ %s"
# 译者:汉字之间无空格,故删除%så‰åŽç©ºæ ¼
-#: builtin/reset.c:169
+#: builtin/reset.c:172
#, c-format
msgid "Cannot do a %s reset in the middle of a merge."
msgstr "在åˆå¹¶è¿‡ç¨‹ä¸­ä¸èƒ½åš%sé‡ç½®æ“作。"
-#: builtin/reset.c:248
+#: builtin/reset.c:251
msgid "be quiet, only report errors"
msgstr "安é™æ¨¡å¼ï¼ŒåªæŠ¥å‘Šé”™è¯¯"
-#: builtin/reset.c:250
+#: builtin/reset.c:253
msgid "reset HEAD and index"
msgstr "é‡ç½® HEAD 和索引"
-#: builtin/reset.c:251
+#: builtin/reset.c:254
msgid "reset only HEAD"
msgstr "åªé‡ç½® HEAD"
-#: builtin/reset.c:253 builtin/reset.c:255
+#: builtin/reset.c:256 builtin/reset.c:258
msgid "reset HEAD, index and working tree"
msgstr "é‡ç½® HEADã€ç´¢å¼•å’Œå·¥ä½œåŒº"
-#: builtin/reset.c:257
+#: builtin/reset.c:260
msgid "reset HEAD but keep local changes"
msgstr "é‡ç½® HEAD 但ä¿å­˜æœ¬åœ°å˜æ›´"
-#: builtin/reset.c:275
+#: builtin/reset.c:278
#, c-format
msgid "Failed to resolve '%s' as a valid revision."
msgstr "无法将 '%s' 解æžä¸ºä¸€ä¸ªæœ‰æ•ˆçš„版本。"
-#: builtin/reset.c:278 builtin/reset.c:286
+#: builtin/reset.c:281 builtin/reset.c:289
#, c-format
msgid "Could not parse object '%s'."
msgstr "ä¸èƒ½è§£æžå¯¹è±¡ '%s'。"
-#: builtin/reset.c:283
+#: builtin/reset.c:286
#, c-format
msgid "Failed to resolve '%s' as a valid tree."
msgstr "无法将 '%s' 解æžä¸ºä¸€ä¸ªæœ‰æ•ˆçš„树对象。"
-#: builtin/reset.c:292
+#: builtin/reset.c:295
msgid "--patch is incompatible with --{hard,mixed,soft}"
msgstr "--patch 与 --{hardã€mixedã€soft} 选项ä¸å…¼å®¹"
-#: builtin/reset.c:301
+#: builtin/reset.c:304
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr "--mixed 带路径已弃用,而是用 'git reset -- <paths>'。"
# 译者:汉字之间无空格,故删除%så‰åŽç©ºæ ¼
-#: builtin/reset.c:303
+#: builtin/reset.c:306
#, c-format
msgid "Cannot do %s reset with paths."
msgstr "ä¸èƒ½å¸¦è·¯å¾„进行%sé‡ç½®ã€‚"
# 译者:汉字之间无空格,故删除%så‰åŽç©ºæ ¼
-#: builtin/reset.c:313
+#: builtin/reset.c:316
#, c-format
msgid "%s reset is not allowed in a bare repository"
msgstr "ä¸èƒ½å¯¹è£¸ç‰ˆæœ¬åº“进行%sé‡ç½®"
-#: builtin/reset.c:333
+#: builtin/reset.c:336
#, c-format
msgid "Could not reset index file to revision '%s'."
msgstr "ä¸èƒ½é‡ç½®ç´¢å¼•æ–‡ä»¶è‡³ç‰ˆæœ¬ '%s'。"
-#: builtin/reset.c:339
+#: builtin/reset.c:342
msgid "Unstaged changes after reset:"
msgstr "é‡ç½®åŽæ’¤å‡ºæš‚存区的å˜æ›´ï¼š"
-#: builtin/reset.c:344
+#: builtin/reset.c:347
msgid "Could not write new index file."
msgstr "ä¸èƒ½å†™å…¥æ–°çš„索引文件。"
-#: builtin/rev-parse.c:339
+#: builtin/rev-parse.c:345
msgid "git rev-parse --parseopt [options] -- [<args>...]"
msgstr "git rev-parse --parseopt [选项] -- [<å‚æ•°>...]"
-#: builtin/rev-parse.c:344
+#: builtin/rev-parse.c:350
msgid "keep the `--` passed as an arg"
msgstr "ä¿æŒ `--` 作为一个å‚数传递"
-#: builtin/rev-parse.c:346
+#: builtin/rev-parse.c:352
msgid "stop parsing after the first non-option argument"
msgstr "é‡åˆ°ç¬¬ä¸€ä¸ªéžé€‰é¡¹å‚æ•°åŽåœæ­¢è§£æž"
-#: builtin/rev-parse.c:464
+#: builtin/rev-parse.c:470
msgid ""
"git rev-parse --parseopt [options] -- [<args>...]\n"
" or: git rev-parse --sq-quote [<arg>...]\n"
@@ -7930,190 +8496,210 @@ msgstr ""
"åˆæ¬¡ä½¿ç”¨æ—¶æ‰§è¡Œ \"git rev-parse --parseopt -h\" æ¥èŽ·å¾—更多信æ¯ã€‚"
#: builtin/revert.c:22
-msgid "git revert [options] <commit-ish>"
-msgstr "git revert [选项] <æ交å·>"
+msgid "git revert [options] <commit-ish>..."
+msgstr "git revert [选项] <æ交å·>..."
#: builtin/revert.c:23
msgid "git revert <subcommand>"
msgstr "git revert <å­å‘½ä»¤>"
#: builtin/revert.c:28
-msgid "git cherry-pick [options] <commit-ish>"
-msgstr "git cherry-pick [选项] <æ交å·>"
+msgid "git cherry-pick [options] <commit-ish>..."
+msgstr "git cherry-pick [选项] <æ交å·>..."
#: builtin/revert.c:29
msgid "git cherry-pick <subcommand>"
msgstr "git cherry-pick <å­å‘½ä»¤>"
-#: builtin/revert.c:70 builtin/revert.c:92
+#: builtin/revert.c:71 builtin/revert.c:94
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨"
-#: builtin/revert.c:103
+#: builtin/revert.c:105
msgid "end revert or cherry-pick sequence"
msgstr "终止å转或拣选æ“作"
-#: builtin/revert.c:104
+#: builtin/revert.c:106
msgid "resume revert or cherry-pick sequence"
msgstr "继续å转或拣选æ“作"
-#: builtin/revert.c:105
+#: builtin/revert.c:107
msgid "cancel revert or cherry-pick sequence"
msgstr "å–消å转或拣选æ“作"
-#: builtin/revert.c:106
+#: builtin/revert.c:108
msgid "don't automatically commit"
msgstr "ä¸è¦è‡ªåŠ¨æ交"
-#: builtin/revert.c:107
+#: builtin/revert.c:109
msgid "edit the commit message"
msgstr "编辑æ交说明"
-#: builtin/revert.c:110
+#: builtin/revert.c:112
msgid "parent number"
msgstr "父编å·"
-#: builtin/revert.c:112
+#: builtin/revert.c:114
msgid "merge strategy"
msgstr "åˆå¹¶ç­–ç•¥"
-#: builtin/revert.c:113
+#: builtin/revert.c:115
msgid "option"
msgstr "选项"
-#: builtin/revert.c:114
+#: builtin/revert.c:116
msgid "option for merge strategy"
msgstr "åˆå¹¶ç­–略的选项"
-#: builtin/revert.c:125
+#: builtin/revert.c:127
msgid "append commit name"
msgstr "追加æ交å称"
-#: builtin/revert.c:126
+#: builtin/revert.c:128
msgid "allow fast-forward"
msgstr "å…许快进å¼"
-#: builtin/revert.c:127
+#: builtin/revert.c:129
msgid "preserve initially empty commits"
msgstr "ä¿ç•™åˆå§‹åŒ–的空æ交"
-#: builtin/revert.c:128
+#: builtin/revert.c:130
msgid "allow commits with empty messages"
msgstr "å…许æ交说明为空"
-#: builtin/revert.c:129
+#: builtin/revert.c:131
msgid "keep redundant, empty commits"
msgstr "ä¿æŒå¤šä½™çš„ã€ç©ºçš„æ交"
-#: builtin/revert.c:133
+#: builtin/revert.c:135
msgid "program error"
msgstr "程åºé”™è¯¯"
-#: builtin/revert.c:223
+#: builtin/revert.c:225
msgid "revert failed"
msgstr "还原失败"
-#: builtin/revert.c:238
+#: builtin/revert.c:240
msgid "cherry-pick failed"
msgstr "拣选失败"
-#: builtin/rm.c:15
+#: builtin/rm.c:16
msgid "git rm [options] [--] <file>..."
msgstr "git rm [选项] [--] <文件>..."
-#: builtin/rm.c:64 builtin/rm.c:186
-#, c-format
+#: builtin/rm.c:64
msgid ""
-"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"the following submodule (or one of its nested submodules)\n"
+"uses a .git directory:"
+msgid_plural ""
+"the following submodules (or one of its nested submodules)\n"
+"use a .git directory:"
+msgstr[0] "如下å­æ¨¡ç»„(或一个其嵌套å­æ¨¡ç»„)使用了一个 .git 目录:"
+msgstr[1] "如下å­æ¨¡ç»„(或一个其嵌套å­æ¨¡ç»„)使用了一个 .git 目录:"
+
+#: builtin/rm.c:70
+msgid ""
+"\n"
"(use 'rm -rf' if you really want to remove it including all of its history)"
msgstr ""
-"å­æ¨¡ç»„ '%s'(或者它的一个嵌套å­æ¨¡ç»„)使用一个 .git 目录\n"
+"\n"
"(使用 'rm -rf' 命令如果您真的想删除它åŠå…¶å…¨éƒ¨åŽ†å²ï¼‰"
-#: builtin/rm.c:174
-#, c-format
+#: builtin/rm.c:230
+msgid ""
+"the following file has staged content different from both the\n"
+"file and the HEAD:"
+msgid_plural ""
+"the following files have staged content different from both the\n"
+"file and the HEAD:"
+msgstr[0] "å¦‚ä¸‹æ–‡ä»¶å…¶æš‚å­˜çš„å†…å®¹å’Œå·¥ä½œåŒºåŠ HEAD 中的都ä¸ä¸€æ ·ï¼š"
+msgstr[1] "å¦‚ä¸‹æ–‡ä»¶å…¶æš‚å­˜çš„å†…å®¹å’Œå·¥ä½œåŒºåŠ HEAD 中的都ä¸ä¸€æ ·ï¼š"
+
+#: builtin/rm.c:235
msgid ""
-"'%s' has staged content different from both the file and the HEAD\n"
+"\n"
"(use -f to force removal)"
msgstr ""
-"'%s' æš‚å­˜çš„å†…å®¹å’Œå·¥ä½œåŒºåŠ HEAD 中的都ä¸ä¸€æ ·\n"
+"\n"
"(使用 -f 强制删除)"
-#: builtin/rm.c:180
-#, c-format
-msgid ""
-"'%s' has changes staged in the index\n"
-"(use --cached to keep the file, or -f to force removal)"
-msgstr ""
-"'%s' 有å˜æ›´å·²æš‚存至索引中\n"
-"(使用 --cached ä¿å­˜æ–‡ä»¶ï¼Œæˆ–用 -f 强制删除)"
+#: builtin/rm.c:239
+msgid "the following file has changes staged in the index:"
+msgid_plural "the following files have changes staged in the index:"
+msgstr[0] "如下文件相对索引区的内容有修改"
+msgstr[1] "如下文件相对索引区的内容有修改"
-#: builtin/rm.c:191
-#, c-format
+#: builtin/rm.c:243 builtin/rm.c:254
msgid ""
-"'%s' has local modifications\n"
+"\n"
"(use --cached to keep the file, or -f to force removal)"
msgstr ""
-"'%s' 有本地修改\n"
-"(使用 --cached ä¿å­˜æ–‡ä»¶ï¼Œæˆ–用 -f 强制删除)"
+"\n"
+"(使用 --cached ä¿ç•™æœ¬åœ°æ–‡ä»¶ï¼Œæˆ–用 -f 强制删除)"
+
+#: builtin/rm.c:251
+msgid "the following file has local modifications:"
+msgid_plural "the following files have local modifications:"
+msgstr[0] "如下文件有本地修改:"
+msgstr[1] "如下文件有本地修改:"
-#: builtin/rm.c:207
+#: builtin/rm.c:269
msgid "do not list removed files"
msgstr "ä¸åˆ—出删除的文件"
-#: builtin/rm.c:208
+#: builtin/rm.c:270
msgid "only remove from the index"
msgstr "åªä»Žç´¢å¼•åŒºåˆ é™¤"
-#: builtin/rm.c:209
+#: builtin/rm.c:271
msgid "override the up-to-date check"
msgstr "忽略文件更新状æ€æ£€æŸ¥"
-#: builtin/rm.c:210
+#: builtin/rm.c:272
msgid "allow recursive removal"
msgstr "å…许递归删除"
-#: builtin/rm.c:212
+#: builtin/rm.c:274
msgid "exit with a zero status even if nothing matched"
msgstr "å³ä½¿æ²¡æœ‰åŒ¹é…,也以零状æ€é€€å‡º"
-#: builtin/rm.c:283
+#: builtin/rm.c:345
#, c-format
msgid "not removing '%s' recursively without -r"
msgstr "未æä¾› -r 选项ä¸ä¼šé€’归删除 '%s'"
-#: builtin/rm.c:322
+#: builtin/rm.c:384
#, c-format
msgid "git rm: unable to remove %s"
msgstr "git rm:ä¸èƒ½åˆ é™¤ %s"
#: builtin/shortlog.c:13
-msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
-msgstr "git shortlog [-n] [-s] [-e] [-w] [版本选项] [--] [<æ交å·>... ]"
+msgid "git shortlog [<options>] [<revision range>] [[--] [<path>...]]"
+msgstr "git shortlog [<选项>] [<版本范围>] [[--] [<路径>...]]"
-#: builtin/shortlog.c:133
+#: builtin/shortlog.c:131
#, c-format
msgid "Missing author: %s"
msgstr "缺少作者:%s"
-#: builtin/shortlog.c:229
+#: builtin/shortlog.c:228
msgid "sort output according to the number of commits per author"
msgstr "æ ¹æ®æ¯ä¸ªä½œè€…çš„æ交数é‡æŽ’åº"
-#: builtin/shortlog.c:231
+#: builtin/shortlog.c:230
msgid "Suppress commit descriptions, only provides commit count"
msgstr "éšè—æ交说明,åªæä¾›æ交数é‡"
-#: builtin/shortlog.c:233
+#: builtin/shortlog.c:232
msgid "Show the email address of each author"
msgstr "显示æ¯ä¸ªä½œè€…的电å­é‚®ä»¶åœ°å€"
-#: builtin/shortlog.c:234
+#: builtin/shortlog.c:233
msgid "w[,i1[,i2]]"
msgstr "w[,i1[,i2]]"
-#: builtin/shortlog.c:235
+#: builtin/shortlog.c:234
msgid "Linewrap output"
msgstr "折行输出"
@@ -8133,47 +8719,47 @@ msgstr ""
msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
msgstr "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
-#: builtin/show-branch.c:651
+#: builtin/show-branch.c:650
msgid "show remote-tracking and local branches"
msgstr "显示远程跟踪的和本地的分支"
-#: builtin/show-branch.c:653
+#: builtin/show-branch.c:652
msgid "show remote-tracking branches"
msgstr "显示远程跟踪的分支"
-#: builtin/show-branch.c:655
+#: builtin/show-branch.c:654
msgid "color '*!+-' corresponding to the branch"
msgstr "ç€è‰² '*!+-' 到相应的分支"
-#: builtin/show-branch.c:657
+#: builtin/show-branch.c:656
msgid "show <n> more commits after the common ancestor"
msgstr "显示共åŒç¥–å…ˆåŽçš„ <n> 个æ交"
-#: builtin/show-branch.c:659
+#: builtin/show-branch.c:658
msgid "synonym to more=-1"
msgstr "å’Œ more=-1 åŒä¹‰"
-#: builtin/show-branch.c:660
+#: builtin/show-branch.c:659
msgid "suppress naming strings"
msgstr "ä¸æ˜¾ç¤ºå­—符串命å"
-#: builtin/show-branch.c:662
+#: builtin/show-branch.c:661
msgid "include the current branch"
msgstr "包括当å‰åˆ†æ”¯"
-#: builtin/show-branch.c:664
+#: builtin/show-branch.c:663
msgid "name commits with their object names"
msgstr "以对象å字命åæ交"
-#: builtin/show-branch.c:666
+#: builtin/show-branch.c:665
msgid "show possible merge bases"
msgstr "显示å¯èƒ½åˆå¹¶çš„基线"
-#: builtin/show-branch.c:668
+#: builtin/show-branch.c:667
msgid "show refs unreachable from any other ref"
msgstr "显示没有任何引用的的引用"
-#: builtin/show-branch.c:670
+#: builtin/show-branch.c:669
msgid "show commits in topological order"
msgstr "以拓扑顺åºæ˜¾ç¤ºæ交"
@@ -8186,14 +8772,14 @@ 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 "显示æ交时以时间为åºä¸”父æ交ä¸èƒ½é¢†å…ˆå­æ交"
+msgid "topologically sort, maintaining date order where possible"
+msgstr "拓扑方å¼æŽ’åºï¼Œå¹¶å°½å¯èƒ½åœ°ä¿æŒæ—¥æœŸé¡ºåº"
-#: builtin/show-branch.c:678
+#: builtin/show-branch.c:679
msgid "<n>[,<base>]"
msgstr "<n>[,<base>]"
-#: builtin/show-branch.c:679
+#: builtin/show-branch.c:680
msgid "show <n> most recent ref-log entries starting at base"
msgstr "显示从 base 开始的 <n> æ¡æœ€è¿‘的引用日志记录"
@@ -8209,35 +8795,35 @@ msgstr ""
msgid "git show-ref --exclude-existing[=pattern] < ref-list"
msgstr "git show-ref --exclude-existing[=模å¼] < 引用列表"
-#: builtin/show-ref.c:165
+#: builtin/show-ref.c:168
msgid "only show tags (can be combined with heads)"
msgstr "åªæ˜¾ç¤º tags(å¯ä»¥å’Œå¤´å…±ç”¨ï¼‰"
-#: builtin/show-ref.c:166
+#: builtin/show-ref.c:169
msgid "only show heads (can be combined with tags)"
msgstr "åªæ˜¾ç¤ºå¤´ï¼ˆå¯ä»¥å’Œ tags 共用)"
-#: builtin/show-ref.c:167
+#: builtin/show-ref.c:170
msgid "stricter reference checking, requires exact ref path"
msgstr "更严格的引用检测,需è¦ç²¾ç¡®çš„引用路径"
-#: builtin/show-ref.c:170 builtin/show-ref.c:172
-msgid "show the HEAD reference"
-msgstr "显示 HEAD 引用"
+#: builtin/show-ref.c:173 builtin/show-ref.c:176
+msgid "show the HEAD reference, even if it would be filtered out"
+msgstr "显示 HEAD 引用,å³ä½¿è¢«è¿‡æ»¤æŽ‰"
-#: builtin/show-ref.c:174
+#: builtin/show-ref.c:178
msgid "dereference tags into object IDs"
msgstr "è½¬æ¢ tags 到对象ID"
-#: builtin/show-ref.c:176
+#: builtin/show-ref.c:180
msgid "only show SHA1 hash using <n> digits"
msgstr "åªæ˜¾ç¤ºä½¿ç”¨ <n> 个数字的 SHA1 哈希"
-#: builtin/show-ref.c:180
+#: builtin/show-ref.c:184
msgid "do not print results to stdout (useful with --verify)"
msgstr "ä¸æ‰“å°ç»“果到标准输出(例如与 --verify å‚数共用)"
-#: builtin/show-ref.c:182
+#: builtin/show-ref.c:186
msgid "show refs from stdin that aren't in local repository"
msgstr "显示从标准输入中读入的ä¸åœ¨æœ¬åœ°ç‰ˆæœ¬åº“中的引用"
@@ -8649,23 +9235,32 @@ msgstr "å°† <å‰ç¼€> å­ç›®å½•å†…容写到一个树对象"
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>' 以获得该特定命令的详细信æ¯ã€‚"
+#: git.c:17
+msgid ""
+"'git help -a' and 'git help -g' lists available subcommands and some\n"
+"concept guides. See 'git help <command>' or 'git help <concept>'\n"
+"to read about a specific subcommand or concept."
+msgstr ""
+"命令 'git help -a' å’Œ 'git help -g' 显示å¯ç”¨çš„å­å‘½ä»¤å’Œä¸€äº›æŒ‡å—。å‚è§\n"
+"'git help <命令>' 或 'git help <指å—>' æ¥æŸ¥çœ‹ç»™å®šçš„å­å‘½ä»¤å¸®åŠ©æˆ–指å—。"
+
+#: parse-options.h:144
+msgid "expiry date"
+msgstr "逾期日期"
-#: parse-options.h:156
+#: parse-options.h:159
msgid "no-op (backward compatibility)"
msgstr "空æ“作(å‘åŽå…¼å®¹ï¼‰"
-#: parse-options.h:232
+#: parse-options.h:236
msgid "be more verbose"
msgstr "更加详细"
-#: parse-options.h:234
+#: parse-options.h:238
msgid "be more quiet"
msgstr "更加安é™"
-#: parse-options.h:240
+#: parse-options.h:244
msgid "use <n> digits to display SHA-1s"
msgstr "用 <n> ä½æ•°å­—显示 SHA-1 哈希值"
@@ -8722,8 +9317,8 @@ msgid "Move or rename a file, a directory, or a symlink"
msgstr "移动或é‡å‘½å一个文件ã€ç›®å½•æˆ–符å·é“¾æŽ¥"
#: common-cmds.h:21
-msgid "Fetch from and merge with another repository or a local branch"
-msgstr "获å–并åˆå¹¶å¦å¤–的版本库或一个本地分支"
+msgid "Fetch from and integrate with another repository or a local branch"
+msgstr "获å–并整åˆå¦å¤–的版本库或一个本地分支"
#: common-cmds.h:22
msgid "Update remote refs along with associated objects"
@@ -8766,11 +9361,11 @@ msgstr "您好åƒåœ¨ä¸Šä¸€æ¬¡ 'am' 失败åŽç§»åŠ¨äº† HEAD。未回退至 ORIG_H
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"When you have resolved this problem, run \"$cmdline --continue\".\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 --continue\"。\n"
"如果您想跳过此补ä¸ï¼Œåˆ™æ‰§è¡Œ \"$cmdline --skip\"。\n"
"è¦æ¢å¤åŽŸåˆ†æ”¯å¹¶åœæ­¢æ‰“è¡¥ä¸ï¼Œæ‰§è¡Œ \"$cmdline --abort\"。"
@@ -8823,25 +9418,34 @@ msgstr ""
"å‚æ•° -b/--binary å·²ç»å¾ˆé•¿æ—¶é—´ä¸åšä»»ä½•å®žè´¨æ“作了,并且将被删除。\n"
"请ä¸è¦å†ä½¿ç”¨å®ƒäº†ã€‚"
-#: git-am.sh:477
+#: git-am.sh:479
#, sh-format
msgid "previous rebase directory $dotest still exists but mbox given."
-msgstr "之å‰çš„å˜åŸºç›®å½• $dotest ä»ç„¶å­˜åœ¨ä½†ç»™å‡ºäº†mbox。"
+msgstr "之å‰çš„å˜åŸºç›®å½• $dotest ä»ç„¶å­˜åœ¨ï¼Œä½†å´æ供了 mbox。"
-#: git-am.sh:482
+#: git-am.sh:484
msgid "Please make up your mind. --skip or --abort?"
msgstr "请下决心。--skip 或是 --abort ?"
-#: git-am.sh:509
+#: git-am.sh:520
+#, sh-format
+msgid ""
+"Stray $dotest directory found.\n"
+"Use \"git am --abort\" to remove it."
+msgstr ""
+"å‘现了错误的 $dotest 目录。\n"
+"使用 \"git am --abort\" 删除它。"
+
+#: git-am.sh:528
msgid "Resolve operation not in progress, we are not resuming."
msgstr "解决æ“作未进行,我们ä¸ä¼šç»§ç»­ã€‚"
-#: git-am.sh:575
+#: git-am.sh:594
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
msgstr "è„的索引:ä¸èƒ½åº”用补ä¸ï¼ˆè„文件:$files)"
-#: git-am.sh:679
+#: git-am.sh:698
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\n"
@@ -8852,15 +9456,15 @@ msgstr ""
"如果您想è¦è·³è¿‡è¿™ä¸ªè¡¥ä¸ï¼Œæ‰§è¡Œ \"$cmdline --skip\"。\n"
"è¦æ¢å¤åŽŸåˆ†æ”¯å¹¶åœæ­¢æ‰“è¡¥ä¸ï¼Œæ‰§è¡Œ \"$cmdline --abort\"。"
-#: git-am.sh:706
+#: git-am.sh:725
msgid "Patch does not have a valid e-mail address."
msgstr "è¡¥ä¸ä¸­æ²¡æœ‰ä¸€ä¸ªæœ‰æ•ˆçš„邮件地å€ã€‚"
-#: git-am.sh:753
+#: git-am.sh:772
msgid "cannot be interactive without stdin connected to a terminal."
msgstr "标准输入没有和终端关è”,ä¸èƒ½è¿›è¡Œäº¤äº’å¼æ“作。"
-#: git-am.sh:757
+#: git-am.sh:776
msgid "Commit Body is:"
msgstr "æ交内容为:"
@@ -8868,16 +9472,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:764
+#: git-am.sh:783
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:800
+#: git-am.sh:819
#, sh-format
msgid "Applying: $FIRSTLINE"
msgstr "正应用:$FIRSTLINE"
-#: git-am.sh:821
+#: git-am.sh:840
msgid ""
"No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
@@ -8887,22 +9491,22 @@ msgstr ""
"如果没有什么è¦æ·»åŠ åˆ°æš‚存区的,则很å¯èƒ½æ˜¯å…¶å®ƒæ交已ç»å¼•å…¥äº†ç›¸åŒçš„å˜æ›´ã€‚\n"
"您也许想è¦è·³è¿‡è¿™ä¸ªè¡¥ä¸ã€‚"
-#: git-am.sh:829
+#: git-am.sh:848
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
msgstr "您的索引中ä»æœ‰æœªåˆå¹¶çš„路径。您是å¦å¿˜äº†æ‰§è¡Œ 'git add'?"
-#: git-am.sh:845
+#: git-am.sh:864
msgid "No changes -- Patch already applied."
msgstr "没有å˜æ›´ —— è¡¥ä¸å·²ç»åº”用过。"
-#: git-am.sh:855
+#: git-am.sh:874
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
msgstr "è¡¥ä¸å¤±è´¥äºŽ $msgnum $FIRSTLINE"
-#: git-am.sh:858
+#: git-am.sh:877
#, sh-format
msgid ""
"The copy of the patch that failed is found in:\n"
@@ -8911,7 +9515,7 @@ msgstr ""
"失败的补ä¸æ–‡ä»¶å‰¯æœ¬ä½äºŽï¼š\n"
" $dotest/patch"
-#: git-am.sh:876
+#: git-am.sh:895
msgid "applying to an empty history"
msgstr "正应用到一个空历å²ä¸Š"
@@ -9010,16 +9614,16 @@ msgstr ""
"然åŽéœ€è¦æ供我至少一个好版本和一个å版本。\n"
"(您å¯ä»¥ç”¨ \"git bisect bad\" å’Œ \"git bisect good\" 命令æ¥æ ‡è¯†ã€‚)"
-#: git-bisect.sh:347 git-bisect.sh:474
+#: git-bisect.sh:363 git-bisect.sh:490
msgid "We are not bisecting."
msgstr "我们没有在二分查找。"
-#: git-bisect.sh:354
+#: git-bisect.sh:370
#, sh-format
msgid "'$invalid' is not a valid commit"
msgstr "'$invalid' ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„æ交"
-#: git-bisect.sh:363
+#: git-bisect.sh:379
#, sh-format
msgid ""
"Could not check out original HEAD '$branch'.\n"
@@ -9028,25 +9632,25 @@ msgstr ""
"ä¸èƒ½æ£€å‡ºåŽŸå§‹ HEAD '$branch'。\n"
"å°è¯• 'git bisect reset <æ交>'。"
-#: git-bisect.sh:390
+#: git-bisect.sh:406
msgid "No logfile given"
msgstr "未æ供日志文件"
-#: git-bisect.sh:391
+#: git-bisect.sh:407
#, sh-format
msgid "cannot read $file for replaying"
msgstr "ä¸èƒ½è¯»å– $file æ¥é‡æ”¾"
-#: git-bisect.sh:408
+#: git-bisect.sh:424
msgid "?? what are you talking about?"
msgstr "?? 您在说什么?"
-#: git-bisect.sh:420
+#: git-bisect.sh:436
#, sh-format
msgid "running $command"
msgstr "è¿è¡Œ $command"
-#: git-bisect.sh:427
+#: git-bisect.sh:443
#, sh-format
msgid ""
"bisect run failed:\n"
@@ -9055,11 +9659,11 @@ msgstr ""
"二分查找è¿è¡Œå¤±è´¥ï¼š\n"
"命令 '$command' çš„é€€å‡ºç  $res å°äºŽ 0 或大于等于 128"
-#: git-bisect.sh:453
+#: git-bisect.sh:469
msgid "bisect run cannot continue any more"
msgstr "二分查找ä¸èƒ½ç»§ç»­è¿è¡Œ"
-#: git-bisect.sh:459
+#: git-bisect.sh:475
#, sh-format
msgid ""
"bisect run failed:\n"
@@ -9068,7 +9672,7 @@ msgstr ""
"二分查找è¿è¡Œå¤±è´¥ï¼š\n"
"'bisect_state $state' 退出ç ä¸º $res"
-#: git-bisect.sh:466
+#: git-bisect.sh:482
msgid "bisect run success"
msgstr "二分查找è¿è¡ŒæˆåŠŸ"
@@ -9086,7 +9690,7 @@ msgstr ""
msgid "Pull is not possible because you have unmerged files."
msgstr "Pull ä¸å¯ç”¨ï¼Œå› ä¸ºæ‚¨å°šæœ‰æœªåˆå¹¶çš„文件。"
-#: git-pull.sh:197
+#: git-pull.sh:203
msgid "updating an unborn branch with changes added to the index"
msgstr "更新尚未诞生的分支,å˜æ›´æ·»åŠ è‡³ç´¢å¼•"
@@ -9094,7 +9698,7 @@ msgstr "更新尚未诞生的分支,å˜æ›´æ·»åŠ è‡³ç´¢å¼•"
#. The working tree and the index file is still based on the
#. $orig_head commit, but we are merging into $curr_head.
#. First update the working tree to match $curr_head.
-#: git-pull.sh:229
+#: git-pull.sh:235
#, sh-format
msgid ""
"Warning: fetch updated the current branch head.\n"
@@ -9104,15 +9708,15 @@ msgstr ""
"警告:fetch 更新了当å‰çš„分支。您的工作区\n"
"警告:从原æ交 $orig_head 快进。"
-#: git-pull.sh:254
+#: git-pull.sh:260
msgid "Cannot merge multiple branches into empty head"
msgstr "无法将多个分支åˆå¹¶åˆ°ç©ºåˆ†æ”¯"
-#: git-pull.sh:258
+#: git-pull.sh:264
msgid "Cannot rebase onto multiple branches"
msgstr "无法å˜åŸºåˆ°å¤šä¸ªåˆ†æ”¯"
-#: git-rebase.sh:53
+#: git-rebase.sh:54
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"
@@ -9123,31 +9727,50 @@ msgstr ""
"如果您想跳过此补ä¸ï¼Œåˆ™æ‰§è¡Œ \"git rebase --skip\"。\n"
"è¦æ¢å¤åŽŸåˆ†æ”¯å¹¶åœæ­¢å˜åŸºï¼Œæ‰§è¡Œ \"git rebase --abort\"。"
+#: git-rebase.sh:156
+msgid "Applied autostash."
+msgstr "æˆåŠŸåº”用 autostash。"
+
+#: git-rebase.sh:159
+#, sh-format
+msgid "Cannot store $stash_sha1"
+msgstr "无法ä¿å­˜ $stash_sha1"
+
#: git-rebase.sh:160
+msgid ""
+"Applying autostash resulted in conflicts.\n"
+"Your changes are safe in the stash.\n"
+"You can run \"git stash pop\" or \"git stash drop\" at any time.\n"
+msgstr ""
+"应用 autostash 导致冲çªã€‚\n"
+"您的修改安全地ä¿å­˜åœ¨ stash 中。\n"
+"您å¯ä»¥åœ¨ä»»ä½•æ—¶å€™è¿è¡Œ \"git stash pop\" 或 \"git stash drop\"。\n"
+
+#: git-rebase.sh:190
msgid "The pre-rebase hook refused to rebase."
msgstr "é’©å­ pre-rebase æ‹’ç»å˜åŸºã€‚"
-#: git-rebase.sh:165
+#: git-rebase.sh:195
msgid "It looks like git-am is in progress. Cannot rebase."
msgstr "似乎正处于在 git-am 的执行过程中。无法å˜åŸºã€‚"
-#: git-rebase.sh:296
+#: git-rebase.sh:329
msgid "The --exec option must be used with the --interactive option"
msgstr "选项 --exec 必须和选项 --interactive åŒæ—¶ä½¿ç”¨"
-#: git-rebase.sh:301
+#: git-rebase.sh:334
msgid "No rebase in progress?"
msgstr "没有正在进行的å˜åŸºï¼Ÿ"
-#: git-rebase.sh:312
+#: git-rebase.sh:345
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr "动作 --edit-todo åªèƒ½ç”¨åœ¨äº¤äº’å¼å˜åŸºè¿‡ç¨‹ä¸­ã€‚"
-#: git-rebase.sh:319
+#: git-rebase.sh:352
msgid "Cannot read HEAD"
msgstr "ä¸èƒ½è¯»å– HEAD"
-#: git-rebase.sh:322
+#: git-rebase.sh:355
msgid ""
"You must edit all merge conflicts and then\n"
"mark them as resolved using git add"
@@ -9155,12 +9778,12 @@ msgstr ""
"您必须编辑所有的åˆå¹¶å†²çªï¼Œç„¶åŽé€šè¿‡ git add\n"
"命令将它们标记为已解决"
-#: git-rebase.sh:340
+#: git-rebase.sh:373
#, sh-format
msgid "Could not move back to $head_name"
msgstr "无法移回 $head_name"
-#: git-rebase.sh:359
+#: git-rebase.sh:392
#, sh-format
msgid ""
"It seems that there is already a $state_dir_base directory, and\n"
@@ -9179,56 +9802,65 @@ msgstr ""
"\t$cmd_clear_stale_rebase\n"
"然åŽå†é‡æ–°æ‰§è¡Œå˜åŸºã€‚为é¿å…您丢失é‡è¦æ•°æ®ï¼Œæˆ‘å·²ç»åœæ­¢å½“å‰æ“作。"
-#: git-rebase.sh:404
+#: git-rebase.sh:437
#, sh-format
msgid "invalid upstream $upstream_name"
msgstr "无效的上游 $upstream_name"
-#: git-rebase.sh:428
+#: git-rebase.sh:461
#, sh-format
msgid "$onto_name: there are more than one merge bases"
msgstr "$onto_name: 有一个以上的åˆå¹¶åŸºå‡†"
-#: git-rebase.sh:431 git-rebase.sh:435
+#: git-rebase.sh:464 git-rebase.sh:468
#, sh-format
msgid "$onto_name: there is no merge base"
msgstr "$onto_name: 没有åˆå¹¶åŸºå‡†"
-#: git-rebase.sh:440
+#: git-rebase.sh:473
#, sh-format
msgid "Does not point to a valid commit: $onto_name"
msgstr "没有指å‘一个有效的æ交:$onto_name"
-#: git-rebase.sh:463
+#: git-rebase.sh:496
#, sh-format
msgid "fatal: no such branch: $branch_name"
msgstr "严é‡é”™è¯¯ï¼šæ— æ­¤åˆ†æ”¯ï¼š$branch_name"
-#: git-rebase.sh:483
+#: git-rebase.sh:519
+msgid "Cannot autostash"
+msgstr "无法 autostash"
+
+#: git-rebase.sh:524
+#, sh-format
+msgid "Created autostash: $stash_abbrev"
+msgstr "创建了 autostash: $stash_abbrev"
+
+#: git-rebase.sh:528
msgid "Please commit or stash them."
msgstr "请æ交或为它们ä¿å­˜è¿›åº¦ã€‚"
-#: git-rebase.sh:501
+#: git-rebase.sh:548
#, sh-format
msgid "Current branch $branch_name is up to date."
msgstr "当å‰åˆ†æ”¯ $branch_name 是最新的。"
-#: git-rebase.sh:504
+#: git-rebase.sh:552
#, sh-format
msgid "Current branch $branch_name is up to date, rebase forced."
msgstr "当å‰åˆ†æ”¯ $branch_name 是最新的,强制å˜åŸºã€‚"
-#: git-rebase.sh:515
+#: git-rebase.sh:563
#, sh-format
msgid "Changes from $mb to $onto:"
msgstr "å˜æ›´ä»Ž $mb 到 $onto:"
#. Detach HEAD and reset the tree
-#: git-rebase.sh:524
+#: git-rebase.sh:572
msgid "First, rewinding head to replay your work on top of it..."
msgstr "首先,é‡ç½®å¤´æŒ‡é’ˆä»¥ä¾¿åœ¨ä¸Šé¢é‡æ”¾æ‚¨çš„工作..."
-#: git-rebase.sh:532
+#: git-rebase.sh:582
#, sh-format
msgid "Fast-forwarded $branch_name to $onto_name."
msgstr "快进 $branch_name 至 $onto_name。"
@@ -9261,6 +9893,11 @@ msgstr "无法删除临时索引(ä¸åº”å‘生)"
msgid "Cannot record working tree state"
msgstr "ä¸èƒ½è®°å½•å·¥ä½œåŒºçŠ¶æ€"
+#: git-stash.sh:190
+#, sh-format
+msgid "Cannot update $ref_stash with $w_commit"
+msgstr "无法用 $w_commit 更新 $ref_stash"
+
#. TRANSLATORS: $option is an invalid option, like
#. `--blah-blah'. The 7 spaces at the beginning of the
#. second line correspond to "error: ". So you should line
@@ -9271,7 +9908,7 @@ msgstr "ä¸èƒ½è®°å½•å·¥ä½œåŒºçŠ¶æ€"
#. $ git stash save --blah-blah 2>&1 | head -n 2
#. error: unknown option for 'stash save': --blah-blah
#. To provide a message, use git stash save -- '--blah-blah'
-#: git-stash.sh:202
+#: git-stash.sh:241
#, sh-format
msgid ""
"error: unknown option for 'stash save': $option\n"
@@ -9280,119 +9917,134 @@ msgstr ""
"错误:'stash save' 的未知选项:$option\n"
" è¦æ供一个æè¿°ä¿¡æ¯ï¼Œä½¿ç”¨ git stash save -- '$option'"
-#: git-stash.sh:223
+#: git-stash.sh:262
msgid "No local changes to save"
msgstr "没有è¦ä¿å­˜çš„本地修改"
-#: git-stash.sh:227
+#: git-stash.sh:268
+msgid ""
+"The following untracked files would NOT be saved but need to be removed by "
+"stash save:"
+msgstr "如下未跟踪文件将ä¸ä¼šè¢«ä¿å­˜ä½†æ˜¯å°†ä¼šå› ä¸ºè¿›åº¦ä¿å­˜è€Œéœ€è¦è¢«åˆ é™¤ï¼š"
+
+#: git-stash.sh:270
+msgid ""
+"Aborting. Consider using either the --force or --include-untracked option."
+msgstr "终止。考虑使用 --force 或者 --include-untracked 选项。"
+
+#: git-stash.sh:274
msgid "Cannot initialize stash"
msgstr "无法åˆå§‹åŒ– stash"
-#: git-stash.sh:235
+#: git-stash.sh:278
msgid "Cannot save the current status"
msgstr "无法ä¿å­˜å½“å‰çŠ¶æ€"
-#: git-stash.sh:253
+#: git-stash.sh:296
msgid "Cannot remove worktree changes"
msgstr "无法删除工作区å˜æ›´"
-#: git-stash.sh:352
+#: git-stash.sh:395
msgid "No stash found."
msgstr "未å‘现 stash。"
-#: git-stash.sh:359
+#: git-stash.sh:402
#, sh-format
msgid "Too many revisions specified: $REV"
msgstr "指定了太多的版本:$REV"
-#: git-stash.sh:365
+#: git-stash.sh:408
#, sh-format
msgid "$reference is not valid reference"
msgstr "$reference ä¸æ˜¯æœ‰æ•ˆçš„引用"
-#: git-stash.sh:393
+#: git-stash.sh:436
#, sh-format
msgid "'$args' is not a stash-like commit"
msgstr "'$args' ä¸æ˜¯ stash æ ·æ交"
-#: git-stash.sh:404
+#: git-stash.sh:447
#, sh-format
msgid "'$args' is not a stash reference"
msgstr "'$args' ä¸æ˜¯ä¸€ä¸ª stash 引用"
-#: git-stash.sh:412
+#: git-stash.sh:455
msgid "unable to refresh index"
msgstr "无法刷新索引"
-#: git-stash.sh:416
+#: git-stash.sh:459
msgid "Cannot apply a stash in the middle of a merge"
msgstr "无法在åˆå¹¶è¿‡ç¨‹ä¸­æ¢å¤è¿›åº¦"
-#: git-stash.sh:424
+#: git-stash.sh:467
msgid "Conflicts in index. Try without --index."
msgstr "索引中有冲çªã€‚å°è¯•ä¸ä½¿ç”¨ --index。"
-#: git-stash.sh:426
+#: git-stash.sh:469
msgid "Could not save index tree"
msgstr "ä¸èƒ½ä¿å­˜ç´¢å¼•æ ‘"
-#: git-stash.sh:460
+#: git-stash.sh:503
msgid "Cannot unstage modified files"
msgstr "无法还原修改的文件"
-#: git-stash.sh:475
+#: git-stash.sh:518
msgid "Index was not unstashed."
msgstr "索引的进度没有被æ¢å¤ã€‚"
-#: git-stash.sh:492
+#: git-stash.sh:535
#, sh-format
msgid "Dropped ${REV} ($s)"
msgstr "丢弃了 ${REV} ($s)"
-#: git-stash.sh:493
+#: git-stash.sh:536
#, sh-format
msgid "${REV}: Could not drop stash entry"
msgstr "${REV}:ä¸èƒ½ä¸¢å¼ƒè¿›åº¦æ¡ç›®"
-#: git-stash.sh:500
+#: git-stash.sh:543
msgid "No branch name specified"
msgstr "未指定分支å"
-#: git-stash.sh:571
+#: git-stash.sh:615
msgid "(To restore them type \"git stash apply\")"
msgstr "(为æ¢å¤æ•°æ®è¾“å…¥ \"git stash apply\")"
-#: git-submodule.sh:90
+#: git-submodule.sh:95
#, sh-format
msgid "cannot strip one component off url '$remoteurl'"
msgstr "无法从 url '$remoteurl' 剥离一个组件"
-#: git-submodule.sh:195
+#: git-submodule.sh:237
#, sh-format
msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
msgstr "未在 .gitmodules 中å‘现路径 '$sm_path' çš„å­æ¨¡ç»„映射"
-#: git-submodule.sh:238
+#: git-submodule.sh:281
#, sh-format
msgid "Clone of '$url' into submodule path '$sm_path' failed"
msgstr "无法克隆 '$url' 到å­æ¨¡ç»„路径 '$sm_path'"
-#: git-submodule.sh:250
+#: git-submodule.sh:293
#, sh-format
msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
msgstr "Gitdir '$a' 在å­æ¨¡ç»„路径 '$b' 之下或相å"
-#: git-submodule.sh:343
+#: git-submodule.sh:403
+msgid "Relative path can only be used from the toplevel of the working tree"
+msgstr "åªèƒ½åœ¨å·¥ä½œåŒºçš„顶级目录中使用相对路径"
+
+#: git-submodule.sh:413
#, sh-format
msgid "repo URL: '$repo' must be absolute or begin with ./|../"
msgstr "版本库URL:'$repo' 必须是ç»å¯¹è·¯å¾„或以 ./|../ 起始"
-#: git-submodule.sh:360
+#: git-submodule.sh:430
#, sh-format
msgid "'$sm_path' already exists in the index"
msgstr "'$sm_path' å·²ç»å­˜åœ¨äºŽç´¢å¼•ä¸­"
-#: git-submodule.sh:364
+#: git-submodule.sh:434
#, sh-format
msgid ""
"The following path is ignored by one of your .gitignore files:\n"
@@ -9403,188 +10055,377 @@ msgstr ""
"$sm_path\n"
"如果您确实想添加它,使用 -f å‚数。"
-#: git-submodule.sh:382
+#: git-submodule.sh:452
#, sh-format
msgid "Adding existing repo at '$sm_path' to the index"
msgstr "添加ä½äºŽ '$sm_path' 的现存版本库到索引"
-#: git-submodule.sh:384
+#: git-submodule.sh:454
#, sh-format
msgid "'$sm_path' already exists and is not a valid git repo"
msgstr "'$sm_path' 已存在且ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„ git 版本库"
-#: git-submodule.sh:392
+#: git-submodule.sh:462
#, sh-format
msgid "A git directory for '$sm_name' is found locally with remote(s):"
msgstr "本地å‘现 '$sm_name' 的一个 git 目录,与其对应的远程版本库:"
-#: git-submodule.sh:394
+#: git-submodule.sh:464
#, sh-format
msgid ""
"If you want to reuse this local git directory instead of cloning again from"
msgstr "如果您想é‡ç”¨æ­¤æœ¬åœ° git 目录而ä¸æ˜¯é‡æ–°å…‹éš†è‡ª"
-#: git-submodule.sh:396
+#: git-submodule.sh:466
#, sh-format
msgid ""
"use the '--force' option. If the local git directory is not the correct repo"
msgstr "使用 '--force' å‚数。如果本地 git 目录ä¸æ˜¯æ­£ç¡®çš„版本库"
-#: git-submodule.sh:397
+#: git-submodule.sh:467
#, sh-format
msgid ""
"or you are unsure what this means choose another name with the '--name' "
"option."
msgstr "或者您ä¸ç¡®å®šå…¶ä¸­å«ä¹‰ä½¿ç”¨ '--name' å‚数选择å¦å¤–一个å称。"
-#: git-submodule.sh:399
+#: git-submodule.sh:469
#, sh-format
msgid "Reactivating local git directory for submodule '$sm_name'."
msgstr "激活本地 git 目录到å­æ¨¡ç»„ '$sm_name'。"
-#: git-submodule.sh:411
+#: git-submodule.sh:481
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
msgstr "ä¸èƒ½æ£€å‡ºå­æ¨¡ç»„ '$sm_path'"
-#: git-submodule.sh:416
+#: git-submodule.sh:486
#, sh-format
msgid "Failed to add submodule '$sm_path'"
msgstr "无法添加å­æ¨¡ç»„ '$sm_path'"
-#: git-submodule.sh:425
+#: git-submodule.sh:495
#, sh-format
msgid "Failed to register submodule '$sm_path'"
msgstr "无法注册å­æ¨¡ç»„ '$sm_path'"
-#: git-submodule.sh:468
+#: git-submodule.sh:539
#, sh-format
-msgid "Entering '$prefix$sm_path'"
-msgstr "正在进入 '$prefix$sm_path'"
+msgid "Entering '$prefix$displaypath'"
+msgstr "正在进入 '$prefix$displaypath'"
-#: git-submodule.sh:482
+#: git-submodule.sh:554
#, sh-format
-msgid "Stopping at '$sm_path'; script returned non-zero status."
-msgstr "åœæ­¢äºŽ '$sm_path',脚本返回éžé›¶å€¼ã€‚"
+msgid "Stopping at '$prefix$displaypath'; script returned non-zero status."
+msgstr "åœæ­¢äºŽ '$prefix$displaypath',脚本返回éžé›¶å€¼ã€‚"
-#: git-submodule.sh:526
+#: git-submodule.sh:600
#, sh-format
-msgid "No url found for submodule path '$sm_path' in .gitmodules"
-msgstr "在 .gitmodules 中未找到å­æ¨¡ç»„路径 '$sm_path' çš„ url"
+msgid "No url found for submodule path '$displaypath' in .gitmodules"
+msgstr "在 .gitmodules 中未找到å­æ¨¡ç»„路径 '$displaypath' çš„ url"
-#: git-submodule.sh:535
+#: git-submodule.sh:609
#, sh-format
-msgid "Failed to register url for submodule path '$sm_path'"
-msgstr "无法为å­æ¨¡ç»„路径 '$sm_path' 注册 url"
+msgid "Failed to register url for submodule path '$displaypath'"
+msgstr "无法为å­æ¨¡ç»„路径 '$displaypath' 注册 url"
-#: git-submodule.sh:537
+#: git-submodule.sh:611
#, sh-format
-msgid "Submodule '$name' ($url) registered for path '$sm_path'"
-msgstr "å­æ¨¡ç»„ '$name' ($url) 已为路径 '$sm_path' 注册"
+msgid "Submodule '$name' ($url) registered for path '$displaypath'"
+msgstr "å­æ¨¡ç»„ '$name' ($url) 未对路径 '$displaypath' 注册"
-#: git-submodule.sh:545
+#: git-submodule.sh:619
#, sh-format
-msgid "Failed to register update mode for submodule path '$sm_path'"
-msgstr "无法为å­æ¨¡ç»„路径 '$sm_path' 注册更新模å¼"
+msgid "Failed to register update mode for submodule path '$displaypath'"
+msgstr "无法为å­æ¨¡ç»„路径 '$displaypath' 注册更新模å¼"
-#: git-submodule.sh:649
+#: git-submodule.sh:656
+#, sh-format
+msgid "Use '.' if you really want to deinitialize all submodules"
+msgstr "使用 '.' 如果您真的想è¦å¯¹æ‰€æœ‰å­æ¨¡ç»„å–消åˆå§‹åŒ–"
+
+#: git-submodule.sh:673
+#, sh-format
+msgid "Submodule work tree '$displaypath' contains a .git directory"
+msgstr "å­æ¨¡ç»„工作区 '$displaypath' 包å«ä¸€ä¸ª .git 目录"
+
+#: git-submodule.sh:674
+#, sh-format
+msgid ""
+"(use 'rm -rf' if you really want to remove it including all of its history)"
+msgstr "(使用 'rm -rf' 命令如果您真的想删除它åŠå…¶å…¨éƒ¨åŽ†å²ï¼‰"
+
+#: git-submodule.sh:680
#, sh-format
msgid ""
-"Submodule path '$sm_path' not initialized\n"
+"Submodule work tree '$displaypath' contains local modifications; use '-f' to "
+"discard them"
+msgstr "å­æ¨¡ç»„工作区 '$displaypath' 包å«æœ¬åœ°ä¿®æ”¹ï¼›ä½¿ç”¨ '-f' 丢弃它们"
+
+#: git-submodule.sh:683
+#, sh-format
+msgid "Cleared directory '$displaypath'"
+msgstr "已清除目录 '$displaypath'"
+
+#: git-submodule.sh:684
+#, sh-format
+msgid "Could not remove submodule work tree '$displaypath'"
+msgstr "无法移除å­æ¨¡ç»„工作区 '$displaypath'"
+
+#: git-submodule.sh:687
+#, sh-format
+msgid "Could not create empty submodule directory '$displaypath'"
+msgstr "ä¸èƒ½åˆ›å»ºç©ºçš„å­æ¨¡ç»„目录 '$displaypath'"
+
+#: git-submodule.sh:696
+#, sh-format
+msgid "Submodule '$name' ($url) unregistered for path '$displaypath'"
+msgstr "å­æ¨¡ç»„ '$name' ($url) 未对路径 '$displaypath' 注册"
+
+#: git-submodule.sh:811
+#, sh-format
+msgid ""
+"Submodule path '$displaypath' not initialized\n"
"Maybe you want to use 'update --init'?"
msgstr ""
-"å­æ¨¡ç»„路径 '$sm_path' 没有åˆå§‹åŒ–\n"
+"å­æ¨¡ç»„路径 '$displaypath' 没有åˆå§‹åŒ–\n"
"也许您想用 'update --init'?"
-#: git-submodule.sh:662
+#: git-submodule.sh:824
#, sh-format
-msgid "Unable to find current revision in submodule path '$sm_path'"
-msgstr "无法在å­æ¨¡ç»„路径 '$sm_path' 中找到当å‰ç‰ˆæœ¬"
+msgid "Unable to find current revision in submodule path '$displaypath'"
+msgstr "无法在å­æ¨¡ç»„路径 '$displaypath' 中找到当å‰ç‰ˆæœ¬"
-#: git-submodule.sh:671 git-submodule.sh:695
+#: git-submodule.sh:833
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
msgstr "无法在å­æ¨¡ç»„路径 '$sm_path' 中获å–"
-#: git-submodule.sh:709
+#: git-submodule.sh:857
#, sh-format
-msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
-msgstr "无法在å­æ¨¡ç»„路径 '$sm_path' 中å˜åŸº '$sha1'"
+msgid "Unable to fetch in submodule path '$displaypath'"
+msgstr "无法在å­æ¨¡ç»„路径 '$displaypath' 中获å–"
-#: git-submodule.sh:710
+#: git-submodule.sh:871
#, sh-format
-msgid "Submodule path '$sm_path': rebased into '$sha1'"
-msgstr "å­æ¨¡ç»„路径 '$sm_path':å˜åŸºè‡³ '$sha1'"
+msgid "Unable to rebase '$sha1' in submodule path '$displaypath'"
+msgstr "无法在å­æ¨¡ç»„路径 '$displaypath' 中å˜åŸº '$sha1'"
-#: git-submodule.sh:715
+#: git-submodule.sh:872
#, sh-format
-msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
-msgstr "无法åˆå¹¶ '$sha1' 到å­æ¨¡ç»„路径 '$sm_path' 中"
+msgid "Submodule path '$displaypath': rebased into '$sha1'"
+msgstr "å­æ¨¡ç»„路径 '$displaypath':å˜åŸºè‡³ '$sha1'"
-#: git-submodule.sh:716
+#: git-submodule.sh:877
#, sh-format
-msgid "Submodule path '$sm_path': merged in '$sha1'"
-msgstr "å­æ¨¡ç»„路径 '$sm_path':已åˆå¹¶å…¥ '$sha1'"
+msgid "Unable to merge '$sha1' in submodule path '$displaypath'"
+msgstr "无法åˆå¹¶ '$sha1' 到å­æ¨¡ç»„路径 '$displaypath' 中"
-#: git-submodule.sh:721
+#: git-submodule.sh:878
#, sh-format
-msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
-msgstr "无法在å­æ¨¡ç»„路径 '$sm_path' 中检出 '$sha1'"
+msgid "Submodule path '$displaypath': merged in '$sha1'"
+msgstr "å­æ¨¡ç»„路径 '$displaypath':已åˆå¹¶å…¥ '$sha1'"
-#: git-submodule.sh:722
+#: git-submodule.sh:883
#, sh-format
-msgid "Submodule path '$sm_path': checked out '$sha1'"
-msgstr "å­æ¨¡ç»„路径 '$sm_path':检出 '$sha1'"
+msgid ""
+"Execution of '$command $sha1' failed in submodule path '$prefix$sm_path'"
+msgstr "在å­æ¨¡ç»„路径 '$prefix$sm_path' 中执行 '$command $sha1' 失败"
-#: git-submodule.sh:744 git-submodule.sh:1066
+#: git-submodule.sh:884
#, sh-format
-msgid "Failed to recurse into submodule path '$sm_path'"
-msgstr "无法递归进å­æ¨¡ç»„路径 '$sm_path'"
+msgid "Submodule path '$prefix$sm_path': '$command $sha1'"
+msgstr "å­æ¨¡ç»„路径 '$prefix$sm_path': '$command $sha1'"
+
+#: git-submodule.sh:889
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$displaypath'"
+msgstr "无法在å­æ¨¡ç»„路径 '$displaypath' 中检出 '$sha1'"
+
+#: git-submodule.sh:890
+#, sh-format
+msgid "Submodule path '$displaypath': checked out '$sha1'"
+msgstr "å­æ¨¡ç»„路径 '$displaypath':检出 '$sha1'"
+
+#: git-submodule.sh:917
+#, sh-format
+msgid "Failed to recurse into submodule path '$displaypath'"
+msgstr "无法递归进å­æ¨¡ç»„路径 '$displaypath'"
-#: git-submodule.sh:852
+#: git-submodule.sh:1025
msgid "The --cached option cannot be used with the --files option"
msgstr "选项 --cached ä¸èƒ½å’Œé€‰é¡¹ --files åŒæ—¶ä½¿ç”¨"
#. unexpected type
-#: git-submodule.sh:892
+#: git-submodule.sh:1066
#, sh-format
msgid "unexpected mode $mod_dst"
msgstr "æ„å¤–çš„æ¨¡å¼ $mod_dst"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: git-submodule.sh:910
+#: git-submodule.sh:1086
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_src"
-msgstr " 警告:$name 未包å«æ交 $sha1_src"
+msgid " Warn: $display_name doesn't contain commit $sha1_src"
+msgstr " 警告:$display_name 未包å«æ交 $sha1_src"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: git-submodule.sh:913
+#: git-submodule.sh:1089
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_dst"
-msgstr " 警告:$name 未包å«æ交 $sha1_dst"
+msgid " Warn: $display_name doesn't contain commit $sha1_dst"
+msgstr " 警告:$display_name 未包å«æ交 $sha1_dst"
# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
-#: git-submodule.sh:916
+#: git-submodule.sh:1092
#, sh-format
-msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
-msgstr " 警告:$name 未包å«æ交 $sha1_src å’Œ $sha1_dst"
+msgid " Warn: $display_name doesn't contain commits $sha1_src and $sha1_dst"
+msgstr " 警告:$display_name 未包å«æ交 $sha1_src å’Œ $sha1_dst"
-#: git-submodule.sh:941
+#: git-submodule.sh:1117
msgid "blob"
msgstr "æ•°æ®å¯¹è±¡"
-#: git-submodule.sh:979
+#: git-submodule.sh:1155
msgid "Submodules changed but not updated:"
msgstr "å­æ¨¡ç»„已修改但尚未更新:"
-#: git-submodule.sh:981
+#: git-submodule.sh:1157
msgid "Submodule changes to be committed:"
msgstr "è¦æ交的å­æ¨¡ç»„å˜æ›´ï¼š"
-#: git-submodule.sh:1129
+#: git-submodule.sh:1242
#, sh-format
-msgid "Synchronizing submodule url for '$prefix$sm_path'"
-msgstr "为 '$prefix$sm_path' åŒæ­¥å­æ¨¡ç»„ url"
+msgid "Failed to recurse into submodule path '$sm_path'"
+msgstr "无法递归进å­æ¨¡ç»„路径 '$sm_path'"
+
+#: git-submodule.sh:1306
+#, sh-format
+msgid "Synchronizing submodule url for '$displaypath'"
+msgstr "为 '$displaypath' åŒæ­¥å­æ¨¡ç»„ url"
+
+#~ msgid ""
+#~ "the following submodule (or one of its nested submodule)\n"
+#~ "uses a .git directory:"
+#~ msgid_plural ""
+#~ "the following submodules (or one of its nested submodule)\n"
+#~ "use a .git directory:"
+#~ msgstr[0] "如下å­æ¨¡ç»„(或一个其嵌套的å­æ¨¡ç»„)使用了一个 .git 目录:"
+#~ msgstr[1] "如下å­æ¨¡ç»„(或一个其嵌套的å­æ¨¡ç»„)使用了一个 .git 目录:"
+
+#~ msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first"
+#~ msgstr "无法修改未åˆå¹¶çš„ .gitmodules,先解决åˆå¹¶å†²çª"
+
+#~ msgid "Could not find section in .gitmodules where path=%s"
+#~ msgstr "无法在 .gitmodules 中找到 path=%s çš„å°èŠ‚"
+
+#~ msgid "Could not update .gitmodules entry %s"
+#~ msgstr "ä¸èƒ½æ›´æ–° .gitmodules æ¡ç›® %s"
+
+#~ msgid "Could not remove .gitmodules entry for %s"
+#~ msgstr "无法移除 %s çš„ .gitmodules æ¡ç›®"
+
+#~ msgid "could not find .gitmodules in index"
+#~ msgstr "无法在索引中找到 .gitmodules"
+
+#~ msgid "reading updated .gitmodules failed"
+#~ msgstr "读å–æ›´æ–°åŽçš„ .gitmodules 失败"
+
+#~ msgid "unable to stat updated .gitmodules"
+#~ msgstr "ä¸èƒ½æžšä¸¾æ›´æ–°åŽçš„ .gitmodules"
+
+#~ msgid "unable to remove .gitmodules from index"
+#~ msgstr "ä¸èƒ½ä»Žç´¢å¼•ä¸­ç§»é™¤ .gitmodules"
+
+#~ msgid "adding updated .gitmodules failed"
+#~ msgstr "添加更新åŽçš„ .gitmodules 失败"
+
+#~ msgid "staging updated .gitmodules failed"
+#~ msgstr "å°†æ›´æ–°åŽ .gitmodules 添加暂存区失败"
+
+#~ msgid "Could not set core.worktree in %s"
+#~ msgstr "ä¸èƒ½åœ¨ %s 中设置 core.worktree"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#~ msgid " (fix conflicts and then run \"git am --resolved\")"
+#~ msgstr " (解决冲çªï¼Œç„¶åŽè¿è¡Œ \"git am --resolved\")"
+
+# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼
+#~ msgid " (all conflicts fixed: run \"git commit\")"
+#~ msgstr " (解决所有冲çªåŽï¼Œæ‰§è¡Œ \"git commit\")"
+
+#~ msgid "more than %d trees given: '%s'"
+#~ msgstr "æ供了超过 %d 个树对象:'%s'"
+
+#~ msgid "You cannot combine --no-ff with --ff-only."
+#~ msgstr "您ä¸èƒ½å°† --no-ff 与 --ff-only åŒæ—¶ä½¿ç”¨ã€‚"
+
+#~ msgid "Huh? Directory %s is in index and no submodule?"
+#~ msgstr "嗯?目录 %s 在索引中并且ä¸æ˜¯å­æ¨¡ç»„?"
+
+#~ msgid ""
+#~ "submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+#~ "(use 'rm -rf' if you really want to remove it including all of its "
+#~ "history)"
+#~ msgstr ""
+#~ "å­æ¨¡ç»„ '%s'(或者它的一个嵌套å­æ¨¡ç»„)使用一个 .git 目录\n"
+#~ "(使用 'rm -rf' 命令如果您真的想删除它åŠå…¶å…¨éƒ¨åŽ†å²ï¼‰"
+
+#~ msgid ""
+#~ "'%s' has changes staged in the index\n"
+#~ "(use --cached to keep the file, or -f to force removal)"
+#~ msgstr ""
+#~ "'%s' 有å˜æ›´å·²æš‚存至索引中\n"
+#~ "(使用 --cached ä¿å­˜æ–‡ä»¶ï¼Œæˆ–用 -f 强制删除)"
+
+#~ msgid "show commits where no parent comes before its children"
+#~ msgstr "显示æ交时以时间为åºä¸”父æ交ä¸èƒ½é¢†å…ˆå­æ交"
+
+#~ msgid "show the HEAD reference"
+#~ msgstr "显示 HEAD 引用"
+
+#~ msgid "Submodule '$name' ($url) registered for path '$sm_path'"
+#~ msgstr "å­æ¨¡ç»„ '$name' ($url) 已为路径 '$sm_path' 注册"
+
+#~ msgid "Change flags"
+#~ msgstr "修改å‚æ•°"
+
+#~ msgid ""
+#~ "NOTE: no more files to clean; press \"t\" to toggle flags of git-clean."
+#~ msgstr "注æ„:没有è¦æ¸…ç†çš„文件;å°è¯•æŒ‰ \"t\" åˆ‡æ¢ git-clean 的选项。"
+
+#~ msgid "Failed to recurse into submodule path '$prefix$sm_path'"
+#~ msgstr "无法递归进å­æ¨¡ç»„路径 '$prefix$sm_path'"
+
+#~ msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+#~ msgstr "git shortlog [-n] [-s] [-e] [-w] [版本选项] [--] [<æ交å·>... ]"
+
+#~ msgid "See 'git help <command>' for more information on a specific command."
+#~ msgstr "å‚è§ 'git help <command>' 以获得该特定命令的详细信æ¯ã€‚"
+
+#~ msgid "BUG: impossible combination of %d and %p"
+#~ msgstr "BUG: æ— æ³•ç»„åˆ %d å’Œ %p"
+
+# 译者:以下三æ¡å®žé™…为一个段è½
+#~ msgid "It took %.2f seconds to enumerate untracked files. 'status -uno'"
+#~ msgstr "耗费了 %.2f 秒以枚举未跟踪的文件。'status -uno'"
+
+# 译者:为对é½ï¼Œä¸‹é¢ä¸¤å¥å†…容有调整
+#~ msgid "may speed it up, but you have to be careful not to forget to add"
+#~ msgstr "也许能æ高速度,但您需è¦å°å¿ƒä¸è¦å¿˜äº†æ·»åŠ æ–°æ–‡ä»¶"
+
+#~ msgid "new files yourself (see 'git help status')."
+#~ msgstr "(å‚è§ 'git help status')。"
+
+#~ msgid "use any ref in .git/refs"
+#~ msgstr "使用 .git/refs 里的任æ„引用"
+
+#~ msgid "use any tag in .git/refs/tags"
+#~ msgstr "使用 .git/refs/tags é‡Œçš„ä»»æ„ tag"
+
+#~ msgid "bad object %s"
+#~ msgstr "å对象 %s"
+
+#~ msgid "bogus committer info %s"
+#~ msgstr "虚å‡çš„æäº¤è€…ä¿¡æ¯ %s"
#~ msgid "can't fdopen 'show' output fd"
#~ msgstr "ä¸èƒ½æ‰“å¼€ 'show' 输出文件å¥æŸ„"
diff --git a/preload-index.c b/preload-index.c
index 49cb08d..8c44ceb 100644
--- a/preload-index.c
+++ b/preload-index.c
@@ -2,9 +2,11 @@
* Copyright (C) 2008 Linus Torvalds
*/
#include "cache.h"
+#include "pathspec.h"
#ifdef NO_PTHREADS
-static void preload_index(struct index_state *index, const char **pathspec)
+static void preload_index(struct index_state *index,
+ const struct pathspec *pathspec)
{
; /* nothing */
}
@@ -24,7 +26,7 @@ static void preload_index(struct index_state *index, const char **pathspec)
struct thread_data {
pthread_t pthread;
struct index_state *index;
- const char **pathspec;
+ struct pathspec pathspec;
int offset, nr;
};
@@ -35,9 +37,7 @@ static void *preload_thread(void *_data)
struct index_state *index = p->index;
struct cache_entry **cep = index->cache + p->offset;
struct cache_def cache;
- struct pathspec pathspec;
- init_pathspec(&pathspec, p->pathspec);
memset(&cache, 0, sizeof(cache));
nr = p->nr;
if (nr + p->offset > index->cache_nr)
@@ -53,7 +53,7 @@ static void *preload_thread(void *_data)
continue;
if (ce_uptodate(ce))
continue;
- if (!ce_path_match(ce, &pathspec))
+ if (!ce_path_match(ce, &p->pathspec))
continue;
if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))
continue;
@@ -63,11 +63,11 @@ static void *preload_thread(void *_data)
continue;
ce_mark_uptodate(ce);
} while (--nr > 0);
- free_pathspec(&pathspec);
return NULL;
}
-static void preload_index(struct index_state *index, const char **pathspec)
+static void preload_index(struct index_state *index,
+ const struct pathspec *pathspec)
{
int threads, i, work, offset;
struct thread_data data[MAX_PARALLEL];
@@ -82,10 +82,12 @@ static void preload_index(struct index_state *index, const char **pathspec)
threads = MAX_PARALLEL;
offset = 0;
work = DIV_ROUND_UP(index->cache_nr, threads);
+ memset(&data, 0, sizeof(data));
for (i = 0; i < threads; i++) {
struct thread_data *p = data+i;
p->index = index;
- p->pathspec = pathspec;
+ if (pathspec)
+ copy_pathspec(&p->pathspec, pathspec);
p->offset = offset;
p->nr = work;
offset += work;
@@ -100,7 +102,8 @@ static void preload_index(struct index_state *index, const char **pathspec)
}
#endif
-int read_index_preload(struct index_state *index, const char **pathspec)
+int read_index_preload(struct index_state *index,
+ const struct pathspec *pathspec)
{
int retval = read_index(index);
diff --git a/pretty.c b/pretty.c
index acbfceb..74563c9 100644
--- a/pretty.c
+++ b/pretty.c
@@ -406,14 +406,11 @@ static const char *show_ident_date(const struct ident_split *ident,
return show_date(date, tz, mode);
}
-void pp_user_info(const struct pretty_print_context *pp,
+void pp_user_info(struct pretty_print_context *pp,
const char *what, struct strbuf *sb,
const char *line, const char *encoding)
{
- struct strbuf name;
- struct strbuf mail;
struct ident_split ident;
- int linelen;
char *line_end;
const char *mailbuf, *namebuf;
size_t namelen, maillen;
@@ -422,18 +419,10 @@ void pp_user_info(const struct pretty_print_context *pp,
if (pp->fmt == CMIT_FMT_ONELINE)
return;
- line_end = strchr(line, '\n');
- if (!line_end) {
- line_end = strchr(line, '\0');
- if (!line_end)
- return;
- }
-
- linelen = ++line_end - line;
- if (split_ident_line(&ident, line, linelen))
+ line_end = strchrnul(line, '\n');
+ if (split_ident_line(&ident, line, line_end - line))
return;
-
mailbuf = ident.mail_begin;
maillen = ident.mail_end - ident.mail_begin;
namebuf = ident.name_begin;
@@ -442,43 +431,50 @@ void pp_user_info(const struct pretty_print_context *pp,
if (pp->mailmap)
map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
- strbuf_init(&mail, 0);
- strbuf_init(&name, 0);
-
- strbuf_add(&mail, mailbuf, maillen);
- strbuf_add(&name, namebuf, namelen);
-
- namelen = name.len + mail.len + 3; /* ' ' + '<' + '>' */
-
if (pp->fmt == CMIT_FMT_EMAIL) {
+ if (pp->from_ident) {
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addstr(&buf, "From: ");
+ strbuf_add(&buf, namebuf, namelen);
+ strbuf_addstr(&buf, " <");
+ strbuf_add(&buf, mailbuf, maillen);
+ strbuf_addstr(&buf, ">\n");
+ string_list_append(&pp->in_body_headers,
+ strbuf_detach(&buf, NULL));
+
+ mailbuf = pp->from_ident->mail_begin;
+ maillen = pp->from_ident->mail_end - mailbuf;
+ namebuf = pp->from_ident->name_begin;
+ namelen = pp->from_ident->name_end - namebuf;
+ }
+
strbuf_addstr(sb, "From: ");
- if (needs_rfc2047_encoding(name.buf, name.len, RFC2047_ADDRESS)) {
- add_rfc2047(sb, name.buf, name.len,
+ if (needs_rfc2047_encoding(namebuf, namelen, RFC2047_ADDRESS)) {
+ add_rfc2047(sb, namebuf, namelen,
encoding, RFC2047_ADDRESS);
max_length = 76; /* per rfc2047 */
- } else if (needs_rfc822_quoting(name.buf, name.len)) {
+ } else if (needs_rfc822_quoting(namebuf, namelen)) {
struct strbuf quoted = STRBUF_INIT;
- add_rfc822_quoted(&quoted, name.buf, name.len);
+ add_rfc822_quoted(&quoted, namebuf, namelen);
strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len,
-6, 1, max_length);
strbuf_release(&quoted);
} else {
- strbuf_add_wrapped_bytes(sb, name.buf, name.len,
+ strbuf_add_wrapped_bytes(sb, namebuf, namelen,
-6, 1, max_length);
}
- if (namelen - name.len + last_line_length(sb) > max_length)
- strbuf_addch(sb, '\n');
- strbuf_addf(sb, " <%s>\n", mail.buf);
+ if (max_length <
+ last_line_length(sb) + strlen(" <") + maillen + strlen(">"))
+ strbuf_addch(sb, '\n');
+ strbuf_addf(sb, " <%.*s>\n", (int)maillen, mailbuf);
} else {
- strbuf_addf(sb, "%s: %.*s%s <%s>\n", what,
- (pp->fmt == CMIT_FMT_FULLER) ? 4 : 0,
- " ", name.buf, mail.buf);
+ strbuf_addf(sb, "%s: %.*s%.*s <%.*s>\n", what,
+ (pp->fmt == CMIT_FMT_FULLER) ? 4 : 0, " ",
+ (int)namelen, namebuf, (int)maillen, mailbuf);
}
- strbuf_release(&mail);
- strbuf_release(&name);
-
switch (pp->fmt) {
case CMIT_FMT_MEDIUM:
strbuf_addf(sb, "Date: %s\n",
@@ -606,6 +602,7 @@ static char *replace_encoding_header(char *buf, const char *encoding)
}
char *logmsg_reencode(const struct commit *commit,
+ char **commit_encoding,
const char *output_encoding)
{
static const char *utf8 = "UTF-8";
@@ -627,9 +624,15 @@ char *logmsg_reencode(const struct commit *commit,
sha1_to_hex(commit->object.sha1), typename(type));
}
- if (!output_encoding || !*output_encoding)
+ if (!output_encoding || !*output_encoding) {
+ if (commit_encoding)
+ *commit_encoding =
+ get_header(commit, msg, "encoding");
return msg;
+ }
encoding = get_header(commit, msg, "encoding");
+ if (commit_encoding)
+ *commit_encoding = encoding;
use_encoding = encoding ? encoding : utf8;
if (same_encoding(use_encoding, output_encoding)) {
/*
@@ -670,7 +673,8 @@ char *logmsg_reencode(const struct commit *commit,
if (out)
out = replace_encoding_header(out, output_encoding);
- free(encoding);
+ if (!commit_encoding)
+ free(encoding);
/*
* If the re-encoding failed, out might be NULL here; in that
* case we just return the commit message verbatim.
@@ -764,26 +768,38 @@ struct chunk {
size_t len;
};
+enum flush_type {
+ no_flush,
+ flush_right,
+ flush_left,
+ flush_left_and_steal,
+ flush_both
+};
+
+enum trunc_type {
+ trunc_none,
+ trunc_left,
+ trunc_middle,
+ trunc_right
+};
+
struct format_commit_context {
const struct commit *commit;
const struct pretty_print_context *pretty_ctx;
unsigned commit_header_parsed:1;
unsigned commit_message_parsed:1;
- unsigned commit_signature_parsed:1;
- struct {
- char *gpg_output;
- char *gpg_status;
- char good_bad;
- char *signer;
- char *key;
- } signature;
+ struct signature_check signature_check;
+ enum flush_type flush_type;
+ enum trunc_type truncate;
char *message;
+ char *commit_encoding;
size_t width, indent1, indent2;
+ int auto_color;
+ int padding;
/* These offsets are relative to the start of the commit message. */
struct chunk author;
struct chunk committer;
- struct chunk encoding;
size_t message_off;
size_t subject_off;
size_t body_off;
@@ -830,9 +846,6 @@ static void parse_commit_header(struct format_commit_context *context)
} else if (!prefixcmp(msg + i, "committer ")) {
context->committer.off = i + 10;
context->committer.len = eol - i - 10;
- } else if (!prefixcmp(msg + i, "encoding ")) {
- context->encoding.off = i + 9;
- context->encoding.len = eol - i - 9;
}
i = eol;
}
@@ -913,23 +926,6 @@ static void parse_commit_message(struct format_commit_context *c)
c->commit_message_parsed = 1;
}
-static void format_decoration(struct strbuf *sb, const struct commit *commit)
-{
- struct name_decoration *d;
- const char *prefix = " (";
-
- load_ref_decorations(DECORATE_SHORT_REFS);
- d = lookup_decoration(&name_decoration, &commit->object);
- while (d) {
- strbuf_addstr(sb, prefix);
- prefix = ", ";
- strbuf_addstr(sb, d->name);
- d = d->next;
- }
- if (prefix[0] == ',')
- strbuf_addch(sb, ')');
-}
-
static void strbuf_wrap(struct strbuf *sb, size_t pos,
size_t width, size_t indent1, size_t indent2)
{
@@ -959,64 +955,6 @@ static void rewrap_message_tail(struct strbuf *sb,
c->indent2 = new_indent2;
}
-static struct {
- char result;
- const char *check;
-} signature_check[] = {
- { 'G', "\n[GNUPG:] GOODSIG " },
- { 'B', "\n[GNUPG:] BADSIG " },
-};
-
-static void parse_signature_lines(struct format_commit_context *ctx)
-{
- const char *buf = ctx->signature.gpg_status;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
- const char *found = strstr(buf, signature_check[i].check);
- const char *next;
- if (!found)
- continue;
- ctx->signature.good_bad = signature_check[i].result;
- found += strlen(signature_check[i].check);
- ctx->signature.key = xmemdupz(found, 16);
- found += 17;
- next = strchrnul(found, '\n');
- ctx->signature.signer = xmemdupz(found, next - found);
- break;
- }
-}
-
-static void parse_commit_signature(struct format_commit_context *ctx)
-{
- struct strbuf payload = STRBUF_INIT;
- struct strbuf signature = STRBUF_INIT;
- struct strbuf gpg_output = STRBUF_INIT;
- struct strbuf gpg_status = STRBUF_INIT;
- int status;
-
- ctx->commit_signature_parsed = 1;
-
- if (parse_signed_commit(ctx->commit->object.sha1,
- &payload, &signature) <= 0)
- goto out;
- status = verify_signed_buffer(payload.buf, payload.len,
- signature.buf, signature.len,
- &gpg_output, &gpg_status);
- if (status && !gpg_output.len)
- goto out;
- ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
- ctx->signature.gpg_status = strbuf_detach(&gpg_status, NULL);
- parse_signature_lines(ctx);
-
- out:
- strbuf_release(&gpg_status);
- strbuf_release(&gpg_output);
- strbuf_release(&payload);
- strbuf_release(&signature);
-}
-
-
static int format_reflog_person(struct strbuf *sb,
char part,
struct reflog_walk_info *log,
@@ -1034,7 +972,112 @@ static int format_reflog_person(struct strbuf *sb,
return format_person_part(sb, part, ident, strlen(ident), dmode);
}
-static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
+static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
+ const char *placeholder,
+ struct format_commit_context *c)
+{
+ if (placeholder[1] == '(') {
+ const char *begin = placeholder + 2;
+ const char *end = strchr(begin, ')');
+ char color[COLOR_MAXLEN];
+
+ if (!end)
+ return 0;
+ if (!prefixcmp(begin, "auto,")) {
+ if (!want_color(c->pretty_ctx->color))
+ return end - placeholder + 1;
+ begin += 5;
+ }
+ color_parse_mem(begin,
+ end - begin,
+ "--pretty format", color);
+ strbuf_addstr(sb, color);
+ return end - placeholder + 1;
+ }
+ if (!prefixcmp(placeholder + 1, "red")) {
+ strbuf_addstr(sb, GIT_COLOR_RED);
+ return 4;
+ } else if (!prefixcmp(placeholder + 1, "green")) {
+ strbuf_addstr(sb, GIT_COLOR_GREEN);
+ return 6;
+ } else if (!prefixcmp(placeholder + 1, "blue")) {
+ strbuf_addstr(sb, GIT_COLOR_BLUE);
+ return 5;
+ } else if (!prefixcmp(placeholder + 1, "reset")) {
+ strbuf_addstr(sb, GIT_COLOR_RESET);
+ return 6;
+ } else
+ return 0;
+}
+
+static size_t parse_padding_placeholder(struct strbuf *sb,
+ const char *placeholder,
+ struct format_commit_context *c)
+{
+ const char *ch = placeholder;
+ enum flush_type flush_type;
+ int to_column = 0;
+
+ switch (*ch++) {
+ case '<':
+ flush_type = flush_right;
+ break;
+ case '>':
+ if (*ch == '<') {
+ flush_type = flush_both;
+ ch++;
+ } else if (*ch == '>') {
+ flush_type = flush_left_and_steal;
+ ch++;
+ } else
+ flush_type = flush_left;
+ break;
+ default:
+ return 0;
+ }
+
+ /* the next value means "wide enough to that column" */
+ if (*ch == '|') {
+ to_column = 1;
+ ch++;
+ }
+
+ if (*ch == '(') {
+ const char *start = ch + 1;
+ const char *end = start + strcspn(start, ",)");
+ char *next;
+ int width;
+ if (!end || end == start)
+ return 0;
+ width = strtoul(start, &next, 10);
+ if (next == start || width == 0)
+ return 0;
+ c->padding = to_column ? -width : width;
+ c->flush_type = flush_type;
+
+ if (*end == ',') {
+ start = end + 1;
+ end = strchr(start, ')');
+ if (!end || end == start)
+ return 0;
+ if (!prefixcmp(start, "trunc)"))
+ c->truncate = trunc_right;
+ else if (!prefixcmp(start, "ltrunc)"))
+ c->truncate = trunc_left;
+ else if (!prefixcmp(start, "mtrunc)"))
+ c->truncate = trunc_middle;
+ else
+ return 0;
+ } else
+ c->truncate = trunc_none;
+
+ return end - placeholder + 1;
+ }
+ return 0;
+}
+
+static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
+ const char *placeholder,
void *context)
{
struct format_commit_context *c = context;
@@ -1046,38 +1089,20 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
/* these are independent of the commit */
switch (placeholder[0]) {
case 'C':
- if (placeholder[1] == '(') {
- const char *begin = placeholder + 2;
- const char *end = strchr(begin, ')');
- char color[COLOR_MAXLEN];
-
- if (!end)
- return 0;
- if (!prefixcmp(begin, "auto,")) {
- if (!want_color(c->pretty_ctx->color))
- return end - placeholder + 1;
- begin += 5;
- }
- color_parse_mem(begin,
- end - begin,
- "--pretty format", color);
- strbuf_addstr(sb, color);
- return end - placeholder + 1;
+ if (!prefixcmp(placeholder + 1, "(auto)")) {
+ c->auto_color = 1;
+ return 7; /* consumed 7 bytes, "C(auto)" */
+ } else {
+ int ret = parse_color(sb, placeholder, c);
+ if (ret)
+ c->auto_color = 0;
+ /*
+ * Otherwise, we decided to treat %C<unknown>
+ * as a literal string, and the previous
+ * %C(auto) is still valid.
+ */
+ return ret;
}
- if (!prefixcmp(placeholder + 1, "red")) {
- strbuf_addstr(sb, GIT_COLOR_RED);
- return 4;
- } else if (!prefixcmp(placeholder + 1, "green")) {
- strbuf_addstr(sb, GIT_COLOR_GREEN);
- return 6;
- } else if (!prefixcmp(placeholder + 1, "blue")) {
- strbuf_addstr(sb, GIT_COLOR_BLUE);
- return 5;
- } else if (!prefixcmp(placeholder + 1, "reset")) {
- strbuf_addstr(sb, GIT_COLOR_RESET);
- return 6;
- } else
- return 0;
case 'n': /* newline */
strbuf_addch(sb, '\n');
return 1;
@@ -1115,6 +1140,10 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
return end - placeholder + 1;
} else
return 0;
+
+ case '<':
+ case '>':
+ return parse_padding_placeholder(sb, placeholder, c);
}
/* these depend on the commit */
@@ -1123,13 +1152,19 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
switch (placeholder[0]) {
case 'H': /* commit hash */
+ strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
+ strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
return 1;
case 'h': /* abbreviated commit hash */
- if (add_again(sb, &c->abbrev_commit_hash))
+ strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
+ if (add_again(sb, &c->abbrev_commit_hash)) {
+ strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
return 1;
+ }
strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
c->pretty_ctx->abbrev));
+ strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
return 1;
case 'T': /* tree hash */
@@ -1166,7 +1201,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
strbuf_addstr(sb, get_revision_mark(NULL, commit));
return 1;
case 'd':
- format_decoration(sb, commit);
+ load_ref_decorations(DECORATE_SHORT_REFS);
+ format_decorations(sb, commit, c->auto_color);
return 1;
case 'g': /* reflog info */
switch(placeholder[1]) {
@@ -1202,27 +1238,29 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
}
if (placeholder[0] == 'G') {
- if (!c->commit_signature_parsed)
- parse_commit_signature(c);
+ if (!c->signature_check.result)
+ check_commit_signature(c->commit, &(c->signature_check));
switch (placeholder[1]) {
case 'G':
- if (c->signature.gpg_output)
- strbuf_addstr(sb, c->signature.gpg_output);
+ if (c->signature_check.gpg_output)
+ strbuf_addstr(sb, c->signature_check.gpg_output);
break;
case '?':
- switch (c->signature.good_bad) {
+ switch (c->signature_check.result) {
case 'G':
case 'B':
- strbuf_addch(sb, c->signature.good_bad);
+ case 'U':
+ case 'N':
+ strbuf_addch(sb, c->signature_check.result);
}
break;
case 'S':
- if (c->signature.signer)
- strbuf_addstr(sb, c->signature.signer);
+ if (c->signature_check.signer)
+ strbuf_addstr(sb, c->signature_check.signer);
break;
case 'K':
- if (c->signature.key)
- strbuf_addstr(sb, c->signature.key);
+ if (c->signature_check.key)
+ strbuf_addstr(sb, c->signature_check.key);
break;
}
return 2;
@@ -1243,7 +1281,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
msg + c->committer.off, c->committer.len,
c->pretty_ctx->date_mode);
case 'e': /* encoding */
- strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
+ if (c->commit_encoding)
+ strbuf_addstr(sb, c->commit_encoding);
return 1;
case 'B': /* raw body */
/* message_off is always left at the initial newline */
@@ -1269,7 +1308,111 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
return 0; /* unknown placeholder */
}
-static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
+static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
+ const char *placeholder,
+ struct format_commit_context *c)
+{
+ struct strbuf local_sb = STRBUF_INIT;
+ int total_consumed = 0, len, padding = c->padding;
+ if (padding < 0) {
+ const char *start = strrchr(sb->buf, '\n');
+ int occupied;
+ if (!start)
+ start = sb->buf;
+ occupied = utf8_strnwidth(start, -1, 1);
+ padding = (-padding) - occupied;
+ }
+ while (1) {
+ int modifier = *placeholder == 'C';
+ int consumed = format_commit_one(&local_sb, placeholder, c);
+ total_consumed += consumed;
+
+ if (!modifier)
+ break;
+
+ placeholder += consumed;
+ if (*placeholder != '%')
+ break;
+ placeholder++;
+ total_consumed++;
+ }
+ len = utf8_strnwidth(local_sb.buf, -1, 1);
+
+ if (c->flush_type == flush_left_and_steal) {
+ const char *ch = sb->buf + sb->len - 1;
+ while (len > padding && ch > sb->buf) {
+ const char *p;
+ if (*ch == ' ') {
+ ch--;
+ padding++;
+ continue;
+ }
+ /* check for trailing ansi sequences */
+ if (*ch != 'm')
+ break;
+ p = ch - 1;
+ while (ch - p < 10 && *p != '\033')
+ p--;
+ if (*p != '\033' ||
+ ch + 1 - p != display_mode_esc_sequence_len(p))
+ break;
+ /*
+ * got a good ansi sequence, put it back to
+ * local_sb as we're cutting sb
+ */
+ strbuf_insert(&local_sb, 0, p, ch + 1 - p);
+ ch = p - 1;
+ }
+ strbuf_setlen(sb, ch + 1 - sb->buf);
+ c->flush_type = flush_left;
+ }
+
+ if (len > padding) {
+ switch (c->truncate) {
+ case trunc_left:
+ strbuf_utf8_replace(&local_sb,
+ 0, len - (padding - 2),
+ "..");
+ break;
+ case trunc_middle:
+ strbuf_utf8_replace(&local_sb,
+ padding / 2 - 1,
+ len - (padding - 2),
+ "..");
+ break;
+ case trunc_right:
+ strbuf_utf8_replace(&local_sb,
+ padding - 2, len - (padding - 2),
+ "..");
+ break;
+ case trunc_none:
+ break;
+ }
+ strbuf_addstr(sb, local_sb.buf);
+ } else {
+ int sb_len = sb->len, offset = 0;
+ if (c->flush_type == flush_left)
+ offset = padding - len;
+ else if (c->flush_type == flush_both)
+ offset = (padding - len) / 2;
+ /*
+ * we calculate padding in columns, now
+ * convert it back to chars
+ */
+ padding = padding - len + local_sb.len;
+ strbuf_grow(sb, padding);
+ strbuf_setlen(sb, sb_len + padding);
+ memset(sb->buf + sb_len, ' ', sb->len - sb_len);
+ memcpy(sb->buf + sb_len + offset, local_sb.buf,
+ local_sb.len);
+ }
+ strbuf_release(&local_sb);
+ c->flush_type = no_flush;
+ return total_consumed;
+}
+
+static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
+ const char *placeholder,
void *context)
{
int consumed;
@@ -1298,7 +1441,10 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
placeholder++;
orig_len = sb->len;
- consumed = format_commit_one(sb, placeholder, context);
+ if (((struct format_commit_context *)context)->flush_type != no_flush)
+ consumed = format_and_pad_commit(sb, placeholder, context);
+ else
+ consumed = format_commit_one(sb, placeholder, context);
if (magic == NO_MAGIC)
return consumed;
@@ -1349,22 +1495,43 @@ void format_commit_message(const struct commit *commit,
{
struct format_commit_context context;
const char *output_enc = pretty_ctx->output_encoding;
+ const char *utf8 = "UTF-8";
memset(&context, 0, sizeof(context));
context.commit = commit;
context.pretty_ctx = pretty_ctx;
context.wrap_start = sb->len;
- context.message = logmsg_reencode(commit, output_enc);
+ context.message = logmsg_reencode(commit,
+ &context.commit_encoding,
+ output_enc);
strbuf_expand(sb, format, format_commit_item, &context);
rewrap_message_tail(sb, &context, 0, 0, 0);
+ if (output_enc) {
+ if (same_encoding(utf8, output_enc))
+ output_enc = NULL;
+ } else {
+ if (context.commit_encoding &&
+ !same_encoding(context.commit_encoding, utf8))
+ output_enc = context.commit_encoding;
+ }
+
+ if (output_enc) {
+ int outsz;
+ char *out = reencode_string_len(sb->buf, sb->len,
+ output_enc, utf8, &outsz);
+ if (out)
+ strbuf_attach(sb, out, outsz, outsz + 1);
+ }
+
+ free(context.commit_encoding);
logmsg_free(context.message, commit);
- free(context.signature.gpg_output);
- free(context.signature.signer);
+ free(context.signature_check.gpg_output);
+ free(context.signature_check.signer);
}
-static void pp_header(const struct pretty_print_context *pp,
+static void pp_header(struct pretty_print_context *pp,
const char *encoding,
const struct commit *commit,
const char **msg_p,
@@ -1425,7 +1592,7 @@ static void pp_header(const struct pretty_print_context *pp,
}
}
-void pp_title_line(const struct pretty_print_context *pp,
+void pp_title_line(struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
const char *encoding,
@@ -1452,6 +1619,16 @@ void pp_title_line(const struct pretty_print_context *pp,
}
strbuf_addch(sb, '\n');
+ if (need_8bit_cte == 0) {
+ int i;
+ for (i = 0; i < pp->in_body_headers.nr; i++) {
+ if (has_non_ascii(pp->in_body_headers.items[i].string)) {
+ need_8bit_cte = 1;
+ break;
+ }
+ }
+ }
+
if (need_8bit_cte > 0) {
const char *header_fmt =
"MIME-Version: 1.0\n"
@@ -1465,10 +1642,21 @@ void pp_title_line(const struct pretty_print_context *pp,
if (pp->fmt == CMIT_FMT_EMAIL) {
strbuf_addch(sb, '\n');
}
+
+ if (pp->in_body_headers.nr) {
+ int i;
+ for (i = 0; i < pp->in_body_headers.nr; i++) {
+ strbuf_addstr(sb, pp->in_body_headers.items[i].string);
+ free(pp->in_body_headers.items[i].string);
+ }
+ string_list_clear(&pp->in_body_headers, 0);
+ strbuf_addch(sb, '\n');
+ }
+
strbuf_release(&title);
}
-void pp_remainder(const struct pretty_print_context *pp,
+void pp_remainder(struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
int indent)
@@ -1500,7 +1688,7 @@ void pp_remainder(const struct pretty_print_context *pp,
}
}
-void pretty_print_commit(const struct pretty_print_context *pp,
+void pretty_print_commit(struct pretty_print_context *pp,
const struct commit *commit,
struct strbuf *sb)
{
@@ -1517,7 +1705,7 @@ void pretty_print_commit(const struct pretty_print_context *pp,
}
encoding = get_log_output_encoding();
- msg = reencoded = logmsg_reencode(commit, encoding);
+ msg = reencoded = logmsg_reencode(commit, NULL, encoding);
if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
indent = 0;
diff --git a/prio-queue.c b/prio-queue.c
new file mode 100644
index 0000000..c9f8c6d
--- /dev/null
+++ b/prio-queue.c
@@ -0,0 +1,84 @@
+#include "cache.h"
+#include "commit.h"
+#include "prio-queue.h"
+
+void prio_queue_reverse(struct prio_queue *queue)
+{
+ int i, j;
+
+ if (queue->compare != NULL)
+ die("BUG: prio_queue_reverse() on non-LIFO queue");
+ for (i = 0; i <= (j = (queue->nr - 1) - i); i++) {
+ struct commit *swap = queue->array[i];
+ queue->array[i] = queue->array[j];
+ queue->array[j] = swap;
+ }
+}
+
+void clear_prio_queue(struct prio_queue *queue)
+{
+ free(queue->array);
+ queue->nr = 0;
+ queue->alloc = 0;
+ queue->array = NULL;
+}
+
+void prio_queue_put(struct prio_queue *queue, void *thing)
+{
+ prio_queue_compare_fn compare = queue->compare;
+ int ix, parent;
+
+ /* Append at the end */
+ ALLOC_GROW(queue->array, queue->nr + 1, queue->alloc);
+ queue->array[queue->nr++] = thing;
+ if (!compare)
+ return; /* LIFO */
+
+ /* Bubble up the new one */
+ for (ix = queue->nr - 1; ix; ix = parent) {
+ parent = (ix - 1) / 2;
+ if (compare(queue->array[parent], queue->array[ix],
+ queue->cb_data) <= 0)
+ break;
+
+ thing = queue->array[parent];
+ queue->array[parent] = queue->array[ix];
+ queue->array[ix] = thing;
+ }
+}
+
+void *prio_queue_get(struct prio_queue *queue)
+{
+ void *result, *swap;
+ int ix, child;
+ prio_queue_compare_fn compare = queue->compare;
+
+ if (!queue->nr)
+ return NULL;
+ if (!compare)
+ return queue->array[--queue->nr]; /* LIFO */
+
+ result = queue->array[0];
+ if (!--queue->nr)
+ return result;
+
+ queue->array[0] = queue->array[queue->nr];
+
+ /* Push down the one at the root */
+ for (ix = 0; ix * 2 + 1 < queue->nr; ix = child) {
+ child = ix * 2 + 1; /* left */
+ if ((child + 1 < queue->nr) &&
+ (compare(queue->array[child], queue->array[child + 1],
+ queue->cb_data) >= 0))
+ child++; /* use right child */
+
+ if (compare(queue->array[ix], queue->array[child],
+ queue->cb_data) <= 0)
+ break;
+
+ swap = queue->array[child];
+ queue->array[child] = queue->array[ix];
+ queue->array[ix] = swap;
+ }
+ return result;
+}
diff --git a/prio-queue.h b/prio-queue.h
new file mode 100644
index 0000000..9c3cd1f
--- /dev/null
+++ b/prio-queue.h
@@ -0,0 +1,48 @@
+#ifndef PRIO_QUEUE_H
+#define PRIO_QUEUE_H
+
+/*
+ * A priority queue implementation, primarily for keeping track of
+ * commits in the 'date-order' so that we process them from new to old
+ * as they are discovered, but can be used to hold any pointer to
+ * struct. The caller is responsible for supplying a function to
+ * compare two "things".
+ *
+ * Alternatively, this data structure can also be used as a LIFO stack
+ * by specifying NULL as the comparison function.
+ */
+
+/*
+ * Compare two "things", one and two; the third parameter is cb_data
+ * in the prio_queue structure. The result is returned as a sign of
+ * the return value, being the same as the sign of the result of
+ * subtracting "two" from "one" (i.e. negative if "one" sorts earlier
+ * than "two").
+ */
+typedef int (*prio_queue_compare_fn)(const void *one, const void *two, void *cb_data);
+
+struct prio_queue {
+ prio_queue_compare_fn compare;
+ void *cb_data;
+ int alloc, nr;
+ void **array;
+};
+
+/*
+ * Add the "thing" to the queue.
+ */
+extern void prio_queue_put(struct prio_queue *, void *thing);
+
+/*
+ * Extract the "thing" that compares the smallest out of the queue,
+ * or NULL. If compare function is NULL, the queue acts as a LIFO
+ * stack.
+ */
+extern void *prio_queue_get(struct prio_queue *);
+
+extern void clear_prio_queue(struct prio_queue *);
+
+/* Reverse the LIFO elements */
+extern void prio_queue_reverse(struct prio_queue *);
+
+#endif /* PRIO_QUEUE_H */
diff --git a/progress.c b/progress.c
index 3971f49..10652b1 100644
--- a/progress.c
+++ b/progress.c
@@ -10,6 +10,7 @@
#include "git-compat-util.h"
#include "progress.h"
+#include "strbuf.h"
#define TP_IDX_MAX 8
@@ -112,34 +113,14 @@ static int display(struct progress *progress, unsigned n, const char *done)
return 0;
}
-static void throughput_string(struct throughput *tp, off_t total,
+static void throughput_string(struct strbuf *buf, off_t total,
unsigned int rate)
{
- int l = sizeof(tp->display);
- if (total > 1 << 30) {
- l -= snprintf(tp->display, l, ", %u.%2.2u GiB",
- (int)(total >> 30),
- (int)(total & ((1 << 30) - 1)) / 10737419);
- } else if (total > 1 << 20) {
- int x = total + 5243; /* for rounding */
- l -= snprintf(tp->display, l, ", %u.%2.2u MiB",
- x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
- } else if (total > 1 << 10) {
- int x = total + 5; /* for rounding */
- l -= snprintf(tp->display, l, ", %u.%2.2u KiB",
- x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
- } else {
- l -= snprintf(tp->display, l, ", %u bytes", (int)total);
- }
-
- if (rate > 1 << 10) {
- int x = rate + 5; /* for rounding */
- snprintf(tp->display + sizeof(tp->display) - l, l,
- " | %u.%2.2u MiB/s",
- x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
- } else if (rate)
- snprintf(tp->display + sizeof(tp->display) - l, l,
- " | %u KiB/s", rate);
+ strbuf_addstr(buf, ", ");
+ strbuf_humanise_bytes(buf, total);
+ strbuf_addstr(buf, " | ");
+ strbuf_humanise_bytes(buf, rate * 1024);
+ strbuf_addstr(buf, "/s");
}
void display_throughput(struct progress *progress, off_t total)
@@ -183,6 +164,7 @@ void display_throughput(struct progress *progress, off_t total)
misecs += (int)(tv.tv_usec - tp->prev_tv.tv_usec) / 977;
if (misecs > 512) {
+ struct strbuf buf = STRBUF_INIT;
unsigned int count, rate;
count = total - tp->prev_total;
@@ -197,7 +179,9 @@ void display_throughput(struct progress *progress, off_t total)
tp->last_misecs[tp->idx] = misecs;
tp->idx = (tp->idx + 1) % TP_IDX_MAX;
- throughput_string(tp, total, rate);
+ throughput_string(&buf, total, rate);
+ strncpy(tp->display, buf.buf, sizeof(tp->display));
+ strbuf_release(&buf);
if (progress->last_value != -1 && progress_update)
display(progress, progress->last_value, NULL);
}
@@ -253,9 +237,12 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)
bufp = (len < sizeof(buf)) ? buf : xmalloc(len + 1);
if (tp) {
+ struct strbuf strbuf = STRBUF_INIT;
unsigned int rate = !tp->avg_misecs ? 0 :
tp->avg_bytes / tp->avg_misecs;
- throughput_string(tp, tp->curr_total, rate);
+ throughput_string(&strbuf, tp->curr_total, rate);
+ strncpy(tp->display, strbuf.buf, sizeof(tp->display));
+ strbuf_release(&strbuf);
}
progress_update = 1;
sprintf(bufp, ", %s.\n", msg);
diff --git a/quote.c b/quote.c
index 911229f..45e3db1 100644
--- a/quote.c
+++ b/quote.c
@@ -42,23 +42,6 @@ void sq_quote_buf(struct strbuf *dst, const char *src)
free(to_free);
}
-void sq_quote_print(FILE *stream, const char *src)
-{
- char c;
-
- fputc('\'', stream);
- while ((c = *src++)) {
- if (need_bs_quote(c)) {
- fputs("'\\", stream);
- fputc(c, stream);
- fputc('\'', stream);
- } else {
- fputc(c, stream);
- }
- }
- fputc('\'', stream);
-}
-
void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
{
int i;
@@ -312,82 +295,27 @@ void write_name_quotedpfx(const char *pfx, size_t pfxlen,
fputc(terminator, fp);
}
-static const char *path_relative(const char *in, int len,
- struct strbuf *sb, const char *prefix,
- int prefix_len);
-
-void write_name_quoted_relative(const char *name, size_t len,
- const char *prefix, size_t prefix_len,
+void write_name_quoted_relative(const char *name, const char *prefix,
FILE *fp, int terminator)
{
struct strbuf sb = STRBUF_INIT;
- name = path_relative(name, len, &sb, prefix, prefix_len);
+ name = relative_path(name, prefix, &sb);
write_name_quoted(name, fp, terminator);
strbuf_release(&sb);
}
-/*
- * Give path as relative to prefix.
- *
- * The strbuf may or may not be used, so do not assume it contains the
- * returned path.
- */
-static const char *path_relative(const char *in, int len,
- struct strbuf *sb, const char *prefix,
- int prefix_len)
-{
- int off, i;
-
- if (len < 0)
- len = strlen(in);
- if (prefix_len < 0) {
- if (prefix)
- prefix_len = strlen(prefix);
- else
- prefix_len = 0;
- }
-
- off = 0;
- i = 0;
- while (i < prefix_len && i < len && prefix[i] == in[i]) {
- if (prefix[i] == '/')
- off = i + 1;
- i++;
- }
- in += off;
- len -= off;
-
- if (i >= prefix_len)
- return in;
-
- strbuf_reset(sb);
- strbuf_grow(sb, len);
-
- while (i < prefix_len) {
- if (prefix[i] == '/')
- strbuf_addstr(sb, "../");
- i++;
- }
- strbuf_add(sb, in, len);
-
- return sb->buf;
-}
-
/* quote path as relative to the given prefix */
-char *quote_path_relative(const char *in, int len,
- struct strbuf *out, const char *prefix)
+char *quote_path_relative(const char *in, const char *prefix,
+ struct strbuf *out)
{
struct strbuf sb = STRBUF_INIT;
- const char *rel = path_relative(in, len, &sb, prefix, -1);
+ const char *rel = relative_path(in, prefix, &sb);
strbuf_reset(out);
quote_c_style_counted(rel, strlen(rel), out, NULL, 0);
strbuf_release(&sb);
- if (!out->len)
- strbuf_addstr(out, "./");
-
return out->buf;
}
@@ -463,72 +391,72 @@ int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
/* quoting as a string literal for other languages */
-void perl_quote_print(FILE *stream, const char *src)
+void perl_quote_buf(struct strbuf *sb, const char *src)
{
const char sq = '\'';
const char bq = '\\';
char c;
- fputc(sq, stream);
+ strbuf_addch(sb, sq);
while ((c = *src++)) {
if (c == sq || c == bq)
- fputc(bq, stream);
- fputc(c, stream);
+ strbuf_addch(sb, bq);
+ strbuf_addch(sb, c);
}
- fputc(sq, stream);
+ strbuf_addch(sb, sq);
}
-void python_quote_print(FILE *stream, const char *src)
+void python_quote_buf(struct strbuf *sb, const char *src)
{
const char sq = '\'';
const char bq = '\\';
const char nl = '\n';
char c;
- fputc(sq, stream);
+ strbuf_addch(sb, sq);
while ((c = *src++)) {
if (c == nl) {
- fputc(bq, stream);
- fputc('n', stream);
+ strbuf_addch(sb, bq);
+ strbuf_addch(sb, 'n');
continue;
}
if (c == sq || c == bq)
- fputc(bq, stream);
- fputc(c, stream);
+ strbuf_addch(sb, bq);
+ strbuf_addch(sb, c);
}
- fputc(sq, stream);
+ strbuf_addch(sb, sq);
}
-void tcl_quote_print(FILE *stream, const char *src)
+void tcl_quote_buf(struct strbuf *sb, const char *src)
{
char c;
- fputc('"', stream);
+ strbuf_addch(sb, '"');
while ((c = *src++)) {
switch (c) {
case '[': case ']':
case '{': case '}':
case '$': case '\\': case '"':
- fputc('\\', stream);
+ strbuf_addch(sb, '\\');
default:
- fputc(c, stream);
+ strbuf_addch(sb, c);
break;
case '\f':
- fputs("\\f", stream);
+ strbuf_addstr(sb, "\\f");
break;
case '\r':
- fputs("\\r", stream);
+ strbuf_addstr(sb, "\\r");
break;
case '\n':
- fputs("\\n", stream);
+ strbuf_addstr(sb, "\\n");
break;
case '\t':
- fputs("\\t", stream);
+ strbuf_addstr(sb, "\\t");
break;
case '\v':
- fputs("\\v", stream);
+ strbuf_addstr(sb, "\\v");
break;
}
}
- fputc('"', stream);
+ strbuf_addch(sb, '"');
}
diff --git a/quote.h b/quote.h
index 133155a..71dcc3a 100644
--- a/quote.h
+++ b/quote.h
@@ -27,8 +27,6 @@ struct strbuf;
* excluding the final null regardless of the buffer size.
*/
-extern void sq_quote_print(FILE *stream, const char *src);
-
extern void sq_quote_buf(struct strbuf *, const char *src);
extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
@@ -60,17 +58,16 @@ extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
extern void write_name_quoted(const char *name, FILE *, int terminator);
extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
const char *name, FILE *, int terminator);
-extern void write_name_quoted_relative(const char *name, size_t len,
- const char *prefix, size_t prefix_len,
+extern void write_name_quoted_relative(const char *name, const char *prefix,
FILE *fp, int terminator);
/* quote path as relative to the given prefix */
-extern char *quote_path_relative(const char *in, int len,
- struct strbuf *out, const char *prefix);
+extern char *quote_path_relative(const char *in, const char *prefix,
+ struct strbuf *out);
/* quoting as a string literal for other languages */
-extern void perl_quote_print(FILE *stream, const char *src);
-extern void python_quote_print(FILE *stream, const char *src);
-extern void tcl_quote_print(FILE *stream, const char *src);
+extern void perl_quote_buf(struct strbuf *sb, const char *src);
+extern void python_quote_buf(struct strbuf *sb, const char *src);
+extern void tcl_quote_buf(struct strbuf *sb, const char *src);
#endif
diff --git a/read-cache.c b/read-cache.c
index 5a9704f..885943a 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -67,6 +67,61 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
}
+void fill_stat_data(struct stat_data *sd, struct stat *st)
+{
+ sd->sd_ctime.sec = (unsigned int)st->st_ctime;
+ sd->sd_mtime.sec = (unsigned int)st->st_mtime;
+ sd->sd_ctime.nsec = ST_CTIME_NSEC(*st);
+ sd->sd_mtime.nsec = ST_MTIME_NSEC(*st);
+ sd->sd_dev = st->st_dev;
+ sd->sd_ino = st->st_ino;
+ sd->sd_uid = st->st_uid;
+ sd->sd_gid = st->st_gid;
+ sd->sd_size = st->st_size;
+}
+
+int match_stat_data(const struct stat_data *sd, struct stat *st)
+{
+ int changed = 0;
+
+ if (sd->sd_mtime.sec != (unsigned int)st->st_mtime)
+ changed |= MTIME_CHANGED;
+ if (trust_ctime && check_stat &&
+ sd->sd_ctime.sec != (unsigned int)st->st_ctime)
+ changed |= CTIME_CHANGED;
+
+#ifdef USE_NSEC
+ if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
+ if (trust_ctime && check_stat &&
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+#endif
+
+ if (check_stat) {
+ if (sd->sd_uid != (unsigned int) st->st_uid ||
+ sd->sd_gid != (unsigned int) st->st_gid)
+ changed |= OWNER_CHANGED;
+ if (sd->sd_ino != (unsigned int) st->st_ino)
+ changed |= INODE_CHANGED;
+ }
+
+#ifdef USE_STDEV
+ /*
+ * st_dev breaks on network filesystems where different
+ * clients will have different views of what "device"
+ * the filesystem is on
+ */
+ if (check_stat && sd->sd_dev != (unsigned int) st->st_dev)
+ changed |= INODE_CHANGED;
+#endif
+
+ if (sd->sd_size != (unsigned int) st->st_size)
+ changed |= DATA_CHANGED;
+
+ return changed;
+}
+
/*
* This only updates the "non-critical" parts of the directory
* cache, ie the parts that aren't tracked by GIT, and only used
@@ -74,15 +129,7 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
*/
void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
{
- ce->ce_ctime.sec = (unsigned int)st->st_ctime;
- ce->ce_mtime.sec = (unsigned int)st->st_mtime;
- ce->ce_ctime.nsec = ST_CTIME_NSEC(*st);
- ce->ce_mtime.nsec = ST_MTIME_NSEC(*st);
- ce->ce_dev = st->st_dev;
- ce->ce_ino = st->st_ino;
- ce->ce_uid = st->st_uid;
- ce->ce_gid = st->st_gid;
- ce->ce_size = st->st_size;
+ fill_stat_data(&ce->ce_stat_data, st);
if (assume_unchanged)
ce->ce_flags |= CE_VALID;
@@ -91,7 +138,7 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
ce_mark_uptodate(ce);
}
-static int ce_compare_data(struct cache_entry *ce, struct stat *st)
+static int ce_compare_data(const struct cache_entry *ce, struct stat *st)
{
int match = -1;
int fd = open(ce->name, O_RDONLY);
@@ -105,7 +152,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
return match;
}
-static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
+static int ce_compare_link(const struct cache_entry *ce, size_t expected_size)
{
int match = -1;
void *buffer;
@@ -126,7 +173,7 @@ static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
return match;
}
-static int ce_compare_gitlink(struct cache_entry *ce)
+static int ce_compare_gitlink(const struct cache_entry *ce)
{
unsigned char sha1[20];
@@ -143,7 +190,7 @@ static int ce_compare_gitlink(struct cache_entry *ce)
return hashcmp(sha1, ce->sha1);
}
-static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
+static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st)
{
switch (st->st_mode & S_IFMT) {
case S_IFREG:
@@ -163,7 +210,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
return 0;
}
-static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
+static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
{
unsigned int changed = 0;
@@ -195,43 +242,11 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
default:
die("internal error: ce_mode is %o", ce->ce_mode);
}
- if (ce->ce_mtime.sec != (unsigned int)st->st_mtime)
- changed |= MTIME_CHANGED;
- if (trust_ctime && check_stat &&
- ce->ce_ctime.sec != (unsigned int)st->st_ctime)
- changed |= CTIME_CHANGED;
-
-#ifdef USE_NSEC
- if (check_stat && ce->ce_mtime.nsec != ST_MTIME_NSEC(*st))
- changed |= MTIME_CHANGED;
- if (trust_ctime && check_stat &&
- ce->ce_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
-#endif
-
- if (check_stat) {
- if (ce->ce_uid != (unsigned int) st->st_uid ||
- ce->ce_gid != (unsigned int) st->st_gid)
- changed |= OWNER_CHANGED;
- if (ce->ce_ino != (unsigned int) st->st_ino)
- changed |= INODE_CHANGED;
- }
-
-#ifdef USE_STDEV
- /*
- * st_dev breaks on network filesystems where different
- * clients will have different views of what "device"
- * the filesystem is on
- */
- if (check_stat && ce->ce_dev != (unsigned int) st->st_dev)
- changed |= INODE_CHANGED;
-#endif
- if (ce->ce_size != (unsigned int) st->st_size)
- changed |= DATA_CHANGED;
+ changed |= match_stat_data(&ce->ce_stat_data, st);
/* Racily smudged entry? */
- if (!ce->ce_size) {
+ if (!ce->ce_stat_data.sd_size) {
if (!is_empty_blob_sha1(ce->sha1))
changed |= DATA_CHANGED;
}
@@ -239,23 +254,24 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
return changed;
}
-static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)
+static int is_racy_timestamp(const struct index_state *istate,
+ const struct cache_entry *ce)
{
return (!S_ISGITLINK(ce->ce_mode) &&
istate->timestamp.sec &&
#ifdef USE_NSEC
/* nanosecond timestamped files can also be racy! */
- (istate->timestamp.sec < ce->ce_mtime.sec ||
- (istate->timestamp.sec == ce->ce_mtime.sec &&
- istate->timestamp.nsec <= ce->ce_mtime.nsec))
+ (istate->timestamp.sec < ce->ce_stat_data.sd_mtime.sec ||
+ (istate->timestamp.sec == ce->ce_stat_data.sd_mtime.sec &&
+ istate->timestamp.nsec <= ce->ce_stat_data.sd_mtime.nsec))
#else
- istate->timestamp.sec <= ce->ce_mtime.sec
+ istate->timestamp.sec <= ce->ce_stat_data.sd_mtime.sec
#endif
);
}
int ie_match_stat(const struct index_state *istate,
- struct cache_entry *ce, struct stat *st,
+ const struct cache_entry *ce, struct stat *st,
unsigned int options)
{
unsigned int changed;
@@ -311,7 +327,8 @@ int ie_match_stat(const struct index_state *istate,
}
int ie_modified(const struct index_state *istate,
- struct cache_entry *ce, struct stat *st, unsigned int options)
+ const struct cache_entry *ce,
+ struct stat *st, unsigned int options)
{
int changed, changed_fs;
@@ -340,7 +357,7 @@ int ie_modified(const struct index_state *istate,
* then we know it is.
*/
if ((changed & DATA_CHANGED) &&
- (S_ISGITLINK(ce->ce_mode) || ce->ce_size != 0))
+ (S_ISGITLINK(ce->ce_mode) || ce->ce_stat_data.sd_size != 0))
return changed;
changed_fs = ce_modified_check_fs(ce, st);
@@ -472,7 +489,7 @@ int remove_index_entry_at(struct index_state *istate, int pos)
}
/*
- * Remove all cache ententries marked for removal, that is where
+ * Remove all cache entries marked for removal, that is where
* CE_REMOVE is set in ce_flags. This is much more effective than
* calling remove_index_entry_at() for each entry to be removed.
*/
@@ -626,7 +643,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
if (*ptr == '/') {
struct cache_entry *foundce;
++ptr;
- foundce = index_name_exists(&the_index, ce->name, ptr - ce->name, ignore_case);
+ foundce = index_name_exists(istate, ce->name, ptr - ce->name, ignore_case);
if (foundce) {
memcpy((void *)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr);
startPtr = ptr;
@@ -705,7 +722,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,
return ce;
}
-int ce_same_name(struct cache_entry *a, struct cache_entry *b)
+int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
{
int len = ce_namelen(a);
return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
@@ -979,7 +996,7 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
if (istate->cache_nr == istate->cache_alloc) {
istate->cache_alloc = alloc_nr(istate->cache_alloc);
istate->cache = xrealloc(istate->cache,
- istate->cache_alloc * sizeof(struct cache_entry *));
+ istate->cache_alloc * sizeof(*istate->cache));
}
/* Add it in.. */
@@ -1097,7 +1114,8 @@ static void show_file(const char * fmt, const char * name, int in_porcelain,
printf(fmt, name);
}
-int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
+int refresh_index(struct index_state *istate, unsigned int flags,
+ const struct pathspec *pathspec,
char *seen, const char *header_msg)
{
int i;
@@ -1132,7 +1150,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
continue;
if (pathspec &&
- !match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
+ !match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen))
filtered = 1;
if (ce_stage(ce)) {
@@ -1212,14 +1230,14 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int reall
struct ondisk_cache_entry {
struct cache_time ctime;
struct cache_time mtime;
- unsigned int dev;
- unsigned int ino;
- unsigned int mode;
- unsigned int uid;
- unsigned int gid;
- unsigned int size;
+ uint32_t dev;
+ uint32_t ino;
+ uint32_t mode;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t size;
unsigned char sha1[20];
- unsigned short flags;
+ uint16_t flags;
char name[FLEX_ARRAY]; /* more */
};
@@ -1231,15 +1249,15 @@ struct ondisk_cache_entry {
struct ondisk_cache_entry_extended {
struct cache_time ctime;
struct cache_time mtime;
- unsigned int dev;
- unsigned int ino;
- unsigned int mode;
- unsigned int uid;
- unsigned int gid;
- unsigned int size;
+ uint32_t dev;
+ uint32_t ino;
+ uint32_t mode;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t size;
unsigned char sha1[20];
- unsigned short flags;
- unsigned short flags2;
+ uint16_t flags;
+ uint16_t flags2;
char name[FLEX_ARRAY]; /* more */
};
@@ -1322,16 +1340,16 @@ static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *on
{
struct cache_entry *ce = xmalloc(cache_entry_size(len));
- ce->ce_ctime.sec = ntoh_l(ondisk->ctime.sec);
- ce->ce_mtime.sec = ntoh_l(ondisk->mtime.sec);
- ce->ce_ctime.nsec = ntoh_l(ondisk->ctime.nsec);
- ce->ce_mtime.nsec = ntoh_l(ondisk->mtime.nsec);
- ce->ce_dev = ntoh_l(ondisk->dev);
- ce->ce_ino = ntoh_l(ondisk->ino);
+ ce->ce_stat_data.sd_ctime.sec = ntoh_l(ondisk->ctime.sec);
+ ce->ce_stat_data.sd_mtime.sec = ntoh_l(ondisk->mtime.sec);
+ ce->ce_stat_data.sd_ctime.nsec = ntoh_l(ondisk->ctime.nsec);
+ ce->ce_stat_data.sd_mtime.nsec = ntoh_l(ondisk->mtime.nsec);
+ ce->ce_stat_data.sd_dev = ntoh_l(ondisk->dev);
+ ce->ce_stat_data.sd_ino = ntoh_l(ondisk->ino);
ce->ce_mode = ntoh_l(ondisk->mode);
- ce->ce_uid = ntoh_l(ondisk->uid);
- ce->ce_gid = ntoh_l(ondisk->gid);
- ce->ce_size = ntoh_l(ondisk->size);
+ ce->ce_stat_data.sd_uid = ntoh_l(ondisk->uid);
+ ce->ce_stat_data.sd_gid = ntoh_l(ondisk->gid);
+ ce->ce_stat_data.sd_size = ntoh_l(ondisk->size);
ce->ce_flags = flags & ~CE_NAMEMASK;
ce->ce_namelen = len;
hashcpy(ce->sha1, ondisk->sha1);
@@ -1449,7 +1467,7 @@ int read_index_from(struct index_state *istate, const char *path)
istate->version = ntohl(hdr->hdr_version);
istate->cache_nr = ntohl(hdr->hdr_entries);
istate->cache_alloc = alloc_nr(istate->cache_nr);
- istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *));
+ istate->cache = xcalloc(istate->cache_alloc, sizeof(*istate->cache));
istate->initialized = 1;
if (istate->version == 4)
@@ -1518,8 +1536,9 @@ int discard_index(struct index_state *istate)
free_name_hash(istate);
cache_tree_free(&(istate->cache_tree));
istate->initialized = 0;
-
- /* no need to throw away allocated active_cache */
+ free(istate->cache);
+ istate->cache = NULL;
+ istate->cache_alloc = 0;
return 0;
}
@@ -1608,7 +1627,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
* The only thing we care about in this function is to smudge the
* falsely clean entry due to touch-update-touch race, so we leave
* everything else as they are. We are called for entries whose
- * ce_mtime match the index file mtime.
+ * ce_stat_data.sd_mtime match the index file mtime.
*
* Note that this actually does not do much for gitlinks, for
* which ce_match_stat_basic() always goes to the actual
@@ -1647,7 +1666,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
* file, and never calls us, so the cached size information
* for "frotz" stays 6 which does not match the filesystem.
*/
- ce->ce_size = 0;
+ ce->ce_stat_data.sd_size = 0;
}
}
@@ -1657,16 +1676,16 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
{
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);
- ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec);
- ondisk->dev = htonl(ce->ce_dev);
- ondisk->ino = htonl(ce->ce_ino);
+ ondisk->ctime.sec = htonl(ce->ce_stat_data.sd_ctime.sec);
+ ondisk->mtime.sec = htonl(ce->ce_stat_data.sd_mtime.sec);
+ ondisk->ctime.nsec = htonl(ce->ce_stat_data.sd_ctime.nsec);
+ ondisk->mtime.nsec = htonl(ce->ce_stat_data.sd_mtime.nsec);
+ ondisk->dev = htonl(ce->ce_stat_data.sd_dev);
+ ondisk->ino = htonl(ce->ce_stat_data.sd_ino);
ondisk->mode = htonl(ce->ce_mode);
- ondisk->uid = htonl(ce->ce_uid);
- ondisk->gid = htonl(ce->ce_gid);
- ondisk->size = htonl(ce->ce_size);
+ ondisk->uid = htonl(ce->ce_stat_data.sd_uid);
+ ondisk->gid = htonl(ce->ce_stat_data.sd_gid);
+ ondisk->size = htonl(ce->ce_stat_data.sd_size);
hashcpy(ondisk->sha1, ce->sha1);
flags = ce->ce_flags;
@@ -1742,7 +1761,7 @@ static int has_racy_timestamp(struct index_state *istate)
}
/*
- * Opportunisticly update the index but do not complain if we can't
+ * Opportunistically update the index but do not complain if we can't
*/
void update_index_if_able(struct index_state *istate, struct lock_file *lockfile)
{
@@ -1899,3 +1918,67 @@ int index_name_is_other(const struct index_state *istate, const char *name,
}
return 1;
}
+
+void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)
+{
+ int pos, len;
+ unsigned long sz;
+ enum object_type type;
+ void *data;
+
+ len = strlen(path);
+ pos = index_name_pos(istate, path, len);
+ if (pos < 0) {
+ /*
+ * We might be in the middle of a merge, in which
+ * case we would read stage #2 (ours).
+ */
+ int i;
+ for (i = -pos - 1;
+ (pos < 0 && i < istate->cache_nr &&
+ !strcmp(istate->cache[i]->name, path));
+ i++)
+ if (ce_stage(istate->cache[i]) == 2)
+ pos = i;
+ }
+ if (pos < 0)
+ return NULL;
+ data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+ if (!data || type != OBJ_BLOB) {
+ free(data);
+ return NULL;
+ }
+ if (size)
+ *size = sz;
+ return data;
+}
+
+void stat_validity_clear(struct stat_validity *sv)
+{
+ free(sv->sd);
+ sv->sd = NULL;
+}
+
+int stat_validity_check(struct stat_validity *sv, const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st) < 0)
+ return sv->sd == NULL;
+ if (!sv->sd)
+ return 0;
+ return S_ISREG(st.st_mode) && !match_stat_data(sv->sd, &st);
+}
+
+void stat_validity_update(struct stat_validity *sv, int fd)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode))
+ stat_validity_clear(sv);
+ else {
+ if (!sv->sd)
+ sv->sd = xcalloc(1, sizeof(struct stat_data));
+ fill_stat_data(sv->sd, &st);
+ }
+}
diff --git a/refs.c b/refs.c
index e2b760d..d78860c 100644
--- a/refs.c
+++ b/refs.c
@@ -109,7 +109,20 @@ struct ref_entry;
* (ref_entry->flag & REF_DIR) is zero.
*/
struct ref_value {
+ /*
+ * The name of the object to which this reference resolves
+ * (which may be a tag object). If REF_ISBROKEN, this is
+ * null. If REF_ISSYMREF, then this is the name of the object
+ * referred to by the last reference in the symlink chain.
+ */
unsigned char sha1[20];
+
+ /*
+ * If REF_KNOWS_PEELED, then this field holds the peeled value
+ * of this reference, or null if the reference is known not to
+ * be peelable. See the documentation for peel_ref() for an
+ * exact definition of "peelable".
+ */
unsigned char peeled[20];
};
@@ -158,7 +171,17 @@ struct ref_dir {
struct ref_entry **entries;
};
-/* ISSYMREF=0x01, ISPACKED=0x02, and ISBROKEN=0x04 are public interfaces */
+/*
+ * Bit values for ref_entry::flag. REF_ISSYMREF=0x01,
+ * REF_ISPACKED=0x02, and REF_ISBROKEN=0x04 are public values; see
+ * refs.h.
+ */
+
+/*
+ * The field ref_entry->u.value.peeled of this value entry contains
+ * the correct peeled value for the reference, which might be
+ * null_sha1 if the reference is not a tag or if it is broken.
+ */
#define REF_KNOWS_PEELED 0x08
/* ref_entry represents a directory of references */
@@ -343,18 +366,17 @@ static int ref_entry_cmp_sslice(const void *key_, const void *ent_)
}
/*
- * Return the entry with the given refname from the ref_dir
- * (non-recursively), sorting dir if necessary. Return NULL if no
- * such entry is found. dir must already be complete.
+ * Return the index of the entry with the given refname from the
+ * ref_dir (non-recursively), sorting dir if necessary. Return -1 if
+ * no such entry is found. dir must already be complete.
*/
-static struct ref_entry *search_ref_dir(struct ref_dir *dir,
- const char *refname, size_t len)
+static int search_ref_dir(struct ref_dir *dir, const char *refname, size_t len)
{
struct ref_entry **r;
struct string_slice key;
if (refname == NULL || !dir->nr)
- return NULL;
+ return -1;
sort_ref_dir(dir);
key.len = len;
@@ -363,9 +385,9 @@ static struct ref_entry *search_ref_dir(struct ref_dir *dir,
ref_entry_cmp_sslice);
if (r == NULL)
- return NULL;
+ return -1;
- return *r;
+ return r - dir->entries;
}
/*
@@ -379,8 +401,9 @@ static struct ref_dir *search_for_subdir(struct ref_dir *dir,
const char *subdirname, size_t len,
int mkdir)
{
- struct ref_entry *entry = search_ref_dir(dir, subdirname, len);
- if (!entry) {
+ int entry_index = search_ref_dir(dir, subdirname, len);
+ struct ref_entry *entry;
+ if (entry_index == -1) {
if (!mkdir)
return NULL;
/*
@@ -391,6 +414,8 @@ static struct ref_dir *search_for_subdir(struct ref_dir *dir,
*/
entry = create_dir_entry(dir->ref_cache, subdirname, len, 0);
add_entry_to_dir(dir, entry);
+ } else {
+ entry = dir->entries[entry_index];
}
return get_ref_dir(entry);
}
@@ -429,12 +454,67 @@ static struct ref_dir *find_containing_dir(struct ref_dir *dir,
*/
static struct ref_entry *find_ref(struct ref_dir *dir, const char *refname)
{
+ int entry_index;
struct ref_entry *entry;
dir = find_containing_dir(dir, refname, 0);
if (!dir)
return NULL;
- entry = search_ref_dir(dir, refname, strlen(refname));
- return (entry && !(entry->flag & REF_DIR)) ? entry : NULL;
+ entry_index = search_ref_dir(dir, refname, strlen(refname));
+ if (entry_index == -1)
+ return NULL;
+ entry = dir->entries[entry_index];
+ return (entry->flag & REF_DIR) ? NULL : entry;
+}
+
+/*
+ * Remove the entry with the given name from dir, recursing into
+ * subdirectories as necessary. If refname is the name of a directory
+ * (i.e., ends with '/'), then remove the directory and its contents.
+ * If the removal was successful, return the number of entries
+ * remaining in the directory entry that contained the deleted entry.
+ * If the name was not found, return -1. Please note that this
+ * function only deletes the entry from the cache; it does not delete
+ * it from the filesystem or ensure that other cache entries (which
+ * might be symbolic references to the removed entry) are updated.
+ * Nor does it remove any containing dir entries that might be made
+ * empty by the removal. dir must represent the top-level directory
+ * and must already be complete.
+ */
+static int remove_entry(struct ref_dir *dir, const char *refname)
+{
+ int refname_len = strlen(refname);
+ int entry_index;
+ struct ref_entry *entry;
+ int is_dir = refname[refname_len - 1] == '/';
+ if (is_dir) {
+ /*
+ * refname represents a reference directory. Remove
+ * the trailing slash; otherwise we will get the
+ * directory *representing* refname rather than the
+ * one *containing* it.
+ */
+ char *dirname = xmemdupz(refname, refname_len - 1);
+ dir = find_containing_dir(dir, dirname, 0);
+ free(dirname);
+ } else {
+ dir = find_containing_dir(dir, refname, 0);
+ }
+ if (!dir)
+ return -1;
+ entry_index = search_ref_dir(dir, refname, refname_len);
+ if (entry_index == -1)
+ return -1;
+ entry = dir->entries[entry_index];
+
+ memmove(&dir->entries[entry_index],
+ &dir->entries[entry_index + 1],
+ (dir->nr - entry_index - 1) * sizeof(*dir->entries)
+ );
+ dir->nr--;
+ if (dir->sorted > entry_index)
+ dir->sorted--;
+ free_ref_entry(entry);
+ return dir->nr;
}
/*
@@ -503,28 +583,69 @@ static void sort_ref_dir(struct ref_dir *dir)
dir->sorted = dir->nr = i;
}
-#define DO_FOR_EACH_INCLUDE_BROKEN 01
+/* Include broken references in a do_for_each_ref*() iteration: */
+#define DO_FOR_EACH_INCLUDE_BROKEN 0x01
+
+/*
+ * Return true iff the reference described by entry can be resolved to
+ * an object in the database. Emit a warning if the referred-to
+ * object does not exist.
+ */
+static int ref_resolves_to_object(struct ref_entry *entry)
+{
+ if (entry->flag & REF_ISBROKEN)
+ return 0;
+ if (!has_sha1_file(entry->u.value.sha1)) {
+ error("%s does not point to a valid object!", entry->name);
+ return 0;
+ }
+ return 1;
+}
+/*
+ * current_ref is a performance hack: when iterating over references
+ * using the for_each_ref*() functions, current_ref is set to the
+ * current reference's entry before calling the callback function. If
+ * the callback function calls peel_ref(), then peel_ref() first
+ * checks whether the reference to be peeled is the current reference
+ * (it usually is) and if so, returns that reference's peeled version
+ * if it is available. This avoids a refname lookup in a common case.
+ */
static struct ref_entry *current_ref;
-static int do_one_ref(const char *base, each_ref_fn fn, int trim,
- int flags, void *cb_data, struct ref_entry *entry)
+typedef int each_ref_entry_fn(struct ref_entry *entry, void *cb_data);
+
+struct ref_entry_cb {
+ const char *base;
+ int trim;
+ int flags;
+ each_ref_fn *fn;
+ void *cb_data;
+};
+
+/*
+ * Handle one reference in a do_for_each_ref*()-style iteration,
+ * calling an each_ref_fn for each entry.
+ */
+static int do_one_ref(struct ref_entry *entry, void *cb_data)
{
+ struct ref_entry_cb *data = cb_data;
+ struct ref_entry *old_current_ref;
int retval;
- if (prefixcmp(entry->name, base))
+
+ if (prefixcmp(entry->name, data->base))
return 0;
- if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) {
- if (entry->flag & REF_ISBROKEN)
- return 0; /* ignore broken refs e.g. dangling symref */
- if (!has_sha1_file(entry->u.value.sha1)) {
- error("%s does not point to a valid object!", entry->name);
- return 0;
- }
- }
+ if (!(data->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
+ !ref_resolves_to_object(entry))
+ return 0;
+
+ /* Store the old value, in case this is a recursive call: */
+ old_current_ref = current_ref;
current_ref = entry;
- retval = fn(entry->name + trim, entry->u.value.sha1, entry->flag, cb_data);
- current_ref = NULL;
+ retval = data->fn(entry->name + data->trim, entry->u.value.sha1,
+ entry->flag, data->cb_data);
+ current_ref = old_current_ref;
return retval;
}
@@ -532,11 +653,11 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
* Call fn for each reference in dir that has index in the range
* offset <= index < dir->nr. Recurse into subdirectories that are in
* that index range, sorting them before iterating. This function
- * does not sort dir itself; it should be sorted beforehand.
+ * does not sort dir itself; it should be sorted beforehand. fn is
+ * called for all references, including broken ones.
*/
-static int do_for_each_ref_in_dir(struct ref_dir *dir, int offset,
- const char *base,
- each_ref_fn fn, int trim, int flags, void *cb_data)
+static int do_for_each_entry_in_dir(struct ref_dir *dir, int offset,
+ each_ref_entry_fn fn, void *cb_data)
{
int i;
assert(dir->sorted == dir->nr);
@@ -546,10 +667,9 @@ static int do_for_each_ref_in_dir(struct ref_dir *dir, int offset,
if (entry->flag & REF_DIR) {
struct ref_dir *subdir = get_ref_dir(entry);
sort_ref_dir(subdir);
- retval = do_for_each_ref_in_dir(subdir, 0,
- base, fn, trim, flags, cb_data);
+ retval = do_for_each_entry_in_dir(subdir, 0, fn, cb_data);
} else {
- retval = do_one_ref(base, fn, trim, flags, cb_data, entry);
+ retval = fn(entry, cb_data);
}
if (retval)
return retval;
@@ -562,12 +682,12 @@ static int do_for_each_ref_in_dir(struct ref_dir *dir, int offset,
* by refname. Recurse into subdirectories. If a value entry appears
* in both dir1 and dir2, then only process the version that is in
* dir2. The input dirs must already be sorted, but subdirs will be
- * sorted as needed.
+ * sorted as needed. fn is called for all references, including
+ * broken ones.
*/
-static int do_for_each_ref_in_dirs(struct ref_dir *dir1,
- struct ref_dir *dir2,
- const char *base, each_ref_fn fn, int trim,
- int flags, void *cb_data)
+static int do_for_each_entry_in_dirs(struct ref_dir *dir1,
+ struct ref_dir *dir2,
+ each_ref_entry_fn fn, void *cb_data)
{
int retval;
int i1 = 0, i2 = 0;
@@ -578,12 +698,10 @@ static int do_for_each_ref_in_dirs(struct ref_dir *dir1,
struct ref_entry *e1, *e2;
int cmp;
if (i1 == dir1->nr) {
- return do_for_each_ref_in_dir(dir2, i2,
- base, fn, trim, flags, cb_data);
+ return do_for_each_entry_in_dir(dir2, i2, fn, cb_data);
}
if (i2 == dir2->nr) {
- return do_for_each_ref_in_dir(dir1, i1,
- base, fn, trim, flags, cb_data);
+ return do_for_each_entry_in_dir(dir1, i1, fn, cb_data);
}
e1 = dir1->entries[i1];
e2 = dir2->entries[i2];
@@ -595,14 +713,13 @@ static int do_for_each_ref_in_dirs(struct ref_dir *dir1,
struct ref_dir *subdir2 = get_ref_dir(e2);
sort_ref_dir(subdir1);
sort_ref_dir(subdir2);
- retval = do_for_each_ref_in_dirs(
- subdir1, subdir2,
- base, fn, trim, flags, cb_data);
+ retval = do_for_each_entry_in_dirs(
+ subdir1, subdir2, fn, cb_data);
i1++;
i2++;
} else if (!(e1->flag & REF_DIR) && !(e2->flag & REF_DIR)) {
/* Both are references; ignore the one from dir1. */
- retval = do_one_ref(base, fn, trim, flags, cb_data, e2);
+ retval = fn(e2, cb_data);
i1++;
i2++;
} else {
@@ -621,26 +738,33 @@ static int do_for_each_ref_in_dirs(struct ref_dir *dir1,
if (e->flag & REF_DIR) {
struct ref_dir *subdir = get_ref_dir(e);
sort_ref_dir(subdir);
- retval = do_for_each_ref_in_dir(
- subdir, 0,
- base, fn, trim, flags, cb_data);
+ retval = do_for_each_entry_in_dir(
+ subdir, 0, fn, cb_data);
} else {
- retval = do_one_ref(base, fn, trim, flags, cb_data, e);
+ retval = fn(e, cb_data);
}
}
if (retval)
return retval;
}
- if (i1 < dir1->nr)
- return do_for_each_ref_in_dir(dir1, i1,
- base, fn, trim, flags, cb_data);
- if (i2 < dir2->nr)
- return do_for_each_ref_in_dir(dir2, i2,
- base, fn, trim, flags, cb_data);
- return 0;
}
/*
+ * Load all of the refs from the dir into our in-memory cache. The hard work
+ * of loading loose refs is done by get_ref_dir(), so we just need to recurse
+ * through all of the sub-directories. We do not even need to care about
+ * sorting, as traversal order does not matter to us.
+ */
+static void prime_ref_dir(struct ref_dir *dir)
+{
+ int i;
+ for (i = 0; i < dir->nr; i++) {
+ struct ref_entry *entry = dir->entries[i];
+ if (entry->flag & REF_DIR)
+ prime_ref_dir(get_ref_dir(entry));
+ }
+}
+/*
* Return true iff refname1 and refname2 conflict with each other.
* Two reference names conflict if one of them exactly matches the
* leading components of the other; e.g., "foo/bar" conflicts with
@@ -661,14 +785,13 @@ struct name_conflict_cb {
const char *conflicting_refname;
};
-static int name_conflict_fn(const char *existingrefname, const unsigned char *sha1,
- int flags, void *cb_data)
+static int name_conflict_fn(struct ref_entry *entry, void *cb_data)
{
struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data;
- if (data->oldrefname && !strcmp(data->oldrefname, existingrefname))
+ if (data->oldrefname && !strcmp(data->oldrefname, entry->name))
return 0;
- if (names_conflict(data->refname, existingrefname)) {
- data->conflicting_refname = existingrefname;
+ if (names_conflict(data->refname, entry->name)) {
+ data->conflicting_refname = entry->name;
return 1;
}
return 0;
@@ -676,7 +799,7 @@ static int name_conflict_fn(const char *existingrefname, const unsigned char *sh
/*
* Return true iff a reference named refname could be created without
- * conflicting with the name of an existing reference in array. If
+ * conflicting with the name of an existing reference in dir. If
* oldrefname is non-NULL, ignore potential conflicts with oldrefname
* (e.g., because oldrefname is scheduled for deletion in the same
* operation).
@@ -690,9 +813,7 @@ static int is_refname_available(const char *refname, const char *oldrefname,
data.conflicting_refname = NULL;
sort_ref_dir(dir);
- if (do_for_each_ref_in_dir(dir, 0, "", name_conflict_fn,
- 0, DO_FOR_EACH_INCLUDE_BROKEN,
- &data)) {
+ if (do_for_each_entry_in_dir(dir, 0, name_conflict_fn, &data)) {
error("'%s' exists; cannot create '%s'",
data.conflicting_refname, refname);
return 0;
@@ -700,6 +821,30 @@ static int is_refname_available(const char *refname, const char *oldrefname,
return 1;
}
+struct packed_ref_cache {
+ struct ref_entry *root;
+
+ /*
+ * Count of references to the data structure in this instance,
+ * including the pointer from ref_cache::packed if any. The
+ * data will not be freed as long as the reference count is
+ * nonzero.
+ */
+ unsigned int referrers;
+
+ /*
+ * Iff the packed-refs file associated with this instance is
+ * currently locked for writing, this points at the associated
+ * lock (which is owned by somebody else). The referrer count
+ * is also incremented when the file is locked and decremented
+ * when it is unlocked.
+ */
+ struct lock_file *lock;
+
+ /* The metadata from when this packed-refs cache was read */
+ struct stat_validity validity;
+};
+
/*
* Future: need to be in "struct repository"
* when doing a full libification.
@@ -707,16 +852,51 @@ static int is_refname_available(const char *refname, const char *oldrefname,
static struct ref_cache {
struct ref_cache *next;
struct ref_entry *loose;
- struct ref_entry *packed;
- /* The submodule name, or "" for the main repo. */
- char name[FLEX_ARRAY];
-} *ref_cache;
+ struct packed_ref_cache *packed;
+ /*
+ * The submodule name, or "" for the main repo. We allocate
+ * length 1 rather than FLEX_ARRAY so that the main ref_cache
+ * is initialized correctly.
+ */
+ char name[1];
+} ref_cache, *submodule_ref_caches;
+
+/* Lock used for the main packed-refs file: */
+static struct lock_file packlock;
+
+/*
+ * Increment the reference count of *packed_refs.
+ */
+static void acquire_packed_ref_cache(struct packed_ref_cache *packed_refs)
+{
+ packed_refs->referrers++;
+}
+
+/*
+ * Decrease the reference count of *packed_refs. If it goes to zero,
+ * free *packed_refs and return true; otherwise return false.
+ */
+static int release_packed_ref_cache(struct packed_ref_cache *packed_refs)
+{
+ if (!--packed_refs->referrers) {
+ free_ref_entry(packed_refs->root);
+ stat_validity_clear(&packed_refs->validity);
+ free(packed_refs);
+ return 1;
+ } else {
+ return 0;
+ }
+}
static void clear_packed_ref_cache(struct ref_cache *refs)
{
if (refs->packed) {
- free_ref_entry(refs->packed);
+ struct packed_ref_cache *packed_refs = refs->packed;
+
+ if (packed_refs->lock)
+ die("internal error: packed-ref cache cleared while locked");
refs->packed = NULL;
+ release_packed_ref_cache(packed_refs);
}
}
@@ -748,18 +928,18 @@ static struct ref_cache *create_ref_cache(const char *submodule)
*/
static struct ref_cache *get_ref_cache(const char *submodule)
{
- struct ref_cache *refs = ref_cache;
- if (!submodule)
- submodule = "";
- while (refs) {
+ struct ref_cache *refs;
+
+ if (!submodule || !*submodule)
+ return &ref_cache;
+
+ for (refs = submodule_ref_caches; refs; refs = refs->next)
if (!strcmp(submodule, refs->name))
return refs;
- refs = refs->next;
- }
refs = create_ref_cache(submodule);
- refs->next = ref_cache;
- ref_cache = refs;
+ refs->next = submodule_ref_caches;
+ submodule_ref_caches = refs;
return refs;
}
@@ -770,6 +950,16 @@ void invalidate_ref_cache(const char *submodule)
clear_loose_ref_cache(refs);
}
+/* The length of a peeled reference line in packed-refs, including EOL: */
+#define PEELED_LINE_LENGTH 42
+
+/*
+ * The packed-refs header line that we write out. Perhaps other
+ * traits will be added later. The trailing space is required.
+ */
+static const char PACKED_REFS_HEADER[] =
+ "# pack-refs with: peeled fully-peeled \n";
+
/*
* Parse one line from a packed-refs file. Write the SHA1 to sha1.
* Return a pointer to the refname within the line (null-terminated),
@@ -862,8 +1052,8 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
}
if (last &&
refline[0] == '^' &&
- strlen(refline) == 42 &&
- refline[41] == '\n' &&
+ strlen(refline) == PEELED_LINE_LENGTH &&
+ refline[PEELED_LINE_LENGTH - 1] == '\n' &&
!get_sha1_hex(refline + 1, sha1)) {
hashcpy(last->u.value.peeled, sha1);
/*
@@ -876,30 +1066,58 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
}
}
-static struct ref_dir *get_packed_refs(struct ref_cache *refs)
+/*
+ * Get the packed_ref_cache for the specified ref_cache, creating it
+ * if necessary.
+ */
+static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs)
{
+ const char *packed_refs_file;
+
+ if (*refs->name)
+ packed_refs_file = git_path_submodule(refs->name, "packed-refs");
+ else
+ packed_refs_file = git_path("packed-refs");
+
+ if (refs->packed &&
+ !stat_validity_check(&refs->packed->validity, packed_refs_file))
+ clear_packed_ref_cache(refs);
+
if (!refs->packed) {
- const char *packed_refs_file;
FILE *f;
- refs->packed = create_dir_entry(refs, "", 0, 0);
- if (*refs->name)
- packed_refs_file = git_path_submodule(refs->name, "packed-refs");
- else
- packed_refs_file = git_path("packed-refs");
+ refs->packed = xcalloc(1, sizeof(*refs->packed));
+ acquire_packed_ref_cache(refs->packed);
+ refs->packed->root = create_dir_entry(refs, "", 0, 0);
f = fopen(packed_refs_file, "r");
if (f) {
- read_packed_refs(f, get_ref_dir(refs->packed));
+ stat_validity_update(&refs->packed->validity, fileno(f));
+ read_packed_refs(f, get_ref_dir(refs->packed->root));
fclose(f);
}
}
- return get_ref_dir(refs->packed);
+ return refs->packed;
+}
+
+static struct ref_dir *get_packed_ref_dir(struct packed_ref_cache *packed_ref_cache)
+{
+ return get_ref_dir(packed_ref_cache->root);
+}
+
+static struct ref_dir *get_packed_refs(struct ref_cache *refs)
+{
+ return get_packed_ref_dir(get_packed_ref_cache(refs));
}
void add_packed_ref(const char *refname, const unsigned char *sha1)
{
- add_ref(get_packed_refs(get_ref_cache(NULL)),
- create_ref_entry(refname, sha1, REF_ISPACKED, 1));
+ struct packed_ref_cache *packed_ref_cache =
+ get_packed_ref_cache(&ref_cache);
+
+ if (!packed_ref_cache->lock)
+ die("internal error: packed refs not locked");
+ add_ref(get_packed_ref_dir(packed_ref_cache),
+ create_ref_entry(refname, sha1, REF_ISPACKED, 1));
}
/*
@@ -1069,18 +1287,43 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
}
/*
- * Try to read ref from the packed references. On success, set sha1
- * and return 0; otherwise, return -1.
+ * Return the ref_entry for the given refname from the packed
+ * references. If it does not exist, return NULL.
+ */
+static struct ref_entry *get_packed_ref(const char *refname)
+{
+ return find_ref(get_packed_refs(&ref_cache), refname);
+}
+
+/*
+ * A loose ref file doesn't exist; check for a packed ref. The
+ * options are forwarded from resolve_safe_unsafe().
*/
-static int get_packed_ref(const char *refname, unsigned char *sha1)
+static const char *handle_missing_loose_ref(const char *refname,
+ unsigned char *sha1,
+ int reading,
+ int *flag)
{
- struct ref_dir *packed = get_packed_refs(get_ref_cache(NULL));
- struct ref_entry *entry = find_ref(packed, refname);
+ struct ref_entry *entry;
+
+ /*
+ * The loose reference file does not exist; check for a packed
+ * reference.
+ */
+ entry = get_packed_ref(refname);
if (entry) {
hashcpy(sha1, entry->u.value.sha1);
- return 0;
+ if (flag)
+ *flag |= REF_ISPACKED;
+ return refname;
+ }
+ /* The reference is not a packed reference, either. */
+ if (reading) {
+ return NULL;
+ } else {
+ hashclr(sha1);
+ return refname;
}
- return -1;
}
const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag)
@@ -1107,32 +1350,34 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
git_snpath(path, sizeof(path), "%s", refname);
+ /*
+ * We might have to loop back here to avoid a race
+ * condition: first we lstat() the file, then we try
+ * to read it as a link or as a file. But if somebody
+ * changes the type of the file (file <-> directory
+ * <-> symlink) between the lstat() and reading, then
+ * we don't want to report that as an error but rather
+ * try again starting with the lstat().
+ */
+ stat_ref:
if (lstat(path, &st) < 0) {
- if (errno != ENOENT)
- return NULL;
- /*
- * The loose reference file does not exist;
- * check for a packed reference.
- */
- if (!get_packed_ref(refname, sha1)) {
- if (flag)
- *flag |= REF_ISPACKED;
- return refname;
- }
- /* The reference is not a packed reference, either. */
- if (reading) {
+ if (errno == ENOENT)
+ return handle_missing_loose_ref(refname, sha1,
+ reading, flag);
+ else
return NULL;
- } else {
- hashclr(sha1);
- return refname;
- }
}
/* Follow "normalized" - ie "refs/.." symlinks by hand */
if (S_ISLNK(st.st_mode)) {
len = readlink(path, buffer, sizeof(buffer)-1);
- if (len < 0)
- return NULL;
+ if (len < 0) {
+ if (errno == ENOENT || errno == EINVAL)
+ /* inconsistent with lstat; retry */
+ goto stat_ref;
+ else
+ return NULL;
+ }
buffer[len] = 0;
if (!prefixcmp(buffer, "refs/") &&
!check_refname_format(buffer, 0)) {
@@ -1155,8 +1400,13 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
* a ref
*/
fd = open(path, O_RDONLY);
- if (fd < 0)
- return NULL;
+ if (fd < 0) {
+ if (errno == ENOENT)
+ /* inconsistent with lstat; retry */
+ goto stat_ref;
+ else
+ return NULL;
+ }
len = read_in_full(fd, buffer, sizeof(buffer)-1);
close(fd);
if (len < 0)
@@ -1168,8 +1418,19 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
/*
* Is it a symbolic ref?
*/
- if (prefixcmp(buffer, "ref:"))
- break;
+ if (prefixcmp(buffer, "ref:")) {
+ /*
+ * Please note that FETCH_HEAD has a second
+ * line containing other data.
+ */
+ if (get_sha1_hex(buffer, sha1) ||
+ (buffer[40] != '\0' && !isspace(buffer[40]))) {
+ if (flag)
+ *flag |= REF_ISBROKEN;
+ return NULL;
+ }
+ return refname;
+ }
if (flag)
*flag |= REF_ISSYMREF;
buf = buffer + 4;
@@ -1182,13 +1443,6 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
}
refname = strcpy(refname_buffer, buf);
}
- /* Please note that FETCH_HEAD has a second line containing other data. */
- if (get_sha1_hex(buffer, sha1) || (buffer[40] != '\0' && !isspace(buffer[40]))) {
- if (flag)
- *flag |= REF_ISBROKEN;
- return NULL;
- }
- return refname;
}
char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag)
@@ -1231,54 +1485,130 @@ static int filter_refs(const char *refname, const unsigned char *sha1, int flags
return filter->fn(refname, sha1, flags, filter->cb_data);
}
+enum peel_status {
+ /* object was peeled successfully: */
+ PEEL_PEELED = 0,
+
+ /*
+ * object cannot be peeled because the named object (or an
+ * object referred to by a tag in the peel chain), does not
+ * exist.
+ */
+ PEEL_INVALID = -1,
+
+ /* object cannot be peeled because it is not a tag: */
+ PEEL_NON_TAG = -2,
+
+ /* ref_entry contains no peeled value because it is a symref: */
+ PEEL_IS_SYMREF = -3,
+
+ /*
+ * ref_entry cannot be peeled because it is broken (i.e., the
+ * symbolic reference cannot even be resolved to an object
+ * name):
+ */
+ PEEL_BROKEN = -4
+};
+
+/*
+ * Peel the named object; i.e., if the object is a tag, resolve the
+ * tag recursively until a non-tag is found. If successful, store the
+ * result to sha1 and return PEEL_PEELED. If the object is not a tag
+ * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,
+ * and leave sha1 unchanged.
+ */
+static enum peel_status peel_object(const unsigned char *name, unsigned char *sha1)
+{
+ struct object *o = lookup_unknown_object(name);
+
+ if (o->type == OBJ_NONE) {
+ int type = sha1_object_info(name, NULL);
+ if (type < 0)
+ return PEEL_INVALID;
+ o->type = type;
+ }
+
+ if (o->type != OBJ_TAG)
+ return PEEL_NON_TAG;
+
+ o = deref_tag_noverify(o);
+ if (!o)
+ return PEEL_INVALID;
+
+ hashcpy(sha1, o->sha1);
+ return PEEL_PEELED;
+}
+
+/*
+ * Peel the entry (if possible) and return its new peel_status. If
+ * repeel is true, re-peel the entry even if there is an old peeled
+ * value that is already stored in it.
+ *
+ * It is OK to call this function with a packed reference entry that
+ * might be stale and might even refer to an object that has since
+ * been garbage-collected. In such a case, if the entry has
+ * REF_KNOWS_PEELED then leave the status unchanged and return
+ * PEEL_PEELED or PEEL_NON_TAG; otherwise, return PEEL_INVALID.
+ */
+static enum peel_status peel_entry(struct ref_entry *entry, int repeel)
+{
+ enum peel_status status;
+
+ if (entry->flag & REF_KNOWS_PEELED) {
+ if (repeel) {
+ entry->flag &= ~REF_KNOWS_PEELED;
+ hashclr(entry->u.value.peeled);
+ } else {
+ return is_null_sha1(entry->u.value.peeled) ?
+ PEEL_NON_TAG : PEEL_PEELED;
+ }
+ }
+ if (entry->flag & REF_ISBROKEN)
+ return PEEL_BROKEN;
+ if (entry->flag & REF_ISSYMREF)
+ return PEEL_IS_SYMREF;
+
+ status = peel_object(entry->u.value.sha1, entry->u.value.peeled);
+ if (status == PEEL_PEELED || status == PEEL_NON_TAG)
+ entry->flag |= REF_KNOWS_PEELED;
+ return status;
+}
+
int peel_ref(const char *refname, unsigned char *sha1)
{
int flag;
unsigned char base[20];
- struct object *o;
if (current_ref && (current_ref->name == refname
- || !strcmp(current_ref->name, refname))) {
- if (current_ref->flag & REF_KNOWS_PEELED) {
- if (is_null_sha1(current_ref->u.value.peeled))
- return -1;
- hashcpy(sha1, current_ref->u.value.peeled);
- return 0;
- }
- hashcpy(base, current_ref->u.value.sha1);
- goto fallback;
+ || !strcmp(current_ref->name, refname))) {
+ if (peel_entry(current_ref, 0))
+ return -1;
+ hashcpy(sha1, current_ref->u.value.peeled);
+ return 0;
}
if (read_ref_full(refname, base, 1, &flag))
return -1;
- if ((flag & REF_ISPACKED)) {
- struct ref_dir *dir = get_packed_refs(get_ref_cache(NULL));
- struct ref_entry *r = find_ref(dir, refname);
-
- if (r != NULL && r->flag & REF_KNOWS_PEELED) {
+ /*
+ * If the reference is packed, read its ref_entry from the
+ * cache in the hope that we already know its peeled value.
+ * We only try this optimization on packed references because
+ * (a) forcing the filling of the loose reference cache could
+ * be expensive and (b) loose references anyway usually do not
+ * have REF_KNOWS_PEELED.
+ */
+ if (flag & REF_ISPACKED) {
+ struct ref_entry *r = get_packed_ref(refname);
+ if (r) {
+ if (peel_entry(r, 0))
+ return -1;
hashcpy(sha1, r->u.value.peeled);
return 0;
}
}
-fallback:
- o = lookup_unknown_object(base);
- if (o->type == OBJ_NONE) {
- int type = sha1_object_info(base, NULL);
- if (type < 0)
- return -1;
- o->type = type;
- }
-
- if (o->type == OBJ_TAG) {
- o = deref_tag_noverify(o);
- if (o) {
- hashcpy(sha1, o->sha1);
- return 0;
- }
- }
- return -1;
+ return peel_object(base, sha1);
}
struct warn_if_dangling_data {
@@ -1316,40 +1646,84 @@ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
for_each_rawref(warn_if_dangling_symref, &data);
}
-static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn fn,
- int trim, int flags, void *cb_data)
+/*
+ * Call fn for each reference in the specified ref_cache, omitting
+ * references not in the containing_dir of base. fn is called for all
+ * references, including broken ones. If fn ever returns a non-zero
+ * value, stop the iteration and return that value; otherwise, return
+ * 0.
+ */
+static int do_for_each_entry(struct ref_cache *refs, const char *base,
+ each_ref_entry_fn fn, void *cb_data)
{
- struct ref_cache *refs = get_ref_cache(submodule);
- struct ref_dir *packed_dir = get_packed_refs(refs);
- struct ref_dir *loose_dir = get_loose_refs(refs);
+ struct packed_ref_cache *packed_ref_cache;
+ struct ref_dir *loose_dir;
+ struct ref_dir *packed_dir;
int retval = 0;
+ /*
+ * We must make sure that all loose refs are read before accessing the
+ * packed-refs file; this avoids a race condition in which loose refs
+ * are migrated to the packed-refs file by a simultaneous process, but
+ * our in-memory view is from before the migration. get_packed_ref_cache()
+ * takes care of making sure our view is up to date with what is on
+ * disk.
+ */
+ loose_dir = get_loose_refs(refs);
if (base && *base) {
- packed_dir = find_containing_dir(packed_dir, base, 0);
loose_dir = find_containing_dir(loose_dir, base, 0);
}
+ if (loose_dir)
+ prime_ref_dir(loose_dir);
+
+ packed_ref_cache = get_packed_ref_cache(refs);
+ acquire_packed_ref_cache(packed_ref_cache);
+ packed_dir = get_packed_ref_dir(packed_ref_cache);
+ if (base && *base) {
+ packed_dir = find_containing_dir(packed_dir, base, 0);
+ }
if (packed_dir && loose_dir) {
sort_ref_dir(packed_dir);
sort_ref_dir(loose_dir);
- retval = do_for_each_ref_in_dirs(
- packed_dir, loose_dir,
- base, fn, trim, flags, cb_data);
+ retval = do_for_each_entry_in_dirs(
+ packed_dir, loose_dir, fn, cb_data);
} else if (packed_dir) {
sort_ref_dir(packed_dir);
- retval = do_for_each_ref_in_dir(
- packed_dir, 0,
- base, fn, trim, flags, cb_data);
+ retval = do_for_each_entry_in_dir(
+ packed_dir, 0, fn, cb_data);
} else if (loose_dir) {
sort_ref_dir(loose_dir);
- retval = do_for_each_ref_in_dir(
- loose_dir, 0,
- base, fn, trim, flags, cb_data);
+ retval = do_for_each_entry_in_dir(
+ loose_dir, 0, fn, cb_data);
}
+ release_packed_ref_cache(packed_ref_cache);
return retval;
}
+/*
+ * Call fn for each reference in the specified ref_cache for which the
+ * refname begins with base. If trim is non-zero, then trim that many
+ * characters off the beginning of each refname before passing the
+ * refname to fn. flags can be DO_FOR_EACH_INCLUDE_BROKEN to include
+ * broken references in the iteration. If fn ever returns a non-zero
+ * value, stop the iteration and return that value; otherwise, return
+ * 0.
+ */
+static int do_for_each_ref(struct ref_cache *refs, const char *base,
+ each_ref_fn fn, int trim, int flags, void *cb_data)
+{
+ struct ref_entry_cb data;
+ data.base = base;
+ data.trim = trim;
+ data.flags = flags;
+ data.fn = fn;
+ data.cb_data = cb_data;
+
+ return do_for_each_entry(refs, base, do_one_ref, &data);
+}
+
static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data)
{
unsigned char sha1[20];
@@ -1380,23 +1754,23 @@ int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
int for_each_ref(each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(NULL, "", fn, 0, 0, cb_data);
+ return do_for_each_ref(&ref_cache, "", fn, 0, 0, cb_data);
}
int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(submodule, "", fn, 0, 0, cb_data);
+ return do_for_each_ref(get_ref_cache(submodule), "", fn, 0, 0, cb_data);
}
int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(NULL, prefix, fn, strlen(prefix), 0, cb_data);
+ return do_for_each_ref(&ref_cache, prefix, fn, strlen(prefix), 0, cb_data);
}
int for_each_ref_in_submodule(const char *submodule, const char *prefix,
each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(submodule, prefix, fn, strlen(prefix), 0, cb_data);
+ return do_for_each_ref(get_ref_cache(submodule), prefix, fn, strlen(prefix), 0, cb_data);
}
int for_each_tag_ref(each_ref_fn fn, void *cb_data)
@@ -1431,7 +1805,7 @@ int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *c
int for_each_replace_ref(each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(NULL, "refs/replace/", fn, 13, 0, cb_data);
+ return do_for_each_ref(&ref_cache, "refs/replace/", fn, 13, 0, cb_data);
}
int head_ref_namespaced(each_ref_fn fn, void *cb_data)
@@ -1454,7 +1828,7 @@ int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
struct strbuf buf = STRBUF_INIT;
int ret;
strbuf_addf(&buf, "%srefs/", get_git_namespace());
- ret = do_for_each_ref(NULL, buf.buf, fn, 0, 0, cb_data);
+ ret = do_for_each_ref(&ref_cache, buf.buf, fn, 0, 0, cb_data);
strbuf_release(&buf);
return ret;
}
@@ -1496,7 +1870,7 @@ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)
int for_each_rawref(each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(NULL, "", fn, 0,
+ return do_for_each_ref(&ref_cache, "", fn, 0,
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
@@ -1702,7 +2076,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
* name is a proper prefix of our refname.
*/
if (missing &&
- !is_refname_available(refname, NULL, get_packed_refs(get_ref_cache(NULL)))) {
+ !is_refname_available(refname, NULL, get_packed_refs(&ref_cache))) {
last_errno = ENOTDIR;
goto error_return;
}
@@ -1754,48 +2128,325 @@ struct ref_lock *lock_any_ref_for_update(const char *refname,
return lock_ref_sha1_basic(refname, old_sha1, flags, NULL);
}
-struct repack_without_ref_sb {
- const char *refname;
- int fd;
-};
-
-static int repack_without_ref_fn(const char *refname, const unsigned char *sha1,
- int flags, void *cb_data)
+/*
+ * Write an entry to the packed-refs file for the specified refname.
+ * If peeled is non-NULL, write it as the entry's peeled value.
+ */
+static void write_packed_entry(int fd, char *refname, unsigned char *sha1,
+ unsigned char *peeled)
{
- struct repack_without_ref_sb *data = cb_data;
char line[PATH_MAX + 100];
int len;
- if (!strcmp(data->refname, refname))
- return 0;
len = snprintf(line, sizeof(line), "%s %s\n",
sha1_to_hex(sha1), refname);
/* this should not happen but just being defensive */
if (len > sizeof(line))
die("too long a refname '%s'", refname);
- write_or_die(data->fd, line, len);
+ write_or_die(fd, line, len);
+
+ if (peeled) {
+ if (snprintf(line, sizeof(line), "^%s\n",
+ sha1_to_hex(peeled)) != PEELED_LINE_LENGTH)
+ die("internal error");
+ write_or_die(fd, line, PEELED_LINE_LENGTH);
+ }
+}
+
+/*
+ * An each_ref_entry_fn that writes the entry to a packed-refs file.
+ */
+static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
+{
+ int *fd = cb_data;
+ enum peel_status peel_status = peel_entry(entry, 0);
+
+ if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
+ error("internal error: %s is not a valid packed reference!",
+ entry->name);
+ write_packed_entry(*fd, entry->name, entry->u.value.sha1,
+ peel_status == PEEL_PEELED ?
+ entry->u.value.peeled : NULL);
return 0;
}
-static struct lock_file packlock;
+int lock_packed_refs(int flags)
+{
+ struct packed_ref_cache *packed_ref_cache;
-static int repack_without_ref(const char *refname)
+ if (hold_lock_file_for_update(&packlock, git_path("packed-refs"), flags) < 0)
+ return -1;
+ /*
+ * Get the current packed-refs while holding the lock. If the
+ * packed-refs file has been modified since we last read it,
+ * this will automatically invalidate the cache and re-read
+ * the packed-refs file.
+ */
+ packed_ref_cache = get_packed_ref_cache(&ref_cache);
+ packed_ref_cache->lock = &packlock;
+ /* Increment the reference count to prevent it from being freed: */
+ acquire_packed_ref_cache(packed_ref_cache);
+ return 0;
+}
+
+int commit_packed_refs(void)
{
- struct repack_without_ref_sb data;
- struct ref_cache *refs = get_ref_cache(NULL);
- struct ref_dir *packed = get_packed_refs(refs);
- if (find_ref(packed, refname) == NULL)
+ struct packed_ref_cache *packed_ref_cache =
+ get_packed_ref_cache(&ref_cache);
+ int error = 0;
+
+ if (!packed_ref_cache->lock)
+ die("internal error: packed-refs not locked");
+ write_or_die(packed_ref_cache->lock->fd,
+ PACKED_REFS_HEADER, strlen(PACKED_REFS_HEADER));
+
+ do_for_each_entry_in_dir(get_packed_ref_dir(packed_ref_cache),
+ 0, write_packed_entry_fn,
+ &packed_ref_cache->lock->fd);
+ if (commit_lock_file(packed_ref_cache->lock))
+ error = -1;
+ packed_ref_cache->lock = NULL;
+ release_packed_ref_cache(packed_ref_cache);
+ return error;
+}
+
+void rollback_packed_refs(void)
+{
+ struct packed_ref_cache *packed_ref_cache =
+ get_packed_ref_cache(&ref_cache);
+
+ if (!packed_ref_cache->lock)
+ die("internal error: packed-refs not locked");
+ rollback_lock_file(packed_ref_cache->lock);
+ packed_ref_cache->lock = NULL;
+ release_packed_ref_cache(packed_ref_cache);
+ clear_packed_ref_cache(&ref_cache);
+}
+
+struct ref_to_prune {
+ struct ref_to_prune *next;
+ unsigned char sha1[20];
+ char name[FLEX_ARRAY];
+};
+
+struct pack_refs_cb_data {
+ unsigned int flags;
+ struct ref_dir *packed_refs;
+ struct ref_to_prune *ref_to_prune;
+};
+
+/*
+ * An each_ref_entry_fn that is run over loose references only. If
+ * the loose reference can be packed, add an entry in the packed ref
+ * cache. If the reference should be pruned, also add it to
+ * ref_to_prune in the pack_refs_cb_data.
+ */
+static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)
+{
+ struct pack_refs_cb_data *cb = cb_data;
+ enum peel_status peel_status;
+ struct ref_entry *packed_entry;
+ int is_tag_ref = !prefixcmp(entry->name, "refs/tags/");
+
+ /* ALWAYS pack tags */
+ if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref)
return 0;
- data.refname = refname;
- data.fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
- if (data.fd < 0) {
+
+ /* Do not pack symbolic or broken refs: */
+ if ((entry->flag & REF_ISSYMREF) || !ref_resolves_to_object(entry))
+ return 0;
+
+ /* Add a packed ref cache entry equivalent to the loose entry. */
+ peel_status = peel_entry(entry, 1);
+ if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
+ die("internal error peeling reference %s (%s)",
+ entry->name, sha1_to_hex(entry->u.value.sha1));
+ packed_entry = find_ref(cb->packed_refs, entry->name);
+ if (packed_entry) {
+ /* Overwrite existing packed entry with info from loose entry */
+ packed_entry->flag = REF_ISPACKED | REF_KNOWS_PEELED;
+ hashcpy(packed_entry->u.value.sha1, entry->u.value.sha1);
+ } else {
+ packed_entry = create_ref_entry(entry->name, entry->u.value.sha1,
+ REF_ISPACKED | REF_KNOWS_PEELED, 0);
+ add_ref(cb->packed_refs, packed_entry);
+ }
+ hashcpy(packed_entry->u.value.peeled, entry->u.value.peeled);
+
+ /* Schedule the loose reference for pruning if requested. */
+ if ((cb->flags & PACK_REFS_PRUNE)) {
+ int namelen = strlen(entry->name) + 1;
+ struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
+ hashcpy(n->sha1, entry->u.value.sha1);
+ strcpy(n->name, entry->name);
+ n->next = cb->ref_to_prune;
+ cb->ref_to_prune = n;
+ }
+ return 0;
+}
+
+/*
+ * Remove empty parents, but spare refs/ and immediate subdirs.
+ * Note: munges *name.
+ */
+static void try_remove_empty_parents(char *name)
+{
+ char *p, *q;
+ int i;
+ p = name;
+ for (i = 0; i < 2; i++) { /* refs/{heads,tags,...}/ */
+ while (*p && *p != '/')
+ p++;
+ /* tolerate duplicate slashes; see check_refname_format() */
+ while (*p == '/')
+ p++;
+ }
+ for (q = p; *q; q++)
+ ;
+ while (1) {
+ while (q > p && *q != '/')
+ q--;
+ while (q > p && *(q-1) == '/')
+ q--;
+ if (q == p)
+ break;
+ *q = '\0';
+ if (rmdir(git_path("%s", name)))
+ break;
+ }
+}
+
+/* make sure nobody touched the ref, and unlink */
+static void prune_ref(struct ref_to_prune *r)
+{
+ struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
+
+ if (lock) {
+ unlink_or_warn(git_path("%s", r->name));
+ unlock_ref(lock);
+ try_remove_empty_parents(r->name);
+ }
+}
+
+static void prune_refs(struct ref_to_prune *r)
+{
+ while (r) {
+ prune_ref(r);
+ r = r->next;
+ }
+}
+
+int pack_refs(unsigned int flags)
+{
+ struct pack_refs_cb_data cbdata;
+
+ memset(&cbdata, 0, sizeof(cbdata));
+ cbdata.flags = flags;
+
+ lock_packed_refs(LOCK_DIE_ON_ERROR);
+ cbdata.packed_refs = get_packed_refs(&ref_cache);
+
+ do_for_each_entry_in_dir(get_loose_refs(&ref_cache), 0,
+ pack_if_possible_fn, &cbdata);
+
+ if (commit_packed_refs())
+ die_errno("unable to overwrite old ref-pack file");
+
+ prune_refs(cbdata.ref_to_prune);
+ return 0;
+}
+
+/*
+ * If entry is no longer needed in packed-refs, add it to the string
+ * list pointed to by cb_data. Reasons for deleting entries:
+ *
+ * - Entry is broken.
+ * - Entry is overridden by a loose ref.
+ * - Entry does not point at a valid object.
+ *
+ * In the first and third cases, also emit an error message because these
+ * are indications of repository corruption.
+ */
+static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
+{
+ struct string_list *refs_to_delete = cb_data;
+
+ if (entry->flag & REF_ISBROKEN) {
+ /* This shouldn't happen to packed refs. */
+ error("%s is broken!", entry->name);
+ string_list_append(refs_to_delete, entry->name);
+ return 0;
+ }
+ if (!has_sha1_file(entry->u.value.sha1)) {
+ unsigned char sha1[20];
+ int flags;
+
+ if (read_ref_full(entry->name, sha1, 0, &flags))
+ /* We should at least have found the packed ref. */
+ die("Internal error");
+ if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED)) {
+ /*
+ * This packed reference is overridden by a
+ * loose reference, so it is OK that its value
+ * is no longer valid; for example, it might
+ * refer to an object that has been garbage
+ * collected. For this purpose we don't even
+ * care whether the loose reference itself is
+ * invalid, broken, symbolic, etc. Silently
+ * remove the packed reference.
+ */
+ string_list_append(refs_to_delete, entry->name);
+ return 0;
+ }
+ /*
+ * There is no overriding loose reference, so the fact
+ * that this reference doesn't refer to a valid object
+ * indicates some kind of repository corruption.
+ * Report the problem, then omit the reference from
+ * the output.
+ */
+ error("%s does not point to a valid object!", entry->name);
+ string_list_append(refs_to_delete, entry->name);
+ return 0;
+ }
+
+ return 0;
+}
+
+static int repack_without_ref(const char *refname)
+{
+ struct ref_dir *packed;
+ struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
+ struct string_list_item *ref_to_delete;
+
+ if (!get_packed_ref(refname))
+ return 0; /* refname does not exist in packed refs */
+
+ if (lock_packed_refs(0)) {
unable_to_lock_error(git_path("packed-refs"), errno);
return error("cannot delete '%s' from packed refs", refname);
}
- clear_packed_ref_cache(refs);
- packed = get_packed_refs(refs);
- do_for_each_ref_in_dir(packed, 0, "", repack_without_ref_fn, 0, 0, &data);
- return commit_lock_file(&packlock);
+ packed = get_packed_refs(&ref_cache);
+
+ /* Remove refname from the cache: */
+ if (remove_entry(packed, refname) == -1) {
+ /*
+ * The packed entry disappeared while we were
+ * acquiring the lock.
+ */
+ rollback_packed_refs();
+ return 0;
+ }
+
+ /* Remove any other accumulated cruft: */
+ do_for_each_entry_in_dir(packed, 0, curate_packed_ref_fn, &refs_to_delete);
+ for_each_string_list_item(ref_to_delete, &refs_to_delete) {
+ if (remove_entry(packed, ref_to_delete->string) == -1)
+ die("internal error");
+ }
+
+ /* Write what remains: */
+ return commit_packed_refs();
}
int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
@@ -1823,7 +2474,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
ret |= repack_without_ref(lock->ref_name);
unlink_or_warn(git_path("logs/%s", lock->ref_name));
- invalidate_ref_cache(NULL);
+ clear_loose_ref_cache(&ref_cache);
unlock_ref(lock);
return ret;
}
@@ -1845,7 +2496,6 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
struct stat loginfo;
int log = !lstat(git_path("logs/%s", oldrefname), &loginfo);
const char *symref = NULL;
- struct ref_cache *refs = get_ref_cache(NULL);
if (log && S_ISLNK(loginfo.st_mode))
return error("reflog for %s is a symlink", oldrefname);
@@ -1857,10 +2507,10 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
if (!symref)
return error("refname %s not found", oldrefname);
- if (!is_refname_available(newrefname, oldrefname, get_packed_refs(refs)))
+ if (!is_refname_available(newrefname, oldrefname, get_packed_refs(&ref_cache)))
return 1;
- if (!is_refname_available(newrefname, oldrefname, get_loose_refs(refs)))
+ if (!is_refname_available(newrefname, oldrefname, get_loose_refs(&ref_cache)))
return 1;
if (log && rename(git_path("logs/%s", oldrefname), git_path(TMP_RENAMED_LOG)))
@@ -2116,7 +2766,7 @@ int write_ref_sha1(struct ref_lock *lock,
unlock_ref(lock);
return -1;
}
- clear_loose_ref_cache(get_ref_cache(NULL));
+ clear_loose_ref_cache(&ref_cache);
if (log_ref_write(lock->ref_name, lock->old_sha1, sha1, logmsg) < 0 ||
(strcmp(lock->ref_name, lock->orig_ref_name) &&
log_ref_write(lock->orig_ref_name, lock->old_sha1, sha1, logmsg) < 0)) {
@@ -2332,59 +2982,117 @@ int read_ref_at(const char *refname, unsigned long at_time, int cnt,
return 1;
}
-int for_each_recent_reflog_ent(const char *refname, each_reflog_ent_fn fn, long ofs, void *cb_data)
+static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *cb_data)
+{
+ unsigned char osha1[20], nsha1[20];
+ char *email_end, *message;
+ unsigned long timestamp;
+ int tz;
+
+ /* old SP new SP name <email> SP time TAB msg LF */
+ if (sb->len < 83 || sb->buf[sb->len - 1] != '\n' ||
+ get_sha1_hex(sb->buf, osha1) || sb->buf[40] != ' ' ||
+ get_sha1_hex(sb->buf + 41, nsha1) || sb->buf[81] != ' ' ||
+ !(email_end = strchr(sb->buf + 82, '>')) ||
+ email_end[1] != ' ' ||
+ !(timestamp = strtoul(email_end + 2, &message, 10)) ||
+ !message || message[0] != ' ' ||
+ (message[1] != '+' && message[1] != '-') ||
+ !isdigit(message[2]) || !isdigit(message[3]) ||
+ !isdigit(message[4]) || !isdigit(message[5]))
+ return 0; /* corrupt? */
+ email_end[1] = '\0';
+ tz = strtol(message + 1, NULL, 10);
+ if (message[6] != '\t')
+ message += 6;
+ else
+ message += 7;
+ return fn(osha1, nsha1, sb->buf + 82, timestamp, tz, message, cb_data);
+}
+
+static char *find_beginning_of_line(char *bob, char *scan)
+{
+ while (bob < scan && *(--scan) != '\n')
+ ; /* keep scanning backwards */
+ /*
+ * Return either beginning of the buffer, or LF at the end of
+ * the previous line.
+ */
+ return scan;
+}
+
+int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data)
{
- const char *logfile;
- FILE *logfp;
struct strbuf sb = STRBUF_INIT;
- int ret = 0;
+ FILE *logfp;
+ long pos;
+ int ret = 0, at_tail = 1;
- logfile = git_path("logs/%s", refname);
- logfp = fopen(logfile, "r");
+ logfp = fopen(git_path("logs/%s", refname), "r");
if (!logfp)
return -1;
- if (ofs) {
- struct stat statbuf;
- if (fstat(fileno(logfp), &statbuf) ||
- statbuf.st_size < ofs ||
- fseek(logfp, -ofs, SEEK_END) ||
- strbuf_getwholeline(&sb, logfp, '\n')) {
- fclose(logfp);
- strbuf_release(&sb);
- return -1;
+ /* Jump to the end */
+ if (fseek(logfp, 0, SEEK_END) < 0)
+ return error("cannot seek back reflog for %s: %s",
+ refname, strerror(errno));
+ pos = ftell(logfp);
+ while (!ret && 0 < pos) {
+ int cnt;
+ size_t nread;
+ char buf[BUFSIZ];
+ char *endp, *scanp;
+
+ /* Fill next block from the end */
+ cnt = (sizeof(buf) < pos) ? sizeof(buf) : pos;
+ if (fseek(logfp, pos - cnt, SEEK_SET))
+ return error("cannot seek back reflog for %s: %s",
+ refname, strerror(errno));
+ nread = fread(buf, cnt, 1, logfp);
+ if (nread != 1)
+ return error("cannot read %d bytes from reflog for %s: %s",
+ cnt, refname, strerror(errno));
+ pos -= cnt;
+
+ scanp = endp = buf + cnt;
+ if (at_tail && scanp[-1] == '\n')
+ /* Looking at the final LF at the end of the file */
+ scanp--;
+ at_tail = 0;
+
+ while (buf < scanp) {
+ /*
+ * terminating LF of the previous line, or the beginning
+ * of the buffer.
+ */
+ char *bp;
+
+ bp = find_beginning_of_line(buf, scanp);
+
+ if (*bp != '\n') {
+ strbuf_splice(&sb, 0, 0, buf, endp - buf);
+ if (pos)
+ break; /* need to fill another block */
+ scanp = buf - 1; /* leave loop */
+ } else {
+ /*
+ * (bp + 1) thru endp is the beginning of the
+ * current line we have in sb
+ */
+ strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
+ scanp = bp;
+ endp = bp + 1;
+ }
+ ret = show_one_reflog_ent(&sb, fn, cb_data);
+ strbuf_reset(&sb);
+ if (ret)
+ break;
}
- }
- while (!strbuf_getwholeline(&sb, logfp, '\n')) {
- unsigned char osha1[20], nsha1[20];
- char *email_end, *message;
- unsigned long timestamp;
- int tz;
-
- /* old SP new SP name <email> SP time TAB msg LF */
- if (sb.len < 83 || sb.buf[sb.len - 1] != '\n' ||
- get_sha1_hex(sb.buf, osha1) || sb.buf[40] != ' ' ||
- get_sha1_hex(sb.buf + 41, nsha1) || sb.buf[81] != ' ' ||
- !(email_end = strchr(sb.buf + 82, '>')) ||
- email_end[1] != ' ' ||
- !(timestamp = strtoul(email_end + 2, &message, 10)) ||
- !message || message[0] != ' ' ||
- (message[1] != '+' && message[1] != '-') ||
- !isdigit(message[2]) || !isdigit(message[3]) ||
- !isdigit(message[4]) || !isdigit(message[5]))
- continue; /* corrupt? */
- email_end[1] = '\0';
- tz = strtol(message + 1, NULL, 10);
- if (message[6] != '\t')
- message += 6;
- else
- message += 7;
- ret = fn(osha1, nsha1, sb.buf + 82, timestamp, tz, message,
- cb_data);
- if (ret)
- break;
}
+ if (!ret && sb.len)
+ ret = show_one_reflog_ent(&sb, fn, cb_data);
+
fclose(logfp);
strbuf_release(&sb);
return ret;
@@ -2392,9 +3100,20 @@ int for_each_recent_reflog_ent(const char *refname, each_reflog_ent_fn fn, long
int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data)
{
- return for_each_recent_reflog_ent(refname, fn, 0, cb_data);
-}
+ FILE *logfp;
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+ logfp = fopen(git_path("logs/%s", refname), "r");
+ if (!logfp)
+ return -1;
+
+ while (!ret && !strbuf_getwholeline(&sb, logfp, '\n'))
+ ret = show_one_reflog_ent(&sb, fn, cb_data);
+ fclose(logfp);
+ strbuf_release(&sb);
+ return ret;
+}
/*
* Call fn for each reflog in the namespace indicated by name. name
* must be empty or end with '/'. Name will be used as a scratch
@@ -2477,14 +3196,6 @@ int update_ref(const char *action, const char *refname,
return 0;
}
-struct ref *find_ref_by_name(const struct ref *list, const char *name)
-{
- for ( ; list; list = list->next)
- if (!strcmp(list->name, name))
- return (struct ref *)list;
- return NULL;
-}
-
/*
* generate a format suitable for scanf from a ref_rev_parse_rules
* rule, that is replace the "%.*s" spec with a "%s" spec
diff --git a/refs.h b/refs.h
index 1b2e2d3..9e5db3a 100644
--- a/refs.h
+++ b/refs.h
@@ -10,18 +10,41 @@ struct ref_lock {
int force_write;
};
+/*
+ * Bit values set in the flags argument passed to each_ref_fn():
+ */
+
+/* Reference is a symbolic reference. */
#define REF_ISSYMREF 0x01
+
+/* Reference is a packed reference. */
#define REF_ISPACKED 0x02
+
+/*
+ * Reference cannot be resolved to an object name: dangling symbolic
+ * reference (directly or indirectly), corrupt reference file, or
+ * symbolic reference refers to ill-formatted reference name.
+ */
#define REF_ISBROKEN 0x04
/*
- * Calls the specified function for each ref file until it returns
- * nonzero, and returns the value. Please note that it is not safe to
- * modify references while an iteration is in progress, unless the
- * same callback function invocation that modifies the reference also
- * returns a nonzero value to immediately stop the iteration.
+ * The signature for the callback function for the for_each_*()
+ * functions below. The memory pointed to by the refname and sha1
+ * arguments is only guaranteed to be valid for the duration of a
+ * single callback invocation.
+ */
+typedef int each_ref_fn(const char *refname,
+ const unsigned char *sha1, int flags, void *cb_data);
+
+/*
+ * The following functions invoke the specified callback function for
+ * each reference indicated. If the function ever returns a nonzero
+ * value, stop the iteration and return that value. Please note that
+ * it is not safe to modify references while an iteration is in
+ * progress, unless the same callback function invocation that
+ * modifies the reference also returns a nonzero value to immediately
+ * stop the iteration.
*/
-typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);
extern int head_ref(each_ref_fn, void *);
extern int for_each_ref(each_ref_fn, void *);
extern int for_each_ref_in(const char *, each_ref_fn, void *);
@@ -54,13 +77,57 @@ extern int for_each_rawref(each_ref_fn, void *);
extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
/*
- * Add a reference to the in-memory packed reference cache. To actually
- * write the reference to the packed-refs file, call pack_refs().
+ * Lock the packed-refs file for writing. Flags is passed to
+ * hold_lock_file_for_update(). Return 0 on success.
+ */
+extern int lock_packed_refs(int flags);
+
+/*
+ * Add a reference to the in-memory packed reference cache. This may
+ * only be called while the packed-refs file is locked (see
+ * lock_packed_refs()). To actually write the packed-refs file, call
+ * commit_packed_refs().
*/
extern void add_packed_ref(const char *refname, const unsigned char *sha1);
+/*
+ * Write the current version of the packed refs cache from memory to
+ * disk. The packed-refs file must already be locked for writing (see
+ * lock_packed_refs()). Return zero on success.
+ */
+extern int commit_packed_refs(void);
+
+/*
+ * Rollback the lockfile for the packed-refs file, and discard the
+ * in-memory packed reference cache. (The packed-refs file will be
+ * read anew if it is needed again after this function is called.)
+ */
+extern void rollback_packed_refs(void);
+
+/*
+ * Flags for controlling behaviour of pack_refs()
+ * PACK_REFS_PRUNE: Prune loose refs after packing
+ * PACK_REFS_ALL: Pack _all_ refs, not just tags and already packed refs
+ */
+#define PACK_REFS_PRUNE 0x0001
+#define PACK_REFS_ALL 0x0002
+
+/*
+ * Write a packed-refs file for the current repository.
+ * flags: Combination of the above PACK_REFS_* flags.
+ */
+int pack_refs(unsigned int flags);
+
extern int ref_exists(const char *);
+/*
+ * If refname is a non-symbolic reference that refers to a tag object,
+ * and the tag can be (recursively) dereferenced to a non-tag object,
+ * store the SHA1 of the referred-to object to sha1 and return 0. If
+ * any of these conditions are not met, return a non-zero value.
+ * Symbolic references are considered unpeelable, even if they
+ * ultimately resolve to a peelable tag.
+ */
extern int peel_ref(const char *refname, unsigned char *sha1);
/** Locks a "refs/" ref returning the lock on success and NULL on failure. **/
@@ -103,7 +170,7 @@ extern int read_ref_at(const char *refname, unsigned long at_time, int cnt,
/* iterate over reflog entries */
typedef int each_reflog_ent_fn(unsigned char *osha1, unsigned char *nsha1, const char *, unsigned long, int, const char *, void *);
int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data);
-int for_each_recent_reflog_ent(const char *refname, each_reflog_ent_fn fn, long, void *cb_data);
+int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data);
/*
* Calls the specified function for each reflog file until it returns nonzero,
diff --git a/remote-curl.c b/remote-curl.c
index 933c69a..b5ebe01 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -6,7 +6,9 @@
#include "exec_cmd.h"
#include "run-command.h"
#include "pkt-line.h"
+#include "string-list.h"
#include "sideband.h"
+#include "argv-array.h"
static struct remote *remote;
static const char *url; /* always ends with a trailing slash */
@@ -15,11 +17,13 @@ struct options {
int verbosity;
unsigned long depth;
unsigned progress : 1,
+ check_self_contained_and_connected : 1,
followtags : 1,
dry_run : 1,
thin : 1;
};
static struct options options;
+static struct string_list cas_options = STRING_LIST_INIT_DUP;
static int set_option(const char *name, const char *value)
{
@@ -66,6 +70,22 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
+ else if (!strcmp(name, "check-connectivity")) {
+ if (!strcmp(value, "true"))
+ options.check_self_contained_and_connected = 1;
+ else if (!strcmp(value, "false"))
+ options.check_self_contained_and_connected = 0;
+ else
+ return -1;
+ return 0;
+ }
+ else if (!strcmp(name, "cas")) {
+ struct strbuf val = STRBUF_INIT;
+ strbuf_addf(&val, "--" CAS_OPT_NAME "=%s", value);
+ string_list_append(&cas_options, val.buf);
+ strbuf_release(&val);
+ return 0;
+ }
else {
return 1 /* unsupported */;
}
@@ -76,21 +96,109 @@ struct discovery {
char *buf_alloc;
char *buf;
size_t len;
+ struct ref *refs;
unsigned proto_git : 1;
};
static struct discovery *last_discovery;
+static struct ref *parse_git_refs(struct discovery *heads, int for_push)
+{
+ struct ref *list = NULL;
+ get_remote_heads(-1, heads->buf, heads->len, &list,
+ for_push ? REF_NORMAL : 0, NULL);
+ return list;
+}
+
+static struct ref *parse_info_refs(struct discovery *heads)
+{
+ char *data, *start, *mid;
+ char *ref_name;
+ int i = 0;
+
+ struct ref *refs = NULL;
+ struct ref *ref = NULL;
+ struct ref *last_ref = NULL;
+
+ data = heads->buf;
+ start = NULL;
+ mid = data;
+ while (i < heads->len) {
+ if (!start) {
+ start = &data[i];
+ }
+ if (data[i] == '\t')
+ mid = &data[i];
+ if (data[i] == '\n') {
+ if (mid - start != 40)
+ die("%sinfo/refs not valid: is this a git repository?", url);
+ data[i] = 0;
+ ref_name = mid + 1;
+ ref = xmalloc(sizeof(struct ref) +
+ strlen(ref_name) + 1);
+ memset(ref, 0, sizeof(struct ref));
+ strcpy(ref->name, ref_name);
+ get_sha1_hex(start, ref->old_sha1);
+ if (!refs)
+ refs = ref;
+ if (last_ref)
+ last_ref->next = ref;
+ last_ref = ref;
+ start = NULL;
+ }
+ i++;
+ }
+
+ ref = alloc_ref("HEAD");
+ if (!http_fetch_ref(url, ref) &&
+ !resolve_remote_symref(ref, refs)) {
+ ref->next = refs;
+ refs = ref;
+ } else {
+ free(ref);
+ }
+
+ return refs;
+}
+
static void free_discovery(struct discovery *d)
{
if (d) {
if (d == last_discovery)
last_discovery = NULL;
free(d->buf_alloc);
+ free_refs(d->refs);
free(d);
}
}
-static struct discovery* discover_refs(const char *service)
+static int show_http_message(struct strbuf *type, struct strbuf *msg)
+{
+ const char *p, *eol;
+
+ /*
+ * We only show text/plain parts, as other types are likely
+ * to be ugly to look at on the user's terminal.
+ *
+ * TODO should handle "; charset=XXX", and re-encode into
+ * logoutputencoding
+ */
+ if (strcasecmp(type->buf, "text/plain"))
+ return -1;
+
+ strbuf_trim(msg);
+ if (!msg->len)
+ return -1;
+
+ p = msg->buf;
+ do {
+ eol = strchrnul(p, '\n');
+ fprintf(stderr, "remote: %.*s\n", (int)(eol - p), p);
+ p = eol + 1;
+ } while(*eol);
+ return 0;
+}
+
+static struct discovery* discover_refs(const char *service, int for_push)
{
struct strbuf exp = STRBUF_INIT;
struct strbuf type = STRBUF_INIT;
@@ -115,18 +223,20 @@ static struct discovery* discover_refs(const char *service)
}
refs_url = strbuf_detach(&buffer, NULL);
- http_ret = http_get_strbuf(refs_url, &type, &buffer, HTTP_NO_CACHE);
+ http_ret = http_get_strbuf(refs_url, &type, &buffer,
+ HTTP_NO_CACHE | HTTP_KEEP_ERROR);
switch (http_ret) {
case HTTP_OK:
break;
case HTTP_MISSING_TARGET:
- die("%s not found: did you run git update-server-info on the"
- " server?", refs_url);
+ show_http_message(&type, &buffer);
+ die("repository '%s' not found", url);
case HTTP_NOAUTH:
- die("Authentication failed");
+ show_http_message(&type, &buffer);
+ die("Authentication failed for '%s'", url);
default:
- http_error(refs_url, http_ret);
- die("HTTP request failed");
+ show_http_message(&type, &buffer);
+ die("unable to access '%s': %s", url, curl_errorstr);
}
last= xcalloc(1, sizeof(*last_discovery));
@@ -138,32 +248,35 @@ static struct discovery* discover_refs(const char *service)
if (maybe_smart &&
(5 <= last->len && last->buf[4] == '#') &&
!strbuf_cmp(&exp, &type)) {
+ char *line;
+
/*
* smart HTTP response; validate that the service
* pkt-line matches our request.
*/
- if (packet_get_line(&buffer, &last->buf, &last->len) <= 0)
- die("%s has invalid packet header", refs_url);
- if (buffer.len && buffer.buf[buffer.len - 1] == '\n')
- strbuf_setlen(&buffer, buffer.len - 1);
+ line = packet_read_line_buf(&last->buf, &last->len, NULL);
strbuf_reset(&exp);
strbuf_addf(&exp, "# service=%s", service);
- if (strbuf_cmp(&exp, &buffer))
- die("invalid server response; got '%s'", buffer.buf);
+ if (strcmp(line, exp.buf))
+ die("invalid server response; got '%s'", line);
strbuf_release(&exp);
/* The header can include additional metadata lines, up
* until a packet flush marker. Ignore these now, but
* in the future we might start to scan them.
*/
- strbuf_reset(&buffer);
- while (packet_get_line(&buffer, &last->buf, &last->len) > 0)
- strbuf_reset(&buffer);
+ while (packet_read_line_buf(&last->buf, &last->len, NULL))
+ ;
last->proto_git = 1;
}
+ if (last->proto_git)
+ last->refs = parse_git_refs(last, for_push);
+ else
+ last->refs = parse_info_refs(last);
+
free(refs_url);
strbuf_release(&exp);
strbuf_release(&type);
@@ -172,99 +285,16 @@ static struct discovery* discover_refs(const char *service)
return last;
}
-static int write_discovery(int in, int out, void *data)
-{
- struct discovery *heads = data;
- int err = 0;
- if (write_in_full(out, heads->buf, heads->len) != heads->len)
- err = 1;
- close(out);
- return err;
-}
-
-static struct ref *parse_git_refs(struct discovery *heads, int for_push)
-{
- struct ref *list = NULL;
- struct async async;
-
- memset(&async, 0, sizeof(async));
- async.proc = write_discovery;
- async.data = heads;
- async.out = -1;
-
- if (start_async(&async))
- die("cannot start thread to parse advertised refs");
- get_remote_heads(async.out, &list,
- for_push ? REF_NORMAL : 0, NULL);
- close(async.out);
- if (finish_async(&async))
- die("ref parsing thread failed");
- return list;
-}
-
-static struct ref *parse_info_refs(struct discovery *heads)
-{
- char *data, *start, *mid;
- char *ref_name;
- int i = 0;
-
- struct ref *refs = NULL;
- struct ref *ref = NULL;
- struct ref *last_ref = NULL;
-
- data = heads->buf;
- start = NULL;
- mid = data;
- while (i < heads->len) {
- if (!start) {
- start = &data[i];
- }
- if (data[i] == '\t')
- mid = &data[i];
- if (data[i] == '\n') {
- if (mid - start != 40)
- die("%sinfo/refs not valid: is this a git repository?", url);
- data[i] = 0;
- ref_name = mid + 1;
- ref = xmalloc(sizeof(struct ref) +
- strlen(ref_name) + 1);
- memset(ref, 0, sizeof(struct ref));
- strcpy(ref->name, ref_name);
- get_sha1_hex(start, ref->old_sha1);
- if (!refs)
- refs = ref;
- if (last_ref)
- last_ref->next = ref;
- last_ref = ref;
- start = NULL;
- }
- i++;
- }
-
- ref = alloc_ref("HEAD");
- if (!http_fetch_ref(url, ref) &&
- !resolve_remote_symref(ref, refs)) {
- ref->next = refs;
- refs = ref;
- } else {
- free(ref);
- }
-
- return refs;
-}
-
static struct ref *get_refs(int for_push)
{
struct discovery *heads;
if (for_push)
- heads = discover_refs("git-receive-pack");
+ heads = discover_refs("git-receive-pack", for_push);
else
- heads = discover_refs("git-upload-pack");
+ heads = discover_refs("git-upload-pack", for_push);
- if (heads->proto_git)
- return parse_git_refs(heads, for_push);
- return parse_info_refs(heads);
+ return heads->refs;
}
static void output_refs(struct ref *refs)
@@ -278,7 +308,6 @@ static void output_refs(struct ref *refs)
}
printf("\n");
fflush(stdout);
- free_refs(refs);
}
struct rpc_state {
@@ -308,7 +337,7 @@ static size_t rpc_out(void *ptr, size_t eltsize,
if (!avail) {
rpc->initial_buffer = 0;
- avail = packet_read_line(rpc->out, rpc->buf, rpc->alloc);
+ avail = packet_read(rpc->out, NULL, NULL, rpc->buf, rpc->alloc, 0);
if (!avail)
return 0;
rpc->pos = 0;
@@ -425,7 +454,7 @@ static int post_rpc(struct rpc_state *rpc)
break;
}
- n = packet_read_line(rpc->out, buf, left);
+ n = packet_read(rpc->out, NULL, NULL, buf, left, 0);
if (!n)
break;
rpc->len += n;
@@ -579,7 +608,7 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
rpc->hdr_accept = strbuf_detach(&buf, NULL);
while (!err) {
- int n = packet_read_line(rpc->out, rpc->buf, rpc->alloc);
+ int n = packet_read(rpc->out, NULL, NULL, rpc->buf, rpc->alloc, 0);
if (!n)
break;
rpc->pos = 0;
@@ -644,7 +673,7 @@ static int fetch_git(struct discovery *heads,
struct strbuf preamble = STRBUF_INIT;
char *depth_arg = NULL;
int argc = 0, i, err;
- const char *argv[15];
+ const char *argv[16];
argv[argc++] = "fetch-pack";
argv[argc++] = "--stateless-rpc";
@@ -658,6 +687,8 @@ static int fetch_git(struct discovery *heads,
argv[argc++] = "-v";
argv[argc++] = "-v";
}
+ if (options.check_self_contained_and_connected)
+ argv[argc++] = "--check-self-contained-and-connected";
if (!options.progress)
argv[argc++] = "--no-progress";
if (options.depth) {
@@ -685,7 +716,7 @@ static int fetch_git(struct discovery *heads,
err = rpc_service(&rpc, heads);
if (rpc.result.len)
- safe_write(1, rpc.result.buf, rpc.result.len);
+ write_or_die(1, rpc.result.buf, rpc.result.len);
strbuf_release(&rpc.result);
strbuf_release(&preamble);
free(depth_arg);
@@ -694,7 +725,7 @@ static int fetch_git(struct discovery *heads,
static int fetch(int nr_heads, struct ref **to_fetch)
{
- struct discovery *d = discover_refs("git-upload-pack");
+ struct discovery *d = discover_refs("git-upload-pack", 0);
if (d->proto_git)
return fetch_git(d, nr_heads, to_fetch);
else
@@ -778,42 +809,44 @@ static int push_dav(int nr_spec, char **specs)
static int push_git(struct discovery *heads, int nr_spec, char **specs)
{
struct rpc_state rpc;
- const char **argv;
- int argc = 0, i, err;
+ int i, err;
+ struct argv_array args;
+ struct string_list_item *cas_option;
+
+ argv_array_init(&args);
+ argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
+ NULL);
- argv = xmalloc((10 + nr_spec) * sizeof(char*));
- argv[argc++] = "send-pack";
- argv[argc++] = "--stateless-rpc";
- argv[argc++] = "--helper-status";
if (options.thin)
- argv[argc++] = "--thin";
+ argv_array_push(&args, "--thin");
if (options.dry_run)
- argv[argc++] = "--dry-run";
+ argv_array_push(&args, "--dry-run");
if (options.verbosity == 0)
- argv[argc++] = "--quiet";
+ argv_array_push(&args, "--quiet");
else if (options.verbosity > 1)
- argv[argc++] = "--verbose";
- argv[argc++] = options.progress ? "--progress" : "--no-progress";
- argv[argc++] = url;
+ argv_array_push(&args, "--verbose");
+ argv_array_push(&args, options.progress ? "--progress" : "--no-progress");
+ for_each_string_list_item(cas_option, &cas_options)
+ argv_array_push(&args, cas_option->string);
+ argv_array_push(&args, url);
for (i = 0; i < nr_spec; i++)
- argv[argc++] = specs[i];
- argv[argc++] = NULL;
+ argv_array_push(&args, specs[i]);
memset(&rpc, 0, sizeof(rpc));
rpc.service_name = "git-receive-pack",
- rpc.argv = argv;
+ rpc.argv = args.argv;
err = rpc_service(&rpc, heads);
if (rpc.result.len)
- safe_write(1, rpc.result.buf, rpc.result.len);
+ write_or_die(1, rpc.result.buf, rpc.result.len);
strbuf_release(&rpc.result);
- free(argv);
+ argv_array_clear(&args);
return err;
}
static int push(int nr_spec, char **specs)
{
- struct discovery *heads = discover_refs("git-receive-pack");
+ struct discovery *heads = discover_refs("git-receive-pack", 1);
int ret;
if (heads->proto_git)
@@ -930,6 +963,7 @@ int main(int argc, const char **argv)
printf("fetch\n");
printf("option\n");
printf("push\n");
+ printf("check-connectivity\n");
printf("\n");
fflush(stdout);
} else {
diff --git a/remote-testsvn.c b/remote-testsvn.c
index 5ddf11c..d7cd5d2 100644
--- a/remote-testsvn.c
+++ b/remote-testsvn.c
@@ -286,7 +286,7 @@ static int do_command(struct strbuf *line)
return 0;
}
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
struct strbuf buf = STRBUF_INIT, url_sb = STRBUF_INIT,
private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT,
diff --git a/remote.c b/remote.c
index e53a6eb..2433467 100644
--- a/remote.c
+++ b/remote.c
@@ -15,6 +15,7 @@ static struct refspec s_tag_refspec = {
0,
1,
0,
+ 0,
"refs/tags/*",
"refs/tags/*"
};
@@ -48,6 +49,7 @@ static int branches_nr;
static struct branch *current_branch;
static const char *default_remote_name;
+static const char *pushremote_name;
static int explicit_default_remote_name;
static struct rewrites rewrites;
@@ -146,6 +148,7 @@ static struct remote *make_remote(const char *name, int len)
}
ret = xcalloc(1, sizeof(struct remote));
+ ret->prune = -1; /* unspecified */
ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
remotes[remotes_nr++] = ret;
if (len)
@@ -274,10 +277,9 @@ static void read_remotes_file(struct remote *remote)
static void read_branches_file(struct remote *remote)
{
- const char *slash = strchr(remote->name, '/');
char *frag;
struct strbuf branch = STRBUF_INIT;
- int n = slash ? slash - remote->name : 1000;
+ int n = 1000;
FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r");
char *s, *p;
int len;
@@ -297,21 +299,11 @@ static void read_branches_file(struct remote *remote)
while (isspace(p[-1]))
*--p = 0;
len = p - s;
- if (slash)
- len += strlen(slash);
p = xmalloc(len + 1);
strcpy(p, s);
- if (slash)
- strcat(p, slash);
/*
- * With "slash", e.g. "git fetch jgarzik/netdev-2.6" when
- * reading from $GIT_DIR/branches/jgarzik fetches "HEAD" from
- * the partial URL obtained from the branches file plus
- * "/netdev-2.6" and does not store it in any tracking ref.
- * #branch specifier in the file is ignored.
- *
- * Otherwise, the branches file would have URL and optionally
+ * The branches file would have URL and optionally
* #branch specified. The "master" (or specified) branch is
* fetched and stored in the local branch of the same name.
*/
@@ -321,12 +313,8 @@ static void read_branches_file(struct remote *remote)
strbuf_addf(&branch, "refs/heads/%s", frag);
} else
strbuf_addstr(&branch, "refs/heads/master");
- if (!slash) {
- strbuf_addf(&branch, ":refs/heads/%s", remote->name);
- } else {
- strbuf_reset(&branch);
- strbuf_addstr(&branch, "HEAD:");
- }
+
+ strbuf_addf(&branch, ":refs/heads/%s", remote->name);
add_url_alias(remote, p);
add_fetch_refspec(remote, strbuf_detach(&branch, NULL));
/*
@@ -356,13 +344,16 @@ static int handle_config(const char *key, const char *value, void *cb)
return 0;
branch = make_branch(name, subkey - name);
if (!strcmp(subkey, ".remote")) {
- if (!value)
- return config_error_nonbool(key);
- branch->remote_name = xstrdup(value);
+ if (git_config_string(&branch->remote_name, key, value))
+ return -1;
if (branch == current_branch) {
default_remote_name = branch->remote_name;
explicit_default_remote_name = 1;
}
+ } else if (!strcmp(subkey, ".pushremote")) {
+ if (branch == current_branch)
+ if (git_config_string(&pushremote_name, key, value))
+ return -1;
} else if (!strcmp(subkey, ".merge")) {
if (!value)
return config_error_nonbool(key);
@@ -388,9 +379,16 @@ static int handle_config(const char *key, const char *value, void *cb)
add_instead_of(rewrite, xstrdup(value));
}
}
+
if (prefixcmp(key, "remote."))
return 0;
name = key + 7;
+
+ /* Handle remote.* variables */
+ if (!strcmp(name, "pushdefault"))
+ return git_config_string(&pushremote_name, key, value);
+
+ /* Handle remote.<name>.* variables */
if (*name == '/') {
warning("Config remote shorthand cannot begin with '/': %s",
name);
@@ -407,6 +405,8 @@ static int handle_config(const char *key, const char *value, void *cb)
remote->skip_default_update = git_config_bool(key, value);
else if (!strcmp(subkey, ".skipfetchall"))
remote->skip_default_update = git_config_bool(key, value);
+ else if (!strcmp(subkey, ".prune"))
+ remote->prune = git_config_bool(key, value);
else if (!strcmp(subkey, ".url")) {
const char *v;
if (git_config_string(&v, key, value))
@@ -538,7 +538,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
/*
* Before going on, special case ":" (or "+:") as a refspec
- * for matching refs.
+ * for pushing matching refs.
*/
if (!fetch && rhs == lhs && rhs[1] == '\0') {
rs[i].matching = 1;
@@ -565,26 +565,25 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
if (fetch) {
- /*
- * LHS
- * - empty is allowed; it means HEAD.
- * - otherwise it must be a valid looking ref.
- */
+ unsigned char unused[40];
+
+ /* LHS */
if (!*rs[i].src)
- ; /* empty is ok */
- else if (check_refname_format(rs[i].src, flags))
+ ; /* empty is ok; it means "HEAD" */
+ else if (llen == 40 && !get_sha1_hex(rs[i].src, unused))
+ rs[i].exact_sha1 = 1; /* ok */
+ else if (!check_refname_format(rs[i].src, flags))
+ ; /* valid looking ref is ok */
+ else
goto invalid;
- /*
- * RHS
- * - missing is ok, and is same as empty.
- * - empty is ok; it means not to store.
- * - otherwise it must be a valid looking ref.
- */
+ /* RHS */
if (!rs[i].dst)
- ; /* ok */
+ ; /* missing is ok; it is the same as empty */
else if (!*rs[i].dst)
- ; /* ok */
- else if (check_refname_format(rs[i].dst, flags))
+ ; /* empty is ok; it means "do not store" */
+ else if (!check_refname_format(rs[i].dst, flags))
+ ; /* valid looking ref is ok */
+ else
goto invalid;
} else {
/*
@@ -671,17 +670,21 @@ static int valid_remote_nick(const char *name)
return !strchr(name, '/'); /* no slash */
}
-struct remote *remote_get(const char *name)
+static struct remote *remote_get_1(const char *name, const char *pushremote_name)
{
struct remote *ret;
int name_given = 0;
- read_config();
if (name)
name_given = 1;
else {
- name = default_remote_name;
- name_given = explicit_default_remote_name;
+ if (pushremote_name) {
+ name = pushremote_name;
+ name_given = 1;
+ } else {
+ name = default_remote_name;
+ name_given = explicit_default_remote_name;
+ }
}
ret = make_remote(name, 0);
@@ -700,6 +703,18 @@ struct remote *remote_get(const char *name)
return ret;
}
+struct remote *remote_get(const char *name)
+{
+ read_config();
+ return remote_get_1(name, NULL);
+}
+
+struct remote *pushremote_get(const char *name)
+{
+ read_config();
+ return remote_get_1(name, pushremote_name);
+}
+
int remote_is_configured(const char *name)
{
int i;
@@ -1195,6 +1210,117 @@ static struct ref **tail_ref(struct ref **head)
return tail;
}
+struct tips {
+ struct commit **tip;
+ int nr, alloc;
+};
+
+static void add_to_tips(struct tips *tips, const unsigned char *sha1)
+{
+ struct commit *commit;
+
+ if (is_null_sha1(sha1))
+ return;
+ commit = lookup_commit_reference_gently(sha1, 1);
+ if (!commit || (commit->object.flags & TMP_MARK))
+ return;
+ commit->object.flags |= TMP_MARK;
+ ALLOC_GROW(tips->tip, tips->nr + 1, tips->alloc);
+ tips->tip[tips->nr++] = commit;
+}
+
+static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***dst_tail)
+{
+ struct string_list dst_tag = STRING_LIST_INIT_NODUP;
+ struct string_list src_tag = STRING_LIST_INIT_NODUP;
+ struct string_list_item *item;
+ struct ref *ref;
+ struct tips sent_tips;
+
+ /*
+ * Collect everything we know they would have at the end of
+ * this push, and collect all tags they have.
+ */
+ memset(&sent_tips, 0, sizeof(sent_tips));
+ for (ref = *dst; ref; ref = ref->next) {
+ if (ref->peer_ref &&
+ !is_null_sha1(ref->peer_ref->new_sha1))
+ add_to_tips(&sent_tips, ref->peer_ref->new_sha1);
+ else
+ add_to_tips(&sent_tips, ref->old_sha1);
+ if (!prefixcmp(ref->name, "refs/tags/"))
+ string_list_append(&dst_tag, ref->name);
+ }
+ clear_commit_marks_many(sent_tips.nr, sent_tips.tip, TMP_MARK);
+
+ sort_string_list(&dst_tag);
+
+ /* Collect tags they do not have. */
+ for (ref = src; ref; ref = ref->next) {
+ if (prefixcmp(ref->name, "refs/tags/"))
+ continue; /* not a tag */
+ if (string_list_has_string(&dst_tag, ref->name))
+ continue; /* they already have it */
+ if (sha1_object_info(ref->new_sha1, NULL) != OBJ_TAG)
+ continue; /* be conservative */
+ item = string_list_append(&src_tag, ref->name);
+ item->util = ref;
+ }
+ string_list_clear(&dst_tag, 0);
+
+ /*
+ * At this point, src_tag lists tags that are missing from
+ * dst, and sent_tips lists the tips we are pushing or those
+ * that we know they already have. An element in the src_tag
+ * that is an ancestor of any of the sent_tips needs to be
+ * sent to the other side.
+ */
+ if (sent_tips.nr) {
+ for_each_string_list_item(item, &src_tag) {
+ struct ref *ref = item->util;
+ struct ref *dst_ref;
+ struct commit *commit;
+
+ if (is_null_sha1(ref->new_sha1))
+ continue;
+ commit = lookup_commit_reference_gently(ref->new_sha1, 1);
+ if (!commit)
+ /* not pushing a commit, which is not an error */
+ continue;
+
+ /*
+ * Is this tag, which they do not have, reachable from
+ * any of the commits we are sending?
+ */
+ if (!in_merge_bases_many(commit, sent_tips.nr, sent_tips.tip))
+ continue;
+
+ /* Add it in */
+ dst_ref = make_linked_ref(ref->name, dst_tail);
+ hashcpy(dst_ref->new_sha1, ref->new_sha1);
+ dst_ref->peer_ref = copy_ref(ref);
+ }
+ }
+ string_list_clear(&src_tag, 0);
+ free(sent_tips.tip);
+}
+
+struct ref *find_ref_by_name(const struct ref *list, const char *name)
+{
+ for ( ; list; list = list->next)
+ if (!strcmp(list->name, name))
+ return (struct ref *)list;
+ return NULL;
+}
+
+static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
+{
+ for ( ; ref; ref = ref->next)
+ string_list_append_nodup(ref_index, ref->name)->util = ref;
+
+ sort_string_list(ref_index);
+}
+
/*
* Given the set of refs the local repository has, the set of refs the
* remote repository has, and the refspec used for push, determine
@@ -1213,6 +1339,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
int errs;
static const char *default_refspec[] = { ":", NULL };
struct ref *ref, **dst_tail = tail_ref(dst);
+ struct string_list dst_ref_index = STRING_LIST_INIT_NODUP;
if (!nr_refspec) {
nr_refspec = 1;
@@ -1223,18 +1350,20 @@ int match_push_refs(struct ref *src, struct ref **dst,
/* pick the remainder */
for (ref = src; ref; ref = ref->next) {
+ struct string_list_item *dst_item;
struct ref *dst_peer;
const struct refspec *pat = NULL;
char *dst_name;
- if (ref->peer_ref)
- continue;
-
dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat);
if (!dst_name)
continue;
- dst_peer = find_ref_by_name(*dst, dst_name);
+ if (!dst_ref_index.nr)
+ prepare_ref_index(&dst_ref_index, *dst);
+
+ dst_item = string_list_lookup(&dst_ref_index, dst_name);
+ dst_peer = dst_item ? dst_item->util : NULL;
if (dst_peer) {
if (dst_peer->peer_ref)
/* We're already sending something to this ref. */
@@ -1251,13 +1380,22 @@ int match_push_refs(struct ref *src, struct ref **dst,
/* Create a new one and link it */
dst_peer = make_linked_ref(dst_name, &dst_tail);
hashcpy(dst_peer->new_sha1, ref->new_sha1);
+ string_list_insert(&dst_ref_index,
+ dst_peer->name)->util = dst_peer;
}
dst_peer->peer_ref = copy_ref(ref);
dst_peer->force = pat->force;
free_name:
free(dst_name);
}
+
+ string_list_clear(&dst_ref_index, 0);
+
+ if (flags & MATCH_REFS_FOLLOW_TAGS)
+ add_missing_tags(src, dst, &dst_tail);
+
if (send_prune) {
+ struct string_list src_ref_index = STRING_LIST_INIT_NODUP;
/* check for missing refs on the remote */
for (ref = *dst; ref; ref = ref->next) {
char *src_name;
@@ -1268,11 +1406,15 @@ int match_push_refs(struct ref *src, struct ref **dst,
src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL);
if (src_name) {
- if (!find_ref_by_name(src, src_name))
+ if (!src_ref_index.nr)
+ prepare_ref_index(&src_ref_index, src);
+ if (!string_list_has_string(&src_ref_index,
+ src_name))
ref->peer_ref = alloc_delete_ref();
free(src_name);
}
}
+ string_list_clear(&src_ref_index, 0);
}
if (errs)
return -1;
@@ -1280,12 +1422,13 @@ int match_push_refs(struct ref *src, struct ref **dst,
}
void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
- int force_update)
+ int force_update)
{
struct ref *ref;
for (ref = remote_refs; ref; ref = ref->next) {
int force_ref_update = ref->force || force_update;
+ int reject_reason = 0;
if (ref->peer_ref)
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
@@ -1300,6 +1443,26 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
}
/*
+ * Bypass the usual "must fast-forward" check but
+ * replace it with a weaker "the old value must be
+ * this value we observed". If the remote ref has
+ * moved and is now different from what we expect,
+ * reject any push.
+ *
+ * It also is an error if the user told us to check
+ * with the remote-tracking branch to find the value
+ * to expect, but we did not have such a tracking
+ * branch.
+ */
+ if (ref->expect_old_sha1) {
+ if (ref->expect_old_no_trackback ||
+ hashcmp(ref->old_sha1, ref->old_sha1_expect))
+ reject_reason = REF_STATUS_REJECT_STALE;
+ }
+
+ /*
+ * The usual "must fast-forward" rules.
+ *
* Decide whether an individual refspec A:B can be
* pushed. The push will succeed if any of the
* following are true:
@@ -1317,24 +1480,26 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
* passing the --force argument
*/
- if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
- int why = 0; /* why would this push require --force? */
-
+ else if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
if (!prefixcmp(ref->name, "refs/tags/"))
- why = REF_STATUS_REJECT_ALREADY_EXISTS;
+ reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
else if (!has_sha1_file(ref->old_sha1))
- why = REF_STATUS_REJECT_FETCH_FIRST;
+ reject_reason = REF_STATUS_REJECT_FETCH_FIRST;
else if (!lookup_commit_reference_gently(ref->old_sha1, 1) ||
!lookup_commit_reference_gently(ref->new_sha1, 1))
- why = REF_STATUS_REJECT_NEEDS_FORCE;
+ reject_reason = REF_STATUS_REJECT_NEEDS_FORCE;
else if (!ref_newer(ref->new_sha1, ref->old_sha1))
- why = REF_STATUS_REJECT_NONFASTFORWARD;
-
- if (!force_ref_update)
- ref->status = why;
- else if (why)
- ref->forced_update = 1;
+ reject_reason = REF_STATUS_REJECT_NONFASTFORWARD;
}
+
+ /*
+ * "--force" will defeat any rejection implemented
+ * by the rules above.
+ */
+ if (!force_ref_update)
+ ref->status = reject_reason;
+ else if (reject_reason)
+ ref->forced_update = 1;
}
}
@@ -1351,8 +1516,7 @@ struct branch *branch_get(const char *name)
ret->remote = remote_get(ret->remote_name);
if (ret->merge_nr) {
int i;
- ret->merge = xcalloc(sizeof(*ret->merge),
- ret->merge_nr);
+ ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge));
for (i = 0; i < ret->merge_nr; i++) {
ret->merge[i] = xcalloc(1, sizeof(**ret->merge));
ret->merge[i]->src = xstrdup(ret->merge_name[i]);
@@ -1466,7 +1630,12 @@ int get_fetch_map(const struct ref *remote_refs,
} else {
const char *name = refspec->src[0] ? refspec->src : "HEAD";
- ref_map = get_remote_ref(remote_refs, name);
+ if (refspec->exact_sha1) {
+ ref_map = alloc_ref(name);
+ get_sha1_hex(name, ref_map->old_sha1);
+ } else {
+ ref_map = get_remote_ref(remote_refs, name);
+ }
if (!missing_ok && !ref_map)
die("Couldn't find remote ref %s", name);
if (ref_map) {
@@ -1801,3 +1970,121 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet
string_list_clear(&ref_names, 0);
return stale_refs;
}
+
+/*
+ * Compare-and-swap
+ */
+void clear_cas_option(struct push_cas_option *cas)
+{
+ int i;
+
+ for (i = 0; i < cas->nr; i++)
+ free(cas->entry[i].refname);
+ free(cas->entry);
+ memset(cas, 0, sizeof(*cas));
+}
+
+static struct push_cas *add_cas_entry(struct push_cas_option *cas,
+ const char *refname,
+ size_t refnamelen)
+{
+ struct push_cas *entry;
+ ALLOC_GROW(cas->entry, cas->nr + 1, cas->alloc);
+ entry = &cas->entry[cas->nr++];
+ memset(entry, 0, sizeof(*entry));
+ entry->refname = xmemdupz(refname, refnamelen);
+ return entry;
+}
+
+int parse_push_cas_option(struct push_cas_option *cas, const char *arg, int unset)
+{
+ const char *colon;
+ struct push_cas *entry;
+
+ if (unset) {
+ /* "--no-<option>" */
+ clear_cas_option(cas);
+ return 0;
+ }
+
+ if (!arg) {
+ /* just "--<option>" */
+ cas->use_tracking_for_rest = 1;
+ return 0;
+ }
+
+ /* "--<option>=refname" or "--<option>=refname:value" */
+ colon = strchrnul(arg, ':');
+ entry = add_cas_entry(cas, arg, colon - arg);
+ if (!*colon)
+ entry->use_tracking = 1;
+ else if (get_sha1(colon + 1, entry->expect))
+ return error("cannot parse expected object name '%s'", colon + 1);
+ return 0;
+}
+
+int parseopt_push_cas_option(const struct option *opt, const char *arg, int unset)
+{
+ return parse_push_cas_option(opt->value, arg, unset);
+}
+
+int is_empty_cas(const struct push_cas_option *cas)
+{
+ return !cas->use_tracking_for_rest && !cas->nr;
+}
+
+/*
+ * Look at remote.fetch refspec and see if we have a remote
+ * tracking branch for the refname there. Fill its current
+ * value in sha1[].
+ * If we cannot do so, return negative to signal an error.
+ */
+static int remote_tracking(struct remote *remote, const char *refname,
+ unsigned char sha1[20])
+{
+ char *dst;
+
+ dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname);
+ if (!dst)
+ return -1; /* no tracking ref for refname at remote */
+ if (read_ref(dst, sha1))
+ return -1; /* we know what the tracking ref is but we cannot read it */
+ return 0;
+}
+
+static void apply_cas(struct push_cas_option *cas,
+ struct remote *remote,
+ struct ref *ref)
+{
+ int i;
+
+ /* Find an explicit --<option>=<name>[:<value>] entry */
+ for (i = 0; i < cas->nr; i++) {
+ struct push_cas *entry = &cas->entry[i];
+ if (!refname_match(entry->refname, ref->name, ref_rev_parse_rules))
+ continue;
+ ref->expect_old_sha1 = 1;
+ if (!entry->use_tracking)
+ hashcpy(ref->old_sha1_expect, cas->entry[i].expect);
+ else if (remote_tracking(remote, ref->name, ref->old_sha1_expect))
+ ref->expect_old_no_trackback = 1;
+ return;
+ }
+
+ /* Are we using "--<option>" to cover all? */
+ if (!cas->use_tracking_for_rest)
+ return;
+
+ ref->expect_old_sha1 = 1;
+ if (remote_tracking(remote, ref->name, ref->old_sha1_expect))
+ ref->expect_old_no_trackback = 1;
+}
+
+void apply_push_cas(struct push_cas_option *cas,
+ struct remote *remote,
+ struct ref *remote_refs)
+{
+ struct ref *ref;
+ for (ref = remote_refs; ref; ref = ref->next)
+ apply_cas(cas, remote, ref);
+}
diff --git a/remote.h b/remote.h
index 251d8fd..131130a 100644
--- a/remote.h
+++ b/remote.h
@@ -1,6 +1,8 @@
#ifndef REMOTE_H
#define REMOTE_H
+#include "parse-options.h"
+
enum {
REMOTE_CONFIG,
REMOTE_REMOTES,
@@ -40,6 +42,7 @@ struct remote {
int fetch_tags;
int skip_default_update;
int mirror;
+ int prune;
const char *receivepack;
const char *uploadpack;
@@ -51,6 +54,7 @@ struct remote {
};
struct remote *remote_get(const char *name);
+struct remote *pushremote_get(const char *name);
int remote_is_configured(const char *name);
typedef int each_remote_fn(struct remote *remote, void *priv);
@@ -62,6 +66,7 @@ struct refspec {
unsigned force : 1;
unsigned pattern : 1;
unsigned matching : 1;
+ unsigned exact_sha1 : 1;
char *src;
char *dst;
@@ -69,6 +74,56 @@ struct refspec {
extern const struct refspec *tag_refspec;
+struct ref {
+ struct ref *next;
+ unsigned char old_sha1[20];
+ unsigned char new_sha1[20];
+ unsigned char old_sha1_expect[20]; /* used by expect-old */
+ char *symref;
+ unsigned int
+ force:1,
+ forced_update:1,
+ expect_old_sha1:1,
+ expect_old_no_trackback:1,
+ deletion:1,
+ matched:1;
+
+ /*
+ * Order is important here, as we write to FETCH_HEAD
+ * in numeric order. And the default NOT_FOR_MERGE
+ * should be 0, so that xcalloc'd structures get it
+ * by default.
+ */
+ enum {
+ FETCH_HEAD_MERGE = -1,
+ FETCH_HEAD_NOT_FOR_MERGE = 0,
+ FETCH_HEAD_IGNORE = 1
+ } fetch_head_status;
+
+ enum {
+ REF_STATUS_NONE = 0,
+ REF_STATUS_OK,
+ REF_STATUS_REJECT_NONFASTFORWARD,
+ REF_STATUS_REJECT_ALREADY_EXISTS,
+ REF_STATUS_REJECT_NODELETE,
+ REF_STATUS_REJECT_FETCH_FIRST,
+ REF_STATUS_REJECT_NEEDS_FORCE,
+ REF_STATUS_REJECT_STALE,
+ REF_STATUS_UPTODATE,
+ REF_STATUS_REMOTE_REJECT,
+ REF_STATUS_EXPECTING_REPORT
+ } status;
+ char *remote_status;
+ struct ref *peer_ref; /* when renaming */
+ char name[FLEX_ARRAY]; /* more */
+};
+
+#define REF_NORMAL (1u << 0)
+#define REF_HEADS (1u << 1)
+#define REF_TAGS (1u << 2)
+
+extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
+
struct ref *alloc_ref(const char *name);
struct ref *copy_ref(const struct ref *ref);
struct ref *copy_ref_list(const struct ref *ref);
@@ -82,6 +137,14 @@ int check_ref_type(const struct ref *ref, int flags);
*/
void free_refs(struct ref *ref);
+struct extra_have_objects {
+ int nr, alloc;
+ unsigned char (*array)[20];
+};
+extern struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
+ struct ref **list, unsigned int flags,
+ struct extra_have_objects *);
+
int resolve_remote_symref(struct ref *ref, struct ref *list);
int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1);
@@ -148,7 +211,8 @@ enum match_refs_flags {
MATCH_REFS_NONE = 0,
MATCH_REFS_ALL = (1 << 0),
MATCH_REFS_MIRROR = (1 << 1),
- MATCH_REFS_PRUNE = (1 << 2)
+ MATCH_REFS_PRUNE = (1 << 2),
+ MATCH_REFS_FOLLOW_TAGS = (1 << 3)
};
/* Reporting of tracking info */
@@ -169,4 +233,27 @@ struct ref *guess_remote_head(const struct ref *head,
/* Return refs which no longer exist on remote */
struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map);
+/*
+ * Compare-and-swap
+ */
+#define CAS_OPT_NAME "force-with-lease"
+
+struct push_cas_option {
+ unsigned use_tracking_for_rest:1;
+ struct push_cas {
+ unsigned char expect[20];
+ unsigned use_tracking:1;
+ char *refname;
+ } *entry;
+ int nr;
+ int alloc;
+};
+
+extern int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
+extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset);
+extern void clear_cas_option(struct push_cas_option *);
+
+extern int is_empty_cas(const struct push_cas_option *);
+void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
+
#endif
diff --git a/rerere.c b/rerere.c
index 98e3e29..1f2d21a 100644
--- a/rerere.c
+++ b/rerere.c
@@ -6,6 +6,7 @@
#include "resolve-undo.h"
#include "ll-merge.h"
#include "attr.h"
+#include "pathspec.h"
#define RESOLVED 0
#define PUNTED 1
@@ -299,7 +300,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
{
mmfile_t mmfile[3] = {{NULL}};
mmbuffer_t result = {NULL, 0};
- struct cache_entry *ce;
+ const struct cache_entry *ce;
int pos, len, i, hunk_no;
struct rerere_io_mem io;
int marker_size = ll_merge_marker_size(path);
@@ -359,7 +360,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
static int check_one_conflict(int i, int *type)
{
- struct cache_entry *e = active_cache[i];
+ const struct cache_entry *e = active_cache[i];
if (!ce_stage(e)) {
*type = RESOLVED;
@@ -374,8 +375,8 @@ static int check_one_conflict(int i, int *type)
/* Only handle regular files with both stages #2 and #3 */
if (i + 1 < active_nr) {
- struct cache_entry *e2 = active_cache[i];
- struct cache_entry *e3 = active_cache[i + 1];
+ const struct cache_entry *e2 = active_cache[i];
+ const struct cache_entry *e3 = active_cache[i + 1];
if (ce_stage(e2) == 2 &&
ce_stage(e3) == 3 &&
ce_same_name(e, e3) &&
@@ -398,7 +399,7 @@ static int find_conflict(struct string_list *conflict)
for (i = 0; i < active_nr;) {
int conflict_type;
- struct cache_entry *e = active_cache[i];
+ const struct cache_entry *e = active_cache[i];
i = check_one_conflict(i, &conflict_type);
if (conflict_type == THREE_STAGED)
string_list_insert(conflict, (const char *)e->name);
@@ -414,7 +415,7 @@ int rerere_remaining(struct string_list *merge_rr)
for (i = 0; i < active_nr;) {
int conflict_type;
- struct cache_entry *e = active_cache[i];
+ const struct cache_entry *e = active_cache[i];
i = check_one_conflict(i, &conflict_type);
if (conflict_type == PUNTED)
string_list_insert(merge_rr, (const char *)e->name);
@@ -656,7 +657,7 @@ static int rerere_forget_one_path(const char *path, struct string_list *rr)
return 0;
}
-int rerere_forget(const char **pathspec)
+int rerere_forget(struct pathspec *pathspec)
{
int i, fd;
struct string_list conflict = STRING_LIST_INIT_DUP;
@@ -671,8 +672,8 @@ int rerere_forget(const char **pathspec)
find_conflict(&conflict);
for (i = 0; i < conflict.nr; i++) {
struct string_list_item *it = &conflict.items[i];
- if (!match_pathspec(pathspec, it->string, strlen(it->string),
- 0, NULL))
+ if (!match_pathspec_depth(pathspec, it->string, strlen(it->string),
+ 0, NULL))
continue;
rerere_forget_one_path(it->string, &merge_rr);
}
diff --git a/rerere.h b/rerere.h
index 156d2aa..4aa06c9 100644
--- a/rerere.h
+++ b/rerere.h
@@ -3,6 +3,8 @@
#include "string-list.h"
+struct pathspec;
+
#define RERERE_AUTOUPDATE 01
#define RERERE_NOAUTOUPDATE 02
@@ -16,7 +18,7 @@ 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 rerere_forget(const char **);
+extern int rerere_forget(struct pathspec *);
extern int rerere_remaining(struct string_list *);
extern void rerere_clear(struct string_list *);
extern void rerere_gc(struct string_list *);
diff --git a/resolve-undo.c b/resolve-undo.c
index 72b4612..c09b006 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -115,10 +115,10 @@ void resolve_undo_clear_index(struct index_state *istate)
int unmerge_index_entry_at(struct index_state *istate, int pos)
{
- struct cache_entry *ce;
+ const struct cache_entry *ce;
struct string_list_item *item;
struct resolve_undo_info *ru;
- int i, err = 0;
+ int i, err = 0, matched;
if (!istate->resolve_undo)
return pos;
@@ -137,6 +137,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
ru = item->util;
if (!ru)
return pos;
+ matched = ce->ce_flags & CE_MATCHED;
remove_index_entry_at(istate, pos);
for (i = 0; i < 3; i++) {
struct cache_entry *nce;
@@ -144,6 +145,8 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
continue;
nce = make_cache_entry(ru->mode[i], ru->sha1[i],
ce->name, i + 1, 0);
+ if (matched)
+ nce->ce_flags |= CE_MATCHED;
if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
err = 1;
error("cannot unmerge '%s'", ce->name);
@@ -156,7 +159,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
return unmerge_index_entry_at(istate, pos);
}
-void unmerge_index(struct index_state *istate, const char **pathspec)
+void unmerge_marked_index(struct index_state *istate)
{
int i;
@@ -164,8 +167,22 @@ void unmerge_index(struct index_state *istate, const char **pathspec)
return;
for (i = 0; i < istate->cache_nr; i++) {
- struct cache_entry *ce = istate->cache[i];
- if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL))
+ const struct cache_entry *ce = istate->cache[i];
+ if (ce->ce_flags & CE_MATCHED)
+ i = unmerge_index_entry_at(istate, i);
+ }
+}
+
+void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
+{
+ int i;
+
+ if (!istate->resolve_undo)
+ return;
+
+ for (i = 0; i < istate->cache_nr; i++) {
+ const struct cache_entry *ce = istate->cache[i];
+ if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
continue;
i = unmerge_index_entry_at(istate, i);
}
diff --git a/resolve-undo.h b/resolve-undo.h
index 8458769..4630645 100644
--- a/resolve-undo.h
+++ b/resolve-undo.h
@@ -11,6 +11,7 @@ extern void resolve_undo_write(struct strbuf *, struct string_list *);
extern struct string_list *resolve_undo_read(const char *, unsigned long);
extern void resolve_undo_clear_index(struct index_state *);
extern int unmerge_index_entry_at(struct index_state *, int);
-extern void unmerge_index(struct index_state *, const char **);
+extern void unmerge_index(struct index_state *, const struct pathspec *);
+extern void unmerge_marked_index(struct index_state *);
#endif
diff --git a/revision.c b/revision.c
index 9df13ca..6230a80 100644
--- a/revision.c
+++ b/revision.c
@@ -13,7 +13,9 @@
#include "decorate.h"
#include "log-tree.h"
#include "string-list.h"
+#include "line-log.h"
#include "mailmap.h"
+#include "commit-slab.h"
volatile show_early_output_fn_t show_early_output;
@@ -70,7 +72,8 @@ static int show_path_truncated(FILE *out, const struct name_path *path)
return ours || emitted;
}
-void show_object_with_name(FILE *out, struct object *obj, const struct name_path *path, const char *component)
+void show_object_with_name(FILE *out, struct object *obj,
+ const struct name_path *path, const char *component)
{
struct name_path leaf;
leaf.up = (struct name_path *)path;
@@ -87,7 +90,9 @@ void add_object(struct object *obj,
struct name_path *path,
const char *name)
{
- add_object_array(obj, path_name(path, name), p);
+ char *pn = path_name(path, name);
+ add_object_array(obj, pn, p);
+ free(pn);
}
static void mark_blob_uninteresting(struct blob *blob)
@@ -186,7 +191,9 @@ void mark_parents_uninteresting(struct commit *commit)
}
}
-static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
+static void add_pending_object_with_mode(struct rev_info *revs,
+ struct object *obj,
+ const char *name, unsigned mode)
{
if (!obj)
return;
@@ -209,7 +216,8 @@ static void add_pending_object_with_mode(struct rev_info *revs, struct object *o
add_object_array_with_mode(obj, name, &revs->pending, mode);
}
-void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
+void add_pending_object(struct rev_info *revs,
+ struct object *obj, const char *name)
{
add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
}
@@ -226,7 +234,9 @@ void add_head_to_pending(struct rev_info *revs)
add_pending_object(revs, obj, "HEAD");
}
-static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
+static struct object *get_reference(struct rev_info *revs, const char *name,
+ const unsigned char *sha1,
+ unsigned int flags)
{
struct object *object;
@@ -247,7 +257,8 @@ void add_pending_sha1(struct rev_info *revs, const char *name,
add_pending_object(revs, object, name);
}
-static struct commit *handle_commit(struct rev_info *revs, struct object *object, const char *name)
+static struct commit *handle_commit(struct rev_info *revs,
+ struct object *object, const char *name)
{
unsigned long flags = object->flags;
@@ -333,6 +344,80 @@ static int everybody_uninteresting(struct commit_list *orig)
}
/*
+ * A definition of "relevant" commit that we can use to simplify limited graphs
+ * by eliminating side branches.
+ *
+ * A "relevant" commit is one that is !UNINTERESTING (ie we are including it
+ * in our list), or that is a specified BOTTOM commit. Then after computing
+ * a limited list, during processing we can generally ignore boundary merges
+ * coming from outside the graph, (ie from irrelevant parents), and treat
+ * those merges as if they were single-parent. TREESAME is defined to consider
+ * only relevant parents, if any. If we are TREESAME to our on-graph parents,
+ * we don't care if we were !TREESAME to non-graph parents.
+ *
+ * Treating bottom commits as relevant ensures that a limited graph's
+ * connection to the actual bottom commit is not viewed as a side branch, but
+ * treated as part of the graph. For example:
+ *
+ * ....Z...A---X---o---o---B
+ * . /
+ * W---Y
+ *
+ * When computing "A..B", the A-X connection is at least as important as
+ * Y-X, despite A being flagged UNINTERESTING.
+ *
+ * And when computing --ancestry-path "A..B", the A-X connection is more
+ * important than Y-X, despite both A and Y being flagged UNINTERESTING.
+ */
+static inline int relevant_commit(struct commit *commit)
+{
+ return (commit->object.flags & (UNINTERESTING | BOTTOM)) != UNINTERESTING;
+}
+
+/*
+ * Return a single relevant commit from a parent list. If we are a TREESAME
+ * commit, and this selects one of our parents, then we can safely simplify to
+ * that parent.
+ */
+static struct commit *one_relevant_parent(const struct rev_info *revs,
+ struct commit_list *orig)
+{
+ struct commit_list *list = orig;
+ struct commit *relevant = NULL;
+
+ if (!orig)
+ return NULL;
+
+ /*
+ * For 1-parent commits, or if first-parent-only, then return that
+ * first parent (even if not "relevant" by the above definition).
+ * TREESAME will have been set purely on that parent.
+ */
+ if (revs->first_parent_only || !orig->next)
+ return orig->item;
+
+ /*
+ * For multi-parent commits, identify a sole relevant parent, if any.
+ * If we have only one relevant parent, then TREESAME will be set purely
+ * with regard to that parent, and we can simplify accordingly.
+ *
+ * If we have more than one relevant parent, or no relevant parents
+ * (and multiple irrelevant ones), then we can't select a parent here
+ * and return NULL.
+ */
+ while (list) {
+ struct commit *commit = list->item;
+ list = list->next;
+ if (relevant_commit(commit)) {
+ if (relevant)
+ return NULL;
+ relevant = commit;
+ }
+ }
+ return relevant;
+}
+
+/*
* The goal is to get REV_TREE_NEW as the result only if the
* diff consists of all '+' (and no other changes), REV_TREE_OLD
* if the whole diff is removal of old data, and otherwise
@@ -368,7 +453,8 @@ static void file_change(struct diff_options *options,
DIFF_OPT_SET(options, HAS_CHANGES);
}
-static int rev_compare_tree(struct rev_info *revs, struct commit *parent, struct commit *commit)
+static int rev_compare_tree(struct rev_info *revs,
+ struct commit *parent, struct commit *commit)
{
struct tree *t1 = parent->tree;
struct tree *t2 = commit->tree;
@@ -429,10 +515,125 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
return retval >= 0 && (tree_difference == REV_TREE_SAME);
}
+struct treesame_state {
+ unsigned int nparents;
+ unsigned char treesame[FLEX_ARRAY];
+};
+
+static struct treesame_state *initialise_treesame(struct rev_info *revs, struct commit *commit)
+{
+ unsigned n = commit_list_count(commit->parents);
+ struct treesame_state *st = xcalloc(1, sizeof(*st) + n);
+ st->nparents = n;
+ add_decoration(&revs->treesame, &commit->object, st);
+ return st;
+}
+
+/*
+ * Must be called immediately after removing the nth_parent from a commit's
+ * parent list, if we are maintaining the per-parent treesame[] decoration.
+ * This does not recalculate the master TREESAME flag - update_treesame()
+ * should be called to update it after a sequence of treesame[] modifications
+ * that may have affected it.
+ */
+static int compact_treesame(struct rev_info *revs, struct commit *commit, unsigned nth_parent)
+{
+ struct treesame_state *st;
+ int old_same;
+
+ if (!commit->parents) {
+ /*
+ * Have just removed the only parent from a non-merge.
+ * Different handling, as we lack decoration.
+ */
+ if (nth_parent != 0)
+ die("compact_treesame %u", nth_parent);
+ old_same = !!(commit->object.flags & TREESAME);
+ if (rev_same_tree_as_empty(revs, commit))
+ commit->object.flags |= TREESAME;
+ else
+ commit->object.flags &= ~TREESAME;
+ return old_same;
+ }
+
+ st = lookup_decoration(&revs->treesame, &commit->object);
+ if (!st || nth_parent >= st->nparents)
+ die("compact_treesame %u", nth_parent);
+
+ old_same = st->treesame[nth_parent];
+ memmove(st->treesame + nth_parent,
+ st->treesame + nth_parent + 1,
+ st->nparents - nth_parent - 1);
+
+ /*
+ * If we've just become a non-merge commit, update TREESAME
+ * immediately, and remove the no-longer-needed decoration.
+ * If still a merge, defer update until update_treesame().
+ */
+ if (--st->nparents == 1) {
+ if (commit->parents->next)
+ die("compact_treesame parents mismatch");
+ if (st->treesame[0] && revs->dense)
+ commit->object.flags |= TREESAME;
+ else
+ commit->object.flags &= ~TREESAME;
+ free(add_decoration(&revs->treesame, &commit->object, NULL));
+ }
+
+ return old_same;
+}
+
+static unsigned update_treesame(struct rev_info *revs, struct commit *commit)
+{
+ if (commit->parents && commit->parents->next) {
+ unsigned n;
+ struct treesame_state *st;
+ struct commit_list *p;
+ unsigned relevant_parents;
+ unsigned relevant_change, irrelevant_change;
+
+ st = lookup_decoration(&revs->treesame, &commit->object);
+ if (!st)
+ die("update_treesame %s", sha1_to_hex(commit->object.sha1));
+ relevant_parents = 0;
+ relevant_change = irrelevant_change = 0;
+ for (p = commit->parents, n = 0; p; n++, p = p->next) {
+ if (relevant_commit(p->item)) {
+ relevant_change |= !st->treesame[n];
+ relevant_parents++;
+ } else
+ irrelevant_change |= !st->treesame[n];
+ }
+ if (relevant_parents ? relevant_change : irrelevant_change)
+ commit->object.flags &= ~TREESAME;
+ else
+ commit->object.flags |= TREESAME;
+ }
+
+ return commit->object.flags & TREESAME;
+}
+
+static inline int limiting_can_increase_treesame(const struct rev_info *revs)
+{
+ /*
+ * TREESAME is irrelevant unless prune && dense;
+ * if simplify_history is set, we can't have a mixture of TREESAME and
+ * !TREESAME INTERESTING parents (and we don't have treesame[]
+ * decoration anyway);
+ * if first_parent_only is set, then the TREESAME flag is locked
+ * against the first parent (and again we lack treesame[] decoration).
+ */
+ return revs->prune && revs->dense &&
+ !revs->simplify_history &&
+ !revs->first_parent_only;
+}
+
static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
{
struct commit_list **pp, *parent;
- int tree_changed = 0, tree_same = 0, nth_parent = 0;
+ struct treesame_state *ts = NULL;
+ int relevant_change = 0, irrelevant_change = 0;
+ int relevant_parents, nth_parent;
/*
* If we don't do pruning, everything is interesting
@@ -456,33 +657,54 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
if (!revs->dense && !commit->parents->next)
return;
- pp = &commit->parents;
- while ((parent = *pp) != NULL) {
+ for (pp = &commit->parents, nth_parent = 0, relevant_parents = 0;
+ (parent = *pp) != NULL;
+ pp = &parent->next, nth_parent++) {
struct commit *p = parent->item;
+ if (relevant_commit(p))
+ relevant_parents++;
- /*
- * Do not compare with later parents when we care only about
- * the first parent chain, in order to avoid derailing the
- * traversal to follow a side branch that brought everything
- * in the path we are limited to by the pathspec.
- */
- if (revs->first_parent_only && nth_parent++)
- break;
+ if (nth_parent == 1) {
+ /*
+ * This our second loop iteration - so we now know
+ * we're dealing with a merge.
+ *
+ * Do not compare with later parents when we care only about
+ * the first parent chain, in order to avoid derailing the
+ * traversal to follow a side branch that brought everything
+ * in the path we are limited to by the pathspec.
+ */
+ if (revs->first_parent_only)
+ break;
+ /*
+ * If this will remain a potentially-simplifiable
+ * merge, remember per-parent treesame if needed.
+ * Initialise the array with the comparison from our
+ * first iteration.
+ */
+ if (revs->treesame.name &&
+ !revs->simplify_history &&
+ !(commit->object.flags & UNINTERESTING)) {
+ ts = initialise_treesame(revs, commit);
+ if (!(irrelevant_change || relevant_change))
+ ts->treesame[0] = 1;
+ }
+ }
if (parse_commit(p) < 0)
die("cannot simplify commit %s (because of %s)",
sha1_to_hex(commit->object.sha1),
sha1_to_hex(p->object.sha1));
switch (rev_compare_tree(revs, p, commit)) {
case REV_TREE_SAME:
- tree_same = 1;
- if (!revs->simplify_history || (p->object.flags & UNINTERESTING)) {
+ if (!revs->simplify_history || !relevant_commit(p)) {
/* Even if a merge with an uninteresting
* side branch brought the entire change
* we are interested in, we do not want
* to lose the other branches of this
* merge, so we just keep going.
*/
- pp = &parent->next;
+ if (ts)
+ ts->treesame[nth_parent] = 1;
continue;
}
parent->next = NULL;
@@ -510,15 +732,27 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
/* fallthrough */
case REV_TREE_OLD:
case REV_TREE_DIFFERENT:
- tree_changed = 1;
- pp = &parent->next;
+ if (relevant_commit(p))
+ relevant_change = 1;
+ else
+ irrelevant_change = 1;
continue;
}
die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
}
- if (tree_changed && !tree_same)
- return;
- commit->object.flags |= TREESAME;
+
+ /*
+ * TREESAME is straightforward for single-parent commits. For merge
+ * commits, it is most useful to define it so that "irrelevant"
+ * parents cannot make us !TREESAME - if we have any relevant
+ * parents, then we only consider TREESAMEness with respect to them,
+ * allowing irrelevant merges from uninteresting branches to be
+ * simplified away. Only if we have only irrelevant parents do we
+ * base TREESAME on them. Note that this logic is replicated in
+ * update_treesame, which should be kept in sync.
+ */
+ if (relevant_parents ? !relevant_change : !irrelevant_change)
+ commit->object.flags |= TREESAME;
}
static void commit_list_insert_by_date_cached(struct commit *p, struct commit_list **head,
@@ -801,16 +1035,12 @@ static void limit_to_ancestry(struct commit_list *bottom, struct commit_list *li
* to filter the result of "A..B" further to the ones that can actually
* reach A.
*/
-static struct commit_list *collect_bottom_commits(struct rev_info *revs)
+static struct commit_list *collect_bottom_commits(struct commit_list *list)
{
- struct commit_list *bottom = NULL;
- int i;
- for (i = 0; i < revs->cmdline.nr; i++) {
- struct rev_cmdline_entry *elem = &revs->cmdline.rev[i];
- if ((elem->flags & UNINTERESTING) &&
- elem->item->type == OBJ_COMMIT)
- commit_list_insert((struct commit *)elem->item, &bottom);
- }
+ struct commit_list *elem, *bottom = NULL;
+ for (elem = list; elem; elem = elem->next)
+ if (elem->item->object.flags & BOTTOM)
+ commit_list_insert(elem->item, &bottom);
return bottom;
}
@@ -841,7 +1071,7 @@ static int limit_list(struct rev_info *revs)
struct commit_list *bottom = NULL;
if (revs->ancestry_path) {
- bottom = collect_bottom_commits(revs);
+ bottom = collect_bottom_commits(list);
if (!bottom)
die("--ancestry-path given but there are no bottom commits");
}
@@ -894,10 +1124,26 @@ static int limit_list(struct rev_info *revs)
free_commit_list(bottom);
}
+ /*
+ * Check if any commits have become TREESAME by some of their parents
+ * becoming UNINTERESTING.
+ */
+ if (limiting_can_increase_treesame(revs))
+ for (list = newlist; list; list = list->next) {
+ struct commit *c = list->item;
+ if (c->object.flags & (UNINTERESTING | TREESAME))
+ continue;
+ update_treesame(revs, c);
+ }
+
revs->commits = newlist;
return 0;
}
+/*
+ * Add an entry to refs->cmdline with the specified information.
+ * *name is copied.
+ */
static void add_rev_cmdline(struct rev_info *revs,
struct object *item,
const char *name,
@@ -909,12 +1155,25 @@ static void add_rev_cmdline(struct rev_info *revs,
ALLOC_GROW(info->rev, nr + 1, info->alloc);
info->rev[nr].item = item;
- info->rev[nr].name = name;
+ info->rev[nr].name = xstrdup(name);
info->rev[nr].whence = whence;
info->rev[nr].flags = flags;
info->nr++;
}
+static void add_rev_cmdline_list(struct rev_info *revs,
+ struct commit_list *commit_list,
+ int whence,
+ unsigned flags)
+{
+ while (commit_list) {
+ struct object *object = &commit_list->item->object;
+ add_rev_cmdline(revs, object, sha1_to_hex(object->sha1),
+ whence, flags);
+ commit_list = commit_list->next;
+ }
+}
+
struct all_refs_cb {
int all_flags;
int warned_bad_reflog;
@@ -1000,7 +1259,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags)
const char *arg = arg_;
if (*arg == '^') {
- flags ^= UNINTERESTING;
+ flags ^= UNINTERESTING | BOTTOM;
arg++;
}
if (get_sha1_committish(arg, sha1))
@@ -1038,7 +1297,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
DIFF_OPT_SET(&revs->pruning, QUICK);
revs->pruning.add_remove = file_add_remove;
revs->pruning.change = file_change;
- revs->lifo = 1;
+ revs->sort_order = REV_SORT_IN_GRAPH_ORDER;
revs->dense = 1;
revs->prefix = prefix;
revs->max_age = -1;
@@ -1092,14 +1351,15 @@ static void prepare_show_merge(struct rev_info *revs)
add_pending_object(revs, &head->object, "HEAD");
add_pending_object(revs, &other->object, "MERGE_HEAD");
bases = get_merge_bases(head, other, 1);
- add_pending_commit_list(revs, bases, UNINTERESTING);
+ add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
+ add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
free_commit_list(bases);
head->object.flags |= SYMMETRIC_LEFT;
if (!active_nr)
read_cache();
for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
if (!ce_stage(ce))
continue;
if (ce_path_match(ce, &revs->prune_data)) {
@@ -1113,7 +1373,7 @@ static void prepare_show_merge(struct rev_info *revs)
i++;
}
free_pathspec(&revs->prune_data);
- init_pathspec(&revs->prune_data, prune);
+ parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC, 0, "", prune);
revs->limited = 1;
}
@@ -1128,13 +1388,15 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
unsigned get_sha1_flags = 0;
+ flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM;
+
dotdot = strstr(arg, "..");
if (dotdot) {
unsigned char from_sha1[20];
const char *next = dotdot + 2;
const char *this = arg;
int symmetric = *next == '.';
- unsigned int flags_exclude = flags ^ UNINTERESTING;
+ unsigned int flags_exclude = flags ^ (UNINTERESTING | BOTTOM);
static const char head_by_default[] = "HEAD";
unsigned int a_flags;
@@ -1179,6 +1441,9 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
if (symmetric) {
exclude = get_merge_bases(a, b, 1);
+ add_rev_cmdline_list(revs, exclude,
+ REV_CMD_MERGE_BASE,
+ flags_exclude);
add_pending_commit_list(revs, exclude,
flags_exclude);
free_commit_list(exclude);
@@ -1207,13 +1472,13 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
dotdot = strstr(arg, "^!");
if (dotdot && !dotdot[2]) {
*dotdot = 0;
- if (!add_parents_only(revs, arg, flags ^ UNINTERESTING))
+ if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM)))
*dotdot = '^';
}
local_flags = 0;
if (*arg == '^') {
- local_flags = UNINTERESTING;
+ local_flags = UNINTERESTING | BOTTOM;
arg++;
}
@@ -1276,7 +1541,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,
}
die("options not supported in --stdin mode");
}
- if (handle_revision_arg(xstrdup(sb.buf), revs, 0,
+ if (handle_revision_arg(sb.buf, revs, 0,
REVARG_CANNOT_BE_FILENAME))
die("bad revision '%s'", sb.buf);
}
@@ -1374,7 +1639,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if (!strcmp(arg, "--merge")) {
revs->show_merge = 1;
} else if (!strcmp(arg, "--topo-order")) {
- revs->lifo = 1;
+ revs->sort_order = REV_SORT_IN_GRAPH_ORDER;
revs->topo_order = 1;
} else if (!strcmp(arg, "--simplify-merges")) {
revs->simplify_merges = 1;
@@ -1392,7 +1657,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->prune = 1;
load_ref_decorations(DECORATE_SHORT_REFS);
} else if (!strcmp(arg, "--date-order")) {
- revs->lifo = 0;
+ revs->sort_order = REV_SORT_BY_COMMIT_DATE;
+ revs->topo_order = 1;
+ } else if (!strcmp(arg, "--author-date-order")) {
+ revs->sort_order = REV_SORT_BY_AUTHOR_DATE;
revs->topo_order = 1;
} else if (!prefixcmp(arg, "--early-output")) {
int count = 100;
@@ -1690,7 +1958,7 @@ static int handle_revision_pseudo_opt(const char *submodule,
handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);
} else if (!strcmp(arg, "--bisect")) {
handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);
- handle_refs(submodule, revs, *flags ^ UNINTERESTING, for_each_good_bisect_ref);
+ handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);
revs->bisect = 1;
} else if (!strcmp(arg, "--tags")) {
handle_refs(submodule, revs, *flags, for_each_tag_ref_submodule);
@@ -1716,7 +1984,7 @@ static int handle_revision_pseudo_opt(const char *submodule,
} else if (!strcmp(arg, "--reflog")) {
handle_reflog(revs, *flags);
} else if (!strcmp(arg, "--not")) {
- *flags ^= UNINTERESTING;
+ *flags ^= UNINTERESTING | BOTTOM;
} else if (!strcmp(arg, "--no-walk")) {
revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
} else if (!prefixcmp(arg, "--no-walk=")) {
@@ -1853,8 +2121,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
*/
ALLOC_GROW(prune_data.path, prune_data.nr+1, prune_data.alloc);
prune_data.path[prune_data.nr++] = NULL;
- init_pathspec(&revs->prune_data,
- get_pathspec(revs->prefix, prune_data.path));
+ parse_pathspec(&revs->prune_data, 0, 0,
+ revs->prefix, prune_data.path);
}
if (revs->def == NULL)
@@ -1887,16 +2155,23 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
revs->limited = 1;
if (revs->prune_data.nr) {
- diff_tree_setup_paths(revs->prune_data.raw, &revs->pruning);
+ copy_pathspec(&revs->pruning.pathspec, &revs->prune_data);
/* Can't prune commits with rename following: the paths change.. */
if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
revs->prune = 1;
if (!revs->full_diff)
- diff_tree_setup_paths(revs->prune_data.raw, &revs->diffopt);
+ copy_pathspec(&revs->diffopt.pathspec,
+ &revs->prune_data);
}
if (revs->combine_merges)
revs->ignore_merges = 0;
revs->diffopt.abbrev = revs->abbrev;
+
+ if (revs->line_level_traverse) {
+ revs->limited = 1;
+ revs->topo_order = 1;
+ }
+
diff_setup_done(&revs->diffopt);
grep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,
@@ -1930,28 +2205,32 @@ static void add_child(struct rev_info *revs, struct commit *parent, struct commi
l->next = add_decoration(&revs->children, &parent->object, l);
}
-static int remove_duplicate_parents(struct commit *commit)
+static int remove_duplicate_parents(struct rev_info *revs, struct commit *commit)
{
+ struct treesame_state *ts = lookup_decoration(&revs->treesame, &commit->object);
struct commit_list **pp, *p;
int surviving_parents;
/* Examine existing parents while marking ones we have seen... */
pp = &commit->parents;
+ surviving_parents = 0;
while ((p = *pp) != NULL) {
struct commit *parent = p->item;
if (parent->object.flags & TMP_MARK) {
*pp = p->next;
+ if (ts)
+ compact_treesame(revs, commit, surviving_parents);
continue;
}
parent->object.flags |= TMP_MARK;
+ surviving_parents++;
pp = &p->next;
}
- /* count them while clearing the temporary mark */
- surviving_parents = 0;
+ /* clear the temporary mark */
for (p = commit->parents; p; p = p->next) {
p->item->object.flags &= ~TMP_MARK;
- surviving_parents++;
}
+ /* no update_treesame() - removing duplicates can't affect TREESAME */
return surviving_parents;
}
@@ -1971,9 +2250,157 @@ static struct merge_simplify_state *locate_simplify_state(struct rev_info *revs,
return st;
}
+static int mark_redundant_parents(struct rev_info *revs, struct commit *commit)
+{
+ struct commit_list *h = reduce_heads(commit->parents);
+ int i = 0, marked = 0;
+ struct commit_list *po, *pn;
+
+ /* Want these for sanity-checking only */
+ int orig_cnt = commit_list_count(commit->parents);
+ int cnt = commit_list_count(h);
+
+ /*
+ * Not ready to remove items yet, just mark them for now, based
+ * on the output of reduce_heads(). reduce_heads outputs the reduced
+ * set in its original order, so this isn't too hard.
+ */
+ po = commit->parents;
+ pn = h;
+ while (po) {
+ if (pn && po->item == pn->item) {
+ pn = pn->next;
+ i++;
+ } else {
+ po->item->object.flags |= TMP_MARK;
+ marked++;
+ }
+ po=po->next;
+ }
+
+ if (i != cnt || cnt+marked != orig_cnt)
+ die("mark_redundant_parents %d %d %d %d", orig_cnt, cnt, i, marked);
+
+ free_commit_list(h);
+
+ return marked;
+}
+
+static int mark_treesame_root_parents(struct rev_info *revs, struct commit *commit)
+{
+ struct commit_list *p;
+ int marked = 0;
+
+ for (p = commit->parents; p; p = p->next) {
+ struct commit *parent = p->item;
+ if (!parent->parents && (parent->object.flags & TREESAME)) {
+ parent->object.flags |= TMP_MARK;
+ marked++;
+ }
+ }
+
+ return marked;
+}
+
+/*
+ * Awkward naming - this means one parent we are TREESAME to.
+ * cf mark_treesame_root_parents: root parents that are TREESAME (to an
+ * empty tree). Better name suggestions?
+ */
+static int leave_one_treesame_to_parent(struct rev_info *revs, struct commit *commit)
+{
+ struct treesame_state *ts = lookup_decoration(&revs->treesame, &commit->object);
+ struct commit *unmarked = NULL, *marked = NULL;
+ struct commit_list *p;
+ unsigned n;
+
+ for (p = commit->parents, n = 0; p; p = p->next, n++) {
+ if (ts->treesame[n]) {
+ if (p->item->object.flags & TMP_MARK) {
+ if (!marked)
+ marked = p->item;
+ } else {
+ if (!unmarked) {
+ unmarked = p->item;
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * If we are TREESAME to a marked-for-deletion parent, but not to any
+ * unmarked parents, unmark the first TREESAME parent. This is the
+ * parent that the default simplify_history==1 scan would have followed,
+ * and it doesn't make sense to omit that path when asking for a
+ * simplified full history. Retaining it improves the chances of
+ * understanding odd missed merges that took an old version of a file.
+ *
+ * Example:
+ *
+ * I--------*X A modified the file, but mainline merge X used
+ * \ / "-s ours", so took the version from I. X is
+ * `-*A--' TREESAME to I and !TREESAME to A.
+ *
+ * Default log from X would produce "I". Without this check,
+ * --full-history --simplify-merges would produce "I-A-X", showing
+ * the merge commit X and that it changed A, but not making clear that
+ * it had just taken the I version. With this check, the topology above
+ * is retained.
+ *
+ * Note that it is possible that the simplification chooses a different
+ * TREESAME parent from the default, in which case this test doesn't
+ * activate, and we _do_ drop the default parent. Example:
+ *
+ * I------X A modified the file, but it was reverted in B,
+ * \ / meaning mainline merge X is TREESAME to both
+ * *A-*B parents.
+ *
+ * Default log would produce "I" by following the first parent;
+ * --full-history --simplify-merges will produce "I-A-B". But this is a
+ * reasonable result - it presents a logical full history leading from
+ * I to X, and X is not an important merge.
+ */
+ if (!unmarked && marked) {
+ marked->object.flags &= ~TMP_MARK;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int remove_marked_parents(struct rev_info *revs, struct commit *commit)
+{
+ struct commit_list **pp, *p;
+ int nth_parent, removed = 0;
+
+ pp = &commit->parents;
+ nth_parent = 0;
+ while ((p = *pp) != NULL) {
+ struct commit *parent = p->item;
+ if (parent->object.flags & TMP_MARK) {
+ parent->object.flags &= ~TMP_MARK;
+ *pp = p->next;
+ free(p);
+ removed++;
+ compact_treesame(revs, commit, nth_parent);
+ continue;
+ }
+ pp = &p->next;
+ nth_parent++;
+ }
+
+ /* Removing parents can only increase TREESAMEness */
+ if (removed && !(commit->object.flags & TREESAME))
+ update_treesame(revs, commit);
+
+ return nth_parent;
+}
+
static struct commit_list **simplify_one(struct rev_info *revs, struct commit *commit, struct commit_list **tail)
{
struct commit_list *p;
+ struct commit *parent;
struct merge_simplify_state *st, *pst;
int cnt;
@@ -2015,7 +2442,9 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
}
/*
- * Rewrite our list of parents.
+ * Rewrite our list of parents. Note that this cannot
+ * affect our TREESAME flags in any way - a commit is
+ * always TREESAME to its simplification.
*/
for (p = commit->parents; p; p = p->next) {
pst = locate_simplify_state(revs, p->item);
@@ -2023,46 +2452,57 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
if (revs->first_parent_only)
break;
}
- if (!revs->first_parent_only)
- cnt = remove_duplicate_parents(commit);
- else
+
+ if (revs->first_parent_only)
cnt = 1;
+ else
+ cnt = remove_duplicate_parents(revs, commit);
/*
* It is possible that we are a merge and one side branch
* does not have any commit that touches the given paths;
- * in such a case, the immediate parents will be rewritten
- * to different commits.
+ * in such a case, the immediate parent from that branch
+ * will be rewritten to be the merge base.
*
* o----X X: the commit we are looking at;
* / / o: a commit that touches the paths;
* ---o----'
*
- * Further reduce the parents by removing redundant parents.
+ * Further, a merge of an independent branch that doesn't
+ * touch the path will reduce to a treesame root parent:
+ *
+ * ----o----X X: the commit we are looking at;
+ * / o: a commit that touches the paths;
+ * r r: a root commit not touching the paths
+ *
+ * Detect and simplify both cases.
*/
if (1 < cnt) {
- struct commit_list *h = reduce_heads(commit->parents);
- cnt = commit_list_count(h);
- free_commit_list(commit->parents);
- commit->parents = h;
+ int marked = mark_redundant_parents(revs, commit);
+ marked += mark_treesame_root_parents(revs, commit);
+ if (marked)
+ marked -= leave_one_treesame_to_parent(revs, commit);
+ if (marked)
+ cnt = remove_marked_parents(revs, commit);
}
/*
* A commit simplifies to itself if it is a root, if it is
* UNINTERESTING, if it touches the given paths, or if it is a
- * merge and its parents simplifies to more than one commits
+ * merge and its parents don't simplify to one relevant commit
* (the first two cases are already handled at the beginning of
* this function).
*
- * Otherwise, it simplifies to what its sole parent simplifies to.
+ * Otherwise, it simplifies to what its sole relevant parent
+ * simplifies to.
*/
if (!cnt ||
(commit->object.flags & UNINTERESTING) ||
!(commit->object.flags & TREESAME) ||
- (1 < cnt))
+ (parent = one_relevant_parent(revs, commit->parents)) == NULL)
st->simplified = commit;
else {
- pst = locate_simplify_state(revs, commit->parents->item);
+ pst = locate_simplify_state(revs, parent);
st->simplified = pst->simplified;
}
return tail;
@@ -2158,6 +2598,11 @@ int prepare_revision_walk(struct rev_info *revs)
if (!revs->leak_pending)
free(list);
+ /* Signal whether we need per-parent treesame decoration */
+ if (revs->simplify_merges ||
+ (revs->limited && limiting_can_increase_treesame(revs)))
+ revs->treesame.name = "treesame";
+
if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
commit_list_sort_by_date(&revs->commits);
if (revs->no_walk)
@@ -2166,7 +2611,9 @@ int prepare_revision_walk(struct rev_info *revs)
if (limit_list(revs) < 0)
return -1;
if (revs->topo_order)
- sort_in_topological_order(&revs->commits, revs->lifo);
+ sort_in_topological_order(&revs->commits, revs->sort_order);
+ if (revs->line_level_traverse)
+ line_log_filter(revs);
if (revs->simplify_merges)
simplify_merges(revs);
if (revs->children.name)
@@ -2174,12 +2621,6 @@ int prepare_revision_walk(struct rev_info *revs)
return 0;
}
-enum rewrite_result {
- rewrite_one_ok,
- rewrite_one_noparents,
- rewrite_one_error
-};
-
static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp)
{
struct commit_list *cache = NULL;
@@ -2189,24 +2630,25 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp
if (!revs->limited)
if (add_parents_to_list(revs, p, &revs->commits, &cache) < 0)
return rewrite_one_error;
- if (p->parents && p->parents->next)
- return rewrite_one_ok;
if (p->object.flags & UNINTERESTING)
return rewrite_one_ok;
if (!(p->object.flags & TREESAME))
return rewrite_one_ok;
if (!p->parents)
return rewrite_one_noparents;
- *pp = p->parents->item;
+ if ((p = one_relevant_parent(revs, p->parents)) == NULL)
+ return rewrite_one_ok;
+ *pp = p;
}
}
-static int rewrite_parents(struct rev_info *revs, struct commit *commit)
+int rewrite_parents(struct rev_info *revs, struct commit *commit,
+ rewrite_parent_fn_t rewrite_parent)
{
struct commit_list **pp = &commit->parents;
while (*pp) {
struct commit_list *parent = *pp;
- switch (rewrite_one(revs, &parent->item)) {
+ switch (rewrite_parent(revs, &parent->item)) {
case rewrite_one_ok:
break;
case rewrite_one_noparents:
@@ -2217,7 +2659,7 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
}
pp = &parent->next;
}
- remove_duplicate_parents(commit);
+ remove_duplicate_parents(revs, commit);
return 0;
}
@@ -2291,7 +2733,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
* in it.
*/
encoding = get_log_output_encoding();
- message = logmsg_reencode(commit, encoding);
+ message = logmsg_reencode(commit, NULL, encoding);
/* Copy the commit to temporary if we are using "fake" headers */
if (buf.len)
@@ -2323,7 +2765,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
return retval;
}
-static inline int want_ancestry(struct rev_info *revs)
+static inline int want_ancestry(const struct rev_info *revs)
{
return (revs->rewrite_parents || revs->children.name);
}
@@ -2341,10 +2783,7 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
if (revs->min_age != -1 && (commit->date > revs->min_age))
return commit_ignore;
if (revs->min_parents || (revs->max_parents >= 0)) {
- int n = 0;
- struct commit_list *p;
- for (p = commit->parents; p; p = p->next)
- n++;
+ int n = commit_list_count(commit->parents);
if ((n < revs->min_parents) ||
((revs->max_parents >= 0) && (n > revs->max_parents)))
return commit_ignore;
@@ -2354,12 +2793,23 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
if (revs->prune && revs->dense) {
/* Commit without changes? */
if (commit->object.flags & TREESAME) {
+ int n;
+ struct commit_list *p;
/* drop merges unless we want parenthood */
if (!want_ancestry(revs))
return commit_ignore;
- /* non-merge - always ignore it */
- if (!commit->parents || !commit->parents->next)
- return commit_ignore;
+ /*
+ * If we want ancestry, then need to keep any merges
+ * between relevant commits to tie together topology.
+ * For consistency with TREESAME and simplification
+ * use "relevant" here rather than just INTERESTING,
+ * to treat bottom commit(s) as part of the topology.
+ */
+ for (n = 0, p = commit->parents; p; p = p->next)
+ if (relevant_commit(p->item))
+ if (++n >= 2)
+ return commit_show;
+ return commit_ignore;
}
}
return commit_show;
@@ -2372,7 +2822,15 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
if (action == commit_show &&
!revs->show_all &&
revs->prune && revs->dense && want_ancestry(revs)) {
- if (rewrite_parents(revs, commit) < 0)
+ /*
+ * --full-diff on simplified parents is no good: it
+ * will show spurious changes from the commits that
+ * were elided. So we save the parents on the side
+ * when --full-diff is in effect.
+ */
+ if (revs->full_diff)
+ save_parents(revs, commit);
+ if (rewrite_parents(revs, commit, rewrite_one) < 0)
return commit_error;
}
return action;
@@ -2391,6 +2849,7 @@ static struct commit *get_revision_1(struct rev_info *revs)
free(entry);
if (revs->reflog_info) {
+ save_parents(revs, commit);
fake_reflog_parent(revs->reflog_info, commit);
commit->object.flags &= ~(ADDED | SEEN | SHOWN);
}
@@ -2422,25 +2881,23 @@ static struct commit *get_revision_1(struct rev_info *revs)
return NULL;
}
-static void gc_boundary(struct object_array *array)
+/*
+ * Return true for entries that have not yet been shown. (This is an
+ * object_array_each_func_t.)
+ */
+static int entry_unshown(struct object_array_entry *entry, void *cb_data_unused)
{
- unsigned nr = array->nr;
- unsigned alloc = array->alloc;
- struct object_array_entry *objects = array->objects;
+ return !(entry->item->flags & SHOWN);
+}
- if (alloc <= nr) {
- unsigned i, j;
- for (i = j = 0; i < nr; i++) {
- if (objects[i].item->flags & SHOWN)
- continue;
- if (i != j)
- objects[j] = objects[i];
- j++;
- }
- for (i = j; i < nr; i++)
- objects[i].item = NULL;
- array->nr = j;
- }
+/*
+ * If array is on the verge of a realloc, garbage-collect any entries
+ * that have already been shown to try to free up some space.
+ */
+static void gc_boundary(struct object_array *array)
+{
+ if (array->nr == array->alloc)
+ object_array_filter(array, entry_unshown, NULL);
}
static void create_boundary_commit_list(struct rev_info *revs)
@@ -2481,7 +2938,7 @@ static void create_boundary_commit_list(struct rev_info *revs)
* If revs->topo_order is set, sort the boundary commits
* in topological order
*/
- sort_in_topological_order(&revs->commits, revs->lifo);
+ sort_in_topological_order(&revs->commits, revs->sort_order);
}
static struct commit *get_revision_internal(struct rev_info *revs)
@@ -2592,6 +3049,8 @@ struct commit *get_revision(struct rev_info *revs)
c = get_revision_internal(revs);
if (c && revs->graph)
graph_update(revs->graph, c);
+ if (!c)
+ free_saved_parents(revs);
return c;
}
@@ -2623,3 +3082,54 @@ void put_revision_mark(const struct rev_info *revs, const struct commit *commit)
fputs(mark, stdout);
putchar(' ');
}
+
+define_commit_slab(saved_parents, struct commit_list *);
+
+#define EMPTY_PARENT_LIST ((struct commit_list *)-1)
+
+void save_parents(struct rev_info *revs, struct commit *commit)
+{
+ struct commit_list **pp;
+
+ if (!revs->saved_parents_slab) {
+ revs->saved_parents_slab = xmalloc(sizeof(struct saved_parents));
+ init_saved_parents(revs->saved_parents_slab);
+ }
+
+ pp = saved_parents_at(revs->saved_parents_slab, commit);
+
+ /*
+ * When walking with reflogs, we may visit the same commit
+ * several times: once for each appearance in the reflog.
+ *
+ * In this case, save_parents() will be called multiple times.
+ * We want to keep only the first set of parents. We need to
+ * store a sentinel value for an empty (i.e., NULL) parent
+ * list to distinguish it from a not-yet-saved list, however.
+ */
+ if (*pp)
+ return;
+ if (commit->parents)
+ *pp = copy_commit_list(commit->parents);
+ else
+ *pp = EMPTY_PARENT_LIST;
+}
+
+struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit)
+{
+ struct commit_list *parents;
+
+ if (!revs->saved_parents_slab)
+ return commit->parents;
+
+ parents = *saved_parents_at(revs->saved_parents_slab, commit);
+ if (parents == EMPTY_PARENT_LIST)
+ return NULL;
+ return parents;
+}
+
+void free_saved_parents(struct rev_info *revs)
+{
+ if (revs->saved_parents_slab)
+ clear_saved_parents(revs->saved_parents_slab);
+}
diff --git a/revision.h b/revision.h
index 5da09ee..e7f1d21 100644
--- a/revision.h
+++ b/revision.h
@@ -4,6 +4,7 @@
#include "parse-options.h"
#include "grep.h"
#include "notes.h"
+#include "commit.h"
#define SEEN (1u<<0)
#define UNINTERESTING (1u<<1)
@@ -15,7 +16,8 @@
#define ADDED (1u<<7) /* Parents already parsed and added? */
#define SYMMETRIC_LEFT (1u<<8)
#define PATCHSAME (1u<<9)
-#define ALL_REV_FLAGS ((1u<<10)-1)
+#define BOTTOM (1u<<10)
+#define ALL_REV_FLAGS ((1u<<11)-1)
#define DECORATE_SHORT_REFS 1
#define DECORATE_FULL_REFS 2
@@ -23,6 +25,7 @@
struct rev_info;
struct log_info;
struct string_list;
+struct saved_parents;
struct rev_cmdline_info {
unsigned int nr;
@@ -35,6 +38,7 @@ struct rev_cmdline_info {
REV_CMD_PARENTS_ONLY,
REV_CMD_LEFT,
REV_CMD_RIGHT,
+ REV_CMD_MERGE_BASE,
REV_CMD_REV
} whence;
unsigned flags;
@@ -60,6 +64,10 @@ struct rev_info {
const char *prefix;
const char *def;
struct pathspec prune_data;
+
+ /* topo-sort */
+ enum rev_sort_order sort_order;
+
unsigned int early_output:1,
ignore_missing:1;
@@ -70,7 +78,6 @@ struct rev_info {
show_all:1,
remove_empty_trees:1,
simplify_history:1,
- lifo:1,
topo_order:1,
simplify_merges:1,
simplify_by_decoration:1,
@@ -96,7 +103,8 @@ struct rev_info {
cherry_mark:1,
bisect:1,
ancestry_path:1,
- first_parent_only:1;
+ first_parent_only:1,
+ line_level_traverse:1;
/* Diff flags */
unsigned int diff:1,
@@ -137,8 +145,9 @@ struct rev_info {
int numbered_files;
int reroll_count;
char *message_id;
+ struct ident_split from_ident;
struct string_list *ref_message_ids;
- const char *add_signoff;
+ int add_signoff;
const char *extra_headers;
const char *log_reencode;
const char *subject_prefix;
@@ -167,6 +176,7 @@ struct rev_info {
struct reflog_walk_info *reflog_info;
struct decoration children;
struct decoration merge_simplification;
+ struct decoration treesame;
/* notes-specific options: which refs to show */
struct display_notes_opt notes_opt;
@@ -175,6 +185,12 @@ struct rev_info {
int count_left;
int count_right;
int count_same;
+
+ /* line level range that we are chasing */
+ struct decoration line_log_data;
+
+ /* copies of the parent lists, for --full-diff display */
+ struct saved_parents *saved_parents_slab;
};
#define REV_TREE_SAME 0
@@ -195,19 +211,23 @@ struct setup_revision_opt {
};
extern void init_revisions(struct rev_info *revs, const char *prefix);
-extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *);
+extern int setup_revisions(int argc, const char **argv, struct rev_info *revs,
+ struct setup_revision_opt *);
extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
- const struct option *options,
- const char * const usagestr[]);
+ const struct option *options,
+ const char * const usagestr[]);
#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 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);
extern struct commit *get_revision(struct rev_info *revs);
-extern char *get_revision_mark(const struct rev_info *revs, const struct commit *commit);
-extern void put_revision_mark(const struct rev_info *revs, const struct commit *commit);
+extern char *get_revision_mark(const struct rev_info *revs,
+ const struct commit *commit);
+extern void put_revision_mark(const struct rev_info *revs,
+ const struct commit *commit);
extern void mark_parents_uninteresting(struct commit *commit);
extern void mark_tree_uninteresting(struct tree *tree);
@@ -220,15 +240,19 @@ struct name_path {
char *path_name(const struct name_path *path, const char *name);
-extern void show_object_with_name(FILE *, struct object *, const struct name_path *, const char *);
+extern void show_object_with_name(FILE *, struct object *,
+ const struct name_path *, const char *);
extern void add_object(struct object *obj,
struct object_array *p,
struct name_path *path,
const char *name);
-extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
-extern void add_pending_sha1(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags);
+extern void add_pending_object(struct rev_info *revs,
+ struct object *obj, const char *name);
+extern void add_pending_sha1(struct rev_info *revs,
+ const char *name, const unsigned char *sha1,
+ unsigned int flags);
extern void add_head_to_pending(struct rev_info *);
@@ -238,7 +262,35 @@ enum commit_action {
commit_error
};
-extern enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit);
-extern enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit);
+extern enum commit_action get_commit_action(struct rev_info *revs,
+ struct commit *commit);
+extern enum commit_action simplify_commit(struct rev_info *revs,
+ struct commit *commit);
+
+enum rewrite_result {
+ rewrite_one_ok,
+ rewrite_one_noparents,
+ rewrite_one_error
+};
+
+typedef enum rewrite_result (*rewrite_parent_fn_t)(struct rev_info *revs, struct commit **pp);
+
+extern int rewrite_parents(struct rev_info *revs, struct commit *commit,
+ rewrite_parent_fn_t rewrite_parent);
+
+/*
+ * Save a copy of the parent list, and return the saved copy. This is
+ * used by the log machinery to retrieve the original parents when
+ * commit->parents has been modified by history simpification.
+ *
+ * You may only call save_parents() once per commit (this is checked
+ * for non-root commits).
+ *
+ * get_saved_parents() will transparently return commit->parents if
+ * history simplification is off.
+ */
+extern void save_parents(struct rev_info *revs, struct commit *commit);
+extern struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
+extern void free_saved_parents(struct rev_info *revs);
#endif
diff --git a/run-command.c b/run-command.c
index 1b32a12..1b7f88e 100644
--- a/run-command.c
+++ b/run-command.c
@@ -72,11 +72,14 @@ static inline void close_pair(int fd[2])
close(fd[1]);
}
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
static inline void dup_devnull(int to)
{
int fd = open("/dev/null", O_RDWR);
- dup2(fd, to);
+ if (fd < 0)
+ die_errno(_("open /dev/null failed"));
+ if (dup2(fd, to) < 0)
+ die_errno(_("dup2(%d,%d) failed"), fd, to);
close(fd);
}
#endif
@@ -159,7 +162,7 @@ static const char **prepare_shell_cmd(const char **argv)
die("BUG: shell command is empty");
if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
nargv[nargc++] = SHELL_PATH;
#else
nargv[nargc++] = "sh";
@@ -182,7 +185,7 @@ static const char **prepare_shell_cmd(const char **argv)
return nargv;
}
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
static int execv_shell_cmd(const char **argv)
{
const char **nargv = prepare_shell_cmd(argv);
@@ -193,7 +196,7 @@ static int execv_shell_cmd(const char **argv)
}
#endif
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
static int child_err = 2;
static int child_notifier = -1;
@@ -334,7 +337,7 @@ fail_pipe:
trace_argv_printf(cmd->argv, "trace: run_command:");
fflush(NULL);
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
{
int notify_pipe[2];
if (pipe(notify_pipe))
diff --git a/run-command.h b/run-command.h
index 221ce33..6b985af 100644
--- a/run-command.h
+++ b/run-command.h
@@ -46,6 +46,7 @@ int finish_command(struct child_process *);
int run_command(struct child_process *);
extern char *find_hook(const char *name);
+LAST_ARG_MUST_BE_NULL
extern int run_hook(const char *index_file, const char *name, ...);
#define RUN_COMMAND_NO_STDIN 1
diff --git a/send-pack.c b/send-pack.c
index 97ab336..b228d65 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -5,6 +5,7 @@
#include "sideband.h"
#include "run-command.h"
#include "remote.h"
+#include "connect.h"
#include "send-pack.h"
#include "quote.h"
#include "transport.h"
@@ -106,15 +107,11 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
static int receive_status(int in, struct ref *refs)
{
struct ref *hint;
- char line[1000];
int ret = 0;
- int len = packet_read_line(in, line, sizeof(line));
- if (len < 10 || memcmp(line, "unpack ", 7))
+ char *line = packet_read_line(in, NULL);
+ if (prefixcmp(line, "unpack "))
return error("did not receive remote status");
- if (memcmp(line, "unpack ok\n", 10)) {
- char *p = line + strlen(line) - 1;
- if (*p == '\n')
- *p = '\0';
+ if (strcmp(line, "unpack ok")) {
error("unpack failed: %s", line + 7);
ret = -1;
}
@@ -122,17 +119,15 @@ static int receive_status(int in, struct ref *refs)
while (1) {
char *refname;
char *msg;
- len = packet_read_line(in, line, sizeof(line));
- if (!len)
+ line = packet_read_line(in, NULL);
+ if (!line)
break;
- if (len < 3 ||
- (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) {
- fprintf(stderr, "protocol error: %s\n", line);
+ if (prefixcmp(line, "ok ") && prefixcmp(line, "ng ")) {
+ error("invalid ref status from remote: %s", line);
ret = -1;
break;
}
- line[strlen(line)-1] = '\0';
refname = line + 3;
msg = strchr(refname, ' ');
if (msg)
@@ -232,6 +227,7 @@ int send_pack(struct send_pack_args *args,
case REF_STATUS_REJECT_ALREADY_EXISTS:
case REF_STATUS_REJECT_FETCH_FIRST:
case REF_STATUS_REJECT_NEEDS_FORCE:
+ case REF_STATUS_REJECT_STALE:
case REF_STATUS_UPTODATE:
continue;
default:
@@ -281,7 +277,7 @@ int send_pack(struct send_pack_args *args,
send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
}
} else {
- safe_write(out, req_buf.buf, req_buf.len);
+ write_or_die(out, req_buf.buf, req_buf.len);
packet_flush(out);
}
strbuf_release(&req_buf);
diff --git a/sequencer.c b/sequencer.c
index bad5077..351548f 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -18,6 +18,89 @@
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
const char sign_off_header[] = "Signed-off-by: ";
+static const char cherry_picked_prefix[] = "(cherry picked from commit ";
+
+static int is_rfc2822_line(const char *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ int ch = buf[i];
+ if (ch == ':')
+ return 1;
+ if (!isalnum(ch) && ch != '-')
+ break;
+ }
+
+ return 0;
+}
+
+static int is_cherry_picked_from_line(const char *buf, int len)
+{
+ /*
+ * We only care that it looks roughly like (cherry picked from ...)
+ */
+ return len > strlen(cherry_picked_prefix) + 1 &&
+ !prefixcmp(buf, cherry_picked_prefix) && buf[len - 1] == ')';
+}
+
+/*
+ * Returns 0 for non-conforming footer
+ * Returns 1 for conforming footer
+ * Returns 2 when sob exists within conforming footer
+ * Returns 3 when sob exists within conforming footer as last entry
+ */
+static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,
+ int ignore_footer)
+{
+ char prev;
+ int i, k;
+ int len = sb->len - ignore_footer;
+ const char *buf = sb->buf;
+ int found_sob = 0;
+
+ /* footer must end with newline */
+ if (!len || buf[len - 1] != '\n')
+ return 0;
+
+ prev = '\0';
+ for (i = len - 1; i > 0; i--) {
+ char ch = buf[i];
+ if (prev == '\n' && ch == '\n') /* paragraph break */
+ break;
+ prev = ch;
+ }
+
+ /* require at least one blank line */
+ if (prev != '\n' || buf[i] != '\n')
+ return 0;
+
+ /* advance to start of last paragraph */
+ while (i < len - 1 && buf[i] == '\n')
+ i++;
+
+ for (; i < len; i = k) {
+ int found_rfc2822;
+
+ for (k = i; k < len && buf[k] != '\n'; k++)
+ ; /* do nothing */
+ k++;
+
+ found_rfc2822 = is_rfc2822_line(buf + i, k - i - 1);
+ if (found_rfc2822 && sob &&
+ !strncmp(buf + i, sob->buf, sob->len))
+ found_sob = k;
+
+ if (!(found_rfc2822 ||
+ is_cherry_picked_from_line(buf + i, k - i - 1)))
+ return 0;
+ }
+ if (found_sob == i)
+ return 3;
+ if (found_sob)
+ return 2;
+ return 1;
+}
static void remove_sequencer_state(void)
{
@@ -187,15 +270,20 @@ static int error_dirty_index(struct replay_opts *opts)
}
static int fast_forward_to(const unsigned char *to, const unsigned char *from,
- int unborn)
+ int unborn, struct replay_opts *opts)
{
struct ref_lock *ref_lock;
+ struct strbuf sb = STRBUF_INIT;
+ int ret;
read_cache();
if (checkout_fast_forward(from, to, 1))
exit(1); /* the callee should have complained already */
ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from, 0);
- return write_ref_sha1(ref_lock, to, "cherry-pick");
+ strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
+ ret = write_ref_sha1(ref_lock, to, sb.buf);
+ strbuf_release(&sb);
+ return ret;
}
static int do_recursive_merge(struct commit *base, struct commit *next,
@@ -237,13 +325,13 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
rollback_lock_file(&index_lock);
if (opts->signoff)
- append_signoff(msgbuf, 0);
+ append_signoff(msgbuf, 0, 0);
if (!clean) {
int i;
strbuf_addstr(msgbuf, "\nConflicts:\n");
for (i = 0; i < active_nr;) {
- struct cache_entry *ce = active_cache[i++];
+ const struct cache_entry *ce = active_cache[i++];
if (ce_stage(ce)) {
strbuf_addch(msgbuf, '\t');
strbuf_addstr(msgbuf, ce->name);
@@ -283,8 +371,9 @@ static int is_index_unchanged(void)
active_cache_tree = cache_tree();
if (!cache_tree_fully_valid(active_cache_tree))
- if (cache_tree_update(active_cache_tree, active_cache,
- active_nr, 0))
+ if (cache_tree_update(active_cache_tree,
+ (const struct cache_entry * const *)active_cache,
+ active_nr, 0))
return error(_("Unable to update cache tree\n"));
return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);
@@ -391,7 +480,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
char *defmsg = NULL;
struct strbuf msgbuf = STRBUF_INIT;
- int res, unborn = 0;
+ int res, unborn = 0, allow;
if (opts->no_commit) {
/*
@@ -440,7 +529,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
if (opts->allow_ff &&
((parent && !hashcmp(parent->object.sha1, head)) ||
(!parent && unborn)))
- return fast_forward_to(commit->object.sha1, head, unborn);
+ return fast_forward_to(commit->object.sha1, head, unborn, opts);
if (parent && parse_commit(parent) < 0)
/* TRANSLATORS: The first %s will be "revert" or
@@ -496,7 +585,9 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
}
if (opts->record_origin) {
- strbuf_addstr(&msgbuf, "(cherry picked from commit ");
+ if (!has_conforming_footer(&msgbuf, NULL, 0))
+ strbuf_addch(&msgbuf, '\n');
+ strbuf_addstr(&msgbuf, cherry_picked_prefix);
strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
strbuf_addstr(&msgbuf, ")\n");
}
@@ -539,14 +630,18 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
msg.subject);
print_advice(res == 1, opts);
rerere(opts->allow_rerere_auto);
- } else {
- int allow = allow_empty(opts, commit);
- if (allow < 0)
- return allow;
- if (!opts->no_commit)
- res = run_git_commit(defmsg, opts, allow);
+ goto leave;
+ }
+
+ allow = allow_empty(opts, commit);
+ if (allow < 0) {
+ res = allow;
+ goto leave;
}
+ if (!opts->no_commit)
+ res = run_git_commit(defmsg, opts, allow);
+leave:
free_message(&msg);
free(defmsg);
@@ -962,6 +1057,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)
{
struct commit_list *todo_list = NULL;
unsigned char sha1[20];
+ int i;
if (opts->subcommand == REPLAY_NONE)
assert(opts->revs);
@@ -982,6 +1078,23 @@ int sequencer_pick_revisions(struct replay_opts *opts)
if (opts->subcommand == REPLAY_CONTINUE)
return sequencer_continue(opts);
+ for (i = 0; i < opts->revs->pending.nr; i++) {
+ unsigned char sha1[20];
+ const char *name = opts->revs->pending.objects[i].name;
+
+ /* This happens when using --stdin. */
+ if (!strlen(name))
+ continue;
+
+ if (!get_sha1(name, sha1)) {
+ if (!lookup_commit_reference_gently(sha1, 1)) {
+ enum object_type type = sha1_object_info(sha1, NULL);
+ die(_("%s: can't cherry-pick a %s"), name, typename(type));
+ }
+ } else
+ die(_("%s: bad revision"), name);
+ }
+
/*
* If we were called as "git cherry-pick <commit>", just
* cherry-pick/revert it, set CHERRY_PICK_HEAD /
@@ -1021,62 +1134,67 @@ int sequencer_pick_revisions(struct replay_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)
+void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)
{
+ unsigned no_dup_sob = flag & APPEND_SIGNOFF_DEDUP;
struct strbuf sob = STRBUF_INIT;
- int i;
+ int has_footer;
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);
+
+ /*
+ * If the whole message buffer is equal to the sob, pretend that we
+ * found a conforming footer with a matching sob
+ */
+ if (msgbuf->len - ignore_footer == sob.len &&
+ !strncmp(msgbuf->buf, sob.buf, sob.len))
+ has_footer = 3;
+ else
+ has_footer = has_conforming_footer(msgbuf, &sob, ignore_footer);
+
+ if (!has_footer) {
+ const char *append_newlines = NULL;
+ size_t len = msgbuf->len - ignore_footer;
+
+ if (!len) {
+ /*
+ * The buffer is completely empty. Leave foom for
+ * the title and body to be filled in by the user.
+ */
+ append_newlines = "\n\n";
+ } else if (msgbuf->buf[len - 1] != '\n') {
+ /*
+ * Incomplete line. Complete the line and add a
+ * blank one so that there is an empty line between
+ * the message body and the sob.
+ */
+ append_newlines = "\n\n";
+ } else if (len == 1) {
+ /*
+ * Buffer contains a single newline. Add another
+ * so that we leave room for the title and body.
+ */
+ append_newlines = "\n";
+ } else if (msgbuf->buf[len - 2] != '\n') {
+ /*
+ * Buffer ends with a single newline. Add another
+ * so that there is an empty line between the message
+ * body and the sob.
+ */
+ append_newlines = "\n";
+ } /* else, the buffer already ends with two newlines. */
+
+ if (append_newlines)
+ strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0,
+ append_newlines, strlen(append_newlines));
}
+
+ if (has_footer != 3 && (!no_dup_sob || has_footer != 2))
+ strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0,
+ sob.buf, sob.len);
+
strbuf_release(&sob);
}
diff --git a/sequencer.h b/sequencer.h
index 9d57d57..1fc22dc 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -6,6 +6,8 @@
#define SEQ_TODO_FILE "sequencer/todo"
#define SEQ_OPTS_FILE "sequencer/opts"
+#define APPEND_SIGNOFF_DEDUP (1u << 0)
+
enum replay_action {
REPLAY_REVERT,
REPLAY_PICK
@@ -48,6 +50,6 @@ int sequencer_pick_revisions(struct replay_opts *opts);
extern const char sign_off_header[];
-void append_signoff(struct strbuf *msgbuf, int ignore_footer);
+void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);
#endif
diff --git a/setup.c b/setup.c
index 94c1e61..f08dd64 100644
--- a/setup.c
+++ b/setup.c
@@ -5,7 +5,19 @@
static int inside_git_dir = -1;
static int inside_work_tree = -1;
-static char *prefix_path_gently(const char *prefix, int len, const char *path)
+/*
+ * Normalize "path", prepending the "prefix" for relative paths. If
+ * remaining_prefix is not NULL, return the actual prefix still
+ * remains in the path. For example, prefix = sub1/sub2/ and path is
+ *
+ * foo -> sub1/sub2/foo (full prefix)
+ * ../foo -> sub1/foo (remaining prefix is sub1/)
+ * ../../bar -> bar (no remaining prefix)
+ * ../../sub1/sub2/foo -> sub1/sub2/foo (but no remaining prefix)
+ * `pwd`/../bar -> sub1/bar (no remaining prefix)
+ */
+char *prefix_path_gently(const char *prefix, int len,
+ int *remaining_prefix, const char *path)
{
const char *orig = path;
char *sanitized;
@@ -13,13 +25,17 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)
const char *temp = real_path(path);
sanitized = xmalloc(len + strlen(temp) + 1);
strcpy(sanitized, temp);
+ if (remaining_prefix)
+ *remaining_prefix = 0;
} else {
sanitized = xmalloc(len + strlen(path) + 1);
if (len)
memcpy(sanitized, prefix, len);
strcpy(sanitized + len, path);
+ if (remaining_prefix)
+ *remaining_prefix = len;
}
- if (normalize_path_copy(sanitized, sanitized))
+ if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix))
goto error_out;
if (is_absolute_path(orig)) {
size_t root_len, len, total;
@@ -44,7 +60,7 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)
char *prefix_path(const char *prefix, int len, const char *path)
{
- char *r = prefix_path_gently(prefix, len, path);
+ char *r = prefix_path_gently(prefix, len, NULL, path);
if (!r)
die("'%s' is outside repository", path);
return r;
@@ -53,7 +69,7 @@ char *prefix_path(const char *prefix, int len, const char *path)
int path_inside_repo(const char *prefix, const char *path)
{
int len = prefix ? strlen(prefix) : 0;
- char *r = prefix_path_gently(prefix, len, path);
+ char *r = prefix_path_gently(prefix, len, NULL, path);
if (r) {
free(r);
return 1;
@@ -154,155 +170,6 @@ void verify_non_filename(const char *prefix, const char *arg)
"'git <command> [<revision>...] -- [<file>...]'", arg);
}
-/*
- * Magic pathspec
- *
- * NEEDSWORK: These need to be moved to dir.h or even to a new
- * pathspec.h when we restructure get_pathspec() users to use the
- * "struct pathspec" interface.
- *
- * Possible future magic semantics include stuff like:
- *
- * { PATHSPEC_NOGLOB, '!', "noglob" },
- * { PATHSPEC_ICASE, '\0', "icase" },
- * { PATHSPEC_RECURSIVE, '*', "recursive" },
- * { PATHSPEC_REGEXP, '\0', "regexp" },
- *
- */
-#define PATHSPEC_FROMTOP (1<<0)
-
-static struct pathspec_magic {
- unsigned bit;
- char mnemonic; /* this cannot be ':'! */
- const char *name;
-} pathspec_magic[] = {
- { PATHSPEC_FROMTOP, '/', "top" },
-};
-
-/*
- * Take an element of a pathspec and check for magic signatures.
- * Append the result to the prefix.
- *
- * For now, we only parse the syntax and throw out anything other than
- * "top" magic.
- *
- * NEEDSWORK: This needs to be rewritten when we start migrating
- * get_pathspec() users to use the "struct pathspec" interface. For
- * example, a pathspec element may be marked as case-insensitive, but
- * the prefix part must always match literally, and a single stupid
- * string cannot express such a case.
- */
-static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)
-{
- unsigned magic = 0;
- const char *copyfrom = elt;
- int i;
-
- if (elt[0] != ':') {
- ; /* nothing to do */
- } else if (elt[1] == '(') {
- /* longhand */
- const char *nextat;
- for (copyfrom = elt + 2;
- *copyfrom && *copyfrom != ')';
- copyfrom = nextat) {
- size_t len = strcspn(copyfrom, ",)");
- if (copyfrom[len] == ',')
- nextat = copyfrom + len + 1;
- else
- /* handle ')' and '\0' */
- nextat = copyfrom + len;
- if (!len)
- continue;
- for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
- if (strlen(pathspec_magic[i].name) == len &&
- !strncmp(pathspec_magic[i].name, copyfrom, len)) {
- magic |= pathspec_magic[i].bit;
- break;
- }
- if (ARRAY_SIZE(pathspec_magic) <= i)
- die("Invalid pathspec magic '%.*s' in '%s'",
- (int) len, copyfrom, elt);
- }
- if (*copyfrom != ')')
- die("Missing ')' at the end of pathspec magic in '%s'", elt);
- copyfrom++;
- } else {
- /* shorthand */
- for (copyfrom = elt + 1;
- *copyfrom && *copyfrom != ':';
- copyfrom++) {
- char ch = *copyfrom;
-
- if (!is_pathspec_magic(ch))
- break;
- for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
- if (pathspec_magic[i].mnemonic == ch) {
- magic |= pathspec_magic[i].bit;
- break;
- }
- if (ARRAY_SIZE(pathspec_magic) <= i)
- die("Unimplemented pathspec magic '%c' in '%s'",
- ch, elt);
- }
- if (*copyfrom == ':')
- copyfrom++;
- }
-
- if (magic & PATHSPEC_FROMTOP)
- return xstrdup(copyfrom);
- else
- return prefix_path(prefix, prefixlen, copyfrom);
-}
-
-/*
- * N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
- * based interface - see pathspec_magic above.
- *
- * Arguments:
- * - prefix - a path relative to the root of the working tree
- * - pathspec - a list of paths underneath the prefix path
- *
- * Iterates over pathspec, prepending each path with prefix,
- * and return the resulting list.
- *
- * If pathspec is empty, return a singleton list containing prefix.
- *
- * If pathspec and prefix are both empty, return an empty list.
- *
- * This is typically used by built-in commands such as add.c, in order
- * to normalize argv arguments provided to the built-in into a list of
- * paths to process, all relative to the root of the working tree.
- */
-const char **get_pathspec(const char *prefix, const char **pathspec)
-{
- const char *entry = *pathspec;
- const char **src, **dst;
- int prefixlen;
-
- if (!prefix && !entry)
- return NULL;
-
- if (!entry) {
- static const char *spec[2];
- spec[0] = prefix;
- spec[1] = NULL;
- return spec;
- }
-
- /* Otherwise we have to re-write the entries.. */
- src = pathspec;
- dst = pathspec;
- prefixlen = prefix ? strlen(prefix) : 0;
- while (*src) {
- *(dst++) = prefix_pathspec(prefix, prefixlen, *src);
- src++;
- }
- *dst = NULL;
- if (!*pathspec)
- return NULL;
- return pathspec;
-}
/*
* Test if it looks like we're at a git directory.
@@ -360,6 +227,7 @@ int is_inside_work_tree(void)
void setup_work_tree(void)
{
+ struct strbuf sb = STRBUF_INIT;
const char *work_tree, *git_dir;
static int initialized = 0;
@@ -379,8 +247,10 @@ void setup_work_tree(void)
if (getenv(GIT_WORK_TREE_ENVIRONMENT))
setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
- set_git_dir(relative_path(git_dir, work_tree));
+ set_git_dir(relative_path(git_dir, work_tree, &sb));
initialized = 1;
+
+ strbuf_release(&sb);
}
static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
@@ -908,3 +778,15 @@ const char *resolve_gitdir(const char *suspect)
return suspect;
return read_gitfile(suspect);
}
+
+/* if any standard file descriptor is missing open it to /dev/null */
+void sanitize_stdfds(void)
+{
+ int fd = open("/dev/null", O_RDWR, 0);
+ while (fd != -1 && fd < 2)
+ fd = dup(fd);
+ if (fd == -1)
+ die_errno("open /dev/null or dup failed");
+ if (fd > 2)
+ close(fd);
+}
diff --git a/sha1_file.c b/sha1_file.c
index 40b2329..8c2d1ed 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -21,6 +21,7 @@
#include "sha1-lookup.h"
#include "bulk-checkin.h"
#include "streaming.h"
+#include "dir.h"
#ifndef O_NOATIME
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -35,6 +36,9 @@ static inline uintmax_t sz_fmt(size_t s) { return s; }
const unsigned char null_sha1[20];
+static const char *no_log_pack_access = "no_log_pack_access";
+static const char *log_pack_access;
+
/*
* This is meant to hold a *small* number of objects that you would
* want read_sha1_file() to be able to return, but yet you do not want
@@ -123,8 +127,13 @@ int safe_create_leading_directories(char *path)
}
}
else if (mkdir(path, 0777)) {
- *pos = '/';
- return -1;
+ if (errno == EEXIST &&
+ !stat(path, &st) && S_ISDIR(st.st_mode)) {
+ ; /* somebody created it since we checked */
+ } else {
+ *pos = '/';
+ return -1;
+ }
}
else if (adjust_shared_perm(path)) {
*pos = '/';
@@ -605,7 +614,7 @@ static void scan_windows(struct packed_git *p,
}
}
-static int unuse_one_window(struct packed_git *current, int keep_fd)
+static int unuse_one_window(struct packed_git *current)
{
struct packed_git *p, *lru_p = NULL;
struct pack_window *lru_w = NULL, *lru_l = NULL;
@@ -619,15 +628,8 @@ static int unuse_one_window(struct packed_git *current, int keep_fd)
pack_mapped -= lru_w->len;
if (lru_l)
lru_l->next = lru_w->next;
- else {
+ else
lru_p->windows = lru_w->next;
- if (!lru_p->windows && lru_p->pack_fd != -1
- && lru_p->pack_fd != keep_fd) {
- close(lru_p->pack_fd);
- pack_open_fds--;
- lru_p->pack_fd = -1;
- }
- }
free(lru_w);
pack_open_windows--;
return 1;
@@ -635,10 +637,10 @@ static int unuse_one_window(struct packed_git *current, int keep_fd)
return 0;
}
-void release_pack_memory(size_t need, int fd)
+void release_pack_memory(size_t need)
{
size_t cur = pack_mapped;
- while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd))
+ while (need >= (cur - pack_mapped) && unuse_one_window(NULL))
; /* nothing */
}
@@ -649,7 +651,7 @@ void *xmmap(void *start, size_t length,
if (ret == MAP_FAILED) {
if (!length)
return NULL;
- release_pack_memory(length, fd);
+ release_pack_memory(length);
ret = mmap(start, length, prot, flags, fd, offset);
if (ret == MAP_FAILED)
die_errno("Out of memory? mmap failed");
@@ -673,6 +675,83 @@ void close_pack_windows(struct packed_git *p)
}
}
+/*
+ * The LRU pack is the one with the oldest MRU window, preferring packs
+ * with no used windows, or the oldest mtime if it has no windows allocated.
+ */
+static void find_lru_pack(struct packed_git *p, struct packed_git **lru_p, struct pack_window **mru_w, int *accept_windows_inuse)
+{
+ struct pack_window *w, *this_mru_w;
+ int has_windows_inuse = 0;
+
+ /*
+ * Reject this pack if it has windows and the previously selected
+ * one does not. If this pack does not have windows, reject
+ * it if the pack file is newer than the previously selected one.
+ */
+ if (*lru_p && !*mru_w && (p->windows || p->mtime > (*lru_p)->mtime))
+ return;
+
+ for (w = this_mru_w = p->windows; w; w = w->next) {
+ /*
+ * Reject this pack if any of its windows are in use,
+ * but the previously selected pack did not have any
+ * inuse windows. Otherwise, record that this pack
+ * has windows in use.
+ */
+ if (w->inuse_cnt) {
+ if (*accept_windows_inuse)
+ has_windows_inuse = 1;
+ else
+ return;
+ }
+
+ if (w->last_used > this_mru_w->last_used)
+ this_mru_w = w;
+
+ /*
+ * Reject this pack if it has windows that have been
+ * used more recently than the previously selected pack.
+ * If the previously selected pack had windows inuse and
+ * we have not encountered a window in this pack that is
+ * inuse, skip this check since we prefer a pack with no
+ * inuse windows to one that has inuse windows.
+ */
+ if (*mru_w && *accept_windows_inuse == has_windows_inuse &&
+ this_mru_w->last_used > (*mru_w)->last_used)
+ return;
+ }
+
+ /*
+ * Select this pack.
+ */
+ *mru_w = this_mru_w;
+ *lru_p = p;
+ *accept_windows_inuse = has_windows_inuse;
+}
+
+static int close_one_pack(void)
+{
+ struct packed_git *p, *lru_p = NULL;
+ struct pack_window *mru_w = NULL;
+ int accept_windows_inuse = 1;
+
+ for (p = packed_git; p; p = p->next) {
+ if (p->pack_fd == -1)
+ continue;
+ find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse);
+ }
+
+ if (lru_p) {
+ close(lru_p->pack_fd);
+ pack_open_fds--;
+ lru_p->pack_fd = -1;
+ return 1;
+ }
+
+ return 0;
+}
+
void unuse_pack(struct pack_window **w_cursor)
{
struct pack_window *w = *w_cursor;
@@ -768,7 +847,7 @@ static int open_packed_git_1(struct packed_git *p)
pack_max_fds = 1;
}
- while (pack_max_fds <= pack_open_fds && unuse_one_window(NULL, -1))
+ while (pack_max_fds <= pack_open_fds && close_one_pack())
; /* nothing */
p->pack_fd = git_open_noatime(p->pack_name);
@@ -884,7 +963,7 @@ unsigned char *use_pack(struct packed_git *p,
win->len = (size_t)len;
pack_mapped += win->len;
while (packed_git_limit < pack_mapped
- && unuse_one_window(p, p->pack_fd))
+ && unuse_one_window(p))
; /* nothing */
win->base = xmmap(NULL, win->len,
PROT_READ, MAP_PRIVATE,
@@ -930,7 +1009,7 @@ static struct packed_git *alloc_packed_git(int extra)
static void try_to_free_pack_memory(size_t size)
{
- release_pack_memory(size, -1);
+ release_pack_memory(size);
}
struct packed_git *add_packed_git(const char *path, int path_len, int local)
@@ -1000,6 +1079,63 @@ void install_packed_git(struct packed_git *pack)
packed_git = pack;
}
+void (*report_garbage)(const char *desc, const char *path);
+
+static void report_helper(const struct string_list *list,
+ int seen_bits, int first, int last)
+{
+ const char *msg;
+ switch (seen_bits) {
+ case 0:
+ msg = "no corresponding .idx nor .pack";
+ break;
+ case 1:
+ msg = "no corresponding .idx";
+ break;
+ case 2:
+ msg = "no corresponding .pack";
+ break;
+ default:
+ return;
+ }
+ for (; first < last; first++)
+ report_garbage(msg, list->items[first].string);
+}
+
+static void report_pack_garbage(struct string_list *list)
+{
+ int i, baselen = -1, first = 0, seen_bits = 0;
+
+ if (!report_garbage)
+ return;
+
+ sort_string_list(list);
+
+ for (i = 0; i < list->nr; i++) {
+ const char *path = list->items[i].string;
+ if (baselen != -1 &&
+ strncmp(path, list->items[first].string, baselen)) {
+ report_helper(list, seen_bits, first, i);
+ baselen = -1;
+ seen_bits = 0;
+ }
+ if (baselen == -1) {
+ const char *dot = strrchr(path, '.');
+ if (!dot) {
+ report_garbage("garbage found", path);
+ continue;
+ }
+ baselen = dot - path + 1;
+ first = i;
+ }
+ if (!strcmp(path + baselen, "pack"))
+ seen_bits |= 1;
+ else if (!strcmp(path + baselen, "idx"))
+ seen_bits |= 2;
+ }
+ report_helper(list, seen_bits, first, list->nr);
+}
+
static void prepare_packed_git_one(char *objdir, int local)
{
/* Ensure that this buffer is large enough so that we can
@@ -1009,6 +1145,7 @@ static void prepare_packed_git_one(char *objdir, int local)
int len;
DIR *dir;
struct dirent *de;
+ struct string_list garbage = STRING_LIST_INIT_DUP;
sprintf(path, "%s/pack", objdir);
len = strlen(path);
@@ -1024,29 +1161,49 @@ static void prepare_packed_git_one(char *objdir, int local)
int namelen = strlen(de->d_name);
struct packed_git *p;
- if (!has_extension(de->d_name, ".idx"))
+ if (len + namelen + 1 > sizeof(path)) {
+ if (report_garbage) {
+ struct strbuf sb = STRBUF_INIT;
+ strbuf_addf(&sb, "%.*s/%s", len - 1, path, de->d_name);
+ report_garbage("path too long", sb.buf);
+ strbuf_release(&sb);
+ }
continue;
+ }
- if (len + namelen + 1 > sizeof(path))
+ if (is_dot_or_dotdot(de->d_name))
continue;
- /* Don't reopen a pack we already have. */
strcpy(path + len, de->d_name);
- for (p = packed_git; p; p = p->next) {
- if (!memcmp(path, p->pack_name, len + namelen - 4))
- break;
+
+ if (has_extension(de->d_name, ".idx")) {
+ /* Don't reopen a pack we already have. */
+ for (p = packed_git; p; p = p->next) {
+ if (!memcmp(path, p->pack_name, len + namelen - 4))
+ break;
+ }
+ if (p == NULL &&
+ /*
+ * See if it really is a valid .idx file with
+ * corresponding .pack file that we can map.
+ */
+ (p = add_packed_git(path, len + namelen, local)) != NULL)
+ install_packed_git(p);
}
- if (p)
- continue;
- /* See if it really is a valid .idx file with corresponding
- * .pack file that we can map.
- */
- p = add_packed_git(path, len + namelen, local);
- if (!p)
+
+ if (!report_garbage)
continue;
- install_packed_git(p);
+
+ if (has_extension(de->d_name, ".idx") ||
+ has_extension(de->d_name, ".pack") ||
+ has_extension(de->d_name, ".keep"))
+ string_list_append(&garbage, path);
+ else
+ report_garbage("garbage found", path);
}
closedir(dir);
+ report_pack_garbage(&garbage);
+ string_list_clear(&garbage, 0);
}
static int sort_pack(const void *a_, const void *b_)
@@ -1187,6 +1344,10 @@ int check_sha1_signature(const unsigned char *sha1, void *map,
char buf[1024 * 16];
ssize_t readlen = read_istream(st, buf, sizeof(buf));
+ if (readlen < 0) {
+ close_istream(st);
+ return -1;
+ }
if (!readlen)
break;
git_SHA1_Update(&c, buf, readlen);
@@ -1215,6 +1376,26 @@ static int git_open_noatime(const char *name)
}
}
+static int stat_sha1_file(const unsigned char *sha1, struct stat *st)
+{
+ char *name = sha1_file_name(sha1);
+ struct alternate_object_database *alt;
+
+ if (!lstat(name, st))
+ return 0;
+
+ prepare_alt_odb();
+ errno = ENOENT;
+ for (alt = alt_odb_list; alt; alt = alt->next) {
+ name = alt->name;
+ fill_sha1_path(name, sha1);
+ if (!lstat(alt->base, st))
+ return 0;
+ }
+
+ return -1;
+}
+
static int open_sha1_file(const unsigned char *sha1)
{
int fd;
@@ -1560,50 +1741,6 @@ static off_t get_delta_base(struct packed_git *p,
return base_offset;
}
-/* forward declaration for a mutually recursive function */
-static int packed_object_info(struct packed_git *p, off_t offset,
- unsigned long *sizep, int *rtype);
-
-static int packed_delta_info(struct packed_git *p,
- struct pack_window **w_curs,
- off_t curpos,
- enum object_type type,
- off_t obj_offset,
- unsigned long *sizep)
-{
- off_t base_offset;
-
- base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset);
- if (!base_offset)
- return OBJ_BAD;
- type = packed_object_info(p, base_offset, NULL, NULL);
- if (type <= OBJ_NONE) {
- struct revindex_entry *revidx;
- const unsigned char *base_sha1;
- revidx = find_pack_revindex(p, base_offset);
- if (!revidx)
- return OBJ_BAD;
- base_sha1 = nth_packed_object_sha1(p, revidx->nr);
- mark_bad_packed_object(p, base_sha1);
- type = sha1_object_info(base_sha1, NULL);
- if (type <= OBJ_NONE)
- return OBJ_BAD;
- }
-
- /* We choose to only get the type of the base object and
- * ignore potentially corrupt pack file that expects the delta
- * based on a base with a wrong size. This saves tons of
- * inflate() calls.
- */
- if (sizep) {
- *sizep = get_size_from_delta(p, w_curs, curpos);
- if (*sizep == 0)
- type = OBJ_BAD;
- }
-
- return type;
-}
-
int unpack_object_header(struct packed_git *p,
struct pack_window **w_curs,
off_t *curpos,
@@ -1630,36 +1767,138 @@ int unpack_object_header(struct packed_git *p,
return type;
}
-static int packed_object_info(struct packed_git *p, off_t obj_offset,
- unsigned long *sizep, int *rtype)
+static int retry_bad_packed_offset(struct packed_git *p, off_t obj_offset)
{
- struct pack_window *w_curs = NULL;
- unsigned long size;
- off_t curpos = obj_offset;
- enum object_type type;
+ int type;
+ struct revindex_entry *revidx;
+ const unsigned char *sha1;
+ revidx = find_pack_revindex(p, obj_offset);
+ if (!revidx)
+ return OBJ_BAD;
+ sha1 = nth_packed_object_sha1(p, revidx->nr);
+ mark_bad_packed_object(p, sha1);
+ type = sha1_object_info(sha1, NULL);
+ if (type <= OBJ_NONE)
+ return OBJ_BAD;
+ return type;
+}
- type = unpack_object_header(p, &w_curs, &curpos, &size);
- if (rtype)
- *rtype = type; /* representation type */
+#define POI_STACK_PREALLOC 64
+
+static enum object_type packed_to_object_type(struct packed_git *p,
+ off_t obj_offset,
+ enum object_type type,
+ struct pack_window **w_curs,
+ off_t curpos)
+{
+ off_t small_poi_stack[POI_STACK_PREALLOC];
+ off_t *poi_stack = small_poi_stack;
+ int poi_stack_nr = 0, poi_stack_alloc = POI_STACK_PREALLOC;
+
+ while (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+ off_t base_offset;
+ unsigned long size;
+ /* Push the object we're going to leave behind */
+ if (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) {
+ poi_stack_alloc = alloc_nr(poi_stack_nr);
+ poi_stack = xmalloc(sizeof(off_t)*poi_stack_alloc);
+ memcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr);
+ } else {
+ ALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc);
+ }
+ poi_stack[poi_stack_nr++] = obj_offset;
+ /* If parsing the base offset fails, just unwind */
+ base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset);
+ if (!base_offset)
+ goto unwind;
+ curpos = obj_offset = base_offset;
+ type = unpack_object_header(p, w_curs, &curpos, &size);
+ if (type <= OBJ_NONE) {
+ /* If getting the base itself fails, we first
+ * retry the base, otherwise unwind */
+ type = retry_bad_packed_offset(p, base_offset);
+ if (type > OBJ_NONE)
+ goto out;
+ goto unwind;
+ }
+ }
switch (type) {
- case OBJ_OFS_DELTA:
- case OBJ_REF_DELTA:
- type = packed_delta_info(p, &w_curs, curpos,
- type, obj_offset, sizep);
- break;
+ case OBJ_BAD:
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
case OBJ_TAG:
- if (sizep)
- *sizep = size;
break;
default:
error("unknown object type %i at offset %"PRIuMAX" in %s",
type, (uintmax_t)obj_offset, p->pack_name);
type = OBJ_BAD;
}
+
+out:
+ if (poi_stack != small_poi_stack)
+ free(poi_stack);
+ return type;
+
+unwind:
+ while (poi_stack_nr) {
+ obj_offset = poi_stack[--poi_stack_nr];
+ type = retry_bad_packed_offset(p, obj_offset);
+ if (type > OBJ_NONE)
+ goto out;
+ }
+ type = OBJ_BAD;
+ goto out;
+}
+
+static int packed_object_info(struct packed_git *p, off_t obj_offset,
+ struct object_info *oi)
+{
+ struct pack_window *w_curs = NULL;
+ unsigned long size;
+ off_t curpos = obj_offset;
+ enum object_type type;
+
+ /*
+ * We always get the representation type, but only convert it to
+ * a "real" type later if the caller is interested.
+ */
+ type = unpack_object_header(p, &w_curs, &curpos, &size);
+
+ if (oi->sizep) {
+ if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+ off_t tmp_pos = curpos;
+ off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
+ type, obj_offset);
+ if (!base_offset) {
+ type = OBJ_BAD;
+ goto out;
+ }
+ *oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
+ if (*oi->sizep == 0) {
+ type = OBJ_BAD;
+ goto out;
+ }
+ } else {
+ *oi->sizep = size;
+ }
+ }
+
+ if (oi->disk_sizep) {
+ struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
+ *oi->disk_sizep = revidx[1].offset - obj_offset;
+ }
+
+ if (oi->typep) {
+ *oi->typep = packed_to_object_type(p, obj_offset, type, &w_curs, curpos);
+ if (*oi->typep < 0) {
+ type = OBJ_BAD;
+ goto out;
+ }
+ }
+
+out:
unuse_pack(&w_curs);
return type;
}
@@ -1723,32 +1962,51 @@ static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset)
return hash % MAX_DELTA_CACHE;
}
-static int in_delta_base_cache(struct packed_git *p, off_t base_offset)
+static struct delta_base_cache_entry *
+get_delta_base_cache_entry(struct packed_git *p, off_t base_offset)
{
unsigned long hash = pack_entry_hash(p, base_offset);
- struct delta_base_cache_entry *ent = delta_base_cache + hash;
+ return delta_base_cache + hash;
+}
+
+static int eq_delta_base_cache_entry(struct delta_base_cache_entry *ent,
+ struct packed_git *p, off_t base_offset)
+{
return (ent->data && ent->p == p && ent->base_offset == base_offset);
}
+static int in_delta_base_cache(struct packed_git *p, off_t base_offset)
+{
+ struct delta_base_cache_entry *ent;
+ ent = get_delta_base_cache_entry(p, base_offset);
+ return eq_delta_base_cache_entry(ent, p, base_offset);
+}
+
+static void clear_delta_base_cache_entry(struct delta_base_cache_entry *ent)
+{
+ ent->data = NULL;
+ ent->lru.next->prev = ent->lru.prev;
+ ent->lru.prev->next = ent->lru.next;
+ delta_base_cached -= ent->size;
+}
+
static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
unsigned long *base_size, enum object_type *type, int keep_cache)
{
+ struct delta_base_cache_entry *ent;
void *ret;
- unsigned long hash = pack_entry_hash(p, base_offset);
- struct delta_base_cache_entry *ent = delta_base_cache + hash;
- ret = ent->data;
- if (!ret || ent->p != p || ent->base_offset != base_offset)
+ ent = get_delta_base_cache_entry(p, base_offset);
+
+ if (!eq_delta_base_cache_entry(ent, p, base_offset))
return unpack_entry(p, base_offset, type, base_size);
- if (!keep_cache) {
- ent->data = NULL;
- ent->lru.next->prev = ent->lru.prev;
- ent->lru.prev->next = ent->lru.next;
- delta_base_cached -= ent->size;
- } else {
+ ret = ent->data;
+
+ if (!keep_cache)
+ clear_delta_base_cache_entry(ent);
+ else
ret = xmemdupz(ent->data, ent->size);
- }
*type = ent->type;
*base_size = ent->size;
return ret;
@@ -1812,78 +2070,23 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
static void *read_object(const unsigned char *sha1, enum object_type *type,
unsigned long *size);
-static void *unpack_delta_entry(struct packed_git *p,
- struct pack_window **w_curs,
- off_t curpos,
- unsigned long delta_size,
- off_t obj_offset,
- enum object_type *type,
- unsigned long *sizep)
-{
- void *delta_data, *result, *base;
- unsigned long base_size;
- off_t base_offset;
-
- base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset);
- if (!base_offset) {
- error("failed to validate delta base reference "
- "at offset %"PRIuMAX" from %s",
- (uintmax_t)curpos, p->pack_name);
- return NULL;
- }
- unuse_pack(w_curs);
- base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0);
- if (!base) {
- /*
- * We're probably in deep shit, but let's try to fetch
- * the required base anyway from another pack or loose.
- * This is costly but should happen only in the presence
- * of a corrupted pack, and is better than failing outright.
- */
- struct revindex_entry *revidx;
- const unsigned char *base_sha1;
- revidx = find_pack_revindex(p, base_offset);
- if (!revidx)
- return NULL;
- base_sha1 = nth_packed_object_sha1(p, revidx->nr);
- error("failed to read delta base object %s"
- " at offset %"PRIuMAX" from %s",
- sha1_to_hex(base_sha1), (uintmax_t)base_offset,
- p->pack_name);
- mark_bad_packed_object(p, base_sha1);
- base = read_object(base_sha1, type, &base_size);
- if (!base)
- return NULL;
- }
-
- delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size);
- if (!delta_data) {
- error("failed to unpack compressed delta "
- "at offset %"PRIuMAX" from %s",
- (uintmax_t)curpos, p->pack_name);
- free(base);
- return NULL;
- }
- result = patch_delta(base, base_size,
- delta_data, delta_size,
- sizep);
- if (!result)
- die("failed to apply delta");
- free(delta_data);
- add_delta_base_cache(p, base_offset, base, base_size, *type);
- return result;
-}
-
static void write_pack_access_log(struct packed_git *p, off_t obj_offset)
{
static FILE *log_file;
+ if (!log_pack_access)
+ log_pack_access = getenv("GIT_TRACE_PACK_ACCESS");
+ if (!log_pack_access)
+ log_pack_access = no_log_pack_access;
+ if (log_pack_access == no_log_pack_access)
+ return;
+
if (!log_file) {
log_file = fopen(log_pack_access, "w");
if (!log_file) {
error("cannot open pack access log '%s' for writing: %s",
log_pack_access, strerror(errno));
- log_pack_access = NULL;
+ log_pack_access = no_log_pack_access;
return;
}
}
@@ -1894,48 +2097,187 @@ static void write_pack_access_log(struct packed_git *p, off_t obj_offset)
int do_check_packed_object_crc;
+#define UNPACK_ENTRY_STACK_PREALLOC 64
+struct unpack_entry_stack_ent {
+ off_t obj_offset;
+ off_t curpos;
+ unsigned long size;
+};
+
void *unpack_entry(struct packed_git *p, off_t obj_offset,
- enum object_type *type, unsigned long *sizep)
+ enum object_type *final_type, unsigned long *final_size)
{
struct pack_window *w_curs = NULL;
off_t curpos = obj_offset;
- void *data;
+ void *data = NULL;
+ unsigned long size;
+ enum object_type type;
+ struct unpack_entry_stack_ent small_delta_stack[UNPACK_ENTRY_STACK_PREALLOC];
+ struct unpack_entry_stack_ent *delta_stack = small_delta_stack;
+ int delta_stack_nr = 0, delta_stack_alloc = UNPACK_ENTRY_STACK_PREALLOC;
+ int base_from_cache = 0;
- if (log_pack_access)
+ if (log_pack_access != no_log_pack_access)
write_pack_access_log(p, obj_offset);
- if (do_check_packed_object_crc && p->index_version > 1) {
- struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
- unsigned long len = revidx[1].offset - obj_offset;
- if (check_pack_crc(p, &w_curs, obj_offset, len, revidx->nr)) {
- const unsigned char *sha1 =
- nth_packed_object_sha1(p, revidx->nr);
- error("bad packed object CRC for %s",
- sha1_to_hex(sha1));
- mark_bad_packed_object(p, sha1);
- unuse_pack(&w_curs);
- return NULL;
+ /* PHASE 1: drill down to the innermost base object */
+ for (;;) {
+ off_t base_offset;
+ int i;
+ struct delta_base_cache_entry *ent;
+
+ if (do_check_packed_object_crc && p->index_version > 1) {
+ struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
+ unsigned long len = revidx[1].offset - obj_offset;
+ if (check_pack_crc(p, &w_curs, obj_offset, len, revidx->nr)) {
+ const unsigned char *sha1 =
+ nth_packed_object_sha1(p, revidx->nr);
+ error("bad packed object CRC for %s",
+ sha1_to_hex(sha1));
+ mark_bad_packed_object(p, sha1);
+ unuse_pack(&w_curs);
+ return NULL;
+ }
+ }
+
+ ent = get_delta_base_cache_entry(p, curpos);
+ if (eq_delta_base_cache_entry(ent, p, curpos)) {
+ type = ent->type;
+ data = ent->data;
+ size = ent->size;
+ clear_delta_base_cache_entry(ent);
+ base_from_cache = 1;
+ break;
+ }
+
+ type = unpack_object_header(p, &w_curs, &curpos, &size);
+ if (type != OBJ_OFS_DELTA && type != OBJ_REF_DELTA)
+ break;
+
+ base_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
+ if (!base_offset) {
+ error("failed to validate delta base reference "
+ "at offset %"PRIuMAX" from %s",
+ (uintmax_t)curpos, p->pack_name);
+ /* bail to phase 2, in hopes of recovery */
+ data = NULL;
+ break;
+ }
+
+ /* push object, proceed to base */
+ if (delta_stack_nr >= delta_stack_alloc
+ && delta_stack == small_delta_stack) {
+ delta_stack_alloc = alloc_nr(delta_stack_nr);
+ delta_stack = xmalloc(sizeof(*delta_stack)*delta_stack_alloc);
+ memcpy(delta_stack, small_delta_stack,
+ sizeof(*delta_stack)*delta_stack_nr);
+ } else {
+ ALLOC_GROW(delta_stack, delta_stack_nr+1, delta_stack_alloc);
}
+ i = delta_stack_nr++;
+ delta_stack[i].obj_offset = obj_offset;
+ delta_stack[i].curpos = curpos;
+ delta_stack[i].size = size;
+
+ curpos = obj_offset = base_offset;
}
- *type = unpack_object_header(p, &w_curs, &curpos, sizep);
- switch (*type) {
+ /* PHASE 2: handle the base */
+ switch (type) {
case OBJ_OFS_DELTA:
case OBJ_REF_DELTA:
- data = unpack_delta_entry(p, &w_curs, curpos, *sizep,
- obj_offset, type, sizep);
+ if (data)
+ die("BUG in unpack_entry: left loop at a valid delta");
break;
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
case OBJ_TAG:
- data = unpack_compressed_entry(p, &w_curs, curpos, *sizep);
+ if (!base_from_cache)
+ data = unpack_compressed_entry(p, &w_curs, curpos, size);
break;
default:
data = NULL;
error("unknown object type %i at offset %"PRIuMAX" in %s",
- *type, (uintmax_t)obj_offset, p->pack_name);
+ type, (uintmax_t)obj_offset, p->pack_name);
+ }
+
+ /* PHASE 3: apply deltas in order */
+
+ /* invariants:
+ * 'data' holds the base data, or NULL if there was corruption
+ */
+ while (delta_stack_nr) {
+ void *delta_data;
+ void *base = data;
+ unsigned long delta_size, base_size = size;
+ int i;
+
+ data = NULL;
+
+ if (base)
+ add_delta_base_cache(p, obj_offset, base, base_size, type);
+
+ if (!base) {
+ /*
+ * We're probably in deep shit, but let's try to fetch
+ * the required base anyway from another pack or loose.
+ * This is costly but should happen only in the presence
+ * of a corrupted pack, and is better than failing outright.
+ */
+ struct revindex_entry *revidx;
+ const unsigned char *base_sha1;
+ revidx = find_pack_revindex(p, obj_offset);
+ if (revidx) {
+ base_sha1 = nth_packed_object_sha1(p, revidx->nr);
+ error("failed to read delta base object %s"
+ " at offset %"PRIuMAX" from %s",
+ sha1_to_hex(base_sha1), (uintmax_t)obj_offset,
+ p->pack_name);
+ mark_bad_packed_object(p, base_sha1);
+ base = read_object(base_sha1, &type, &base_size);
+ }
+ }
+
+ i = --delta_stack_nr;
+ obj_offset = delta_stack[i].obj_offset;
+ curpos = delta_stack[i].curpos;
+ delta_size = delta_stack[i].size;
+
+ if (!base)
+ continue;
+
+ delta_data = unpack_compressed_entry(p, &w_curs, curpos, delta_size);
+
+ if (!delta_data) {
+ error("failed to unpack compressed delta "
+ "at offset %"PRIuMAX" from %s",
+ (uintmax_t)curpos, p->pack_name);
+ data = NULL;
+ continue;
+ }
+
+ data = patch_delta(base, base_size,
+ delta_data, delta_size,
+ &size);
+
+ /*
+ * We could not apply the delta; warn the user, but keep going.
+ * Our failure will be noticed either in the next iteration of
+ * the loop, or if this is the final delta, in the caller when
+ * we return NULL. Those code paths will take care of making
+ * a more explicit warning and retrying with another copy of
+ * the object.
+ */
+ if (!data)
+ error("failed to apply delta");
+
+ free(delta_data);
}
+
+ *final_type = type;
+ *final_size = size;
+
unuse_pack(&w_curs);
return data;
}
@@ -2130,7 +2472,8 @@ struct packed_git *find_sha1_pack(const unsigned char *sha1,
}
-static int sha1_loose_object_info(const unsigned char *sha1, unsigned long *sizep)
+static int sha1_loose_object_info(const unsigned char *sha1,
+ struct object_info *oi)
{
int status;
unsigned long mapsize, size;
@@ -2138,19 +2481,37 @@ static int sha1_loose_object_info(const unsigned char *sha1, unsigned long *size
git_zstream stream;
char hdr[32];
+ /*
+ * If we don't care about type or size, then we don't
+ * need to look inside the object at all.
+ */
+ if (!oi->typep && !oi->sizep) {
+ if (oi->disk_sizep) {
+ struct stat st;
+ if (stat_sha1_file(sha1, &st) < 0)
+ return -1;
+ *oi->disk_sizep = st.st_size;
+ }
+ return 0;
+ }
+
map = map_sha1_file(sha1, &mapsize);
if (!map)
- return error("unable to find %s", sha1_to_hex(sha1));
+ return -1;
+ if (oi->disk_sizep)
+ *oi->disk_sizep = mapsize;
if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
status = error("unable to unpack %s header",
sha1_to_hex(sha1));
else if ((status = parse_sha1_header(hdr, &size)) < 0)
status = error("unable to parse %s header", sha1_to_hex(sha1));
- else if (sizep)
- *sizep = size;
+ else if (oi->sizep)
+ *oi->sizep = size;
git_inflate_end(&stream);
munmap(map, mapsize);
- return status;
+ if (oi->typep)
+ *oi->typep = status;
+ return 0;
}
/* returns enum object_type or negative */
@@ -2158,34 +2519,37 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
{
struct cached_object *co;
struct pack_entry e;
- int status, rtype;
+ int rtype;
co = find_cached_object(sha1);
if (co) {
+ if (oi->typep)
+ *(oi->typep) = co->type;
if (oi->sizep)
*(oi->sizep) = co->size;
+ if (oi->disk_sizep)
+ *(oi->disk_sizep) = 0;
oi->whence = OI_CACHED;
- return co->type;
+ return 0;
}
if (!find_pack_entry(sha1, &e)) {
/* Most likely it's a loose object. */
- status = sha1_loose_object_info(sha1, oi->sizep);
- if (status >= 0) {
+ if (!sha1_loose_object_info(sha1, oi)) {
oi->whence = OI_LOOSE;
- return status;
+ return 0;
}
/* Not a loose object; someone else may have just packed it. */
reprepare_packed_git();
if (!find_pack_entry(sha1, &e))
- return status;
+ return -1;
}
- status = packed_object_info(e.p, e.offset, oi->sizep, &rtype);
- if (status < 0) {
+ rtype = packed_object_info(e.p, e.offset, oi);
+ if (rtype < 0) {
mark_bad_packed_object(e.p, sha1);
- status = sha1_object_info_extended(sha1, oi);
+ return sha1_object_info_extended(sha1, oi);
} else if (in_delta_base_cache(e.p, e.offset)) {
oi->whence = OI_DBCACHED;
} else {
@@ -2196,15 +2560,19 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
rtype == OBJ_OFS_DELTA);
}
- return status;
+ return 0;
}
int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
{
- struct object_info oi;
+ enum object_type type;
+ struct object_info oi = {NULL};
+ oi.typep = &type;
oi.sizep = sizep;
- return sha1_object_info_extended(sha1, &oi);
+ if (sha1_object_info_extended(sha1, &oi) < 0)
+ return -1;
+ return type;
}
static void *read_packed_sha1(const unsigned char *sha1,
diff --git a/sha1_name.c b/sha1_name.c
index c50630a..65ad066 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -52,7 +52,7 @@ static void update_candidates(struct disambiguate_state *ds, const unsigned char
}
if (!ds->candidate_ok) {
- /* discard the candidate; we know it does not satisify fn */
+ /* discard the candidate; we know it does not satisfy fn */
hashcpy(ds->candidate, current);
ds->candidate_checked = 0;
return;
@@ -241,7 +241,7 @@ static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data
return 0;
/* We need to do this the hard way... */
- obj = deref_tag(lookup_object(sha1), NULL, 0);
+ obj = deref_tag(parse_object(sha1), NULL, 0);
if (obj && obj->type == OBJ_COMMIT)
return 1;
return 0;
@@ -431,22 +431,51 @@ static inline int upstream_mark(const char *string, int len)
}
static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
+static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf);
static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
{
static const char *warn_msg = "refname '%.*s' is ambiguous.";
+ static const char *object_name_msg = N_(
+ "Git normally never creates a ref that ends with 40 hex characters\n"
+ "because it will be ignored when you just specify 40-hex. These refs\n"
+ "may be created by mistake. For example,\n"
+ "\n"
+ " git checkout -b $br $(git rev-parse ...)\n"
+ "\n"
+ "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
+ "examine these refs and maybe delete them. Turn this message off by\n"
+ "running \"git config advice.objectNameWarning false\"");
+ unsigned char tmp_sha1[20];
char *real_ref = NULL;
int refs_found = 0;
- int at, reflog_len;
-
- if (len == 40 && !get_sha1_hex(str, sha1))
+ int at, reflog_len, nth_prior = 0;
+
+ if (len == 40 && !get_sha1_hex(str, sha1)) {
+ if (warn_on_object_refname_ambiguity) {
+ refs_found = dwim_ref(str, len, tmp_sha1, &real_ref);
+ if (refs_found > 0 && warn_ambiguous_refs) {
+ warning(warn_msg, len, str);
+ if (advice_object_name_warning)
+ fprintf(stderr, "%s\n", _(object_name_msg));
+ }
+ free(real_ref);
+ }
return 0;
+ }
/* basic@{time or number or -number} format to query ref-log */
reflog_len = at = 0;
if (len && str[len-1] == '}') {
- for (at = len-2; at >= 0; at--) {
+ for (at = len-4; at >= 0; at--) {
if (str[at] == '@' && str[at+1] == '{') {
+ if (str[at+2] == '-') {
+ if (at != 0)
+ /* @{-N} not at start */
+ return -1;
+ nth_prior = 1;
+ continue;
+ }
if (!upstream_mark(str + at, len - at)) {
reflog_len = (len-1) - (at+2);
len = at;
@@ -460,20 +489,22 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
if (len && ambiguous_path(str, len))
return -1;
- if (!len && reflog_len) {
+ if (nth_prior) {
struct strbuf buf = STRBUF_INIT;
- int ret;
- /* try the @{-N} syntax for n-th checkout */
- 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, 0);
- } else if (ret == 0) {
- return -1;
+ int detached;
+
+ if (interpret_nth_prior_checkout(str, &buf) > 0) {
+ detached = (buf.len == 40 && !get_sha1_hex(buf.buf, sha1));
+ strbuf_release(&buf);
+ if (detached)
+ return 0;
}
+ }
+
+ if (!len && reflog_len)
/* allow "@{...}" to mean the current branch reflog */
refs_found = dwim_ref("HEAD", 4, sha1, &real_ref);
- } else if (reflog_len)
+ else if (reflog_len)
refs_found = dwim_log(str, len, sha1, &real_ref);
else
refs_found = dwim_ref(str, len, sha1, &real_ref);
@@ -481,7 +512,9 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
if (!refs_found)
return -1;
- if (warn_ambiguous_refs && refs_found > 1)
+ if (warn_ambiguous_refs &&
+ (refs_found > 1 ||
+ !get_short_sha1(str, len, tmp_sha1, GET_SHA1_QUIETLY)))
warning(warn_msg, len, str);
if (reflog_len) {
@@ -490,10 +523,6 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
unsigned long co_time;
int co_tz, co_cnt;
- /* a @{-N} placed anywhere except the start is an error */
- if (str[at+2] == '-')
- return -1;
-
/* Is it asking for N-th entry, or approxidate? */
for (i = nth = 0; 0 <= nth && i < reflog_len; i++) {
char ch = str[at+2+i];
@@ -517,12 +546,21 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
}
if (read_ref_at(real_ref, at_time, nth, sha1, NULL,
&co_time, &co_tz, &co_cnt)) {
+ if (!len) {
+ if (!prefixcmp(real_ref, "refs/heads/")) {
+ str = real_ref + 11;
+ len = strlen(real_ref + 11);
+ } else {
+ /* detached HEAD */
+ str = "HEAD";
+ len = 4;
+ }
+ }
if (at_time)
warning("Log for '%.*s' only goes "
"back to %s.", len, str,
show_date(co_time, co_tz, DATE_RFC2822));
else {
- free(real_ref);
die("Log for '%.*s' only has %d entries.",
len, str, co_cnt);
}
@@ -594,7 +632,7 @@ struct object *peel_to_type(const char *name, int namelen,
while (1) {
if (!o || (!o->parsed && !parse_object(o->sha1)))
return NULL;
- if (o->type == expected_type)
+ if (expected_type == OBJ_ANY || o->type == expected_type)
return o;
if (o->type == OBJ_TAG)
o = ((struct tag*) o)->tagged;
@@ -645,6 +683,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
expected_type = OBJ_TREE;
else if (!strncmp(blob_type, sp, 4) && sp[4] == '}')
expected_type = OBJ_BLOB;
+ else if (!prefixcmp(sp, "object}"))
+ expected_type = OBJ_ANY;
else if (sp[0] == '}')
expected_type = OBJ_NONE;
else if (sp[0] == '/')
@@ -654,6 +694,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
if (expected_type == OBJ_COMMIT)
lookup_flags = GET_SHA1_COMMITTISH;
+ else if (expected_type == OBJ_TREE)
+ lookup_flags = GET_SHA1_TREEISH;
if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
return -1;
@@ -856,8 +898,8 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
}
struct grab_nth_branch_switch_cbdata {
- long cnt, alloc;
- struct strbuf *buf;
+ int remaining;
+ struct strbuf buf;
};
static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
@@ -867,7 +909,6 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
struct grab_nth_branch_switch_cbdata *cb = cb_data;
const char *match = NULL, *target = NULL;
size_t len;
- int nth;
if (!prefixcmp(message, "checkout: moving from ")) {
match = message + strlen("checkout: moving from ");
@@ -876,11 +917,12 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
if (!match || !target)
return 0;
-
- len = target - match;
- nth = cb->cnt++ % cb->alloc;
- strbuf_reset(&cb->buf[nth]);
- strbuf_add(&cb->buf[nth], match, len);
+ if (--(cb->remaining) == 0) {
+ len = target - match;
+ strbuf_reset(&cb->buf);
+ strbuf_add(&cb->buf, match, len);
+ return 1; /* we are done */
+ }
return 0;
}
@@ -891,7 +933,7 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf)
{
long nth;
- int i, retval;
+ int retval;
struct grab_nth_branch_switch_cbdata cb;
const char *brace;
char *num_end;
@@ -901,34 +943,22 @@ static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf)
brace = strchr(name, '}');
if (!brace)
return -1;
- nth = strtol(name+3, &num_end, 10);
+ nth = strtol(name + 3, &num_end, 10);
if (num_end != brace)
return -1;
if (nth <= 0)
return -1;
- cb.alloc = nth;
- cb.buf = xmalloc(nth * sizeof(struct strbuf));
- for (i = 0; i < nth; i++)
- strbuf_init(&cb.buf[i], 20);
- cb.cnt = 0;
+ cb.remaining = nth;
+ strbuf_init(&cb.buf, 20);
+
retval = 0;
- for_each_recent_reflog_ent("HEAD", grab_nth_branch_switch, 40960, &cb);
- if (cb.cnt < nth) {
- cb.cnt = 0;
- for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb);
+ if (0 < for_each_reflog_ent_reverse("HEAD", grab_nth_branch_switch, &cb)) {
+ strbuf_reset(buf);
+ strbuf_add(buf, cb.buf.buf, cb.buf.len);
+ retval = brace - name + 1;
}
- if (cb.cnt < nth)
- goto release_return;
- i = cb.cnt % nth;
- strbuf_reset(buf);
- strbuf_add(buf, cb.buf[i].buf, cb.buf[i].len);
- retval = brace-name+1;
-
-release_return:
- for (i = 0; i < nth; i++)
- strbuf_release(&cb.buf[i]);
- free(cb.buf);
+ strbuf_release(&cb.buf);
return retval;
}
@@ -974,6 +1004,27 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
return st;
}
+static int reinterpret(const char *name, int namelen, int len, struct strbuf *buf)
+{
+ /* we have extra data, which might need further processing */
+ struct strbuf tmp = STRBUF_INIT;
+ int used = buf->len;
+ int ret;
+
+ strbuf_add(buf, name + len, namelen - len);
+ ret = interpret_branch_name(buf->buf, &tmp);
+ /* that data was not interpreted, remove our cruft */
+ if (ret < 0) {
+ strbuf_setlen(buf, used);
+ return len;
+ }
+ strbuf_reset(buf);
+ strbuf_addbuf(buf, &tmp);
+ strbuf_release(&tmp);
+ /* tweak for size of {-N} versus expanded ref name */
+ return ret - used + len;
+}
+
/*
* This reads short-hand syntax that not only evaluates to a commit
* object name, but also can act as if the end user spelled the name
@@ -1003,28 +1054,13 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
int len = interpret_nth_prior_checkout(name, buf);
int tmp_len;
- if (!len)
+ if (!len) {
return len; /* syntax Ok, not enough switches */
- if (0 < len && len == namelen)
- return len; /* consumed all */
- else if (0 < len) {
- /* we have extra data, which might need further processing */
- struct strbuf tmp = STRBUF_INIT;
- int used = buf->len;
- int ret;
-
- strbuf_add(buf, name + len, namelen - len);
- ret = interpret_branch_name(buf->buf, &tmp);
- /* that data was not interpreted, remove our cruft */
- if (ret < 0) {
- strbuf_setlen(buf, used);
- return len;
- }
- strbuf_reset(buf);
- strbuf_addbuf(buf, &tmp);
- strbuf_release(&tmp);
- /* tweak for size of {-N} versus expanded ref name */
- return ret - used + len;
+ } else if (len > 0) {
+ if (len == namelen)
+ return len; /* consumed all */
+ else
+ return reinterpret(name, namelen, len, buf);
}
cp = strchr(name, '@');
@@ -1041,14 +1077,15 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
* points to something different than a branch.
*/
if (!upstream)
- return error(_("HEAD does not point to a branch"));
+ die(_("HEAD does not point to a branch"));
if (!upstream->merge || !upstream->merge[0]->dst) {
if (!ref_exists(upstream->refname))
- return error(_("No such branch: '%s'"), cp);
- if (!upstream->merge)
- return error(_("No upstream configured for branch '%s'"),
- upstream->name);
- return error(
+ die(_("No such branch: '%s'"), cp);
+ if (!upstream->merge) {
+ die(_("No upstream configured for branch '%s'"),
+ upstream->name);
+ }
+ die(
_("Upstream branch '%s' not stored as a remote-tracking branch"),
upstream->merge[0]->src);
}
@@ -1063,9 +1100,13 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
int strbuf_branchname(struct strbuf *sb, const char *name)
{
int len = strlen(name);
- if (interpret_branch_name(name, sb) == len)
+ int used = interpret_branch_name(name, sb);
+
+ if (used == len)
return 0;
- strbuf_add(sb, name, len);
+ if (used < 0)
+ used = 0;
+ strbuf_add(sb, name + used, len - used);
return len;
}
@@ -1178,7 +1219,7 @@ static void diagnose_invalid_index_path(int stage,
const char *filename)
{
struct stat st;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
int pos;
unsigned namelen = strlen(filename);
unsigned fullnamelen;
@@ -1272,7 +1313,7 @@ static int get_sha1_with_context_1(const char *name,
*/
if (name[0] == ':') {
int stage = 0;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
char *new_path = NULL;
int pos;
if (!only_to_die && namelen > 2 && name[1] == '/') {
diff --git a/shallow.c b/shallow.c
index 6be915f..8a9c96d 100644
--- a/shallow.c
+++ b/shallow.c
@@ -3,6 +3,16 @@
#include "tag.h"
static int is_shallow = -1;
+static struct stat shallow_stat;
+static char *alternate_shallow_file;
+
+void set_alternate_shallow_file(const char *path)
+{
+ if (is_shallow != -1)
+ die("BUG: is_repository_shallow must not be called before set_alternate_shallow_file");
+ free(alternate_shallow_file);
+ alternate_shallow_file = path ? xstrdup(path) : NULL;
+}
int register_shallow(const unsigned char *sha1)
{
@@ -21,12 +31,21 @@ int is_repository_shallow(void)
{
FILE *fp;
char buf[1024];
+ const char *path = alternate_shallow_file;
if (is_shallow >= 0)
return is_shallow;
- fp = fopen(git_path("shallow"), "r");
- if (!fp) {
+ if (!path)
+ path = git_path("shallow");
+ /*
+ * fetch-pack sets '--shallow-file ""' as an indicator that no
+ * shallow file should be used. We could just open it and it
+ * will likely fail. But let's do an explicit check instead.
+ */
+ if (!*path ||
+ stat(path, &shallow_stat) ||
+ (fp = fopen(path, "r")) == NULL) {
is_shallow = 0;
return is_shallow;
}
@@ -91,20 +110,34 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
continue;
*pointer = cur_depth;
}
- if (cur_depth < depth) {
- if (p->next)
- add_object_array(&p->item->object,
- NULL, &stack);
- else {
- commit = p->item;
- cur_depth = *(int *)commit->util;
- }
- } else {
- commit_list_insert(p->item, &result);
- p->item->object.flags |= shallow_flag;
+ if (p->next)
+ add_object_array(&p->item->object,
+ NULL, &stack);
+ else {
+ commit = p->item;
+ cur_depth = *(int *)commit->util;
}
}
}
return result;
}
+
+void check_shallow_file_for_update(void)
+{
+ struct stat st;
+
+ if (!is_shallow)
+ return;
+ else if (is_shallow == -1)
+ die("BUG: shallow must be initialized by now");
+
+ if (stat(git_path("shallow"), &st))
+ die("shallow file was removed during fetch");
+ else if (st.st_mtime != shallow_stat.st_mtime
+#ifdef USE_NSEC
+ || ST_MTIME_NSEC(st) != ST_MTIME_NSEC(shallow_stat)
+#endif
+ )
+ die("shallow file was changed during fetch");
+}
diff --git a/shell.c b/shell.c
index 84b237f..66350b2 100644
--- a/shell.c
+++ b/shell.c
@@ -6,6 +6,7 @@
#define COMMAND_DIR "git-shell-commands"
#define HELP_COMMAND COMMAND_DIR "/help"
+#define NOLOGIN_COMMAND COMMAND_DIR "/no-interactive-login"
static int do_generic_cmd(const char *me, char *arg)
{
@@ -65,6 +66,18 @@ static void run_shell(void)
{
int done = 0;
static const char *help_argv[] = { HELP_COMMAND, NULL };
+
+ if (!access(NOLOGIN_COMMAND, F_OK)) {
+ /* Interactive login disabled. */
+ const char *argv[] = { NOLOGIN_COMMAND, NULL };
+ int status;
+
+ status = run_command_v_opt(argv, 0);
+ if (status < 0)
+ exit(127);
+ exit(status);
+ }
+
/* Print help if enabled */
run_command_v_opt(help_argv, RUN_SILENT_EXEC_FAILURE);
@@ -134,7 +147,6 @@ int main(int argc, char **argv)
char *prog;
const char **user_argv;
struct commands *cmd;
- int devnull_fd;
int count;
git_setup_gettext();
@@ -143,15 +155,10 @@ int main(int argc, char **argv)
/*
* Always open file descriptors 0/1/2 to avoid clobbering files
- * in die(). It also avoids not messing up when the pipes are
- * dup'ed onto stdin/stdout/stderr in the child processes we spawn.
+ * in die(). It also avoids messing up when the pipes are dup'ed
+ * onto stdin/stdout/stderr in the child processes we spawn.
*/
- devnull_fd = open("/dev/null", O_RDWR);
- while (devnull_fd >= 0 && devnull_fd <= 2)
- devnull_fd = dup(devnull_fd);
- if (devnull_fd == -1)
- die_errno("opening /dev/null failed");
- close (devnull_fd);
+ sanitize_stdfds();
/*
* Special hack to pretend to be a CVS server
diff --git a/sideband.c b/sideband.c
index d5ffa1c..d1125f5 100644
--- a/sideband.c
+++ b/sideband.c
@@ -1,3 +1,4 @@
+#include "cache.h"
#include "pkt-line.h"
#include "sideband.h"
@@ -37,7 +38,7 @@ int recv_sideband(const char *me, int in_stream, int out)
while (1) {
int band, len;
- len = packet_read_line(in_stream, buf + pf, LARGE_PACKET_MAX);
+ len = packet_read(in_stream, NULL, NULL, buf + pf, LARGE_PACKET_MAX, 0);
if (len == 0)
break;
if (len < 1) {
@@ -108,7 +109,7 @@ int recv_sideband(const char *me, int in_stream, int out)
} while (len);
continue;
case 1:
- safe_write(out, buf + pf+1, len);
+ write_or_die(out, buf + pf+1, len);
continue;
default:
fprintf(stderr, "%s: protocol error: bad band #%d\n",
@@ -138,12 +139,12 @@ ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet
if (0 <= band) {
sprintf(hdr, "%04x", n + 5);
hdr[4] = band;
- safe_write(fd, hdr, 5);
+ write_or_die(fd, hdr, 5);
} else {
sprintf(hdr, "%04x", n + 4);
- safe_write(fd, hdr, 4);
+ write_or_die(fd, hdr, 4);
}
- safe_write(fd, p, n);
+ write_or_die(fd, p, n);
p += n;
sz -= n;
}
diff --git a/sideband.h b/sideband.h
index d72db35..e46bed0 100644
--- a/sideband.h
+++ b/sideband.h
@@ -4,9 +4,6 @@
#define SIDEBAND_PROTOCOL_ERROR -2
#define SIDEBAND_REMOTE_ERROR -1
-#define DEFAULT_PACKET_MAX 1000
-#define LARGE_PACKET_MAX 65520
-
int recv_sideband(const char *me, int in_stream, int out);
ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max);
diff --git a/strbuf.c b/strbuf.c
index 48e9abb..1170d01 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -528,6 +528,25 @@ void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
strbuf_add_urlencode(sb, s, strlen(s), reserved);
}
+void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
+{
+ if (bytes > 1 << 30) {
+ strbuf_addf(buf, "%u.%2.2u GiB",
+ (int)(bytes >> 30),
+ (int)(bytes & ((1 << 30) - 1)) / 10737419);
+ } else if (bytes > 1 << 20) {
+ int x = bytes + 5243; /* for rounding */
+ strbuf_addf(buf, "%u.%2.2u MiB",
+ x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
+ } else if (bytes > 1 << 10) {
+ int x = bytes + 5; /* for rounding */
+ strbuf_addf(buf, "%u.%2.2u KiB",
+ x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
+ } else {
+ strbuf_addf(buf, "%u bytes", (int)bytes);
+ }
+}
+
int printf_ln(const char *fmt, ...)
{
int ret;
diff --git a/strbuf.h b/strbuf.h
index 958822c..73e80ce 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -170,6 +170,7 @@ extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
extern void strbuf_addstr_urlencode(struct strbuf *, const char *,
int reserved);
+extern void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes);
__attribute__((format (printf,1,2)))
extern int printf_ln(const char *fmt, ...);
diff --git a/streaming.c b/streaming.c
index 4d978e5..debe904 100644
--- a/streaming.c
+++ b/streaming.c
@@ -111,11 +111,11 @@ static enum input_source istream_source(const unsigned char *sha1,
unsigned long size;
int status;
+ oi->typep = type;
oi->sizep = &size;
status = sha1_object_info_extended(sha1, oi);
if (status < 0)
return stream_error;
- *type = status;
switch (oi->whence) {
case OI_LOOSE:
@@ -135,7 +135,7 @@ struct git_istream *open_istream(const unsigned char *sha1,
struct stream_filter *filter)
{
struct git_istream *st;
- struct object_info oi;
+ struct object_info oi = {NULL};
const unsigned char *real = lookup_replace_object(sha1);
enum input_source src = istream_source(real, type, &oi);
@@ -149,7 +149,7 @@ struct git_istream *open_istream(const unsigned char *sha1,
return NULL;
}
}
- if (st && filter) {
+ if (filter) {
/* Add "&& !is_null_stream_filter(filter)" for performance */
struct git_istream *nst = attach_stream_filter(st, filter);
if (!nst)
@@ -237,7 +237,7 @@ static read_method_decl(filtered)
if (!fs->input_finished) {
fs->i_end = read_istream(fs->upstream, fs->ibuf, FILTER_BUFFER);
if (fs->i_end < 0)
- break;
+ return -1;
if (fs->i_end)
continue;
}
@@ -309,7 +309,7 @@ static read_method_decl(loose)
st->z_state = z_done;
break;
}
- if (status != Z_OK && status != Z_BUF_ERROR) {
+ if (status != Z_OK && (status != Z_BUF_ERROR || total_read < sz)) {
git_inflate_end(&st->z);
st->z_state = z_error;
return -1;
@@ -514,6 +514,8 @@ int stream_blob_to_fd(int fd, unsigned const char *sha1, struct stream_filter *f
ssize_t wrote, holeto;
ssize_t readlen = read_istream(st, buf, sizeof(buf));
+ if (readlen < 0)
+ goto close_and_exit;
if (!readlen)
break;
if (can_seek && sizeof(buf) == readlen) {
diff --git a/submodule.c b/submodule.c
index 975bc87..1905d75 100644
--- a/submodule.c
+++ b/submodule.c
@@ -10,6 +10,7 @@
#include "string-list.h"
#include "sha1-array.h"
#include "argv-array.h"
+#include "blob.h"
static struct string_list config_name_for_path;
static struct string_list config_fetch_recurse_submodules_for_name;
@@ -30,6 +31,118 @@ static struct sha1_array ref_tips_after_fetch;
*/
static int gitmodules_is_unmerged;
+/*
+ * This flag is set if the .gitmodules file had unstaged modifications on
+ * startup. This must be checked before allowing modifications to the
+ * .gitmodules file with the intention to stage them later, because when
+ * continuing we would stage the modifications the user didn't stage herself
+ * too. That might change in a future version when we learn to stage the
+ * changes we do ourselves without staging any previous modifications.
+ */
+static int gitmodules_is_modified;
+
+
+int is_staging_gitmodules_ok(void)
+{
+ return !gitmodules_is_modified;
+}
+
+/*
+ * Try to update the "path" entry in the "submodule.<name>" section of the
+ * .gitmodules file. Return 0 only if a .gitmodules file was found, a section
+ * with the correct path=<oldpath> setting was found and we could update it.
+ */
+int update_path_in_gitmodules(const char *oldpath, const char *newpath)
+{
+ struct strbuf entry = STRBUF_INIT;
+ struct string_list_item *path_option;
+
+ if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
+ return -1;
+
+ if (gitmodules_is_unmerged)
+ die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
+
+ path_option = unsorted_string_list_lookup(&config_name_for_path, oldpath);
+ if (!path_option) {
+ warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
+ return -1;
+ }
+ strbuf_addstr(&entry, "submodule.");
+ strbuf_addstr(&entry, path_option->util);
+ strbuf_addstr(&entry, ".path");
+ if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) {
+ /* Maybe the user already did that, don't error out here */
+ warning(_("Could not update .gitmodules entry %s"), entry.buf);
+ strbuf_release(&entry);
+ return -1;
+ }
+ strbuf_release(&entry);
+ return 0;
+}
+
+/*
+ * Try to remove the "submodule.<name>" section from .gitmodules where the given
+ * path is configured. Return 0 only if a .gitmodules file was found, a section
+ * with the correct path=<path> setting was found and we could remove it.
+ */
+int remove_path_from_gitmodules(const char *path)
+{
+ struct strbuf sect = STRBUF_INIT;
+ struct string_list_item *path_option;
+
+ if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
+ return -1;
+
+ if (gitmodules_is_unmerged)
+ die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
+
+ path_option = unsorted_string_list_lookup(&config_name_for_path, path);
+ if (!path_option) {
+ warning(_("Could not find section in .gitmodules where path=%s"), path);
+ return -1;
+ }
+ strbuf_addstr(&sect, "submodule.");
+ strbuf_addstr(&sect, path_option->util);
+ if (git_config_rename_section_in_file(".gitmodules", sect.buf, NULL) < 0) {
+ /* Maybe the user already did that, don't error out here */
+ warning(_("Could not remove .gitmodules entry for %s"), path);
+ strbuf_release(&sect);
+ return -1;
+ }
+ strbuf_release(&sect);
+ return 0;
+}
+
+void stage_updated_gitmodules(void)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct stat st;
+ int pos;
+ struct cache_entry *ce;
+ int namelen = strlen(".gitmodules");
+
+ pos = cache_name_pos(".gitmodules", namelen);
+ if (pos < 0) {
+ warning(_("could not find .gitmodules in index"));
+ return;
+ }
+ ce = active_cache[pos];
+ ce->ce_flags = namelen;
+ if (strbuf_read_file(&buf, ".gitmodules", 0) < 0)
+ die(_("reading updated .gitmodules failed"));
+ if (lstat(".gitmodules", &st) < 0)
+ die_errno(_("unable to stat updated .gitmodules"));
+ fill_stat_cache_info(ce, &st);
+ ce->ce_mode = ce_mode_from_stat(ce, st.st_mode);
+ if (remove_cache_entry_at(pos) < 0)
+ die(_("unable to remove .gitmodules from index"));
+ if (write_sha1_file(buf.buf, buf.len, blob_type, ce->sha1))
+ die(_("adding updated .gitmodules failed"));
+ if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
+ die(_("staging updated .gitmodules failed"));
+}
+
static int add_submodule_odb(const char *path)
{
struct strbuf objects_directory = STRBUF_INIT;
@@ -116,6 +229,11 @@ void gitmodules_config(void)
!memcmp(ce->name, ".gitmodules", 11))
gitmodules_is_unmerged = 1;
}
+ } else if (pos < active_nr) {
+ struct stat st;
+ if (lstat(".gitmodules", &st) == 0 &&
+ ce_match_stat(active_cache[pos], &st, 0) & DATA_CHANGED)
+ gitmodules_is_modified = 1;
}
if (!gitmodules_is_unmerged)
@@ -134,6 +252,9 @@ int parse_submodule_config_option(const char *var, const char *value)
return 0;
if (!strcmp(key, "path")) {
+ if (!value)
+ return config_error_nonbool(var);
+
config = unsorted_string_list_lookup(&config_name_for_path, value);
if (config)
free(config->util);
@@ -151,6 +272,9 @@ int parse_submodule_config_option(const char *var, const char *value)
} else if (!strcmp(key, "ignore")) {
char *name_cstr;
+ if (!value)
+ return config_error_nonbool(var);
+
if (strcmp(value, "untracked") && strcmp(value, "dirty") &&
strcmp(value, "all") && strcmp(value, "none")) {
warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var);
@@ -216,6 +340,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path,
}
static void print_submodule_summary(struct rev_info *rev, FILE *f,
+ const char *line_prefix,
const char *del, const char *add, const char *reset)
{
static const char format[] = " %m %s";
@@ -225,7 +350,9 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f,
while ((commit = get_revision(rev))) {
struct pretty_print_context ctx = {0};
ctx.date_mode = rev->date_mode;
+ ctx.output_encoding = get_log_output_encoding();
strbuf_setlen(&sb, 0);
+ strbuf_addstr(&sb, line_prefix);
if (commit->object.flags & SYMMETRIC_LEFT) {
if (del)
strbuf_addstr(&sb, del);
@@ -256,6 +383,7 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
}
void show_submodule_summary(FILE *f, const char *path,
+ const char *line_prefix,
unsigned char one[20], unsigned char two[20],
unsigned dirty_submodule, const char *meta,
const char *del, const char *add, const char *reset)
@@ -280,16 +408,18 @@ void show_submodule_summary(FILE *f, const char *path,
message = "(revision walker failed)";
if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
- fprintf(f, "Submodule %s contains untracked content\n", path);
+ fprintf(f, "%sSubmodule %s contains untracked content\n",
+ line_prefix, path);
if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
- fprintf(f, "Submodule %s contains modified content\n", path);
+ fprintf(f, "%sSubmodule %s contains modified content\n",
+ line_prefix, path);
if (!hashcmp(one, two)) {
strbuf_release(&sb);
return;
}
- strbuf_addf(&sb, "%sSubmodule %s %s..", meta, path,
+ strbuf_addf(&sb, "%s%sSubmodule %s %s..", line_prefix, meta, path,
find_unique_abbrev(one, DEFAULT_ABBREV));
if (!fast_backward && !fast_forward)
strbuf_addch(&sb, '.');
@@ -301,7 +431,7 @@ void show_submodule_summary(FILE *f, const char *path,
fwrite(sb.buf, sb.len, 1, f);
if (!message) /* only NULL if we succeeded in setting up the walk */
- print_submodule_summary(&rev, f, del, add, reset);
+ print_submodule_summary(&rev, f, line_prefix, del, add, reset);
if (left)
clear_commit_marks(left, ~0);
if (right)
@@ -598,9 +728,8 @@ int fetch_populated_submodules(const struct argv_array *options,
if (!work_tree)
goto out;
- if (!the_index.initialized)
- if (read_cache() < 0)
- die("index file corrupt");
+ if (read_cache() < 0)
+ die("index file corrupt");
argv_array_push(&argv, "fetch");
for (i = 0; i < options->argc; i++)
@@ -619,7 +748,7 @@ int fetch_populated_submodules(const struct argv_array *options,
struct strbuf submodule_path = STRBUF_INIT;
struct strbuf submodule_git_dir = STRBUF_INIT;
struct strbuf submodule_prefix = STRBUF_INIT;
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
const char *git_dir, *name, *default_argv;
if (!S_ISGITLINK(ce->ce_mode))
@@ -841,7 +970,7 @@ static int find_first_merges(struct object_array *result, const char *path,
struct commit *a, struct commit *b)
{
int i, j;
- struct object_array merges;
+ struct object_array merges = OBJECT_ARRAY_INIT;
struct commit *commit;
int contains_another;
@@ -851,7 +980,6 @@ static int find_first_merges(struct object_array *result, const char *path,
struct rev_info revs;
struct setup_revision_opt rev_opts;
- memset(&merges, 0, sizeof(merges));
memset(result, 0, sizeof(struct object_array));
memset(&rev_opts, 0, sizeof(rev_opts));
@@ -889,8 +1017,7 @@ static int find_first_merges(struct object_array *result, const char *path,
}
if (!contains_another)
- add_object_array(merges.objects[i].item,
- merges.objects[i].name, result);
+ add_object_array(merges.objects[i].item, NULL, result);
}
free(merges.objects);
@@ -1001,3 +1128,34 @@ int merge_submodule(unsigned char result[20], const char *path,
free(merges.objects);
return 0;
}
+
+/* Update gitfile and core.worktree setting to connect work tree and git dir */
+void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)
+{
+ struct strbuf file_name = STRBUF_INIT;
+ struct strbuf rel_path = STRBUF_INIT;
+ const char *real_work_tree = xstrdup(real_path(work_tree));
+ FILE *fp;
+
+ /* Update gitfile */
+ strbuf_addf(&file_name, "%s/.git", work_tree);
+ fp = fopen(file_name.buf, "w");
+ if (!fp)
+ die(_("Could not create git link %s"), file_name.buf);
+ fprintf(fp, "gitdir: %s\n", relative_path(git_dir, real_work_tree,
+ &rel_path));
+ fclose(fp);
+
+ /* Update core.worktree setting */
+ strbuf_reset(&file_name);
+ strbuf_addf(&file_name, "%s/config", git_dir);
+ if (git_config_set_in_file(file_name.buf, "core.worktree",
+ relative_path(real_work_tree, git_dir,
+ &rel_path)))
+ die(_("Could not set core.worktree in %s"),
+ file_name.buf);
+
+ strbuf_release(&file_name);
+ strbuf_release(&rel_path);
+ free((void *)real_work_tree);
+}
diff --git a/submodule.h b/submodule.h
index 3dc1b3f..7beec48 100644
--- a/submodule.h
+++ b/submodule.h
@@ -11,6 +11,10 @@ enum {
RECURSE_SUBMODULES_ON = 2
};
+int is_staging_gitmodules_ok(void);
+int update_path_in_gitmodules(const char *oldpath, const char *newpath);
+int remove_path_from_gitmodules(const char *path);
+void stage_updated_gitmodules(void);
void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
const char *path);
int submodule_config(const char *var, const char *value, void *cb);
@@ -19,6 +23,7 @@ int parse_submodule_config_option(const char *var, const char *value);
void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
void show_submodule_summary(FILE *f, const char *path,
+ const char *line_prefix,
unsigned char one[20], unsigned char two[20],
unsigned dirty_submodule, const char *meta,
const char *del, const char *add, const char *reset);
@@ -35,5 +40,6 @@ int merge_submodule(unsigned char result[20], const char *path, const unsigned c
int find_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name,
struct string_list *needs_pushing);
int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name);
+void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);
#endif
diff --git a/t/.gitattributes b/t/.gitattributes
index 1b97c54..2d44088 100644
--- a/t/.gitattributes
+++ b/t/.gitattributes
@@ -1 +1,2 @@
t[0-9][0-9][0-9][0-9]/* -whitespace
+t0110/url-* binary
diff --git a/t/Makefile b/t/Makefile
index 44ca7d3..2373a04 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -15,9 +15,16 @@ PROVE ?= prove
DEFAULT_TEST_TARGET ?= test
TEST_LINT ?= test-lint-duplicates test-lint-executable
+ifdef TEST_OUTPUT_DIRECTORY
+TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results
+else
+TEST_RESULTS_DIRECTORY = test-results
+endif
+
# Shell quote;
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
+TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY))
T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
TSVN = $(sort $(wildcard t91[0-9][0-9]-*.sh))
@@ -36,10 +43,10 @@ $(T):
@echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
pre-clean:
- $(RM) -r test-results
+ $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
clean-except-prove-cache:
- $(RM) -r 'trash directory'.* test-results
+ $(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)'
$(RM) -r valgrind/bin
clean: clean-except-prove-cache
@@ -65,7 +72,7 @@ aggregate-results-and-cleanup: $(T)
$(MAKE) clean
aggregate-results:
- for f in test-results/t*-*.counts; do \
+ for f in '$(TEST_RESULTS_DIRECTORY_SQ)'/t*-*.counts; do \
echo "$$f"; \
done | '$(SHELL_PATH_SQ)' ./aggregate-results.sh
diff --git a/t/README b/t/README
index f8bf3ec..2167125 100644
--- a/t/README
+++ b/t/README
@@ -76,6 +76,11 @@ appropriately before running "make".
command being run and their output if any are also
output.
+--verbose-only=<pattern>::
+ Like --verbose, but the effect is limited to tests with
+ numbers matching <pattern>. The number matched against is
+ simply the running count of the test within the file.
+
--debug::
This may help the person who is developing a new test.
It causes the command defined with test_debug to run.
@@ -95,23 +100,37 @@ appropriately before running "make".
This causes additional long-running tests to be run (where
available), for more exhaustive testing.
---valgrind::
- Execute all Git binaries with valgrind and exit with status
- 126 on errors (just like regular tests, this will only stop
- the test script when running under -i). Valgrind errors
- go to stderr, so you might want to pass the -v option, too.
+--valgrind=<tool>::
+ Execute all Git binaries under valgrind tool <tool> and exit
+ with status 126 on errors (just like regular tests, this will
+ only stop the test script when running under -i).
Since it makes no sense to run the tests with --valgrind and
not see any output, this option implies --verbose. For
convenience, it also implies --tee.
- Note that valgrind is run with the option --leak-check=no,
+ <tool> defaults to 'memcheck', just like valgrind itself.
+ Other particularly useful choices include 'helgrind' and
+ 'drd', but you may use any tool recognized by your valgrind
+ installation.
+
+ As a special case, <tool> can be 'memcheck-fast', which uses
+ memcheck but disables --track-origins. Use this if you are
+ running tests in bulk, to see if there are _any_ memory
+ issues.
+
+ Note that memcheck is run with the option --leak-check=no,
as the git process is short-lived and some errors are not
interesting. In order to run a single command under the same
conditions manually, you should set GIT_VALGRIND to point to
the 't/valgrind/' directory and use the commands under
't/valgrind/bin/'.
+--valgrind-only=<pattern>::
+ Like --valgrind, but the effect is limited to tests with
+ numbers matching <pattern>. The number matched against is
+ simply the running count of the test within the file.
+
--tee::
In addition to printing the test output to the terminal,
write it to files named 't/test-results/$TEST_NAME.out'.
@@ -315,6 +334,9 @@ Don't:
use 'test_must_fail git cmd'. This will signal a failure if git
dies in an unexpected way (e.g. segfault).
+ On the other hand, don't use test_must_fail for running regular
+ platform commands; just use '! cmd'.
+
- use perl without spelling it as "$PERL_PATH". This is to help our
friends on Windows where the platform Perl often adds CR before
the end of line, and they bundle Git with a version of Perl that
@@ -583,6 +605,20 @@ library for your script to use.
test_cmp expected actual
'
+ - test_ln_s_add <path1> <path2>
+
+ This function helps systems whose filesystem does not support symbolic
+ links. Use it to add a symbolic link entry to the index when it is not
+ important that the file system entry is a symbolic link, i.e., instead
+ of the sequence
+
+ ln -s foo bar &&
+ git add bar
+
+ Sometimes it is possible to split a test in a part that does not need
+ the symbolic link in the file system and a part that does; then only
+ the latter part need be protected by a SYMLINKS prerequisite (see below).
+
Prerequisites
-------------
diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh
index c56a77d..99caa42 100644
--- a/t/annotate-tests.sh
+++ b/t/annotate-tests.sh
@@ -2,11 +2,21 @@
# sourced from t8001-annotate.sh and t8002-blame.sh.
check_count () {
- head=
- case "$1" in -h) head="$2"; shift; shift ;; esac
- echo "$PROG file $head" >&4
- $PROG file $head >.result || return 1
- cat .result | perl -e '
+ head= &&
+ file='file' &&
+ options= &&
+ while :
+ do
+ case "$1" in
+ -h) head="$2"; shift; shift ;;
+ -f) file="$2"; shift; shift ;;
+ -*) options="$options $1"; shift ;;
+ *) break ;;
+ esac
+ done &&
+ echo "$PROG $options $file $head" >&4 &&
+ $PROG $options $file $head >actual &&
+ perl -e '
my %expect = (@ARGV);
my %count = map { $_ => 0 } keys %expect;
while (<STDIN>) {
@@ -31,107 +41,492 @@ check_count () {
print STDERR "Author $author (expected $value, attributed $count) $ok\n";
}
exit($bad);
- ' "$@"
+ ' "$@" <actual
}
-test_expect_success \
- 'prepare reference tree' \
- 'echo "1A quick brown fox jumps over the" >file &&
- echo "lazy dog" >>file &&
- git add file &&
- GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" git commit -a -m "Initial."'
-
-test_expect_success \
- 'check all lines blamed on A' \
- 'check_count A 2'
-
-test_expect_success \
- 'Setup new lines blamed on B' \
- 'echo "2A quick brown fox jumps over the" >>file &&
- echo "lazy dog" >> file &&
- GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" git commit -a -m "Second."'
-
-test_expect_success \
- 'Two lines blamed on A, two on B' \
- 'check_count A 2 B 2'
-
-test_expect_success \
- 'merge-setup part 1' \
- 'git checkout -b branch1 master &&
- echo "3A slow green fox jumps into the" >> file &&
- echo "well." >> file &&
- GIT_AUTHOR_NAME="B1" GIT_AUTHOR_EMAIL="B1@test.git" git commit -a -m "Branch1-1"'
-
-test_expect_success \
- 'Two lines blamed on A, two on B, two on B1' \
- 'check_count A 2 B 2 B1 2'
-
-test_expect_success \
- 'merge-setup part 2' \
- 'git checkout -b branch2 master &&
- sed -e "s/2A quick brown/4A quick brown lazy dog/" < file > file.new &&
- mv file.new file &&
- GIT_AUTHOR_NAME="B2" GIT_AUTHOR_EMAIL="B2@test.git" git commit -a -m "Branch2-1"'
-
-test_expect_success \
- 'Two lines blamed on A, one on B, one on B2' \
- 'check_count A 2 B 1 B2 1'
-
-test_expect_success \
- 'merge-setup part 3' \
- 'git pull . branch1'
-
-test_expect_success \
- 'Two lines blamed on A, one on B, two on B1, one on B2' \
- 'check_count A 2 B 1 B1 2 B2 1'
-
-test_expect_success \
- 'Annotating an old revision works' \
- 'check_count -h master A 2 B 2'
-
-test_expect_success \
- 'Annotating an old revision works' \
- 'check_count -h master^ A 2'
-
-test_expect_success \
- 'merge-setup part 4' \
- 'echo "evil merge." >>file &&
- git commit -a --amend'
-
-test_expect_success \
- 'Two lines blamed on A, one on B, two on B1, one on B2, one on A U Thor' \
- 'check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1'
-
-test_expect_success \
- 'an incomplete line added' \
- 'echo "incomplete" | tr -d "\\012" >>file &&
- GIT_AUTHOR_NAME="C" GIT_AUTHOR_EMAIL="C@test.git" git commit -a -m "Incomplete"'
-
-test_expect_success \
- 'With incomplete lines.' \
- 'check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 C 1'
-
-test_expect_success \
- 'some edit' \
- 'mv file file.orig &&
- {
- cat file.orig &&
- echo
- } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" > file &&
- echo "incomplete" | tr -d "\\012" >>file &&
- GIT_AUTHOR_NAME="D" GIT_AUTHOR_EMAIL="D@test.git" git commit -a -m "edit"'
-
-test_expect_success \
- 'some edit' \
- 'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1'
-
-test_expect_success \
- 'an obfuscated email added' \
- 'echo "No robots allowed" > file.new &&
- cat file >> file.new &&
- mv file.new file &&
- GIT_AUTHOR_NAME="E" GIT_AUTHOR_EMAIL="E at test dot git" git commit -a -m "norobots"'
-
-test_expect_success \
- 'obfuscated email parsed' \
- 'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1'
+test_expect_success 'setup A lines' '
+ echo "1A quick brown fox jumps over the" >file &&
+ echo "lazy dog" >>file &&
+ git add file &&
+ GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" \
+ git commit -a -m "Initial."
+'
+
+test_expect_success 'blame 1 author' '
+ check_count A 2
+'
+
+test_expect_success 'setup B lines' '
+ echo "2A quick brown fox jumps over the" >>file &&
+ echo "lazy dog" >>file &&
+ GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" \
+ git commit -a -m "Second."
+'
+
+test_expect_success 'blame 2 authors' '
+ check_count A 2 B 2
+'
+
+test_expect_success 'setup B1 lines (branch1)' '
+ git checkout -b branch1 master &&
+ echo "3A slow green fox jumps into the" >>file &&
+ echo "well." >>file &&
+ GIT_AUTHOR_NAME="B1" GIT_AUTHOR_EMAIL="B1@test.git" \
+ git commit -a -m "Branch1-1"
+'
+
+test_expect_success 'blame 2 authors + 1 branch1 author' '
+ check_count A 2 B 2 B1 2
+'
+
+test_expect_success 'setup B2 lines (branch2)' '
+ git checkout -b branch2 master &&
+ sed -e "s/2A quick brown/4A quick brown lazy dog/" <file >file.new &&
+ mv file.new file &&
+ GIT_AUTHOR_NAME="B2" GIT_AUTHOR_EMAIL="B2@test.git" \
+ git commit -a -m "Branch2-1"
+'
+
+test_expect_success 'blame 2 authors + 1 branch2 author' '
+ check_count A 2 B 1 B2 1
+'
+
+test_expect_success 'merge branch1 & branch2' '
+ git pull . branch1
+'
+
+test_expect_success 'blame 2 authors + 2 merged-in authors' '
+ check_count A 2 B 1 B1 2 B2 1
+'
+
+test_expect_success 'blame ancestor' '
+ check_count -h master A 2 B 2
+'
+
+test_expect_success 'blame great-ancestor' '
+ check_count -h master^ A 2
+'
+
+test_expect_success 'setup evil merge' '
+ echo "evil merge." >>file &&
+ git commit -a --amend
+'
+
+test_expect_success 'blame evil merge' '
+ check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1
+'
+
+test_expect_success 'setup incomplete line' '
+ echo "incomplete" | tr -d "\\012" >>file &&
+ GIT_AUTHOR_NAME="C" GIT_AUTHOR_EMAIL="C@test.git" \
+ git commit -a -m "Incomplete"
+'
+
+test_expect_success 'blame incomplete line' '
+ check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 C 1
+'
+
+test_expect_success 'setup edits' '
+ mv file file.orig &&
+ {
+ cat file.orig &&
+ echo
+ } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" >file &&
+ echo "incomplete" | tr -d "\\012" >>file &&
+ GIT_AUTHOR_NAME="D" GIT_AUTHOR_EMAIL="D@test.git" \
+ git commit -a -m "edit"
+'
+
+test_expect_success 'blame edits' '
+ check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1
+'
+
+test_expect_success 'setup obfuscated email' '
+ echo "No robots allowed" >file.new &&
+ cat file >>file.new &&
+ mv file.new file &&
+ GIT_AUTHOR_NAME="E" GIT_AUTHOR_EMAIL="E at test dot git" \
+ git commit -a -m "norobots"
+'
+
+test_expect_success 'blame obfuscated email' '
+ check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1
+'
+
+test_expect_success 'blame -L 1 (all)' '
+ check_count -L1 A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1
+'
+
+test_expect_success 'blame -L , (all)' '
+ check_count -L, A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1
+'
+
+test_expect_success 'blame -L X (X to end)' '
+ check_count -L5 B1 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L X, (X to end)' '
+ check_count -L5, B1 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L ,Y (up to Y)' '
+ check_count -L,3 A 1 B2 1 E 1
+'
+
+test_expect_success 'blame -L X,X' '
+ check_count -L3,3 B2 1
+'
+
+test_expect_success 'blame -L X,Y' '
+ check_count -L3,6 B 1 B1 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L Y,X (undocumented)' '
+ check_count -L6,3 B 1 B1 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L -X' '
+ test_must_fail $PROG -L-1 file
+'
+
+test_expect_success 'blame -L 0' '
+ test_must_fail $PROG -L0 file
+'
+
+test_expect_success 'blame -L ,0' '
+ test_must_fail $PROG -L,0 file
+'
+
+test_expect_success 'blame -L ,+0' '
+ test_must_fail $PROG -L,+0 file
+'
+
+test_expect_success 'blame -L X,+0' '
+ test_must_fail $PROG -L1,+0 file
+'
+
+test_expect_success 'blame -L X,+1' '
+ check_count -L3,+1 B2 1
+'
+
+test_expect_success 'blame -L X,+N' '
+ check_count -L3,+4 B 1 B1 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L ,-0' '
+ test_must_fail $PROG -L,-0 file
+'
+
+test_expect_success 'blame -L X,-0' '
+ test_must_fail $PROG -L1,-0 file
+'
+
+test_expect_success 'blame -L X,-1' '
+ check_count -L3,-1 B2 1
+'
+
+test_expect_success 'blame -L X,-N' '
+ check_count -L6,-4 B 1 B1 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L /RE/ (RE to end)' '
+ check_count -L/evil/ C 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/,/RE2/' '
+ check_count -L/robot/,/green/ A 1 B 1 B2 1 D 1 E 1
+'
+
+test_expect_success 'blame -L X,/RE/' '
+ check_count -L5,/evil/ B1 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/,Y' '
+ check_count -L/99/,7 B1 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/,+N' '
+ check_count -L/99/,+3 B1 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/,-N' '
+ check_count -L/99/,-3 B 1 B2 1 D 1
+'
+
+# 'file' ends with an incomplete line, so 'wc' reports one fewer lines than
+# git-blame sees, hence the last line is actually $(wc...)+1.
+test_expect_success 'blame -L X (X == nlines)' '
+ n=$(expr $(wc -l <file) + 1) &&
+ check_count -L$n C 1
+'
+
+test_expect_success 'blame -L X (X == nlines + 1)' '
+ n=$(expr $(wc -l <file) + 2) &&
+ test_must_fail $PROG -L$n file
+'
+
+test_expect_success 'blame -L X (X > nlines)' '
+ test_must_fail $PROG -L12345 file
+'
+
+test_expect_success 'blame -L ,Y (Y == nlines)' '
+ n=$(expr $(wc -l <file) + 1) &&
+ check_count -L,$n A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1
+'
+
+test_expect_success 'blame -L ,Y (Y == nlines + 1)' '
+ n=$(expr $(wc -l <file) + 2) &&
+ test_must_fail $PROG -L,$n file
+'
+
+test_expect_success 'blame -L ,Y (Y > nlines)' '
+ test_must_fail $PROG -L,12345 file
+'
+
+test_expect_success 'blame -L multiple (disjoint)' '
+ check_count -L2,3 -L6,7 A 1 B1 1 B2 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L multiple (disjoint: unordered)' '
+ check_count -L6,7 -L2,3 A 1 B1 1 B2 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L multiple (adjacent)' '
+ check_count -L2,3 -L4,5 A 1 B 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L multiple (adjacent: unordered)' '
+ check_count -L4,5 -L2,3 A 1 B 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L multiple (overlapping)' '
+ check_count -L2,4 -L3,5 A 1 B 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L multiple (overlapping: unordered)' '
+ check_count -L3,5 -L2,4 A 1 B 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L multiple (superset/subset)' '
+ check_count -L2,8 -L3,5 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L multiple (superset/subset: unordered)' '
+ check_count -L3,5 -L2,8 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/ (relative)' '
+ check_count -L3,3 -L/fox/ B1 1 B2 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/ (relative: no preceding range)' '
+ check_count -L/dog/ A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/ (relative: adjacent)' '
+ check_count -L1,1 -L/dog/,+1 A 1 E 1
+'
+
+test_expect_success 'blame -L /RE/ (relative: not found)' '
+ test_must_fail $PROG -L4,4 -L/dog/ file
+'
+
+test_expect_success 'blame -L /RE/ (relative: end-of-file)' '
+ test_must_fail $PROG -L, -L/$/ file
+'
+
+test_expect_success 'blame -L ^/RE/ (absolute)' '
+ check_count -L3,3 -L^/dog/,+2 A 1 B2 1
+'
+
+test_expect_success 'blame -L ^/RE/ (absolute: no preceding range)' '
+ check_count -L^/dog/,+2 A 1 B2 1
+'
+
+test_expect_success 'blame -L ^/RE/ (absolute: not found)' '
+ test_must_fail $PROG -L4,4 -L^/tambourine/ file
+'
+
+test_expect_success 'blame -L ^/RE/ (absolute: end-of-file)' '
+ n=$(expr $(wc -l <file) + 1) &&
+ check_count -L$n -L^/$/,+2 A 1 C 1 E 1
+'
+
+test_expect_success 'setup -L :regex' '
+ tr Q "\\t" >hello.c <<-\EOF &&
+ int main(int argc, const char *argv[])
+ {
+ Qputs("hello");
+ }
+ EOF
+ git add hello.c &&
+ GIT_AUTHOR_NAME="F" GIT_AUTHOR_EMAIL="F@test.git" \
+ git commit -m "hello" &&
+
+ mv hello.c hello.orig &&
+ sed -e "/}/ {x; s/$/Qputs(\"goodbye\");/; G;}" <hello.orig |
+ tr Q "\\t" >hello.c &&
+ GIT_AUTHOR_NAME="G" GIT_AUTHOR_EMAIL="G@test.git" \
+ git commit -a -m "goodbye" &&
+
+ mv hello.c hello.orig &&
+ echo "#include <stdio.h>" >hello.c &&
+ cat hello.orig >>hello.c &&
+ tr Q "\\t" >>hello.c <<-\EOF
+ void mail()
+ {
+ Qputs("mail");
+ }
+ EOF
+ GIT_AUTHOR_NAME="H" GIT_AUTHOR_EMAIL="H@test.git" \
+ git commit -a -m "mail"
+'
+
+test_expect_success 'blame -L :literal' '
+ check_count -f hello.c -L:main F 4 G 1
+'
+
+test_expect_success 'blame -L :regex' '
+ check_count -f hello.c "-L:m[a-z][a-z]l" H 4
+'
+
+test_expect_success 'blame -L :nomatch' '
+ test_must_fail $PROG -L:nomatch hello.c
+'
+
+test_expect_success 'blame -L :RE (relative)' '
+ check_count -f hello.c -L3,3 -L:ma.. F 1 H 4
+'
+
+test_expect_success 'blame -L :RE (relative: no preceding range)' '
+ check_count -f hello.c -L:ma.. F 4 G 1
+'
+
+test_expect_success 'blame -L :RE (relative: not found)' '
+ test_must_fail $PROG -L3,3 -L:tambourine hello.c
+'
+
+test_expect_success 'blame -L :RE (relative: end-of-file)' '
+ test_must_fail $PROG -L, -L:main hello.c
+'
+
+test_expect_success 'blame -L ^:RE (absolute)' '
+ check_count -f hello.c -L3,3 -L^:ma.. F 4 G 1
+'
+
+test_expect_success 'blame -L ^:RE (absolute: no preceding range)' '
+ check_count -f hello.c -L^:ma.. F 4 G 1
+'
+
+test_expect_success 'blame -L ^:RE (absolute: not found)' '
+ test_must_fail $PROG -L4,4 -L^:tambourine hello.c
+'
+
+test_expect_success 'blame -L ^:RE (absolute: end-of-file)' '
+ n=$(printf "%d" $(wc -l <hello.c)) &&
+ check_count -f hello.c -L$n -L^:ma.. F 4 G 1 H 1
+'
+
+test_expect_success 'setup incremental' '
+ (
+ GIT_AUTHOR_NAME=I &&
+ export GIT_AUTHOR_NAME &&
+ GIT_AUTHOR_EMAIL=I@test.git &&
+ export GIT_AUTHOR_EMAIL &&
+ >incremental &&
+ git add incremental &&
+ git commit -m "step 0" &&
+ printf "partial" >>incremental &&
+ git commit -a -m "step 0.5" &&
+ echo >>incremental &&
+ git commit -a -m "step 1"
+ )
+'
+
+test_expect_success 'blame empty' '
+ check_count -h HEAD^^ -f incremental
+'
+
+test_expect_success 'blame -L 0 empty' '
+ test_must_fail $PROG -L0 incremental HEAD^^
+'
+
+test_expect_success 'blame -L 1 empty' '
+ test_must_fail $PROG -L1 incremental HEAD^^
+'
+
+test_expect_success 'blame -L 2 empty' '
+ test_must_fail $PROG -L2 incremental HEAD^^
+'
+
+test_expect_success 'blame half' '
+ check_count -h HEAD^ -f incremental I 1
+'
+
+test_expect_success 'blame -L 0 half' '
+ test_must_fail $PROG -L0 incremental HEAD^
+'
+
+test_expect_success 'blame -L 1 half' '
+ check_count -h HEAD^ -f incremental -L1 I 1
+'
+
+test_expect_success 'blame -L 2 half' '
+ test_must_fail $PROG -L2 incremental HEAD^
+'
+
+test_expect_success 'blame -L 3 half' '
+ test_must_fail $PROG -L3 incremental HEAD^
+'
+
+test_expect_success 'blame full' '
+ check_count -f incremental I 1
+'
+
+test_expect_success 'blame -L 0 full' '
+ test_must_fail $PROG -L0 incremental
+'
+
+test_expect_success 'blame -L 1 full' '
+ check_count -f incremental -L1 I 1
+'
+
+test_expect_success 'blame -L 2 full' '
+ test_must_fail $PROG -L2 incremental
+'
+
+test_expect_success 'blame -L 3 full' '
+ test_must_fail $PROG -L3 incremental
+'
+
+test_expect_success 'blame -L' '
+ test_must_fail $PROG -L file
+'
+
+test_expect_success 'blame -L X,+' '
+ test_must_fail $PROG -L1,+ file
+'
+
+test_expect_success 'blame -L X,-' '
+ test_must_fail $PROG -L1,- file
+'
+
+test_expect_success 'blame -L X (non-numeric X)' '
+ test_must_fail $PROG -LX file
+'
+
+test_expect_success 'blame -L X,Y (non-numeric Y)' '
+ test_must_fail $PROG -L1,Y file
+'
+
+test_expect_success 'blame -L X,+N (non-numeric N)' '
+ test_must_fail $PROG -L1,+N file
+'
+
+test_expect_success 'blame -L X,-N (non-numeric N)' '
+ test_must_fail $PROG -L1,-N file
+'
+
+test_expect_success 'blame -L ,^/RE/' '
+ test_must_fail $PROG -L1,^/99/ file
+'
diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl
index 8b5a71d..45971f4 100755
--- a/t/check-non-portable-shell.pl
+++ b/t/check-non-portable-shell.pl
@@ -21,6 +21,7 @@ while (<>) {
/^\s*declare\s+/ and err 'arrays/declare not portable';
/^\s*[^#]\s*which\s/ and err 'which is not portable (please use type)';
/test\s+[^=]*==/ and err '"test a == b" is not portable (please use =)';
+ /^\s*export\s+[^=]*=/ and err '"export FOO=bar" is not portable (please use FOO=bar && export FOO)';
# this resets our $. for each file
close ARGV if eof;
}
diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh
index ae2dc46..9e381e0 100644
--- a/t/gitweb-lib.sh
+++ b/t/gitweb-lib.sh
@@ -36,7 +36,7 @@ EOF
# You can set the GITWEB_TEST_INSTALLED environment variable to
# the gitwebdir (the directory where gitweb is installed / deployed to)
- # of an existing gitweb instalation to test that installation,
+ # of an existing gitweb installation to test that installation,
# or simply to pathname of installed gitweb script.
if test -n "$GITWEB_TEST_INSTALLED" ; then
if test -d $GITWEB_TEST_INSTALLED; then
diff --git a/t/lib-gpg/pubring.gpg b/t/lib-gpg/pubring.gpg
index 83855fa..1a3c2d4 100644
--- a/t/lib-gpg/pubring.gpg
+++ b/t/lib-gpg/pubring.gpg
Binary files differ
diff --git a/t/lib-gpg/random_seed b/t/lib-gpg/random_seed
index 8fed133..95d249f 100644
--- a/t/lib-gpg/random_seed
+++ b/t/lib-gpg/random_seed
Binary files differ
diff --git a/t/lib-gpg/secring.gpg b/t/lib-gpg/secring.gpg
index d831cd9..82dca8f 100644
--- a/t/lib-gpg/secring.gpg
+++ b/t/lib-gpg/secring.gpg
Binary files differ
diff --git a/t/lib-gpg/trustdb.gpg b/t/lib-gpg/trustdb.gpg
index abace96..4879ae9 100644
--- a/t/lib-gpg/trustdb.gpg
+++ b/t/lib-gpg/trustdb.gpg
Binary files differ
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 895b925..dab405d 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -141,10 +141,11 @@ stop_httpd() {
-f "$TEST_PATH/apache.conf" $HTTPD_PARA -k stop
}
-test_http_push_nonff() {
+test_http_push_nonff () {
REMOTE_REPO=$1
LOCAL_REPO=$2
BRANCH=$3
+ EXPECT_CAS_RESULT=${4-failure}
test_expect_success 'non-fast-forward push fails' '
cd "$REMOTE_REPO" &&
@@ -167,6 +168,22 @@ test_http_push_nonff() {
test_expect_success 'non-fast-forward push shows help message' '
test_i18ngrep "Updates were rejected because" output
'
+
+ test_expect_failure 'force with lease aka cas' '
+ HEAD=$( cd "$REMOTE_REPO" && git rev-parse --verify HEAD ) &&
+ test_when_finished '\''
+ (cd "$REMOTE_REPO" && git update-ref HEAD "$HEAD")
+ '\'' &&
+ (
+ cd "$LOCAL_REPO" &&
+ git push -v --force-with-lease=$BRANCH:$HEAD origin
+ ) &&
+ git rev-parse --verify "$BRANCH" >expect &&
+ (
+ cd "$REMOTE_REPO" && git rev-parse --verify HEAD
+ ) >actual &&
+ test_cmp expect actual
+ '
}
setup_askpass_helper() {
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 542241b..397c480 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -1,5 +1,4 @@
ServerName dummy
-LockFile accept.lock
PidFile httpd.pid
DocumentRoot www
LogFormat "%h %l %u %t \"%r\" %>s %b" common
@@ -23,6 +22,13 @@ ErrorLog error.log
<IfModule !mod_version.c>
LoadModule version_module modules/mod_version.so
</IfModule>
+<IfModule !mod_headers.c>
+ LoadModule headers_module modules/mod_headers.so
+</IfModule>
+
+<IfVersion < 2.4>
+LockFile accept.lock
+</IfVersion>
<IfVersion < 2.1>
<IfModule !mod_auth.c>
@@ -45,6 +51,21 @@ ErrorLog error.log
</IfModule>
</IfVersion>
+<IfVersion >= 2.4>
+<IfModule !mod_authn_core.c>
+ LoadModule authn_core_module modules/mod_authn_core.so
+</IfModule>
+<IfModule !mod_authz_core.c>
+ LoadModule authz_core_module modules/mod_authz_core.so
+</IfModule>
+<IfModule !mod_access_compat.c>
+ LoadModule access_compat_module modules/mod_access_compat.so
+</IfModule>
+<IfModule !mod_mpm_prefork.c>
+ LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
+</IfModule>
+</IfVersion>
+
PassEnv GIT_VALGRIND
PassEnv GIT_VALGRIND_OPTIONS
@@ -64,6 +85,16 @@ Alias /auth/dumb/ www/auth/dumb/
SetEnv GIT_COMMITTER_NAME "Custom User"
SetEnv GIT_COMMITTER_EMAIL custom@example.com
</LocationMatch>
+<LocationMatch /smart_namespace/>
+ SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
+ SetEnv GIT_HTTP_EXPORT_ALL
+ SetEnv GIT_NAMESPACE ns
+</LocationMatch>
+<LocationMatch /smart_cookies/>
+ SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
+ SetEnv GIT_HTTP_EXPORT_ALL
+ Header set Set-Cookie name=value
+</LocationMatch>
ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
ScriptAlias /broken_smart/ broken-smart-http.sh/
<Directory ${GIT_EXEC_PATH}>
diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index 6ccf797..8ff87fb 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -17,51 +17,98 @@
# ("squash", "fixup", "edit", or "reword") and the SHA1 taken
# from the specified line.
#
+# "exec_cmd_with_args" -- add an "exec cmd with args" line.
+#
# "#" -- Add a comment line.
#
# ">" -- Add a blank line.
set_fake_editor () {
- echo "#!$SHELL_PATH" >fake-editor.sh
- cat >> fake-editor.sh <<\EOF
-case "$1" in
-*/COMMIT_EDITMSG)
- test -z "$EXPECT_HEADER_COUNT" ||
- test "$EXPECT_HEADER_COUNT" = "$(sed -n '1s/^# This is a combination of \(.*\) commits\./\1/p' < "$1")" ||
+ write_script fake-editor.sh <<-\EOF
+ case "$1" in
+ */COMMIT_EDITMSG)
+ test -z "$EXPECT_HEADER_COUNT" ||
+ test "$EXPECT_HEADER_COUNT" = "$(sed -n '1s/^# This is a combination of \(.*\) commits\./\1/p' < "$1")" ||
+ exit
+ test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1"
+ test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1"
exit
- test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1"
- test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1"
- exit
- ;;
-esac
-test -z "$EXPECT_COUNT" ||
- test "$EXPECT_COUNT" = $(sed -e '/^#/d' -e '/^$/d' < "$1" | wc -l) ||
- exit
-test -z "$FAKE_LINES" && exit
-grep -v '^#' < "$1" > "$1".tmp
-rm -f "$1"
-echo 'rebase -i script before editing:'
-cat "$1".tmp
-action=pick
-for line in $FAKE_LINES; do
- case $line in
- squash|fixup|edit|reword)
- action="$line";;
- exec*)
- echo "$line" | sed 's/_/ /g' >> "$1";;
- "#")
- echo '# comment' >> "$1";;
- ">")
- echo >> "$1";;
- *)
- sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
- action=pick;;
+ ;;
esac
-done
-echo 'rebase -i script after editing:'
-cat "$1"
-EOF
+ test -z "$EXPECT_COUNT" ||
+ test "$EXPECT_COUNT" = $(sed -e '/^#/d' -e '/^$/d' < "$1" | wc -l) ||
+ exit
+ test -z "$FAKE_LINES" && exit
+ grep -v '^#' < "$1" > "$1".tmp
+ rm -f "$1"
+ echo 'rebase -i script before editing:'
+ cat "$1".tmp
+ action=pick
+ for line in $FAKE_LINES; do
+ case $line in
+ squash|fixup|edit|reword)
+ action="$line";;
+ exec*)
+ echo "$line" | sed 's/_/ /g' >> "$1";;
+ "#")
+ echo '# comment' >> "$1";;
+ ">")
+ echo >> "$1";;
+ *)
+ sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
+ action=pick;;
+ esac
+ done
+ echo 'rebase -i script after editing:'
+ cat "$1"
+ EOF
+
+ test_set_editor "$(pwd)/fake-editor.sh"
+}
+
+# After set_cat_todo_editor, rebase -i will write the todo list (ignoring
+# blank lines and comments) to stdout, and exit failure (so you should run
+# it with test_must_fail). This can be used to verify the expected user
+# experience, for todo list changes that do not affect the outcome of
+# rebase; or as an extra check in addition to checking the outcome.
+set_cat_todo_editor () {
+ write_script fake-editor.sh <<-\EOF
+ grep "^[^#]" "$1"
+ exit 1
+ EOF
test_set_editor "$(pwd)/fake-editor.sh"
- chmod a+x fake-editor.sh
+}
+
+# checks that the revisions in "$2" represent a linear range with the
+# subjects in "$1"
+test_linear_range () {
+ revlist_merges=$(git rev-list --merges "$2") &&
+ test -z "$revlist_merges" &&
+ expected=$1
+ set -- $(git log --reverse --format=%s "$2")
+ test "$expected" = "$*"
+}
+
+reset_rebase () {
+ test_might_fail git rebase --abort &&
+ git reset --hard &&
+ git clean -f
+}
+
+cherry_pick () {
+ git cherry-pick -n "$2" &&
+ git commit -m "$1" &&
+ git tag "$1"
+}
+
+revert () {
+ git revert -n "$2" &&
+ git commit -m "$1" &&
+ git tag "$1"
+}
+
+make_empty () {
+ git commit --allow-empty -m "$1" &&
+ git tag "$1"
}
diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh
index ea25dd8..3f2d873 100644
--- a/t/lib-t6000.sh
+++ b/t/lib-t6000.sh
@@ -1,55 +1,50 @@
: included from 6002 and others
-[ -d .git/refs/tags ] || mkdir -p .git/refs/tags
+mkdir -p .git/refs/tags
-:> sed.script
+>sed.script
-# Answer the sha1 has associated with the tag. The tag must exist in .git or .git/refs/tags
-tag()
-{
+# Answer the sha1 has associated with the tag. The tag must exist in .git/refs/tags
+tag () {
_tag=$1
- [ -f .git/refs/tags/$_tag ] || error "tag: \"$_tag\" does not exist"
- cat .git/refs/tags/$_tag
+ test -f ".git/refs/tags/$_tag" || error "tag: \"$_tag\" does not exist"
+ cat ".git/refs/tags/$_tag"
}
# Generate a commit using the text specified to make it unique and the tree
# named by the tag specified.
-unique_commit()
-{
+unique_commit () {
_text=$1
- _tree=$2
+ _tree=$2
shift 2
- echo $_text | git commit-tree $(tag $_tree) "$@"
+ echo "$_text" | git commit-tree $(tag "$_tree") "$@"
}
# Save the output of a command into the tag specified. Prepend
# a substitution script for the tag onto the front of sed.script
-save_tag()
-{
+save_tag () {
_tag=$1
- [ -n "$_tag" ] || error "usage: save_tag tag commit-args ..."
+ test -n "$_tag" || error "usage: save_tag tag commit-args ..."
shift 1
- "$@" >.git/refs/tags/$_tag
+ "$@" >".git/refs/tags/$_tag"
- echo "s/$(tag $_tag)/$_tag/g" > sed.script.tmp
- cat sed.script >> sed.script.tmp
+ echo "s/$(tag $_tag)/$_tag/g" >sed.script.tmp
+ cat sed.script >>sed.script.tmp
rm sed.script
mv sed.script.tmp sed.script
}
-# Replace unhelpful sha1 hashses with their symbolic equivalents
-entag()
-{
+# Replace unhelpful sha1 hashes with their symbolic equivalents
+entag () {
sed -f sed.script
}
# Execute a command after first saving, then setting the GIT_AUTHOR_EMAIL
# tag to a specified value. Restore the original value on return.
-as_author()
-{
+as_author () {
_author=$1
shift 1
- _save=$GIT_AUTHOR_EMAIL
+ _save=$GIT_AUTHOR_EMAIL
GIT_AUTHOR_EMAIL="$_author"
export GIT_AUTHOR_EMAIL
@@ -63,45 +58,58 @@ as_author()
fi
}
-commit_date()
-{
- _commit=$1
- git cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p"
+commit_date () {
+ _commit=$1
+ git cat-file commit $_commit |
+ sed -n "s/^committer .*> \([0-9]*\) .*/\1/p"
}
-on_committer_date()
-{
- _date=$1
- shift 1
- GIT_COMMITTER_DATE="$_date"
- export GIT_COMMITTER_DATE
- "$@"
- unset GIT_COMMITTER_DATE
+# Assign the value of fake date to a variable, but
+# allow fairly common "1971-08-16 00:00" to be omittd
+assign_fake_date () {
+ case "$2" in
+ ??:??:??) eval "$1='1971-08-16 $2'" ;;
+ ??:??) eval "$1='1971-08-16 00:$2'" ;;
+ ??) eval "$1='1971-08-16 00:00:$2'" ;;
+ *) eval "$1='$2'" ;;
+ esac
+}
+
+on_committer_date () {
+ assign_fake_date GIT_COMMITTER_DATE "$1"
+ export GIT_COMMITTER_DATE
+ shift 1
+ "$@"
+}
+
+on_dates () {
+ assign_fake_date GIT_COMMITTER_DATE "$1"
+ assign_fake_date GIT_AUTHOR_DATE "$2"
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+ shift 2
+ "$@"
}
# Execute a command and suppress any error output.
-hide_error()
-{
+hide_error () {
"$@" 2>/dev/null
}
-check_output()
-{
+check_output () {
_name=$1
shift 1
- if eval "$*" | entag > $_name.actual
+ if eval "$*" | entag >"$_name.actual"
then
- test_cmp $_name.expected $_name.actual
+ test_cmp "$_name.expected" "$_name.actual"
else
- return 1;
+ return 1
fi
}
# Turn a reasonable test description into a reasonable test name.
# All alphanums translated into -'s which are then compressed and stripped
# from front and back.
-name_from_description()
-{
+name_from_description () {
perl -pe '
s/[^A-Za-z0-9.]/-/g;
s/-+/-/g;
@@ -119,9 +127,11 @@ name_from_description()
test_output_expect_success()
{
_description=$1
- _test=$2
- [ $# -eq 2 ] || error "usage: test_output_expect_success description test <<EOF ... EOF"
- _name=$(echo $_description | name_from_description)
- cat > $_name.expected
+ _test=$2
+ test $# -eq 2 ||
+ error "usage: test_output_expect_success description test <<EOF ... EOF"
+
+ _name=$(echo $_description | name_from_description)
+ cat >"$_name.expected"
test_expect_success "$_description" "check_output $_name \"$_test\""
}
diff --git a/t/perf/README b/t/perf/README
index c552f56..8848c14 100644
--- a/t/perf/README
+++ b/t/perf/README
@@ -66,7 +66,7 @@ You can set the following variables (also in your config.mak):
GIT_PERF_LARGE_REPO
Repositories to copy for the performance tests. The normal
repo should be at least git.git size. The large repo should
- probably be about linux-2.6.git size for optimal results.
+ probably be about linux.git size for optimal results.
Both default to the git.git you are running from.
You can also pass the options taken by ordinary git tests; the most
diff --git a/t/perf/p0002-read-cache.sh b/t/perf/p0002-read-cache.sh
new file mode 100755
index 0000000..9180ae9
--- /dev/null
+++ b/t/perf/p0002-read-cache.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+test_description="Tests performance of reading the index"
+
+. ./perf-lib.sh
+
+test_perf_default_repo
+
+count=1000
+test_perf "read_cache/discard_cache $count times" "
+ test-read-cache $count
+"
+
+test_done
diff --git a/t/perf/p4211-line-log.sh b/t/perf/p4211-line-log.sh
new file mode 100755
index 0000000..3d074b0
--- /dev/null
+++ b/t/perf/p4211-line-log.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+test_description='Tests log -L performance'
+. ./perf-lib.sh
+
+test_perf_default_repo
+
+# Pick a file to log pseudo-randomly. The sort key is the blob hash,
+# so it is stable.
+test_expect_success 'select a file' '
+ git ls-tree HEAD | grep ^100644 |
+ sort -k 3 | head -1 | cut -f 2 >filelist
+'
+
+file=$(cat filelist)
+export file
+
+test_perf 'git rev-list --topo-order (baseline)' '
+ git rev-list --topo-order HEAD >/dev/null
+'
+
+test_perf 'git log --follow (baseline for -M)' '
+ git log --oneline --follow -- "$file" >/dev/null
+'
+
+test_perf 'git log -L' '
+ git log -L 1:"$file" >/dev/null
+'
+
+test_perf 'git log -M -L' '
+ git log -M -L 1:"$file" >/dev/null
+'
+
+test_done
diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh
index a816fbc..f4eecaa 100644
--- a/t/perf/perf-lib.sh
+++ b/t/perf/perf-lib.sh
@@ -150,6 +150,7 @@ exit $ret' >&3 2>&4
test_perf () {
+ test_start_
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 2 ||
error "bug in the test script: not 2 or 3 parameters to test-expect-success"
@@ -160,7 +161,7 @@ test_perf () {
echo "$test_count" >>"$perf_results_dir"/$base.subtests
echo "$1" >"$perf_results_dir"/$base.$test_count.descr
if test -z "$verbose"; then
- echo -n "perf $test_count - $1:"
+ printf "%s" "perf $test_count - $1:"
else
echo "perf $test_count - $1:"
fi
@@ -169,7 +170,7 @@ test_perf () {
if test_run_perf_ "$2"
then
if test -z "$verbose"; then
- echo -n " $i"
+ printf " %s" "$i"
else
echo "* timing run $i/$GIT_PERF_REPEAT_COUNT:"
fi
@@ -187,7 +188,7 @@ test_perf () {
base="$perf_results_dir"/"$perf_results_prefix$(basename "$0" .sh)"."$test_count"
"$TEST_DIRECTORY"/perf/min_time.perl test_time.* >"$base".times
fi
- echo >&3 ""
+ test_finish_
}
# We extend test_done to print timings at the end (./run disables this
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index cefe33d..10be52b 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -47,8 +47,14 @@ test_expect_failure 'pretend we have a known breakage' '
run_sub_test_lib_test () {
name="$1" descr="$2" # stdin is the body of the test code
+ shift 2
mkdir "$name" &&
(
+ # Pretend we're a test harness. This prevents
+ # test-lib from writing the counts to a file that will
+ # later be summarized, showing spurious "failed" tests
+ HARNESS_ACTIVE=t &&
+ export HARNESS_ACTIVE &&
cd "$name" &&
cat >"$name.sh" <<-EOF &&
#!$SHELL_PATH
@@ -65,7 +71,7 @@ run_sub_test_lib_test () {
cat >>"$name.sh" &&
chmod +x "$name.sh" &&
export TEST_DIRECTORY &&
- ./"$name.sh" >out 2>err
+ ./"$name.sh" "$@" >out 2>err
)
}
@@ -215,6 +221,60 @@ test_expect_success 'pretend we have a mix of all possible results' "
EOF
"
+test_expect_success 'test --verbose' '
+ test_must_fail run_sub_test_lib_test \
+ test-verbose "test verbose" --verbose <<-\EOF &&
+ test_expect_success "passing test" true
+ test_expect_success "test with output" "echo foo"
+ test_expect_success "failing test" false
+ test_done
+ EOF
+ mv test-verbose/out test-verbose/out+
+ grep -v "^Initialized empty" test-verbose/out+ >test-verbose/out &&
+ check_sub_test_lib_test test-verbose <<-\EOF
+ > expecting success: true
+ > Z
+ > ok 1 - passing test
+ > Z
+ > expecting success: echo foo
+ > foo
+ > Z
+ > ok 2 - test with output
+ > Z
+ > expecting success: false
+ > Z
+ > not ok 3 - failing test
+ > # false
+ > Z
+ > # failed 1 among 3 test(s)
+ > 1..3
+ EOF
+'
+
+test_expect_success 'test --verbose-only' '
+ test_must_fail run_sub_test_lib_test \
+ test-verbose-only-2 "test verbose-only=2" \
+ --verbose-only=2 <<-\EOF &&
+ test_expect_success "passing test" true
+ test_expect_success "test with output" "echo foo"
+ test_expect_success "failing test" false
+ test_done
+ EOF
+ check_sub_test_lib_test test-verbose-only-2 <<-\EOF
+ > ok 1 - passing test
+ > Z
+ > expecting success: echo foo
+ > foo
+ > Z
+ > ok 2 - test with output
+ > Z
+ > not ok 3 - failing test
+ > # false
+ > # failed 1 among 3 test(s)
+ > 1..3
+ EOF
+'
+
test_set_prereq HAVEIT
haveit=no
test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
@@ -367,22 +427,6 @@ test_expect_success 'validate object ID of a known tree' '
# Various types of objects
-# Some filesystems do not support symblic links; on such systems
-# some expected values are different
-if test_have_prereq SYMLINKS
-then
- expectfilter=cat
- expectedtree=087704a96baf1c2d1c869a8b084481e121c88b5b
- expectedptree1=21ae8269cacbe57ae09138dcc3a2887f904d02b3
- expectedptree2=3c5e5399f3a333eddecce7a9b9465b63f65f51e2
-else
- expectfilter='grep -v sym'
- expectedtree=8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46
- expectedptree1=cfb8591b2f65de8b8cc1020cd7d9e67e7793b325
- expectedptree2=ce580448f0148b985a513b693fdf7d802cacb44f
-fi
-
-
test_expect_success 'adding various types of objects with git update-index --add' '
mkdir path2 path3 path3/subp3 &&
paths="path0 path2/file2 path3/file3 path3/subp3/file3" &&
@@ -390,10 +434,7 @@ test_expect_success 'adding various types of objects with git update-index --add
for p in $paths
do
echo "hello $p" >$p || exit 1
- if test_have_prereq SYMLINKS
- then
- ln -s "hello $p" ${p}sym || exit 1
- fi
+ test_ln_s_add "hello $p" ${p}sym || exit 1
done
) &&
find path* ! -type d -print | xargs git update-index --add
@@ -405,7 +446,7 @@ test_expect_success 'showing stage with git ls-files --stage' '
'
test_expect_success 'validate git ls-files output for a known tree' '
- $expectfilter >expected <<-\EOF &&
+ cat >expected <<-\EOF &&
100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0
120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym
100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2
@@ -423,14 +464,14 @@ test_expect_success 'writing tree out with git write-tree' '
'
test_expect_success 'validate object ID for a known tree' '
- test "$tree" = "$expectedtree"
+ test "$tree" = 087704a96baf1c2d1c869a8b084481e121c88b5b
'
test_expect_success 'showing tree with git ls-tree' '
git ls-tree $tree >current
'
-test_expect_success SYMLINKS 'git ls-tree output for a known tree' '
+test_expect_success 'git ls-tree output for a known tree' '
cat >expected <<-\EOF &&
100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
@@ -447,7 +488,7 @@ test_expect_success 'showing tree with git ls-tree -r' '
'
test_expect_success 'git ls-tree -r output for a known tree' '
- $expectfilter >expected <<-\EOF &&
+ cat >expected <<-\EOF &&
100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
@@ -465,7 +506,7 @@ test_expect_success 'showing tree with git ls-tree -r -t' '
git ls-tree -r -t $tree >current
'
-test_expect_success SYMLINKS 'git ls-tree -r output for a known tree' '
+test_expect_success 'git ls-tree -r output for a known tree' '
cat >expected <<-\EOF &&
100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
@@ -487,7 +528,7 @@ test_expect_success 'writing partial tree out with git write-tree --prefix' '
'
test_expect_success 'validate object ID for a known tree' '
- test "$ptree" = "$expectedptree1"
+ test "$ptree" = 21ae8269cacbe57ae09138dcc3a2887f904d02b3
'
test_expect_success 'writing partial tree out with git write-tree --prefix' '
@@ -495,7 +536,7 @@ test_expect_success 'writing partial tree out with git write-tree --prefix' '
'
test_expect_success 'validate object ID for a known tree' '
- test "$ptree" = "$expectedptree2"
+ test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2
'
test_expect_success 'put invalid objects into the index' '
@@ -529,7 +570,7 @@ test_expect_success 'git read-tree followed by write-tree should be idempotent'
'
test_expect_success 'validate git diff-files output for a know cache/work tree state' '
- $expectfilter >expected <<\EOF &&
+ cat >expected <<\EOF &&
:100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M path0
:120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M path0sym
:100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M path2/file2
@@ -553,7 +594,7 @@ test_expect_success 'no diff after checkout and git update-index --refresh' '
'
################################################################
-P=$expectedtree
+P=087704a96baf1c2d1c869a8b084481e121c88b5b
test_expect_success 'git commit-tree records the correct tree in a commit' '
commit0=$(echo NO | git commit-tree $P) &&
diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh
index 93e58c0..981437b 100755
--- a/t/t0005-signals.sh
+++ b/t/t0005-signals.sh
@@ -20,4 +20,11 @@ test_expect_success 'sigchain works' '
test_cmp expect actual
'
+test_expect_success !MINGW 'signals are propagated using shell convention' '
+ # we use exec here to avoid any sub-shell interpretation
+ # of the exit code
+ git config alias.sigterm "!exec test-sigchain" &&
+ test_expect_code 143 git sigterm
+'
+
test_done
diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index 9c1bde1..96f40fe 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -66,16 +66,23 @@ test_check_ignore () {
init_vars &&
rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
- echo git $global_args check-ignore $quiet_opt $verbose_opt $args \
+ echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
>"$HOME/cmd" &&
+ echo "$expect_code" >"$HOME/expected-exit-code" &&
test_expect_code "$expect_code" \
- git $global_args check-ignore $quiet_opt $verbose_opt $args \
+ git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
>"$HOME/stdout" 2>"$HOME/stderr" &&
test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
stderr_empty_on_success "$expect_code"
}
-# Runs the same code with 3 different levels of output verbosity,
+# Runs the same code with 4 different levels of output verbosity:
+#
+# 1. with -q / --quiet
+# 2. with default verbosity
+# 3. with -v / --verbose
+# 4. with -v / --verbose, *and* -n / --non-matching
+#
# expecting success each time. Takes advantage of the fact that
# check-ignore --verbose output is the same as normal output except
# for the extra first column.
@@ -83,7 +90,9 @@ test_check_ignore () {
# Arguments:
# - (optional) prereqs for this test, e.g. 'SYMLINKS'
# - test name
-# - output to expect from -v / --verbose mode
+# - output to expect from the fourth verbosity mode (the output
+# from the other verbosity modes is automatically inferred
+# from this value)
# - code to run (should invoke test_check_ignore)
test_expect_success_multi () {
prereq=
@@ -92,8 +101,9 @@ test_expect_success_multi () {
prereq=$1
shift
fi
- testname="$1" expect_verbose="$2" code="$3"
+ testname="$1" expect_all="$2" code="$3"
+ expect_verbose=$( echo "$expect_all" | grep -v '^:: ' )
expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
test_expect_success $prereq "$testname" '
@@ -101,23 +111,40 @@ test_expect_success_multi () {
eval "$code"
'
- for quiet_opt in '-q' '--quiet'
- do
- test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
+ # --quiet is only valid when a single pattern is passed
+ if test $( echo "$expect_all" | wc -l ) = 1
+ then
+ for quiet_opt in '-q' '--quiet'
+ do
+ test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
expect '' &&
$code
"
- done
- quiet_opt=
+ done
+ quiet_opt=
+ fi
for verbose_opt in '-v' '--verbose'
do
- test_expect_success $prereq "$testname${verbose_opt:+ with $verbose_opt}" "
- expect '$expect_verbose' &&
- $code
- "
+ for non_matching_opt in '' ' -n' ' --non-matching'
+ do
+ if test -n "$non_matching_opt"
+ then
+ my_expect="$expect_all"
+ else
+ my_expect="$expect_verbose"
+ fi
+
+ test_code="
+ expect '$my_expect' &&
+ $code
+ "
+ opts="$verbose_opt$non_matching_opt"
+ test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code"
+ done
done
verbose_opt=
+ non_matching_opt=
}
test_expect_success 'setup' '
@@ -178,7 +205,7 @@ test_expect_success 'setup' '
#
# test invalid inputs
-test_expect_success_multi '. corner-case' '' '
+test_expect_success_multi '. corner-case' ':: .' '
test_check_ignore . 1
'
@@ -189,11 +216,7 @@ test_expect_success_multi 'empty command line' '' '
test_expect_success_multi '--stdin with empty STDIN' '' '
test_check_ignore "--stdin" 1 </dev/null &&
- if test -n "$quiet_opt"; then
- test_stderr ""
- else
- test_stderr "no pathspec given."
- fi
+ test_stderr ""
'
test_expect_success '-q with multiple args' '
@@ -276,27 +299,39 @@ do
where="in subdir $subdir"
fi
- test_expect_success_multi "non-existent file $where not ignored" '' "
- test_check_ignore '${subdir}non-existent' 1
- "
+ test_expect_success_multi "non-existent file $where not ignored" \
+ ":: ${subdir}non-existent" \
+ "test_check_ignore '${subdir}non-existent' 1"
test_expect_success_multi "non-existent file $where ignored" \
- ".gitignore:1:one ${subdir}one" "
- test_check_ignore '${subdir}one'
- "
+ ".gitignore:1:one ${subdir}one" \
+ "test_check_ignore '${subdir}one'"
- test_expect_success_multi "existing untracked file $where not ignored" '' "
- test_check_ignore '${subdir}not-ignored' 1
- "
+ test_expect_success_multi "existing untracked file $where not ignored" \
+ ":: ${subdir}not-ignored" \
+ "test_check_ignore '${subdir}not-ignored' 1"
- test_expect_success_multi "existing tracked file $where not ignored" '' "
- test_check_ignore '${subdir}ignored-but-in-index' 1
- "
+ test_expect_success_multi "existing tracked file $where not ignored" \
+ ":: ${subdir}ignored-but-in-index" \
+ "test_check_ignore '${subdir}ignored-but-in-index' 1"
test_expect_success_multi "existing untracked file $where ignored" \
- ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" "
- test_check_ignore '${subdir}ignored-and-untracked'
- "
+ ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+ "test_check_ignore '${subdir}ignored-and-untracked'"
+
+ test_expect_success_multi "mix of file types $where" \
+":: ${subdir}non-existent
+.gitignore:1:one ${subdir}one
+:: ${subdir}not-ignored
+:: ${subdir}ignored-but-in-index
+.gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+ "test_check_ignore '
+ ${subdir}non-existent
+ ${subdir}one
+ ${subdir}not-ignored
+ ${subdir}ignored-but-in-index
+ ${subdir}ignored-and-untracked'
+ "
done
# Having established the above, from now on we mostly test against
@@ -391,13 +426,13 @@ test_expect_success 'cd to ignored sub-directory with -v' '
#
# test handling of symlinks
-test_expect_success_multi SYMLINKS 'symlink' '' '
+test_expect_success_multi SYMLINKS 'symlink' ':: a/symlink' '
test_check_ignore "a/symlink" 1
'
test_expect_success_multi SYMLINKS 'beyond a symlink' '' '
test_check_ignore "a/symlink/foo" 128 &&
- test_stderr "fatal: '\''a/symlink/foo'\'' is beyond a symbolic link"
+ test_stderr "fatal: pathspec '\''a/symlink/foo'\'' is beyond a symbolic link"
'
test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
@@ -405,7 +440,7 @@ test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
cd a &&
test_check_ignore "symlink/foo" 128
) &&
- test_stderr "fatal: '\''symlink/foo'\'' is beyond a symbolic link"
+ test_stderr "fatal: pathspec '\''symlink/foo'\'' is beyond a symbolic link"
'
############################################################################
@@ -414,7 +449,7 @@ test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
test_expect_success_multi 'submodule' '' '
test_check_ignore "a/submodule/one" 128 &&
- test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
+ test_stderr "fatal: Pathspec '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
'
test_expect_success_multi 'submodule from subdirectory' '' '
@@ -422,7 +457,7 @@ test_expect_success_multi 'submodule from subdirectory' '' '
cd a &&
test_check_ignore "submodule/one" 128
) &&
- test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
+ test_stderr "fatal: Pathspec '\''submodule/one'\'' is in submodule '\''a/submodule'\''"
'
############################################################################
@@ -574,37 +609,34 @@ cat <<-\EOF >stdin
globaltwo
b/globaltwo
../b/globaltwo
+ c/not-ignored
EOF
-cat <<-\EOF >expected-default
- ../one
- one
- b/on
- b/one
- b/one one
- b/one two
- "b/one\"three"
- b/two
- b/twooo
- ../globaltwo
- globaltwo
- b/globaltwo
- ../b/globaltwo
-EOF
-cat <<-EOF >expected-verbose
+# N.B. we deliberately end STDIN with a non-matching pattern in order
+# to test that the exit code indicates that one or more of the
+# provided paths is ignored - in other words, that it represents an
+# aggregation of all the results, not just the final result.
+
+cat <<-EOF >expected-all
.gitignore:1:one ../one
+ :: ../not-ignored
.gitignore:1:one one
+ :: not-ignored
a/b/.gitignore:8:!on* b/on
a/b/.gitignore:8:!on* b/one
a/b/.gitignore:8:!on* b/one one
a/b/.gitignore:8:!on* b/one two
a/b/.gitignore:8:!on* "b/one\"three"
a/b/.gitignore:9:!two b/two
+ :: b/not-ignored
a/.gitignore:1:two* b/twooo
$global_excludes:2:!globaltwo ../globaltwo
$global_excludes:2:!globaltwo globaltwo
$global_excludes:2:!globaltwo b/globaltwo
$global_excludes:2:!globaltwo ../b/globaltwo
+ :: c/not-ignored
EOF
+grep -v '^:: ' expected-all >expected-verbose
+sed -e 's/.* //' expected-verbose >expected-default
sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
tr "\n" "\0" >stdin0
@@ -629,6 +661,14 @@ test_expect_success '--stdin from subdirectory with -v' '
)
'
+test_expect_success '--stdin from subdirectory with -v -n' '
+ expect_from_stdin <expected-all &&
+ (
+ cd a &&
+ test_check_ignore "--stdin -v -n" <../stdin
+ )
+'
+
for opts in '--stdin -z' '-z --stdin'
do
test_expect_success "$opts from subdirectory" '
@@ -648,5 +688,31 @@ do
'
done
+test_expect_success PIPE 'streaming support for --stdin' '
+ mkfifo in out &&
+ (git check-ignore -n -v --stdin <in >out &) &&
+
+ # We cannot just "echo >in" because check-ignore would get EOF
+ # after echo exited; instead we open the descriptor in our
+ # shell, and then echo to the fd. We make sure to close it at
+ # the end, so that the subprocess does get EOF and dies
+ # properly.
+ #
+ # Similarly, we must keep "out" open so that check-ignore does
+ # not ever get SIGPIPE trying to write to us. Not only would that
+ # produce incorrect results, but then there would be no writer on the
+ # other end of the pipe, and we would potentially block forever trying
+ # to open it.
+ exec 9>in &&
+ exec 8<out &&
+ test_when_finished "exec 9>&-" &&
+ test_when_finished "exec 8<&-" &&
+ echo >&9 one &&
+ read response <&8 &&
+ echo "$response" | grep "^\.gitignore:1:one one" &&
+ echo >&9 two &&
+ read response <&8 &&
+ echo "$response" | grep "^:: two"
+'
test_done
diff --git a/t/t0009-prio-queue.sh b/t/t0009-prio-queue.sh
new file mode 100755
index 0000000..94045c3
--- /dev/null
+++ b/t/t0009-prio-queue.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='basic tests for priority queue implementation'
+. ./test-lib.sh
+
+cat >expect <<'EOF'
+1
+2
+3
+4
+5
+5
+6
+7
+8
+9
+10
+EOF
+test_expect_success 'basic ordering' '
+ test-prio-queue 2 6 3 10 9 5 7 4 5 8 1 dump >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+2
+3
+4
+1
+5
+6
+EOF
+test_expect_success 'mixed put and get' '
+ test-prio-queue 6 2 4 get 5 3 get get 1 dump >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+1
+2
+NULL
+1
+2
+NULL
+EOF
+test_expect_success 'notice empty queue' '
+ test-prio-queue 1 2 get get get 1 2 get get get >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index 1a8f44c..e526184 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -81,6 +81,14 @@ test_expect_success 'safecrlf: print warning only once' '
test $(git add doublewarn 2>&1 | grep "CRLF will be replaced by LF" | wc -l) = 1
'
+
+test_expect_success 'safecrlf: git diff demotes safecrlf=true to warn' '
+ git config core.autocrlf input &&
+ git config core.safecrlf true &&
+ git diff HEAD
+'
+
+
test_expect_success 'switch off autocrlf, safecrlf, reset HEAD' '
git config core.autocrlf false &&
git config core.safecrlf false &&
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index e50f0f7..b92e6cb 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -190,4 +190,18 @@ test_expect_success 'required filter clean failure' '
test_must_fail git add test.fc
'
+test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
+
+test_expect_success EXPENSIVE 'filter large file' '
+ git config filter.largefile.smudge cat &&
+ git config filter.largefile.clean cat &&
+ for i in $(test_seq 1 2048); do printf "%1048576d" 1; done >2GB &&
+ echo "2GB filter=largefile" >.gitattributes &&
+ git add 2GB 2>err &&
+ ! test -s err &&
+ rm -f 2GB &&
+ git checkout -- 2GB 2>err &&
+ ! test -s err
+'
+
test_done
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index 244a43c..65606df 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -50,7 +50,7 @@ EOF
test_expect_success 'test help' '
test_must_fail test-parse-options -h > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_i18ncmp expect output
'
@@ -75,7 +75,7 @@ check() {
shift &&
sed "s/^$what .*/$what $expect/" <expect.template >expect &&
test-parse-options $* >output 2>output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
}
@@ -86,7 +86,7 @@ check_i18n() {
shift &&
sed "s/^$what .*/$what $expect/" <expect.template >expect &&
test-parse-options $* >output 2>output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_i18ncmp expect output
}
@@ -99,7 +99,7 @@ check_unknown() {
esac &&
cat expect.err >>expect &&
test_must_fail test-parse-options $* >output 2>output.err &&
- test ! -s output &&
+ test_must_be_empty output &&
test_cmp expect output.err
}
@@ -112,7 +112,7 @@ check_unknown_i18n() {
esac &&
cat expect.err >>expect &&
test_must_fail test-parse-options $* >output 2>output.err &&
- test ! -s output &&
+ test_must_be_empty output &&
test_i18ncmp expect output.err
}
@@ -149,7 +149,7 @@ test_expect_success 'short options' '
test-parse-options -s123 -b -i 1729 -b -vv -n -F my.file \
> output 2> output.err &&
test_cmp expect output &&
- test ! -s output.err
+ test_must_be_empty output.err
'
cat > expect << EOF
@@ -168,7 +168,7 @@ test_expect_success 'long options' '
test-parse-options --boolean --integer 1729 --boolean --string2=321 \
--verbose --verbose --no-dry-run --abbrev=10 --file fi.le\
--obsolete > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -199,7 +199,7 @@ EOF
test_expect_success 'intermingled arguments' '
test-parse-options a1 --string 123 b1 --boolean -j 13 -- --boolean \
> output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -217,13 +217,13 @@ EOF
test_expect_success 'unambiguously abbreviated option' '
test-parse-options --int 2 --boolean --no-bo > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
test_expect_success 'unambiguously abbreviated option with "="' '
test-parse-options --int=2 > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -246,7 +246,7 @@ EOF
test_expect_success 'non ambiguous option (after two options it abbreviates)' '
test-parse-options --st 123 > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -256,7 +256,7 @@ EOF
test_expect_success 'detect possible typos' '
test_must_fail test-parse-options -boolean > output 2> output.err &&
- test ! -s output &&
+ test_must_be_empty output &&
test_cmp typo.err output.err
'
@@ -266,7 +266,7 @@ EOF
test_expect_success 'detect possible typos' '
test_must_fail test-parse-options -ambiguous > output 2> output.err &&
- test ! -s output &&
+ test_must_be_empty output &&
test_cmp typo.err output.err
'
@@ -285,7 +285,7 @@ EOF
test_expect_success 'keep some options as arguments' '
test-parse-options --quux > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -305,7 +305,7 @@ EOF
test_expect_success 'OPT_DATE() and OPT_SET_PTR() work' '
test-parse-options -t "1970-01-01 00:00:01 +0000" --default-string \
foo -q > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -324,7 +324,7 @@ EOF
test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' '
test-parse-options --length=four -b -4 > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -352,13 +352,13 @@ EOF
test_expect_success 'OPT_BIT() and OPT_SET_INT() work' '
test-parse-options --set23 -bbbbb --no-or4 > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' '
test-parse-options --set23 -bbbbb --neg-or4 > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -376,19 +376,19 @@ EOF
test_expect_success 'OPT_BIT() works' '
test-parse-options -bb --or4 > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
test_expect_success 'OPT_NEGBIT() works' '
test-parse-options -bb --no-neg-or4 > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' '
test-parse-options + + + + + + > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -406,7 +406,7 @@ EOF
test_expect_success 'OPT_NUMBER_CALLBACK() works' '
test-parse-options -12345 > output 2> output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
@@ -424,7 +424,7 @@ EOF
test_expect_success 'negation of OPT_NONEG flags is not ambiguous' '
test-parse-options --no-ambig >output 2>output.err &&
- test ! -s output.err &&
+ test_must_be_empty output.err &&
test_cmp expect output
'
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 09a42a4..3a48de2 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -8,8 +8,15 @@ test_description='Test various path utilities'
. ./test-lib.sh
norm_path() {
+ expected=$(test-path-utils mingw_path "$2")
test_expect_success $3 "normalize path: $1 => $2" \
- "test \"\$(test-path-utils normalize_path_copy '$1')\" = '$2'"
+ "test \"\$(test-path-utils normalize_path_copy '$1')\" = '$expected'"
+}
+
+relative_path() {
+ expected=$(test-path-utils mingw_path "$3")
+ test_expect_success $4 "relative path: $1 $2 => $3" \
+ "test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
# On Windows, we are using MSYS's bash, which mangles the paths.
@@ -34,8 +41,8 @@ ancestor() {
test \"\$actual\" = '$expected'"
}
-# Absolute path tests must be skipped on Windows because due to path mangling
-# the test program never sees a POSIX-style absolute path
+# Some absolute path tests should be skipped on Windows due to path mangling
+# on POSIX-style absolute paths
case $(uname -s) in
*MINGW*)
;;
@@ -68,30 +75,30 @@ norm_path d1/s1//../s2/../../d2 d2
norm_path d1/.../d2 d1/.../d2
norm_path d1/..././../d2 d1/d2
-norm_path / / POSIX
+norm_path / /
norm_path // / POSIX
norm_path /// / POSIX
-norm_path /. / POSIX
+norm_path /. /
norm_path /./ / POSIX
norm_path /./.. ++failed++ POSIX
-norm_path /../. ++failed++ POSIX
+norm_path /../. ++failed++
norm_path /./../.// ++failed++ POSIX
norm_path /dir/.. / POSIX
norm_path /dir/sub/../.. / POSIX
norm_path /dir/sub/../../.. ++failed++ POSIX
-norm_path /dir /dir POSIX
-norm_path /dir// /dir/ POSIX
-norm_path /./dir /dir POSIX
-norm_path /dir/. /dir/ POSIX
-norm_path /dir///./ /dir/ POSIX
-norm_path /dir//sub/.. /dir/ POSIX
-norm_path /dir/sub/../ /dir/ POSIX
+norm_path /dir /dir
+norm_path /dir// /dir/
+norm_path /./dir /dir
+norm_path /dir/. /dir/
+norm_path /dir///./ /dir/
+norm_path /dir//sub/.. /dir/
+norm_path /dir/sub/../ /dir/
norm_path //dir/sub/../. /dir/ POSIX
-norm_path /dir/s1/../s2/ /dir/s2/ POSIX
-norm_path /d1/s1///s2/..//../s3/ /d1/s3/ POSIX
-norm_path /d1/s1//../s2/../../d2 /d2 POSIX
-norm_path /d1/.../d2 /d1/.../d2 POSIX
-norm_path /d1/..././../d2 /d1/d2 POSIX
+norm_path /dir/s1/../s2/ /dir/s2/
+norm_path /d1/s1///s2/..//../s3/ /d1/s3/
+norm_path /d1/s1//../s2/../../d2 /d2
+norm_path /d1/.../d2 /d1/.../d2
+norm_path /d1/..././../d2 /d1/d2
ancestor / / -1
ancestor /foo / 0
@@ -183,4 +190,33 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
'
+relative_path /a/b/c/ /a/b/ c/
+relative_path /a/b/c/ /a/b c/
+relative_path /a//b//c/ //a/b// c/ POSIX
+relative_path /a/b /a/b ./
+relative_path /a/b/ /a/b ./
+relative_path /a /a/b ../
+relative_path / /a/b/ ../../
+relative_path /a/c /a/b/ ../c
+relative_path /a/c /a/b ../c
+relative_path /x/y /a/b/ ../../x/y
+relative_path /a/b "<empty>" /a/b
+relative_path /a/b "<null>" /a/b
+relative_path a/b/c/ a/b/ c/
+relative_path a/b/c/ a/b c/
+relative_path a/b//c a//b c
+relative_path a/b/ a/b/ ./
+relative_path a/b/ a/b ./
+relative_path a a/b ../
+relative_path x/y a/b ../../x/y
+relative_path a/c a/b ../c
+relative_path a/b "<empty>" a/b
+relative_path a/b "<null>" a/b
+relative_path "<empty>" /a/b ./
+relative_path "<empty>" "<empty>" ./
+relative_path "<empty>" "<null>" ./
+relative_path "<null>" "<empty>" ./
+relative_path "<null>" "<null>" ./
+relative_path "<null>" /a/b ./
+
test_done
diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh
index 986b2a8..5ed69a6 100755
--- a/t/t0070-fundamental.sh
+++ b/t/t0070-fundamental.sh
@@ -25,6 +25,10 @@ test_expect_success POSIXPERM,SANITY 'mktemp to unwritable directory prints file
grep "cannotwrite/test" err
'
+test_expect_success 'git_mkstemps_mode does not fail if fd 0 is not open' '
+ git commit --allow-empty -m message <&-
+'
+
test_expect_success 'check for a bug in the regex routines' '
# if this test fails, re-build git with NO_REGEX=1
test-regex
diff --git a/t/t0100-previous.sh b/t/t0100-previous.sh
index 315b9b3..e0a6940 100755
--- a/t/t0100-previous.sh
+++ b/t/t0100-previous.sh
@@ -27,6 +27,7 @@ test_expect_success 'merge @{-1}' '
test_commit B &&
git checkout A &&
test_commit C &&
+ test_commit D &&
git branch -f master B &&
git branch -f other &&
git checkout other &&
@@ -35,14 +36,24 @@ test_expect_success 'merge @{-1}' '
git cat-file commit HEAD | grep "Merge branch '\''other'\''"
'
-test_expect_success 'merge @{-1} when there is not enough switches yet' '
+test_expect_success 'merge @{-1}~1' '
+ git checkout master &&
+ git reset --hard B &&
+ git checkout other &&
+ git checkout master &&
+ git merge @{-1}~1 &&
+ git cat-file commit HEAD >actual &&
+ grep "Merge branch '\''other'\''" actual
+'
+
+test_expect_success 'merge @{-100} before checking out that many branches yet' '
git reflog expire --expire=now &&
git checkout -f master &&
git reset --hard B &&
git branch -f other C &&
git checkout other &&
git checkout master &&
- test_must_fail git merge @{-12}
+ test_must_fail git merge @{-100}
'
test_done
diff --git a/t/t0110-urlmatch-normalization.sh b/t/t0110-urlmatch-normalization.sh
new file mode 100755
index 0000000..8d6096d
--- /dev/null
+++ b/t/t0110-urlmatch-normalization.sh
@@ -0,0 +1,177 @@
+#!/bin/sh
+
+test_description='urlmatch URL normalization'
+. ./test-lib.sh
+
+# The base name of the test url files
+tu="$TEST_DIRECTORY/t0110/url"
+
+# Note that only file: URLs should be allowed without a host
+
+test_expect_success 'url scheme' '
+ ! test-urlmatch-normalization "" &&
+ ! test-urlmatch-normalization "_" &&
+ ! test-urlmatch-normalization "scheme" &&
+ ! test-urlmatch-normalization "scheme:" &&
+ ! test-urlmatch-normalization "scheme:/" &&
+ ! test-urlmatch-normalization "scheme://" &&
+ ! test-urlmatch-normalization "file" &&
+ ! test-urlmatch-normalization "file:" &&
+ ! test-urlmatch-normalization "file:/" &&
+ test-urlmatch-normalization "file://" &&
+ ! test-urlmatch-normalization "://acme.co" &&
+ ! test-urlmatch-normalization "x_test://acme.co" &&
+ ! test-urlmatch-normalization "-test://acme.co" &&
+ ! test-urlmatch-normalization "0test://acme.co" &&
+ ! test-urlmatch-normalization "+test://acme.co" &&
+ ! test-urlmatch-normalization ".test://acme.co" &&
+ ! test-urlmatch-normalization "schem%6e://" &&
+ test-urlmatch-normalization "x-Test+v1.0://acme.co" &&
+ test "$(test-urlmatch-normalization -p "AbCdeF://x.Y")" = "abcdef://x.y/"
+'
+
+test_expect_success 'url authority' '
+ ! test-urlmatch-normalization "scheme://user:pass@" &&
+ ! test-urlmatch-normalization "scheme://?" &&
+ ! test-urlmatch-normalization "scheme://#" &&
+ ! test-urlmatch-normalization "scheme:///" &&
+ ! test-urlmatch-normalization "scheme://:" &&
+ ! test-urlmatch-normalization "scheme://:555" &&
+ test-urlmatch-normalization "file://user:pass@" &&
+ test-urlmatch-normalization "file://?" &&
+ test-urlmatch-normalization "file://#" &&
+ test-urlmatch-normalization "file:///" &&
+ test-urlmatch-normalization "file://:" &&
+ ! test-urlmatch-normalization "file://:555" &&
+ test-urlmatch-normalization "scheme://user:pass@host" &&
+ test-urlmatch-normalization "scheme://@host" &&
+ test-urlmatch-normalization "scheme://%00@host" &&
+ ! test-urlmatch-normalization "scheme://%%@host" &&
+ ! test-urlmatch-normalization "scheme://host_" &&
+ test-urlmatch-normalization "scheme://user:pass@host/" &&
+ test-urlmatch-normalization "scheme://@host/" &&
+ test-urlmatch-normalization "scheme://host/" &&
+ test-urlmatch-normalization "scheme://host?x" &&
+ test-urlmatch-normalization "scheme://host#x" &&
+ test-urlmatch-normalization "scheme://host/@" &&
+ test-urlmatch-normalization "scheme://host?@x" &&
+ test-urlmatch-normalization "scheme://host#@x" &&
+ test-urlmatch-normalization "scheme://[::1]" &&
+ test-urlmatch-normalization "scheme://[::1]/" &&
+ ! test-urlmatch-normalization "scheme://hos%41/" &&
+ test-urlmatch-normalization "scheme://[invalid....:/" &&
+ test-urlmatch-normalization "scheme://invalid....:]/" &&
+ ! test-urlmatch-normalization "scheme://invalid....:[/" &&
+ ! test-urlmatch-normalization "scheme://invalid....:["
+'
+
+test_expect_success 'url port checks' '
+ test-urlmatch-normalization "xyz://q@some.host:" &&
+ test-urlmatch-normalization "xyz://q@some.host:456/" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:0" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:0000000" &&
+ test-urlmatch-normalization "xyz://q@some.host:0000001?" &&
+ test-urlmatch-normalization "xyz://q@some.host:065535#" &&
+ test-urlmatch-normalization "xyz://q@some.host:65535" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:65536" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:99999" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:100000" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:100001" &&
+ test-urlmatch-normalization "http://q@some.host:80" &&
+ test-urlmatch-normalization "https://q@some.host:443" &&
+ test-urlmatch-normalization "http://q@some.host:80/" &&
+ test-urlmatch-normalization "https://q@some.host:443?" &&
+ ! test-urlmatch-normalization "http://q@:8008" &&
+ ! test-urlmatch-normalization "http://:8080" &&
+ ! test-urlmatch-normalization "http://:" &&
+ test-urlmatch-normalization "xyz://q@some.host:456/" &&
+ test-urlmatch-normalization "xyz://[::1]:456/" &&
+ test-urlmatch-normalization "xyz://[::1]:/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:000/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:0%300/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:0x80/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:4294967297/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:030f/"
+'
+
+test_expect_success 'url port normalization' '
+ test "$(test-urlmatch-normalization -p "http://x:800")" = "http://x:800/" &&
+ test "$(test-urlmatch-normalization -p "http://x:0800")" = "http://x:800/" &&
+ test "$(test-urlmatch-normalization -p "http://x:00000800")" = "http://x:800/" &&
+ test "$(test-urlmatch-normalization -p "http://x:065535")" = "http://x:65535/" &&
+ test "$(test-urlmatch-normalization -p "http://x:1")" = "http://x:1/" &&
+ test "$(test-urlmatch-normalization -p "http://x:80")" = "http://x/" &&
+ test "$(test-urlmatch-normalization -p "http://x:080")" = "http://x/" &&
+ test "$(test-urlmatch-normalization -p "http://x:000000080")" = "http://x/" &&
+ test "$(test-urlmatch-normalization -p "https://x:443")" = "https://x/" &&
+ test "$(test-urlmatch-normalization -p "https://x:0443")" = "https://x/" &&
+ test "$(test-urlmatch-normalization -p "https://x:000000443")" = "https://x/"
+'
+
+test_expect_success 'url general escapes' '
+ ! test-urlmatch-normalization "http://x.y?%fg" &&
+ test "$(test-urlmatch-normalization -p "X://W/%7e%41^%3a")" = "x://w/~A%5E%3A" &&
+ test "$(test-urlmatch-normalization -p "X://W/:/?#[]@")" = "x://w/:/?#[]@" &&
+ test "$(test-urlmatch-normalization -p "X://W/$&()*+,;=")" = "x://w/$&()*+,;=" &&
+ test "$(test-urlmatch-normalization -p "X://W/'\''")" = "x://w/'\''" &&
+ test "$(test-urlmatch-normalization -p "X://W?'\!'")" = "x://w/?'\!'"
+'
+
+test_expect_success 'url high-bit escapes' '
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-1")")" = "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-2")")" = "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-3")")" = "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-4")")" = "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-5")")" = "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-6")")" = "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-7")")" = "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-8")")" = "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-9")")" = "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-10")")" = "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-11")")" = "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD"
+'
+
+test_expect_success 'url username/password escapes' '
+ test "$(test-urlmatch-normalization -p "x://%41%62(^):%70+d@foo")" = "x://Ab(%5E):p+d@foo/"
+'
+
+test_expect_success 'url normalized lengths' '
+ test "$(test-urlmatch-normalization -l "Http://%4d%65:%4d^%70@The.Host")" = 25 &&
+ test "$(test-urlmatch-normalization -l "http://%41:%42@x.y/%61/")" = 17 &&
+ test "$(test-urlmatch-normalization -l "http://@x.y/^")" = 15
+'
+
+test_expect_success 'url . and .. segments' '
+ test "$(test-urlmatch-normalization -p "x://y/.")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/./")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/.")" = "x://y/a" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./")" = "x://y/a/" &&
+ test "$(test-urlmatch-normalization -p "x://y/.?")" = "x://y/?" &&
+ test "$(test-urlmatch-normalization -p "x://y/./?")" = "x://y/?" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/.?")" = "x://y/a?" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./?")" = "x://y/a/?" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./b/.././../c")" = "x://y/c" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./b/../.././c/")" = "x://y/c/" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./b/.././../c/././.././.")" = "x://y/" &&
+ ! test-urlmatch-normalization "x://y/a/./b/.././../c/././.././.." &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./?/././..")" = "x://y/a/?/././.." &&
+ test "$(test-urlmatch-normalization -p "x://y/%2e/")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/%2E/")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/%2e./")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/b/.%2E/")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/c/%2e%2E/")" = "x://y/"
+'
+
+# http://@foo specifies an empty user name but does not specify a password
+# http://foo specifies neither a user name nor a password
+# So they should not be equivalent
+test_expect_success 'url equivalents' '
+ test-urlmatch-normalization "httP://x" "Http://X/" &&
+ test-urlmatch-normalization "Http://%4d%65:%4d^%70@The.Host" "hTTP://Me:%4D^p@the.HOST:80/" &&
+ ! test-urlmatch-normalization "https://@x.y/^" "httpS://x.y:443/^" &&
+ test-urlmatch-normalization "https://@x.y/^" "httpS://@x.y:0443/^" &&
+ test-urlmatch-normalization "https://@x.y/^/../abc" "httpS://@x.y:0443/abc" &&
+ test-urlmatch-normalization "https://@x.y/^/.." "httpS://@x.y:0443/"
+'
+
+test_done
diff --git a/t/t0110/README b/t/t0110/README
new file mode 100644
index 0000000..ad4a50e
--- /dev/null
+++ b/t/t0110/README
@@ -0,0 +1,9 @@
+The url data files in this directory contain URLs with characters
+in the range 0x01-0x1f and 0x7f-0xff to test the proper normalization
+of unprintable characters.
+
+A select few characters in the 0x01-0x1f range are skipped to help
+avoid problems running the test itself.
+
+The urls are in test files in this directory rather than being
+embedded in the test script for portability.
diff --git a/t/t0110/url-1 b/t/t0110/url-1
new file mode 100644
index 0000000..519019c
--- /dev/null
+++ b/t/t0110/url-1
@@ -0,0 +1 @@
+x://q/
diff --git a/t/t0110/url-10 b/t/t0110/url-10
new file mode 100644
index 0000000..b9965de
--- /dev/null
+++ b/t/t0110/url-10
@@ -0,0 +1 @@
+x://q/ðñòóôõö÷øùúûüýþÿ
diff --git a/t/t0110/url-11 b/t/t0110/url-11
new file mode 100644
index 0000000..f0a50f1
--- /dev/null
+++ b/t/t0110/url-11
@@ -0,0 +1 @@
+x://q/€߿ࠀ�ð€€ð¯¿½
diff --git a/t/t0110/url-2 b/t/t0110/url-2
new file mode 100644
index 0000000..43334b0
--- /dev/null
+++ b/t/t0110/url-2
@@ -0,0 +1 @@
+x://q/
diff --git a/t/t0110/url-3 b/t/t0110/url-3
new file mode 100644
index 0000000..7378c7b
--- /dev/null
+++ b/t/t0110/url-3
@@ -0,0 +1 @@
+x://q/€‚ƒ„…†‡ˆ‰Š‹ŒŽ
diff --git a/t/t0110/url-4 b/t/t0110/url-4
new file mode 100644
index 0000000..220b198
--- /dev/null
+++ b/t/t0110/url-4
@@ -0,0 +1 @@
+x://q/‘’“”•–—˜™š›œžŸ
diff --git a/t/t0110/url-5 b/t/t0110/url-5
new file mode 100644
index 0000000..1ccd927
--- /dev/null
+++ b/t/t0110/url-5
@@ -0,0 +1 @@
+x://q/ ¡¢£¤¥¦§¨©ª«¬­®¯
diff --git a/t/t0110/url-6 b/t/t0110/url-6
new file mode 100644
index 0000000..e8283aa
--- /dev/null
+++ b/t/t0110/url-6
@@ -0,0 +1 @@
+x://q/°±²³´µ¶·¸¹º»¼½¾¿
diff --git a/t/t0110/url-7 b/t/t0110/url-7
new file mode 100644
index 0000000..fa7c10b
--- /dev/null
+++ b/t/t0110/url-7
@@ -0,0 +1 @@
+x://q/ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
diff --git a/t/t0110/url-8 b/t/t0110/url-8
new file mode 100644
index 0000000..79a0ba8
--- /dev/null
+++ b/t/t0110/url-8
@@ -0,0 +1 @@
+x://q/ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß
diff --git a/t/t0110/url-9 b/t/t0110/url-9
new file mode 100644
index 0000000..8b44bec
--- /dev/null
+++ b/t/t0110/url-9
@@ -0,0 +1 @@
+x://q/àáâãäåæçèéêëìíîï
diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh
index b3ae7d5..3e72aff 100755
--- a/t/t1004-read-tree-m-u-wf.sh
+++ b/t/t1004-read-tree-m-u-wf.sh
@@ -158,7 +158,7 @@ test_expect_success '3-way not overwriting local changes (their side)' '
'
-test_expect_success SYMLINKS 'funny symlink in work tree' '
+test_expect_success 'funny symlink in work tree' '
git reset --hard &&
git checkout -b sym-b side-b &&
@@ -170,15 +170,14 @@ test_expect_success SYMLINKS 'funny symlink in work tree' '
rm -fr a &&
git checkout -b sym-a side-a &&
mkdir -p a &&
- ln -s ../b a/b &&
- git add a/b &&
+ test_ln_s_add ../b a/b &&
git commit -m "we add a/b" &&
read_tree_u_must_succeed -m -u sym-a sym-a sym-b
'
-test_expect_success SYMLINKS,SANITY 'funny symlink in work tree, un-unlink-able' '
+test_expect_success SANITY 'funny symlink in work tree, un-unlink-able' '
rm -fr a b &&
git reset --hard &&
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 9cc5c6b..a420742 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -36,66 +36,54 @@ $content"
'
test_expect_success "Type of $type is correct" '
- test $type = "$(git cat-file -t $sha1)"
+ echo $type >expect &&
+ git cat-file -t $sha1 >actual &&
+ test_cmp expect actual
'
test_expect_success "Size of $type is correct" '
- test $size = "$(git cat-file -s $sha1)"
+ echo $size >expect &&
+ git cat-file -s $sha1 >actual &&
+ test_cmp expect actual
'
test -z "$content" ||
test_expect_success "Content of $type is correct" '
- expect="$(maybe_remove_timestamp "$content" $no_ts)"
- actual="$(maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts)"
-
- if test "z$expect" = "z$actual"
- then
- : happy
- else
- echo "Oops: expected $expect"
- echo "but got $actual"
- false
- fi
+ maybe_remove_timestamp "$content" $no_ts >expect &&
+ maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts >actual &&
+ test_cmp expect actual
'
test_expect_success "Pretty content of $type is correct" '
- expect="$(maybe_remove_timestamp "$pretty_content" $no_ts)"
- actual="$(maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts)"
- if test "z$expect" = "z$actual"
- then
- : happy
- else
- echo "Oops: expected $expect"
- echo "but got $actual"
- false
- fi
+ maybe_remove_timestamp "$pretty_content" $no_ts >expect &&
+ maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts >actual &&
+ test_cmp expect actual
'
test -z "$content" ||
test_expect_success "--batch output of $type is correct" '
- expect="$(maybe_remove_timestamp "$batch_output" $no_ts)"
- actual="$(maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts)"
- if test "z$expect" = "z$actual"
- then
- : happy
- else
- echo "Oops: expected $expect"
- echo "but got $actual"
- false
- fi
+ maybe_remove_timestamp "$batch_output" $no_ts >expect &&
+ maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts >actual &&
+ test_cmp expect actual
'
test_expect_success "--batch-check output of $type is correct" '
- expect="$sha1 $type $size"
- actual="$(echo_without_newline $sha1 | git cat-file --batch-check)"
- if test "z$expect" = "z$actual"
- then
- : happy
- else
- echo "Oops: expected $expect"
- echo "but got $actual"
- false
- fi
+ echo "$sha1 $type $size" >expect &&
+ echo_without_newline $sha1 | git cat-file --batch-check >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "custom --batch-check format" '
+ echo "$type $sha1" >expect &&
+ echo $sha1 | git cat-file --batch-check="%(objecttype) %(objectname)" >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success '--batch-check with %(rest)' '
+ echo "$type this is some extra content" >expect &&
+ echo "$sha1 this is some extra content" |
+ git cat-file --batch-check="%(objecttype) %(rest)" >actual &&
+ test_cmp expect actual
'
}
@@ -110,6 +98,14 @@ test_expect_success "setup" '
run_tests 'blob' $hello_sha1 $hello_size "$hello_content" "$hello_content"
+test_expect_success '--batch-check without %(rest) considers whole line' '
+ echo "$hello_sha1 blob $hello_size" >expect &&
+ git update-index --add --cacheinfo 100644 $hello_sha1 "white space" &&
+ test_when_finished "git update-index --remove \"white space\"" &&
+ echo ":white space" | git cat-file --batch-check >actual &&
+ test_cmp expect actual
+'
+
tree_sha1=$(git write-tree)
tree_size=33
tree_pretty_content="100644 blob $hello_sha1 hello"
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index 5c0053a..0c74bee 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -250,4 +250,28 @@ EOF
test_cmp expected actual
'
+test_expect_success 'checkout without --ignore-skip-worktree-bits' '
+ echo "*" >.git/info/sparse-checkout &&
+ git checkout -f top &&
+ test_path_is_file init.t &&
+ echo sub >.git/info/sparse-checkout &&
+ git checkout &&
+ echo modified >> sub/added &&
+ git checkout . &&
+ test_path_is_missing init.t &&
+ git diff --exit-code HEAD
+'
+
+test_expect_success 'checkout with --ignore-skip-worktree-bits' '
+ echo "*" >.git/info/sparse-checkout &&
+ git checkout -f top &&
+ test_path_is_file init.t &&
+ echo sub >.git/info/sparse-checkout &&
+ git checkout &&
+ echo modified >> sub/added &&
+ git checkout --ignore-skip-worktree-bits . &&
+ test_path_is_file init.t &&
+ git diff --exit-code HEAD
+'
+
test_done
diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh
new file mode 100755
index 0000000..3f87051
--- /dev/null
+++ b/t/t1060-object-corruption.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+test_description='see how we handle various forms of corruption'
+. ./test-lib.sh
+
+# convert "1234abcd" to ".git/objects/12/34abcd"
+obj_to_file() {
+ echo "$(git rev-parse --git-dir)/objects/$(git rev-parse "$1" | sed 's,..,&/,')"
+}
+
+# Convert byte at offset "$2" of object "$1" into '\0'
+corrupt_byte() {
+ obj_file=$(obj_to_file "$1") &&
+ chmod +w "$obj_file" &&
+ printf '\0' | dd of="$obj_file" bs=1 seek="$2" conv=notrunc
+}
+
+test_expect_success 'setup corrupt repo' '
+ git init bit-error &&
+ (
+ cd bit-error &&
+ test_commit content &&
+ corrupt_byte HEAD:content.t 10
+ )
+'
+
+test_expect_success 'setup repo with missing object' '
+ git init missing &&
+ (
+ cd missing &&
+ test_commit content &&
+ rm -f "$(obj_to_file HEAD:content.t)"
+ )
+'
+
+test_expect_success 'setup repo with misnamed object' '
+ git init misnamed &&
+ (
+ cd misnamed &&
+ test_commit content &&
+ good=$(obj_to_file HEAD:content.t) &&
+ blob=$(echo corrupt | git hash-object -w --stdin) &&
+ bad=$(obj_to_file $blob) &&
+ rm -f "$good" &&
+ mv "$bad" "$good"
+ )
+'
+
+test_expect_success 'streaming a corrupt blob fails' '
+ (
+ cd bit-error &&
+ test_must_fail git cat-file blob HEAD:content.t
+ )
+'
+
+test_expect_success 'read-tree -u detects bit-errors in blobs' '
+ (
+ cd bit-error &&
+ rm -f content.t &&
+ test_must_fail git read-tree --reset -u HEAD
+ )
+'
+
+test_expect_success 'read-tree -u detects missing objects' '
+ (
+ cd missing &&
+ rm -f content.t &&
+ test_must_fail git read-tree --reset -u HEAD
+ )
+'
+
+# We use --bare to make sure that the transport detects it, not the checkout
+# phase.
+test_expect_success 'clone --no-local --bare detects corruption' '
+ test_must_fail git clone --no-local --bare bit-error corrupt-transport
+'
+
+test_expect_success 'clone --no-local --bare detects missing object' '
+ test_must_fail git clone --no-local --bare missing missing-transport
+'
+
+test_expect_success 'clone --no-local --bare detects misnamed object' '
+ test_must_fail git clone --no-local --bare misnamed misnamed-transport
+'
+
+# We do not expect --local to detect corruption at the transport layer,
+# so we are really checking the checkout() code path.
+test_expect_success 'clone --local detects corruption' '
+ test_must_fail git clone --local bit-error corrupt-checkout
+'
+
+test_expect_success 'error detected during checkout leaves repo intact' '
+ test_path_is_dir corrupt-checkout/.git
+'
+
+test_expect_success 'clone --local detects missing objects' '
+ test_must_fail git clone --local missing missing-checkout
+'
+
+test_expect_failure 'clone --local detects misnamed objects' '
+ test_must_fail git clone --local misnamed misnamed-checkout
+'
+
+test_done
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 3c96fda..9673593 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -652,16 +652,23 @@ test_expect_success numbers '
test_cmp expect actual
'
+test_expect_success '--int is at least 64 bits' '
+ git config giga.watts 121g &&
+ echo 129922760704 >expect &&
+ git config --int --get giga.watts >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'invalid unit' '
git config aninvalid.unit "1auto" &&
echo 1auto >expect &&
git config aninvalid.unit >actual &&
test_cmp expect actual &&
- cat > expect <<-\EOF
- fatal: bad config value for '\''aninvalid.unit'\'' in .git/config
+ cat >expect <<-\EOF
+ fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in .git/config: invalid unit
EOF
test_must_fail git config --int --get aninvalid.unit 2>actual &&
- test_cmp actual expect
+ test_i18ncmp expect actual
'
cat > expect << EOF
@@ -1087,4 +1094,64 @@ test_expect_success 'barf on incomplete string' '
grep " line 3 " error
'
+test_expect_success 'urlmatch' '
+ cat >.git/config <<-\EOF &&
+ [http]
+ sslVerify
+ [http "https://weak.example.com"]
+ sslVerify = false
+ cookieFile = /tmp/cookie.txt
+ EOF
+
+ echo true >expect &&
+ git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual &&
+ test_cmp expect actual &&
+
+ echo false >expect &&
+ git config --bool --get-urlmatch http.sslverify https://weak.example.com >actual &&
+ test_cmp expect actual &&
+
+ {
+ echo http.cookiefile /tmp/cookie.txt &&
+ echo http.sslverify false
+ } >expect &&
+ git config --get-urlmatch HTTP https://weak.example.com >actual &&
+ test_cmp expect actual
+'
+
+# good section hygiene
+test_expect_failure 'unsetting the last key in a section removes header' '
+ cat >.git/config <<-\EOF &&
+ # some generic comment on the configuration file itself
+ # a comment specific to this "section" section.
+ [section]
+ # some intervening lines
+ # that should also be dropped
+
+ key = value
+ # please be careful when you update the above variable
+ EOF
+
+ cat >expect <<-\EOF &&
+ # some generic comment on the configuration file itself
+ EOF
+
+ git config --unset section.key &&
+ test_cmp expect .git/config
+'
+
+test_expect_failure 'adding a key into an empty section reuses header' '
+ cat >.git/config <<-\EOF &&
+ [section]
+ EOF
+
+ q_to_tab >expect <<-\EOF &&
+ [section]
+ Qkey = value
+ EOF
+
+ git config section.key value
+ test_cmp expect .git/config
+'
+
test_done
diff --git a/t/t1307-config-blob.sh b/t/t1307-config-blob.sh
new file mode 100755
index 0000000..fdc257e
--- /dev/null
+++ b/t/t1307-config-blob.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+test_description='support for reading config from a blob'
+. ./test-lib.sh
+
+test_expect_success 'create config blob' '
+ cat >config <<-\EOF &&
+ [some]
+ value = 1
+ EOF
+ git add config &&
+ git commit -m foo
+'
+
+test_expect_success 'list config blob contents' '
+ echo some.value=1 >expect &&
+ git config --blob=HEAD:config --list >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch value from blob' '
+ echo true >expect &&
+ git config --blob=HEAD:config --bool some.value >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'reading non-existing value from blob is an error' '
+ test_must_fail git config --blob=HEAD:config non.existing
+'
+
+test_expect_success 'reading from blob and file is an error' '
+ test_must_fail git config --blob=HEAD:config --system --list
+'
+
+test_expect_success 'reading from missing ref is an error' '
+ test_must_fail git config --blob=HEAD:doesnotexist --list
+'
+
+test_expect_success 'reading from non-blob is an error' '
+ test_must_fail git config --blob=HEAD --list
+'
+
+test_expect_success 'setting a value in a blob is an error' '
+ test_must_fail git config --blob=HEAD:config some.value foo
+'
+
+test_expect_success 'deleting a value in a blob is an error' '
+ test_must_fail git config --blob=HEAD:config --unset some.value
+'
+
+test_expect_success 'editing a blob is an error' '
+ test_must_fail git config --blob=HEAD:config --edit
+'
+
+test_expect_success 'parse errors in blobs are properly attributed' '
+ cat >config <<-\EOF &&
+ [some]
+ value = "
+ EOF
+ git add config &&
+ git commit -m broken &&
+
+ test_must_fail git config --blob=HEAD:config some.value 2>err &&
+
+ # just grep for our token as the exact error message is likely to
+ # change or be internationalized
+ grep "HEAD:config" err
+'
+
+test_done
diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
new file mode 100755
index 0000000..3e500ed
--- /dev/null
+++ b/t/t1403-show-ref.sh
@@ -0,0 +1,167 @@
+#!/bin/sh
+
+test_description='show-ref'
+. ./test-lib.sh
+
+test_expect_success setup '
+ test_commit A &&
+ git tag -f -a -m "annotated A" A &&
+ git checkout -b side &&
+ test_commit B &&
+ git tag -f -a -m "annotated B" B &&
+ git checkout master &&
+ test_commit C &&
+ git branch B A^0
+'
+
+test_expect_success 'show-ref' '
+ echo $(git rev-parse refs/tags/A) refs/tags/A >expect &&
+
+ git show-ref A >actual &&
+ test_cmp expect actual &&
+
+ git show-ref tags/A >actual &&
+ test_cmp expect actual &&
+
+ git show-ref refs/tags/A >actual &&
+ test_cmp expect actual &&
+
+ >expect &&
+
+ test_must_fail git show-ref D >actual
+ test_cmp expect actual
+'
+
+test_expect_success 'show-ref -q' '
+ >expect &&
+
+ git show-ref -q A >actual &&
+ test_cmp expect actual &&
+
+ git show-ref -q tags/A >actual &&
+ test_cmp expect actual &&
+
+ git show-ref -q refs/tags/A >actual &&
+ test_cmp expect actual &&
+
+ test_must_fail git show-ref -q D >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show-ref --verify' '
+ echo $(git rev-parse refs/tags/A) refs/tags/A >expect &&
+
+ git show-ref --verify refs/tags/A >actual &&
+ test_cmp expect actual &&
+
+ >expect &&
+
+ test_must_fail git show-ref --verify A >actual &&
+ test_cmp expect actual &&
+
+ test_must_fail git show-ref --verify tags/A >actual &&
+ test_cmp expect actual &&
+
+ test_must_fail git show-ref --verify D >actual
+ test_cmp expect actual
+'
+
+test_expect_success 'show-ref --verify -q' '
+ >expect &&
+
+ git show-ref --verify -q refs/tags/A >actual &&
+ test_cmp expect actual &&
+
+ test_must_fail git show-ref --verify -q A >actual &&
+ test_cmp expect actual &&
+
+ test_must_fail git show-ref --verify -q tags/A >actual &&
+ test_cmp expect actual &&
+
+ test_must_fail git show-ref --verify -q D >actual
+ test_cmp expect actual
+'
+
+test_expect_success 'show-ref -d' '
+ {
+ echo $(git rev-parse refs/tags/A) refs/tags/A &&
+ echo $(git rev-parse refs/tags/A^0) "refs/tags/A^{}"
+ echo $(git rev-parse refs/tags/C) refs/tags/C
+ } >expect &&
+ git show-ref -d A C >actual &&
+ test_cmp expect actual &&
+
+ git show-ref -d tags/A tags/C >actual &&
+ test_cmp expect actual &&
+
+ git show-ref -d refs/tags/A refs/tags/C >actual &&
+ test_cmp expect actual &&
+
+ echo $(git rev-parse refs/heads/master) refs/heads/master >expect &&
+ git show-ref -d master >actual &&
+ test_cmp expect actual &&
+
+ git show-ref -d heads/master >actual &&
+ test_cmp expect actual &&
+
+ git show-ref -d refs/heads/master >actual &&
+ test_cmp expect actual
+
+ git show-ref -d --verify refs/heads/master >actual &&
+ test_cmp expect actual
+
+ >expect &&
+
+ test_must_fail git show-ref -d --verify master >actual &&
+ test_cmp expect actual &&
+
+ test_must_fail git show-ref -d --verify heads/master >actual &&
+ test_cmp expect actual
+
+'
+
+test_expect_success 'show-ref --heads, --tags, --head, pattern' '
+ for branch in B master side
+ do
+ echo $(git rev-parse refs/heads/$branch) refs/heads/$branch
+ done >expect.heads &&
+ git show-ref --heads >actual &&
+ test_cmp expect.heads actual &&
+
+ for tag in A B C
+ do
+ echo $(git rev-parse refs/tags/$tag) refs/tags/$tag
+ done >expect.tags &&
+ git show-ref --tags >actual &&
+ test_cmp expect.tags actual &&
+
+ cat expect.heads expect.tags >expect &&
+ git show-ref --heads --tags >actual &&
+ test_cmp expect actual &&
+
+ {
+ echo $(git rev-parse HEAD) HEAD &&
+ cat expect.heads expect.tags
+ } >expect &&
+ git show-ref --heads --tags --head >actual &&
+ test_cmp expect actual &&
+
+ {
+ echo $(git rev-parse HEAD) HEAD &&
+ echo $(git rev-parse refs/heads/B) refs/heads/B
+ echo $(git rev-parse refs/tags/B) refs/tags/B
+ } >expect &&
+ git show-ref --head B >actual &&
+ test_cmp expect actual &&
+
+ {
+ echo $(git rev-parse HEAD) HEAD &&
+ echo $(git rev-parse refs/heads/B) refs/heads/B
+ echo $(git rev-parse refs/tags/B) refs/tags/B
+ echo $(git rev-parse refs/tags/B^0) "refs/tags/B^{}"
+ } >expect &&
+ git show-ref --head -d B >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh
index 9a105fe..6f47c0d 100755
--- a/t/t1411-reflog-show.sh
+++ b/t/t1411-reflog-show.sh
@@ -144,4 +144,26 @@ test_expect_success 'empty reflog file' '
test_cmp expect actual
'
+# This guards against the alternative of showing the diffs vs. the
+# reflog ancestor. The reflog used is designed to list the commits
+# more than once, so as to exercise the corresponding logic.
+test_expect_success 'git log -g -p shows diffs vs. parents' '
+ test_commit two &&
+ git branch flipflop &&
+ git update-ref refs/heads/flipflop -m flip1 HEAD^ &&
+ git update-ref refs/heads/flipflop -m flop1 HEAD &&
+ git update-ref refs/heads/flipflop -m flip2 HEAD^ &&
+ git log -g -p flipflop >reflog &&
+ grep -v ^Reflog reflog >actual &&
+ git log -1 -p HEAD^ >log.one &&
+ git log -1 -p HEAD >log.two &&
+ (
+ cat log.one; echo
+ cat log.two; echo
+ cat log.one; echo
+ cat log.two
+ ) >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh
index b27a720..2a19e79 100755
--- a/t/t1507-rev-parse-upstream.sh
+++ b/t/t1507-rev-parse-upstream.sh
@@ -129,8 +129,7 @@ test_expect_success 'branch@{u} works when tracking a local branch' '
test_expect_success 'branch@{u} error message when no upstream' '
cat >expect <<-EOF &&
- error: No upstream configured for branch ${sq}non-tracking${sq}
- fatal: Needed a single revision
+ fatal: No upstream configured for branch ${sq}non-tracking${sq}
EOF
error_message non-tracking@{u} 2>actual &&
test_i18ncmp expect actual
@@ -138,8 +137,7 @@ test_expect_success 'branch@{u} error message when no upstream' '
test_expect_success '@{u} error message when no upstream' '
cat >expect <<-EOF &&
- error: No upstream configured for branch ${sq}master${sq}
- fatal: Needed a single revision
+ fatal: No upstream configured for branch ${sq}master${sq}
EOF
test_must_fail git rev-parse --verify @{u} 2>actual &&
test_i18ncmp expect actual
@@ -147,8 +145,7 @@ test_expect_success '@{u} error message when no upstream' '
test_expect_success 'branch@{u} error message with misspelt branch' '
cat >expect <<-EOF &&
- error: No such branch: ${sq}no-such-branch${sq}
- fatal: Needed a single revision
+ fatal: No such branch: ${sq}no-such-branch${sq}
EOF
error_message no-such-branch@{u} 2>actual &&
test_i18ncmp expect actual
@@ -156,8 +153,7 @@ test_expect_success 'branch@{u} error message with misspelt branch' '
test_expect_success '@{u} error message when not on a branch' '
cat >expect <<-EOF &&
- error: HEAD does not point to a branch
- fatal: Needed a single revision
+ fatal: HEAD does not point to a branch
EOF
git checkout HEAD^0 &&
test_must_fail git rev-parse --verify @{u} 2>actual &&
@@ -166,8 +162,7 @@ test_expect_success '@{u} error message when not on a branch' '
test_expect_success 'branch@{u} error message if upstream branch not fetched' '
cat >expect <<-EOF &&
- error: Upstream branch ${sq}refs/heads/side${sq} not stored as a remote-tracking branch
- fatal: Needed a single revision
+ fatal: Upstream branch ${sq}refs/heads/side${sq} not stored as a remote-tracking branch
EOF
error_message bad-upstream@{u} 2>actual &&
test_i18ncmp expect actual
diff --git a/t/t1508-at-combinations.sh b/t/t1508-at-combinations.sh
index d5d6244..e5aea3b 100755
--- a/t/t1508-at-combinations.sh
+++ b/t/t1508-at-combinations.sh
@@ -4,17 +4,24 @@ test_description='test various @{X} syntax combinations together'
. ./test-lib.sh
check() {
-test_expect_${3:-success} "$1 = $2" "
- echo '$2' >expect &&
- git log -1 --format=%s '$1' >actual &&
- test_cmp expect actual
-"
+ test_expect_${4:-success} "$1 = $3" "
+ echo '$3' >expect &&
+ if test '$2' = 'commit'
+ then
+ git log -1 --format=%s '$1' >actual
+ else
+ git rev-parse --symbolic-full-name '$1' >actual
+ fi &&
+ test_cmp expect actual
+ "
}
+
nonsense() {
-test_expect_${2:-success} "$1 is nonsensical" "
- test_must_fail git log -1 '$1'
-"
+ test_expect_${2:-success} "$1 is nonsensical" "
+ test_must_fail git rev-parse --verify '$1'
+ "
}
+
fail() {
"$@" failure
}
@@ -31,21 +38,40 @@ test_expect_success 'setup' '
git checkout -b new-branch &&
test_commit new-one &&
test_commit new-two &&
- git config branch.old-branch.remote . &&
- git config branch.old-branch.merge refs/heads/master &&
- git config branch.new-branch.remote . &&
- git config branch.new-branch.merge refs/heads/upstream-branch
+ git branch -u master old-branch &&
+ git branch -u upstream-branch new-branch
'
-check HEAD new-two
-check "@{1}" new-one
-check "@{-1}" old-two
-check "@{-1}@{1}" old-one
-check "@{u}" upstream-two
-check "@{u}@{1}" upstream-one
-check "@{-1}@{u}" master-two
-check "@{-1}@{u}@{1}" master-one
+check HEAD ref refs/heads/new-branch
+check "@{1}" commit new-one
+check "HEAD@{1}" commit new-one
+check "@{now}" commit new-two
+check "HEAD@{now}" commit new-two
+check "@{-1}" ref refs/heads/old-branch
+check "@{-1}@{0}" commit old-two
+check "@{-1}@{1}" commit old-one
+check "@{u}" ref refs/heads/upstream-branch
+check "HEAD@{u}" ref refs/heads/upstream-branch
+check "@{u}@{1}" commit upstream-one
+check "@{-1}@{u}" ref refs/heads/master
+check "@{-1}@{u}@{1}" commit master-one
nonsense "@{u}@{-1}"
+nonsense "@{0}@{0}"
nonsense "@{1}@{u}"
+nonsense "HEAD@{-1}"
+nonsense "@{-1}@{-1}"
+
+# @{N} versus HEAD@{N}
+
+check "HEAD@{3}" commit old-two
+nonsense "@{3}"
+
+test_expect_success 'switch to old-branch' '
+ git checkout old-branch
+'
+
+check HEAD ref refs/heads/old-branch
+check "HEAD@{1}" commit new-two
+check "@{1}" commit old-one
test_done
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index 6b3d797..4a155c8 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -77,6 +77,7 @@ test_expect_success 'disambiguate blob' '
test_expect_success 'disambiguate tree' '
commit=$(echo "d7xm" | git commit-tree 000000000) &&
+ # this commit is fffff2e and not ambiguous with the 00000* objects
test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc)
'
@@ -99,10 +100,14 @@ test_expect_success 'disambiguate commit-ish' '
test_expect_success 'disambiguate commit' '
commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) &&
+ # this commit is ffffffd8 and not ambiguous with the 00000* objects
test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f)
'
test_expect_success 'log name1..name2 takes only commit-ishes on both ends' '
+ # These are underspecified from the prefix-length point of view
+ # to disambiguate the commit with other objects, but there is only
+ # one commit that has 00000* prefix at this point.
git log 000000000..000000000 &&
git log ..000000000 &&
git log 000000000.. &&
@@ -112,16 +117,19 @@ test_expect_success 'log name1..name2 takes only commit-ishes on both ends' '
'
test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' '
+ # Likewise.
git rev-parse 000000000..000000000 &&
git rev-parse ..000000000 &&
git rev-parse 000000000..
'
test_expect_success 'git log takes only commit-ish' '
+ # Likewise.
git log 000000000
'
test_expect_success 'git reset takes only commit-ish' '
+ # Likewise.
git reset 000000000
'
@@ -131,26 +139,30 @@ test_expect_success 'first tag' '
'
test_expect_failure 'two semi-ambiguous commit-ish' '
+ # At this point, we have a tag 0000000000f8f that points
+ # at a commit 0000000000e4f, and a tree and a blob that
+ # share 0000000000 prefix with these tag and commit.
+ #
# Once the parser becomes ultra-smart, it could notice that
- # 110282 before ^{commit} name many different objects, but
+ # 0000000000 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} &&
+ git rev-parse --verify 0000000000^{commit} &&
# likewise
- git log 000000000..000000000 &&
- git log ..000000000 &&
- git log 000000000.. &&
- git log 000000000...000000000 &&
- git log ...000000000 &&
- git log 000000000...
+ git log 0000000000..0000000000 &&
+ git log ..0000000000 &&
+ git log 0000000000.. &&
+ git log 0000000000...0000000000 &&
+ git log ...0000000000 &&
+ git log 0000000000...
'
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}
+ git rev-parse --verify 0000000000^{tree}
'
test_expect_success 'parse describe name' '
@@ -241,7 +253,7 @@ 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} &&
+ test_must_fail git rev-parse --verify 00000000^{commit} &&
# likewise
test_must_fail git log 000000000..000000000 &&
@@ -261,4 +273,22 @@ test_expect_success 'rev-parse --disambiguate' '
test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
'
+test_expect_success 'ambiguous 40-hex ref' '
+ TREE=$(git mktree </dev/null) &&
+ REF=`git rev-parse HEAD` &&
+ VAL=$(git commit-tree $TREE </dev/null) &&
+ git update-ref refs/heads/$REF $VAL &&
+ test `git rev-parse $REF 2>err` = $REF &&
+ grep "refname.*${REF}.*ambiguous" err
+'
+
+test_expect_success 'ambiguous short sha1 ref' '
+ TREE=$(git mktree </dev/null) &&
+ REF=`git rev-parse --short HEAD` &&
+ VAL=$(git commit-tree $TREE </dev/null) &&
+ git update-ref refs/heads/$REF $VAL &&
+ test `git rev-parse $REF 2>err` = $VAL &&
+ grep "refname.*${REF}.*ambiguous" err
+'
+
test_done
diff --git a/t/t1513-rev-parse-prefix.sh b/t/t1513-rev-parse-prefix.sh
new file mode 100755
index 0000000..87ec3ae
--- /dev/null
+++ b/t/t1513-rev-parse-prefix.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+
+test_description='Tests for rev-parse --prefix'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ mkdir -p sub1/sub2 &&
+ echo top >top &&
+ echo file1 >sub1/file1 &&
+ echo file2 >sub1/sub2/file2 &&
+ git add top sub1/file1 sub1/sub2/file2 &&
+ git commit -m commit
+'
+
+test_expect_success 'empty prefix -- file' '
+ git rev-parse --prefix "" -- top sub1/file1 >actual &&
+ cat <<-\EOF >expected &&
+ --
+ top
+ sub1/file1
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'valid prefix -- file' '
+ git rev-parse --prefix sub1/ -- file1 sub2/file2 >actual &&
+ cat <<-\EOF >expected &&
+ --
+ sub1/file1
+ sub1/sub2/file2
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'valid prefix -- ../file' '
+ git rev-parse --prefix sub1/ -- ../top sub2/file2 >actual &&
+ cat <<-\EOF >expected &&
+ --
+ sub1/../top
+ sub1/sub2/file2
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'empty prefix HEAD:./path' '
+ git rev-parse --prefix "" HEAD:./top >actual &&
+ git rev-parse HEAD:top >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'valid prefix HEAD:./path' '
+ git rev-parse --prefix sub1/ HEAD:./file1 >actual &&
+ git rev-parse HEAD:sub1/file1 >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'valid prefix HEAD:../path' '
+ git rev-parse --prefix sub1/ HEAD:../top >actual &&
+ git rev-parse HEAD:top >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'prefix ignored with HEAD:top' '
+ git rev-parse --prefix sub1/ HEAD:top >actual &&
+ git rev-parse HEAD:top >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'disambiguate path with valid prefix' '
+ git rev-parse --prefix sub1/ file1 >actual &&
+ cat <<-\EOF >expected &&
+ sub1/file1
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'file and refs with prefix' '
+ git rev-parse --prefix sub1/ master file1 >actual &&
+ cat <<-EOF >expected &&
+ $(git rev-parse master)
+ sub1/file1
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'two-levels deep' '
+ git rev-parse --prefix sub1/sub2/ -- file2 >actual &&
+ cat <<-\EOF >expected &&
+ --
+ sub1/sub2/file2
+ EOF
+ test_cmp expected actual
+'
+
+test_done
diff --git a/t/t2001-checkout-cache-clash.sh b/t/t2001-checkout-cache-clash.sh
index 98aa73e..1fc8e63 100755
--- a/t/t2001-checkout-cache-clash.sh
+++ b/t/t2001-checkout-cache-clash.sh
@@ -59,10 +59,9 @@ test_expect_success \
'git read-tree -m $tree1 && git checkout-index -f -a'
test_debug 'show_files $tree1'
-test_expect_success SYMLINKS \
- 'git update-index --add a symlink.' \
- 'ln -s path0 path1 &&
- git update-index --add path1'
+test_expect_success \
+ 'add a symlink' \
+ 'test_ln_s_add path0 path1'
test_expect_success \
'writing tree out with git write-tree' \
'tree3=$(git write-tree)'
diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh
index 0f4b289..f171a55 100755
--- a/t/t2004-checkout-cache-temp.sh
+++ b/t/t2004-checkout-cache-temp.sh
@@ -194,11 +194,10 @@ test_expect_success \
test $(cat ../$s1) = tree1asubdir/path5)
)'
-test_expect_success SYMLINKS \
+test_expect_success \
'checkout --temp symlink' '
rm -f path* .merge_* out .git/index &&
-ln -s b a &&
-git update-index --add a &&
+test_ln_s_add b a &&
t4=$(git write-tree) &&
rm -f .git/index &&
git read-tree $t4 &&
diff --git a/t/t2007-checkout-symlink.sh b/t/t2007-checkout-symlink.sh
index e6f59f1..fc9aad5 100755
--- a/t/t2007-checkout-symlink.sh
+++ b/t/t2007-checkout-symlink.sh
@@ -6,7 +6,7 @@ test_description='git checkout to switch between branches with symlink<->dir'
. ./test-lib.sh
-test_expect_success SYMLINKS setup '
+test_expect_success setup '
mkdir frotz &&
echo hello >frotz/filfre &&
@@ -25,25 +25,25 @@ test_expect_success SYMLINKS setup '
git rm --cached frotz/filfre &&
mv frotz xyzzy &&
- ln -s xyzzy frotz &&
- git add xyzzy/filfre frotz &&
+ test_ln_s_add xyzzy frotz &&
+ git add xyzzy/filfre &&
test_tick &&
git commit -m "side moves frotz/ to xyzzy/ and adds frotz->xyzzy/"
'
-test_expect_success SYMLINKS 'switch from symlink to dir' '
+test_expect_success 'switch from symlink to dir' '
git checkout master
'
-test_expect_success SYMLINKS 'Remove temporary directories & switch to master' '
+test_expect_success 'Remove temporary directories & switch to master' '
rm -fr frotz xyzzy nitfol &&
git checkout -f master
'
-test_expect_success SYMLINKS 'switch from dir to symlink' '
+test_expect_success 'switch from dir to symlink' '
git checkout side
diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh
index b44de9d..e7ba8c5 100755
--- a/t/t2012-checkout-last.sh
+++ b/t/t2012-checkout-last.sh
@@ -116,4 +116,38 @@ test_expect_success 'master...' '
test "z$(git rev-parse --verify HEAD)" = "z$(git rev-parse --verify master^)"
'
+test_expect_success '"checkout -" works after a rebase A' '
+ git checkout master &&
+ git checkout other &&
+ git rebase master &&
+ git checkout - &&
+ test "z$(git symbolic-ref HEAD)" = "zrefs/heads/master"
+'
+
+test_expect_success '"checkout -" works after a rebase A B' '
+ git branch moodle master~1 &&
+ git checkout master &&
+ git checkout other &&
+ git rebase master moodle &&
+ git checkout - &&
+ test "z$(git symbolic-ref HEAD)" = "zrefs/heads/master"
+'
+
+test_expect_success '"checkout -" works after a rebase -i A' '
+ git checkout master &&
+ git checkout other &&
+ git rebase -i master &&
+ git checkout - &&
+ test "z$(git symbolic-ref HEAD)" = "zrefs/heads/master"
+'
+
+test_expect_success '"checkout -" works after a rebase -i A B' '
+ git branch foodle master~1 &&
+ git checkout master &&
+ git checkout other &&
+ git rebase master foodle &&
+ git checkout - &&
+ test "z$(git symbolic-ref HEAD)" = "zrefs/heads/master"
+'
+
test_done
diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh
index 5da63e9..c2ada7d 100755
--- a/t/t2021-checkout-overwrite.sh
+++ b/t/t2021-checkout-overwrite.sh
@@ -29,21 +29,25 @@ test_expect_success 'checkout commit with dir must not remove untracked a/b' '
test -f a/b
'
-test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink' '
+test_expect_success 'create a commit where dir a/b changed to symlink' '
rm -rf a/b && # cleanup if previous test failed
git checkout -f -b symlink start &&
rm -rf a/b &&
- ln -s foo a/b &&
git add -A &&
+ test_ln_s_add foo a/b &&
git commit -m "dir to symlink"
'
-test_expect_success SYMLINKS 'checkout commit with dir must not remove untracked a/b' '
+test_expect_success 'checkout commit with dir must not remove untracked a/b' '
git rm --cached a/b &&
git commit -m "un-track the symlink" &&
- test_must_fail git checkout start &&
+ test_must_fail git checkout start
+'
+
+test_expect_success SYMLINKS 'the symlink remained' '
+
test -h a/b
'
diff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh
index 56090d2..8e3545d 100755
--- a/t/t2022-checkout-paths.sh
+++ b/t/t2022-checkout-paths.sh
@@ -39,4 +39,26 @@ test_expect_success 'checking out paths out of a tree does not clobber unrelated
test_cmp expect.next2 dir/next2
'
+test_expect_success 'do not touch unmerged entries matching $path but not in $tree' '
+ git checkout next &&
+ git reset --hard &&
+
+ cat dir/common >expect.common &&
+ EMPTY_SHA1=$(git hash-object -w --stdin </dev/null) &&
+ git rm dir/next0 &&
+ cat >expect.next0 <<-EOF &&
+ 100644 $EMPTY_SHA1 1 dir/next0
+ 100644 $EMPTY_SHA1 2 dir/next0
+ EOF
+ git update-index --index-info <expect.next0 &&
+
+ git checkout master dir &&
+
+ test_cmp expect.common dir/common &&
+ test_path_is_file dir/master &&
+ git diff --exit-code master dir/master &&
+ git ls-files -s dir/next0 >actual.next0 &&
+ test_cmp expect.next0 actual.next0
+'
+
test_done
diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh
new file mode 100755
index 0000000..dee55e4
--- /dev/null
+++ b/t/t2024-checkout-dwim.sh
@@ -0,0 +1,167 @@
+#!/bin/sh
+
+test_description='checkout <branch>
+
+Ensures that checkout on an unborn branch does what the user expects'
+
+. ./test-lib.sh
+
+# Is the current branch "refs/heads/$1"?
+test_branch () {
+ printf "%s\n" "refs/heads/$1" >expect.HEAD &&
+ git symbolic-ref HEAD >actual.HEAD &&
+ test_cmp expect.HEAD actual.HEAD
+}
+
+# Is branch "refs/heads/$1" set to pull from "$2/$3"?
+test_branch_upstream () {
+ printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
+ {
+ git config "branch.$1.remote" &&
+ git config "branch.$1.merge"
+ } >actual.upstream &&
+ test_cmp expect.upstream actual.upstream
+}
+
+test_expect_success 'setup' '
+ test_commit my_master &&
+ git init repo_a &&
+ (
+ cd repo_a &&
+ test_commit a_master &&
+ git checkout -b foo &&
+ test_commit a_foo &&
+ git checkout -b bar &&
+ test_commit a_bar
+ ) &&
+ git init repo_b &&
+ (
+ cd repo_b &&
+ test_commit b_master &&
+ git checkout -b foo &&
+ test_commit b_foo &&
+ git checkout -b baz &&
+ test_commit b_baz
+ ) &&
+ git remote add repo_a repo_a &&
+ git remote add repo_b repo_b &&
+ git config remote.repo_b.fetch \
+ "+refs/heads/*:refs/remotes/other_b/*" &&
+ git fetch --all
+'
+
+test_expect_success 'checkout of non-existing branch fails' '
+ git checkout -B master &&
+ test_might_fail git branch -D xyzzy &&
+
+ test_must_fail git checkout xyzzy &&
+ test_must_fail git rev-parse --verify refs/heads/xyzzy &&
+ test_branch master
+'
+
+test_expect_success 'checkout of branch from multiple remotes fails #1' '
+ git checkout -B master &&
+ test_might_fail git branch -D foo &&
+
+ test_must_fail git checkout foo &&
+ test_must_fail git rev-parse --verify refs/heads/foo &&
+ test_branch master
+'
+
+test_expect_success 'checkout of branch from a single remote succeeds #1' '
+ git checkout -B master &&
+ test_might_fail git branch -D bar &&
+
+ git checkout bar &&
+ test_branch bar &&
+ test_cmp_rev remotes/repo_a/bar HEAD &&
+ test_branch_upstream bar repo_a bar
+'
+
+test_expect_success 'checkout of branch from a single remote succeeds #2' '
+ git checkout -B master &&
+ test_might_fail git branch -D baz &&
+
+ git checkout baz &&
+ test_branch baz &&
+ test_cmp_rev remotes/other_b/baz HEAD &&
+ test_branch_upstream baz repo_b baz
+'
+
+test_expect_success '--no-guess suppresses branch auto-vivification' '
+ git checkout -B master &&
+ test_might_fail git branch -D bar &&
+
+ test_must_fail git checkout --no-guess bar &&
+ test_must_fail git rev-parse --verify refs/heads/bar &&
+ test_branch master
+'
+
+test_expect_success 'setup more remotes with unconventional refspecs' '
+ git checkout -B master &&
+ git init repo_c &&
+ (
+ cd repo_c &&
+ test_commit c_master &&
+ git checkout -b bar &&
+ test_commit c_bar
+ git checkout -b spam &&
+ test_commit c_spam
+ ) &&
+ git init repo_d &&
+ (
+ cd repo_d &&
+ test_commit d_master &&
+ git checkout -b baz &&
+ test_commit f_baz
+ git checkout -b eggs &&
+ test_commit c_eggs
+ ) &&
+ git remote add repo_c repo_c &&
+ git config remote.repo_c.fetch \
+ "+refs/heads/*:refs/remotes/extra_dir/repo_c/extra_dir/*" &&
+ git remote add repo_d repo_d &&
+ git config remote.repo_d.fetch \
+ "+refs/heads/*:refs/repo_d/*" &&
+ git fetch --all
+'
+
+test_expect_success 'checkout of branch from multiple remotes fails #2' '
+ git checkout -B master &&
+ test_might_fail git branch -D bar &&
+
+ test_must_fail git checkout bar &&
+ test_must_fail git rev-parse --verify refs/heads/bar &&
+ test_branch master
+'
+
+test_expect_success 'checkout of branch from multiple remotes fails #3' '
+ git checkout -B master &&
+ test_might_fail git branch -D baz &&
+
+ test_must_fail git checkout baz &&
+ test_must_fail git rev-parse --verify refs/heads/baz &&
+ test_branch master
+'
+
+test_expect_success 'checkout of branch from a single remote succeeds #3' '
+ git checkout -B master &&
+ test_might_fail git branch -D spam &&
+
+ git checkout spam &&
+ test_branch spam &&
+ test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
+ test_branch_upstream spam repo_c spam
+'
+
+test_expect_success 'checkout of branch from a single remote succeeds #4' '
+ git checkout -B master &&
+ test_might_fail git branch -D eggs &&
+
+ git checkout eggs &&
+ test_branch eggs &&
+ test_cmp_rev refs/repo_d/eggs HEAD &&
+ test_branch_upstream eggs repo_d eggs
+'
+
+test_done
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index 4cdebda..9bf2bdf 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -80,11 +80,26 @@ test_expect_success 'change gets noticed' '
'
-test_expect_success SYMLINKS 'replace a file with a symlink' '
+# Note that this is scheduled to change in Git 2.0, when
+# "git add -u" will become full-tree by default.
+test_expect_success 'non-limited update in subdir leaves root alone' '
+ (
+ cd dir1 &&
+ echo even more >>sub2 &&
+ git add -u
+ ) &&
+ cat >expect <<-\EOF &&
+ check
+ top
+ EOF
+ git diff-files --name-only >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'replace a file with a symlink' '
rm foo &&
- ln -s top foo &&
- git add -u -- foo
+ test_ln_s_add top foo
'
@@ -150,9 +165,9 @@ test_expect_success 'add -u resolves unmerged paths' '
echo 2 >path3 &&
echo 2 >path5 &&
- # Explicit resolving by adding removed paths should fail
- test_must_fail git add path4 &&
- test_must_fail git add path6 &&
+ # Fail to explicitly resolve removed paths with "git add"
+ test_must_fail git add --no-all path4 &&
+ test_must_fail git add --no-all path6 &&
# "add -u" should notice removals no matter what stages
# the index entries are in.
diff --git a/t/t2202-add-addremove.sh b/t/t2202-add-addremove.sh
index 6a81510..fc8b59e 100755
--- a/t/t2202-add-addremove.sh
+++ b/t/t2202-add-addremove.sh
@@ -41,4 +41,14 @@ test_expect_success 'git add --all' '
test_cmp expect actual
'
+test_expect_success 'Just "git add" is a no-op' '
+ git reset --hard &&
+ echo >will-remove &&
+ >will-not-be-added &&
+ git add &&
+ git diff-index --name-status --cached HEAD >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh
index efb7ebc..f0421c0 100755
--- a/t/t3001-ls-files-others-exclude.sh
+++ b/t/t3001-ls-files-others-exclude.sh
@@ -103,7 +103,7 @@ test_expect_success \
test_cmp expect output'
test_expect_success 'restore gitignore' '
- git checkout $allignores &&
+ git checkout --ignore-skip-worktree-bits $allignores &&
rm .git/index
'
@@ -175,6 +175,24 @@ test_expect_success 'negated exclude matches can override previous ones' '
grep "^a.1" output
'
+test_expect_success 'excluded directory overrides content patterns' '
+
+ git ls-files --others --exclude="one" --exclude="!one/a.1" >output &&
+ if grep "^one/a.1" output
+ then
+ false
+ fi
+'
+
+test_expect_success 'negated directory doesn'\''t affect content patterns' '
+
+ git ls-files --others --exclude="!one" --exclude="one/a.1" >output &&
+ if grep "^one/a.1" output
+ then
+ false
+ fi
+'
+
test_expect_success 'subdirectory ignore (setup)' '
mkdir -p top/l1/l2 &&
(
@@ -214,6 +232,55 @@ test_expect_success 'subdirectory ignore (l1)' '
test_cmp expect actual
'
+test_expect_success 'show/hide empty ignored directory (setup)' '
+ rm top/l1/l2/l1 &&
+ rm top/l1/.gitignore
+'
+
+test_expect_success 'show empty ignored directory with --directory' '
+ (
+ cd top &&
+ git ls-files -o -i --exclude l1 --directory
+ ) >actual &&
+ echo l1/ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'hide empty ignored directory with --no-empty-directory' '
+ (
+ cd top &&
+ git ls-files -o -i --exclude l1 --directory --no-empty-directory
+ ) >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show/hide empty ignored sub-directory (setup)' '
+ > top/l1/tracked &&
+ (
+ cd top &&
+ git add -f l1/tracked
+ )
+'
+
+test_expect_success 'show empty ignored sub-directory with --directory' '
+ (
+ cd top &&
+ git ls-files -o -i --exclude l1 --directory
+ ) >actual &&
+ echo l1/l2/ >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'hide empty ignored sub-directory with --no-empty-directory' '
+ (
+ cd top &&
+ git ls-files -o -i --exclude l1 --directory --no-empty-directory
+ ) >actual &&
+ >expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'pattern matches prefix completely' '
: >expect &&
git ls-files -i -o --exclude "/three/a.3[abc]" >actual &&
diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh
index 95671c2..6d3b828 100755
--- a/t/t3010-ls-files-killed-modified.sh
+++ b/t/t3010-ls-files-killed-modified.sh
@@ -11,6 +11,9 @@ This test prepares the following in the cache:
path1 - a symlink
path2/file2 - a file in a directory
path3/file3 - a file in a directory
+ pathx/ju - a file in a directory
+ submod1/ - a submodule
+ submod2/ - another submodule
and the following on the filesystem:
@@ -21,9 +24,12 @@ and the following on the filesystem:
path4 - a file
path5 - a symlink
path6/file6 - a file in a directory
+ pathx/ju/nk - a file in a directory to be killed
+ submod1/ - a submodule (modified from the cache)
+ submod2/ - a submodule (matches the cache)
-git ls-files -k should report that existing filesystem
-objects except path4, path5 and path6/file6 to be killed.
+git ls-files -k should report that existing filesystem objects
+path0/*, path1/*, path2 and path3 to be killed.
Also for modification test, the cache and working tree have:
@@ -33,75 +39,91 @@ Also for modification test, the cache and working tree have:
path10 - a non-empty file, cache dirtied.
We should report path0, path1, path2/file2, path3/file3, path7 and path8
-modified without reporting path9 and path10.
+modified without reporting path9 and path10. submod1 is also modified.
'
. ./test-lib.sh
-date >path0
-if test_have_prereq SYMLINKS
-then
- ln -s xyzzy path1
-else
- date > path1
-fi
-mkdir path2 path3
-date >path2/file2
-date >path3/file3
-: >path7
-date >path8
-: >path9
-date >path10
-test_expect_success \
- 'git update-index --add to add various paths.' \
- "git update-index --add -- path0 path1 path?/file? path7 path8 path9 path10"
-
-rm -fr path? ;# leave path10 alone
-date >path2
-if test_have_prereq SYMLINKS
-then
- ln -s frotz path3
- ln -s nitfol path5
-else
- date > path3
- date > path5
-fi
-mkdir path0 path1 path6
-date >path0/file0
-date >path1/file1
-date >path6/file6
-date >path7
-: >path8
-: >path9
-touch path10
-
-test_expect_success \
- 'git ls-files -k to show killed files.' \
- 'git ls-files -k >.output'
-cat >.expected <<EOF
-path0/file0
-path1/file1
-path2
-path3
-EOF
-
-test_expect_success \
- 'validate git ls-files -k output.' \
- 'test_cmp .expected .output'
-
-test_expect_success \
- 'git ls-files -m to show modified files.' \
- 'git ls-files -m >.output'
-cat >.expected <<EOF
-path0
-path1
-path2/file2
-path3/file3
-path7
-path8
-EOF
-
-test_expect_success \
- 'validate git ls-files -m output.' \
- 'test_cmp .expected .output'
+test_expect_success 'git update-index --add to add various paths.' '
+ date >path0 &&
+ test_ln_s_add xyzzy path1 &&
+ mkdir path2 path3 pathx &&
+ date >path2/file2 &&
+ date >path3/file3 &&
+ >pathx/ju &&
+ : >path7 &&
+ date >path8 &&
+ : >path9 &&
+ date >path10 &&
+ git update-index --add -- path0 path?/file? pathx/ju path7 path8 path9 path10 &&
+ for i in 1 2
+ do
+ git init submod$i &&
+ (
+ cd submod$i && git commit --allow-empty -m "empty $i"
+ ) || break
+ done &&
+ git update-index --add submod[12]
+ (
+ cd submod1 &&
+ git commit --allow-empty -m "empty 1 (updated)"
+ ) &&
+ rm -fr path? # leave path10 alone
+'
+
+test_expect_success 'git ls-files -k to show killed files.' '
+ date >path2 &&
+ if test_have_prereq SYMLINKS
+ then
+ ln -s frotz path3 &&
+ ln -s nitfol path5
+ else
+ date >path3 &&
+ date >path5
+ fi &&
+ mkdir -p path0 path1 path6 pathx/ju &&
+ date >path0/file0 &&
+ date >path1/file1 &&
+ date >path6/file6 &&
+ date >path7 &&
+ : >path8 &&
+ : >path9 &&
+ touch path10 &&
+ >pathx/ju/nk &&
+ cat >.expected <<-\EOF
+ path0/file0
+ path1/file1
+ path2
+ path3
+ pathx/ju/nk
+ EOF
+'
+
+test_expect_success 'git ls-files -k output (w/o icase)' '
+ git ls-files -k >.output
+ test_cmp .expected .output
+'
+
+test_expect_success 'git ls-files -k output (w/ icase)' '
+ git -c core.ignorecase=true ls-files -k >.output
+ test_cmp .expected .output
+'
+
+test_expect_success 'git ls-files -m to show modified files.' '
+ git ls-files -m >.output
+'
+
+test_expect_success 'validate git ls-files -m output.' '
+ cat >.expected <<-\EOF &&
+ path0
+ path1
+ path2/file2
+ path3/file3
+ path7
+ path8
+ pathx/ju
+ submod1
+ EOF
+ test_cmp .expected .output
+'
test_done
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index a5e3da7..2f96100 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -25,10 +25,7 @@ test_expect_success 'setup 1' '
git branch submod &&
git branch copy &&
git branch rename &&
- if test_have_prereq SYMLINKS
- then
- git branch rename-ln
- fi &&
+ git branch rename-ln &&
echo hello >>a &&
cp a d/e &&
@@ -260,16 +257,12 @@ test_expect_success 'setup 8' '
git add e &&
test_tick &&
git commit -m "rename a->e" &&
- if test_have_prereq SYMLINKS
- then
- git checkout rename-ln &&
- git mv a e &&
- ln -s e a &&
- git add a e &&
- test_tick &&
- git commit -m "rename a->e, symlink a->e" &&
- oln=`printf e | git hash-object --stdin`
- fi
+ git checkout rename-ln &&
+ git mv a e &&
+ test_ln_s_add e a &&
+ test_tick &&
+ git commit -m "rename a->e, symlink a->e" &&
+ oln=`printf e | git hash-object --stdin`
'
test_expect_success 'setup 9' '
@@ -569,28 +562,25 @@ test_expect_success 'merge-recursive copy vs. rename' '
test_cmp expected actual
'
-if test_have_prereq SYMLINKS
-then
- test_expect_failure 'merge-recursive rename vs. rename/symlink' '
-
- git checkout -f rename &&
- git merge rename-ln &&
- ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
- (
- echo "120000 blob $oln a"
- echo "100644 blob $o0 b"
- echo "100644 blob $o0 c"
- echo "100644 blob $o0 d/e"
- echo "100644 blob $o0 e"
- echo "120000 $oln 0 a"
- echo "100644 $o0 0 b"
- echo "100644 $o0 0 c"
- echo "100644 $o0 0 d/e"
- echo "100644 $o0 0 e"
- ) >expected &&
- test_cmp expected actual
- '
-fi
+test_expect_failure 'merge-recursive rename vs. rename/symlink' '
+
+ git checkout -f rename &&
+ git merge rename-ln &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "120000 blob $oln a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 blob $o0 e"
+ echo "120000 $oln 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ echo "100644 $o0 0 e"
+ ) >expected &&
+ test_cmp expected actual
+'
test_done
diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh
index 2b17311..5fd7bbb 100755
--- a/t/t3032-merge-recursive-options.sh
+++ b/t/t3032-merge-recursive-options.sh
@@ -14,7 +14,7 @@ test_description='merge-recursive options
. ./test-lib.sh
test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b
-test_have_prereq MINGW && export GREP_OPTIONS=-U
+test_have_prereq GREP_STRIPS_CR && export GREP_OPTIONS=-U
test_expect_success 'setup' '
conflict_hunks () {
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 4c37057..38446a0 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -6,20 +6,20 @@ test_description='wildmatch tests'
match() {
if [ $1 = 1 ]; then
- test_expect_success "wildmatch: match '$3' '$4'" "
+ test_expect_success "wildmatch: match '$3' '$4'" "
test-wildmatch wildmatch '$3' '$4'
"
else
- test_expect_success "wildmatch: no match '$3' '$4'" "
+ test_expect_success "wildmatch: no match '$3' '$4'" "
! test-wildmatch wildmatch '$3' '$4'
"
fi
if [ $2 = 1 ]; then
- test_expect_success "fnmatch: match '$3' '$4'" "
+ test_expect_success "fnmatch: match '$3' '$4'" "
test-wildmatch fnmatch '$3' '$4'
"
elif [ $2 = 0 ]; then
- test_expect_success "fnmatch: no match '$3' '$4'" "
+ test_expect_success "fnmatch: no match '$3' '$4'" "
! test-wildmatch fnmatch '$3' '$4'
"
# else
@@ -29,13 +29,25 @@ match() {
fi
}
+imatch() {
+ if [ $1 = 1 ]; then
+ test_expect_success "iwildmatch: match '$2' '$3'" "
+ test-wildmatch iwildmatch '$2' '$3'
+ "
+ else
+ test_expect_success "iwildmatch: no match '$2' '$3'" "
+ ! test-wildmatch iwildmatch '$2' '$3'
+ "
+ fi
+}
+
pathmatch() {
if [ $1 = 1 ]; then
- test_expect_success "pathmatch: match '$2' '$3'" "
+ test_expect_success "pathmatch: match '$2' '$3'" "
test-wildmatch pathmatch '$2' '$3'
"
else
- test_expect_success "pathmatch: no match '$2' '$3'" "
+ test_expect_success "pathmatch: no match '$2' '$3'" "
! test-wildmatch pathmatch '$2' '$3'
"
fi
@@ -235,4 +247,35 @@ pathmatch 1 abcXdefXghi '*X*i'
pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i'
pathmatch 1 ab/cXd/efXg/hi '*Xg*i'
+# Case-sensitivy features
+match 0 x 'a' '[A-Z]'
+match 1 x 'A' '[A-Z]'
+match 0 x 'A' '[a-z]'
+match 1 x 'a' '[a-z]'
+match 0 x 'a' '[[:upper:]]'
+match 1 x 'A' '[[:upper:]]'
+match 0 x 'A' '[[:lower:]]'
+match 1 x 'a' '[[:lower:]]'
+match 0 x 'A' '[B-Za]'
+match 1 x 'a' '[B-Za]'
+match 0 x 'A' '[B-a]'
+match 1 x 'a' '[B-a]'
+match 0 x 'z' '[Z-y]'
+match 1 x 'Z' '[Z-y]'
+
+imatch 1 'a' '[A-Z]'
+imatch 1 'A' '[A-Z]'
+imatch 1 'A' '[a-z]'
+imatch 1 'a' '[a-z]'
+imatch 1 'a' '[[:upper:]]'
+imatch 1 'A' '[[:upper:]]'
+imatch 1 'A' '[[:lower:]]'
+imatch 1 'a' '[[:lower:]]'
+imatch 1 'A' '[B-Za]'
+imatch 1 'a' '[B-Za]'
+imatch 1 'A' '[B-a]'
+imatch 1 'a' '[B-a]'
+imatch 1 'z' '[Z-y]'
+imatch 1 'Z' '[Z-y]'
+
test_done
diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh
index 81d90b6..eb73c06 100755
--- a/t/t3100-ls-tree-restrict.sh
+++ b/t/t3100-ls-tree-restrict.sh
@@ -22,20 +22,8 @@ test_expect_success \
'setup' \
'mkdir path2 path2/baz &&
echo Hi >path0 &&
- if test_have_prereq SYMLINKS
- then
- ln -s path0 path1 &&
- ln -s ../path1 path2/bazbo
- make_expected () {
- cat >expected
- }
- else
- printf path0 > path1 &&
- printf ../path1 > path2/bazbo
- make_expected () {
- sed -e "s/120000 /100644 /" >expected
- }
- fi &&
+ test_ln_s_add path0 path1 &&
+ test_ln_s_add ../path1 path2/bazbo &&
echo Lo >path2/foo &&
echo Mi >path2/baz/b &&
find path? \( -type f -o -type l \) -print |
@@ -51,7 +39,7 @@ test_output () {
test_expect_success \
'ls-tree plain' \
'git ls-tree $tree >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
100644 blob X path0
120000 blob X path1
040000 tree X path2
@@ -61,7 +49,7 @@ EOF
test_expect_success \
'ls-tree recursive' \
'git ls-tree -r $tree >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
100644 blob X path0
120000 blob X path1
100644 blob X path2/baz/b
@@ -73,7 +61,7 @@ EOF
test_expect_success \
'ls-tree recursive with -t' \
'git ls-tree -r -t $tree >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
100644 blob X path0
120000 blob X path1
040000 tree X path2
@@ -87,7 +75,7 @@ EOF
test_expect_success \
'ls-tree recursive with -d' \
'git ls-tree -r -d $tree >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
040000 tree X path2
040000 tree X path2/baz
EOF
@@ -96,7 +84,7 @@ EOF
test_expect_success \
'ls-tree filtered with path' \
'git ls-tree $tree path >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
EOF
test_output'
@@ -106,7 +94,7 @@ EOF
test_expect_success \
'ls-tree filtered with path1 path0' \
'git ls-tree $tree path1 path0 >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
100644 blob X path0
120000 blob X path1
EOF
@@ -115,7 +103,7 @@ EOF
test_expect_success \
'ls-tree filtered with path0/' \
'git ls-tree $tree path0/ >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
EOF
test_output'
@@ -124,7 +112,7 @@ EOF
test_expect_success \
'ls-tree filtered with path2' \
'git ls-tree $tree path2 >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
040000 tree X path2
EOF
test_output'
@@ -133,7 +121,7 @@ EOF
test_expect_success \
'ls-tree filtered with path2/' \
'git ls-tree $tree path2/ >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
040000 tree X path2/baz
120000 blob X path2/bazbo
100644 blob X path2/foo
@@ -145,7 +133,7 @@ EOF
test_expect_success \
'ls-tree filtered with path2/baz' \
'git ls-tree $tree path2/baz >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
040000 tree X path2/baz
EOF
test_output'
@@ -153,14 +141,14 @@ EOF
test_expect_success \
'ls-tree filtered with path2/bak' \
'git ls-tree $tree path2/bak >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
EOF
test_output'
test_expect_success \
'ls-tree -t filtered with path2/bak' \
'git ls-tree -t $tree path2/bak >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
040000 tree X path2
EOF
test_output'
@@ -168,7 +156,7 @@ EOF
test_expect_success \
'ls-tree with one path a prefix of the other' \
'git ls-tree $tree path2/baz path2/bazbo >current &&
- make_expected <<\EOF &&
+ cat >expected <<\EOF &&
040000 tree X path2/baz
120000 blob X path2/bazbo
EOF
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index b08c9f2..44ec6a4 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -75,7 +75,7 @@ test_expect_success 'git branch l should work after branch l/m has been deleted'
test_expect_success 'git branch -m dumps usage' '
test_expect_code 128 git branch -m 2>err &&
- test_i18ngrep "too many branches for a rename operation" err
+ test_i18ngrep "branch name required" err
'
test_expect_success 'git branch -m m m/m should work' '
@@ -317,13 +317,13 @@ test_expect_success 'test tracking setup (non-wildcard, matching)' '
test $(git config branch.my4.merge) = refs/heads/master
'
-test_expect_success 'test tracking setup (non-wildcard, not matching)' '
+test_expect_success 'tracking setup fails on non-matching refspec' '
git config remote.local.url . &&
git config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
(git show-ref -q refs/remotes/local/master || git fetch local) &&
- git branch --track my5 local/master &&
- ! test "$(git config branch.my5.remote)" = local &&
- ! test "$(git config branch.my5.merge)" = refs/heads/master
+ test_must_fail git branch --track my5 local/master &&
+ test_must_fail git config branch.my5.remote &&
+ test_must_fail git config branch.my5.merge
'
test_expect_success 'test tracking setup via config' '
@@ -409,6 +409,18 @@ test_expect_success '--set-upstream-to fails on detached HEAD' '
git checkout -
'
+test_expect_success '--set-upstream-to fails on a missing dst branch' '
+ test_must_fail git branch --set-upstream-to master does-not-exist
+'
+
+test_expect_success '--set-upstream-to fails on a missing src branch' '
+ test_must_fail git branch --set-upstream-to does-not-exist master
+'
+
+test_expect_success '--set-upstream-to fails on a non-ref' '
+ test_must_fail git branch --set-upstream-to HEAD^{}
+'
+
test_expect_success 'use --set-upstream-to modify HEAD' '
test_config branch.master.remote foo &&
test_config branch.master.merge foo &&
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 76fe7e0..ba4f98e 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -94,13 +94,13 @@ test_expect_success 'git branch -v pattern does not show branch summaries' '
test_must_fail git branch -v branch*
'
-cat >expect <<'EOF'
-* (no branch)
+test_expect_success 'git branch shows detached HEAD properly' '
+ cat >expect <<EOF &&
+* (detached from $(git rev-parse --short HEAD^0))
branch-one
branch-two
master
EOF
-test_expect_success 'git branch shows detached HEAD properly' '
git checkout HEAD^0 &&
git branch >actual &&
test_i18ncmp expect actual
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index cd04361..1a2080e 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -118,4 +118,37 @@ test_expect_success 'pack, prune and repack' '
test_cmp all-of-them again
'
+test_expect_success 'explicit pack-refs with dangling packed reference' '
+ git commit --allow-empty -m "soon to be garbage-collected" &&
+ git pack-refs --all &&
+ git reset --hard HEAD^ &&
+ git reflog expire --expire=all --all &&
+ git prune --expire=all &&
+ git pack-refs --all 2>result &&
+ test_cmp /dev/null result
+'
+
+test_expect_success 'delete ref with dangling packed version' '
+ git checkout -b lamb &&
+ git commit --allow-empty -m "future garbage" &&
+ git pack-refs --all &&
+ git reset --hard HEAD^ &&
+ git checkout master &&
+ git reflog expire --expire=all --all &&
+ git prune --expire=all &&
+ git branch -d lamb 2>result &&
+ test_cmp /dev/null result
+'
+
+test_expect_success 'delete ref while another dangling packed ref' '
+ git branch lamb &&
+ git commit --allow-empty -m "future garbage" &&
+ git pack-refs --all &&
+ git reset --hard HEAD^ &&
+ git reflog expire --expire=all --all &&
+ git prune --expire=all &&
+ git branch -d lamb 2>result &&
+ test_cmp /dev/null result
+'
+
test_done
diff --git a/t/t3211-peel-ref.sh b/t/t3211-peel-ref.sh
index d4d7792..3b7caca 100755
--- a/t/t3211-peel-ref.sh
+++ b/t/t3211-peel-ref.sh
@@ -61,4 +61,13 @@ test_expect_success 'refs are peeled outside of refs/tags (old packed)' '
test_cmp expect actual
'
+test_expect_success 'peeled refs survive deletion of packed ref' '
+ git pack-refs --all &&
+ cp .git/packed-refs fully-peeled &&
+ git branch yadda &&
+ git pack-refs --all &&
+ git branch -d yadda &&
+ test_cmp fully-peeled .git/packed-refs
+'
+
test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 1de0ebd..ebf93b0 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -40,13 +40,6 @@ test_expect_success 'prepare repository with topic branches' '
echo Side >>C &&
git add C &&
git commit -m "Add C" &&
- git checkout -b nonlinear my-topic-branch &&
- echo Edit >>B &&
- git add B &&
- git commit -m "Modify B" &&
- git merge side &&
- git checkout -b upstream-merged-nonlinear &&
- git merge master &&
git checkout -f my-topic-branch &&
git tag topic
'
@@ -66,26 +59,15 @@ test_expect_success 'rebase against master' '
git rebase master
'
-test_expect_success 'rebase against master twice' '
- git rebase master >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 &&
- 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 &&
- 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 &&
- test_i18ngrep "Fast-forwarded HEAD to my-topic-branch" out
+test_expect_success 'rebase, with <onto> and <upstream> specified as :/quuxery' '
+ test_when_finished "git branch -D torebase" &&
+ git checkout -b torebase my-topic-branch^ &&
+ upstream=$(git rev-parse ":/Add B") &&
+ onto=$(git rev-parse ":/Add A") &&
+ git rebase --onto $onto $upstream &&
+ git reset --hard my-topic-branch^ &&
+ git rebase --onto ":/Add A" ":/Add B" &&
+ git checkout my-topic-branch
'
test_expect_success 'the rebase operation should not have destroyed author information' '
@@ -101,29 +83,14 @@ test_expect_success 'HEAD was detached during rebase' '
test $(git rev-parse HEAD@{1}) != $(git rev-parse my-topic-branch@{1})
'
-test_expect_success 'rebase after merge master' '
- git reset --hard topic &&
- git merge master &&
- git rebase master &&
- ! (git show | grep "^Merge:")
-'
-
-test_expect_success 'rebase of history with merges is linearized' '
- git checkout nonlinear &&
- test 4 = $(git rev-list master.. | wc -l) &&
- git rebase master &&
- test 3 = $(git rev-list master.. | wc -l)
-'
-
-test_expect_success 'rebase of history with merges after upstream merge is linearized' '
- git checkout upstream-merged-nonlinear &&
- test 5 = $(git rev-list master.. | wc -l) &&
- git rebase master &&
- test 3 = $(git rev-list master.. | wc -l)
+test_expect_success 'rebase from ambiguous branch name' '
+ git checkout -b topic side &&
+ git rebase master
'
test_expect_success 'rebase a single mode change' '
git checkout master &&
+ git branch -D topic &&
echo 1 >X &&
git add X &&
test_tick &&
@@ -138,8 +105,7 @@ test_expect_success 'rebase a single mode change' '
'
test_expect_success 'rebase is not broken by diff.renames' '
- git config diff.renames copies &&
- test_when_finished "git config --unset diff.renames" &&
+ test_config diff.renames copies &&
git checkout filemove &&
GIT_TRACE=1 git rebase force-3way
'
@@ -179,7 +145,7 @@ test_expect_success 'default to @{upstream} when upstream arg is missing' '
test_expect_success 'rebase -q is quiet' '
git checkout -b quiet topic &&
git rebase -q master >output.out 2>&1 &&
- test ! -s output.out
+ test_must_be_empty output.out
'
test_expect_success 'Rebase a commit that sprinkles CRs in' '
diff --git a/t/t3401-rebase-partial.sh b/t/t3401-rebase-partial.sh
deleted file mode 100755
index 58f4823..0000000
--- a/t/t3401-rebase-partial.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2006 Yann Dirson, based on t3400 by Amos Waterland
-#
-
-test_description='git rebase should detect patches integrated upstream
-
-This test cherry-picks one local change of two into master branch, and
-checks that git rebase succeeds with only the second patch in the
-local branch.
-'
-. ./test-lib.sh
-
-test_expect_success 'prepare repository with topic branch' '
- test_commit A &&
- git checkout -b my-topic-branch &&
- test_commit B &&
- test_commit C &&
- git checkout -f master &&
- test_commit A2 A.t
-'
-
-test_expect_success 'pick top patch from topic branch into master' '
- git cherry-pick C &&
- git checkout -f my-topic-branch
-'
-
-test_debug '
- git cherry master &&
- git format-patch -k --stdout --full-index master >/dev/null &&
- gitk --all & sleep 1
-'
-
-test_expect_success 'rebase topic branch against new master and check git am did not get halted' '
- git rebase master &&
- test_path_is_missing .git/rebase-apply
-'
-
-test_expect_success 'rebase --merge topic branch that was partially merged upstream' '
- git reset --hard C &&
- git rebase --merge master &&
- test_path_is_missing .git/rebase-merge
-'
-
-test_expect_success 'rebase ignores empty commit' '
- git reset --hard A &&
- git commit --allow-empty -m empty &&
- test_commit D &&
- git rebase C &&
- test "$(git log --format=%s C..)" = "D"
-'
-
-test_expect_success 'rebase --keep-empty' '
- git reset --hard D &&
- git rebase --keep-empty C &&
- test "$(git log --format=%s C..)" = "D
-empty"
-'
-
-test_expect_success 'rebase --keep-empty keeps empty even if already in upstream' '
- git reset --hard A &&
- git commit --allow-empty -m also-empty &&
- git rebase --keep-empty D &&
- test "$(git log --format=%s A..)" = "also-empty
-D
-empty"
-'
-
-test_done
diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh
index 826500b..3968020 100755
--- a/t/t3403-rebase-skip.sh
+++ b/t/t3403-rebase-skip.sh
@@ -64,10 +64,11 @@ test_expect_success 'rebase with --merge' '
test_expect_success 'rebase --skip with --merge' '
git rebase --skip
- '
+'
-test_expect_success 'merge and reference trees equal' \
- 'test -z "`git diff-tree skip-merge skip-reference`"'
+test_expect_success 'merge and reference trees equal' '
+ test -z "`git diff-tree skip-merge skip-reference`"
+'
test_expect_success 'moved back to branch correctly' '
test refs/heads/skip-merge = $(git symbolic-ref HEAD)
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 15dcbd4..50e22b1 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -29,8 +29,6 @@ Initial setup:
. "$TEST_DIRECTORY"/lib-rebase.sh
-set_fake_editor
-
# WARNING: Modifications to the initial repository can change the SHA ID used
# in the expect2 file for the 'stop on conflicting pick' test.
@@ -72,6 +70,7 @@ export SHELL
test_expect_success 'rebase -i with the exec command' '
git checkout master &&
(
+ set_fake_editor &&
FAKE_LINES="1 exec_>touch-one
2 exec_>touch-two exec_false exec_>touch-three
3 4 exec_>\"touch-file__name_with_spaces\";_>touch-after-semicolon 5" &&
@@ -93,6 +92,7 @@ test_expect_success 'rebase -i with the exec command' '
test_expect_success 'rebase -i with the exec command runs from tree root' '
git checkout master &&
mkdir subdir && (cd subdir &&
+ set_fake_editor &&
FAKE_LINES="1 exec_>touch-subdir" \
git rebase -i HEAD^
) &&
@@ -103,6 +103,7 @@ test_expect_success 'rebase -i with the exec command runs from tree root' '
test_expect_success 'rebase -i with the exec command checks tree cleanness' '
git checkout master &&
(
+ set_fake_editor &&
FAKE_LINES="exec_echo_foo_>file1 1" &&
export FAKE_LINES &&
test_must_fail git rebase -i HEAD^
@@ -116,6 +117,7 @@ test_expect_success 'rebase -i with exec of inexistent command' '
git checkout master &&
test_when_finished "git rebase --abort" &&
(
+ set_fake_editor &&
FAKE_LINES="exec_this-command-does-not-exist 1" &&
export FAKE_LINES &&
test_must_fail git rebase -i HEAD^ >actual 2>&1
@@ -125,6 +127,7 @@ test_expect_success 'rebase -i with exec of inexistent command' '
test_expect_success 'no changes are a nop' '
git checkout branch2 &&
+ set_fake_editor &&
git rebase -i F &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
test $(git rev-parse I) = $(git rev-parse HEAD)
@@ -134,6 +137,7 @@ test_expect_success 'test the [branch] option' '
git checkout -b dead-end &&
git rm file6 &&
git commit -m "stop here" &&
+ set_fake_editor &&
git rebase -i F branch2 &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
test $(git rev-parse I) = $(git rev-parse branch2) &&
@@ -142,6 +146,7 @@ test_expect_success 'test the [branch] option' '
test_expect_success 'test --onto <branch>' '
git checkout -b test-onto branch2 &&
+ set_fake_editor &&
git rebase -i --onto branch1 F &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" &&
test $(git rev-parse HEAD^) = $(git rev-parse branch1) &&
@@ -151,6 +156,7 @@ test_expect_success 'test --onto <branch>' '
test_expect_success 'rebase on top of a non-conflicting commit' '
git checkout branch1 &&
git tag original-branch1 &&
+ set_fake_editor &&
git rebase -i branch2 &&
test file6 = $(git diff --name-only original-branch1) &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
@@ -163,6 +169,7 @@ test_expect_success 'reflog for the branch shows state before rebase' '
'
test_expect_success 'exchange two commits' '
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i HEAD~2 &&
test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
test G = $(git cat-file commit HEAD | sed -ne \$p)
@@ -188,6 +195,7 @@ EOF
test_expect_success 'stop on conflicting pick' '
git tag new-branch1 &&
+ set_fake_editor &&
test_must_fail git rebase -i master &&
test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" &&
test_cmp expect .git/rebase-merge/patch &&
@@ -208,6 +216,7 @@ test_expect_success 'abort' '
test_expect_success 'abort with error when new base cannot be checked out' '
git rm --cached file1 &&
git commit -m "remove file in base" &&
+ set_fake_editor &&
test_must_fail git rebase -i master > output 2>&1 &&
grep "The following untracked working tree files would be overwritten by checkout:" \
output &&
@@ -222,6 +231,7 @@ test_expect_success 'retain authorship' '
test_tick &&
GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
git tag twerp &&
+ set_fake_editor &&
git rebase -i --onto master HEAD^ &&
git show HEAD | grep "^Author: Twerp Snog"
'
@@ -232,6 +242,7 @@ test_expect_success 'squash' '
test_tick &&
GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 &&
echo "******************************" &&
+ set_fake_editor &&
FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \
git rebase -i --onto master HEAD~2 &&
test B = $(cat file7) &&
@@ -244,6 +255,7 @@ test_expect_success 'retain authorship when squashing' '
test_expect_success '-p handles "no changes" gracefully' '
HEAD=$(git rev-parse HEAD) &&
+ set_fake_editor &&
git rebase -i -p HEAD^ &&
git update-index --refresh &&
git diff-files --quiet &&
@@ -253,6 +265,7 @@ test_expect_success '-p handles "no changes" gracefully' '
test_expect_failure 'exchange two commits with -p' '
git checkout H &&
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i -p HEAD~2 &&
test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
test G = $(git cat-file commit HEAD | sed -ne \$p)
@@ -287,6 +300,7 @@ test_expect_success 'preserve merges with -p' '
git commit -m M file1 &&
git checkout -b to-be-rebased &&
test_tick &&
+ set_fake_editor &&
git rebase -i -p --onto branch1 master &&
git update-index --refresh &&
git diff-files --quiet &&
@@ -301,6 +315,7 @@ test_expect_success 'preserve merges with -p' '
'
test_expect_success 'edit ancestor with -p' '
+ set_fake_editor &&
FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 &&
echo 2 > unrelated-file &&
test_tick &&
@@ -314,6 +329,7 @@ test_expect_success 'edit ancestor with -p' '
test_expect_success '--continue tries to commit' '
test_tick &&
+ set_fake_editor &&
test_must_fail git rebase -i --onto new-branch1 HEAD^ &&
echo resolved > file1 &&
git add file1 &&
@@ -325,6 +341,7 @@ test_expect_success '--continue tries to commit' '
test_expect_success 'verbose flag is heeded, even after --continue' '
git reset --hard master@{1} &&
test_tick &&
+ set_fake_editor &&
test_must_fail git rebase -v -i --onto new-branch1 HEAD^ &&
echo resolved > file1 &&
git add file1 &&
@@ -334,6 +351,7 @@ test_expect_success 'verbose flag is heeded, even after --continue' '
test_expect_success 'multi-squash only fires up editor once' '
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
@@ -344,6 +362,7 @@ test_expect_success 'multi-squash only fires up editor once' '
test_expect_success 'multi-fixup does not fire up editor' '
git checkout -b multi-fixup E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="NEVER" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \
git rebase -i $base &&
test $base = $(git rev-parse HEAD^) &&
@@ -355,6 +374,7 @@ test_expect_success 'multi-fixup does not fire up editor' '
test_expect_success 'commit message used after conflict' '
git checkout -b conflict-fixup conflict-branch &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
(
FAKE_LINES="1 fixup 3 fixup 4" &&
export FAKE_LINES &&
@@ -373,6 +393,7 @@ test_expect_success 'commit message used after conflict' '
test_expect_success 'commit message retained after conflict' '
git checkout -b conflict-squash conflict-branch &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
(
FAKE_LINES="1 fixup 3 squash 4" &&
export FAKE_LINES &&
@@ -399,6 +420,7 @@ EOF
test_expect_success 'squash and fixup generate correct log messages' '
git checkout -b squash-fixup E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
@@ -411,6 +433,7 @@ test_expect_success 'squash and fixup generate correct log messages' '
test_expect_success 'squash ignores comments' '
git checkout -b skip-comments E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
@@ -423,6 +446,7 @@ test_expect_success 'squash ignores comments' '
test_expect_success 'squash ignores blank lines' '
git checkout -b skip-blank-lines E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
@@ -435,6 +459,7 @@ test_expect_success 'squash ignores blank lines' '
test_expect_success 'squash works as expected' '
git checkout -b squash-works no-conflict-branch &&
one=$(git rev-parse HEAD~3) &&
+ set_fake_editor &&
FAKE_LINES="1 squash 3 2" EXPECT_HEADER_COUNT=2 \
git rebase -i HEAD~3 &&
test $one = $(git rev-parse HEAD~2)
@@ -443,6 +468,7 @@ test_expect_success 'squash works as expected' '
test_expect_success 'interrupted squash works as expected' '
git checkout -b interrupted-squash conflict-branch &&
one=$(git rev-parse HEAD~3) &&
+ set_fake_editor &&
(
FAKE_LINES="1 squash 3 2" &&
export FAKE_LINES &&
@@ -460,6 +486,7 @@ test_expect_success 'interrupted squash works as expected' '
test_expect_success 'interrupted squash works as expected (case 2)' '
git checkout -b interrupted-squash2 conflict-branch &&
one=$(git rev-parse HEAD~3) &&
+ set_fake_editor &&
(
FAKE_LINES="3 squash 1 2" &&
export FAKE_LINES &&
@@ -477,21 +504,14 @@ test_expect_success 'interrupted squash works as expected (case 2)' '
test $one = $(git rev-parse HEAD~2)
'
-test_expect_success 'ignore patch if in upstream' '
- HEAD=$(git rev-parse HEAD) &&
- git checkout -b has-cherry-picked HEAD^ &&
+test_expect_success '--continue tries to commit, even for "edit"' '
echo unrelated > file7 &&
git add file7 &&
test_tick &&
git commit -m "unrelated change" &&
- git cherry-pick $HEAD &&
- EXPECT_COUNT=1 git rebase -i $HEAD &&
- test $HEAD = $(git rev-parse HEAD^)
-'
-
-test_expect_success '--continue tries to commit, even for "edit"' '
parent=$(git rev-parse HEAD^) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo edited > file7 &&
git add file7 &&
@@ -504,6 +524,7 @@ test_expect_success '--continue tries to commit, even for "edit"' '
test_expect_success 'aborted --continue does not squash commits after "edit"' '
old=$(git rev-parse HEAD) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo "edited again" > file7 &&
git add file7 &&
@@ -518,6 +539,7 @@ test_expect_success 'aborted --continue does not squash commits after "edit"' '
test_expect_success 'auto-amend only edited commits after "edit"' '
test_tick &&
+ set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo "edited again" > file7 &&
git add file7 &&
@@ -536,6 +558,7 @@ test_expect_success 'auto-amend only edited commits after "edit"' '
test_expect_success 'clean error after failed "exec"' '
test_tick &&
test_when_finished "git rebase --abort || :" &&
+ set_fake_editor &&
(
FAKE_LINES="1 exec_false" &&
export FAKE_LINES &&
@@ -551,6 +574,7 @@ test_expect_success 'rebase a detached HEAD' '
grandparent=$(git rev-parse HEAD~2) &&
git checkout $(git rev-parse HEAD) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i HEAD~2 &&
test $grandparent = $(git rev-parse HEAD~2)
'
@@ -567,6 +591,7 @@ test_expect_success 'rebase a commit violating pre-commit' '
test_must_fail git commit -m doesnt-verify file1 &&
git commit -m doesnt-verify --no-verify file1 &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES=2 git rebase -i HEAD~2
'
@@ -588,6 +613,7 @@ test_expect_success 'rebase with a file named HEAD in worktree' '
git commit -m "Add body"
) &&
+ set_fake_editor &&
FAKE_LINES="1 squash 2" git rebase -i to-be-rebased &&
test "$(git show -s --pretty=format:%an)" = "Squashed Away"
@@ -599,6 +625,7 @@ test_expect_success 'do "noop" when there is nothing to cherry-pick' '
GIT_EDITOR=: git commit --amend \
--author="Somebody else <somebody@else.com>" &&
test $(git rev-parse branch3) != $(git rev-parse branch4) &&
+ set_fake_editor &&
git rebase -i branch3 &&
test $(git rev-parse branch3) = $(git rev-parse branch4)
@@ -623,10 +650,12 @@ test_expect_success 'submodule rebase setup' '
git commit -a -m "submodule second"
) &&
test_tick &&
+ set_fake_editor &&
git commit -a -m "Three changes submodule"
'
test_expect_success 'submodule rebase -i' '
+ set_fake_editor &&
FAKE_LINES="1 squash 2 3" git rebase -i A
'
@@ -644,6 +673,7 @@ test_expect_success 'submodule conflict setup' '
'
test_expect_success 'rebase -i continue with only submodule staged' '
+ set_fake_editor &&
test_must_fail git rebase -i submodule-base &&
git add sub &&
git rebase --continue &&
@@ -653,6 +683,7 @@ test_expect_success 'rebase -i continue with only submodule staged' '
test_expect_success 'rebase -i continue with unstaged submodule' '
git checkout submodule-topic &&
git reset --hard &&
+ set_fake_editor &&
test_must_fail git rebase -i submodule-base &&
git reset &&
git rebase --continue &&
@@ -665,6 +696,7 @@ test_expect_success 'avoid unnecessary reset' '
test-chmtime =123456789 file3 &&
git update-index --refresh &&
HEAD=$(git rev-parse HEAD) &&
+ set_fake_editor &&
git rebase -i HEAD~4 &&
test $HEAD = $(git rev-parse HEAD) &&
MTIME=$(test-chmtime -v +0 file3 | sed 's/[^0-9].*$//') &&
@@ -673,6 +705,7 @@ test_expect_success 'avoid unnecessary reset' '
test_expect_success 'reword' '
git checkout -b reword-branch master &&
+ set_fake_editor &&
FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" git rebase -i A &&
git show HEAD | grep "E changed" &&
test $(git rev-parse master) != $(git rev-parse HEAD) &&
@@ -692,7 +725,8 @@ test_expect_success 'rebase -i can copy notes' '
test_commit n2 &&
test_commit n3 &&
git notes add -m"a note" n3 &&
- git rebase --onto n1 n2 &&
+ set_fake_editor &&
+ git rebase -i --onto n1 n2 &&
test "a note" = "$(git notes show HEAD)"
'
@@ -705,6 +739,7 @@ EOF
test_expect_success 'rebase -i can copy notes over a fixup' '
git reset --hard n3 &&
git notes add -m"an earlier note" n2 &&
+ set_fake_editor &&
GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 fixup 2" git rebase -i n1 &&
git notes show > output &&
test_cmp expect output
@@ -714,6 +749,7 @@ test_expect_success 'rebase while detaching HEAD' '
git symbolic-ref HEAD &&
grandparent=$(git rev-parse HEAD~2) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 &&
test $grandparent = $(git rev-parse HEAD~2) &&
test_must_fail git symbolic-ref HEAD
@@ -723,6 +759,7 @@ test_tick # Ensure that the rebased commits get a different timestamp.
test_expect_success 'always cherry-pick with --no-ff' '
git checkout no-ff-branch &&
git tag original-no-ff-branch &&
+ set_fake_editor &&
git rebase -i --no-ff A &&
touch empty &&
for p in 0 1 2
@@ -755,6 +792,7 @@ test_expect_success 'set up commits with funny messages' '
test_expect_success 'rebase-i history with funny messages' '
git rev-list A..funny >expect &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="1 2 3 4" git rebase -i A &&
git rev-list A.. >actual &&
test_cmp expect actual
@@ -771,6 +809,7 @@ test_expect_success 'prepare for rebase -i --exec' '
test_expect_success 'running "git rebase -i --exec git show HEAD"' '
+ set_fake_editor &&
git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
@@ -784,6 +823,7 @@ test_expect_success 'running "git rebase -i --exec git show HEAD"' '
test_expect_success 'running "git rebase --exec git show HEAD -i"' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
@@ -797,6 +837,7 @@ test_expect_success 'running "git rebase --exec git show HEAD -i"' '
test_expect_success 'running "git rebase -ix git show HEAD"' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase -ix "git show HEAD" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
@@ -810,6 +851,7 @@ test_expect_success 'running "git rebase -ix git show HEAD"' '
test_expect_success 'rebase -ix with several <CMD>' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
@@ -823,6 +865,7 @@ test_expect_success 'rebase -ix with several <CMD>' '
test_expect_success 'rebase -ix with several instances of --exec' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
@@ -844,6 +887,7 @@ test_expect_success 'rebase -ix with --autosquash' '
echo bis >bis.txt &&
git add bis.txt &&
git commit -m "fixup! two_exec" &&
+ set_fake_editor &&
(
git checkout -b autosquash_actual &&
git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
@@ -862,6 +906,7 @@ test_expect_success 'rebase -ix with --autosquash' '
test_expect_success 'rebase --exec without -i shows error message' '
git reset --hard execute &&
+ set_fake_editor &&
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
@@ -870,6 +915,7 @@ test_expect_success 'rebase --exec without -i shows error message' '
test_expect_success 'rebase -i --exec without <CMD>' '
git reset --hard execute &&
+ set_fake_editor &&
test_must_fail git rebase -i --exec 2>tmp &&
sed -e "1d" tmp >actual &&
test_must_fail git rebase -h >expected &&
@@ -879,6 +925,7 @@ test_expect_success 'rebase -i --exec without <CMD>' '
test_expect_success 'rebase -i --root re-order and drop commits' '
git checkout E &&
+ set_fake_editor &&
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) &&
@@ -892,6 +939,7 @@ test_expect_success 'rebase -i --root retain root commit author and message' '
echo B >file7 &&
git add file7 &&
GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
+ set_fake_editor &&
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$"
@@ -900,6 +948,7 @@ test_expect_success 'rebase -i --root retain root commit author and message' '
test_expect_success 'rebase -i --root temporary sentinel commit' '
git checkout B &&
(
+ set_fake_editor &&
FAKE_LINES="2" &&
export FAKE_LINES &&
test_must_fail git rebase -i --root
@@ -910,6 +959,7 @@ test_expect_success 'rebase -i --root temporary sentinel commit' '
test_expect_success 'rebase -i --root fixup root commit' '
git checkout B &&
+ set_fake_editor &&
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) &&
@@ -919,6 +969,7 @@ test_expect_success 'rebase -i --root fixup root commit' '
test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' '
git reset --hard &&
git checkout conflict-branch &&
+ set_fake_editor &&
test_must_fail git rebase --onto HEAD~2 HEAD~ &&
test_must_fail git rebase --edit-todo &&
git rebase --abort
@@ -927,6 +978,7 @@ test_expect_success 'rebase --edit-todo does not works on non-interactive rebase
test_expect_success 'rebase --edit-todo can be used to modify todo' '
git reset --hard &&
git checkout no-conflict-branch^0 &&
+ set_fake_editor &&
FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 &&
FAKE_LINES="2 1" git rebase --edit-todo &&
git rebase --continue
@@ -934,11 +986,26 @@ test_expect_success 'rebase --edit-todo can be used to modify todo' '
test L = $(git cat-file commit HEAD | sed -ne \$p)
'
+test_expect_success 'rebase -i produces readable reflog' '
+ git reset --hard &&
+ git branch -f branch-reflog-test H &&
+ set_fake_editor &&
+ git rebase -i --onto I F branch-reflog-test &&
+ cat >expect <<-\EOF &&
+ rebase -i (start): checkout I
+ rebase -i (pick): G
+ rebase -i (pick): H
+ rebase -i (finish): returning to refs/heads/branch-reflog-test
+ EOF
+ tail -n 4 .git/logs/HEAD |
+ sed -e "s/.* //" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'rebase -i respects core.commentchar' '
git reset --hard &&
git checkout E^0 &&
- git config core.commentchar "\\" &&
- test_when_finished "git config --unset core.commentchar" &&
+ test_config core.commentchar "\\" &&
write_script remove-all-but-first.sh <<-\EOF &&
sed -e "2,\$s/^/\\\\/" "$1" >"$1.tmp" &&
mv "$1.tmp" "$1"
@@ -948,4 +1015,63 @@ test_expect_success 'rebase -i respects core.commentchar' '
test B = $(git cat-file commit HEAD^ | sed -ne \$p)
'
+test_expect_success 'rebase -i, with <onto> and <upstream> specified as :/quuxery' '
+ test_when_finished "git branch -D torebase" &&
+ git checkout -b torebase branch1 &&
+ upstream=$(git rev-parse ":/J") &&
+ onto=$(git rev-parse ":/A") &&
+ git rebase --onto $onto $upstream &&
+ git reset --hard branch1 &&
+ git rebase --onto ":/A" ":/J" &&
+ git checkout branch1
+'
+
+test_expect_success 'rebase -i with --strategy and -X' '
+ git checkout -b conflict-merge-use-theirs conflict-branch &&
+ git reset --hard HEAD^ &&
+ echo five >conflict &&
+ echo Z >file1 &&
+ git commit -a -m "one file conflict" &&
+ EDITOR=true git rebase -i --strategy=recursive -Xours conflict-branch &&
+ test $(git show conflict-branch:conflict) = $(cat conflict) &&
+ test $(cat file1) = Z
+'
+
+test_expect_success 'rebase -i error on commits with \ in message' '
+ current_head=$(git rev-parse HEAD)
+ test_when_finished "git rebase --abort; git reset --hard $current_head; rm -f error" &&
+ test_commit TO-REMOVE will-conflict old-content &&
+ test_commit "\temp" will-conflict new-content dummy &&
+ (
+ EDITOR=true &&
+ export EDITOR &&
+ test_must_fail git rebase -i HEAD^ --onto HEAD^^ 2>error
+ ) &&
+ test_expect_code 1 grep " emp" error
+'
+
+test_expect_success 'short SHA-1 setup' '
+ test_when_finished "git checkout master" &&
+ git checkout --orphan collide &&
+ git rm -rf . &&
+ (
+ unset test_tick &&
+ test_commit collide1 collide &&
+ test_commit --notick collide2 collide &&
+ test_commit --notick collide3 collide
+ )
+'
+
+test_expect_success 'short SHA-1 collide' '
+ test_when_finished "reset_rebase && git checkout master" &&
+ git checkout collide &&
+ (
+ unset test_tick &&
+ test_tick &&
+ set_fake_editor &&
+ FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \
+ FAKE_LINES="reword 1 2" git rebase -i HEAD~2
+ )
+'
+
test_done
diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh
index e6a9a0d..0392e36 100755
--- a/t/t3406-rebase-message.sh
+++ b/t/t3406-rebase-message.sh
@@ -4,27 +4,17 @@ test_description='messages from rebase operation'
. ./test-lib.sh
-quick_one () {
- echo "$1" >"file$1" &&
- git add "file$1" &&
- test_tick &&
- git commit -m "$1"
-}
+test_expect_success 'setup' '
+ test_commit O fileO &&
+ test_commit X fileX &&
+ test_commit A fileA &&
+ test_commit B fileB &&
+ test_commit Y fileY &&
-test_expect_success setup '
- quick_one O &&
- git branch topic &&
- quick_one X &&
- quick_one A &&
- quick_one B &&
- quick_one Y &&
-
- git checkout topic &&
- quick_one A &&
- quick_one B &&
- quick_one Z &&
+ git checkout -b topic O &&
+ git cherry-pick A B &&
+ test_commit Z fileZ &&
git tag start
-
'
cat >expect <<\EOF
@@ -34,12 +24,32 @@ Committed: 0003 Z
EOF
test_expect_success 'rebase -m' '
-
git rebase -m master >report &&
sed -n -e "/^Already applied: /p" \
-e "/^Committed: /p" report >actual &&
test_cmp expect actual
+'
+
+test_expect_success 'rebase against master twice' '
+ git rebase master >out &&
+ test_i18ngrep "Current branch topic is up to date" out
+'
+
+test_expect_success 'rebase against master twice with --force' '
+ git rebase --force-rebase master >out &&
+ test_i18ngrep "Current branch topic is up to date, rebase forced" out
+'
+
+test_expect_success 'rebase against master twice from another branch' '
+ git checkout topic^ &&
+ git rebase master topic >out &&
+ test_i18ngrep "Current branch topic is up to date" out
+'
+test_expect_success 'rebase fast-forward to master' '
+ git checkout topic^ &&
+ git rebase topic >out &&
+ test_i18ngrep "Fast-forwarded HEAD to topic" out
'
test_expect_success 'rebase --stat' '
diff --git a/t/t3409-rebase-preserve-merges.sh b/t/t3409-rebase-preserve-merges.sh
index 6de4e22..8c251c5 100755
--- a/t/t3409-rebase-preserve-merges.sh
+++ b/t/t3409-rebase-preserve-merges.sh
@@ -11,14 +11,6 @@ Run "git rebase -p" and check that merges are properly carried along
GIT_AUTHOR_EMAIL=bogus_email_address
export GIT_AUTHOR_EMAIL
-# Clone 1 (trivial merge):
-#
-# A1--A2 <-- origin/master
-# \ \
-# B1--M <-- topic
-# \
-# B2 <-- origin/topic
-#
# Clone 2 (conflicting merge):
#
# A1--A2--B3 <-- origin/master
@@ -37,15 +29,7 @@ export GIT_AUTHOR_EMAIL
# \
# B2 <-- origin/topic
#
-# Clone 4 (merge using second parent as base):
-#
-# A1--A2--B3 <-- origin/master
-# \
-# B1--A3--M <-- topic
-# \ /
-# \--A4 <-- topic2
-# \
-# B2 <-- origin/topic
+# Clone 4 (same as Clone 3)
test_expect_success 'setup for merge-preserving rebase' \
'echo First > A &&
@@ -58,20 +42,6 @@ test_expect_success 'setup for merge-preserving rebase' \
git checkout -f master &&
echo Third >> A &&
git commit -a -m "Modify A2" &&
-
- git clone ./. clone1 &&
- (cd clone1 &&
- git checkout -b topic origin/topic &&
- git merge origin/master
- ) &&
-
- git clone ./. clone4 &&
- (
- cd clone4 &&
- git checkout -b topic origin/topic &&
- git merge origin/master
- ) &&
-
echo Fifth > B &&
git add B &&
git commit -m "Add different B" &&
@@ -96,21 +66,21 @@ test_expect_success 'setup for merge-preserving rebase' \
git merge --no-ff topic2
) &&
+ git clone ./. clone4 &&
+ (
+ cd clone4 &&
+ git checkout -b topic2 origin/topic &&
+ echo Sixth > A &&
+ git commit -a -m "Modify A3" &&
+ git checkout -b topic origin/topic &&
+ git merge --no-ff topic2
+ ) &&
+
git checkout topic &&
echo Fourth >> B &&
git commit -a -m "Modify B2"
'
-test_expect_success 'rebase -p fakes interactive rebase' '
- (
- cd clone1 &&
- git fetch &&
- git rebase -p origin/topic &&
- test 1 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) &&
- test 1 = $(git rev-list --all --pretty=oneline | grep "Merge remote-tracking branch " | wc -l)
- )
-'
-
test_expect_success '--continue works after a conflict' '
(
cd clone2 &&
@@ -138,14 +108,14 @@ test_expect_success 'rebase -p preserves no-ff merges' '
)
'
-test_expect_success 'rebase -p works when base inside second parent' '
+test_expect_success 'rebase -p ignores merge.log config' '
(
cd clone4 &&
git fetch &&
- git rebase -p HEAD^2 &&
- test 1 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) &&
- test 1 = $(git rev-list --all --pretty=oneline | grep "Modify B" | wc -l) &&
- test 1 = $(git rev-list --all --pretty=oneline | grep "Merge remote-tracking branch " | wc -l)
+ git -c merge.log=1 rebase -p origin/topic &&
+ echo >expected &&
+ git log --format="%b" -1 >current &&
+ test_cmp expected current
)
'
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index a1e86c4..41370ab 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -4,6 +4,8 @@ test_description='auto squash'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
test_expect_success setup '
echo 0 >file0 &&
git add . &&
@@ -193,4 +195,59 @@ test_expect_success 'use commit --squash' '
test_auto_commit_flags squash 2
'
+test_auto_fixup_fixup () {
+ git reset --hard base &&
+ echo 1 >file1 &&
+ git add -u &&
+ test_tick &&
+ git commit -m "$1! first" &&
+ echo 2 >file1 &&
+ git add -u &&
+ test_tick &&
+ git commit -m "$1! $2! first" &&
+ git tag "final-$1-$2" &&
+ test_tick &&
+ (
+ set_cat_todo_editor &&
+ test_must_fail git rebase --autosquash -i HEAD^^^^ >actual &&
+ cat >expected <<-EOF &&
+ pick $(git rev-parse --short HEAD^^^) first commit
+ $1 $(git rev-parse --short HEAD^) $1! first
+ $1 $(git rev-parse --short HEAD) $1! $2! first
+ pick $(git rev-parse --short HEAD^^) second commit
+ EOF
+ test_cmp expected actual
+ ) &&
+ git rebase --autosquash -i HEAD^^^^ &&
+ git log --oneline >actual &&
+ test_line_count = 3 actual
+ git diff --exit-code "final-$1-$2" &&
+ test 2 = "$(git cat-file blob HEAD^:file1)" &&
+ if test "$1" = "fixup"
+ then
+ test 1 = $(git cat-file commit HEAD^ | grep first | wc -l)
+ elif test "$1" = "squash"
+ then
+ test 3 = $(git cat-file commit HEAD^ | grep first | wc -l)
+ else
+ false
+ fi
+}
+
+test_expect_success 'fixup! fixup!' '
+ test_auto_fixup_fixup fixup fixup
+'
+
+test_expect_success 'fixup! squash!' '
+ test_auto_fixup_fixup fixup squash
+'
+
+test_expect_success 'squash! squash!' '
+ test_auto_fixup_fixup squash squash
+'
+
+test_expect_success 'squash! fixup!' '
+ test_auto_fixup_fixup squash fixup
+'
+
test_done
diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh
new file mode 100755
index 0000000..90eb264
--- /dev/null
+++ b/t/t3420-rebase-autostash.sh
@@ -0,0 +1,170 @@
+#!/bin/sh
+#
+# Copyright (c) 2013 Ramkumar Ramachandra
+#
+
+test_description='git rebase --autostash tests'
+. ./test-lib.sh
+
+test_expect_success setup '
+ echo hello-world >file0 &&
+ git add . &&
+ test_tick &&
+ git commit -m "initial commit" &&
+ git checkout -b feature-branch &&
+ echo another-hello >file1 &&
+ echo goodbye >file2 &&
+ git add . &&
+ test_tick &&
+ git commit -m "second commit" &&
+ echo final-goodbye >file3 &&
+ git add . &&
+ test_tick &&
+ git commit -m "third commit" &&
+ git checkout -b unrelated-onto-branch master &&
+ echo unrelated >file4 &&
+ git add . &&
+ test_tick &&
+ git commit -m "unrelated commit" &&
+ git checkout -b related-onto-branch master &&
+ echo conflicting-change >file2 &&
+ git add . &&
+ test_tick &&
+ git commit -m "related commit"
+'
+
+testrebase() {
+ type=$1
+ dotest=$2
+
+ test_expect_success "rebase$type: dirty worktree, non-conflicting rebase" '
+ test_config rebase.autostash true &&
+ git reset --hard &&
+ git checkout -b rebased-feature-branch feature-branch &&
+ test_when_finished git branch -D rebased-feature-branch &&
+ echo dirty >>file3 &&
+ git rebase$type unrelated-onto-branch &&
+ grep unrelated file4 &&
+ grep dirty file3 &&
+ git checkout feature-branch
+ '
+
+ test_expect_success "rebase$type: dirty index, non-conflicting rebase" '
+ test_config rebase.autostash true &&
+ git reset --hard &&
+ git checkout -b rebased-feature-branch feature-branch &&
+ test_when_finished git branch -D rebased-feature-branch &&
+ echo dirty >>file3 &&
+ git add file3 &&
+ git rebase$type unrelated-onto-branch &&
+ grep unrelated file4 &&
+ grep dirty file3 &&
+ git checkout feature-branch
+ '
+
+ test_expect_success "rebase$type: conflicting rebase" '
+ test_config rebase.autostash true &&
+ git reset --hard &&
+ git checkout -b rebased-feature-branch feature-branch &&
+ test_when_finished git branch -D rebased-feature-branch &&
+ echo dirty >>file3 &&
+ test_must_fail git rebase$type related-onto-branch &&
+ test_path_is_file $dotest/autostash &&
+ ! grep dirty file3 &&
+ rm -rf $dotest &&
+ git reset --hard &&
+ git checkout feature-branch
+ '
+
+ test_expect_success "rebase$type: --continue" '
+ test_config rebase.autostash true &&
+ git reset --hard &&
+ git checkout -b rebased-feature-branch feature-branch &&
+ test_when_finished git branch -D rebased-feature-branch &&
+ echo dirty >>file3 &&
+ test_must_fail git rebase$type related-onto-branch &&
+ test_path_is_file $dotest/autostash &&
+ ! grep dirty file3 &&
+ echo "conflicting-plus-goodbye" >file2 &&
+ git add file2 &&
+ git rebase --continue &&
+ test_path_is_missing $dotest/autostash &&
+ grep dirty file3 &&
+ git checkout feature-branch
+ '
+
+ test_expect_success "rebase$type: --skip" '
+ test_config rebase.autostash true &&
+ git reset --hard &&
+ git checkout -b rebased-feature-branch feature-branch &&
+ test_when_finished git branch -D rebased-feature-branch &&
+ echo dirty >>file3 &&
+ test_must_fail git rebase$type related-onto-branch &&
+ test_path_is_file $dotest/autostash &&
+ ! grep dirty file3 &&
+ git rebase --skip &&
+ test_path_is_missing $dotest/autostash &&
+ grep dirty file3 &&
+ git checkout feature-branch
+ '
+
+ test_expect_success "rebase$type: --abort" '
+ test_config rebase.autostash true &&
+ git reset --hard &&
+ git checkout -b rebased-feature-branch feature-branch &&
+ test_when_finished git branch -D rebased-feature-branch &&
+ echo dirty >>file3 &&
+ test_must_fail git rebase$type related-onto-branch &&
+ test_path_is_file $dotest/autostash &&
+ ! grep dirty file3 &&
+ git rebase --abort &&
+ test_path_is_missing $dotest/autostash &&
+ grep dirty file3 &&
+ git checkout feature-branch
+ '
+
+ test_expect_success "rebase$type: non-conflicting rebase, conflicting stash" '
+ test_config rebase.autostash true &&
+ git reset --hard &&
+ git checkout -b rebased-feature-branch feature-branch &&
+ test_when_finished git branch -D rebased-feature-branch &&
+ echo dirty >file4 &&
+ git add file4 &&
+ git rebase$type unrelated-onto-branch &&
+ test_path_is_missing $dotest &&
+ git reset --hard &&
+ grep unrelated file4 &&
+ ! grep dirty file4 &&
+ git checkout feature-branch &&
+ git stash pop &&
+ grep dirty file4
+ '
+}
+
+test_expect_success "rebase: fast-forward rebase" '
+ test_config rebase.autostash true &&
+ git reset --hard &&
+ git checkout -b behind-feature-branch feature-branch~1 &&
+ test_when_finished git branch -D behind-feature-branch &&
+ echo dirty >>file1 &&
+ git rebase feature-branch &&
+ grep dirty file1 &&
+ git checkout feature-branch
+'
+
+test_expect_success "rebase: noop rebase" '
+ test_config rebase.autostash true &&
+ git reset --hard &&
+ git checkout -b same-feature-branch feature-branch &&
+ test_when_finished git branch -D same-feature-branch &&
+ echo dirty >>file1 &&
+ git rebase feature-branch &&
+ grep dirty file1 &&
+ git checkout feature-branch
+'
+
+testrebase "" .git/rebase-apply
+testrebase " --merge" .git/rebase-merge
+testrebase " --interactive" .git/rebase-merge
+
+test_done
diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh
new file mode 100755
index 0000000..9c55cba
--- /dev/null
+++ b/t/t3421-rebase-topology-linear.sh
@@ -0,0 +1,350 @@
+#!/bin/sh
+
+test_description='basic rebase topology tests'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+# a---b---c
+# \
+# d---e
+test_expect_success 'setup' '
+ test_commit a &&
+ test_commit b &&
+ test_commit c &&
+ git checkout b &&
+ test_commit d &&
+ test_commit e
+'
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "simple rebase $*" "
+ reset_rebase &&
+ git rebase $* c e &&
+ test_cmp_rev c HEAD~2 &&
+ test_linear_range 'd e' c..
+ "
+}
+test_run_rebase success ''
+test_run_rebase success -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* is no-op if upstream is an ancestor" "
+ reset_rebase &&
+ git rebase $* b e &&
+ test_cmp_rev e HEAD
+ "
+}
+test_run_rebase success ''
+test_run_rebase success -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* -f rewrites even if upstream is an ancestor" "
+ reset_rebase &&
+ git rebase $* -f b e &&
+ ! test_cmp_rev e HEAD &&
+ test_cmp_rev b HEAD~2 &&
+ test_linear_range 'd e' b..
+ "
+}
+test_run_rebase success ''
+test_run_rebase success -m
+test_run_rebase success -i
+test_run_rebase failure -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* fast-forwards from ancestor of upstream" "
+ reset_rebase &&
+ git rebase $* e b &&
+ test_cmp_rev e HEAD
+ "
+}
+test_run_rebase success ''
+test_run_rebase success -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+# f
+# /
+# a---b---c---g---h
+# \
+# d---gp--i
+#
+# gp = cherry-picked g
+# h = reverted g
+#
+# Reverted patches are there for tests to be able to check if a commit
+# that introduced the same change as another commit is
+# dropped. Without reverted commits, we could get false positives
+# because applying the patch succeeds, but simply results in no
+# changes.
+test_expect_success 'setup of linear history for range selection tests' '
+ git checkout c &&
+ test_commit g &&
+ revert h g &&
+ git checkout d &&
+ cherry_pick gp g &&
+ test_commit i &&
+ git checkout b &&
+ test_commit f
+'
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* drops patches in upstream" "
+ reset_rebase &&
+ git rebase $* h i &&
+ test_cmp_rev h HEAD~2 &&
+ test_linear_range 'd i' h..
+ "
+}
+test_run_rebase success ''
+test_run_rebase failure -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* can drop last patch if in upstream" "
+ reset_rebase &&
+ git rebase $* h gp &&
+ test_cmp_rev h HEAD^ &&
+ test_linear_range 'd' h..
+ "
+}
+test_run_rebase success ''
+test_run_rebase failure -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* --onto drops patches in upstream" "
+ reset_rebase &&
+ git rebase $* --onto f h i &&
+ test_cmp_rev f HEAD~2 &&
+ test_linear_range 'd i' f..
+ "
+}
+test_run_rebase success ''
+test_run_rebase failure -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* --onto does not drop patches in onto" "
+ reset_rebase &&
+ git rebase $* --onto h f i &&
+ test_cmp_rev h HEAD~3 &&
+ test_linear_range 'd gp i' h..
+ "
+}
+test_run_rebase success ''
+test_run_rebase success -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+# a---b---c---j!
+# \
+# d---k!--l
+#
+# ! = empty
+test_expect_success 'setup of linear history for empty commit tests' '
+ git checkout c &&
+ make_empty j &&
+ git checkout d &&
+ make_empty k &&
+ test_commit l
+'
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* drops empty commit" "
+ reset_rebase &&
+ git rebase $* c l &&
+ test_cmp_rev c HEAD~2 &&
+ test_linear_range 'd l' c..
+ "
+}
+test_run_rebase success ''
+test_run_rebase success -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* --keep-empty" "
+ reset_rebase &&
+ git rebase $* --keep-empty c l &&
+ test_cmp_rev c HEAD~3 &&
+ test_linear_range 'd k l' c..
+ "
+}
+test_run_rebase success ''
+test_run_rebase failure -m
+test_run_rebase success -i
+test_run_rebase failure -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* --keep-empty keeps empty even if already in upstream" "
+ reset_rebase &&
+ git rebase $* --keep-empty j l &&
+ test_cmp_rev j HEAD~3 &&
+ test_linear_range 'd k l' j..
+ "
+}
+test_run_rebase success ''
+test_run_rebase failure -m
+test_run_rebase failure -i
+test_run_rebase failure -p
+
+# m
+# /
+# a---b---c---g
+#
+# x---y---bp
+#
+# bp = cherry-picked b
+# m = reverted b
+#
+# Reverted patches are there for tests to be able to check if a commit
+# that introduced the same change as another commit is
+# dropped. Without reverted commits, we could get false positives
+# because applying the patch succeeds, but simply results in no
+# changes.
+test_expect_success 'setup of linear history for test involving root' '
+ git checkout b &&
+ revert m b &&
+ git checkout --orphan disjoint &&
+ git rm -rf . &&
+ test_commit x &&
+ test_commit y &&
+ cherry_pick bp b
+'
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* --onto --root" "
+ reset_rebase &&
+ git rebase $* --onto c --root y &&
+ test_cmp_rev c HEAD~2 &&
+ test_linear_range 'x y' c..
+ "
+}
+test_run_rebase success ''
+test_run_rebase failure -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* without --onto --root with disjoint history" "
+ reset_rebase &&
+ git rebase $* c y &&
+ test_cmp_rev c HEAD~2 &&
+ test_linear_range 'x y' c..
+ "
+}
+test_run_rebase success ''
+test_run_rebase failure -m
+test_run_rebase success -i
+test_run_rebase failure -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* --onto --root drops patch in onto" "
+ reset_rebase &&
+ git rebase $* --onto m --root bp &&
+ test_cmp_rev m HEAD~2 &&
+ test_linear_range 'x y' m..
+ "
+}
+test_run_rebase success ''
+test_run_rebase failure -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* --onto --root with merge-base does not go to root" "
+ reset_rebase &&
+ git rebase $* --onto m --root g &&
+ test_cmp_rev m HEAD~2 &&
+ test_linear_range 'c g' m..
+ "
+}
+
+test_run_rebase success ''
+test_run_rebase success -m
+test_run_rebase success -i
+test_run_rebase failure -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* without --onto --root with disjoint history drops patch in onto" "
+ reset_rebase &&
+ git rebase $* m bp &&
+ test_cmp_rev m HEAD~2 &&
+ test_linear_range 'x y' m..
+ "
+}
+test_run_rebase success ''
+test_run_rebase failure -m
+test_run_rebase success -i
+test_run_rebase failure -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* --root on linear history is a no-op" "
+ reset_rebase &&
+ git rebase $* --root c &&
+ test_cmp_rev c HEAD
+ "
+}
+test_run_rebase failure ''
+test_run_rebase failure -m
+test_run_rebase failure -i
+test_run_rebase failure -p
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* -f --root on linear history causes re-write" "
+ reset_rebase &&
+ git rebase $* -f --root c &&
+ ! test_cmp_rev a HEAD~2 &&
+ test_linear_range 'a b c' HEAD
+ "
+}
+test_run_rebase success ''
+test_run_rebase success -m
+test_run_rebase success -i
+test_run_rebase success -p
+
+test_done
diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh
new file mode 100755
index 0000000..1d195fb
--- /dev/null
+++ b/t/t3425-rebase-topology-merges.sh
@@ -0,0 +1,258 @@
+#!/bin/sh
+
+test_description='rebase topology tests with merges'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+test_revision_subjects () {
+ expected="$1"
+ shift
+ set -- $(git log --format=%s --no-walk=unsorted "$@")
+ test "$expected" = "$*"
+}
+
+# a---b-----------c
+# \ \
+# d-------e \
+# \ \ \
+# n---o---w---v
+# \
+# z
+test_expect_success 'setup of non-linear-history' '
+ test_commit a &&
+ test_commit b &&
+ test_commit c &&
+ git checkout b &&
+ test_commit d &&
+ test_commit e
+
+ git checkout c &&
+ test_commit g &&
+ revert h g &&
+ git checkout d &&
+ cherry_pick gp g &&
+ test_commit i &&
+ git checkout b &&
+ test_commit f
+
+ git checkout d &&
+ test_commit n &&
+ test_commit o &&
+ test_merge w e &&
+ test_merge v c &&
+ git checkout o &&
+ test_commit z
+'
+
+test_run_rebase () {
+ result=$1
+ shift
+ test_expect_$result "rebase $* after merge from upstream" "
+ reset_rebase &&
+ git rebase $* e w &&
+ test_cmp_rev e HEAD~2 &&
+ test_linear_range 'n o' e..
+ "
+}
+test_run_rebase success ''
+test_run_rebase success -m
+test_run_rebase success -i
+
+test_run_rebase () {
+ result=$1
+ shift
+ expected=$1
+ shift
+ test_expect_$result "rebase $* of non-linear history is linearized in place" "
+ reset_rebase &&
+ git rebase $* d w &&
+ test_cmp_rev d HEAD~3 &&
+ test_linear_range "\'"$expected"\'" d..
+ "
+}
+#TODO: make order consistent across all flavors of rebase
+test_run_rebase success 'e n o' ''
+test_run_rebase success 'e n o' -m
+test_run_rebase success 'n o e' -i
+
+test_run_rebase () {
+ result=$1
+ shift
+ expected=$1
+ shift
+ test_expect_$result "rebase $* of non-linear history is linearized upstream" "
+ reset_rebase &&
+ git rebase $* c w &&
+ test_cmp_rev c HEAD~4 &&
+ test_linear_range "\'"$expected"\'" c..
+ "
+}
+#TODO: make order consistent across all flavors of rebase
+test_run_rebase success 'd e n o' ''
+test_run_rebase success 'd e n o' -m
+test_run_rebase success 'd n o e' -i
+
+test_run_rebase () {
+ result=$1
+ shift
+ expected=$1
+ shift
+ test_expect_$result "rebase $* of non-linear history with merges after upstream merge is linearized" "
+ reset_rebase &&
+ git rebase $* c v &&
+ test_cmp_rev c HEAD~4 &&
+ test_linear_range "\'"$expected"\'" c..
+ "
+}
+#TODO: make order consistent across all flavors of rebase
+test_run_rebase success 'd e n o' ''
+test_run_rebase success 'd e n o' -m
+test_run_rebase success 'd n o e' -i
+
+test_expect_success "rebase -p is no-op in non-linear history" "
+ reset_rebase &&
+ git rebase -p d w &&
+ test_cmp_rev w HEAD
+"
+
+test_expect_success "rebase -p is no-op when base inside second parent" "
+ reset_rebase &&
+ git rebase -p e w &&
+ test_cmp_rev w HEAD
+"
+
+test_expect_failure "rebase -p --root on non-linear history is a no-op" "
+ reset_rebase &&
+ git rebase -p --root w &&
+ test_cmp_rev w HEAD
+"
+
+test_expect_success "rebase -p re-creates merge from side branch" "
+ reset_rebase &&
+ git rebase -p z w &&
+ test_cmp_rev z HEAD^ &&
+ test_cmp_rev w^2 HEAD^2
+"
+
+test_expect_success "rebase -p re-creates internal merge" "
+ reset_rebase &&
+ git rebase -p c w &&
+ test_cmp_rev c HEAD~4 &&
+ test_cmp_rev HEAD^2^ HEAD~3 &&
+ test_revision_subjects 'd n e o w' HEAD~3 HEAD~2 HEAD^2 HEAD^ HEAD
+"
+
+test_expect_success "rebase -p can re-create two branches on onto" "
+ reset_rebase &&
+ git rebase -p --onto c d w &&
+ test_cmp_rev c HEAD~3 &&
+ test_cmp_rev c HEAD^2^ &&
+ test_revision_subjects 'n e o w' HEAD~2 HEAD^2 HEAD^ HEAD
+"
+
+# f
+# /
+# a---b---c---g---h
+# \
+# d---gp--i
+# \ \
+# e-------u
+#
+# gp = cherry-picked g
+# h = reverted g
+test_expect_success 'setup of non-linear-history for patch-equivalence tests' '
+ git checkout e &&
+ test_merge u i
+'
+
+test_expect_success "rebase -p re-creates history around dropped commit matching upstream" "
+ reset_rebase &&
+ git rebase -p h u &&
+ test_cmp_rev h HEAD~3 &&
+ test_cmp_rev HEAD^2^ HEAD~2 &&
+ test_revision_subjects 'd i e u' HEAD~2 HEAD^2 HEAD^ HEAD
+"
+
+test_expect_success "rebase -p --onto in merged history drops patches in upstream" "
+ reset_rebase &&
+ git rebase -p --onto f h u &&
+ test_cmp_rev f HEAD~3 &&
+ test_cmp_rev HEAD^2^ HEAD~2 &&
+ test_revision_subjects 'd i e u' HEAD~2 HEAD^2 HEAD^ HEAD
+"
+
+test_expect_success "rebase -p --onto in merged history does not drop patches in onto" "
+ reset_rebase &&
+ git rebase -p --onto h f u &&
+ test_cmp_rev h HEAD~3 &&
+ test_cmp_rev HEAD^2~2 HEAD~2 &&
+ test_revision_subjects 'd gp i e u' HEAD~2 HEAD^2^ HEAD^2 HEAD^ HEAD
+"
+
+# a---b---c---g---h
+# \
+# d---gp--s
+# \ \ /
+# \ X
+# \ / \
+# e---t
+#
+# gp = cherry-picked g
+# h = reverted g
+test_expect_success 'setup of non-linear-history for dropping whole side' '
+ git checkout gp &&
+ test_merge s e &&
+ git checkout e &&
+ test_merge t gp
+'
+
+test_expect_failure "rebase -p drops merge commit when entire first-parent side is dropped" "
+ reset_rebase &&
+ git rebase -p h s &&
+ test_cmp_rev h HEAD~2 &&
+ test_linear_range 'd e' h..
+"
+
+test_expect_success "rebase -p drops merge commit when entire second-parent side is dropped" "
+ reset_rebase &&
+ git rebase -p h t &&
+ test_cmp_rev h HEAD~2 &&
+ test_linear_range 'd e' h..
+"
+
+# a---b---c
+# \
+# d---e
+# \ \
+# n---r
+# \
+# o
+#
+# r = tree-same with n
+test_expect_success 'setup of non-linear-history for empty commits' '
+ git checkout n &&
+ git merge --no-commit e &&
+ git reset n . &&
+ git commit -m r &&
+ git reset --hard &&
+ git clean -f &&
+ git tag r
+'
+
+test_expect_success "rebase -p re-creates empty internal merge commit" "
+ reset_rebase &&
+ git rebase -p c r &&
+ test_cmp_rev c HEAD~3 &&
+ test_cmp_rev HEAD^2^ HEAD~2 &&
+ test_revision_subjects 'd e n r' HEAD~2 HEAD^2 HEAD^ HEAD
+"
+
+test_expect_success "rebase -p re-creates empty merge commit" "
+ reset_rebase &&
+ git rebase -p o r &&
+ test_cmp_rev e HEAD^2 &&
+ test_cmp_rev o HEAD^ &&
+ test_revision_subjects 'r' HEAD
+"
+
+test_done
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 6f489e2..46aaf2f 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -100,7 +100,7 @@ test_expect_success 'revert forbidden on dirty working tree' '
'
-test_expect_success 'chery-pick on unborn branch' '
+test_expect_success 'cherry-pick on unborn branch' '
git checkout --orphan unborn &&
git rm --cached -r . &&
rm -rf * &&
diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index a0c6e30..fbdc47c 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -28,29 +28,21 @@ test_expect_success setup '
'
test_expect_success 'cherry-pick an empty commit' '
- git checkout master && {
- git cherry-pick empty-branch^
- test "$?" = 1
- }
+ git checkout master &&
+ test_expect_code 1 git cherry-pick empty-branch^
'
test_expect_success 'index lockfile was removed' '
-
test ! -f .git/index.lock
-
'
test_expect_success 'cherry-pick a commit with an empty message' '
- git checkout master && {
- git cherry-pick empty-branch
- test "$?" = 1
- }
+ git checkout master &&
+ test_expect_code 1 git cherry-pick empty-branch
'
test_expect_success 'index lockfile was removed' '
-
test ! -f .git/index.lock
-
'
test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' '
@@ -101,7 +93,7 @@ test_expect_success 'cherry-pick a no-op with --keep-redundant' '
git reset --hard &&
git checkout fork^0 &&
git cherry-pick --keep-redundant-commits master &&
- git show -s --format='%s' >actual &&
+ git show -s --format=%s >actual &&
echo "add file2 on master" >expect &&
test_cmp expect actual
'
diff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh
index 373aad6..fb889ac 100755
--- a/t/t3506-cherry-pick-ff.sh
+++ b/t/t3506-cherry-pick-ff.sh
@@ -105,7 +105,7 @@ test_expect_success 'cherry pick a root commit with --ff' '
test "$(git rev-parse --verify HEAD)" = "1df192cd8bc58a2b275d842cede4d221ad9000d1"
'
-test_expect_success 'chery-pick --ff on unborn branch' '
+test_expect_success 'cherry-pick --ff on unborn branch' '
git checkout --orphan unborn &&
git rm --cached -r . &&
rm -rf * &&
diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh
index 4e7136b..19c99d7 100755
--- a/t/t3508-cherry-pick-many-commits.sh
+++ b/t/t3508-cherry-pick-many-commits.sh
@@ -55,6 +55,12 @@ one
two"
'
+test_expect_success 'cherry-pick three one two: fails' '
+ git checkout -f master &&
+ git reset --hard first &&
+ test_must_fail git cherry-pick three one two:
+'
+
test_expect_success 'output to keep user entertained during multi-pick' '
cat <<-\EOF >expected &&
[master OBJID] second
diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh
index df921d1..1e5b394 100755
--- a/t/t3509-cherry-pick-merge-df.sh
+++ b/t/t3509-cherry-pick-merge-df.sh
@@ -10,17 +10,15 @@ test_expect_success 'Initialize repository' '
git commit -m a
'
-test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' '
+test_expect_success 'Setup rename across paths each below D/F conflicts' '
mkdir b &&
- ln -s ../a b/a &&
- git add b &&
+ test_ln_s_add ../a b/a &&
git commit -m b &&
git checkout -b branch &&
rm b/a &&
- mv a b/a &&
- ln -s b/a a &&
- git add . &&
+ git mv a b/a &&
+ test_ln_s_add b/a a &&
git commit -m swap &&
>f1 &&
@@ -28,7 +26,7 @@ test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts
git commit -m f1
'
-test_expect_success SYMLINKS 'Cherry-pick succeeds with rename across D/F conflicts' '
+test_expect_success 'Cherry-pick succeeds with rename across D/F conflicts' '
git reset --hard &&
git checkout master^0 &&
git cherry-pick branch
@@ -76,7 +74,7 @@ test_expect_success 'Setup rename with file on one side matching different dirna
echo content > sub/file &&
echo foo > othersub/whatever &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git rm -rf othersub &&
git mv sub/file othersub &&
diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh
new file mode 100755
index 0000000..f977279
--- /dev/null
+++ b/t/t3511-cherry-pick-x.sh
@@ -0,0 +1,219 @@
+#!/bin/sh
+
+test_description='Test cherry-pick -x and -s'
+
+. ./test-lib.sh
+
+pristine_detach () {
+ git cherry-pick --quit &&
+ git checkout -f "$1^0" &&
+ git read-tree -u --reset HEAD &&
+ git clean -d -f -f -q -x
+}
+
+mesg_one_line='base: commit message'
+
+mesg_no_footer="$mesg_one_line
+
+OneWordBodyThatsNotA-S-o-B"
+
+mesg_with_footer="$mesg_no_footer
+
+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+Signed-off-by: A.U. Thor <author@example.com>
+Signed-off-by: B.U. Thor <buthor@example.com>"
+
+mesg_broken_footer="$mesg_no_footer
+
+The signed-off-by string should begin with the words Signed-off-by followed
+by a colon and space, and then the signers name and email address. e.g.
+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
+
+mesg_with_footer_sob="$mesg_with_footer
+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
+
+mesg_with_cherry_footer="$mesg_with_footer_sob
+(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
+Tested-by: C.U. Thor <cuthor@example.com>"
+
+
+test_expect_success setup '
+ git config advice.detachedhead false &&
+ echo unrelated >unrelated &&
+ git add unrelated &&
+ test_commit initial foo a &&
+ test_commit "$mesg_one_line" foo b mesg-one-line &&
+ git reset --hard initial &&
+ test_commit "$mesg_no_footer" foo b mesg-no-footer &&
+ git reset --hard initial &&
+ test_commit "$mesg_broken_footer" foo b mesg-broken-footer &&
+ git reset --hard initial &&
+ test_commit "$mesg_with_footer" foo b mesg-with-footer &&
+ git reset --hard initial &&
+ test_commit "$mesg_with_footer_sob" foo b mesg-with-footer-sob &&
+ git reset --hard initial &&
+ test_commit "$mesg_with_cherry_footer" foo b mesg-with-cherry-footer &&
+ pristine_detach initial &&
+ test_commit conflicting unrelated
+'
+
+test_expect_success 'cherry-pick -x inserts blank line after one line subject' '
+ pristine_detach initial &&
+ sha1=`git rev-parse mesg-one-line^0` &&
+ git cherry-pick -x mesg-one-line &&
+ cat <<-EOF >expect &&
+ $mesg_one_line
+
+ (cherry picked from commit $sha1)
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -s inserts blank line after one line subject' '
+ pristine_detach initial &&
+ git cherry-pick -s mesg-one-line &&
+ cat <<-EOF >expect &&
+ $mesg_one_line
+
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -s inserts blank line after non-conforming footer' '
+ pristine_detach initial &&
+ git cherry-pick -s mesg-broken-footer &&
+ cat <<-EOF >expect &&
+ $mesg_broken_footer
+
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -x inserts blank line when conforming footer not found' '
+ pristine_detach initial &&
+ sha1=`git rev-parse mesg-no-footer^0` &&
+ git cherry-pick -x mesg-no-footer &&
+ cat <<-EOF >expect &&
+ $mesg_no_footer
+
+ (cherry picked from commit $sha1)
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -s inserts blank line when conforming footer not found' '
+ pristine_detach initial &&
+ git cherry-pick -s mesg-no-footer &&
+ cat <<-EOF >expect &&
+ $mesg_no_footer
+
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -x -s inserts blank line when conforming footer not found' '
+ pristine_detach initial &&
+ sha1=`git rev-parse mesg-no-footer^0` &&
+ git cherry-pick -x -s mesg-no-footer &&
+ cat <<-EOF >expect &&
+ $mesg_no_footer
+
+ (cherry picked from commit $sha1)
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -s adds sob when last sob doesnt match committer' '
+ pristine_detach initial &&
+ git cherry-pick -s mesg-with-footer &&
+ cat <<-EOF >expect &&
+ $mesg_with_footer
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -x -s adds sob when last sob doesnt match committer' '
+ pristine_detach initial &&
+ sha1=`git rev-parse mesg-with-footer^0` &&
+ git cherry-pick -x -s mesg-with-footer &&
+ cat <<-EOF >expect &&
+ $mesg_with_footer
+ (cherry picked from commit $sha1)
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -s refrains from adding duplicate trailing sob' '
+ pristine_detach initial &&
+ git cherry-pick -s mesg-with-footer-sob &&
+ cat <<-EOF >expect &&
+ $mesg_with_footer_sob
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -x -s adds sob even when trailing sob exists for committer' '
+ pristine_detach initial &&
+ sha1=`git rev-parse mesg-with-footer-sob^0` &&
+ git cherry-pick -x -s mesg-with-footer-sob &&
+ cat <<-EOF >expect &&
+ $mesg_with_footer_sob
+ (cherry picked from commit $sha1)
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -x treats "(cherry picked from..." line as part of footer' '
+ pristine_detach initial &&
+ sha1=`git rev-parse mesg-with-cherry-footer^0` &&
+ git cherry-pick -x mesg-with-cherry-footer &&
+ cat <<-EOF >expect &&
+ $mesg_with_cherry_footer
+ (cherry picked from commit $sha1)
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -s treats "(cherry picked from..." line as part of footer' '
+ pristine_detach initial &&
+ git cherry-pick -s mesg-with-cherry-footer &&
+ cat <<-EOF >expect &&
+ $mesg_with_cherry_footer
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick -x -s treats "(cherry picked from..." line as part of footer' '
+ pristine_detach initial &&
+ sha1=`git rev-parse mesg-with-cherry-footer^0` &&
+ git cherry-pick -x -s mesg-with-cherry-footer &&
+ cat <<-EOF >expect &&
+ $mesg_with_cherry_footer
+ (cherry picked from commit $sha1)
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+ git log -1 --pretty=format:%B >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 37bf5f1..639cb70 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -263,6 +263,7 @@ test_expect_success 'rm removes subdirectories recursively' '
'
cat >expect <<EOF
+M .gitmodules
D submod
EOF
@@ -270,6 +271,15 @@ cat >expect.modified <<EOF
M submod
EOF
+cat >expect.cached <<EOF
+D submod
+EOF
+
+cat >expect.both_deleted<<EOF
+D .gitmodules
+D submod
+EOF
+
test_expect_success 'rm removes empty submodules from work tree' '
mkdir submod &&
git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) submod &&
@@ -281,16 +291,20 @@ test_expect_success 'rm removes empty submodules from work tree' '
git rm submod &&
test ! -e submod &&
git status -s -uno --ignore-submodules=none > actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
-test_expect_success 'rm removes removed submodule from index' '
+test_expect_success 'rm removes removed submodule from index and .gitmodules' '
git reset --hard &&
git submodule update &&
rm -rf submod &&
git rm submod &&
git status -s -uno --ignore-submodules=none > actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
test_expect_success 'rm removes work tree of unmodified submodules' '
@@ -299,7 +313,9 @@ test_expect_success 'rm removes work tree of unmodified submodules' '
git rm submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none > actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
test_expect_success 'rm removes a submodule with a trailing /' '
@@ -333,6 +349,72 @@ test_expect_success 'rm of a populated submodule with different HEAD fails unles
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none > actual &&
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
+'
+
+test_expect_success 'rm --cached leaves work tree of populated submodules and .gitmodules alone' '
+ git reset --hard &&
+ git submodule update &&
+ git rm --cached submod &&
+ test -d submod &&
+ test -f submod/.git &&
+ git status -s -uno >actual &&
+ test_cmp expect.cached actual &&
+ git config -f .gitmodules submodule.sub.url &&
+ git config -f .gitmodules submodule.sub.path
+'
+
+test_expect_success 'rm --dry-run does not touch the submodule or .gitmodules' '
+ git reset --hard &&
+ git submodule update &&
+ git rm -n submod &&
+ test -f submod/.git &&
+ git diff-index --exit-code HEAD
+'
+
+test_expect_success 'rm does not complain when no .gitmodules file is found' '
+ git reset --hard &&
+ git submodule update &&
+ git rm .gitmodules &&
+ git rm submod >actual 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -d submod &&
+ ! test -f submod/.git &&
+ git status -s -uno >actual &&
+ test_cmp expect.both_deleted actual
+'
+
+test_expect_success 'rm will error out on a modified .gitmodules file unless staged' '
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules foo.bar true &&
+ test_must_fail git rm submod >actual 2>actual.err &&
+ test -s actual.err &&
+ test -d submod &&
+ test -f submod/.git &&
+ git diff-files --quiet -- submod &&
+ git add .gitmodules &&
+ git rm submod >actual 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -d submod &&
+ ! test -f submod/.git &&
+ git status -s -uno >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rm issues a warning when section is not found in .gitmodules' '
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules --remove-section submodule.sub &&
+ git add .gitmodules &&
+ echo "warning: Could not find section in .gitmodules where path=submod" >expect.err &&
+ git rm submod >actual 2>actual.err &&
+ test_i18ncmp expect.err actual.err &&
+ ! test -d submod &&
+ ! test -f submod/.git &&
+ git status -s -uno >actual &&
test_cmp expect actual
'
@@ -427,7 +509,9 @@ test_expect_success 'rm of a conflicted populated submodule with different HEAD
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none > actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
test_expect_success 'rm of a conflicted populated submodule with modifications fails unless forced' '
@@ -446,7 +530,9 @@ test_expect_success 'rm of a conflicted populated submodule with modifications f
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none > actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
test_expect_success 'rm of a conflicted populated submodule with untracked files fails unless forced' '
@@ -622,4 +708,165 @@ test_expect_success 'rm of a populated nested submodule with a nested .git direc
rm -rf submod
'
+test_expect_success 'rm of d/f when d has become a non-directory' '
+ rm -rf d &&
+ mkdir d &&
+ >d/f &&
+ git add d &&
+ rm -rf d &&
+ >d &&
+ git rm d/f &&
+ test_must_fail git rev-parse --verify :d/f &&
+ test_path_is_file d
+'
+
+test_expect_success SYMLINKS 'rm of d/f when d has become a dangling symlink' '
+ rm -rf d &&
+ mkdir d &&
+ >d/f &&
+ git add d &&
+ rm -rf d &&
+ ln -s nonexistent d &&
+ git rm d/f &&
+ test_must_fail git rev-parse --verify :d/f &&
+ test -h d &&
+ test_path_is_missing d
+'
+
+test_expect_success 'rm of file when it has become a directory' '
+ rm -rf d &&
+ >d &&
+ git add d &&
+ rm -f d &&
+ mkdir d &&
+ >d/f &&
+ test_must_fail git rm d &&
+ git rev-parse --verify :d &&
+ test_path_is_file d/f
+'
+
+test_expect_success SYMLINKS 'rm across a symlinked leading path (no index)' '
+ rm -rf d e &&
+ mkdir e &&
+ echo content >e/f &&
+ ln -s e d &&
+ git add -A e d &&
+ git commit -m "symlink d to e, e/f exists" &&
+ test_must_fail git rm d/f &&
+ git rev-parse --verify :d &&
+ git rev-parse --verify :e/f &&
+ test -h d &&
+ test_path_is_file e/f
+'
+
+test_expect_failure SYMLINKS 'rm across a symlinked leading path (w/ index)' '
+ rm -rf d e &&
+ mkdir d &&
+ echo content >d/f &&
+ git add -A e d &&
+ git commit -m "d/f exists" &&
+ mv d e &&
+ ln -s e d &&
+ test_must_fail git rm d/f &&
+ git rev-parse --verify :d/f &&
+ test -h d &&
+ test_path_is_file e/f
+'
+
+test_expect_success 'setup for testing rm messages' '
+ >bar.txt &&
+ >foo.txt &&
+ git add bar.txt foo.txt
+'
+
+test_expect_success 'rm files with different staged content' '
+ cat >expect <<-\EOF &&
+ error: the following files have staged content different from both the
+ file and the HEAD:
+ bar.txt
+ foo.txt
+ (use -f to force removal)
+ EOF
+ echo content1 >foo.txt &&
+ echo content1 >bar.txt &&
+ test_must_fail git rm foo.txt bar.txt 2>actual &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'rm files with different staged content without hints' '
+ cat >expect <<-\EOF &&
+ error: the following files have staged content different from both the
+ file and the HEAD:
+ bar.txt
+ foo.txt
+ EOF
+ echo content2 >foo.txt &&
+ echo content2 >bar.txt &&
+ test_must_fail git -c advice.rmhints=false rm foo.txt bar.txt 2>actual &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'rm file with local modification' '
+ cat >expect <<-\EOF &&
+ error: the following file has local modifications:
+ foo.txt
+ (use --cached to keep the file, or -f to force removal)
+ EOF
+ git commit -m "testing rm 3" &&
+ echo content3 >foo.txt &&
+ test_must_fail git rm foo.txt 2>actual &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'rm file with local modification without hints' '
+ cat >expect <<-\EOF &&
+ error: the following file has local modifications:
+ bar.txt
+ EOF
+ echo content4 >bar.txt &&
+ test_must_fail git -c advice.rmhints=false rm bar.txt 2>actual &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'rm file with changes in the index' '
+ cat >expect <<-\EOF &&
+ error: the following file has changes staged in the index:
+ foo.txt
+ (use --cached to keep the file, or -f to force removal)
+ EOF
+ git reset --hard &&
+ echo content5 >foo.txt &&
+ git add foo.txt &&
+ test_must_fail git rm foo.txt 2>actual &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'rm file with changes in the index without hints' '
+ cat >expect <<-\EOF &&
+ error: the following file has changes staged in the index:
+ foo.txt
+ EOF
+ test_must_fail git -c advice.rmhints=false rm foo.txt 2>actual &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'rm files with two different errors' '
+ cat >expect <<-\EOF &&
+ error: the following file has staged content different from both the
+ file and the HEAD:
+ foo1.txt
+ (use -f to force removal)
+ error: the following file has changes staged in the index:
+ bar1.txt
+ (use --cached to keep the file, or -f to force removal)
+ EOF
+ echo content >foo1.txt &&
+ git add foo1.txt &&
+ echo content6 >foo1.txt &&
+ echo content6 >bar1.txt &&
+ git add bar1.txt &&
+ test_must_fail git rm bar1.txt foo1.txt 2>actual &&
+ test_i18ncmp expect actual
+'
+
test_done
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 874b3a6..aab86e8 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -30,10 +30,9 @@ test_expect_success \
*) echo fail; git ls-files --stage xfoo1; (exit 1);;
esac'
-test_expect_success SYMLINKS 'git add: filemode=0 should not get confused by symlink' '
+test_expect_success 'git add: filemode=0 should not get confused by symlink' '
rm -f xfoo1 &&
- ln -s foo xfoo1 &&
- git add xfoo1 &&
+ test_ln_s_add foo xfoo1 &&
case "`git ls-files --stage xfoo1`" in
120000" "*xfoo1) echo pass;;
*) echo fail; git ls-files --stage xfoo1; (exit 1);;
@@ -51,21 +50,19 @@ test_expect_success \
*) echo fail; git ls-files --stage xfoo2; (exit 1);;
esac'
-test_expect_success SYMLINKS 'git add: filemode=0 should not get confused by symlink' '
+test_expect_success 'git add: filemode=0 should not get confused by symlink' '
rm -f xfoo2 &&
- ln -s foo xfoo2 &&
- git update-index --add xfoo2 &&
+ test_ln_s_add foo xfoo2 &&
case "`git ls-files --stage xfoo2`" in
120000" "*xfoo2) echo pass;;
*) echo fail; git ls-files --stage xfoo2; (exit 1);;
esac
'
-test_expect_success SYMLINKS \
+test_expect_success \
'git update-index --add: Test that executable bit is not used...' \
'git config core.filemode 0 &&
- ln -s xfoo2 xfoo3 &&
- git update-index --add xfoo3 &&
+ test_ln_s_add xfoo2 xfoo3 && # runs git update-index --add
case "`git ls-files --stage xfoo3`" in
120000" "*xfoo3) echo pass;;
*) echo fail; git ls-files --stage xfoo3; (exit 1);;
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
index 37ddabb..4bf1dbe 100755
--- a/t/t3900-i18n-commit.sh
+++ b/t/t3900-i18n-commit.sh
@@ -34,11 +34,47 @@ test_expect_success 'no encoding header for base case' '
test z = "z$E"
'
-test_expect_failure 'UTF-16 refused because of NULs' '
+test_expect_success 'UTF-16 refused because of NULs' '
echo UTF-16 >F &&
- git commit -a -F "$TEST_DIRECTORY"/t3900/UTF-16.txt
+ test_must_fail git commit -a -F "$TEST_DIRECTORY"/t3900/UTF-16.txt
'
+test_expect_success 'UTF-8 invalid characters refused' '
+ test_when_finished "rm -f $HOME/stderr $HOME/invalid" &&
+ echo "UTF-8 characters" >F &&
+ printf "Commit message\n\nInvalid surrogate:\355\240\200\n" \
+ >"$HOME/invalid" &&
+ git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
+ grep "did not conform" "$HOME"/stderr
+'
+
+test_expect_success 'UTF-8 overlong sequences rejected' '
+ test_when_finished "rm -f $HOME/stderr $HOME/invalid" &&
+ rm -f "$HOME/stderr" "$HOME/invalid" &&
+ echo "UTF-8 overlong" >F &&
+ printf "\340\202\251ommit message\n\nThis is not a space:\300\240\n" \
+ >"$HOME/invalid" &&
+ git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
+ grep "did not conform" "$HOME"/stderr
+'
+
+test_expect_success 'UTF-8 non-characters refused' '
+ test_when_finished "rm -f $HOME/stderr $HOME/invalid" &&
+ echo "UTF-8 non-character 1" >F &&
+ printf "Commit message\n\nNon-character:\364\217\277\276\n" \
+ >"$HOME/invalid" &&
+ git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
+ grep "did not conform" "$HOME"/stderr
+'
+
+test_expect_success 'UTF-8 non-characters refused' '
+ test_when_finished "rm -f $HOME/stderr $HOME/invalid" &&
+ echo "UTF-8 non-character 2." >F &&
+ printf "Commit message\n\nNon-character:\357\267\220\n" \
+ >"$HOME/invalid" &&
+ git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
+ grep "did not conform" "$HOME"/stderr
+'
for H in ISO8859-1 eucJP ISO-2022-JP
do
diff --git a/t/t3900/UTF-16.txt b/t/t3900/UTF-16.txt
new file mode 100644
index 0000000..2257f05
--- /dev/null
+++ b/t/t3900/UTF-16.txt
Binary files differ
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 5dfbda7..debda7a 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -200,17 +200,17 @@ test_expect_success 'apply -q is quiet' '
echo foo > file &&
git stash &&
git stash apply -q > output.out 2>&1 &&
- test ! -s output.out
+ test_must_be_empty output.out
'
test_expect_success 'save -q is quiet' '
git stash save --quiet > output.out 2>&1 &&
- test ! -s output.out
+ test_must_be_empty output.out
'
test_expect_success 'pop -q is quiet' '
git stash pop -q > output.out 2>&1 &&
- test ! -s output.out
+ test_must_be_empty output.out
'
test_expect_success 'pop -q --index works and is quiet' '
@@ -219,13 +219,13 @@ test_expect_success 'pop -q --index works and is quiet' '
git stash save --quiet &&
git stash pop -q --index > output.out 2>&1 &&
test foo = "$(git show :file)" &&
- test ! -s output.out
+ test_must_be_empty output.out
'
test_expect_success 'drop -q is quiet' '
git stash &&
git stash drop -q > output.out 2>&1 &&
- test ! -s output.out
+ test_must_be_empty output.out
'
test_expect_success 'stash -k' '
@@ -336,41 +336,58 @@ test_expect_success SYMLINKS 'stash file to symlink (full stage)' '
# This test creates a commit with a symlink used for the following tests
-test_expect_success SYMLINKS 'stash symlink to file' '
+test_expect_success 'stash symlink to file' '
git reset --hard &&
- ln -s file filelink &&
- git add filelink &&
+ test_ln_s_add file filelink &&
git commit -m "Add symlink" &&
rm filelink &&
cp file filelink &&
- git stash save "symlink to file" &&
+ git stash save "symlink to file"
+'
+
+test_expect_success SYMLINKS 'this must have re-created the symlink' '
test -h filelink &&
- case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac &&
+ case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac
+'
+
+test_expect_success 'unstash must re-create the file' '
git stash apply &&
! test -h filelink &&
test bar = "$(cat file)"
'
-test_expect_success SYMLINKS 'stash symlink to file (stage rm)' '
+test_expect_success 'stash symlink to file (stage rm)' '
git reset --hard &&
git rm filelink &&
cp file filelink &&
- git stash save "symlink to file (stage rm)" &&
+ git stash save "symlink to file (stage rm)"
+'
+
+test_expect_success SYMLINKS 'this must have re-created the symlink' '
test -h filelink &&
- case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac &&
+ case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac
+'
+
+test_expect_success 'unstash must re-create the file' '
git stash apply &&
! test -h filelink &&
test bar = "$(cat file)"
'
-test_expect_success SYMLINKS 'stash symlink to file (full stage)' '
+test_expect_success 'stash symlink to file (full stage)' '
git reset --hard &&
rm filelink &&
cp file filelink &&
git add filelink &&
- git stash save "symlink to file (full stage)" &&
+ git stash save "symlink to file (full stage)"
+'
+
+test_expect_success SYMLINKS 'this must have re-created the symlink' '
test -h filelink &&
- case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac &&
+ case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac
+'
+
+test_expect_success 'unstash must re-create the file' '
git stash apply &&
! test -h filelink &&
test bar = "$(cat file)"
@@ -637,4 +654,23 @@ test_expect_success 'stash where working directory contains "HEAD" file' '
test_cmp output expect
'
+test_expect_success 'store called with invalid commit' '
+ test_must_fail git stash store foo
+'
+
+test_expect_success 'store updates stash ref and reflog' '
+ git stash clear &&
+ git reset --hard &&
+ echo quux >bazzy &&
+ git add bazzy &&
+ STASH_ID=$(git stash create) &&
+ git reset --hard &&
+ ! grep quux bazzy &&
+ git stash store -m quuxery $STASH_ID &&
+ test $(cat .git/refs/stash) = $STASH_ID &&
+ grep $STASH_ID .git/logs/refs/stash &&
+ git stash pop &&
+ grep quux bazzy
+'
+
test_done
diff --git a/t/t4000-diff-format.sh b/t/t4000-diff-format.sh
index 6ddd469..8de36b7 100755
--- a/t/t4000-diff-format.sh
+++ b/t/t4000-diff-format.sh
@@ -15,17 +15,17 @@ line 3'
cat path0 >path1
chmod +x path1
-test_expect_success \
- 'update-index --add two files with and without +x.' \
- 'git update-index --add path0 path1'
+test_expect_success 'update-index --add two files with and without +x.' '
+ git update-index --add path0 path1
+'
mv path0 path0-
sed -e 's/line/Line/' <path0- >path0
chmod +x path0
rm -f path1
-test_expect_success \
- 'git diff-files -p after editing work tree.' \
- 'git diff-files -p >current'
+test_expect_success 'git diff-files -p after editing work tree.' '
+ git diff-files -p >actual
+'
# that's as far as it comes
if [ "$(git config --get core.filemode)" = false ]
@@ -55,8 +55,38 @@ deleted file mode 100755
-line 3
EOF
-test_expect_success \
- 'validate git diff-files -p output.' \
- 'compare_diff_patch current expected'
+test_expect_success 'validate git diff-files -p output.' '
+ compare_diff_patch expected actual
+'
+
+test_expect_success 'git diff-files -s after editing work tree' '
+ git diff-files -s >actual 2>err &&
+ test_must_be_empty actual &&
+ test_must_be_empty err
+'
+
+test_expect_success 'git diff-files --no-patch as synonym for -s' '
+ git diff-files --no-patch >actual 2>err &&
+ test_must_be_empty actual &&
+ test_must_be_empty err
+'
+
+test_expect_success 'git diff-files --no-patch --patch shows the patch' '
+ git diff-files --no-patch --patch >actual &&
+ compare_diff_patch expected actual
+'
+
+test_expect_success 'git diff-files --no-patch --patch-with-raw shows the patch and raw data' '
+ git diff-files --no-patch --patch-with-raw >actual &&
+ grep -q "^:100644 100755 .* 0000000000000000000000000000000000000000 M path0\$" actual &&
+ tail -n +4 actual >actual-patch &&
+ compare_diff_patch expected actual-patch
+'
+
+test_expect_success 'git diff-files --patch --no-patch does not show the patch' '
+ git diff-files --patch --no-patch >actual 2>err &&
+ test_must_be_empty actual &&
+ test_must_be_empty err
+'
test_done
diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh
index 73b4a24..27e98a8 100755
--- a/t/t4008-diff-break-rewrite.sh
+++ b/t/t4008-diff-break-rewrite.sh
@@ -99,11 +99,11 @@ test_expect_success \
'validate result of -B -M (#4)' \
'compare_diff_raw expected current'
-test_expect_success SYMLINKS \
+test_expect_success \
'make file0 into something completely different' \
'rm -f file0 &&
- ln -s frotz file0 &&
- git update-index file0 file1'
+ test_ln_s_add frotz file0 &&
+ git update-index file1'
test_expect_success \
'run diff with -B' \
@@ -114,7 +114,7 @@ cat >expected <<\EOF
:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100 file1
EOF
-test_expect_success SYMLINKS \
+test_expect_success \
'validate result of -B (#5)' \
'compare_diff_raw expected current'
@@ -129,7 +129,7 @@ cat >expected <<\EOF
:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R file0 file1
EOF
-test_expect_success SYMLINKS \
+test_expect_success \
'validate result of -B -M (#6)' \
'compare_diff_raw expected current'
@@ -144,7 +144,7 @@ cat >expected <<\EOF
:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M file1
EOF
-test_expect_success SYMLINKS \
+test_expect_success \
'validate result of -M (#7)' \
'compare_diff_raw expected current'
diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh
index f0d5041..13e7f62 100755
--- a/t/t4011-diff-symlink.sh
+++ b/t/t4011-diff-symlink.sh
@@ -9,7 +9,7 @@ test_description='Test diff of symlinks.
. ./test-lib.sh
. "$TEST_DIRECTORY"/diff-lib.sh
-test_expect_success SYMLINKS 'diff new symlink and file' '
+test_expect_success 'diff new symlink and file' '
cat >expected <<-\EOF &&
diff --git a/frotz b/frotz
new file mode 120000
@@ -27,22 +27,25 @@ test_expect_success SYMLINKS 'diff new symlink and file' '
@@ -0,0 +1 @@
+xyzzy
EOF
- ln -s xyzzy frotz &&
- echo xyzzy >nitfol &&
+
+ # the empty tree
git update-index &&
tree=$(git write-tree) &&
- git update-index --add frotz nitfol &&
+
+ test_ln_s_add xyzzy frotz &&
+ echo xyzzy >nitfol &&
+ git update-index --add nitfol &&
GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current &&
compare_diff_patch expected current
'
-test_expect_success SYMLINKS 'diff unchanged symlink and file' '
+test_expect_success 'diff unchanged symlink and file' '
tree=$(git write-tree) &&
git update-index frotz nitfol &&
test -z "$(git diff-index --name-only $tree)"
'
-test_expect_success SYMLINKS 'diff removed symlink and file' '
+test_expect_success 'diff removed symlink and file' '
cat >expected <<-\EOF &&
diff --git a/frotz b/frotz
deleted file mode 120000
@@ -66,12 +69,18 @@ test_expect_success SYMLINKS 'diff removed symlink and file' '
compare_diff_patch expected current
'
-test_expect_success SYMLINKS 'diff identical, but newly created symlink and file' '
+test_expect_success 'diff identical, but newly created symlink and file' '
>expected &&
rm -f frotz nitfol &&
echo xyzzy >nitfol &&
test-chmtime +10 nitfol &&
- ln -s xyzzy frotz &&
+ if test_have_prereq SYMLINKS
+ then
+ ln -s xyzzy frotz
+ else
+ printf xyzzy >frotz
+ # the symlink property propagates from the index
+ fi &&
git diff-index -M -p $tree >current &&
compare_diff_patch expected current &&
@@ -80,7 +89,7 @@ test_expect_success SYMLINKS 'diff identical, but newly created symlink and file
compare_diff_patch expected current
'
-test_expect_success SYMLINKS 'diff different symlink and file' '
+test_expect_success 'diff different symlink and file' '
cat >expected <<-\EOF &&
diff --git a/frotz b/frotz
index 7c465af..df1db54 120000
@@ -100,7 +109,13 @@ test_expect_success SYMLINKS 'diff different symlink and file' '
+yxyyz
EOF
rm -f frotz &&
- ln -s yxyyz frotz &&
+ if test_have_prereq SYMLINKS
+ then
+ ln -s yxyyz frotz
+ else
+ printf yxyyz >frotz
+ # the symlink property propagates from the index
+ fi &&
echo yxyyz >nitfol &&
git diff-index -M -p $tree >current &&
compare_diff_patch expected current
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 183fbe5..668933b 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -972,6 +972,311 @@ test_expect_success 'empty subject prefix does not have extra space' '
test_cmp expect actual
'
+test_expect_success '--from=ident notices bogus ident' '
+ test_must_fail git format-patch -1 --stdout --from=foo >patch
+'
+
+test_expect_success '--from=ident replaces author' '
+ git format-patch -1 --stdout --from="Me <me@example.com>" >patch &&
+ cat >expect <<-\EOF &&
+ From: Me <me@example.com>
+
+ From: A U Thor <author@example.com>
+
+ EOF
+ sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
+ test_cmp expect patch.head
+'
+
+test_expect_success '--from uses committer ident' '
+ git format-patch -1 --stdout --from >patch &&
+ cat >expect <<-\EOF &&
+ From: C O Mitter <committer@example.com>
+
+ From: A U Thor <author@example.com>
+
+ EOF
+ sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
+ test_cmp expect patch.head
+'
+
+test_expect_success 'in-body headers trigger content encoding' '
+ GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
+ test_when_finished "git reset --hard HEAD^" &&
+ git format-patch -1 --stdout --from >patch &&
+ cat >expect <<-\EOF &&
+ From: C O Mitter <committer@example.com>
+ Content-Type: text/plain; charset=UTF-8
+
+ From: éxötìc <author@example.com>
+
+ EOF
+ sed -ne "/^From:/p; /^$/p; /^Content-Type/p; /^---$/q" <patch >patch.head &&
+ test_cmp expect patch.head
+'
+
+append_signoff()
+{
+ C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
+ git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
+ sed -n -e "1,/^---$/p" append_signoff.patch |
+ egrep -n "^Subject|Sign|^$"
+}
+
+test_expect_success 'signoff: commit with no body' '
+ append_signoff </dev/null >actual &&
+ cat <<\EOF | sed "s/EOL$//" >expected &&
+4:Subject: [PATCH] EOL
+8:
+9:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: commit with only subject' '
+ echo subject | append_signoff >actual &&
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+9:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: commit with only subject that does not end with NL' '
+ printf subject | append_signoff >actual &&
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+9:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: no existing signoffs' '
+ append_signoff <<\EOF >actual &&
+subject
+
+body
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+10:
+11:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: no existing signoffs and no trailing NL' '
+ printf "subject\n\nbody" | append_signoff >actual &&
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+10:
+11:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: some random signoff' '
+ append_signoff <<\EOF >actual &&
+subject
+
+body
+
+Signed-off-by: my@house
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+10:
+11:Signed-off-by: my@house
+12:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: misc conforming footer elements' '
+ append_signoff <<\EOF >actual &&
+subject
+
+body
+
+Signed-off-by: my@house
+(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
+Tested-by: Some One <someone@example.com>
+Bug: 1234
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+10:
+11:Signed-off-by: my@house
+15:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: some random signoff-alike' '
+ append_signoff <<\EOF >actual &&
+subject
+
+body
+Fooled-by-me: my@house
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+11:
+12:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: not really a signoff' '
+ append_signoff <<\EOF >actual &&
+subject
+
+I want to mention about Signed-off-by: here.
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+9:I want to mention about Signed-off-by: here.
+10:
+11:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: not really a signoff (2)' '
+ append_signoff <<\EOF >actual &&
+subject
+
+My unfortunate
+Signed-off-by: example happens to be wrapped here.
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+10:Signed-off-by: example happens to be wrapped here.
+11:
+12:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: valid S-o-b paragraph in the middle' '
+ append_signoff <<\EOF >actual &&
+subject
+
+Signed-off-by: my@house
+Signed-off-by: your@house
+
+A lot of houses.
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+9:Signed-off-by: my@house
+10:Signed-off-by: your@house
+11:
+13:
+14:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: the same signoff at the end' '
+ append_signoff <<\EOF >actual &&
+subject
+
+body
+
+Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+10:
+11:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: the same signoff at the end, no trailing NL' '
+ printf "subject\n\nSigned-off-by: C O Mitter <committer@example.com>" |
+ append_signoff >actual &&
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+9:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: the same signoff NOT at the end' '
+ append_signoff <<\EOF >actual &&
+subject
+
+body
+
+Signed-off-by: C O Mitter <committer@example.com>
+Signed-off-by: my@house
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+10:
+11:Signed-off-by: C O Mitter <committer@example.com>
+12:Signed-off-by: my@house
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: detect garbage in non-conforming footer' '
+ append_signoff <<\EOF >actual &&
+subject
+
+body
+
+Tested-by: my@house
+Some Trash
+Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+10:
+13:Signed-off-by: C O Mitter <committer@example.com>
+14:
+15:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'signoff: footer begins with non-signoff without @ sign' '
+ append_signoff <<\EOF >actual &&
+subject
+
+body
+
+Reviewed-id: Noone
+Tested-by: my@house
+Change-id: Ideadbeef
+Signed-off-by: C O Mitter <committer@example.com>
+Bug: 1234
+EOF
+ cat >expected <<\EOF &&
+4:Subject: [PATCH] subject
+8:
+10:
+14:Signed-off-by: C O Mitter <committer@example.com>
+EOF
+ test_cmp expected actual
+'
+
test_expect_success 'format patch ignores color.ui' '
test_unconfig color.ui &&
git format-patch --stdout -1 >expect &&
@@ -1022,4 +1327,37 @@ test_expect_success 'cover letter using branch description (6)' '
grep hello actual >/dev/null
'
+test_expect_success 'cover letter with nothing' '
+ git format-patch --stdout --cover-letter >actual &&
+ test_line_count = 0 actual
+'
+
+test_expect_success 'cover letter auto' '
+ mkdir -p tmp &&
+ test_when_finished "rm -rf tmp;
+ git config --unset format.coverletter" &&
+
+ git config format.coverletter auto &&
+ git format-patch -o tmp -1 >list &&
+ test_line_count = 1 list &&
+ git format-patch -o tmp -2 >list &&
+ test_line_count = 3 list
+'
+
+test_expect_success 'cover letter auto user override' '
+ mkdir -p tmp &&
+ test_when_finished "rm -rf tmp;
+ git config --unset format.coverletter" &&
+
+ git config format.coverletter auto &&
+ git format-patch -o tmp --cover-letter -1 >list &&
+ test_line_count = 2 list &&
+ git format-patch -o tmp --cover-letter -2 >list &&
+ test_line_count = 3 list &&
+ git format-patch -o tmp --no-cover-letter -1 >list &&
+ test_line_count = 1 list &&
+ git format-patch -o tmp --no-cover-letter -2 >list &&
+ test_line_count = 2 list
+'
+
test_done
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index cc3db13..3fb4b97 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -142,6 +142,351 @@ EOF
git diff --ignore-space-at-eol > out
test_expect_success 'another test, with --ignore-space-at-eol' 'test_cmp expect out'
+test_expect_success 'ignore-blank-lines: only new lines' '
+ test_seq 5 >x &&
+ git update-index x &&
+ test_seq 5 | sed "/3/i \\
+" >x &&
+ git diff --ignore-blank-lines >out &&
+ >expect &&
+ test_cmp out expect
+'
+
+test_expect_success 'ignore-blank-lines: only new lines with space' '
+ test_seq 5 >x &&
+ git update-index x &&
+ test_seq 5 | sed "/3/i \ " >x &&
+ git diff -w --ignore-blank-lines >out &&
+ >expect &&
+ test_cmp out expect
+'
+
+test_expect_success 'ignore-blank-lines: after change' '
+ cat <<-\EOF >x &&
+ 1
+ 2
+
+ 3
+ 4
+ 5
+
+ 6
+ 7
+ EOF
+ git update-index x &&
+ cat <<-\EOF >x &&
+ change
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+
+ 7
+ EOF
+ git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
+ cat <<-\EOF >expected &&
+ diff --git a/x b/x
+ --- a/x
+ +++ b/x
+ @@ -1,6 +1,7 @@
+ +change
+ +
+ 1
+ 2
+ -
+ 3
+ 4
+ 5
+ EOF
+ compare_diff_patch expected out.tmp
+'
+
+test_expect_success 'ignore-blank-lines: before change' '
+ cat <<-\EOF >x &&
+ 1
+ 2
+
+ 3
+ 4
+ 5
+ 6
+ 7
+ EOF
+ git update-index x &&
+ cat <<-\EOF >x &&
+
+ 1
+ 2
+ 3
+ 4
+ 5
+
+ 6
+ 7
+ change
+ EOF
+ git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
+ cat <<-\EOF >expected &&
+ diff --git a/x b/x
+ --- a/x
+ +++ b/x
+ @@ -4,5 +4,7 @@
+ 3
+ 4
+ 5
+ +
+ 6
+ 7
+ +change
+ EOF
+ compare_diff_patch expected out.tmp
+'
+
+test_expect_success 'ignore-blank-lines: between changes' '
+ cat <<-\EOF >x &&
+ 1
+ 2
+ 3
+ 4
+ 5
+
+
+ 6
+ 7
+ 8
+ 9
+ 10
+ EOF
+ git update-index x &&
+ cat <<-\EOF >x &&
+ change
+ 1
+ 2
+
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+
+ 9
+ 10
+ change
+ EOF
+ git diff --ignore-blank-lines >out.tmp &&
+ cat <<-\EOF >expected &&
+ diff --git a/x b/x
+ --- a/x
+ +++ b/x
+ @@ -1,5 +1,7 @@
+ +change
+ 1
+ 2
+ +
+ 3
+ 4
+ 5
+ @@ -8,5 +8,7 @@
+ 6
+ 7
+ 8
+ +
+ 9
+ 10
+ +change
+ EOF
+ compare_diff_patch expected out.tmp
+'
+
+test_expect_success 'ignore-blank-lines: between changes (with interhunkctx)' '
+ test_seq 10 >x &&
+ git update-index x &&
+ cat <<-\EOF >x &&
+ change
+ 1
+ 2
+
+ 3
+ 4
+ 5
+
+ 6
+ 7
+ 8
+ 9
+
+ 10
+ change
+ EOF
+ git diff --inter-hunk-context=2 --ignore-blank-lines >out.tmp &&
+ cat <<-\EOF >expected &&
+ diff --git a/x b/x
+ --- a/x
+ +++ b/x
+ @@ -1,10 +1,15 @@
+ +change
+ 1
+ 2
+ +
+ 3
+ 4
+ 5
+ +
+ 6
+ 7
+ 8
+ 9
+ +
+ 10
+ +change
+ EOF
+ compare_diff_patch expected out.tmp
+'
+
+test_expect_success 'ignore-blank-lines: scattered spaces' '
+ test_seq 10 >x &&
+ git update-index x &&
+ cat <<-\EOF >x &&
+ change
+ 1
+ 2
+ 3
+
+ 4
+
+ 5
+
+ 6
+
+
+ 7
+
+ 8
+ 9
+ 10
+ change
+ EOF
+ git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
+ cat <<-\EOF >expected &&
+ diff --git a/x b/x
+ --- a/x
+ +++ b/x
+ @@ -1,3 +1,4 @@
+ +change
+ 1
+ 2
+ 3
+ @@ -8,3 +15,4 @@
+ 8
+ 9
+ 10
+ +change
+ EOF
+ compare_diff_patch expected out.tmp
+'
+
+test_expect_success 'ignore-blank-lines: spaces coalesce' '
+ test_seq 6 >x &&
+ git update-index x &&
+ cat <<-\EOF >x &&
+ change
+ 1
+ 2
+ 3
+
+ 4
+
+ 5
+
+ 6
+ change
+ EOF
+ git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
+ cat <<-\EOF >expected &&
+ diff --git a/x b/x
+ --- a/x
+ +++ b/x
+ @@ -1,6 +1,11 @@
+ +change
+ 1
+ 2
+ 3
+ +
+ 4
+ +
+ 5
+ +
+ 6
+ +change
+ EOF
+ compare_diff_patch expected out.tmp
+'
+
+test_expect_success 'ignore-blank-lines: mix changes and blank lines' '
+ test_seq 16 >x &&
+ git update-index x &&
+ cat <<-\EOF >x &&
+ change
+ 1
+ 2
+
+ 3
+ 4
+ 5
+ change
+ 6
+ 7
+ 8
+
+ 9
+ 10
+ 11
+ change
+ 12
+ 13
+ 14
+
+ 15
+ 16
+ change
+ EOF
+ git diff --ignore-blank-lines >out.tmp &&
+ cat <<-\EOF >expected &&
+ diff --git a/x b/x
+ --- a/x
+ +++ b/x
+ @@ -1,8 +1,11 @@
+ +change
+ 1
+ 2
+ +
+ 3
+ 4
+ 5
+ +change
+ 6
+ 7
+ 8
+ @@ -9,8 +13,11 @@
+ 9
+ 10
+ 11
+ +change
+ 12
+ 13
+ 14
+ +
+ 15
+ 16
+ +change
+ EOF
+ compare_diff_patch expected out.tmp
+'
+
test_expect_success 'check mixed spaces and tabs in indent' '
# This is indented with SP HT SP.
diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh
index 5d20acf..55d549f 100755
--- a/t/t4023-diff-rename-typechange.sh
+++ b/t/t4023-diff-rename-typechange.sh
@@ -4,44 +4,44 @@ test_description='typechange rename detection'
. ./test-lib.sh
-test_expect_success SYMLINKS setup '
+test_expect_success setup '
rm -f foo bar &&
cat "$TEST_DIRECTORY"/../COPYING >foo &&
- ln -s linklink bar &&
- git add foo bar &&
+ test_ln_s_add linklink bar &&
+ git add foo &&
git commit -a -m Initial &&
git tag one &&
- rm -f foo bar &&
+ git rm -f foo bar &&
cat "$TEST_DIRECTORY"/../COPYING >bar &&
- ln -s linklink foo &&
- git add foo bar &&
+ test_ln_s_add linklink foo &&
+ git add bar &&
git commit -a -m Second &&
git tag two &&
- rm -f foo bar &&
+ git rm -f foo bar &&
cat "$TEST_DIRECTORY"/../COPYING >foo &&
git add foo &&
git commit -a -m Third &&
git tag three &&
mv foo bar &&
- ln -s linklink foo &&
- git add foo bar &&
+ test_ln_s_add linklink foo &&
+ git add bar &&
git commit -a -m Fourth &&
git tag four &&
# This is purely for sanity check
- rm -f foo bar &&
+ git rm -f foo bar &&
cat "$TEST_DIRECTORY"/../COPYING >foo &&
cat "$TEST_DIRECTORY"/../Makefile >bar &&
git add foo bar &&
git commit -a -m Fifth &&
git tag five &&
- rm -f foo bar &&
+ git rm -f foo bar &&
cat "$TEST_DIRECTORY"/../Makefile >foo &&
cat "$TEST_DIRECTORY"/../COPYING >bar &&
git add foo bar &&
@@ -50,7 +50,7 @@ test_expect_success SYMLINKS setup '
'
-test_expect_success SYMLINKS 'cross renames to be detected for regular files' '
+test_expect_success 'cross renames to be detected for regular files' '
git diff-tree five six -r --name-status -B -M | sort >actual &&
{
@@ -61,7 +61,7 @@ test_expect_success SYMLINKS 'cross renames to be detected for regular files' '
'
-test_expect_success SYMLINKS 'cross renames to be detected for typechange' '
+test_expect_success 'cross renames to be detected for typechange' '
git diff-tree one two -r --name-status -B -M | sort >actual &&
{
@@ -72,7 +72,7 @@ test_expect_success SYMLINKS 'cross renames to be detected for typechange' '
'
-test_expect_success SYMLINKS 'moves and renames' '
+test_expect_success 'moves and renames' '
git diff-tree three four -r --name-status -B -M | sort >actual &&
{
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index 53ec330..f75f46f 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -139,12 +139,10 @@ index 0000000..67be421
+frotz
\ No newline at end of file
EOF
-# make a symlink the hard way that works on symlink-challenged file systems
+
test_expect_success 'textconv does not act on symlinks' '
- printf frotz > file &&
- git add file &&
- git ls-files -s | sed -e s/100644/120000/ |
- git update-index --index-info &&
+ rm -f file &&
+ test_ln_s_add frotz file &&
git commit -m typechange &&
git show >diff &&
find_diff <diff >actual &&
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index 40ab333..f2f55fc 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -230,7 +230,7 @@ test_expect_success '.gitattributes override config' '
'
test_expect_success 'setup: remove diff driver regex' '
- test_might_fail git config --unset diff.testdriver.wordRegex
+ test_unconfig diff.testdriver.wordRegex
'
test_expect_success 'use configured regex' '
@@ -335,8 +335,7 @@ test_expect_success 'word-diff with diff.sbe' '
c
EOF
- test_when_finished "git config --unset diff.suppress-blank-empty" &&
- git config diff.suppress-blank-empty true &&
+ test_config diff.suppress-blank-empty true &&
word_diff --word-diff=plain
'
@@ -368,7 +367,7 @@ test_expect_success 'setup history with two files' '
test_expect_success 'wordRegex for the first file does not apply to the second' '
echo "*.tex diff=tex" >.gitattributes &&
- git config diff.tex.wordRegex "[a-z]+|." &&
+ test_config diff.tex.wordRegex "[a-z]+|." &&
cat >expect <<-\EOF &&
diff --git a/a.tex b/a.tex
--- a/a.tex
diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh
index b7e16a7..1019d7b 100755
--- a/t/t4038-diff-combined.sh
+++ b/t/t4038-diff-combined.sh
@@ -224,4 +224,181 @@ test_expect_success 'check combined output (ignore all spaces)' '
compare_diff_patch expected actual
'
+test_expect_success 'combine diff coalesce simple' '
+ >test &&
+ git add test &&
+ git commit -m initial &&
+ test_seq 4 >test &&
+ git commit -a -m empty1 &&
+ git branch side1 &&
+ git checkout HEAD^ &&
+ test_seq 5 >test &&
+ git commit -a -m empty2 &&
+ test_must_fail git merge side1 &&
+ >test &&
+ git commit -a -m merge &&
+ git show >actual.tmp &&
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
+ tr -d Q <<-\EOF >expected &&
+ --1
+ --2
+ --3
+ --4
+ - 5
+ EOF
+ compare_diff_patch expected actual
+'
+
+test_expect_success 'combine diff coalesce tricky' '
+ >test &&
+ git add test &&
+ git commit -m initial --allow-empty &&
+ cat <<-\EOF >test &&
+ 3
+ 1
+ 2
+ 3
+ 4
+ EOF
+ git commit -a -m empty1 &&
+ git branch -f side1 &&
+ git checkout HEAD^ &&
+ cat <<-\EOF >test &&
+ 1
+ 3
+ 5
+ 4
+ EOF
+ git commit -a -m empty2 &&
+ git branch -f side2 &&
+ test_must_fail git merge side1 &&
+ >test &&
+ git commit -a -m merge &&
+ git show >actual.tmp &&
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
+ tr -d Q <<-\EOF >expected &&
+ -3
+ --1
+ -2
+ --3
+ - 5
+ --4
+ EOF
+ compare_diff_patch expected actual &&
+ git checkout -f side1 &&
+ test_must_fail git merge side2 &&
+ >test &&
+ git commit -a -m merge &&
+ git show >actual.tmp &&
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
+ tr -d Q <<-\EOF >expected &&
+ - 3
+ --1
+ - 2
+ --3
+ -5
+ --4
+ EOF
+ compare_diff_patch expected actual
+'
+
+test_expect_failure 'combine diff coalesce three parents' '
+ >test &&
+ git add test &&
+ git commit -m initial --allow-empty &&
+ cat <<-\EOF >test &&
+ 3
+ 1
+ 2
+ 3
+ 4
+ EOF
+ git commit -a -m empty1 &&
+ git checkout -B side1 &&
+ git checkout HEAD^ &&
+ cat <<-\EOF >test &&
+ 1
+ 3
+ 7
+ 5
+ 4
+ EOF
+ git commit -a -m empty2 &&
+ git branch -f side2 &&
+ git checkout HEAD^ &&
+ cat <<-\EOF >test &&
+ 3
+ 1
+ 6
+ 5
+ 4
+ EOF
+ git commit -a -m empty3 &&
+ >test &&
+ git add test &&
+ TREE=$(git write-tree) &&
+ COMMIT=$(git commit-tree -p HEAD -p side1 -p side2 -m merge $TREE) &&
+ git show $COMMIT >actual.tmp &&
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
+ tr -d Q <<-\EOF >expected &&
+ -- 3
+ ---1
+ - 6
+ - 2
+ --3
+ -7
+ - -5
+ ---4
+ EOF
+ compare_diff_patch expected actual
+'
+
+# Test for a bug reported at
+# http://thread.gmane.org/gmane.comp.version-control.git/224410
+# where a delete lines were missing from combined diff output when they
+# occurred exactly before the context lines of a later change.
+test_expect_success 'combine diff missing delete bug' '
+ git commit -m initial --allow-empty &&
+ cat <<-\EOF >test &&
+ 1
+ 2
+ 3
+ 4
+ EOF
+ git add test &&
+ git commit -a -m side1 &&
+ git checkout -B side1 &&
+ git checkout HEAD^ &&
+ cat <<-\EOF >test &&
+ 0
+ 1
+ 2
+ 3
+ 4modified
+ EOF
+ git add test &&
+ git commit -m side2 &&
+ git branch -f side2 &&
+ test_must_fail git merge --no-commit side1 &&
+ cat <<-\EOF >test &&
+ 1
+ 2
+ 3
+ 4modified
+ EOF
+ git add test &&
+ git commit -a -m merge &&
+ git diff-tree -c -p HEAD >actual.tmp &&
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
+ tr -d Q <<-\EOF >expected &&
+ - 0
+ 1
+ 2
+ 3
+ -4
+ +4modified
+ EOF
+ compare_diff_patch expected actual
+'
+
test_done
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index 32d4a60..1751c83 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -1,6 +1,7 @@
#!/bin/sh
#
# Copyright (c) 2009 Jens Lehmann, based on t7401 by Ping Yin
+# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests)
#
test_description='Support for verbose submodule differences in git diff
@@ -10,6 +11,9 @@ This test tries to verify the sanity of the --submodule option of git diff.
. ./test-lib.sh
+# String "added" in German (translated with Google Translate), encoded in UTF-8,
+# used in sample commit log messages in add_file() function below.
+added=$(printf "hinzugef\303\274gt")
add_file () {
(
cd "$1" &&
@@ -19,7 +23,8 @@ add_file () {
echo "$name" >"$name" &&
git add "$name" &&
test_tick &&
- git commit -m "Add $name" || exit
+ msg_added_iso88591=$(echo "Add $name ($added $name)" | iconv -f utf-8 -t iso8859-1) &&
+ git -c 'i18n.commitEncoding=iso8859-1' commit -m "$msg_added_iso88591"
done >/dev/null &&
git rev-parse --short --verify HEAD
)
@@ -93,7 +98,7 @@ test_expect_success 'modified submodule(forward)' '
git diff-index -p --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
Submodule sm1 $head1..$head2:
- > Add foo3
+ > Add foo3 ($added foo3)
EOF
test_cmp expected actual
'
@@ -102,7 +107,7 @@ test_expect_success 'modified submodule(forward)' '
git diff --submodule=log >actual &&
cat >expected <<-EOF &&
Submodule sm1 $head1..$head2:
- > Add foo3
+ > Add foo3 ($added foo3)
EOF
test_cmp expected actual
'
@@ -111,7 +116,7 @@ test_expect_success 'modified submodule(forward) --submodule' '
git diff --submodule >actual &&
cat >expected <<-EOF &&
Submodule sm1 $head1..$head2:
- > Add foo3
+ > Add foo3 ($added foo3)
EOF
test_cmp expected actual
'
@@ -142,8 +147,8 @@ test_expect_success 'modified submodule(backward)' '
git diff-index -p --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
Submodule sm1 $head2..$head3 (rewind):
- < Add foo3
- < Add foo2
+ < Add foo3 ($added foo3)
+ < Add foo2 ($added foo2)
EOF
test_cmp expected actual
'
@@ -153,10 +158,10 @@ test_expect_success 'modified submodule(backward and forward)' '
git diff-index -p --submodule=log HEAD >actual &&
cat >expected <<-EOF &&
Submodule sm1 $head2...$head4:
- > Add foo5
- > Add foo4
- < Add foo3
- < Add foo2
+ > Add foo5 ($added foo5)
+ > Add foo4 ($added foo4)
+ < Add foo3 ($added foo3)
+ < Add foo2 ($added foo2)
EOF
test_cmp expected actual
'
diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh
index 97172b4..cd04543 100755
--- a/t/t4055-diff-context.sh
+++ b/t/t4055-diff-context.sh
@@ -73,7 +73,7 @@ test_expect_success 'plumbing not affected' '
test_expect_success 'non-integer config parsing' '
git config diff.context no &&
test_must_fail git diff 2>output &&
- test_i18ngrep "bad config value" output
+ test_i18ngrep "bad numeric config value" output
'
test_expect_success 'negative integer config parsing' '
diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh
index 7c39843..1618a6d 100755
--- a/t/t4111-apply-subdir.sh
+++ b/t/t4111-apply-subdir.sh
@@ -86,6 +86,20 @@ test_expect_success 'apply --index from subdir of toplevel' '
test_cmp expected sub/dir/file
'
+test_expect_success 'apply half-broken patch from subdir of toplevel' '
+ (
+ cd sub/dir &&
+ test_must_fail git apply <<-EOF
+ --- sub/dir/file
+ +++ sub/dir/file
+ @@ -1,0 +1,0 @@
+ --- file_in_root
+ +++ file_in_root
+ @@ -1,0 +1,0 @@
+ EOF
+ )
+'
+
test_expect_success 'apply from .git dir' '
cp postimage expected &&
cp preimage .git/file &&
diff --git a/t/t4114-apply-typechange.sh b/t/t4114-apply-typechange.sh
index f12826f..ebadbc3 100755
--- a/t/t4114-apply-typechange.sh
+++ b/t/t4114-apply-typechange.sh
@@ -9,20 +9,19 @@ test_description='git apply should not get confused with type changes.
. ./test-lib.sh
-test_expect_success SYMLINKS 'setup repository and commits' '
+test_expect_success 'setup repository and commits' '
echo "hello world" > foo &&
echo "hi planet" > bar &&
git update-index --add foo bar &&
git commit -m initial &&
git branch initial &&
rm -f foo &&
- ln -s bar foo &&
- git update-index foo &&
+ test_ln_s_add bar foo &&
git commit -m "foo symlinked to bar" &&
git branch foo-symlinked-to-bar &&
- rm -f foo &&
+ git rm -f foo &&
echo "how far is the sun?" > foo &&
- git update-index foo &&
+ git update-index --add foo &&
git commit -m "foo back to file" &&
git branch foo-back-to-file &&
printf "\0" > foo &&
@@ -42,7 +41,7 @@ test_expect_success SYMLINKS 'setup repository and commits' '
git branch foo-baz-renamed-from-foo
'
-test_expect_success SYMLINKS 'file renamed from foo to foo/baz' '
+test_expect_success 'file renamed from foo to foo/baz' '
git checkout -f initial &&
git diff-tree -M -p HEAD foo-baz-renamed-from-foo > patch &&
git apply --index < patch
@@ -50,7 +49,7 @@ test_expect_success SYMLINKS 'file renamed from foo to foo/baz' '
test_debug 'cat patch'
-test_expect_success SYMLINKS 'file renamed from foo/baz to foo' '
+test_expect_success 'file renamed from foo/baz to foo' '
git checkout -f foo-baz-renamed-from-foo &&
git diff-tree -M -p HEAD initial > patch &&
git apply --index < patch
@@ -58,7 +57,7 @@ test_expect_success SYMLINKS 'file renamed from foo/baz to foo' '
test_debug 'cat patch'
-test_expect_success SYMLINKS 'directory becomes file' '
+test_expect_success 'directory becomes file' '
git checkout -f foo-becomes-a-directory &&
git diff-tree -p HEAD initial > patch &&
git apply --index < patch
@@ -66,7 +65,7 @@ test_expect_success SYMLINKS 'directory becomes file' '
test_debug 'cat patch'
-test_expect_success SYMLINKS 'file becomes directory' '
+test_expect_success 'file becomes directory' '
git checkout -f initial &&
git diff-tree -p HEAD foo-becomes-a-directory > patch &&
git apply --index < patch
@@ -74,7 +73,7 @@ test_expect_success SYMLINKS 'file becomes directory' '
test_debug 'cat patch'
-test_expect_success SYMLINKS 'file becomes symlink' '
+test_expect_success 'file becomes symlink' '
git checkout -f initial &&
git diff-tree -p HEAD foo-symlinked-to-bar > patch &&
git apply --index < patch
@@ -82,21 +81,21 @@ test_expect_success SYMLINKS 'file becomes symlink' '
test_debug 'cat patch'
-test_expect_success SYMLINKS 'symlink becomes file' '
+test_expect_success 'symlink becomes file' '
git checkout -f foo-symlinked-to-bar &&
git diff-tree -p HEAD foo-back-to-file > patch &&
git apply --index < patch
'
test_debug 'cat patch'
-test_expect_success SYMLINKS 'binary file becomes symlink' '
+test_expect_success 'binary file becomes symlink' '
git checkout -f foo-becomes-binary &&
git diff-tree -p --binary HEAD foo-symlinked-to-bar > patch &&
git apply --index < patch
'
test_debug 'cat patch'
-test_expect_success SYMLINKS 'symlink becomes binary file' '
+test_expect_success 'symlink becomes binary file' '
git checkout -f foo-symlinked-to-bar &&
git diff-tree -p --binary HEAD foo-becomes-binary > patch &&
git apply --index < patch
@@ -104,7 +103,7 @@ test_expect_success SYMLINKS 'symlink becomes binary file' '
test_debug 'cat patch'
-test_expect_success SYMLINKS 'symlink becomes directory' '
+test_expect_success 'symlink becomes directory' '
git checkout -f foo-symlinked-to-bar &&
git diff-tree -p HEAD foo-becomes-a-directory > patch &&
git apply --index < patch
@@ -112,7 +111,7 @@ test_expect_success SYMLINKS 'symlink becomes directory' '
test_debug 'cat patch'
-test_expect_success SYMLINKS 'directory becomes symlink' '
+test_expect_success 'directory becomes symlink' '
git checkout -f foo-becomes-a-directory &&
git diff-tree -p HEAD foo-symlinked-to-bar > patch &&
git apply --index < patch
diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
index 7674dd2..872fcda 100755
--- a/t/t4115-apply-symlink.sh
+++ b/t/t4115-apply-symlink.sh
@@ -9,18 +9,16 @@ test_description='git apply symlinks and partial files
. ./test-lib.sh
-test_expect_success SYMLINKS setup '
+test_expect_success setup '
- ln -s path1/path2/path3/path4/path5 link1 &&
- git add link? &&
+ test_ln_s_add path1/path2/path3/path4/path5 link1 &&
git commit -m initial &&
git branch side &&
rm -f link? &&
- ln -s htap6 link1 &&
- git update-index link? &&
+ test_ln_s_add htap6 link1 &&
git commit -m second &&
git diff-tree -p HEAD^ HEAD >patch &&
@@ -37,7 +35,7 @@ test_expect_success SYMLINKS 'apply symlink patch' '
'
-test_expect_success SYMLINKS 'apply --index symlink patch' '
+test_expect_success 'apply --index symlink patch' '
git checkout -f side &&
git apply --index patch &&
diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh
index 3940737..70b3a06 100755
--- a/t/t4122-apply-symlink-inside.sh
+++ b/t/t4122-apply-symlink-inside.sh
@@ -10,11 +10,11 @@ lecho () {
done
}
-test_expect_success SYMLINKS setup '
+test_expect_success setup '
mkdir -p arch/i386/boot arch/x86_64 &&
lecho 1 2 3 4 5 >arch/i386/boot/Makefile &&
- ln -s ../i386/boot arch/x86_64/boot &&
+ test_ln_s_add ../i386/boot arch/x86_64/boot &&
git add . &&
test_tick &&
git commit -m initial &&
@@ -31,7 +31,7 @@ test_expect_success SYMLINKS setup '
'
-test_expect_success SYMLINKS apply '
+test_expect_success apply '
git checkout test &&
git diff --exit-code test &&
@@ -40,7 +40,7 @@ test_expect_success SYMLINKS apply '
'
-test_expect_success SYMLINKS 'check result' '
+test_expect_success 'check result' '
git diff --exit-code master &&
git diff --exit-code --cached master &&
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 12f6b02..5edb79a 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -147,7 +147,7 @@ test_expect_success 'am applies patch correctly' '
git checkout first &&
test_tick &&
git am <patch1 &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git diff --exit-code second &&
test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
@@ -158,7 +158,7 @@ test_expect_success 'am applies patch e-mail not in a mbox' '
git reset --hard &&
git checkout first &&
git am patch1.eml &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git diff --exit-code second &&
test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
@@ -169,7 +169,7 @@ test_expect_success 'am applies patch e-mail not in a mbox with CRLF' '
git reset --hard &&
git checkout first &&
git am patch1-crlf.eml &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git diff --exit-code second &&
test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
@@ -180,7 +180,7 @@ test_expect_success 'am applies patch e-mail with preceding whitespace' '
git reset --hard &&
git checkout first &&
git am patch1-ws.eml &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git diff --exit-code second &&
test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
@@ -206,7 +206,7 @@ test_expect_success 'am changes committer and keeps author' '
git reset --hard &&
git checkout first &&
git am patch2 &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
test "$(git rev-parse master^^)" = "$(git rev-parse HEAD^^)" &&
git diff --exit-code master..HEAD &&
git diff --exit-code master^..HEAD^ &&
@@ -258,7 +258,7 @@ test_expect_success 'am --keep really keeps the subject' '
git reset --hard &&
git checkout HEAD^ &&
git am --keep patch4 &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git cat-file commit HEAD >actual &&
grep "Re: Re: Re: \[PATCH 1/5 v2\] \[foo\] third" actual
'
@@ -268,7 +268,7 @@ test_expect_success 'am --keep-non-patch really keeps the non-patch part' '
git reset --hard &&
git checkout HEAD^ &&
git am --keep-non-patch patch4 &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git cat-file commit HEAD >actual &&
grep "^\[foo\] third" actual
'
@@ -283,7 +283,7 @@ test_expect_success 'am -3 falls back to 3-way merge' '
test_tick &&
git commit -m "copied stuff" &&
git am -3 lorem-move.patch &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git diff --exit-code lorem
'
@@ -297,7 +297,7 @@ test_expect_success 'am -3 -p0 can read --no-prefix patch' '
test_tick &&
git commit -m "copied stuff" &&
git am -3 -p0 lorem-zero.patch &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git diff --exit-code lorem
'
@@ -307,7 +307,7 @@ test_expect_success 'am can rename a file' '
git reset --hard &&
git checkout lorem^0 &&
git am rename.patch &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git update-index --refresh &&
git diff --exit-code rename
'
@@ -318,7 +318,7 @@ test_expect_success 'am -3 can rename a file' '
git reset --hard &&
git checkout lorem^0 &&
git am -3 rename.patch &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git update-index --refresh &&
git diff --exit-code rename
'
@@ -329,7 +329,7 @@ test_expect_success 'am -3 can rename a file after falling back to 3-way merge'
git reset --hard &&
git checkout lorem^0 &&
git am -3 rename-add.patch &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git update-index --refresh &&
git diff --exit-code rename
'
@@ -358,11 +358,17 @@ test_expect_success 'am pauses on conflict' '
test_expect_success 'am --skip works' '
echo goodbye >expected &&
git am --skip &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git diff --exit-code lorem2^^ -- file &&
test_cmp expected another
'
+test_expect_success 'am --abort removes a stray directory' '
+ mkdir .git/rebase-apply &&
+ git am --abort &&
+ test_path_is_missing .git/rebase-apply
+'
+
test_expect_success 'am --resolved works' '
echo goodbye >expected &&
rm -fr .git/rebase-apply &&
@@ -373,7 +379,7 @@ test_expect_success 'am --resolved works' '
echo resolved >>file &&
git add file &&
git am --resolved &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
test_cmp expected another
'
@@ -382,7 +388,7 @@ test_expect_success 'am takes patches from a Pine mailbox' '
git reset --hard &&
git checkout first &&
cat pine patch1 | git am &&
- ! test -d .git/rebase-apply &&
+ test_path_is_missing .git/rebase-apply &&
git diff --exit-code master^..HEAD
'
@@ -391,7 +397,7 @@ test_expect_success 'am fails on mail without patch' '
git reset --hard &&
test_must_fail git am <failmail &&
git am --abort &&
- ! test -d .git/rebase-apply
+ test_path_is_missing .git/rebase-apply
'
test_expect_success 'am fails on empty patch' '
@@ -400,7 +406,7 @@ test_expect_success 'am fails on empty patch' '
echo "---" >>failmail &&
test_must_fail git am <failmail &&
git am --skip &&
- ! test -d .git/rebase-apply
+ test_path_is_missing .git/rebase-apply
'
test_expect_success 'am works from stdin in subdirectory' '
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index fa686b8..cb03d28 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -419,8 +419,6 @@ test_expect_success 'log --graph with merge' '
'
test_expect_success 'log.decorate configuration' '
- test_might_fail git config --unset-all log.decorate &&
-
git log --oneline >expect.none &&
git log --oneline --decorate >expect.short &&
git log --oneline --decorate=full >expect.full &&
@@ -429,8 +427,7 @@ test_expect_success 'log.decorate configuration' '
git log --oneline >actual &&
test_cmp expect.short actual &&
- git config --unset-all log.decorate &&
- git config log.decorate true &&
+ test_config log.decorate true &&
git log --oneline >actual &&
test_cmp expect.short actual &&
git log --oneline --decorate=full >actual &&
@@ -438,8 +435,7 @@ test_expect_success 'log.decorate configuration' '
git log --oneline --decorate=no >actual &&
test_cmp expect.none actual &&
- git config --unset-all log.decorate &&
- git config log.decorate no &&
+ test_config log.decorate no &&
git log --oneline >actual &&
test_cmp expect.none actual &&
git log --oneline --decorate >actual &&
@@ -447,8 +443,7 @@ test_expect_success 'log.decorate configuration' '
git log --oneline --decorate=full >actual &&
test_cmp expect.full actual &&
- git config --unset-all log.decorate &&
- git config log.decorate 1 &&
+ test_config log.decorate 1 &&
git log --oneline >actual &&
test_cmp expect.short actual &&
git log --oneline --decorate=full >actual &&
@@ -456,8 +451,7 @@ test_expect_success 'log.decorate configuration' '
git log --oneline --decorate=no >actual &&
test_cmp expect.none actual &&
- git config --unset-all log.decorate &&
- git config log.decorate short &&
+ test_config log.decorate short &&
git log --oneline >actual &&
test_cmp expect.short actual &&
git log --oneline --no-decorate >actual &&
@@ -465,8 +459,7 @@ test_expect_success 'log.decorate configuration' '
git log --oneline --decorate=full >actual &&
test_cmp expect.full actual &&
- git config --unset-all log.decorate &&
- git config log.decorate full &&
+ test_config log.decorate full &&
git log --oneline >actual &&
test_cmp expect.full actual &&
git log --oneline --no-decorate >actual &&
@@ -474,16 +467,15 @@ test_expect_success 'log.decorate configuration' '
git log --oneline --decorate >actual &&
test_cmp expect.short actual
- git config --unset-all log.decorate &&
+ test_unconfig log.decorate &&
git log --pretty=raw >expect.raw &&
- git config log.decorate full &&
+ test_config log.decorate full &&
git log --pretty=raw >actual &&
test_cmp expect.raw actual
'
test_expect_success 'reflog is expected format' '
- test_might_fail git config --remove-section log &&
git log -g --abbrev-commit --pretty=oneline >expect &&
git reflog >actual &&
test_cmp expect actual
@@ -496,10 +488,6 @@ test_expect_success 'whatchanged is expected format' '
'
test_expect_success 'log.abbrevCommit configuration' '
- test_when_finished "git config --unset log.abbrevCommit" &&
-
- test_might_fail git config --unset log.abbrevCommit &&
-
git log --abbrev-commit >expect.log.abbrev &&
git log --no-abbrev-commit >expect.log.full &&
git log --pretty=raw >expect.log.raw &&
@@ -508,7 +496,7 @@ test_expect_success 'log.abbrevCommit configuration' '
git whatchanged --abbrev-commit >expect.whatchanged.abbrev &&
git whatchanged --no-abbrev-commit >expect.whatchanged.full &&
- git config log.abbrevCommit true &&
+ test_config log.abbrevCommit true &&
git log >actual &&
test_cmp expect.log.abbrev actual &&
@@ -542,6 +530,20 @@ test_expect_success 'show added path under "--follow -M"' '
)
'
+test_expect_success 'git log -c --follow' '
+ test_create_repo follow-c &&
+ (
+ cd follow-c &&
+ test_commit initial file original &&
+ git rm file &&
+ test_commit rename file2 original &&
+ git reset --hard initial &&
+ test_commit modify file foo &&
+ git merge -m merge rename &&
+ git log -c --follow file2
+ )
+'
+
cat >expect <<\EOF
* commit COMMIT_OBJECT_NAME
|\ Merge: MERGE_PARENTS
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 842b754..ce3eace 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -13,6 +13,11 @@ fuzz_blame () {
}
test_expect_success setup '
+ cat >contacts <<-\EOF &&
+ A U Thor <author@example.com>
+ nick1 <bugs@company.xx>
+ EOF
+
echo one >one &&
git add one &&
test_tick &&
@@ -23,6 +28,44 @@ test_expect_success setup '
git commit --author "nick1 <bugs@company.xx>" -m second
'
+test_expect_success 'check-mailmap no arguments' '
+ test_must_fail git check-mailmap
+'
+
+test_expect_success 'check-mailmap arguments' '
+ cat >expect <<-\EOF &&
+ A U Thor <author@example.com>
+ nick1 <bugs@company.xx>
+ EOF
+ git check-mailmap \
+ "A U Thor <author@example.com>" \
+ "nick1 <bugs@company.xx>" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check-mailmap --stdin' '
+ cat >expect <<-\EOF &&
+ A U Thor <author@example.com>
+ nick1 <bugs@company.xx>
+ EOF
+ git check-mailmap --stdin <contacts >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check-mailmap --stdin arguments' '
+ cat >expect <<-\EOF &&
+ Internal Guy <bugs@company.xy>
+ EOF
+ cat <contacts >>expect &&
+ git check-mailmap --stdin "Internal Guy <bugs@company.xy>" \
+ <contacts >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check-mailmap bogus contact' '
+ test_must_fail git check-mailmap bogus
+'
+
cat >expect <<\EOF
A U Thor (1):
initial
@@ -159,7 +202,8 @@ test_expect_success 'setup mailmap blob tests' '
Blob Guy <author@example.com>
Blob Guy <bugs@company.xx>
EOF
- git add just-bugs both &&
+ printf "Tricky Guy <author@example.com>" >no-newline &&
+ git add just-bugs both no-newline &&
git commit -m "my mailmaps" &&
echo "Repo Guy <author@example.com>" >.mailmap &&
echo "Internal Guy <author@example.com>" >internal.map
@@ -243,10 +287,41 @@ test_expect_success 'mailmap.blob defaults to HEAD:.mailmap in bare repo' '
)
'
+test_expect_success 'mailmap.blob can handle blobs without trailing newline' '
+ cat >expect <<-\EOF &&
+ Tricky Guy (1):
+ initial
+
+ nick1 (1):
+ second
+
+ EOF
+ git -c mailmap.blob=map:no-newline shortlog HEAD >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'cleanup after mailmap.blob tests' '
rm -f .mailmap
'
+test_expect_success 'single-character name' '
+ echo " 1 A <author@example.com>" >expect &&
+ echo " 1 nick1 <bugs@company.xx>" >>expect &&
+ echo "A <author@example.com>" >.mailmap &&
+ test_when_finished "rm .mailmap" &&
+ git shortlog -es HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'preserve canonical email case' '
+ echo " 1 A U Thor <AUTHOR@example.com>" >expect &&
+ echo " 1 nick1 <bugs@company.xx>" >>expect &&
+ echo "<AUTHOR@example.com> <author@example.com>" >.mailmap &&
+ test_when_finished "rm .mailmap" &&
+ git shortlog -es HEAD >actual &&
+ test_cmp expect actual
+'
+
# Extended mailmap configurations should give us the following output for shortlog
cat >expect <<\EOF
A U Thor <author@example.com> (1):
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 98a43d4..fb00041 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -1,20 +1,38 @@
#!/bin/sh
#
# Copyright (c) 2010, Will Palmer
+# Copyright (c) 2011, Alexey Shumkin (+ non-UTF-8 commit encoding tests)
#
test_description='Test pretty formats'
. ./test-lib.sh
+sample_utf8_part=$(printf "f\303\244ng")
+
+commit_msg () {
+ # String "initial. initial" partly in German
+ # (translated with Google Translate),
+ # encoded in UTF-8, used as a commit log message below.
+ msg="initial. an${sample_utf8_part}lich\n"
+ if test -n "$1"
+ then
+ printf "$msg" | iconv -f utf-8 -t "$1"
+ else
+ printf "$msg"
+ fi
+}
+
test_expect_success 'set up basic repos' '
>foo &&
>bar &&
git add foo &&
test_tick &&
- git commit -m initial &&
+ git config i18n.commitEncoding iso8859-1 &&
+ git commit -m "$(commit_msg iso8859-1)" &&
git add bar &&
test_tick &&
- git commit -m "add bar"
+ git commit -m "add bar" &&
+ git config --unset i18n.commitEncoding
'
test_expect_success 'alias builtin format' '
@@ -38,6 +56,20 @@ test_expect_success 'alias user-defined format' '
test_cmp expected actual
'
+test_expect_success 'alias user-defined tformat with %s (iso8859-1 encoding)' '
+ git config i18n.logOutputEncoding iso8859-1 &&
+ git log --oneline >expected-s &&
+ git log --pretty="tformat:%h %s" >actual-s &&
+ git config --unset i18n.logOutputEncoding &&
+ test_cmp expected-s actual-s
+'
+
+test_expect_success 'alias user-defined tformat with %s (utf-8 encoding)' '
+ git log --oneline >expected-s &&
+ git log --pretty="tformat:%h %s" >actual-s &&
+ test_cmp expected-s actual-s
+'
+
test_expect_success 'alias user-defined tformat' '
git log --pretty="tformat:%h" >expected &&
git config pretty.test-alias "tformat:%h" &&
@@ -72,13 +104,13 @@ test_expect_success 'alias loop' '
'
test_expect_success 'NUL separation' '
- printf "add bar\0initial" >expected &&
+ printf "add bar\0$(commit_msg)" >expected &&
git log -z --pretty="format:%s" >actual &&
test_cmp expected actual
'
test_expect_success 'NUL termination' '
- printf "add bar\0initial\0" >expected &&
+ printf "add bar\0$(commit_msg)\0" >expected &&
git log -z --pretty="tformat:%s" >actual &&
test_cmp expected actual
'
@@ -86,7 +118,7 @@ test_expect_success 'NUL termination' '
test_expect_success 'NUL separation with --stat' '
stat0_part=$(git diff --stat HEAD^ HEAD) &&
stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
- printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n" >expected &&
+ printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n" >expected &&
git log -z --stat --pretty="format:%s" >actual &&
test_i18ncmp expected actual
'
@@ -94,9 +126,188 @@ test_expect_success 'NUL separation with --stat' '
test_expect_failure 'NUL termination with --stat' '
stat0_part=$(git diff --stat HEAD^ HEAD) &&
stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
- printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n\0" >expected &&
+ printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n0" >expected &&
git log -z --stat --pretty="tformat:%s" >actual &&
test_i18ncmp expected actual
'
+test_expect_success 'setup more commits' '
+ test_commit "message one" one one message-one &&
+ test_commit "message two" two two message-two &&
+ head1=$(git rev-parse --verify --short HEAD~0) &&
+ head2=$(git rev-parse --verify --short HEAD~1) &&
+ head3=$(git rev-parse --verify --short HEAD~2) &&
+ head4=$(git rev-parse --verify --short HEAD~3)
+'
+
+test_expect_success 'left alignment formatting' '
+ git log --pretty="format:%<(40)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ qz_to_tab_space <<EOF >expected &&
+message two Z
+message one Z
+add bar Z
+$(commit_msg) Z
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting at the nth column' '
+ git log --pretty="format:%h %<|(40)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ qz_to_tab_space <<EOF >expected &&
+$head1 message two Z
+$head2 message one Z
+$head3 add bar Z
+$head4 $(commit_msg) Z
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with no padding' '
+ git log --pretty="format:%<(1)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ cat <<EOF >expected &&
+message two
+message one
+add bar
+$(commit_msg)
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with trunc' '
+ git log --pretty="format:%<(10,trunc)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ qz_to_tab_space <<EOF >expected &&
+message ..
+message ..
+add bar Z
+initial...
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with ltrunc' '
+ git log --pretty="format:%<(10,ltrunc)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ qz_to_tab_space <<EOF >expected &&
+..sage two
+..sage one
+add bar Z
+..${sample_utf8_part}lich
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with mtrunc' '
+ git log --pretty="format:%<(10,mtrunc)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ qz_to_tab_space <<EOF >expected &&
+mess.. two
+mess.. one
+add bar Z
+init..lich
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'right alignment formatting' '
+ git log --pretty="format:%>(40)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ qz_to_tab_space <<EOF >expected &&
+Z message two
+Z message one
+Z add bar
+Z $(commit_msg)
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'right alignment formatting at the nth column' '
+ git log --pretty="format:%h %>|(40)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ qz_to_tab_space <<EOF >expected &&
+$head1 message two
+$head2 message one
+$head3 add bar
+$head4 $(commit_msg)
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'right alignment formatting with no padding' '
+ git log --pretty="format:%>(1)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ cat <<EOF >expected &&
+message two
+message one
+add bar
+$(commit_msg)
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'center alignment formatting' '
+ git log --pretty="format:%><(40)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ qz_to_tab_space <<EOF >expected &&
+Z message two Z
+Z message one Z
+Z add bar Z
+Z $(commit_msg) Z
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'center alignment formatting at the nth column' '
+ git log --pretty="format:%h %><|(40)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ qz_to_tab_space <<EOF >expected &&
+$head1 message two Z
+$head2 message one Z
+$head3 add bar Z
+$head4 $(commit_msg) Z
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'center alignment formatting with no padding' '
+ git log --pretty="format:%><(1)%s" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ cat <<EOF >expected &&
+message two
+message one
+add bar
+$(commit_msg)
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'left/right alignment formatting with stealing' '
+ git commit --amend -m short --author "long long long <long@me.com>" &&
+ git log --pretty="format:%<(10,trunc)%s%>>(10,ltrunc)% an" >actual &&
+ # complete the incomplete line at the end
+ echo >>actual &&
+ cat <<EOF >expected &&
+short long long long
+message .. A U Thor
+add bar A U Thor
+initial... A U Thor
+EOF
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh
index bbde31b..925f577 100755
--- a/t/t4207-log-decoration-colors.sh
+++ b/t/t4207-log-decoration-colors.sh
@@ -44,15 +44,15 @@ test_expect_success setup '
'
cat >expected <<EOF
-${c_commit}COMMIT_ID (${c_HEAD}HEAD${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
${c_tag}tag: v1.0${c_reset}${c_commit},\
${c_tag}tag: B${c_reset}${c_commit},\
${c_branch}master${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID (${c_tag}tag: A1${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A1${c_reset}${c_commit},\
${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
-${c_commit}COMMIT_ID (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
On master: Changes to A.t
-${c_commit}COMMIT_ID (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
EOF
# We want log to show all, but the second parent to refs/stash is irrelevant
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
new file mode 100755
index 0000000..7369d3c
--- /dev/null
+++ b/t/t4211-line-log.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+
+test_description='test log -L'
+. ./test-lib.sh
+
+test_expect_success 'setup (import history)' '
+ git fast-import < "$TEST_DIRECTORY"/t4211/history.export &&
+ git reset --hard
+'
+
+canned_test_1 () {
+ test_expect_$1 "$2" "
+ git log $2 >actual &&
+ test_cmp \"\$TEST_DIRECTORY\"/t4211/expect.$3 actual
+ "
+}
+
+canned_test () {
+ canned_test_1 success "$@"
+}
+canned_test_failure () {
+ canned_test_1 failure "$@"
+}
+
+test_bad_opts () {
+ test_expect_success "invalid args: $1" "
+ test_must_fail git log $1 2>errors &&
+ grep '$2' errors
+ "
+}
+
+canned_test "-L 4,12:a.c simple" simple-f
+canned_test "-L 4,+9:a.c simple" simple-f
+canned_test "-L '/long f/,/^}/:a.c' simple" simple-f
+canned_test "-L :f:a.c simple" simple-f-to-main
+
+canned_test "-L '/main/,/^}/:a.c' simple" simple-main
+canned_test "-L :main:a.c simple" simple-main-to-end
+
+canned_test "-L 1,+4:a.c simple" beginning-of-file
+
+canned_test "-L 20:a.c simple" end-of-file
+
+canned_test "-L '/long f/',/^}/:a.c -L /main/,/^}/:a.c simple" two-ranges
+canned_test "-L 24,+1:a.c simple" vanishes-early
+
+canned_test "-M -L '/long f/,/^}/:b.c' move-support" move-support-f
+canned_test "-M -L ':f:b.c' parallel-change" parallel-change-f-to-main
+
+canned_test "-L 4,12:a.c -L :main:a.c simple" multiple
+canned_test "-L 4,18:a.c -L ^:main:a.c simple" multiple-overlapping
+canned_test "-L :main:a.c -L 4,18:a.c simple" multiple-overlapping
+canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset
+canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset
+
+test_bad_opts "-L" "switch.*requires a value"
+test_bad_opts "-L b.c" "argument.*not of the form"
+test_bad_opts "-L 1:" "argument.*not of the form"
+test_bad_opts "-L 1:nonexistent" "There is no path"
+test_bad_opts "-L 1:simple" "There is no path"
+test_bad_opts "-L '/foo:b.c'" "argument.*not of the form"
+test_bad_opts "-L 1000:b.c" "has only.*lines"
+test_bad_opts "-L 1,1000:b.c" "has only.*lines"
+test_bad_opts "-L :b.c" "argument.*not of the form"
+test_bad_opts "-L :foo:b.c" "no match"
+
+test_expect_success '-L X (X == nlines)' '
+ n=$(wc -l <b.c) &&
+ git log -L $n:b.c
+'
+
+test_expect_success '-L X (X == nlines + 1)' '
+ n=$(expr $(wc -l <b.c) + 1) &&
+ test_must_fail git log -L $n:b.c
+'
+
+test_expect_success '-L X (X == nlines + 2)' '
+ n=$(expr $(wc -l <b.c) + 2) &&
+ test_must_fail git log -L $n:b.c
+'
+
+test_expect_success '-L ,Y (Y == nlines)' '
+ n=$(printf "%d" $(wc -l <b.c)) &&
+ git log -L ,$n:b.c
+'
+
+test_expect_success '-L ,Y (Y == nlines + 1)' '
+ n=$(expr $(wc -l <b.c) + 1) &&
+ test_must_fail git log -L ,$n:b.c
+'
+
+test_expect_success '-L ,Y (Y == nlines + 2)' '
+ n=$(expr $(wc -l <b.c) + 2) &&
+ test_must_fail git log -L ,$n:b.c
+'
+
+test_done
diff --git a/t/t4211/expect.beginning-of-file b/t/t4211/expect.beginning-of-file
new file mode 100644
index 0000000..91b4054
--- /dev/null
+++ b/t/t4211/expect.beginning-of-file
@@ -0,0 +1,43 @@
+commit 4a23ae5c98d59a58c6da036156959f2dc9f472ad
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:47:40 2013 +0100
+
+ change at very beginning
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -1,3 +1,4 @@
++#include <unistd.h>
+ #include <stdio.h>
+
+ long f(long x)
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -1,3 +1,3 @@
+ #include <stdio.h>
+
+-int f(int x)
++long f(long x)
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +1,3 @@
++#include <stdio.h>
++
++int f(int x)
diff --git a/t/t4211/expect.end-of-file b/t/t4211/expect.end-of-file
new file mode 100644
index 0000000..bd25bb2
--- /dev/null
+++ b/t/t4211/expect.end-of-file
@@ -0,0 +1,62 @@
+commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:43 2013 +0100
+
+ change back to complete line
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -20,3 +20,5 @@
+ printf("%ld\n", f(15));
+ return 0;
+-}
+\ No newline at end of file
++}
++
++/* incomplete lines are bad! */
+
+commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:10 2013 +0100
+
+ change to an incomplete line at end
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -20,3 +20,3 @@
+ printf("%ld\n", f(15));
+ return 0;
+-}
++}
+\ No newline at end of file
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -19,3 +19,3 @@
+- printf("%d\n", f(15));
++ printf("%ld\n", f(15));
+ return 0;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +18,3 @@
++ printf("%d\n", f(15));
++ return 0;
++}
diff --git a/t/t4211/expect.move-support-f b/t/t4211/expect.move-support-f
new file mode 100644
index 0000000..c905e01
--- /dev/null
+++ b/t/t4211/expect.move-support-f
@@ -0,0 +1,80 @@
+commit 6ce3c4ff690136099bb17e1a8766b75764726ea7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:49:50 2013 +0100
+
+ another simple change
+
+diff --git a/b.c b/b.c
+--- a/b.c
++++ b/b.c
+@@ -4,9 +4,9 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+- x >>= 1;
++ x /= 2;
+ s++;
+ }
+ return s;
+ }
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,9 +3,9 @@
+-int f(int x)
++long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:55 2013 +0100
+
+ change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,8 +3,9 @@
+ int f(int x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
++ return s;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,8 @@
++int f(int x)
++{
++ int s = 0;
++ while (x) {
++ x >>= 1;
++ s++;
++ }
++}
diff --git a/t/t4211/expect.multiple b/t/t4211/expect.multiple
new file mode 100644
index 0000000..76ad5b5
--- /dev/null
+++ b/t/t4211/expect.multiple
@@ -0,0 +1,104 @@
+commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:43 2013 +0100
+
+ change back to complete line
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -18,5 +18,7 @@
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
+\ No newline at end of file
++}
++
++/* incomplete lines are bad! */
+
+commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:10 2013 +0100
+
+ change to an incomplete line at end
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -18,5 +18,5 @@
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
++}
+\ No newline at end of file
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,9 +3,9 @@
+-int f(int x)
++long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+@@ -17,5 +17,5 @@
+ int main ()
+ {
+- printf("%d\n", f(15));
++ printf("%ld\n", f(15));
+ return 0;
+ }
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:55 2013 +0100
+
+ change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,8 +3,9 @@
+ int f(int x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
++ return s;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,8 @@
++int f(int x)
++{
++ int s = 0;
++ while (x) {
++ x >>= 1;
++ s++;
++ }
++}
diff --git a/t/t4211/expect.multiple-overlapping b/t/t4211/expect.multiple-overlapping
new file mode 100644
index 0000000..d930b6e
--- /dev/null
+++ b/t/t4211/expect.multiple-overlapping
@@ -0,0 +1,187 @@
+commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:43 2013 +0100
+
+ change back to complete line
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -4,19 +4,21 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+ * This is only an example!
+ */
+
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
+\ No newline at end of file
++}
++
++/* incomplete lines are bad! */
+
+commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:10 2013 +0100
+
+ change to an incomplete line at end
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -4,19 +4,19 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+ * This is only an example!
+ */
+
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
++}
+\ No newline at end of file
+
+commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:41 2013 +0100
+
+ touch comment
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,19 +3,19 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+- * A comment.
++ * This is only an example!
+ */
+
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+ }
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,19 +3,19 @@
+-int f(int x)
++long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+ * A comment.
+ */
+
+ int main ()
+ {
+- printf("%d\n", f(15));
++ printf("%ld\n", f(15));
+ return 0;
+ }
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:55 2013 +0100
+
+ change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,18 +3,19 @@
+ int f(int x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
++ return s;
+ }
+
+ /*
+ * A comment.
+ */
+
+ int main ()
+ {
+ printf("%d\n", f(15));
+ return 0;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,18 @@
++int f(int x)
++{
++ int s = 0;
++ while (x) {
++ x >>= 1;
++ s++;
++ }
++}
++
++/*
++ * A comment.
++ */
++
++int main ()
++{
++ printf("%d\n", f(15));
++ return 0;
++}
diff --git a/t/t4211/expect.multiple-superset b/t/t4211/expect.multiple-superset
new file mode 100644
index 0000000..d930b6e
--- /dev/null
+++ b/t/t4211/expect.multiple-superset
@@ -0,0 +1,187 @@
+commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:43 2013 +0100
+
+ change back to complete line
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -4,19 +4,21 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+ * This is only an example!
+ */
+
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
+\ No newline at end of file
++}
++
++/* incomplete lines are bad! */
+
+commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:10 2013 +0100
+
+ change to an incomplete line at end
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -4,19 +4,19 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+ * This is only an example!
+ */
+
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
++}
+\ No newline at end of file
+
+commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:41 2013 +0100
+
+ touch comment
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,19 +3,19 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+- * A comment.
++ * This is only an example!
+ */
+
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+ }
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,19 +3,19 @@
+-int f(int x)
++long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+ * A comment.
+ */
+
+ int main ()
+ {
+- printf("%d\n", f(15));
++ printf("%ld\n", f(15));
+ return 0;
+ }
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:55 2013 +0100
+
+ change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,18 +3,19 @@
+ int f(int x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
++ return s;
+ }
+
+ /*
+ * A comment.
+ */
+
+ int main ()
+ {
+ printf("%d\n", f(15));
+ return 0;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,18 @@
++int f(int x)
++{
++ int s = 0;
++ while (x) {
++ x >>= 1;
++ s++;
++ }
++}
++
++/*
++ * A comment.
++ */
++
++int main ()
++{
++ printf("%d\n", f(15));
++ return 0;
++}
diff --git a/t/t4211/expect.parallel-change-f-to-main b/t/t4211/expect.parallel-change-f-to-main
new file mode 100644
index 0000000..052def8
--- /dev/null
+++ b/t/t4211/expect.parallel-change-f-to-main
@@ -0,0 +1,160 @@
+commit 0469c60bc4837d52d97b1f081dec5f98dea20fed
+Merge: ba227c6 6ce3c4f
+Author: Thomas Rast <trast@inf.ethz.ch>
+Date: Fri Apr 12 16:16:24 2013 +0200
+
+ Merge across the rename
+
+
+commit 6ce3c4ff690136099bb17e1a8766b75764726ea7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:49:50 2013 +0100
+
+ another simple change
+
+diff --git a/b.c b/b.c
+--- a/b.c
++++ b/b.c
+@@ -4,14 +4,14 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+- x >>= 1;
++ x /= 2;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+ * This is only an example!
+ */
+
+
+commit ba227c6632349700fbb957dec2b50f5e2358be3f
+Author: Thomas Rast <trast@inf.ethz.ch>
+Date: Fri Apr 12 16:15:57 2013 +0200
+
+ change on another line of history while rename happens
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -4,14 +4,14 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+- * This is only an example!
++ * This is only a short example!
+ */
+
+
+commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:41 2013 +0100
+
+ touch comment
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,14 +3,14 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+- * A comment.
++ * This is only an example!
+ */
+
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,14 +3,14 @@
+-int f(int x)
++long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+ * A comment.
+ */
+
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:55 2013 +0100
+
+ change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,13 +3,14 @@
+ int f(int x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
++ return s;
+ }
+
+ /*
+ * A comment.
+ */
+
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,13 @@
++int f(int x)
++{
++ int s = 0;
++ while (x) {
++ x >>= 1;
++ s++;
++ }
++}
++
++/*
++ * A comment.
++ */
++
diff --git a/t/t4211/expect.simple-f b/t/t4211/expect.simple-f
new file mode 100644
index 0000000..a1f5bc4
--- /dev/null
+++ b/t/t4211/expect.simple-f
@@ -0,0 +1,59 @@
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,9 +3,9 @@
+-int f(int x)
++long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:55 2013 +0100
+
+ change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,8 +3,9 @@
+ int f(int x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
++ return s;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,8 @@
++int f(int x)
++{
++ int s = 0;
++ while (x) {
++ x >>= 1;
++ s++;
++ }
++}
diff --git a/t/t4211/expect.simple-f-to-main b/t/t4211/expect.simple-f-to-main
new file mode 100644
index 0000000..a475768
--- /dev/null
+++ b/t/t4211/expect.simple-f-to-main
@@ -0,0 +1,100 @@
+commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:41 2013 +0100
+
+ touch comment
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,14 +3,14 @@
+ long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+- * A comment.
++ * This is only an example!
+ */
+
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,14 +3,14 @@
+-int f(int x)
++long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+
+ /*
+ * A comment.
+ */
+
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:55 2013 +0100
+
+ change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,13 +3,14 @@
+ int f(int x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
++ return s;
+ }
+
+ /*
+ * A comment.
+ */
+
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,13 @@
++int f(int x)
++{
++ int s = 0;
++ while (x) {
++ x >>= 1;
++ s++;
++ }
++}
++
++/*
++ * A comment.
++ */
++
diff --git a/t/t4211/expect.simple-main b/t/t4211/expect.simple-main
new file mode 100644
index 0000000..39ce39b
--- /dev/null
+++ b/t/t4211/expect.simple-main
@@ -0,0 +1,68 @@
+commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:43 2013 +0100
+
+ change back to complete line
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -18,5 +18,5 @@
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
+\ No newline at end of file
++}
+
+commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:10 2013 +0100
+
+ change to an incomplete line at end
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -18,5 +18,5 @@
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
++}
+\ No newline at end of file
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -17,5 +17,5 @@
+ int main ()
+ {
+- printf("%d\n", f(15));
++ printf("%ld\n", f(15));
+ return 0;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +16,5 @@
++int main ()
++{
++ printf("%d\n", f(15));
++ return 0;
++}
diff --git a/t/t4211/expect.simple-main-to-end b/t/t4211/expect.simple-main-to-end
new file mode 100644
index 0000000..8480bd9
--- /dev/null
+++ b/t/t4211/expect.simple-main-to-end
@@ -0,0 +1,70 @@
+commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:43 2013 +0100
+
+ change back to complete line
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -18,5 +18,7 @@
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
+\ No newline at end of file
++}
++
++/* incomplete lines are bad! */
+
+commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:10 2013 +0100
+
+ change to an incomplete line at end
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -18,5 +18,5 @@
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
++}
+\ No newline at end of file
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -17,5 +17,5 @@
+ int main ()
+ {
+- printf("%d\n", f(15));
++ printf("%ld\n", f(15));
+ return 0;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +16,5 @@
++int main ()
++{
++ printf("%d\n", f(15));
++ return 0;
++}
diff --git a/t/t4211/expect.two-ranges b/t/t4211/expect.two-ranges
new file mode 100644
index 0000000..6109aa0
--- /dev/null
+++ b/t/t4211/expect.two-ranges
@@ -0,0 +1,102 @@
+commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:43 2013 +0100
+
+ change back to complete line
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -18,5 +18,5 @@
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
+\ No newline at end of file
++}
+
+commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:10 2013 +0100
+
+ change to an incomplete line at end
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -18,5 +18,5 @@
+ int main ()
+ {
+ printf("%ld\n", f(15));
+ return 0;
+-}
++}
+\ No newline at end of file
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:45:16 2013 +0100
+
+ touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,9 +3,9 @@
+-int f(int x)
++long f(long x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+ }
+@@ -17,5 +17,5 @@
+ int main ()
+ {
+- printf("%d\n", f(15));
++ printf("%ld\n", f(15));
+ return 0;
+ }
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:55 2013 +0100
+
+ change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,8 +3,9 @@
+ int f(int x)
+ {
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
++ return s;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,8 @@
++int f(int x)
++{
++ int s = 0;
++ while (x) {
++ x >>= 1;
++ s++;
++ }
++}
diff --git a/t/t4211/expect.vanishes-early b/t/t4211/expect.vanishes-early
new file mode 100644
index 0000000..1f7cd06
--- /dev/null
+++ b/t/t4211/expect.vanishes-early
@@ -0,0 +1,39 @@
+commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:43 2013 +0100
+
+ change back to complete line
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -22,1 +24,1 @@
+-}
+\ No newline at end of file
++/* incomplete lines are bad! */
+
+commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:48:10 2013 +0100
+
+ change to an incomplete line at end
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -22,1 +22,1 @@
+-}
++}
+\ No newline at end of file
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date: Thu Feb 28 10:44:48 2013 +0100
+
+ initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +20,1 @@
++}
diff --git a/t/t4211/history.export b/t/t4211/history.export
new file mode 100644
index 0000000..f9f41e2
--- /dev/null
+++ b/t/t4211/history.export
@@ -0,0 +1,406 @@
+blob
+mark :1
+data 157
+#include <stdio.h>
+
+int f(int x)
+{
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+}
+
+/*
+ * A comment.
+ */
+
+int main ()
+{
+ printf("%d\n", f(15));
+ return 0;
+}
+
+reset refs/tags/simple
+commit refs/tags/simple
+mark :2
+author Thomas Rast <trast@student.ethz.ch> 1362044688 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362044688 +0100
+data 8
+initial
+M 100644 :1 a.c
+
+blob
+mark :3
+data 168
+#include <stdio.h>
+
+int f(int x)
+{
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+}
+
+/*
+ * A comment.
+ */
+
+int main ()
+{
+ printf("%d\n", f(15));
+ return 0;
+}
+
+commit refs/tags/simple
+mark :4
+author Thomas Rast <trast@student.ethz.ch> 1362044695 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362044695 +0100
+data 11
+change f()
+from :2
+M 100644 :3 a.c
+
+blob
+mark :5
+data 171
+#include <stdio.h>
+
+long f(long x)
+{
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+}
+
+/*
+ * A comment.
+ */
+
+int main ()
+{
+ printf("%ld\n", f(15));
+ return 0;
+}
+
+commit refs/tags/simple
+mark :6
+author Thomas Rast <trast@student.ethz.ch> 1362044716 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362044716 +0100
+data 21
+touch both functions
+from :4
+M 100644 :5 a.c
+
+blob
+mark :7
+data 185
+#include <stdio.h>
+
+long f(long x)
+{
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+}
+
+/*
+ * This is only an example!
+ */
+
+int main ()
+{
+ printf("%ld\n", f(15));
+ return 0;
+}
+
+commit refs/tags/simple
+mark :8
+author Thomas Rast <trast@student.ethz.ch> 1362044741 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362044741 +0100
+data 14
+touch comment
+from :6
+M 100644 :7 a.c
+
+blob
+mark :9
+data 205
+#include <unistd.h>
+#include <stdio.h>
+
+long f(long x)
+{
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+}
+
+/*
+ * This is only an example!
+ */
+
+int main ()
+{
+ printf("%ld\n", f(15));
+ return 0;
+}
+
+commit refs/tags/simple
+mark :10
+author Thomas Rast <trast@student.ethz.ch> 1362044860 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362044860 +0100
+data 25
+change at very beginning
+from :8
+M 100644 :9 a.c
+
+blob
+mark :11
+data 204
+#include <unistd.h>
+#include <stdio.h>
+
+long f(long x)
+{
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+}
+
+/*
+ * This is only an example!
+ */
+
+int main ()
+{
+ printf("%ld\n", f(15));
+ return 0;
+}
+commit refs/tags/simple
+mark :12
+author Thomas Rast <trast@student.ethz.ch> 1362044890 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362044890 +0100
+data 36
+change to an incomplete line at end
+from :10
+M 100644 :11 a.c
+
+blob
+mark :13
+data 238
+#include <unistd.h>
+#include <stdio.h>
+
+long f(long x)
+{
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+}
+
+/*
+ * This is only an example!
+ */
+
+int main ()
+{
+ printf("%ld\n", f(15));
+ return 0;
+}
+
+/* incomplete lines are bad! */
+
+commit refs/tags/simple
+mark :14
+author Thomas Rast <trast@student.ethz.ch> 1362044923 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362044923 +0100
+data 29
+change back to complete line
+from :12
+M 100644 :13 a.c
+
+commit refs/tags/move-support
+mark :15
+author Thomas Rast <trast@student.ethz.ch> 1362044968 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362044968 +0100
+data 10
+move file
+from :14
+D a.c
+M 100644 :13 b.c
+
+blob
+mark :16
+data 237
+#include <unistd.h>
+#include <stdio.h>
+
+long f(long x)
+{
+ int s = 0;
+ while (x) {
+ x /= 2;
+ s++;
+ }
+ return s;
+}
+
+/*
+ * This is only an example!
+ */
+
+int main ()
+{
+ printf("%ld\n", f(15));
+ return 0;
+}
+
+/* incomplete lines are bad! */
+
+commit refs/tags/move-support
+mark :17
+author Thomas Rast <trast@student.ethz.ch> 1362044990 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362044990 +0100
+data 22
+another simple change
+from :15
+M 100644 :16 b.c
+
+blob
+mark :18
+data 254
+#include <unistd.h>
+#include <stdio.h>
+
+long f(long x);
+
+/*
+ * This is only an example!
+ */
+
+int main ()
+{
+ printf("%ld\n", f(15));
+ return 0;
+}
+
+/* incomplete lines are bad! */
+
+long f(long x)
+{
+ int s = 0;
+ while (x) {
+ x /= 2;
+ s++;
+ }
+ return s;
+}
+
+commit refs/heads/master
+mark :19
+author Thomas Rast <trast@student.ethz.ch> 1362045024 +0100
+committer Thomas Rast <trast@student.ethz.ch> 1362045024 +0100
+data 21
+move within the file
+from :17
+M 100644 :18 b.c
+
+blob
+mark :20
+data 243
+#include <unistd.h>
+#include <stdio.h>
+
+long f(long x)
+{
+ int s = 0;
+ while (x) {
+ x >>= 1;
+ s++;
+ }
+ return s;
+}
+
+/*
+ * This is only a short example!
+ */
+
+int main ()
+{
+ printf("%ld\n", f(15));
+ return 0;
+}
+
+/* incomplete lines are bad! */
+
+commit refs/heads/parallel-change
+mark :21
+author Thomas Rast <trast@inf.ethz.ch> 1365776157 +0200
+committer Thomas Rast <trast@inf.ethz.ch> 1365776157 +0200
+data 55
+change on another line of history while rename happens
+from :14
+M 100644 :20 a.c
+
+blob
+mark :22
+data 242
+#include <unistd.h>
+#include <stdio.h>
+
+long f(long x)
+{
+ int s = 0;
+ while (x) {
+ x /= 2;
+ s++;
+ }
+ return s;
+}
+
+/*
+ * This is only a short example!
+ */
+
+int main ()
+{
+ printf("%ld\n", f(15));
+ return 0;
+}
+
+/* incomplete lines are bad! */
+
+commit refs/heads/parallel-change
+mark :23
+author Thomas Rast <trast@inf.ethz.ch> 1365776184 +0200
+committer Thomas Rast <trast@inf.ethz.ch> 1365776191 +0200
+data 24
+Merge across the rename
+from :21
+merge :17
+D a.c
+M 100644 :22 b.c
+
+reset refs/heads/parallel-change
+from :23
+
diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh
index d0b2a45..9015e47 100755
--- a/t/t4300-merge-tree.sh
+++ b/t/t4300-merge-tree.sh
@@ -26,8 +26,6 @@ EXPECTED
test_expect_success 'file add !A, B' '
cat >expected <<\EXPECTED &&
-added in local
- our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
EXPECTED
git reset --hard initial &&
@@ -38,9 +36,6 @@ EXPECTED
test_expect_success 'file add A, B (same)' '
cat >expected <<\EXPECTED &&
-added in both
- our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
- their 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
EXPECTED
git reset --hard initial &&
@@ -181,9 +176,6 @@ AAA" &&
test_expect_success 'file remove A, !B' '
cat >expected <<\EXPECTED &&
-removed in local
- base 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
- their 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
EXPECTED
git reset --hard initial &&
@@ -213,6 +205,19 @@ EXPECTED
test_cmp expected actual
'
+test_expect_success 'file remove A, B (same)' '
+ cat >expected <<\EXPECTED &&
+EXPECTED
+
+ git reset --hard initial &&
+ test_commit "rm-a-b-base" "ONE" "AAA" &&
+ git rm ONE &&
+ git commit -m "rm-a-b" &&
+ git tag "rm-a-b" &&
+ git merge-tree rm-a-b-base rm-a-b rm-a-b >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'file change A, remove B' '
cat >expected <<\EXPECTED &&
removed in remote
@@ -254,6 +259,57 @@ EXPECTED
test_cmp expected actual
'
+test_expect_success 'tree add A, B (same)' '
+ cat >expect <<-\EOF &&
+ EOF
+ git reset --hard initial &&
+ mkdir sub &&
+ test_commit "add sub/file" "sub/file" "file" add-tree-A &&
+ git merge-tree initial add-tree-A add-tree-A >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'tree add A, B (different)' '
+ cat >expect <<-\EOF &&
+ added in both
+ our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d sub/file
+ their 100644 ba629238ca89489f2b350e196ca445e09d8bb834 sub/file
+ @@ -1 +1,5 @@
+ +<<<<<<< .our
+ AAA
+ +=======
+ +BBB
+ +>>>>>>> .their
+ EOF
+ git reset --hard initial &&
+ mkdir sub &&
+ test_commit "add sub/file" "sub/file" "AAA" add-tree-a-b-A &&
+ git reset --hard initial &&
+ mkdir sub &&
+ test_commit "add sub/file" "sub/file" "BBB" add-tree-a-b-B &&
+ git merge-tree initial add-tree-a-b-A add-tree-a-b-B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'tree unchanged A, removed B' '
+ cat >expect <<-\EOF &&
+ removed in remote
+ base 100644 43d5a8ed6ef6c00ff775008633f95787d088285d sub/file
+ our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d sub/file
+ @@ -1 +0,0 @@
+ -AAA
+ EOF
+ git reset --hard initial &&
+ mkdir sub &&
+ test_commit "add sub/file" "sub/file" "AAA" tree-remove-b-initial &&
+ git rm sub/file &&
+ test_tick &&
+ git commit -m "remove sub/file" &&
+ git tag tree-remove-b-B &&
+ git merge-tree tree-remove-b-initial tree-remove-b-initial tree-remove-b-B >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'turn file to tree' '
git reset --hard initial &&
rm initial-file &&
@@ -283,8 +339,6 @@ test_expect_success 'turn tree to file' '
test_commit "make-file" "dir" "CCC" &&
git merge-tree add-tree add-another-tree make-file >actual &&
cat >expect <<-\EOF &&
- added in local
- our 100644 ba629238ca89489f2b350e196ca445e09d8bb834 dir/another
removed in remote
base 100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 3fbd366..c2023b1 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -30,10 +30,76 @@ GUNZIP=${GUNZIP:-gzip -d}
SUBSTFORMAT=%H%n
+test_lazy_prereq TAR_NEEDS_PAX_FALLBACK '
+ (
+ mkdir pax &&
+ cd pax &&
+ "$TAR" xf "$TEST_DIRECTORY"/t5000/pax.tar &&
+ test -f PaxHeaders.1791/file
+ )
+'
+
+get_pax_header() {
+ file=$1
+ header=$2=
+
+ while read len rest
+ do
+ if test "$len" = $(echo "$len $rest" | wc -c)
+ then
+ case "$rest" in
+ $header*)
+ echo "${rest#$header}"
+ ;;
+ esac
+ fi
+ done <"$file"
+}
+
+check_tar() {
+ tarfile=$1.tar
+ listfile=$1.lst
+ dir=$1
+ dir_with_prefix=$dir/$2
+
+ test_expect_success ' extract tar archive' '
+ (mkdir $dir && cd $dir && "$TAR" xf -) <$tarfile
+ '
+
+ test_expect_success TAR_NEEDS_PAX_FALLBACK ' interpret pax headers' '
+ (
+ cd $dir &&
+ for header in *.paxheader
+ do
+ data=${header%.paxheader}.data &&
+ if test -h $data -o -e $data
+ then
+ path=$(get_pax_header $header path) &&
+ if test -n "$path"
+ then
+ mv "$data" "$path"
+ fi
+ fi
+ done
+ )
+ '
+
+ test_expect_success ' validate filenames' '
+ (cd ${dir_with_prefix}a && find .) | sort >$listfile &&
+ test_cmp a.lst $listfile
+ '
+
+ test_expect_success ' validate file contents' '
+ diff -r a ${dir_with_prefix}a
+ '
+}
+
test_expect_success \
'populate workdir' \
- 'mkdir a b c &&
+ 'mkdir a &&
echo simple textfile >a/a &&
+ ten=0123456789 && hundred=$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten &&
+ echo long filename >a/four$hundred &&
mkdir a/bin &&
cp /bin/sh a/bin &&
printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
@@ -62,6 +128,12 @@ test_expect_success \
git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \
git commit-tree $treeid </dev/null)'
+test_expect_success 'setup export-subst' '
+ echo "substfile?" export-subst >>.git/info/attributes &&
+ git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
+ >a/substfile1
+'
+
test_expect_success \
'create bare clone' \
'git clone --bare . bare.git &&
@@ -75,13 +147,19 @@ test_expect_success \
'git archive' \
'git archive HEAD >b.tar'
-test_expect_success \
- 'git tar-tree' \
- 'git tar-tree HEAD >b2.tar'
+check_tar b
-test_expect_success \
- 'git archive vs. git tar-tree' \
- 'test_cmp b.tar b2.tar'
+test_expect_success 'git archive --prefix=prefix/' '
+ git archive --prefix=prefix/ HEAD >with_prefix.tar
+'
+
+check_tar with_prefix prefix/
+
+test_expect_success 'git-archive --prefix=olde-' '
+ git archive --prefix=olde- HEAD >with_olde-prefix.tar
+'
+
+check_tar with_olde-prefix olde-
test_expect_success 'git archive on large files' '
test_config core.bigfilethreshold 1 &&
@@ -118,66 +196,14 @@ test_expect_success \
'git get-tar-commit-id <b.tar >b.commitid &&
test_cmp .git/$(git symbolic-ref HEAD) b.commitid'
-test_expect_success \
- 'extract tar archive' \
- '(cd b && "$TAR" xf -) <b.tar'
-
-test_expect_success \
- 'validate filenames' \
- '(cd b/a && find .) | sort >b.lst &&
- test_cmp a.lst b.lst'
-
-test_expect_success \
- 'validate file contents' \
- 'diff -r a b/a'
-
-test_expect_success \
- 'git tar-tree with prefix' \
- 'git tar-tree HEAD prefix >c.tar'
-
-test_expect_success \
- 'extract tar archive with prefix' \
- '(cd c && "$TAR" xf -) <c.tar'
-
-test_expect_success \
- 'validate filenames with prefix' \
- '(cd c/prefix/a && find .) | sort >c.lst &&
- test_cmp a.lst c.lst'
-
-test_expect_success \
- 'validate file contents with prefix' \
- 'diff -r a c/prefix/a'
-
-test_expect_success \
- 'create archives with substfiles' \
- 'cp .git/info/attributes .git/info/attributes.before &&
- echo "substfile?" export-subst >>.git/info/attributes &&
- git archive HEAD >f.tar &&
- git archive --prefix=prefix/ HEAD >g.tar &&
- mv .git/info/attributes.before .git/info/attributes'
-
-test_expect_success \
- 'extract substfiles' \
- '(mkdir f && cd f && "$TAR" xf -) <f.tar'
-
-test_expect_success \
- 'validate substfile contents' \
- 'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
- >f/a/substfile1.expected &&
- test_cmp f/a/substfile1.expected f/a/substfile1 &&
- test_cmp a/substfile2 f/a/substfile2
+test_expect_success 'git tar-tree' '
+ git tar-tree HEAD >tar-tree.tar &&
+ test_cmp b.tar tar-tree.tar
'
-test_expect_success \
- 'extract substfiles from archive with prefix' \
- '(mkdir g && cd g && "$TAR" xf -) <g.tar'
-
-test_expect_success \
- 'validate substfile contents from archive with prefix' \
- 'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
- >g/prefix/a/substfile1.expected &&
- test_cmp g/prefix/a/substfile1.expected g/prefix/a/substfile1 &&
- test_cmp a/substfile2 g/prefix/a/substfile2
+test_expect_success 'git tar-tree with prefix' '
+ git tar-tree HEAD prefix >tar-tree_with_prefix.tar &&
+ test_cmp with_prefix.tar tar-tree_with_prefix.tar
'
test_expect_success 'git archive with --output, override inferred format' '
@@ -197,18 +223,6 @@ test_expect_success 'clients cannot access unreachable commits' '
test_must_fail git archive --remote=. $sha1 >remote.tar
'
-test_expect_success 'git-archive --prefix=olde-' '
- git archive --prefix=olde- >h.tar HEAD &&
- (
- mkdir h &&
- cd h &&
- "$TAR" xf - <../h.tar
- ) &&
- test -d h/olde-a &&
- test -d h/olde-a/bin &&
- test -f h/olde-a/bin/sh
-'
-
test_expect_success 'setup tar filters' '
git config tar.tar.foo.command "tr ab ba" &&
git config tar.bar.command "tr ab ba" &&
diff --git a/t/t5000/pax.tar b/t/t5000/pax.tar
new file mode 100644
index 0000000..d911737
--- /dev/null
+++ b/t/t5000/pax.tar
Binary files differ
diff --git a/t/t5003-archive-zip.sh b/t/t5003-archive-zip.sh
index 4e7b05d..c72f71e 100755
--- a/t/t5003-archive-zip.sh
+++ b/t/t5003-archive-zip.sh
@@ -37,7 +37,7 @@ check_zip() {
test_expect_success \
'populate workdir' \
- 'mkdir a b c &&
+ 'mkdir a &&
echo simple textfile >a/a &&
mkdir a/bin &&
cp /bin/sh a/bin &&
diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh
index 8d1bbd3..67f3b54 100755
--- a/t/t5004-archive-corner-cases.sh
+++ b/t/t5004-archive-corner-cases.sh
@@ -27,6 +27,21 @@ check_dir() {
test_cmp expect actual
}
+
+# bsdtar/libarchive versions before 3.1.3 consider a tar file with a
+# global pax header that is not followed by a file record as corrupt.
+if "$TAR" tf "$TEST_DIRECTORY"/t5004/empty-with-pax-header.tar >/dev/null 2>&1
+then
+ test_set_prereq HEADER_ONLY_TAR_OK
+fi
+
+test_expect_success HEADER_ONLY_TAR_OK 'tar archive of commit with empty tree' '
+ git archive --format=tar HEAD >empty-with-pax-header.tar &&
+ make_dir extract &&
+ "$TAR" xf empty-with-pax-header.tar -C extract &&
+ check_dir extract
+'
+
test_expect_success 'tar archive of empty tree is empty' '
git archive --format=tar HEAD: >empty.tar &&
perl -e "print \"\\0\" x 10240" >10knuls.tar &&
diff --git a/t/t5004/empty-with-pax-header.tar b/t/t5004/empty-with-pax-header.tar
new file mode 100644
index 0000000..da9e39e
--- /dev/null
+++ b/t/t5004/empty-with-pax-header.tar
Binary files differ
diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh
index 432f98c..1afa0d5 100755
--- a/t/t5150-request-pull.sh
+++ b/t/t5150-request-pull.sh
@@ -80,12 +80,12 @@ test_expect_success 'setup: two scripts for reading pull requests' '
cat <<-EOT >fuzz.sed
#!/bin/sed -nf
+ s/$downstream_url_for_sed/URL/g
s/$_x40/OBJECT_NAME/g
s/A U Thor/AUTHOR/g
s/[-0-9]\{10\} [:0-9]\{8\} [-+][0-9]\{4\}/DATE/g
s/ [^ ].*/ SUBJECT/g
s/ [^ ].* (DATE)/ SUBJECT (DATE)/g
- s/$downstream_url_for_sed/URL/g
s/for-upstream/BRANCH/g
s/mnemonic.txt/FILENAME/g
s/^version [0-9]/VERSION/
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index 5b1250f..35926de 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -51,7 +51,7 @@ do_corrupt_object() {
ofs=`git show-index < ${pack}.idx | grep $1 | cut -f1 -d" "` &&
ofs=$(($ofs + $2)) &&
chmod +w ${pack}.pack &&
- dd of=${pack}.pack count=1 bs=1 conv=notrunc seek=$ofs &&
+ dd of=${pack}.pack bs=1 conv=notrunc seek=$ofs &&
test_must_fail git verify-pack ${pack}.pack
}
@@ -276,6 +276,33 @@ test_expect_success \
git cat-file blob $blob_3 > /dev/null'
test_expect_success \
+ 'corruption of delta base reference pointing to wrong object' \
+ 'create_new_pack --delta-base-offset &&
+ git prune-packed &&
+ printf "\220\033" | do_corrupt_object $blob_3 2 &&
+ git cat-file blob $blob_1 >/dev/null &&
+ git cat-file blob $blob_2 >/dev/null &&
+ test_must_fail git cat-file blob $blob_3 >/dev/null'
+
+test_expect_success \
+ '... but having a loose copy allows for full recovery' \
+ 'mv ${pack}.idx tmp &&
+ git hash-object -t blob -w file_3 &&
+ mv tmp ${pack}.idx &&
+ git cat-file blob $blob_1 > /dev/null &&
+ git cat-file blob $blob_2 > /dev/null &&
+ git cat-file blob $blob_3 > /dev/null'
+
+test_expect_success \
+ '... and then a repack "clears" the corruption' \
+ 'do_repack --delta-base-offset --no-reuse-delta &&
+ git prune-packed &&
+ git verify-pack ${pack}.pack &&
+ git cat-file blob $blob_1 > /dev/null &&
+ git cat-file blob $blob_2 > /dev/null &&
+ git cat-file blob $blob_3 > /dev/null'
+
+test_expect_success \
'corrupting header to have too small output buffer fails unpack' \
'create_new_pack &&
git prune-packed &&
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
index d645328..e4bb3a1 100755
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -195,4 +195,30 @@ test_expect_success 'gc: prune old objects after local clone' '
)
'
+test_expect_success 'garbage report in count-objects -v' '
+ : >.git/objects/pack/foo &&
+ : >.git/objects/pack/foo.bar &&
+ : >.git/objects/pack/foo.keep &&
+ : >.git/objects/pack/foo.pack &&
+ : >.git/objects/pack/fake.bar &&
+ : >.git/objects/pack/fake.keep &&
+ : >.git/objects/pack/fake.pack &&
+ : >.git/objects/pack/fake.idx &&
+ : >.git/objects/pack/fake2.keep &&
+ : >.git/objects/pack/fake3.idx &&
+ git count-objects -v 2>stderr &&
+ grep "index file .git/objects/pack/fake.idx is too small" stderr &&
+ grep "^warning:" stderr | sort >actual &&
+ cat >expected <<\EOF &&
+warning: garbage found: .git/objects/pack/fake.bar
+warning: garbage found: .git/objects/pack/foo
+warning: garbage found: .git/objects/pack/foo.bar
+warning: no corresponding .idx nor .pack: .git/objects/pack/fake2.keep
+warning: no corresponding .idx: .git/objects/pack/foo.keep
+warning: no corresponding .idx: .git/objects/pack/foo.pack
+warning: no corresponding .pack: .git/objects/pack/fake3.idx
+EOF
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
index c240035..2b8c0ba 100755
--- a/t/t5404-tracking-branches.sh
+++ b/t/t5404-tracking-branches.sh
@@ -36,7 +36,7 @@ test_expect_success 'prepare pushable branches' '
'
test_expect_success 'mixed-success push returns error' '
- test_must_fail git push
+ test_must_fail git push origin :
'
test_expect_success 'check tracking branches updated correctly after push' '
diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index baa670c..ea2e0d4 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -31,8 +31,8 @@ clear_hook_input () {
}
verify_hook_input () {
- test_cmp "$TRASH_DIRECTORY"/post-rewrite.args expected.args &&
- test_cmp "$TRASH_DIRECTORY"/post-rewrite.data expected.data
+ test_cmp expected.args "$TRASH_DIRECTORY"/post-rewrite.args &&
+ test_cmp expected.data "$TRASH_DIRECTORY"/post-rewrite.data
}
test_expect_success 'git commit --amend' '
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index d574085..a80584e 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -135,6 +135,13 @@ test_expect_success 'clone shallow depth 1' '
test "`git --git-dir=shallow0/.git rev-list --count HEAD`" = 1
'
+test_expect_success 'clone shallow depth 1 with fsck' '
+ git config --global fetch.fsckobjects true &&
+ git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0fsck &&
+ test "`git --git-dir=shallow0fsck/.git rev-list --count HEAD`" = 1 &&
+ git config --global --unset fetch.fsckobjects
+'
+
test_expect_success 'clone shallow' '
git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow
'
@@ -373,6 +380,20 @@ test_expect_success 'clone shallow with packed refs' '
test_cmp count8.expected count8.actual
'
+test_expect_success 'fetch in shallow repo unreachable shallow objects' '
+ (
+ git clone --bare --branch B --single-branch "file://$(pwd)/." no-reflog &&
+ git clone --depth 1 "file://$(pwd)/no-reflog" shallow9 &&
+ cd no-reflog &&
+ git tag -d TAGB1 TAGB2 &&
+ git update-ref refs/heads/B B~~ &&
+ git gc --prune=now &&
+ cd ../shallow9 &&
+ git fetch origin &&
+ git fsck --no-dangling
+ )
+'
+
test_expect_success 'setup tests for the --stdin parameter' '
for head in C D E F
do
@@ -484,4 +505,20 @@ test_expect_success 'test --all, --depth, and explicit tag' '
) >out-adt 2>error-adt
'
+test_expect_success 'shallow fetch with tags does not break the repository' '
+ mkdir repo1 &&
+ (
+ cd repo1 &&
+ git init &&
+ test_commit 1 &&
+ test_commit 2 &&
+ test_commit 3 &&
+ mkdir repo2 &&
+ cd repo2 &&
+ git init &&
+ git fetch --depth=2 ../.git master:branch &&
+ git fsck
+ )
+'
+
test_done
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 60de2d6..f30c038 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -4,10 +4,6 @@ test_description='test automatic tag following'
. ./test-lib.sh
-if ! test_have_prereq NOT_MINGW; then
- say "GIT_DEBUG_SEND_PACK not supported - skipping tests"
-fi
-
# End state of the repository:
#
# T - tag1 S - tag2
@@ -17,7 +13,7 @@ fi
# \ C - origin/cat \
# origin/master master
-test_expect_success NOT_MINGW setup '
+test_expect_success setup '
test_tick &&
echo ichi >file &&
git add file &&
@@ -39,28 +35,35 @@ test_expect_success NOT_MINGW setup '
'
U=UPLOAD_LOG
+UPATH="$(pwd)/$U"
-test_expect_success NOT_MINGW 'setup expect' '
+test_expect_success 'setup expect' '
cat - <<EOF >expect
-#S
want $A
-#E
EOF
'
-test_expect_success NOT_MINGW 'fetch A (new commit : 1 connection)' '
+get_needs () {
+ test -s "$1" &&
+ perl -alne '
+ next unless $F[1] eq "upload-pack<";
+ last if $F[2] eq "0000";
+ print $F[2], " ", $F[3];
+ ' "$1"
+}
+
+test_expect_success 'fetch A (new commit : 1 connection)' '
rm -f $U &&
(
cd cloned &&
- GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
+ GIT_TRACE_PACKET=$UPATH git fetch &&
test $A = $(git rev-parse --verify origin/master)
) &&
- test -s $U &&
- cut -d" " -f1,2 $U >actual &&
+ get_needs $U >actual &&
test_cmp expect actual
'
-test_expect_success NOT_MINGW "create tag T on A, create C on branch cat" '
+test_expect_success "create tag T on A, create C on branch cat" '
git tag -a -m tag1 tag1 $A &&
T=$(git rev-parse --verify tag1) &&
@@ -72,30 +75,27 @@ test_expect_success NOT_MINGW "create tag T on A, create C on branch cat" '
git checkout master
'
-test_expect_success NOT_MINGW 'setup expect' '
+test_expect_success 'setup expect' '
cat - <<EOF >expect
-#S
want $C
want $T
-#E
EOF
'
-test_expect_success NOT_MINGW 'fetch C, T (new branch, tag : 1 connection)' '
+test_expect_success 'fetch C, T (new branch, tag : 1 connection)' '
rm -f $U &&
(
cd cloned &&
- GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
+ GIT_TRACE_PACKET=$UPATH git fetch &&
test $C = $(git rev-parse --verify origin/cat) &&
test $T = $(git rev-parse --verify tag1) &&
test $A = $(git rev-parse --verify tag1^0)
) &&
- test -s $U &&
- cut -d" " -f1,2 $U >actual &&
+ get_needs $U >actual &&
test_cmp expect actual
'
-test_expect_success NOT_MINGW "create commits O, B, tag S on B" '
+test_expect_success "create commits O, B, tag S on B" '
test_tick &&
echo O >file &&
git add file &&
@@ -111,39 +111,34 @@ test_expect_success NOT_MINGW "create commits O, B, tag S on B" '
S=$(git rev-parse --verify tag2)
'
-test_expect_success NOT_MINGW 'setup expect' '
+test_expect_success 'setup expect' '
cat - <<EOF >expect
-#S
want $B
want $S
-#E
EOF
'
-test_expect_success NOT_MINGW 'fetch B, S (commit and tag : 1 connection)' '
+test_expect_success 'fetch B, S (commit and tag : 1 connection)' '
rm -f $U &&
(
cd cloned &&
- GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
+ GIT_TRACE_PACKET=$UPATH git fetch &&
test $B = $(git rev-parse --verify origin/master) &&
test $B = $(git rev-parse --verify tag2^0) &&
test $S = $(git rev-parse --verify tag2)
) &&
- test -s $U &&
- cut -d" " -f1,2 $U >actual &&
+ get_needs $U >actual &&
test_cmp expect actual
'
-test_expect_success NOT_MINGW 'setup expect' '
+test_expect_success 'setup expect' '
cat - <<EOF >expect
-#S
want $B
want $S
-#E
EOF
'
-test_expect_success NOT_MINGW 'new clone fetch master and tags' '
+test_expect_success 'new clone fetch master and tags' '
git branch -D cat
rm -f $U
(
@@ -151,15 +146,14 @@ test_expect_success NOT_MINGW 'new clone fetch master and tags' '
cd clone2 &&
git init &&
git remote add origin .. &&
- GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
+ GIT_TRACE_PACKET=$UPATH git fetch &&
test $B = $(git rev-parse --verify origin/master) &&
test $S = $(git rev-parse --verify tag2) &&
test $B = $(git rev-parse --verify tag2^0) &&
test $T = $(git rev-parse --verify tag1) &&
test $A = $(git rev-parse --verify tag1^0)
) &&
- test -s $U &&
- cut -d" " -f1,2 $U >actual &&
+ get_needs $U >actual &&
test_cmp expect actual
'
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 8b411eb..8f6e392 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -42,107 +42,104 @@ check_tracking_branch () {
}
test_expect_success setup '
-
setup_repository one &&
setup_repository two &&
(
- cd two && git branch another
+ cd two &&
+ git branch another
) &&
git clone one test
-
'
test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' '
-(
- cd test &&
- tokens_match origin "$(git remote)" &&
- check_remote_track origin master side &&
- check_tracking_branch origin HEAD master side
-)
+ (
+ cd test &&
+ tokens_match origin "$(git remote)" &&
+ check_remote_track origin master side &&
+ check_tracking_branch origin HEAD master side
+ )
'
test_expect_success 'add another remote' '
-(
- cd test &&
- git remote add -f second ../two &&
- tokens_match "origin second" "$(git remote)" &&
- check_tracking_branch second master side another &&
- git for-each-ref "--format=%(refname)" refs/remotes |
- sed -e "/^refs\/remotes\/origin\//d" \
- -e "/^refs\/remotes\/second\//d" >actual &&
- >expect &&
- test_cmp expect actual
-)
+ (
+ cd test &&
+ git remote add -f second ../two &&
+ tokens_match "origin second" "$(git remote)" &&
+ check_tracking_branch second master side another &&
+ git for-each-ref "--format=%(refname)" refs/remotes |
+ sed -e "/^refs\/remotes\/origin\//d" \
+ -e "/^refs\/remotes\/second\//d" >actual &&
+ >expect &&
+ test_cmp expect actual
+ )
'
-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 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 &&
- case `git config remote.second.fetch` in
- +*) true ;;
- *) false ;;
- esac
-)
+ (
+ cd test &&
+ case `git config remote.second.fetch` in
+ +*) true ;;
+ *) false ;;
+ esac
+ )
'
test_expect_success 'remove remote' '
-(
- cd test &&
- git symbolic-ref refs/remotes/second/HEAD refs/remotes/second/master &&
- git remote rm second
-)
+ (
+ cd test &&
+ git symbolic-ref refs/remotes/second/HEAD refs/remotes/second/master &&
+ git remote rm second
+ )
'
test_expect_success C_LOCALE_OUTPUT 'remove remote' '
-(
- cd test &&
- tokens_match origin "$(git remote)" &&
- check_remote_track origin master side &&
- git for-each-ref "--format=%(refname)" refs/remotes |
- sed -e "/^refs\/remotes\/origin\//d" >actual &&
- >expect &&
- test_cmp expect actual
-)
+ (
+ cd test &&
+ tokens_match origin "$(git remote)" &&
+ check_remote_track origin master side &&
+ git for-each-ref "--format=%(refname)" refs/remotes |
+ sed -e "/^refs\/remotes\/origin\//d" >actual &&
+ >expect &&
+ test_cmp expect actual
+ )
'
test_expect_success 'remove remote protects local branches' '
-(
- cd test &&
- { cat >expect1 <<EOF
-Note: A branch outside the refs/remotes/ hierarchy was not removed;
-to delete it, use:
- git branch -d master
-EOF
- } &&
- { cat >expect2 <<EOF
-Note: Some branches outside the refs/remotes/ hierarchy were not removed;
-to delete them, use:
- git branch -d foobranch
- git branch -d master
-EOF
- } &&
- git tag footag &&
- git config --add remote.oops.fetch "+refs/*:refs/*" &&
- 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_i18ncmp expect1 actual1 &&
- test_i18ncmp expect2 actual2
-)
-'
-
-cat > test/expect << EOF
+ (
+ cd test &&
+ cat >expect1 <<-\EOF &&
+ Note: A branch outside the refs/remotes/ hierarchy was not removed;
+ to delete it, use:
+ git branch -d master
+ EOF
+ cat >expect2 <<-\EOF &&
+ Note: Some branches outside the refs/remotes/ hierarchy were not removed;
+ to delete them, use:
+ git branch -d foobranch
+ git branch -d master
+ EOF
+ git tag footag &&
+ git config --add remote.oops.fetch "+refs/*:refs/*" &&
+ 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_i18ncmp expect1 actual1 &&
+ test_i18ncmp expect2 actual2
+ )
+'
+
+cat >test/expect <<EOF
* remote origin
Fetch URL: $(pwd)/one
Push URL: $(pwd)/one
@@ -172,36 +169,40 @@ cat > test/expect << EOF
EOF
test_expect_success 'show' '
- (cd test &&
- git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream &&
- git fetch &&
- git checkout -b ahead origin/master &&
- echo 1 >> file &&
- test_tick &&
- git commit -m update file &&
- git checkout master &&
- git branch --track octopus origin/master &&
- git branch --track rebase origin/master &&
- git branch -d -r origin/master &&
- git config --add remote.two.url ../two &&
- git config --add remote.two.pushurl ../three &&
- git config branch.rebase.rebase true &&
- git config branch.octopus.merge "topic-a topic-b topic-c" &&
- (cd ../one &&
- echo 1 > file &&
- test_tick &&
- git commit -m update file) &&
- git config --add remote.origin.push : &&
- git config --add remote.origin.push refs/heads/master:refs/heads/upstream &&
- git config --add remote.origin.push +refs/tags/lastbackup &&
- git config --add remote.two.push +refs/heads/ahead:refs/heads/master &&
- git config --add remote.two.push refs/heads/master:refs/heads/another &&
- git remote show origin two > output &&
- git branch -d rebase octopus &&
- test_i18ncmp expect output)
-'
-
-cat > test/expect << EOF
+ (
+ cd test &&
+ git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream &&
+ git fetch &&
+ git checkout -b ahead origin/master &&
+ echo 1 >>file &&
+ test_tick &&
+ git commit -m update file &&
+ git checkout master &&
+ git branch --track octopus origin/master &&
+ git branch --track rebase origin/master &&
+ git branch -d -r origin/master &&
+ git config --add remote.two.url ../two &&
+ git config --add remote.two.pushurl ../three &&
+ git config branch.rebase.rebase true &&
+ git config branch.octopus.merge "topic-a topic-b topic-c" &&
+ (
+ cd ../one &&
+ echo 1 >file &&
+ test_tick &&
+ git commit -m update file
+ ) &&
+ git config --add remote.origin.push : &&
+ git config --add remote.origin.push refs/heads/master:refs/heads/upstream &&
+ git config --add remote.origin.push +refs/tags/lastbackup &&
+ git config --add remote.two.push +refs/heads/ahead:refs/heads/master &&
+ git config --add remote.two.push refs/heads/master:refs/heads/another &&
+ git remote show origin two >output &&
+ git branch -d rebase octopus &&
+ test_i18ncmp expect output
+ )
+'
+
+cat >test/expect <<EOF
* remote origin
Fetch URL: $(pwd)/one
Push URL: $(pwd)/one
@@ -219,152 +220,187 @@ cat > test/expect << EOF
EOF
test_expect_success 'show -n' '
- (mv one one.unreachable &&
- cd test &&
- git remote show -n origin > output &&
- mv ../one.unreachable ../one &&
- test_i18ncmp expect output)
+ mv one one.unreachable &&
+ (
+ cd test &&
+ git remote show -n origin >output &&
+ mv ../one.unreachable ../one &&
+ test_i18ncmp expect output
+ )
'
test_expect_success 'prune' '
- (cd one &&
- git branch -m side side2) &&
- (cd test &&
- git fetch origin &&
- git remote prune origin &&
- git rev-parse refs/remotes/origin/side2 &&
- test_must_fail git rev-parse refs/remotes/origin/side)
+ (
+ cd one &&
+ git branch -m side side2
+ ) &&
+ (
+ cd test &&
+ git fetch origin &&
+ git remote prune origin &&
+ git rev-parse refs/remotes/origin/side2 &&
+ test_must_fail git rev-parse refs/remotes/origin/side
+ )
'
test_expect_success 'set-head --delete' '
- (cd test &&
- git symbolic-ref refs/remotes/origin/HEAD &&
- git remote set-head --delete origin &&
- test_must_fail git symbolic-ref refs/remotes/origin/HEAD)
+ (
+ cd test &&
+ git symbolic-ref refs/remotes/origin/HEAD &&
+ git remote set-head --delete origin &&
+ test_must_fail git symbolic-ref refs/remotes/origin/HEAD
+ )
'
test_expect_success 'set-head --auto' '
- (cd test &&
- git remote set-head --auto origin &&
- echo refs/remotes/origin/master >expect &&
- git symbolic-ref refs/remotes/origin/HEAD >output &&
- test_cmp expect output
+ (
+ cd test &&
+ git remote set-head --auto origin &&
+ echo refs/remotes/origin/master >expect &&
+ git symbolic-ref refs/remotes/origin/HEAD >output &&
+ test_cmp expect output
)
'
-cat >test/expect <<EOF
+cat >test/expect <<\EOF
error: Multiple remote HEAD branches. Please choose one explicitly with:
git remote set-head two another
git remote set-head two master
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_i18ncmp expect output)
+ (
+ cd test &&
+ test_must_fail git remote set-head --auto two >output 2>&1 &&
+ test_i18ncmp expect output
+ )
'
-cat >test/expect <<EOF
+cat >test/expect <<\EOF
refs/remotes/origin/side2
EOF
test_expect_success 'set-head explicit' '
- (cd test &&
- git remote set-head origin side2 &&
- git symbolic-ref refs/remotes/origin/HEAD >output &&
- git remote set-head origin master &&
- test_cmp expect output)
+ (
+ cd test &&
+ git remote set-head origin side2 &&
+ git symbolic-ref refs/remotes/origin/HEAD >output &&
+ git remote set-head origin master &&
+ test_cmp expect output
+ )
'
-cat > test/expect << EOF
+cat >test/expect <<EOF
Pruning origin
URL: $(pwd)/one
* [would prune] origin/side2
EOF
test_expect_success 'prune --dry-run' '
- (cd one &&
- git branch -m side2 side) &&
- (cd test &&
- git remote prune --dry-run origin > output &&
- git rev-parse refs/remotes/origin/side2 &&
- test_must_fail git rev-parse refs/remotes/origin/side &&
- (cd ../one &&
- git branch -m side side2) &&
- test_i18ncmp expect output)
+ (
+ cd one &&
+ git branch -m side2 side) &&
+ (
+ cd test &&
+ git remote prune --dry-run origin >output &&
+ git rev-parse refs/remotes/origin/side2 &&
+ test_must_fail git rev-parse refs/remotes/origin/side &&
+ (
+ cd ../one &&
+ git branch -m side side2) &&
+ test_i18ncmp expect output
+ )
'
test_expect_success 'add --mirror && prune' '
- (mkdir mirror &&
- cd mirror &&
- git init --bare &&
- git remote add --mirror -f origin ../one) &&
- (cd one &&
- git branch -m side2 side) &&
- (cd mirror &&
- git rev-parse --verify refs/heads/side2 &&
- test_must_fail git rev-parse --verify refs/heads/side &&
- git fetch origin &&
- git remote prune origin &&
- test_must_fail git rev-parse --verify refs/heads/side2 &&
- git rev-parse --verify refs/heads/side)
+ mkdir mirror &&
+ (
+ cd mirror &&
+ git init --bare &&
+ git remote add --mirror -f origin ../one
+ ) &&
+ (
+ cd one &&
+ git branch -m side2 side
+ ) &&
+ (
+ cd mirror &&
+ git rev-parse --verify refs/heads/side2 &&
+ test_must_fail git rev-parse --verify refs/heads/side &&
+ git fetch origin &&
+ git remote prune origin &&
+ test_must_fail git rev-parse --verify refs/heads/side2 &&
+ git rev-parse --verify refs/heads/side
+ )
'
test_expect_success 'add --mirror=fetch' '
mkdir mirror-fetch &&
git init mirror-fetch/parent &&
- (cd mirror-fetch/parent &&
- test_commit one) &&
+ (
+ cd mirror-fetch/parent &&
+ test_commit one
+ ) &&
git init --bare mirror-fetch/child &&
- (cd mirror-fetch/child &&
- git remote add --mirror=fetch -f parent ../parent)
+ (
+ cd mirror-fetch/child &&
+ git remote add --mirror=fetch -f parent ../parent
+ )
'
test_expect_success 'fetch mirrors act as mirrors during fetch' '
- (cd mirror-fetch/parent &&
- git branch new &&
- git branch -m master renamed
+ (
+ cd mirror-fetch/parent &&
+ git branch new &&
+ git branch -m master renamed
) &&
- (cd mirror-fetch/child &&
- git fetch parent &&
- git rev-parse --verify refs/heads/new &&
- git rev-parse --verify refs/heads/renamed
+ (
+ cd mirror-fetch/child &&
+ git fetch parent &&
+ git rev-parse --verify refs/heads/new &&
+ git rev-parse --verify refs/heads/renamed
)
'
test_expect_success 'fetch mirrors can prune' '
- (cd mirror-fetch/child &&
- git remote prune parent &&
- test_must_fail git rev-parse --verify refs/heads/master
+ (
+ cd mirror-fetch/child &&
+ git remote prune parent &&
+ test_must_fail git rev-parse --verify refs/heads/master
)
'
test_expect_success 'fetch mirrors do not act as mirrors during push' '
- (cd mirror-fetch/parent &&
- git checkout HEAD^0
+ (
+ cd mirror-fetch/parent &&
+ git checkout HEAD^0
) &&
- (cd mirror-fetch/child &&
- git branch -m renamed renamed2 &&
- git push parent
+ (
+ cd mirror-fetch/child &&
+ git branch -m renamed renamed2 &&
+ git push parent :
) &&
- (cd mirror-fetch/parent &&
- git rev-parse --verify renamed &&
- test_must_fail git rev-parse --verify refs/heads/renamed2
+ (
+ cd mirror-fetch/parent &&
+ git rev-parse --verify renamed &&
+ test_must_fail git rev-parse --verify refs/heads/renamed2
)
'
test_expect_success 'add fetch mirror with specific branches' '
git init --bare mirror-fetch/track &&
- (cd mirror-fetch/track &&
- git remote add --mirror=fetch -t heads/new parent ../parent
+ (
+ cd mirror-fetch/track &&
+ git remote add --mirror=fetch -t heads/new parent ../parent
)
'
test_expect_success 'fetch mirror respects specific branches' '
- (cd mirror-fetch/track &&
- git fetch parent &&
- git rev-parse --verify refs/heads/new &&
- test_must_fail git rev-parse --verify refs/heads/renamed
+ (
+ cd mirror-fetch/track &&
+ git fetch parent &&
+ git rev-parse --verify refs/heads/new &&
+ test_must_fail git rev-parse --verify refs/heads/renamed
)
'
@@ -372,60 +408,72 @@ test_expect_success 'add --mirror=push' '
mkdir mirror-push &&
git init --bare mirror-push/public &&
git init mirror-push/private &&
- (cd mirror-push/private &&
- test_commit one &&
- git remote add --mirror=push public ../public
+ (
+ cd mirror-push/private &&
+ test_commit one &&
+ git remote add --mirror=push public ../public
)
'
test_expect_success 'push mirrors act as mirrors during push' '
- (cd mirror-push/private &&
- git branch new &&
- git branch -m master renamed &&
- git push public
+ (
+ cd mirror-push/private &&
+ git branch new &&
+ git branch -m master renamed &&
+ git push public
) &&
- (cd mirror-push/private &&
- git rev-parse --verify refs/heads/new &&
- git rev-parse --verify refs/heads/renamed &&
- test_must_fail git rev-parse --verify refs/heads/master
+ (
+ cd mirror-push/private &&
+ git rev-parse --verify refs/heads/new &&
+ git rev-parse --verify refs/heads/renamed &&
+ test_must_fail git rev-parse --verify refs/heads/master
)
'
test_expect_success 'push mirrors do not act as mirrors during fetch' '
- (cd mirror-push/public &&
- git branch -m renamed renamed2 &&
- git symbolic-ref HEAD refs/heads/renamed2
+ (
+ cd mirror-push/public &&
+ git branch -m renamed renamed2 &&
+ git symbolic-ref HEAD refs/heads/renamed2
) &&
- (cd mirror-push/private &&
- git fetch public &&
- git rev-parse --verify refs/heads/renamed &&
- test_must_fail git rev-parse --verify refs/heads/renamed2
+ (
+ cd mirror-push/private &&
+ git fetch public &&
+ git rev-parse --verify refs/heads/renamed &&
+ test_must_fail git rev-parse --verify refs/heads/renamed2
)
'
test_expect_success 'push mirrors do not allow you to specify refs' '
git init mirror-push/track &&
- (cd mirror-push/track &&
- test_must_fail git remote add --mirror=push -t new public ../public
+ (
+ cd mirror-push/track &&
+ test_must_fail git remote add --mirror=push -t new public ../public
)
'
test_expect_success 'add alt && prune' '
- (mkdir alttst &&
- cd alttst &&
- git init &&
- git remote add -f origin ../one &&
- git config remote.alt.url ../one &&
- git config remote.alt.fetch "+refs/heads/*:refs/remotes/origin/*") &&
- (cd one &&
- git branch -m side side2) &&
- (cd alttst &&
- git rev-parse --verify refs/remotes/origin/side &&
- test_must_fail git rev-parse --verify refs/remotes/origin/side2 &&
- git fetch alt &&
- git remote prune alt &&
- test_must_fail git rev-parse --verify refs/remotes/origin/side &&
- git rev-parse --verify refs/remotes/origin/side2)
+ mkdir alttst &&
+ (
+ cd alttst &&
+ git init &&
+ git remote add -f origin ../one &&
+ git config remote.alt.url ../one &&
+ git config remote.alt.fetch "+refs/heads/*:refs/remotes/origin/*"
+ ) &&
+ (
+ cd one &&
+ git branch -m side side2
+ ) &&
+ (
+ cd alttst &&
+ git rev-parse --verify refs/remotes/origin/side &&
+ test_must_fail git rev-parse --verify refs/remotes/origin/side2 &&
+ git fetch alt &&
+ git remote prune alt &&
+ test_must_fail git rev-parse --verify refs/remotes/origin/side &&
+ git rev-parse --verify refs/remotes/origin/side2
+ )
'
cat >test/expect <<\EOF
@@ -433,20 +481,24 @@ some-tag
EOF
test_expect_success 'add with reachable tags (default)' '
- (cd one &&
- >foobar &&
- git add foobar &&
- git commit -m "Foobar" &&
- git tag -a -m "Foobar tag" foobar-tag &&
- git reset --hard HEAD~1 &&
- git tag -a -m "Some tag" some-tag) &&
- (mkdir add-tags &&
- cd add-tags &&
- git init &&
- git remote add -f origin ../one &&
- git tag -l some-tag >../test/output &&
- git tag -l foobar-tag >>../test/output &&
- test_must_fail git config remote.origin.tagopt) &&
+ (
+ cd one &&
+ >foobar &&
+ git add foobar &&
+ git commit -m "Foobar" &&
+ git tag -a -m "Foobar tag" foobar-tag &&
+ git reset --hard HEAD~1 &&
+ git tag -a -m "Some tag" some-tag
+ ) &&
+ mkdir add-tags &&
+ (
+ cd add-tags &&
+ git init &&
+ git remote add -f origin ../one &&
+ git tag -l some-tag >../test/output &&
+ git tag -l foobar-tag >>../test/output &&
+ test_must_fail git config remote.origin.tagopt
+ ) &&
test_cmp test/expect test/output
'
@@ -457,14 +509,16 @@ foobar-tag
EOF
test_expect_success 'add --tags' '
- (rm -rf add-tags &&
- mkdir add-tags &&
- cd add-tags &&
- git init &&
- git remote add -f --tags origin ../one &&
- git tag -l some-tag >../test/output &&
- git tag -l foobar-tag >>../test/output &&
- git config remote.origin.tagopt >>../test/output) &&
+ rm -rf add-tags &&
+ (
+ mkdir add-tags &&
+ cd add-tags &&
+ git init &&
+ git remote add -f --tags origin ../one &&
+ git tag -l some-tag >../test/output &&
+ git tag -l foobar-tag >>../test/output &&
+ git config remote.origin.tagopt >>../test/output
+ ) &&
test_cmp test/expect test/output
'
@@ -473,25 +527,31 @@ cat >test/expect <<\EOF
EOF
test_expect_success 'add --no-tags' '
- (rm -rf add-tags &&
- mkdir add-no-tags &&
- cd add-no-tags &&
- git init &&
- git remote add -f --no-tags origin ../one &&
- git tag -l some-tag >../test/output &&
- git tag -l foobar-tag >../test/output &&
- git config remote.origin.tagopt >>../test/output) &&
- (cd one &&
- git tag -d some-tag foobar-tag) &&
+ rm -rf add-tags &&
+ (
+ mkdir add-no-tags &&
+ cd add-no-tags &&
+ git init &&
+ git remote add -f --no-tags origin ../one &&
+ git tag -l some-tag >../test/output &&
+ git tag -l foobar-tag >../test/output &&
+ git config remote.origin.tagopt >>../test/output
+ ) &&
+ (
+ cd one &&
+ git tag -d some-tag foobar-tag
+ ) &&
test_cmp test/expect test/output
'
test_expect_success 'reject --no-no-tags' '
- (cd add-no-tags &&
- test_must_fail git remote add -f --no-no-tags neworigin ../one)
+ (
+ cd add-no-tags &&
+ test_must_fail git remote add -f --no-no-tags neworigin ../one
+ )
'
-cat > one/expect << EOF
+cat >one/expect <<\EOF
apis/master
apis/side
drosophila/another
@@ -500,17 +560,17 @@ cat > one/expect << EOF
EOF
test_expect_success 'update' '
-
- (cd one &&
- git remote add drosophila ../two &&
- git remote add apis ../mirror &&
- git remote update &&
- git branch -r > output &&
- test_cmp expect output)
-
+ (
+ cd one &&
+ git remote add drosophila ../two &&
+ git remote add apis ../mirror &&
+ git remote update &&
+ git branch -r >output &&
+ test_cmp expect output
+ )
'
-cat > one/expect << EOF
+cat >one/expect <<\EOF
drosophila/another
drosophila/master
drosophila/side
@@ -521,34 +581,40 @@ cat > one/expect << EOF
EOF
test_expect_success 'update with arguments' '
-
- (cd one &&
- for b in $(git branch -r)
- do
+ (
+ cd one &&
+ for b in $(git branch -r)
+ do
git branch -r -d $b || break
- done &&
- git remote add manduca ../mirror &&
- git remote add megaloprepus ../mirror &&
- git config remotes.phobaeticus "drosophila megaloprepus" &&
- git config remotes.titanus manduca &&
- git remote update phobaeticus titanus &&
- git branch -r > output &&
- test_cmp expect output)
-
+ done &&
+ git remote add manduca ../mirror &&
+ git remote add megaloprepus ../mirror &&
+ git config remotes.phobaeticus "drosophila megaloprepus" &&
+ git config remotes.titanus manduca &&
+ git remote update phobaeticus titanus &&
+ git branch -r >output &&
+ test_cmp expect output
+ )
'
test_expect_success 'update --prune' '
-
- (cd one &&
- git branch -m side2 side3) &&
- (cd test &&
- git remote update --prune &&
- (cd ../one && git branch -m side3 side2) &&
- git rev-parse refs/remotes/origin/side3 &&
- test_must_fail git rev-parse refs/remotes/origin/side2)
+ (
+ cd one &&
+ git branch -m side2 side3
+ ) &&
+ (
+ cd test &&
+ git remote update --prune &&
+ (
+ cd ../one &&
+ git branch -m side3 side2
+ ) &&
+ git rev-parse refs/remotes/origin/side3 &&
+ test_must_fail git rev-parse refs/remotes/origin/side2
+ )
'
-cat > one/expect << EOF
+cat >one/expect <<-\EOF
apis/master
apis/side
manduca/master
@@ -558,176 +624,204 @@ cat > one/expect << EOF
EOF
test_expect_success 'update default' '
-
- (cd one &&
- for b in $(git branch -r)
- do
+ (
+ cd one &&
+ for b in $(git branch -r)
+ do
git branch -r -d $b || break
- done &&
- git config remote.drosophila.skipDefaultUpdate true &&
- git remote update default &&
- git branch -r > output &&
- test_cmp expect output)
-
+ done &&
+ git config remote.drosophila.skipDefaultUpdate true &&
+ git remote update default &&
+ git branch -r >output &&
+ test_cmp expect output
+ )
'
-cat > one/expect << EOF
+cat >one/expect <<\EOF
drosophila/another
drosophila/master
drosophila/side
EOF
test_expect_success 'update default (overridden, with funny whitespace)' '
-
- (cd one &&
- for b in $(git branch -r)
- do
+ (
+ cd one &&
+ for b in $(git branch -r)
+ do
git branch -r -d $b || break
- done &&
- git config remotes.default "$(printf "\t drosophila \n")" &&
- git remote update default &&
- git branch -r > output &&
- test_cmp expect output)
-
+ done &&
+ git config remotes.default "$(printf "\t drosophila \n")" &&
+ git remote update default &&
+ git branch -r >output &&
+ test_cmp expect output
+ )
'
test_expect_success 'update (with remotes.default defined)' '
-
- (cd one &&
- for b in $(git branch -r)
- do
+ (
+ cd one &&
+ for b in $(git branch -r)
+ do
git branch -r -d $b || break
- done &&
- git config remotes.default "drosophila" &&
- git remote update &&
- git branch -r > output &&
- test_cmp expect output)
-
+ done &&
+ git config remotes.default "drosophila" &&
+ git remote update &&
+ git branch -r >output &&
+ test_cmp expect output
+ )
'
test_expect_success '"remote show" does not show symbolic refs' '
-
git clone one three &&
- (cd three &&
- git remote show origin > output &&
- ! grep "^ *HEAD$" < output &&
- ! grep -i stale < output)
-
+ (
+ cd three &&
+ git remote show origin >output &&
+ ! grep "^ *HEAD$" < output &&
+ ! grep -i stale < output
+ )
'
test_expect_success 'reject adding remote with an invalid name' '
-
test_must_fail git remote add some:url desired-name
-
'
# The first three test if the tracking branches are properly renamed,
# the last two ones check if the config is updated.
test_expect_success 'rename a remote' '
-
git clone one four &&
- (cd four &&
- git remote rename origin upstream &&
- rmdir .git/refs/remotes/origin &&
- test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/master" &&
- test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" &&
- test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" &&
- test "$(git config branch.master.remote)" = "upstream")
-
+ (
+ cd four &&
+ git remote rename origin upstream &&
+ rmdir .git/refs/remotes/origin &&
+ test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/master" &&
+ test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" &&
+ test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" &&
+ test "$(git config branch.master.remote)" = "upstream"
+ )
'
test_expect_success 'rename does not update a non-default fetch refspec' '
-
git clone one four.one &&
- (cd four.one &&
- git config remote.origin.fetch +refs/heads/*:refs/heads/origin/* &&
- git remote rename origin upstream &&
- test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/heads/origin/*" &&
- git rev-parse -q origin/master)
-
+ (
+ cd four.one &&
+ git config remote.origin.fetch +refs/heads/*:refs/heads/origin/* &&
+ git remote rename origin upstream &&
+ test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/heads/origin/*" &&
+ git rev-parse -q origin/master
+ )
'
test_expect_success 'rename a remote with name part of fetch spec' '
-
git clone one four.two &&
- (cd four.two &&
- git remote rename origin remote &&
- git remote rename remote upstream &&
- test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*")
-
+ (
+ cd four.two &&
+ git remote rename origin remote &&
+ git remote rename remote upstream &&
+ test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*"
+ )
'
test_expect_success 'rename a remote with name prefix of other remote' '
-
git clone one four.three &&
- (cd four.three &&
- git remote add o git://example.com/repo.git &&
- git remote rename o upstream &&
- test "$(git rev-parse origin/master)" = "$(git rev-parse master)")
-
+ (
+ cd four.three &&
+ git remote add o git://example.com/repo.git &&
+ git remote rename o upstream &&
+ test "$(git rev-parse origin/master)" = "$(git rev-parse master)"
+ )
'
-cat > remotes_origin << EOF
+cat >remotes_origin <<EOF
URL: $(pwd)/one
Push: refs/heads/master:refs/heads/upstream
+Push: refs/heads/next:refs/heads/upstream2
Pull: refs/heads/master:refs/heads/origin
+Pull: refs/heads/next:refs/heads/origin2
EOF
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 remove origin &&
- mkdir -p .git/remotes &&
- cat ../remotes_origin > .git/remotes/origin &&
- git remote rename origin origin &&
- ! test -f .git/remotes/origin &&
- test "$(git config remote.origin.url)" = "$origin_url" &&
- test "$(git config remote.origin.push)" = "refs/heads/master:refs/heads/upstream" &&
- test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin")
+ (
+ cd five &&
+ git remote remove origin &&
+ mkdir -p .git/remotes &&
+ cat ../remotes_origin >.git/remotes/origin &&
+ git remote rename origin origin &&
+ test_path_is_missing .git/remotes/origin &&
+ test "$(git config remote.origin.url)" = "$origin_url" &&
+ cat >push_expected <<-\EOF &&
+ refs/heads/master:refs/heads/upstream
+ refs/heads/next:refs/heads/upstream2
+ EOF
+ cat >fetch_expected <<-\EOF &&
+ refs/heads/master:refs/heads/origin
+ refs/heads/next:refs/heads/origin2
+ EOF
+ git config --get-all remote.origin.push >push_actual &&
+ git config --get-all remote.origin.fetch >fetch_actual &&
+ test_cmp push_expected push_actual &&
+ test_cmp fetch_expected fetch_actual
+ )
'
test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' '
git clone one six &&
origin_url=$(pwd)/one &&
- (cd six &&
- git remote rm origin &&
- echo "$origin_url" > .git/branches/origin &&
- git remote rename origin origin &&
- ! test -f .git/branches/origin &&
- test "$(git config remote.origin.url)" = "$origin_url" &&
- test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin")
+ (
+ cd six &&
+ git remote rm origin &&
+ echo "$origin_url" >.git/branches/origin &&
+ git remote rename origin origin &&
+ test_path_is_missing .git/branches/origin &&
+ test "$(git config remote.origin.url)" = "$origin_url" &&
+ test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin" &&
+ test "$(git config remote.origin.push)" = "HEAD:refs/heads/master"
+ )
'
-test_expect_success 'remote prune to cause a dangling symref' '
+test_expect_success 'migrate a remote from named file in $GIT_DIR/branches (2)' '
git clone one seven &&
(
+ cd seven &&
+ git remote rm origin &&
+ echo "quux#foom" > .git/branches/origin &&
+ git remote rename origin origin &&
+ test_path_is_missing .git/branches/origin &&
+ test "$(git config remote.origin.url)" = "quux" &&
+ test "$(git config remote.origin.fetch)" = "refs/heads/foom:refs/heads/origin"
+ test "$(git config remote.origin.push)" = "HEAD:refs/heads/foom"
+ )
+'
+
+test_expect_success 'remote prune to cause a dangling symref' '
+ git clone one eight &&
+ (
cd one &&
git checkout side2 &&
git branch -D master
) &&
(
- cd seven &&
+ cd eight &&
git remote prune origin
) >err 2>&1 &&
test_i18ngrep "has become dangling" err &&
: And the dangling symref will not cause other annoying errors &&
(
- cd seven &&
+ cd eight &&
git branch -a
) 2>err &&
! grep "points nowhere" err &&
(
- cd seven &&
+ cd eight &&
test_must_fail git branch nomore origin
) 2>err &&
grep "dangling symref" err
'
test_expect_success 'show empty remote' '
-
test_create_repo empty &&
git clone empty empty-clone &&
(
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index d7a19a1..1f0f8e6 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -370,30 +370,39 @@ test_expect_success 'bundle should record HEAD correctly' '
'
-test_expect_success 'explicit fetch should not update tracking' '
+test_expect_success 'mark initial state of origin/master' '
+ (
+ cd three &&
+ git tag base-origin-master refs/remotes/origin/master
+ )
+'
+
+test_expect_success 'explicit fetch should update tracking' '
cd "$D" &&
git branch -f side &&
(
cd three &&
+ git update-ref refs/remotes/origin/master base-origin-master &&
o=$(git rev-parse --verify refs/remotes/origin/master) &&
git fetch origin master &&
n=$(git rev-parse --verify refs/remotes/origin/master) &&
- test "$o" = "$n" &&
+ test "$o" != "$n" &&
test_must_fail git rev-parse --verify refs/remotes/origin/side
)
'
-test_expect_success 'explicit pull should not update tracking' '
+test_expect_success 'explicit pull should update tracking' '
cd "$D" &&
git branch -f side &&
(
cd three &&
+ git update-ref refs/remotes/origin/master base-origin-master &&
o=$(git rev-parse --verify refs/remotes/origin/master) &&
git pull origin master &&
n=$(git rev-parse --verify refs/remotes/origin/master) &&
- test "$o" = "$n" &&
+ test "$o" != "$n" &&
test_must_fail git rev-parse --verify refs/remotes/origin/side
)
'
@@ -404,6 +413,7 @@ test_expect_success 'configured fetch updates tracking' '
git branch -f side &&
(
cd three &&
+ git update-ref refs/remotes/origin/master base-origin-master &&
o=$(git rev-parse --verify refs/remotes/origin/master) &&
git fetch origin &&
n=$(git rev-parse --verify refs/remotes/origin/master) &&
@@ -412,6 +422,22 @@ test_expect_success 'configured fetch updates tracking' '
)
'
+test_expect_success 'non-matching refspecs do not confuse tracking update' '
+ cd "$D" &&
+ git update-ref refs/odd/location HEAD &&
+ (
+ cd three &&
+ git update-ref refs/remotes/origin/master base-origin-master &&
+ git config --add remote.origin.fetch \
+ refs/odd/location:refs/remotes/origin/odd &&
+ o=$(git rev-parse --verify refs/remotes/origin/master) &&
+ git fetch origin master &&
+ n=$(git rev-parse --verify refs/remotes/origin/master) &&
+ test "$o" != "$n" &&
+ test_must_fail git rev-parse --verify refs/remotes/origin/odd
+ )
+'
+
test_expect_success 'pushing nonexistent branch by mistake should not segv' '
cd "$D" &&
@@ -471,6 +497,88 @@ test_expect_success "should be able to fetch with duplicate refspecs" '
)
'
+# configured prune tests
+
+set_config_tristate () {
+ # var=$1 val=$2
+ case "$2" in
+ unset) test_unconfig "$1" ;;
+ *) git config "$1" "$2" ;;
+ esac
+}
+
+test_configured_prune () {
+ fetch_prune=$1 remote_origin_prune=$2 cmdline=$3 expected=$4
+
+ test_expect_success "prune fetch.prune=$1 remote.origin.prune=$2${3:+ $3}; $4" '
+ # make sure a newbranch is there in . and also in one
+ git branch -f newbranch &&
+ (
+ cd one &&
+ test_unconfig fetch.prune &&
+ test_unconfig remote.origin.prune &&
+ git fetch &&
+ git rev-parse --verify refs/remotes/origin/newbranch
+ )
+
+ # now remove it
+ git branch -d newbranch &&
+
+ # then test
+ (
+ cd one &&
+ set_config_tristate fetch.prune $fetch_prune &&
+ set_config_tristate remote.origin.prune $remote_origin_prune &&
+
+ git fetch $cmdline &&
+ case "$expected" in
+ pruned)
+ test_must_fail git rev-parse --verify refs/remotes/origin/newbranch
+ ;;
+ kept)
+ git rev-parse --verify refs/remotes/origin/newbranch
+ ;;
+ esac
+ )
+ '
+}
+
+test_configured_prune unset unset "" kept
+test_configured_prune unset unset "--no-prune" kept
+test_configured_prune unset unset "--prune" pruned
+
+test_configured_prune false unset "" kept
+test_configured_prune false unset "--no-prune" kept
+test_configured_prune false unset "--prune" pruned
+
+test_configured_prune true unset "" pruned
+test_configured_prune true unset "--prune" pruned
+test_configured_prune true unset "--no-prune" kept
+
+test_configured_prune unset false "" kept
+test_configured_prune unset false "--no-prune" kept
+test_configured_prune unset false "--prune" pruned
+
+test_configured_prune false false "" kept
+test_configured_prune false false "--no-prune" kept
+test_configured_prune false false "--prune" pruned
+
+test_configured_prune true false "" kept
+test_configured_prune true false "--prune" pruned
+test_configured_prune true false "--no-prune" kept
+
+test_configured_prune unset true "" pruned
+test_configured_prune unset true "--no-prune" kept
+test_configured_prune unset true "--prune" pruned
+
+test_configured_prune false true "" pruned
+test_configured_prune false true "--no-prune" kept
+test_configured_prune false true "--prune" pruned
+
+test_configured_prune true true "" pruned
+test_configured_prune true true "--prune" pruned
+test_configured_prune true true "--no-prune" kept
+
test_expect_success 'all boundary commits are excluded' '
test_commit base &&
test_commit oneside &&
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 9a21cd6..99c32d7 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1,16 +1,28 @@
#!/bin/sh
-test_description='fetching and pushing, with or without wildcard'
+test_description='Basic fetch/push functionality.
+
+This test checks the following functionality:
+
+* command-line syntax
+* refspecs
+* fast-forward detection, and overriding it
+* configuration
+* hooks
+* --porcelain output format
+* hiderefs
+'
. ./test-lib.sh
D=`pwd`
mk_empty () {
- rm -fr testrepo &&
- mkdir testrepo &&
+ repo_name="$1"
+ rm -fr "$repo_name" &&
+ mkdir "$repo_name" &&
(
- cd testrepo &&
+ cd "$repo_name" &&
git init &&
git config receive.denyCurrentBranch warn &&
mv .git/hooks .git/hooks-disabled
@@ -18,32 +30,33 @@ mk_empty () {
}
mk_test () {
- mk_empty &&
+ repo_name="$1"
+ shift
+
+ mk_empty "$repo_name" &&
(
for ref in "$@"
do
- git push testrepo $the_first_commit:refs/$ref || {
- echo "Oops, push refs/$ref failure"
- exit 1
- }
+ git push "$repo_name" $the_first_commit:refs/$ref ||
+ exit
done &&
- cd testrepo &&
+ cd "$repo_name" &&
for ref in "$@"
do
- r=$(git show-ref -s --verify refs/$ref) &&
- test "z$r" = "z$the_first_commit" || {
- echo "Oops, refs/$ref is wrong"
- exit 1
- }
+ echo "$the_first_commit" >expect &&
+ git show-ref -s --verify refs/$ref >actual &&
+ test_cmp expect actual ||
+ exit
done &&
git fsck --full
)
}
mk_test_with_hooks() {
+ repo_name=$1
mk_test "$@" &&
(
- cd testrepo &&
+ cd "$repo_name" &&
mkdir .git/hooks &&
cd .git/hooks &&
@@ -75,22 +88,23 @@ mk_test_with_hooks() {
}
mk_child() {
- rm -rf "$1" &&
- git clone testrepo "$1"
+ rm -rf "$2" &&
+ git clone "$1" "$2"
}
check_push_result () {
+ repo_name="$1"
+ shift
+
(
- cd testrepo &&
- it="$1" &&
- shift
+ cd "$repo_name" &&
+ echo "$1" >expect &&
+ shift &&
for ref in "$@"
do
- r=$(git show-ref -s --verify refs/$ref) &&
- test "z$r" = "z$it" || {
- echo "Oops, refs/$ref is wrong"
- exit 1
- }
+ git show-ref -s --verify refs/$ref >actual &&
+ test_cmp expect actual ||
+ exit
done &&
git fsck --full
)
@@ -113,35 +127,33 @@ test_expect_success setup '
'
test_expect_success 'fetch without wildcard' '
- mk_empty &&
+ mk_empty testrepo &&
(
cd testrepo &&
git fetch .. refs/heads/master:refs/remotes/origin/master &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
-
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'fetch with wildcard' '
- mk_empty &&
+ mk_empty testrepo &&
(
cd testrepo &&
git config remote.up.url .. &&
git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
git fetch up &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
-
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'fetch with insteadOf' '
- mk_empty &&
+ mk_empty testrepo &&
(
TRASH=$(pwd)/ &&
cd testrepo &&
@@ -150,15 +162,14 @@ test_expect_success 'fetch with insteadOf' '
git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
git fetch up &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
-
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'fetch with pushInsteadOf (should not rewrite)' '
- mk_empty &&
+ mk_empty testrepo &&
(
TRASH=$(pwd)/ &&
cd testrepo &&
@@ -167,321 +178,310 @@ test_expect_success 'fetch with pushInsteadOf (should not rewrite)' '
git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
git fetch up &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
-
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'push without wildcard' '
- mk_empty &&
+ mk_empty testrepo &&
git push testrepo refs/heads/master:refs/remotes/origin/master &&
(
cd testrepo &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
-
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'push with wildcard' '
- mk_empty &&
+ mk_empty testrepo &&
git push testrepo "refs/heads/*:refs/remotes/origin/*" &&
(
cd testrepo &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
-
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'push with insteadOf' '
- mk_empty &&
+ mk_empty testrepo &&
TRASH="$(pwd)/" &&
- git config "url.$TRASH.insteadOf" trash/ &&
+ test_config "url.$TRASH.insteadOf" trash/ &&
git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
(
cd testrepo &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
-
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'push with pushInsteadOf' '
- mk_empty &&
+ mk_empty testrepo &&
TRASH="$(pwd)/" &&
- git config "url.$TRASH.pushInsteadOf" trash/ &&
+ test_config "url.$TRASH.pushInsteadOf" trash/ &&
git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
(
cd testrepo &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
-
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf should not rewrite)' '
- mk_empty &&
- git config "url.trash2/.pushInsteadOf" testrepo/ &&
- git config "url.trash3/.pusnInsteadOf" trash/wrong &&
- git config remote.r.url trash/wrong &&
- git config remote.r.pushurl "testrepo/" &&
+ mk_empty testrepo &&
+ test_config "url.trash2/.pushInsteadOf" testrepo/ &&
+ test_config "url.trash3/.pusnInsteadOf" trash/wrong &&
+ test_config remote.r.url trash/wrong &&
+ test_config remote.r.pushurl "testrepo/" &&
git push r refs/heads/master:refs/remotes/origin/master &&
(
cd testrepo &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
-
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'push with matching heads' '
- mk_test heads/master &&
- git push testrepo &&
- check_push_result $the_commit heads/master
+ mk_test testrepo heads/master &&
+ git push testrepo : &&
+ check_push_result testrepo $the_commit heads/master
'
test_expect_success 'push with matching heads on the command line' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git push testrepo : &&
- check_push_result $the_commit heads/master
+ check_push_result testrepo $the_commit heads/master
'
test_expect_success 'failed (non-fast-forward) push with matching heads' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git push testrepo : &&
git commit --amend -massaged &&
test_must_fail git push testrepo &&
- check_push_result $the_commit heads/master &&
+ check_push_result testrepo $the_commit heads/master &&
git reset --hard $the_commit
'
test_expect_success 'push --force with matching heads' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git push testrepo : &&
git commit --amend -massaged &&
- git push --force testrepo &&
- ! check_push_result $the_commit heads/master &&
+ git push --force testrepo : &&
+ ! check_push_result testrepo $the_commit heads/master &&
git reset --hard $the_commit
'
test_expect_success 'push with matching heads and forced update' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git push testrepo : &&
git commit --amend -massaged &&
git push testrepo +: &&
- ! check_push_result $the_commit heads/master &&
+ ! check_push_result testrepo $the_commit heads/master &&
git reset --hard $the_commit
'
test_expect_success 'push with no ambiguity (1)' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git push testrepo master:master &&
- check_push_result $the_commit heads/master
+ check_push_result testrepo $the_commit heads/master
'
test_expect_success 'push with no ambiguity (2)' '
- mk_test remotes/origin/master &&
+ mk_test testrepo remotes/origin/master &&
git push testrepo master:origin/master &&
- check_push_result $the_commit remotes/origin/master
+ check_push_result testrepo $the_commit remotes/origin/master
'
test_expect_success 'push with colon-less refspec, no ambiguity' '
- mk_test heads/master heads/t/master &&
+ mk_test testrepo heads/master heads/t/master &&
git branch -f t/master master &&
git push testrepo master &&
- check_push_result $the_commit heads/master &&
- check_push_result $the_first_commit heads/t/master
+ check_push_result testrepo $the_commit heads/master &&
+ check_push_result testrepo $the_first_commit heads/t/master
'
test_expect_success 'push with weak ambiguity (1)' '
- mk_test heads/master remotes/origin/master &&
+ mk_test testrepo heads/master remotes/origin/master &&
git push testrepo master:master &&
- check_push_result $the_commit heads/master &&
- check_push_result $the_first_commit remotes/origin/master
+ check_push_result testrepo $the_commit heads/master &&
+ check_push_result testrepo $the_first_commit remotes/origin/master
'
test_expect_success 'push with weak ambiguity (2)' '
- mk_test heads/master remotes/origin/master remotes/another/master &&
+ mk_test testrepo heads/master remotes/origin/master remotes/another/master &&
git push testrepo master:master &&
- check_push_result $the_commit heads/master &&
- check_push_result $the_first_commit remotes/origin/master remotes/another/master
+ check_push_result testrepo $the_commit heads/master &&
+ check_push_result testrepo $the_first_commit remotes/origin/master remotes/another/master
'
test_expect_success 'push with ambiguity' '
- mk_test heads/frotz tags/frotz &&
- if git push testrepo master:frotz
- then
- echo "Oops, should have failed"
- false
- else
- check_push_result $the_first_commit heads/frotz tags/frotz
- fi
+ mk_test testrepo heads/frotz tags/frotz &&
+ test_must_fail git push testrepo master:frotz &&
+ check_push_result testrepo $the_first_commit heads/frotz tags/frotz
'
test_expect_success 'push with colon-less refspec (1)' '
- mk_test heads/frotz tags/frotz &&
+ mk_test testrepo heads/frotz tags/frotz &&
git branch -f frotz master &&
git push testrepo frotz &&
- check_push_result $the_commit heads/frotz &&
- check_push_result $the_first_commit tags/frotz
+ check_push_result testrepo $the_commit heads/frotz &&
+ check_push_result testrepo $the_first_commit tags/frotz
'
test_expect_success 'push with colon-less refspec (2)' '
- mk_test heads/frotz tags/frotz &&
+ mk_test testrepo heads/frotz tags/frotz &&
if git show-ref --verify -q refs/heads/frotz
then
git branch -D frotz
fi &&
git tag -f frotz &&
git push -f testrepo frotz &&
- check_push_result $the_commit tags/frotz &&
- check_push_result $the_first_commit heads/frotz
+ check_push_result testrepo $the_commit tags/frotz &&
+ check_push_result testrepo $the_first_commit heads/frotz
'
test_expect_success 'push with colon-less refspec (3)' '
- mk_test &&
+ mk_test testrepo &&
if git show-ref --verify -q refs/tags/frotz
then
git tag -d frotz
fi &&
git branch -f frotz master &&
git push testrepo frotz &&
- check_push_result $the_commit heads/frotz &&
+ check_push_result testrepo $the_commit heads/frotz &&
test 1 = $( cd testrepo && git show-ref | wc -l )
'
test_expect_success 'push with colon-less refspec (4)' '
- mk_test &&
+ mk_test testrepo &&
if git show-ref --verify -q refs/heads/frotz
then
git branch -D frotz
fi &&
git tag -f frotz &&
git push testrepo frotz &&
- check_push_result $the_commit tags/frotz &&
+ check_push_result testrepo $the_commit tags/frotz &&
test 1 = $( cd testrepo && git show-ref | wc -l )
'
test_expect_success 'push head with non-existent, incomplete dest' '
- mk_test &&
+ mk_test testrepo &&
git push testrepo master:branch &&
- check_push_result $the_commit heads/branch
+ check_push_result testrepo $the_commit heads/branch
'
test_expect_success 'push tag with non-existent, incomplete dest' '
- mk_test &&
+ mk_test testrepo &&
git tag -f v1.0 &&
git push testrepo v1.0:tag &&
- check_push_result $the_commit tags/tag
+ check_push_result testrepo $the_commit tags/tag
'
test_expect_success 'push sha1 with non-existent, incomplete dest' '
- mk_test &&
+ mk_test testrepo &&
test_must_fail git push testrepo `git rev-parse master`:foo
'
test_expect_success 'push ref expression with non-existent, incomplete dest' '
- mk_test &&
+ mk_test testrepo &&
test_must_fail git push testrepo master^:branch
'
test_expect_success 'push with HEAD' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git checkout master &&
git push testrepo HEAD &&
- check_push_result $the_commit heads/master
+ check_push_result testrepo $the_commit heads/master
'
test_expect_success 'push with HEAD nonexisting at remote' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git checkout -b local master &&
git push testrepo HEAD &&
- check_push_result $the_commit heads/local
+ check_push_result testrepo $the_commit heads/local
'
test_expect_success 'push with +HEAD' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git checkout master &&
git branch -D local &&
git checkout -b local &&
git push testrepo master local &&
- check_push_result $the_commit heads/master &&
- check_push_result $the_commit heads/local &&
+ check_push_result testrepo $the_commit heads/master &&
+ check_push_result testrepo $the_commit heads/local &&
# Without force rewinding should fail
git reset --hard HEAD^ &&
test_must_fail git push testrepo HEAD &&
- check_push_result $the_commit heads/local &&
+ check_push_result testrepo $the_commit heads/local &&
# With force rewinding should succeed
git push testrepo +HEAD &&
- check_push_result $the_first_commit heads/local
+ check_push_result testrepo $the_first_commit heads/local
'
test_expect_success 'push HEAD with non-existent, incomplete dest' '
- mk_test &&
+ mk_test testrepo &&
git checkout master &&
git push testrepo HEAD:branch &&
- check_push_result $the_commit heads/branch
+ check_push_result testrepo $the_commit heads/branch
'
test_expect_success 'push with config remote.*.push = HEAD' '
- mk_test heads/local &&
+ mk_test testrepo heads/local &&
git checkout master &&
git branch -f local $the_commit &&
(
@@ -489,46 +489,68 @@ test_expect_success 'push with config remote.*.push = HEAD' '
git checkout local &&
git reset --hard $the_first_commit
) &&
- git config remote.there.url testrepo &&
- git config remote.there.push HEAD &&
- git config branch.master.remote there &&
+ test_config remote.there.url testrepo &&
+ test_config remote.there.push HEAD &&
+ test_config branch.master.remote there &&
+ git push &&
+ check_push_result testrepo $the_commit heads/master &&
+ check_push_result testrepo $the_first_commit heads/local
+'
+
+test_expect_success 'push with remote.pushdefault' '
+ mk_test up_repo heads/master &&
+ mk_test down_repo heads/master &&
+ test_config remote.up.url up_repo &&
+ test_config remote.down.url down_repo &&
+ test_config branch.master.remote up &&
+ test_config remote.pushdefault down &&
+ test_config push.default matching &&
git push &&
- check_push_result $the_commit heads/master &&
- check_push_result $the_first_commit heads/local
+ check_push_result up_repo $the_first_commit heads/master &&
+ check_push_result down_repo $the_commit heads/master
'
-# clean up the cruft left with the previous one
-git config --remove-section remote.there
-git config --remove-section branch.master
-
test_expect_success 'push with config remote.*.pushurl' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git checkout master &&
- git config remote.there.url test2repo &&
- git config remote.there.pushurl testrepo &&
- git push there &&
- check_push_result $the_commit heads/master
+ test_config remote.there.url test2repo &&
+ test_config remote.there.pushurl testrepo &&
+ git push there : &&
+ check_push_result testrepo $the_commit heads/master
+'
+
+test_expect_success 'push with config branch.*.pushremote' '
+ mk_test up_repo heads/master &&
+ mk_test side_repo heads/master &&
+ mk_test down_repo heads/master &&
+ test_config remote.up.url up_repo &&
+ test_config remote.pushdefault side_repo &&
+ test_config remote.down.url down_repo &&
+ test_config branch.master.remote up &&
+ test_config branch.master.pushremote down &&
+ test_config push.default matching &&
+ git push &&
+ check_push_result up_repo $the_first_commit heads/master &&
+ check_push_result side_repo $the_first_commit heads/master &&
+ check_push_result down_repo $the_commit heads/master
'
-# clean up the cruft left with the previous one
-git config --remove-section remote.there
-
test_expect_success 'push with dry-run' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
(
cd testrepo &&
old_commit=$(git show-ref -s --verify refs/heads/master)
) &&
- git push --dry-run testrepo &&
- check_push_result $old_commit heads/master
+ git push --dry-run testrepo : &&
+ check_push_result testrepo $old_commit heads/master
'
test_expect_success 'push updates local refs' '
- mk_test heads/master &&
- mk_child child &&
+ mk_test testrepo heads/master &&
+ mk_child testrepo child &&
(
cd child &&
git pull .. master &&
@@ -541,9 +563,9 @@ test_expect_success 'push updates local refs' '
test_expect_success 'push updates up-to-date local refs' '
- mk_test heads/master &&
- mk_child child1 &&
- mk_child child2 &&
+ mk_test testrepo heads/master &&
+ mk_child testrepo child1 &&
+ mk_child testrepo child2 &&
(cd child1 && git pull .. master && git push) &&
(
cd child2 &&
@@ -557,8 +579,8 @@ test_expect_success 'push updates up-to-date local refs' '
test_expect_success 'push preserves up-to-date packed refs' '
- mk_test heads/master &&
- mk_child child &&
+ mk_test testrepo heads/master &&
+ mk_child testrepo child &&
(
cd child &&
git push &&
@@ -569,8 +591,8 @@ test_expect_success 'push preserves up-to-date packed refs' '
test_expect_success 'push does not update local refs on failure' '
- mk_test heads/master &&
- mk_child child &&
+ mk_test testrepo heads/master &&
+ mk_child testrepo child &&
mkdir testrepo/.git/hooks &&
echo "#!/no/frobnication/today" >testrepo/.git/hooks/pre-receive &&
chmod +x testrepo/.git/hooks/pre-receive &&
@@ -586,7 +608,7 @@ test_expect_success 'push does not update local refs on failure' '
test_expect_success 'allow deleting an invalid remote ref' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
rm -f testrepo/.git/objects/??/* &&
git push testrepo :refs/heads/master &&
(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)
@@ -594,7 +616,7 @@ test_expect_success 'allow deleting an invalid remote ref' '
'
test_expect_success 'pushing valid refs triggers post-receive and post-update hooks' '
- mk_test_with_hooks heads/master heads/next &&
+ mk_test_with_hooks testrepo heads/master heads/next &&
orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
newmaster=$(git show-ref -s --verify refs/heads/master) &&
orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&
@@ -630,7 +652,7 @@ test_expect_success 'pushing valid refs triggers post-receive and post-update ho
'
test_expect_success 'deleting dangling ref triggers hooks with correct args' '
- mk_test_with_hooks heads/master &&
+ mk_test_with_hooks testrepo heads/master &&
rm -f testrepo/.git/objects/??/* &&
git push testrepo :refs/heads/master &&
(
@@ -659,7 +681,7 @@ test_expect_success 'deleting dangling ref triggers hooks with correct args' '
'
test_expect_success 'deletion of a non-existent ref is not fed to post-receive and post-update hooks' '
- mk_test_with_hooks heads/master &&
+ mk_test_with_hooks testrepo heads/master &&
orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
newmaster=$(git show-ref -s --verify refs/heads/master) &&
git push testrepo master :refs/heads/nonexistent &&
@@ -691,7 +713,7 @@ test_expect_success 'deletion of a non-existent ref is not fed to post-receive a
'
test_expect_success 'deletion of a non-existent ref alone does trigger post-receive and post-update hooks' '
- mk_test_with_hooks heads/master &&
+ mk_test_with_hooks testrepo heads/master &&
git push testrepo :refs/heads/nonexistent &&
(
cd testrepo/.git &&
@@ -711,7 +733,7 @@ test_expect_success 'deletion of a non-existent ref alone does trigger post-rece
'
test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks with correct input' '
- mk_test_with_hooks heads/master heads/next heads/pu &&
+ mk_test_with_hooks testrepo heads/master heads/next heads/pu &&
orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
newmaster=$(git show-ref -s --verify refs/heads/master) &&
orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&
@@ -757,14 +779,14 @@ test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks w
'
test_expect_success 'allow deleting a ref using --delete' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
(cd testrepo && git config receive.denyDeleteCurrent warn) &&
git push testrepo --delete master &&
(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)
'
test_expect_success 'allow deleting a tag using --delete' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
git tag -a -m dummy_message deltag heads/master &&
git push testrepo --tags &&
(cd testrepo && git rev-parse --verify -q refs/tags/deltag) &&
@@ -773,17 +795,17 @@ test_expect_success 'allow deleting a tag using --delete' '
'
test_expect_success 'push --delete without args aborts' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
test_must_fail git push testrepo --delete
'
test_expect_success 'push --delete refuses src:dest refspecs' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
test_must_fail git push testrepo --delete master:foo
'
test_expect_success 'warn on push to HEAD of non-bare repository' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
(
cd testrepo &&
git checkout master &&
@@ -794,7 +816,7 @@ test_expect_success 'warn on push to HEAD of non-bare repository' '
'
test_expect_success 'deny push to HEAD of non-bare repository' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
(
cd testrepo &&
git checkout master &&
@@ -804,7 +826,7 @@ test_expect_success 'deny push to HEAD of non-bare repository' '
'
test_expect_success 'allow push to HEAD of bare repository (bare)' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
(
cd testrepo &&
git checkout master &&
@@ -816,7 +838,7 @@ test_expect_success 'allow push to HEAD of bare repository (bare)' '
'
test_expect_success 'allow push to HEAD of non-bare repository (config)' '
- mk_test heads/master &&
+ mk_test testrepo heads/master &&
(
cd testrepo &&
git checkout master &&
@@ -827,63 +849,63 @@ test_expect_success 'allow push to HEAD of non-bare repository (config)' '
'
test_expect_success 'fetch with branches' '
- mk_empty &&
+ mk_empty testrepo &&
git branch second $the_first_commit &&
git checkout second &&
echo ".." > testrepo/.git/branches/branch1 &&
(
cd testrepo &&
git fetch branch1 &&
- r=$(git show-ref -s --verify refs/heads/branch1) &&
- test "z$r" = "z$the_commit" &&
- test 1 = $(git for-each-ref refs/heads | wc -l)
+ echo "$the_commit commit refs/heads/branch1" >expect &&
+ git for-each-ref refs/heads >actual &&
+ test_cmp expect actual
) &&
git checkout master
'
test_expect_success 'fetch with branches containing #' '
- mk_empty &&
+ mk_empty testrepo &&
echo "..#second" > testrepo/.git/branches/branch2 &&
(
cd testrepo &&
git fetch branch2 &&
- r=$(git show-ref -s --verify refs/heads/branch2) &&
- test "z$r" = "z$the_first_commit" &&
- test 1 = $(git for-each-ref refs/heads | wc -l)
+ echo "$the_first_commit commit refs/heads/branch2" >expect &&
+ git for-each-ref refs/heads >actual &&
+ test_cmp expect actual
) &&
git checkout master
'
test_expect_success 'push with branches' '
- mk_empty &&
+ mk_empty testrepo &&
git checkout second &&
echo "testrepo" > .git/branches/branch1 &&
git push branch1 &&
(
cd testrepo &&
- r=$(git show-ref -s --verify refs/heads/master) &&
- test "z$r" = "z$the_first_commit" &&
- test 1 = $(git for-each-ref refs/heads | wc -l)
+ echo "$the_first_commit commit refs/heads/master" >expect &&
+ git for-each-ref refs/heads >actual &&
+ test_cmp expect actual
)
'
test_expect_success 'push with branches containing #' '
- mk_empty &&
+ mk_empty testrepo &&
echo "testrepo#branch3" > .git/branches/branch2 &&
git push branch2 &&
(
cd testrepo &&
- r=$(git show-ref -s --verify refs/heads/branch3) &&
- test "z$r" = "z$the_first_commit" &&
- test 1 = $(git for-each-ref refs/heads | wc -l)
+ echo "$the_first_commit commit refs/heads/branch3" >expect &&
+ git for-each-ref refs/heads >actual &&
+ test_cmp expect actual
) &&
git checkout master
'
test_expect_success 'push into aliased refs (consistent)' '
- mk_test heads/master &&
- mk_child child1 &&
- mk_child child2 &&
+ mk_test testrepo heads/master &&
+ mk_child testrepo child1 &&
+ mk_child testrepo child2 &&
(
cd child1 &&
git branch foo &&
@@ -903,9 +925,9 @@ test_expect_success 'push into aliased refs (consistent)' '
'
test_expect_success 'push into aliased refs (inconsistent)' '
- mk_test heads/master &&
- mk_child child1 &&
- mk_child child2 &&
+ mk_test testrepo heads/master &&
+ mk_child testrepo child1 &&
+ mk_child testrepo child2 &&
(
cd child1 &&
git branch foo &&
@@ -930,9 +952,9 @@ test_expect_success 'push into aliased refs (inconsistent)' '
'
test_expect_success 'push requires --force to update lightweight tag' '
- mk_test heads/master &&
- mk_child child1 &&
- mk_child child2 &&
+ mk_test testrepo heads/master &&
+ mk_child testrepo child1 &&
+ mk_child testrepo child2 &&
(
cd child1 &&
git tag Tag &&
@@ -951,28 +973,28 @@ test_expect_success 'push requires --force to update lightweight tag' '
'
test_expect_success 'push --porcelain' '
- mk_empty &&
+ mk_empty testrepo &&
echo >.git/foo "To testrepo" &&
echo >>.git/foo "* refs/heads/master:refs/remotes/origin/master [new branch]" &&
echo >>.git/foo "Done" &&
git push >.git/bar --porcelain testrepo refs/heads/master:refs/remotes/origin/master &&
(
cd testrepo &&
- r=$(git show-ref -s --verify refs/remotes/origin/master) &&
- test "z$r" = "z$the_commit" &&
- test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+ echo "$the_commit commit refs/remotes/origin/master" >expect &&
+ git for-each-ref refs/remotes/origin >actual &&
+ test_cmp expect actual
) &&
test_cmp .git/foo .git/bar
'
test_expect_success 'push --porcelain bad url' '
- mk_empty &&
+ mk_empty testrepo &&
test_must_fail git push >.git/bar --porcelain asdfasdfasd refs/heads/master:refs/remotes/origin/master &&
test_must_fail grep -q Done .git/bar
'
test_expect_success 'push --porcelain rejected' '
- mk_empty &&
+ mk_empty testrepo &&
git push testrepo refs/heads/master:refs/remotes/origin/master &&
(cd testrepo &&
git reset --hard origin/master^
@@ -986,7 +1008,7 @@ test_expect_success 'push --porcelain rejected' '
'
test_expect_success 'push --porcelain --dry-run rejected' '
- mk_empty &&
+ mk_empty testrepo &&
git push testrepo refs/heads/master:refs/remotes/origin/master &&
(cd testrepo &&
git reset --hard origin/master
@@ -1001,25 +1023,25 @@ test_expect_success 'push --porcelain --dry-run rejected' '
'
test_expect_success 'push --prune' '
- mk_test heads/master heads/second heads/foo heads/bar &&
- git push --prune testrepo &&
- check_push_result $the_commit heads/master &&
- check_push_result $the_first_commit heads/second &&
- ! check_push_result $the_first_commit heads/foo heads/bar
+ mk_test testrepo heads/master heads/second heads/foo heads/bar &&
+ git push --prune testrepo : &&
+ check_push_result testrepo $the_commit heads/master &&
+ check_push_result testrepo $the_first_commit heads/second &&
+ ! check_push_result testrepo $the_first_commit heads/foo heads/bar
'
test_expect_success 'push --prune refspec' '
- mk_test tmp/master tmp/second tmp/foo tmp/bar &&
+ mk_test testrepo tmp/master tmp/second tmp/foo tmp/bar &&
git push --prune testrepo "refs/heads/*:refs/tmp/*" &&
- check_push_result $the_commit tmp/master &&
- check_push_result $the_first_commit tmp/second &&
- ! check_push_result $the_first_commit tmp/foo tmp/bar
+ check_push_result testrepo $the_commit tmp/master &&
+ check_push_result testrepo $the_first_commit tmp/second &&
+ ! check_push_result testrepo $the_first_commit tmp/foo tmp/bar
'
for configsection in transfer receive
do
test_expect_success "push to update a ref hidden by $configsection.hiderefs" '
- mk_test heads/master hidden/one hidden/two hidden/three &&
+ mk_test testrepo heads/master hidden/one hidden/two hidden/three &&
(
cd testrepo &&
git config $configsection.hiderefs refs/hidden
@@ -1027,20 +1049,144 @@ do
# push to unhidden ref succeeds normally
git push testrepo master:refs/heads/master &&
- check_push_result $the_commit heads/master &&
+ check_push_result testrepo $the_commit heads/master &&
# push to update a hidden ref should fail
test_must_fail git push testrepo master:refs/hidden/one &&
- check_push_result $the_first_commit hidden/one &&
+ check_push_result testrepo $the_first_commit hidden/one &&
# push to delete a hidden ref should fail
test_must_fail git push testrepo :refs/hidden/two &&
- check_push_result $the_first_commit hidden/two &&
+ check_push_result testrepo $the_first_commit hidden/two &&
# idempotent push to update a hidden ref should fail
test_must_fail git push testrepo $the_first_commit:refs/hidden/three &&
- check_push_result $the_first_commit hidden/three
+ check_push_result testrepo $the_first_commit hidden/three
'
done
+test_expect_success 'fetch exact SHA1' '
+ mk_test testrepo heads/master hidden/one &&
+ git push testrepo master:refs/hidden/one &&
+ (
+ cd testrepo &&
+ git config transfer.hiderefs refs/hidden
+ ) &&
+ check_push_result testrepo $the_commit hidden/one &&
+
+ mk_child testrepo child &&
+ (
+ cd child &&
+
+ # make sure $the_commit does not exist here
+ git repack -a -d &&
+ git prune &&
+ test_must_fail git cat-file -t $the_commit &&
+
+ # fetching the hidden object should fail by default
+ test_must_fail git fetch -v ../testrepo $the_commit:refs/heads/copy &&
+ test_must_fail git rev-parse --verify refs/heads/copy &&
+
+ # the server side can allow it to succeed
+ (
+ cd ../testrepo &&
+ git config uploadpack.allowtipsha1inwant true
+ ) &&
+
+ git fetch -v ../testrepo $the_commit:refs/heads/copy &&
+ result=$(git rev-parse --verify refs/heads/copy) &&
+ test "$the_commit" = "$result"
+ )
+'
+
+test_expect_success 'fetch follows tags by default' '
+ mk_test testrepo heads/master &&
+ rm -fr src dst &&
+ git init src &&
+ (
+ cd src &&
+ git pull ../testrepo master &&
+ git tag -m "annotated" tag &&
+ git for-each-ref >tmp1 &&
+ (
+ cat tmp1
+ sed -n "s|refs/heads/master$|refs/remotes/origin/master|p" tmp1
+ ) |
+ sort -k 3 >../expect
+ ) &&
+ git init dst &&
+ (
+ cd dst &&
+ git remote add origin ../src &&
+ git config branch.master.remote origin &&
+ git config branch.master.merge refs/heads/master &&
+ git pull &&
+ git for-each-ref >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push does not follow tags by default' '
+ mk_test testrepo heads/master &&
+ rm -fr src dst &&
+ git init src &&
+ git init --bare dst &&
+ (
+ cd src &&
+ git pull ../testrepo master &&
+ git tag -m "annotated" tag &&
+ git checkout -b another &&
+ git commit --allow-empty -m "future commit" &&
+ git tag -m "future" future &&
+ git checkout master &&
+ git for-each-ref refs/heads/master >../expect &&
+ git push ../dst master
+ ) &&
+ (
+ cd dst &&
+ git for-each-ref >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push --follow-tag only pushes relevant tags' '
+ mk_test testrepo heads/master &&
+ rm -fr src dst &&
+ git init src &&
+ git init --bare dst &&
+ (
+ cd src &&
+ git pull ../testrepo master &&
+ git tag -m "annotated" tag &&
+ git checkout -b another &&
+ git commit --allow-empty -m "future commit" &&
+ git tag -m "future" future &&
+ git checkout master &&
+ git for-each-ref refs/heads/master refs/tags/tag >../expect
+ git push --follow-tag ../dst master
+ ) &&
+ (
+ cd dst &&
+ git for-each-ref >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push --no-thin must produce non-thin pack' '
+ cat >>path1 <<\EOF &&
+keep base version of path1 big enough, compared to the new changes
+later, in order to pass size heuristics in
+builtin/pack-objects.c:try_delta()
+EOF
+ git commit -am initial &&
+ git init no-thin &&
+ git --git-dir=no-thin/.git config receive.unpacklimit 0 &&
+ git push no-thin/.git refs/heads/master:refs/heads/foo &&
+ echo modified >> path1 &&
+ git commit -am modified &&
+ git repack -adf &&
+ rcvpck="git receive-pack --reject-thin-pack-for-testing" &&
+ git push --no-thin --receive-pack="$rcvpck" no-thin/.git refs/heads/master:refs/heads/foo
+'
+
test_done
diff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh
index e2ad260..12a5dfb 100755
--- a/t/t5517-push-mirror.sh
+++ b/t/t5517-push-mirror.sh
@@ -256,7 +256,7 @@ test_expect_success 'remote.foo.mirror=no has no effect' '
git branch keep master &&
git push --mirror up &&
git branch -D keep &&
- git push up
+ git push up :
) &&
(
cd mirror &&
diff --git a/t/t5519-push-alternates.sh b/t/t5519-push-alternates.sh
index c00c9b0..11fcd37 100755
--- a/t/t5519-push-alternates.sh
+++ b/t/t5519-push-alternates.sh
@@ -40,7 +40,7 @@ test_expect_success 'alice works and pushes' '
cd alice-work &&
echo more >file &&
git commit -a -m second &&
- git push ../alice-pub
+ git push ../alice-pub :
)
'
@@ -57,7 +57,7 @@ test_expect_success 'bob fetches from alice, works and pushes' '
git pull ../alice-pub master &&
echo more bob >file &&
git commit -a -m third &&
- git push ../bob-pub
+ git push ../bob-pub :
) &&
# Check that the second commit by Alice is not sent
@@ -86,7 +86,7 @@ test_expect_success 'alice works and pushes again' '
cd alice-work &&
echo more alice >file &&
git commit -a -m fourth &&
- git push ../alice-pub
+ git push ../alice-pub :
)
'
@@ -99,7 +99,7 @@ test_expect_success 'bob works and pushes' '
cd bob-work &&
echo yet more bob >file &&
git commit -a -m fifth &&
- git push ../bob-pub
+ git push ../bob-pub :
)
'
@@ -115,7 +115,7 @@ test_expect_success 'alice works and pushes yet again' '
git commit -a -m sixth.2 &&
echo more and more alice >>file &&
git commit -a -m sixth.3 &&
- git push ../alice-pub
+ git push ../alice-pub :
)
'
@@ -136,7 +136,7 @@ test_expect_success 'bob works and pushes again' '
git hash-object -t commit -w commit &&
echo even more bob >file &&
git commit -a -m seventh &&
- git push ../bob-pub
+ git push ../bob-pub :
)
'
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 35304b4..227d293 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -57,6 +57,35 @@ test_expect_success 'pulling into void does not overwrite untracked files' '
)
'
+test_expect_success 'pulling into void does not overwrite staged files' '
+ git init cloned-staged-colliding &&
+ (
+ cd cloned-staged-colliding &&
+ echo "alternate content" >file &&
+ git add file &&
+ test_must_fail git pull .. master &&
+ echo "alternate content" >expect &&
+ test_cmp expect file &&
+ git cat-file blob :file >file.index &&
+ test_cmp expect file.index
+ )
+'
+
+
+test_expect_success 'pulling into void does not remove new staged files' '
+ git init cloned-staged-new &&
+ (
+ cd cloned-staged-new &&
+ echo "new tracked file" >newfile &&
+ git add newfile &&
+ git pull .. master &&
+ echo "new tracked file" >expect &&
+ test_cmp expect newfile &&
+ git cat-file blob :newfile >newfile.index &&
+ test_cmp expect newfile.index
+ )
+'
+
test_expect_success 'test . as a remote' '
git branch copy master &&
@@ -96,8 +125,7 @@ test_expect_success '--rebase' '
'
test_expect_success 'pull.rebase' '
git reset --hard before-rebase &&
- git config --bool pull.rebase true &&
- test_when_finished "git config --unset pull.rebase" &&
+ test_config pull.rebase true &&
git pull . copy &&
test $(git rev-parse HEAD^) = $(git rev-parse copy) &&
test new = $(git show HEAD:file2)
@@ -105,8 +133,7 @@ test_expect_success 'pull.rebase' '
test_expect_success 'branch.to-rebase.rebase' '
git reset --hard before-rebase &&
- git config --bool branch.to-rebase.rebase true &&
- test_when_finished "git config --unset branch.to-rebase.rebase" &&
+ test_config branch.to-rebase.rebase true &&
git pull . copy &&
test $(git rev-parse HEAD^) = $(git rev-parse copy) &&
test new = $(git show HEAD:file2)
@@ -114,15 +141,102 @@ test_expect_success 'branch.to-rebase.rebase' '
test_expect_success 'branch.to-rebase.rebase should override pull.rebase' '
git reset --hard before-rebase &&
- git config --bool pull.rebase true &&
- test_when_finished "git config --unset pull.rebase" &&
- git config --bool branch.to-rebase.rebase false &&
- test_when_finished "git config --unset branch.to-rebase.rebase" &&
+ test_config pull.rebase true &&
+ test_config branch.to-rebase.rebase false &&
git pull . copy &&
test $(git rev-parse HEAD^) != $(git rev-parse copy) &&
test new = $(git show HEAD:file2)
'
+# add a feature branch, keep-merge, that is merged into master, so the
+# test can try preserving the merge commit (or not) with various
+# --rebase flags/pull.rebase settings.
+test_expect_success 'preserve merge setup' '
+ git reset --hard before-rebase &&
+ git checkout -b keep-merge second^ &&
+ test_commit file3 &&
+ git checkout to-rebase &&
+ git merge keep-merge &&
+ git tag before-preserve-rebase
+'
+
+test_expect_success 'pull.rebase=false create a new merge commit' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase false &&
+ git pull . copy &&
+ test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) &&
+ test $(git rev-parse HEAD^2) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success 'pull.rebase=true flattens keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase true &&
+ git pull . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success 'pull.rebase=1 is treated as true and flattens keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase 1 &&
+ git pull . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success 'pull.rebase=preserve rebases and merges keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase preserve &&
+ git pull . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge)
+'
+
+test_expect_success 'pull.rebase=invalid fails' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase invalid &&
+ ! git pull . copy
+'
+
+test_expect_success '--rebase=false create a new merge commit' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase true &&
+ git pull --rebase=false . copy &&
+ test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) &&
+ test $(git rev-parse HEAD^2) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success '--rebase=true rebases and flattens keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase preserve &&
+ git pull --rebase=true . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success '--rebase=preserve rebases and merges keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase true &&
+ git pull --rebase=preserve . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge)
+'
+
+test_expect_success '--rebase=invalid fails' '
+ git reset --hard before-preserve-rebase &&
+ ! git pull --rebase=invalid . copy
+'
+
+test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase preserve &&
+ git pull --rebase . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
test_expect_success '--rebase with rebased upstream' '
git remote add -f me . &&
@@ -171,9 +285,9 @@ test_expect_success 'pull --rebase dies early with dirty working directory' '
git update-ref refs/remotes/me/copy copy^ &&
COPY=$(git rev-parse --verify me/copy) &&
git rebase --onto $COPY copy &&
- git config branch.to-rebase.remote me &&
- git config branch.to-rebase.merge refs/heads/copy &&
- git config branch.to-rebase.rebase true &&
+ test_config branch.to-rebase.remote me &&
+ test_config branch.to-rebase.merge refs/heads/copy &&
+ test_config branch.to-rebase.rebase true &&
echo dirty >> file &&
git add file &&
test_must_fail git pull &&
diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index aa31abe..453aba5 100755
--- a/t/t5521-pull-options.sh
+++ b/t/t5521-pull-options.sh
@@ -15,19 +15,19 @@ test_expect_success 'git pull -q' '
mkdir clonedq &&
(cd clonedq && git init &&
git pull -q "../parent" >out 2>err &&
- test ! -s err &&
- test ! -s out)
+ test_must_be_empty err &&
+ test_must_be_empty out)
'
test_expect_success 'git pull -q --rebase' '
mkdir clonedqrb &&
(cd clonedqrb && git init &&
git pull -q --rebase "../parent" >out 2>err &&
- test ! -s err &&
- test ! -s out &&
+ test_must_be_empty err &&
+ test_must_be_empty out &&
git pull -q --rebase "../parent" >out 2>err &&
- test ! -s err &&
- test ! -s out)
+ test_must_be_empty err &&
+ test_must_be_empty out)
'
test_expect_success 'git pull' '
@@ -35,7 +35,7 @@ test_expect_success 'git pull' '
(cd cloned && git init &&
git pull "../parent" >out 2>err &&
test -s err &&
- test ! -s out)
+ test_must_be_empty out)
'
test_expect_success 'git pull --rebase' '
@@ -43,7 +43,7 @@ test_expect_success 'git pull --rebase' '
(cd clonedrb && git init &&
git pull --rebase "../parent" >out 2>err &&
test -s err &&
- test ! -s out)
+ test_must_be_empty out)
'
test_expect_success 'git pull -v' '
@@ -51,7 +51,7 @@ test_expect_success 'git pull -v' '
(cd clonedv && git init &&
git pull -v "../parent" >out 2>err &&
test -s err &&
- test ! -s out)
+ test_must_be_empty out)
'
test_expect_success 'git pull -v --rebase' '
@@ -59,22 +59,22 @@ test_expect_success 'git pull -v --rebase' '
(cd clonedvrb && git init &&
git pull -v --rebase "../parent" >out 2>err &&
test -s err &&
- test ! -s out)
+ test_must_be_empty out)
'
test_expect_success 'git pull -v -q' '
mkdir clonedvq &&
(cd clonedvq && git init &&
git pull -v -q "../parent" >out 2>err &&
- test ! -s out &&
- test ! -s err)
+ test_must_be_empty out &&
+ test_must_be_empty err)
'
test_expect_success 'git pull -q -v' '
mkdir clonedqv &&
(cd clonedqv && git init &&
git pull -q -v "../parent" >out 2>err &&
- test ! -s out &&
+ test_must_be_empty out &&
test -s err)
'
diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh
index 4736da8..6a5ac3a 100755
--- a/t/t5528-push-default.sh
+++ b/t/t5528-push-default.sh
@@ -15,17 +15,19 @@ test_expect_success 'setup bare remotes' '
# $1 = local revision
# $2 = remote revision (tested to be equal to the local one)
+# $3 = [optional] repo to check for actual output (repo1 by default)
check_pushed_commit () {
git log -1 --format='%h %s' "$1" >expect &&
- git --git-dir=repo1 log -1 --format='%h %s' "$2" >actual &&
+ git --git-dir="${3:-repo1}" log -1 --format='%h %s' "$2" >actual &&
test_cmp expect actual
}
# $1 = push.default value
# $2 = expected target branch for the push
+# $3 = [optional] repo to check for actual output (repo1 by default)
test_push_success () {
git -c push.default="$1" push &&
- check_pushed_commit HEAD "$2"
+ check_pushed_commit HEAD "$2" "$3"
}
# $1 = push.default value
@@ -37,6 +39,26 @@ test_push_failure () {
test_cmp expect actual
}
+# $1 = success or failure
+# $2 = push.default value
+# $3 = branch to check for actual output (master or foo)
+# $4 = [optional] switch to triangular workflow
+test_pushdefault_workflow () {
+ workflow=central
+ pushdefault=parent1
+ if test -n "${4-}"; then
+ workflow=triangular
+ pushdefault=parent2
+ fi
+ test_expect_success "push.default = $2 $1 in $workflow workflows" "
+ test_config branch.master.remote parent1 &&
+ test_config branch.master.merge refs/heads/foo &&
+ test_config remote.pushdefault $pushdefault &&
+ test_commit commit-for-$2${4+-triangular} &&
+ test_push_$1 $2 $3 ${4+repo2}
+ "
+}
+
test_expect_success '"upstream" pushes to configured upstream' '
git checkout master &&
test_config branch.master.remote parent1 &&
@@ -48,7 +70,6 @@ test_expect_success '"upstream" pushes to configured upstream' '
test_expect_success '"upstream" does not push on unconfigured remote' '
git checkout master &&
test_unconfig branch.master.remote &&
- test_config push.default upstream &&
test_commit three &&
test_push_failure upstream
'
@@ -57,7 +78,6 @@ test_expect_success '"upstream" does not push on unconfigured branch' '
git checkout master &&
test_config branch.master.remote parent1 &&
test_unconfig branch.master.merge &&
- test_config push.default upstream
test_commit four &&
test_push_failure upstream
'
@@ -115,4 +135,41 @@ test_expect_success 'push to existing branch, upstream configured with different
test_cmp expect-other-name actual-other-name
'
+# We are on 'master', which integrates with 'foo' from parent1
+# remote (set in test_pushdefault_workflow helper). Push to
+# parent1 in centralized, and push to parent2 in triangular workflow.
+# The parent1 repository has 'master' and 'foo' branches, while
+# the parent2 repository has only 'master' branch.
+#
+# test_pushdefault_workflow() arguments:
+# $1 = success or failure
+# $2 = push.default value
+# $3 = branch to check for actual output (master or foo)
+# $4 = [optional] switch to triangular workflow
+
+# update parent1's master (which is not our upstream)
+test_pushdefault_workflow success current master
+
+# update parent1's foo (which is our upstream)
+test_pushdefault_workflow success upstream foo
+
+# upsream is foo which is not the name of the current branch
+test_pushdefault_workflow failure simple master
+
+# master and foo are updated
+test_pushdefault_workflow success matching master
+
+# master is updated
+test_pushdefault_workflow success current master triangular
+
+# upstream mode cannot be used in triangular
+test_pushdefault_workflow failure upstream foo triangular
+
+# in triangular, 'simple' works as 'current' and update the branch
+# with the same name.
+test_pushdefault_workflow success simple master triangular
+
+# master is updated (parent2 does not have foo)
+test_pushdefault_workflow success matching master triangular
+
test_done
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
index 1947c28..8c16e04 100755
--- a/t/t5531-deep-submodule-push.sh
+++ b/t/t5531-deep-submodule-push.sh
@@ -16,6 +16,7 @@ test_expect_success setup '
(
cd gar/bage &&
git init &&
+ git config push.default matching &&
>junk &&
git add junk &&
git commit -m "Initial junk"
diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh
new file mode 100755
index 0000000..ba20d83
--- /dev/null
+++ b/t/t5533-push-cas.sh
@@ -0,0 +1,189 @@
+#!/bin/sh
+
+test_description='compare & swap push force/delete safety'
+
+. ./test-lib.sh
+
+setup_srcdst_basic () {
+ rm -fr src dst &&
+ git clone --no-local . src &&
+ git clone --no-local src dst &&
+ (
+ cd src && git checkout HEAD^0
+ )
+}
+
+test_expect_success setup '
+ : create template repository
+ test_commit A &&
+ test_commit B &&
+ test_commit C
+'
+
+test_expect_success 'push to update (protected)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ test_must_fail git push --force-with-lease=master:master origin master
+ ) &&
+ git ls-remote . refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (protected, forced)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ git push --force --force-with-lease=master:master origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (protected, tracking)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git checkout master &&
+ test_commit D &&
+ git checkout HEAD^0
+ ) &&
+ git ls-remote src refs/heads/master >expect &&
+ (
+ cd dst &&
+ test_commit E &&
+ git ls-remote . refs/remotes/origin/master >expect &&
+ test_must_fail git push --force-with-lease=master origin master &&
+ git ls-remote . refs/remotes/origin/master >actual &&
+ test_cmp expect actual
+ ) &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (protected, tracking, forced)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git checkout master &&
+ test_commit D &&
+ git checkout HEAD^0
+ ) &&
+ (
+ cd dst &&
+ test_commit E &&
+ git ls-remote . refs/remotes/origin/master >expect &&
+ git push --force --force-with-lease=master origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (allowed)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ git push --force-with-lease=master:master^ origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (allowed, tracking)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ git push --force-with-lease=master origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (allowed even though no-ff)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git reset --hard HEAD^ &&
+ test_commit D &&
+ git push --force-with-lease=master origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to delete (protected)' '
+ setup_srcdst_basic &&
+ git ls-remote src refs/heads/master >expect &&
+ (
+ cd dst &&
+ test_must_fail git push --force-with-lease=master:master^ origin :master
+ ) &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to delete (protected, forced)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git push --force --force-with-lease=master:master^ origin :master
+ ) &&
+ >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to delete (allowed)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git push --force-with-lease=master origin :master
+ ) &&
+ >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cover everything with default force-with-lease (protected)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git branch naster master^
+ )
+ git ls-remote src refs/heads/\* >expect &&
+ (
+ cd dst &&
+ test_must_fail git push --force-with-lease origin master master:naster
+ ) &&
+ git ls-remote src refs/heads/\* >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cover everything with default force-with-lease (allowed)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git branch naster master^
+ )
+ (
+ cd dst &&
+ git fetch &&
+ git push --force-with-lease origin master master:naster
+ ) &&
+ git ls-remote dst refs/heads/master |
+ sed -e "s/master/naster/" >expect &&
+ git ls-remote src refs/heads/naster >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh
index 8a9dc85..470ac54 100755
--- a/t/t5541-http-push.sh
+++ b/t/t5541-http-push.sh
@@ -153,7 +153,7 @@ test_expect_success 'used receive-pack service' '
'
test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \
- "$ROOT_PATH"/test_repo_clone master
+ "$ROOT_PATH"/test_repo_clone master success
test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper' '
# create a dissimilarly-named remote ref so that git is unable to match the
@@ -181,8 +181,7 @@ test_expect_success 'push (chunked)' '
git checkout master &&
test_commit commit path3 &&
HEAD=$(git rev-parse --verify HEAD) &&
- git config http.postbuffer 4 &&
- test_when_finished "git config --unset http.postbuffer" &&
+ test_config http.postbuffer 4 &&
git push -v -v origin $BRANCH 2>err &&
grep "POST git-receive-pack (chunked)" err &&
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh
index 80d20c8..f7d0f14 100755
--- a/t/t5550-http-fetch.sh
+++ b/t/t5550-http-fetch.sh
@@ -13,6 +13,7 @@ LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}
start_httpd
test_expect_success 'setup repository' '
+ git config push.default matching &&
echo content1 >file &&
git add file &&
git commit -m one
diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh
index 47eb769..8196af1 100755
--- a/t/t5551-http-fetch.sh
+++ b/t/t5551-http-fetch.sh
@@ -13,6 +13,7 @@ LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5551'}
start_httpd
test_expect_success 'setup repository' '
+ git config push.default matching &&
echo content >file &&
git add file &&
git commit -m one
@@ -162,6 +163,46 @@ test_expect_success 'invalid Content-Type rejected' '
grep "not valid:" actual
'
+test_expect_success 'create namespaced refs' '
+ test_commit namespaced &&
+ git push public HEAD:refs/namespaces/ns/refs/heads/master &&
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+ symbolic-ref refs/namespaces/ns/HEAD refs/namespaces/ns/refs/heads/master
+'
+
+test_expect_success 'smart clone respects namespace' '
+ git clone "$HTTPD_URL/smart_namespace/repo.git" ns-smart &&
+ echo namespaced >expect &&
+ git --git-dir=ns-smart/.git log -1 --format=%s >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'dumb clone via http-backend respects namespace' '
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+ config http.getanyfile true &&
+ GIT_SMART_HTTP=0 git clone \
+ "$HTTPD_URL/smart_namespace/repo.git" ns-dumb &&
+ echo namespaced >expect &&
+ git --git-dir=ns-dumb/.git log -1 --format=%s >actual &&
+ test_cmp expect actual
+'
+
+cat >cookies.txt <<EOF
+127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue
+EOF
+cat >expect_cookies.txt <<EOF
+
+127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue
+127.0.0.1 FALSE /smart_cookies/repo.git/info/ FALSE 0 name value
+EOF
+test_expect_success 'cookies stored in http.cookiefile when http.savecookies set' '
+ git config http.cookiefile cookies.txt &&
+ git config http.savecookies true &&
+ git ls-remote $HTTPD_URL/smart_cookies/repo.git master &&
+ tail -3 cookies.txt > cookies_tail.txt
+ test_cmp expect_cookies.txt cookies_tail.txt
+'
+
test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
@@ -184,13 +225,17 @@ test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
# now assign tags to all the dangling commits we created above
tag=$("$PERL_PATH" -e "print \"bla\" x 30") &&
- sed -e "s/^:\(.\+\) \(.\+\)$/\2 refs\/tags\/$tag-\1/" <marks >>packed-refs
+ sed -e "s|^:\([^ ]*\) \(.*\)$|\2 refs/tags/$tag-\1|" <marks >>packed-refs
)
'
test_expect_success EXPENSIVE 'clone the 50,000 tag repo to check OS command line overflow' '
git clone $HTTPD_URL/smart/repo.git too-many-refs 2>err &&
- test_line_count = 0 err
+ test_line_count = 0 err &&
+ (
+ cd too-many-refs &&
+ test $(git for-each-ref refs/tags | wc -l) = 50000
+ )
'
stop_httpd
diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh
index ef98d95..9be9ae3 100755
--- a/t/t5560-http-backend-noserver.sh
+++ b/t/t5560-http-backend-noserver.sh
@@ -5,7 +5,7 @@ test_description='test git-http-backend-noserver'
HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY"
-test_have_prereq MINGW && export GREP_OPTIONS=-U
+test_have_prereq GREP_STRIPS_CR && export GREP_OPTIONS=-U
run_backend() {
echo "$2" |
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
index a3a4e47..f01edff 100755
--- a/t/t5570-git-daemon.sh
+++ b/t/t5570-git-daemon.sh
@@ -8,6 +8,7 @@ LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570}
start_git_daemon
test_expect_success 'setup repository' '
+ git config push.default matching &&
echo content >file &&
git add file &&
git commit -m one
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 67869b4..0629149 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -280,4 +280,9 @@ test_expect_success 'clone checking out a tag' '
test_cmp fetch.expected fetch.actual
'
+test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' '
+ cp -R src "foo:bar" &&
+ git clone "./foo:bar" foobar
+'
+
test_done
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index c47d450..6537911 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -54,11 +54,14 @@ cd "$base_dir"
rm -f "$U.D"
-test_expect_success 'cloning with reference (no -l -s)' \
-'GIT_DEBUG_SEND_PACK=3 git clone --reference B "file://$(pwd)/A" D 3>"$U.D"'
+test_expect_success 'cloning with reference (no -l -s)' '
+ GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D
+'
-test_expect_success 'fetched no objects' \
-'! grep "^want" "$U.D"'
+test_expect_success 'fetched no objects' '
+ test -s "$U.D" &&
+ ! grep " want" "$U.D"
+'
cd "$base_dir"
@@ -173,12 +176,26 @@ test_expect_success 'fetch with incomplete alternates' '
(
cd K &&
git remote add J "file://$base_dir/J" &&
- GIT_DEBUG_SEND_PACK=3 git fetch J 3>"$U.K"
+ GIT_TRACE_PACKET=$U.K git fetch J
) &&
master_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/master) &&
- ! grep "^want $master_object" "$U.K" &&
+ test -s "$U.K" &&
+ ! grep " want $master_object" "$U.K" &&
tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) &&
- ! grep "^want $tag_object" "$U.K"
+ ! grep " want $tag_object" "$U.K"
+'
+
+test_expect_success 'clone using repo with gitfile as a reference' '
+ git clone --separate-git-dir=L A M &&
+ git clone --reference=M A N &&
+ echo "$base_dir/L/objects" >expected &&
+ test_cmp expected "$base_dir/N/.git/objects/info/alternates"
+'
+
+test_expect_success 'clone using repo pointed at by gitfile as reference' '
+ git clone --reference=M/.git A O &&
+ echo "$base_dir/L/objects" >expected &&
+ test_cmp expected "$base_dir/O/.git/objects/info/alternates"
'
test_done
diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh
index 02cb024..85cadfa 100755
--- a/t/t5702-clone-options.sh
+++ b/t/t5702-clone-options.sh
@@ -22,7 +22,7 @@ test_expect_success 'clone -o' '
test_expect_success 'redirected clone' '
git clone "file://$(pwd)/parent" clone-redirected >out 2>err &&
- test ! -s err
+ test_must_be_empty err
'
test_expect_success 'redirected clone -v' '
diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh
index aa04529..5a6e49d 100755
--- a/t/t5710-info-alternate.sh
+++ b/t/t5710-info-alternate.sh
@@ -58,7 +58,7 @@ test_expect_success 'creating too deep nesting' \
git clone -l -s D E &&
git clone -l -s E F &&
git clone -l -s F G &&
-git clone -l -s G H'
+git clone --bare -l -s G H'
test_expect_success 'invalidity of deepest repository' \
'cd H && {
diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh
index f387027..613f69a 100755
--- a/t/t5801-remote-helpers.sh
+++ b/t/t5801-remote-helpers.sh
@@ -6,11 +6,7 @@
test_description='Test remote-helper import and export commands'
. ./test-lib.sh
-
-if ! type "${BASH-bash}" >/dev/null 2>&1; then
- skip_all='skipping remote-testgit tests, bash not available'
- test_done
-fi
+. "$TEST_DIRECTORY"/lib-gpg.sh
compare_refs() {
git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
@@ -100,39 +96,28 @@ test_expect_failure 'push new branch with old:new refspec' '
test_expect_success 'cloning without refspec' '
GIT_REMOTE_TESTGIT_REFSPEC="" \
- git clone "testgit::${PWD}/server" local2 &&
+ git clone "testgit::${PWD}/server" local2 2>error &&
+ grep "This remote helper should implement refspec capability" error &&
compare_refs local2 HEAD server HEAD
'
test_expect_success 'pulling without refspecs' '
(cd local2 &&
git reset --hard &&
- GIT_REMOTE_TESTGIT_REFSPEC="" git pull) &&
+ GIT_REMOTE_TESTGIT_REFSPEC="" git pull 2>../error) &&
+ grep "This remote helper should implement refspec capability" error &&
compare_refs local2 HEAD server HEAD
'
-test_expect_failure 'pushing without refspecs' '
+test_expect_success 'pushing without refspecs' '
test_when_finished "(cd local2 && git reset --hard origin)" &&
(cd local2 &&
echo content >>file &&
git commit -a -m ten &&
- GIT_REMOTE_TESTGIT_REFSPEC="" git push) &&
- compare_refs local2 HEAD server HEAD
-'
-
-test_expect_success 'pulling with straight refspec' '
- (cd local2 &&
- GIT_REMOTE_TESTGIT_REFSPEC="*:*" git pull) &&
- compare_refs local2 HEAD server HEAD
-'
-
-test_expect_failure 'pushing with straight refspec' '
- test_when_finished "(cd local2 && git reset --hard origin)" &&
- (cd local2 &&
- echo content >>file &&
- git commit -a -m eleven &&
- GIT_REMOTE_TESTGIT_REFSPEC="*:*" git push) &&
- compare_refs local2 HEAD server HEAD
+ GIT_REMOTE_TESTGIT_REFSPEC="" &&
+ export GIT_REMOTE_TESTGIT_REFSPEC &&
+ test_must_fail git push 2>../error) &&
+ grep "remote-helper doesn.t support push; refspec needed" error
'
test_expect_success 'pulling without marks' '
@@ -166,4 +151,92 @@ test_expect_success 'push ref with existing object' '
compare_refs local dup server dup
'
+test_expect_success GPG 'push signed tag' '
+ (cd local &&
+ git checkout master &&
+ git tag -s -m signed-tag signed-tag &&
+ git push origin signed-tag
+ ) &&
+ compare_refs local signed-tag^{} server signed-tag^{} &&
+ test_must_fail compare_refs local signed-tag server signed-tag
+'
+
+test_expect_success GPG 'push signed tag with signed-tags capability' '
+ (cd local &&
+ git checkout master &&
+ git tag -s -m signed-tag signed-tag-2 &&
+ GIT_REMOTE_TESTGIT_SIGNED_TAGS=1 git push origin signed-tag-2
+ ) &&
+ compare_refs local signed-tag-2 server signed-tag-2
+'
+
+test_expect_success 'push update refs' '
+ (cd local &&
+ git checkout -b update master &&
+ echo update >>file &&
+ git commit -a -m update &&
+ git push origin update &&
+ git rev-parse --verify remotes/origin/update >expect &&
+ git rev-parse --verify testgit/origin/heads/update >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'push update refs disabled by no-private-update' '
+ (cd local &&
+ echo more-update >>file &&
+ git commit -a -m more-update &&
+ git rev-parse --verify testgit/origin/heads/update >expect &&
+ GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE=t git push origin update &&
+ git rev-parse --verify testgit/origin/heads/update >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'push update refs failure' '
+ (cd local &&
+ git checkout update &&
+ echo "update fail" >>file &&
+ git commit -a -m "update fail" &&
+ git rev-parse --verify testgit/origin/heads/update >expect &&
+ GIT_REMOTE_TESTGIT_PUSH_ERROR="non-fast forward" &&
+ export GIT_REMOTE_TESTGIT_PUSH_ERROR &&
+ test_expect_code 1 git push origin update &&
+ git rev-parse --verify testgit/origin/heads/update >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'proper failure checks for fetching' '
+ (GIT_REMOTE_TESTGIT_FAILURE=1 &&
+ export GIT_REMOTE_TESTGIT_FAILURE &&
+ cd local &&
+ test_must_fail git fetch 2> error &&
+ cat error &&
+ grep -q "Error while running fast-import" error
+ )
+'
+
+test_expect_success 'proper failure checks for pushing' '
+ (GIT_REMOTE_TESTGIT_FAILURE=1 &&
+ export GIT_REMOTE_TESTGIT_FAILURE &&
+ cd local &&
+ test_must_fail git push --all
+ )
+'
+
+test_expect_success 'push messages' '
+ (cd local &&
+ git checkout -b new_branch master &&
+ echo new >>file &&
+ git commit -a -m new &&
+ git push origin new_branch &&
+ git fetch origin &&
+ echo new >>file &&
+ git commit -a -m new &&
+ git push origin new_branch 2> msg &&
+ ! grep "\[new branch\]" msg
+ )
+'
+
test_done
diff --git a/t/t5802-connect-helper.sh b/t/t5802-connect-helper.sh
new file mode 100755
index 0000000..878faf2
--- /dev/null
+++ b/t/t5802-connect-helper.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+test_description='ext::cmd remote "connect" helper'
+. ./test-lib.sh
+
+test_expect_success setup '
+ test_tick &&
+ git commit --allow-empty -m initial &&
+ test_tick &&
+ git commit --allow-empty -m second &&
+ test_tick &&
+ git commit --allow-empty -m third &&
+ test_tick &&
+ git tag -a -m "tip three" three &&
+
+ test_tick &&
+ git commit --allow-empty -m fourth
+'
+
+test_expect_success clone '
+ cmd=$(echo "echo >&2 ext::sh invoked && %S .." | sed -e "s/ /% /g") &&
+ git clone "ext::sh -c %S% ." dst &&
+ git for-each-ref refs/heads/ refs/tags/ >expect &&
+ (
+ cd dst &&
+ git config remote.origin.url "ext::sh -c $cmd" &&
+ git for-each-ref refs/heads/ refs/tags/
+ ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'update following tag' '
+ test_tick &&
+ git commit --allow-empty -m fifth &&
+ test_tick &&
+ git tag -a -m "tip five" five &&
+ git for-each-ref refs/heads/ refs/tags/ >expect &&
+ (
+ cd dst &&
+ git pull &&
+ git for-each-ref refs/heads/ refs/tags/ >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'update backfilled tag' '
+ test_tick &&
+ git commit --allow-empty -m sixth &&
+ test_tick &&
+ git tag -a -m "tip two" two three^1 &&
+ git for-each-ref refs/heads/ refs/tags/ >expect &&
+ (
+ cd dst &&
+ git pull &&
+ git for-each-ref refs/heads/ refs/tags/ >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'update backfilled tag without primary transfer' '
+ test_tick &&
+ git tag -a -m "tip one " one two^1 &&
+ git for-each-ref refs/heads/ refs/tags/ >expect &&
+ (
+ cd dst &&
+ git pull &&
+ git for-each-ref refs/heads/ refs/tags/ >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index fb07536..43ad772 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -39,25 +39,25 @@ test_bisection_diff()
date >path0
git update-index --add path0
save_tag tree git write-tree
-on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
-on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
-on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
-on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1
-on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2
-on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0
-on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0
-on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1
-on_committer_date "1971-08-16 00:00:08" save_tag b2 unique_commit b2 tree -p b1
-on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b2 tree -p b2
-on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
-on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2
-on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1
-on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2
-on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
-on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
-on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4
-on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3
-on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4
+on_committer_date "00:00" hide_error save_tag root unique_commit root tree
+on_committer_date "00:01" save_tag l0 unique_commit l0 tree -p root
+on_committer_date "00:02" save_tag l1 unique_commit l1 tree -p l0
+on_committer_date "00:03" save_tag l2 unique_commit l2 tree -p l1
+on_committer_date "00:04" save_tag a0 unique_commit a0 tree -p l2
+on_committer_date "00:05" save_tag a1 unique_commit a1 tree -p a0
+on_committer_date "00:06" save_tag b1 unique_commit b1 tree -p a0
+on_committer_date "00:07" save_tag c1 unique_commit c1 tree -p b1
+on_committer_date "00:08" save_tag b2 unique_commit b2 tree -p b1
+on_committer_date "00:09" save_tag b3 unique_commit b2 tree -p b2
+on_committer_date "00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
+on_committer_date "00:11" save_tag c3 unique_commit c3 tree -p c2
+on_committer_date "00:12" save_tag a2 unique_commit a2 tree -p a1
+on_committer_date "00:13" save_tag a3 unique_commit a3 tree -p a2
+on_committer_date "00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
+on_committer_date "00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
+on_committer_date "00:16" save_tag l3 unique_commit l3 tree -p a4
+on_committer_date "00:17" save_tag l4 unique_commit l4 tree -p l3
+on_committer_date "00:18" save_tag l5 unique_commit l5 tree -p l4
git update-ref HEAD $(tag l5)
@@ -90,29 +90,29 @@ git update-ref HEAD $(tag l5)
# F
-on_committer_date "1971-08-16 00:00:00" hide_error save_tag F unique_commit F tree
-on_committer_date "1971-08-16 00:00:01" save_tag e8 unique_commit e8 tree -p F
-on_committer_date "1971-08-16 00:00:02" save_tag e7 unique_commit e7 tree -p e8
-on_committer_date "1971-08-16 00:00:03" save_tag e6 unique_commit e6 tree -p e7
-on_committer_date "1971-08-16 00:00:04" save_tag e5 unique_commit e5 tree -p e6
-on_committer_date "1971-08-16 00:00:05" save_tag f4 unique_commit f4 tree -p F
-on_committer_date "1971-08-16 00:00:06" save_tag f3 unique_commit f3 tree -p f4
-on_committer_date "1971-08-16 00:00:07" save_tag f2 unique_commit f2 tree -p f3
-on_committer_date "1971-08-16 00:00:08" save_tag f1 unique_commit f1 tree -p f2
-on_committer_date "1971-08-16 00:00:09" save_tag e4 unique_commit e4 tree -p e5
-on_committer_date "1971-08-16 00:00:10" save_tag e3 unique_commit e3 tree -p e4
-on_committer_date "1971-08-16 00:00:11" save_tag e2 unique_commit e2 tree -p e3
-on_committer_date "1971-08-16 00:00:12" save_tag e1 unique_commit e1 tree -p e2
-on_committer_date "1971-08-16 00:00:13" save_tag E unique_commit E tree -p e1 -p f1
-
-on_committer_date "1971-08-16 00:00:00" hide_error save_tag U unique_commit U tree
-on_committer_date "1971-08-16 00:00:01" save_tag u0 unique_commit u0 tree -p U
-on_committer_date "1971-08-16 00:00:01" save_tag u1 unique_commit u1 tree -p u0
-on_committer_date "1971-08-16 00:00:02" save_tag u2 unique_commit u2 tree -p u0
-on_committer_date "1971-08-16 00:00:03" save_tag u3 unique_commit u3 tree -p u0
-on_committer_date "1971-08-16 00:00:04" save_tag u4 unique_commit u4 tree -p u0
-on_committer_date "1971-08-16 00:00:05" save_tag u5 unique_commit u5 tree -p u0
-on_committer_date "1971-08-16 00:00:06" save_tag V unique_commit V tree -p u1 -p u2 -p u3 -p u4 -p u5
+on_committer_date "00:00" hide_error save_tag F unique_commit F tree
+on_committer_date "00:01" save_tag e8 unique_commit e8 tree -p F
+on_committer_date "00:02" save_tag e7 unique_commit e7 tree -p e8
+on_committer_date "00:03" save_tag e6 unique_commit e6 tree -p e7
+on_committer_date "00:04" save_tag e5 unique_commit e5 tree -p e6
+on_committer_date "00:05" save_tag f4 unique_commit f4 tree -p F
+on_committer_date "00:06" save_tag f3 unique_commit f3 tree -p f4
+on_committer_date "00:07" save_tag f2 unique_commit f2 tree -p f3
+on_committer_date "00:08" save_tag f1 unique_commit f1 tree -p f2
+on_committer_date "00:09" save_tag e4 unique_commit e4 tree -p e5
+on_committer_date "00:10" save_tag e3 unique_commit e3 tree -p e4
+on_committer_date "00:11" save_tag e2 unique_commit e2 tree -p e3
+on_committer_date "00:12" save_tag e1 unique_commit e1 tree -p e2
+on_committer_date "00:13" save_tag E unique_commit E tree -p e1 -p f1
+
+on_committer_date "00:00" hide_error save_tag U unique_commit U tree
+on_committer_date "00:01" save_tag u0 unique_commit u0 tree -p U
+on_committer_date "00:01" save_tag u1 unique_commit u1 tree -p u0
+on_committer_date "00:02" save_tag u2 unique_commit u2 tree -p u0
+on_committer_date "00:03" save_tag u3 unique_commit u3 tree -p u0
+on_committer_date "00:04" save_tag u4 unique_commit u4 tree -p u0
+on_committer_date "00:05" save_tag u5 unique_commit u5 tree -p u0
+on_committer_date "00:06" save_tag V unique_commit V tree -p u1 -p u2 -p u3 -p u4 -p u5
test_sequence()
{
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index e4c52b0..24d1836 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -16,39 +16,34 @@ list_duplicates()
date >path0
git update-index --add path0
save_tag tree git write-tree
-on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
-on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
-on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
-on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1
-on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2
-on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0
-on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0
-on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1
-on_committer_date "1971-08-16 00:00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1
-on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b3 tree -p b2
-on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
-on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2
-on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1
-on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2
-on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
-on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
-on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4
-on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3
-on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4
-on_committer_date "1971-08-16 00:00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3
-on_committer_date "1971-08-16 00:00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4
-on_committer_date "1971-08-16 00:00:21" hide_error save_tag alt_root unique_commit alt_root tree
-on_committer_date "1971-08-16 00:00:22" save_tag r0 unique_commit r0 tree -p alt_root
-on_committer_date "1971-08-16 00:00:23" save_tag r1 unique_commit r1 tree -p r0
-on_committer_date "1971-08-16 00:00:24" save_tag l5r1 unique_commit l5r1 tree -p l5 -p r1
-on_committer_date "1971-08-16 00:00:25" save_tag r1l5 unique_commit r1l5 tree -p r1 -p l5
+on_dates "00:00" "00:00" hide_error save_tag root unique_commit root tree
+on_dates "00:01" "00:01" save_tag l0 unique_commit l0 tree -p root
+on_dates "00:02" "00:02" save_tag l1 unique_commit l1 tree -p l0
+on_dates "00:03" "00:03" save_tag l2 unique_commit l2 tree -p l1
+on_dates "00:04" "00:04" save_tag a0 unique_commit a0 tree -p l2
+on_dates "00:05" "00:05" save_tag a1 unique_commit a1 tree -p a0
+on_dates "00:06" "00:06" save_tag b1 unique_commit b1 tree -p a0
+on_dates "00:07" "00:07" save_tag c1 unique_commit c1 tree -p b1
+on_dates "00:08" "00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1
+on_dates "00:09" "00:09" save_tag b3 unique_commit b3 tree -p b2
+on_dates "00:10" "00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
+on_dates "00:11" "00:11" save_tag c3 unique_commit c3 tree -p c2
+on_dates "00:12" "00:00" save_tag a2 unique_commit a2 tree -p a1
+on_dates "00:13" "00:01" save_tag a3 unique_commit a3 tree -p a2
+on_dates "00:14" "00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
+on_dates "00:15" "00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
+on_dates "00:16" "00:16" save_tag l3 unique_commit l3 tree -p a4
+on_dates "00:17" "00:17" save_tag l4 unique_commit l4 tree -p l3
+on_dates "00:18" "00:18" save_tag l5 unique_commit l5 tree -p l4
+on_dates "00:19" "00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3
+on_dates "00:20" "00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4
+on_dates "00:21" "00:21" hide_error save_tag alt_root unique_commit alt_root tree
+on_dates "00:22" "00:22" save_tag r0 unique_commit r0 tree -p alt_root
+on_dates "00:23" "00:23" save_tag r1 unique_commit r1 tree -p r0
+on_dates "00:24" "00:24" save_tag l5r1 unique_commit l5r1 tree -p l5 -p r1
+on_dates "00:25" "00:25" save_tag r1l5 unique_commit r1l5 tree -p r1 -p l5
-#
-# note: as of 20/6, it isn't possible to create duplicate parents, so this
-# can't be tested.
-#
-#on_committer_date "1971-08-16 00:00:20" save_tag m3 unique_commit m3 tree -p c3 -p a4 -p c3
hide_error save_tag e1 as_author e@example.com unique_commit e1 tree
save_tag e2 as_author e@example.com unique_commit e2 tree -p e1
save_tag f1 as_author f@example.com unique_commit f1 tree -p e1
@@ -105,6 +100,50 @@ l0
root
EOF
+test_output_expect_success 'simple date order' 'git rev-list --date-order HEAD' <<EOF
+l5
+l4
+l3
+a4
+b4
+a3
+a2
+c3
+c2
+b3
+b2
+c1
+b1
+a1
+a0
+l2
+l1
+l0
+root
+EOF
+
+test_output_expect_success 'simple author-date order' 'git rev-list --author-date-order HEAD' <<EOF
+l5
+l4
+l3
+a4
+b4
+c3
+c2
+b3
+b2
+c1
+b1
+a3
+a2
+a1
+a0
+l2
+l1
+l0
+root
+EOF
+
test_output_expect_success 'two diamonds topo order (g6)' 'git rev-list --topo-order g4' <<EOF
g4
h2
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 3fc3b74..9874403 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -1,20 +1,45 @@
#!/bin/sh
+# Copyright (c) 2009 Jens Lehmann
+# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests)
+
test_description='git rev-list --pretty=format test'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
test_tick
+# String "added" in German
+# (translated with Google Translate),
+# encoded in UTF-8, used as a commit log message below.
+added=$(printf "added (hinzugef\303\274gt) foo")
+added_iso88591=$(echo "$added" | iconv -f utf-8 -t iso8859-1)
+# same but "changed"
+changed=$(printf "changed (ge\303\244ndert) foo")
+changed_iso88591=$(echo "$changed" | iconv -f utf-8 -t iso8859-1)
+
test_expect_success 'setup' '
-touch foo && git add foo && git commit -m "added foo" &&
- echo changed >foo && git commit -a -m "changed foo"
+ : >foo &&
+ git add foo &&
+ git config i18n.commitEncoding iso8859-1 &&
+ git commit -m "$added_iso88591" &&
+ head1=$(git rev-parse --verify HEAD) &&
+ head1_short=$(git rev-parse --verify --short $head1) &&
+ tree1=$(git rev-parse --verify HEAD:) &&
+ tree1_short=$(git rev-parse --verify --short $tree1) &&
+ echo "$changed" > foo &&
+ git commit -a -m "$changed_iso88591" &&
+ head2=$(git rev-parse --verify HEAD) &&
+ head2_short=$(git rev-parse --verify --short $head2) &&
+ tree2=$(git rev-parse --verify HEAD:) &&
+ tree2_short=$(git rev-parse --verify --short $tree2)
+ git config --unset i18n.commitEncoding
'
-# usage: test_format name format_string <expected_output
+# usage: test_format name format_string [failure] <expected_output
test_format () {
cat >expect.$1
- test_expect_success "format $1" "
+ test_expect_${3:-success} "format $1" "
git rev-list --pretty=format:'$2' master >output.$1 &&
test_cmp expect.$1 output.$1
"
@@ -32,49 +57,49 @@ has_no_color () {
test_cmp expect "$1"
}
-test_format percent %%h <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format percent %%h <<EOF
+commit $head2
%h
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
%h
EOF
-test_format hash %H%n%h <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-131a310eb913d107dd3c09a65d1651175898735d
-131a310
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-86c75cf
+test_format hash %H%n%h <<EOF
+commit $head2
+$head2
+$head2_short
+commit $head1
+$head1
+$head1_short
EOF
-test_format tree %T%n%t <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-fe722612f26da5064c32ca3843aa154bdb0b08a0
-fe72261
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-4d5fcadc293a348e88f777dc0920f11e7d71441c
-4d5fcad
+test_format tree %T%n%t <<EOF
+commit $head2
+$tree2
+$tree2_short
+commit $head1
+$tree1
+$tree1_short
EOF
-test_format parents %P%n%p <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-86c75cf
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format parents %P%n%p <<EOF
+commit $head2
+$head1
+$head1_short
+commit $head1
EOF
# we don't test relative here
-test_format author %an%n%ae%n%ad%n%aD%n%at <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format author %an%n%ae%n%ad%n%aD%n%at <<EOF
+commit $head2
A U Thor
author@example.com
Thu Apr 7 15:13:13 2005 -0700
Thu, 7 Apr 2005 15:13:13 -0700
1112911993
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
A U Thor
author@example.com
Thu Apr 7 15:13:13 2005 -0700
@@ -82,14 +107,14 @@ Thu, 7 Apr 2005 15:13:13 -0700
1112911993
EOF
-test_format committer %cn%n%ce%n%cd%n%cD%n%ct <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format committer %cn%n%ce%n%cd%n%cD%n%ct <<EOF
+commit $head2
C O Mitter
committer@example.com
Thu Apr 7 15:13:13 2005 -0700
Thu, 7 Apr 2005 15:13:13 -0700
1112911993
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
C O Mitter
committer@example.com
Thu Apr 7 15:13:13 2005 -0700
@@ -97,43 +122,45 @@ Thu, 7 Apr 2005 15:13:13 -0700
1112911993
EOF
-test_format encoding %e <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format encoding %e <<EOF
+commit $head2
+iso8859-1
+commit $head1
+iso8859-1
EOF
-test_format subject %s <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-changed foo
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-added foo
+test_format subject %s <<EOF
+commit $head2
+$changed
+commit $head1
+$added
EOF
-test_format body %b <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+test_format body %b <<EOF
+commit $head2
+commit $head1
EOF
-test_format raw-body %B <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
-changed foo
+test_format raw-body %B <<EOF
+commit $head2
+$changed
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-added foo
+commit $head1
+$added
EOF
-test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<EOF
+commit $head2
foobarbazxyzzy
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
foobarbazxyzzy
EOF
-test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<'EOF'
-commit 131a310eb913d107dd3c09a65d1651175898735d
+test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<EOF
+commit $head2
foo
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+commit $head1
foo
EOF
@@ -179,46 +206,71 @@ test_expect_success '%C(auto) respects --color=auto (stdout not tty)' '
)
'
-cat >commit-msg <<'EOF'
+iconv -f utf-8 -t iso8859-1 > commit-msg <<EOF
Test printing of complex bodies
This commit message is much longer than the others,
and it will be encoded in iso8859-1. We should therefore
include an iso8859 character: ¡bueno!
EOF
+
test_expect_success 'setup complex body' '
-git config i18n.commitencoding iso8859-1 &&
- echo change2 >foo && git commit -a -F commit-msg
+ git config i18n.commitencoding iso8859-1 &&
+ echo change2 >foo && git commit -a -F commit-msg &&
+ head3=$(git rev-parse --verify HEAD) &&
+ head3_short=$(git rev-parse --short $head3)
'
-test_format complex-encoding %e <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+test_format complex-encoding %e <<EOF
+commit $head3
+iso8859-1
+commit $head2
+iso8859-1
+commit $head1
iso8859-1
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
EOF
-test_format complex-subject %s <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+test_format complex-subject %s <<EOF
+commit $head3
Test printing of complex bodies
-commit 131a310eb913d107dd3c09a65d1651175898735d
-changed foo
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
-added foo
+commit $head2
+$changed_iso88591
+commit $head1
+$added_iso88591
EOF
-test_format complex-body %b <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
-This commit message is much longer than the others,
-and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+test_expect_success 'prepare expected messages (for test %b)' '
+ cat <<-EOF >expected.utf-8 &&
+ commit $head3
+ This commit message is much longer than the others,
+ and it will be encoded in iso8859-1. We should therefore
+ include an iso8859 character: ¡bueno!
+
+ commit $head2
+ commit $head1
+ EOF
+ iconv -f utf-8 -t iso8859-1 expected.utf-8 >expected.iso8859-1
+'
+
+test_format complex-body %b <expected.iso8859-1
-commit 131a310eb913d107dd3c09a65d1651175898735d
-commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
+# Git uses i18n.commitEncoding if no i18n.logOutputEncoding set
+# so unset i18n.commitEncoding to test encoding conversion
+git config --unset i18n.commitEncoding
+
+test_format complex-subject-commitencoding-unset %s <<EOF
+commit $head3
+Test printing of complex bodies
+commit $head2
+$changed
+commit $head1
+$added
EOF
+test_format complex-body-commitencoding-unset %b <expected.utf-8
+
test_expect_success '%x00 shows NUL' '
- echo >expect commit f58db70b055c5718631e5c61528b28b12090cdea &&
+ echo >expect commit $head3 &&
echo >>expect fooQbar &&
git rev-list -1 --format=foo%x00bar HEAD >actual.nul &&
nul_to_q <actual.nul >actual &&
@@ -265,12 +317,12 @@ test_expect_success 'add LF before non-empty (2)' '
test_expect_success 'add SP before non-empty (1)' '
git show -s --pretty=format:"%s% bThanks" HEAD^^ >actual &&
- test $(wc -w <actual) = 2
+ test $(wc -w <actual) = 3
'
test_expect_success 'add SP before non-empty (2)' '
git show -s --pretty=format:"%s% sThanks" HEAD^^ >actual &&
- test $(wc -w <actual) = 4
+ test $(wc -w <actual) = 6
'
test_expect_success '--abbrev' '
diff --git a/t/t6012-rev-list-simplify.sh b/t/t6012-rev-list-simplify.sh
index 839ad97..fde5e71 100755
--- a/t/t6012-rev-list-simplify.sh
+++ b/t/t6012-rev-list-simplify.sh
@@ -14,21 +14,24 @@ unnote () {
test_expect_success setup '
echo "Hi there" >file &&
- git add file &&
- test_tick && git commit -m "Initial file" &&
+ echo "initial" >lost &&
+ git add file lost &&
+ test_tick && git commit -m "Initial file and lost" &&
note A &&
git branch other-branch &&
echo "Hello" >file &&
- git add file &&
- test_tick && git commit -m "Modified file" &&
+ echo "second" >lost &&
+ git add file lost &&
+ test_tick && git commit -m "Modified file and lost" &&
note B &&
git checkout other-branch &&
echo "Hello" >file &&
- git add file &&
+ >lost &&
+ git add file lost &&
test_tick && git commit -m "Modified the file identically" &&
note C &&
@@ -37,7 +40,9 @@ test_expect_success setup '
test_tick && git commit -m "Add another file" &&
note D &&
- test_tick && git merge -m "merge" master &&
+ test_tick &&
+ test_must_fail git merge -m "merge" master &&
+ >lost && git commit -a -m "merge" &&
note E &&
echo "Yet another" >elif &&
@@ -56,19 +61,37 @@ test_expect_success setup '
echo "Final change" >file &&
test_tick && git commit -a -m "Final change" &&
- note I
+ note I &&
+
+ git symbolic-ref HEAD refs/heads/unrelated &&
+ git rm -f "*" &&
+ echo "Unrelated branch" >side &&
+ git add side &&
+ test_tick && git commit -m "Side root" &&
+ note J &&
+
+ git checkout master &&
+ test_tick && git merge -m "Coolest" unrelated &&
+ note K &&
+
+ echo "Immaterial" >elif &&
+ git add elif &&
+ test_tick && git commit -m "Last" &&
+ note L
'
FMT='tformat:%P %H | %s'
-check_result () {
+check_outcome () {
+ outcome=$1
+ shift
for c in $1
do
echo "$c"
done >expect &&
shift &&
param="$*" &&
- test_expect_success "log $param" '
+ test_expect_$outcome "log $param" '
git log --pretty="$FMT" --parents $param |
unnote >actual &&
sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual &&
@@ -79,13 +102,35 @@ check_result () {
'
}
-check_result 'I H G F E D C B A' --full-history
-check_result 'I H E C B A' --full-history -- file
-check_result 'I H E C B A' --full-history --topo-order -- file
-check_result 'I H E C B A' --full-history --date-order -- file
+check_result () {
+ check_outcome success "$@"
+}
+
+check_result 'L K J I H G F E D C B A' --full-history
+check_result 'K I H E C B A' --full-history -- file
+check_result 'K I H E C B A' --full-history --topo-order -- file
+check_result 'K I H E C B A' --full-history --date-order -- file
check_result 'I E C B A' --simplify-merges -- file
check_result 'I B A' -- file
check_result 'I B A' --topo-order -- file
check_result 'H' --first-parent -- another-file
+check_result 'E C B A' --full-history E -- lost
+test_expect_success 'full history simplification without parent' '
+ printf "%s\n" E C B A >expect &&
+ git log --pretty="$FMT" --full-history E -- lost |
+ unnote >actual &&
+ sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual &&
+ test_cmp expect check || {
+ cat actual
+ false
+ }
+'
+
+test_expect_success '--full-diff is not affected by --parents' '
+ git log -p --pretty="%H" --full-diff -- file >expected &&
+ git log -p --pretty="%H" --full-diff --parents -- file >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t6019-rev-list-ancestry-path.sh b/t/t6019-rev-list-ancestry-path.sh
index 39b4cb0..dabebae 100755
--- a/t/t6019-rev-list-ancestry-path.sh
+++ b/t/t6019-rev-list-ancestry-path.sh
@@ -13,6 +13,13 @@ test_description='--ancestry-path'
#
# D..M -- M.t == M
# --ancestry-path D..M -- M.t == M
+#
+# F...I == F G H I
+# --ancestry-path F...I == F H I
+#
+# G..M -- G.t == [nothing - was dropped in "-s ours" merge L]
+# --ancestry-path G..M -- G.t == L
+# --ancestry-path --simplify-merges G^..M -- G.t == G L
. ./test-lib.sh
@@ -63,13 +70,52 @@ test_expect_success 'rev-list D..M -- M.t' '
test_cmp expect actual
'
-test_expect_success 'rev-list --ancestry-patch D..M -- M.t' '
+test_expect_success 'rev-list --ancestry-path D..M -- M.t' '
echo M >expect &&
git rev-list --ancestry-path --format=%s D..M -- M.t |
sed -e "/^commit /d" >actual &&
test_cmp expect actual
'
+test_expect_success 'rev-list F...I' '
+ for c in F G H I; do echo $c; done >expect &&
+ git rev-list --format=%s F...I |
+ sed -e "/^commit /d" |
+ sort >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --ancestry-path F...I' '
+ for c in F H I; do echo $c; done >expect &&
+ git rev-list --ancestry-path --format=%s F...I |
+ sed -e "/^commit /d" |
+ sort >actual &&
+ test_cmp expect actual
+'
+
+# G.t is dropped in an "-s ours" merge
+test_expect_success 'rev-list G..M -- G.t' '
+ >expect &&
+ git rev-list --format=%s G..M -- G.t |
+ sed -e "/^commit /d" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --ancestry-path G..M -- G.t' '
+ echo L >expect &&
+ git rev-list --ancestry-path --format=%s G..M -- G.t |
+ sed -e "/^commit /d" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --ancestry-path --simplify-merges G^..M -- G.t' '
+ for c in G L; do echo $c; done >expect &&
+ git rev-list --ancestry-path --simplify-merges --format=%s G^..M -- G.t |
+ sed -e "/^commit /d" |
+ sort >actual &&
+ test_cmp expect actual
+'
+
# b---bc
# / \ /
# a X
diff --git a/t/t6021-merge-criss-cross.sh b/t/t6021-merge-criss-cross.sh
index 331b9b0..d15b313 100755
--- a/t/t6021-merge-criss-cross.sh
+++ b/t/t6021-merge-criss-cross.sh
@@ -3,7 +3,7 @@
# Copyright (c) 2005 Fredrik Kuivinen
#
-# See http://marc.theaimsgroup.com/?l=git&m=111463358500362&w=2 for a
+# See http://marc.info/?l=git&m=111463358500362&w=2 for a
# nice description of what this is about.
diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh
index c680f78..a89dfbe 100755
--- a/t/t6022-merge-rename.sh
+++ b/t/t6022-merge-rename.sh
@@ -259,7 +259,7 @@ test_expect_success 'setup for rename + d/f conflicts' '
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
echo foo >dir/file-in-the-way &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
echo 11 >>sub/file &&
echo more >>dir/file-in-the-way &&
@@ -439,7 +439,7 @@ test_expect_success 'setup both rename source and destination involved in D/F co
mkdir one &&
echo stuff >one/file &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git mv one/file destdir &&
git commit -m "Renamed to destdir" &&
@@ -479,7 +479,7 @@ test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '
echo stuff >one/file &&
echo other >two/file &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git rm -rf one &&
git mv two/file one &&
@@ -539,7 +539,7 @@ test_expect_success 'setup rename of one file to two, with directories in the wa
echo stuff >original &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
mkdir two &&
>two/file &&
@@ -583,7 +583,7 @@ test_expect_success 'setup rename one file to two; directories moving out of the
mkdir one two &&
touch one/file two/file &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git rm -rf one &&
git mv original one &&
@@ -618,7 +618,7 @@ test_expect_success 'setup avoid unnecessary update, normal rename' '
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git mv original rename &&
echo 11 >>rename &&
@@ -649,7 +649,7 @@ test_expect_success 'setup to test avoiding unnecessary update, with D/F conflic
mkdir df &&
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git mv df/file temp &&
rm -rf df &&
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 8bf99e1..064f5ce 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -164,7 +164,7 @@ test_expect_success 'bisect start: existing ".git/BISECT_START" not modified if
cp .git/BISECT_START saved &&
test_must_fail git bisect start $HASH4 foo -- &&
git branch > branch.output &&
- test_i18ngrep "* (no branch)" branch.output > /dev/null &&
+ test_i18ngrep "* (no branch, bisect started on other)" branch.output > /dev/null &&
test_cmp saved .git/BISECT_START
'
test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' '
@@ -741,4 +741,42 @@ test_expect_success 'bisect: demonstrate identification of damage boundary' "
git bisect reset
"
+cat > expected.bisect-log <<EOF
+# bad: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>.
+# good: [7b7f204a749c3125d5224ed61ea2ae1187ad046f] Add <2: A new day for git> into <hello>.
+git bisect start '32a594a3fdac2d57cf6d02987e30eec68511498c' '7b7f204a749c3125d5224ed61ea2ae1187ad046f'
+# good: [3de952f2416b6084f557ec417709eac740c6818c] Add <3: Another new day for git> into <hello>.
+git bisect good 3de952f2416b6084f557ec417709eac740c6818c
+# first bad commit: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>.
+EOF
+
+test_expect_success 'bisect log: successfull result' '
+ git bisect reset &&
+ git bisect start $HASH4 $HASH2 &&
+ git bisect good &&
+ git bisect log >bisect-log.txt &&
+ test_cmp expected.bisect-log bisect-log.txt &&
+ git bisect reset
+'
+
+cat > expected.bisect-skip-log <<EOF
+# bad: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>.
+# good: [7b7f204a749c3125d5224ed61ea2ae1187ad046f] Add <2: A new day for git> into <hello>.
+git bisect start '32a594a3fdac2d57cf6d02987e30eec68511498c' '7b7f204a749c3125d5224ed61ea2ae1187ad046f'
+# skip: [3de952f2416b6084f557ec417709eac740c6818c] Add <3: Another new day for git> into <hello>.
+git bisect skip 3de952f2416b6084f557ec417709eac740c6818c
+# only skipped commits left to test
+# possible first bad commit: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>.
+# possible first bad commit: [3de952f2416b6084f557ec417709eac740c6818c] Add <3: Another new day for git> into <hello>.
+EOF
+
+test_expect_success 'bisect log: only skip commits left' '
+ git bisect reset &&
+ git bisect start $HASH4 $HASH2 &&
+ test_must_fail git bisect skip &&
+ git bisect log >bisect-skip-log.txt &&
+ test_cmp expected.bisect-skip-log bisect-skip-log.txt &&
+ git bisect reset
+'
+
test_done
diff --git a/t/t6035-merge-dir-to-symlink.sh b/t/t6035-merge-dir-to-symlink.sh
index 2599ae5..9324ea4 100755
--- a/t/t6035-merge-dir-to-symlink.sh
+++ b/t/t6035-merge-dir-to-symlink.sh
@@ -3,7 +3,7 @@
test_description='merging when a directory was replaced with a symlink'
. ./test-lib.sh
-test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink' '
+test_expect_success 'create a commit where dir a/b changed to symlink' '
mkdir -p a/b/c a/b-2/c &&
> a/b/c/d &&
> a/b-2/c/d &&
@@ -12,12 +12,12 @@ test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink'
git commit -m base &&
git tag start &&
rm -rf a/b &&
- ln -s b-2 a/b &&
git add -A &&
+ test_ln_s_add b-2 a/b &&
git commit -m "dir to symlink"
'
-test_expect_success SYMLINKS 'checkout does not clobber untracked symlink' '
+test_expect_success 'checkout does not clobber untracked symlink' '
git checkout HEAD^0 &&
git reset --hard master &&
git rm --cached a/b &&
@@ -25,7 +25,7 @@ test_expect_success SYMLINKS 'checkout does not clobber untracked symlink' '
test_must_fail git checkout start^0
'
-test_expect_success SYMLINKS 'a/b-2/c/d is kept when clobbering symlink b' '
+test_expect_success 'a/b-2/c/d is kept when clobbering symlink b' '
git checkout HEAD^0 &&
git reset --hard master &&
git rm --cached a/b &&
@@ -34,14 +34,14 @@ test_expect_success SYMLINKS 'a/b-2/c/d is kept when clobbering symlink b' '
test -f a/b-2/c/d
'
-test_expect_success SYMLINKS 'checkout should not have deleted a/b-2/c/d' '
+test_expect_success 'checkout should not have deleted a/b-2/c/d' '
git checkout HEAD^0 &&
git reset --hard master &&
git checkout start^0 &&
test -f a/b-2/c/d
'
-test_expect_success SYMLINKS 'setup for merge test' '
+test_expect_success 'setup for merge test' '
git reset --hard &&
test -f a/b-2/c/d &&
echo x > a/x &&
@@ -50,39 +50,51 @@ test_expect_success SYMLINKS 'setup for merge test' '
git tag baseline
'
-test_expect_success SYMLINKS 'Handle D/F conflict, do not lose a/b-2/c/d in merge (resolve)' '
+test_expect_success 'Handle D/F conflict, do not lose a/b-2/c/d in merge (resolve)' '
git reset --hard &&
git checkout baseline^0 &&
git merge -s resolve master &&
- test -h a/b &&
test -f a/b-2/c/d
'
-test_expect_success SYMLINKS 'Handle D/F conflict, do not lose a/b-2/c/d in merge (recursive)' '
+test_expect_success SYMLINKS 'a/b was resolved as symlink' '
+ test -h a/b
+'
+
+test_expect_success 'Handle D/F conflict, do not lose a/b-2/c/d in merge (recursive)' '
git reset --hard &&
git checkout baseline^0 &&
git merge -s recursive master &&
- test -h a/b &&
test -f a/b-2/c/d
'
-test_expect_success SYMLINKS 'Handle F/D conflict, do not lose a/b-2/c/d in merge (resolve)' '
+test_expect_success SYMLINKS 'a/b was resolved as symlink' '
+ test -h a/b
+'
+
+test_expect_success 'Handle F/D conflict, do not lose a/b-2/c/d in merge (resolve)' '
git reset --hard &&
git checkout master^0 &&
git merge -s resolve baseline^0 &&
- test -h a/b &&
test -f a/b-2/c/d
'
-test_expect_success SYMLINKS 'Handle F/D conflict, do not lose a/b-2/c/d in merge (recursive)' '
+test_expect_success SYMLINKS 'a/b was resolved as symlink' '
+ test -h a/b
+'
+
+test_expect_success 'Handle F/D conflict, do not lose a/b-2/c/d in merge (recursive)' '
git reset --hard &&
git checkout master^0 &&
git merge -s recursive baseline^0 &&
- test -h a/b &&
test -f a/b-2/c/d
'
-test_expect_failure SYMLINKS 'do not lose untracked in merge (resolve)' '
+test_expect_success SYMLINKS 'a/b was resolved as symlink' '
+ test -h a/b
+'
+
+test_expect_failure 'do not lose untracked in merge (resolve)' '
git reset --hard &&
git checkout baseline^0 &&
>a/b/c/e &&
@@ -91,7 +103,7 @@ test_expect_failure SYMLINKS 'do not lose untracked in merge (resolve)' '
test -f a/b-2/c/d
'
-test_expect_success SYMLINKS 'do not lose untracked in merge (recursive)' '
+test_expect_success 'do not lose untracked in merge (recursive)' '
git reset --hard &&
git checkout baseline^0 &&
>a/b/c/e &&
@@ -100,52 +112,61 @@ test_expect_success SYMLINKS 'do not lose untracked in merge (recursive)' '
test -f a/b-2/c/d
'
-test_expect_success SYMLINKS 'do not lose modifications in merge (resolve)' '
+test_expect_success 'do not lose modifications in merge (resolve)' '
git reset --hard &&
git checkout baseline^0 &&
echo more content >>a/b/c/d &&
test_must_fail git merge -s resolve master
'
-test_expect_success SYMLINKS 'do not lose modifications in merge (recursive)' '
+test_expect_success 'do not lose modifications in merge (recursive)' '
git reset --hard &&
git checkout baseline^0 &&
echo more content >>a/b/c/d &&
test_must_fail git merge -s recursive master
'
-test_expect_success SYMLINKS 'setup a merge where dir a/b-2 changed to symlink' '
+test_expect_success 'setup a merge where dir a/b-2 changed to symlink' '
git reset --hard &&
git checkout start^0 &&
rm -rf a/b-2 &&
- ln -s b a/b-2 &&
git add -A &&
+ test_ln_s_add b a/b-2 &&
git commit -m "dir a/b-2 to symlink" &&
git tag test2
'
-test_expect_success SYMLINKS 'merge should not have D/F conflicts (resolve)' '
+test_expect_success 'merge should not have D/F conflicts (resolve)' '
git reset --hard &&
git checkout baseline^0 &&
git merge -s resolve test2 &&
- test -h a/b-2 &&
test -f a/b/c/d
'
-test_expect_success SYMLINKS 'merge should not have D/F conflicts (recursive)' '
+test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' '
+ test -h a/b-2
+'
+
+test_expect_success 'merge should not have D/F conflicts (recursive)' '
git reset --hard &&
git checkout baseline^0 &&
git merge -s recursive test2 &&
- test -h a/b-2 &&
test -f a/b/c/d
'
-test_expect_success SYMLINKS 'merge should not have F/D conflicts (recursive)' '
+test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' '
+ test -h a/b-2
+'
+
+test_expect_success 'merge should not have F/D conflicts (recursive)' '
git reset --hard &&
git checkout -b foo test2 &&
git merge -s recursive baseline^0 &&
- test -h a/b-2 &&
test -f a/b/c/d
'
+test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' '
+ test -h a/b-2
+'
+
test_done
diff --git a/t/t6111-rev-list-treesame.sh b/t/t6111-rev-list-treesame.sh
new file mode 100755
index 0000000..88b84df
--- /dev/null
+++ b/t/t6111-rev-list-treesame.sh
@@ -0,0 +1,196 @@
+#!/bin/sh
+#
+# ,---E--. *H----------. * marks !TREESAME parent paths
+# / \ / \*
+# *A--*B---D--*F-*G---------K-*L-*M
+# \ /* \ /
+# `-C-' `-*I-*J
+#
+# A creates "file", B and F change it.
+# Odd merge G takes the old version from B.
+# I changes it, but J reverts it, so K is TREESAME to both parents.
+# H and L both change "file", and M merges those changes.
+
+test_description='TREESAME and limiting'
+
+. ./test-lib.sh
+
+note () {
+ git tag "$1"
+}
+
+unnote () {
+ git name-rev --tags --stdin | sed -e "s|$_x40 (tags/\([^)]*\))\([ ]\)|\1\2|g"
+}
+
+test_expect_success setup '
+ test_commit "Initial file" file "Hi there" A &&
+ git branch other-branch &&
+
+ test_commit "file=Hello" file "Hello" B &&
+ git branch third-branch &&
+
+ git checkout other-branch &&
+ test_commit "Added other" other "Hello" C &&
+
+ git checkout master &&
+ test_merge D other-branch &&
+
+ git checkout third-branch &&
+ test_commit "Third file" third "Nothing" E &&
+
+ git checkout master &&
+ test_commit "file=Blah" file "Blah" F &&
+
+ test_tick && git merge --no-commit third-branch &&
+ git checkout third-branch file &&
+ git commit &&
+ note G &&
+ git branch fiddler-branch &&
+
+ git checkout -b part2-branch &&
+ test_commit "file=Part 2" file "Part 2" H &&
+
+ git checkout fiddler-branch &&
+ test_commit "Bad commit" file "Silly" I &&
+
+ test_tick && git revert I && note J &&
+
+ git checkout master &&
+ test_tick && git merge --no-ff fiddler-branch &&
+ note K
+
+ test_commit "file=Part 1" file "Part 1" L &&
+
+ test_tick && test_must_fail git merge part2-branch &&
+ test_commit M file "Parts 1+2"
+'
+
+check_outcome () {
+ outcome=$1
+ shift
+
+ case "$1" in
+ *"("*)
+ FMT="%P %H | %s"
+ munge_actual="
+ s/^\([^ ]*\) \([^ ]*\) .*/(\1)\2/
+ s/ //g
+ s/()//
+ "
+ ;;
+ *)
+ FMT="%H | %s"
+ munge_actual="s/^\([^ ]*\) .*/\1/"
+ ;;
+ esac &&
+ printf "%s\n" $1 >expect &&
+ shift
+
+ param="$*" &&
+ test_expect_$outcome "log $param" '
+ git log --format="$FMT" $param |
+ unnote >actual &&
+ sed -e "$munge_actual" <actual >check &&
+ test_cmp expect check || {
+ cat actual
+ false
+ }
+ '
+}
+
+check_result () {
+ check_outcome success "$@"
+}
+
+# Odd merge G drops a change in F. Important that G is listed in all
+# except the most basic list. Achieving this means normal merge D will also be
+# shown in normal full-history, as we can't distinguish unless we do a
+# simplification pass. After simplification, D is dropped but G remains.
+# Also, merge simplification of G should not drop the parent B that the default
+# simple history follows.
+check_result 'M L K J I H G F E D C B A'
+check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FE)G (D)F (B)E (BC)D (A)C (A)B A'
+check_result 'M H L K J I G E F D C B A' --topo-order
+check_result 'M L H B A' -- file
+check_result '(LH)M (B)L (B)H (A)B A' --parents -- file
+check_result 'M L J I H G F D B A' --full-history -- file
+check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FB)G (D)F (BA)D (A)B A' --full-history --parents -- file
+check_result '(LH)M (G)H (J)L (I)J (G)I (FB)G (B)F (A)B A' --simplify-merges -- file
+check_result 'M L K G F D B A' --first-parent
+check_result 'M L G F B A' --first-parent -- file
+
+# Check that odd merge G remains shown when F is the bottom.
+check_result 'M L K J I H G E' F..M
+check_result 'M H L K J I G E' F..M --topo-order
+check_result 'M L H' F..M -- file
+check_result '(LH)M (B)L (B)H' --parents F..M -- file
+check_result 'M L J I H G' F..M --full-history -- file
+check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FB)G' F..M --full-history --parents -- file
+check_result '(LH)M (G)H (J)L (I)J (G)I (FB)G' F..M --simplify-merges -- file
+check_result 'M L K J I H G' F..M --ancestry-path
+check_result 'M L J I H G' F..M --ancestry-path -- file
+check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FE)G' F..M --ancestry-path --parents -- file
+check_result '(LH)M (G)H (J)L (I)J (G)I (FE)G' F..M --ancestry-path --simplify-merges -- file
+check_result 'M L K G' F..M --first-parent
+check_result 'M L G' F..M --first-parent -- file
+
+# Note that G is pruned when E is the bottom, even if it's the same commit list
+# If we want history since E, then we're quite happy to ignore G that took E.
+check_result 'M L K J I H G' E..M --ancestry-path
+check_result 'M L J I H' E..M --ancestry-path -- file
+check_result '(LH)M (K)L (EJ)K (I)J (E)I (E)H' E..M --ancestry-path --parents -- file
+check_result '(LH)M (E)H (J)L (I)J (E)I' E..M --ancestry-path --simplify-merges -- file
+
+# Should still be able to ignore I-J branch in simple log, despite limiting
+# to G.
+check_result 'M L K J I H' G..M
+check_result 'M H L K J I' G..M --topo-order
+check_result 'M L H' G..M -- file
+check_result '(LH)M (G)L (G)H' G..M --parents -- file
+check_result 'M L J I H' G..M --full-history -- file
+check_result 'M L K J I H' G..M --full-history --parents -- file
+check_result 'M H L J I' G..M --simplify-merges -- file
+check_result 'M L K J I H' G..M --ancestry-path
+check_result 'M L J I H' G..M --ancestry-path -- file
+check_result 'M L K J I H' G..M --ancestry-path --parents -- file
+check_result 'M H L J I' G..M --ancestry-path --simplify-merges -- file
+
+# B..F should be able to simplify the merge D from irrelevant side branch C.
+# Default log should also be free to follow B-D, and ignore C.
+# But --full-history shouldn't drop D on its own - without simplification,
+# we can't decide if the merge from INTERESTING commit C was sensible.
+check_result 'F D C' B..F
+check_result 'F' B..F -- file
+check_result '(B)F' B..F --parents -- file
+check_result 'F D' B..F --full-history -- file
+check_result '(D)F (BA)D' B..F --full-history --parents -- file
+check_result '(B)F' B..F --simplify-merges -- file
+check_result 'F D' B..F --ancestry-path
+check_result 'F' B..F --ancestry-path -- file
+check_result 'F' B..F --ancestry-path --parents -- file
+check_result 'F' B..F --ancestry-path --simplify-merges -- file
+check_result 'F D' B..F --first-parent
+check_result 'F' B..F --first-parent -- file
+
+# E...F should be equivalent to E F ^B, and be able to drop D as above.
+check_result 'F' E F ^B -- file # includes D
+check_result 'F' E...F -- file # includes D
+
+# Any sort of full history of C..F should show D, as it's the connection to C,
+# and it differs from it.
+check_result 'F D B' C..F
+check_result 'F B' C..F -- file
+check_result '(B)F (A)B' C..F --parents -- file
+check_result 'F D B' C..F --full-history -- file
+check_result '(D)F (BC)D (A)B' C..F --full-history --parents -- file
+check_result '(D)F (BC)D (A)B' C..F --simplify-merges -- file
+check_result 'F D' C..F --ancestry-path
+check_result 'F D' C..F --ancestry-path -- file
+check_result 'F D' C..F --ancestry-path --parents -- file
+check_result 'F D' C..F --ancestry-path --simplify-merges -- file
+check_result 'F D B' C..F --first-parent
+check_result 'F B' C..F --first-parent -- file
+
+
+test_done
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index f67aa6f..c0e5b2a 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -110,6 +110,9 @@ check_describe tags/e --all HEAD^^^
check_describe B-0-* --long HEAD^^2^
check_describe A-3-* --long HEAD^^2
+check_describe c-7-* --tags
+check_describe e-3-* --first-parent --tags
+
: >err.expect
check_describe A --all A^0
test_expect_success 'no warning was displayed for A' '
@@ -171,4 +174,28 @@ check_describe "test2-lightweight-*" --tags --match="test2-*"
check_describe "test2-lightweight-*" --long --tags --match="test2-*" HEAD^
+test_expect_success 'name-rev with exact tags' '
+ echo A >expect &&
+ tag_object=$(git rev-parse refs/tags/A) &&
+ git name-rev --tags --name-only $tag_object >actual &&
+ test_cmp expect actual &&
+
+ echo "A^0" >expect &&
+ tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+ git name-rev --tags --name-only $tagged_commit >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'describe --contains with the exact tags' '
+ echo "A^0" >expect &&
+ tag_object=$(git rev-parse refs/tags/A) &&
+ git describe --contains $tag_object >actual &&
+ test_cmp expect actual &&
+
+ echo "A^0" >expect &&
+ tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+ git describe --contains $tagged_commit >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh
index 39ef619..ea00d71 100755
--- a/t/t6130-pathspec-noglob.sh
+++ b/t/t6130-pathspec-noglob.sh
@@ -32,6 +32,16 @@ test_expect_success 'star pathspec globs' '
test_cmp expect actual
'
+test_expect_success 'star pathspec globs' '
+ cat >expect <<-\EOF &&
+ bracket
+ star
+ vanilla
+ EOF
+ git log --format=%s -- ":(glob)f*" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'bracket pathspec globs and matches literal brackets' '
cat >expect <<-\EOF &&
bracket
@@ -41,28 +51,105 @@ test_expect_success 'bracket pathspec globs and matches literal brackets' '
test_cmp expect actual
'
+test_expect_success 'bracket pathspec globs and matches literal brackets' '
+ cat >expect <<-\EOF &&
+ bracket
+ vanilla
+ EOF
+ git log --format=%s -- ":(glob)f[o][o]" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'no-glob option matches literally (vanilla)' '
echo vanilla >expect &&
git --literal-pathspecs log --format=%s -- foo >actual &&
test_cmp expect actual
'
+test_expect_success 'no-glob option matches literally (vanilla)' '
+ echo vanilla >expect &&
+ git log --format=%s -- ":(literal)foo" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'no-glob option matches literally (star)' '
echo star >expect &&
git --literal-pathspecs log --format=%s -- "f*" >actual &&
test_cmp expect actual
'
+test_expect_success 'no-glob option matches literally (star)' '
+ echo star >expect &&
+ git log --format=%s -- ":(literal)f*" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'no-glob option matches literally (bracket)' '
echo bracket >expect &&
git --literal-pathspecs log --format=%s -- "f[o][o]" >actual &&
test_cmp expect actual
'
+test_expect_success 'no-glob option matches literally (bracket)' '
+ echo bracket >expect &&
+ git log --format=%s -- ":(literal)f[o][o]" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'no-glob option disables :(literal)' '
+ : >expect &&
+ git --literal-pathspecs log --format=%s -- ":(literal)foo" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'no-glob environment variable works' '
echo star >expect &&
GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual &&
test_cmp expect actual
'
+test_expect_success 'setup xxx/bar' '
+ mkdir xxx &&
+ test_commit xxx xxx/bar
+'
+
+test_expect_success '**/ works with :(glob)' '
+ cat >expect <<-\EOF &&
+ xxx
+ unrelated
+ EOF
+ git log --format=%s -- ":(glob)**/bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '**/ does not work with --noglob-pathspecs' '
+ : >expect &&
+ git --noglob-pathspecs log --format=%s -- "**/bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '**/ works with :(glob) and --noglob-pathspecs' '
+ cat >expect <<-\EOF &&
+ xxx
+ unrelated
+ EOF
+ git --noglob-pathspecs log --format=%s -- ":(glob)**/bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '**/ works with --glob-pathspecs' '
+ cat >expect <<-\EOF &&
+ xxx
+ unrelated
+ EOF
+ git --glob-pathspecs log --format=%s -- "**/bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '**/ does not work with :(literal) and --glob-pathspecs' '
+ : >expect &&
+ git --glob-pathspecs log --format=%s -- ":(literal)**/bar" >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6131-pathspec-icase.sh b/t/t6131-pathspec-icase.sh
new file mode 100755
index 0000000..8d4a7fc
--- /dev/null
+++ b/t/t6131-pathspec-icase.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+test_description='test case insensitive pathspec limiting'
+. ./test-lib.sh
+
+if test_have_prereq CASE_INSENSITIVE_FS
+then
+ skip_all='skipping case sensitive tests - case insensitive file system'
+ test_done
+fi
+
+test_expect_success 'create commits with glob characters' '
+ test_commit bar bar &&
+ test_commit bAr bAr &&
+ test_commit BAR BAR &&
+ mkdir foo &&
+ test_commit foo/bar foo/bar &&
+ test_commit foo/bAr foo/bAr &&
+ test_commit foo/BAR foo/BAR &&
+ mkdir fOo &&
+ test_commit fOo/bar fOo/bar &&
+ test_commit fOo/bAr fOo/bAr &&
+ test_commit fOo/BAR fOo/BAR &&
+ mkdir FOO &&
+ test_commit FOO/bar FOO/bar &&
+ test_commit FOO/bAr FOO/bAr &&
+ test_commit FOO/BAR FOO/BAR
+'
+
+test_expect_success 'tree_entry_interesting matches bar' '
+ echo bar >expect &&
+ git log --format=%s -- "bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'tree_entry_interesting matches :(icase)bar' '
+ cat <<-EOF >expect &&
+ BAR
+ bAr
+ bar
+ EOF
+ git log --format=%s -- ":(icase)bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'tree_entry_interesting matches :(icase)bar with prefix' '
+ cat <<-EOF >expect &&
+ fOo/BAR
+ fOo/bAr
+ fOo/bar
+ EOF
+ ( cd fOo && git log --format=%s -- ":(icase)bar" ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'tree_entry_interesting matches :(icase)bar with empty prefix' '
+ cat <<-EOF >expect &&
+ FOO/BAR
+ FOO/bAr
+ FOO/bar
+ fOo/BAR
+ fOo/bAr
+ fOo/bar
+ foo/BAR
+ foo/bAr
+ foo/bar
+ EOF
+ ( cd fOo && git log --format=%s -- ":(icase)../foo/bar" ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'match_pathspec_depth matches :(icase)bar' '
+ cat <<-EOF >expect &&
+ BAR
+ bAr
+ bar
+ EOF
+ git ls-files ":(icase)bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'match_pathspec_depth matches :(icase)bar with prefix' '
+ cat <<-EOF >expect &&
+ fOo/BAR
+ fOo/bAr
+ fOo/bar
+ EOF
+ ( cd fOo && git ls-files --full-name ":(icase)bar" ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'match_pathspec_depth matches :(icase)bar with empty prefix' '
+ cat <<-EOF >expect &&
+ bar
+ fOo/BAR
+ fOo/bAr
+ fOo/bar
+ EOF
+ ( cd fOo && git ls-files --full-name ":(icase)bar" ../bar ) >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index a845b15..d432f42 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -218,13 +218,13 @@ test_expect_success 'git mv should not change sha1 of moved cache entry' '
rm -f dirty dirty2
-test_expect_success SYMLINKS 'git mv should overwrite symlink to a file' '
+test_expect_success 'git mv should overwrite symlink to a file' '
rm -fr .git &&
git init &&
echo 1 >moved &&
- ln -s moved symlink &&
- git add moved symlink &&
+ test_ln_s_add moved symlink &&
+ git add moved &&
test_must_fail git mv moved symlink &&
git mv -f moved symlink &&
! test -e moved &&
@@ -237,22 +237,154 @@ test_expect_success SYMLINKS 'git mv should overwrite symlink to a file' '
rm -f moved symlink
-test_expect_success SYMLINKS 'git mv should overwrite file with a symlink' '
+test_expect_success 'git mv should overwrite file with a symlink' '
rm -fr .git &&
git init &&
echo 1 >moved &&
- ln -s moved symlink &&
- git add moved symlink &&
+ test_ln_s_add moved symlink &&
+ git add moved &&
test_must_fail git mv symlink moved &&
git mv -f symlink moved &&
! test -e symlink &&
- test -h moved &&
git update-index --refresh &&
git diff-files --quiet
'
+test_expect_success SYMLINKS 'check moved symlink' '
+
+ test -h moved
+'
+
rm -f moved symlink
+test_expect_success 'setup submodule' '
+ git commit -m initial &&
+ git reset --hard &&
+ git submodule add ./. sub &&
+ echo content >file &&
+ git add file &&
+ git commit -m "added sub and file"
+'
+
+test_expect_success 'git mv cannot move a submodule in a file' '
+ test_must_fail git mv sub file
+'
+
+test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ git rm .gitmodules &&
+ (
+ cd sub &&
+ rm -f .git &&
+ cp -a ../.git/modules/sub .git &&
+ GIT_WORK_TREE=. git config --unset core.worktree
+ ) &&
+ mkdir mod &&
+ git mv sub mod/sub &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'git mv moves a submodule with gitfile' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ (
+ cd mod &&
+ git mv ../sub/ .
+ ) &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ echo mod/sub >expected &&
+ git config -f .gitmodules submodule.sub.path >actual &&
+ test_cmp expected actual &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv does not complain when no .gitmodules file is found' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git rm .gitmodules &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ git mv sub mod/sub 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules foo.bar true &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ test_must_fail git mv sub mod/sub 2>actual.err &&
+ test -s actual.err &&
+ test -e sub &&
+ git diff-files --quiet -- sub &&
+ git add .gitmodules &&
+ git mv sub mod/sub 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules --remove-section submodule.sub &&
+ git add .gitmodules &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
+ git mv sub mod/sub 2>actual.err &&
+ test_i18ncmp expect.err actual.err &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git mv -n sub mod/sub 2>actual.err &&
+ test -f sub/.git &&
+ git diff-index --exit-code HEAD &&
+ git update-index --refresh &&
+ git diff-files --quiet -- sub .gitmodules
+'
+
test_done
diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh
index 8f3b54d..88d60c1 100755
--- a/t/t7011-skip-worktree-reading.sh
+++ b/t/t7011-skip-worktree-reading.sh
@@ -91,12 +91,12 @@ test_expect_success 'update-index --remove' '
test_cmp expected 1
'
-test_expect_success 'ls-files --delete' '
+test_expect_success 'ls-files --deleted' '
setup_absent &&
test -z "$(git ls-files -d)"
'
-test_expect_success 'ls-files --delete' '
+test_expect_success 'ls-files --deleted' '
setup_dirty &&
test -z "$(git ls-files -d)"
'
diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh
index 0da1214..460789b 100755
--- a/t/t7061-wtstatus-ignore.sh
+++ b/t/t7061-wtstatus-ignore.sh
@@ -32,6 +32,25 @@ test_expect_success 'status untracked directory with --ignored -u' '
git status --porcelain --ignored -u >actual &&
test_cmp expected actual
'
+cat >expected <<\EOF
+?? untracked/uncommitted
+!! untracked/ignored
+EOF
+
+test_expect_success 'status prefixed untracked directory with --ignored' '
+ git status --porcelain --ignored untracked/ >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? untracked/uncommitted
+!! untracked/ignored
+EOF
+
+test_expect_success 'status prefixed untracked sub-directory with --ignored -u' '
+ git status --porcelain --ignored -u untracked/ >actual &&
+ test_cmp expected actual
+'
cat >expected <<\EOF
?? .gitignore
@@ -64,13 +83,35 @@ cat >expected <<\EOF
?? .gitignore
?? actual
?? expected
-!! untracked-ignored/
EOF
-test_expect_success 'status untracked directory with ignored files with --ignore' '
+test_expect_success 'status empty untracked directory with --ignore' '
rm -rf ignored &&
mkdir untracked-ignored &&
mkdir untracked-ignored/test &&
+ git status --porcelain --ignored >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+EOF
+
+test_expect_success 'status empty untracked directory with --ignore -u' '
+ git status --porcelain --ignored -u >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! untracked-ignored/
+EOF
+
+test_expect_success 'status untracked directory with ignored files with --ignore' '
: >untracked-ignored/ignored &&
: >untracked-ignored/test/ignored &&
git status --porcelain --ignored >actual &&
@@ -122,10 +163,34 @@ cat >expected <<\EOF
?? .gitignore
?? actual
?? expected
-!! tracked/
+EOF
+
+test_expect_success 'status ignored tracked directory and ignored file with --ignore' '
+ echo "committed" >>.gitignore &&
+ git status --porcelain --ignored >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+EOF
+
+test_expect_success 'status ignored tracked directory and ignored file with --ignore -u' '
+ git status --porcelain --ignored -u >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! tracked/uncommitted
EOF
test_expect_success 'status ignored tracked directory and uncommitted file with --ignore' '
+ echo "tracked" >.gitignore &&
: >tracked/uncommitted &&
git status --porcelain --ignored >actual &&
test_cmp expected actual
@@ -143,4 +208,58 @@ test_expect_success 'status ignored tracked directory and uncommitted file with
test_cmp expected actual
'
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! tracked/ignored/
+EOF
+
+test_expect_success 'status ignored tracked directory with uncommitted file in untracked subdir with --ignore' '
+ rm -rf tracked/uncommitted &&
+ mkdir tracked/ignored &&
+ : >tracked/ignored/uncommitted &&
+ git status --porcelain --ignored >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! tracked/ignored/uncommitted
+EOF
+
+test_expect_success 'status ignored tracked directory with uncommitted file in untracked subdir with --ignore -u' '
+ git status --porcelain --ignored -u >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! tracked/ignored/uncommitted
+EOF
+
+test_expect_success 'status ignored tracked directory with uncommitted file in tracked subdir with --ignore' '
+ : >tracked/ignored/committed &&
+ git add -f tracked/ignored/committed &&
+ git commit -m. &&
+ git status --porcelain --ignored >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! tracked/ignored/uncommitted
+EOF
+
+test_expect_success 'status ignored tracked directory with uncommitted file in tracked subdir with --ignore -u' '
+ git status --porcelain --ignored -u >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index df82ec9..8d4b50d 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -9,6 +9,19 @@ Documented tests for git reset'
. ./test-lib.sh
+commit_msg () {
+ # String "modify 2nd file (changed)" partly in German
+ # (translated with Google Translate),
+ # encoded in UTF-8, used as a commit log message below.
+ msg="modify 2nd file (ge\303\244ndert)\n"
+ if test -n "$1"
+ then
+ printf "$msg" | iconv -f utf-8 -t "$1"
+ else
+ printf "$msg"
+ fi
+}
+
test_expect_success 'creating initial files and commits' '
test_tick &&
echo "1st file" >first &&
@@ -28,7 +41,7 @@ test_expect_success 'creating initial files and commits' '
echo "1st line 2nd file" >secondfile &&
echo "2nd line 2nd file" >>secondfile &&
- git commit -a -m "modify 2nd file" &&
+ git -c "i18n.commitEncoding=iso8859-1" commit -a -m "$(commit_msg iso8859-1)" &&
head5=$(git rev-parse --verify HEAD)
'
# git log --pretty=oneline # to see those SHA1 involved
@@ -44,6 +57,20 @@ check_changes () {
done | test_cmp .cat_expect -
}
+test_expect_success 'reset --hard message' '
+ hex=$(git log -1 --format="%h") &&
+ git reset --hard > .actual &&
+ echo HEAD is now at $hex $(commit_msg) > .expected &&
+ test_cmp .expected .actual
+'
+
+test_expect_success 'reset --hard message (iso8859-1 logoutputencoding)' '
+ hex=$(git log -1 --format="%h") &&
+ git -c "i18n.logOutputEncoding=iso8859-1" reset --hard > .actual &&
+ echo HEAD is now at $hex $(commit_msg iso8859-1) > .expected &&
+ test_cmp .expected .actual
+'
+
>.diff_expect
>.cached_expect
cat >.cat_expect <<EOF
@@ -192,7 +219,8 @@ test_expect_success \
'changing files and redo the last commit should succeed' '
echo "3rd line 2nd file" >>secondfile &&
git commit -a -C ORIG_HEAD &&
- check_changes 3d3b7be011a58ca0c179ae45d94e6c83c0b0cd0d &&
+ head4=$(git rev-parse --verify HEAD) &&
+ check_changes $head4 &&
test "$(git rev-parse ORIG_HEAD)" = \
$head5
'
@@ -211,7 +239,7 @@ test_expect_success \
git reset --hard HEAD~2 &&
check_changes ddaefe00f1da16864591c61fdc7adb5d7cd6b74e &&
test "$(git rev-parse ORIG_HEAD)" = \
- 3d3b7be011a58ca0c179ae45d94e6c83c0b0cd0d
+ $head4
'
>.diff_expect
@@ -303,7 +331,7 @@ test_expect_success 'redoing the last two commits should succeed' '
echo "1st line 2nd file" >secondfile &&
echo "2nd line 2nd file" >>secondfile &&
- git commit -a -m "modify 2nd file" &&
+ git -c "i18n.commitEncoding=iso8859-1" commit -a -m "$(commit_msg iso8859-1)" &&
check_changes $head5
'
@@ -326,10 +354,11 @@ test_expect_success '--hard reset to HEAD should clear a failed merge' '
git checkout branch2 &&
echo "3rd line in branch2" >>secondfile &&
git commit -a -m "change in branch2" &&
+ head3=$(git rev-parse --verify HEAD) &&
test_must_fail git pull . branch1 &&
git reset --hard &&
- check_changes 77abb337073fb4369a7ad69ff6f5ec0e4d6b54bb
+ check_changes $head3
'
>.diff_expect
@@ -457,7 +486,7 @@ test_expect_success 'disambiguation (1)' '
test_must_fail git diff --quiet -- secondfile &&
test -z "$(git diff --cached --name-only)" &&
test -f secondfile &&
- test ! -s secondfile
+ test_must_be_empty secondfile
'
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index be9672e..0c9ec0a 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -431,6 +431,7 @@ test_expect_success 'detach a symbolic link HEAD' '
test_expect_success \
'checkout with --track fakes a sensible -b <name>' '
+ git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
git update-ref refs/remotes/origin/koala/bear renamer &&
git checkout --track origin/koala/bear &&
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index ccfb54d..710be90 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -298,6 +298,23 @@ test_expect_success 'git clean -d -x' '
'
+test_expect_success 'git clean -d -x with ignored tracked directory' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
+ git clean -d -x -e src &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test -f src/part3.c &&
+ test ! -d docs &&
+ test ! -f obj.o &&
+ test ! -d build
+
+'
+
test_expect_success 'git clean -X' '
mkdir -p build docs &&
@@ -332,6 +349,23 @@ test_expect_success 'git clean -d -X' '
'
+test_expect_success 'git clean -d -X with ignored tracked directory' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
+ git clean -d -X -e src &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test ! -f src/part3.c &&
+ test -f docs/manual.txt &&
+ test ! -f obj.o &&
+ test ! -d build
+
+'
+
test_expect_success 'clean.requireForce defaults to true' '
git config --unset clean.requireForce &&
diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh
new file mode 100755
index 0000000..3ae394e
--- /dev/null
+++ b/t/t7301-clean-interactive.sh
@@ -0,0 +1,475 @@
+#!/bin/sh
+
+test_description='git clean -i basic tests'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+
+ mkdir -p src &&
+ touch src/part1.c Makefile &&
+ echo build >.gitignore &&
+ echo \*.o >>.gitignore &&
+ git add . &&
+ git commit -m setup &&
+ touch src/part2.c README &&
+ git add .
+
+'
+
+test_expect_success 'git clean -i (c: clean hotkey)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ echo c | git clean -i &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test ! -f src/part3.h &&
+ test ! -f src/part4.c &&
+ test ! -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -i (cl: clean prefix)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ echo cl | git clean -i &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test ! -f src/part3.h &&
+ test ! -f src/part4.c &&
+ test ! -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -i (quit)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ echo quit | git clean -i &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test -f docs/manual.txt &&
+ test -f src/part3.c &&
+ test -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -i (Ctrl+D)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ echo "\04" | git clean -i &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test -f docs/manual.txt &&
+ test -f src/part3.c &&
+ test -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (filter all)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo f; echo "*"; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test -f docs/manual.txt &&
+ test -f src/part3.c &&
+ test -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (filter patterns)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo f; echo "part3.* *.out"; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test ! -f docs/manual.txt &&
+ test -f src/part3.c &&
+ test -f src/part3.h &&
+ test ! -f src/part4.c &&
+ test ! -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (filter patterns 2)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo f; echo "* !*.out"; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test -f docs/manual.txt &&
+ test -f src/part3.c &&
+ test -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (select - all)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo s; echo "*"; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test ! -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test ! -f src/part3.h &&
+ test ! -f src/part4.c &&
+ test ! -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (select - none)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo s; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test -f docs/manual.txt &&
+ test -f src/part3.c &&
+ test -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (select - number)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo s; echo 3; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (select - number 2)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo s; echo 2 3; echo 5; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test ! -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test -f src/part3.h &&
+ test ! -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (select - number 3)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo s; echo 3,4 5; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test ! -f src/part3.h &&
+ test ! -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (select - filenames)' '
+
+ mkdir -p build docs &&
+ touch a.out foo.txt bar.txt baz.txt &&
+ (echo s; echo a.out fo ba bar; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test ! -f a.out &&
+ test ! -f foo.txt &&
+ test ! -f bar.txt &&
+ test -f baz.txt &&
+ rm baz.txt
+
+'
+
+test_expect_success 'git clean -id (select - range)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo s; echo 1,3-4; echo 2; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test ! -f src/part3.c &&
+ test ! -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test ! -f docs/manual.txt &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (select - range 2)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo s; echo 4- 1; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test -f docs/manual.txt &&
+ test -f src/part3.c &&
+ test ! -f src/part3.h &&
+ test ! -f src/part4.c &&
+ test ! -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (inverse select)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo s; echo "*"; echo -5- 1 -2; echo; echo c) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test ! -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (ask)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo a; echo Y; echo y; echo no; echo yes; echo bad; echo) | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test ! -f docs/manual.txt &&
+ test -f src/part3.c &&
+ test ! -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id (ask - Ctrl+D)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (echo a; echo Y; echo no; echo yes; echo "\04") | \
+ git clean -id &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id with prefix and path (filter)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (cd build/ && \
+ (echo f; echo "docs"; echo "*.h"; echo ; echo c) | \
+ git clean -id ..) &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test -f src/part3.h &&
+ test ! -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id with prefix and path (select by name)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (cd build/ && \
+ (echo s; echo "../docs/"; echo "../src/part3.c"; \
+ echo "../src/part4.c"; echo; echo c) | \
+ git clean -id ..) &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test -f a.out &&
+ test ! -f docs/manual.txt &&
+ test ! -f src/part3.c &&
+ test -f src/part3.h &&
+ test ! -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_expect_success 'git clean -id with prefix and path (ask)' '
+
+ mkdir -p build docs &&
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+ docs/manual.txt obj.o build/lib.so &&
+ (cd build/ && \
+ (echo a; echo Y; echo y; echo no; echo yes; echo bad; echo) | \
+ git clean -id ..) &&
+ test -f Makefile &&
+ test -f README &&
+ test -f src/part1.c &&
+ test -f src/part2.c &&
+ test ! -f a.out &&
+ test ! -f docs/manual.txt &&
+ test -f src/part3.c &&
+ test ! -f src/part3.h &&
+ test -f src/part4.c &&
+ test -f src/part4.h &&
+ test -f obj.o &&
+ test -f build/lib.so
+
+'
+
+test_done
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 2683cba..4192fe0 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -18,6 +18,16 @@ test_expect_success 'setup - initial commit' '
git branch initial
'
+test_expect_success 'configuration parsing' '
+ test_when_finished "rm -f .gitmodules" &&
+ cat >.gitmodules <<-\EOF &&
+ [submodule "s"]
+ path
+ ignore
+ EOF
+ test_must_fail git status
+'
+
test_expect_success 'setup - repository in init subdirectory' '
mkdir init &&
(
@@ -78,7 +88,7 @@ test_expect_success 'submodule add' '
(
cd addtest &&
git submodule add -q "$submodurl" submod >actual &&
- test ! -s actual &&
+ test_must_be_empty actual &&
echo "gitdir: ../.git/modules/submod" >expect &&
test_cmp expect submod/.git &&
(
@@ -212,6 +222,32 @@ test_expect_success 'submodule add with ./, /.. and // in path' '
test_cmp empty untracked
'
+test_expect_success 'submodule add in subdirectory' '
+ echo "refs/heads/master" >expect &&
+ >empty &&
+
+ mkdir addtest/sub &&
+ (
+ cd addtest/sub &&
+ git submodule add "$submodurl" ../realsubmod3 &&
+ git submodule init
+ ) &&
+
+ rm -f heads head untracked &&
+ inspect addtest/realsubmod3 ../.. &&
+ test_cmp expect heads &&
+ test_cmp expect head &&
+ test_cmp empty untracked
+'
+
+test_expect_success 'submodule add in subdirectory with relative path should fail' '
+ (
+ cd addtest/sub &&
+ test_must_fail git submodule add ../../ submod3 2>../../output.err
+ ) &&
+ test_i18ngrep toplevel output.err
+'
+
test_expect_success 'setup - add an example entry to .gitmodules' '
GIT_CONFIG=.gitmodules \
git config submodule.example.url git://example.com/init.git
@@ -308,7 +344,7 @@ test_expect_success 'update should work when path is an empty dir' '
mkdir init &&
git submodule update -q >update.out &&
- test ! -s update.out &&
+ test_must_be_empty update.out &&
inspect init &&
test_cmp expect head-sha1
@@ -319,6 +355,26 @@ test_expect_success 'status should be "up-to-date" after update' '
grep "^ $rev1" list
'
+test_expect_success 'status "up-to-date" from subdirectory' '
+ mkdir -p sub &&
+ (
+ cd sub &&
+ git submodule status >../list
+ ) &&
+ grep "^ $rev1" list &&
+ grep "\\.\\./init" list
+'
+
+test_expect_success 'status "up-to-date" from subdirectory with path' '
+ mkdir -p sub &&
+ (
+ cd sub &&
+ git submodule status ../init >../list
+ ) &&
+ grep "^ $rev1" list &&
+ grep "\\.\\./init" list
+'
+
test_expect_success 'status should be "modified" after submodule commit' '
(
cd init &&
@@ -399,6 +455,25 @@ test_expect_success 'update --init' '
git rev-parse --resolve-git-dir init/.git
'
+test_expect_success 'update --init from subdirectory' '
+ mv init init2 &&
+ git config -f .gitmodules submodule.example.url "$(pwd)/init2" &&
+ git config --remove-section submodule.example &&
+ test_must_fail git config submodule.example.url &&
+
+ mkdir -p sub &&
+ (
+ cd sub &&
+ git submodule update ../init >update.out &&
+ cat update.out &&
+ test_i18ngrep "not initialized" update.out &&
+ test_must_fail git rev-parse --resolve-git-dir ../init/.git &&
+
+ git submodule update --init ../init
+ ) &&
+ git rev-parse --resolve-git-dir init/.git
+'
+
test_expect_success 'do not add files from a submodule' '
git reset --hard &&
@@ -696,7 +771,7 @@ test_expect_success 'submodule add --name allows to replace a submodule with ano
rm -rf repo &&
git rm repo &&
git submodule add -q --name repo_new "$submodurl/bare.git" repo >actual &&
- test ! -s actual &&
+ test_must_be_empty actual &&
echo "gitdir: ../.git/modules/submod" >expect &&
test_cmp expect submod/.git &&
(
@@ -708,13 +783,11 @@ test_expect_success 'submodule add --name allows to replace a submodule with ano
test_cmp expect .git
) &&
echo "repo" >expect &&
- git config -f .gitmodules submodule.repo.path >actual &&
- test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.repo.path &&
git config -f .gitmodules submodule.repo_new.path >actual &&
test_cmp expect actual&&
echo "$submodurl/repo" >expect &&
- git config -f .gitmodules submodule.repo.url >actual &&
- test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.repo.url &&
echo "$submodurl/bare.git" >expect &&
git config -f .gitmodules submodule.repo_new.url >actual &&
test_cmp expect actual &&
@@ -734,12 +807,8 @@ test_expect_success 'submodule add with an existing name fails unless forced' '
git rm repo &&
test_must_fail git submodule add -q --name repo_new "$submodurl/repo.git" repo &&
test ! -d repo &&
- echo "repo" >expect &&
- git config -f .gitmodules submodule.repo_new.path >actual &&
- test_cmp expect actual&&
- echo "$submodurl/bare.git" >expect &&
- git config -f .gitmodules submodule.repo_new.url >actual &&
- test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.repo_new.path &&
+ test_must_fail git config -f .gitmodules submodule.repo_new.url &&
echo "$submodurl/bare.git" >expect &&
git config submodule.repo_new.url >actual &&
test_cmp expect actual &&
@@ -757,4 +826,161 @@ test_expect_success 'submodule add with an existing name fails unless forced' '
)
'
+test_expect_success 'set up a second submodule' '
+ git submodule add ./init2 example2 &&
+ git commit -m "submodule example2 added"
+'
+
+test_expect_success 'submodule deinit should remove the whole submodule section from .git/config' '
+ git config submodule.example.foo bar &&
+ git config submodule.example2.frotz nitfol &&
+ git submodule deinit init &&
+ test -z "$(git config --get-regexp "submodule\.example\.")" &&
+ test -n "$(git config --get-regexp "submodule\.example2\.")" &&
+ test -f example2/.git &&
+ rmdir init
+'
+
+test_expect_success 'submodule deinit from subdirectory' '
+ git submodule update --init &&
+ git config submodule.example.foo bar &&
+ mkdir -p sub &&
+ (
+ cd sub &&
+ git submodule deinit ../init >../output
+ ) &&
+ grep "\\.\\./init" output &&
+ test -z "$(git config --get-regexp "submodule\.example\.")" &&
+ test -n "$(git config --get-regexp "submodule\.example2\.")" &&
+ test -f example2/.git &&
+ rmdir init
+'
+
+test_expect_success 'submodule deinit . deinits all initialized submodules' '
+ git submodule update --init &&
+ git config submodule.example.foo bar &&
+ git config submodule.example2.frotz nitfol &&
+ test_must_fail git submodule deinit &&
+ git submodule deinit . >actual &&
+ test -z "$(git config --get-regexp "submodule\.example\.")" &&
+ test -z "$(git config --get-regexp "submodule\.example2\.")" &&
+ test_i18ngrep "Cleared directory .init" actual &&
+ test_i18ngrep "Cleared directory .example2" actual &&
+ rmdir init example2
+'
+
+test_expect_success 'submodule deinit deinits a submodule when its work tree is missing or empty' '
+ git submodule update --init &&
+ rm -rf init example2/* example2/.git &&
+ git submodule deinit init example2 >actual &&
+ test -z "$(git config --get-regexp "submodule\.example\.")" &&
+ test -z "$(git config --get-regexp "submodule\.example2\.")" &&
+ test_i18ngrep ! "Cleared directory .init" actual &&
+ test_i18ngrep "Cleared directory .example2" actual &&
+ rmdir init
+'
+
+test_expect_success 'submodule deinit fails when the submodule contains modifications unless forced' '
+ git submodule update --init &&
+ echo X >>init/s &&
+ test_must_fail git submodule deinit init &&
+ test -n "$(git config --get-regexp "submodule\.example\.")" &&
+ test -f example2/.git &&
+ git submodule deinit -f init >actual &&
+ test -z "$(git config --get-regexp "submodule\.example\.")" &&
+ test_i18ngrep "Cleared directory .init" actual &&
+ rmdir init
+'
+
+test_expect_success 'submodule deinit fails when the submodule contains untracked files unless forced' '
+ git submodule update --init &&
+ echo X >>init/untracked &&
+ test_must_fail git submodule deinit init &&
+ test -n "$(git config --get-regexp "submodule\.example\.")" &&
+ test -f example2/.git &&
+ git submodule deinit -f init >actual &&
+ test -z "$(git config --get-regexp "submodule\.example\.")" &&
+ test_i18ngrep "Cleared directory .init" actual &&
+ rmdir init
+'
+
+test_expect_success 'submodule deinit fails when the submodule HEAD does not match unless forced' '
+ git submodule update --init &&
+ (
+ cd init &&
+ git checkout HEAD^
+ ) &&
+ test_must_fail git submodule deinit init &&
+ test -n "$(git config --get-regexp "submodule\.example\.")" &&
+ test -f example2/.git &&
+ git submodule deinit -f init >actual &&
+ test -z "$(git config --get-regexp "submodule\.example\.")" &&
+ test_i18ngrep "Cleared directory .init" actual &&
+ rmdir init
+'
+
+test_expect_success 'submodule deinit is silent when used on an uninitialized submodule' '
+ git submodule update --init &&
+ git submodule deinit init >actual &&
+ test_i18ngrep "Submodule .example. (.*) unregistered for path .init" actual &&
+ test_i18ngrep "Cleared directory .init" actual &&
+ git submodule deinit init >actual &&
+ test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
+ test_i18ngrep "Cleared directory .init" actual &&
+ git submodule deinit . >actual &&
+ test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
+ test_i18ngrep "Submodule .example2. (.*) unregistered for path .example2" actual &&
+ test_i18ngrep "Cleared directory .init" actual &&
+ git submodule deinit . >actual &&
+ test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
+ test_i18ngrep ! "Submodule .example2. (.*) unregistered for path .example2" actual &&
+ test_i18ngrep "Cleared directory .init" actual &&
+ rmdir init example2
+'
+
+test_expect_success 'submodule deinit fails when submodule has a .git directory even when forced' '
+ git submodule update --init &&
+ (
+ cd init &&
+ rm .git &&
+ cp -R ../.git/modules/example .git &&
+ GIT_WORK_TREE=. git config --unset core.worktree
+ ) &&
+ test_must_fail git submodule deinit init &&
+ test_must_fail git submodule deinit -f init &&
+ test -d init/.git &&
+ test -n "$(git config --get-regexp "submodule\.example\.")"
+'
+
+test_expect_success 'submodule with UTF-8 name' '
+ svname=$(printf "\303\245 \303\244\303\266") &&
+ mkdir "$svname" &&
+ (
+ cd "$svname" &&
+ git init &&
+ >sub &&
+ git add sub &&
+ git commit -m "init sub"
+ ) &&
+ test_config core.precomposeunicode true &&
+ git submodule add ./"$svname" &&
+ git submodule >&2 &&
+ test -n "$(git submodule | grep "$svname")"
+'
+
+test_expect_success 'submodule add clone shallow submodule' '
+ mkdir super &&
+ pwd=$(pwd)
+ (
+ cd super &&
+ git init &&
+ git submodule add --depth=1 file://"$pwd"/example2 submodule &&
+ (
+ cd submodule &&
+ test 1 = $(git log --oneline | wc -l)
+ )
+ )
+'
+
+
test_done
diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh
index 30b429e..ac2434c 100755
--- a/t/t7401-submodule-summary.sh
+++ b/t/t7401-submodule-summary.sh
@@ -45,6 +45,42 @@ EOF
test_cmp expected actual
"
+test_expect_success 'added submodule (subdirectory)' "
+ mkdir sub &&
+ (
+ cd sub &&
+ git submodule summary >../actual
+ ) &&
+ cat >expected <<-EOF &&
+* ../sm1 0000000...$head1 (2):
+ > Add foo2
+
+EOF
+ test_cmp expected actual
+"
+
+test_expect_success 'added submodule (subdirectory only)' "
+ (
+ cd sub &&
+ git submodule summary . >../actual
+ ) &&
+ >expected &&
+ test_cmp expected actual
+"
+
+test_expect_success 'added submodule (subdirectory with explicit path)' "
+ (
+ cd sub &&
+ git submodule summary ../sm1 >../actual
+ ) &&
+ cat >expected <<-EOF &&
+* ../sm1 0000000...$head1 (2):
+ > Add foo2
+
+EOF
+ test_cmp expected actual
+"
+
commit_file sm1 &&
head2=$(add_file sm1 foo3)
@@ -76,8 +112,8 @@ head3=$(
)
test_expect_success 'modified submodule(backward)' "
- git submodule summary >actual &&
- cat >expected <<-EOF &&
+ git submodule summary >actual &&
+ cat >expected <<-EOF &&
* sm1 $head2...$head3 (2):
< Add foo3
< Add foo2
@@ -89,8 +125,8 @@ EOF
head4=$(add_file sm1 foo4 foo5) &&
head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
test_expect_success 'modified submodule(backward and forward)' "
- git submodule summary >actual &&
- cat >expected <<-EOF &&
+ git submodule summary >actual &&
+ cat >expected <<-EOF &&
* sm1 $head2...$head4 (4):
> Add foo5
> Add foo4
@@ -102,15 +138,15 @@ EOF
"
test_expect_success '--summary-limit' "
- git submodule summary -n 3 >actual &&
- cat >expected <<-EOF &&
+ git submodule summary -n 3 >actual &&
+ cat >expected <<-EOF &&
* sm1 $head2...$head4 (4):
> Add foo5
> Add foo4
< Add foo3
EOF
- test_cmp expected actual
+ test_cmp expected actual
"
commit_file sm1 &&
@@ -122,8 +158,8 @@ rm -f sm1 &&
mv sm1-bak sm1
test_expect_success 'typechanged submodule(submodule->blob), --cached' "
- git submodule summary --cached >actual &&
- cat >expected <<-EOF &&
+ git submodule summary --cached >actual &&
+ cat >expected <<-EOF &&
* sm1 $head4(submodule)->$head5(blob) (3):
< Add foo5
@@ -132,59 +168,59 @@ EOF
"
test_expect_success 'typechanged submodule(submodule->blob), --files' "
- git submodule summary --files >actual &&
- cat >expected <<-EOF &&
+ git submodule summary --files >actual &&
+ cat >expected <<-EOF &&
* sm1 $head5(blob)->$head4(submodule) (3):
> Add foo5
EOF
- test_i18ncmp actual expected
+ test_i18ncmp actual expected
"
rm -rf sm1 &&
git checkout-index sm1
test_expect_success 'typechanged submodule(submodule->blob)' "
- git submodule summary >actual &&
- cat >expected <<-EOF &&
+ git submodule summary >actual &&
+ cat >expected <<-EOF &&
* sm1 $head4(submodule)->$head5(blob):
EOF
- test_i18ncmp actual expected
+ test_i18ncmp actual expected
"
rm -f sm1 &&
test_create_repo sm1 &&
head6=$(add_file sm1 foo6 foo7)
test_expect_success 'nonexistent commit' "
- git submodule summary >actual &&
- cat >expected <<-EOF &&
+ git submodule summary >actual &&
+ cat >expected <<-EOF &&
* sm1 $head4...$head6:
Warn: sm1 doesn't contain commit $head4_full
EOF
- test_i18ncmp actual expected
+ test_i18ncmp actual expected
"
commit_file
test_expect_success 'typechanged submodule(blob->submodule)' "
- git submodule summary >actual &&
- cat >expected <<-EOF &&
+ git submodule summary >actual &&
+ cat >expected <<-EOF &&
* sm1 $head5(blob)->$head6(submodule) (2):
> Add foo7
EOF
- test_i18ncmp expected actual
+ test_i18ncmp expected actual
"
commit_file sm1 &&
rm -rf sm1
test_expect_success 'deleted submodule' "
- git submodule summary >actual &&
- cat >expected <<-EOF &&
+ git submodule summary >actual &&
+ cat >expected <<-EOF &&
* sm1 $head6...0000000:
EOF
- test_cmp expected actual
+ test_cmp expected actual
"
test_create_repo sm2 &&
@@ -192,43 +228,43 @@ head7=$(add_file sm2 foo8 foo9) &&
git add sm2
test_expect_success 'multiple submodules' "
- git submodule summary >actual &&
- cat >expected <<-EOF &&
+ git submodule summary >actual &&
+ cat >expected <<-EOF &&
* sm1 $head6...0000000:
* sm2 0000000...$head7 (2):
> Add foo9
EOF
- test_cmp expected actual
+ test_cmp expected actual
"
test_expect_success 'path filter' "
- git submodule summary sm2 >actual &&
- cat >expected <<-EOF &&
+ git submodule summary sm2 >actual &&
+ cat >expected <<-EOF &&
* sm2 0000000...$head7 (2):
> Add foo9
EOF
- test_cmp expected actual
+ test_cmp expected actual
"
commit_file sm2
test_expect_success 'given commit' "
- git submodule summary HEAD^ >actual &&
- cat >expected <<-EOF &&
+ git submodule summary HEAD^ >actual &&
+ cat >expected <<-EOF &&
* sm1 $head6...0000000:
* sm2 0000000...$head7 (2):
> Add foo9
EOF
- test_cmp expected actual
+ test_cmp expected actual
"
test_expect_success '--for-status' "
- git submodule summary --for-status HEAD^ >actual &&
- test_i18ncmp actual - <<EOF
+ git submodule summary --for-status HEAD^ >actual &&
+ test_i18ncmp actual - <<EOF
# Submodule changes to be committed:
#
# * sm1 $head6...0000000:
@@ -240,14 +276,14 @@ EOF
"
test_expect_success 'fail when using --files together with --cached' "
- test_must_fail git submodule summary --files --cached
+ test_must_fail git submodule summary --files --cached
"
test_expect_success 'should not fail in an empty repo' "
- git init xyzzy &&
- cd xyzzy &&
- git submodule summary >output 2>&1 &&
- test_cmp output /dev/null
+ git init xyzzy &&
+ cd xyzzy &&
+ git submodule summary >output 2>&1 &&
+ test_cmp output /dev/null
"
test_done
diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
index 94e26c4..79bc135 100755
--- a/t/t7403-submodule-sync.sh
+++ b/t/t7403-submodule-sync.sh
@@ -11,216 +11,338 @@ These tests exercise the "git submodule sync" subcommand.
. ./test-lib.sh
test_expect_success setup '
- echo file > file &&
+ echo file >file &&
git add file &&
test_tick &&
git commit -m upstream &&
git clone . super &&
git clone super submodule &&
- (cd submodule &&
- git submodule add ../submodule sub-submodule &&
- test_tick &&
- git commit -m "sub-submodule"
+ (
+ cd submodule &&
+ git submodule add ../submodule sub-submodule &&
+ test_tick &&
+ git commit -m "sub-submodule"
) &&
- (cd super &&
- git submodule add ../submodule submodule &&
- test_tick &&
- git commit -m "submodule"
+ (
+ cd super &&
+ git submodule add ../submodule submodule &&
+ test_tick &&
+ git commit -m "submodule"
) &&
git clone super super-clone &&
- (cd super-clone && git submodule update --init --recursive) &&
+ (
+ cd super-clone &&
+ git submodule update --init --recursive
+ ) &&
git clone super empty-clone &&
- (cd empty-clone && git submodule init) &&
+ (
+ cd empty-clone &&
+ git submodule init
+ ) &&
git clone super top-only-clone &&
git clone super relative-clone &&
- (cd relative-clone && git submodule update --init --recursive) &&
+ (
+ cd relative-clone &&
+ git submodule update --init --recursive
+ ) &&
git clone super recursive-clone &&
- (cd recursive-clone && git submodule update --init --recursive)
+ (
+ cd recursive-clone &&
+ git submodule update --init --recursive
+ )
'
test_expect_success 'change submodule' '
- (cd submodule &&
- echo second line >> file &&
- test_tick &&
- git commit -a -m "change submodule"
+ (
+ cd submodule &&
+ echo second line >>file &&
+ test_tick &&
+ git commit -a -m "change submodule"
)
'
+reset_submodule_urls () {
+ local root
+ root=$(pwd) &&
+ (
+ cd super-clone/submodule &&
+ git config remote.origin.url "$root/submodule"
+ ) &&
+ (
+ cd super-clone/submodule/sub-submodule &&
+ git config remote.origin.url "$root/submodule"
+ )
+}
+
test_expect_success 'change submodule url' '
- (cd super &&
- cd submodule &&
- git checkout master &&
- git pull
+ (
+ cd super &&
+ cd submodule &&
+ git checkout master &&
+ git pull
) &&
mv submodule moved-submodule &&
- (cd moved-submodule &&
- git config -f .gitmodules submodule.sub-submodule.url ../moved-submodule &&
- test_tick &&
- git commit -a -m moved-sub-submodule
+ (
+ cd moved-submodule &&
+ git config -f .gitmodules submodule.sub-submodule.url ../moved-submodule &&
+ test_tick &&
+ git commit -a -m moved-sub-submodule
) &&
- (cd super &&
- git config -f .gitmodules submodule.submodule.url ../moved-submodule &&
- test_tick &&
- git commit -a -m moved-submodule
+ (
+ cd super &&
+ git config -f .gitmodules submodule.submodule.url ../moved-submodule &&
+ test_tick &&
+ git commit -a -m moved-submodule
)
'
test_expect_success '"git submodule sync" should update submodule URLs' '
- (cd super-clone &&
- git pull --no-recurse-submodules &&
- git submodule sync
+ (
+ cd super-clone &&
+ git pull --no-recurse-submodules &&
+ git submodule sync
) &&
- test -d "$(cd super-clone/submodule &&
- git config remote.origin.url
+ test -d "$(
+ cd super-clone/submodule &&
+ git config remote.origin.url
)" &&
- test ! -d "$(cd super-clone/submodule/sub-submodule &&
- git config remote.origin.url
+ test ! -d "$(
+ cd super-clone/submodule/sub-submodule &&
+ git config remote.origin.url
)" &&
- (cd super-clone/submodule &&
- git checkout master &&
- git pull
+ (
+ cd super-clone/submodule &&
+ git checkout master &&
+ git pull
) &&
- (cd super-clone &&
- test -d "$(git config submodule.submodule.url)"
+ (
+ cd super-clone &&
+ test -d "$(git config submodule.submodule.url)"
)
'
test_expect_success '"git submodule sync --recursive" should update all submodule URLs' '
- (cd super-clone &&
- (cd submodule &&
- git pull --no-recurse-submodules
- ) &&
- git submodule sync --recursive
+ (
+ cd super-clone &&
+ (
+ cd submodule &&
+ git pull --no-recurse-submodules
+ ) &&
+ git submodule sync --recursive
+ ) &&
+ test -d "$(
+ cd super-clone/submodule &&
+ git config remote.origin.url
+ )" &&
+ test -d "$(
+ cd super-clone/submodule/sub-submodule &&
+ git config remote.origin.url
+ )" &&
+ (
+ cd super-clone/submodule/sub-submodule &&
+ git checkout master &&
+ git pull
+ )
+'
+
+test_expect_success 'reset submodule URLs' '
+ reset_submodule_urls super-clone
+'
+
+test_expect_success '"git submodule sync" should update submodule URLs - subdirectory' '
+ (
+ cd super-clone &&
+ git pull --no-recurse-submodules &&
+ mkdir -p sub &&
+ cd sub &&
+ git submodule sync >../../output
+ ) &&
+ grep "\\.\\./submodule" output &&
+ test -d "$(
+ cd super-clone/submodule &&
+ git config remote.origin.url
+ )" &&
+ test ! -d "$(
+ cd super-clone/submodule/sub-submodule &&
+ git config remote.origin.url
+ )" &&
+ (
+ cd super-clone/submodule &&
+ git checkout master &&
+ git pull
+ ) &&
+ (
+ cd super-clone &&
+ test -d "$(git config submodule.submodule.url)"
+ )
+'
+
+test_expect_success '"git submodule sync --recursive" should update all submodule URLs - subdirectory' '
+ (
+ cd super-clone &&
+ (
+ cd submodule &&
+ git pull --no-recurse-submodules
+ ) &&
+ mkdir -p sub &&
+ cd sub &&
+ git submodule sync --recursive >../../output
) &&
- test -d "$(cd super-clone/submodule &&
- git config remote.origin.url
+ grep "\\.\\./submodule/sub-submodule" output &&
+ test -d "$(
+ cd super-clone/submodule &&
+ git config remote.origin.url
)" &&
- test -d "$(cd super-clone/submodule/sub-submodule &&
- git config remote.origin.url
+ test -d "$(
+ cd super-clone/submodule/sub-submodule &&
+ git config remote.origin.url
)" &&
- (cd super-clone/submodule/sub-submodule &&
- git checkout master &&
- git pull
+ (
+ cd super-clone/submodule/sub-submodule &&
+ git checkout master &&
+ git pull
)
'
test_expect_success '"git submodule sync" should update known submodule URLs' '
- (cd empty-clone &&
- git pull &&
- git submodule sync &&
- test -d "$(git config submodule.submodule.url)"
+ (
+ cd empty-clone &&
+ git pull &&
+ git submodule sync &&
+ test -d "$(git config submodule.submodule.url)"
)
'
test_expect_success '"git submodule sync" should not vivify uninteresting submodule' '
- (cd top-only-clone &&
- git pull &&
- git submodule sync &&
- test -z "$(git config submodule.submodule.url)" &&
- git submodule sync submodule &&
- test -z "$(git config submodule.submodule.url)"
+ (
+ cd top-only-clone &&
+ git pull &&
+ git submodule sync &&
+ test -z "$(git config submodule.submodule.url)" &&
+ git submodule sync submodule &&
+ test -z "$(git config submodule.submodule.url)"
)
'
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"
- )
+ (
+ 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"
- )
- (cd submodule/sub-submodule &&
- test "$(git config remote.origin.url)" != "../../foo/submodule"
- )
+ (
+ 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"
+ ) &&
+ (
+ cd submodule/sub-submodule &&
+ test "$(git config remote.origin.url)" != "../../foo/submodule"
+ )
)
'
test_expect_success '"git submodule sync --recursive" propagates changes in origin' '
- (cd recursive-clone &&
- git remote set-url origin foo/bar &&
- git submodule sync --recursive &&
- (cd submodule &&
- #actual foo/submodule
- test "$(git config remote.origin.url)" = "../foo/submodule"
- )
- (cd submodule/sub-submodule &&
- test "$(git config remote.origin.url)" = "../../foo/submodule"
- )
+ (
+ cd recursive-clone &&
+ git remote set-url origin foo/bar &&
+ git submodule sync --recursive &&
+ (
+ cd submodule &&
+ #actual foo/submodule
+ test "$(git config remote.origin.url)" = "../foo/submodule"
+ ) &&
+ (
+ cd submodule/sub-submodule &&
+ test "$(git config remote.origin.url)" = "../../foo/submodule"
+ )
)
'
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"
- )
+ (
+ 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"
- )
+ (
+ 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"
- )
+ (
+ 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"
- )
+ (
+ 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"
- )
+ (
+ 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"
+ )
)
'
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 1a3d20b..b192f93 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -80,6 +80,21 @@ test_expect_success 'submodule update detaching the HEAD ' '
)
'
+test_expect_success 'submodule update from subdirectory' '
+ (cd super/submodule &&
+ git reset --hard HEAD~1
+ ) &&
+ mkdir super/sub &&
+ (cd super/sub &&
+ (cd ../submodule &&
+ compare_head
+ ) &&
+ git submodule update ../submodule &&
+ cd ../submodule &&
+ ! compare_head
+ )
+'
+
apos="'";
test_expect_success 'submodule update does not fetch already present commits' '
(cd submodule &&
@@ -279,6 +294,35 @@ test_expect_success 'submodule update - checkout in .git/config' '
)
'
+test_expect_success 'submodule update - command in .git/config' '
+ (cd super &&
+ git config submodule.submodule.update "!git checkout"
+ ) &&
+ (cd super/submodule &&
+ git reset --hard HEAD^
+ ) &&
+ (cd super &&
+ (cd submodule &&
+ compare_head
+ ) &&
+ git submodule update submodule &&
+ cd submodule &&
+ ! compare_head
+ )
+'
+
+test_expect_success 'submodule update - command in .git/config catches failure' '
+ (cd super &&
+ git config submodule.submodule.update "!false"
+ ) &&
+ (cd super/submodule &&
+ git reset --hard HEAD^
+ ) &&
+ (cd super &&
+ test_must_fail git submodule update submodule
+ )
+'
+
test_expect_success 'submodule init picks up rebase' '
(cd super &&
git config -f .gitmodules submodule.rebasing.update rebase &&
@@ -596,14 +640,14 @@ test_expect_success 'submodule add places git-dir in superprojects git-dir recur
git log > ../../../expected
) &&
git commit -m "added subsubmodule" &&
- git push
+ git push origin :
) &&
(cd .git/modules/deeper/submodule/modules/subsubmodule &&
git log > ../../../../../actual
) &&
git add deeper/submodule &&
git commit -m "update submodule" &&
- git push &&
+ git push origin : &&
test_cmp actual expected
)
'
@@ -665,8 +709,10 @@ test_expect_success 'submodule add properly re-creates deeper level submodules'
test_expect_success 'submodule update properly revives a moved submodule' '
(cd super &&
+ H=$(git rev-parse --short HEAD) &&
git commit -am "pre move" &&
- git status >expect&&
+ H2=$(git rev-parse --short HEAD) &&
+ git status | sed "s/$H/XXX/" >expect &&
H=$(cd submodule2; git rev-parse HEAD) &&
git rm --cached submodule2 &&
rm -rf submodule2 &&
@@ -675,7 +721,7 @@ test_expect_success 'submodule update properly revives a moved submodule' '
git config -f .gitmodules submodule.submodule2.path "moved/sub module"
git commit -am "post move" &&
git submodule update &&
- git status >actual &&
+ git status | sed "s/$H2/XXX/" >actual &&
test_cmp expect actual
)
'
@@ -683,14 +729,24 @@ test_expect_success 'submodule update properly revives a moved submodule' '
test_expect_success SYMLINKS 'submodule update can handle symbolic links in pwd' '
mkdir -p linked/dir &&
ln -s linked/dir linkto &&
- (
- cd linkto &&
- git clone "$TRASH_DIRECTORY"/super_update_r2 super &&
- (
- cd super &&
- git submodule update --init --recursive
- )
+ (cd linkto &&
+ git clone "$TRASH_DIRECTORY"/super_update_r2 super &&
+ (cd super &&
+ git submodule update --init --recursive
+ )
)
'
+test_expect_success 'submodule update clone shallow submodule' '
+ git clone cloned super3 &&
+ pwd=$(pwd)
+ (cd super3 &&
+ sed -e "s#url = ../#url = file://$pwd/#" <.gitmodules >.gitmodules.tmp &&
+ mv -f .gitmodules.tmp .gitmodules &&
+ git submodule update --init --depth=3
+ (cd submodule &&
+ test 1 = $(git log --oneline | wc -l)
+ )
+ )
+'
test_done
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 107b4b7..be93f10 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -80,6 +80,22 @@ test_expect_success 'test basic "submodule foreach" usage' '
test_i18ncmp expect actual
'
+cat >expect <<EOF
+Entering '../sub1'
+$pwd/clone-foo1-../sub1-$sub1sha1
+Entering '../sub3'
+$pwd/clone-foo3-../sub3-$sub3sha1
+EOF
+
+test_expect_success 'test "submodule foreach" from subdirectory' '
+ mkdir clone/sub &&
+ (
+ cd clone/sub &&
+ git submodule foreach "echo \$toplevel-\$name-\$sm_path-\$sha1" >../../actual
+ ) &&
+ test_i18ncmp expect actual
+'
+
test_expect_success 'setup nested submodules' '
git clone submodule nested1 &&
git clone submodule nested2 &&
@@ -129,7 +145,7 @@ test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' '
git rev-parse --resolve-git-dir nested1/.git &&
test_must_fail git rev-parse --resolve-git-dir nested1/nested2/.git &&
git submodule foreach "git submodule update --init" &&
- git rev-parse --resolve-git-dir nested1/nested1/nested2/.git
+ git rev-parse --resolve-git-dir nested1/nested2/.git &&
test_must_fail git rev-parse --resolve-git-dir nested1/nested2/nested3/.git
)
'
diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh
index 1c908f4..bdc1f29 100755
--- a/t/t7500-commit.sh
+++ b/t/t7500-commit.sh
@@ -13,9 +13,9 @@ commit_msg_is () {
expect=commit_msg_is.expect
actual=commit_msg_is.actual
- printf "%s" "$(git log --pretty=format:%s%b -1)" >$expect &&
- printf "%s" "$1" >$actual &&
- test_i18ncmp $expect $actual
+ printf "%s" "$(git log --pretty=format:%s%b -1)" >"$actual" &&
+ printf "%s" "$1" >"$expect" &&
+ test_i18ncmp "$expect" "$actual"
}
# A sanity check to see if commit is working at all.
@@ -36,8 +36,7 @@ test_expect_success 'nonexistent template file should return error' '
'
test_expect_success 'nonexistent template file in config should return error' '
- git config commit.template "$PWD"/notexist &&
- test_when_finished "git config --unset commit.template" &&
+ test_config commit.template "$PWD"/notexist &&
(
GIT_EDITOR="echo hello >\"\$1\"" &&
export GIT_EDITOR &&
@@ -93,14 +92,13 @@ test_expect_success '-t option should be short for --template' '
test_expect_success 'config-specified template should commit' '
echo "new template" > "$TEMPLATE" &&
- git config commit.template "$TEMPLATE" &&
+ test_config commit.template "$TEMPLATE" &&
echo "more content" >> foo &&
git add foo &&
(
test_set_editor "$TEST_DIRECTORY"/t7500/add-content &&
git commit
) &&
- git config --unset commit.template &&
commit_msg_is "new templatecommit message"
'
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index 195e747..99ce36f 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -524,4 +524,17 @@ test_expect_success 'commit a file whose name is a dash' '
test_i18ngrep " changed, 5 insertions" output
'
+test_expect_success '--only works on to-be-born branch' '
+ # This test relies on having something in the index, as it
+ # would not otherwise actually prove much. So check this.
+ test -n "$(git ls-files)" &&
+ git checkout --orphan orphan &&
+ echo foo >newfile &&
+ git add newfile &&
+ git commit --only newfile -m"--only on unborn branch" &&
+ echo newfile >expected &&
+ git ls-tree -r --name-only HEAD >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index 292bc08..6313da2 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -171,10 +171,9 @@ test_expect_success 'verbose' '
test_expect_success 'verbose respects diff config' '
- git config color.diff always &&
+ test_config color.diff always &&
git status -v >actual &&
- grep "\[1mdiff --git" actual &&
- git config --unset color.diff
+ grep "\[1mdiff --git" actual
'
mesg_with_comment_and_newlines='
@@ -263,32 +262,40 @@ test_expect_success 'cleanup commit message (fail on invalid cleanup mode config
test_expect_success 'cleanup commit message (no config and no option uses default)' '
echo content >>file &&
git add file &&
- test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
- git commit --no-status &&
+ (
+ test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
+ git commit --no-status
+ ) &&
commit_msg_is "commit message"
'
test_expect_success 'cleanup commit message (option overrides default)' '
echo content >>file &&
git add file &&
- test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
- git commit --cleanup=whitespace --no-status &&
+ (
+ test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
+ git commit --cleanup=whitespace --no-status
+ ) &&
commit_msg_is "commit message # comment"
'
test_expect_success 'cleanup commit message (config overrides default)' '
echo content >>file &&
git add file &&
- test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
- git -c commit.cleanup=whitespace commit --no-status &&
+ (
+ test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
+ git -c commit.cleanup=whitespace commit --no-status
+ ) &&
commit_msg_is "commit message # comment"
'
test_expect_success 'cleanup commit message (option overrides config)' '
echo content >>file &&
git add file &&
- test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
- git -c commit.cleanup=whitespace commit --cleanup=default &&
+ (
+ test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
+ git -c commit.cleanup=whitespace commit --cleanup=default
+ ) &&
commit_msg_is "commit message"
'
@@ -354,6 +361,23 @@ test_expect_success !AUTOIDENT 'do not fire editor when committer is bogus' '
test_cmp expect .git/result
'
+test_expect_success 'do not fire editor if -m <msg> was given' '
+ echo tick >file &&
+ git add file &&
+ echo "editor not started" >.git/result &&
+ (GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" git commit -m tick) &&
+ test "$(cat .git/result)" = "editor not started"
+'
+
+test_expect_success 'do not fire editor if -m "" was given' '
+ echo tock >file &&
+ git add file &&
+ echo "editor not started" >.git/result &&
+ (GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" \
+ git commit -m "" --allow-empty-message) &&
+ test "$(cat .git/result)" = "editor not started"
+'
+
test_expect_success 'do not fire editor in the presence of conflicts' '
git clean -f &&
@@ -417,6 +441,18 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
'
+test_expect_success 'commit -s places sob on third line after two empty lines' '
+ git commit -s --allow-empty --allow-empty-message &&
+ cat <<-EOF >expect &&
+
+
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+
+ EOF
+ sed -e "/^#/d" -e "s/^:.*//" .git/COMMIT_EDITMSG >actual &&
+ test_cmp expect actual
+'
+
write_script .git/FAKE_EDITOR <<\EOF
mv "$1" "$1.orig"
(
@@ -427,16 +463,6 @@ EOF
echo '## Custom template' >template
-clear_config () {
- (
- git config --unset-all "$1"
- case $? in
- 0|5) exit 0 ;;
- *) exit 1 ;;
- esac
- )
-}
-
try_commit () {
git reset --hard &&
echo >>negative &&
@@ -452,67 +478,57 @@ try_commit () {
try_commit_status_combo () {
test_expect_success 'commit' '
- clear_config commit.status &&
try_commit "" &&
test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit' '
- clear_config commit.status &&
try_commit "" &&
test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --status' '
- clear_config commit.status &&
try_commit --status &&
test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --no-status' '
- clear_config commit.status &&
try_commit --no-status &&
test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit with commit.status = yes' '
- clear_config commit.status &&
- git config commit.status yes &&
+ test_config commit.status yes &&
try_commit "" &&
test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit with commit.status = no' '
- clear_config commit.status &&
- git config commit.status no &&
+ test_config commit.status no &&
try_commit "" &&
test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --status with commit.status = yes' '
- clear_config commit.status &&
- git config commit.status yes &&
+ test_config commit.status yes &&
try_commit --status &&
test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --no-status with commit.status = yes' '
- clear_config commit.status &&
- git config commit.status yes &&
+ test_config commit.status yes &&
try_commit --no-status &&
test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --status with commit.status = no' '
- clear_config commit.status &&
- git config commit.status no &&
+ test_config commit.status no &&
try_commit --status &&
test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --no-status with commit.status = no' '
- clear_config commit.status &&
- git config commit.status no &&
+ test_config commit.status no &&
try_commit --no-status &&
test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
@@ -526,8 +542,7 @@ use_template="-t template"
try_commit_status_combo
test_expect_success 'commit --status with custom comment character' '
- test_when_finished "git config --unset core.commentchar" &&
- git config core.commentchar ";" &&
+ test_config core.commentchar ";" &&
try_commit --status &&
test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG
'
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index aecb4d1..ac3d0fe 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -131,8 +131,7 @@ cat >expect <<\EOF
EOF
test_expect_success 'status (advice.statusHints false)' '
- test_when_finished "git config --unset advice.statusHints" &&
- git config advice.statusHints false &&
+ test_config advice.statusHints false &&
git status >output &&
test_i18ncmp expect output
@@ -332,8 +331,7 @@ test_expect_success 'status -uno' '
'
test_expect_success 'status (status.showUntrackedFiles no)' '
- git config status.showuntrackedfiles no
- test_when_finished "git config --unset status.showuntrackedfiles" &&
+ test_config status.showuntrackedfiles no &&
git status >output &&
test_i18ncmp expect output
'
@@ -348,12 +346,11 @@ cat >expect <<EOF
#
# Untracked files not listed
EOF
-git config advice.statusHints false
test_expect_success 'status -uno (advice.statusHints false)' '
+ test_config advice.statusHints false &&
git status -uno >output &&
test_i18ncmp expect output
'
-git config --unset advice.statusHints
cat >expect << EOF
M dir1/modified
@@ -400,8 +397,7 @@ test_expect_success 'status -unormal' '
'
test_expect_success 'status (status.showUntrackedFiles normal)' '
- git config status.showuntrackedfiles normal
- test_when_finished "git config --unset status.showuntrackedfiles" &&
+ test_config status.showuntrackedfiles normal
git status >output &&
test_i18ncmp expect output
'
@@ -459,8 +455,7 @@ test_expect_success 'status -uall' '
'
test_expect_success 'status (status.showUntrackedFiles all)' '
- git config status.showuntrackedfiles all
- test_when_finished "git config --unset status.showuntrackedfiles" &&
+ test_config status.showuntrackedfiles all
git status >output &&
test_i18ncmp expect output
'
@@ -485,10 +480,9 @@ test_expect_success 'status -s -uall' '
test_cmp expect output
'
test_expect_success 'status -s (status.showUntrackedFiles all)' '
- git config status.showuntrackedfiles all
+ test_config status.showuntrackedfiles all &&
git status -s >output &&
rm -rf dir3 &&
- git config --unset status.showuntrackedfiles &&
test_cmp expect output
'
@@ -588,15 +582,13 @@ cat >expect <<\EOF
EOF
test_expect_success 'status with color.ui' '
- git config color.ui always &&
- test_when_finished "git config --unset color.ui" &&
+ test_config color.ui always &&
git status | test_decode_color >output &&
test_i18ncmp expect output
'
test_expect_success 'status with color.status' '
- git config color.status always &&
- test_when_finished "git config --unset color.status" &&
+ test_config color.status always &&
git status | test_decode_color >output &&
test_i18ncmp expect output
'
@@ -720,8 +712,7 @@ EOF
test_expect_success 'status without relative paths' '
- git config status.relativePaths false &&
- test_when_finished "git config --unset status.relativePaths" &&
+ test_config status.relativePaths false &&
(cd dir1 && git status) >output &&
test_i18ncmp expect output
@@ -740,8 +731,7 @@ EOF
test_expect_success 'status -s without relative paths' '
- git config status.relativePaths false &&
- test_when_finished "git config --unset status.relativePaths" &&
+ test_config status.relativePaths false &&
(cd dir1 && git status -s) >output &&
test_cmp expect output
@@ -1038,15 +1028,14 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un
'
test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' '
- git config diff.ignoreSubmodules dirty &&
+ test_config diff.ignoreSubmodules dirty &&
git status >output &&
test_i18ncmp expect output &&
git config --add -f .gitmodules submodule.subname.ignore untracked &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status >output &&
test_i18ncmp expect output &&
- git config -f .gitmodules --remove-section submodule.subname &&
- git config --unset diff.ignoreSubmodules
+ git config -f .gitmodules --remove-section submodule.subname
'
test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' '
@@ -1066,15 +1055,14 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with untrac
'
test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' '
- git config diff.ignoreSubmodules dirty &&
+ test_config diff.ignoreSubmodules dirty &&
git status >output &&
! test -s actual &&
git config --add -f .gitmodules submodule.subname.ignore dirty &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status >output &&
test_i18ncmp expect output &&
- git config -f .gitmodules --remove-section submodule.subname &&
- git config --unset diff.ignoreSubmodules
+ git config -f .gitmodules --remove-section submodule.subname
'
test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' '
@@ -1291,15 +1279,13 @@ cat > expect << EOF
EOF
test_expect_success "status (core.commentchar with submodule summary)" '
- test_when_finished "git config --unset core.commentchar" &&
- git config core.commentchar ";" &&
+ test_config core.commentchar ";" &&
git status >output &&
test_i18ncmp expect output
'
test_expect_success "status (core.commentchar with two chars with submodule summary)" '
- test_when_finished "git config --unset core.commentchar" &&
- git config core.commentchar ";;" &&
+ test_config core.commentchar ";;" &&
git status >output &&
test_i18ncmp expect output
'
@@ -1349,4 +1335,66 @@ test_expect_failure '.git/config ignore=all suppresses submodule summary' '
git config -f .gitmodules --remove-section submodule.subname
'
+test_expect_success 'setup of test environment' '
+ git config status.showUntrackedFiles no &&
+ git status -s >expected_short &&
+ git status --no-short >expected_noshort
+'
+
+test_expect_success '"status.short=true" same as "-s"' '
+ git -c status.short=true status >actual &&
+ test_cmp expected_short actual
+'
+
+test_expect_success '"status.short=true" weaker than "--no-short"' '
+ git -c status.short=true status --no-short >actual &&
+ test_cmp expected_noshort actual
+'
+
+test_expect_success '"status.short=false" same as "--no-short"' '
+ git -c status.short=false status >actual &&
+ test_cmp expected_noshort actual
+'
+
+test_expect_success '"status.short=false" weaker than "-s"' '
+ git -c status.short=false status -s >actual &&
+ test_cmp expected_short actual
+'
+
+test_expect_success '"status.branch=true" same as "-b"' '
+ git status -sb >expected_branch &&
+ git -c status.branch=true status -s >actual &&
+ test_cmp expected_branch actual
+'
+
+test_expect_success '"status.branch=true" different from "--no-branch"' '
+ git status -s --no-branch >expected_nobranch &&
+ git -c status.branch=true status -s >actual &&
+ test_must_fail test_cmp expected_nobranch actual
+'
+
+test_expect_success '"status.branch=true" weaker than "--no-branch"' '
+ git -c status.branch=true status -s --no-branch >actual &&
+ test_cmp expected_nobranch actual
+'
+
+test_expect_success '"status.branch=true" weaker than "--porcelain"' '
+ git -c status.branch=true status --porcelain >actual &&
+ test_cmp expected_nobranch actual
+'
+
+test_expect_success '"status.branch=false" same as "--no-branch"' '
+ git -c status.branch=false status -s >actual &&
+ test_cmp expected_nobranch actual
+'
+
+test_expect_success '"status.branch=false" weaker than "-b"' '
+ git -c status.branch=false status -sb >actual &&
+ test_cmp expected_branch actual
+'
+
+test_expect_success 'Restore default test environment' '
+ git config --unset status.showUntrackedFiles
+'
+
test_done
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
index 9d46106..31a798f 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -77,7 +77,7 @@ test_expect_success 'status when rebase in progress before resolving conflicts'
ONTO=$(git rev-parse --short HEAD^^) &&
test_must_fail git rebase HEAD^ --onto HEAD^^ &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
# (fix conflicts and then run "git rebase --continue")
# (use "git rebase --skip" to skip this patch)
@@ -104,7 +104,7 @@ test_expect_success 'status when rebase in progress before rebase --continue' '
echo three >main.txt &&
git add main.txt &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
# (all conflicts fixed: run "git rebase --continue")
#
@@ -136,7 +136,7 @@ test_expect_success 'status during rebase -i when conflicts unresolved' '
ONTO=$(git rev-parse --short rebase_i_conflicts) &&
test_must_fail git rebase -i rebase_i_conflicts &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
# (fix conflicts and then run "git rebase --continue")
# (use "git rebase --skip" to skip this patch)
@@ -162,7 +162,7 @@ test_expect_success 'status during rebase -i after resolving conflicts' '
test_must_fail git rebase -i rebase_i_conflicts &&
git add main.txt &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
# (all conflicts fixed: run "git rebase --continue")
#
@@ -190,7 +190,7 @@ test_expect_success 'status when rebasing -i in edit mode' '
ONTO=$(git rev-parse --short HEAD~2) &&
git rebase -i HEAD~2 &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently editing a commit while rebasing branch '\''rebase_i_edit'\'' on '\''$ONTO'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
@@ -216,7 +216,7 @@ test_expect_success 'status when splitting a commit' '
git rebase -i HEAD~3 &&
git reset HEAD^ &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''$ONTO'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
@@ -247,7 +247,7 @@ test_expect_success 'status after editing the last commit with --amend during a
git rebase -i HEAD~3 &&
git commit --amend -m "foo" &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently editing a commit while rebasing branch '\''amend_last'\'' on '\''$ONTO'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
@@ -277,7 +277,7 @@ test_expect_success 'status: (continue first edit) second edit' '
git rebase -i HEAD~3 &&
git rebase --continue &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
@@ -299,7 +299,7 @@ test_expect_success 'status: (continue first edit) second edit and split' '
git rebase --continue &&
git reset HEAD^ &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
@@ -326,7 +326,7 @@ test_expect_success 'status: (continue first edit) second edit and amend' '
git rebase --continue &&
git commit --amend -m "foo" &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
@@ -348,7 +348,7 @@ test_expect_success 'status: (amend first edit) second edit' '
git commit --amend -m "a" &&
git rebase --continue &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
@@ -371,7 +371,7 @@ test_expect_success 'status: (amend first edit) second edit and split' '
git rebase --continue &&
git reset HEAD^ &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
@@ -399,7 +399,7 @@ test_expect_success 'status: (amend first edit) second edit and amend' '
git rebase --continue &&
git commit --amend -m "d" &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
@@ -423,7 +423,7 @@ test_expect_success 'status: (split first edit) second edit' '
git commit -m "e" &&
git rebase --continue &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
@@ -448,7 +448,7 @@ test_expect_success 'status: (split first edit) second edit and split' '
git rebase --continue &&
git reset HEAD^ &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
@@ -478,7 +478,7 @@ test_expect_success 'status: (split first edit) second edit and amend' '
git rebase --continue &&
git commit --amend -m "h" &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
@@ -507,7 +507,7 @@ test_expect_success 'status in an am session: file already exists' '
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")
+ # (fix conflicts and then run "git am --continue")
# (use "git am --skip" to skip this patch)
# (use "git am --abort" to restore the original branch)
#
@@ -529,7 +529,7 @@ test_expect_success 'status in an am session: file does not exist' '
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")
+ # (fix conflicts and then run "git am --continue")
# (use "git am --skip" to skip this patch)
# (use "git am --abort" to restore the original branch)
#
@@ -573,9 +573,10 @@ test_expect_success 'status when bisecting' '
git bisect start &&
git bisect bad &&
git bisect good one_bisect &&
- cat >expected <<-\EOF &&
- # Not currently on any branch.
- # You are currently bisecting branch '\''bisect'\''.
+ TGT=$(git rev-parse --short two_bisect) &&
+ cat >expected <<-EOF &&
+ # HEAD detached at $TGT
+ # You are currently bisecting, started from branch '\''bisect'\''.
# (use "git bisect reset" to get back to the original branch)
#
nothing to commit (use -u to show untracked files)
@@ -597,7 +598,7 @@ test_expect_success 'status when rebase conflicts with statushints disabled' '
ONTO=$(git rev-parse --short HEAD^^) &&
test_must_fail git rebase HEAD^ --onto HEAD^^ &&
cat >expected <<-EOF &&
- # Not currently on any branch.
+ # rebase in progress; onto $ONTO
# You are currently rebasing branch '\''statushints_disabled'\'' on '\''$ONTO'\''.
#
# Unmerged paths:
@@ -628,7 +629,8 @@ test_expect_success 'status when cherry-picking before resolving conflicts' '
cat >expected <<-\EOF &&
# On branch cherry_branch
# You are currently cherry-picking.
- # (fix conflicts and run "git commit")
+ # (fix conflicts and run "git cherry-pick --continue")
+ # (use "git cherry-pick --abort" to cancel the cherry-pick operation)
#
# Unmerged paths:
# (use "git add <file>..." to mark resolution)
@@ -651,7 +653,8 @@ test_expect_success 'status when cherry-picking after resolving conflicts' '
cat >expected <<-\EOF &&
# On branch cherry_branch
# You are currently cherry-picking.
- # (all conflicts fixed: run "git commit")
+ # (all conflicts fixed: run "git cherry-pick --continue")
+ # (use "git cherry-pick --abort" to cancel the cherry-pick operation)
#
# Changes to be committed:
#
@@ -663,5 +666,81 @@ test_expect_success 'status when cherry-picking after resolving conflicts' '
test_i18ncmp expected actual
'
+test_expect_success 'status showing detached at and from a tag' '
+ test_commit atag tagging &&
+ git checkout atag &&
+ cat >expected <<-\EOF
+ # HEAD detached at atag
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual &&
+
+ git reset --hard HEAD^ &&
+ cat >expected <<-\EOF
+ # HEAD detached from atag
+ nothing to commit (use -u to show untracked files)
+ EOF
+ git status --untracked-files=no >actual &&
+ test_i18ncmp expected actual
+'
+
+test_expect_success 'status while reverting commit (conflicts)' '
+ git checkout master &&
+ echo before >to-revert.txt &&
+ test_commit before to-revert.txt &&
+ echo old >to-revert.txt &&
+ test_commit old to-revert.txt &&
+ echo new >to-revert.txt &&
+ test_commit new to-revert.txt &&
+ TO_REVERT=$(git rev-parse --short HEAD^) &&
+ test_must_fail git revert $TO_REVERT &&
+ cat >expected <<-EOF
+ # On branch master
+ # You are currently reverting commit $TO_REVERT.
+ # (fix conflicts and run "git revert --continue")
+ # (use "git revert --abort" to cancel the revert operation)
+ #
+ # Unmerged paths:
+ # (use "git reset HEAD <file>..." to unstage)
+ # (use "git add <file>..." to mark resolution)
+ #
+ # both modified: to-revert.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 while reverting commit (conflicts resolved)' '
+ echo reverted >to-revert.txt &&
+ git add to-revert.txt &&
+ cat >expected <<-EOF
+ # On branch master
+ # You are currently reverting commit $TO_REVERT.
+ # (all conflicts fixed: run "git revert --continue")
+ # (use "git revert --abort" to cancel the revert operation)
+ #
+ # Changes to be committed:
+ # (use "git reset HEAD <file>..." to unstage)
+ #
+ # modified: to-revert.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 after reverting commit' '
+ git revert --continue &&
+ cat >expected <<-\EOF
+ # On branch master
+ nothing to commit (use -u 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 5e19598..10aa028 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -56,7 +56,8 @@ create_merge_msgs () {
echo &&
git log --no-merges ^HEAD c2 c3
} >squash.1-5-9 &&
- echo >msg.nolog &&
+ : >msg.nologff &&
+ echo >msg.nolognoff &&
{
echo "* tag 'c3':" &&
echo " commit 3" &&
@@ -244,8 +245,7 @@ test_expect_success 'merges with --ff-only' '
test_expect_success 'merges with merge.ff=only' '
git reset --hard c1 &&
test_tick &&
- test_when_finished "git config --unset merge.ff" &&
- git config merge.ff only &&
+ test_config merge.ff "only" &&
test_must_fail git merge c2 &&
test_must_fail git merge c3 &&
test_must_fail git merge c2 c3 &&
@@ -316,7 +316,7 @@ test_expect_success 'merge c1 with c2 (squash)' '
test_debug 'git log --graph --decorate --oneline --all'
-test_expect_success 'unsuccesful merge of c1 with c2 (squash, ff-only)' '
+test_expect_success 'unsuccessful merge of c1 with c2 (squash, ff-only)' '
git reset --hard c1 &&
test_must_fail git merge --squash --ff-only c2
'
@@ -336,7 +336,7 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c1 with c2 (no-commit in config)' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "--no-commit" &&
+ test_config branch.master.mergeoptions "--no-commit" &&
git merge c2 &&
verify_merge file result.1-5 &&
verify_head $c1 &&
@@ -346,12 +346,11 @@ test_expect_success 'merge c1 with c2 (no-commit in config)' '
test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c1 with c2 (log in config)' '
- git config branch.master.mergeoptions "" &&
git reset --hard c1 &&
git merge --log c2 &&
git show -s --pretty=tformat:%s%n%b >expect &&
- git config branch.master.mergeoptions --log &&
+ test_config branch.master.mergeoptions "--log" &&
git reset --hard c1 &&
git merge c2 &&
git show -s --pretty=tformat:%s%n%b >actual &&
@@ -360,17 +359,12 @@ test_expect_success 'merge c1 with c2 (log in config)' '
'
test_expect_success 'merge c1 with c2 (log in config gets overridden)' '
- test_when_finished "git config --remove-section branch.master" &&
- test_when_finished "git config --remove-section merge" &&
- test_might_fail git config --remove-section branch.master &&
- test_might_fail git config --remove-section merge &&
-
git reset --hard c1 &&
git merge c2 &&
git show -s --pretty=tformat:%s%n%b >expect &&
- git config branch.master.mergeoptions "--no-log" &&
- git config merge.log true &&
+ test_config branch.master.mergeoptions "--no-log" &&
+ test_config merge.log "true" &&
git reset --hard c1 &&
git merge c2 &&
git show -s --pretty=tformat:%s%n%b >actual &&
@@ -380,7 +374,7 @@ test_expect_success 'merge c1 with c2 (log in config gets overridden)' '
test_expect_success 'merge c1 with c2 (squash in config)' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "--squash" &&
+ test_config branch.master.mergeoptions "--squash" &&
git merge c2 &&
verify_merge file result.1-5 &&
verify_head $c1 &&
@@ -392,7 +386,7 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'override config option -n with --summary' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "-n" &&
+ test_config branch.master.mergeoptions "-n" &&
test_tick &&
git merge --summary c2 >diffstat.txt &&
verify_merge file result.1-5 msg.1-5 &&
@@ -406,7 +400,7 @@ test_expect_success 'override config option -n with --summary' '
test_expect_success 'override config option -n with --stat' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "-n" &&
+ test_config branch.master.mergeoptions "-n" &&
test_tick &&
git merge --stat c2 >diffstat.txt &&
verify_merge file result.1-5 msg.1-5 &&
@@ -422,7 +416,7 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'override config option --stat' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "--stat" &&
+ test_config branch.master.mergeoptions "--stat" &&
test_tick &&
git merge -n c2 >diffstat.txt &&
verify_merge file result.1-5 msg.1-5 &&
@@ -438,7 +432,7 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c1 with c2 (override --no-commit)' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "--no-commit" &&
+ test_config branch.master.mergeoptions "--no-commit" &&
test_tick &&
git merge --commit c2 &&
verify_merge file result.1-5 msg.1-5 &&
@@ -449,7 +443,7 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c1 with c2 (override --squash)' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "--squash" &&
+ test_config branch.master.mergeoptions "--squash" &&
test_tick &&
git merge --no-squash c2 &&
verify_merge file result.1-5 msg.1-5 &&
@@ -460,7 +454,6 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c0 with c1 (no-ff)' '
git reset --hard c0 &&
- git config branch.master.mergeoptions "" &&
test_tick &&
git merge --no-ff c1 &&
verify_merge file result.1 &&
@@ -471,10 +464,9 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c0 with c1 (merge.ff=false)' '
git reset --hard c0 &&
- git config merge.ff false &&
+ test_config merge.ff "false" &&
test_tick &&
git merge c1 &&
- git config --remove-section merge &&
verify_merge file result.1 &&
verify_parents $c0 $c1
'
@@ -482,22 +474,19 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'combine branch.master.mergeoptions with merge.ff' '
git reset --hard c0 &&
- git config branch.master.mergeoptions --ff &&
- git config merge.ff false &&
+ test_config branch.master.mergeoptions "--ff" &&
+ test_config merge.ff "false" &&
test_tick &&
git merge c1 &&
- git config --remove-section "branch.master" &&
- git config --remove-section "merge" &&
verify_merge file result.1 &&
verify_parents "$c0"
'
test_expect_success 'tolerate unknown values for merge.ff' '
git reset --hard c0 &&
- git config merge.ff something-new &&
+ test_config merge.ff "something-new" &&
test_tick &&
git merge c1 2>message &&
- git config --remove-section "merge" &&
verify_head "$c1" &&
test_cmp empty message
'
@@ -508,14 +497,20 @@ test_expect_success 'combining --squash and --no-ff is refused' '
test_must_fail git merge --no-ff --squash c1
'
-test_expect_success 'combining --ff-only and --no-ff is refused' '
- test_must_fail git merge --ff-only --no-ff c1 &&
- test_must_fail git merge --no-ff --ff-only c1
+test_expect_success 'option --ff-only overwrites --no-ff' '
+ git merge --no-ff --ff-only c1 &&
+ test_must_fail git merge --no-ff --ff-only c2
+'
+
+test_expect_success 'option --no-ff overrides merge.ff=only config' '
+ git reset --hard c0 &&
+ test_config merge.ff only &&
+ git merge --no-ff c1
'
test_expect_success 'merge c0 with c1 (ff overrides no-ff)' '
git reset --hard c0 &&
- git config branch.master.mergeoptions "--no-ff" &&
+ test_config branch.master.mergeoptions "--no-ff" &&
git merge --ff c1 &&
verify_merge file result.1 &&
verify_head $c1
@@ -525,14 +520,20 @@ test_expect_success 'merge log message' '
git reset --hard c0 &&
git merge --no-log c2 &&
git show -s --pretty=format:%b HEAD >msg.act &&
- test_cmp msg.nolog msg.act &&
+ test_cmp msg.nologff msg.act &&
+
+ git reset --hard c0 &&
+ test_config branch.master.mergeoptions "--no-ff" &&
+ git merge --no-log c2 &&
+ git show -s --pretty=format:%b HEAD >msg.act &&
+ test_cmp msg.nolognoff msg.act &&
git merge --log c3 &&
git show -s --pretty=format:%b HEAD >msg.act &&
test_cmp msg.log msg.act &&
git reset --hard HEAD^ &&
- git config merge.log yes &&
+ test_config merge.log "yes" &&
git merge c3 &&
git show -s --pretty=format:%b HEAD >msg.act &&
test_cmp msg.log msg.act
@@ -542,7 +543,6 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c1 with c0, c2, c0, and c1' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "" &&
test_tick &&
git merge c0 c2 c0 c1 &&
verify_merge file result.1-5 &&
@@ -553,7 +553,6 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c1 with c0, c2, c0, and c1' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "" &&
test_tick &&
git merge c0 c2 c0 c1 &&
verify_merge file result.1-5 &&
@@ -564,7 +563,6 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c1 with c1 and c2' '
git reset --hard c1 &&
- git config branch.master.mergeoptions "" &&
test_tick &&
git merge c1 c2 &&
verify_merge file result.1-5 &&
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index 25dac79..830a4c3 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -109,7 +109,7 @@ test_expect_success 'setup conflicted merge' '
'
# First do the merge with resolve and recursive then verify that
-# recusive is chosen.
+# recursive is chosen.
test_expect_success 'merge picks up the best result' '
git config --unset-all pull.twohead &&
diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh
index 6547eb8..758a623 100755
--- a/t/t7607-merge-overwrite.sh
+++ b/t/t7607-merge-overwrite.sh
@@ -141,11 +141,10 @@ test_expect_success SYMLINKS 'will not overwrite untracked symlink in leading pa
test_path_is_missing .git/MERGE_HEAD
'
-test_expect_success SYMLINKS 'will not be confused by symlink in leading path' '
+test_expect_success 'will not be confused by symlink in leading path' '
git reset --hard c0 &&
rm -rf sub &&
- ln -s sub2 sub &&
- git add sub &&
+ test_ln_s_add sub2 sub &&
git commit -m ln &&
git checkout sub
'
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
index d526b1d..05d9db0 100755
--- a/t/t7610-mergetool.sh
+++ b/t/t7610-mergetool.sh
@@ -253,7 +253,7 @@ test_expect_success 'deleted vs modified submodule' '
git checkout -b test6 branch1 &&
git submodule update -N &&
mv submod submod-movedaside &&
- git rm submod &&
+ git rm --cached submod &&
git commit -m "Submodule deleted from branch" &&
git checkout -b test6.a test6 &&
test_must_fail git merge master &&
@@ -322,7 +322,7 @@ test_expect_success 'file vs modified submodule' '
git checkout -b test7 branch1 &&
git submodule update -N &&
mv submod submod-movedaside &&
- git rm submod &&
+ git rm --cached submod &&
echo not a submodule >submod &&
git add submod &&
git commit -m "Submodule path becomes file" &&
@@ -453,7 +453,7 @@ test_expect_success 'submodule in subdirectory' '
test_expect_success 'directory vs modified submodule' '
git checkout -b test11 branch1 &&
mv submod submod-movedaside &&
- git rm submod &&
+ git rm --cached submod &&
mkdir submod &&
echo not a submodule >submod/file16 &&
git add submod/file16 &&
diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh
new file mode 100755
index 0000000..21a0bf8
--- /dev/null
+++ b/t/t7612-merge-verify-signatures.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+test_description='merge signature verification tests'
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-gpg.sh"
+
+test_expect_success GPG 'create signed commits' '
+ echo 1 >file && git add file &&
+ test_tick && git commit -m initial &&
+ git tag initial &&
+
+ git checkout -b side-signed &&
+ echo 3 >elif && git add elif &&
+ test_tick && git commit -S -m "signed on side" &&
+ git checkout initial &&
+
+ git checkout -b side-unsigned &&
+ echo 3 >foo && git add foo &&
+ test_tick && git commit -m "unsigned on side" &&
+ git checkout initial &&
+
+ git checkout -b side-bad &&
+ echo 3 >bar && git add bar &&
+ test_tick && git commit -S -m "bad on side" &&
+ git cat-file commit side-bad >raw &&
+ sed -e "s/bad/forged bad/" raw >forged &&
+ git hash-object -w -t commit forged >forged.commit &&
+ git checkout initial &&
+
+ git checkout -b side-untrusted &&
+ echo 3 >baz && git add baz &&
+ test_tick && git commit -SB7227189 -m "untrusted on side"
+
+ git checkout master
+'
+
+test_expect_success GPG 'merge unsigned commit with verification' '
+ test_must_fail git merge --ff-only --verify-signatures side-unsigned 2>mergeerror &&
+ test_i18ngrep "does not have a GPG signature" mergeerror
+'
+
+test_expect_success GPG 'merge commit with bad signature with verification' '
+ test_must_fail git merge --ff-only --verify-signatures $(cat forged.commit) 2>mergeerror &&
+ test_i18ngrep "has a bad GPG signature" mergeerror
+'
+
+test_expect_success GPG 'merge commit with untrusted signature with verification' '
+ test_must_fail git merge --ff-only --verify-signatures side-untrusted 2>mergeerror &&
+ test_i18ngrep "has an untrusted GPG signature" mergeerror
+'
+
+test_expect_success GPG 'merge signed commit with verification' '
+ git merge --verbose --ff-only --verify-signatures side-signed >mergeoutput &&
+ test_i18ngrep "has a good GPG signature" mergeoutput
+'
+
+test_expect_success GPG 'merge commit with bad signature without verification' '
+ git merge $(cat forged.commit)
+'
+
+test_done
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index eb1d3f8..2418528 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2009, 2010 David Aguilar
+# Copyright (c) 2009, 2010, 2012, 2013 David Aguilar
#
test_description='git-difftool
@@ -10,47 +10,19 @@ Testing basic diff tool invocation
. ./test-lib.sh
-remove_config_vars()
+difftool_test_setup ()
{
- # Unset all config variables used by git-difftool
- git config --unset diff.tool
- git config --unset diff.guitool
- git config --unset difftool.test-tool.cmd
- git config --unset difftool.prompt
- git config --unset merge.tool
- git config --unset mergetool.test-tool.cmd
- git config --unset mergetool.prompt
- return 0
+ test_config diff.tool test-tool &&
+ test_config difftool.test-tool.cmd 'cat "$LOCAL"' &&
+ test_config difftool.bogus-tool.cmd false
}
-restore_test_defaults()
-{
- # Restores the test defaults used by several tests
- remove_config_vars
- unset GIT_DIFF_TOOL
- unset GIT_DIFFTOOL_PROMPT
- unset GIT_DIFFTOOL_NO_PROMPT
- git config diff.tool test-tool &&
- git config difftool.test-tool.cmd 'cat $LOCAL'
- git config difftool.bogus-tool.cmd false
-}
-
-prompt_given()
+prompt_given ()
{
prompt="$1"
test "$prompt" = "Launch 'test-tool' [Y/n]: branch"
}
-stdin_contains()
-{
- grep >/dev/null "$1"
-}
-
-stdin_doesnot_contain()
-{
- ! stdin_contains "$1"
-}
-
# Create a file on master and change it on branch
test_expect_success PERL 'setup' '
echo master >file &&
@@ -65,249 +37,237 @@ test_expect_success PERL 'setup' '
# Configure a custom difftool.<tool>.cmd and use it
test_expect_success PERL 'custom commands' '
- restore_test_defaults &&
- git config difftool.test-tool.cmd "cat \$REMOTE" &&
+ difftool_test_setup &&
+ test_config difftool.test-tool.cmd "cat \"\$REMOTE\"" &&
+ echo master >expect &&
+ git difftool --no-prompt branch >actual &&
+ test_cmp expect actual &&
- diff=$(git difftool --no-prompt branch) &&
- test "$diff" = "master" &&
-
- restore_test_defaults &&
- diff=$(git difftool --no-prompt branch) &&
- test "$diff" = "branch"
+ test_config difftool.test-tool.cmd "cat \"\$LOCAL\"" &&
+ echo branch >expect &&
+ git difftool --no-prompt branch >actual &&
+ test_cmp expect actual
'
-# 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
+test_expect_success PERL 'custom tool commands override built-ins' '
+ test_config difftool.vimdiff.cmd "cat \"\$REMOTE\"" &&
+ echo master >expect &&
+ git difftool --tool vimdiff --no-prompt branch >actual &&
+ test_cmp expect actual
'
-# 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)
- test "$?" = 1 &&
- test "$diff" = ""
+ : >expect &&
+ test_expect_code 1 \
+ git difftool --no-prompt --tool=bad-tool branch >actual &&
+ test_cmp expect actual
'
test_expect_success PERL 'difftool forwards arguments to diff' '
+ difftool_test_setup &&
>for-diff &&
git add for-diff &&
echo changes>for-diff &&
git add for-diff &&
- diff=$(git difftool --cached --no-prompt -- for-diff) &&
- test "$diff" = "" &&
+ : >expect &&
+ git difftool --cached --no-prompt -- for-diff >actual &&
+ test_cmp expect actual &&
git reset -- for-diff &&
rm for-diff
'
test_expect_success PERL 'difftool honors --gui' '
- git config merge.tool bogus-tool &&
- git config diff.tool bogus-tool &&
- git config diff.guitool test-tool &&
+ difftool_test_setup &&
+ test_config merge.tool bogus-tool &&
+ test_config diff.tool bogus-tool &&
+ test_config diff.guitool test-tool &&
- diff=$(git difftool --no-prompt --gui branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults
+ echo branch >expect &&
+ git difftool --no-prompt --gui branch >actual &&
+ test_cmp expect actual
'
test_expect_success PERL 'difftool --gui last setting wins' '
- git config diff.guitool bogus-tool &&
- git difftool --no-prompt --gui --no-gui &&
-
- git config merge.tool bogus-tool &&
- git config diff.tool bogus-tool &&
- git config diff.guitool test-tool &&
- diff=$(git difftool --no-prompt --no-gui --gui branch) &&
- test "$diff" = "branch" &&
+ difftool_test_setup &&
+ : >expect &&
+ git difftool --no-prompt --gui --no-gui >actual &&
+ test_cmp expect actual &&
- restore_test_defaults
+ test_config merge.tool bogus-tool &&
+ test_config diff.tool bogus-tool &&
+ test_config diff.guitool test-tool &&
+ echo branch >expect &&
+ git difftool --no-prompt --no-gui --gui branch >actual &&
+ test_cmp expect actual
'
test_expect_success PERL 'difftool --gui works without configured diff.guitool' '
- git config diff.tool test-tool &&
-
- diff=$(git difftool --no-prompt --gui branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults
+ difftool_test_setup &&
+ echo branch >expect &&
+ git difftool --no-prompt --gui branch >actual &&
+ test_cmp expect actual
'
# Specify the diff tool using $GIT_DIFF_TOOL
test_expect_success PERL 'GIT_DIFF_TOOL variable' '
- test_might_fail git config --unset diff.tool &&
- GIT_DIFF_TOOL=test-tool &&
- export GIT_DIFF_TOOL &&
-
- diff=$(git difftool --no-prompt branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults
+ difftool_test_setup &&
+ git config --unset diff.tool &&
+ echo branch >expect &&
+ GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
+ test_cmp expect actual
'
# Test the $GIT_*_TOOL variables and ensure
# that $GIT_DIFF_TOOL always wins unless --tool is specified
test_expect_success PERL 'GIT_DIFF_TOOL overrides' '
- git config diff.tool bogus-tool &&
- git config merge.tool bogus-tool &&
+ difftool_test_setup &&
+ test_config diff.tool bogus-tool &&
+ test_config merge.tool bogus-tool &&
- GIT_DIFF_TOOL=test-tool &&
- export GIT_DIFF_TOOL &&
+ echo branch >expect &&
+ GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
+ test_cmp expect actual &&
- diff=$(git difftool --no-prompt branch) &&
- test "$diff" = "branch" &&
-
- GIT_DIFF_TOOL=bogus-tool &&
- export GIT_DIFF_TOOL &&
-
- diff=$(git difftool --no-prompt --tool=test-tool branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults
+ test_config diff.tool bogus-tool &&
+ test_config merge.tool bogus-tool &&
+ GIT_DIFF_TOOL=bogus-tool \
+ git difftool --no-prompt --tool=test-tool branch >actual &&
+ test_cmp expect actual
'
# Test that we don't have to pass --no-prompt to difftool
# when $GIT_DIFFTOOL_NO_PROMPT is true
test_expect_success PERL 'GIT_DIFFTOOL_NO_PROMPT variable' '
- GIT_DIFFTOOL_NO_PROMPT=true &&
- export GIT_DIFFTOOL_NO_PROMPT &&
-
- diff=$(git difftool branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults
+ difftool_test_setup &&
+ echo branch >expect &&
+ GIT_DIFFTOOL_NO_PROMPT=true git difftool branch >actual &&
+ test_cmp expect actual
'
# git-difftool supports the difftool.prompt variable.
# Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
test_expect_success PERL 'GIT_DIFFTOOL_PROMPT variable' '
- git config difftool.prompt false &&
- GIT_DIFFTOOL_PROMPT=true &&
- export GIT_DIFFTOOL_PROMPT &&
-
- prompt=$(echo | git difftool branch | tail -1) &&
- prompt_given "$prompt" &&
-
- restore_test_defaults
+ difftool_test_setup &&
+ test_config difftool.prompt false &&
+ echo >input &&
+ GIT_DIFFTOOL_PROMPT=true git difftool branch <input >output &&
+ prompt=$(tail -1 <output) &&
+ prompt_given "$prompt"
'
# Test that we don't have to pass --no-prompt when difftool.prompt is false
test_expect_success PERL 'difftool.prompt config variable is false' '
- git config difftool.prompt false &&
-
- diff=$(git difftool branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults
+ difftool_test_setup &&
+ test_config difftool.prompt false &&
+ echo branch >expect &&
+ git difftool branch >actual &&
+ test_cmp expect actual
'
# Test that we don't have to pass --no-prompt when mergetool.prompt is false
test_expect_success PERL 'difftool merge.prompt = false' '
+ difftool_test_setup &&
test_might_fail git config --unset difftool.prompt &&
- git config mergetool.prompt false &&
-
- diff=$(git difftool branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults
+ test_config mergetool.prompt false &&
+ echo branch >expect &&
+ git difftool branch >actual &&
+ test_cmp expect actual
'
# Test that the -y flag can override difftool.prompt = true
test_expect_success PERL 'difftool.prompt can overridden with -y' '
- git config difftool.prompt true &&
-
- diff=$(git difftool -y branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults
+ difftool_test_setup &&
+ test_config difftool.prompt true &&
+ echo branch >expect &&
+ git difftool -y branch >actual &&
+ test_cmp expect actual
'
# Test that the --prompt flag can override difftool.prompt = false
test_expect_success PERL 'difftool.prompt can overridden with --prompt' '
- git config difftool.prompt false &&
-
- prompt=$(echo | git difftool --prompt branch | tail -1) &&
- prompt_given "$prompt" &&
-
- restore_test_defaults
+ difftool_test_setup &&
+ test_config difftool.prompt false &&
+ echo >input &&
+ git difftool --prompt branch <input >output &&
+ prompt=$(tail -1 <output) &&
+ prompt_given "$prompt"
'
# Test that the last flag passed on the command-line wins
test_expect_success PERL 'difftool last flag wins' '
- diff=$(git difftool --prompt --no-prompt branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults &&
-
- prompt=$(echo | git difftool --no-prompt --prompt branch | tail -1) &&
- prompt_given "$prompt" &&
-
- restore_test_defaults
+ difftool_test_setup &&
+ echo branch >expect &&
+ git difftool --prompt --no-prompt branch >actual &&
+ test_cmp expect actual &&
+ echo >input &&
+ git difftool --no-prompt --prompt branch <input >output &&
+ prompt=$(tail -1 <output) &&
+ prompt_given "$prompt"
'
# git-difftool falls back to git-mergetool config variables
# so test that behavior here
test_expect_success PERL 'difftool + mergetool config variables' '
- remove_config_vars &&
- git config merge.tool test-tool &&
- git config mergetool.test-tool.cmd "cat \$LOCAL" &&
-
- diff=$(git difftool --no-prompt branch) &&
- test "$diff" = "branch" &&
+ test_config merge.tool test-tool &&
+ test_config mergetool.test-tool.cmd "cat \$LOCAL" &&
+ echo branch >expect &&
+ git difftool --no-prompt branch >actual &&
+ test_cmp expect actual &&
# set merge.tool to something bogus, diff.tool to test-tool
- git config merge.tool bogus-tool &&
- git config diff.tool test-tool &&
-
- diff=$(git difftool --no-prompt branch) &&
- test "$diff" = "branch" &&
-
- restore_test_defaults
+ test_config merge.tool bogus-tool &&
+ test_config diff.tool test-tool &&
+ git difftool --no-prompt branch >actual &&
+ test_cmp expect actual
'
test_expect_success PERL 'difftool.<tool>.path' '
- git config difftool.tkdiff.path echo &&
- diff=$(git difftool --tool=tkdiff --no-prompt branch) &&
- git config --unset difftool.tkdiff.path &&
- lines=$(echo "$diff" | grep file | wc -l) &&
- test "$lines" -eq 1 &&
-
- restore_test_defaults
+ test_config difftool.tkdiff.path echo &&
+ git difftool --tool=tkdiff --no-prompt branch >output &&
+ lines=$(grep file output | wc -l) &&
+ test "$lines" -eq 1
'
test_expect_success PERL 'difftool --extcmd=cat' '
- diff=$(git difftool --no-prompt --extcmd=cat branch) &&
- test "$diff" = branch"$LF"master
+ echo branch >expect &&
+ echo master >>expect &&
+ git difftool --no-prompt --extcmd=cat branch >actual &&
+ test_cmp expect actual
'
test_expect_success PERL 'difftool --extcmd cat' '
- diff=$(git difftool --no-prompt --extcmd cat branch) &&
- test "$diff" = branch"$LF"master
+ echo branch >expect &&
+ echo master >>expect &&
+ git difftool --no-prompt --extcmd=cat branch >actual &&
+ test_cmp expect actual
'
test_expect_success PERL 'difftool -x cat' '
- diff=$(git difftool --no-prompt -x cat branch) &&
- test "$diff" = branch"$LF"master
+ echo branch >expect &&
+ echo master >>expect &&
+ git difftool --no-prompt -x cat branch >actual &&
+ test_cmp expect actual
'
test_expect_success PERL 'difftool --extcmd echo arg1' '
- diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"echo\ \$1\" branch) &&
- test "$diff" = file
+ echo file >expect &&
+ git difftool --no-prompt \
+ --extcmd sh\ -c\ \"echo\ \$1\" branch >actual &&
+ test_cmp expect actual
'
test_expect_success PERL 'difftool --extcmd cat arg1' '
- diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"cat\ \$1\" branch) &&
- test "$diff" = master
+ echo master >expect &&
+ git difftool --no-prompt \
+ --extcmd sh\ -c\ \"cat\ \$1\" branch >actual &&
+ test_cmp expect actual
'
test_expect_success PERL 'difftool --extcmd cat arg2' '
- diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"cat\ \$2\" branch) &&
- test "$diff" = branch
+ echo branch >expect &&
+ git difftool --no-prompt \
+ --extcmd sh\ -c\ \"cat\ \$2\" branch >actual &&
+ test_cmp expect actual
'
# Create a second file on master and a different version on branch
@@ -324,26 +284,26 @@ test_expect_success PERL 'setup with 2 files different' '
'
test_expect_success PERL 'say no to the first file' '
- diff=$( (echo n; echo) | git difftool -x cat branch ) &&
-
- echo "$diff" | stdin_contains m2 &&
- echo "$diff" | stdin_contains br2 &&
- echo "$diff" | stdin_doesnot_contain master &&
- echo "$diff" | stdin_doesnot_contain branch
+ (echo n && echo) >input &&
+ git difftool -x cat branch <input >output &&
+ grep m2 output &&
+ grep br2 output &&
+ ! grep master output &&
+ ! grep branch output
'
test_expect_success PERL 'say no to the second file' '
- diff=$( (echo; echo n) | git difftool -x cat branch ) &&
-
- echo "$diff" | stdin_contains master &&
- echo "$diff" | stdin_contains branch &&
- echo "$diff" | stdin_doesnot_contain m2 &&
- echo "$diff" | stdin_doesnot_contain br2
+ (echo && echo n) >input &&
+ git difftool -x cat branch <input >output &&
+ grep master output &&
+ grep branch output &&
+ ! grep m2 output &&
+ ! grep br2 output
'
test_expect_success PERL 'difftool --tool-help' '
- tool_help=$(git difftool --tool-help) &&
- echo "$tool_help" | stdin_contains tool
+ git difftool --tool-help >output &&
+ grep tool output
'
test_expect_success PERL 'setup change in subdirectory' '
@@ -354,34 +314,123 @@ test_expect_success PERL 'setup change in subdirectory' '
git commit -m "added sub/sub" &&
echo test >>file &&
echo test >>sub/sub &&
- git add . &&
+ git add file sub/sub &&
git commit -m "modified both"
'
-test_expect_success PERL 'difftool -d' '
- diff=$(git difftool -d --extcmd ls branch) &&
- echo "$diff" | stdin_contains sub &&
- echo "$diff" | stdin_contains file
+run_dir_diff_test () {
+ test_expect_success PERL "$1 --no-symlinks" "
+ symlinks=--no-symlinks &&
+ $2
+ "
+ test_expect_success PERL,SYMLINKS "$1 --symlinks" "
+ symlinks=--symlinks &&
+ $2
+ "
+}
+
+run_dir_diff_test 'difftool -d' '
+ git difftool -d $symlinks --extcmd ls branch >output &&
+ grep sub output &&
+ grep file output
'
-test_expect_success PERL 'difftool --dir-diff' '
- diff=$(git difftool --dir-diff --extcmd ls branch) &&
- echo "$diff" | stdin_contains sub &&
- echo "$diff" | stdin_contains file
+run_dir_diff_test 'difftool --dir-diff' '
+ git difftool --dir-diff $symlinks --extcmd ls branch >output &&
+ grep sub output &&
+ grep file output
'
-test_expect_success PERL 'difftool --dir-diff ignores --prompt' '
- diff=$(git difftool --dir-diff --prompt --extcmd ls branch) &&
- echo "$diff" | stdin_contains sub &&
- echo "$diff" | stdin_contains file
+run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
+ git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&
+ grep sub output &&
+ grep file output
'
-test_expect_success PERL 'difftool --dir-diff from subdirectory' '
+run_dir_diff_test 'difftool --dir-diff from subdirectory' '
(
cd sub &&
- diff=$(git difftool --dir-diff --extcmd ls branch) &&
- echo "$diff" | stdin_contains sub &&
- echo "$diff" | stdin_contains file
+ git difftool --dir-diff $symlinks --extcmd ls branch >output &&
+ grep sub output &&
+ grep file output
+ )
+'
+
+run_dir_diff_test 'difftool --dir-diff when worktree file is missing' '
+ test_when_finished git reset --hard &&
+ rm file2 &&
+ git difftool --dir-diff $symlinks --extcmd ls branch master >output &&
+ grep file2 output
+'
+
+write_script .git/CHECK_SYMLINKS <<\EOF
+for f in file file2 sub/sub
+do
+ echo "$f"
+ readlink "$2/$f"
+done >actual
+EOF
+
+test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
+ cat >expect <<-EOF &&
+ file
+ $(pwd)/file
+ file2
+ $(pwd)/file2
+ sub/sub
+ $(pwd)/sub/sub
+ EOF
+ git difftool --dir-diff --symlink \
+ --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
+ test_cmp actual expect
+'
+
+write_script modify-right-file <<\EOF
+echo "new content" >"$2/file"
+EOF
+
+run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' '
+ test_when_finished git reset --hard &&
+ echo "orig content" >file &&
+ git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch &&
+ echo "new content" >expect &&
+ test_cmp expect file
+'
+
+run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
+ test_when_finished git reset --hard &&
+ git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch &&
+ echo "new content" >expect &&
+ test_cmp expect file
+'
+
+write_script modify-file <<\EOF
+echo "new content" >file
+EOF
+
+test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' '
+ echo "orig content" >file &&
+ git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-file" branch &&
+ echo "new content" >expect &&
+ test_cmp expect file
+'
+
+write_script modify-both-files <<\EOF
+echo "wt content" >file &&
+echo "tmp content" >"$2/file" &&
+echo "$2" >tmpdir
+EOF
+
+test_expect_success PERL 'difftool --no-symlinks detects conflict ' '
+ (
+ TMPDIR=$TRASH_DIRECTORY &&
+ export TMPDIR &&
+ echo "orig content" >file &&
+ test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-both-files" branch &&
+ echo "wt content" >expect &&
+ test_cmp expect file &&
+ echo "tmp content" >expect &&
+ test_cmp expect "$(cat tmpdir)/file"
)
'
diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh
index 41962f0..72176e4 100755
--- a/t/t8001-annotate.sh
+++ b/t/t8001-annotate.sh
@@ -6,9 +6,9 @@ test_description='git annotate'
PROG='git annotate'
. "$TEST_DIRECTORY"/annotate-tests.sh
-test_expect_success 'Annotating an old revision works' '
- git annotate file master >result &&
- awk "{ print \$3; }" <result >authors &&
+test_expect_success 'annotate old revision' '
+ git annotate file master >actual &&
+ awk "{ print \$3; }" <actual >authors &&
test 2 = $(grep A <authors | wc -l) &&
test 2 = $(grep B <authors | wc -l)
'
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index e2896cf..5cdf3f1 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -7,8 +7,16 @@ PROG='git blame -c'
. "$TEST_DIRECTORY"/annotate-tests.sh
PROG='git blame -c -e'
-test_expect_success 'Blame --show-email works' '
- check_count "<A@test.git>" 1 "<B@test.git>" 1 "<B1@test.git>" 1 "<B2@test.git>" 1 "<author@example.com>" 1 "<C@test.git>" 1 "<D@test.git>" 1 "<E at test dot git>" 1
+test_expect_success 'blame --show-email' '
+ check_count \
+ "<A@test.git>" 1 \
+ "<B@test.git>" 1 \
+ "<B1@test.git>" 1 \
+ "<B2@test.git>" 1 \
+ "<author@example.com>" 1 \
+ "<C@test.git>" 1 \
+ "<D@test.git>" 1 \
+ "<E at test dot git>" 1
'
test_done
diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh
index 230143c..e7cac1d 100755
--- a/t/t8003-blame-corner-cases.sh
+++ b/t/t8003-blame-corner-cases.sh
@@ -175,6 +175,12 @@ test_expect_success 'blame -L with invalid end' '
grep "has only 2 lines" errors
'
+test_expect_success 'blame parses <end> part of -L' '
+ git blame -L1,1 tres >out &&
+ cat out &&
+ test $(wc -l < out) -eq 1
+'
+
test_expect_success 'indent of line numbers, nine lines' '
git blame nine_lines >actual &&
test $(grep -c " " actual) = 0
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index bf6caa4..7683515 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -18,17 +18,13 @@ test_expect_success 'setup ' '
echo "bin: test number 0" >zero.bin &&
echo "bin: test 1" >one.bin &&
echo "bin: test number 2" >two.bin &&
- if test_have_prereq SYMLINKS; then
- ln -s one.bin symlink.bin
- fi &&
+ test_ln_s_add one.bin symlink.bin &&
git add . &&
GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" &&
echo "bin: test 1 version 2" >one.bin &&
echo "bin: test number 2 version 2" >>two.bin &&
- if test_have_prereq SYMLINKS; then
- rm symlink.bin &&
- ln -s two.bin symlink.bin
- fi &&
+ rm -f symlink.bin &&
+ test_ln_s_add two.bin symlink.bin &&
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
@@ -135,7 +131,7 @@ test_expect_success SYMLINKS 'blame --textconv (on symlink)' '
# cp two.bin three.bin and make small tweak
# (this will direct blame -C -C three.bin to consider two.bin and symlink.bin)
-test_expect_success SYMLINKS 'make another new commit' '
+test_expect_success 'make another new commit' '
cat >three.bin <<\EOF &&
bin: test number 2
bin: test number 2 version 2
@@ -146,7 +142,7 @@ EOF
GIT_AUTHOR_NAME=Number4 git commit -a -m Fourth --date="2010-01-01 23:00:00"
'
-test_expect_success SYMLINKS 'blame on last commit (-C -C, symlink)' '
+test_expect_success 'blame on last commit (-C -C, symlink)' '
git blame -C -C three.bin >blame &&
find_blame <blame >result &&
cat >expected <<\EOF &&
diff --git a/t/t8007-cat-file-textconv.sh b/t/t8007-cat-file-textconv.sh
index 78a0085..b95e102 100755
--- a/t/t8007-cat-file-textconv.sh
+++ b/t/t8007-cat-file-textconv.sh
@@ -12,9 +12,7 @@ chmod +x helper
test_expect_success 'setup ' '
echo "bin: test" >one.bin &&
- if test_have_prereq SYMLINKS; then
- ln -s one.bin symlink.bin
- fi &&
+ test_ln_s_add one.bin symlink.bin &&
git add . &&
GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" &&
echo "bin: test version 2" >one.bin &&
@@ -72,14 +70,14 @@ test_expect_success 'cat-file --textconv on previous commit' '
test_cmp expected result
'
-test_expect_success SYMLINKS 'cat-file without --textconv (symlink)' '
+test_expect_success 'cat-file without --textconv (symlink)' '
git cat-file blob :symlink.bin >result &&
printf "%s" "one.bin" >expected
test_cmp expected result
'
-test_expect_success SYMLINKS 'cat-file --textconv on index (symlink)' '
+test_expect_success 'cat-file --textconv on index (symlink)' '
! git cat-file --textconv :symlink.bin 2>result &&
cat >expected <<\EOF &&
fatal: git cat-file --textconv: unable to run textconv on :symlink.bin
@@ -87,7 +85,7 @@ EOF
test_cmp expected result
'
-test_expect_success SYMLINKS 'cat-file --textconv on HEAD (symlink)' '
+test_expect_success 'cat-file --textconv on HEAD (symlink)' '
! git cat-file --textconv HEAD:symlink.bin 2>result &&
cat >expected <<EOF &&
fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index ebd5c5d..2813aa9 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -171,6 +171,81 @@ Result: OK
EOF
"
+test_suppress_self () {
+ test_commit $3 &&
+ test_when_finished "git reset --hard HEAD^" &&
+
+ write_script cccmd-sed <<-EOF &&
+ sed -n -e s/^cccmd--//p "\$1"
+ EOF
+
+ git commit --amend --author="$1 <$2>" -F - &&
+ clean_fake_sendmail &&
+ git format-patch --stdout -1 >"suppress-self-$3.patch" &&
+
+ git send-email --from="$1 <$2>" \
+ --to=nobody@example.com \
+ --cc-cmd=./cccmd-sed \
+ --suppress-cc=self \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ suppress-self-$3.patch &&
+
+ mv msgtxt1 msgtxt1-$3 &&
+ sed -e '/^$/q' msgtxt1-$3 >"msghdr1-$3" &&
+ >"expected-no-cc-$3" &&
+
+ (grep '^Cc:' msghdr1-$3 >"actual-no-cc-$3";
+ test_cmp expected-no-cc-$3 actual-no-cc-$3)
+}
+
+test_suppress_self_unquoted () {
+ test_suppress_self "$1" "$2" "unquoted-$3" <<-EOF
+ test suppress-cc.self unquoted-$3 with name $1 email $2
+
+ unquoted-$3
+
+ cccmd--$1 <$2>
+
+ Cc: $1 <$2>
+ Signed-off-by: $1 <$2>
+ EOF
+}
+
+test_suppress_self_quoted () {
+ test_suppress_self "$1" "$2" "quoted-$3" <<-EOF
+ test suppress-cc.self quoted-$3 with name $1 email $2
+
+ quoted-$3
+
+ cccmd--"$1" <$2>
+
+ Cc: $1 <$2>
+ Cc: "$1" <$2>
+ Signed-off-by: $1 <$2>
+ Signed-off-by: "$1" <$2>
+ EOF
+}
+
+test_expect_success $PREREQ 'self name is suppressed' "
+ test_suppress_self_unquoted 'A U Thor' 'author@example.com' \
+ 'self_name_suppressed'
+"
+
+test_expect_success $PREREQ 'self name with dot is suppressed' "
+ test_suppress_self_quoted 'A U. Thor' 'author@example.com' \
+ 'self_name_dot_suppressed'
+"
+
+test_expect_success $PREREQ 'non-ascii self name is suppressed' "
+ test_suppress_self_quoted 'Füñný Nâmé' 'odd_?=mail@example.com' \
+ 'non_ascii_self_suppressed'
+"
+
+test_expect_success $PREREQ 'sanitized self name is suppressed' "
+ test_suppress_self_unquoted '\"A U. Thor\"' 'author@example.com' \
+ 'self_name_sanitized_suppressed'
+"
+
test_expect_success $PREREQ 'Show all headers' '
git send-email \
--dry-run \
@@ -881,6 +956,20 @@ test_expect_success $PREREQ 'utf8 author is correctly passed on' '
grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1
'
+test_expect_success $PREREQ 'utf8 sender is not duplicated' '
+ clean_fake_sendmail &&
+ test_commit weird_sender &&
+ test_when_finished "git reset --hard HEAD^" &&
+ git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" &&
+ git format-patch --stdout -1 >funny_name.patch &&
+ git send-email --from="Füñný Nâmé <odd_?=mail@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ funny_name.patch &&
+ grep "^From: " msgtxt1 >msgfrom &&
+ test_line_count = 1 msgfrom
+'
+
test_expect_success $PREREQ 'sendemail.composeencoding works' '
clean_fake_sendmail &&
git config sendemail.composeencoding iso-8859-1 &&
@@ -1003,55 +1092,6 @@ test_expect_success $PREREQ 'threading but no chain-reply-to' '
grep "In-Reply-To: " stdout
'
-test_expect_success $PREREQ 'warning with an implicit --chain-reply-to' '
- git send-email \
- --dry-run \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- outdir/000?-*.patch 2>errors >out &&
- grep "no-chain-reply-to" errors
-'
-
-test_expect_success $PREREQ 'no warning with an explicit --chain-reply-to' '
- git send-email \
- --dry-run \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --chain-reply-to \
- outdir/000?-*.patch 2>errors >out &&
- ! grep "no-chain-reply-to" errors
-'
-
-test_expect_success $PREREQ 'no warning with an explicit --no-chain-reply-to' '
- git send-email \
- --dry-run \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --nochain-reply-to \
- outdir/000?-*.patch 2>errors >out &&
- ! grep "no-chain-reply-to" errors
-'
-
-test_expect_success $PREREQ 'no warning with sendemail.chainreplyto = false' '
- git config sendemail.chainreplyto false &&
- git send-email \
- --dry-run \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- outdir/000?-*.patch 2>errors >out &&
- ! grep "no-chain-reply-to" errors
-'
-
-test_expect_success $PREREQ 'no warning with sendemail.chainreplyto = true' '
- git config sendemail.chainreplyto true &&
- git send-email \
- --dry-run \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- outdir/000?-*.patch 2>errors >out &&
- ! grep "no-chain-reply-to" errors
-'
-
test_expect_success $PREREQ 'sendemail.to works' '
git config --replace-all sendemail.to "Somebody <somebody@ex.com>" &&
git send-email \
diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh
index d9f6b73..4d81ba1 100755
--- a/t/t9020-remote-svn.sh
+++ b/t/t9020-remote-svn.sh
@@ -24,7 +24,7 @@ init_git () {
rm -fr .git &&
git init &&
#git remote add svnsim testsvn::sim:///$TEST_DIRECTORY/t9020/example.svnrdump
- # let's reuse an exisiting dump file!?
+ # let's reuse an existing dump file!?
git remote add svnsim testsvn::sim://$TEST_DIRECTORY/t9154/svn.dump
git remote add svnfile testsvn::file://$TEST_DIRECTORY/t9154/svn.dump
}
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index a61d671..9861c71 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -7,7 +7,7 @@ test_description='test that git handles an svn repository with missing md5sums'
# Loading a node from a svn dumpfile without a Text-Content-Length
# field causes svn to neglect to store or report an md5sum. (it will
# calculate one if you had put Text-Content-Length: 0). This showed
-# up in a repository creted with cvs2svn.
+# up in a repository created with cvs2svn.
cat > dumpfile.svn <<EOF
SVN-fs-dump-format-version: 1
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index 3077851..f524d2f 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -48,7 +48,7 @@ test_expect_success 'setup svn repository' '
test_expect_success 'setup git mirror and merge' '
git svn init "$svnrepo" -t tags -T trunk -b branches &&
git svn fetch &&
- git checkout --track -b svn remotes/trunk &&
+ git checkout -b svn remotes/trunk &&
git checkout -b merge &&
echo new file > new_file &&
git add new_file &&
diff --git a/t/t9147-git-svn-include-paths.sh b/t/t9147-git-svn-include-paths.sh
new file mode 100755
index 0000000..a90ff58
--- /dev/null
+++ b/t/t9147-git-svn-include-paths.sh
@@ -0,0 +1,149 @@
+#!/bin/sh
+#
+# Copyright (c) 2013 Paul Walmsley - based on t9134 by Vitaly Shukela
+#
+
+test_description='git svn property tests'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup test repository' '
+ svn_cmd co "$svnrepo" s &&
+ (
+ cd s &&
+ mkdir qqq www xxx &&
+ echo test_qqq > qqq/test_qqq.txt &&
+ echo test_www > www/test_www.txt &&
+ echo test_xxx > xxx/test_xxx.txt &&
+ svn_cmd add qqq &&
+ svn_cmd add www &&
+ svn_cmd add xxx &&
+ svn_cmd commit -m "create some files" &&
+ svn_cmd up &&
+ echo hi >> www/test_www.txt &&
+ svn_cmd commit -m "modify www/test_www.txt" &&
+ svn_cmd up
+ )
+'
+
+test_expect_success 'clone an SVN repository with filter to include qqq directory' '
+ git svn clone --include-paths="qqq" "$svnrepo" g &&
+ echo test_qqq > expect &&
+ for i in g/*/*.txt; do cat $i >> expect2; done &&
+ test_cmp expect expect2
+'
+
+
+test_expect_success 'init+fetch an SVN repository with included qqq directory' '
+ git svn init "$svnrepo" c &&
+ ( cd c && git svn fetch --include-paths="qqq" ) &&
+ rm expect2 &&
+ echo test_qqq > expect &&
+ for i in c/*/*.txt; do cat $i >> expect2; done &&
+ test_cmp expect expect2
+'
+
+test_expect_success 'verify include-paths config saved by clone' '
+ (
+ cd g &&
+ git config --get svn-remote.svn.include-paths | fgrep "qqq"
+ )
+'
+
+test_expect_success 'SVN-side change outside of www' '
+ (
+ cd s &&
+ echo b >> qqq/test_qqq.txt &&
+ svn_cmd commit -m "SVN-side change outside of www" &&
+ svn_cmd up &&
+ svn_cmd log -v | fgrep "SVN-side change outside of www"
+ )
+'
+
+test_expect_success 'update git svn-cloned repo (config include)' '
+ (
+ cd g &&
+ git svn rebase &&
+ printf "test_qqq\nb\n" > expect &&
+ for i in */*.txt; do cat $i >> expect2; done &&
+ test_cmp expect2 expect &&
+ rm expect expect2
+ )
+'
+
+test_expect_success 'update git svn-cloned repo (option include)' '
+ (
+ cd c &&
+ git svn rebase --include-paths="qqq" &&
+ printf "test_qqq\nb\n" > expect &&
+ for i in */*.txt; do cat $i >> expect2; done &&
+ test_cmp expect2 expect &&
+ rm expect expect2
+ )
+'
+
+test_expect_success 'SVN-side change inside of ignored www' '
+ (
+ cd s &&
+ echo zaq >> www/test_www.txt
+ svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
+ svn_cmd up &&
+ svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
+ )
+'
+
+test_expect_success 'update git svn-cloned repo (config include)' '
+ (
+ cd g &&
+ git svn rebase &&
+ printf "test_qqq\nb\n" > expect &&
+ for i in */*.txt; do cat $i >> expect2; done &&
+ test_cmp expect2 expect &&
+ rm expect expect2
+ )
+'
+
+test_expect_success 'update git svn-cloned repo (option include)' '
+ (
+ cd c &&
+ git svn rebase --include-paths="qqq" &&
+ printf "test_qqq\nb\n" > expect &&
+ for i in */*.txt; do cat $i >> expect2; done &&
+ test_cmp expect2 expect &&
+ rm expect expect2
+ )
+'
+
+test_expect_success 'SVN-side change in and out of included qqq' '
+ (
+ cd s &&
+ echo cvf >> www/test_www.txt
+ echo ygg >> qqq/test_qqq.txt
+ svn_cmd commit -m "SVN-side change in and out of ignored www" &&
+ svn_cmd up &&
+ svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
+ )
+'
+
+test_expect_success 'update git svn-cloned repo again (config include)' '
+ (
+ cd g &&
+ git svn rebase &&
+ printf "test_qqq\nb\nygg\n" > expect &&
+ for i in */*.txt; do cat $i >> expect2; done &&
+ test_cmp expect2 expect &&
+ rm expect expect2
+ )
+'
+
+test_expect_success 'update git svn-cloned repo again (option include)' '
+ (
+ cd c &&
+ git svn rebase --include-paths="qqq" &&
+ printf "test_qqq\nb\nygg\n" > expect &&
+ for i in */*.txt; do cat $i >> expect2; done &&
+ test_cmp expect2 expect &&
+ rm expect expect2
+ )
+'
+
+test_done
diff --git a/t/t9161-git-svn-mergeinfo-push.sh b/t/t9161-git-svn-mergeinfo-push.sh
index 6ef0c0b..1eab701 100755
--- a/t/t9161-git-svn-mergeinfo-push.sh
+++ b/t/t9161-git-svn-mergeinfo-push.sh
@@ -88,7 +88,6 @@ test_expect_success 'check reintegration mergeinfo' '
test "$mergeinfo" = "/branches/svnb1:2-4,7-9,13-18
/branches/svnb2:3,8,16-17
/branches/svnb3:4,9
-/branches/svnb4:5-6,10-12
/branches/svnb5:6,11"
'
diff --git a/t/t9167-git-svn-cmd-branch-subproject.sh b/t/t9167-git-svn-cmd-branch-subproject.sh
new file mode 100755
index 0000000..53def87
--- /dev/null
+++ b/t/t9167-git-svn-cmd-branch-subproject.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# Copyright (c) 2013 Tobias Schulte
+#
+
+test_description='git svn branch for subproject clones'
+. ./lib-git-svn.sh
+
+test_expect_success 'initialize svnrepo' '
+ mkdir import &&
+ (
+ cd import &&
+ mkdir -p trunk/project branches tags &&
+ (
+ cd trunk/project &&
+ echo foo > foo
+ ) &&
+ svn_cmd import -m "import for git-svn" . "$svnrepo" >/dev/null
+ ) &&
+ rm -rf import &&
+ svn_cmd co "$svnrepo"/trunk/project trunk/project &&
+ (
+ cd trunk/project &&
+ echo bar >> foo &&
+ svn_cmd ci -m "updated trunk"
+ ) &&
+ rm -rf trunk
+'
+
+test_expect_success 'import into git' '
+ git svn init --trunk=trunk/project --branches=branches/*/project \
+ --tags=tags/*/project "$svnrepo" &&
+ git svn fetch &&
+ git checkout remotes/trunk
+'
+
+test_expect_success 'git svn branch tests' '
+ test_must_fail git svn branch a &&
+ git svn branch --parents a &&
+ test_must_fail git svn branch -t tag1 &&
+ git svn branch --parents -t tag1 &&
+ test_must_fail git svn branch --tag tag2 &&
+ git svn branch --parents --tag tag2 &&
+ test_must_fail git svn tag tag3 &&
+ git svn tag --parents tag3
+'
+
+test_done
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index ac6f3b6..31a770d 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -1031,6 +1031,32 @@ test_expect_success \
git diff-tree -M -r M3^ M3 >actual &&
compare_diff_raw expect actual'
+cat >input <<INPUT_END
+commit refs/heads/M4
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+rename root
+COMMIT
+
+from refs/heads/M2^0
+R "" sub
+
+INPUT_END
+
+cat >expect <<EOF
+:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2/oldf sub/file2/oldf
+:100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 R100 file4 sub/file4
+:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you sub/i/am/new/to/you
+:100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 R100 newdir/exec.sh sub/newdir/exec.sh
+:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting sub/newdir/interesting
+EOF
+test_expect_success \
+ 'M: rename root to subdirectory' \
+ 'git fast-import <input &&
+ git diff-tree -M -r M4^ M4 >actual &&
+ cat actual &&
+ compare_diff_raw expect actual'
+
###
### series N
###
@@ -1228,6 +1254,29 @@ test_expect_success \
compare_diff_raw expect actual'
test_expect_success \
+ 'N: copy root by path' \
+ 'cat >expect <<-\EOF &&
+ :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf oldroot/file2/newf
+ :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf oldroot/file2/oldf
+ :100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 C100 file4 oldroot/file4
+ :100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 C100 newdir/exec.sh oldroot/newdir/exec.sh
+ :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting oldroot/newdir/interesting
+ EOF
+ cat >input <<-INPUT_END &&
+ commit refs/heads/N-copy-root-path
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ copy root directory by (empty) path
+ COMMIT
+
+ from refs/heads/branch^0
+ C "" oldroot
+ INPUT_END
+ git fast-import <input &&
+ git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual &&
+ compare_diff_raw expect actual'
+
+test_expect_success \
'N: delete directory by copying' \
'cat >expect <<-\EOF &&
OBJID
@@ -2934,4 +2983,20 @@ test_expect_success 'S: ls with garbage after sha1 must fail' '
test_i18ngrep "space after tree-ish" err
'
+###
+### series T (ls)
+###
+# Setup is carried over from series S.
+
+test_expect_success 'T: ls root tree' '
+ sed -e "s/Z\$//" >expect <<-EOF &&
+ 040000 tree $(git rev-parse S^{tree}) Z
+ EOF
+ sha1=$(git rev-parse --verify S) &&
+ git fast-import --import-marks=marks <<-EOF >actual &&
+ ls $sha1 ""
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 9320b4f..34c2d8f 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -146,6 +146,12 @@ test_expect_success 'signed-tags=strip' '
'
+test_expect_success 'signed-tags=warn-strip' '
+ git fast-export --signed-tags=warn-strip sign-your-name >output 2>err &&
+ ! grep PGP output &&
+ test -s err
+'
+
test_expect_success 'setup submodule' '
git checkout -f master &&
@@ -390,7 +396,7 @@ test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj'
test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag'
test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj'
-test_expect_success SYMLINKS 'directory becomes symlink' '
+test_expect_success 'directory becomes symlink' '
git init dirtosymlink &&
git init result &&
(
@@ -402,8 +408,7 @@ test_expect_success SYMLINKS 'directory becomes symlink' '
git add foo/world bar/world &&
git commit -q -mone &&
git rm -r foo &&
- ln -s bar foo &&
- git add foo &&
+ test_ln_s_add bar foo &&
git commit -q -mtwo
) &&
(
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 9502f24..0431386 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -36,6 +36,7 @@ export CVSROOT CVS_SERVER
rm -rf "$CVSWORK" "$SERVERDIR"
test_expect_success 'setup' '
+ git config push.default matching &&
echo >empty &&
git add empty &&
git commit -q -m "First Commit" &&
diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh
index 1c5bc84..8c3db76 100755
--- a/t/t9401-git-cvsserver-crlf.sh
+++ b/t/t9401-git-cvsserver-crlf.sh
@@ -84,6 +84,7 @@ export CVSROOT CVS_SERVER
rm -rf "$CVSWORK" "$SERVERDIR"
test_expect_success 'setup' '
+ git config push.default matching &&
echo "Simple text file" >textfile.c &&
echo "File with embedded NUL: Q <- there" | q_to_nul > binfile.bin &&
mkdir subdir &&
diff --git a/t/t9402-git-cvsserver-refs.sh b/t/t9402-git-cvsserver-refs.sh
index 735a018..db69af2 100755
--- a/t/t9402-git-cvsserver-refs.sh
+++ b/t/t9402-git-cvsserver-refs.sh
@@ -330,7 +330,7 @@ test_expect_success 'validate result of edits [cvswork2]' '
test_expect_success 'validate basic diffs saved during above cvswork2 edits' '
test $(grep Index: cvsEdit1.diff | wc -l) = 1 &&
- test ! -s cvsEdit2-empty.diff &&
+ test_must_be_empty cvsEdit2-empty.diff &&
test $(grep Index: cvsEdit2-N.diff | wc -l) = 1 &&
test $(grep Index: cvsEdit3.diff | wc -l) = 3 &&
rm -rf diffSandbox &&
@@ -456,20 +456,20 @@ test_expect_success 'cvs up -r $(git rev-parse v1)' '
test_expect_success 'cvs diff -r v1 -u' '
( cd cvswork && cvs -f diff -r v1 -u ) >cvsDiff.out 2>cvs.log &&
- test ! -s cvsDiff.out &&
- test ! -s cvs.log
+ test_must_be_empty cvsDiff.out &&
+ test_must_be_empty cvs.log
'
test_expect_success 'cvs diff -N -r v2 -u' '
( cd cvswork && ! cvs -f diff -N -r v2 -u ) >cvsDiff.out 2>cvs.log &&
- test ! -s cvs.log &&
+ test_must_be_empty cvs.log &&
test -s cvsDiff.out &&
check_diff cvsDiff.out v2 v1 >check_diff.out 2>&1
'
test_expect_success 'cvs diff -N -r v2 -r v1.2' '
( cd cvswork && ! cvs -f diff -N -r v2 -r v1.2 -u ) >cvsDiff.out 2>cvs.log &&
- test ! -s cvs.log &&
+ test_must_be_empty cvs.log &&
test -s cvsDiff.out &&
check_diff cvsDiff.out v2 v1.2 >check_diff.out 2>&1
'
@@ -488,7 +488,7 @@ test_expect_success 'apply early [cvswork3] diff to b3' '
test_expect_success 'check [cvswork3] diff' '
( cd cvswork3 && ! cvs -f diff -N -u ) >"$WORKDIR/cvsDiff.out" 2>cvs.log &&
- test ! -s cvs.log &&
+ test_must_be_empty cvs.log &&
test -s cvsDiff.out &&
test $(grep Index: cvsDiff.out | wc -l) = 3 &&
test_cmp cvsDiff.out cvswork3edit.diff &&
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 90bb605..6fca193 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -156,10 +156,10 @@ test_expect_success \
git commit -a -m "File renamed." &&
gitweb_run "p=.git;a=commitdiff"'
-test_expect_success SYMLINKS \
+test_expect_success \
'commitdiff(0): file to symlink' \
'rm renamed_file &&
- ln -s file renamed_file &&
+ test_ln_s_add file renamed_file &&
git commit -a -m "File to symlink." &&
gitweb_run "p=.git;a=commitdiff"'
@@ -212,15 +212,14 @@ test_expect_success \
# ----------------------------------------------------------------------
# commitdiff testing (taken from t4114-apply-typechange.sh)
-test_expect_success SYMLINKS 'setup typechange commits' '
+test_expect_success 'setup typechange commits' '
echo "hello world" > foo &&
echo "hi planet" > bar &&
git update-index --add foo bar &&
git commit -m initial &&
git branch initial &&
rm -f foo &&
- ln -s bar foo &&
- git update-index foo &&
+ test_ln_s_add bar foo &&
git commit -m "foo symlinked to bar" &&
git branch foo-symlinked-to-bar &&
rm -f foo &&
@@ -361,11 +360,7 @@ test_expect_success \
echo "Changed" >> 04-rename-to &&
test_chmod +x 05-mode-change &&
rm -f 06-file-or-symlink &&
- if test_have_prereq SYMLINKS; then
- ln -s 01-change 06-file-or-symlink
- else
- printf %s 01-change > 06-file-or-symlink
- fi &&
+ test_ln_s_add 01-change 06-file-or-symlink &&
echo "Changed and have mode changed" > 07-change-mode-change &&
test_chmod +x 07-change-mode-change &&
git commit -a -m "Large commit" &&
@@ -539,8 +534,7 @@ test_expect_success \
test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" &&
echo "ISO-8859-1" >> file &&
git add file &&
- git config i18n.commitencoding ISO-8859-1 &&
- test_when_finished "git config --unset i18n.commitencoding" &&
+ test_config i18n.commitencoding ISO-8859-1 &&
git commit -F "$TEST_DIRECTORY"/t3900/ISO8859-1.txt &&
gitweb_run "p=.git;a=commit"'
diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh
index 9730821..2bf142d 100755
--- a/t/t9801-git-p4-branch.sh
+++ b/t/t9801-git-p4-branch.sh
@@ -469,9 +469,11 @@ test_expect_success 'use-client-spec detect-branches skips branches setup' '
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"
+ echo b3/b3-file3_1 >b3/b3-file3_1 &&
+ echo b3/b3-file3_2 >b3/b3-file3_2 &&
+ p4 add b3/b3-file3_1 &&
+ p4 add b3/b3-file3_2 &&
+ p4 submit -d "b3/b3-file3_1 b3/b3-file3_2"
)
'
@@ -487,6 +489,21 @@ test_expect_success 'use-client-spec detect-branches skips branches' '
)
'
+test_expect_success 'use-client-spec detect-branches skips files in branches' '
+ client_view "//depot/usecs/... //client/..." \
+ "-//depot/usecs/b3/b3-file3_1 //client/b3/b3-file3_1" &&
+ 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/b3 &&
+ test_path_is_file b1-file1 &&
+ test_path_is_file b3-file3_2 &&
+ test_path_is_missing b3-file3_1
+ )
+'
+
test_expect_success 'kill p4d' '
kill_p4d
'
diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh
index eeefa67..a82744b 100755
--- a/t/t9802-git-p4-filetype.sh
+++ b/t/t9802-git-p4-filetype.sh
@@ -28,7 +28,7 @@ test_expect_success 'p4 client newlines, unix' '
test_cmp f-unix-orig f-unix &&
# make sure stored in repo as unix newlines
- # use sed to eat python-appened newline
+ # use sed to eat python-appended newline
p4 -G print //depot/f-unix | marshal_dump data 2 |\
sed \$d >f-unix-p4-print &&
test_cmp f-unix-orig f-unix-p4-print &&
@@ -95,7 +95,7 @@ test_expect_success 'gitattributes setting eol=lf produces lf newlines' '
git init &&
echo "* eol=lf" >.gitattributes &&
git p4 sync //depot@all &&
- git checkout master &&
+ git checkout -b master p4/master &&
test_cmp "$cli"/f-unix-orig f-unix &&
test_cmp "$cli"/f-win-as-lf f-win
)
@@ -109,7 +109,7 @@ test_expect_success 'gitattributes setting eol=crlf produces crlf newlines' '
git init &&
echo "* eol=crlf" >.gitattributes &&
git p4 sync //depot@all &&
- git checkout master &&
+ git checkout -b master p4/master &&
test_cmp "$cli"/f-unix-as-crlf f-unix &&
test_cmp "$cli"/f-win-orig f-win
)
diff --git a/t/t9808-git-p4-chdir.sh b/t/t9808-git-p4-chdir.sh
index dc92e60..11d2b51 100755
--- a/t/t9808-git-p4-chdir.sh
+++ b/t/t9808-git-p4-chdir.sh
@@ -42,6 +42,47 @@ test_expect_success 'P4CONFIG and relative dir clone' '
)
'
+# Common setup using .p4config to set P4CLIENT and P4PORT breaks
+# if clone destination is relative. Make sure that chdir() expands
+# the relative path in --dest to absolute.
+test_expect_success 'p4 client root would be relative due to clone --dest' '
+ test_when_finished cleanup_git &&
+ (
+ echo P4PORT=$P4PORT >git/.p4config &&
+ P4CONFIG=.p4config &&
+ export P4CONFIG &&
+ unset P4PORT &&
+ git p4 clone --dest="git" //depot
+ )
+'
+
+# When the p4 client Root is a symlink, make sure chdir() does not use
+# getcwd() to convert it to a physical path.
+test_expect_success SYMLINKS 'p4 client root symlink should stay symbolic' '
+ physical="$TRASH_DIRECTORY/physical" &&
+ symbolic="$TRASH_DIRECTORY/symbolic" &&
+ test_when_finished "rm -rf \"$physical\"" &&
+ test_when_finished "rm \"$symbolic\"" &&
+ mkdir -p "$physical" &&
+ ln -s "$physical" "$symbolic" &&
+ test_when_finished cleanup_git &&
+ (
+ P4CLIENT=client-sym &&
+ p4 client -i <<-EOF &&
+ Client: $P4CLIENT
+ Description: $P4CLIENT
+ Root: $symbolic
+ LineEnd: unix
+ View: //depot/... //$P4CLIENT/...
+ EOF
+ git p4 clone --dest="$git" //depot &&
+ cd "$git" &&
+ test_commit file2 &&
+ git config git-p4.skipSubmitEdit true &&
+ git p4 submit
+ )
+'
+
test_expect_success 'kill p4d' '
kill_p4d
'
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index adc1372..2d4beb5 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -69,6 +69,7 @@ run_completion ()
local -a COMPREPLY _words
local _cword
_words=( $1 )
+ test "${1: -1}" = ' ' && _words[${#_words[@]}+1]=''
(( _cword = ${#_words[@]} - 1 ))
__git_wrap__git_main && print_comp
}
@@ -104,6 +105,157 @@ test_gitcomp ()
test_cmp expected out
}
+# Test __gitcomp_nl
+# Arguments are:
+# 1: current word (cur)
+# -: the rest are passed to __gitcomp_nl
+test_gitcomp_nl ()
+{
+ local -a COMPREPLY &&
+ sed -e 's/Z$//' >expected &&
+ cur="$1" &&
+ shift &&
+ __gitcomp_nl "$@" &&
+ print_comp &&
+ test_cmp expected out
+}
+
+invalid_variable_name='${foo.bar}'
+
+actual="$TRASH_DIRECTORY/actual"
+
+test_expect_success 'setup for __gitdir tests' '
+ mkdir -p subdir/subsubdir &&
+ git init otherrepo
+'
+
+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 "$(pwd -P)/.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 "$(pwd -P)/.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 "$(pwd -P)/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 "$(pwd -P)/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 "$(pwd -P)/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 '__gitcomp - trailing space - options' '
test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message=
--reset-author" <<-EOF
@@ -147,8 +299,51 @@ test_expect_success '__gitcomp - suffix' '
EOF
'
+test_expect_success '__gitcomp - doesnt fail because of invalid variable name' '
+ __gitcomp "$invalid_variable_name"
+'
+
+read -r -d "" refs <<-\EOF
+maint
+master
+next
+pu
+EOF
+
+test_expect_success '__gitcomp_nl - trailing space' '
+ test_gitcomp_nl "m" "$refs" <<-EOF
+ maint Z
+ master Z
+ EOF
+'
+
+test_expect_success '__gitcomp_nl - prefix' '
+ test_gitcomp_nl "--fixup=m" "$refs" "--fixup=" "m" <<-EOF
+ --fixup=maint Z
+ --fixup=master Z
+ EOF
+'
+
+test_expect_success '__gitcomp_nl - suffix' '
+ test_gitcomp_nl "branch.ma" "$refs" "branch." "ma" "." <<-\EOF
+ branch.maint.Z
+ branch.master.Z
+ EOF
+'
+
+test_expect_success '__gitcomp_nl - no suffix' '
+ test_gitcomp_nl "ma" "$refs" "" "ma" "" <<-\EOF
+ maintZ
+ masterZ
+ EOF
+'
+
+test_expect_success '__gitcomp_nl - doesnt fail because of invalid variable name' '
+ __gitcomp_nl "$invalid_variable_name"
+'
+
test_expect_success 'basic' '
- run_completion "git \"\"" &&
+ run_completion "git " &&
# built-in
grep -q "^add \$" out &&
# script
@@ -170,6 +365,7 @@ test_expect_success 'double dash "git" itself' '
--exec-path Z
--exec-path=
--html-path Z
+ --man-path Z
--info-path Z
--work-tree=
--namespace=
@@ -271,7 +467,7 @@ test_expect_success 'complete tree filename with spaces' '
EOF
'
-test_expect_failure 'complete tree filename with metacharacters' '
+test_expect_success 'complete tree filename with metacharacters' '
echo content >"name with \${meta}" &&
git add . &&
git commit -m meta &&
@@ -286,4 +482,81 @@ test_expect_success 'send-email' '
test_completion "git send-email ma" "master "
'
+test_expect_success 'complete files' '
+ git init tmp && cd tmp &&
+ test_when_finished "cd .. && rm -rf tmp" &&
+
+ echo "expected" > .gitignore &&
+ echo "out" >> .gitignore &&
+
+ git add .gitignore &&
+ test_completion "git commit " ".gitignore" &&
+
+ git commit -m ignore &&
+
+ touch new &&
+ test_completion "git add " "new" &&
+
+ git add new &&
+ git commit -a -m new &&
+ test_completion "git add " "" &&
+
+ git mv new modified &&
+ echo modify > modified &&
+ test_completion "git add " "modified" &&
+
+ touch untracked &&
+
+ : TODO .gitignore should not be here &&
+ test_completion "git rm " <<-\EOF &&
+ .gitignore
+ modified
+ EOF
+
+ test_completion "git clean " "untracked" &&
+
+ : TODO .gitignore should not be here &&
+ test_completion "git mv " <<-\EOF &&
+ .gitignore
+ modified
+ EOF
+
+ mkdir dir &&
+ touch dir/file-in-dir &&
+ git add dir/file-in-dir &&
+ git commit -m dir &&
+
+ mkdir untracked-dir &&
+
+ : TODO .gitignore should not be here &&
+ test_completion "git mv modified " <<-\EOF &&
+ .gitignore
+ dir
+ modified
+ untracked
+ untracked-dir
+ EOF
+
+ test_completion "git commit " "modified" &&
+
+ : TODO .gitignore should not be here &&
+ test_completion "git ls-files " <<-\EOF
+ .gitignore
+ dir
+ modified
+ EOF
+
+ touch momified &&
+ test_completion "git add mom" "momified"
+'
+
+test_expect_failure 'complete with tilde expansion' '
+ git init tmp && cd tmp &&
+ test_when_finished "cd .. && rm -rf tmp" &&
+
+ touch ~/tmp/file &&
+
+ test_completion "git add ~/tmp/" "~/tmp/file"
+'
+
test_done
diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh
index 2101d91..59f875e 100755
--- a/t/t9903-bash-prompt.sh
+++ b/t/t9903-bash-prompt.sh
@@ -10,522 +10,581 @@ test_description='test git-specific bash prompt functions'
. "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh"
actual="$TRASH_DIRECTORY/actual"
+c_red='\\[\\e[31m\\]'
+c_green='\\[\\e[32m\\]'
+c_lblue='\\[\\e[1;34m\\]'
+c_clear='\\[\\e[0m\\]'
test_expect_success 'setup for prompt tests' '
- mkdir -p subdir/subsubdir &&
git init otherrepo &&
- echo 1 > file &&
+ 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 &&
+ echo 2 >file &&
git commit -m "second b1" file &&
- echo 3 > file &&
+ echo 3 >file &&
git commit -m "third b1" file &&
git tag -a -m msg2 t2 &&
git checkout -b b2 master &&
- echo 0 > file &&
+ echo 0 >file &&
git commit -m "second b2" file &&
+ echo 00 >file &&
+ git commit -m "another b2" file &&
+ echo 000 >file &&
+ git commit -m "yet another 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_expect_success 'prompt - branch name' '
+ printf " (master)" >expected &&
+ __git_ps1 >"$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_expect_success SYMLINKS 'prompt - branch name - symlink symref' '
+ printf " (master)" >expected &&
+ test_when_finished "git checkout master" &&
+ test_config core.preferSymlinkRefs true &&
+ git checkout master &&
+ __git_ps1 >"$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_expect_success 'prompt - unborn branch' '
+ printf " (unborn)" >expected &&
+ git checkout --orphan unborn &&
+ test_when_finished "git checkout master" &&
+ __git_ps1 >"$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"
-'
+repo_with_newline='repo
+with
+newline'
-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"
-'
+if mkdir "$repo_with_newline" 2>/dev/null
+then
+ test_set_prereq FUNNYNAMES
+else
+ say 'Your filesystem does not allow newlines in filenames.'
+fi
-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" &&
+test_expect_success FUNNYNAMES 'prompt - with newline in path' '
+ printf " (master)" >expected &&
+ git init "$repo_with_newline" &&
+ test_when_finished "rm -rf \"$repo_with_newline\"" &&
+ mkdir "$repo_with_newline"/subdir &&
(
- cd link &&
- __gitdir > "$actual"
+ cd "$repo_with_newline/subdir" &&
+ __git_ps1 >"$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 &&
+ printf " ((%s...))" $(git log -1 --format="%h" --abbrev=13 b1^) >expected &&
+ test_config core.abbrev 13 &&
git checkout b1^ &&
test_when_finished "git checkout master" &&
- __git_ps1 > "$actual" &&
+ __git_ps1 >"$actual" &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - describe detached head - contains' '
- printf " ((t2~1))" > expected &&
+ printf " ((t2~1))" >expected &&
git checkout b1^ &&
test_when_finished "git checkout master" &&
(
GIT_PS1_DESCRIBE_STYLE=contains &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - describe detached head - branch' '
- printf " ((b1~1))" > expected &&
+ printf " ((b1~1))" >expected &&
git checkout b1^ &&
test_when_finished "git checkout master" &&
(
GIT_PS1_DESCRIBE_STYLE=branch &&
- __git_ps1 > "$actual"
+ __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 &&
+ 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"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - describe detached head - default' '
- printf " ((t2))" > expected &&
+ printf " ((t2))" >expected &&
git checkout --detach b1 &&
test_when_finished "git checkout master" &&
- __git_ps1 > "$actual" &&
+ __git_ps1 >"$actual" &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - inside .git directory' '
- printf " (GIT_DIR!)" > expected &&
+ printf " (GIT_DIR!)" >expected &&
(
cd .git &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - deep inside .git directory' '
- printf " (GIT_DIR!)" > expected &&
+ printf " (GIT_DIR!)" >expected &&
(
cd .git/refs/heads &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - inside bare repository' '
- printf " (BARE:master)" > expected &&
+ printf " (BARE:master)" >expected &&
git init --bare bare.git &&
test_when_finished "rm -rf bare.git" &&
(
cd bare.git &&
- __git_ps1 > "$actual"
+ __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
+ printf " (b1|REBASE-i 2/3)" >expected
+ write_script fake_editor.sh <<-\EOF &&
+ echo "exec echo" >"$1"
+ echo "edit $(git log -1 --format="%h")" >>"$1"
+ echo "exec echo" >>"$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" &&
+ __git_ps1 >"$actual" &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - rebase merge' '
- printf " (b2|REBASE-m)" > expected &&
+ printf " (b2|REBASE-m 1/3)" >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" &&
+ __git_ps1 >"$actual" &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - rebase' '
- printf " ((t2)|REBASE)" > expected &&
+ printf " (b2|REBASE 1/3)" >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" &&
+ __git_ps1 >"$actual" &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - merge' '
- printf " (b1|MERGING)" > expected &&
+ 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" &&
+ __git_ps1 >"$actual" &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - cherry-pick' '
- printf " (master|CHERRY-PICKING)" > expected &&
+ printf " (master|CHERRY-PICKING)" >expected &&
test_must_fail git cherry-pick b1 &&
test_when_finished "git reset --hard" &&
- __git_ps1 > "$actual" &&
+ __git_ps1 >"$actual" &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - bisect' '
- printf " (master|BISECTING)" > expected &&
+ printf " (master|BISECTING)" >expected &&
git bisect start &&
test_when_finished "git bisect reset" &&
- __git_ps1 > "$actual" &&
+ __git_ps1 >"$actual" &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - dirty status indicator - clean' '
- printf " (master)" > expected &&
+ printf " (master)" >expected &&
(
GIT_PS1_SHOWDIRTYSTATE=y &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - dirty status indicator - dirty worktree' '
- printf " (master *)" > expected &&
- echo "dirty" > file &&
+ printf " (master *)" >expected &&
+ echo "dirty" >file &&
test_when_finished "git reset --hard" &&
(
GIT_PS1_SHOWDIRTYSTATE=y &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - dirty status indicator - dirty index' '
- printf " (master +)" > expected &&
- echo "dirty" > file &&
+ printf " (master +)" >expected &&
+ echo "dirty" >file &&
test_when_finished "git reset --hard" &&
git add -u &&
(
GIT_PS1_SHOWDIRTYSTATE=y &&
- __git_ps1 > "$actual"
+ __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 &&
+ printf " (master *+)" >expected &&
+ echo "dirty index" >file &&
test_when_finished "git reset --hard" &&
git add -u &&
- echo "dirty worktree" > file &&
+ echo "dirty worktree" >file &&
(
GIT_PS1_SHOWDIRTYSTATE=y &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - dirty status indicator - before root commit' '
- printf " (master #)" > expected &&
+ printf " (master #)" >expected &&
(
GIT_PS1_SHOWDIRTYSTATE=y &&
cd otherrepo &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - dirty status indicator - shell variable unset with config disabled' '
- printf " (master)" > expected &&
- echo "dirty" > file &&
+ printf " (master)" >expected &&
+ echo "dirty" >file &&
test_when_finished "git reset --hard" &&
test_config bash.showDirtyState false &&
(
sane_unset GIT_PS1_SHOWDIRTYSTATE &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - dirty status indicator - shell variable unset with config enabled' '
- printf " (master)" > expected &&
- echo "dirty" > file &&
+ printf " (master)" >expected &&
+ echo "dirty" >file &&
test_when_finished "git reset --hard" &&
test_config bash.showDirtyState true &&
(
sane_unset GIT_PS1_SHOWDIRTYSTATE &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - dirty status indicator - shell variable set with config disabled' '
- printf " (master)" > expected &&
- echo "dirty" > file &&
+ printf " (master)" >expected &&
+ echo "dirty" >file &&
test_when_finished "git reset --hard" &&
test_config bash.showDirtyState false &&
(
GIT_PS1_SHOWDIRTYSTATE=y &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - dirty status indicator - shell variable set with config enabled' '
- printf " (master *)" > expected &&
- echo "dirty" > file &&
+ printf " (master *)" >expected &&
+ echo "dirty" >file &&
test_when_finished "git reset --hard" &&
test_config bash.showDirtyState true &&
(
GIT_PS1_SHOWDIRTYSTATE=y &&
- __git_ps1 > "$actual"
+ __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 &&
+ printf " (GIT_DIR!)" >expected &&
+ echo "dirty" >file &&
test_when_finished "git reset --hard" &&
(
GIT_PS1_SHOWDIRTYSTATE=y &&
cd .git &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - stash status indicator - no stash' '
- printf " (master)" > expected &&
+ printf " (master)" >expected &&
(
GIT_PS1_SHOWSTASHSTATE=y &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - stash status indicator - stash' '
- printf " (master $)" > expected &&
+ printf " (master $)" >expected &&
echo 2 >file &&
git stash &&
test_when_finished "git stash drop" &&
+ git pack-refs --all &&
(
GIT_PS1_SHOWSTASHSTATE=y &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - stash status indicator - not shown inside .git directory' '
- printf " (GIT_DIR!)" > expected &&
+ printf " (GIT_DIR!)" >expected &&
echo 2 >file &&
git stash &&
test_when_finished "git stash drop" &&
(
GIT_PS1_SHOWSTASHSTATE=y &&
cd .git &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - untracked files status indicator - no untracked files' '
- printf " (master)" > expected &&
+ printf " (master)" >expected &&
(
GIT_PS1_SHOWUNTRACKEDFILES=y &&
cd otherrepo &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - untracked files status indicator - untracked files' '
- printf " (master %%)" > expected &&
+ printf " (master %%)" >expected &&
(
GIT_PS1_SHOWUNTRACKEDFILES=y &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - untracked files status indicator - shell variable unset with config disabled' '
- printf " (master)" > expected &&
+ printf " (master)" >expected &&
test_config bash.showUntrackedFiles false &&
(
sane_unset GIT_PS1_SHOWUNTRACKEDFILES &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - untracked files status indicator - shell variable unset with config enabled' '
- printf " (master)" > expected &&
+ printf " (master)" >expected &&
test_config bash.showUntrackedFiles true &&
(
sane_unset GIT_PS1_SHOWUNTRACKEDFILES &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - untracked files status indicator - shell variable set with config disabled' '
- printf " (master)" > expected &&
+ printf " (master)" >expected &&
test_config bash.showUntrackedFiles false &&
(
GIT_PS1_SHOWUNTRACKEDFILES=y &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - untracked files status indicator - shell variable set with config enabled' '
- printf " (master %%)" > expected &&
+ printf " (master %%)" >expected &&
test_config bash.showUntrackedFiles true &&
(
GIT_PS1_SHOWUNTRACKEDFILES=y &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - untracked files status indicator - not shown inside .git directory' '
- printf " (GIT_DIR!)" > expected &&
+ printf " (GIT_DIR!)" >expected &&
(
GIT_PS1_SHOWUNTRACKEDFILES=y &&
cd .git &&
- __git_ps1 > "$actual"
+ __git_ps1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'prompt - format string starting with dash' '
- printf -- "-master" > expected &&
- __git_ps1 "-%s" > "$actual" &&
+ printf -- "-master" >expected &&
+ __git_ps1 "-%s" >"$actual" &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - pc mode' '
+ printf "BEFORE: (master):AFTER" >expected &&
+ printf "" >expected_output &&
+ (
+ __git_ps1 "BEFORE:" ":AFTER" >"$actual" &&
+ test_cmp expected_output "$actual" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bash color pc mode - branch name' '
+ printf "BEFORE: (${c_green}master${c_clear}):AFTER" >expected &&
+ (
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ __git_ps1 "BEFORE:" ":AFTER" >"$actual"
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bash color pc mode - detached head' '
+ printf "BEFORE: (${c_red}(%s...)${c_clear}):AFTER" $(git log -1 --format="%h" b1^) >expected &&
+ git checkout b1^ &&
+ test_when_finished "git checkout master" &&
+ (
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bash color pc mode - dirty status indicator - dirty worktree' '
+ printf "BEFORE: (${c_green}master${c_clear} ${c_red}*${c_clear}):AFTER" >expected &&
+ echo "dirty" >file &&
+ test_when_finished "git reset --hard" &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bash color pc mode - dirty status indicator - dirty index' '
+ printf "BEFORE: (${c_green}master${c_clear} ${c_green}+${c_clear}):AFTER" >expected &&
+ echo "dirty" >file &&
+ test_when_finished "git reset --hard" &&
+ git add -u &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bash color pc mode - dirty status indicator - dirty index and worktree' '
+ printf "BEFORE: (${c_green}master${c_clear} ${c_red}*${c_green}+${c_clear}):AFTER" >expected &&
+ echo "dirty index" >file &&
+ test_when_finished "git reset --hard" &&
+ git add -u &&
+ echo "dirty worktree" >file &&
+ (
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bash color pc mode - dirty status indicator - before root commit' '
+ printf "BEFORE: (${c_green}master${c_clear} ${c_green}#${c_clear}):AFTER" >expected &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ cd otherrepo &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bash color pc mode - inside .git directory' '
+ printf "BEFORE: (${c_green}GIT_DIR!${c_clear}):AFTER" >expected &&
+ echo "dirty" >file &&
+ test_when_finished "git reset --hard" &&
+ (
+ GIT_PS1_SHOWDIRTYSTATE=y &&
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ cd .git &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bash color pc mode - stash status indicator' '
+ printf "BEFORE: (${c_green}master${c_clear} ${c_lblue}\$${c_clear}):AFTER" >expected &&
+ echo 2 >file &&
+ git stash &&
+ test_when_finished "git stash drop" &&
+ (
+ GIT_PS1_SHOWSTASHSTATE=y &&
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - bash color pc mode - untracked files status indicator' '
+ printf "BEFORE: (${c_green}master${c_clear} ${c_red}%%${c_clear}):AFTER" >expected &&
+ (
+ GIT_PS1_SHOWUNTRACKEDFILES=y &&
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - zsh color pc mode' '
+ printf "BEFORE: (%%F{green}master%%f):AFTER" >expected &&
+ (
+ ZSH_VERSION=5.0.0 &&
+ GIT_PS1_SHOWCOLORHINTS=y &&
+ __git_ps1 "BEFORE:" ":AFTER" >"$actual"
+ printf "%s" "$PS1" >"$actual"
+ ) &&
test_cmp expected "$actual"
'
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 3fc9cc9..a7e9aac 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -139,12 +139,12 @@ test_pause () {
fi
}
-# Call test_commit with the arguments "<message> [<file> [<contents>]]"
+# Call test_commit with the arguments "<message> [<file> [<contents> [<tag>]]]"
#
# This will commit a file with the given contents and the given commit
-# message. It will also add a tag with <message> as name.
+# message, and tag the resulting commit with the given tag name.
#
-# Both <file> and <contents> default to <message>.
+# <file>, <contents>, and <tag> all default to <message>.
test_commit () {
notick= &&
@@ -172,7 +172,7 @@ test_commit () {
test_tick
fi &&
git commit $signoff -m "$1" &&
- git tag "$1"
+ git tag "${4:-$1}"
}
# Call test_merge with the arguments "<message> <commit>", where <commit>
@@ -343,6 +343,7 @@ test_declared_prereq () {
}
test_expect_failure () {
+ test_start_
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 2 ||
error "bug in the test script: not 2 or 3 parameters to test-expect-failure"
@@ -357,10 +358,11 @@ test_expect_failure () {
test_known_broken_failure_ "$1"
fi
fi
- echo >&3 ""
+ test_finish_
}
test_expect_success () {
+ test_start_
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 2 ||
error "bug in the test script: not 2 or 3 parameters to test-expect-success"
@@ -375,7 +377,7 @@ test_expect_success () {
test_failure_ "$@"
fi
fi
- echo >&3 ""
+ test_finish_
}
# test_external runs external test scripts that provide continuous
@@ -540,6 +542,9 @@ test_must_fail () {
elif test $exit_code = 127; then
echo >&2 "test_must_fail: command not found: $*"
return 1
+ elif test $exit_code = 126; then
+ echo >&2 "test_must_fail: valgrind error: $*"
+ return 1
fi
return 0
}
@@ -606,6 +611,18 @@ test_cmp() {
$GIT_TEST_CMP "$@"
}
+# Check if the file expected to be empty is indeed empty, and barfs
+# otherwise.
+
+test_must_be_empty () {
+ if test -s "$1"
+ then
+ echo "'$1' is not empty, it contains:"
+ cat "$1"
+ return 1
+ fi
+}
+
# Tests that its two parameters refer to the same revision
test_cmp_rev () {
git rev-parse --verify "$1" >expect.rev &&
@@ -676,3 +693,20 @@ test_create_repo () {
mv .git/hooks .git/hooks-disabled
) || exit
}
+
+# This function helps on symlink challenged file systems when it is not
+# important that the file system entry is a symbolic link.
+# Use test_ln_s_add instead of "ln -s x y && git add y" to add a
+# symbolic link entry y to the index.
+
+test_ln_s_add () {
+ if test_have_prereq SYMLINKS
+ then
+ ln -s "$1" "$2" &&
+ git update-index --add "$2"
+ else
+ printf '%s' "$1" >"$2" &&
+ ln_s_obj=$(git hash-object -w "$2") &&
+ git update-index --add --cacheinfo 120000 $ln_s_obj "$2"
+ fi
+}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 657b0bd..1aa27bd 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -54,8 +54,8 @@ done,*)
# do not redirect again
;;
*' --tee '*|*' --va'*)
- mkdir -p test-results
- BASE=test-results/$(basename "$0" .sh)
+ mkdir -p "$TEST_OUTPUT_DIRECTORY/test-results"
+ BASE="$TEST_OUTPUT_DIRECTORY/test-results/$(basename "$0" .sh)"
(GIT_TEST_TEE_STARTED=done ${SHELL_PATH} "$0" "$@" 2>&1;
echo $? > $BASE.exit) | tee $BASE.out
test "$(cat $BASE.exit)" = 0
@@ -92,6 +92,7 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
print join("\n", @vars);
')
unset XDG_CONFIG_HOME
+unset GITPERLLIB
GIT_AUTHOR_EMAIL=author@example.com
GIT_AUTHOR_NAME='A U Thor'
GIT_COMMITTER_EMAIL=committer@example.com
@@ -184,6 +185,9 @@ do
help=t; shift ;;
-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
verbose=t; shift ;;
+ --verbose-only=*)
+ verbose_only=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ shift ;;
-q|--q|--qu|--qui|--quie|--quiet)
# Ignore --quiet under a TAP::Harness. Saying how many tests
# passed without the ok/not ok details is always an error.
@@ -193,17 +197,45 @@ do
--no-color)
color=; shift ;;
--va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
- valgrind=t; verbose=t; shift ;;
+ valgrind=memcheck
+ shift ;;
+ --valgrind=*)
+ valgrind=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ shift ;;
+ --valgrind-only=*)
+ valgrind_only=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ shift ;;
+ --valgrind-parallel=*)
+ valgrind_parallel=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ shift ;;
+ --valgrind-only-stride=*)
+ valgrind_only_stride=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ shift ;;
+ --valgrind-only-offset=*)
+ valgrind_only_offset=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ shift ;;
--tee)
shift ;; # was handled already
--root=*)
root=$(expr "z$1" : 'z[^=]*=\(.*\)')
shift ;;
+ --statusprefix=*)
+ statusprefix=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ shift ;;
*)
echo "error: unknown test option '$1'" >&2; exit 1 ;;
esac
done
+if test -n "$valgrind_only" || test -n "$valgrind_only_stride"
+then
+ test -z "$valgrind" && valgrind=memcheck
+ test -z "$verbose" && verbose_only="$valgrind_only"
+elif test -n "$valgrind"
+then
+ verbose=t
+fi
+
if test -n "$color"
then
say_color () {
@@ -297,12 +329,12 @@ trap 'die' EXIT
test_ok_ () {
test_success=$(($test_success + 1))
- say_color "" "ok $test_count - $@"
+ say_color "" "${statusprefix}ok $test_count - $@"
}
test_failure_ () {
test_failure=$(($test_failure + 1))
- say_color error "not ok $test_count - $1"
+ say_color error "${statusprefix}not ok $test_count - $1"
shift
echo "$@" | sed -e 's/^/# /'
test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; }
@@ -310,18 +342,83 @@ test_failure_ () {
test_known_broken_ok_ () {
test_fixed=$(($test_fixed+1))
- say_color error "ok $test_count - $@ # TODO known breakage vanished"
+ say_color error "${statusprefix}ok $test_count - $@ # TODO known breakage vanished"
}
test_known_broken_failure_ () {
test_broken=$(($test_broken+1))
- say_color warn "not ok $test_count - $@ # TODO known breakage"
+ say_color warn "${statusprefix}not ok $test_count - $@ # TODO known breakage"
}
test_debug () {
test "$debug" = "" || eval "$1"
}
+match_pattern_list () {
+ arg="$1"
+ shift
+ test -z "$*" && return 1
+ for pattern_
+ do
+ case "$arg" in
+ $pattern_)
+ return 0
+ esac
+ done
+ return 1
+}
+
+maybe_teardown_verbose () {
+ test -z "$verbose_only" && return
+ exec 4>/dev/null 3>/dev/null
+ verbose=
+}
+
+last_verbose=t
+maybe_setup_verbose () {
+ test -z "$verbose_only" && return
+ if match_pattern_list $test_count $verbose_only ||
+ { test -n "$valgrind_only_stride" &&
+ expr $test_count "%" $valgrind_only_stride - $valgrind_only_offset = 0 >/dev/null; }
+ then
+ exec 4>&2 3>&1
+ # Emit a delimiting blank line when going from
+ # non-verbose to verbose. Within verbose mode the
+ # delimiter is printed by test_expect_*. The choice
+ # of the initial $last_verbose is such that before
+ # test 1, we do not print it.
+ test -z "$last_verbose" && echo >&3 ""
+ verbose=t
+ else
+ exec 4>/dev/null 3>/dev/null
+ verbose=
+ fi
+ last_verbose=$verbose
+}
+
+maybe_teardown_valgrind () {
+ test -z "$GIT_VALGRIND" && return
+ GIT_VALGRIND_ENABLED=
+}
+
+maybe_setup_valgrind () {
+ test -z "$GIT_VALGRIND" && return
+ if test -z "$valgrind_only" && test -z "$valgrind_only_stride"
+ then
+ GIT_VALGRIND_ENABLED=t
+ return
+ fi
+ GIT_VALGRIND_ENABLED=
+ if match_pattern_list $test_count $valgrind_only
+ then
+ GIT_VALGRIND_ENABLED=t
+ elif test -n "$valgrind_only_stride" &&
+ expr $test_count "%" $valgrind_only_stride - $valgrind_only_offset = 0 >/dev/null
+ then
+ GIT_VALGRIND_ENABLED=t
+ fi
+}
+
test_eval_ () {
# This is a separate function because some tests use
# "return" to end a test_expect_success block early.
@@ -331,8 +428,10 @@ test_eval_ () {
test_run_ () {
test_cleanup=:
expecting_failure=$2
+ setup_malloc_check
test_eval_ "$1"
eval_ret=$?
+ teardown_malloc_check
if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"
then
@@ -347,17 +446,24 @@ test_run_ () {
return "$eval_ret"
}
-test_skip () {
+test_start_ () {
test_count=$(($test_count+1))
+ maybe_setup_verbose
+ maybe_setup_valgrind
+}
+
+test_finish_ () {
+ echo >&3 ""
+ maybe_teardown_valgrind
+ maybe_teardown_verbose
+}
+
+test_skip () {
to_skip=
- for skp in $GIT_SKIP_TESTS
- do
- case $this_test.$test_count in
- $skp)
- to_skip=t
- break
- esac
- done
+ if match_pattern_list $this_test.$test_count $GIT_SKIP_TESTS
+ then
+ to_skip=t
+ fi
if test -z "$to_skip" && test -n "$test_prereq" &&
! test_have_prereq "$test_prereq"
then
@@ -371,8 +477,8 @@ test_skip () {
of_prereq=" of $test_prereq"
fi
- say_color skip >&3 "skipping test: $@"
- say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
+ say_color skip >&3 "${statusprefix}skipping test: $@"
+ say_color skip "${statusprefix}ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
: true
;;
*)
@@ -389,6 +495,8 @@ test_at_end_hook_ () {
test_done () {
GIT_EXIT_OK=t
+ # Note: t0000 relies on $HARNESS_ACTIVE disabling the .counts
+ # output file
if test -z "$HARNESS_ACTIVE"
then
test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results"
@@ -408,11 +516,11 @@ test_done () {
if test "$test_fixed" != 0
then
- say_color error "# $test_fixed known breakage(s) vanished; please update test(s)"
+ say_color error "${statusprefix}# $test_fixed known breakage(s) vanished; please update test(s)"
fi
if test "$test_broken" != 0
then
- say_color warn "# still have $test_broken known breakage(s)"
+ say_color warn "${statusprefix}# still have $test_broken known breakage(s)"
fi
if test "$test_broken" != 0 || test "$test_fixed" != 0
then
@@ -435,9 +543,9 @@ test_done () {
then
if test $test_remaining -gt 0
then
- say_color pass "# passed all $msg"
+ say_color pass "${statusprefix}# passed all $msg"
fi
- say "1..$test_count$skip_all"
+ say "${statusprefix}1..$test_count$skip_all"
fi
test -d "$remove_trash" &&
@@ -451,8 +559,8 @@ test_done () {
*)
if test $test_external_has_tap -eq 0
then
- say_color error "# failed $test_failure among $msg"
- say "1..$test_count"
+ say_color error "${statusprefix}# failed $test_failure among $msg"
+ say "${statusprefix}1..$test_count"
fi
exit 1 ;;
@@ -460,6 +568,9 @@ test_done () {
esac
}
+
+# Set up a directory that we can put in PATH which redirects all git
+# calls to 'valgrind git ...'.
if test -n "$valgrind"
then
make_symlink () {
@@ -507,29 +618,43 @@ then
make_symlink "$symlink_target" "$GIT_VALGRIND/bin/$base" || exit
}
- # override all git executables in TEST_DIRECTORY/..
- GIT_VALGRIND=$TEST_DIRECTORY/valgrind
- mkdir -p "$GIT_VALGRIND"/bin
- for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-*
- do
- make_valgrind_symlink $file
- done
- # special-case the mergetools loadables
- make_symlink "$GIT_BUILD_DIR"/mergetools "$GIT_VALGRIND/bin/mergetools"
- OLDIFS=$IFS
- IFS=:
- for path in $PATH
- do
- ls "$path"/git-* 2> /dev/null |
- while read file
+ # In the case of --valgrind-parallel, we only need to do the
+ # wrapping once, in the main script. The worker children all
+ # have $valgrind_only_stride set, so we can skip based on that.
+ if test -z "$valgrind_only_stride"
+ then
+ # override all git executables in TEST_DIRECTORY/..
+ GIT_VALGRIND=$TEST_DIRECTORY/valgrind
+ mkdir -p "$GIT_VALGRIND"/bin
+ for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-*
do
- make_valgrind_symlink "$file"
+ make_valgrind_symlink $file
done
- done
- IFS=$OLDIFS
+ # special-case the mergetools loadables
+ make_symlink "$GIT_BUILD_DIR"/mergetools "$GIT_VALGRIND/bin/mergetools"
+ OLDIFS=$IFS
+ IFS=:
+ for path in $PATH
+ do
+ ls "$path"/git-* 2> /dev/null |
+ while read file
+ do
+ make_valgrind_symlink "$file"
+ done
+ done
+ IFS=$OLDIFS
+ fi
PATH=$GIT_VALGRIND/bin:$PATH
GIT_EXEC_PATH=$GIT_VALGRIND/bin
export GIT_VALGRIND
+ GIT_VALGRIND_MODE="$valgrind"
+ export GIT_VALGRIND_MODE
+ GIT_VALGRIND_ENABLED=t
+ if test -n "$valgrind_only" || test -n "$valgrind_only_stride"
+ then
+ GIT_VALGRIND_ENABLED=
+ fi
+ export GIT_VALGRIND_ENABLED
elif test -n "$GIT_TEST_INSTALLED"
then
GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) ||
@@ -614,21 +739,53 @@ then
else
mkdir -p "$TRASH_DIRECTORY"
fi
+
+# Gross hack to spawn N sub-instances of the tests in parallel, and
+# summarize the results. Note that if this is enabled, the script
+# terminates at the end of this 'if' block.
+if test -n "$valgrind_parallel"
+then
+ for i in $(test_seq 1 $valgrind_parallel)
+ do
+ root="$TRASH_DIRECTORY/vgparallel-$i"
+ mkdir "$root"
+ TEST_OUTPUT_DIRECTORY="$root" \
+ ${SHELL_PATH} "$0" \
+ --root="$root" --statusprefix="[$i] " \
+ --valgrind="$valgrind" \
+ --valgrind-only-stride="$valgrind_parallel" \
+ --valgrind-only-offset="$i" &
+ pids="$pids $!"
+ done
+ trap "kill $pids" INT TERM HUP
+ wait $pids
+ trap - INT TERM HUP
+ for i in $(test_seq 1 $valgrind_parallel)
+ do
+ root="$TRASH_DIRECTORY/vgparallel-$i"
+ eval "$(cat "$root/test-results/$(basename "$0" .sh)"-*.counts |
+ sed 's/^\([a-z][a-z]*\) \([0-9][0-9]*\)/inner_\1=\2/')"
+ test_count=$(expr $test_count + $inner_total)
+ test_success=$(expr $test_success + $inner_success)
+ test_fixed=$(expr $test_fixed + $inner_fixed)
+ test_broken=$(expr $test_broken + $inner_broken)
+ test_failure=$(expr $test_failure + $inner_failed)
+ done
+ test_done
+fi
+
# Use -P to resolve symlinks in our working directory so that the cwd
# in subprocesses like git equals our $PWD (for pathname comparisons).
cd -P "$TRASH_DIRECTORY" || exit 1
this_test=${0##*/}
this_test=${this_test%%-*}
-for skp in $GIT_SKIP_TESTS
-do
- case "$this_test" in
- $skp)
- say_color info >&3 "skipping test $this_test altogether"
- skip_all="skip all tests in $this_test"
- test_done
- esac
-done
+if match_pattern_list "$this_test" $GIT_SKIP_TESTS
+then
+ say_color info >&3 "skipping test $this_test altogether"
+ skip_all="skip all tests in $this_test"
+ test_done
+fi
# Provide an implementation of the 'yes' utility
yes () {
@@ -668,6 +825,7 @@ case $(uname -s) in
test_set_prereq MINGW
test_set_prereq NOT_CYGWIN
test_set_prereq SED_STRIPS_CR
+ test_set_prereq GREP_STRIPS_CR
;;
*CYGWIN*)
test_set_prereq POSIXPERM
@@ -675,6 +833,7 @@ case $(uname -s) in
test_set_prereq NOT_MINGW
test_set_prereq CYGWIN
test_set_prereq SED_STRIPS_CR
+ test_set_prereq GREP_STRIPS_CR
;;
*)
test_set_prereq POSIXPERM
@@ -729,7 +888,14 @@ test_i18ngrep () {
test_lazy_prereq PIPE '
# test whether the filesystem supports FIFOs
- rm -f testfifo && mkfifo testfifo
+ case $(uname -s) in
+ CYGWIN*)
+ false
+ ;;
+ *)
+ rm -f testfifo && mkfifo testfifo
+ ;;
+ esac
'
test_lazy_prereq SYMLINKS '
diff --git a/t/valgrind/analyze.sh b/t/valgrind/analyze.sh
index d8105d9..2ffc80f 100755
--- a/t/valgrind/analyze.sh
+++ b/t/valgrind/analyze.sh
@@ -1,6 +1,10 @@
#!/bin/sh
-out_prefix=$(dirname "$0")/../test-results/valgrind.out
+# Get TEST_OUTPUT_DIRECTORY from GIT-BUILD-OPTIONS if it's there...
+. "$(dirname "$0")/../../GIT-BUILD-OPTIONS"
+# ... otherwise set it to the default value.
+: ${TEST_OUTPUT_DIRECTORY=$(dirname "$0")/..}
+
output=
count=0
total_count=0
@@ -115,7 +119,7 @@ handle_one () {
finish_output
}
-for test_script in "$(dirname "$0")"/../test-results/*.out
+for test_script in "$TEST_OUTPUT_DIRECTORY"/test-results/*.out
do
handle_one $test_script
done
diff --git a/t/valgrind/valgrind.sh b/t/valgrind/valgrind.sh
index 582b4dc..4215303 100755
--- a/t/valgrind/valgrind.sh
+++ b/t/valgrind/valgrind.sh
@@ -2,20 +2,30 @@
base=$(basename "$0")
-TRACK_ORIGINS=
+TOOL_OPTIONS='--leak-check=no'
-VALGRIND_VERSION=$(valgrind --version)
-VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)')
-VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)')
-test 3 -gt "$VALGRIND_MAJOR" ||
-test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" ||
-TRACK_ORIGINS=--track-origins=yes
+test -z "$GIT_VALGRIND_ENABLED" &&
+exec "$GIT_VALGRIND"/../../"$base" "$@"
+
+case "$GIT_VALGRIND_MODE" in
+memcheck-fast)
+ ;;
+memcheck)
+ VALGRIND_VERSION=$(valgrind --version)
+ VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)')
+ VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)')
+ test 3 -gt "$VALGRIND_MAJOR" ||
+ test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" ||
+ TOOL_OPTIONS="$TOOL_OPTIONS --track-origins=yes"
+ ;;
+*)
+ TOOL_OPTIONS="--tool=$GIT_VALGRIND_MODE"
+esac
exec valgrind -q --error-exitcode=126 \
- --leak-check=no \
- --suppressions="$GIT_VALGRIND/default.supp" \
--gen-suppressions=all \
- $TRACK_ORIGINS \
+ --suppressions="$GIT_VALGRIND/default.supp" \
+ $TOOL_OPTIONS \
--log-fd=4 \
--input-fd=4 \
$GIT_VALGRIND_OPTIONS \
diff --git a/templates/hooks--pre-commit.sample b/templates/hooks--pre-commit.sample
index 18c4829..586e3bf 100755
--- a/templates/hooks--pre-commit.sample
+++ b/templates/hooks--pre-commit.sample
@@ -15,13 +15,13 @@ else
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
-# If you want to allow non-ascii filenames set this variable to true.
+# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
-# Cross platform projects tend to avoid non-ascii filenames; prevent
+# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
@@ -31,18 +31,17 @@ if [ "$allownonascii" != "true" ] &&
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
- echo "Error: Attempt to add a non-ascii file name."
- echo
- echo "This can cause problems if you want to work"
- echo "with people on other platforms."
- echo
- echo "To be portable it is advisable to rename the file ..."
- echo
- echo "If you know what you are doing you can disable this"
- echo "check using:"
- echo
- echo " git config hooks.allownonascii true"
- echo
+ cat <<\EOF
+Error: Attempt to add a non-ASCII file name.
+
+This can cause problems if you want to work with people on other platforms.
+
+To be portable it is advisable to rename the file.
+
+If you know what you are doing you can disable this check using:
+
+ git config hooks.allownonascii true
+EOF
exit 1
fi
diff --git a/templates/hooks--pre-push.sample b/templates/hooks--pre-push.sample
index 15ab6d8..1f3bceb 100755
--- a/templates/hooks--pre-push.sample
+++ b/templates/hooks--pre-push.sample
@@ -30,6 +30,7 @@ do
if [ "$local_sha" = $z40 ]
then
# Handle delete
+ :
else
if [ "$remote_sha" = $z40 ]
then
diff --git a/test-chmtime.c b/test-chmtime.c
index 02b42ba..0df7487 100644
--- a/test-chmtime.c
+++ b/test-chmtime.c
@@ -56,7 +56,7 @@ static int timespec_arg(const char *arg, long int *set_time, int *set_eq)
return 1;
}
-int main(int argc, const char *argv[])
+int main(int argc, char *argv[])
{
static int verbose;
@@ -84,15 +84,15 @@ int main(int argc, const char *argv[])
if (stat(argv[i], &sb) < 0) {
fprintf(stderr, "Failed to stat %s: %s\n",
argv[i], strerror(errno));
- return -1;
+ return 1;
}
-#ifdef WIN32
+#ifdef GIT_WINDOWS_NATIVE
if (!(sb.st_mode & S_IWUSR) &&
chmod(argv[i], sb.st_mode | S_IWUSR)) {
fprintf(stderr, "Could not make user-writable %s: %s",
argv[i], strerror(errno));
- return -1;
+ return 1;
}
#endif
@@ -107,7 +107,7 @@ int main(int argc, const char *argv[])
if (utb.modtime != sb.st_mtime && utime(argv[i], &utb) < 0) {
fprintf(stderr, "Failed to modify time on %s: %s\n",
argv[i], strerror(errno));
- return -1;
+ return 1;
}
}
@@ -115,5 +115,5 @@ int main(int argc, const char *argv[])
usage:
fprintf(stderr, "usage: %s %s\n", argv[0], usage_str);
- return -1;
+ return 1;
}
diff --git a/test-dump-cache-tree.c b/test-dump-cache-tree.c
index a6ffdf3..47eab97 100644
--- a/test-dump-cache-tree.c
+++ b/test-dump-cache-tree.c
@@ -59,6 +59,8 @@ int main(int ac, char **av)
struct cache_tree *another = cache_tree();
if (read_cache() < 0)
die("unable to read index file");
- cache_tree_update(another, active_cache, active_nr, WRITE_TREE_DRY_RUN);
+ cache_tree_update(another,
+ (const struct cache_entry * const *)active_cache,
+ active_nr, WRITE_TREE_DRY_RUN);
return dump_cache_tree(active_cache_tree, another, "");
}
diff --git a/test-index-version.c b/test-index-version.c
index bfaad9e..05d4699 100644
--- a/test-index-version.c
+++ b/test-index-version.c
@@ -1,6 +1,6 @@
#include "cache.h"
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
struct cache_header hdr;
int version;
diff --git a/test-mergesort.c b/test-mergesort.c
index 3f388b4..ea3b959 100644
--- a/test-mergesort.c
+++ b/test-mergesort.c
@@ -22,7 +22,7 @@ static int compare_strings(const void *a, const void *b)
return strcmp(x->text, y->text);
}
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
struct line *line, *p = NULL, *lines = NULL;
struct strbuf sb = STRBUF_INIT;
diff --git a/test-parse-options.c b/test-parse-options.c
index 3c9510a..434e8b8 100644
--- a/test-parse-options.c
+++ b/test-parse-options.c
@@ -29,7 +29,7 @@ static int number_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
const char *prefix = "prefix/";
const char *usage[] = {
@@ -81,7 +81,7 @@ int main(int argc, const char **argv)
};
int i;
- argc = parse_options(argc, argv, prefix, options, usage, 0);
+ argc = parse_options(argc, (const char **)argv, prefix, options, usage, 0);
printf("boolean: %d\n", boolean);
printf("integer: %u\n", integer);
diff --git a/test-path-utils.c b/test-path-utils.c
index 0092cbf..bb975e4 100644
--- a/test-path-utils.c
+++ b/test-path-utils.c
@@ -28,6 +28,19 @@ static int normalize_ceiling_entry(struct string_list_item *item, void *unused)
return 1;
}
+static void normalize_argv_string(const char **var, const char *input)
+{
+ if (!strcmp(input, "<null>"))
+ *var = NULL;
+ else if (!strcmp(input, "<empty>"))
+ *var = "";
+ else
+ *var = input;
+
+ if (*var && (**var == '<' || **var == '('))
+ die("Bad value: %s\n", input);
+}
+
int main(int argc, char **argv)
{
if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
@@ -103,6 +116,25 @@ int main(int argc, char **argv)
return 0;
}
+ if (argc == 3 && !strcmp(argv[1], "mingw_path")) {
+ puts(argv[2]);
+ return 0;
+ }
+
+ if (argc == 4 && !strcmp(argv[1], "relative_path")) {
+ struct strbuf sb = STRBUF_INIT;
+ const char *in, *prefix, *rel;
+ normalize_argv_string(&in, argv[2]);
+ normalize_argv_string(&prefix, argv[3]);
+ rel = relative_path(in, prefix, &sb);
+ if (!rel)
+ puts("(null)");
+ else
+ puts(strlen(rel) > 0 ? rel : "(empty)");
+ strbuf_release(&sb);
+ return 0;
+ }
+
fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
argv[1] ? argv[1] : "(there was none)");
return 1;
diff --git a/test-prio-queue.c b/test-prio-queue.c
new file mode 100644
index 0000000..7be72f0
--- /dev/null
+++ b/test-prio-queue.c
@@ -0,0 +1,39 @@
+#include "cache.h"
+#include "prio-queue.h"
+
+static int intcmp(const void *va, const void *vb, void *data)
+{
+ const int *a = va, *b = vb;
+ return *a - *b;
+}
+
+static void show(int *v)
+{
+ if (!v)
+ printf("NULL\n");
+ else
+ printf("%d\n", *v);
+ free(v);
+}
+
+int main(int argc, char **argv)
+{
+ struct prio_queue pq = { intcmp };
+
+ while (*++argv) {
+ if (!strcmp(*argv, "get"))
+ show(prio_queue_get(&pq));
+ else if (!strcmp(*argv, "dump")) {
+ int *v;
+ while ((v = prio_queue_get(&pq)))
+ show(v);
+ }
+ else {
+ int *v = malloc(sizeof(*v));
+ *v = atoi(*argv);
+ prio_queue_put(&pq, v);
+ }
+ }
+
+ return 0;
+}
diff --git a/test-read-cache.c b/test-read-cache.c
new file mode 100644
index 0000000..b25bcf1
--- /dev/null
+++ b/test-read-cache.c
@@ -0,0 +1,13 @@
+#include "cache.h"
+
+int main (int argc, char **argv)
+{
+ int i, cnt = 1;
+ if (argc == 2)
+ cnt = strtol(argv[1], NULL, 0);
+ for (i = 0; i < cnt; i++) {
+ read_cache();
+ discard_cache();
+ }
+ return 0;
+}
diff --git a/test-subprocess.c b/test-subprocess.c
index f2d4c0d..93525eb 100644
--- a/test-subprocess.c
+++ b/test-subprocess.c
@@ -1,7 +1,7 @@
#include "cache.h"
#include "run-command.h"
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
struct child_process cp;
int nogit = 0;
@@ -15,6 +15,6 @@ int main(int argc, const char **argv)
}
memset(&cp, 0, sizeof(cp));
cp.git_cmd = 1;
- cp.argv = argv + 1;
+ cp.argv = (const char **)argv + 1;
return run_command(&cp);
}
diff --git a/test-svn-fe.c b/test-svn-fe.c
index 0f2d9a4..120ec96 100644
--- a/test-svn-fe.c
+++ b/test-svn-fe.c
@@ -24,7 +24,7 @@ static int apply_delta(int argc, char *argv[])
die_errno("cannot open preimage");
if (buffer_init(&delta, argv[3]))
die_errno("cannot open delta");
- if (svndiff0_apply(&delta, (off_t) strtoull(argv[4], NULL, 0),
+ if (svndiff0_apply(&delta, (off_t) strtoumax(argv[4], NULL, 0),
&preimage_view, stdout))
return 1;
if (buffer_deinit(&preimage))
diff --git a/test-urlmatch-normalization.c b/test-urlmatch-normalization.c
new file mode 100644
index 0000000..090bf21
--- /dev/null
+++ b/test-urlmatch-normalization.c
@@ -0,0 +1,50 @@
+#include "git-compat-util.h"
+#include "urlmatch.h"
+
+int main(int argc, char **argv)
+{
+ const char usage[] = "test-urlmatch-normalization [-p | -l] <url1> | <url1> <url2>";
+ char *url1, *url2;
+ int opt_p = 0, opt_l = 0;
+
+ /*
+ * For one url, succeed if url_normalize succeeds on it, fail otherwise.
+ * For two urls, succeed only if url_normalize succeeds on both and
+ * the results compare equal with strcmp. If -p is given (one url only)
+ * and url_normalize succeeds, print the result followed by "\n". If
+ * -l is given (one url only) and url_normalize succeeds, print the
+ * returned length in decimal followed by "\n".
+ */
+
+ if (argc > 1 && !strcmp(argv[1], "-p")) {
+ opt_p = 1;
+ argc--;
+ argv++;
+ } else if (argc > 1 && !strcmp(argv[1], "-l")) {
+ opt_l = 1;
+ argc--;
+ argv++;
+ }
+
+ if (argc < 2 || argc > 3)
+ die("%s", usage);
+
+ if (argc == 2) {
+ struct url_info info;
+ url1 = url_normalize(argv[1], &info);
+ if (!url1)
+ return 1;
+ if (opt_p)
+ printf("%s\n", url1);
+ if (opt_l)
+ printf("%u\n", (unsigned)info.url_len);
+ return 0;
+ }
+
+ if (opt_p || opt_l)
+ die("%s", usage);
+
+ url1 = url_normalize(argv[1], NULL);
+ url2 = url_normalize(argv[2], NULL);
+ return (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1;
+}
diff --git a/thread-utils.c b/thread-utils.c
index 7f4b76a..97396a7 100644
--- a/thread-utils.c
+++ b/thread-utils.c
@@ -24,7 +24,7 @@ int online_cpus(void)
long ncpus;
#endif
-#ifdef _WIN32
+#ifdef GIT_WINDOWS_NATIVE
SYSTEM_INFO info;
GetSystemInfo(&info);
diff --git a/trace.c b/trace.c
index 5ec0e3b..3d744d1 100644
--- a/trace.c
+++ b/trace.c
@@ -75,6 +75,7 @@ static void trace_vprintf(const char *key, const char *fmt, va_list ap)
strbuf_release(&buf);
}
+__attribute__((format (printf, 2, 3)))
static void trace_printf_key(const char *key, const char *fmt, ...)
{
va_list ap;
diff --git a/transport-helper.c b/transport-helper.c
index fdd79d8..b32e2d6 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -11,6 +11,7 @@
#include "thread-utils.h"
#include "sigchain.h"
#include "argv-array.h"
+#include "refs.h"
static int debug;
@@ -25,7 +26,10 @@ struct helper_data {
option : 1,
push : 1,
connect : 1,
- no_disconnect_req : 1;
+ signed_tags : 1,
+ check_connectivity : 1,
+ no_disconnect_req : 1,
+ no_private_update : 1;
char *export_marks;
char *import_marks;
/* These go from remote name (as in "list") to private name */
@@ -46,7 +50,7 @@ static void sendline(struct helper_data *helper, struct strbuf *buffer)
die_errno("Full write to remote helper failed");
}
-static int recvline_fh(FILE *helper, struct strbuf *buffer)
+static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)
{
strbuf_reset(buffer);
if (debug)
@@ -64,7 +68,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer)
static int recvline(struct helper_data *helper, struct strbuf *buffer)
{
- return recvline_fh(helper->out, buffer);
+ return recvline_fh(helper->out, buffer, helper->name);
}
static void xchgline(struct helper_data *helper, struct strbuf *buffer)
@@ -184,6 +188,8 @@ static struct child_process *get_helper(struct transport *transport)
data->bidi_import = 1;
else if (!strcmp(capname, "export"))
data->export = 1;
+ else if (!strcmp(capname, "check-connectivity"))
+ data->check_connectivity = 1;
else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
ALLOC_GROW(refspecs,
refspec_nr + 1,
@@ -191,6 +197,8 @@ static struct child_process *get_helper(struct transport *transport)
refspecs[refspec_nr++] = xstrdup(capname + strlen("refspec "));
} else if (!strcmp(capname, "connect")) {
data->connect = 1;
+ } else if (!strcmp(capname, "signed-tags")) {
+ data->signed_tags = 1;
} else if (!prefixcmp(capname, "export-marks ")) {
struct strbuf arg = STRBUF_INIT;
strbuf_addstr(&arg, "--export-marks=");
@@ -201,6 +209,8 @@ static struct child_process *get_helper(struct transport *transport)
strbuf_addstr(&arg, "--import-marks=");
strbuf_addstr(&arg, capname + strlen("import-marks "));
data->import_marks = strbuf_detach(&arg, NULL);
+ } else if (!prefixcmp(capname, "no-private-update")) {
+ data->no_private_update = 1;
} else if (mandatory) {
die("Unknown mandatory capability %s. This remote "
"helper probably needs newer version of Git.",
@@ -214,6 +224,8 @@ static struct child_process *get_helper(struct transport *transport)
for (i = 0; i < refspec_nr; i++)
free((char *)refspecs[i]);
free(refspecs);
+ } else if (data->import || data->bidi_import || data->export) {
+ warning("This remote helper should implement refspec capability.");
}
strbuf_release(&buf);
if (debug)
@@ -343,6 +355,9 @@ static int fetch_with_fetch(struct transport *transport,
struct strbuf buf = STRBUF_INIT;
standard_options(transport);
+ if (data->check_connectivity &&
+ data->transport_options.check_self_contained_and_connected)
+ set_helper_option(transport, "check-connectivity", "true");
for (i = 0; i < nr_heads; i++) {
const struct ref *posn = to_fetch[i];
@@ -366,6 +381,10 @@ static int fetch_with_fetch(struct transport *transport,
else
transport->pack_lockfile = xstrdup(name);
}
+ else if (data->check_connectivity &&
+ data->transport_options.check_self_contained_and_connected &&
+ !strcmp(buf.buf, "connectivity-ok"))
+ data->transport_options.self_contained_and_connected = 1;
else if (!buf.len)
break;
else
@@ -409,9 +428,11 @@ static int get_exporter(struct transport *transport,
/* we need to duplicate helper->in because we want to use it after
* fastexport is done with it. */
fastexport->out = dup(helper->in);
- fastexport->argv = xcalloc(5 + revlist_args->nr, sizeof(*fastexport->argv));
+ fastexport->argv = xcalloc(6 + revlist_args->nr, sizeof(*fastexport->argv));
fastexport->argv[argc++] = "fast-export";
fastexport->argv[argc++] = "--use-done-feature";
+ fastexport->argv[argc++] = data->signed_tags ?
+ "--signed-tags=verbatim" : "--signed-tags=warn-strip";
if (data->export_marks)
fastexport->argv[argc++] = data->export_marks;
if (data->import_marks)
@@ -468,7 +489,7 @@ static int fetch_with_import(struct transport *transport,
* were fetching.
*
* (If no "refspec" capability was specified, for historical
- * reasons we default to *:*.)
+ * reasons we default to the equivalent of *:*.)
*
* Store the result in to_fetch[i].old_sha1. Callers such
* as "git fetch" can use the value to write feedback to the
@@ -535,7 +556,7 @@ static int process_connect_service(struct transport *transport,
goto exit;
sendline(data, &cmdbuf);
- recvline_fh(input, &cmdbuf);
+ recvline_fh(input, &cmdbuf, name);
if (!strcmp(cmdbuf.buf, "")) {
data->no_disconnect_req = 1;
if (debug)
@@ -617,7 +638,7 @@ static int fetch(struct transport *transport,
return -1;
}
-static void push_update_ref_status(struct strbuf *buf,
+static int push_update_ref_status(struct strbuf *buf,
struct ref **ref,
struct ref *remote_refs)
{
@@ -675,6 +696,11 @@ static void push_update_ref_status(struct strbuf *buf,
free(msg);
msg = NULL;
}
+ else if (!strcmp(msg, "stale info")) {
+ status = REF_STATUS_REJECT_STALE;
+ free(msg);
+ msg = NULL;
+ }
}
if (*ref)
@@ -683,7 +709,7 @@ static void push_update_ref_status(struct strbuf *buf,
*ref = find_ref_by_name(remote_refs, refname);
if (!*ref) {
warning("helper reported unexpected status of %s", refname);
- return;
+ return 1;
}
if ((*ref)->status != REF_STATUS_NONE) {
@@ -692,11 +718,12 @@ static void push_update_ref_status(struct strbuf *buf,
* status reported by the remote helper if the latter is 'no match'.
*/
if (status == REF_STATUS_NONE)
- return;
+ return 1;
}
(*ref)->status = status;
(*ref)->remote_status = msg;
+ return !(status == REF_STATUS_OK);
}
static void push_update_refs_status(struct helper_data *data,
@@ -705,23 +732,38 @@ static void push_update_refs_status(struct helper_data *data,
struct strbuf buf = STRBUF_INIT;
struct ref *ref = remote_refs;
for (;;) {
+ char *private;
+
recvline(data, &buf);
if (!buf.len)
break;
- push_update_ref_status(&buf, &ref, remote_refs);
+ if (push_update_ref_status(&buf, &ref, remote_refs))
+ continue;
+
+ if (!data->refspecs || data->no_private_update)
+ continue;
+
+ /* propagate back the update to the remote namespace */
+ private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
+ if (!private)
+ continue;
+ update_ref("update by helper", private, ref->new_sha1, NULL, 0, 0);
+ free(private);
}
strbuf_release(&buf);
}
static int push_refs_with_push(struct transport *transport,
- struct ref *remote_refs, int flags)
+ struct ref *remote_refs, int flags)
{
int force_all = flags & TRANSPORT_PUSH_FORCE;
int mirror = flags & TRANSPORT_PUSH_MIRROR;
struct helper_data *data = transport->data;
struct strbuf buf = STRBUF_INIT;
struct ref *ref;
+ struct string_list cas_options = STRING_LIST_INIT_DUP;
+ struct string_list_item *cas_option;
get_helper(transport);
if (!data->push)
@@ -734,6 +776,7 @@ static int push_refs_with_push(struct transport *transport,
/* Check for statuses set by set_ref_status_for_push() */
switch (ref->status) {
case REF_STATUS_REJECT_NONFASTFORWARD:
+ case REF_STATUS_REJECT_STALE:
case REF_STATUS_REJECT_ALREADY_EXISTS:
case REF_STATUS_UPTODATE:
continue;
@@ -756,11 +799,29 @@ static int push_refs_with_push(struct transport *transport,
strbuf_addch(&buf, ':');
strbuf_addstr(&buf, ref->name);
strbuf_addch(&buf, '\n');
+
+ /*
+ * The "--force-with-lease" options without explicit
+ * values to expect have already been expanded into
+ * the ref->old_sha1_expect[] field; we can ignore
+ * transport->smart_options->cas altogether and instead
+ * can enumerate them from the refs.
+ */
+ if (ref->expect_old_sha1) {
+ struct strbuf cas = STRBUF_INIT;
+ strbuf_addf(&cas, "%s:%s",
+ ref->name, sha1_to_hex(ref->old_sha1_expect));
+ string_list_append(&cas_options, strbuf_detach(&cas, NULL));
+ }
}
- if (buf.len == 0)
+ if (buf.len == 0) {
+ string_list_clear(&cas_options, 0);
return 0;
+ }
standard_options(transport);
+ for_each_string_list_item(cas_option, &cas_options)
+ set_helper_option(transport, "cas", cas_option->string);
if (flags & TRANSPORT_PUSH_DRY_RUN) {
if (set_helper_option(transport, "dry-run", "true") != 0)
@@ -784,6 +845,14 @@ static int push_refs_with_export(struct transport *transport,
struct string_list revlist_args = STRING_LIST_INIT_NODUP;
struct strbuf buf = STRBUF_INIT;
+ if (!data->refspecs)
+ die("remote-helper doesn't support push; refspec needed");
+
+ if (flags & TRANSPORT_PUSH_DRY_RUN) {
+ if (set_helper_option(transport, "dry-run", "true") != 0)
+ die("helper %s does not support dry-run", data->name);
+ }
+
helper = get_helper(transport);
write_constant(helper->in, "export\n");
@@ -794,22 +863,25 @@ static int push_refs_with_export(struct transport *transport,
char *private;
unsigned char sha1[20];
- if (!data->refspecs)
- continue;
+ if (ref->deletion)
+ die("remote-helpers do not support ref deletion");
+
private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
if (private && !get_sha1(private, sha1)) {
strbuf_addf(&buf, "^%s", private);
string_list_append(&revlist_args, strbuf_detach(&buf, NULL));
+ hashcpy(ref->old_sha1, sha1);
}
free(private);
- if (ref->deletion) {
+ if (ref->deletion)
die("remote-helpers do not support ref deletion");
- }
- if (ref->peer_ref)
+ if (ref->peer_ref) {
+ if (strcmp(ref->peer_ref->name, ref->name))
+ die("remote-helpers do not support old:new syntax");
string_list_append(&revlist_args, ref->peer_ref->name);
-
+ }
}
if (get_exporter(transport, &exporter, &revlist_args))
@@ -949,6 +1021,7 @@ int transport_helper_init(struct transport *transport, const char *name)
#define PBUFFERSIZE 8192
/* Print bidirectional transfer loop debug message. */
+__attribute__((format (printf, 1, 2)))
static void transfer_debug(const char *fmt, ...)
{
va_list args;
@@ -1034,7 +1107,7 @@ static int udt_do_read(struct unidirectional_transfer *t)
return -1;
} else if (bytes == 0) {
transfer_debug("%s EOF (with %i bytes in buffer)",
- t->src_name, t->bufuse);
+ t->src_name, (int)t->bufuse);
t->state = SSTATE_FLUSHING;
} else if (bytes > 0) {
t->bufuse += bytes;
@@ -1098,7 +1171,7 @@ static void *udt_copy_task_routine(void *udt)
#ifndef NO_PTHREADS
/*
- * Join thread, with apporiate errors on failure. Name is name for the
+ * Join thread, with appropriate errors on failure. Name is name for the
* thread (for error messages). Returns 0 on success, 1 on failure.
*/
static int tloop_join(pthread_t thread, const char *name)
@@ -1164,7 +1237,7 @@ static void udt_kill_transfer(struct unidirectional_transfer *t)
}
/*
- * Join process, with apporiate errors on failure. Name is name for the
+ * Join process, with appropriate errors on failure. Name is name for the
* process (for error messages). Returns 0 on success, 1 on failure.
*/
static int tloop_join(pid_t pid, const char *name)
diff --git a/transport.c b/transport.c
index e6f9346..7202b77 100644
--- a/transport.c
+++ b/transport.c
@@ -3,6 +3,8 @@
#include "run-command.h"
#include "pkt-line.h"
#include "fetch-pack.h"
+#include "remote.h"
+#include "connect.h"
#include "send-pack.h"
#include "walker.h"
#include "bundle.h"
@@ -508,7 +510,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
struct ref *refs;
connect_setup(transport, for_push, 0);
- get_remote_heads(data->fd[0], &refs,
+ get_remote_heads(data->fd[0], NULL, 0, &refs,
for_push ? REF_NORMAL : 0, &data->extra_have);
data->got_remote_heads = 1;
@@ -519,11 +521,9 @@ static int fetch_refs_via_pack(struct transport *transport,
int nr_heads, struct ref **to_fetch)
{
struct git_transport_data *data = transport->data;
- struct string_list sought = STRING_LIST_INIT_DUP;
const struct ref *refs;
char *dest = xstrdup(transport->url);
struct fetch_pack_args args;
- int i;
struct ref *refs_tmp = NULL;
memset(&args, 0, sizeof(args));
@@ -536,29 +536,30 @@ static int fetch_refs_via_pack(struct transport *transport,
args.quiet = (transport->verbose < 0);
args.no_progress = !transport->progress;
args.depth = data->options.depth;
-
- for (i = 0; i < nr_heads; i++)
- string_list_append(&sought, to_fetch[i]->name);
+ args.check_self_contained_and_connected =
+ data->options.check_self_contained_and_connected;
if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
- get_remote_heads(data->fd[0], &refs_tmp, 0, NULL);
+ get_remote_heads(data->fd[0], NULL, 0, &refs_tmp, 0, NULL);
data->got_remote_heads = 1;
}
refs = fetch_pack(&args, data->fd, data->conn,
refs_tmp ? refs_tmp : transport->remote_refs,
- dest, &sought, &transport->pack_lockfile);
+ dest, to_fetch, nr_heads,
+ &transport->pack_lockfile);
close(data->fd[0]);
close(data->fd[1]);
if (finish_connect(data->conn))
refs = NULL;
data->conn = NULL;
data->got_remote_heads = 0;
+ data->options.self_contained_and_connected =
+ args.self_contained_and_connected;
free_refs(refs_tmp);
- string_list_clear(&sought, 0);
free(dest);
return (refs ? 0 : -1);
}
@@ -708,6 +709,10 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
"needs force", porcelain);
break;
+ case REF_STATUS_REJECT_STALE:
+ print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ "stale info", porcelain);
+ break;
case REF_STATUS_REMOTE_REJECT:
print_ref_status('!', "[remote rejected]", ref,
ref->deletion ? NULL : ref->peer_ref,
@@ -800,7 +805,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
struct ref *tmp_refs;
connect_setup(transport, 1, 0);
- get_remote_heads(data->fd[0], &tmp_refs, REF_NORMAL, NULL);
+ get_remote_heads(data->fd[0], NULL, 0, &tmp_refs, REF_NORMAL, NULL);
data->got_remote_heads = 1;
}
@@ -876,6 +881,8 @@ void transport_take_over(struct transport *transport,
transport->push_refs = git_transport_push;
transport->disconnect = disconnect_git;
transport->smart_options = &(data->options);
+
+ transport->cannot_reuse = 1;
}
static int is_local(const char *url)
@@ -1077,6 +1084,7 @@ static int run_pre_push_hook(struct transport *transport,
for (r = remote_refs; r; r = r->next) {
if (!r->peer_ref) continue;
if (r->status == REF_STATUS_REJECT_NONFASTFORWARD) continue;
+ if (r->status == REF_STATUS_REJECT_STALE) continue;
if (r->status == REF_STATUS_UPTODATE) continue;
strbuf_reset(&buf);
@@ -1133,12 +1141,20 @@ int transport_push(struct transport *transport,
match_flags |= MATCH_REFS_MIRROR;
if (flags & TRANSPORT_PUSH_PRUNE)
match_flags |= MATCH_REFS_PRUNE;
+ if (flags & TRANSPORT_PUSH_FOLLOW_TAGS)
+ match_flags |= MATCH_REFS_FOLLOW_TAGS;
if (match_push_refs(local_refs, &remote_refs,
refspec_nr, refspec, match_flags)) {
return -1;
}
+ if (transport->smart_options &&
+ transport->smart_options->cas &&
+ !is_empty_cas(transport->smart_options->cas))
+ apply_push_cas(transport->smart_options->cas,
+ transport->remote, remote_refs);
+
set_ref_status_for_push(remote_refs,
flags & TRANSPORT_PUSH_MIRROR,
flags & TRANSPORT_PUSH_FORCE);
@@ -1231,7 +1247,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
* then local and remote refs are likely to still be equal.
* Just feed them all to the fetch method in that case.
* This condition shouldn't be met in a non-deepening fetch
- * (see builtin-fetch.c:quickfetch()).
+ * (see builtin/fetch.c:quickfetch()).
*/
heads = xmalloc(nr_refs * sizeof(*heads));
for (rm = refs; rm; rm = rm->next)
diff --git a/transport.h b/transport.h
index e7beb81..8f96bed 100644
--- a/transport.h
+++ b/transport.h
@@ -2,15 +2,19 @@
#define TRANSPORT_H
#include "cache.h"
+#include "run-command.h"
#include "remote.h"
struct git_transport_options {
unsigned thin : 1;
unsigned keep : 1;
unsigned followtags : 1;
+ unsigned check_self_contained_and_connected : 1;
+ unsigned self_contained_and_connected : 1;
int depth;
const char *uploadpack;
const char *receivepack;
+ struct push_cas_option *cas;
};
struct transport {
@@ -25,6 +29,12 @@ struct transport {
*/
unsigned got_remote_refs : 1;
+ /*
+ * Transports that call take-over destroys the data specific to
+ * the transport type while doing so, and cannot be reused.
+ */
+ unsigned cannot_reuse : 1;
+
/**
* Returns 0 if successful, positive if the option is not
* recognized or is inapplicable, and negative if the option
@@ -105,6 +115,7 @@ struct transport {
#define TRANSPORT_PUSH_PRUNE 128
#define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256
#define TRANSPORT_PUSH_NO_HOOK 512
+#define TRANSPORT_PUSH_FOLLOW_TAGS 1024
#define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
#define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)
@@ -123,6 +134,9 @@ struct transport *transport_get(struct remote *, const char *);
/* Transfer the data as a thin pack if not null */
#define TRANS_OPT_THIN "thin"
+/* Check the current value of the remote ref */
+#define TRANS_OPT_CAS "cas"
+
/* Keep the pack that was transferred if not null */
#define TRANS_OPT_KEEP "keep"
@@ -167,7 +181,7 @@ int transport_connect(struct transport *transport, const char *name,
int transport_helper_init(struct transport *transport, const char *name);
int bidirectional_transfer_loop(int input, int output);
-/* common methods used by transport.c and builtin-send-pack.c */
+/* common methods used by transport.c and builtin/send-pack.c */
void transport_verify_remote_names(int nr_heads, const char **heads);
void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose);
diff --git a/tree-diff.c b/tree-diff.c
index ba01563..ccf9d7c 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -138,7 +138,6 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
/* Enable recursion indefinitely */
opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
- opt->pathspec.max_depth = -1;
strbuf_init(&base, PATH_MAX);
strbuf_add(&base, base_str, baselen);
@@ -196,9 +195,27 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
struct diff_options diff_opts;
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_filepair *choice;
- const char *paths[1];
int i;
+ /*
+ * follow-rename code is very specific, we need exactly one
+ * path. Magic that matches more than one path is not
+ * supported.
+ */
+ GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
+#if 0
+ /*
+ * We should reject wildcards as well. Unfortunately we
+ * haven't got a reliable way to detect that 'foo\*bar' in
+ * fact has no wildcards. nowildcard_len is merely a hint for
+ * optimization. Let it slip for now until wildmatch is taught
+ * about dry-run mode and returns wildcard info.
+ */
+ if (opt->pathspec.has_wildcard)
+ die("BUG:%s:%d: wildcards are not supported",
+ __FILE__, __LINE__);
+#endif
+
/* Remove the file creation entry from the diff queue, and remember it */
choice = q->queue[0];
q->nr = 0;
@@ -207,15 +224,13 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
DIFF_OPT_SET(&diff_opts, RECURSIVE);
DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
- diff_opts.single_follow = opt->pathspec.raw[0];
+ diff_opts.single_follow = opt->pathspec.items[0].match;
diff_opts.break_opt = opt->break_opt;
diff_opts.rename_score = opt->rename_score;
- paths[0] = NULL;
- diff_tree_setup_paths(paths, &diff_opts);
diff_setup_done(&diff_opts);
diff_tree(t1, t2, base, &diff_opts);
diffcore_std(&diff_opts);
- diff_tree_release_paths(&diff_opts);
+ free_pathspec(&diff_opts.pathspec);
/* Go through the new set of filepairing, and see if we find a more interesting one */
opt->found_follow = 0;
@@ -228,15 +243,18 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
* the future!
*/
if ((p->status == 'R' || p->status == 'C') &&
- !strcmp(p->two->path, opt->pathspec.raw[0])) {
+ !strcmp(p->two->path, opt->pathspec.items[0].match)) {
+ const char *path[2];
+
/* Switch the file-pairs around */
q->queue[i] = choice;
choice = p;
/* Update the path we use from now on.. */
- diff_tree_release_paths(opt);
- opt->pathspec.raw[0] = xstrdup(p->one->path);
- diff_tree_setup_paths(opt->pathspec.raw, opt);
+ path[0] = p->one->path;
+ path[1] = NULL;
+ free_pathspec(&opt->pathspec);
+ parse_pathspec(&opt->pathspec, PATHSPEC_ALL_MAGIC, 0, "", path);
/*
* The caller expects us to return a set of vanilla
@@ -310,13 +328,3 @@ int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_
free(tree);
return retval;
}
-
-void diff_tree_release_paths(struct diff_options *opt)
-{
- free_pathspec(&opt->pathspec);
-}
-
-void diff_tree_setup_paths(const char **p, struct diff_options *opt)
-{
- init_pathspec(&opt->pathspec, p);
-}
diff --git a/tree-walk.c b/tree-walk.c
index 6e30ef9..5ece8c3 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -3,6 +3,7 @@
#include "unpack-trees.h"
#include "dir.h"
#include "tree.h"
+#include "pathspec.h"
static const char *get_mode(const char *str, unsigned int *modep)
{
@@ -323,7 +324,6 @@ static inline int prune_traversal(struct name_entry *e,
int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
{
- int ret = 0;
int error = 0;
struct name_entry *entry = xmalloc(n*sizeof(*entry));
int i;
@@ -341,6 +341,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
strbuf_setlen(&base, info->pathlen);
}
for (;;) {
+ int trees_used;
unsigned long mask, dirmask;
const char *first = NULL;
int first_len = 0;
@@ -404,15 +405,14 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
if (interesting < 0)
break;
if (interesting) {
- ret = info->fn(n, mask, dirmask, entry, info);
- if (ret < 0) {
- error = ret;
+ trees_used = info->fn(n, mask, dirmask, entry, info);
+ if (trees_used < 0) {
+ error = trees_used;
if (!info->show_all_errors)
break;
}
- mask &= ret;
+ mask &= trees_used;
}
- ret = 0;
for (i = 0; i < n; i++)
if (mask & (1ul << i))
update_extended_entry(tx + i, entry + i);
@@ -488,13 +488,25 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
return retval;
}
-static int match_entry(const struct name_entry *entry, int pathlen,
+static int match_entry(const struct pathspec_item *item,
+ const struct name_entry *entry, int pathlen,
const char *match, int matchlen,
enum interesting *never_interesting)
{
int m = -1; /* signals that we haven't called strncmp() */
- if (*never_interesting != entry_not_interesting) {
+ if (item->magic & PATHSPEC_ICASE)
+ /*
+ * "Never interesting" trick requires exact
+ * matching. We could do something clever with inexact
+ * matching, but it's trickier (and not to forget that
+ * strcasecmp is locale-dependent, at least in
+ * glibc). Just disable it for now. It can't be worse
+ * than the wildcard's codepath of '[Tt][Hi][Is][Ss]'
+ * pattern.
+ */
+ *never_interesting = entry_not_interesting;
+ else if (*never_interesting != entry_not_interesting) {
/*
* We have not seen any match that sorts later
* than the current path.
@@ -540,7 +552,7 @@ static int match_entry(const struct name_entry *entry, int pathlen,
* we cheated and did not do strncmp(), so we do
* that here.
*/
- m = strncmp(match, entry->path, pathlen);
+ m = ps_strncmp(item, match, entry->path, pathlen);
/*
* If common part matched earlier then it is a hit,
@@ -548,15 +560,39 @@ static int match_entry(const struct name_entry *entry, int pathlen,
* leading directory and is shorter than match.
*/
if (!m)
+ /*
+ * match_entry does not check if the prefix part is
+ * matched case-sensitively. If the entry is a
+ * directory and part of prefix, it'll be rematched
+ * eventually by basecmp with special treatment for
+ * the prefix.
+ */
return 1;
return 0;
}
-static int match_dir_prefix(const char *base,
+/* :(icase)-aware string compare */
+static int basecmp(const struct pathspec_item *item,
+ const char *base, const char *match, int len)
+{
+ if (item->magic & PATHSPEC_ICASE) {
+ int ret, n = len > item->prefix ? item->prefix : len;
+ ret = strncmp(base, match, n);
+ if (ret)
+ return ret;
+ base += n;
+ match += n;
+ len -= n;
+ }
+ return ps_strncmp(item, base, match, len);
+}
+
+static int match_dir_prefix(const struct pathspec_item *item,
+ const char *base,
const char *match, int matchlen)
{
- if (strncmp(base, match, matchlen))
+ if (basecmp(item, base, match, matchlen))
return 0;
/*
@@ -593,7 +629,7 @@ static int match_wildcard_base(const struct pathspec_item *item,
*/
if (baselen >= matchlen) {
*matched = matchlen;
- return !strncmp(base, match, matchlen);
+ return !basecmp(item, base, match, matchlen);
}
dirlen = matchlen;
@@ -606,7 +642,7 @@ static int match_wildcard_base(const struct pathspec_item *item,
* base ends with '/' so we are sure it really matches
* directory
*/
- if (strncmp(base, match, baselen))
+ if (basecmp(item, base, match, baselen))
return 0;
*matched = baselen;
} else
@@ -635,8 +671,17 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
enum interesting never_interesting = ps->has_wildcard ?
entry_not_interesting : all_entries_not_interesting;
+ GUARD_PATHSPEC(ps,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
if (!ps->nr) {
- if (!ps->recursive || ps->max_depth == -1)
+ if (!ps->recursive ||
+ !(ps->magic & PATHSPEC_MAXDEPTH) ||
+ ps->max_depth == -1)
return all_entries_interesting;
return within_depth(base->buf + base_offset, baselen,
!!S_ISDIR(entry->mode),
@@ -654,10 +699,12 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
if (baselen >= matchlen) {
/* If it doesn't match, move along... */
- if (!match_dir_prefix(base_str, match, matchlen))
+ if (!match_dir_prefix(item, base_str, match, matchlen))
goto match_wildcards;
- if (!ps->recursive || ps->max_depth == -1)
+ if (!ps->recursive ||
+ !(ps->magic & PATHSPEC_MAXDEPTH) ||
+ ps->max_depth == -1)
return all_entries_interesting;
return within_depth(base_str + matchlen + 1,
@@ -668,15 +715,14 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
}
/* Either there must be no base, or the base must match. */
- if (baselen == 0 || !strncmp(base_str, match, baselen)) {
- if (match_entry(entry, pathlen,
+ if (baselen == 0 || !basecmp(item, base_str, match, baselen)) {
+ if (match_entry(item, entry, pathlen,
match + baselen, matchlen - baselen,
&never_interesting))
return entry_interesting;
if (item->nowildcard_len < item->len) {
- if (!git_fnmatch(match + baselen, entry->path,
- item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
+ if (!git_fnmatch(item, match + baselen, entry->path,
item->nowildcard_len - baselen))
return entry_interesting;
@@ -717,8 +763,7 @@ match_wildcards:
strbuf_add(base, entry->path, pathlen);
- if (!git_fnmatch(match, base->buf + base_offset,
- item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
+ if (!git_fnmatch(item, match, base->buf + base_offset,
item->nowildcard_len)) {
strbuf_setlen(base, base_offset + baselen);
return entry_interesting;
diff --git a/tree-walk.h b/tree-walk.h
index 2bf0db9..ae04b64 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -46,7 +46,7 @@ struct traverse_info {
int pathlen;
struct pathspec *pathspec;
- unsigned long conflicts;
+ unsigned long df_conflicts;
traverse_callback_t fn;
void *data;
int show_all_errors;
diff --git a/tree.c b/tree.c
index 62fed63..549e588 100644
--- a/tree.c
+++ b/tree.c
@@ -47,7 +47,7 @@ static int read_one_entry_quick(const unsigned char *sha1, const char *base, int
}
static int read_tree_1(struct tree *tree, struct strbuf *base,
- int stage, struct pathspec *pathspec,
+ int stage, const struct pathspec *pathspec,
read_tree_fn_t fn, void *context)
{
struct tree_desc desc;
@@ -116,7 +116,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
int read_tree_recursive(struct tree *tree,
const char *base, int baselen,
- int stage, struct pathspec *pathspec,
+ int stage, const struct pathspec *pathspec,
read_tree_fn_t fn, void *context)
{
struct strbuf sb = STRBUF_INIT;
@@ -159,7 +159,7 @@ int read_tree(struct tree *tree, int stage, struct pathspec *match)
* sort at the end.
*/
for (i = 0; !fn && i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
if (ce_stage(ce) == stage)
fn = read_one_entry;
}
diff --git a/tree.h b/tree.h
index 69bcb5e..9dc90ba 100644
--- a/tree.h
+++ b/tree.h
@@ -25,7 +25,7 @@ typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const ch
extern int read_tree_recursive(struct tree *tree,
const char *base, int baselen,
- int stage, struct pathspec *pathspec,
+ int stage, const struct pathspec *pathspec,
read_tree_fn_t fn, void *context);
extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec);
diff --git a/unpack-trees.c b/unpack-trees.c
index 09e53df..1a61e6f 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -116,14 +116,20 @@ static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
-static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
- unsigned int set, unsigned int clear)
+static struct cache_entry *dup_entry(const struct cache_entry *ce)
{
unsigned int size = ce_size(ce);
struct cache_entry *new = xmalloc(size);
memcpy(new, ce, size);
- do_add_entry(o, new, set, clear);
+ return new;
+}
+
+static void add_entry(struct unpack_trees_options *o,
+ const struct cache_entry *ce,
+ unsigned int set, unsigned int clear)
+{
+ do_add_entry(o, dup_entry(ce), set, clear);
}
/*
@@ -173,7 +179,7 @@ static void display_error_msgs(struct unpack_trees_options *o)
* Unlink the last component and schedule the leading directories for
* removal, such that empty directories get removed.
*/
-static void unlink_entry(struct cache_entry *ce)
+static void unlink_entry(const struct cache_entry *ce)
{
if (!check_leading_path(ce->name, ce_namelen(ce)))
return;
@@ -193,7 +199,7 @@ static int check_updates(struct unpack_trees_options *o)
if (o->update && o->verbose_update) {
for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
- struct cache_entry *ce = index->cache[cnt];
+ const struct cache_entry *ce = index->cache[cnt];
if (ce->ce_flags & (CE_UPDATE | CE_WT_REMOVE))
total++;
}
@@ -206,7 +212,7 @@ static int check_updates(struct unpack_trees_options *o)
if (o->update)
git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
for (i = 0; i < index->cache_nr; i++) {
- struct cache_entry *ce = index->cache[i];
+ const struct cache_entry *ce = index->cache[i];
if (ce->ce_flags & CE_WT_REMOVE) {
display_progress(progress, ++cnt);
@@ -235,8 +241,11 @@ static int check_updates(struct unpack_trees_options *o)
return errs != 0;
}
-static int verify_uptodate_sparse(struct cache_entry *ce, struct unpack_trees_options *o);
-static int verify_absent_sparse(struct cache_entry *ce, enum unpack_trees_error_types, struct unpack_trees_options *o);
+static int verify_uptodate_sparse(const struct cache_entry *ce,
+ struct unpack_trees_options *o);
+static int verify_absent_sparse(const struct cache_entry *ce,
+ enum unpack_trees_error_types,
+ struct unpack_trees_options *o);
static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_options *o)
{
@@ -291,7 +300,8 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt
return 0;
}
-static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o)
+static inline int call_unpack_fn(const struct cache_entry * const *src,
+ struct unpack_trees_options *o)
{
int ret = o->fn(src, o);
if (ret > 0)
@@ -320,7 +330,7 @@ static void mark_all_ce_unused(struct index_state *index)
index->cache[i]->ce_flags &= ~(CE_UNPACKED | CE_ADDED | CE_NEW_SKIP_WORKTREE);
}
-static int locate_in_src_index(struct cache_entry *ce,
+static int locate_in_src_index(const struct cache_entry *ce,
struct unpack_trees_options *o)
{
struct index_state *index = o->src_index;
@@ -366,7 +376,7 @@ static struct cache_entry *next_cache_entry(struct unpack_trees_options *o)
return NULL;
}
-static void add_same_unmerged(struct cache_entry *ce,
+static void add_same_unmerged(const struct cache_entry *ce,
struct unpack_trees_options *o)
{
struct index_state *index = o->src_index;
@@ -388,7 +398,7 @@ static void add_same_unmerged(struct cache_entry *ce,
static int unpack_index_entry(struct cache_entry *ce,
struct unpack_trees_options *o)
{
- struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
+ const struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
int ret;
src[0] = ce;
@@ -454,7 +464,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
newinfo.pathspec = info->pathspec;
newinfo.name = *p;
newinfo.pathlen += tree_entry_len(p) + 1;
- newinfo.conflicts |= df_conflicts;
+ newinfo.df_conflicts |= df_conflicts;
for (i = 0; i < n; i++, dirmask >>= 1) {
const unsigned char *sha1 = NULL;
@@ -555,17 +565,12 @@ static int unpack_nondirectories(int n, unsigned long mask,
{
int i;
struct unpack_trees_options *o = info->data;
- unsigned long conflicts;
+ unsigned long conflicts = info->df_conflicts | dirmask;
/* Do we have *only* directories? Nothing to do */
if (mask == dirmask && !src[0])
return 0;
- conflicts = info->conflicts;
- if (o->merge)
- conflicts >>= 1;
- conflicts |= dirmask;
-
/*
* Ok, we've filled in up to any potential index entry in src[0],
* now do the rest.
@@ -590,8 +595,16 @@ static int unpack_nondirectories(int n, unsigned long mask,
src[i + o->merge] = create_ce_entry(info, names + i, stage);
}
- if (o->merge)
- return call_unpack_fn(src, o);
+ if (o->merge) {
+ int rc = call_unpack_fn((const struct cache_entry * const *)src,
+ o);
+ for (i = 0; i < n; i++) {
+ struct cache_entry *ce = src[i + o->merge];
+ if (ce != o->df_conflict_entry)
+ free(ce);
+ }
+ return rc;
+ }
for (i = 0; i < n; i++)
if (src[i] && src[i] != o->df_conflict_entry)
@@ -637,7 +650,7 @@ static int find_cache_pos(struct traverse_info *info,
int p_len = tree_entry_len(p);
for (pos = o->cache_bottom; pos < index->cache_nr; pos++) {
- struct cache_entry *ce = index->cache[pos];
+ const struct cache_entry *ce = index->cache[pos];
const char *ce_name, *ce_slash;
int cmp, ce_len;
@@ -789,13 +802,6 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
/* Now handle any directories.. */
if (dirmask) {
- unsigned long conflicts = mask & ~dirmask;
- if (o->merge) {
- conflicts <<= 1;
- if (src[0])
- conflicts |= 1;
- }
-
/* special case: "diff-index --cached" looking at a tree */
if (o->diff_index_cached &&
n == 1 && dirmask == 1 && S_ISDIR(names->mode)) {
@@ -814,7 +820,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
}
}
- if (traverse_trees_recursive(n, dirmask, conflicts,
+ if (traverse_trees_recursive(n, dirmask, mask & ~dirmask,
names, info) < 0)
return -1;
return mask;
@@ -995,7 +1001,9 @@ static void mark_new_skip_worktree(struct exclude_list *el,
select_flag, skip_wt_flag, el);
}
-static int verify_absent(struct cache_entry *, enum unpack_trees_error_types, struct unpack_trees_options *);
+static int verify_absent(const struct cache_entry *,
+ enum unpack_trees_error_types,
+ struct unpack_trees_options *);
/*
* N-way merge "len" trees. Returns 0 on success, -1 on failure to manipulate the
* resulting index, -2 on failure to reflect the changes to the work tree.
@@ -1026,10 +1034,6 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
o->el = &el;
}
- if (o->dir) {
- o->path_exclude_check = xmalloc(sizeof(struct path_exclude_check));
- path_exclude_check_init(o->path_exclude_check, o->dir);
- }
memset(&o->result, 0, sizeof(o->result));
o->result.initialized = 1;
o->result.timestamp.sec = o->src_index->timestamp.sec;
@@ -1150,15 +1154,13 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
o->src_index = NULL;
ret = check_updates(o) ? (-2) : 0;
- if (o->dst_index)
+ if (o->dst_index) {
+ discard_index(o->dst_index);
*o->dst_index = o->result;
+ }
done:
clear_exclude_list(&el);
- if (o->path_exclude_check) {
- path_exclude_check_clear(o->path_exclude_check);
- free(o->path_exclude_check);
- }
return ret;
return_failed:
@@ -1173,12 +1175,13 @@ return_failed:
/* Here come the merge functions */
-static int reject_merge(struct cache_entry *ce, struct unpack_trees_options *o)
+static int reject_merge(const struct cache_entry *ce,
+ struct unpack_trees_options *o)
{
return add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
}
-static int same(struct cache_entry *a, struct cache_entry *b)
+static int same(const struct cache_entry *a, const struct cache_entry *b)
{
if (!!a != !!b)
return 0;
@@ -1195,9 +1198,9 @@ static int same(struct cache_entry *a, struct cache_entry *b)
* When a CE gets turned into an unmerged entry, we
* want it to be up-to-date
*/
-static int verify_uptodate_1(struct cache_entry *ce,
- struct unpack_trees_options *o,
- enum unpack_trees_error_types error_type)
+static int verify_uptodate_1(const struct cache_entry *ce,
+ struct unpack_trees_options *o,
+ enum unpack_trees_error_types error_type)
{
struct stat st;
@@ -1236,7 +1239,7 @@ static int verify_uptodate_1(struct cache_entry *ce,
add_rejected_path(o, error_type, ce->name);
}
-static int verify_uptodate(struct cache_entry *ce,
+static int verify_uptodate(const struct cache_entry *ce,
struct unpack_trees_options *o)
{
if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
@@ -1244,13 +1247,14 @@ static int verify_uptodate(struct cache_entry *ce,
return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE);
}
-static int verify_uptodate_sparse(struct cache_entry *ce,
+static int verify_uptodate_sparse(const struct cache_entry *ce,
struct unpack_trees_options *o)
{
return verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);
}
-static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
+static void invalidate_ce_path(const struct cache_entry *ce,
+ struct unpack_trees_options *o)
{
if (ce)
cache_tree_invalidate_path(o->src_index->cache_tree, ce->name);
@@ -1263,16 +1267,16 @@ static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_optio
* Currently, git does not checkout subprojects during a superproject
* checkout, so it is not going to overwrite anything.
*/
-static int verify_clean_submodule(struct cache_entry *ce,
- enum unpack_trees_error_types error_type,
- struct unpack_trees_options *o)
+static int verify_clean_submodule(const struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
+ struct unpack_trees_options *o)
{
return 0;
}
-static int verify_clean_subdirectory(struct cache_entry *ce,
- enum unpack_trees_error_types error_type,
- struct unpack_trees_options *o)
+static int verify_clean_subdirectory(const struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
+ struct unpack_trees_options *o)
{
/*
* we are about to extract "ce->name"; we would not want to lose
@@ -1351,18 +1355,18 @@ static int verify_clean_subdirectory(struct cache_entry *ce,
*/
static int icase_exists(struct unpack_trees_options *o, const char *name, int len, struct stat *st)
{
- struct cache_entry *src;
+ const struct cache_entry *src;
src = index_name_exists(o->src_index, name, len, 1);
return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
}
static int check_ok_to_remove(const char *name, int len, int dtype,
- struct cache_entry *ce, struct stat *st,
+ const struct cache_entry *ce, struct stat *st,
enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
- struct cache_entry *result;
+ const struct cache_entry *result;
/*
* It may be that the 'lstat()' succeeded even though
@@ -1375,7 +1379,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
return 0;
if (o->dir &&
- is_path_excluded(o->path_exclude_check, name, -1, &dtype))
+ is_excluded(o->dir, name, &dtype))
/*
* ce->name is explicitly excluded, so it is Ok to
* overwrite it.
@@ -1413,9 +1417,9 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
* We do not want to remove or overwrite a working tree file that
* is not tracked, unless it is ignored.
*/
-static int verify_absent_1(struct cache_entry *ce,
- enum unpack_trees_error_types error_type,
- struct unpack_trees_options *o)
+static int verify_absent_1(const struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
+ struct unpack_trees_options *o)
{
int len;
struct stat st;
@@ -1448,7 +1452,7 @@ static int verify_absent_1(struct cache_entry *ce,
}
}
-static int verify_absent(struct cache_entry *ce,
+static int verify_absent(const struct cache_entry *ce,
enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
@@ -1457,9 +1461,9 @@ static int verify_absent(struct cache_entry *ce,
return verify_absent_1(ce, error_type, o);
}
-static int verify_absent_sparse(struct cache_entry *ce,
- enum unpack_trees_error_types error_type,
- struct unpack_trees_options *o)
+static int verify_absent_sparse(const struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
+ struct unpack_trees_options *o)
{
enum unpack_trees_error_types orphaned_error = error_type;
if (orphaned_error == ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN)
@@ -1468,10 +1472,12 @@ static int verify_absent_sparse(struct cache_entry *ce,
return verify_absent_1(ce, orphaned_error, o);
}
-static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
- struct unpack_trees_options *o)
+static int merged_entry(const struct cache_entry *ce,
+ const struct cache_entry *old,
+ struct unpack_trees_options *o)
{
int update = CE_UPDATE;
+ struct cache_entry *merge = dup_entry(ce);
if (!old) {
/*
@@ -1489,8 +1495,11 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
update |= CE_ADDED;
merge->ce_flags |= CE_NEW_SKIP_WORKTREE;
- if (verify_absent(merge, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
+ if (verify_absent(merge,
+ ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
+ free(merge);
return -1;
+ }
invalidate_ce_path(merge, o);
} else if (!(old->ce_flags & CE_CONFLICTED)) {
/*
@@ -1504,8 +1513,10 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
copy_cache_entry(merge, old);
update = 0;
} else {
- if (verify_uptodate(old, o))
+ if (verify_uptodate(old, o)) {
+ free(merge);
return -1;
+ }
/* Migrate old flags over */
update |= old->ce_flags & (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
invalidate_ce_path(old, o);
@@ -1518,12 +1529,13 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
invalidate_ce_path(old, o);
}
- add_entry(o, merge, update, CE_STAGEMASK);
+ do_add_entry(o, merge, update, CE_STAGEMASK);
return 1;
}
-static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
- struct unpack_trees_options *o)
+static int deleted_entry(const struct cache_entry *ce,
+ const struct cache_entry *old,
+ struct unpack_trees_options *o)
{
/* Did it exist in the index? */
if (!old) {
@@ -1538,7 +1550,8 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
return 1;
}
-static int keep_entry(struct cache_entry *ce, struct unpack_trees_options *o)
+static int keep_entry(const struct cache_entry *ce,
+ struct unpack_trees_options *o)
{
add_entry(o, ce, 0, 0);
return 1;
@@ -1560,11 +1573,12 @@ static void show_stage_entry(FILE *o,
}
#endif
-int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
+int threeway_merge(const struct cache_entry * const *stages,
+ struct unpack_trees_options *o)
{
- struct cache_entry *index;
- struct cache_entry *head;
- struct cache_entry *remote = stages[o->head_idx + 1];
+ const struct cache_entry *index;
+ const struct cache_entry *head;
+ const struct cache_entry *remote = stages[o->head_idx + 1];
int count;
int head_match = 0;
int remote_match = 0;
@@ -1649,7 +1663,7 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
if (o->aggressive) {
int head_deleted = !head;
int remote_deleted = !remote;
- struct cache_entry *ce = NULL;
+ const struct cache_entry *ce = NULL;
if (index)
ce = index;
@@ -1732,11 +1746,12 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
* "carry forward" rule, please see <Documentation/git-read-tree.txt>.
*
*/
-int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
+int twoway_merge(const struct cache_entry * const *src,
+ struct unpack_trees_options *o)
{
- struct cache_entry *current = src[0];
- struct cache_entry *oldtree = src[1];
- struct cache_entry *newtree = src[2];
+ const struct cache_entry *current = src[0];
+ const struct cache_entry *oldtree = src[1];
+ const struct cache_entry *newtree = src[2];
if (o->merge_size != 2)
return error("Cannot do a twoway merge of %d trees",
@@ -1798,11 +1813,11 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
* Keep the index entries at stage0, collapse stage1 but make sure
* stage0 does not have anything there.
*/
-int bind_merge(struct cache_entry **src,
- struct unpack_trees_options *o)
+int bind_merge(const struct cache_entry * const *src,
+ struct unpack_trees_options *o)
{
- struct cache_entry *old = src[0];
- struct cache_entry *a = src[1];
+ const struct cache_entry *old = src[0];
+ const struct cache_entry *a = src[1];
if (o->merge_size != 1)
return error("Cannot do a bind merge of %d trees",
@@ -1822,10 +1837,11 @@ int bind_merge(struct cache_entry **src,
* The rule is:
* - take the stat information from stage0, take the data from stage1
*/
-int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)
+int oneway_merge(const struct cache_entry * const *src,
+ struct unpack_trees_options *o)
{
- struct cache_entry *old = src[0];
- struct cache_entry *a = src[1];
+ const struct cache_entry *old = src[0];
+ const struct cache_entry *a = src[1];
if (o->merge_size != 1)
return error("Cannot do a oneway merge of %d trees",
diff --git a/unpack-trees.h b/unpack-trees.h
index ec74a9f..36a73a6 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -8,7 +8,7 @@
struct unpack_trees_options;
struct exclude_list;
-typedef int (*merge_fn_t)(struct cache_entry **src,
+typedef int (*merge_fn_t)(const struct cache_entry * const *src,
struct unpack_trees_options *options);
enum unpack_trees_error_types {
@@ -52,7 +52,6 @@ struct unpack_trees_options {
const char *prefix;
int cache_bottom;
struct dir_struct *dir;
- struct path_exclude_check *path_exclude_check;
struct pathspec *pathspec;
merge_fn_t fn;
const char *msgs[NB_UNPACK_TREES_ERROR_TYPES];
@@ -78,9 +77,13 @@ struct unpack_trees_options {
extern int unpack_trees(unsigned n, struct tree_desc *t,
struct unpack_trees_options *options);
-int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o);
-int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o);
-int bind_merge(struct cache_entry **src, struct unpack_trees_options *o);
-int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o);
+int threeway_merge(const struct cache_entry * const *stages,
+ struct unpack_trees_options *o);
+int twoway_merge(const struct cache_entry * const *src,
+ struct unpack_trees_options *o);
+int bind_merge(const struct cache_entry * const *src,
+ struct unpack_trees_options *o);
+int oneway_merge(const struct cache_entry * const *src,
+ struct unpack_trees_options *o);
#endif
diff --git a/upload-pack.c b/upload-pack.c
index 948cfff..b03492e 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -10,6 +10,7 @@
#include "revision.h"
#include "list-objects.h"
#include "run-command.h"
+#include "connect.h"
#include "sigchain.h"
#include "version.h"
#include "string-list.h"
@@ -26,6 +27,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<
#define SHALLOW (1u << 16)
#define NOT_SHALLOW (1u << 17)
#define CLIENT_SHALLOW (1u << 18)
+#define HIDDEN_REF (1u << 19)
static unsigned long oldest_have;
@@ -33,6 +35,7 @@ static int multi_ack;
static int no_done;
static int use_thin_pack, use_ofs_delta, use_include_tag;
static int no_progress, daemon_mode;
+static int allow_tip_sha1_in_want;
static int shallow_nr;
static struct object_array have_obj;
static struct object_array want_obj;
@@ -42,7 +45,6 @@ static unsigned int timeout;
* otherwise maximum packet size (up to 65520 bytes).
*/
static int use_sideband;
-static int debug_fd;
static int advertise_refs;
static int stateless_rpc;
@@ -51,13 +53,6 @@ static void reset_timeout(void)
alarm(timeout);
}
-static int strip(char *line, int len)
-{
- if (len && line[len-1] == '\n')
- line[--len] = 0;
- return len;
-}
-
static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
{
if (use_sideband)
@@ -70,7 +65,8 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
xwrite(fd, data, sz);
return sz;
}
- return safe_write(fd, data, sz);
+ write_or_die(fd, data, sz);
+ return sz;
}
static FILE *pack_pipe = NULL;
@@ -413,7 +409,6 @@ static int ok_to_give_up(void)
static int get_common_commits(void)
{
- static char line[1000];
unsigned char sha1[20];
char last_hex[41];
int got_common = 0;
@@ -423,10 +418,10 @@ static int get_common_commits(void)
save_commit_buffer = 0;
for (;;) {
- int len = packet_read_line(0, line, sizeof(line));
+ char *line = packet_read_line(0, NULL);
reset_timeout();
- if (!len) {
+ if (!line) {
if (multi_ack == 2 && got_common
&& !got_other && ok_to_give_up()) {
sent_ready = 1;
@@ -445,7 +440,6 @@ static int get_common_commits(void)
got_other = 0;
continue;
}
- strip(line, len);
if (!prefixcmp(line, "have ")) {
switch (got_sha1(line+5, sha1)) {
case -1: /* they have what we do not */
@@ -485,6 +479,12 @@ static int get_common_commits(void)
}
}
+static int is_our_ref(struct object *o)
+{
+ return o->flags &
+ ((allow_tip_sha1_in_want ? HIDDEN_REF : 0) | OUR_REF);
+}
+
static void check_non_tip(void)
{
static const char *argv[] = {
@@ -521,7 +521,7 @@ static void check_non_tip(void)
o = get_indexed_object(--i);
if (!o)
continue;
- if (!(o->flags & OUR_REF))
+ if (!is_our_ref(o))
continue;
memcpy(namebuf + 1, sha1_to_hex(o->sha1), 40);
if (write_in_full(cmd.in, namebuf, 42) < 0)
@@ -530,7 +530,7 @@ static void check_non_tip(void)
namebuf[40] = '\n';
for (i = 0; i < want_obj.nr; i++) {
o = want_obj.objects[i].item;
- if (o->flags & OUR_REF)
+ if (is_our_ref(o))
continue;
memcpy(namebuf, sha1_to_hex(o->sha1), 40);
if (write_in_full(cmd.in, namebuf, 41) < 0)
@@ -564,7 +564,7 @@ error:
/* Pick one of them (we know there at least is one) */
for (i = 0; i < want_obj.nr; i++) {
o = want_obj.objects[i].item;
- if (!(o->flags & OUR_REF))
+ if (!is_our_ref(o))
die("git upload-pack: not our ref %s",
sha1_to_hex(o->sha1));
}
@@ -573,36 +573,33 @@ error:
static void receive_needs(void)
{
struct object_array shallows = OBJECT_ARRAY_INIT;
- static char line[1000];
- int len, depth = 0;
+ int depth = 0;
int has_non_tip = 0;
shallow_nr = 0;
- if (debug_fd)
- write_str_in_full(debug_fd, "#S\n");
for (;;) {
struct object *o;
const char *features;
unsigned char sha1_buf[20];
- len = packet_read_line(0, line, sizeof(line));
+ char *line = packet_read_line(0, NULL);
reset_timeout();
- if (!len)
+ if (!line)
break;
- if (debug_fd)
- write_in_full(debug_fd, line, len);
if (!prefixcmp(line, "shallow ")) {
unsigned char sha1[20];
struct object *object;
- if (get_sha1(line + 8, sha1))
+ if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);
object = parse_object(sha1);
if (!object)
- die("did not find object for %s", line);
+ continue;
if (object->type != OBJ_COMMIT)
die("invalid shallow object %s", sha1_to_hex(sha1));
- object->flags |= CLIENT_SHALLOW;
- add_object_array(object, NULL, &shallows);
+ if (!(object->flags & CLIENT_SHALLOW)) {
+ object->flags |= CLIENT_SHALLOW;
+ add_object_array(object, NULL, &shallows);
+ }
continue;
}
if (!prefixcmp(line, "deepen ")) {
@@ -644,13 +641,11 @@ static void receive_needs(void)
sha1_to_hex(sha1_buf));
if (!(o->flags & WANTED)) {
o->flags |= WANTED;
- if (!(o->flags & OUR_REF))
+ if (!is_our_ref(o))
has_non_tip = 1;
add_object_array(o, NULL, &want_obj);
}
}
- if (debug_fd)
- write_str_in_full(debug_fd, "#E\n");
/*
* We have sent all our refs already, and the other end
@@ -730,8 +725,10 @@ static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag
{
struct object *o = lookup_unknown_object(sha1);
- if (ref_is_hidden(refname))
+ if (ref_is_hidden(refname)) {
+ o->flags |= HIDDEN_REF;
return 1;
+ }
if (!o)
die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));
o->flags |= OUR_REF;
@@ -750,9 +747,10 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
return 0;
if (capabilities)
- packet_write(1, "%s %s%c%s%s agent=%s\n",
+ packet_write(1, "%s %s%c%s%s%s agent=%s\n",
sha1_to_hex(sha1), refname_nons,
0, capabilities,
+ allow_tip_sha1_in_want ? " allow-tip-sha1-in-want" : "",
stateless_rpc ? " no-done" : "",
git_user_agent_sanitized());
else
@@ -786,6 +784,8 @@ static void upload_pack(void)
static int upload_pack_config(const char *var, const char *value, void *unused)
{
+ if (!strcmp("uploadpack.allowtipsha1inwant", var))
+ allow_tip_sha1_in_want = git_config_bool(var, value);
return parse_hide_refs_config(var, value, "uploadpack");
}
@@ -841,8 +841,6 @@ int main(int argc, char **argv)
if (is_repository_shallow())
die("attempt to fetch/clone from a shallow repository");
git_config(upload_pack_config, NULL);
- if (getenv("GIT_DEBUG_SEND_PACK"))
- debug_fd = atoi(getenv("GIT_DEBUG_SEND_PACK"));
upload_pack();
return 0;
}
diff --git a/urlmatch.c b/urlmatch.c
new file mode 100644
index 0000000..1db76c8
--- /dev/null
+++ b/urlmatch.c
@@ -0,0 +1,535 @@
+#include "cache.h"
+#include "urlmatch.h"
+
+#define URL_ALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+#define URL_DIGIT "0123456789"
+#define URL_ALPHADIGIT URL_ALPHA URL_DIGIT
+#define URL_SCHEME_CHARS URL_ALPHADIGIT "+.-"
+#define URL_HOST_CHARS URL_ALPHADIGIT ".-[:]" /* IPv6 literals need [:] */
+#define URL_UNSAFE_CHARS " <>\"%{}|\\^`" /* plus 0x00-0x1F,0x7F-0xFF */
+#define URL_GEN_RESERVED ":/?#[]@"
+#define URL_SUB_RESERVED "!$&'()*+,;="
+#define URL_RESERVED URL_GEN_RESERVED URL_SUB_RESERVED /* only allowed delims */
+
+static int append_normalized_escapes(struct strbuf *buf,
+ const char *from,
+ size_t from_len,
+ const char *esc_extra,
+ const char *esc_ok)
+{
+ /*
+ * Append to strbuf 'buf' characters from string 'from' with length
+ * 'from_len' while unescaping characters that do not need to be escaped
+ * and escaping characters that do. The set of characters to escape
+ * (the complement of which is unescaped) starts out as the RFC 3986
+ * unsafe characters (0x00-0x1F,0x7F-0xFF," <>\"#%{}|\\^`"). If
+ * 'esc_extra' is not NULL, those additional characters will also always
+ * be escaped. If 'esc_ok' is not NULL, those characters will be left
+ * escaped if found that way, but will not be unescaped otherwise (used
+ * for delimiters). If a %-escape sequence is encountered that is not
+ * followed by 2 hexadecimal digits, the sequence is invalid and
+ * false (0) will be returned. Otherwise true (1) will be returned for
+ * success.
+ *
+ * Note that all %-escape sequences will be normalized to UPPERCASE
+ * as indicated in RFC 3986. Unless included in esc_extra or esc_ok
+ * alphanumerics and "-._~" will always be unescaped as per RFC 3986.
+ */
+
+ while (from_len) {
+ int ch = *from++;
+ int was_esc = 0;
+
+ from_len--;
+ if (ch == '%') {
+ if (from_len < 2 ||
+ !isxdigit((unsigned char)from[0]) ||
+ !isxdigit((unsigned char)from[1]))
+ return 0;
+ ch = hexval_table[(unsigned char)*from++] << 4;
+ ch |= hexval_table[(unsigned char)*from++];
+ from_len -= 2;
+ was_esc = 1;
+ }
+ if ((unsigned char)ch <= 0x1F || (unsigned char)ch >= 0x7F ||
+ strchr(URL_UNSAFE_CHARS, ch) ||
+ (esc_extra && strchr(esc_extra, ch)) ||
+ (was_esc && strchr(esc_ok, ch)))
+ strbuf_addf(buf, "%%%02X", (unsigned char)ch);
+ else
+ strbuf_addch(buf, ch);
+ }
+
+ return 1;
+}
+
+char *url_normalize(const char *url, struct url_info *out_info)
+{
+ /*
+ * Normalize NUL-terminated url using the following rules:
+ *
+ * 1. Case-insensitive parts of url will be converted to lower case
+ * 2. %-encoded characters that do not need to be will be unencoded
+ * 3. Characters that are not %-encoded and must be will be encoded
+ * 4. All %-encodings will be converted to upper case hexadecimal
+ * 5. Leading 0s are removed from port numbers
+ * 6. If the default port for the scheme is given it will be removed
+ * 7. A path part (including empty) not starting with '/' has one added
+ * 8. Any dot segments (. or ..) in the path are resolved and removed
+ * 9. IPv6 host literals are allowed (but not normalized or validated)
+ *
+ * The rules are based on information in RFC 3986.
+ *
+ * Please note this function requires a full URL including a scheme
+ * and host part (except for file: URLs which may have an empty host).
+ *
+ * The return value is a newly allocated string that must be freed
+ * or NULL if the url is not valid.
+ *
+ * If out_info is non-NULL, the url and err fields therein will always
+ * be set. If a non-NULL value is returned, it will be stored in
+ * out_info->url as well, out_info->err will be set to NULL and the
+ * other fields of *out_info will also be filled in. If a NULL value
+ * is returned, NULL will be stored in out_info->url and out_info->err
+ * will be set to a brief, translated, error message, but no other
+ * fields will be filled in.
+ *
+ * This is NOT a URL validation function. Full URL validation is NOT
+ * performed. Some invalid host names are passed through this function
+ * undetected. However, most all other problems that make a URL invalid
+ * will be detected (including a missing host for non file: URLs).
+ */
+
+ size_t url_len = strlen(url);
+ struct strbuf norm;
+ size_t spanned;
+ size_t scheme_len, user_off=0, user_len=0, passwd_off=0, passwd_len=0;
+ size_t host_off=0, host_len=0, port_len=0, path_off, path_len, result_len;
+ const char *slash_ptr, *at_ptr, *colon_ptr, *path_start;
+ char *result;
+
+ /*
+ * Copy lowercased scheme and :// suffix, %-escapes are not allowed
+ * First character of scheme must be URL_ALPHA
+ */
+ spanned = strspn(url, URL_SCHEME_CHARS);
+ if (!spanned || !isalpha(url[0]) || spanned + 3 > url_len ||
+ url[spanned] != ':' || url[spanned+1] != '/' || url[spanned+2] != '/') {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid URL scheme name or missing '://' suffix");
+ }
+ return NULL; /* Bad scheme and/or missing "://" part */
+ }
+ strbuf_init(&norm, url_len);
+ scheme_len = spanned;
+ spanned += 3;
+ url_len -= spanned;
+ while (spanned--)
+ strbuf_addch(&norm, tolower(*url++));
+
+
+ /*
+ * Copy any username:password if present normalizing %-escapes
+ */
+ at_ptr = strchr(url, '@');
+ slash_ptr = url + strcspn(url, "/?#");
+ if (at_ptr && at_ptr < slash_ptr) {
+ user_off = norm.len;
+ if (at_ptr > url) {
+ if (!append_normalized_escapes(&norm, url, at_ptr - url,
+ "", URL_RESERVED)) {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid %XX escape sequence");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ colon_ptr = strchr(norm.buf + scheme_len + 3, ':');
+ if (colon_ptr) {
+ passwd_off = (colon_ptr + 1) - norm.buf;
+ passwd_len = norm.len - passwd_off;
+ user_len = (passwd_off - 1) - (scheme_len + 3);
+ } else {
+ user_len = norm.len - (scheme_len + 3);
+ }
+ }
+ strbuf_addch(&norm, '@');
+ url_len -= (++at_ptr - url);
+ url = at_ptr;
+ }
+
+
+ /*
+ * Copy the host part excluding any port part, no %-escapes allowed
+ */
+ if (!url_len || strchr(":/?#", *url)) {
+ /* Missing host invalid for all URL schemes except file */
+ if (strncmp(norm.buf, "file:", 5)) {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("missing host and scheme is not 'file:'");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ } else {
+ host_off = norm.len;
+ }
+ colon_ptr = slash_ptr - 1;
+ while (colon_ptr > url && *colon_ptr != ':' && *colon_ptr != ']')
+ colon_ptr--;
+ if (*colon_ptr != ':') {
+ colon_ptr = slash_ptr;
+ } else if (!host_off && colon_ptr < slash_ptr && colon_ptr + 1 != slash_ptr) {
+ /* file: URLs may not have a port number */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("a 'file:' URL may not have a port number");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ spanned = strspn(url, URL_HOST_CHARS);
+ if (spanned < colon_ptr - url) {
+ /* Host name has invalid characters */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid characters in host name");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ while (url < colon_ptr) {
+ strbuf_addch(&norm, tolower(*url++));
+ url_len--;
+ }
+
+
+ /*
+ * Check the port part and copy if not the default (after removing any
+ * leading 0s); no %-escapes allowed
+ */
+ if (colon_ptr < slash_ptr) {
+ /* skip the ':' and leading 0s but not the last one if all 0s */
+ url++;
+ url += strspn(url, "0");
+ if (url == slash_ptr && url[-1] == '0')
+ url--;
+ if (url == slash_ptr) {
+ /* Skip ":" port with no number, it's same as default */
+ } else if (slash_ptr - url == 2 &&
+ !strncmp(norm.buf, "http:", 5) &&
+ !strncmp(url, "80", 2)) {
+ /* Skip http :80 as it's the default */
+ } else if (slash_ptr - url == 3 &&
+ !strncmp(norm.buf, "https:", 6) &&
+ !strncmp(url, "443", 3)) {
+ /* Skip https :443 as it's the default */
+ } else {
+ /*
+ * Port number must be all digits with leading 0s removed
+ * and since all the protocols we deal with have a 16-bit
+ * port number it must also be in the range 1..65535
+ * 0 is not allowed because that means "next available"
+ * on just about every system and therefore cannot be used
+ */
+ unsigned long pnum = 0;
+ spanned = strspn(url, URL_DIGIT);
+ if (spanned < slash_ptr - url) {
+ /* port number has invalid characters */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid port number");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ if (slash_ptr - url <= 5)
+ pnum = strtoul(url, NULL, 10);
+ if (pnum == 0 || pnum > 65535) {
+ /* port number not in range 1..65535 */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid port number");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ strbuf_addch(&norm, ':');
+ strbuf_add(&norm, url, slash_ptr - url);
+ port_len = slash_ptr - url;
+ }
+ url_len -= slash_ptr - colon_ptr;
+ url = slash_ptr;
+ }
+ if (host_off)
+ host_len = norm.len - host_off;
+
+
+ /*
+ * Now copy the path resolving any . and .. segments being careful not
+ * to corrupt the URL by unescaping any delimiters, but do add an
+ * initial '/' if it's missing and do normalize any %-escape sequences.
+ */
+ path_off = norm.len;
+ path_start = norm.buf + path_off;
+ strbuf_addch(&norm, '/');
+ if (*url == '/') {
+ url++;
+ url_len--;
+ }
+ for (;;) {
+ const char *seg_start = norm.buf + norm.len;
+ const char *next_slash = url + strcspn(url, "/?#");
+ int skip_add_slash = 0;
+ /*
+ * RFC 3689 indicates that any . or .. segments should be
+ * unescaped before being checked for.
+ */
+ if (!append_normalized_escapes(&norm, url, next_slash - url, "",
+ URL_RESERVED)) {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid %XX escape sequence");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ if (!strcmp(seg_start, ".")) {
+ /* ignore a . segment; be careful not to remove initial '/' */
+ if (seg_start == path_start + 1) {
+ strbuf_setlen(&norm, norm.len - 1);
+ skip_add_slash = 1;
+ } else {
+ strbuf_setlen(&norm, norm.len - 2);
+ }
+ } else if (!strcmp(seg_start, "..")) {
+ /*
+ * ignore a .. segment and remove the previous segment;
+ * be careful not to remove initial '/' from path
+ */
+ const char *prev_slash = norm.buf + norm.len - 3;
+ if (prev_slash == path_start) {
+ /* invalid .. because no previous segment to remove */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid '..' path segment");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ while (*--prev_slash != '/') {}
+ if (prev_slash == path_start) {
+ strbuf_setlen(&norm, prev_slash - norm.buf + 1);
+ skip_add_slash = 1;
+ } else {
+ strbuf_setlen(&norm, prev_slash - norm.buf);
+ }
+ }
+ url_len -= next_slash - url;
+ url = next_slash;
+ /* if the next char is not '/' done with the path */
+ if (*url != '/')
+ break;
+ url++;
+ url_len--;
+ if (!skip_add_slash)
+ strbuf_addch(&norm, '/');
+ }
+ path_len = norm.len - path_off;
+
+
+ /*
+ * Now simply copy the rest, if any, only normalizing %-escapes and
+ * being careful not to corrupt the URL by unescaping any delimiters.
+ */
+ if (*url) {
+ if (!append_normalized_escapes(&norm, url, url_len, "", URL_RESERVED)) {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid %XX escape sequence");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ }
+
+
+ result = strbuf_detach(&norm, &result_len);
+ if (out_info) {
+ out_info->url = result;
+ out_info->err = NULL;
+ out_info->url_len = result_len;
+ out_info->scheme_len = scheme_len;
+ out_info->user_off = user_off;
+ out_info->user_len = user_len;
+ out_info->passwd_off = passwd_off;
+ out_info->passwd_len = passwd_len;
+ out_info->host_off = host_off;
+ out_info->host_len = host_len;
+ out_info->port_len = port_len;
+ out_info->path_off = path_off;
+ out_info->path_len = path_len;
+ }
+ return result;
+}
+
+static size_t url_match_prefix(const char *url,
+ const char *url_prefix,
+ size_t url_prefix_len)
+{
+ /*
+ * url_prefix matches url if url_prefix is an exact match for url or it
+ * is a prefix of url and the match ends on a path component boundary.
+ * Both url and url_prefix are considered to have an implicit '/' on the
+ * end for matching purposes if they do not already.
+ *
+ * url must be NUL terminated. url_prefix_len is the length of
+ * url_prefix which need not be NUL terminated.
+ *
+ * The return value is the length of the match in characters (including
+ * the final '/' even if it's implicit) or 0 for no match.
+ *
+ * Passing NULL as url and/or url_prefix will always cause 0 to be
+ * returned without causing any faults.
+ */
+ if (!url || !url_prefix)
+ return 0;
+ if (!url_prefix_len || (url_prefix_len == 1 && *url_prefix == '/'))
+ return (!*url || *url == '/') ? 1 : 0;
+ if (url_prefix[url_prefix_len - 1] == '/')
+ url_prefix_len--;
+ if (strncmp(url, url_prefix, url_prefix_len))
+ return 0;
+ if ((strlen(url) == url_prefix_len) || (url[url_prefix_len] == '/'))
+ return url_prefix_len + 1;
+ return 0;
+}
+
+int match_urls(const struct url_info *url,
+ const struct url_info *url_prefix,
+ int *exactusermatch)
+{
+ /*
+ * url_prefix matches url if the scheme, host and port of url_prefix
+ * are the same as those of url and the path portion of url_prefix
+ * is the same as the path portion of url or it is a prefix that
+ * matches at a '/' boundary. If url_prefix contains a user name,
+ * that must also exactly match the user name in url.
+ *
+ * If the user, host, port and path match in this fashion, the returned
+ * value is the length of the path match including any implicit
+ * final '/'. For example, "http://me@example.com/path" is matched by
+ * "http://example.com" with a path length of 1.
+ *
+ * If there is a match and exactusermatch is not NULL, then
+ * *exactusermatch will be set to true if both url and url_prefix
+ * contained a user name or false if url_prefix did not have a
+ * user name. If there is no match *exactusermatch is left untouched.
+ */
+ int usermatched = 0;
+ int pathmatchlen;
+
+ if (!url || !url_prefix || !url->url || !url_prefix->url)
+ return 0;
+
+ /* check the scheme */
+ if (url_prefix->scheme_len != url->scheme_len ||
+ strncmp(url->url, url_prefix->url, url->scheme_len))
+ return 0; /* schemes do not match */
+
+ /* check the user name if url_prefix has one */
+ if (url_prefix->user_off) {
+ if (!url->user_off || url->user_len != url_prefix->user_len ||
+ strncmp(url->url + url->user_off,
+ url_prefix->url + url_prefix->user_off,
+ url->user_len))
+ return 0; /* url_prefix has a user but it's not a match */
+ usermatched = 1;
+ }
+
+ /* check the host and port */
+ if (url_prefix->host_len != url->host_len ||
+ strncmp(url->url + url->host_off,
+ url_prefix->url + url_prefix->host_off, url->host_len))
+ return 0; /* host names and/or ports do not match */
+
+ /* check the path */
+ pathmatchlen = url_match_prefix(
+ url->url + url->path_off,
+ url_prefix->url + url_prefix->path_off,
+ url_prefix->url_len - url_prefix->path_off);
+
+ if (pathmatchlen && exactusermatch)
+ *exactusermatch = usermatched;
+ return pathmatchlen;
+}
+
+int urlmatch_config_entry(const char *var, const char *value, void *cb)
+{
+ struct string_list_item *item;
+ struct urlmatch_config *collect = cb;
+ struct urlmatch_item *matched;
+ struct url_info *url = &collect->url;
+ const char *key, *dot;
+ struct strbuf synthkey = STRBUF_INIT;
+ size_t matched_len = 0;
+ int user_matched = 0;
+ int retval;
+
+ key = skip_prefix(var, collect->section);
+ if (!key || *(key++) != '.') {
+ if (collect->cascade_fn)
+ return collect->cascade_fn(var, value, cb);
+ return 0; /* not interested */
+ }
+ dot = strrchr(key, '.');
+ if (dot) {
+ char *config_url, *norm_url;
+ struct url_info norm_info;
+
+ config_url = xmemdupz(key, dot - key);
+ norm_url = url_normalize(config_url, &norm_info);
+ free(config_url);
+ if (!norm_url)
+ return 0;
+ matched_len = match_urls(url, &norm_info, &user_matched);
+ free(norm_url);
+ if (!matched_len)
+ return 0;
+ key = dot + 1;
+ }
+
+ if (collect->key && strcmp(key, collect->key))
+ return 0;
+
+ item = string_list_insert(&collect->vars, key);
+ if (!item->util) {
+ matched = xcalloc(1, sizeof(*matched));
+ item->util = matched;
+ } else {
+ matched = item->util;
+ /*
+ * Is our match shorter? Is our match the same
+ * length, and without user while the current
+ * candidate is with user? Then we cannot use it.
+ */
+ if (matched_len < matched->matched_len ||
+ ((matched_len == matched->matched_len) &&
+ (!user_matched && matched->user_matched)))
+ return 0;
+ /* Otherwise, replace it with this one. */
+ }
+
+ matched->matched_len = matched_len;
+ matched->user_matched = user_matched;
+ strbuf_addstr(&synthkey, collect->section);
+ strbuf_addch(&synthkey, '.');
+ strbuf_addstr(&synthkey, key);
+ retval = collect->collect_fn(synthkey.buf, value, collect->cb);
+
+ strbuf_release(&synthkey);
+ return retval;
+}
diff --git a/urlmatch.h b/urlmatch.h
new file mode 100644
index 0000000..b461dfd
--- /dev/null
+++ b/urlmatch.h
@@ -0,0 +1,54 @@
+#ifndef URL_MATCH_H
+#include "string-list.h"
+
+struct url_info {
+ /* normalized url on success, must be freed, otherwise NULL */
+ char *url;
+ /* if !url, a brief reason for the failure, otherwise NULL */
+ const char *err;
+
+ /* the rest of the fields are only set if url != NULL */
+
+ size_t url_len; /* total length of url (which is now normalized) */
+ size_t scheme_len; /* length of scheme name (excluding final :) */
+ size_t user_off; /* offset into url to start of user name (0 => none) */
+ size_t user_len; /* length of user name; if user_off != 0 but
+ user_len == 0, an empty user name was given */
+ size_t passwd_off; /* offset into url to start of passwd (0 => none) */
+ size_t passwd_len; /* length of passwd; if passwd_off != 0 but
+ passwd_len == 0, an empty passwd was given */
+ size_t host_off; /* offset into url to start of host name (0 => none) */
+ size_t host_len; /* length of host name; this INCLUDES any ':portnum';
+ * file urls may have host_len == 0 */
+ size_t port_len; /* if a portnum is present (port_len != 0), it has
+ * this length (excluding the leading ':') at the
+ * end of the host name (always 0 for file urls) */
+ size_t path_off; /* offset into url to the start of the url path;
+ * this will always point to a '/' character
+ * after the url has been normalized */
+ size_t path_len; /* length of path portion excluding any trailing
+ * '?...' and '#...' portion; will always be >= 1 */
+};
+
+extern char *url_normalize(const char *, struct url_info *);
+extern int match_urls(const struct url_info *url, const struct url_info *url_prefix, int *exactusermatch);
+
+struct urlmatch_item {
+ size_t matched_len;
+ char user_matched;
+};
+
+struct urlmatch_config {
+ struct string_list vars;
+ struct url_info url;
+ const char *section;
+ const char *key;
+
+ void *cb;
+ int (*collect_fn)(const char *var, const char *value, void *cb);
+ int (*cascade_fn)(const char *var, const char *value, void *cb);
+};
+
+extern int urlmatch_config_entry(const char *var, const char *value, void *cb);
+
+#endif /* URL_MATCH_H */
diff --git a/utf8.c b/utf8.c
index 7f64857..0d20e0a 100644
--- a/utf8.c
+++ b/utf8.c
@@ -9,6 +9,20 @@ struct interval {
int last;
};
+size_t display_mode_esc_sequence_len(const char *s)
+{
+ const char *p = s;
+ if (*p++ != '\033')
+ return 0;
+ if (*p++ != '[')
+ return 0;
+ while (isdigit(*p) || *p == ';')
+ p++;
+ if (*p++ != 'm')
+ return 0;
+ return p - s;
+}
+
/* auxiliary function for binary search in interval table */
static int bisearch(ucs_char_t ucs, const struct interval *table, int max)
{
@@ -252,18 +266,26 @@ int utf8_width(const char **start, size_t *remainder_p)
* string, assuming that the string is utf8. Returns strlen() instead
* if the string does not look like a valid utf8 string.
*/
-int utf8_strwidth(const char *string)
+int utf8_strnwidth(const char *string, int len, int skip_ansi)
{
int width = 0;
const char *orig = string;
- while (1) {
- if (!string)
- return strlen(orig);
- if (!*string)
- return width;
+ if (len == -1)
+ len = strlen(string);
+ while (string && string < orig + len) {
+ int skip;
+ while (skip_ansi &&
+ (skip = display_mode_esc_sequence_len(string)) != 0)
+ string += skip;
width += utf8_width(&string, NULL);
}
+ return string ? width : len;
+}
+
+int utf8_strwidth(const char *string)
+{
+ return utf8_strnwidth(string, -1, 0);
}
int is_utf8(const char *text)
@@ -303,20 +325,6 @@ static void strbuf_add_indented_text(struct strbuf *buf, const char *text,
}
}
-static size_t display_mode_esc_sequence_len(const char *s)
-{
- const char *p = s;
- if (*p++ != '\033')
- return 0;
- if (*p++ != '[')
- return 0;
- while (isdigit(*p) || *p == ';')
- p++;
- if (*p++ != 'm')
- return 0;
- return p - s;
-}
-
/*
* Wrap the text, if necessary. The variable indent is the indent for the
* first line, indent2 is the indent for all other lines.
@@ -413,6 +421,52 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
free(tmp);
}
+void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
+ const char *subst)
+{
+ struct strbuf sb_dst = STRBUF_INIT;
+ char *src = sb_src->buf;
+ char *end = src + sb_src->len;
+ char *dst;
+ int w = 0, subst_len = 0;
+
+ if (subst)
+ subst_len = strlen(subst);
+ strbuf_grow(&sb_dst, sb_src->len + subst_len);
+ dst = sb_dst.buf;
+
+ while (src < end) {
+ char *old;
+ size_t n;
+
+ while ((n = display_mode_esc_sequence_len(src))) {
+ memcpy(dst, src, n);
+ src += n;
+ dst += n;
+ }
+
+ old = src;
+ n = utf8_width((const char**)&src, NULL);
+ if (!src) /* broken utf-8, do nothing */
+ return;
+ if (n && w >= pos && w < pos + width) {
+ if (subst) {
+ memcpy(dst, subst, subst_len);
+ dst += subst_len;
+ subst = NULL;
+ }
+ w += n;
+ continue;
+ }
+ memcpy(dst, old, src - old);
+ dst += src - old;
+ w += n;
+ }
+ strbuf_setlen(&sb_dst, dst - sb_dst.buf);
+ strbuf_swap(sb_src, &sb_dst);
+ strbuf_release(&sb_dst);
+}
+
int is_encoding_utf8(const char *name)
{
if (!name)
@@ -460,7 +514,7 @@ int utf8_fprintf(FILE *stream, const char *format, ...)
#else
typedef char * iconv_ibp;
#endif
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv, int *outsz_p)
{
size_t outsz, outalloc;
char *out, *outpos;
@@ -494,13 +548,17 @@ char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
}
else {
*outpos = '\0';
+ if (outsz_p)
+ *outsz_p = outpos - out;
break;
}
}
return out;
}
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+char *reencode_string_len(const char *in, int insz,
+ const char *out_encoding, const char *in_encoding,
+ int *outsz)
{
iconv_t conv;
char *out;
@@ -526,7 +584,7 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
return NULL;
}
- out = reencode_string_iconv(in, strlen(in), conv);
+ out = reencode_string_iconv(in, insz, conv, outsz);
iconv_close(conv);
return out;
}
diff --git a/utf8.h b/utf8.h
index 1f8ecad..65d0e42 100644
--- a/utf8.h
+++ b/utf8.h
@@ -3,25 +3,43 @@
typedef unsigned int ucs_char_t; /* assuming 32bit int */
+size_t display_mode_esc_sequence_len(const char *s);
int utf8_width(const char **start, size_t *remainder_p);
+int utf8_strnwidth(const char *string, int len, int skip_ansi);
int utf8_strwidth(const char *string);
int is_utf8(const char *text);
int is_encoding_utf8(const char *name);
int same_encoding(const char *, const char *);
+__attribute__((format (printf, 2, 3)))
int utf8_fprintf(FILE *, const char *, ...);
void strbuf_add_wrapped_text(struct strbuf *buf,
const char *text, int indent, int indent2, int width);
void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
int indent, int indent2, int width);
+void strbuf_utf8_replace(struct strbuf *sb, int pos, int width,
+ const char *subst);
#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);
+char *reencode_string_iconv(const char *in, size_t insz,
+ iconv_t conv, int *outsz);
+char *reencode_string_len(const char *in, int insz,
+ const char *out_encoding,
+ const char *in_encoding,
+ int *outsz);
#else
-#define reencode_string(a,b,c) NULL
+#define reencode_string_len(a,b,c,d,e) NULL
#endif
+static inline char *reencode_string(const char *in,
+ const char *out_encoding,
+ const char *in_encoding)
+{
+ return reencode_string_len(in, strlen(in),
+ out_encoding, in_encoding,
+ NULL);
+}
+
int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
#endif
diff --git a/wildmatch.c b/wildmatch.c
index 7192bdc..f91ba99 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -196,6 +196,11 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
}
if (t_ch <= p_ch && t_ch >= prev_ch)
matched = 1;
+ else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch)) {
+ uchar t_ch_upper = toupper(t_ch);
+ if (t_ch_upper <= p_ch && t_ch_upper >= prev_ch)
+ matched = 1;
+ }
p_ch = 0; /* This makes "prev_ch" get set to 0. */
} else if (p_ch == '[' && p[1] == ':') {
const uchar *s;
@@ -245,6 +250,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
} else if (CC_EQ(s,i, "upper")) {
if (ISUPPER(t_ch))
matched = 1;
+ else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch))
+ matched = 1;
} else if (CC_EQ(s,i, "xdigit")) {
if (ISXDIGIT(t_ch))
matched = 1;
diff --git a/wrap-for-bin.sh b/wrap-for-bin.sh
index 53a8dd0..701d233 100644
--- a/wrap-for-bin.sh
+++ b/wrap-for-bin.sh
@@ -14,7 +14,7 @@ else
GIT_TEMPLATE_DIR='@@BUILD_DIR@@/templates/blt'
export GIT_TEMPLATE_DIR
fi
-GITPERLLIB='@@BUILD_DIR@@/perl/blib/lib'
+GITPERLLIB='@@BUILD_DIR@@/perl/blib/lib'"${GITPERLLIB:+:$GITPERLLIB}"
GIT_TEXTDOMAINDIR='@@BUILD_DIR@@/po/build/locale'
PATH='@@BUILD_DIR@@/bin-wrappers:'"$PATH"
export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR
diff --git a/wrapper.c b/wrapper.c
index bac59d2..f92b147 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -131,6 +131,14 @@ void *xcalloc(size_t nmemb, size_t size)
}
/*
+ * Limit size of IO chunks, because huge chunks only cause pain. OS X
+ * 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in
+ * the absense of bugs, large chunks can result in bad latencies when
+ * you decide to kill the process.
+ */
+#define MAX_IO_SIZE (8*1024*1024)
+
+/*
* xread() is the same a read(), but it automatically restarts read()
* operations with a recoverable error (EAGAIN and EINTR). xread()
* DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
@@ -138,6 +146,8 @@ void *xcalloc(size_t nmemb, size_t size)
ssize_t xread(int fd, void *buf, size_t len)
{
ssize_t nr;
+ if (len > MAX_IO_SIZE)
+ len = MAX_IO_SIZE;
while (1) {
nr = read(fd, buf, len);
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
@@ -154,6 +164,8 @@ ssize_t xread(int fd, void *buf, size_t len)
ssize_t xwrite(int fd, const void *buf, size_t len)
{
ssize_t nr;
+ if (len > MAX_IO_SIZE)
+ len = MAX_IO_SIZE;
while (1) {
nr = write(fd, buf, len);
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
@@ -322,7 +334,7 @@ int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
template[5] = letters[v % num_letters]; v /= num_letters;
fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
- if (fd > 0)
+ if (fd >= 0)
return fd;
/*
* Fatal error (EPERM, ENOSPC etc).
@@ -408,18 +420,24 @@ 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)
+static int access_error_is_ok(int err, unsigned flag)
+{
+ return err == ENOENT || err == ENOTDIR ||
+ ((flag & ACCESS_EACCES_OK) && err == EACCES);
+}
+
+int access_or_warn(const char *path, int mode, unsigned flag)
{
int ret = access(path, mode);
- if (ret && errno != ENOENT && errno != ENOTDIR)
+ if (ret && !access_error_is_ok(errno, flag))
warn_on_inaccessible(path);
return ret;
}
-int access_or_die(const char *path, int mode)
+int access_or_die(const char *path, int mode, unsigned flag)
{
int ret = access(path, mode);
- if (ret && errno != ENOENT && errno != ENOTDIR)
+ if (ret && !access_error_is_ok(errno, flag))
die_errno(_("unable to access '%s'"), path);
return ret;
}
diff --git a/write_or_die.c b/write_or_die.c
index 960f448..b50f99a 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -1,5 +1,15 @@
#include "cache.h"
+static void check_pipe(int err)
+{
+ if (err == EPIPE) {
+ signal(SIGPIPE, SIG_DFL);
+ raise(SIGPIPE);
+ /* Should never happen, but just in case... */
+ exit(141);
+ }
+}
+
/*
* Some cases use stdio, but want to flush after the write
* to get error handling (and to get better interactive
@@ -34,8 +44,7 @@ void maybe_flush_or_die(FILE *f, const char *desc)
return;
}
if (fflush(f)) {
- if (errno == EPIPE)
- exit(0);
+ check_pipe(errno);
die_errno("write failure on '%s'", desc);
}
}
@@ -50,8 +59,7 @@ void fsync_or_die(int fd, const char *msg)
void write_or_die(int fd, const void *buf, size_t count)
{
if (write_in_full(fd, buf, count) < 0) {
- if (errno == EPIPE)
- exit(0);
+ check_pipe(errno);
die_errno("write error");
}
}
@@ -59,8 +67,7 @@ void write_or_die(int fd, const void *buf, size_t count)
int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)
{
if (write_in_full(fd, buf, count) < 0) {
- if (errno == EPIPE)
- exit(0);
+ check_pipe(errno);
fprintf(stderr, "%s: write error (%s)\n",
msg, strerror(errno));
return 0;
diff --git a/wt-status.c b/wt-status.c
index 81e4fa5..ff4b324 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "pathspec.h"
#include "wt-status.h"
#include "object.h"
#include "dir.h"
@@ -127,6 +128,7 @@ void wt_status_prepare(struct wt_status *s)
s->change.strdup_strings = 1;
s->untracked.strdup_strings = 1;
s->ignored.strdup_strings = 1;
+ s->show_branch = -1; /* unspecified */
}
static void wt_status_print_unmerged_header(struct wt_status *s)
@@ -243,7 +245,7 @@ static void wt_status_print_unmerged_data(struct wt_status *s,
struct strbuf onebuf = STRBUF_INIT;
const char *one, *how = _("bug");
- one = quote_path(it->string, -1, &onebuf, s->prefix);
+ one = quote_path(it->string, s->prefix, &onebuf);
status_printf(s, color(WT_STATUS_HEADER, s), "\t");
switch (d->stagemask) {
case 1: how = _("both deleted:"); break;
@@ -297,8 +299,8 @@ static void wt_status_print_change_data(struct wt_status *s,
change_type);
}
- one = quote_path(one_name, -1, &onebuf, s->prefix);
- two = quote_path(two_name, -1, &twobuf, s->prefix);
+ one = quote_path(one_name, s->prefix, &onebuf);
+ two = quote_path(two_name, s->prefix, &twobuf);
status_printf(s, color(WT_STATUS_HEADER, s), "\t");
switch (status) {
@@ -371,7 +373,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
static int unmerged_mask(const char *path)
{
int pos, mask;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
pos = cache_name_pos(path, strlen(path));
if (0 <= pos)
@@ -437,7 +439,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
}
rev.diffopt.format_callback = wt_status_collect_changed_cb;
rev.diffopt.format_callback_data = s;
- init_pathspec(&rev.prune_data, s->pathspec);
+ copy_pathspec(&rev.prune_data, &s->pathspec);
run_diff_files(&rev, 0);
}
@@ -462,22 +464,20 @@ static void wt_status_collect_changes_index(struct wt_status *s)
rev.diffopt.detect_rename = 1;
rev.diffopt.rename_limit = 200;
rev.diffopt.break_opt = 0;
- init_pathspec(&rev.prune_data, s->pathspec);
+ copy_pathspec(&rev.prune_data, &s->pathspec);
run_diff_index(&rev, 1);
}
static void wt_status_collect_changes_initial(struct wt_status *s)
{
- struct pathspec pathspec;
int i;
- init_pathspec(&pathspec, s->pathspec);
for (i = 0; i < active_nr; i++) {
struct string_list_item *it;
struct wt_status_change_data *d;
- struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = active_cache[i];
- if (!ce_path_match(ce, &pathspec))
+ if (!ce_path_match(ce, &s->pathspec))
continue;
it = string_list_insert(&s->change, ce->name);
d = it->util;
@@ -492,7 +492,6 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
else
d->index_status = DIFF_STATUS_ADDED;
}
- free_pathspec(&pathspec);
}
static void wt_status_collect_untracked(struct wt_status *s)
@@ -511,33 +510,31 @@ static void wt_status_collect_untracked(struct wt_status *s)
if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
dir.flags |=
DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
+ if (s->show_ignored_files)
+ dir.flags |= DIR_SHOW_IGNORED_TOO;
setup_standard_excludes(&dir);
- fill_directory(&dir, s->pathspec);
+ fill_directory(&dir, &s->pathspec);
+
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
if (cache_name_is_other(ent->name, ent->len) &&
- match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
+ match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
string_list_insert(&s->untracked, ent->name);
free(ent);
}
- if (s->show_ignored_files) {
- dir.nr = 0;
- dir.flags = DIR_SHOW_IGNORED;
- if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
- dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
- fill_directory(&dir, s->pathspec);
- for (i = 0; i < dir.nr; i++) {
- struct dir_entry *ent = dir.entries[i];
- if (cache_name_is_other(ent->name, ent->len) &&
- match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
- string_list_insert(&s->ignored, ent->name);
- free(ent);
- }
+ for (i = 0; i < dir.ignored_nr; i++) {
+ struct dir_entry *ent = dir.ignored[i];
+ if (cache_name_is_other(ent->name, ent->len) &&
+ match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
+ string_list_insert(&s->ignored, ent->name);
+ free(ent);
}
free(dir.entries);
+ free(dir.ignored);
+ clear_directory(&dir);
if (advice_status_u_option) {
struct timeval t_end;
@@ -708,8 +705,7 @@ static void wt_status_print_other(struct wt_status *s,
struct string_list_item *it;
const char *path;
it = &(l->items[i]);
- path = quote_path(it->string, strlen(it->string),
- &buf, s->prefix);
+ path = quote_path(it->string, s->prefix, &buf);
if (column_active(s->colopts)) {
string_list_append(&output, path);
continue;
@@ -828,7 +824,7 @@ static void show_am_in_progress(struct wt_status *s,
if (advice_status_hints) {
if (!state->am_empty_patch)
status_printf_ln(s, color,
- _(" (fix conflicts and then run \"git am --resolved\")"));
+ _(" (fix conflicts and then run \"git am --continue\")"));
status_printf_ln(s, color,
_(" (use \"git am --skip\" to skip this patch)"));
status_printf_ln(s, color,
@@ -957,10 +953,31 @@ static void show_cherry_pick_in_progress(struct wt_status *s,
if (advice_status_hints) {
if (has_unmerged(s))
status_printf_ln(s, color,
- _(" (fix conflicts and run \"git commit\")"));
+ _(" (fix conflicts and run \"git cherry-pick --continue\")"));
+ else
+ status_printf_ln(s, color,
+ _(" (all conflicts fixed: run \"git cherry-pick --continue\")"));
+ status_printf_ln(s, color,
+ _(" (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"));
+ }
+ wt_status_print_trailer(s);
+}
+
+static void show_revert_in_progress(struct wt_status *s,
+ struct wt_status_state *state,
+ const char *color)
+{
+ status_printf_ln(s, color, _("You are currently reverting commit %s."),
+ find_unique_abbrev(state->revert_head_sha1, DEFAULT_ABBREV));
+ if (advice_status_hints) {
+ if (has_unmerged(s))
+ status_printf_ln(s, color,
+ _(" (fix conflicts and run \"git revert --continue\")"));
else
status_printf_ln(s, color,
- _(" (all conflicts fixed: run \"git commit\")"));
+ _(" (all conflicts fixed: run \"git revert --continue\")"));
+ status_printf_ln(s, color,
+ _(" (use \"git revert --abort\" to cancel the revert operation)"));
}
wt_status_print_trailer(s);
}
@@ -971,7 +988,7 @@ static void show_bisect_in_progress(struct wt_status *s,
{
if (state->branch)
status_printf_ln(s, color,
- _("You are currently bisecting branch '%s'."),
+ _("You are currently bisecting, started from branch '%s'."),
state->branch);
else
status_printf_ln(s, color,
@@ -985,96 +1002,170 @@ static void show_bisect_in_progress(struct wt_status *s,
/*
* Extract branch information from rebase/bisect
*/
-static void read_and_strip_branch(struct strbuf *sb,
- const char **branch,
- const char *path)
+static char *read_and_strip_branch(const char *path)
{
+ struct strbuf sb = STRBUF_INIT;
unsigned char sha1[20];
- strbuf_reset(sb);
- if (strbuf_read_file(sb, git_path("%s", path), 0) <= 0)
- return;
+ if (strbuf_read_file(&sb, git_path("%s", path), 0) <= 0)
+ goto got_nothing;
- while (sb->len && sb->buf[sb->len - 1] == '\n')
- strbuf_setlen(sb, sb->len - 1);
- if (!sb->len)
- return;
- if (!prefixcmp(sb->buf, "refs/heads/"))
- *branch = sb->buf + strlen("refs/heads/");
- else if (!prefixcmp(sb->buf, "refs/"))
- *branch = sb->buf;
- else if (!get_sha1_hex(sb->buf, sha1)) {
+ while (&sb.len && sb.buf[sb.len - 1] == '\n')
+ strbuf_setlen(&sb, sb.len - 1);
+ if (!sb.len)
+ goto got_nothing;
+ if (!prefixcmp(sb.buf, "refs/heads/"))
+ strbuf_remove(&sb,0, strlen("refs/heads/"));
+ else if (!prefixcmp(sb.buf, "refs/"))
+ ;
+ else if (!get_sha1_hex(sb.buf, sha1)) {
const char *abbrev;
abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
- strbuf_reset(sb);
- strbuf_addstr(sb, abbrev);
- *branch = sb->buf;
- } else if (!strcmp(sb->buf, "detached HEAD")) /* rebase */
- ;
+ strbuf_reset(&sb);
+ strbuf_addstr(&sb, abbrev);
+ } else if (!strcmp(sb.buf, "detached HEAD")) /* rebase */
+ goto got_nothing;
else /* bisect */
- *branch = sb->buf;
+ ;
+ return strbuf_detach(&sb, NULL);
+
+got_nothing:
+ strbuf_release(&sb);
+ return NULL;
}
-static void wt_status_print_state(struct wt_status *s)
+struct grab_1st_switch_cbdata {
+ struct strbuf buf;
+ unsigned char nsha1[20];
+};
+
+static int grab_1st_switch(unsigned char *osha1, unsigned char *nsha1,
+ const char *email, unsigned long timestamp, int tz,
+ const char *message, void *cb_data)
{
- const char *state_color = color(WT_STATUS_HEADER, s);
- struct strbuf branch = STRBUF_INIT;
- struct strbuf onto = STRBUF_INIT;
- struct wt_status_state state;
- struct stat st;
+ struct grab_1st_switch_cbdata *cb = cb_data;
+ const char *target = NULL, *end;
- memset(&state, 0, sizeof(state));
+ if (prefixcmp(message, "checkout: moving from "))
+ return 0;
+ message += strlen("checkout: moving from ");
+ target = strstr(message, " to ");
+ if (!target)
+ return 0;
+ target += strlen(" to ");
+ strbuf_reset(&cb->buf);
+ hashcpy(cb->nsha1, nsha1);
+ for (end = target; *end && *end != '\n'; end++)
+ ;
+ strbuf_add(&cb->buf, target, end - target);
+ return 1;
+}
+
+static void wt_status_get_detached_from(struct wt_status_state *state)
+{
+ struct grab_1st_switch_cbdata cb;
+ struct commit *commit;
+ unsigned char sha1[20];
+ char *ref = NULL;
+
+ strbuf_init(&cb.buf, 0);
+ if (for_each_reflog_ent_reverse("HEAD", grab_1st_switch, &cb) <= 0) {
+ strbuf_release(&cb.buf);
+ return;
+ }
+
+ if (dwim_ref(cb.buf.buf, cb.buf.len, sha1, &ref) == 1 &&
+ /* sha1 is a commit? match without further lookup */
+ (!hashcmp(cb.nsha1, sha1) ||
+ /* perhaps sha1 is a tag, try to dereference to a commit */
+ ((commit = lookup_commit_reference_gently(sha1, 1)) != NULL &&
+ !hashcmp(cb.nsha1, commit->object.sha1)))) {
+ int ofs;
+ if (!prefixcmp(ref, "refs/tags/"))
+ ofs = strlen("refs/tags/");
+ else if (!prefixcmp(ref, "refs/remotes/"))
+ ofs = strlen("refs/remotes/");
+ else
+ ofs = 0;
+ state->detached_from = xstrdup(ref + ofs);
+ } else
+ state->detached_from =
+ xstrdup(find_unique_abbrev(cb.nsha1, DEFAULT_ABBREV));
+ hashcpy(state->detached_sha1, cb.nsha1);
+
+ free(ref);
+ strbuf_release(&cb.buf);
+}
+
+void wt_status_get_state(struct wt_status_state *state,
+ int get_detached_from)
+{
+ struct stat st;
+ unsigned char sha1[20];
if (!stat(git_path("MERGE_HEAD"), &st)) {
- state.merge_in_progress = 1;
+ 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;
+ state->am_in_progress = 1;
if (!stat(git_path("rebase-apply/patch"), &st) && !st.st_size)
- state.am_empty_patch = 1;
+ state->am_empty_patch = 1;
} else {
- state.rebase_in_progress = 1;
- read_and_strip_branch(&branch, &state.branch,
- "rebase-apply/head-name");
- read_and_strip_branch(&onto, &state.onto,
- "rebase-apply/onto");
+ state->rebase_in_progress = 1;
+ state->branch = read_and_strip_branch("rebase-apply/head-name");
+ state->onto = read_and_strip_branch("rebase-apply/onto");
}
} else if (!stat(git_path("rebase-merge"), &st)) {
if (!stat(git_path("rebase-merge/interactive"), &st))
- state.rebase_interactive_in_progress = 1;
+ state->rebase_interactive_in_progress = 1;
else
- state.rebase_in_progress = 1;
- read_and_strip_branch(&branch, &state.branch,
- "rebase-merge/head-name");
- read_and_strip_branch(&onto, &state.onto,
- "rebase-merge/onto");
+ state->rebase_in_progress = 1;
+ state->branch = read_and_strip_branch("rebase-merge/head-name");
+ state->onto = read_and_strip_branch("rebase-merge/onto");
} else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
- state.cherry_pick_in_progress = 1;
+ state->cherry_pick_in_progress = 1;
}
if (!stat(git_path("BISECT_LOG"), &st)) {
- state.bisect_in_progress = 1;
- read_and_strip_branch(&branch, &state.branch,
- "BISECT_START");
+ state->bisect_in_progress = 1;
+ state->branch = read_and_strip_branch("BISECT_START");
+ }
+ if (!stat(git_path("REVERT_HEAD"), &st) &&
+ !get_sha1("REVERT_HEAD", sha1)) {
+ state->revert_in_progress = 1;
+ hashcpy(state->revert_head_sha1, sha1);
}
- 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);
- strbuf_release(&branch);
- strbuf_release(&onto);
+ if (get_detached_from)
+ wt_status_get_detached_from(state);
+}
+
+static void wt_status_print_state(struct wt_status *s,
+ struct wt_status_state *state)
+{
+ const char *state_color = color(WT_STATUS_HEADER, s);
+ 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);
+ else if (state->revert_in_progress)
+ show_revert_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);
const char *branch_status_color = color(WT_STATUS_HEADER, s);
+ struct wt_status_state state;
+
+ memset(&state, 0, sizeof(state));
+ wt_status_get_state(&state,
+ s->branch && !strcmp(s->branch, "HEAD"));
if (s->branch) {
const char *on_what = _("On branch ");
@@ -1082,9 +1173,22 @@ void wt_status_print(struct wt_status *s)
if (!prefixcmp(branch_name, "refs/heads/"))
branch_name += 11;
else if (!strcmp(branch_name, "HEAD")) {
- branch_name = "";
branch_status_color = color(WT_STATUS_NOBRANCH, s);
- on_what = _("Not currently on any branch.");
+ if (state.rebase_in_progress || state.rebase_interactive_in_progress) {
+ on_what = _("rebase in progress; onto ");
+ branch_name = state.onto;
+ } else if (state.detached_from) {
+ unsigned char sha1[20];
+ branch_name = state.detached_from;
+ if (!get_sha1("HEAD", sha1) &&
+ !hashcmp(sha1, state.detached_sha1))
+ on_what = _("HEAD detached at ");
+ else
+ on_what = _("HEAD detached from ");
+ } else {
+ branch_name = "";
+ on_what = _("Not currently on any branch.");
+ }
}
status_printf(s, color(WT_STATUS_HEADER, s), "");
status_printf_more(s, branch_status_color, "%s", on_what);
@@ -1093,7 +1197,11 @@ void wt_status_print(struct wt_status *s)
wt_status_print_tracking(s);
}
- wt_status_print_state(s);
+ wt_status_print_state(s, &state);
+ free(state.branch);
+ free(state.onto);
+ free(state.detached_from);
+
if (s->is_initial) {
status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
status_printf_ln(s, color(WT_STATUS_HEADER, s), _("Initial commit"));
@@ -1182,7 +1290,7 @@ static void wt_shortstatus_unmerged(struct string_list_item *it,
} else {
struct strbuf onebuf = STRBUF_INIT;
const char *one;
- one = quote_path(it->string, -1, &onebuf, s->prefix);
+ one = quote_path(it->string, s->prefix, &onebuf);
printf(" %s\n", one);
strbuf_release(&onebuf);
}
@@ -1210,7 +1318,7 @@ static void wt_shortstatus_status(struct string_list_item *it,
struct strbuf onebuf = STRBUF_INIT;
const char *one;
if (d->head_path) {
- one = quote_path(d->head_path, -1, &onebuf, s->prefix);
+ one = quote_path(d->head_path, s->prefix, &onebuf);
if (*one != '"' && strchr(one, ' ') != NULL) {
putchar('"');
strbuf_addch(&onebuf, '"');
@@ -1219,7 +1327,7 @@ static void wt_shortstatus_status(struct string_list_item *it,
printf("%s -> ", one);
strbuf_release(&onebuf);
}
- one = quote_path(it->string, -1, &onebuf, s->prefix);
+ one = quote_path(it->string, s->prefix, &onebuf);
if (*one != '"' && strchr(one, ' ') != NULL) {
putchar('"');
strbuf_addch(&onebuf, '"');
@@ -1238,7 +1346,7 @@ static void wt_shortstatus_other(struct string_list_item *it,
} else {
struct strbuf onebuf = STRBUF_INIT;
const char *one;
- one = quote_path(it->string, -1, &onebuf, s->prefix);
+ one = quote_path(it->string, s->prefix, &onebuf);
color_fprintf(s->fp, color(WT_STATUS_UNTRACKED, s), "%s", sign);
printf(" %s\n", one);
strbuf_release(&onebuf);
diff --git a/wt-status.h b/wt-status.h
index 74208c0..9966c13 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -44,7 +44,7 @@ struct wt_status {
int is_initial;
char *branch;
const char *reference;
- const char **pathspec;
+ struct pathspec pathspec;
int verbose;
int amend;
enum commit_whence whence;
@@ -80,20 +80,25 @@ struct wt_status_state {
int rebase_interactive_in_progress;
int cherry_pick_in_progress;
int bisect_in_progress;
- const char *branch;
- const char *onto;
+ int revert_in_progress;
+ char *branch;
+ char *onto;
+ char *detached_from;
+ unsigned char detached_sha1[20];
+ unsigned char revert_head_sha1[20];
};
void wt_status_prepare(struct wt_status *s);
void wt_status_print(struct wt_status *s);
void wt_status_collect(struct wt_status *s);
+void wt_status_get_state(struct wt_status_state *state, int get_detached_from);
void wt_shortstatus_print(struct wt_status *s);
void wt_porcelain_print(struct wt_status *s);
-void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, ...)
- ;
-void status_printf(struct wt_status *s, const char *color, const char *fmt, ...)
- ;
+__attribute__((format (printf, 3, 4)))
+void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, ...);
+__attribute__((format (printf, 3, 4)))
+void status_printf(struct wt_status *s, const char *color, const char *fmt, ...);
#endif /* STATUS_H */
diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h
index 219a3bb..c033991 100644
--- a/xdiff/xdiff.h
+++ b/xdiff/xdiff.h
@@ -39,6 +39,8 @@ extern "C" {
#define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF)
#define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK)
+#define XDF_IGNORE_BLANK_LINES (1 << 7)
+
#define XDL_EMIT_FUNCNAMES (1 << 0)
#define XDL_EMIT_COMMON (1 << 1)
#define XDL_EMIT_FUNCCONTEXT (1 << 2)
diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c
index b2eb6db..2358a2d 100644
--- a/xdiff/xdiffi.c
+++ b/xdiff/xdiffi.c
@@ -394,6 +394,7 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1,
xch->i2 = i2;
xch->chg1 = chg1;
xch->chg2 = chg2;
+ xch->ignore = 0;
return xch;
}
@@ -544,7 +545,9 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
xdchange_t *xch, *xche;
for (xch = xscr; xch; xch = xche->next) {
- xche = xdl_get_hunk(xch, xecfg);
+ xche = xdl_get_hunk(&xch, xecfg);
+ if (!xch)
+ break;
if (xecfg->hunk_func(xch->i1, xche->i1 + xche->chg1 - xch->i1,
xch->i2, xche->i2 + xche->chg2 - xch->i2,
ecb->priv) < 0)
@@ -553,6 +556,27 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
return 0;
}
+static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags)
+{
+ xdchange_t *xch;
+
+ for (xch = xscr; xch; xch = xch->next) {
+ int ignore = 1;
+ xrecord_t **rec;
+ long i;
+
+ rec = &xe->xdf1.recs[xch->i1];
+ for (i = 0; i < xch->chg1 && ignore; i++)
+ ignore = xdl_blankline(rec[i]->ptr, rec[i]->size, flags);
+
+ rec = &xe->xdf2.recs[xch->i2];
+ for (i = 0; i < xch->chg2 && ignore; i++)
+ ignore = xdl_blankline(rec[i]->ptr, rec[i]->size, flags);
+
+ xch->ignore = ignore;
+ }
+}
+
int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
xdemitconf_t const *xecfg, xdemitcb_t *ecb) {
xdchange_t *xscr;
@@ -571,6 +595,9 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
return -1;
}
if (xscr) {
+ if (xpp->flags & XDF_IGNORE_BLANK_LINES)
+ xdl_mark_ignorable(xscr, &xe, xpp->flags);
+
if (ef(&xe, xscr, ecb, xecfg) < 0) {
xdl_free_script(xscr);
diff --git a/xdiff/xdiffi.h b/xdiff/xdiffi.h
index 7a92ea9..8b81206 100644
--- a/xdiff/xdiffi.h
+++ b/xdiff/xdiffi.h
@@ -41,6 +41,7 @@ typedef struct s_xdchange {
struct s_xdchange *next;
long i1, i2;
long chg1, chg2;
+ int ignore;
} xdchange_t;
diff --git a/xdiff/xemit.c b/xdiff/xemit.c
index d11dbf9..4d86458 100644
--- a/xdiff/xemit.c
+++ b/xdiff/xemit.c
@@ -56,16 +56,51 @@ static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *
/*
* Starting at the passed change atom, find the latest change atom to be included
* inside the differential hunk according to the specified configuration.
+ * Also advance xscr if the first changes must be discarded.
*/
-xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg) {
- xdchange_t *xch, *xchp;
+xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
+{
+ xdchange_t *xch, *xchp, *lxch;
long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen;
+ long max_ignorable = xecfg->ctxlen;
+ unsigned long ignored = 0; /* number of ignored blank lines */
+
+ /* remove ignorable changes that are too far before other changes */
+ for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) {
+ xch = xchp->next;
+
+ if (xch == NULL ||
+ xch->i1 - (xchp->i1 + xchp->chg1) >= max_ignorable)
+ *xscr = xch;
+ }
+
+ if (*xscr == NULL)
+ return NULL;
+
+ lxch = *xscr;
- for (xchp = xscr, xch = xscr->next; xch; xchp = xch, xch = xch->next)
- if (xch->i1 - (xchp->i1 + xchp->chg1) > max_common)
+ for (xchp = *xscr, xch = xchp->next; xch; xchp = xch, xch = xch->next) {
+ long distance = xch->i1 - (xchp->i1 + xchp->chg1);
+ if (distance > max_common)
break;
- return xchp;
+ if (distance < max_ignorable && (!xch->ignore || lxch == xchp)) {
+ lxch = xch;
+ ignored = 0;
+ } else if (distance < max_ignorable && xch->ignore) {
+ ignored += xch->chg2;
+ } else if (lxch != xchp &&
+ xch->i1 + ignored - (lxch->i1 + lxch->chg1) > max_common) {
+ break;
+ } else if (!xch->ignore) {
+ lxch = xch;
+ ignored = 0;
+ } else {
+ ignored += xch->chg2;
+ }
+ }
+
+ return lxch;
}
@@ -139,7 +174,9 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
return xdl_emit_common(xe, xscr, ecb, xecfg);
for (xch = xscr; xch; xch = xche->next) {
- xche = xdl_get_hunk(xch, xecfg);
+ xche = xdl_get_hunk(&xch, xecfg);
+ if (!xch)
+ break;
s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);
s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
diff --git a/xdiff/xemit.h b/xdiff/xemit.h
index c2e2e83..d297107 100644
--- a/xdiff/xemit.h
+++ b/xdiff/xemit.h
@@ -27,7 +27,7 @@
typedef int (*emit_func_t)(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
xdemitconf_t const *xecfg);
-xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg);
+xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg);
int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
xdemitconf_t const *xecfg);
diff --git a/xdiff/xutils.c b/xdiff/xutils.c
index 9504eae..62cb23d 100644
--- a/xdiff/xutils.c
+++ b/xdiff/xutils.c
@@ -143,6 +143,19 @@ long xdl_guess_lines(mmfile_t *mf, long sample) {
return nl + 1;
}
+int xdl_blankline(const char *line, long size, long flags)
+{
+ long i;
+
+ if (!(flags & XDF_WHITESPACE_FLAGS))
+ return (size <= 1);
+
+ for (i = 0; i < size && XDL_ISSPACE(line[i]); i++)
+ ;
+
+ return (i == size);
+}
+
int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
{
int i1, i2;
diff --git a/xdiff/xutils.h b/xdiff/xutils.h
index ad1428e..4646ce5 100644
--- a/xdiff/xutils.h
+++ b/xdiff/xutils.h
@@ -32,6 +32,7 @@ int xdl_cha_init(chastore_t *cha, long isize, long icount);
void xdl_cha_free(chastore_t *cha);
void *xdl_cha_alloc(chastore_t *cha);
long xdl_guess_lines(mmfile_t *mf, long sample);
+int xdl_blankline(const char *line, long size, long flags);
int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags);
unsigned long xdl_hash_record(char const **data, char const *top, long flags);
unsigned int xdl_hashbits(unsigned int size);
diff --git a/zlib.c b/zlib.c
index 2b2c0c7..61e6df0 100644
--- a/zlib.c
+++ b/zlib.c
@@ -168,13 +168,8 @@ void git_deflate_init(git_zstream *strm, int level)
strm->z.msg ? strm->z.msg : "no message");
}
-void git_deflate_init_gzip(git_zstream *strm, int level)
+static void do_git_deflate_init(git_zstream *strm, int level, int windowBits)
{
- /*
- * Use default 15 bits, +16 is to generate gzip header/trailer
- * instead of the zlib wrapper.
- */
- const int windowBits = 15 + 16;
int status;
zlib_pre_call(strm);
@@ -188,6 +183,24 @@ void git_deflate_init_gzip(git_zstream *strm, int level)
strm->z.msg ? strm->z.msg : "no message");
}
+void git_deflate_init_gzip(git_zstream *strm, int level)
+{
+ /*
+ * Use default 15 bits, +16 is to generate gzip header/trailer
+ * instead of the zlib wrapper.
+ */
+ do_git_deflate_init(strm, level, 15 + 16);
+}
+
+void git_deflate_init_raw(git_zstream *strm, int level)
+{
+ /*
+ * Use default 15 bits, negate the value to get raw compressed
+ * data without zlib header and trailer.
+ */
+ do_git_deflate_init(strm, level, -15);
+}
+
int git_deflate_abort(git_zstream *strm)
{
int status;