summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--Documentation/CodingGuidelines34
-rw-r--r--Documentation/Makefile13
-rw-r--r--Documentation/RelNotes/1.8.4.2.txt14
-rw-r--r--Documentation/RelNotes/1.8.4.3.txt54
-rw-r--r--Documentation/RelNotes/1.8.4.4.txt10
-rw-r--r--Documentation/RelNotes/1.8.4.5.txt13
-rw-r--r--Documentation/RelNotes/1.8.5.1.txt9
-rw-r--r--Documentation/RelNotes/1.8.5.2.txt20
-rw-r--r--Documentation/RelNotes/1.8.5.3.txt27
-rw-r--r--Documentation/RelNotes/1.8.5.4.txt48
-rw-r--r--Documentation/RelNotes/1.8.5.5.txt37
-rw-r--r--Documentation/RelNotes/1.8.5.txt218
-rw-r--r--Documentation/RelNotes/1.9.0.txt345
-rw-r--r--Documentation/SubmittingPatches11
-rw-r--r--Documentation/config.txt30
-rw-r--r--Documentation/date-formats.txt4
-rw-r--r--Documentation/diff-config.txt5
-rw-r--r--Documentation/diff-options.txt3
-rw-r--r--Documentation/fetch-options.txt40
-rw-r--r--Documentation/git-am.txt6
-rw-r--r--Documentation/git-blame.txt5
-rw-r--r--Documentation/git-cat-file.txt12
-rw-r--r--Documentation/git-checkout.txt4
-rw-r--r--Documentation/git-cherry-pick.txt7
-rw-r--r--Documentation/git-cherry.txt143
-rw-r--r--Documentation/git-clone.txt20
-rw-r--r--Documentation/git-column.txt5
-rw-r--r--Documentation/git-commit-tree.txt5
-rw-r--r--Documentation/git-commit.txt4
-rw-r--r--Documentation/git-cvsimport.txt4
-rw-r--r--Documentation/git-diff.txt2
-rw-r--r--Documentation/git-fast-import.txt10
-rw-r--r--Documentation/git-fetch-pack.txt15
-rw-r--r--Documentation/git-fetch.txt17
-rw-r--r--Documentation/git-filter-branch.txt33
-rw-r--r--Documentation/git-for-each-ref.txt24
-rw-r--r--Documentation/git-http-backend.txt8
-rw-r--r--Documentation/git-log.txt51
-rw-r--r--Documentation/git-lost-found.txt74
-rw-r--r--Documentation/git-merge-base.txt38
-rw-r--r--Documentation/git-mv.txt12
-rw-r--r--Documentation/git-notes.txt10
-rw-r--r--Documentation/git-p4.txt6
-rw-r--r--Documentation/git-pack-objects.txt3
-rw-r--r--Documentation/git-peek-remote.txt43
-rw-r--r--Documentation/git-prune.txt2
-rw-r--r--Documentation/git-pull.txt8
-rw-r--r--Documentation/git-push.txt9
-rw-r--r--Documentation/git-rebase.txt14
-rw-r--r--Documentation/git-remote-ext.txt5
-rw-r--r--Documentation/git-remote-fd.txt4
-rw-r--r--Documentation/git-remote.txt2
-rw-r--r--Documentation/git-repack.txt2
-rw-r--r--Documentation/git-replace.txt19
-rw-r--r--Documentation/git-repo-config.txt23
-rw-r--r--Documentation/git-reset.txt5
-rw-r--r--Documentation/git-rev-parse.txt22
-rw-r--r--Documentation/git-revert.txt6
-rw-r--r--Documentation/git-rm.txt9
-rw-r--r--Documentation/git-show-ref.txt1
-rw-r--r--Documentation/git-submodule.txt46
-rw-r--r--Documentation/git-svn.txt32
-rw-r--r--Documentation/git-tag.txt5
-rw-r--r--Documentation/git-tar-tree.txt82
-rw-r--r--Documentation/git-unpack-objects.txt2
-rw-r--r--Documentation/git-web--browse.txt1
-rw-r--r--Documentation/git.txt30
-rw-r--r--Documentation/gitattributes.txt9
-rw-r--r--Documentation/gitcli.txt18
-rw-r--r--Documentation/githooks.txt2
-rw-r--r--Documentation/gitignore.txt27
-rw-r--r--Documentation/gitk.txt123
-rw-r--r--Documentation/gitmodules.txt6
-rw-r--r--Documentation/gitremote-helpers.txt7
-rw-r--r--Documentation/gitweb.conf.txt55
-rw-r--r--Documentation/glossary-content.txt40
-rw-r--r--Documentation/howto/maintain-git.txt18
-rw-r--r--Documentation/howto/recover-corrupted-object-harder.txt242
-rw-r--r--Documentation/howto/setup-git-server-over-http.txt4
-rw-r--r--Documentation/merge-options.txt9
-rw-r--r--Documentation/merge-strategies.txt10
-rw-r--r--Documentation/rev-list-options.txt262
-rw-r--r--Documentation/revisions.txt2
-rw-r--r--Documentation/technical/api-builtin.txt4
-rw-r--r--Documentation/technical/api-hash.txt52
-rw-r--r--Documentation/technical/api-hashmap.txt235
-rw-r--r--Documentation/technical/api-parse-options.txt6
-rw-r--r--Documentation/technical/api-ref-iteration.txt4
-rw-r--r--Documentation/technical/api-remote.txt20
-rw-r--r--Documentation/technical/http-protocol.txt229
-rw-r--r--Documentation/technical/pack-heuristics.txt4
-rw-r--r--Documentation/technical/pack-protocol.txt7
-rw-r--r--Documentation/technical/protocol-capabilities.txt31
-rw-r--r--Documentation/user-manual.txt4
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile33
l---------RelNotes2
-rw-r--r--abspath.c22
-rw-r--r--alias.c13
-rw-r--r--alloc.c2
-rw-r--r--archive.c2
-rw-r--r--attr.c2
-rw-r--r--base85.c2
-rw-r--r--bisect.c6
-rw-r--r--block-sha1/sha1.c4
-rw-r--r--branch.c4
-rw-r--r--builtin.h3
-rw-r--r--builtin/add.c10
-rw-r--r--builtin/apply.c24
-rw-r--r--builtin/archive.c4
-rw-r--r--builtin/blame.c114
-rw-r--r--builtin/branch.c19
-rw-r--r--builtin/cat-file.c38
-rw-r--r--builtin/checkout-index.c2
-rw-r--r--builtin/checkout.c122
-rw-r--r--builtin/clean.c31
-rw-r--r--builtin/clone.c30
-rw-r--r--builtin/column.c2
-rw-r--r--builtin/commit-tree.c12
-rw-r--r--builtin/commit.c40
-rw-r--r--builtin/config.c6
-rw-r--r--builtin/describe.c62
-rw-r--r--builtin/diff.c77
-rw-r--r--builtin/fast-export.c6
-rw-r--r--builtin/fetch-pack.c43
-rw-r--r--builtin/fetch.c373
-rw-r--r--builtin/fmt-merge-msg.c10
-rw-r--r--builtin/for-each-ref.c138
-rw-r--r--builtin/fsck.c6
-rw-r--r--builtin/gc.c32
-rw-r--r--builtin/get-tar-commit-id.c40
-rw-r--r--builtin/grep.c6
-rw-r--r--builtin/help.c14
-rw-r--r--builtin/index-pack.c8
-rw-r--r--builtin/init-db.c11
-rw-r--r--builtin/log.c8
-rw-r--r--builtin/ls-files.c9
-rw-r--r--builtin/ls-remote.c4
-rw-r--r--builtin/ls-tree.c2
-rw-r--r--builtin/mailinfo.c16
-rw-r--r--builtin/merge-base.c175
-rw-r--r--builtin/merge-recursive.c4
-rw-r--r--builtin/merge.c28
-rw-r--r--builtin/mv.c38
-rw-r--r--builtin/name-rev.c9
-rw-r--r--builtin/notes.c2
-rw-r--r--builtin/pack-objects.c4
-rw-r--r--builtin/prune-packed.c38
-rw-r--r--builtin/prune.c46
-rw-r--r--builtin/push.c91
-rw-r--r--builtin/read-tree.c2
-rw-r--r--builtin/receive-pack.c319
-rw-r--r--builtin/reflog.c4
-rw-r--r--builtin/remote.c227
-rw-r--r--builtin/repack.c36
-rw-r--r--builtin/replace.c67
-rw-r--r--builtin/reset.c42
-rw-r--r--builtin/rev-list.c2
-rw-r--r--builtin/rev-parse.c84
-rw-r--r--builtin/revert.c2
-rw-r--r--builtin/rm.c4
-rw-r--r--builtin/send-pack.c17
-rw-r--r--builtin/shortlog.c6
-rw-r--r--builtin/show-branch.c23
-rw-r--r--builtin/show-ref.c6
-rw-r--r--builtin/symbolic-ref.c4
-rw-r--r--builtin/tag.c2
-rw-r--r--builtin/tar-tree.c102
-rw-r--r--builtin/unpack-objects.c2
-rw-r--r--builtin/update-index.c42
-rw-r--r--builtin/update-ref.c10
-rw-r--r--builtin/upload-archive.c2
-rw-r--r--bundle.c32
-rw-r--r--cache.h82
-rw-r--r--command-list.txt4
-rw-r--r--commit-slab.h39
-rw-r--r--commit.c65
-rw-r--r--commit.h42
-rw-r--r--compat/mingw.c17
-rw-r--r--compat/mingw.h3
-rw-r--r--compat/regex/regcomp.c2
-rwxr-xr-x[-rw-r--r--]compat/vcbuild/scripts/clink.pl0
-rwxr-xr-x[-rw-r--r--]compat/vcbuild/scripts/lib.pl0
-rw-r--r--config.c41
-rw-r--r--config.mak.uname7
-rw-r--r--connect.c336
-rw-r--r--connect.h3
-rw-r--r--connected.c44
-rw-r--r--connected.h2
-rwxr-xr-x[-rw-r--r--]contrib/buildsystems/engine.pl0
-rwxr-xr-x[-rw-r--r--]contrib/buildsystems/generate0
-rwxr-xr-x[-rw-r--r--]contrib/buildsystems/parse.pl0
-rw-r--r--contrib/completion/git-completion.bash39
-rw-r--r--contrib/completion/git-completion.tcsh2
-rw-r--r--contrib/completion/git-completion.zsh10
-rw-r--r--contrib/completion/git-prompt.sh2
-rw-r--r--contrib/credential/gnome-keyring/git-credential-gnome-keyring.c85
-rwxr-xr-xcontrib/examples/git-whatchanged.sh4
-rwxr-xr-xcontrib/git-resurrect.sh1
-rwxr-xr-xcontrib/gitview/gitview2
-rwxr-xr-xcontrib/hooks/post-receive-email1
-rwxr-xr-x[-rw-r--r--]contrib/hooks/pre-auto-gc-battery1
-rwxr-xr-x[-rw-r--r--]contrib/hooks/setgitperms.perl0
-rwxr-xr-x[-rw-r--r--]contrib/hooks/update-paranoid0
-rw-r--r--contrib/mw-to-git/Makefile9
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki.perl2
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw-lib.sh2
-rw-r--r--contrib/mw-to-git/t/test.config2
-rw-r--r--contrib/p4import/README1
-rw-r--r--contrib/p4import/git-p4import.py365
-rw-r--r--contrib/p4import/git-p4import.txt167
-rwxr-xr-xcontrib/remote-helpers/git-remote-bzr21
-rwxr-xr-xcontrib/remote-helpers/git-remote-hg32
-rwxr-xr-xcontrib/remote-helpers/test-bzr.sh5
-rwxr-xr-xcontrib/remote-helpers/test-hg.sh109
-rw-r--r--contrib/subtree/Makefile7
-rwxr-xr-xcontrib/subtree/git-subtree.sh22
-rw-r--r--contrib/subtree/git-subtree.txt14
-rw-r--r--convert.c2
-rw-r--r--csum-file.c3
-rw-r--r--csum-file.h2
-rw-r--r--daemon.c40
-rw-r--r--date.c2
-rw-r--r--diff-lib.c5
-rw-r--r--diff-no-index.c44
-rw-r--r--diff.c154
-rw-r--r--diff.h6
-rw-r--r--diffcore-order.c34
-rw-r--r--diffcore-rename.c185
-rw-r--r--diffcore.h10
-rw-r--r--dir.c96
-rw-r--r--dir.h24
-rw-r--r--entry.c21
-rw-r--r--environment.c13
-rw-r--r--fast-import.c80
-rw-r--r--fetch-pack.c157
-rw-r--r--fetch-pack.h30
-rw-r--r--gettext.c19
-rwxr-xr-xgit-add--interactive.perl22
-rwxr-xr-xgit-am.sh30
-rwxr-xr-xgit-bisect.sh2
-rw-r--r--git-compat-util.h10
-rwxr-xr-xgit-cvsserver.perl10
-rwxr-xr-xgit-difftool--helper.sh3
-rwxr-xr-xgit-gui/GIT-VERSION-GEN2
-rw-r--r--git-gui/Makefile2
-rwxr-xr-xgit-gui/git-gui.sh61
-rw-r--r--git-gui/lib/blame.tcl2
-rw-r--r--git-gui/lib/choose_repository.tcl12
-rw-r--r--git-gui/lib/index.tcl2
-rw-r--r--git-gui/lib/option.tcl2
-rw-r--r--git-gui/lib/spellcheck.tcl4
-rw-r--r--git-gui/macosx/Info.plist2
-rw-r--r--git-gui/po/bg.po2694
-rw-r--r--git-gui/po/glossary/bg.po287
-rw-r--r--git-gui/po/glossary/git-gui-glossary.txt29
-rwxr-xr-x[-rw-r--r--]git-gui/po/po2msg.sh0
-rwxr-xr-x[-rw-r--r--]git-gui/windows/git-gui.sh0
-rwxr-xr-xgit-instaweb.sh3
-rwxr-xr-xgit-lost-found.sh33
-rw-r--r--git-mergetool--lib.sh3
-rwxr-xr-xgit-p4.py19
-rw-r--r--git-parse-remote.sh4
-rwxr-xr-xgit-pull.sh42
-rwxr-xr-xgit-quiltimport.sh1
-rw-r--r--git-rebase--am.sh11
-rw-r--r--git-rebase--interactive.sh48
-rw-r--r--git-rebase--merge.sh6
-rwxr-xr-xgit-rebase.sh82
-rwxr-xr-xgit-request-pull.sh3
-rwxr-xr-xgit-send-email.perl11
-rw-r--r--git-sh-i18n.sh5
-rw-r--r--git-sh-setup.sh14
-rwxr-xr-xgit-stash.sh14
-rwxr-xr-xgit-submodule.sh112
-rwxr-xr-xgit-web--browse.sh6
-rw-r--r--git.c273
-rw-r--r--git.rc4
-rwxr-xr-xgitk-git/gitk634
-rw-r--r--gitk-git/po/bg.po1334
-rwxr-xr-x[-rw-r--r--]gitk-git/po/po2msg.sh0
-rwxr-xr-xgitweb/gitweb.perl184
-rw-r--r--graph.c4
-rw-r--r--hash.c110
-rw-r--r--hash.h50
-rw-r--r--hashmap.c228
-rw-r--r--hashmap.h71
-rw-r--r--help.c8
-rw-r--r--http-backend.c4
-rw-r--r--http-push.c8
-rw-r--r--http.c189
-rw-r--r--http.h31
-rw-r--r--ident.c16
-rw-r--r--imap-send.c10
-rw-r--r--line-log.c29
-rw-r--r--list-objects.c20
-rw-r--r--log-tree.c16
-rw-r--r--merge-recursive.c12
-rw-r--r--name-hash.c163
-rw-r--r--notes-utils.c6
-rw-r--r--notes.c8
-rw-r--r--pack-write.c11
-rw-r--r--pack.h2
-rw-r--r--pager.c13
-rw-r--r--parse-options.c12
-rw-r--r--parse-options.h11
-rw-r--r--path.c67
-rw-r--r--pathspec.c54
-rw-r--r--pathspec.h11
-rw-r--r--perl/Git/SVN.pm41
-rw-r--r--perl/Git/SVN/Editor.pm10
-rw-r--r--perl/Git/SVN/Log.pm1
-rw-r--r--pkt-line.c4
-rw-r--r--po/TEAMS12
-rw-r--r--po/bg.po10404
-rw-r--r--po/da.po3503
-rw-r--r--po/de.po3526
-rw-r--r--po/fr.po3538
-rw-r--r--po/git.pot3379
-rw-r--r--po/nl.po3493
-rw-r--r--po/sv.po3488
-rw-r--r--po/vi.po4272
-rw-r--r--po/zh_CN.po3626
-rw-r--r--preload-index.c3
-rw-r--r--pretty.c38
-rw-r--r--prompt.c3
-rw-r--r--read-cache.c49
-rw-r--r--refs.c182
-rw-r--r--refs.h8
-rw-r--r--remote-curl.c147
-rw-r--r--remote-testsvn.c10
-rw-r--r--remote.c158
-rw-r--r--remote.h19
-rw-r--r--replace_object.c3
-rw-r--r--rerere.c4
-rw-r--r--resolve-undo.c9
-rw-r--r--revision.c207
-rw-r--r--revision.h9
-rw-r--r--run-command.c13
-rw-r--r--send-pack.c37
-rw-r--r--send-pack.h2
-rw-r--r--sequencer.c19
-rw-r--r--sequencer.h2
-rw-r--r--setup.c107
-rw-r--r--sha1_file.c276
-rw-r--r--sha1_name.c140
-rw-r--r--shallow.c472
-rw-r--r--shell.c2
-rw-r--r--strbuf.c18
-rw-r--r--streaming.c4
-rw-r--r--submodule.c27
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/00compile.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/add_path_to_url.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/can_compress.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/canonicalize_url.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/collapse_dotdot.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/fatal.t0
-rwxr-xr-x[-rw-r--r--]t/Git-SVN/Utils/join_paths.t0
-rw-r--r--t/README27
-rw-r--r--t/annotate-tests.sh23
-rw-r--r--t/gitweb-lib.sh5
-rw-r--r--t/lib-bash.sh7
-rwxr-xr-xt/lib-credential.sh4
-rw-r--r--t/lib-cvs.sh2
-rw-r--r--t/lib-diff-alternative.sh3
-rw-r--r--t/lib-gettext.sh3
-rw-r--r--t/lib-git-daemon.sh20
-rw-r--r--t/lib-git-p4.sh23
-rw-r--r--t/lib-git-svn.sh4
-rw-r--r--t/lib-httpd.sh49
-rw-r--r--t/lib-httpd/apache.conf2
-rw-r--r--t/lib-httpd/passwd2
-rw-r--r--t/lib-pack.sh10
-rw-r--r--t/lib-pager.sh2
-rw-r--r--t/lib-prereq-FILEMODE.sh11
-rw-r--r--t/lib-read-tree.sh54
-rw-r--r--t/lib-rebase.sh2
-rw-r--r--t/lib-terminal.sh6
-rwxr-xr-xt/perf/p0001-rev-list.sh12
-rwxr-xr-xt/perf/p4001-diff-no-index.sh22
-rw-r--r--t/perf/perf-lib.sh4
-rwxr-xr-xt/t0000-basic.sh19
-rwxr-xr-xt/t0002-gitfile.sh3
-rwxr-xr-xt/t0003-attributes.sh1
-rwxr-xr-xt/t0008-ignores.sh30
-rwxr-xr-xt/t0011-hashmap.sh240
-rwxr-xr-xt/t0060-path-utils.sh81
-rwxr-xr-xt/t0202-gettext-perl.sh4
-rwxr-xr-x[-rw-r--r--]t/t0202/test.pl0
-rwxr-xr-xt/t1005-read-tree-reset.sh141
-rwxr-xr-xt/t1006-cat-file.sh62
-rwxr-xr-xt/t1010-mktree.sh4
-rwxr-xr-xt/t1013-loose-object-format.sh66
-rw-r--r--t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6bin117 -> 0 bytes
-rw-r--r--t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435bin17 -> 0 bytes
-rw-r--r--t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbdbin18 -> 0 bytes
-rw-r--r--t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99bin19 -> 0 bytes
-rw-r--r--t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752ebin10 -> 0 bytes
-rw-r--r--t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696bin181 -> 0 bytes
-rw-r--r--t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fdbin26 -> 0 bytes
-rw-r--r--t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb2
-rw-r--r--t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09bin139 -> 0 bytes
-rw-r--r--t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8bin54 -> 0 bytes
-rw-r--r--t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730bin13 -> 0 bytes
-rw-r--r--t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fabin156 -> 0 bytes
-rw-r--r--t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64fbin252 -> 0 bytes
-rw-r--r--t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832bin11 -> 0 bytes
-rw-r--r--t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8bin34 -> 0 bytes
-rw-r--r--t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391bin9 -> 0 bytes
-rw-r--r--t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a1
-rwxr-xr-xt/t1303-wacky-config.sh64
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh42
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh24
-rwxr-xr-xt/t1507-rev-parse-upstream.sh37
-rwxr-xr-xt/t1508-at-combinations.sh15
-rwxr-xr-xt/t2010-checkout-ambiguous.sh6
-rwxr-xr-xt/t2024-checkout-dwim.sh21
-rwxr-xr-xt/t3004-ls-files-basic.sh17
-rwxr-xr-xt/t3030-merge-recursive.sh47
-rwxr-xr-xt/t3200-branch.sh2
-rwxr-xr-xt/t3300-funny-names.sh6
-rwxr-xr-xt/t3400-rebase.sh16
-rwxr-xr-xt/t3600-rm.sh27
-rwxr-xr-xt/t3700-add.sh19
-rwxr-xr-xt/t3701-add-interactive.sh1
-rwxr-xr-xt/t3903-stash.sh12
-rwxr-xr-xt/t4010-diff-pathspec.sh36
-rwxr-xr-xt/t4014-format-patch.sh2
-rwxr-xr-xt/t4015-diff-whitespace.sh5
-rwxr-xr-xt/t4020-diff-external.sh15
-rwxr-xr-xt/t4029-diff-trailing-space.sh2
-rw-r--r--t/t4034/ada/expect2
-rwxr-xr-xt/t4035-diff-quiet.sh6
-rwxr-xr-xt/t4053-diff-no-index.sh26
-rwxr-xr-xt/t4056-diff-order.sh100
-rwxr-xr-xt/t4102-apply-rename.sh1
-rwxr-xr-xt/t4103-apply-binary.sh4
-rwxr-xr-xt/t4116-apply-reverse.sh8
-rwxr-xr-xt/t4120-apply-popt.sh1
-rwxr-xr-xt/t4129-apply-samemode.sh1
-rwxr-xr-xt/t4200-rerere.sh10
-rwxr-xr-xt/t4205-log-pretty-formats.sh15
-rwxr-xr-xt/t4208-log-magic-pathspec.sh15
-rwxr-xr-xt/t4212-log-corrupt.sh9
-rwxr-xr-xt/t5000-tar-tree.sh36
-rwxr-xr-xt/t5001-archive-attr.sh10
-rwxr-xr-xt/t5300-pack-object.sh18
-rwxr-xr-xt/t5302-pack-index.sh4
-rwxr-xr-xt/t5303-pack-corruption-resilience.sh4
-rwxr-xr-xt/t5304-prune.sh10
-rwxr-xr-xt/t5500-fetch-pack.sh87
-rwxr-xr-xt/t5505-remote.sh16
-rwxr-xr-xt/t5510-fetch.sh73
-rw-r--r--t/t5515/fetch.br-unconfig_--tags_.._.git1
-rw-r--r--t/t5515/fetch.master_--tags_.._.git1
-rwxr-xr-xt/t5516-fetch-push.sh75
-rwxr-xr-xt/t5525-fetch-tagopt.sh23
-rwxr-xr-xt/t5531-deep-submodule-push.sh1
-rwxr-xr-xt/t5536-fetch-conflicts.sh100
-rwxr-xr-xt/t5537-fetch-shallow.sh203
-rwxr-xr-xt/t5538-push-shallow.sh182
-rwxr-xr-xt/t5540-http-push.sh5
-rwxr-xr-xt/t5541-http-push.sh7
-rwxr-xr-xt/t5550-http-fetch.sh11
-rwxr-xr-xt/t5551-http-fetch.sh18
-rwxr-xr-xt/t5561-http-backend.sh1
-rwxr-xr-xt/t5570-git-daemon.sh6
-rwxr-xr-xt/t5601-clone.sh150
-rwxr-xr-xt/t6000-rev-list-misc.sh25
-rwxr-xr-xt/t6010-merge-base.sh67
-rwxr-xr-xt/t6011-rev-list-with-bad-commit.sh2
-rwxr-xr-xt/t6013-rev-list-reverse-parents.sh4
-rwxr-xr-xt/t6018-rev-list-glob.sh54
-rwxr-xr-xt/t6031-merge-recursive.sh1
-rwxr-xr-xt/t6040-tracking-info.sh24
-rwxr-xr-xt/t6050-replace.sh42
-rwxr-xr-xt/t6101-rev-parse-parents.sh16
-rwxr-xr-xt/t6130-pathspec-noglob.sh7
-rwxr-xr-xt/t6131-pathspec-icase.sh12
-rwxr-xr-xt/t6132-pathspec-exclude.sh184
-rwxr-xr-xt/t6300-for-each-ref.sh73
-rwxr-xr-xt/t6500-gc.sh5
-rwxr-xr-xt/t7001-mv.sh76
-rwxr-xr-xt/t7006-pager.sh12
-rwxr-xr-xt/t7101-reset-empty-subdirs.sh (renamed from t/t7101-reset.sh)0
-rwxr-xr-xt/t7102-reset.sh15
-rwxr-xr-xt/t7104-reset-hard.sh (renamed from t/t7104-reset.sh)0
-rwxr-xr-xt/t7105-reset-patch.sh10
-rwxr-xr-xt/t7106-reset-unborn-branch.sh5
-rwxr-xr-xt/t7406-submodule-update.sh64
-rwxr-xr-xt/t7407-submodule-foreach.sh13
-rwxr-xr-xt/t7501-commit.sh1
-rwxr-xr-xt/t7507-commit-verbose.sh28
-rwxr-xr-xt/t7508-status.sh2
-rwxr-xr-xt/t7510-signed-commit.sh25
-rwxr-xr-xt/t7601-merge-pull-config.sh21
-rwxr-xr-xt/t7700-repack.sh2
-rwxr-xr-xt/t9001-send-email.sh1
-rwxr-xr-xt/t9114-git-svn-dcommit-merge.sh2
-rwxr-xr-xt/t9129-git-svn-i18n-commitencoding.sh2
-rwxr-xr-xt/t9137-git-svn-dcommit-clobber-series.sh8
-rwxr-xr-x[-rw-r--r--]t/t9150/make-svk-dump0
-rwxr-xr-x[-rw-r--r--]t/t9151/make-svnmerge-dump0
-rwxr-xr-xt/t9200-git-cvsexportcommit.sh1
-rwxr-xr-xt/t9300-fast-import.sh2
-rwxr-xr-xt/t9350-fast-export.sh2
-rwxr-xr-xt/t9400-git-cvsserver-server.sh2
-rwxr-xr-xt/t9401-git-cvsserver-crlf.sh2
-rwxr-xr-xt/t9402-git-cvsserver-refs.sh2
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh2
-rwxr-xr-xt/t9700-perl-git.sh4
-rwxr-xr-xt/t9802-git-p4-filetype.sh83
-rwxr-xr-xt/t9805-git-p4-skip-submit-edit.sh6
-rwxr-xr-xt/t9807-git-p4-submit.sh2
-rwxr-xr-xt/t9809-git-p4-client-view.sh16
-rwxr-xr-xt/t9810-git-p4-rcs.sh2
-rwxr-xr-xt/t9812-git-p4-wildcards.sh50
-rwxr-xr-xt/t9813-git-p4-preserve-users.sh38
-rwxr-xr-xt/t9816-git-p4-locked.sh145
-rw-r--r--t/test-lib-functions.sh79
-rw-r--r--t/test-lib.sh154
-rw-r--r--tag.c10
-rw-r--r--test-hashmap.c255
-rw-r--r--test-line-buffer.c6
-rw-r--r--test-string-list.c2
-rw-r--r--trace.c2
-rw-r--r--transport-helper.c28
-rw-r--r--transport.c65
-rw-r--r--transport.h16
-rw-r--r--tree-diff.c31
-rw-r--r--tree-walk.c89
-rw-r--r--tree-walk.h2
-rw-r--r--unpack-trees.c79
-rw-r--r--upload-pack.c71
-rw-r--r--userdiff.c4
-rw-r--r--vcs-svn/fast_export.c11
-rw-r--r--wrapper.c2
-rw-r--r--wt-status.c131
-rw-r--r--wt-status.h1
-rw-r--r--xdiff/xemit.c2
541 files changed, 39361 insertions, 22567 deletions
diff --git a/.gitignore b/.gitignore
index 66199ed..dc600f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
/GIT-CFLAGS
/GIT-LDFLAGS
/GIT-PREFIX
+/GIT-PERL-DEFINES
/GIT-PYTHON-VARS
/GIT-SCRIPT-DEFINES
/GIT-USER-AGENT
@@ -75,7 +76,6 @@
/git-init-db
/git-instaweb
/git-log
-/git-lost-found
/git-ls-files
/git-ls-remote
/git-ls-tree
@@ -105,7 +105,6 @@
/git-pack-refs
/git-parse-remote
/git-patch-id
-/git-peek-remote
/git-prune
/git-prune-packed
/git-pull
@@ -131,7 +130,6 @@
/git-remote-testsvn
/git-repack
/git-replace
-/git-repo-config
/git-request-pull
/git-rerere
/git-reset
@@ -159,7 +157,6 @@
/git-svn
/git-symbolic-ref
/git-tag
-/git-tar-tree
/git-unpack-file
/git-unpack-objects
/git-update-index
@@ -185,6 +182,7 @@
/test-dump-cache-tree
/test-scrap-cache-tree
/test-genrandom
+/test-hashmap
/test-index-version
/test-line-buffer
/test-match-trees
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index a600e35..ef67b53 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -260,9 +260,11 @@ Writing Documentation:
Every user-visible change should be reflected in the documentation.
The same general rule as for code applies -- imitate the existing
- conventions. A few commented examples follow to provide reference
- when writing or modifying command usage strings and synopsis sections
- in the manual pages:
+ conventions.
+
+ A few commented examples follow to provide reference when writing or
+ modifying command usage strings and synopsis sections in the manual
+ pages:
Placeholders are spelled in lowercase and enclosed in angle brackets:
<file>
@@ -312,3 +314,29 @@ Writing Documentation:
Use 'git' (all lowercase) when talking about commands i.e. something
the user would type into a shell and use 'Git' (uppercase first letter)
when talking about the version control system and its properties.
+
+ A few commented examples follow to provide reference when writing or
+ modifying paragraphs or option/command explanations that contain options
+ or commands:
+
+ Literal examples (e.g. use of command-line options, command names, and
+ configuration variables) are typeset in monospace, and if you can use
+ `backticks around word phrases`, do so.
+ `--pretty=oneline`
+ `git rev-list`
+ `remote.pushdefault`
+
+ Word phrases enclosed in `backtick characters` are rendered literally
+ and will not be further expanded. The use of `backticks` to achieve the
+ previous rule means that literal examples should not use AsciiDoc
+ escapes.
+ Correct:
+ `--pretty=oneline`
+ Incorrect:
+ `\--pretty=oneline`
+
+ If some place in the documentation needs to typeset a command usage
+ example with inline substitutions, it is fine to use +monospaced and
+ inline substituted text+ instead of `monospaced literal text`, and with
+ the former, the part that should not get substituted must be
+ quoted/escaped.
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 4f13a23..fc6b2cf 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -2,6 +2,9 @@
MAN1_TXT =
MAN5_TXT =
MAN7_TXT =
+TECH_DOCS =
+ARTICLES =
+SP_ARTICLES =
MAN1_TXT += $(filter-out \
$(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
@@ -37,12 +40,12 @@ MAN_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
OBSOLETE_HTML = git-remote-helpers.html
DOC_HTML = $(MAN_HTML) $(OBSOLETE_HTML)
-ARTICLES = howto-index
+ARTICLES += howto-index
ARTICLES += everyday
ARTICLES += git-tools
ARTICLES += git-bisect-lk2009
# with their own formatting rules.
-SP_ARTICLES = user-manual
+SP_ARTICLES += user-manual
SP_ARTICLES += howto/new-command
SP_ARTICLES += howto/revert-branch-rebase
SP_ARTICLES += howto/using-merge-subtree
@@ -53,13 +56,15 @@ SP_ARTICLES += howto/setup-git-server-over-http
SP_ARTICLES += howto/separating-topic-branches
SP_ARTICLES += howto/revert-a-faulty-merge
SP_ARTICLES += howto/recover-corrupted-blob-object
+SP_ARTICLES += howto/recover-corrupted-object-harder
SP_ARTICLES += howto/rebuild-from-update-hook
SP_ARTICLES += howto/rebase-from-internal-branch
SP_ARTICLES += howto/maintain-git
API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
SP_ARTICLES += $(API_DOCS)
-TECH_DOCS = technical/index-format
+TECH_DOCS += technical/http-protocol
+TECH_DOCS += technical/index-format
TECH_DOCS += technical/pack-format
TECH_DOCS += technical/pack-heuristics
TECH_DOCS += technical/pack-protocol
@@ -323,7 +328,7 @@ manpage-base-url.xsl: manpage-base-url.xsl.in
user-manual.xml: user-manual.txt user-manual.conf
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
- $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book -o $@+ $< && \
+ $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d article -o $@+ $< && \
mv $@+ $@
technical/api-index.txt: technical/api-index-skel.txt \
diff --git a/Documentation/RelNotes/1.8.4.2.txt b/Documentation/RelNotes/1.8.4.2.txt
index 867ae69..9adccb1 100644
--- a/Documentation/RelNotes/1.8.4.2.txt
+++ b/Documentation/RelNotes/1.8.4.2.txt
@@ -4,6 +4,20 @@ Git v1.8.4.2 Release Notes
Fixes since v1.8.4.1
--------------------
+ * "git clone" gave some progress messages to the standard output, not
+ to the standard error, and did not allow suppressing them with the
+ "--no-progress" option.
+
+ * "format-patch --from=<whom>" forgot to omit unnecessary in-body
+ from line, i.e. when <whom> is the same as the real author.
+
+ * "git shortlog" used to choke and die when there is a malformed
+ commit (e.g. missing authors); it now simply ignore such a commit
+ and keeps going.
+
+ * "git merge-recursive" did not parse its "--diff-algorithm=" command
+ line option correctly.
+
* "git branch --track" had a minor regression in v1.8.3.2 and later
that made it impossible to base your local work on anything but a
local branch of the upstream repository you are tracking from.
diff --git a/Documentation/RelNotes/1.8.4.3.txt b/Documentation/RelNotes/1.8.4.3.txt
new file mode 100644
index 0000000..03f3d17
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.3.txt
@@ -0,0 +1,54 @@
+Git v1.8.4.3 Release Notes
+========================
+
+Fixes since v1.8.4.2
+--------------------
+
+ * The interaction between use of Perl in our test suite and NO_PERL
+ has been clarified a bit.
+
+ * A fast-import stream expresses a pathname with funny characters by
+ quoting them in C style; remote-hg remote helper (in contrib/)
+ forgot to unquote such a path.
+
+ * One long-standing flaw in the pack transfer protocol used by "git
+ clone" was that there was no way to tell the other end which branch
+ "HEAD" points at, and the receiving end needed to guess. A new
+ capability has been defined in the pack protocol to convey this
+ information so that cloning from a repository with more than one
+ branches pointing at the same commit where the HEAD is at now
+ reliably sets the initial branch in the resulting repository.
+
+ * We did not handle cases where http transport gets redirected during
+ the authorization request (e.g. from http:// to https://).
+
+ * "git rev-list --objects ^v1.0^ v1.0" gave v1.0 tag itself in the
+ output, but "git rev-list --objects v1.0^..v1.0" did not.
+
+ * The fall-back parsing of commit objects with broken author or
+ committer lines were less robust than ideal in picking up the
+ timestamps.
+
+ * Bash prompting code to deal with an SVN remote as an upstream
+ were coded in a way not supported by older Bash versions (3.x).
+
+ * "git checkout topic", when there is not yet a local "topic" branch
+ but there is a unique remote-tracking branch for a remote "topic"
+ branch, pretended as if "git checkout -t -b topic remote/$r/topic"
+ (for that unique remote $r) was run. This hack however was not
+ implemented for "git checkout topic --".
+
+ * Coloring around octopus merges in "log --graph" output was screwy.
+
+ * We did not generate HTML version of documentation to "git subtree"
+ in contrib/.
+
+ * The synopsis section of "git unpack-objects" documentation has been
+ clarified a bit.
+
+ * An ancient How-To on serving Git repositories on an HTTP server
+ lacked a warning that it has been mostly superseded with more
+ modern way.
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
diff --git a/Documentation/RelNotes/1.8.4.4.txt b/Documentation/RelNotes/1.8.4.4.txt
new file mode 100644
index 0000000..7bc4c5dc
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.4.txt
@@ -0,0 +1,10 @@
+Git v1.8.4.4 Release Notes
+========================
+
+Fixes since v1.8.4.3
+--------------------
+
+ * The fix in v1.8.4.3 to the pack transfer protocol to propagate
+ the target of symbolic refs broke "git clone/git fetch" from a
+ repository with too many symbolic refs. As a hotfix/workaround,
+ we transfer only the information on HEAD.
diff --git a/Documentation/RelNotes/1.8.4.5.txt b/Documentation/RelNotes/1.8.4.5.txt
new file mode 100644
index 0000000..215bd1a
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.5.txt
@@ -0,0 +1,13 @@
+Git v1.8.4.5 Release Notes
+==========================
+
+Fixes since v1.8.4.4
+--------------------
+
+ * Recent update to remote-hg that attempted to make it work better
+ with non ASCII pathnames fed Unicode strings to the underlying Hg
+ API, which was wrong.
+
+ * "git submodule init" copied "submodule.$name.update" settings from
+ .gitmodules to .git/config without making sure if the suggested
+ value was sensible.
diff --git a/Documentation/RelNotes/1.8.5.1.txt b/Documentation/RelNotes/1.8.5.1.txt
new file mode 100644
index 0000000..7236aaf
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.1.txt
@@ -0,0 +1,9 @@
+Git v1.8.5.1 Release Notes
+==========================
+
+Fixes since v1.8.5
+------------------
+
+ * "git submodule init" copied "submodule.$name.update" settings from
+ .gitmodules to .git/config without making sure if the suggested
+ value was sensible.
diff --git a/Documentation/RelNotes/1.8.5.2.txt b/Documentation/RelNotes/1.8.5.2.txt
new file mode 100644
index 0000000..3ac4984
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.2.txt
@@ -0,0 +1,20 @@
+Git v1.8.5.2 Release Notes
+==========================
+
+Fixes since v1.8.5.1
+--------------------
+
+ * "git diff -- ':(icase)makefile'" was unnecessarily rejected at the
+ command line parser.
+
+ * "git cat-file --batch-check=ok" did not check the existence of
+ the named object.
+
+ * "git am --abort" sometimes complained about not being able to write
+ a tree with an 0{40} object in it.
+
+ * Two processes creating loose objects at the same time could have
+ failed unnecessarily when the name of their new objects started
+ with the same byte value, due to a race condition.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.3.txt b/Documentation/RelNotes/1.8.5.3.txt
new file mode 100644
index 0000000..3de2dd0
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.3.txt
@@ -0,0 +1,27 @@
+Git v1.8.5.3 Release Notes
+==========================
+
+Fixes since v1.8.5.2
+--------------------
+
+ * The "--[no-]informative-errors" options to "git daemon" were parsed
+ a bit too loosely, allowing any other string after these option
+ names.
+
+ * A "gc" process running as a different user should be able to stop a
+ new "gc" process from starting.
+
+ * An earlier "clean-up" introduced an unnecessary memory leak to the
+ credential subsystem.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+ out, but it didn't.
+
+ * "git rev-parse <revs> -- <paths>" did not implement the usual
+ disambiguation rules the commands in the "git log" family used in
+ the same way.
+
+ * "git cat-file --batch=", an admittedly useless command, did not
+ behave very well.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.4.txt b/Documentation/RelNotes/1.8.5.4.txt
new file mode 100644
index 0000000..d18c403
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.4.txt
@@ -0,0 +1,48 @@
+Git v1.8.5.4 Release Notes
+==========================
+
+Fixes since v1.8.5.3
+--------------------
+
+ * "git fetch --depth=0" was a no-op, and was silently ignored.
+ Diagnose it as an error.
+
+ * Remote repository URL expressed in scp-style host:path notation are
+ parsed more carefully (e.g. "foo/bar:baz" is local, "[::1]:/~user" asks
+ to connect to user's home directory on host at address ::1.
+
+ * SSL-related options were not passed correctly to underlying socket
+ layer in "git send-email".
+
+ * "git commit -v" appends the patch to the log message before
+ editing, and then removes the patch when the editor returned
+ control. However, the patch was not stripped correctly when the
+ first modified path was a submodule.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+ out, but it didn't.
+
+ * When we figure out how many file descriptors to allocate for
+ keeping packfiles open, a system with non-working getrlimit() could
+ cause us to die(), but because we make this call only to get a
+ rough estimate of how many is available and we do not even attempt
+ to use up all file descriptors available ourselves, it is nicer to
+ fall back to a reasonable low value rather than dying.
+
+ * "git log --decorate" did not handle a tag pointed by another tag
+ nicely.
+
+ * "git add -A" (no other arguments) in a totally empty working tree
+ used to emit an error.
+
+ * There is no reason to have a hardcoded upper limit of the number of
+ parents for an octopus merge, created via the graft mechanism, but
+ there was.
+
+ * The implementation of 'git stash $cmd "stash@{...}"' did not quote
+ the stash argument properly and left it split at IFS whitespace.
+
+ * The documentation to "git pull" hinted there is an "-m" option
+ because it incorrectly shared the documentation with "git merge".
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.5.txt b/Documentation/RelNotes/1.8.5.5.txt
new file mode 100644
index 0000000..9191ce9
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.5.txt
@@ -0,0 +1,37 @@
+Git v1.8.5.5 Release Notes
+==========================
+
+Fixes since v1.8.5.4
+--------------------
+
+ * The pathspec matching code, while comparing two trees (e.g. "git
+ diff A B -- path1 path2") was too aggressive and failed to match
+ some paths when multiple pathspecs were involved.
+
+ * "git repack --max-pack-size=8g" stopped being parsed correctly when
+ the command was reimplemented in C.
+
+ * A recent update to "git send-email" broke platforms where
+ /etc/ssl/certs/ directory exists but cannot be used as SSL_ca_path
+ (e.g. Fedora rawhide).
+
+ * A handful of bugs around interpreting $branch@{upstream} notation
+ and its lookalike, when $branch part has interesting characters,
+ e.g. "@", and ":", have been fixed.
+
+ * "git clone" would fail to clone from a repository that has a ref
+ directly under "refs/", e.g. "refs/stash", because different
+ validation paths do different things on such a refname. Loosen the
+ client side's validation to allow such a ref.
+
+ * "git log --left-right A...B" lost the "leftness" of commits
+ reachable from A when A is a tag as a side effect of a recent
+ bugfix. This is a regression in 1.8.4.x series.
+
+ * "git merge-base --octopus" used to leave cleaning up suboptimal
+ result to the caller, but now it does the clean-up itself.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+ out, but it didn't.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.txt b/Documentation/RelNotes/1.8.5.txt
index 4c2aa70..602df0c 100644
--- a/Documentation/RelNotes/1.8.5.txt
+++ b/Documentation/RelNotes/1.8.5.txt
@@ -8,7 +8,7 @@ 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:
+semantics, which 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
@@ -53,9 +53,12 @@ Updates since v1.8.4
Foreign interfaces, subsystems and ports.
- * "git-svn" used with SVN 1.8.0 when talking over https:// connection
+ * "git-svn" has been taught to use the serf library, which is the
+ only option SVN 1.8.0 offers us when talking the HTTP protocol.
+
+ * "git-svn" talking over an https:// connection using the serf library
dumped core due to a bug in the serf library that SVN uses. Work
- it around on our side, even though the SVN side is being fixed.
+ around it on our side, even though the SVN side is being fixed.
* On MacOS X, we detected if the filesystem needs the "pre-composed
unicode strings" workaround, but did not automatically enable it.
@@ -65,10 +68,7 @@ Foreign interfaces, subsystems and ports.
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.
+ OpenSSL's.
* "git fast-import" treats an empty path given to "ls" as the root of
the tree.
@@ -76,22 +76,25 @@ Foreign interfaces, subsystems and ports.
UI, Workflows & Features
- * "git grep" and "git show" pays attention to "--textconv" option
+ * xdg-open can be used as a browser backend for "git web-browse"
+ (hence to show "git help -w" output), when available.
+
+ * "git grep" and "git show" pay attention to the "--textconv" option
when these commands are told to operate on blob objects (e.g. "git
- grep -e pattern HEAD:Makefile").
+ grep -e pattern --textconv HEAD:Makefile").
* "git replace" helper no longer allows an object to be replaced with
another object of a different type to avoid confusion (you can
- still manually craft such replacement using "git update-ref", as an
+ still manually craft such a replacement using "git update-ref", as an
escape hatch).
- * "git status" no longer prints dirty status information for
+ * "git status" no longer prints the dirty status information of
submodules for which submodule.$name.ignore is set to "all".
* "git rebase -i" honours core.abbrev when preparing the insn sheet
for editing.
- * "git status" during a cherry-pick shows what original commit is
+ * "git status" during a cherry-pick shows which original commit is
being picked.
* Instead of typing four capital letters "HEAD", you can say "@" now,
@@ -99,21 +102,21 @@ UI, Workflows & Features
* "git check-ignore" follows the same rule as "git add" and "git
status" in that the ignore/exclude mechanism does not take effect
- on paths that are already tracked. With "--no-index" option, it
+ on paths that are already tracked. With the "--no-index" option, it
can be used to diagnose which paths that should have been ignored
have been mistakenly added to the index.
* Some irrelevant "advice" messages that are shared with "git status"
output have been removed from the commit log template.
- * "update-refs" learnt a "--stdin" option to read multiple update
+ * "update-refs" learned a "--stdin" option to read multiple update
requests and perform them in an all-or-none fashion.
* Just like "make -C <directory>", "git -C <directory> ..." tells Git
to go there before doing anything else.
- * Just like "git checkout -" knows to check out and "git merge -"
- knows to merge the branch you were previously on, "git cherry-pick"
+ * Just like "git checkout -" knows to check out, and "git merge -"
+ knows to merge, the branch you were previously on, "git cherry-pick"
now understands "git cherry-pick -" to pick from the previous
branch.
@@ -123,59 +126,58 @@ UI, Workflows & Features
"git status --porcelain" instead, as its format is stable and easier
to parse.
- * Make "foo^{tag}" to peel a tag to itself, i.e. no-op., and fail if
- "foo" is not a tag. "git rev-parse --verify v1.0^{tag}" would be
- a more convenient way to say "test $(git cat-file -t v1.0) = tag".
+ * The ref syntax "foo^{tag}" (with the literal string "{tag}") peels a
+ tag ref to itself, i.e. it's a no-op., and fails if
+ "foo" is not a tag. "git rev-parse --verify v1.0^{tag}" is
+ a more convenient way than "test $(git cat-file -t v1.0) = tag" to
+ check if v1.0 is a tag.
* "git branch -v -v" (and "git status") did not distinguish among a
- branch that does not build on any other branch, a branch that is in
- sync with the branch it builds on, and a branch that is configured
- to build on some other branch that no longer exists.
+ branch that is not based on any other branch, a branch that is in
+ sync with its upstream branch, and a branch that is configured with an
+ upstream branch that no longer exists.
- * A packfile that stores the same object more than once is broken and
- will be rejected by "git index-pack" that is run when receiving
- data over the wire.
-
- * Earlier we started rejecting an attempt to add 0{40} object name to
+ * Earlier we started rejecting any attempt to add the 0{40} object name to
the index and to tree objects, but it sometimes is necessary to
- allow so to be able to use tools like filter-branch to correct such
- broken tree objects. "filter-branch" can again be used to to do
- so.
+ allow this to be able to use tools like filter-branch to correct such
+ broken tree objects. "filter-branch" can again be used to do this.
* "git config" did not provide a way to set or access numbers larger
than a native "int" on the platform; it now provides 64-bit signed
integers on all platforms.
* "git pull --rebase" always chose to do the bog-standard flattening
- rebase. You can tell it to run "rebase --preserve-merges" by
+ rebase. You can tell it to run "rebase --preserve-merges" with
+ "git pull --rebase=preserve" or 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.
+ * Magic pathspecs like ":(icase)makefile" (matches both Makefile
+ and makefile) and ":(glob)foo/**/bar" (matches "bar" in "foo"
+ and any subdirectory of "foo") can be used in more places.
- * The "http.*" variables can now be specified per URL that the
- configuration applies. For example,
+ * The "http.*" variables can now be specified for individual URLs.
+ For example,
[http]
sslVerify = true
[http "https://weak.example.com/"]
sslVerify = false
- would flip http.sslVerify off only when talking to that specified
+ would flip http.sslVerify off only when talking to that specific
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
+ * "git mv A B" when moving a submodule has been taught to
+ relocate the submodule's 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.
+ origin of multiple blocks of lines.
* The http transport clients can optionally ask to save cookies
- with http.savecookies configuration variable.
+ with the 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
@@ -197,7 +199,7 @@ UI, Workflows & Features
* "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
+ wondering 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.
@@ -205,6 +207,12 @@ UI, Workflows & Features
Performance, Internal Implementation, etc.
+ * "git for-each-ref" when asking for merely the object name does not
+ have to parse the object pointed at by the refs; the codepath has
+ been optimized.
+
+ * The HTTP transport will try to use TCP keepalive when able.
+
* "git repack" is now written in C.
* Build procedure for MSVC has been updated.
@@ -213,23 +221,23 @@ Performance, Internal Implementation, etc.
should apply the same "no subprocess or pipe" optimization as we
apply to user-supplied GIT_PAGER=cat.
- * 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
+ * Many commands use a --dashed-option as an operation mode selector
+ (e.g. "git tag --delete") that excludes other operation modes
+ (e.g. "git tag --delete --verify" is nonsense) and that cannot be
+ negated (e.g. "git tag --no-delete" is nonsense). The 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
+ * OPT_BOOLEAN() in the 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
+ * "git gc" exits early without doing any 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
+ close pack windows that are not used and also closed filehandles to
+ open but unused packfiles. These are now controlled separately
to better cope with the load.
Also contains various documentation updates and code clean-ups.
@@ -239,20 +247,82 @@ 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
+track are contained in this release (see the maintenance releases' notes for
details).
- * "git clone" gave some progress messages to the standard output, not
- to the standard error, and did not allow suppressing them with the
+ * An ancient How-To on serving Git repositories on an HTTP server
+ lacked a warning that it has been mostly superseded with a more
+ modern way.
+ (merge 6d52bc3 sc/doc-howto-dumb-http later to maint).
+
+ * The interaction between the use of Perl in our test suite and NO_PERL
+ has been clarified a bit.
+ (merge f8fc0ee jn/test-prereq-perl-doc later to maint).
+
+ * The synopsis section of the "git unpack-objects" documentation has been
+ clarified a bit.
+ (merge 61e2e22 vd/doc-unpack-objects later to maint).
+
+ * We did not generate the HTML version of the documentation to "git subtree"
+ in contrib/.
+ (merge 95c62fb jk/subtree-install-fix later to maint).
+
+ * A fast-import stream expresses a pathname with funny characters by
+ quoting them in C style; the remote-hg remote helper forgot to unquote
+ such a path.
+ (merge 1136265 ap/remote-hg-unquote-cquote later to maint).
+
+ * "git reset -p HEAD" has a codepath to special-case it to behave
+ differently from resetting to contents of other commits, but a
+ recent change broke it.
+
+ * Coloring around octopus merges in "log --graph" output was screwy.
+ (merge 339c17b hn/log-graph-color-octopus later to maint).
+
+ * "git checkout topic", when there is not yet a local "topic" branch
+ but there is a unique remote-tracking branch for a remote "topic"
+ branch, pretended as if "git checkout -t -b topic remote/$r/topic"
+ (for that unique remote $r) was run. This hack however was not
+ implemented for "git checkout topic --".
+ (merge bca3969 mm/checkout-auto-track-fix later to maint).
+
+ * One long-standing flaw in the pack transfer protocol used by "git
+ clone" was that there was no way to tell the other end which branch
+ "HEAD" points at, and the receiving end needed to guess. A new
+ capability has been defined in the pack protocol to convey this
+ information so that cloning from a repository with more than one
+ branch pointing at the same commit where the HEAD is at now
+ reliably sets the initial branch in the resulting repository.
+ (merge 360a326 jc/upload-pack-send-symref later to maint).
+
+ * We did not handle cases where the http transport gets redirected during
+ the authorization request (e.g. from http:// to https://).
+ (merge 70900ed jk/http-auth-redirects later to maint).
+
+ * Bash prompting code to deal with an SVN remote as an upstream
+ was coded in a way unsupported by older Bash versions (3.x).
+ (merge 52ec889 sg/prompt-svn-remote-fix later to maint).
+
+ * The fall-back parsing of commit objects with broken author or
+ committer lines was less robust than ideal in picking up the
+ timestamps.
+ (merge 03818a4 jk/split-broken-ident later to maint).
+
+ * "git rev-list --objects ^v1.0^ v1.0" gave the v1.0 tag itself in the
+ output, but "git rev-list --objects v1.0^..v1.0" did not.
+ (merge 895c5ba jc/revision-range-unpeel later to maint).
+
+ * "git clone" wrote some progress messages to standard output, not
+ to standard error, and did not suppress them with the
--no-progress option.
(merge 643f918 jk/clone-progress-to-stderr later to maint).
- * "format-patch --from=<whom>" forgot to omit unnecessary in-body
+ * "format-patch --from=<whom>" forgot to omit an unnecessary in-body
from line, i.e. when <whom> is the same as the real author.
(merge 662cc30 jk/format-patch-from later to maint).
* "git shortlog" used to choke and die when there is a malformed
- commit (e.g. missing authors); it now simply ignore such a commit
+ commit (e.g. missing authors); it now simply ignores such a commit
and keeps going.
(merge cd4f09e jk/shortlog-tolerate-broken-commit later to maint).
@@ -266,16 +336,16 @@ details).
small empty messages to keep the connection alive.
(merge 115dedd jk/upload-pack-keepalive later to maint).
- * "git rebase" had a portability regression in v1.8.4 to trigger a
+ * "git rebase" had a portability regression in v1.8.4 that triggered a
bug in some BSD shell implementations.
(merge 99855dd mm/rebase-continue-freebsd-WB later to maint).
* "git branch --track" had a minor regression in v1.8.3.2 and later
that made it impossible to base your local work on anything but a
- local branch of the upstream repository you are tracking from.
+ local branch of the upstream repository you are tracking.
(merge b0f49ff jh/checkout-auto-tracking later to maint).
- * When the webserver responds with "405 Method Not Allowed", "git
+ * When the web server responds with "405 Method Not Allowed", "git
http-backend" should tell the client what methods are allowed with
the "Allow" header.
(merge 9247be0 bc/http-backend-allow-405 later to maint).
@@ -289,22 +359,22 @@ details).
executable files.
(merge 1b48d56 jc/cvsserver-perm-bit-fix later to maint).
- * When send-email comes up with an error message to die with upon
+ * When send-email obtains an error message to die with upon
failure to start an SSL session, it tried to read the error string
from a wrong place.
(merge 6cb0c88 bc/send-email-ssl-die-message-fix later to maint).
- * The implementation of "add -i" has a crippling code to work around
+ * The implementation of "add -i" has some crippling code to work around an
ActiveState Perl limitation but it by mistake also triggered on Git
for Windows where MSYS perl is used.
(merge df17e77 js/add-i-mingw later to maint).
- * We made sure that we notice the user-supplied GIT_DIR is actually a
+ * We made sure that we notice when the user-supplied GIT_DIR is actually a
gitfile, but did not do the same when the default ".git" is a
gitfile.
(merge 487a2b7 nd/git-dir-pointing-at-gitfile later to maint).
- * When an object is not found after checking the packfiles and then
+ * When an object is not found after checking the packfiles and the
loose object directory, read_sha1_file() re-checks the packfiles to
prevent racing with a concurrent repacker; teach the same logic to
has_sha1_file().
@@ -322,22 +392,22 @@ details).
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
+ * The shortened commit object names in the insn sheet that is prepared at the
+ beginning of a "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.
+ and as a side effect left the merge summary message in the log, but
+ when rebasing there is no need for the 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.
+ * A call to xread() was used without a loop around it to cope with short
+ reads 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
+ * "git rebase -i" forgot that the comment character is
configurable while reading its insn sheet.
(merge 7bca7af es/rebase-i-respect-core-commentchar later to maint).
@@ -348,8 +418,8 @@ details).
* 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.
+ broken 64-bit systems that refuse to read or write more than 2GB
+ in one go.
(merge a487916 sp/clip-read-write-to-8mb later to maint).
* "git fetch" that auto-followed tags incorrectly reused the
@@ -363,17 +433,17 @@ details).
had a similar problem.
(merge 838f9a1 tr/log-full-diff-keep-true-parents later to maint).
- * Setting submodule.*.path configuration variable to true (without
+ * Setting a 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.
+ generic) fed a random, data dependent string to 'echo' and
+ expected 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
+ grok some constructs like 'printf -v varname' which the prompt and
completion code started to use recently.
(merge a44aa69 bc/completion-for-bash-3.0 later to maint).
diff --git a/Documentation/RelNotes/1.9.0.txt b/Documentation/RelNotes/1.9.0.txt
new file mode 100644
index 0000000..752d791
--- /dev/null
+++ b/Documentation/RelNotes/1.9.0.txt
@@ -0,0 +1,345 @@
+Git v1.9.0 Release Notes
+========================
+
+Backward compatibility notes
+----------------------------
+
+"git submodule foreach $cmd $args" used to treat "$cmd $args" the same
+way "ssh" did, concatenating them into a single string and letting the
+shell unquote. Careless users who forget to sufficiently quote $args
+get their argument split at $IFS whitespaces by the shell, and got
+unexpected results due to this. Starting from this release, the
+command line is passed directly to the shell, if it has an argument.
+
+Read-only support for experimental loose-object format, in which users
+could optionally choose to write their loose objects for a short
+while between v1.4.3 and v1.5.3 era, has been dropped.
+
+The meanings of the "--tags" option to "git fetch" has changed; the
+command fetches tags _in addition to_ what is fetched by the same
+command line without the option.
+
+The way "git push $there $what" interprets the $what part given on the
+command line, when it does not have a colon that explicitly tells us
+what ref at the $there repository is to be updated, has been enhanced.
+
+A handful of ancient commands that have long been deprecated are
+finally gone (repo-config, tar-tree, lost-found, and peek-remote).
+
+
+Backward compatibility notes (for Git 2.0.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, which 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.
+
+The default prefix for "git svn" will change in Git 2.0. For a long
+time, "git svn" created its remote-tracking branches directly under
+refs/remotes, but it will place them under refs/remotes/origin/ unless
+it is told otherwise with its --prefix option.
+
+
+Updates since v1.8.5
+--------------------
+
+Foreign interfaces, subsystems and ports.
+
+ * The HTTP transport, when talking GSS-Negotiate, uses "100
+ Continue" response to avoid having to rewind and resend a large
+ payload, which may not be always doable.
+
+ * Various bugfixes to remote-bzr and remote-hg (in contrib/).
+
+ * The build procedure is aware of MirBSD now.
+
+ * Various "git p4", "git svn" and "gitk" updates.
+
+
+UI, Workflows & Features
+
+ * Fetching from a shallowly-cloned repository used to be forbidden,
+ primarily because the codepaths involved were not carefully vetted
+ and we did not bother supporting such usage. This release attempts
+ to allow object transfer out of a shallowly-cloned repository in a
+ more controlled way (i.e. the receiver becomes a shallow repository
+ with a truncated history).
+
+ * Just like we give a reasonable default for "less" via the LESS
+ environment variable, we now specify a reasonable default for "lv"
+ via the "LV" environment variable when spawning the pager.
+
+ * Two-level configuration variable names in "branch.*" and "remote.*"
+ hierarchies, whose variables are predominantly three-level, were
+ not completed by hitting a <TAB> in bash and zsh completions.
+
+ * Fetching a 'frotz' branch with "git fetch", while a 'frotz/nitfol'
+ remote-tracking branch from an earlier fetch was still there, would
+ error out, primarily because the command was not told that it is
+ allowed to lose any information on our side. "git fetch --prune"
+ now can be used to remove 'frotz/nitfol' to make room for fetching and
+ storing the 'frotz' remote-tracking branch.
+
+ * "diff.orderfile=<file>" configuration variable can be used to
+ pretend as if the "-O<file>" option were given from the command
+ line of "git diff", etc.
+
+ * The negative pathspec syntax allows "git log -- . ':!dir'" to tell
+ us "I am interested in everything but 'dir' directory".
+
+ * "git difftool" shows how many different paths there are in total,
+ and how many of them have been shown so far, to indicate progress.
+
+ * "git push origin master" used to push our 'master' branch to update
+ the 'master' branch at the 'origin' repository. This has been
+ enhanced to use the same ref mapping "git push origin" would use to
+ determine what ref at the 'origin' to be updated with our 'master'.
+ For example, with this configuration
+
+ [remote "origin"]
+ push = refs/heads/*:refs/review/*
+
+ that would cause "git push origin" to push out our local branches
+ to corresponding refs under refs/review/ hierarchy at 'origin',
+ "git push origin master" would update 'refs/review/master' over
+ there. Alternatively, if push.default is set to 'upstream' and our
+ 'master' is set to integrate with 'topic' from the 'origin' branch,
+ running "git push origin" while on our 'master' would update their
+ 'topic' branch, and running "git push origin master" while on any
+ of our branches does the same.
+
+ * "gitweb" learned to treat ref hierarchies other than refs/heads as
+ if they are additional branch namespaces (e.g. refs/changes/ in
+ Gerrit).
+
+ * "git for-each-ref --format=..." learned a few formatting directives;
+ e.g. "%(color:red)%(HEAD)%(color:reset) %(refname:short) %(subject)".
+
+ * The command string given to "git submodule foreach" is passed
+ directly to the shell, without being eval'ed. This is a backward
+ incompatible change that may break existing users.
+
+ * "git log" and friends learned the "--exclude=<glob>" option, to
+ allow people to say "list history of all branches except those that
+ match this pattern" with "git log --exclude='*/*' --branches".
+
+ * "git rev-parse --parseopt" learned a new "--stuck-long" option to
+ help scripts parse options with an optional parameter.
+
+ * The "--tags" option to "git fetch" no longer tells the command to
+ fetch _only_ the tags. It instead fetches tags _in addition to_
+ what are fetched by the same command line without the option.
+
+
+Performance, Internal Implementation, etc.
+
+ * When parsing a 40-hex string into the object name, the string is
+ checked to see if it can be interpreted as a ref so that a warning
+ can be given for ambiguity. The code kicked in even when the
+ core.warnambiguousrefs is set to false to squelch this warning, in
+ which case the cycles spent to look at the ref namespace were an
+ expensive no-op, as the result was discarded without being used.
+
+ * The naming convention of the packfiles has been updated; it used to
+ be based on the enumeration of names of the objects that are
+ contained in the pack, but now it also depends on how the packed
+ result is represented---packing the same set of objects using
+ different settings (or delta order) would produce a pack with
+ different name.
+
+ * "git diff --no-index" mode used to unnecessarily attempt to read
+ the index when there is one.
+
+ * The deprecated parse-options macro OPT_BOOLEAN has been removed;
+ use OPT_BOOL or OPT_COUNTUP in new code.
+
+ * A few duplicate implementations of prefix/suffix string comparison
+ functions have been unified to starts_with() and ends_with().
+
+ * The new PERLLIB_EXTRA makefile variable can be used to specify
+ additional directories Perl modules (e.g. the ones necessary to run
+ git-svn) are installed on the platform when building.
+
+ * "git merge-base" learned the "--fork-point" mode, that implements
+ the same logic used in "git pull --rebase" to find a suitable fork
+ point out of the reflog entries for the remote-tracking branch the
+ work has been based on. "git rebase" has the same logic that can be
+ triggered with the "--fork-point" option.
+
+ * A third-party "receive-pack" (the responder to "git push") can
+ advertise the "no-thin" capability to tell "git push" not to use
+ the thin-pack optimization. Our receive-pack has always been
+ capable of accepting and fattening a thin-pack, and will continue
+ not to ask "git push" to use a non-thin pack.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.5
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.5 in the maintenance
+track are contained in this release (see the maintenance releases' notes
+for details).
+
+ * The pathspec matching code, while comparing two trees (e.g. "git
+ diff A B -- path1 path2") was too aggressive and failed to match
+ some paths when multiple pathspecs were involved.
+
+ * "git repack --max-pack-size=8g" stopped being parsed correctly when
+ the command was reimplemented in C.
+
+ * An earlier update in v1.8.4.x to "git rev-list --objects" with
+ negative ref had a performance regression.
+ (merge 200abe7 jk/mark-edges-uninteresting later to maint).
+
+ * A recent update to "git send-email" broke platforms where
+ /etc/ssl/certs/ directory exists but cannot be used as SSL_ca_path
+ (e.g. Fedora rawhide).
+
+ * A handful of bugs around interpreting $branch@{upstream} notation
+ and its lookalike, when $branch part has interesting characters,
+ e.g. "@", and ":", have been fixed.
+
+ * "git clone" would fail to clone from a repository that has a ref
+ directly under "refs/", e.g. "refs/stash", because different
+ validation paths do different things on such a refname. Loosen the
+ client side's validation to allow such a ref.
+
+ * "git log --left-right A...B" lost the "leftness" of commits
+ reachable from A when A is a tag as a side effect of a recent
+ bugfix. This is a regression in 1.8.4.x series.
+
+ * documentations to "git pull" hinted there is an "-m" option because
+ it incorrectly shared the documentation with "git merge".
+
+ * "git diff A B submod" and "git diff A B submod/" ought to have done
+ the same for a submodule "submod", but didn't.
+
+ * "git clone $origin foo\bar\baz" on Windows failed to create the
+ leading directories (i.e. a moral-equivalent of "mkdir -p").
+
+ * "submodule.*.update=checkout", when propagated from .gitmodules to
+ .git/config, turned into a "submodule.*.update=none", which did not
+ make much sense.
+ (merge efa8fd7 fp/submodule-checkout-mode later to maint).
+
+ * The implementation of 'git stash $cmd "stash@{...}"' did not quote
+ the stash argument properly and left it split at IFS whitespace.
+
+ * The "--[no-]informative-errors" options to "git daemon" were parsed
+ a bit too loosely, allowing any other string after these option
+ names.
+
+ * There is no reason to have a hardcoded upper limit for the number of
+ parents of an octopus merge, created via the graft mechanism, but
+ there was.
+
+ * The basic test used to leave unnecessary trash directories in the
+ t/ directory.
+ (merge 738a8be jk/test-framework-updates later to maint).
+
+ * "git merge-base --octopus" used to leave cleaning up suboptimal
+ result to the caller, but now it does the clean-up itself.
+
+ * A "gc" process running as a different user should be able to stop a
+ new "gc" process from starting, but it didn't.
+
+ * An earlier "clean-up" introduced an unnecessary memory leak.
+
+ * "git add -A" (no other arguments) in a totally empty working tree
+ used to emit an error.
+
+ * "git log --decorate" did not handle a tag pointed by another tag
+ nicely.
+
+ * When we figure out how many file descriptors to allocate for
+ keeping packfiles open, a system with non-working getrlimit() could
+ cause us to die(), but because we make this call only to get a
+ rough estimate of how many are available and we do not even attempt
+ to use up all available file descriptors ourselves, it is nicer to
+ fall back to a reasonable low value rather than dying.
+
+ * read_sha1_file(), that is the workhorse to read the contents given
+ an object name, honoured object replacements, but there was no
+ corresponding mechanism to sha1_object_info() that was used to
+ obtain the metainfo (e.g. type & size) about the object. This led
+ callers to weird inconsistencies.
+ (merge 663a856 cc/replace-object-info later to maint).
+
+ * "git cat-file --batch=", an admittedly useless command, did not
+ behave very well.
+
+ * "git rev-parse <revs> -- <paths>" did not implement the usual
+ disambiguation rules the commands in the "git log" family used in
+ the same way.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+ out, but it didn't.
+
+ * A workaround to an old bug in glibc prior to glibc 2.17 has been
+ retired; this would remove a side effect of the workaround that
+ corrupts system error messages in non-C locales.
+
+ * SSL-related options were not passed correctly to underlying socket
+ layer in "git send-email".
+
+ * "git commit -v" appends the patch to the log message before
+ editing, and then removes the patch when the editor returned
+ control. However, the patch was not stripped correctly when the
+ first modified path was a submodule.
+
+ * "git fetch --depth=0" was a no-op, and was silently ignored.
+ Diagnose it as an error.
+
+ * Remote repository URLs expressed in scp-style host:path notation are
+ parsed more carefully (e.g. "foo/bar:baz" is local, "[::1]:/~user" asks
+ to connect to user's home directory on host at address ::1.
+
+ * "git diff -- ':(icase)makefile'" was unnecessarily rejected at the
+ command line parser.
+
+ * "git cat-file --batch-check=ok" did not check the existence of
+ the named object.
+
+ * "git am --abort" sometimes complained about not being able to write
+ a tree with an 0{40} object in it.
+
+ * Two processes creating loose objects at the same time could have
+ failed unnecessarily when the name of their new objects started
+ with the same byte value, due to a race condition.
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 7055576..e6d46ed 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -139,8 +139,15 @@ People on the Git mailing list need to be able to read and
comment on the changes you are submitting. It is important for
a developer to be able to "quote" your changes, using standard
e-mail tools, so that they may comment on specific portions of
-your code. For this reason, all patches should be submitted
-"inline". If your log message (including your name on the
+your code. For this reason, each patch should be submitted
+"inline" in a separate message.
+
+Multiple related patches should be grouped into their own e-mail
+thread to help readers find all parts of the series. To that end,
+send them as replies to either an additional "cover letter" message
+(see below), the first patch, or the respective preceding patch.
+
+If your log message (including your name on the
Signed-off-by line) is not writable in ASCII, make sure that
you send off a message in the correct encoding.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 499a3c4..040197b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -567,6 +567,10 @@ be passed to the shell by Git, which will translate the final
command to `LESS=FRSX less -+S`. The environment tells the command
to set the `S` option to chop long lines but the command line
resets it to the default to fold long lines.
++
+Likewise, when the `LV` environment variable is unset, Git sets it
+to `-c`. You can override this setting by exporting `LV` with
+another value or setting `core.pager` to `lv +c`.
core.whitespace::
A comma separated list of common whitespace problems to
@@ -988,6 +992,14 @@ commit.cleanup::
have to remove the help lines that begin with `#` in the commit log
template yourself, if you do this).
+commit.gpgsign::
+
+ A boolean to specify whether all commits should be GPG signed.
+ Use of this option when doing operations such as rebase can
+ result in a large number of commits being signed. It may be
+ convenient to use an agent to avoid typing your GPG passphrase
+ several times.
+
commit.status::
A boolean to enable/disable inclusion of status information in the
commit message template when using an editor to prepare the commit
@@ -1902,6 +1914,16 @@ pretty.<name>::
Note that an alias with the same name as a built-in format
will be silently ignored.
+pull.ff::
+ By default, Git does not create an extra merge commit when merging
+ a commit that is a descendant of the current commit. Instead, the
+ tip of the current branch is fast-forwarded. When set to `false`,
+ this variable tells Git to create an extra merge commit in such
+ a case (equivalent to giving the `--no-ff` option from the command
+ line). When set to `only`, only such fast-forward merges are
+ allowed (equivalent to giving the `--ff-only` option from the
+ command line).
+
pull.rebase::
When true, rebase branches on top of the fetched branch, instead
of merging the default branch from the default remote when "git
@@ -2051,6 +2073,10 @@ receive.updateserverinfo::
If set to true, git-receive-pack will run git-update-server-info
after receiving data from git-push and updating refs.
+receive.shallowupdate::
+ If set to true, .git/shallow can be updated when new refs
+ require new shallow roots. Otherwise those refs are rejected.
+
remote.pushdefault::
The remote to push to by default. Overrides
`branch.<name>.remote` for all branches, and is overridden by
@@ -2112,8 +2138,8 @@ remote.<name>.vcs::
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).
+ remove any remote-tracking references that no longer exist on the
+ remote (as if the `--prune` option was given on the command line).
Overrides `fetch.prune` settings, if any.
remotes.<group>::
diff --git a/Documentation/date-formats.txt b/Documentation/date-formats.txt
index c000f08..ccd1fc8 100644
--- a/Documentation/date-formats.txt
+++ b/Documentation/date-formats.txt
@@ -8,9 +8,9 @@ endif::git-commit[]
support the following date formats:
Git internal format::
- It is `<unix timestamp> <timezone offset>`, where `<unix
+ It is `<unix timestamp> <time zone offset>`, where `<unix
timestamp>` is the number of seconds since the UNIX epoch.
- `<timezone offset>` is a positive or negative offset from UTC.
+ `<time zone offset>` is a positive or negative offset from UTC.
For example CET (which is 2 hours ahead UTC) is `+0200`.
RFC 2822::
diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt
index 223b931..f07b451 100644
--- a/Documentation/diff-config.txt
+++ b/Documentation/diff-config.txt
@@ -98,6 +98,11 @@ diff.mnemonicprefix::
diff.noprefix::
If set, 'git diff' does not show any source or destination prefix.
+diff.orderfile::
+ File indicating how to order files within a diff, using
+ one shell glob pattern per line.
+ Can be overridden by the '-O' option to linkgit:git-diff[1].
+
diff.renameLimit::
The number of files to consider when performing the copy/rename
detection; equivalent to the 'git diff' option '-l'.
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index bbed2cd..9b37b2a 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -432,6 +432,9 @@ endif::git-format-patch[]
-O<orderfile>::
Output the patch in the order specified in the
<orderfile>, which has one shell glob pattern per line.
+ This overrides the `diff.orderfile` configuration variable
+ (see linkgit:git-config[1]). To cancel `diff.orderfile`,
+ use `-O/dev/null`.
ifndef::git-format-patch[]
-R::
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index ba1fe49..92c68c3 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -14,8 +14,18 @@
branch history. Tags for the deepened commits are not fetched.
--unshallow::
- Convert a shallow repository to a complete one, removing all
- the limitations imposed by shallow repositories.
+ If the source repository is complete, convert a shallow
+ repository to a complete one, removing all the limitations
+ imposed by shallow repositories.
++
+If the source repository is shallow, fetch as much as possible so that
+the current repository has the same history as the source repository.
+
+--update-shallow::
+ By default when fetching from a shallow repository,
+ `git fetch` refuses refs that require updating
+ .git/shallow. This option updates .git/shallow and accept such
+ refs.
ifndef::git-pull[]
--dry-run::
@@ -41,17 +51,20 @@ ifndef::git-pull[]
-p::
--prune::
- After fetching, remove any remote-tracking branches which
- no longer exist on the remote.
+ After fetching, remove any remote-tracking references that no
+ longer exist on the remote. Tags are not subject to pruning
+ if they are fetched only because of the default tag
+ auto-following or due to a --tags option. However, if tags
+ are fetched due to an explicit refspec (either on the command
+ line or in the remote configuration, for example if the remote
+ was cloned with the --mirror option), then they are also
+ subject to pruning.
endif::git-pull[]
-ifdef::git-pull[]
---no-tags::
-endif::git-pull[]
ifndef::git-pull[]
-n::
---no-tags::
endif::git-pull[]
+--no-tags::
By default, tags that point at objects that are downloaded
from the remote repository are fetched and stored locally.
This option disables this automatic tag following. The default
@@ -61,11 +74,12 @@ endif::git-pull[]
ifndef::git-pull[]
-t::
--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
- remote.$name.fetch variable) are overridden and not used.
+ Fetch all tags from the remote (i.e., fetch remote tags
+ `refs/tags/*` into local tags with the same name), in addition
+ to whatever else would otherwise be fetched. Using this
+ option alone does not subject tags to pruning, even if --prune
+ is used (though tags may be pruned anyway if they are also the
+ destination of an explicit refspec; see '--prune').
--recurse-submodules[=yes|on-demand|no]::
This option controls if and under what conditions new commits of
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 54d8461..17924d0 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -14,7 +14,7 @@ SYNOPSIS
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
[--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
- [--[no-]scissors]
+ [--[no-]scissors] [-S[<keyid>]]
[(<mbox> | <Maildir>)...]
'git am' (--continue | --skip | --abort)
@@ -119,6 +119,10 @@ default. You can use `--no-utf8` to override this.
Skip the current patch. This is only meaningful when
restarting an aborted patch.
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign commits.
+
--continue::
-r::
--resolved::
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index f2c85cc..9f23a86 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -35,7 +35,8 @@ Apart from supporting file annotation, Git also supports searching the
development history for when a code snippet occurred in a change. This makes it
possible to track when a code snippet was added to a file, moved or copied
between files, and eventually deleted or replaced. It works by searching for
-a text string in the diff. A small example:
+a text string in the diff. A small example of the pickaxe interface
+that searches for `blame_usage`:
-----------------------------------------------------------------------------
$ git log --pretty=oneline -S'blame_usage'
@@ -103,7 +104,7 @@ This header line is followed by the following information
at least once for each commit:
- the author name ("author"), email ("author-mail"), time
- ("author-time"), and timezone ("author-tz"); similarly
+ ("author-time"), and time zone ("author-tz"); similarly
for committer.
- the filename in the commit that the line is attributed to.
- the first line of the commit log message ("summary").
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 322f5ed..f6a16f4 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -109,6 +109,11 @@ newline. The available atoms are:
The size, in bytes, that the object takes up on disk. See the
note about on-disk sizes in the `CAVEATS` section below.
+`deltabase`::
+ If the object is stored as a delta on-disk, this expands to the
+ 40-hex sha1 of the delta base object. Otherwise, expands to the
+ null sha1 (40 zeroes). See `CAVEATS` below.
+
`rest`::
If this atom is used in the output string, input lines are split
at the first whitespace boundary. All characters before that
@@ -152,10 +157,11 @@ 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.
+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 or delta base
+will be reported.
GIT
---
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 91294f8..33ad2ad 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -232,8 +232,8 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
commit, your HEAD becomes "detached" and you are no longer on
any branch (see below for details).
+
-As a special case, the `"@{-N}"` syntax for the N-th last branch
-checks out the branch (instead of detaching). You may also specify
+As a special case, the `"@{-N}"` syntax for the N-th last branch/commit
+checks out branches (instead of detaching). You may also specify
`-` which is synonymous with `"@{-1}"`.
+
As a further special case, you may use `"A...B"` as a shortcut for the
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index c205d23..f1e6b2f 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -8,7 +8,8 @@ git-cherry-pick - Apply the changes introduced by some existing commits
SYNOPSIS
--------
[verse]
-'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>...
+'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
+ [-S[<keyid>]] <commit>...
'git cherry-pick' --continue
'git cherry-pick' --quit
'git cherry-pick' --abort
@@ -100,6 +101,10 @@ effect to your index in a row.
--signoff::
Add Signed-off-by line at the end of the commit message.
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign commits.
+
--ff::
If the current HEAD is the same as the parent of the
cherry-pick'ed commit, then a fast forward to this commit will
diff --git a/Documentation/git-cherry.txt b/Documentation/git-cherry.txt
index 2d0daae..0ea921a 100644
--- a/Documentation/git-cherry.txt
+++ b/Documentation/git-cherry.txt
@@ -3,7 +3,7 @@ git-cherry(1)
NAME
----
-git-cherry - Find commits not merged upstream
+git-cherry - Find commits yet to be applied to upstream
SYNOPSIS
--------
@@ -12,46 +12,26 @@ SYNOPSIS
DESCRIPTION
-----------
-The changeset (or "diff") of each commit between the fork-point and <head>
-is compared against each commit between the fork-point and <upstream>.
-The diffs are compared after removing any whitespace and line numbers.
+Determine whether there are commits in `<head>..<upstream>` that are
+equivalent to those in the range `<limit>..<head>`.
-Every commit that doesn't exist in the <upstream> branch
-has its id (sha1) reported, prefixed by a symbol. The ones that have
-equivalent change already
-in the <upstream> branch are prefixed with a minus (-) sign, and those
-that only exist in the <head> branch are prefixed with a plus (+) symbol:
-
- __*__*__*__*__> <upstream>
- /
- fork-point
- \__+__+__-__+__+__-__+__> <head>
-
-
-If a <limit> has been given then the commits along the <head> branch up
-to and including <limit> are not reported:
-
- __*__*__*__*__> <upstream>
- /
- fork-point
- \__*__*__<limit>__-__+__> <head>
-
-
-Because 'git cherry' compares the changeset rather than the commit id
-(sha1), you can use 'git cherry' to find out if a commit you made locally
-has been applied <upstream> under a different commit id. For example,
-this will happen if you're feeding patches <upstream> via email rather
-than pushing or pulling commits directly.
+The equivalence test is based on the diff, after removing whitespace
+and line numbers. git-cherry therefore detects when commits have been
+"copied" by means of linkgit:git-cherry-pick[1], linkgit:git-am[1] or
+linkgit:git-rebase[1].
+Outputs the SHA1 of every commit in `<limit>..<head>`, prefixed with
+`-` for commits that have an equivalent in <upstream>, and `+` for
+commits that do not.
OPTIONS
-------
-v::
- Verbose.
+ Show the commit subjects next to the SHA1s.
<upstream>::
- Upstream branch to compare against.
- Defaults to the first tracked remote branch, if available.
+ Upstream branch to search for equivalent commits.
+ Defaults to the upstream branch of HEAD.
<head>::
Working branch; defaults to HEAD.
@@ -59,6 +39,103 @@ OPTIONS
<limit>::
Do not report commits up to (and including) limit.
+EXAMPLES
+--------
+
+Patch workflows
+~~~~~~~~~~~~~~~
+
+git-cherry is frequently used in patch-based workflows (see
+linkgit:gitworkflows[7]) to determine if a series of patches has been
+applied by the upstream maintainer. In such a workflow you might
+create and send a topic branch like this:
+
+------------
+$ git checkout -b topic origin/master
+# work and create some commits
+$ git format-patch origin/master
+$ git send-email ... 00*
+------------
+
+Later, you can see whether your changes have been applied by saying
+(still on `topic`):
+
+------------
+$ git fetch # update your notion of origin/master
+$ git cherry -v
+------------
+
+Concrete example
+~~~~~~~~~~~~~~~~
+
+In a situation where topic consisted of three commits, and the
+maintainer applied two of them, the situation might look like:
+
+------------
+$ git log --graph --oneline --decorate --boundary origin/master...topic
+* 7654321 (origin/master) upstream tip commit
+[... snip some other commits ...]
+* cccc111 cherry-pick of C
+* aaaa111 cherry-pick of A
+[... snip a lot more that has happened ...]
+| * cccc000 (topic) commit C
+| * bbbb000 commit B
+| * aaaa000 commit A
+|/
+o 1234567 branch point
+------------
+
+In such cases, git-cherry shows a concise summary of what has yet to
+be applied:
+
+------------
+$ git cherry origin/master topic
+- cccc000... commit C
++ bbbb000... commit B
+- aaaa000... commit A
+------------
+
+Here, we see that the commits A and C (marked with `-`) can be
+dropped from your `topic` branch when you rebase it on top of
+`origin/master`, while the commit B (marked with `+`) still needs to
+be kept so that it will be sent to be applied to `origin/master`.
+
+
+Using a limit
+~~~~~~~~~~~~~
+
+The optional <limit> is useful in cases where your topic is based on
+other work that is not in upstream. Expanding on the previous
+example, this might look like:
+
+------------
+$ git log --graph --oneline --decorate --boundary origin/master...topic
+* 7654321 (origin/master) upstream tip commit
+[... snip some other commits ...]
+* cccc111 cherry-pick of C
+* aaaa111 cherry-pick of A
+[... snip a lot more that has happened ...]
+| * cccc000 (topic) commit C
+| * bbbb000 commit B
+| * aaaa000 commit A
+| * 0000fff (base) unpublished stuff F
+[... snip ...]
+| * 0000aaa unpublished stuff A
+|/
+o 1234567 merge-base between upstream and topic
+------------
+
+By specifying `base` as the limit, you can avoid listing commits
+between `base` and `topic`:
+
+------------
+$ git cherry origin/master topic base
+- cccc000... commit C
++ bbbb000... commit B
+- aaaa000... commit A
+------------
+
+
SEE ALSO
--------
linkgit:git-patch-id[1]
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 450f158..0363d00 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -55,15 +55,12 @@ repository is specified as a URL, then this flag is ignored (and we
never use the local optimizations). Specifying `--no-local` will
override the default when `/path/to/repo` is given, using the regular
Git transport instead.
-+
-To force copying instead of hardlinking (which may be desirable if you
-are trying to make a back-up of your repository), but still avoid the
-usual "Git aware" transport mechanism, `--no-hardlinks` can be used.
--no-hardlinks::
- Optimize the cloning process from a repository on a
- local filesystem by copying files under `.git/objects`
- directory.
+ Force the cloning process from a repository on a local
+ filesystem to copy the files under the `.git/objects`
+ directory instead of using hardlinks. This may be desirable
+ if you are trying to make a back-up of your repository.
--shared::
-s::
@@ -181,12 +178,7 @@ objects from the source repository into a pack in the cloned repository.
--depth <depth>::
Create a 'shallow' clone with a history truncated to the
- specified number of revisions. A shallow repository has a
- number of limitations (you cannot clone or fetch from
- it, nor push from nor into it), but is adequate if you
- are only interested in the recent history of a large project
- with a long history, and would want to send in fixes
- as patches.
+ specified number of revisions.
--[no-]single-branch::
Clone only the history leading to the tip of a single branch,
@@ -213,7 +205,7 @@ objects from the source repository into a pack in the cloned repository.
--separate-git-dir=<git dir>::
Instead of placing the cloned repository where it is supposed
to be, place the cloned repository at the specified directory,
- then make a filesytem-agnostic Git symbolic link to there.
+ then make a filesystem-agnostic Git symbolic link to there.
The result is Git repository can be separated from working
tree.
diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
index 5d6f1cc..03d1846 100644
--- a/Documentation/git-column.txt
+++ b/Documentation/git-column.txt
@@ -43,11 +43,6 @@ OPTIONS
--padding=<N>::
The number of spaces between columns. One space by default.
-
-Author
-------
-Written by Nguyen Thai Ngoc Duy <pclouds@gmail.com>
-
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index cafdc96..a469eab 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -55,8 +55,13 @@ OPTIONS
from the standard input.
-S[<keyid>]::
+--gpg-sign[=<keyid>]::
GPG-sign commit.
+--no-gpg-sign::
+ Countermand `commit.gpgsign` configuration variable that is
+ set to force each and every commit to be signed.
+
Commit Information
------------------
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 1a7616c..7c42e9c 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -302,6 +302,10 @@ configuration variable documented in linkgit:git-config[1].
--gpg-sign[=<keyid>]::
GPG-sign commit.
+--no-gpg-sign::
+ Countermand `commit.gpgsign` configuration variable that is
+ set to force each and every commit to be signed.
+
\--::
Do not interpret any more arguments as options.
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt
index d1bcda2..2df9953 100644
--- a/Documentation/git-cvsimport.txt
+++ b/Documentation/git-cvsimport.txt
@@ -144,7 +144,7 @@ This option can be used several times to provide several detection regexes.
CVS by default uses the Unix username when writing its
commit logs. Using this option and an author-conv-file
maps the name recorded in CVS to author name, e-mail and
- optional timezone:
+ optional time zone:
+
---------
exon=Andreas Ericsson <ae@op5.se>
@@ -154,7 +154,7 @@ This option can be used several times to provide several detection regexes.
+
'git cvsimport' will make it appear as those authors had
their GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL set properly
-all along. If a timezone is specified, GIT_AUTHOR_DATE will
+all along. If a time zone is specified, GIT_AUTHOR_DATE will
have the corresponding offset applied.
+
For convenience, this data is saved to `$GIT_DIR/cvs-authors`
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 33fbd8c..56fb7e5 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -44,7 +44,7 @@ two blob objects, or changes between two files on disk.
commit relative to the named <commit>. Typically you
would want comparison with the latest commit, so if you
do not give <commit>, it defaults to HEAD.
- If HEAD does not exist (e.g. unborned branches) and
+ If HEAD does not exist (e.g. unborn branches) and
<commit> is not given, it shows all staged changes.
--staged is a synonym of --cached.
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 73f9806..fd22a9a 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -251,7 +251,7 @@ advisement to help formatting routines display the timestamp.
If the local offset is not available in the source material, use
``+0000'', or the most common local offset. For example many
organizations have a CVS repository which has only ever been accessed
-by users who are located in the same location and timezone. In this
+by users who are located in the same location and time zone. In this
case a reasonable offset from UTC could be assumed.
+
Unlike the `rfc2822` format, this format is very strict. Any
@@ -271,7 +271,7 @@ the malformed string. There are also some types of malformed
strings which Git will parse wrong, and yet consider valid.
Seriously malformed strings will be rejected.
+
-Unlike the `raw` format above, the timezone/UTC offset information
+Unlike the `raw` format above, the time zone/UTC offset information
contained in an RFC 2822 date string is used to adjust the date
value to UTC prior to storage. Therefore it is important that
this information be as accurate as possible.
@@ -287,13 +287,13 @@ format, or its format is easily convertible to it, as there is no
ambiguity in parsing.
`now`::
- Always use the current time and timezone. The literal
+ Always use the current time and time zone. The literal
`now` must always be supplied for `<when>`.
+
-This is a toy format. The current time and timezone of this system
+This is a toy format. The current time and time zone of this system
is always copied into the identity string at the time it is being
created by fast-import. There is no way to specify a different time or
-timezone.
+time zone.
+
This particular format is supplied as it's short to implement and
may be useful to a process that wants to create a new commit
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index 444b805..93b5067 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -12,7 +12,7 @@ SYNOPSIS
'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag]
[--upload-pack=<git-upload-pack>]
[--depth=<n>] [--no-progress]
- [-v] [<host>:]<directory> [<refs>...]
+ [-v] <repository> [<refs>...]
DESCRIPTION
-----------
@@ -97,19 +97,18 @@ be in a separate packet, and the list must end with a flush packet.
-v::
Run verbosely.
-<host>::
- A remote host that houses the repository. When this
- part is specified, 'git-upload-pack' is invoked via
- ssh.
-
-<directory>::
- The repository to sync from.
+<repository>::
+ The URL to the remote repository.
<refs>...::
The remote heads to update from. This is relative to
$GIT_DIR (e.g. "HEAD", "refs/heads/master"). When
unspecified, update from all heads the remote side has.
+SEE ALSO
+--------
+linkgit:git-fetch[1]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index e08a028..5809aa4 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -24,19 +24,22 @@ The ref names and their object names of fetched refs are stored
in `.git/FETCH_HEAD`. This information is left for a later merge
operation done by 'git merge'.
-When <refspec> stores the fetched result in remote-tracking branches,
-the tags that point at these branches are automatically
-followed. This is done by first fetching from the remote using
-the given <refspec>s, and if the repository has objects that are
-pointed by remote tags that it does not yet have, then fetch
-those missing tags. If the other end has tags that point at
-branches you are not interested in, you will not get them.
+By default, tags are auto-followed. This means that when fetching
+from a remote, any tags on the remote that point to objects that exist
+in the local repository are fetched. The effect is to fetch tags that
+point at branches that you are interested in. This default behavior
+can be changed by using the --tags or --no-tags options, by
+configuring remote.<name>.tagopt, or by using a refspec that fetches
+tags explicitly.
'git fetch' can fetch from either a single named repository,
or from several repositories at once if <group> is given and
there is a remotes.<group> entry in the configuration file.
(See linkgit:git-config[1]).
+When no remote is specified, by default the `origin` remote will be used,
+unless there's an upstream branch configured for the current branch.
+
OPTIONS
-------
include::fetch-options.txt[]
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index e4c8e82..2eba627 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -393,7 +393,7 @@ git filter-branch --index-filter \
Checklist for Shrinking a Repository
------------------------------------
-git-filter-branch is often used to get rid of a subset of files,
+git-filter-branch can be used to get rid of a subset of files,
usually with some combination of `--index-filter` and
`--subdirectory-filter`. People expect the resulting repository to
be smaller than the original, but you need a few more steps to
@@ -429,6 +429,37 @@ warned.
(or if your git-gc is not new enough to support arguments to
`--prune`, use `git repack -ad; git prune` instead).
+Notes
+-----
+
+git-filter-branch allows you to make complex shell-scripted rewrites
+of your Git history, but you probably don't need this flexibility if
+you're simply _removing unwanted data_ like large files or passwords.
+For those operations you may want to consider
+link:http://rtyley.github.io/bfg-repo-cleaner/[The BFG Repo-Cleaner],
+a JVM-based alternative to git-filter-branch, typically at least
+10-50x faster for those use-cases, and with quite different
+characteristics:
+
+* Any particular version of a file is cleaned exactly _once_. The BFG,
+ unlike git-filter-branch, does not give you the opportunity to
+ handle a file differently based on where or when it was committed
+ within your history. This constraint gives the core performance
+ benefit of The BFG, and is well-suited to the task of cleansing bad
+ data - you don't care _where_ the bad data is, you just want it
+ _gone_.
+
+* By default The BFG takes full advantage of multi-core machines,
+ cleansing commit file-trees in parallel. git-filter-branch cleans
+ commits sequentially (ie in a single-threaded manner), though it
+ _is_ possible to write filters that include their own parallellism,
+ in the scripts executed against each commit.
+
+* The link:http://rtyley.github.io/bfg-repo-cleaner/#examples[command options]
+ are much more restrictive than git-filter branch, and dedicated just
+ to the tasks of removing unwanted data- e.g:
+ `--strip-blobs-bigger-than 1M`.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index f2e08d1..4240875 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -91,7 +91,19 @@ objectname::
upstream::
The name of a local ref which can be considered ``upstream''
from the displayed ref. Respects `:short` in the same way as
- `refname` above.
+ `refname` above. Additionally respects `:track` to show
+ "[ahead N, behind M]" and `:trackshort` to show the terse
+ version: ">" (ahead), "<" (behind), "<>" (ahead and behind),
+ or "=" (in sync). Has no effect if the ref does not have
+ tracking information associated with it.
+
+HEAD::
+ '*' if HEAD matches current ref (the checked out branch), ' '
+ otherwise.
+
+color::
+ Change output color. Followed by `:<colorname>`, where names
+ are described in `color.branch.*`.
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
@@ -207,13 +219,9 @@ eval=`git for-each-ref --shell --format="$fmt" \
eval "$eval"
------------
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>.
-
-Documentation
--------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
+SEE ALSO
+--------
+linkgit:git-show-ref[1]
GIT
---
diff --git a/Documentation/git-http-backend.txt b/Documentation/git-http-backend.txt
index e3bcdb5..e8c13f6 100644
--- a/Documentation/git-http-backend.txt
+++ b/Documentation/git-http-backend.txt
@@ -263,14 +263,6 @@ identifying information of the remote user who performed the push.
All CGI environment variables are available to each of the hooks
invoked by the 'git-receive-pack'.
-Author
-------
-Written by Shawn O. Pearce <spearce@spearce.org>.
-
-Documentation
---------------
-Documentation by Shawn O. Pearce <spearce@spearce.org>.
-
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 34097ef..1f7bc67 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -15,9 +15,9 @@ DESCRIPTION
-----------
Shows the commit logs.
-The command takes options applicable to the 'git rev-list'
+The command takes options applicable to the `git rev-list`
command to control what is shown and how, and options applicable to
-the 'git diff-*' commands to control how the changes
+the `git diff-*` commands to control how the changes
each commit introduces are shown.
@@ -42,29 +42,27 @@ OPTIONS
--use-mailmap::
Use mailmap file to map author and committer names and email
- to canonical real names and email addresses. See
+ addresses to canonical real names and email addresses. See
linkgit:git-shortlog[1].
--full-diff::
- Without this flag, "git log -p <path>..." shows commits that
+ Without this flag, `git log -p <path>...` shows commits that
touch the specified paths, and diffs about the same specified
paths. With this, the full diff is shown for commits that touch
the specified paths; this means that "<path>..." limits only
commits, and doesn't limit diff for those commits.
+
Note that this affects all diff-based output types, e.g. those
-produced by --stat etc.
+produced by `--stat`, etc.
--log-size::
- Before the log message print out its size in bytes. Intended
- mainly for porcelain tools consumption. If Git is unable to
- produce a valid value size is set to zero.
- Note that only message is considered, if also a diff is shown
- its size is not included.
+ Include a line ``log size <number>'' in the output for each commit,
+ where <number> is the length of that commit's message in bytes.
+ Intended to speed up tools that read log messages from `git log`
+ output by allowing them to allocate space in advance.
-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
@@ -80,16 +78,16 @@ include::line-range-format.txt[]
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"
+ 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
+ that match the specified paths came to be. See 'History
+ Simplification' below for details and other simplification
modes.
+
-Paths may need to be prefixed with "\-- " to separate them from
+Paths may need to be prefixed with ``\-- '' to separate them from
options or the revision range, when confusion arises.
include::rev-list-options.txt[]
@@ -113,12 +111,12 @@ EXAMPLES
`git log v2.6.12.. include/scsi drivers/scsi`::
Show all commits since version 'v2.6.12' that changed any file
- in the include/scsi or drivers/scsi subdirectories
+ in the `include/scsi` or `drivers/scsi` subdirectories
`git log --since="2 weeks ago" -- gitk`::
Show the changes during the last two weeks to the file 'gitk'.
- The "--" is necessary to avoid confusion with the *branch* named
+ The ``--'' is necessary to avoid confusion with the *branch* named
'gitk'
`git log --name-status release..test`::
@@ -129,7 +127,7 @@ EXAMPLES
`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.
@@ -147,17 +145,18 @@ EXAMPLES
`git log -p -m --first-parent`::
Shows the history including change diffs, but only from the
- "main branch" perspective, skipping commits that come from merged
+ ``main branch'' perspective, skipping commits that come from merged
branches, and showing full diffs of changes introduced by the merges.
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
+ 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
@@ -172,12 +171,12 @@ See linkgit:git-config[1] for core variables and linkgit:git-diff[1]
for settings related to diff generation.
format.pretty::
- Default for the `--format` option. (See "PRETTY FORMATS" above.)
- Defaults to "medium".
+ Default for the `--format` option. (See 'Pretty Formats' above.)
+ Defaults to `medium`.
i18n.logOutputEncoding::
- Encoding to use when displaying logs. (See "Discussion", above.)
- Defaults to the value of `i18n.commitEncoding` if set, UTF-8
+ Encoding to use when displaying logs. (See 'Discussion' above.)
+ Defaults to the value of `i18n.commitEncoding` if set, and UTF-8
otherwise.
log.date::
@@ -186,7 +185,7 @@ log.date::
dates like `Sat May 8 19:35:34 2010 -0500`.
log.showroot::
- If `false`, 'git log' and related commands will not treat the
+ If `false`, `git log` and related commands will not treat the
initial commit as a big creation event. Any root commits in
`git log -p` output would be shown without a diff attached.
The default is `true`.
@@ -197,7 +196,7 @@ mailmap.*::
notes.displayRef::
Which refs, in addition to the default set by `core.notesRef`
or 'GIT_NOTES_REF', to read notes from when showing commit
- messages with the 'log' family of commands. See
+ messages with the `log` family of commands. See
linkgit:git-notes[1].
+
May be an unabbreviated ref name or a glob and may be specified
diff --git a/Documentation/git-lost-found.txt b/Documentation/git-lost-found.txt
deleted file mode 100644
index d549328..0000000
--- a/Documentation/git-lost-found.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-git-lost-found(1)
-=================
-
-NAME
-----
-git-lost-found - Recover lost refs that luckily have not yet been pruned
-
-SYNOPSIS
---------
-[verse]
-'git lost-found'
-
-DESCRIPTION
------------
-
-*NOTE*: this command is deprecated. Use linkgit:git-fsck[1] with
-the option '--lost-found' instead.
-
-Finds dangling commits and tags from the object database, and
-creates refs to them in the .git/lost-found/ directory. Commits and
-tags that dereference to commits are stored in .git/lost-found/commit,
-and other objects are stored in .git/lost-found/other.
-
-
-OUTPUT
-------
-Prints to standard output the object names and one-line descriptions
-of any commits or tags found.
-
-EXAMPLE
--------
-
-Suppose you run 'git tag -f' and mistype the tag to overwrite.
-The ref to your tag is overwritten, but until you run 'git
-prune', the tag itself is still there.
-
-------------
-$ git lost-found
-[1ef2b196d909eed523d4f3c9bf54b78cdd6843c6] GIT 0.99.9c
-...
-------------
-
-Also you can use gitk to browse how any tags found relate to each
-other.
-
-------------
-$ gitk $(cd .git/lost-found/commit && echo ??*)
-------------
-
-After making sure you know which the object is the tag you are looking
-for, you can reconnect it to your regular `refs` hierarchy by using
-the `update-ref` command.
-
-------------
-$ git cat-file -t 1ef2b196
-tag
-$ git cat-file tag 1ef2b196
-object fa41bbce8e38c67a218415de6cfa510c7e50032a
-type commit
-tag v0.99.9c
-tagger Junio C Hamano <junkio@cox.net> 1131059594 -0800
-
-GIT 0.99.9c
-
-This contains the following changes from the "master" branch, since
-...
-$ git update-ref refs/tags/not-lost-anymore 1ef2b196
-$ git rev-parse not-lost-anymore
-1ef2b196d909eed523d4f3c9bf54b78cdd6843c6
-------------
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt
index 87842e3..808426f 100644
--- a/Documentation/git-merge-base.txt
+++ b/Documentation/git-merge-base.txt
@@ -13,6 +13,7 @@ SYNOPSIS
'git merge-base' [-a|--all] --octopus <commit>...
'git merge-base' --is-ancestor <commit> <commit>
'git merge-base' --independent <commit>...
+'git merge-base' --fork-point <ref> [<commit>]
DESCRIPTION
-----------
@@ -24,8 +25,8 @@ that does not have any better common ancestor is a 'best common
ancestor', i.e. a 'merge base'. Note that there can be more than one
merge base for a pair of commits.
-OPERATION MODE
---------------
+OPERATION MODES
+---------------
As the most common special case, specifying only two commits on the
command line means computing the merge base between the given two commits.
@@ -56,6 +57,14 @@ from linkgit:git-show-branch[1] when used with the `--merge-base` option.
and exit with status 0 if true, or with status 1 if not.
Errors are signaled by a non-zero status that is not 1.
+--fork-point::
+ Find the point at which a branch (or any history that leads
+ to <commit>) forked from another branch (or any reference)
+ <ref>. This does not just look for the common ancestor of
+ the two commits, but also takes into account the reflog of
+ <ref> to see if the history leading to <commit> forked from
+ an earlier incarnation of the branch <ref> (see discussion
+ on this mode below).
OPTIONS
-------
@@ -137,6 +146,31 @@ In modern git, you can say this in a more direct way:
instead.
+Discussion on fork-point mode
+-----------------------------
+
+After working on the `topic` branch created with `git checkout -b
+topic origin/master`, the history of remote-tracking branch
+`origin/master` may have been rewound and rebuilt, leading to a
+history of this shape:
+
+ o---B1
+ /
+ ---o---o---B2--o---o---o---B (origin/master)
+ \
+ B3
+ \
+ Derived (topic)
+
+where `origin/master` used to point at commits B3, B2, B1 and now it
+points at B, and your `topic` branch was started on top of it back
+when `origin/master` was at B3. This mode uses the reflog of
+`origin/master` to find B3 as the fork point, so that the `topic`
+can be rebased on top of the updated `origin/master` by:
+
+ $ fork_point=$(git merge-base --fork-point origin/master topic)
+ $ git rebase --onto origin/master $fork_point topic
+
See also
--------
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index b1f7988..e453132 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -52,6 +52,18 @@ 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).
+BUGS
+----
+Each time a superproject update moves a populated submodule (e.g. when
+switching between commits before and after the move) a stale submodule
+checkout will remain in the old location and an empty directory will
+appear in the new location. To populate the submodule again in the new
+location the user will have to run "git submodule update"
+afterwards. Removing the old directory is only safe when it uses a
+gitfile, as otherwise the history of the submodule will be deleted
+too. Both steps will be obsolete when recursive submodule update has
+been implemented.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index 46ef046..84bb0fe 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -375,16 +375,6 @@ does not match any refs is silently ignored.
If not set in the environment, the list of notes to copy depends
on the `notes.rewrite.<command>` and `notes.rewriteRef` settings.
-
-Author
-------
-Written by Johannes Schindelin <johannes.schindelin@gmx.de> and
-Johan Herland <johan@herland.net>
-
-Documentation
--------------
-Documentation by Johannes Schindelin and Johan Herland
-
GIT
---
Part of the linkgit:git[7] suite
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index 8cba16d..6ab5f94 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -168,7 +168,8 @@ All commands except clone accept these options.
--git-dir <dir>::
Set the 'GIT_DIR' environment variable. See linkgit:git[1].
---verbose, -v::
+-v::
+--verbose::
Provide more progress information.
Sync options
@@ -279,7 +280,8 @@ These options can be used to modify 'git p4 submit' behavior.
Export tags from Git as p4 labels. Tags found in Git are applied
to the perforce working directory.
---dry-run, -n::
+-n::
+--dry-run::
Show just what commits would be submitted to p4; do not change
state in Git or p4.
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index d94edcd..cdab9ed 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -51,8 +51,7 @@ base-name::
<base-name> to determine the name of the created file.
When this option is used, the two files are written in
<base-name>-<SHA-1>.{pack,idx} files. <SHA-1> is a hash
- of the sorted object names to make the resulting filename
- based on the pack content, and written to the standard
+ based on the pack content and is written to the standard
output of the command.
--stdout::
diff --git a/Documentation/git-peek-remote.txt b/Documentation/git-peek-remote.txt
deleted file mode 100644
index 87ea3fb..0000000
--- a/Documentation/git-peek-remote.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-git-peek-remote(1)
-==================
-
-NAME
-----
-git-peek-remote - List the references in a remote repository
-
-
-SYNOPSIS
---------
-[verse]
-'git peek-remote' [--upload-pack=<git-upload-pack>] [<host>:]<directory>
-
-DESCRIPTION
------------
-This command is deprecated; use 'git ls-remote' instead.
-
-OPTIONS
--------
---upload-pack=<git-upload-pack>::
- Use this to specify the path to 'git-upload-pack' on the
- remote side, if it is not found on your $PATH. Some
- installations of sshd ignores the user's environment
- setup scripts for login shells (e.g. .bash_profile) and
- your privately installed git may not be found on the system
- default $PATH. Another workaround suggested is to set
- up your $PATH in ".bashrc", but this flag is for people
- who do not want to pay the overhead for non-interactive
- shells, but prefer having a lean .bashrc file (they set most of
- the things up in .bash_profile).
-
-<host>::
- A remote host that houses the repository. When this
- part is specified, 'git-upload-pack' is invoked via
- ssh.
-
-<directory>::
- The repository to sync from.
-
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt
index bf82410..058ac0d 100644
--- a/Documentation/git-prune.txt
+++ b/Documentation/git-prune.txt
@@ -24,6 +24,8 @@ objects unreachable from any of these head objects from the object database.
In addition, it
prunes the unpacked objects that are also found in packs by
running 'git prune-packed'.
+It also removes entries from .git/shallow that are not reachable by
+any ref.
Note that unreachable, packed objects will remain. If this is
not desired, see linkgit:git-repack[1].
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index beea10b..200eb22 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -42,6 +42,8 @@ Assume the following history exists and the current branch is
A---B---C master on origin
/
D---E---F---G master
+ ^
+ origin/master in your repository
------------
Then "`git pull`" will fetch and replay the changes from the remote
@@ -51,7 +53,7 @@ result in a new commit along with the names of the two parent commits
and a log message from the user describing the changes.
------------
- A---B---C remotes/origin/master
+ A---B---C origin/master
/ \
D---E---F---G---H master
------------
@@ -97,10 +99,10 @@ must be given before the options meant for 'git fetch'.
Options related to merging
~~~~~~~~~~~~~~~~~~~~~~~~~~
-include::merge-options.txt[]
-
:git-pull: 1
+include::merge-options.txt[]
+
-r::
--rebase[=false|true|preserve]::
When true, rebase the current branch on top of the upstream
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 9eec740..2b7f4f9 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -56,8 +56,13 @@ it can be any arbitrary "SHA-1 expression", such as `master~4` or
+
The <dst> tells which ref on the remote side is updated with this
push. Arbitrary expressions cannot be used here, an actual ref must
-be named. If `:`<dst> is omitted, the same ref as <src> will be
-updated.
+be named.
+If `git push [<repository>]` without any `<refspec>` argument is set to
+update some ref at the destination with `<src>` with
+`remote.<repository>.push` configuration variable, `:<dst>` part can
+be omitted---such a push will update a ref that `<src>` normally updates
+without any `<refspec>` on the command line. Otherwise, missing
+`:<dst>` means to update the same ref as the `<src>`.
+
The object referenced by <src> is used to update the <dst> reference
on the remote side. By default this is only allowed if <dst> is not
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 94e07fd..2a93c64 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -281,6 +281,10 @@ which makes little sense.
specified, `-s recursive`. Note the reversal of 'ours' and
'theirs' as noted above for the `-m` option.
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign commits.
+
-q::
--quiet::
Be quiet. Implies --no-stat.
@@ -324,6 +328,16 @@ fresh commits so it can be remerged successfully without needing to "revert
the reversion" (see the
link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).
+--fork-point::
+--no-fork-point::
+ Use 'git merge-base --fork-point' to find a better common ancestor
+ between `upstream` and `branch` when calculating which commits have
+ have been introduced by `branch` (see linkgit:git-merge-base[1]).
++
+If no non-option arguments are given on the command line, then the default is
+`--fork-point @{u}` otherwise the `upstream` argument is interpreted literally
+unless the `--fork-point` option is specified.
+
--ignore-whitespace::
--whitespace=<option>::
These flag are passed to the 'git apply' program
diff --git a/Documentation/git-remote-ext.txt b/Documentation/git-remote-ext.txt
index 8cfc748..cd0bb77 100644
--- a/Documentation/git-remote-ext.txt
+++ b/Documentation/git-remote-ext.txt
@@ -116,11 +116,6 @@ begins with `ext::`. Examples:
determined by the helper using environment variables (see
above).
-Documentation
---------------
-Documentation by Ilari Liusvaara, Jonathan Nieder and the Git list
-<git@vger.kernel.org>
-
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-remote-fd.txt b/Documentation/git-remote-fd.txt
index 933c2ad..bcd3766 100644
--- a/Documentation/git-remote-fd.txt
+++ b/Documentation/git-remote-fd.txt
@@ -50,10 +50,6 @@ EXAMPLES
`git push fd::7,8/bar master`::
Same as above.
-Documentation
---------------
-Documentation by Ilari Liusvaara and the Git list <git@vger.kernel.org>
-
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 2507c8b..cb103c8 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -3,7 +3,7 @@ git-remote(1)
NAME
----
-git-remote - manage set of tracked repositories
+git-remote - Manage set of tracked repositories
SYNOPSIS
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index dad186c..002cfd5 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -14,7 +14,7 @@ SYNOPSIS
DESCRIPTION
-----------
-This script is used to combine all objects that do not currently
+This command is used to combine all objects that do not currently
reside in a "pack", into a pack. It can also be used to re-organize
existing packs into a single, more efficient pack.
diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt
index f373ab4..0a02f70 100644
--- a/Documentation/git-replace.txt
+++ b/Documentation/git-replace.txt
@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git replace' [-f] <object> <replacement>
'git replace' -d <object>...
-'git replace' -l [<pattern>]
+'git replace' [--format=<format>] [-l [<pattern>]]
DESCRIPTION
-----------
@@ -70,6 +70,23 @@ OPTIONS
Typing "git replace" without arguments, also lists all replace
refs.
+--format=<format>::
+ When listing, use the specified <format>, which can be one of
+ 'short', 'medium' and 'long'. When omitted, the format
+ defaults to 'short'.
+
+FORMATS
+-------
+
+The following format are available:
+
+* 'short':
+ <replaced sha1>
+* 'medium':
+ <replaced sha1> -> <replacement sha1>
+* 'long':
+ <replaced sha1> (<replaced type>) -> <replacement sha1> (<replacement type>)
+
CREATING REPLACEMENT OBJECTS
----------------------------
diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt
deleted file mode 100644
index 9ec115b..0000000
--- a/Documentation/git-repo-config.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-git-repo-config(1)
-==================
-
-NAME
-----
-git-repo-config - Get and set repository or global options
-
-
-SYNOPSIS
---------
-[verse]
-'git repo-config' ...
-
-
-DESCRIPTION
------------
-
-This is a synonym for linkgit:git-config[1]. Please refer to the
-documentation of that command.
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index f445cb3..a077ba0 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git reset' [-q] [<tree-ish>] [--] <paths>...
'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]
-'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
+'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
DESCRIPTION
-----------
@@ -60,6 +60,9 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
Resets the index but not the working tree (i.e., the changed files
are preserved but not marked for commit) and reports what has not
been updated. This is the default action.
++
+If `-N` is specified, removed paths are marked as intent-to-add (see
+linkgit:git-add[1]).
--hard::
Resets the index and working tree. Any changes to tracked files in the
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index d068a65..0d2cdcd 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -50,6 +50,10 @@ Options for --parseopt
the first non-option argument. This can be used to parse sub-commands
that take options themselves.
+--stuck-long::
+ Only meaningful in `--parseopt` mode. Output the options in their
+ long form if available, and with their arguments stuck.
+
Options for Filtering
~~~~~~~~~~~~~~~~~~~~~
@@ -173,6 +177,20 @@ shown. If the pattern does not contain a globbing character (`?`,
character (`?`, `*`, or `[`), it is turned into a prefix
match by appending `/*`.
+--exclude=<glob-pattern>::
+ Do not include refs matching '<glob-pattern>' that the next `--all`,
+ `--branches`, `--tags`, `--remotes`, or `--glob` would otherwise
+ consider. Repetitions of this option accumulate exclusion patterns
+ up to the next `--all`, `--branches`, `--tags`, `--remotes`, or
+ `--glob` option (other options or arguments do not clear
+ accumlated patterns).
++
+The patterns given should not begin with `refs/heads`, `refs/tags`, or
+`refs/remotes` when applied to `--branches`, `--tags`, or `--remotes`,
+respectively, and they must begin with `refs/` when applied to `--glob`
+or `--all`. If a trailing '/{asterisk}' is intended, it must be given
+explicitly.
+
--disambiguate=<prefix>::
Show every object whose name begins with the given prefix.
The <prefix> must be at least 4 hexadecimal digits long to
@@ -285,7 +303,9 @@ Each line of options has this format:
`<flags>` are of `*`, `=`, `?` or `!`.
* Use `=` if the option takes an argument.
- * Use `?` to mean that the option is optional (though its use is discouraged).
+ * Use `?` to mean that the option takes an optional argument. You
+ probably want to use the `--stuck-long` mode to be able to
+ unambiguously parse the optional argument.
* Use `*` to mean that this option should not be listed in the usage
generated for the `-h` argument. It's shown for `--help-all` as
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 2de67a5..9eb83f0 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' [--[no-]edit] [-n] [-m parent-number] [-s] <commit>...
+'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
'git revert' --continue
'git revert' --quit
'git revert' --abort
@@ -80,6 +80,10 @@ more details.
This is useful when reverting more than one commits'
effect to your index in a row.
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign commits.
+
-s::
--signoff::
Add Signed-off-by line at the end of the commit message.
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index 9d731b4..f1efc11 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -170,6 +170,15 @@ of files and subdirectories under the `Documentation/` directory.
(i.e. you are listing the files explicitly), it
does not remove `subdir/git-foo.sh`.
+BUGS
+----
+Each time a superproject update removes a populated submodule
+(e.g. when switching between commits before and after the removal) a
+stale submodule checkout will remain in the old location. Removing the
+old directory is only safe when it uses a gitfile, as otherwise the
+history of the submodule will be deleted too. This step will be
+obsolete when recursive submodule update has been implemented.
+
SEE ALSO
--------
linkgit:git-add[1]
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index b0a309b..ffd1b03 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -175,6 +175,7 @@ FILES
SEE ALSO
--------
+linkgit:git-for-each-ref[1],
linkgit:git-ls-remote[1],
linkgit:git-update-ref[1],
linkgit:gitrepository-layout[5]
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index bfef8a0..21cb59a 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -15,8 +15,8 @@ SYNOPSIS
'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>] [--depth <depth>]
- [--merge] [--recursive] [--] [<path>...]
+ [-f|--force] [--rebase|--merge|--checkout] [--reference <repository>]
+ [--depth <depth>] [--recursive] [--] [<path>...]
'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
[commit] [--] [<path>...]
'git submodule' [--quiet] foreach [--recursive] <command>
@@ -155,13 +155,31 @@ 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`. 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.
+ checkout the commit specified in the index of the containing
+ repository. The update mode defaults to `checkout`, but can be
+ configured with the `submodule.<name>.update` setting or the
+ `--rebase`, `--merge`, or `--checkout` options.
++
+For updates that clone missing submodules, checkout-mode updates will
+create submodules with detached HEADs; all other modes will create
+submodules with a local branch named after `submodule.<path>.branch`.
++
+For updates that do not clone missing submodules, the submodule's HEAD
+is only touched when the remote reference does not match the
+submodule's HEAD (for none-mode updates, the submodule is never
+touched). The remote reference is usually the gitlinked commit from
+the superproject's tree, but with `--remote` it is the upstream
+subproject's `submodule.<name>.branch`. This remote reference is
+integrated with the submodule's HEAD using the specified update mode.
+For checkout-mode updates, that will result in a detached HEAD. For
+rebase- and merge-mode updates, the commit referenced by the
+submodule's HEAD may change, but the symbolic reference will remain
+unchanged (i.e. checked-out branches will still be checked-out
+branches, and detached HEADs will still be detached HEADs). If none
+of the builtin modes fit your needs, set `submodule.<name>.update` to
+`!command` to configure a custom integration command. `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
@@ -281,6 +299,16 @@ In order to ensure a current tracking branch state, `update --remote`
fetches the submodule's remote repository before calculating the
SHA-1. If you don't want to fetch, you should use `submodule update
--remote --no-fetch`.
++
+Use this option to integrate changes from the upstream subproject with
+your submodule's current HEAD. Alternatively, you can run `git pull`
+from the submodule, which is equivalent except for the remote branch
+name: `update --remote` uses the default upstream repository and
+`submodule.<name>.branch`, while `git pull` uses the submodule's
+`branch.<name>.merge`. Prefer `submodule.<name>.branch` if you want
+to distribute the default upstream branch with the superproject and
+`branch.<name>.merge` if you want a more native feel while working in
+the submodule itself.
-N::
--no-fetch::
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 2a38476..30c5ee2 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -124,15 +124,15 @@ This automatically updates the rev_map if needed (see
'$GIT_DIR/svn/\*\*/.rev_map.*' in the FILES section below for details).
--localtime;;
- Store Git commit times in the local timezone instead of UTC. This
+ Store Git commit times in the local time zone instead of UTC. This
makes 'git log' (even without --date=local) show the same times
- that `svn log` would in the local timezone.
+ that `svn log` would in the local time zone.
+
This doesn't interfere with interoperating with the Subversion
repository you cloned from, but if you wish for your local Git
repository to be able to interoperate with someone else's local Git
repository, either don't use this option or you should both use it in
-the same local timezone.
+the same local time zone.
--parent;;
Fetch only from the SVN parent of the current HEAD.
@@ -175,11 +175,11 @@ Skip "branches" and "tags" of first level directories;;
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
- values may be needed for 'clone'/'fetch' to complete in reasonable
- time. But overly large values may lead to higher memory usage and
- request timeouts.
+ Fetch <n> log entries per request when scanning Subversion history.
+ The default is 100. For very large Subversion repositories, larger
+ values may be needed for 'clone'/'fetch' to complete in reasonable
+ time. But overly large values may lead to higher memory usage and
+ request timeouts.
'clone'::
Runs 'init' and 'fetch'. It will automatically create a
@@ -275,7 +275,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 is "no" or "quit", without
+ 'git svn dcommit' returns immediately if answer is "no" or "quit", without
committing anything to SVN.
'branch'::
@@ -366,12 +366,12 @@ environment). This command has the same behaviour.
Any other arguments are passed directly to 'git log'
'blame'::
- Show what revision and author last modified each line of a file. The
- output of this mode is format-compatible with the output of
- `svn blame' by default. Like the SVN blame command,
- local uncommitted changes in the working tree are ignored;
- the version of the file in the HEAD revision is annotated. Unknown
- arguments are passed directly to 'git blame'.
+ Show what revision and author last modified each line of a file. The
+ output of this mode is format-compatible with the output of
+ `svn blame' by default. Like the SVN blame command,
+ local uncommitted changes in the working tree are ignored;
+ the version of the file in the HEAD revision is annotated. Unknown
+ arguments are passed directly to 'git blame'.
+
--git-format;;
Produce output in the same format as 'git blame', but with
@@ -830,7 +830,7 @@ Tracking and contributing to an entire Subversion-managed project
# View all branches and tags you have cloned:
git branch -r
# Create a new branch in SVN
- git svn branch waldo
+ git svn branch waldo
# Reset your master to trunk (or any other branch, replacing 'trunk'
# with the appropriate name):
git reset --hard svn/trunk
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index c418c44..404257d 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -103,8 +103,9 @@ OPTIONS
+
This option is only applicable when listing tags without annotation lines.
---contains <commit>::
- Only list tags which contain the specified commit.
+--contains [<commit>]::
+ Only list tags which contain the specified commit (HEAD if not
+ specified).
--points-at <object>::
Only list tags of the given object.
diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt
deleted file mode 100644
index f7362dc..0000000
--- a/Documentation/git-tar-tree.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-git-tar-tree(1)
-===============
-
-NAME
-----
-git-tar-tree - Create a tar archive of the files in the named tree object
-
-
-SYNOPSIS
---------
-[verse]
-'git tar-tree' [--remote=<repo>] <tree-ish> [ <base> ]
-
-DESCRIPTION
------------
-THIS COMMAND IS DEPRECATED. Use 'git archive' with `--format=tar`
-option instead (and move the <base> argument to `--prefix=base/`).
-
-Creates a tar archive containing the tree structure for the named tree.
-When <base> is specified it is added as a leading path to the files in the
-generated tar archive.
-
-'git tar-tree' behaves differently when given a tree ID versus when given
-a commit ID or tag ID. In the first case the current time is used as
-modification time of each file in the archive. In the latter case the
-commit time as recorded in the referenced commit object is used instead.
-Additionally the commit ID is stored in a global extended pax header.
-It can be extracted using 'git get-tar-commit-id'.
-
-OPTIONS
--------
-
-<tree-ish>::
- The tree or commit to produce tar archive for. If it is
- the object name of a commit object.
-
-<base>::
- Leading path to the files in the resulting tar archive.
-
---remote=<repo>::
- Instead of making a tar archive from local repository,
- retrieve a tar archive from a remote repository.
-
-CONFIGURATION
--------------
-
-tar.umask::
- This variable can be used to restrict the permission bits of
- tar archive entries. The default is 0002, which turns off the
- world write bit. The special value "user" indicates that the
- archiving user's umask will be used instead. See umask(2) for
- details.
-
-EXAMPLES
---------
-`git tar-tree HEAD junk | (cd /var/tmp/ && tar xf -)`::
-
- Create a tar archive that contains the contents of the
- latest commit on the current branch, and extracts it in
- `/var/tmp/junk` directory.
-
-`git tar-tree v1.4.0 git-1.4.0 | gzip >git-1.4.0.tar.gz`::
-
- Create a tarball for v1.4.0 release.
-
-`git tar-tree v1.4.0^{tree} git-1.4.0 | gzip >git-1.4.0.tar.gz`::
-
- Create a tarball for v1.4.0 release, but without a
- global extended pax header.
-
-`git tar-tree --remote=example.com:git.git v1.4.0 >git-1.4.0.tar`::
-
- Get a tarball v1.4.0 from example.com.
-
-`git tar-tree HEAD:Documentation/ git-docs > git-1.4.0-docs.tar`::
-
- Put everything in the current head's Documentation/ directory
- into 'git-1.4.0-docs.tar', with the prefix 'git-docs/'.
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.txt
index ff23494..12cb108 100644
--- a/Documentation/git-unpack-objects.txt
+++ b/Documentation/git-unpack-objects.txt
@@ -9,7 +9,7 @@ git-unpack-objects - Unpack objects from a packed archive
SYNOPSIS
--------
[verse]
-'git unpack-objects' [-n] [-q] [-r] [--strict] <pack-file
+'git unpack-objects' [-n] [-q] [-r] [--strict] < <pack-file>
DESCRIPTION
diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt
index 5aec4ec..2de575f 100644
--- a/Documentation/git-web--browse.txt
+++ b/Documentation/git-web--browse.txt
@@ -35,6 +35,7 @@ The following browsers (or commands) are currently supported:
* open (this is the default under Mac OS X GUI)
* start (this is the default under MinGW)
* cygstart (this is the default under Cygwin)
+* xdg-open
Custom commands may also be specified.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 4f7e07f..02bbc08 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,28 @@ 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.1/git.html[documentation for release 1.8.4.1]
+* link:v1.9.0/git.html[documentation for release 1.9.0]
* release notes for
+ link:RelNotes/1.9.0.txt[1.9.0].
+
+* link:v1.8.5.5/git.html[documentation for release 1.8.5.5]
+
+* release notes for
+ link:RelNotes/1.8.5.5.txt[1.8.5.5],
+ link:RelNotes/1.8.5.4.txt[1.8.5.4],
+ link:RelNotes/1.8.5.3.txt[1.8.5.3],
+ link:RelNotes/1.8.5.2.txt[1.8.5.2],
+ link:RelNotes/1.8.5.1.txt[1.8.5.1],
+ link:RelNotes/1.8.5.txt[1.8.5].
+
+* link:v1.8.4.5/git.html[documentation for release 1.8.4.5]
+
+* release notes for
+ link:RelNotes/1.8.4.5.txt[1.8.4.5],
+ link:RelNotes/1.8.4.4.txt[1.8.4.4],
+ link:RelNotes/1.8.4.3.txt[1.8.4.3],
+ link:RelNotes/1.8.4.2.txt[1.8.4.2],
link:RelNotes/1.8.4.1.txt[1.8.4.1],
link:RelNotes/1.8.4.txt[1.8.4].
@@ -796,6 +815,15 @@ temporary file --- it is removed when 'GIT_EXTERNAL_DIFF' exits.
+
For a path that is unmerged, 'GIT_EXTERNAL_DIFF' is called with 1
parameter, <path>.
++
+For each path 'GIT_EXTERNAL_DIFF' is called, two environment variables,
+'GIT_DIFF_PATH_COUNTER' and 'GIT_DIFF_PATH_TOTAL' are set.
+
+'GIT_DIFF_PATH_COUNTER'::
+ A 1-based counter incremented by one for every path.
+
+'GIT_DIFF_PATH_TOTAL'::
+ The total number of paths.
other
~~~~~
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index b322a26..643c1ba 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -930,9 +930,12 @@ state.
DEFINING MACRO ATTRIBUTES
-------------------------
-Custom macro attributes can be defined only in the `.gitattributes`
-file at the toplevel (i.e. not in any subdirectory). The built-in
-macro attribute "binary" is equivalent to:
+Custom macro attributes can be defined only in top-level gitattributes
+files (`$GIT_DIR/info/attributes`, the `.gitattributes` file at the
+top level of the working tree, or the global or system-wide
+gitattributes files), not in `.gitattributes` files in working tree
+subdirectories. The built-in macro attribute "binary" is equivalent
+to:
------------
[attr]binary -diff -merge -text
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index 3146413..1c3e109 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -28,7 +28,7 @@ arguments. Here are the rules:
they can be disambiguated by placing `--` between them.
E.g. `git diff -- HEAD` is, "I have a file called HEAD in my work
tree. Please show changes between the version I staged in the index
- and what I have in the work tree for that file". not "show difference
+ and what I have in the work tree for that file", not "show difference
between the HEAD commit and the work tree as a whole". You can say
`git diff HEAD --` to ask for the latter.
@@ -72,23 +72,23 @@ scripting Git:
* splitting short options to separate words (prefer `git foo -a -b`
to `git foo -ab`, the latter may not even work).
- * when a command line option takes an argument, use the 'sticked' form. In
+ * when a command line option takes an argument, use the 'stuck' form. In
other words, write `git foo -oArg` instead of `git foo -o Arg` for short
options, and `git foo --long-opt=Arg` instead of `git foo --long-opt Arg`
for long options. An option that takes optional option-argument must be
- written in the 'sticked' form.
+ written in the 'stuck' form.
* when you give a revision parameter to a command, make sure the parameter is
not ambiguous with a name of a file in the work tree. E.g. do not write
`git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work
if you happen to have a file called `HEAD` in the work tree.
- * many commands allow a long option "--option" to be abbreviated
+ * many commands allow a long option `--option` to be abbreviated
only to their unique prefix (e.g. if there is no other option
- whose name begins with "opt", you may be able to spell "--opt" to
- invoke the "--option" flag), but you should fully spell them out
+ whose name begins with `opt`, you may be able to spell `--opt` to
+ invoke the `--option` flag), but you should fully spell them out
when writing your scripts; later versions of Git may introduce a
- new option whose name shares the same prefix, e.g. "--optimize",
+ new option whose name shares the same prefix, e.g. `--optimize`,
to make a short prefix that used to be unique no longer unique.
@@ -149,7 +149,7 @@ prefix of a long option as if it is fully spelled out, but use this
with a caution. For example, `git commit --amen` behaves as if you
typed `git commit --amend`, but that is true only until a later version
of Git introduces another option that shares the same prefix,
-e.g `git commit --amenity" option.
+e.g. `git commit --amenity` option.
Separating argument from the option
@@ -165,7 +165,7 @@ $ git foo -o Arg
----------------------------
However, this is *NOT* allowed for switches with an optional value, where the
-'sticked' form must be used:
+'stuck' form must be used:
----------------------------
$ git describe --abbrev HEAD # correct
$ git describe --abbrev=10 HEAD # correct
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index d48bf4d..d954bf6 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -251,7 +251,7 @@ three parameters:
- the name of the ref being updated,
- the old object name stored in the ref,
- - and the new objectname to be stored in the ref.
+ - and the new object name to be stored in the ref.
A zero exit from the update hook allows the ref to be updated.
Exiting with a non-zero status prevents 'git-receive-pack'
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 54e334e..b08d34d 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -7,7 +7,7 @@ gitignore - Specifies intentionally untracked files to ignore
SYNOPSIS
--------
-$GIT_DIR/info/exclude, .gitignore
+$HOME/.config/git/ignore, $GIT_DIR/info/exclude, .gitignore
DESCRIPTION
-----------
@@ -79,8 +79,10 @@ PATTERN FORMAT
- An optional prefix "`!`" which negates the pattern; any
matching file excluded by a previous pattern will become
- included again. If a negated pattern matches, this will
- override lower precedence patterns sources.
+ included again. It is not possible to re-include a file if a parent
+ directory of that file is excluded. Git doesn't list excluded
+ directories for performance reasons, so any patterns on contained
+ files have no effect, no matter where they are defined.
Put a backslash ("`\`") in front of the first "`!`" for patterns
that begin with a literal "`!`", for example, "`\!important!.txt`".
@@ -113,12 +115,12 @@ 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"
+ "`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
+ - 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
@@ -182,6 +184,19 @@ Another example:
The second .gitignore prevents Git from ignoring
`arch/foo/kernel/vmlinux.lds.S`.
+Example to exclude everything except a specific directory `foo/bar`
+(note the `/*` - without the slash, the wildcard would also exclude
+everything within `foo/bar`):
+
+--------------------------------------------------------------
+ $ cat .gitignore
+ # exclude everything except directory foo/bar
+ /*
+ !/foo
+ /foo/*
+ !/foo/bar
+--------------------------------------------------------------
+
SEE ALSO
--------
linkgit:git-rm[1],
diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt
index c17e760..1e9e38a 100644
--- a/Documentation/gitk.txt
+++ b/Documentation/gitk.txt
@@ -8,7 +8,7 @@ gitk - The Git repository browser
SYNOPSIS
--------
[verse]
-'gitk' [<option>...] [<revs>] [--] [<path>...]
+'gitk' [<options>] [<revision range>] [\--] [<path>...]
DESCRIPTION
-----------
@@ -16,21 +16,38 @@ Displays changes in a repository or a selected set of commits. This includes
visualizing the commit graph, showing information related to each commit, and
the files in the trees of each revision.
-Historically, gitk was the first repository browser. It's written in tcl/tk
-and started off in a separate repository but was later merged into the main
-Git repository.
-
OPTIONS
-------
-To control which revisions to show, the command takes options applicable to
-the 'git rev-list' command (see linkgit:git-rev-list[1]).
-This manual page describes only the most
-frequently used options.
--n <number>::
---max-count=<number>::
+To control which revisions to show, gitk supports most options
+applicable to the 'git rev-list' command. It also supports a few
+options applicable to the 'git diff-*' commands to control how the
+changes each commit introduces are shown. Finally, it supports some
+gitk-specific options.
+
+gitk generally only understands options with arguments in the
+'sticked' form (see linkgit:gitcli[7]) due to limitations in the
+command line parser.
+
+rev-list options and arguments
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This manual page describes only the most frequently used options. See
+linkgit:git-rev-list[1] for a complete list.
+
+--all::
+
+ Show all refs (branches, tags, etc.).
+
+--branches[=<pattern>]::
+--tags[=<pattern>]::
+--remotes[=<pattern>]::
- Limits the number of commits to show.
+ Pretend as if all the branches (tags, remote branches, resp.)
+ are listed on the command line as '<commit>'. If '<pattern>'
+ is given, limit refs to ones matching given shell glob. If
+ pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the
+ end is implied.
--since=<date>::
@@ -40,9 +57,9 @@ frequently used options.
Show commits older than a specific date.
---all::
+--date-order::
- Show all branches.
+ Sort commits by date when possible.
--merge::
@@ -51,19 +68,53 @@ frequently used options.
that modify the conflicted files and do not exist on all the heads
being merged.
---argscmd=<command>::
- Command to be run each time gitk has to determine the list of
- <revs> to show. The command is expected to print on its standard
- output a list of additional revs to be shown, one per line.
- Use this instead of explicitly specifying <revs> if the set of
- commits to show may vary between refreshes.
+--left-right::
---select-commit=<ref>::
+ Mark which side of a symmetric diff a commit is reachable
+ from. Commits from the left side are prefixed with a `<`
+ symbol and those from the right with a `>` symbol.
- Automatically select the specified commit after loading the graph.
- Default behavior is equivalent to specifying '--select-commit=HEAD'.
+--full-history::
+
+ When filtering history with '<path>...', does not prune some
+ history. (See "History simplification" in linkgit:git-log[1]
+ for a more detailed explanation.)
+
+--simplify-merges::
+
+ Additional option to '--full-history' to remove some needless
+ merges from the resulting history, as there are no selected
+ commits contributing to this merge. (See "History
+ simplification" in linkgit:git-log[1] for a more detailed
+ explanation.)
-<revs>::
+--ancestry-path::
+
+ When given a range of commits to display
+ (e.g. 'commit1..commit2' or 'commit2 {caret}commit1'), only
+ display commits that exist directly on the ancestry chain
+ between the 'commit1' and 'commit2', i.e. commits that are
+ both descendants of 'commit1', and ancestors of 'commit2'.
+ (See "History simplification" in linkgit:git-log[1] for a more
+ detailed explanation.)
+
+-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.
++
+*Note:* gitk (unlike linkgit:git-log[1]) currently only understands
+this option if you specify it "glued together" with its argument. Do
+*not* put a space after `-L`.
++
+include::line-range-format.txt[]
+
+<revision range>::
Limit the revisions to show. This can be either a single revision
meaning show from the given revision and back, or it can be a range in
@@ -78,6 +129,23 @@ frequently used options.
avoid ambiguity with respect to revision names use "--" to separate the paths
from any preceding options.
+gitk-specific options
+~~~~~~~~~~~~~~~~~~~~~
+
+--argscmd=<command>::
+
+ Command to be run each time gitk has to determine the revision
+ range to show. The command is expected to print on its
+ standard output a list of additional revisions to be shown,
+ one per line. Use this instead of explicitly specifying a
+ '<revision range>' if the set of commits to show may vary
+ between refreshes.
+
+--select-commit=<ref>::
+
+ Select the specified commit after loading the graph.
+ Default behavior is equivalent to specifying '--select-commit=HEAD'.
+
Examples
--------
gitk v2.6.12.. include/scsi drivers/scsi::
@@ -101,6 +169,13 @@ Files
Gitk creates the .gitk file in your $HOME directory to store preferences
such as display options, font, and colors.
+History
+-------
+Gitk was the first graphical repository browser. It's written in
+tcl/tk and started off in a separate repository but was later merged
+into the main Git repository.
+
+
SEE ALSO
--------
'qgit(1)'::
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index f7be93f..f539e3f 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -35,6 +35,8 @@ submodule.<name>.url::
linkgit:git-clone[1] or (if it begins with ./ or ../) a location
relative to the superproject's origin repository.
+In addition, there are a number of optional keys:
+
submodule.<name>.update::
Defines what to do when the submodule is updated by the superproject.
If 'checkout' (the default), the new commit specified in the
@@ -53,6 +55,10 @@ submodule.<name>.branch::
A remote branch name for tracking updates in the upstream submodule.
If the option is not specified, it defaults to 'master'. See the
`--remote` documentation in linkgit:git-submodule[1] for details.
++
+This branch name is also used for the local branch created by
+non-checkout cloning updates. See the `update` documentation in
+linkgit:git-submodule[1] for details.
submodule.<name>.fetchRecurseSubmodules::
This option can be used to control recursive fetching of this
diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt
index f1f4ca9..c2908db 100644
--- a/Documentation/gitremote-helpers.txt
+++ b/Documentation/gitremote-helpers.txt
@@ -437,6 +437,13 @@ set by Git if the remote helper has the 'option' capability.
'option check-connectivity' \{'true'|'false'\}::
Request the helper to check connectivity of a clone.
+'option cloning \{'true'|'false'\}::
+ Notify the helper this is a clone request (i.e. the current
+ repository is guaranteed empty).
+
+'option update-shallow \{'true'|'false'\}::
+ Allow to extend .git/shallow if the new refs require it.
+
SEE ALSO
--------
linkgit:git-remote[1]
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index 305db63..952f503 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -630,13 +630,13 @@ need to set this element to empty list i.e. `[]`.
override::
If this field has a true value then the given feature is
- overriddable, which means that it can be configured
+ overridable, which means that it can be configured
(or enabled/disabled) on a per-repository basis.
+
Usually given "<feature>" is configurable via the `gitweb.<feature>`
config variable in the per-repository Git configuration file.
+
-*Note* that no feature is overriddable by default.
+*Note* that no feature is overridable by default.
sub::
Internal detail of implementation. What is important is that
@@ -822,18 +822,18 @@ timed::
Project specific override is not supported.
javascript-timezone::
- Enable and configure the ability to change a common timezone for dates
+ Enable and configure the ability to change a common time zone for dates
in gitweb output via JavaScript. Dates in gitweb output include
authordate and committerdate in "commit", "commitdiff" and "log"
views, and taggerdate in "tag" view. Enabled by default.
+
-The value is a list of three values: a default timezone (for if the client
-hasn't selected some other timezone and saved it in a cookie), a name of cookie
-where to store selected timezone, and a CSS class used to mark up
+The value is a list of three values: a default time zone (for if the client
+hasn't selected some other time zone and saved it in a cookie), a name of cookie
+where to store selected time zone, and a CSS class used to mark up
dates for manipulation. If you want to turn this feature off, set "default"
to empty list: `[]`.
+
-Typical gitweb config files will only change starting (default) timezone,
+Typical gitweb config files will only change starting (default) time zone,
and leave other elements at their default values:
+
---------------------------------------------------------------------------
@@ -843,12 +843,49 @@ $feature{'javascript-timezone'}{'default'}[0] = "utc";
The example configuration presented here is guaranteed to be backwards
and forward compatible.
+
-Timezone values can be "local" (for local timezone that browser uses), "utc"
+Time zone values can be "local" (for local time zone that browser uses), "utc"
(what gitweb uses when JavaScript or this feature is disabled), or numerical
-timezones in the form of "+/-HHMM", such as "+0200".
+time zones in the form of "+/-HHMM", such as "+0200".
+
Project specific override is not supported.
+extra-branch-refs::
+ List of additional directories under "refs" which are going to
+ be used as branch refs. For example if you have a gerrit setup
+ where all branches under refs/heads/ are official,
+ push-after-review ones and branches under refs/sandbox/,
+ refs/wip and refs/other are user ones where permissions are
+ much wider, then you might want to set this variable as
+ follows:
++
+--------------------------------------------------------------------------------
+$feature{'extra-branch-refs'}{'default'} =
+ ['sandbox', 'wip', 'other'];
+--------------------------------------------------------------------------------
++
+This feature can be configured on per-repository basis after setting
+$feature{'extra-branch-refs'}{'override'} to true, via repository's
+`gitweb.extraBranchRefs` configuration variable, which contains a
+space separated list of refs. An example:
++
+--------------------------------------------------------------------------------
+[gitweb]
+ extraBranchRefs = sandbox wip other
+--------------------------------------------------------------------------------
++
+The gitweb.extraBranchRefs is actually a multi-valued configuration
+variable, so following example is also correct and the result is the
+same as of the snippet above:
++
+--------------------------------------------------------------------------------
+[gitweb]
+ extraBranchRefs = sandbox
+ extraBranchRefs = wip other
+--------------------------------------------------------------------------------
++
+It is an error to specify a ref that does not pass "git check-ref-format"
+scrutiny. Duplicated values are filtered.
+
EXAMPLES
--------
diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt
index e470661..378306f 100644
--- a/Documentation/glossary-content.txt
+++ b/Documentation/glossary-content.txt
@@ -323,24 +323,26 @@ including Documentation/chapter_1/figure_1.jpg.
A pathspec that begins with a colon `:` has special meaning. In the
short form, the leading colon `:` is followed by zero or more "magic
signature" letters (which optionally is terminated by another colon `:`),
-and the remainder is the pattern to match against the path. The optional
-colon that terminates the "magic signature" can be omitted if the pattern
-begins with a character that cannot be a "magic signature" and is not a
-colon.
+and the remainder is the pattern to match against the path.
+The "magic signature" consists of ASCII symbols that are neither
+alphanumeric, glob, regex special charaters nor colon.
+The optional colon that terminates the "magic signature" can be
+omitted if the pattern begins with a character that does not belong to
+"magic signature" symbol set and is not a colon.
+
In the long form, the leading colon `:` is followed by a open
parenthesis `(`, a comma-separated list of zero or more "magic words",
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.
+A pathspec with only a colon means "there is no pathspec". This form
+should not be combined with other pathspec.
+
--
-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.
+top;;
+ The magic word `top` (magic signature: `/`) 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
@@ -362,12 +364,12 @@ 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"
+ "`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
+ - 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
@@ -377,14 +379,12 @@ full pathname may have special meaning:
- Other consecutive asterisks are considered invalid.
+
Glob magic is incompatible with literal magic.
+
+exclude;;
+ After a path matches any non-exclude pathspec, it will be run
+ through all exclude pathspec (magic signature: `!`). If it
+ matches, the path is ignored.
--
-+
-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.
[[def_parent]]parent::
A <<def_commit_object,commit object>> contains a (possibly empty) list
diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt
index 33ae69c..ca43787 100644
--- a/Documentation/howto/maintain-git.txt
+++ b/Documentation/howto/maintain-git.txt
@@ -39,26 +39,26 @@ The policy on Integration is informally mentioned in "A Note
from the maintainer" message, which is periodically posted to
this mailing list after each feature release is made.
- - Feature releases are numbered as vX.Y.Z and are meant to
+ - Feature releases are numbered as vX.Y.0 and are meant to
contain bugfixes and enhancements in any area, including
functionality, performance and usability, without regression.
- One release cycle for a feature release is expected to last for
eight to ten weeks.
- - Maintenance releases are numbered as vX.Y.Z.W and are meant
- to contain only bugfixes for the corresponding vX.Y.Z feature
- release and earlier maintenance releases vX.Y.Z.V (V < W).
+ - Maintenance releases are numbered as vX.Y.Z and are meant
+ to contain only bugfixes for the corresponding vX.Y.0 feature
+ release and earlier maintenance releases vX.Y.W (W < Z).
- 'master' branch is used to prepare for the next feature
release. In other words, at some point, the tip of 'master'
- branch is tagged with vX.Y.Z.
+ branch is tagged with vX.Y.0.
- 'maint' branch is used to prepare for the next maintenance
- release. After the feature release vX.Y.Z is made, the tip
+ release. After the feature release vX.Y.0 is made, the tip
of 'maint' branch is set to that release, and bugfixes will
accumulate on the branch, and at some point, the tip of the
- branch is tagged with vX.Y.Z.1, vX.Y.Z.2, and so on.
+ branch is tagged with vX.Y.1, vX.Y.2, and so on.
- 'next' branch is used to publish changes (both enhancements
and fixes) that (1) have worthwhile goal, (2) are in a fairly
@@ -86,6 +86,10 @@ this mailing list after each feature release is made.
users are encouraged to test it so that regressions and bugs
are found before new topics are merged to 'master'.
+Note that before v1.9.0 release, the version numbers used to be
+structured slightly differently. vX.Y.Z were feature releases while
+vX.Y.Z.W were maintenance releases for vX.Y.Z.
+
A Typical Git Day
-----------------
diff --git a/Documentation/howto/recover-corrupted-object-harder.txt b/Documentation/howto/recover-corrupted-object-harder.txt
new file mode 100644
index 0000000..6f33dac
--- /dev/null
+++ b/Documentation/howto/recover-corrupted-object-harder.txt
@@ -0,0 +1,242 @@
+Date: Wed, 16 Oct 2013 04:34:01 -0400
+From: Jeff King <peff@peff.net>
+Subject: pack corruption post-mortem
+Abstract: Recovering a corrupted object when no good copy is available.
+Content-type: text/asciidoc
+
+How to recover an object from scratch
+=====================================
+
+I was recently presented with a repository with a corrupted packfile,
+and was asked if the data was recoverable. This post-mortem describes
+the steps I took to investigate and fix the problem. I thought others
+might find the process interesting, and it might help somebody in the
+same situation.
+
+********************************
+Note: In this case, no good copy of the repository was available. For
+the much easier case where you can get the corrupted object from
+elsewhere, see link:recover-corrupted-blob-object.html[this howto].
+********************************
+
+I started with an fsck, which found a problem with exactly one object
+(I've used $pack and $obj below to keep the output readable, and also
+because I'll refer to them later):
+
+-----------
+ $ git fsck
+ error: $pack SHA1 checksum mismatch
+ error: index CRC mismatch for object $obj from $pack at offset 51653873
+ error: inflate: data stream error (incorrect data check)
+ error: cannot unpack $obj from $pack at offset 51653873
+-----------
+
+The pack checksum failing means a byte is munged somewhere, and it is
+presumably in the object mentioned (since both the index checksum and
+zlib were failing).
+
+Reading the zlib source code, I found that "incorrect data check" means
+that the adler-32 checksum at the end of the zlib data did not match the
+inflated data. So stepping the data through zlib would not help, as it
+did not fail until the very end, when we realize the crc does not match.
+The problematic bytes could be anywhere in the object data.
+
+The first thing I did was pull the broken data out of the packfile. I
+needed to know how big the object was, which I found out with:
+
+------------
+ $ git show-index <$idx | cut -d' ' -f1 | sort -n | grep -A1 51653873
+ 51653873
+ 51664736
+------------
+
+Show-index gives us the list of objects and their offsets. We throw away
+everything but the offsets, and then sort them so that our interesting
+offset (which we got from the fsck output above) is followed immediately
+by the offset of the next object. Now we know that the object data is
+10863 bytes long, and we can grab it with:
+
+------------
+ dd if=$pack of=object bs=1 skip=51653873 count=10863
+------------
+
+I inspected a hexdump of the data, looking for any obvious bogosity
+(e.g., a 4K run of zeroes would be a good sign of filesystem
+corruption). But everything looked pretty reasonable.
+
+Note that the "object" file isn't fit for feeding straight to zlib; it
+has the git packed object header, which is variable-length. We want to
+strip that off so we can start playing with the zlib data directly. You
+can either work your way through it manually (the format is described in
+link:../technical/pack-format.html[Documentation/technical/pack-format.txt]),
+or you can walk through it in a debugger. I did the latter, creating a
+valid pack like:
+
+------------
+ # pack magic and version
+ printf 'PACK\0\0\0\2' >tmp.pack
+ # pack has one object
+ printf '\0\0\0\1' >>tmp.pack
+ # now add our object data
+ cat object >>tmp.pack
+ # and then append the pack trailer
+ /path/to/git.git/test-sha1 -b <tmp.pack >trailer
+ cat trailer >>tmp.pack
+------------
+
+and then running "git index-pack tmp.pack" in the debugger (stop at
+unpack_raw_entry). Doing this, I found that there were 3 bytes of header
+(and the header itself had a sane type and size). So I stripped those
+off with:
+
+------------
+ dd if=object of=zlib bs=1 skip=3
+------------
+
+I ran the result through zlib's inflate using a custom C program. And
+while it did report the error, I did get the right number of output
+bytes (i.e., it matched git's size header that we decoded above). But
+feeding the result back to "git hash-object" didn't produce the same
+sha1. So there were some wrong bytes, but I didn't know which. The file
+happened to be C source code, so I hoped I could notice something
+obviously wrong with it, but I didn't. I even got it to compile!
+
+I also tried comparing it to other versions of the same path in the
+repository, hoping that there would be some part of the diff that didn't
+make sense. Unfortunately, this happened to be the only revision of this
+particular file in the repository, so I had nothing to compare against.
+
+So I took a different approach. Working under the guess that the
+corruption was limited to a single byte, I wrote a program to munge each
+byte individually, and try inflating the result. Since the object was
+only 10K compressed, that worked out to about 2.5M attempts, which took
+a few minutes.
+
+The program I used is here:
+
+----------------------------------------------
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <zlib.h>
+
+static int try_zlib(unsigned char *buf, int len)
+{
+ /* make this absurdly large so we don't have to loop */
+ static unsigned char out[1024*1024];
+ z_stream z;
+ int ret;
+
+ memset(&z, 0, sizeof(z));
+ inflateInit(&z);
+
+ z.next_in = buf;
+ z.avail_in = len;
+ z.next_out = out;
+ z.avail_out = sizeof(out);
+
+ ret = inflate(&z, 0);
+ inflateEnd(&z);
+ return ret >= 0;
+}
+
+/* eye candy */
+static int counter = 0;
+static void progress(int sig)
+{
+ fprintf(stderr, "\r%d", counter);
+ alarm(1);
+}
+
+int main(void)
+{
+ /* oversized so we can read the whole buffer in */
+ unsigned char buf[1024*1024];
+ int len;
+ unsigned i, j;
+
+ signal(SIGALRM, progress);
+ alarm(1);
+
+ len = read(0, buf, sizeof(buf));
+ for (i = 0; i < len; i++) {
+ unsigned char c = buf[i];
+ for (j = 0; j <= 0xff; j++) {
+ buf[i] = j;
+
+ counter++;
+ if (try_zlib(buf, len))
+ printf("i=%d, j=%x\n", i, j);
+ }
+ buf[i] = c;
+ }
+
+ alarm(0);
+ fprintf(stderr, "\n");
+ return 0;
+}
+----------------------------------------------
+
+I compiled and ran with:
+
+-------
+ gcc -Wall -Werror -O3 munge.c -o munge -lz
+ ./munge <zlib
+-------
+
+
+There were a few false positives early on (if you write "no data" in the
+zlib header, zlib thinks it's just fine :) ). But I got a hit about
+halfway through:
+
+-------
+ i=5642, j=c7
+-------
+
+I let it run to completion, and got a few more hits at the end (where it
+was munging the crc to match our broken data). So there was a good
+chance this middle hit was the source of the problem.
+
+I confirmed by tweaking the byte in a hex editor, zlib inflating the
+result (no errors!), and then piping the output into "git hash-object",
+which reported the sha1 of the broken object. Success!
+
+I fixed the packfile itself with:
+
+-------
+ chmod +w $pack
+ printf '\xc7' | dd of=$pack bs=1 seek=51659518 conv=notrunc
+ chmod -w $pack
+-------
+
+The `\xc7` comes from the replacement byte our "munge" program found.
+The offset 51659518 is derived by taking the original object offset
+(51653873), adding the replacement offset found by "munge" (5642), and
+then adding back in the 3 bytes of git header we stripped.
+
+After that, "git fsck" ran clean.
+
+As for the corruption itself, I was lucky that it was indeed a single
+byte. In fact, it turned out to be a single bit. The byte 0xc7 was
+corrupted to 0xc5. So presumably it was caused by faulty hardware, or a
+cosmic ray.
+
+And the aborted attempt to look at the inflated output to see what was
+wrong? I could have looked forever and never found it. Here's the diff
+between what the corrupted data inflates to, versus the real data:
+
+--------------
+ - cp = strtok (arg, "+");
+ + cp = strtok (arg, ".");
+--------------
+
+It tweaked one byte and still ended up as valid, readable C that just
+happened to do something totally different! One takeaway is that on a
+less unlucky day, looking at the zlib output might have actually been
+helpful, as most random changes would actually break the C code.
+
+But more importantly, git's hashing and checksumming noticed a problem
+that easily could have gone undetected in another system. The result
+still compiled, but would have caused an interesting bug (that would
+have been blamed on some random commit).
diff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.txt
index 981cbdd..6de4f3c 100644
--- a/Documentation/howto/setup-git-server-over-http.txt
+++ b/Documentation/howto/setup-git-server-over-http.txt
@@ -6,6 +6,10 @@ Content-type: text/asciidoc
How to setup Git server over http
=================================
+NOTE: This document is from 2006. A lot has happened since then, and this
+document is now relevant mainly if your web host is not CGI capable.
+Almost everyone else should instead look at linkgit:git-http-backend[1].
+
Since Apache is one of those packages people like to compile
themselves while others prefer the bureaucrat's dream Debian, it is
impossible to give guidelines which will work for everyone. Just send
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index afba8d4..e134315 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -14,9 +14,12 @@ inspect and further tweak the merge result before committing.
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` (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.
+ discouraged).
+ifndef::git-pull[]
+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.
+endif::git-pull[]
+
Older scripts may depend on the historical behaviour of not allowing the
user to edit the merge log message. They will see an editor opened when
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt
index 49a9a7d..3509498 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -20,7 +20,7 @@ recursive::
merged tree of the common ancestors and uses that as
the reference tree for the 3-way merge. This has been
reported to result in fewer merge conflicts without
- causing mis-merges by tests done on actual merge commits
+ causing mismerges by tests done on actual merge commits
taken from Linux 2.6 kernel development history.
Additionally this can detect and handle merges involving
renames. This is the default merge strategy when
@@ -113,3 +113,11 @@ subtree::
match the tree structure of A, instead of reading the trees at
the same level. This adjustment is also done to the common
ancestor tree.
+
+With the strategies that use 3-way merge (including the default, 'recursive'),
+if a change is made on both branches, but later reverted on one of the
+branches, that change will be present in the merged result; some people find
+this behavior confusing. It occurs because only the heads and the merge base
+are considered when performing a merge, not the individual commits. The merge
+algorithm therefore considers the reverted change as no change at all, and
+substitutes the changed version instead.
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index c236b85..9a3da36 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -18,33 +18,27 @@ ordering and formatting options, such as `--reverse`.
-<number>::
-n <number>::
--max-count=<number>::
-
Limit the number of commits to output.
--skip=<number>::
-
Skip 'number' commits before starting to show the commit output.
--since=<date>::
--after=<date>::
-
Show commits more recent than a specific date.
--until=<date>::
--before=<date>::
-
Show commits older than a specific date.
ifdef::git-rev-list[]
--max-age=<timestamp>::
--min-age=<timestamp>::
-
Limit the commits output to specified time range.
endif::git-rev-list[]
--author=<pattern>::
--committer=<pattern>::
-
Limit the commits output to ones with author/committer
header lines that match the specified pattern (regular
expression). With more than one `--author=<pattern>`,
@@ -52,7 +46,6 @@ endif::git-rev-list[]
chosen (similarly for multiple `--committer=<pattern>`).
--grep-reflog=<pattern>::
-
Limit the commits output to ones with reflog entries that
match the specified pattern (regular expression). With
more than one `--grep-reflog`, commits whose reflog message
@@ -60,7 +53,6 @@ endif::git-rev-list[]
error to use this option unless `--walk-reflogs` is in use.
--grep=<pattern>::
-
Limit the commits output to ones with log message that
matches the specified pattern (regular expression). With
more than one `--grep=<pattern>`, commits whose message
@@ -71,46 +63,39 @@ When `--show-notes` is in effect, the message from the notes as
if it is part of the log message.
--all-match::
- Limit the commits output to ones that match all given --grep,
+ Limit the commits output to ones that match all given `--grep`,
instead of ones that match at least one.
-i::
--regexp-ignore-case::
-
- Match the regexp limiting patterns without regard to letters case.
+ Match the regular expression limiting patterns without regard to letter
+ case.
--basic-regexp::
-
Consider the limiting patterns to be basic regular expressions;
this is the default.
-E::
--extended-regexp::
-
Consider the limiting patterns to be extended regular expressions
instead of the default basic regular expressions.
-F::
--fixed-strings::
-
Consider the limiting patterns to be fixed strings (don't interpret
pattern as a regular expression).
--perl-regexp::
-
- Consider the limiting patterns to be Perl-compatible regexp.
+ Consider the limiting patterns to be Perl-compatible regular expressions.
Requires libpcre to be compiled in.
--remove-empty::
-
Stop when a given path disappears from the tree.
--merges::
-
Print only merge commits. This is exactly the same as `--min-parents=2`.
--no-merges::
-
Do not print commits with more than one parent. This is
exactly the same as `--max-parents=1`.
@@ -118,7 +103,6 @@ if it is part of the log message.
--max-parents=<number>::
--no-min-parents::
--no-max-parents::
-
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`
@@ -138,31 +122,26 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
brought in to your history by such a merge.
--not::
-
Reverses the meaning of the '{caret}' prefix (or lack thereof)
- for all following revision specifiers, up to the next '--not'.
+ for all following revision specifiers, up to the next `--not`.
--all::
-
Pretend as if all the refs in `refs/` are listed on the
command line as '<commit>'.
--branches[=<pattern>]::
-
Pretend as if all the refs in `refs/heads` are listed
on the command line as '<commit>'. If '<pattern>' is given, limit
branches to ones matching given shell glob. If pattern lacks '?',
'{asterisk}', or '[', '/{asterisk}' at the end is implied.
--tags[=<pattern>]::
-
Pretend as if all the refs in `refs/tags` are listed
on the command line as '<commit>'. If '<pattern>' is given, limit
tags to ones matching given shell glob. If pattern lacks '?', '{asterisk}',
or '[', '/{asterisk}' at the end is implied.
--remotes[=<pattern>]::
-
Pretend as if all the refs in `refs/remotes` are listed
on the command line as '<commit>'. If '<pattern>' is given, limit
remote-tracking branches to ones matching given shell glob.
@@ -174,14 +153,27 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
is automatically prepended if missing. If pattern lacks '?', '{asterisk}',
or '[', '/{asterisk}' at the end is implied.
---ignore-missing::
+--exclude=<glob-pattern>::
+ Do not include refs matching '<glob-pattern>' that the next `--all`,
+ `--branches`, `--tags`, `--remotes`, or `--glob` would otherwise
+ consider. Repetitions of this option accumulate exclusion patterns
+ up to the next `--all`, `--branches`, `--tags`, `--remotes`, or
+ `--glob` option (other options or arguments do not clear
+ accumlated patterns).
++
+The patterns given should not begin with `refs/heads`, `refs/tags`, or
+`refs/remotes` when applied to `--branches`, `--tags`, or `--remotes`,
+respectively, and they must begin with `refs/` when applied to `--glob`
+or `--all`. If a trailing '/{asterisk}' is intended, it must be given
+explicitly.
+
+--ignore-missing::
Upon seeing an invalid object name in the input, pretend as if
the bad input was not given.
ifndef::git-rev-list[]
--bisect::
-
Pretend as if the bad bisection ref `refs/bisect/bad`
was listed and as if it was followed by `--not` and the good
bisection refs `refs/bisect/good-*` on the command
@@ -189,7 +181,6 @@ ifndef::git-rev-list[]
endif::git-rev-list[]
--stdin::
-
In addition to the '<commit>' listed on the command
line, read them from the standard input. If a '--' separator is
seen, stop reading commits and start reading paths to limit the
@@ -197,36 +188,32 @@ endif::git-rev-list[]
ifdef::git-rev-list[]
--quiet::
-
Don't print anything to standard output. This form
is primarily meant to allow the caller to
test the exit status to see if a range of objects is fully
connected (or not). It is faster than redirecting stdout
- to /dev/null as the output does not have to be formatted.
+ to `/dev/null` as the output does not have to be formatted.
endif::git-rev-list[]
--cherry-mark::
-
Like `--cherry-pick` (see below) but mark equivalent commits
with `=` rather than omitting them, and inequivalent ones with `+`.
--cherry-pick::
-
Omit any commit that introduces the same change as
- another commit on the "other side" when the set of
+ another commit on the ``other side'' when the set of
commits are limited with symmetric difference.
+
For example, if you have two branches, `A` and `B`, a usual way
to list all commits on only one side of them is with
`--left-right` (see the example below in the description of
-the `--left-right` option). It however shows the commits that were cherry-picked
-from the other branch (for example, "3rd on b" may be cherry-picked
-from branch A). With this option, such pairs of commits are
+the `--left-right` option). However, it shows the commits that were
+cherry-picked from the other branch (for example, ``3rd on b'' may be
+cherry-picked from branch A). With this option, such pairs of commits are
excluded from the output.
--left-only::
--right-only::
-
List only commits on the respective side of a symmetric range,
i.e. only those which would be marked `<` resp. `>` by
`--left-right`.
@@ -238,7 +225,6 @@ More precisely, `--cherry-pick --right-only --no-merges` gives the exact
list.
--cherry::
-
A synonym for `--right-only --cherry-mark --no-merges`; useful to
limit the output to the commits on our side and mark those that
have been applied to the other side of a forked history with
@@ -247,30 +233,27 @@ list.
-g::
--walk-reflogs::
-
Instead of walking the commit ancestry chain, walk
reflog entries from the most recent one to older ones.
When this option is used you cannot specify commits to
exclude (that is, '{caret}commit', 'commit1..commit2',
nor 'commit1\...commit2' notations cannot be used).
+
-With '\--pretty' format other than oneline (for obvious reasons),
+With `--pretty` format other than `oneline` (for obvious reasons),
this causes the output to have two extra lines of information
taken from the reflog. By default, 'commit@\{Nth}' notation is
used in the output. When the starting commit is specified as
'commit@\{now}', output also uses 'commit@\{timestamp}' notation
-instead. Under '\--pretty=oneline', the commit message is
+instead. Under `--pretty=oneline`, the commit message is
prefixed with this information on the same line.
-This option cannot be combined with '\--reverse'.
+This option cannot be combined with `--reverse`.
See also linkgit:git-reflog[1].
--merge::
-
After a failed merge, show refs that touch files having a
conflict and don't exist on all heads to merge.
--boundary::
-
Output excluded boundary commits. Boundary commits are
prefixed with `-`.
@@ -295,11 +278,9 @@ is how to do it, as there are various strategies to simplify the history.
The following options select the commits to be shown:
<paths>::
-
Commits modifying the given <paths> are selected.
--simplify-by-decoration::
-
Commits that are referred by some branch or tag are selected.
Note that extra commits can be shown to give a meaningful history.
@@ -307,33 +288,27 @@ Note that extra commits can be shown to give a meaningful history.
The following options affect the way the simplification is performed:
Default mode::
-
Simplifies the history to the simplest history explaining the
final state of the tree. Simplest because it prunes some side
branches if the end result is the same (i.e. merging branches
with the same content)
--full-history::
-
Same as the default mode, but does not prune some history.
--dense::
-
Only the selected commits are shown, plus some to have a
meaningful history.
--sparse::
-
All commits in the simplified history are shown.
--simplify-merges::
-
- Additional option to '--full-history' to remove some needless
+ Additional option to `--full-history` to remove some needless
merges from the resulting history, as there are no selected
commits contributing to this merge.
--ancestry-path::
-
When given a range of commits to display (e.g. 'commit1..commit2'
or 'commit2 {caret}commit1'), only display commits that exist
directly on the ancestry chain between the 'commit1' and
@@ -360,36 +335,35 @@ 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
- "asdf", and a file `quux` exists with contents "quux". Initial
+ ``asdf'', and a file `quux` exists with contents ``quux''. Initial
commits are compared to an empty tree, so `I` is !TREESAME.
-* In `A`, `foo` contains just "foo".
+* In `A`, `foo` contains just ``foo''.
* `B` contains the same change as `A`. Its merge `M` is trivial and
hence TREESAME to all parents.
-* `C` does not change `foo`, but its merge `N` changes it to "foobar",
+* `C` does not change `foo`, but its merge `N` changes it to ``foobar'',
so it is not TREESAME to any parent.
-* `D` sets `foo` to "baz". Its merge `O` combines the strings from
- `N` and `D` to "foobarbaz"; i.e., it is not TREESAME to any parent.
+* `D` sets `foo` to ``baz''. Its merge `O` combines the strings from
+ `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". `P` is TREESAME to `O`, but not to `E`.
+* `E` changes `quux` to ``xyzzy'', and its merge `P` combines the
+ 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
-(via '\--parents' or '\--children') are used. The following settings
+`rev-list` walks backwards through history, including or excluding
+commits based on whether `--full-history` and/or parent rewriting
+(via `--parents` or `--children`) are used. The following settings
are available.
Default mode::
-
Commits are included if they are not TREESAME to any parent
- (though this can be changed, see '\--sparse' below). If the
+ (though this can be changed, see `--sparse` below). If the
commit was a merge, and it was TREESAME to one parent, follow
only that parent. (Even if there are several TREESAME
parents, follow only one of them.) Otherwise, follow all
@@ -408,12 +382,11 @@ available, removed `B` from consideration entirely. `C` was
considered via `N`, but is TREESAME. Root commits are compared to an
empty tree, so `I` is !TREESAME.
+
-Parent/child relations are only visible with --parents, but that does
+Parent/child relations are only visible with `--parents`, but that does
not affect the commits selected in default mode, so we have shown the
parent lines.
--full-history without parent rewriting::
-
This mode differs from the default in one point: always follow
all parents of a merge, even if it is TREESAME to one of them.
Even if more than one side of the merge has commits that are
@@ -433,9 +406,8 @@ about the parent/child relationships between the commits, so we show
them disconnected.
--full-history with parent rewriting::
-
Ordinary commits are only included if they are !TREESAME
- (though this can be changed, see '\--sparse' below).
+ (though this can be changed, see `--sparse` below).
+
Merges are always included. However, their parent list is rewritten:
Along each parent, prune away commits that are not included
@@ -449,7 +421,7 @@ themselves. This results in
`-------------'
-----------------------------------------------------------------------
+
-Compare to '\--full-history' without rewriting above. Note that `E`
+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`, and `X`, `Y` and `Q`.
@@ -458,22 +430,19 @@ In addition to the above settings, you can change whether TREESAME
affects inclusion:
--dense::
-
Commits that are walked are included if they are not TREESAME
to any parent.
--sparse::
-
All commits that are walked are included.
+
-Note that without '\--full-history', this still simplifies merges: if
+Note that without `--full-history`, this still simplifies merges: if
one of the parents is TREESAME, we follow only that one, so the other
sides of the merge are never walked.
--simplify-merges::
-
First, build a history graph in the same way that
- '\--full-history' with parent rewriting does (see above).
+ `--full-history` with parent rewriting does (see above).
+
Then simplify each commit `C` to its replacement `C'` in the final
history according to the following rules:
@@ -492,7 +461,7 @@ history according to the following rules:
--
+
The effect of this is best shown by way of comparing to
-'\--full-history' with parent rewriting. The example turns into:
+`--full-history` with parent rewriting. The example turns into:
+
-----------------------------------------------------------------------
.-A---M---N---O
@@ -502,7 +471,7 @@ The effect of this is best shown by way of comparing to
`---------'
-----------------------------------------------------------------------
+
-Note the major differences in `N`, `P` and `Q` 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
@@ -519,11 +488,10 @@ Note the major differences in `N`, `P` and `Q` over '--full-history':
Finally, there is a fifth simplification mode available:
--ancestry-path::
-
Limit the displayed commits to those directly on the ancestry
- chain between the "from" and "to" commits in the given commit
- range. I.e. only display commits that are ancestor of the "to"
- commit, and descendants of the "from" commit.
+ chain between the ``from'' and ``to'' commits in the given commit
+ range. I.e. only display commits that are ancestor of the ``to''
+ commit and descendants of the ``from'' commit.
+
As an example use case, consider the following commit history:
+
@@ -538,14 +506,14 @@ As an example use case, consider the following commit history:
A regular 'D..M' computes the set of commits that are ancestors of `M`,
but excludes the ones that are ancestors of `D`. This is useful to see
what happened to the history leading to `M` since `D`, in the sense
-that "what does `M` have that did not exist in `D`". The result in this
+that ``what does `M` have that did not exist in `D`''. The result in this
example would be all the commits, except `A` and `B` (and `D` itself,
of course).
+
When we want to find out what commits in `M` are contaminated with the
bug introduced by `D` and need fixing, however, we might want to view
only the subset of 'D..M' that are actually descendants of `D`, i.e.
-excluding `C` and `K`. This is exactly what the '--ancestry-path'
+excluding `C` and `K`. This is exactly what the `--ancestry-path`
option does. Applied to the 'D..M' range, it results in:
+
-----------------------------------------------------------------------
@@ -556,7 +524,7 @@ option does. Applied to the 'D..M' range, it results in:
L--M
-----------------------------------------------------------------------
-The '\--simplify-by-decoration' option allows you to view only the
+The `--simplify-by-decoration` option allows you to view only the
big picture of the topology of the history, by omitting commits
that are not referenced by tags. Commits are marked as !TREESAME
(in other words, kept after history simplification rules described
@@ -569,50 +537,47 @@ Bisection Helpers
~~~~~~~~~~~~~~~~~
--bisect::
-
-Limit output to the one commit object which is roughly halfway between
-included and excluded commits. Note that the bad bisection ref
-`refs/bisect/bad` is added to the included commits (if it
-exists) and the good bisection refs `refs/bisect/good-*` are
-added to the excluded commits (if they exist). Thus, supposing there
-are no refs in `refs/bisect/`, if
-
+ Limit output to the one commit object which is roughly halfway between
+ included and excluded commits. Note that the bad bisection ref
+ `refs/bisect/bad` is added to the included commits (if it
+ exists) and the good bisection refs `refs/bisect/good-*` are
+ added to the excluded commits (if they exist). Thus, supposing there
+ are no refs in `refs/bisect/`, if
++
-----------------------------------------------------------------------
$ git rev-list --bisect foo ^bar ^baz
-----------------------------------------------------------------------
-
++
outputs 'midpoint', the output of the two commands
-
++
-----------------------------------------------------------------------
$ git rev-list foo ^midpoint
$ git rev-list midpoint ^bar ^baz
-----------------------------------------------------------------------
-
++
would be of roughly the same length. Finding the change which
introduces a regression is thus reduced to a binary search: repeatedly
generate and test new 'midpoint's until the commit chain is of length
one.
--bisect-vars::
-
-This calculates the same as `--bisect`, except that refs in
-`refs/bisect/` are not used, and except that this outputs
-text ready to be eval'ed by the shell. These lines will assign the
-name of the midpoint revision to the variable `bisect_rev`, and the
-expected number of commits to be tested after `bisect_rev` is tested
-to `bisect_nr`, the expected number of commits to be tested if
-`bisect_rev` turns out to be good to `bisect_good`, the expected
-number of commits to be tested if `bisect_rev` turns out to be bad to
-`bisect_bad`, and the number of commits we are bisecting right now to
-`bisect_all`.
+ This calculates the same as `--bisect`, except that refs in
+ `refs/bisect/` are not used, and except that this outputs
+ text ready to be eval'ed by the shell. These lines will assign the
+ name of the midpoint revision to the variable `bisect_rev`, and the
+ expected number of commits to be tested after `bisect_rev` is tested
+ to `bisect_nr`, the expected number of commits to be tested if
+ `bisect_rev` turns out to be good to `bisect_good`, the expected
+ number of commits to be tested if `bisect_rev` turns out to be bad to
+ `bisect_bad`, and the number of commits we are bisecting right now to
+ `bisect_all`.
--bisect-all::
-
-This outputs all the commit objects between the included and excluded
-commits, ordered by their distance to the included and excluded
-commits. Refs in `refs/bisect/` are not used. The farthest
-from them is displayed first. (This is the only one displayed by
-`--bisect`.)
+ This outputs all the commit objects between the included and excluded
+ commits, ordered by their distance to the included and excluded
+ commits. Refs in `refs/bisect/` are not used. The farthest
+ from them is displayed first. (This is the only one displayed by
+ `--bisect`.)
+
This is useful because it makes it easy to choose a good commit to
test when you want to avoid to test some of them for some reason (they
@@ -662,9 +627,8 @@ avoid showing the commits from two parallel development track mixed
together.
--reverse::
-
Output the commits in reverse order.
- Cannot be combined with '\--walk-reflogs'.
+ Cannot be combined with `--walk-reflogs`.
Object Traversal
~~~~~~~~~~~~~~~~
@@ -672,37 +636,32 @@ Object Traversal
These options are mostly targeted for packing of Git repositories.
--objects::
-
Print the object IDs of any object referenced by the listed
- commits. '--objects foo ^bar' thus means "send me
+ commits. `--objects foo ^bar` thus means ``send me
all object IDs which I need to download if I have the commit
- object 'bar', but not 'foo'".
+ object _bar_ but not _foo_''.
--objects-edge::
-
- Similar to '--objects', but also print the IDs of excluded
- commits prefixed with a "-" character. This is used by
- linkgit:git-pack-objects[1] to build "thin" pack, which records
+ Similar to `--objects`, but also print the IDs of excluded
+ commits prefixed with a ``-'' character. This is used by
+ linkgit:git-pack-objects[1] to build ``thin'' pack, which records
objects in deltified form based on objects contained in these
excluded commits to reduce network traffic.
--unpacked::
-
- Only useful with '--objects'; print the object IDs that are not
+ Only useful with `--objects`; print the object IDs that are not
in packs.
--no-walk[=(sorted|unsorted)]::
-
Only show the given commits, but do not traverse their ancestors.
This has no effect if a range is specified. If the argument
- "unsorted" is given, the commits are show in the order they were
- given on the command line. Otherwise (if "sorted" or no argument
- was given), the commits are show in reverse chronological order
+ `unsorted` is given, the commits are shown in the order they were
+ given on the command line. Otherwise (if `sorted` or no argument
+ was given), the commits are shown in reverse chronological order
by commit time.
--do-walk::
-
- Overrides a previous --no-walk.
+ Overrides a previous `--no-walk`.
Commit Formatting
~~~~~~~~~~~~~~~~~
@@ -716,46 +675,41 @@ endif::git-rev-list[]
include::pretty-options.txt[]
--relative-date::
-
Synonym for `--date=relative`.
--date=(relative|local|default|iso|rfc|short|raw)::
-
Only takes effect for dates shown in human-readable format, such
- as when using "--pretty". `log.date` config variable sets a default
- value for log command's --date option.
+ as when using `--pretty`. `log.date` config variable sets a default
+ value for the log command's `--date` option.
+
`--date=relative` shows dates relative to the current time,
-e.g. "2 hours ago".
+e.g. ``2 hours ago''.
+
-`--date=local` shows timestamps in user's local timezone.
+`--date=local` shows timestamps in user's local time zone.
+
`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
+
`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
-format, often found in E-mail messages.
+format, often found in email messages.
+
-`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
+`--date=short` shows only the date, but not the time, in `YYYY-MM-DD` format.
+
`--date=raw` shows the date in the internal raw Git format `%s %z` format.
+
-`--date=default` shows timestamps in the original timezone
+`--date=default` shows timestamps in the original time zone
(either committer's or author's).
ifdef::git-rev-list[]
--header::
-
Print the contents of the commit in raw-format; each record is
separated with a NUL character.
endif::git-rev-list[]
--parents::
-
Print also the parents of the commit (in the form "commit parent...").
Also enables parent rewriting, see 'History Simplification' below.
--children::
-
Print also the children of the commit (in the form "commit child...").
Also enables parent rewriting, see 'History Simplification' below.
@@ -765,7 +719,6 @@ ifdef::git-rev-list[]
endif::git-rev-list[]
--left-right::
-
Mark which side of a symmetric diff a commit is reachable from.
Commits from the left side are prefixed with `<` and those from
the right with `>`. If combined with `--boundary`, those
@@ -795,7 +748,6 @@ you would get an output like this:
-----------------------------------------------------------------------
--graph::
-
Draw a text-based graphical representation of the commit history
on the left hand side of the output. This may cause extra lines
to be printed in between commits, in order for the graph history
@@ -803,31 +755,29 @@ you would get an output like this:
+
This enables parent rewriting, see 'History Simplification' below.
+
-This implies the '--topo-order' option by default, but the
-'--date-order' option may also be specified.
+This implies the `--topo-order` option by default, but the
+`--date-order` option may also be specified.
ifdef::git-rev-list[]
--count::
Print a number stating how many commits would have been
listed, and suppress all other output. When used together
- with '--left-right', instead print the counts for left and
+ with `--left-right`, instead print the counts for left and
right commits, separated by a tab. When used together with
- '--cherry-mark', omit patch equivalent commits from these
+ `--cherry-mark`, omit patch equivalent commits from these
counts and print the count for equivalent commits separated
by a tab.
endif::git-rev-list[]
-
ifndef::git-rev-list[]
Diff Formatting
~~~~~~~~~~~~~~~
-Below are listed options that control the formatting of diff output.
+Listed below are options that control the formatting of diff output.
Some of them are specific to linkgit:git-rev-list[1], however other diff
options may be given. See linkgit:git-diff-files[1] for more options.
-c::
-
With this option, diff output for a merge commit
shows the differences from each of the parents to the merge result
simultaneously instead of showing pairwise diff between a parent
@@ -835,26 +785,22 @@ options may be given. See linkgit:git-diff-files[1] for more options.
which were modified from all parents.
--cc::
-
- This flag implies the '-c' option and further compresses the
+ This flag implies the `-c` option and further compresses the
patch output by omitting uninteresting hunks whose contents in
the parents have only two variants and the merge result picks
one of them without modification.
-m::
-
This flag makes the merge commits show the full diff like
regular commits; for each merge parent, a separate log entry
and diff is generated. An exception is that only diff against
- the first parent is shown when '--first-parent' option is given;
+ the first parent is shown when `--first-parent` option is given;
in that case, the output represents the changes the merge
brought _into_ the then-current branch.
-r::
-
Show recursive diffs.
-t::
-
- Show the tree objects in the diff output. This implies '-r'.
+ Show the tree objects in the diff output. This implies `-r`.
endif::git-rev-list[]
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 2c06ed3..5a286d0 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -88,7 +88,7 @@ some output processing may assume ref names in UTF-8.
branch 'blabla' then '@\{1\}' means the same as 'blabla@\{1\}'.
'@\{-<n>\}', e.g. '@\{-1\}'::
- The construct '@\{-<n>\}' means the <n>th branch checked out
+ The construct '@\{-<n>\}' means the <n>th branch/commit checked out
before the current one.
'<branchname>@\{upstream\}', e.g. 'master@\{upstream\}', '@\{u\}'::
diff --git a/Documentation/technical/api-builtin.txt b/Documentation/technical/api-builtin.txt
index f3c1357..e3d6e7a 100644
--- a/Documentation/technical/api-builtin.txt
+++ b/Documentation/technical/api-builtin.txt
@@ -14,8 +14,8 @@ Git:
. Add the external declaration for the function to `builtin.h`.
-. Add the command to `commands[]` table in `handle_internal_command()`,
- defined in `git.c`. The entry should look like:
+. Add the command to the `commands[]` table defined in `git.c`.
+ The entry should look like:
{ "foo", cmd_foo, <options> },
+
diff --git a/Documentation/technical/api-hash.txt b/Documentation/technical/api-hash.txt
deleted file mode 100644
index e5061e0..0000000
--- a/Documentation/technical/api-hash.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-hash API
-========
-
-The hash API is a collection of simple hash table functions. Users are expected
-to implement their own hashing.
-
-Data Structures
----------------
-
-`struct hash_table`::
-
- The hash table structure. The `array` member points to the hash table
- entries. The `size` member counts the total number of valid and invalid
- entries in the table. The `nr` member keeps track of the number of
- valid entries.
-
-`struct hash_table_entry`::
-
- An opaque structure representing an entry in the hash table. The `hash`
- member is the entry's hash key and the `ptr` member is the entry's
- value.
-
-Functions
----------
-
-`init_hash`::
-
- Initialize the hash table.
-
-`free_hash`::
-
- Release memory associated with the hash table.
-
-`insert_hash`::
-
- Insert a pointer into the hash table. If an entry with that hash
- already exists, a pointer to the existing entry's value is returned.
- Otherwise NULL is returned. This allows callers to implement
- chaining, etc.
-
-`lookup_hash`::
-
- Lookup an entry in the hash table. If an entry with that hash exists
- the entry's value is returned. Otherwise NULL is returned.
-
-`for_each_hash`::
-
- Call a function for each entry in the hash table. The function is
- expected to take the entry's value as its only argument and return an
- int. If the function returns a negative int the loop is aborted
- immediately. Otherwise, the return value is accumulated and the sum
- returned upon completion of the loop.
diff --git a/Documentation/technical/api-hashmap.txt b/Documentation/technical/api-hashmap.txt
new file mode 100644
index 0000000..42ca234
--- /dev/null
+++ b/Documentation/technical/api-hashmap.txt
@@ -0,0 +1,235 @@
+hashmap API
+===========
+
+The hashmap API is a generic implementation of hash-based key-value mappings.
+
+Data Structures
+---------------
+
+`struct hashmap`::
+
+ The hash table structure.
++
+The `size` member keeps track of the total number of entries. The `cmpfn`
+member is a function used to compare two entries for equality. The `table` and
+`tablesize` members store the hash table and its size, respectively.
+
+`struct hashmap_entry`::
+
+ An opaque structure representing an entry in the hash table, which must
+ be used as first member of user data structures. Ideally it should be
+ followed by an int-sized member to prevent unused memory on 64-bit
+ systems due to alignment.
++
+The `hash` member is the entry's hash code and the `next` member points to the
+next entry in case of collisions (i.e. if multiple entries map to the same
+bucket).
+
+`struct hashmap_iter`::
+
+ An iterator structure, to be used with hashmap_iter_* functions.
+
+Types
+-----
+
+`int (*hashmap_cmp_fn)(const void *entry, const void *entry_or_key, const void *keydata)`::
+
+ User-supplied function to test two hashmap entries for equality. Shall
+ return 0 if the entries are equal.
++
+This function is always called with non-NULL `entry` / `entry_or_key`
+parameters that have the same hash code. When looking up an entry, the `key`
+and `keydata` parameters to hashmap_get and hashmap_remove are always passed
+as second and third argument, respectively. Otherwise, `keydata` is NULL.
+
+Functions
+---------
+
+`unsigned int strhash(const char *buf)`::
+`unsigned int strihash(const char *buf)`::
+`unsigned int memhash(const void *buf, size_t len)`::
+`unsigned int memihash(const void *buf, size_t len)`::
+
+ Ready-to-use hash functions for strings, using the FNV-1 algorithm (see
+ http://www.isthe.com/chongo/tech/comp/fnv).
++
+`strhash` and `strihash` take 0-terminated strings, while `memhash` and
+`memihash` operate on arbitrary-length memory.
++
+`strihash` and `memihash` are case insensitive versions.
+
+`void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function, size_t initial_size)`::
+
+ Initializes a hashmap structure.
++
+`map` is the hashmap to initialize.
++
+The `equals_function` can be specified to compare two entries for equality.
+If NULL, entries are considered equal if their hash codes are equal.
++
+If the total number of entries is known in advance, the `initial_size`
+parameter may be used to preallocate a sufficiently large table and thus
+prevent expensive resizing. If 0, the table is dynamically resized.
+
+`void hashmap_free(struct hashmap *map, int free_entries)`::
+
+ Frees a hashmap structure and allocated memory.
++
+`map` is the hashmap to free.
++
+If `free_entries` is true, each hashmap_entry in the map is freed as well
+(using stdlib's free()).
+
+`void hashmap_entry_init(void *entry, unsigned int hash)`::
+
+ Initializes a hashmap_entry structure.
++
+`entry` points to the entry to initialize.
++
+`hash` is the hash code of the entry.
+
+`void *hashmap_get(const struct hashmap *map, const void *key, const void *keydata)`::
+
+ Returns the hashmap entry for the specified key, or NULL if not found.
++
+`map` is the hashmap structure.
++
+`key` is a hashmap_entry structure (or user data structure that starts with
+hashmap_entry) that has at least been initialized with the proper hash code
+(via `hashmap_entry_init`).
++
+If an entry with matching hash code is found, `key` and `keydata` are passed
+to `hashmap_cmp_fn` to decide whether the entry matches the key.
+
+`void *hashmap_get_next(const struct hashmap *map, const void *entry)`::
+
+ Returns the next equal hashmap entry, or NULL if not found. This can be
+ used to iterate over duplicate entries (see `hashmap_add`).
++
+`map` is the hashmap structure.
++
+`entry` is the hashmap_entry to start the search from, obtained via a previous
+call to `hashmap_get` or `hashmap_get_next`.
+
+`void hashmap_add(struct hashmap *map, void *entry)`::
+
+ Adds a hashmap entry. This allows to add duplicate entries (i.e.
+ separate values with the same key according to hashmap_cmp_fn).
++
+`map` is the hashmap structure.
++
+`entry` is the entry to add.
+
+`void *hashmap_put(struct hashmap *map, void *entry)`::
+
+ Adds or replaces a hashmap entry. If the hashmap contains duplicate
+ entries equal to the specified entry, only one of them will be replaced.
++
+`map` is the hashmap structure.
++
+`entry` is the entry to add or replace.
++
+Returns the replaced entry, or NULL if not found (i.e. the entry was added).
+
+`void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata)`::
+
+ Removes a hashmap entry matching the specified key. If the hashmap
+ contains duplicate entries equal to the specified key, only one of
+ them will be removed.
++
+`map` is the hashmap structure.
++
+`key` is a hashmap_entry structure (or user data structure that starts with
+hashmap_entry) that has at least been initialized with the proper hash code
+(via `hashmap_entry_init`).
++
+If an entry with matching hash code is found, `key` and `keydata` are
+passed to `hashmap_cmp_fn` to decide whether the entry matches the key.
++
+Returns the removed entry, or NULL if not found.
+
+`void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter)`::
+`void *hashmap_iter_next(struct hashmap_iter *iter)`::
+`void *hashmap_iter_first(struct hashmap *map, struct hashmap_iter *iter)`::
+
+ Used to iterate over all entries of a hashmap.
++
+`hashmap_iter_init` initializes a `hashmap_iter` structure.
++
+`hashmap_iter_next` returns the next hashmap_entry, or NULL if there are no
+more entries.
++
+`hashmap_iter_first` is a combination of both (i.e. initializes the iterator
+and returns the first entry, if any).
+
+Usage example
+-------------
+
+Here's a simple usage example that maps long keys to double values.
+[source,c]
+------------
+struct hashmap map;
+
+struct long2double {
+ struct hashmap_entry ent; /* must be the first member! */
+ long key;
+ double value;
+};
+
+static int long2double_cmp(const struct long2double *e1, const struct long2double *e2, const void *unused)
+{
+ return !(e1->key == e2->key);
+}
+
+void long2double_init(void)
+{
+ hashmap_init(&map, (hashmap_cmp_fn) long2double_cmp, 0);
+}
+
+void long2double_free(void)
+{
+ hashmap_free(&map, 1);
+}
+
+static struct long2double *find_entry(long key)
+{
+ struct long2double k;
+ hashmap_entry_init(&k, memhash(&key, sizeof(long)));
+ k.key = key;
+ return hashmap_get(&map, &k, NULL);
+}
+
+double get_value(long key)
+{
+ struct long2double *e = find_entry(key);
+ return e ? e->value : 0;
+}
+
+void set_value(long key, double value)
+{
+ struct long2double *e = find_entry(key);
+ if (!e) {
+ e = malloc(sizeof(struct long2double));
+ hashmap_entry_init(e, memhash(&key, sizeof(long)));
+ e->key = key;
+ hashmap_add(&map, e);
+ }
+ e->value = value;
+}
+------------
+
+Using variable-sized keys
+-------------------------
+
+The `hashmap_entry_get` and `hashmap_entry_remove` functions expect an ordinary
+`hashmap_entry` structure as key to find the correct entry. If the key data is
+variable-sized (e.g. a FLEX_ARRAY string) or quite large, it is undesirable
+to create a full-fledged entry structure on the heap and copy all the key data
+into the structure.
+
+In this case, the `keydata` parameter can be used to pass
+variable-sized key data directly to the comparison function, and the `key`
+parameter can be a stripped-down, fixed size entry structure allocated on the
+stack.
+
+See test-hashmap.c for an example using arbitrary-length strings as keys.
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 0be2b51..be50cf4 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -29,9 +29,9 @@ that allow to change the behavior of a command.
The parse-options API allows:
-* 'sticked' and 'separate form' of options with arguments.
- `-oArg` is sticked, `-o Arg` is separate form.
- `--option=Arg` is sticked, `--option Arg` is separate form.
+* 'stuck' and 'separate form' of options with arguments.
+ `-oArg` is stuck, `-o Arg` is separate form.
+ `--option=Arg` is stuck, `--option Arg` is separate form.
* Long options may be 'abbreviated', as long as the abbreviation
is unambiguous.
diff --git a/Documentation/technical/api-ref-iteration.txt b/Documentation/technical/api-ref-iteration.txt
index aa1c50f..02adfd4 100644
--- a/Documentation/technical/api-ref-iteration.txt
+++ b/Documentation/technical/api-ref-iteration.txt
@@ -50,10 +50,10 @@ submodules object database. You can do this by a code-snippet like
this:
const char *path = "path/to/submodule"
- if (!add_submodule_odb(path))
+ if (add_submodule_odb(path))
die("Error submodule '%s' not populated.", path);
-`add_submodule_odb()` will return an non-zero value on success. If you
+`add_submodule_odb()` will return zero on success. If you
do not do this you will get an error for each ref that it does not point
to a valid object.
diff --git a/Documentation/technical/api-remote.txt b/Documentation/technical/api-remote.txt
index 4be8776..5d245aa 100644
--- a/Documentation/technical/api-remote.txt
+++ b/Documentation/technical/api-remote.txt
@@ -58,16 +58,16 @@ default remote, given the current branch and configuration.
struct refspec
--------------
-A struct refspec holds the parsed interpretation of a refspec. If it
-will force updates (starts with a '+'), force is true. If it is a
-pattern (sides end with '*') pattern is true. src and dest are the two
-sides (if a pattern, only the part outside of the wildcards); if there
-is only one side, it is src, and dst is NULL; if sides exist but are
-empty (i.e., the refspec either starts or ends with ':'), the
-corresponding side is "".
-
-This parsing can be done to an array of strings to give an array of
-struct refpsecs with parse_ref_spec().
+A struct refspec holds the parsed interpretation of a refspec. If it
+will force updates (starts with a '+'), force is true. If it is a
+pattern (sides end with '*') pattern is true. src and dest are the
+two sides (including '*' characters if present); if there is only one
+side, it is src, and dst is NULL; if sides exist but are empty (i.e.,
+the refspec either starts or ends with ':'), the corresponding side is
+"".
+
+An array of strings can be parsed into an array of struct refspecs
+using parse_fetch_refspec() or parse_push_refspec().
remote_find_tracking(), given a remote and a struct refspec with
either src or dst filled out, will fill out the other such that the
diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt
index caf941a..544373b 100644
--- a/Documentation/technical/http-protocol.txt
+++ b/Documentation/technical/http-protocol.txt
@@ -20,13 +20,13 @@ 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
+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
+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.
+supplied `$GIT_URL` string.
An example of a dumb client requesting for a loose object:
@@ -43,10 +43,10 @@ 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
+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'.
+`$GIT_URL/info/refs` as `foo/info/refs` and not `foo//info/refs`.
Authentication
@@ -103,14 +103,14 @@ 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
+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
+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.
@@ -126,9 +126,9 @@ 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
+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.
+`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
@@ -148,7 +148,7 @@ 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,
+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
@@ -161,21 +161,21 @@ without any search/query parameters.
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.
+`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-".
+`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'.
+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'.
+the default ref named `HEAD`.
info_refs = *( ref_record )
ref_record = any_ref / peeled_ref
@@ -192,13 +192,14 @@ HTTP clients that support the "smart" protocol (or both the
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
+`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:
+dumb server reply:
+
S: 200 OK
S:
S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint
@@ -206,7 +207,8 @@ The request MUST NOT contain additional query parameters.
S: 2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0
S: a3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}
- smart server reply:
+smart server reply:
+
S: 200 OK
S: Content-Type: application/x-git-upload-pack-advertisement
S: Cache-Control: no-cache
@@ -228,7 +230,7 @@ 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.
+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.
@@ -236,35 +238,35 @@ 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'.
+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
+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 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
+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".
+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
+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
+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)
@@ -286,12 +288,13 @@ declarations behind a NUL on the first ref.
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.
+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'.
+`$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
@@ -307,16 +310,16 @@ Clients MUST first perform ref discovery with
S: ....ACK %s, continue
S: ....NAK
-Clients MUST NOT reuse or revalidate a cached reponse.
+Clients MUST NOT reuse or revalidate a cached response.
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
+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".
+server advertises capability `allow-tip-sha1-in-want`.
compute_request = want_list
have_list
@@ -332,128 +335,128 @@ server advertises capability "allow-tip-sha1-in-want".
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):
+(C = client, S = server):
+
+'init step:'
+
+C: Use ref discovery to obtain the advertised refs.
+
+C: Place any object seen into set `advertised`.
- 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 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: 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.
+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:
+'one compute step:'
- C: 0032want <WANT #1>...............................
- C: 0032want <WANT #2>...............................
+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 <common #1>.............................
+ C: 0032have <common #2>.............................
....
- C: 0032have <HAVE #1>...............................
- C: 0032have <HAVE #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.
+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:
+Commands MUST appear in the following order, if they appear
+at all in the request stream:
- * want
- * have
+* "want"
+* "have"
- The stream is terminated by a pkt-line flush ("0000").
+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.
+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.
+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:
+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.
+S: Parse the git-upload-pack request:
- If no WANT objects are received, send an error:
+Verify all objects in `want` are directly reachable from refs.
-TODO: Define error if no want lines are requested.
+The server MAY walk backwards through history or through
+the reflog to permit slightly stale requests.
- If any WANT object is not reachable, send an error:
+If no "want" objects are received, send an error:
+TODO: Define error if no "want" lines are requested.
-TODO: Define error if an invalid want is 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.
+Create an empty list, `s_common`.
- If 'have' was sent:
+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.
+Loop through the objects in the order supplied by the client.
- (s) Send the git-upload-pack response:
+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`.
- If the server has found a closed set of objects to pack or the
- request ends with "done", it replies with the pack.
+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.
+ S: PACK...
- Here a "closed set of objects" is defined to have at least
- one path from every WANT to at least one COMMON object.
+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.
- If the server needs more information, it replies with a
- status continue response:
+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
+C: Parse the upload-pack response:
+ TODO: Document parsing response
- Do another compute step.
+'Do another compute step.'
Smart Service git-receive-pack
------------------------------
-This service reads from the repository pointed to by $GIT_URL.
+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'.
+`$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
@@ -468,7 +471,7 @@ Clients MUST first perform ref discovery with
S:
S: ....
-Clients MUST NOT reuse or revalidate a cached reponse.
+Clients MUST NOT reuse or revalidate a cached response.
Servers MUST include sufficient Cache-Control headers
to prevent caching of the response.
diff --git a/Documentation/technical/pack-heuristics.txt b/Documentation/technical/pack-heuristics.txt
index b7bd951..95a07db 100644
--- a/Documentation/technical/pack-heuristics.txt
+++ b/Documentation/technical/pack-heuristics.txt
@@ -1,5 +1,5 @@
- Concerning Git's Packing Heuristics
- ===================================
+Concerning Git's Packing Heuristics
+===================================
Oh, here's a really stupid question:
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index b898e97..c73b62f 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -161,6 +161,7 @@ MUST peel the ref if it's an annotated tag.
----
advertised-refs = (no-refs / list-of-refs)
+ *shallow
flush-pkt
no-refs = PKT-LINE(zero-id SP "capabilities^{}"
@@ -174,6 +175,8 @@ MUST peel the ref if it's an annotated tag.
other-tip = obj-id SP refname LF
other-peeled = obj-id SP refname "^{}" LF
+ shallow = PKT-LINE("shallow" SP obj-id)
+
capability-list = capability *(SP capability)
capability = 1*(LC_ALPHA / DIGIT / "-" / "_")
LC_ALPHA = %x61-7A
@@ -461,7 +464,9 @@ contain all the objects that the server will need to complete the new
references.
----
- update-request = command-list [pack-file]
+ update-request = *shallow command-list [pack-file]
+
+ shallow = PKT-LINE("shallow" SP obj-id)
command-list = PKT-LINE(command NUL capability-list LF)
*PKT-LINE(command LF)
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index fd8ffa5..e3e7924 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -72,14 +72,29 @@ interleaved with S-R-Q.
thin-pack
---------
-This capability means that the server can send a 'thin' pack, a pack
-which does not contain base objects; if those base objects are available
-on client side. Client requests 'thin-pack' capability when it
-understands how to "thicken" it by adding required delta bases making
-it self-contained.
-
-Client MUST NOT request 'thin-pack' capability if it cannot turn a thin
-pack into a self-contained pack.
+A thin pack is one with deltas which reference base objects not
+contained within the pack (but are known to exist at the receiving
+end). This can reduce the network traffic significantly, but it
+requires the receiving end to know how to "thicken" these packs by
+adding the missing bases to the pack.
+
+The upload-pack server advertises 'thin-pack' when it can generate
+and send a thin pack. A client requests the 'thin-pack' capability
+when it understands how to "thicken" it, notifying the server that
+it can receive such a pack. A client MUST NOT request the
+'thin-pack' capability if it cannot turn a thin pack into a
+self-contained pack.
+
+Receive-pack, on the other hand, is assumed by default to be able to
+handle thin packs, but can ask the client not to use the feature by
+advertising the 'no-thin' capability. A client MUST NOT send a thin
+pack if the server advertises the 'no-thin' capability.
+
+The reasons for this asymmetry are historical. The receive-pack
+program did not exist until after the invention of thin packs, so
+historically the reference implementation of receive-pack always
+understood thin packs. Adding 'no-thin' later allowed receive-pack
+to disable the feature in a backwards-compatible manner.
side-band, side-band-64k
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index cbb01a1..d4f9804 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1,5 +1,5 @@
Git User Manual
-_______________
+===============
Git is a fast distributed revision control system.
@@ -3795,7 +3795,7 @@ like so:
$ git update-index filename
-------------------------------------------------
-but to avoid common mistakes with filename globbing etc, the command
+but to avoid common mistakes with filename globbing etc., the command
will not normally add totally new entries or remove old entries,
i.e. it will normally just update existing cache entries.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index b444c18..2b97352 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.4.GIT
+DEF_VER=v1.9.0
LF='
'
diff --git a/Makefile b/Makefile
index 555d44c..d4ce53a 100644
--- a/Makefile
+++ b/Makefile
@@ -452,7 +452,6 @@ SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-difftool--helper.sh
SCRIPT_SH += git-filter-branch.sh
-SCRIPT_SH += git-lost-found.sh
SCRIPT_SH += git-merge-octopus.sh
SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
@@ -556,6 +555,7 @@ TEST_PROGRAMS_NEED_X += test-date
TEST_PROGRAMS_NEED_X += test-delta
TEST_PROGRAMS_NEED_X += test-dump-cache-tree
TEST_PROGRAMS_NEED_X += test-genrandom
+TEST_PROGRAMS_NEED_X += test-hashmap
TEST_PROGRAMS_NEED_X += test-index-version
TEST_PROGRAMS_NEED_X += test-line-buffer
TEST_PROGRAMS_NEED_X += test-match-trees
@@ -587,11 +587,8 @@ BUILT_INS += git-cherry$X
BUILT_INS += git-cherry-pick$X
BUILT_INS += git-format-patch$X
BUILT_INS += git-fsck-objects$X
-BUILT_INS += git-get-tar-commit-id$X
BUILT_INS += git-init$X
BUILT_INS += git-merge-subtree$X
-BUILT_INS += git-peek-remote$X
-BUILT_INS += git-repo-config$X
BUILT_INS += git-show$X
BUILT_INS += git-stage$X
BUILT_INS += git-status$X
@@ -677,7 +674,7 @@ LIB_H += git-compat-util.h
LIB_H += gpg-interface.h
LIB_H += graph.h
LIB_H += grep.h
-LIB_H += hash.h
+LIB_H += hashmap.h
LIB_H += help.h
LIB_H += http.h
LIB_H += kwset.h
@@ -814,7 +811,7 @@ LIB_OBJS += gettext.o
LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o
LIB_OBJS += grep.o
-LIB_OBJS += hash.o
+LIB_OBJS += hashmap.o
LIB_OBJS += help.o
LIB_OBJS += hex.o
LIB_OBJS += ident.o
@@ -943,6 +940,7 @@ BUILTIN_OBJS += builtin/fmt-merge-msg.o
BUILTIN_OBJS += builtin/for-each-ref.o
BUILTIN_OBJS += builtin/fsck.o
BUILTIN_OBJS += builtin/gc.o
+BUILTIN_OBJS += builtin/get-tar-commit-id.o
BUILTIN_OBJS += builtin/grep.o
BUILTIN_OBJS += builtin/hash-object.o
BUILTIN_OBJS += builtin/help.o
@@ -994,7 +992,6 @@ BUILTIN_OBJS += builtin/show-ref.o
BUILTIN_OBJS += builtin/stripspace.o
BUILTIN_OBJS += builtin/symbolic-ref.o
BUILTIN_OBJS += builtin/tag.o
-BUILTIN_OBJS += builtin/tar-tree.o
BUILTIN_OBJS += builtin/unpack-file.o
BUILTIN_OBJS += builtin/unpack-objects.o
BUILTIN_OBJS += builtin/update-index.o
@@ -1599,6 +1596,7 @@ PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
DIFF_SQ = $(subst ','\'',$(DIFF))
+PERLLIB_EXTRA_SQ = $(subst ','\'',$(PERLLIB_EXTRA))
LIBS = $(GITLIBS) $(EXTLIBS)
@@ -1787,7 +1785,7 @@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
git.res: git.rc GIT-VERSION-FILE
$(QUIET_RC)$(RC) \
- $(join -DMAJOR= -DMINOR= -DPATCH=, $(wordlist 1,3,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \
+ $(join -DMAJOR= -DMINOR=, $(wordlist 1,2,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \
-DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" $< -o $@
ifndef NO_PERL
@@ -1803,9 +1801,12 @@ perl/PM.stamp: FORCE
perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
-$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
+PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ)
+$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl perl/perl.mak GIT-PERL-DEFINES GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $@+ && \
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
+ INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \
+ INSTLIBDIR="$$INSTLIBDIR$${INSTLIBDIR_EXTRA:+:$$INSTLIBDIR_EXTRA}" && \
sed -e '1{' \
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
-e ' h' \
@@ -1818,6 +1819,13 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
chmod +x $@+ && \
mv $@+ $@
+GIT-PERL-DEFINES: FORCE
+ @FLAGS='$(PERL_DEFINES)'; \
+ if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
+ echo >&2 " * new perl-specific parameters"; \
+ echo "$$FLAGS" >$@; \
+ fi
+
.PHONY: gitweb
gitweb:
@@ -2054,10 +2062,10 @@ git-imap-send$X: imap-send.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
-git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
+git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL)
-git-http-push$X: revision.o http.o http-push.o GIT-LDFLAGS $(GITLIBS)
+git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
@@ -2506,7 +2514,8 @@ ifndef NO_TCLTK
$(MAKE) -C git-gui clean
endif
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
- $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES GIT-PYTHON-VARS
+ $(RM) GIT-USER-AGENT GIT-PREFIX
+ $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PYTHON-VARS
.PHONY: all install profile-clean clean strip
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
diff --git a/RelNotes b/RelNotes
index 61c3b54..bb52cf9 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.5.txt \ No newline at end of file
+Documentation/RelNotes/1.9.0.txt \ No newline at end of file
diff --git a/abspath.c b/abspath.c
index 64adbe2..ca33558 100644
--- a/abspath.c
+++ b/abspath.c
@@ -110,7 +110,7 @@ static const char *real_path_internal(const char *path, int die_on_error)
else
goto error_out;
}
- if (len && !is_dir_sep(buf[len-1]))
+ if (len && !is_dir_sep(buf[len - 1]))
buf[len++] = '/';
strcpy(buf + len, last_elem);
free(last_elem);
@@ -143,7 +143,7 @@ static const char *real_path_internal(const char *path, int die_on_error)
error_out:
free(last_elem);
if (*cwd && chdir(cwd))
- die_errno ("Could not change back to '%s'", cwd);
+ die_errno("Could not change back to '%s'", cwd);
return retval;
}
@@ -201,7 +201,7 @@ const char *absolute_path(const char *path)
if (!cwd)
die_errno("Cannot determine the current working directory");
len = strlen(cwd);
- fmt = (len > 0 && is_dir_sep(cwd[len-1])) ? "%s%s" : "%s/%s";
+ fmt = (len > 0 && is_dir_sep(cwd[len - 1])) ? "%s%s" : "%s/%s";
if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX)
die("Too long path: %.*s", 60, path);
}
@@ -215,23 +215,25 @@ 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];
+ static struct strbuf path = STRBUF_INIT;
#ifndef GIT_WINDOWS_NATIVE
if (!pfx_len || is_absolute_path(arg))
return arg;
- memcpy(path, pfx, pfx_len);
- strcpy(path + pfx_len, arg);
+ strbuf_reset(&path);
+ strbuf_add(&path, pfx, pfx_len);
+ strbuf_addstr(&path, arg);
#else
char *p;
/* don't add prefix to absolute paths, but still replace '\' by '/' */
+ strbuf_reset(&path);
if (is_absolute_path(arg))
pfx_len = 0;
else if (pfx_len)
- memcpy(path, pfx, pfx_len);
- strcpy(path + pfx_len, arg);
- for (p = path + pfx_len; *p; p++)
+ strbuf_add(&path, pfx, pfx_len);
+ strbuf_addstr(&path, arg);
+ for (p = path.buf + pfx_len; *p; p++)
if (*p == '\\')
*p = '/';
#endif
- return path;
+ return path.buf;
}
diff --git a/alias.c b/alias.c
index eb9f08b..5efc3d6 100644
--- a/alias.c
+++ b/alias.c
@@ -5,7 +5,7 @@ static char *alias_val;
static int alias_lookup_cb(const char *k, const char *v, void *cb)
{
- if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
+ if (starts_with(k, "alias.") && !strcmp(k + 6, alias_key)) {
if (!v)
return config_error_nonbool(k);
alias_val = xstrdup(v);
@@ -34,7 +34,7 @@ int split_cmdline(char *cmdline, const char ***argv)
int src, dst, count = 0, size = 16;
char quoted = 0;
- *argv = xmalloc(sizeof(char *) * size);
+ *argv = xmalloc(sizeof(**argv) * size);
/* split alias_string */
(*argv)[count++] = cmdline;
@@ -45,7 +45,7 @@ int split_cmdline(char *cmdline, const char ***argv)
while (cmdline[++src]
&& isspace(cmdline[src]))
; /* skip */
- ALLOC_GROW(*argv, count+1, size);
+ ALLOC_GROW(*argv, count + 1, size);
(*argv)[count++] = cmdline + dst;
} else if (!quoted && (c == '\'' || c == '"')) {
quoted = c;
@@ -76,12 +76,13 @@ int split_cmdline(char *cmdline, const char ***argv)
return -SPLIT_CMDLINE_UNCLOSED_QUOTE;
}
- ALLOC_GROW(*argv, count+1, size);
+ ALLOC_GROW(*argv, count + 1, size);
(*argv)[count] = NULL;
return count;
}
-const char *split_cmdline_strerror(int split_cmdline_errno) {
- return split_cmdline_errors[-split_cmdline_errno-1];
+const char *split_cmdline_strerror(int split_cmdline_errno)
+{
+ return split_cmdline_errors[-split_cmdline_errno - 1];
}
diff --git a/alloc.c b/alloc.c
index aeae55c..f3ee745 100644
--- a/alloc.c
+++ b/alloc.c
@@ -58,7 +58,7 @@ static void report(const char *name, unsigned int count, size_t size)
}
#define REPORT(name) \
- report(#name, name##_allocs, name##_allocs*sizeof(struct name) >> 10)
+ report(#name, name##_allocs, name##_allocs * sizeof(struct name) >> 10)
void alloc_report(void)
{
diff --git a/archive.c b/archive.c
index 99fadc8..346f3b2 100644
--- a/archive.c
+++ b/archive.c
@@ -440,7 +440,7 @@ static int match_extension(const char *filename, const char *ext)
* prefix is non-empty (k.e., we don't match .tar.gz with no actual
* filename).
*/
- if (prefixlen < 2 || filename[prefixlen-1] != '.')
+ if (prefixlen < 2 || filename[prefixlen - 1] != '.')
return 0;
return !strcmp(filename + prefixlen, ext);
}
diff --git a/attr.c b/attr.c
index 0e774c6..8d13d70 100644
--- a/attr.c
+++ b/attr.c
@@ -211,7 +211,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
name = cp;
namelen = strcspn(name, blank);
if (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen &&
- !prefixcmp(name, ATTRIBUTE_MACRO_PREFIX)) {
+ starts_with(name, ATTRIBUTE_MACRO_PREFIX)) {
if (!macro_ok) {
fprintf(stderr, "%s not allowed: %s:%d\n",
name, src, lineno);
diff --git a/base85.c b/base85.c
index 781b575..5ca601e 100644
--- a/base85.c
+++ b/base85.c
@@ -41,7 +41,7 @@ int decode_85(char *dst, const char *buffer, int len)
{
prep_base85();
- say2("decode 85 <%.*s>", len/4*5, buffer);
+ say2("decode 85 <%.*s>", len / 4 * 5, buffer);
while (len) {
unsigned acc = 0;
int de, cnt = 4;
diff --git a/bisect.c b/bisect.c
index 1e46a4f..8448d27 100644
--- a/bisect.c
+++ b/bisect.c
@@ -406,9 +406,9 @@ static int register_ref(const char *refname, const unsigned char *sha1,
if (!strcmp(refname, "bad")) {
current_bad_sha1 = xmalloc(20);
hashcpy(current_bad_sha1, sha1);
- } else if (!prefixcmp(refname, "good-")) {
+ } else if (starts_with(refname, "good-")) {
sha1_array_append(&good_revs, sha1);
- } else if (!prefixcmp(refname, "skip-")) {
+ } else if (starts_with(refname, "skip-")) {
sha1_array_append(&skipped_revs, sha1);
}
@@ -685,7 +685,6 @@ static void mark_expected_rev(char *bisect_rev_hex)
static int bisect_checkout(char *bisect_rev_hex, int no_checkout)
{
- int res;
mark_expected_rev(bisect_rev_hex);
@@ -696,6 +695,7 @@ static int bisect_checkout(char *bisect_rev_hex, int no_checkout)
die("update-ref --no-deref HEAD failed on %s",
bisect_rev_hex);
} else {
+ int res;
res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
if (res)
exit(res);
diff --git a/block-sha1/sha1.c b/block-sha1/sha1.c
index 6d637bd..22b125c 100644
--- a/block-sha1/sha1.c
+++ b/block-sha1/sha1.c
@@ -242,10 +242,10 @@ void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx)
padlen[1] = htonl((uint32_t)(ctx->size << 3));
i = ctx->size & 63;
- blk_SHA1_Update(ctx, pad, 1+ (63 & (55 - i)));
+ blk_SHA1_Update(ctx, pad, 1 + (63 & (55 - i)));
blk_SHA1_Update(ctx, padlen, 8);
/* Output hash */
for (i = 0; i < 5; i++)
- put_be32(hashout + i*4, ctx->H[i]);
+ put_be32(hashout + i * 4, ctx->H[i]);
}
diff --git a/branch.c b/branch.c
index 9e6c68e..723a36b 100644
--- a/branch.c
+++ b/branch.c
@@ -50,7 +50,7 @@ static int should_setup_rebase(const char *origin)
void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
{
const char *shortname = remote + 11;
- int remote_is_branch = !prefixcmp(remote, "refs/heads/");
+ int remote_is_branch = starts_with(remote, "refs/heads/");
struct strbuf key = STRBUF_INIT;
int rebasing = should_setup_rebase(origin);
@@ -272,7 +272,7 @@ void create_branch(const char *head,
break;
case 1:
/* Unique completion -- good, only if it is a real branch */
- if (prefixcmp(real_ref, "refs/heads/") &&
+ if (!starts_with(real_ref, "refs/heads/") &&
validate_remote_tracking_branch(real_ref)) {
if (explicit_tracking)
die(_(upstream_not_branch), start_name);
diff --git a/builtin.h b/builtin.h
index b56cf07..c47c110 100644
--- a/builtin.h
+++ b/builtin.h
@@ -27,6 +27,8 @@ extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);
+extern int is_builtin(const char *s);
+
extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
extern int cmd_apply(int argc, const char **argv, const char *prefix);
@@ -103,7 +105,6 @@ extern int cmd_remote(int argc, const char **argv, const char *prefix);
extern int cmd_remote_ext(int argc, const char **argv, const char *prefix);
extern int cmd_remote_fd(int argc, const char **argv, const char *prefix);
extern int cmd_repack(int argc, const char **argv, const char *prefix);
-extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
extern int cmd_rerere(int argc, const char **argv, const char *prefix);
extern int cmd_reset(int argc, const char **argv, const char *prefix);
extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index 226f758..672adc0 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -208,8 +208,7 @@ static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,
i = dir->nr;
while (--i >= 0) {
struct dir_entry *entry = *src++;
- if (match_pathspec_depth(pathspec, entry->name, entry->len,
- prefix, seen))
+ if (dir_path_match(entry, pathspec, prefix, seen))
*dst++ = entry;
else if (flag & WARN_IMPLICIT_DOT)
/*
@@ -540,11 +539,14 @@ int cmd_add(int argc, const char **argv, const char *prefix)
PATHSPEC_FROMTOP |
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
- PATHSPEC_ICASE);
+ PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE);
for (i = 0; i < pathspec.nr; i++) {
const char *path = pathspec.items[i].match;
- if (!seen[i] &&
+ if (pathspec.items[i].magic & PATHSPEC_EXCLUDE)
+ continue;
+ if (!seen[i] && path[0] &&
((pathspec.items[i].magic &
(PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
!file_exists(path))) {
diff --git a/builtin/apply.c b/builtin/apply.c
index ef32e4f..a7e72d5 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1409,10 +1409,10 @@ static void recount_diff(const char *line, int size, struct fragment *fragment)
case '\\':
continue;
case '@':
- ret = size < 3 || prefixcmp(line, "@@ ");
+ ret = size < 3 || !starts_with(line, "@@ ");
break;
case 'd':
- ret = size < 5 || prefixcmp(line, "diff ");
+ ret = size < 5 || !starts_with(line, "diff ");
break;
default:
ret = -1;
@@ -1798,11 +1798,11 @@ static struct fragment *parse_binary_hunk(char **buf_p,
*status_p = 0;
- if (!prefixcmp(buffer, "delta ")) {
+ if (starts_with(buffer, "delta ")) {
patch_method = BINARY_DELTA_DEFLATED;
origlen = strtoul(buffer + 6, NULL, 10);
}
- else if (!prefixcmp(buffer, "literal ")) {
+ else if (starts_with(buffer, "literal ")) {
patch_method = BINARY_LITERAL_DEFLATED;
origlen = strtoul(buffer + 8, NULL, 10);
}
@@ -1943,13 +1943,7 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
size - offset - hdrsize, patch);
if (!patchsize) {
- static const char *binhdr[] = {
- "Binary files ",
- "Files ",
- NULL,
- };
static const char git_binary[] = "GIT binary patch\n";
- int i;
int hd = hdrsize + offset;
unsigned long llen = linelen(buffer + hd, size - hd);
@@ -1965,6 +1959,12 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
patchsize = 0;
}
else if (!memcmp(" differ\n", buffer + hd + llen - 8, 8)) {
+ static const char *binhdr[] = {
+ "Binary files ",
+ "Files ",
+ NULL,
+ };
+ int i;
for (i = 0; binhdr[i]; i++) {
int len = strlen(binhdr[i]);
if (len < size - hd &&
@@ -3627,12 +3627,12 @@ static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20
hunk->oldpos == 1 && hunk->oldlines == 1 &&
/* does preimage begin with the heading? */
(preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL &&
- !prefixcmp(++preimage, heading) &&
+ starts_with(++preimage, heading) &&
/* does it record full SHA-1? */
!get_sha1_hex(preimage + sizeof(heading) - 1, sha1) &&
preimage[sizeof(heading) + 40 - 1] == '\n' &&
/* does the abbreviated name on the index line agree with it? */
- !prefixcmp(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
+ starts_with(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
return 0; /* it all looks fine */
/* we may have full object name on the index line */
diff --git a/builtin/archive.c b/builtin/archive.c
index 49178f1..a1e3b94 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -57,9 +57,9 @@ static int run_remote_archiver(int argc, const char **argv,
if (!buf)
die(_("git archive: expected ACK/NAK, got EOF"));
if (strcmp(buf, "ACK")) {
- if (!prefixcmp(buf, "NACK "))
+ if (starts_with(buf, "NACK "))
die(_("git archive: NACK %s"), buf + 5);
- if (!prefixcmp(buf, "ERR "))
+ if (starts_with(buf, "ERR "))
die(_("remote error: %s"), buf + 4);
die(_("git archive: protocol error"));
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 6da7233..e5b5d71 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -197,7 +197,6 @@ static void drop_origin_blob(struct origin *o)
* scoreboard structure, sorted by the target line number.
*/
struct blame_entry {
- struct blame_entry *prev;
struct blame_entry *next;
/* the first line of this group in the final image;
@@ -256,15 +255,6 @@ struct scoreboard {
int *lineno;
};
-static inline int same_suspect(struct origin *a, struct origin *b)
-{
- if (a == b)
- return 1;
- if (a->commit != b->commit)
- return 0;
- return !strcmp(a->path, b->path);
-}
-
static void sanity_check_refcnt(struct scoreboard *);
/*
@@ -277,13 +267,11 @@ static void coalesce(struct scoreboard *sb)
struct blame_entry *ent, *next;
for (ent = sb->ent; ent && (next = ent->next); ent = next) {
- if (same_suspect(ent->suspect, next->suspect) &&
+ if (ent->suspect == next->suspect &&
ent->guilty == next->guilty &&
ent->s_lno + ent->num_lines == next->s_lno) {
ent->num_lines += next->num_lines;
ent->next = next->next;
- if (ent->next)
- ent->next->prev = ent;
origin_decref(next->suspect);
free(next);
ent->score = 0;
@@ -409,7 +397,9 @@ static struct origin *find_origin(struct scoreboard *sb,
paths[0] = origin->path;
paths[1] = NULL;
- parse_pathspec(&diff_opts.pathspec, PATHSPEC_ALL_MAGIC, 0, "", paths);
+ parse_pathspec(&diff_opts.pathspec,
+ PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
+ PATHSPEC_LITERAL_PATH, "", paths);
diff_setup_done(&diff_opts);
if (is_null_sha1(origin->commit->object.sha1))
@@ -532,7 +522,7 @@ static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
prev = ent;
/* prev, if not NULL, is the last one that is below e */
- e->prev = prev;
+
if (prev) {
e->next = prev->next;
prev->next = e;
@@ -541,8 +531,6 @@ static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
e->next = sb->ent;
sb->ent = e;
}
- if (e->next)
- e->next->prev = e;
}
/*
@@ -553,14 +541,12 @@ static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
*/
static void dup_entry(struct blame_entry *dst, struct blame_entry *src)
{
- struct blame_entry *p, *n;
+ struct blame_entry *n;
- p = dst->prev;
n = dst->next;
origin_incref(src->suspect);
origin_decref(dst->suspect);
memcpy(dst, src, sizeof(*src));
- dst->prev = p;
dst->next = n;
dst->score = 0;
}
@@ -740,7 +726,7 @@ static int find_last_in_target(struct scoreboard *sb, struct origin *target)
int last_in_target = -1;
for (e = sb->ent; e; e = e->next) {
- if (e->guilty || !same_suspect(e->suspect, target))
+ if (e->guilty || e->suspect != target)
continue;
if (last_in_target < e->s_lno + e->num_lines)
last_in_target = e->s_lno + e->num_lines;
@@ -760,7 +746,7 @@ static void blame_chunk(struct scoreboard *sb,
struct blame_entry *e;
for (e = sb->ent; e; e = e->next) {
- if (e->guilty || !same_suspect(e->suspect, target))
+ if (e->guilty || e->suspect != target)
continue;
if (same <= e->s_lno)
continue;
@@ -937,7 +923,6 @@ static void find_copy_in_blob(struct scoreboard *sb,
mmfile_t *file_p)
{
const char *cp;
- int cnt;
mmfile_t file_o;
struct handle_split_cb_data d;
@@ -948,13 +933,7 @@ static void find_copy_in_blob(struct scoreboard *sb,
*/
cp = nth_line(sb, ent->lno);
file_o.ptr = (char *) cp;
- cnt = ent->num_lines;
-
- while (cnt && cp < sb->final_buf + sb->final_buf_size) {
- if (*cp++ == '\n')
- cnt--;
- }
- file_o.size = cp - file_o.ptr;
+ file_o.size = nth_line(sb, ent->lno + ent->num_lines) - cp;
/*
* file_o is a part of final image we are annotating.
@@ -990,7 +969,7 @@ static int find_move_in_parent(struct scoreboard *sb,
while (made_progress) {
made_progress = 0;
for (e = sb->ent; e; e = e->next) {
- if (e->guilty || !same_suspect(e->suspect, target) ||
+ if (e->guilty || e->suspect != target ||
ent_score(sb, e) < blame_move_score)
continue;
find_copy_in_blob(sb, e, parent, split, &file_p);
@@ -1025,14 +1004,14 @@ static struct blame_list *setup_blame_list(struct scoreboard *sb,
for (e = sb->ent, num_ents = 0; e; e = e->next)
if (!e->scanned && !e->guilty &&
- same_suspect(e->suspect, target) &&
+ e->suspect == target &&
min_score < ent_score(sb, e))
num_ents++;
if (num_ents) {
blame_list = xcalloc(num_ents, sizeof(struct blame_list));
for (e = sb->ent, i = 0; e; e = e->next)
if (!e->scanned && !e->guilty &&
- same_suspect(e->suspect, target) &&
+ e->suspect == target &&
min_score < ent_score(sb, e))
blame_list[i++].ent = e;
}
@@ -1176,7 +1155,7 @@ static void pass_whole_blame(struct scoreboard *sb,
origin->file.ptr = NULL;
}
for (e = sb->ent; e; e = e->next) {
- if (!same_suspect(e->suspect, origin))
+ if (e->suspect != origin)
continue;
origin_incref(porigin);
origin_decref(e->suspect);
@@ -1549,8 +1528,7 @@ static void assign_blame(struct scoreboard *sb, int opt)
*/
origin_incref(suspect);
commit = suspect->commit;
- if (!commit->object.parsed)
- parse_commit(commit);
+ parse_commit(commit);
if (reverse ||
(!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age)))
@@ -1566,7 +1544,7 @@ static void assign_blame(struct scoreboard *sb, int opt)
/* Take responsibility for the remaining entries */
for (ent = sb->ent; ent; ent = ent->next)
- if (same_suspect(ent->suspect, suspect))
+ if (ent->suspect == suspect)
found_guilty_entry(ent);
origin_decref(suspect);
@@ -1579,14 +1557,14 @@ static const char *format_time(unsigned long time, const char *tz_str,
int show_raw_time)
{
static char time_buf[128];
- const char *time_str;
- int time_len;
- int tz;
if (show_raw_time) {
snprintf(time_buf, sizeof(time_buf), "%lu %s", time, tz_str);
}
else {
+ const char *time_str;
+ int time_len;
+ int tz;
tz = atoi(tz_str);
time_str = show_date(time, tz, blame_date_mode);
time_len = strlen(time_str);
@@ -1771,25 +1749,41 @@ static int prepare_lines(struct scoreboard *sb)
{
const char *buf = sb->final_buf;
unsigned long len = sb->final_buf_size;
- int num = 0, incomplete = 0, bol = 1;
+ const char *end = buf + len;
+ const char *p;
+ int *lineno;
+ int num = 0, incomplete = 0;
- if (len && buf[len-1] != '\n')
- incomplete++; /* incomplete line at the end */
- while (len--) {
- if (bol) {
- sb->lineno = xrealloc(sb->lineno,
- sizeof(int *) * (num + 1));
- sb->lineno[num] = buf - sb->final_buf;
- bol = 0;
- }
- if (*buf++ == '\n') {
+ for (p = buf;;) {
+ p = memchr(p, '\n', end - p);
+ if (p) {
+ p++;
num++;
- bol = 1;
+ continue;
}
+ break;
+ }
+
+ if (len && end[-1] != '\n')
+ incomplete++; /* incomplete line at the end */
+
+ sb->lineno = xmalloc(sizeof(*sb->lineno) * (num + incomplete + 1));
+ lineno = sb->lineno;
+
+ *lineno++ = 0;
+ for (p = buf;;) {
+ p = memchr(p, '\n', end - p);
+ if (p) {
+ p++;
+ *lineno++ = p - buf;
+ continue;
+ }
+ break;
}
- sb->lineno = xrealloc(sb->lineno,
- sizeof(int *) * (num + incomplete + 1));
- sb->lineno[num + incomplete] = buf - sb->final_buf;
+
+ if (incomplete)
+ *lineno++ = len;
+
sb->num_lines = num + incomplete;
return sb->num_lines;
}
@@ -1802,17 +1796,17 @@ static int prepare_lines(struct scoreboard *sb)
static int read_ancestry(const char *graft_file)
{
FILE *fp = fopen(graft_file, "r");
- char buf[1024];
+ struct strbuf buf = STRBUF_INIT;
if (!fp)
return -1;
- while (fgets(buf, sizeof(buf), fp)) {
+ while (!strbuf_getwholeline(&buf, fp, '\n')) {
/* The format is just "Commit Parent1 Parent2 ...\n" */
- int len = strlen(buf);
- struct commit_graft *graft = read_graft_line(buf, len);
+ struct commit_graft *graft = read_graft_line(buf.buf, buf.len);
if (graft)
register_commit_graft(graft, 0);
}
fclose(fp);
+ strbuf_release(&buf);
return 0;
}
@@ -2501,8 +2495,6 @@ parse_done:
ent->suspect = o;
ent->s_lno = bottom;
ent->next = next;
- if (next)
- next->prev = ent;
origin_incref(o);
}
origin_decref(o);
diff --git a/builtin/branch.c b/builtin/branch.c
index ad0f86d..b4d7716 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -81,13 +81,13 @@ static int parse_branch_color_slot(const char *var, int ofs)
static int git_branch_config(const char *var, const char *value, void *cb)
{
- if (!prefixcmp(var, "column."))
+ if (starts_with(var, "column."))
return git_column_config(var, value, "branch", &colopts);
if (!strcmp(var, "color.branch")) {
branch_use_color = git_config_colorbool(var, value);
return 0;
}
- if (!prefixcmp(var, "color.branch.")) {
+ if (starts_with(var, "color.branch.")) {
int slot = parse_branch_color_slot(var, 13);
if (slot < 0)
return 0;
@@ -424,6 +424,7 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
struct branch *branch = branch_get(branch_name);
struct strbuf fancy = STRBUF_INIT;
int upstream_is_gone = 0;
+ int added_decoration = 1;
switch (stat_tracking_info(branch, &ours, &theirs)) {
case 0:
@@ -451,9 +452,13 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
if (upstream_is_gone) {
if (show_upstream_ref)
strbuf_addf(stat, _("[%s: gone]"), fancy.buf);
+ else
+ added_decoration = 0;
} else if (!ours && !theirs) {
if (show_upstream_ref)
strbuf_addf(stat, _("[%s]"), fancy.buf);
+ else
+ added_decoration = 0;
} else if (!ours) {
if (show_upstream_ref)
strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
@@ -474,7 +479,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
ours, theirs);
}
strbuf_release(&fancy);
- strbuf_addch(stat, ' ');
+ if (added_decoration)
+ strbuf_addch(stat, ' ');
free(ref);
}
@@ -496,7 +502,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item,
const char *sub = _(" **** invalid ref ****");
struct commit *commit = item->commit;
- if (commit && !parse_commit(commit)) {
+ if (!parse_commit(commit)) {
pp_commit_easy(CMIT_FMT_ONELINE, commit, &subject);
sub = subject.buf;
}
@@ -862,7 +868,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!strcmp(head, "HEAD")) {
detached = 1;
} else {
- if (prefixcmp(head, "refs/heads/"))
+ if (!starts_with(head, "refs/heads/"))
die(_("HEAD not found below refs/heads!"));
head += 11;
}
@@ -975,9 +981,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
die(_("no such branch '%s'"), argv[0]);
}
- if (!branch_has_merge_config(branch)) {
+ if (!branch_has_merge_config(branch))
die(_("Branch '%s' has no upstream information"), branch->name);
- }
strbuf_addf(&buf, "branch.%s.remote", branch->name);
git_config_set_multivar(buf.buf, NULL, NULL, 1);
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index b2ca775..d5a93e0 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -118,6 +118,7 @@ struct expand_data {
unsigned long size;
unsigned long disk_size;
const char *rest;
+ unsigned char delta_base_sha1[20];
/*
* If mark_query is true, we do not expand anything, but rather
@@ -174,6 +175,11 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
data->split_on_whitespace = 1;
else if (data->rest)
strbuf_addstr(sb, data->rest);
+ } else if (is_atom("deltabase", atom, len)) {
+ if (data->mark_query)
+ data->info.delta_base_sha1 = data->delta_base_sha1;
+ else
+ strbuf_addstr(sb, sha1_to_hex(data->delta_base_sha1));
} else
die("unknown format element: %.*s", len, atom);
}
@@ -193,25 +199,28 @@ static size_t expand_format(struct strbuf *sb, const char *start, void *data)
return end - start + 1;
}
-static void print_object_or_die(int fd, const unsigned char *sha1,
- enum object_type type, unsigned long size)
+static void print_object_or_die(int fd, struct expand_data *data)
{
- if (type == OBJ_BLOB) {
+ const unsigned char *sha1 = data->sha1;
+
+ assert(data->info.typep);
+
+ if (data->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;
+ enum object_type type;
+ unsigned long size;
void *contents;
- contents = read_sha1_file(sha1, &rtype, &rsize);
+ contents = read_sha1_file(sha1, &type, &size);
if (!contents)
die("object %s disappeared", sha1_to_hex(sha1));
- if (rtype != type)
+ if (type != data->type)
die("object %s changed type!?", sha1_to_hex(sha1));
- if (rsize != size)
- die("object %s change size!?", sha1_to_hex(sha1));
+ if (data->info.sizep && size != data->size)
+ die("object %s changed size!?", sha1_to_hex(sha1));
write_or_die(fd, contents, size);
free(contents);
@@ -238,7 +247,7 @@ static int batch_one_object(const char *obj_name, struct batch_options *opt,
return 0;
}
- if (sha1_object_info_extended(data->sha1, &data->info) < 0) {
+ if (sha1_object_info_extended(data->sha1, &data->info, LOOKUP_REPLACE_OBJECT) < 0) {
printf("%s missing\n", obj_name);
fflush(stdout);
return 0;
@@ -250,7 +259,7 @@ static int batch_one_object(const char *obj_name, struct batch_options *opt,
strbuf_release(&buf);
if (opt->print_contents) {
- print_object_or_die(1, data->sha1, data->type, data->size);
+ print_object_or_die(1, data);
write_or_die(1, "\n", 1);
}
return 0;
@@ -275,6 +284,13 @@ static int batch_objects(struct batch_options *opt)
data.mark_query = 0;
/*
+ * If we are printing out the object, then always fill in the type,
+ * since we will want to decide whether or not to stream.
+ */
+ if (opt->print_contents)
+ data.info.typep = &data.type;
+
+ /*
* 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
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 69e167b..61e75eb 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -14,7 +14,7 @@
static int line_termination = '\n';
static int checkout_stage; /* default to checkout stage0 */
static int to_tempfile;
-static char topath[4][PATH_MAX + 1];
+static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
static struct checkout state;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 0f57397..ada51fa 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -297,8 +297,7 @@ static int checkout_paths(const struct checkout_opts *opts,
* match_pathspec() for _all_ entries when
* opts->source_tree != NULL.
*/
- if (match_pathspec_depth(&opts->pathspec, ce->name, ce_namelen(ce),
- 0, ps_matched))
+ if (ce_path_match(ce, &opts->pathspec, ps_matched))
ce->ce_flags |= CE_MATCHED;
}
@@ -380,8 +379,8 @@ static void show_local_changes(struct object *head,
static void describe_detached_head(const char *msg, struct commit *commit)
{
struct strbuf sb = STRBUF_INIT;
- parse_commit(commit);
- pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
+ if (!parse_commit(commit))
+ pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
fprintf(stderr, "%s %s... %s\n", msg,
find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV), sb.buf);
strbuf_release(&sb);
@@ -677,12 +676,12 @@ static int add_pending_uninteresting_ref(const char *refname,
static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
{
- parse_commit(commit);
strbuf_addstr(sb, " ");
strbuf_addstr(sb,
find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
strbuf_addch(sb, ' ');
- pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
+ if (!parse_commit(commit))
+ pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
strbuf_addch(sb, '\n');
}
@@ -781,7 +780,7 @@ static int switch_branches(const struct checkout_opts *opts,
if (!(flag & REF_ISSYMREF))
old.path = NULL;
- if (old.path && !prefixcmp(old.path, "refs/heads/"))
+ if (old.path && starts_with(old.path, "refs/heads/"))
old.name = old.path + strlen("refs/heads/");
if (!new->name) {
@@ -789,7 +788,7 @@ static int switch_branches(const struct checkout_opts *opts,
new->commit = old.commit;
if (!new->commit)
die(_("You are on a branch yet to be born"));
- parse_commit(new->commit);
+ parse_commit_or_die(new->commit);
}
ret = merge_working_tree(opts, &old, new, &writeout_error);
@@ -816,7 +815,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
return 0;
}
- if (!prefixcmp(var, "submodule."))
+ if (starts_with(var, "submodule."))
return parse_submodule_config_option(var, value);
return git_xmerge_config(var, value, NULL);
@@ -873,7 +872,9 @@ static int parse_branchname_arg(int argc, const char **argv,
int argcount = 0;
unsigned char branch_rev[20];
const char *arg;
- int has_dash_dash;
+ int dash_dash_pos;
+ int has_dash_dash = 0;
+ int i;
/*
* case 1: git checkout <ref> -- [<paths>]
@@ -885,20 +886,30 @@ static int parse_branchname_arg(int argc, const char **argv,
*
* everything after the '--' must be paths.
*
- * case 3: git checkout <something> [<paths>]
+ * case 3: git checkout <something> [--]
*
- * With no paths, if <something> is a commit, that is to
- * switch to the branch or detach HEAD at it. As a special case,
- * if <something> is A...B (missing A or B means HEAD but you can
- * omit at most one side), and if there is a unique merge base
- * between A and B, A...B names that merge base.
+ * (a) If <something> is a commit, that is to
+ * switch to the branch or detach HEAD at it. As a special case,
+ * if <something> is A...B (missing A or B means HEAD but you can
+ * omit at most one side), and if there is a unique merge base
+ * between A and B, A...B names that merge base.
*
- * With no paths, if <something> is _not_ a commit, no -t nor -b
- * was given, and there is a tracking branch whose name is
- * <something> in one and only one remote, then this is a short-hand
- * to fork local <something> from that remote-tracking branch.
+ * (b) If <something> is _not_ a commit, either "--" is present
+ * or <something> is not a path, no -t nor -b was given, and
+ * and there is a tracking branch whose name is <something>
+ * in one and only one remote, then this is a short-hand to
+ * fork local <something> from that remote-tracking branch.
*
- * Otherwise <something> shall not be ambiguous.
+ * (c) Otherwise, if "--" is present, treat it like case (1).
+ *
+ * (d) Otherwise :
+ * - if it's a reference, treat it like case (1)
+ * - else if it's a path, treat it like case (2)
+ * - else: fail.
+ *
+ * case 4: git checkout <something> <paths>
+ *
+ * The first argument must not be ambiguous.
* - If it's *only* a reference, treat it like case (1).
* - If it's only a path, treat it like case (2).
* - else: fail.
@@ -907,28 +918,59 @@ static int parse_branchname_arg(int argc, const char **argv,
if (!argc)
return 0;
- if (!strcmp(argv[0], "--")) /* case (2) */
- return 1;
-
arg = argv[0];
- has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
+ dash_dash_pos = -1;
+ for (i = 0; i < argc; i++) {
+ if (!strcmp(argv[i], "--")) {
+ dash_dash_pos = i;
+ break;
+ }
+ }
+ if (dash_dash_pos == 0)
+ return 1; /* case (2) */
+ else if (dash_dash_pos == 1)
+ has_dash_dash = 1; /* case (3) or (1) */
+ else if (dash_dash_pos >= 2)
+ die(_("only one reference expected, %d given."), dash_dash_pos);
if (!strcmp(arg, "-"))
arg = "@{-1}";
if (get_sha1_mb(arg, rev)) {
- if (has_dash_dash) /* case (1) */
- die(_("invalid reference: %s"), arg);
- if (dwim_new_local_branch_ok &&
- !check_filename(NULL, arg) &&
- argc == 1) {
+ /*
+ * Either case (3) or (4), with <something> not being
+ * a commit, or an attempt to use case (1) with an
+ * invalid ref.
+ *
+ * It's likely an error, but we need to find out if
+ * we should auto-create the branch, case (3).(b).
+ */
+ int recover_with_dwim = dwim_new_local_branch_ok;
+
+ if (check_filename(NULL, arg) && !has_dash_dash)
+ recover_with_dwim = 0;
+ /*
+ * Accept "git checkout foo" and "git checkout foo --"
+ * as candidates for dwim.
+ */
+ if (!(argc == 1 && !has_dash_dash) &&
+ !(argc == 2 && has_dash_dash))
+ recover_with_dwim = 0;
+
+ if (recover_with_dwim) {
const char *remote = unique_tracking_name(arg, rev);
- if (!remote)
- return argcount;
- *new_branch = arg;
- arg = remote;
- /* DWIMmed to create local branch */
- } else {
+ if (remote) {
+ *new_branch = arg;
+ arg = remote;
+ /* DWIMmed to create local branch, case (3).(b) */
+ } else {
+ recover_with_dwim = 0;
+ }
+ }
+
+ if (!recover_with_dwim) {
+ if (has_dash_dash)
+ die(_("invalid reference: %s"), arg);
return argcount;
}
}
@@ -952,13 +994,13 @@ static int parse_branchname_arg(int argc, const char **argv,
/* not a commit */
*source_tree = parse_tree_indirect(rev);
} else {
- parse_commit(new->commit);
+ parse_commit_or_die(new->commit);
*source_tree = new->commit->tree;
}
if (!*source_tree) /* case (1): want a tree */
die(_("reference is not a tree: %s"), arg);
- if (!has_dash_dash) {/* case (3 -> 1) */
+ if (!has_dash_dash) {/* case (3).(d) -> (1) */
/*
* Do not complain the most common case
* git checkout branch
@@ -1108,9 +1150,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
const char *argv0 = argv[0];
if (!argc || !strcmp(argv0, "--"))
die (_("--track needs a branch name"));
- if (!prefixcmp(argv0, "refs/"))
+ if (starts_with(argv0, "refs/"))
argv0 += 5;
- if (!prefixcmp(argv0, "remotes/"))
+ if (starts_with(argv0, "remotes/"))
argv0 += 8;
argv0 = strchr(argv0, '/');
if (!argv0 || !argv0[1])
diff --git a/builtin/clean.c b/builtin/clean.c
index 615cd57..114d7bf 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -100,7 +100,7 @@ static int parse_clean_color_slot(const char *var)
static int git_clean_config(const char *var, const char *value, void *cb)
{
- if (!prefixcmp(var, "column."))
+ if (starts_with(var, "column."))
return git_column_config(var, value, "clean", &colopts);
/* honors the color.interactive* config variables which also
@@ -109,7 +109,7 @@ static int git_clean_config(const char *var, const char *value, void *cb)
clean_use_color = git_config_colorbool(var, value);
return 0;
}
- if (!prefixcmp(var, "color.interactive.")) {
+ if (starts_with(var, "color.interactive.")) {
int slot = parse_clean_color_slot(var +
strlen("color.interactive."));
if (slot < 0)
@@ -154,7 +154,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
DIR *dir;
struct strbuf quoted = STRBUF_INIT;
struct dirent *e;
- int res = 0, ret = 0, gone = 1, original_len = path->len, len, i;
+ int res = 0, ret = 0, gone = 1, original_len = path->len, len;
unsigned char submodule_head[20];
struct string_list dels = STRING_LIST_INIT_DUP;
@@ -242,6 +242,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
}
if (!*dir_gone && !quiet) {
+ int i;
for (i = 0; i < dels.nr; i++)
printf(dry_run ? _(msg_would_remove) : _(msg_remove), dels.items[i].string);
}
@@ -933,36 +934,18 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
- int len, pos;
int matches = 0;
- const struct cache_entry *ce;
struct stat st;
const char *rel;
- /*
- * Remove the '/' at the end that directory
- * walking adds for directory entries.
- */
- len = ent->len;
- if (len && ent->name[len-1] == '/')
- len--;
- pos = cache_name_pos(ent->name, len);
- if (0 <= pos)
- continue; /* exact match */
- pos = -pos - 1;
- if (pos < active_nr) {
- ce = active_cache[pos];
- if (ce_namelen(ce) == len &&
- !memcmp(ce->name, ent->name, len))
- continue; /* Yup, this one exists unmerged */
- }
+ if (!cache_name_is_other(ent->name, ent->len))
+ continue;
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);
+ matches = dir_path_match(ent, &pathspec, 0, NULL);
if (S_ISDIR(st.st_mode)) {
if (remove_directories || (matches == MATCHED_EXACTLY)) {
diff --git a/builtin/clone.c b/builtin/clone.c
index 874e0fd..43e772c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -252,6 +252,12 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
die(_("reference repository '%s' is not a local repository."),
item->string);
+ if (!access(mkpath("%s/shallow", ref_git), F_OK))
+ die(_("reference repository '%s' is shallow"), item->string);
+
+ if (!access(mkpath("%s/info/grafts", ref_git), F_OK))
+ die(_("reference repository '%s' is grafted"), item->string);
+
strbuf_addf(&alternate, "%s/objects", ref_git);
add_to_alternates_file(alternate.buf);
strbuf_release(&alternate);
@@ -508,9 +514,9 @@ static void write_followtags(const struct ref *refs, const char *msg)
{
const struct ref *ref;
for (ref = refs; ref; ref = ref->next) {
- if (prefixcmp(ref->name, "refs/tags/"))
+ if (!starts_with(ref->name, "refs/tags/"))
continue;
- if (!suffixcmp(ref->name, "^{}"))
+ if (ends_with(ref->name, "^{}"))
continue;
if (!has_sha1_file(ref->old_sha1))
continue;
@@ -578,7 +584,7 @@ static void update_remote_refs(const struct ref *refs,
static void update_head(const struct ref *our, const struct ref *remote,
const char *msg)
{
- if (our && !prefixcmp(our->name, "refs/heads/")) {
+ if (our && starts_with(our->name, "refs/heads/")) {
/* Local default branch link */
create_symref("HEAD", our->name, NULL);
if (!option_bare) {
@@ -625,7 +631,7 @@ static int checkout(void)
if (advice_detached_head)
detach_advice(sha1_to_hex(sha1));
} else {
- if (prefixcmp(head, "refs/heads/"))
+ if (!starts_with(head, "refs/heads/"))
die(_("HEAD not found below refs/heads!"));
}
free(head);
@@ -791,11 +797,22 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
else
repo = repo_name;
is_local = option_local != 0 && path && !is_bundle;
- if (is_local && option_depth)
- warning(_("--depth is ignored in local clones; use file:// instead."));
+ if (is_local) {
+ if (option_depth)
+ warning(_("--depth is ignored in local clones; use file:// instead."));
+ if (!access(mkpath("%s/shallow", path), F_OK)) {
+ if (option_local > 0)
+ warning(_("source repository is shallow, ignoring --local"));
+ is_local = 0;
+ }
+ }
if (option_local > 0 && !is_local)
warning(_("--local is ignored"));
+ /* no need to be strict, transport_set_option() will validate it again */
+ if (option_depth && atoi(option_depth) < 1)
+ die(_("depth %s is not a positive number"), option_depth);
+
if (argc == 2)
dir = xstrdup(argv[1]);
else
@@ -883,6 +900,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote = remote_get(option_origin);
transport = transport_get(remote, remote->url[0]);
+ transport->cloning = 1;
if (!transport->get_refs_list || (!is_local && !transport->fetch))
die(_("Don't know how to clone %s"), transport->url);
diff --git a/builtin/column.c b/builtin/column.c
index e125a55..7581852 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -34,7 +34,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)
};
/* This one is special and must be the first one */
- if (argc > 1 && !prefixcmp(argv[1], "--command=")) {
+ if (argc > 1 && starts_with(argv[1], "--command=")) {
command = argv[1] + 10;
git_config(column_config, (void *)command);
} else
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index f641ff2..987a4c3 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -12,6 +12,8 @@
static const char commit_tree_usage[] = "git commit-tree [(-p <sha1>)...] [-S[<keyid>]] [-m <message>] [-F <file>] <sha1> <changelog";
+static const char *sign_commit;
+
static void new_parent(struct commit *parent, struct commit_list **parents_p)
{
unsigned char *sha1 = parent->object.sha1;
@@ -31,6 +33,10 @@ static int commit_tree_config(const char *var, const char *value, void *cb)
int status = git_gpg_config(var, value, NULL);
if (status)
return status;
+ if (!strcmp(var, "commit.gpgsign")) {
+ sign_commit = git_config_bool(var, value) ? "" : NULL;
+ return 0;
+ }
return git_default_config(var, value, cb);
}
@@ -41,7 +47,6 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
unsigned char tree_sha1[20];
unsigned char commit_sha1[20];
struct strbuf buffer = STRBUF_INIT;
- const char *sign_commit = NULL;
git_config(commit_tree_config, NULL);
@@ -66,6 +71,11 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
continue;
}
+ if (!strcmp(arg, "--no-gpg-sign")) {
+ sign_commit = NULL;
+ continue;
+ }
+
if (!strcmp(arg, "-m")) {
if (argc <= ++i)
usage(commit_tree_usage);
diff --git a/builtin/commit.c b/builtin/commit.c
index 6ab4605..3783bca 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -234,7 +234,7 @@ static int list_paths(struct string_list *list, const char *with_tree,
if (ce->ce_flags & CE_UPDATE)
continue;
- if (!match_pathspec_depth(pattern, ce->name, ce_namelen(ce), 0, m))
+ if (!ce_path_match(ce, pattern, m))
continue;
item = string_list_insert(list, ce->name);
if (ce_skip_worktree(ce))
@@ -307,7 +307,6 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
int fd;
struct string_list partial;
struct pathspec pathspec;
- char *old_index_env = NULL;
int refresh_flags = REFRESH_QUIET;
if (is_status)
@@ -320,6 +319,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
die(_("index file corrupt"));
if (interactive) {
+ char *old_index_env = NULL;
fd = hold_locked_index(&index_lock, 1);
refresh_cache_or_die(refresh_flags);
@@ -600,12 +600,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
{
struct stat statbuf;
struct strbuf committer_ident = STRBUF_INIT;
- int commitable, saved_color_setting;
+ int commitable;
struct strbuf sb = STRBUF_INIT;
- char *buffer;
const char *hook_arg1 = NULL;
const char *hook_arg2 = NULL;
- int ident_shown = 0;
int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
int old_display_comment_prefix;
@@ -649,6 +647,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
logfile);
hook_arg1 = "message";
} else if (use_message) {
+ char *buffer;
buffer = strstr(use_message_buffer, "\n\n");
if (!use_editor && (!buffer || buffer[2] == '\0'))
die(_("commit has empty message"));
@@ -733,7 +732,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
eol = nl - sb.buf;
else
eol = sb.len;
- if (!prefixcmp(sb.buf + previous, "\nConflicts:\n")) {
+ if (starts_with(sb.buf + previous, "\nConflicts:\n")) {
ignore_footer = sb.len - previous;
break;
}
@@ -753,6 +752,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
/* This checks if committer ident is explicitly given */
strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));
if (use_editor && include_status) {
+ int ident_shown = 0;
+ int saved_color_setting;
char *ai_tmp, *ci_tmp;
if (whence != FROM_COMMIT)
status_printf_ln(s, GIT_COLOR_NORMAL,
@@ -904,7 +905,7 @@ static int rest_is_empty(struct strbuf *sb, int start)
eol = sb->len;
if (strlen(sign_off_header) <= eol - i &&
- !prefixcmp(sb->buf + i, sign_off_header)) {
+ starts_with(sb->buf + i, sign_off_header)) {
i = eol;
continue;
}
@@ -1183,7 +1184,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
{
struct wt_status *s = cb;
- if (!prefixcmp(k, "column."))
+ if (starts_with(k, "column."))
return git_column_config(k, v, "status", &s->colopts);
if (!strcmp(k, "status.submodulesummary")) {
int is_bool;
@@ -1211,7 +1212,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
s->display_comment_prefix = git_config_bool(k, v);
return 0;
}
- if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
+ if (starts_with(k, "status.color.") || starts_with(k, "color.status.")) {
int slot = parse_status_slot(k, 13);
if (slot < 0)
return 0;
@@ -1338,7 +1339,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
commit = lookup_commit(sha1);
if (!commit)
die(_("couldn't look up newly created commit"));
- if (!commit || parse_commit(commit))
+ if (parse_commit(commit))
die(_("could not parse newly created commit"));
strbuf_addstr(&format, "format:%h] %s");
@@ -1377,7 +1378,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL);
printf("[%s%s ",
- !prefixcmp(head, "refs/heads/") ?
+ starts_with(head, "refs/heads/") ?
head + 11 :
!strcmp(head, "HEAD") ?
_("detached HEAD") :
@@ -1406,6 +1407,10 @@ static int git_commit_config(const char *k, const char *v, void *cb)
}
if (!strcmp(k, "commit.cleanup"))
return git_config_string(&cleanup_arg, k, v);
+ if (!strcmp(k, "commit.gpgsign")) {
+ sign_commit = git_config_bool(k, v) ? "" : NULL;
+ return 0;
+ }
status = git_gpg_config(k, v, NULL);
if (status)
@@ -1505,12 +1510,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
struct strbuf sb = STRBUF_INIT;
struct strbuf author_ident = STRBUF_INIT;
const char *index_file, *reflog_msg;
- char *nl, *p;
+ char *nl;
unsigned char sha1[20];
struct ref_lock *ref_lock;
struct commit_list *parents = NULL, **pptr = &parents;
struct stat statbuf;
- int allow_fast_forward = 1;
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
@@ -1525,7 +1529,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
current_head = NULL;
else {
current_head = lookup_commit_or_die(sha1, "HEAD");
- if (!current_head || parse_commit(current_head))
+ if (parse_commit(current_head))
die(_("could not parse HEAD commit"));
}
argc = parse_and_validate_options(argc, argv, builtin_commit_options,
@@ -1558,6 +1562,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
} else if (whence == FROM_MERGE) {
struct strbuf m = STRBUF_INIT;
FILE *fp;
+ int allow_fast_forward = 1;
if (!reflog_msg)
reflog_msg = "commit (merge)";
@@ -1601,11 +1606,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
/* Truncate the message just before the diff, if any. */
- if (verbose) {
- p = strstr(sb.buf, "\ndiff --git ");
- if (p != NULL)
- strbuf_setlen(&sb, p - sb.buf + 1);
- }
+ if (verbose)
+ wt_status_truncate_message_at_cut_line(&sb);
if (cleanup_mode != CLEANUP_NONE)
stripspace(&sb, cleanup_mode == CLEANUP_ALL);
diff --git a/builtin/config.c b/builtin/config.c
index 20e89fe..92ebf23 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -671,9 +671,3 @@ int cmd_config(int argc, const char **argv, const char *prefix)
return 0;
}
-
-int cmd_repo_config(int argc, const char **argv, const char *prefix)
-{
- fprintf(stderr, "WARNING: git repo-config is deprecated in favor of git config.\n");
- return cmd_config(argc, argv, prefix);
-}
diff --git a/builtin/describe.c b/builtin/describe.c
index b9d3603..dadd999 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -6,10 +6,10 @@
#include "exec_cmd.h"
#include "parse-options.h"
#include "diff.h"
-#include "hash.h"
+#include "hashmap.h"
#include "argv-array.h"
-#define SEEN (1u<<0)
+#define SEEN (1u << 0)
#define MAX_TAGS (FLAG_BITS - 1)
static const char * const describe_usage[] = {
@@ -25,7 +25,7 @@ static int longformat;
static int first_parent;
static int abbrev = -1; /* unspecified */
static int max_candidates = 10;
-static struct hash_table names;
+static struct hashmap names;
static int have_util;
static const char *pattern;
static int always;
@@ -36,9 +36,8 @@ static const char *diff_index_args[] = {
"diff-index", "--quiet", "HEAD", "--", NULL
};
-
struct commit_name {
- struct commit_name *next;
+ struct hashmap_entry entry;
unsigned char peeled[20];
struct tag *tag;
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
@@ -46,10 +45,17 @@ struct commit_name {
unsigned char sha1[20];
char *path;
};
+
static const char *prio_names[] = {
"head", "lightweight", "annotated",
};
+static int commit_name_cmp(const struct commit_name *cn1,
+ const struct commit_name *cn2, const void *peeled)
+{
+ return hashcmp(cn1->peeled, peeled ? peeled : cn2->peeled);
+}
+
static inline unsigned int hash_sha1(const unsigned char *sha1)
{
unsigned int hash;
@@ -59,21 +65,9 @@ static inline unsigned int hash_sha1(const unsigned char *sha1)
static inline struct commit_name *find_commit_name(const unsigned char *peeled)
{
- struct commit_name *n = lookup_hash(hash_sha1(peeled), &names);
- while (n && !!hashcmp(peeled, n->peeled))
- n = n->next;
- return n;
-}
-
-static int set_util(void *chain, void *data)
-{
- struct commit_name *n;
- for (n = chain; n; n = n->next) {
- struct commit *c = lookup_commit_reference_gently(n->peeled, 1);
- if (c)
- c->util = n;
- }
- return 0;
+ struct commit_name key;
+ hashmap_entry_init(&key, hash_sha1(peeled));
+ return hashmap_get(&names, &key, peeled);
}
static int replace_name(struct commit_name *e,
@@ -118,16 +112,10 @@ static void add_to_known_names(const char *path,
struct tag *tag = NULL;
if (replace_name(e, prio, sha1, &tag)) {
if (!e) {
- void **pos;
e = xmalloc(sizeof(struct commit_name));
hashcpy(e->peeled, peeled);
- pos = insert_hash(hash_sha1(peeled), e, &names);
- if (pos) {
- e->next = *pos;
- *pos = e;
- } else {
- e->next = NULL;
- }
+ hashmap_entry_init(e, hash_sha1(peeled));
+ hashmap_add(&names, e);
e->path = NULL;
}
e->tag = tag;
@@ -141,7 +129,7 @@ static void add_to_known_names(const char *path,
static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
- int is_tag = !prefixcmp(path, "refs/tags/");
+ int is_tag = starts_with(path, "refs/tags/");
unsigned char peeled[20];
int is_annotated, prio;
@@ -292,7 +280,14 @@ static void describe(const char *arg, int last_one)
fprintf(stderr, _("searching to describe %s\n"), arg);
if (!have_util) {
- for_each_hash(&names, set_util, NULL);
+ struct hashmap_iter iter;
+ struct commit *c;
+ struct commit_name *n = hashmap_iter_first(&names, &iter);
+ for (; n; n = hashmap_iter_next(&iter)) {
+ c = lookup_commit_reference_gently(n->peeled, 1);
+ if (c)
+ c->util = n;
+ }
have_util = 1;
}
@@ -463,9 +458,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
return cmd_name_rev(args.argc, args.argv, prefix);
}
- init_hash(&names);
+ hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, 0);
for_each_rawref(get_name, NULL);
- if (!names.nr && !always)
+ if (!names.size && !always)
die(_("No names found, cannot describe anything."));
if (argc == 0) {
@@ -488,9 +483,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
} else if (dirty) {
die(_("--dirty is incompatible with commit-ishes"));
} else {
- while (argc-- > 0) {
+ while (argc-- > 0)
describe(*argv++, argc == 0);
- }
}
return 0;
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 2fb8c5d..0f247d2 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -16,6 +16,9 @@
#include "submodule.h"
#include "sha1-array.h"
+#define DIFF_NO_INDEX_EXPLICIT 1
+#define DIFF_NO_INDEX_IMPLICIT 2
+
struct blobinfo {
unsigned char sha1[20];
const char *name;
@@ -64,15 +67,18 @@ static void stuff_change(struct diff_options *opt,
static int builtin_diff_b_f(struct rev_info *revs,
int argc, const char **argv,
- struct blobinfo *blob,
- const char *path)
+ struct blobinfo *blob)
{
/* Blob vs file in the working tree*/
struct stat st;
+ const char *path;
if (argc > 1)
usage(builtin_diff_usage);
+ GUARD_PATHSPEC(&revs->prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
+ path = revs->prune_data.items[0].match;
+
if (lstat(path, &st))
die_errno(_("failed to stat '%s'"), path);
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
@@ -169,7 +175,7 @@ static int builtin_diff_tree(struct rev_info *revs,
if (ent1->item->flags & UNINTERESTING)
swap = 1;
sha1[swap] = ent0->item->sha1;
- sha1[1-swap] = ent1->item->sha1;
+ sha1[1 - swap] = ent1->item->sha1;
diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt);
log_tree_diff_flush(revs);
return 0;
@@ -255,9 +261,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
struct rev_info rev;
struct object_array ent = OBJECT_ARRAY_INIT;
int blobs = 0, paths = 0;
- const char *path = NULL;
struct blobinfo blob[2];
- int nongit;
+ int nongit = 0, no_index = 0;
int result = 0;
/*
@@ -283,14 +288,59 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
* Other cases are errors.
*/
- prefix = setup_git_directory_gently(&nongit);
- gitmodules_config();
+ /* Were we asked to do --no-index explicitly? */
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "--")) {
+ i++;
+ break;
+ }
+ if (!strcmp(argv[i], "--no-index"))
+ no_index = DIFF_NO_INDEX_EXPLICIT;
+ if (argv[i][0] != '-')
+ break;
+ }
+
+ if (!no_index)
+ prefix = setup_git_directory_gently(&nongit);
+
+ /*
+ * Treat git diff with at least one path outside of the
+ * repo the same as if the command would have been executed
+ * outside of a git repository. In this case it behaves
+ * the same way as "git diff --no-index <a> <b>", which acts
+ * as a colourful "diff" replacement.
+ */
+ if (nongit || ((argc == i + 2) &&
+ (!path_inside_repo(prefix, argv[i]) ||
+ !path_inside_repo(prefix, argv[i + 1]))))
+ no_index = DIFF_NO_INDEX_IMPLICIT;
+
+ if (!no_index)
+ gitmodules_config();
git_config(git_diff_ui_config, NULL);
init_revisions(&rev, prefix);
- /* If this is a no-index diff, just run it and exit there. */
- diff_no_index(&rev, argc, argv, nongit, prefix);
+ if (no_index && argc != i + 2) {
+ if (no_index == DIFF_NO_INDEX_IMPLICIT) {
+ /*
+ * There was no --no-index and there were not two
+ * paths. It is possible that the user intended
+ * to do an inside-repository operation.
+ */
+ fprintf(stderr, "Not a git repository\n");
+ fprintf(stderr,
+ "To compare two paths outside a working tree:\n");
+ }
+ /* Give the usage message for non-repository usage and exit. */
+ usagef("git diff %s <path> <path>",
+ no_index == DIFF_NO_INDEX_EXPLICIT ?
+ "--no-index" : "[--no-index]");
+
+ }
+ if (no_index)
+ /* If this is a no-index diff, just run it and exit there. */
+ diff_no_index(&rev, argc, argv, prefix);
/* Otherwise, we are doing the usual "git" diff */
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
@@ -366,13 +416,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
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;
+ if (rev.prune_data.nr)
paths += rev.prune_data.nr;
- }
/*
* Now, do the arguments look reasonable?
@@ -385,7 +430,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
case 1:
if (paths != 1)
usage(builtin_diff_usage);
- result = builtin_diff_b_f(&rev, argc, argv, blob, path);
+ result = builtin_diff_b_f(&rev, argc, argv, blob);
break;
case 2:
if (paths)
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 78250ea..b8d8a3a 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -287,7 +287,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
- parse_commit(commit);
+ parse_commit_or_die(commit);
author = strstr(commit->buffer, "\nauthor ");
if (!author)
die ("Could not find author in commit %s",
@@ -308,7 +308,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
if (commit->parents &&
get_object_mark(&commit->parents->item->object) != 0 &&
!full_tree) {
- parse_commit(commit->parents->item);
+ parse_commit_or_die(commit->parents->item);
diff_tree_sha1(commit->parents->item->tree->object.sha1,
commit->tree->object.sha1, "", &rev->diffopt);
}
@@ -476,7 +476,7 @@ static void handle_tag(const char *name, struct tag *tag)
}
}
- if (!prefixcmp(name, "refs/tags/"))
+ if (starts_with(name, "refs/tags/"))
name += 10;
printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n",
name, tagged_mark,
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index c8e8582..1262b40 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -3,16 +3,24 @@
#include "fetch-pack.h"
#include "remote.h"
#include "connect.h"
+#include "sha1-array.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>...]";
+"[--no-progress] [--diag-url] [-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);
+ unsigned char sha1[20];
+
+ if (namelen > 41 && name[40] == ' ' && !get_sha1_hex(name, sha1)) {
+ hashcpy(ref->old_sha1, sha1);
+ name += 41;
+ namelen -= 41;
+ }
memcpy(ref->name, name, namelen);
ref->name[namelen] = '\0';
@@ -39,6 +47,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
char **pack_lockfile_ptr = NULL;
struct child_process *conn;
struct fetch_pack_args args;
+ struct sha1_array shallow = SHA1_ARRAY_INIT;
packet_trace_identity("fetch-pack");
@@ -48,11 +57,11 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc && *argv[i] == '-'; i++) {
const char *arg = argv[i];
- if (!prefixcmp(arg, "--upload-pack=")) {
+ if (starts_with(arg, "--upload-pack=")) {
args.uploadpack = arg + 14;
continue;
}
- if (!prefixcmp(arg, "--exec=")) {
+ if (starts_with(arg, "--exec=")) {
args.uploadpack = arg + 7;
continue;
}
@@ -81,11 +90,15 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.stdin_refs = 1;
continue;
}
+ if (!strcmp("--diag-url", arg)) {
+ args.diag_url = 1;
+ continue;
+ }
if (!strcmp("-v", arg)) {
args.verbose = 1;
continue;
}
- if (!prefixcmp(arg, "--depth=")) {
+ if (starts_with(arg, "--depth=")) {
args.depth = strtol(arg + 8, NULL, 0);
continue;
}
@@ -106,6 +119,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.check_self_contained_and_connected = 1;
continue;
}
+ if (!strcmp("--cloning", arg)) {
+ args.cloning = 1;
+ continue;
+ }
+ if (!strcmp("--update-shallow", arg)) {
+ args.update_shallow = 1;
+ continue;
+ }
usage(fetch_pack_usage);
}
@@ -146,14 +167,18 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
fd[0] = 0;
fd[1] = 1;
} else {
+ int flags = args.verbose ? CONNECT_VERBOSE : 0;
+ if (args.diag_url)
+ flags |= CONNECT_DIAG_URL;
conn = git_connect(fd, dest, args.uploadpack,
- args.verbose ? CONNECT_VERBOSE : 0);
+ flags);
+ if (!conn)
+ return args.diag_url ? 0 : 1;
}
+ get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow);
- get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL);
-
- ref = fetch_pack(&args, fd, conn, ref, dest,
- sought, nr_sought, pack_lockfile_ptr);
+ ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
+ &shallow, pack_lockfile_ptr);
if (pack_lockfile) {
printf("lock %s\n", pack_lockfile);
fflush(stdout);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index bd7a101..55f457c 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -36,7 +36,7 @@ static int prune = -1; /* unspecified */
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 int tags = TAGS_DEFAULT, unshallow, update_shallow;
static const char *depth;
static const char *upload_pack;
static struct strbuf default_rla = STRBUF_INIT;
@@ -44,6 +44,7 @@ static struct transport *gtransport;
static struct transport *gsecondary;
static const char *submodule_prefix = "";
static const char *recurse_submodules_default;
+static int shown_url = 0;
static int option_parse_recurse_submodules(const struct option *opt,
const char *arg, int unset)
@@ -104,6 +105,8 @@ static struct option builtin_fetch_options[] = {
{ OPTION_STRING, 0, "recurse-submodules-default",
&recurse_submodules_default, NULL,
N_("default mode for recursion"), PARSE_OPT_HIDDEN },
+ OPT_BOOL(0, "update-shallow", &update_shallow,
+ N_("accept refs that update .git/shallow")),
OPT_END()
};
@@ -160,48 +163,156 @@ static void add_merge_config(struct ref **head,
}
}
+static int add_existing(const char *refname, const unsigned char *sha1,
+ int flag, void *cbdata)
+{
+ struct string_list *list = (struct string_list *)cbdata;
+ struct string_list_item *item = string_list_insert(list, refname);
+ item->util = xmalloc(20);
+ hashcpy(item->util, sha1);
+ return 0;
+}
+
+static int will_fetch(struct ref **head, const unsigned char *sha1)
+{
+ struct ref *rm = *head;
+ while (rm) {
+ if (!hashcmp(rm->old_sha1, sha1))
+ return 1;
+ rm = rm->next;
+ }
+ return 0;
+}
+
static void find_non_local_tags(struct transport *transport,
struct ref **head,
- struct ref ***tail);
+ struct ref ***tail)
+{
+ 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;
+
+ for_each_ref(add_existing, &existing_refs);
+ for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
+ if (!starts_with(ref->name, "refs/tags/"))
+ continue;
+
+ /*
+ * The peeled ref always follows the matching base
+ * ref, so if we see a peeled ref that we don't want
+ * to fetch then we can mark the ref entry in the list
+ * as one to ignore by setting util to NULL.
+ */
+ if (ends_with(ref->name, "^{}")) {
+ if (item && !has_sha1_file(ref->old_sha1) &&
+ !will_fetch(head, ref->old_sha1) &&
+ !has_sha1_file(item->util) &&
+ !will_fetch(head, item->util))
+ item->util = NULL;
+ item = NULL;
+ continue;
+ }
+
+ /*
+ * If item is non-NULL here, then we previously saw a
+ * ref not followed by a peeled reference, so we need
+ * to check if it is a lightweight tag that we want to
+ * fetch.
+ */
+ if (item && !has_sha1_file(item->util) &&
+ !will_fetch(head, item->util))
+ item->util = NULL;
+
+ item = NULL;
+
+ /* skip duplicates and refs that we already have */
+ if (string_list_has_string(&remote_refs, ref->name) ||
+ string_list_has_string(&existing_refs, ref->name))
+ continue;
+
+ item = string_list_insert(&remote_refs, ref->name);
+ item->util = (void *)ref->old_sha1;
+ }
+ string_list_clear(&existing_refs, 1);
+
+ /*
+ * We may have a final lightweight tag that needs to be
+ * checked to see if it needs fetching.
+ */
+ if (item && !has_sha1_file(item->util) &&
+ !will_fetch(head, item->util))
+ item->util = NULL;
+
+ /*
+ * For all the tags in the remote_refs string list,
+ * add them to the list of refs to be fetched
+ */
+ for_each_string_list_item(item, &remote_refs) {
+ /* Unless we have already decided to ignore this item... */
+ if (item->util)
+ {
+ struct ref *rm = alloc_ref(item->string);
+ rm->peer_ref = alloc_ref(item->string);
+ hashcpy(rm->old_sha1, item->util);
+ **tail = rm;
+ *tail = &rm->next;
+ }
+ }
+
+ string_list_clear(&remote_refs, 0);
+}
static struct ref *get_ref_map(struct transport *transport,
- struct refspec *refs, int ref_count, int tags,
- int *autotags)
+ struct refspec *refspecs, int refspec_count,
+ int tags, int *autotags)
{
int i;
struct ref *rm;
struct ref *ref_map = NULL;
struct ref **tail = &ref_map;
- const struct ref *remote_refs = transport_get_remote_refs(transport);
+ /* opportunistically-updated references: */
+ struct ref *orefs = NULL, **oref_tail = &orefs;
- if (ref_count || tags == TAGS_SET) {
- struct ref **old_tail;
+ const struct ref *remote_refs = transport_get_remote_refs(transport);
- for (i = 0; i < ref_count; i++) {
- get_fetch_map(remote_refs, &refs[i], &tail, 0);
- if (refs[i].dst && refs[i].dst[0])
+ if (refspec_count) {
+ for (i = 0; i < refspec_count; i++) {
+ get_fetch_map(remote_refs, &refspecs[i], &tail, 0);
+ if (refspecs[i].dst && refspecs[i].dst[0])
*autotags = 1;
}
- /* Merge everything on the command line, but not --tags */
+ /* Merge everything on the command line (but not --tags) */
for (rm = ref_map; rm; rm = rm->next)
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.
+ * For any refs that we happen to be fetching via
+ * command-line arguments, the destination ref might
+ * have been missing or have been different than the
+ * remote-tracking ref that would be derived from the
+ * configured refspec. In these cases, we want to
+ * take the opportunity to update their configured
+ * remote-tracking reference. However, we do not want
+ * to mention these entries in FETCH_HEAD at all, as
+ * they would simply be duplicates of existing
+ * entries, so we set them FETCH_HEAD_IGNORE below.
+ *
+ * We compute these entries now, based only on the
+ * refspecs specified on the command line. But we add
+ * them to the list following the refspecs resulting
+ * from the tags option so that one of the latter,
+ * which has FETCH_HEAD_NOT_FOR_MERGE, is not removed
+ * by ref_remove_duplicates() in favor of one of these
+ * opportunistic entries with FETCH_HEAD_IGNORE.
*/
- 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;
+ &oref_tail, 1);
+
+ if (tags == TAGS_SET)
+ get_fetch_map(remote_refs, tag_refspec, &tail, 0);
} else {
/* Use the defaults */
struct remote *remote = transport->remote;
@@ -238,11 +349,21 @@ static struct ref *get_ref_map(struct transport *transport,
tail = &ref_map->next;
}
}
- if (tags == TAGS_DEFAULT && *autotags)
+
+ if (tags == TAGS_SET)
+ /* also fetch all tags */
+ get_fetch_map(remote_refs, tag_refspec, &tail, 0);
+ else if (tags == TAGS_DEFAULT && *autotags)
find_non_local_tags(transport, &ref_map, &tail);
- ref_remove_duplicates(ref_map);
- return ref_map;
+ /* Now append any refs to be updated opportunistically: */
+ *tail = orefs;
+ for (rm = orefs; rm; rm = rm->next) {
+ rm->fetch_head_status = FETCH_HEAD_IGNORE;
+ tail = &rm->next;
+ }
+
+ return ref_remove_duplicates(ref_map);
}
#define STORE_REF_ERROR_OTHER 1
@@ -313,7 +434,7 @@ static int update_local_ref(struct ref *ref,
}
if (!is_null_sha1(ref->old_sha1) &&
- !prefixcmp(ref->name, "refs/tags/")) {
+ starts_with(ref->name, "refs/tags/")) {
int r;
r = s_update_ref("updating tag", ref, 0);
strbuf_addf(display, "%c %-*s %-*s -> %s%s",
@@ -336,10 +457,10 @@ static int update_local_ref(struct ref *ref,
* more likely to follow a standard layout.
*/
const char *name = remote_ref ? remote_ref->name : "";
- if (!prefixcmp(name, "refs/tags/")) {
+ if (starts_with(name, "refs/tags/")) {
msg = "storing tag";
what = _("[new tag]");
- } else if (!prefixcmp(name, "refs/heads/")) {
+ } else if (starts_with(name, "refs/heads/")) {
msg = "storing head";
what = _("[new branch]");
} else {
@@ -405,6 +526,8 @@ static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
struct ref **rm = cb_data;
struct ref *ref = *rm;
+ while (ref && ref->status == REF_STATUS_REJECT_SHALLOW)
+ ref = ref->next;
if (!ref)
return -1; /* end of the list */
*rm = ref->next;
@@ -417,7 +540,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
{
FILE *fp;
struct commit *commit;
- int url_len, i, shown_url = 0, rc = 0;
+ int url_len, i, rc = 0;
struct strbuf note = STRBUF_INIT;
const char *what, *kind;
struct ref *rm;
@@ -451,6 +574,13 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
struct ref *ref = NULL;
const char *merge_status_marker = "";
+ if (rm->status == REF_STATUS_REJECT_SHALLOW) {
+ if (want_status == FETCH_HEAD_MERGE)
+ warning(_("reject %s because shallow roots are not allowed to be updated"),
+ rm->peer_ref ? rm->peer_ref->name : rm->name);
+ continue;
+ }
+
commit = lookup_commit_reference_gently(rm->old_sha1, 1);
if (!commit)
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
@@ -471,15 +601,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
kind = "";
what = "";
}
- else if (!prefixcmp(rm->name, "refs/heads/")) {
+ else if (starts_with(rm->name, "refs/heads/")) {
kind = "branch";
what = rm->name + 11;
}
- else if (!prefixcmp(rm->name, "refs/tags/")) {
+ else if (starts_with(rm->name, "refs/tags/")) {
kind = "tag";
what = rm->name + 10;
}
- else if (!prefixcmp(rm->name, "refs/remotes/")) {
+ else if (starts_with(rm->name, "refs/remotes/")) {
kind = "remote-tracking branch";
what = rm->name + 13;
}
@@ -590,17 +720,36 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
return ret;
}
-static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
+static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
+ const char *raw_url)
{
- int result = 0;
+ int url_len, i, result = 0;
struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
+ char *url;
const char *dangling_msg = dry_run
? _(" (%s will become dangling)")
: _(" (%s has become dangling)");
+ if (raw_url)
+ url = transport_anonymize_url(raw_url);
+ else
+ url = xstrdup("foreign");
+
+ url_len = strlen(url);
+ for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
+ ;
+
+ url_len = i + 1;
+ if (4 < i && !strncmp(".git", url + i - 3, 4))
+ url_len = i - 3;
+
for (ref = stale_refs; ref; ref = ref->next) {
if (!dry_run)
result |= delete_ref(ref->name, NULL, 0);
+ if (verbosity >= 0 && !shown_url) {
+ fprintf(stderr, _("From %.*s\n"), url_len, url);
+ shown_url = 1;
+ }
if (verbosity >= 0) {
fprintf(stderr, " x %-*s %-*s -> %s\n",
TRANSPORT_SUMMARY(_("[deleted]")),
@@ -608,110 +757,11 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
}
+ free(url);
free_refs(stale_refs);
return result;
}
-static int add_existing(const char *refname, const unsigned char *sha1,
- int flag, void *cbdata)
-{
- struct string_list *list = (struct string_list *)cbdata;
- struct string_list_item *item = string_list_insert(list, refname);
- item->util = xmalloc(20);
- hashcpy(item->util, sha1);
- return 0;
-}
-
-static int will_fetch(struct ref **head, const unsigned char *sha1)
-{
- struct ref *rm = *head;
- while (rm) {
- if (!hashcmp(rm->old_sha1, sha1))
- return 1;
- rm = rm->next;
- }
- return 0;
-}
-
-static void find_non_local_tags(struct transport *transport,
- struct ref **head,
- struct ref ***tail)
-{
- 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;
-
- for_each_ref(add_existing, &existing_refs);
- for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
- if (prefixcmp(ref->name, "refs/tags/"))
- continue;
-
- /*
- * The peeled ref always follows the matching base
- * ref, so if we see a peeled ref that we don't want
- * to fetch then we can mark the ref entry in the list
- * as one to ignore by setting util to NULL.
- */
- if (!suffixcmp(ref->name, "^{}")) {
- if (item && !has_sha1_file(ref->old_sha1) &&
- !will_fetch(head, ref->old_sha1) &&
- !has_sha1_file(item->util) &&
- !will_fetch(head, item->util))
- item->util = NULL;
- item = NULL;
- continue;
- }
-
- /*
- * If item is non-NULL here, then we previously saw a
- * ref not followed by a peeled reference, so we need
- * to check if it is a lightweight tag that we want to
- * fetch.
- */
- if (item && !has_sha1_file(item->util) &&
- !will_fetch(head, item->util))
- item->util = NULL;
-
- item = NULL;
-
- /* skip duplicates and refs that we already have */
- if (string_list_has_string(&remote_refs, ref->name) ||
- string_list_has_string(&existing_refs, ref->name))
- continue;
-
- item = string_list_insert(&remote_refs, ref->name);
- item->util = (void *)ref->old_sha1;
- }
- string_list_clear(&existing_refs, 1);
-
- /*
- * We may have a final lightweight tag that needs to be
- * checked to see if it needs fetching.
- */
- if (item && !has_sha1_file(item->util) &&
- !will_fetch(head, item->util))
- item->util = NULL;
-
- /*
- * For all the tags in the remote_refs string list,
- * add them to the list of refs to be fetched
- */
- for_each_string_list_item(item, &remote_refs) {
- /* Unless we have already decided to ignore this item... */
- if (item->util)
- {
- struct ref *rm = alloc_ref(item->string);
- rm->peer_ref = alloc_ref(item->string);
- hashcpy(rm->old_sha1, item->util);
- **tail = rm;
- *tail = &rm->next;
- }
- }
-
- string_list_clear(&remote_refs, 0);
-}
-
static void check_not_current_branch(struct ref *ref_map)
{
struct branch *current_branch = branch_get(NULL);
@@ -759,6 +809,8 @@ static struct transport *prepare_transport(struct remote *remote)
set_option(transport, TRANS_OPT_KEEP, "yes");
if (depth)
set_option(transport, TRANS_OPT_DEPTH, depth);
+ if (update_shallow)
+ set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
return transport;
}
@@ -824,39 +876,26 @@ static int do_fetch(struct transport *transport,
if (tags == TAGS_DEFAULT && autotags)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
- if (fetch_refs(transport, ref_map)) {
- free_refs(ref_map);
- retcode = 1;
- goto cleanup;
- }
if (prune) {
/*
- * If --tags was specified, pretend that the user gave us
- * the canonical tags refspec
+ * We only prune based on refspecs specified
+ * explicitly (via command line or configuration); we
+ * don't care whether --tags was specified.
*/
- if (tags == TAGS_SET) {
- const char *tags_str = "refs/tags/*:refs/tags/*";
- struct refspec *tags_refspec, *refspec;
-
- /* Copy the refspec and add the tags to it */
- refspec = xcalloc(ref_count + 1, sizeof(struct refspec));
- tags_refspec = parse_fetch_refspec(1, &tags_str);
- memcpy(refspec, refs, ref_count * sizeof(struct refspec));
- memcpy(&refspec[ref_count], tags_refspec, sizeof(struct refspec));
- ref_count++;
-
- prune_refs(refspec, ref_count, ref_map);
-
- ref_count--;
- /* The rest of the strings belong to fetch_one */
- free_refspec(1, tags_refspec);
- free(refspec);
- } else if (ref_count) {
- prune_refs(refs, ref_count, ref_map);
+ if (ref_count) {
+ prune_refs(refs, ref_count, ref_map, transport->url);
} else {
- prune_refs(transport->remote->fetch, transport->remote->fetch_refspec_nr, ref_map);
+ prune_refs(transport->remote->fetch,
+ transport->remote->fetch_refspec_nr,
+ ref_map,
+ transport->url);
}
}
+ if (fetch_refs(transport, ref_map)) {
+ free_refs(ref_map);
+ retcode = 1;
+ goto cleanup;
+ }
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
@@ -892,7 +931,7 @@ static int get_remote_group(const char *key, const char *value, void *priv)
{
struct remote_group_data *g = priv;
- if (!prefixcmp(key, "remotes.") &&
+ if (starts_with(key, "remotes.") &&
!strcmp(key + 8, g->name)) {
/* split list by white space */
int space = strcspn(value, " \t\n");
@@ -930,8 +969,8 @@ static void add_options_to_argv(struct argv_array *argv)
{
if (dry_run)
argv_array_push(argv, "--dry-run");
- if (prune > 0)
- argv_array_push(argv, "--prune");
+ if (prune != -1)
+ argv_array_push(argv, prune ? "--prune" : "--no-prune");
if (update_head_ok)
argv_array_push(argv, "--update-head-ok");
if (force)
@@ -987,7 +1026,6 @@ static int fetch_multiple(struct string_list *list)
static int fetch_one(struct remote *remote, int argc, const char **argv)
{
- int i;
static const char **refs = NULL;
struct refspec *refspec;
int ref_nr = 0;
@@ -1011,6 +1049,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
if (argc > 0) {
int j = 0;
+ int i;
refs = xcalloc(argc + 1, sizeof(const char *));
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "tag")) {
@@ -1075,6 +1114,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
}
}
+ /* no need to be strict, transport_set_option() will validate it again */
+ if (depth && atoi(depth) < 1)
+ die(_("depth %s is not a positive number"), depth);
+
if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
if (recurse_submodules_default) {
int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 1c04070..3906eda 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -109,7 +109,7 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
if (len < 43 || line[40] != '\t')
return 1;
- if (!prefixcmp(line + 41, "not-for-merge"))
+ if (starts_with(line + 41, "not-for-merge"))
return 0;
if (line[41] != '\t')
@@ -155,16 +155,16 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
if (pulling_head) {
origin = src;
src_data->head_status |= 1;
- } else if (!prefixcmp(line, "branch ")) {
+ } else if (starts_with(line, "branch ")) {
origin_data->is_local_branch = 1;
origin = line + 7;
string_list_append(&src_data->branch, origin);
src_data->head_status |= 2;
- } else if (!prefixcmp(line, "tag ")) {
+ } else if (starts_with(line, "tag ")) {
origin = line;
string_list_append(&src_data->tag, origin + 4);
src_data->head_status |= 2;
- } else if (!prefixcmp(line, "remote-tracking branch ")) {
+ } else if (starts_with(line, "remote-tracking branch ")) {
origin = line + strlen("remote-tracking branch ");
string_list_append(&src_data->r_branch, origin);
src_data->head_status |= 2;
@@ -605,7 +605,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
resolve_refdup("HEAD", head_sha1, 1, NULL);
if (!current_branch)
die("No current branch");
- if (!prefixcmp(current_branch, "refs/heads/"))
+ if (starts_with(current_branch, "refs/heads/"))
current_branch += 11;
find_merge_parents(&merge_parents, in, head_sha1);
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 1d4083c..51798b4 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -9,6 +9,7 @@
#include "quote.h"
#include "parse-options.h"
#include "remote.h"
+#include "color.h"
/* Quoting styles */
#define QUOTE_NONE 0
@@ -75,6 +76,8 @@ static struct {
{ "upstream" },
{ "symref" },
{ "flag" },
+ { "HEAD" },
+ { "color" },
};
/*
@@ -89,7 +92,8 @@ static struct {
*/
static const char **used_atom;
static cmp_type *used_atom_type;
-static int used_atom_cnt, sort_atom_limit, need_tagged, need_symref;
+static int used_atom_cnt, need_tagged, need_symref;
+static int need_color_reset_at_eol;
/*
* Used to parse format string and sort specifiers
@@ -176,13 +180,21 @@ static const char *find_next(const char *cp)
static int verify_format(const char *format)
{
const char *cp, *sp;
+ static const char color_reset[] = "color:reset";
+
+ need_color_reset_at_eol = 0;
for (cp = format; *cp && (sp = find_next(cp)); ) {
const char *ep = strchr(sp, ')');
+ int at;
+
if (!ep)
return error("malformed format string %s", sp);
/* sp points at "%(" and ep points at the closing ")" */
- parse_atom(sp + 2, ep);
+ at = parse_atom(sp + 2, ep);
cp = ep + 1;
+
+ if (!memcmp(used_atom[at], "color:", 6))
+ need_color_reset_at_eol = !!strcmp(used_atom[at], color_reset);
}
return 0;
}
@@ -205,6 +217,22 @@ static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned lo
return buf;
}
+static int grab_objectname(const char *name, const unsigned char *sha1,
+ struct atom_value *v)
+{
+ if (!strcmp(name, "objectname")) {
+ char *s = xmalloc(41);
+ strcpy(s, sha1_to_hex(sha1));
+ v->s = s;
+ return 1;
+ }
+ if (!strcmp(name, "objectname:short")) {
+ v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
+ return 1;
+ }
+ return 0;
+}
+
/* See grab_values */
static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
{
@@ -225,15 +253,8 @@ static void grab_common_values(struct atom_value *val, int deref, struct object
v->ul = sz;
v->s = s;
}
- else if (!strcmp(name, "objectname")) {
- char *s = xmalloc(41);
- strcpy(s, sha1_to_hex(obj->sha1));
- v->s = s;
- }
- else if (!strcmp(name, "objectname:short")) {
- v->s = xstrdup(find_unique_abbrev(obj->sha1,
- DEFAULT_ABBREV));
- }
+ else if (deref)
+ grab_objectname(name, obj->sha1, v);
}
}
@@ -432,7 +453,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
if (name[wholen] != 0 &&
strcmp(name + wholen, "name") &&
strcmp(name + wholen, "email") &&
- prefixcmp(name + wholen, "date"))
+ !starts_with(name + wholen, "date"))
continue;
if (!wholine)
wholine = find_wholine(who, wholen, buf, sz);
@@ -444,7 +465,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
v->s = copy_name(wholine);
else if (!strcmp(name + wholen, "email"))
v->s = copy_email(wholine);
- else if (!prefixcmp(name + wholen, "date"))
+ else if (starts_with(name + wholen, "date"))
grab_date(wholine, v, name);
}
@@ -466,7 +487,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
if (deref)
name++;
- if (!prefixcmp(name, "creatordate"))
+ if (starts_with(name, "creatordate"))
grab_date(wholine, v, name);
else if (!strcmp(name, "creator"))
v->s = copy_line(wholine);
@@ -640,20 +661,20 @@ static void populate_value(struct refinfo *ref)
int deref = 0;
const char *refname;
const char *formatp;
+ struct branch *branch = NULL;
if (*name == '*') {
deref = 1;
name++;
}
- if (!prefixcmp(name, "refname"))
+ if (starts_with(name, "refname"))
refname = ref->refname;
- else if (!prefixcmp(name, "symref"))
+ else if (starts_with(name, "symref"))
refname = ref->symref ? ref->symref : "";
- else if (!prefixcmp(name, "upstream")) {
- struct branch *branch;
+ else if (starts_with(name, "upstream")) {
/* only local branches may have an upstream */
- if (prefixcmp(ref->refname, "refs/heads/"))
+ if (!starts_with(ref->refname, "refs/heads/"))
continue;
branch = branch_get(ref->refname + 11);
@@ -661,8 +682,13 @@ static void populate_value(struct refinfo *ref)
!branch->merge[0]->dst)
continue;
refname = branch->merge[0]->dst;
- }
- else if (!strcmp(name, "flag")) {
+ } else if (starts_with(name, "color:")) {
+ char color[COLOR_MAXLEN] = "";
+
+ color_parse(name + 6, "--format", color);
+ v->s = xstrdup(color);
+ continue;
+ } else if (!strcmp(name, "flag")) {
char buf[256], *cp = buf;
if (ref->flag & REF_ISSYMREF)
cp = copy_advance(cp, ",symref");
@@ -675,18 +701,62 @@ static void populate_value(struct refinfo *ref)
v->s = xstrdup(buf + 1);
}
continue;
- }
- else
+ } else if (!deref && grab_objectname(name, ref->objectname, v)) {
+ continue;
+ } else if (!strcmp(name, "HEAD")) {
+ const char *head;
+ unsigned char sha1[20];
+
+ head = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
+ if (!strcmp(ref->refname, head))
+ v->s = "*";
+ else
+ v->s = " ";
+ continue;
+ } else
continue;
formatp = strchr(name, ':');
- /* look for "short" refname format */
if (formatp) {
+ int num_ours, num_theirs;
+
formatp++;
if (!strcmp(formatp, "short"))
refname = shorten_unambiguous_ref(refname,
warn_ambiguous_refs);
- else
+ else if (!strcmp(formatp, "track") &&
+ starts_with(name, "upstream")) {
+ char buf[40];
+
+ stat_tracking_info(branch, &num_ours, &num_theirs);
+ if (!num_ours && !num_theirs)
+ v->s = "";
+ else if (!num_ours) {
+ sprintf(buf, "[behind %d]", num_theirs);
+ v->s = xstrdup(buf);
+ } else if (!num_theirs) {
+ sprintf(buf, "[ahead %d]", num_ours);
+ v->s = xstrdup(buf);
+ } else {
+ sprintf(buf, "[ahead %d, behind %d]",
+ num_ours, num_theirs);
+ v->s = xstrdup(buf);
+ }
+ continue;
+ } else if (!strcmp(formatp, "trackshort") &&
+ starts_with(name, "upstream")) {
+ assert(branch);
+ stat_tracking_info(branch, &num_ours, &num_theirs);
+ if (!num_ours && !num_theirs)
+ v->s = "=";
+ else if (!num_ours)
+ v->s = "<";
+ else if (!num_theirs)
+ v->s = ">";
+ else
+ v->s = "<>";
+ continue;
+ } else
die("unknown %.*s format %s",
(int)(formatp - name), name, formatp);
}
@@ -864,11 +934,9 @@ static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs
qsort(refs, num_refs, sizeof(struct refinfo *), compare_refs);
}
-static void print_value(struct refinfo *ref, int atom, int quote_style)
+static void print_value(struct atom_value *v, 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);
@@ -935,15 +1003,26 @@ static void show_ref(struct refinfo *info, const char *format, int quote_style)
const char *cp, *sp, *ep;
for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
+ struct atom_value *atomv;
+
ep = strchr(sp, ')');
if (cp < sp)
emit(cp, sp);
- print_value(info, parse_atom(sp + 2, ep), quote_style);
+ get_value(info, parse_atom(sp + 2, ep), &atomv);
+ print_value(atomv, quote_style);
}
if (*cp) {
sp = cp + strlen(cp);
emit(cp, sp);
}
+ if (need_color_reset_at_eol) {
+ struct atom_value resetv;
+ char color[COLOR_MAXLEN] = "";
+
+ color_parse("reset", "--format", color);
+ resetv.s = color;
+ print_value(&resetv, quote_style);
+ }
putchar('\n');
}
@@ -1026,7 +1105,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
if (!sort)
sort = default_sort();
- sort_atom_limit = used_atom_cnt;
/* for warn_ambiguous_refs */
git_config(git_default_config, NULL);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 97ce678..1affdd5 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -442,7 +442,7 @@ static void fsck_dir(int i, char *path)
add_sha1_list(sha1, DIRENT_SORT_HINT(de));
continue;
}
- if (!prefixcmp(de->d_name, "tmp_obj_"))
+ if (starts_with(de->d_name, "tmp_obj_"))
continue;
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
}
@@ -484,7 +484,7 @@ static int fsck_handle_reflog(const char *logname, const unsigned char *sha1, in
static int is_branch(const char *refname)
{
- return !strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/");
+ return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
}
static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
@@ -566,7 +566,7 @@ static int fsck_head_link(void)
if (!strcmp(head_points_at, "HEAD"))
/* detached HEAD */
null_is_error = 1;
- else if (prefixcmp(head_points_at, "refs/heads/"))
+ else if (!starts_with(head_points_at, "refs/heads/"))
return error("HEAD points to something strange (%s)",
head_points_at);
if (is_null_sha1(head_sha1)) {
diff --git a/builtin/gc.c b/builtin/gc.c
index 891a2c2..5bbb5e3 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -14,7 +14,9 @@
#include "cache.h"
#include "parse-options.h"
#include "run-command.h"
+#include "sigchain.h"
#include "argv-array.h"
+#include "commit.h"
#define FAILED_RUN "failed to run %s"
@@ -35,6 +37,21 @@ static struct argv_array repack = ARGV_ARRAY_INIT;
static struct argv_array prune = ARGV_ARRAY_INIT;
static struct argv_array rerere = ARGV_ARRAY_INIT;
+static char *pidfile;
+
+static void remove_pidfile(void)
+{
+ if (pidfile)
+ unlink(pidfile);
+}
+
+static void remove_pidfile_on_signal(int signo)
+{
+ remove_pidfile();
+ sigchain_pop(signo);
+ raise(signo);
+}
+
static int gc_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "gc.packrefs")) {
@@ -171,13 +188,16 @@ static int need_to_gc(void)
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;
+ int fd;
+
+ if (pidfile)
+ /* already locked */
+ return NULL;
if (gethostname(my_host, sizeof(my_host)))
strcpy(my_host, "unknown");
@@ -185,6 +205,8 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
fd = hold_lock_file_for_update(&lock, git_path("gc.pid"),
LOCK_DIE_ON_ERROR);
if (!force) {
+ static char locking_host[128];
+ int should_exit;
fp = fopen(git_path("gc.pid"), "r");
memset(locking_host, 0, sizeof(locking_host));
should_exit =
@@ -202,7 +224,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
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));
+ (strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM);
if (fp != NULL)
fclose(fp);
if (should_exit) {
@@ -219,6 +241,10 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
strbuf_release(&sb);
commit_lock_file(&lock);
+ pidfile = git_pathdup("gc.pid");
+ sigchain_push_common(remove_pidfile_on_signal);
+ atexit(remove_pidfile);
+
return NULL;
}
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
new file mode 100644
index 0000000..aa72596
--- /dev/null
+++ b/builtin/get-tar-commit-id.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2005, 2006 Rene Scharfe
+ */
+#include "cache.h"
+#include "commit.h"
+#include "tar.h"
+#include "builtin.h"
+#include "quote.h"
+
+static const char builtin_get_tar_commit_id_usage[] =
+"git get-tar-commit-id < <tarfile>";
+
+/* ustar header + extended global header content */
+#define RECORDSIZE (512)
+#define HEADERSIZE (2 * RECORDSIZE)
+
+int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
+{
+ char buffer[HEADERSIZE];
+ struct ustar_header *header = (struct ustar_header *)buffer;
+ char *content = buffer + RECORDSIZE;
+ ssize_t n;
+
+ if (argc != 1)
+ usage(builtin_get_tar_commit_id_usage);
+
+ n = read_in_full(0, buffer, HEADERSIZE);
+ if (n < HEADERSIZE)
+ die("git get-tar-commit-id: read error");
+ if (header->typeflag[0] != 'g')
+ return 1;
+ if (memcmp(content, "52 comment=", 11))
+ return 1;
+
+ n = write_in_full(1, content + 11, 41);
+ if (n < 41)
+ die_errno("git get-tar-commit-id: write error");
+
+ return 0;
+}
diff --git a/builtin/grep.c b/builtin/grep.c
index 63f8603..69ac2d8 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -379,7 +379,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
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))
+ if (!ce_path_match(ce, pathspec, NULL))
continue;
/*
* If CE_VALID is on, we assume worktree file and its cache entry
@@ -524,9 +524,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
fill_directory(&dir, pathspec);
for (i = 0; i < dir.nr; i++) {
- const char *name = dir.entries[i]->name;
- int namelen = strlen(name);
- if (!match_pathspec_depth(pathspec, name, namelen, 0, NULL))
+ if (!dir_path_match(dir.entries[i], pathspec, 0, NULL))
continue;
hit |= grep_file(opt, dir.entries[i]->name);
if (hit && opt->status_only)
diff --git a/builtin/help.c b/builtin/help.c
index f1e236b..1fdefeb 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -100,7 +100,7 @@ static int check_emacsclient_version(void)
*/
finish_command(&ec_process);
- if (prefixcmp(buffer.buf, "emacsclient")) {
+ if (!starts_with(buffer.buf, "emacsclient")) {
strbuf_release(&buffer);
return error(_("Failed to parse emacsclient version."));
}
@@ -258,7 +258,7 @@ static int add_man_viewer_info(const char *var, const char *value)
static int git_help_config(const char *var, const char *value, void *cb)
{
- if (!prefixcmp(var, "column."))
+ if (starts_with(var, "column."))
return git_column_config(var, value, "help", &colopts);
if (!strcmp(var, "help.format")) {
if (!value)
@@ -278,7 +278,7 @@ static int git_help_config(const char *var, const char *value, void *cb)
add_man_viewer(value);
return 0;
}
- if (!prefixcmp(var, "man."))
+ if (starts_with(var, "man."))
return add_man_viewer_info(var, value);
return git_default_config(var, value, cb);
@@ -288,6 +288,10 @@ static struct cmdnames main_cmds, other_cmds;
static int is_git_command(const char *s)
{
+ if (is_builtin(s))
+ return 1;
+
+ load_command_list("git-", &main_cmds, &other_cmds);
return is_in_cmdlist(&main_cmds, s) ||
is_in_cmdlist(&other_cmds, s);
}
@@ -306,7 +310,7 @@ static const char *cmd_to_page(const char *git_cmd)
{
if (!git_cmd)
return "git";
- else if (!prefixcmp(git_cmd, "git"))
+ else if (starts_with(git_cmd, "git"))
return git_cmd;
else if (is_git_command(git_cmd))
return prepend("git-", git_cmd);
@@ -449,7 +453,6 @@ int cmd_help(int argc, const char **argv, const char *prefix)
int nongit;
const char *alias;
enum help_format parsed_help_format;
- load_command_list("git-", &main_cmds, &other_cmds);
argc = parse_options(argc, argv, prefix, builtin_help_options,
builtin_help_usage, 0);
@@ -458,6 +461,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)
if (show_all) {
git_config(git_help_config, NULL);
printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
+ load_command_list("git-", &main_cmds, &other_cmds);
list_commands(colopts, &main_cmds, &other_cmds);
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 9e9eb4b..2f37a38 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1534,9 +1534,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
stat_only = 1;
} else if (!strcmp(arg, "--keep")) {
keep_msg = "";
- } else if (!prefixcmp(arg, "--keep=")) {
+ } else if (starts_with(arg, "--keep=")) {
keep_msg = arg + 7;
- } else if (!prefixcmp(arg, "--threads=")) {
+ } else if (starts_with(arg, "--threads=")) {
char *end;
nr_threads = strtoul(arg+10, &end, 0);
if (!arg[10] || *end || nr_threads < 0)
@@ -1547,7 +1547,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
"ignoring %s"), arg);
nr_threads = 1;
#endif
- } else if (!prefixcmp(arg, "--pack_header=")) {
+ } else if (starts_with(arg, "--pack_header=")) {
struct pack_header *hdr;
char *c;
@@ -1566,7 +1566,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (index_name || (i+1) >= argc)
usage(index_pack_usage);
index_name = argv[++i];
- } else if (!prefixcmp(arg, "--index-version=")) {
+ } else if (starts_with(arg, "--index-version=")) {
char *c;
opts.version = strtoul(arg + 16, &c, 10);
if (opts.version > 2)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 78aa387..c7c76bb 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -266,7 +266,7 @@ static int create_default_files(const char *template_path)
/* allow template config file to override the default */
if (log_all_ref_updates == -1)
git_config_set("core.logallrefupdates", "true");
- if (prefixcmp(git_dir, work_tree) ||
+ if (!starts_with(git_dir, work_tree) ||
strcmp(git_dir + strlen(work_tree), "/.git")) {
git_config_set("core.worktree", work_tree);
}
@@ -515,13 +515,14 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
saved = shared_repository;
shared_repository = 0;
switch (safe_create_leading_directories_const(argv[0])) {
- case -3:
+ case SCLD_OK:
+ case SCLD_PERMS:
+ break;
+ case SCLD_EXISTS:
errno = EEXIST;
/* fallthru */
- case -1:
- die_errno(_("cannot mkdir %s"), argv[0]);
- break;
default:
+ die_errno(_("cannot mkdir %s"), argv[0]);
break;
}
shared_repository = saved;
diff --git a/builtin/log.c b/builtin/log.c
index b708517..b97373d 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -391,7 +391,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
default_show_root = git_config_bool(var, value);
return 0;
}
- if (!prefixcmp(var, "color.decorate."))
+ if (starts_with(var, "color.decorate."))
return parse_decorate_color_config(var, 15, value);
if (!strcmp(var, "log.mailmap")) {
use_mailmap_config = git_config_bool(var, value);
@@ -477,7 +477,7 @@ static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
int new_offset = offset + 1;
while (new_offset < size && buf[new_offset++] != '\n')
; /* do nothing */
- if (!prefixcmp(buf + offset, "tagger "))
+ if (starts_with(buf + offset, "tagger "))
show_tagger(buf + offset + 7,
new_offset - offset - 7, rev);
offset = new_offset;
@@ -882,7 +882,7 @@ static char *find_branch_name(struct rev_info *rev)
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/") &&
+ starts_with(full_ref, "refs/heads/") &&
!hashcmp(tip_sha1, branch_sha1))
branch = xstrdup(full_ref + strlen("refs/heads/"));
free(full_ref);
@@ -1388,7 +1388,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
unsigned char sha1[20];
const char *ref;
ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
- if (ref && !prefixcmp(ref, "refs/heads/"))
+ if (ref && starts_with(ref, "refs/heads/"))
branch_name = xstrdup(ref + strlen("refs/heads/"));
else
branch_name = xstrdup(""); /* no branch */
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index e1cf6d8..47c3880 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -64,7 +64,7 @@ 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_depth(&pathspec, ent->name, ent->len, len, ps_matched))
+ if (!dir_path_match(ent, &pathspec, len, ps_matched))
return;
fputs(tag, stdout);
@@ -139,7 +139,9 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)
if (len >= ce_namelen(ce))
die("git ls-files: internal error - cache entry not superset of prefix");
- if (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), len, ps_matched))
+ if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
+ len, ps_matched,
+ S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)))
return;
if (tag && *tag && show_valid_bit &&
@@ -195,7 +197,8 @@ static void show_ru_info(void)
len = strlen(path);
if (len < max_prefix_len)
continue; /* outside of the prefix */
- if (!match_pathspec_depth(&pathspec, path, len, max_prefix_len, ps_matched))
+ if (!match_pathspec(&pathspec, path, len,
+ max_prefix_len, ps_matched, 0))
continue; /* uninterested */
for (i = 0; i < 3; i++) {
if (!ui->mode[i])
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 25e83cf..39e5144 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -50,11 +50,11 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
const char *arg = argv[i];
if (*arg == '-') {
- if (!prefixcmp(arg, "--upload-pack=")) {
+ if (starts_with(arg, "--upload-pack=")) {
uploadpack = arg + 14;
continue;
}
- if (!prefixcmp(arg, "--exec=")) {
+ if (starts_with(arg, "--exec=")) {
uploadpack = arg + 7;
continue;
}
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 65ec931..51184df 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -171,7 +171,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
* 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()
+ * match_pathspec() or tree_entry_interesting()
*/
parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE,
PATHSPEC_PREFER_CWD,
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 24a772d..2c3cd8e 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -328,11 +328,11 @@ static int check_header(const struct strbuf *line,
}
/* for inbody stuff */
- if (!prefixcmp(line->buf, ">From") && isspace(line->buf[5])) {
+ if (starts_with(line->buf, ">From") && isspace(line->buf[5])) {
ret = 1; /* Should this return 0? */
goto check_header_out;
}
- if (!prefixcmp(line->buf, "[PATCH]") && isspace(line->buf[7])) {
+ if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) {
for (i = 0; header[i]; i++) {
if (!memcmp("Subject", header[i], 7)) {
handle_header(&hdr_data[i], line);
@@ -361,7 +361,7 @@ static int is_rfc2822_header(const struct strbuf *line)
char *cp = line->buf;
/* Count mbox From headers as headers */
- if (!prefixcmp(cp, "From ") || !prefixcmp(cp, ">From "))
+ if (starts_with(cp, "From ") || starts_with(cp, ">From "))
return 1;
while ((ch = *cp++)) {
@@ -671,11 +671,11 @@ static inline int patchbreak(const struct strbuf *line)
size_t i;
/* Beginning of a "diff -" header? */
- if (!prefixcmp(line->buf, "diff -"))
+ if (starts_with(line->buf, "diff -"))
return 1;
/* CVS "Index: " line? */
- if (!prefixcmp(line->buf, "Index: "))
+ if (starts_with(line->buf, "Index: "))
return 1;
/*
@@ -685,7 +685,7 @@ static inline int patchbreak(const struct strbuf *line)
if (line->len < 4)
return 0;
- if (!prefixcmp(line->buf, "---")) {
+ if (starts_with(line->buf, "---")) {
/* space followed by a filename? */
if (line->buf[3] == ' ' && !isspace(line->buf[4]))
return 1;
@@ -986,7 +986,7 @@ static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)
static int git_mailinfo_config(const char *var, const char *value, void *unused)
{
- if (prefixcmp(var, "mailinfo."))
+ if (!starts_with(var, "mailinfo."))
return git_default_config(var, value, unused);
if (!strcmp(var, "mailinfo.scissors")) {
use_scissors = git_config_bool(var, value);
@@ -1020,7 +1020,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
metainfo_charset = def_charset;
else if (!strcmp(argv[1], "-n"))
metainfo_charset = NULL;
- else if (!prefixcmp(argv[1], "--encoding="))
+ else if (starts_with(argv[1], "--encoding="))
metainfo_charset = argv[1] + 11;
else if (!strcmp(argv[1], "--scissors"))
use_scissors = 1;
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index e88eb93..0ecde8d 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -1,6 +1,9 @@
#include "builtin.h"
#include "cache.h"
#include "commit.h"
+#include "refs.h"
+#include "diff.h"
+#include "revision.h"
#include "parse-options.h"
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
@@ -27,6 +30,7 @@ static const char * const merge_base_usage[] = {
N_("git merge-base [-a|--all] --octopus <commit>..."),
N_("git merge-base --independent <commit>..."),
N_("git merge-base --is-ancestor <commit> <commit>"),
+ N_("git merge-base --fork-point <ref> [<commit>]"),
NULL
};
@@ -44,19 +48,36 @@ static struct commit *get_commit_reference(const char *arg)
return r;
}
-static int handle_octopus(int count, const char **args, int reduce, int show_all)
+static int handle_independent(int count, const char **args)
{
struct commit_list *revs = NULL;
struct commit_list *result;
int i;
- if (reduce)
- show_all = 1;
+ for (i = count - 1; i >= 0; i--)
+ commit_list_insert(get_commit_reference(args[i]), &revs);
+
+ result = reduce_heads(revs);
+ if (!result)
+ return 1;
+
+ while (result) {
+ printf("%s\n", sha1_to_hex(result->item->object.sha1));
+ result = result->next;
+ }
+ return 0;
+}
+
+static int handle_octopus(int count, const char **args, int show_all)
+{
+ struct commit_list *revs = NULL;
+ struct commit_list *result;
+ int i;
for (i = count - 1; i >= 0; i--)
commit_list_insert(get_commit_reference(args[i]), &revs);
- result = reduce ? reduce_heads(revs) : get_octopus_merge_bases(revs);
+ result = reduce_heads(get_octopus_merge_bases(revs));
if (!result)
return 1;
@@ -85,37 +106,151 @@ static int handle_is_ancestor(int argc, const char **argv)
return 1;
}
+struct rev_collect {
+ struct commit **commit;
+ int nr;
+ int alloc;
+ unsigned int initial : 1;
+};
+
+static void add_one_commit(unsigned char *sha1, struct rev_collect *revs)
+{
+ struct commit *commit;
+
+ if (is_null_sha1(sha1))
+ return;
+
+ commit = lookup_commit(sha1);
+ if (!commit ||
+ (commit->object.flags & TMP_MARK) ||
+ parse_commit(commit))
+ return;
+
+ ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
+ revs->commit[revs->nr++] = commit;
+ commit->object.flags |= TMP_MARK;
+}
+
+static int collect_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+ const char *ident, unsigned long timestamp,
+ int tz, const char *message, void *cbdata)
+{
+ struct rev_collect *revs = cbdata;
+
+ if (revs->initial) {
+ revs->initial = 0;
+ add_one_commit(osha1, revs);
+ }
+ add_one_commit(nsha1, revs);
+ return 0;
+}
+
+static int handle_fork_point(int argc, const char **argv)
+{
+ unsigned char sha1[20];
+ char *refname;
+ const char *commitname;
+ struct rev_collect revs;
+ struct commit *derived;
+ struct commit_list *bases;
+ int i, ret = 0;
+
+ switch (dwim_ref(argv[0], strlen(argv[0]), sha1, &refname)) {
+ case 0:
+ die("No such ref: '%s'", argv[0]);
+ case 1:
+ break; /* good */
+ default:
+ die("Ambiguous refname: '%s'", argv[0]);
+ }
+
+ commitname = (argc == 2) ? argv[1] : "HEAD";
+ if (get_sha1(commitname, sha1))
+ die("Not a valid object name: '%s'", commitname);
+
+ derived = lookup_commit_reference(sha1);
+ memset(&revs, 0, sizeof(revs));
+ revs.initial = 1;
+ for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
+
+ for (i = 0; i < revs.nr; i++)
+ revs.commit[i]->object.flags &= ~TMP_MARK;
+
+ bases = get_merge_bases_many(derived, revs.nr, revs.commit, 0);
+
+ /*
+ * There should be one and only one merge base, when we found
+ * a common ancestor among reflog entries.
+ */
+ if (!bases || bases->next) {
+ ret = 1;
+ goto cleanup_return;
+ }
+
+ /* And the found one must be one of the reflog entries */
+ for (i = 0; i < revs.nr; i++)
+ if (&bases->item->object == &revs.commit[i]->object)
+ break; /* found */
+ if (revs.nr <= i) {
+ ret = 1; /* not found */
+ goto cleanup_return;
+ }
+
+ printf("%s\n", sha1_to_hex(bases->item->object.sha1));
+
+cleanup_return:
+ free_commit_list(bases);
+ return ret;
+}
+
int cmd_merge_base(int argc, const char **argv, const char *prefix)
{
struct commit **rev;
int rev_nr = 0;
int show_all = 0;
- int octopus = 0;
- int reduce = 0;
- int is_ancestor = 0;
+ int cmdmode = 0;
struct option options[] = {
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_CMDMODE(0, "octopus", &cmdmode,
+ N_("find ancestors for a single n-way merge"), 'o'),
+ OPT_CMDMODE(0, "independent", &cmdmode,
+ N_("list revs not reachable from others"), 'r'),
+ OPT_CMDMODE(0, "is-ancestor", &cmdmode,
+ N_("is the first one ancestor of the other?"), 'a'),
+ OPT_CMDMODE(0, "fork-point", &cmdmode,
+ N_("find where <commit> forked from reflog of <ref>"), 'f'),
OPT_END()
};
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
- if (!octopus && !reduce && argc < 2)
- usage_with_options(merge_base_usage, options);
- if (is_ancestor && (show_all || octopus || reduce))
- die("--is-ancestor cannot be used with other options");
- if (is_ancestor)
+
+ if (cmdmode == 'a') {
+ if (argc < 2)
+ usage_with_options(merge_base_usage, options);
+ if (show_all)
+ die("--is-ancestor cannot be used with --all");
return handle_is_ancestor(argc, argv);
- if (reduce && (show_all || octopus))
- die("--independent cannot be used with other options");
+ }
- if (octopus || reduce)
- return handle_octopus(argc, argv, reduce, show_all);
+ if (cmdmode == 'r' && show_all)
+ die("--independent cannot be used with --all");
+
+ if (cmdmode == 'o')
+ return handle_octopus(argc, argv, show_all);
+
+ if (cmdmode == 'r')
+ return handle_independent(argc, argv);
+
+ if (cmdmode == 'f') {
+ if (argc < 1 || 2 < argc)
+ usage_with_options(merge_base_usage, options);
+ return handle_fork_point(argc, argv);
+ }
+
+ if (argc < 2)
+ usage_with_options(merge_base_usage, options);
rev = xmalloc(argc * sizeof(*rev));
while (argc-- > 0)
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 3a64f5d..a90f28f 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -29,7 +29,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
struct commit *result;
init_merge_options(&o);
- if (argv[0] && !suffixcmp(argv[0], "-subtree"))
+ if (argv[0] && ends_with(argv[0], "-subtree"))
o.subtree_shift = "";
if (argc < 4)
@@ -38,7 +38,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc; ++i) {
const char *arg = argv[i];
- if (!prefixcmp(arg, "--")) {
+ if (starts_with(arg, "--")) {
if (!arg[2])
break;
if (parse_merge_opt(&o, arg + 2))
diff --git a/builtin/merge.c b/builtin/merge.c
index 02a69c1..f0cf120 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -186,13 +186,6 @@ 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"),
@@ -210,9 +203,9 @@ static struct option builtin_merge_options[] = {
OPT_BOOL('e', "edit", &option_edit,
N_("edit message before committing")),
OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
- { OPTION_CALLBACK, 0, "ff-only", NULL, NULL,
+ { OPTION_SET_INT, 0, "ff-only", &fast_forward, NULL,
N_("abort if fast-forward is not possible"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, option_parse_ff_only },
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 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")),
@@ -374,7 +367,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
sha1_to_hex(commit->object.sha1));
pretty_print_commit(&ctx, commit, &out);
}
- if (write(fd, out.buf, out.len) < 0)
+ if (write_in_full(fd, out.buf, out.len) != out.len)
die_errno(_("Writing SQUASH_MSG"));
if (close(fd))
die_errno(_("Finishing SQUASH_MSG"));
@@ -453,17 +446,17 @@ static void merge_name(const char *remote, struct strbuf *msg)
die(_("'%s' does not point to a commit"), remote);
if (dwim_ref(remote, strlen(remote), branch_head, &found_ref) > 0) {
- if (!prefixcmp(found_ref, "refs/heads/")) {
+ if (starts_with(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
sha1_to_hex(branch_head), remote);
goto cleanup;
}
- if (!prefixcmp(found_ref, "refs/tags/")) {
+ if (starts_with(found_ref, "refs/tags/")) {
strbuf_addf(msg, "%s\t\ttag '%s' of .\n",
sha1_to_hex(branch_head), remote);
goto cleanup;
}
- if (!prefixcmp(found_ref, "refs/remotes/")) {
+ if (starts_with(found_ref, "refs/remotes/")) {
strbuf_addf(msg, "%s\t\tremote-tracking branch '%s' of .\n",
sha1_to_hex(branch_head), remote);
goto cleanup;
@@ -577,8 +570,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
{
int status;
- if (branch && !prefixcmp(k, "branch.") &&
- !prefixcmp(k + 7, branch) &&
+ if (branch && starts_with(k, "branch.") &&
+ starts_with(k + 7, branch) &&
!strcmp(k + 7 + strlen(branch), ".mergeoptions")) {
free(branch_mergeoptions);
branch_mergeoptions = xstrdup(v);
@@ -604,6 +597,9 @@ static int git_merge_config(const char *k, const char *v, void *cb)
} else if (!strcmp(k, "merge.defaulttoupstream")) {
default_to_upstream = git_config_bool(k, v);
return 0;
+ } else if (!strcmp(k, "commit.gpgsign")) {
+ sign_commit = git_config_bool(k, v) ? "" : NULL;
+ return 0;
}
status = fmt_merge_msg_config(k, v, cb);
@@ -1113,7 +1109,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* current branch.
*/
branch = branch_to_free = resolve_refdup("HEAD", head_sha1, 0, &flag);
- if (branch && !prefixcmp(branch, "refs/heads/"))
+ if (branch && starts_with(branch, "refs/heads/"))
branch += 11;
if (!branch || is_null_sha1(head_sha1))
head_commit = NULL;
diff --git a/builtin/mv.c b/builtin/mv.c
index aec79d1..21c46d1 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -16,9 +16,12 @@ static const char * const builtin_mv_usage[] = {
NULL
};
+#define DUP_BASENAME 1
+#define KEEP_TRAILING_SLASH 2
+
static const char **internal_copy_pathspec(const char *prefix,
const char **pathspec,
- int count, int base_name)
+ int count, unsigned flags)
{
int i;
const char **result = xmalloc((count + 1) * sizeof(const char *));
@@ -27,11 +30,12 @@ static const char **internal_copy_pathspec(const char *prefix,
for (i = 0; i < count; i++) {
int length = strlen(result[i]);
int to_copy = length;
- while (to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
+ while (!(flags & KEEP_TRAILING_SLASH) &&
+ to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
to_copy--;
- if (to_copy != length || base_name) {
+ if (to_copy != length || flags & DUP_BASENAME) {
char *it = xmemdupz(result[i], to_copy);
- if (base_name) {
+ if (flags & DUP_BASENAME) {
result[i] = xstrdup(basename(it));
free(it);
} else
@@ -55,6 +59,7 @@ static const char *add_slash(const char *path)
}
static struct lock_file lock_file;
+#define SUBMODULE_WITH_GITDIR ((const char *)1)
int cmd_mv(int argc, const char **argv, const char *prefix)
{
@@ -86,16 +91,21 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
source = internal_copy_pathspec(prefix, argv, argc, 0);
modes = xcalloc(argc, sizeof(enum update_mode));
- dest_path = internal_copy_pathspec(prefix, argv + argc, 1, 0);
+ /*
+ * Keep trailing slash, needed to let
+ * "git mv file no-such-dir/" error out.
+ */
+ dest_path = internal_copy_pathspec(prefix, argv + argc, 1,
+ KEEP_TRAILING_SLASH);
submodule_gitfile = xcalloc(argc, sizeof(char *));
if (dest_path[0][0] == '\0')
/* special case: "." was normalized to "" */
- destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
+ destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
else if (!lstat(dest_path[0], &st) &&
S_ISDIR(st.st_mode)) {
dest_path[0] = add_slash(dest_path[0]);
- destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
+ destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
} else {
if (argc != 1)
die("destination '%s' is not a directory", dest_path[0]);
@@ -132,6 +142,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf);
if (submodule_gitfile[i])
submodule_gitfile[i] = xstrdup(submodule_gitfile[i]);
+ else
+ submodule_gitfile[i] = SUBMODULE_WITH_GITDIR;
strbuf_release(&submodule_dotgit);
} else {
const char *src_w_slash = add_slash(src);
@@ -202,6 +214,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
}
} else if (string_list_has_string(&src_for_dst, dst))
bad = _("multiple sources for the same target");
+ else if (is_dir_sep(dst[strlen(dst) - 1]))
+ bad = _("destination directory does not exist");
else
string_list_insert(&src_for_dst, dst);
@@ -230,10 +244,12 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
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 (submodule_gitfile[i]) {
+ if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
+ connect_work_tree_and_git_dir(dst, submodule_gitfile[i]);
+ if (!update_path_in_gitmodules(src, dst))
+ gitmodules_modified = 1;
+ }
}
if (mode == WORKING_DIRECTORY)
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 20fcf8c..0b21d7e 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -27,8 +27,7 @@ static void name_rev(struct commit *commit,
struct commit_list *parents;
int parent_number = 1;
- if (!commit->object.parsed)
- parse_commit(commit);
+ parse_commit(commit);
if (commit->date < cutoff)
return;
@@ -101,9 +100,9 @@ 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/"))
+ else if (starts_with(refname, "refs/heads/"))
refname = refname + 11;
- else if (!prefixcmp(refname, "refs/"))
+ else if (starts_with(refname, "refs/"))
refname = refname + 5;
return refname;
}
@@ -149,7 +148,7 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
int can_abbreviate_output = data->tags_only && data->name_only;
int deref = 0;
- if (data->tags_only && prefixcmp(path, "refs/tags/"))
+ if (data->tags_only && !starts_with(path, "refs/tags/"))
return 0;
if (data->ref_filter) {
diff --git a/builtin/notes.c b/builtin/notes.c
index d459e23..2b24d05 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -347,7 +347,7 @@ static struct notes_tree *init_notes_check(const char *subcommand)
init_notes(NULL, NULL, NULL, 0);
t = &default_notes_tree;
- if (prefixcmp(t->ref, "refs/notes/"))
+ if (!starts_with(t->ref, "refs/notes/"))
die("Refusing to %s notes in %s (outside of refs/notes/)",
subcommand, t->ref);
return t;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index fd74197..c733379 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -769,8 +769,6 @@ static void write_pack_file(void)
f = create_tmp_packfile(&pack_tmp_name);
offset = write_pack_header(f, nr_remaining);
- if (!offset)
- die_errno("unable to write pack header");
if (reuse_packfile) {
off_t packfile_size;
@@ -2089,7 +2087,7 @@ static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, vo
{
unsigned char peeled[20];
- if (!prefixcmp(path, "refs/tags/") && /* is a tag? */
+ if (starts_with(path, "refs/tags/") && /* is a tag? */
!peel_ref(path, peeled) && /* peelable? */
packlist_find(&to_pack, peeled, NULL)) /* object packed? */
add_object_entry(sha1, OBJ_TAG, NULL, 0);
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index fa6ce42..fcf5fb6 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -10,58 +10,62 @@ static const char * const prune_packed_usage[] = {
static struct progress *progress;
-static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
+static void prune_dir(int i, DIR *dir, struct strbuf *pathname, int opts)
{
struct dirent *de;
char hex[40];
+ int top_len = pathname->len;
sprintf(hex, "%02x", i);
while ((de = readdir(dir)) != NULL) {
unsigned char sha1[20];
if (strlen(de->d_name) != 38)
continue;
- memcpy(hex+2, de->d_name, 38);
+ memcpy(hex + 2, de->d_name, 38);
if (get_sha1_hex(hex, sha1))
continue;
if (!has_sha1_pack(sha1))
continue;
- memcpy(pathname + len, de->d_name, 38);
+
+ strbuf_add(pathname, de->d_name, 38);
if (opts & PRUNE_PACKED_DRY_RUN)
- printf("rm -f %s\n", pathname);
+ printf("rm -f %s\n", pathname->buf);
else
- unlink_or_warn(pathname);
+ unlink_or_warn(pathname->buf);
display_progress(progress, i + 1);
+ strbuf_setlen(pathname, top_len);
}
}
void prune_packed_objects(int opts)
{
int i;
- static char pathname[PATH_MAX];
const char *dir = get_object_directory();
- int len = strlen(dir);
+ struct strbuf pathname = STRBUF_INIT;
+ int top_len;
+ strbuf_addstr(&pathname, dir);
if (opts & PRUNE_PACKED_VERBOSE)
progress = start_progress_delay("Removing duplicate objects",
256, 95, 2);
- if (len > PATH_MAX - 42)
- die("impossible object directory");
- memcpy(pathname, dir, len);
- if (len && pathname[len-1] != '/')
- pathname[len++] = '/';
+ if (pathname.len && pathname.buf[pathname.len - 1] != '/')
+ strbuf_addch(&pathname, '/');
+
+ top_len = pathname.len;
for (i = 0; i < 256; i++) {
DIR *d;
display_progress(progress, i + 1);
- sprintf(pathname + len, "%02x/", i);
- d = opendir(pathname);
+ strbuf_setlen(&pathname, top_len);
+ strbuf_addf(&pathname, "%02x/", i);
+ d = opendir(pathname.buf);
if (!d)
continue;
- prune_dir(i, d, pathname, len + 3, opts);
+ prune_dir(i, d, &pathname, opts);
closedir(d);
- pathname[len + 2] = '\0';
- rmdir(pathname);
+ strbuf_setlen(&pathname, top_len + 2);
+ rmdir(pathname.buf);
}
stop_progress(&progress);
}
diff --git a/builtin/prune.c b/builtin/prune.c
index 6366917..de43b26 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -17,9 +17,8 @@ static int verbose;
static unsigned long expire;
static int show_progress = -1;
-static int prune_tmp_object(const char *path, const char *filename)
+static int prune_tmp_file(const char *fullpath)
{
- const char *fullpath = mkpath("%s/%s", path, filename);
struct stat st;
if (lstat(fullpath, &st))
return error("Could not stat '%s'", fullpath);
@@ -32,9 +31,8 @@ static int prune_tmp_object(const char *path, const char *filename)
return 0;
}
-static int prune_object(char *path, const char *filename, const unsigned char *sha1)
+static int prune_object(const char *fullpath, const unsigned char *sha1)
{
- const char *fullpath = mkpath("%s/%s", path, filename);
struct stat st;
if (lstat(fullpath, &st))
return error("Could not stat '%s'", fullpath);
@@ -50,9 +48,10 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
return 0;
}
-static int prune_dir(int i, char *path)
+static int prune_dir(int i, struct strbuf *path)
{
- DIR *dir = opendir(path);
+ size_t baselen = path->len;
+ DIR *dir = opendir(path->buf);
struct dirent *de;
if (!dir)
@@ -77,28 +76,39 @@ static int prune_dir(int i, char *path)
if (lookup_object(sha1))
continue;
- prune_object(path, de->d_name, sha1);
+ strbuf_addf(path, "/%s", de->d_name);
+ prune_object(path->buf, sha1);
+ strbuf_setlen(path, baselen);
continue;
}
- if (!prefixcmp(de->d_name, "tmp_obj_")) {
- prune_tmp_object(path, de->d_name);
+ if (starts_with(de->d_name, "tmp_obj_")) {
+ strbuf_addf(path, "/%s", de->d_name);
+ prune_tmp_file(path->buf);
+ strbuf_setlen(path, baselen);
continue;
}
- fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
+ fprintf(stderr, "bad sha1 file: %s/%s\n", path->buf, de->d_name);
}
closedir(dir);
if (!show_only)
- rmdir(path);
+ rmdir(path->buf);
return 0;
}
static void prune_object_dir(const char *path)
{
+ struct strbuf buf = STRBUF_INIT;
+ size_t baselen;
int i;
+
+ strbuf_addstr(&buf, path);
+ strbuf_addch(&buf, '/');
+ baselen = buf.len;
+
for (i = 0; i < 256; i++) {
- static char dir[4096];
- sprintf(dir, "%s/%02x", path, i);
- prune_dir(i, dir);
+ strbuf_addf(&buf, "%02x", i);
+ prune_dir(i, &buf);
+ strbuf_setlen(&buf, baselen);
}
}
@@ -119,8 +129,8 @@ static void remove_temporary_files(const char *path)
return;
}
while ((de = readdir(dir)) != NULL)
- if (!prefixcmp(de->d_name, "tmp_"))
- prune_tmp_object(path, de->d_name);
+ if (starts_with(de->d_name, "tmp_"))
+ prune_tmp_file(mkpath("%s/%s", path, de->d_name));
closedir(dir);
}
@@ -170,5 +180,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
s = mkpathdup("%s/pack", get_object_directory());
remove_temporary_files(s);
free(s);
+
+ if (is_repository_shallow())
+ prune_shallow(show_only);
+
return 0;
}
diff --git a/builtin/push.c b/builtin/push.c
index 7b1b66c..0e50ddb 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -35,35 +35,75 @@ static void add_refspec(const char *ref)
refspec[refspec_nr-1] = ref;
}
-static void set_refspecs(const char **refs, int nr)
+static const char *map_refspec(const char *ref,
+ struct remote *remote, struct ref *local_refs)
{
+ struct ref *matched = NULL;
+
+ /* Does "ref" uniquely name our ref? */
+ if (count_refspec_match(ref, local_refs, &matched) != 1)
+ return ref;
+
+ if (remote->push) {
+ struct refspec query;
+ memset(&query, 0, sizeof(struct refspec));
+ query.src = matched->name;
+ if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) &&
+ query.dst) {
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addf(&buf, "%s%s:%s",
+ query.force ? "+" : "",
+ query.src, query.dst);
+ return strbuf_detach(&buf, NULL);
+ }
+ }
+
+ if (push_default == PUSH_DEFAULT_UPSTREAM &&
+ !prefixcmp(matched->name, "refs/heads/")) {
+ struct branch *branch = branch_get(matched->name + 11);
+ if (branch->merge_nr == 1 && branch->merge[0]->src) {
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addf(&buf, "%s:%s",
+ ref, branch->merge[0]->src);
+ return strbuf_detach(&buf, NULL);
+ }
+ }
+
+ return ref;
+}
+
+static void set_refspecs(const char **refs, int nr, const char *repo)
+{
+ struct remote *remote = NULL;
+ struct ref *local_refs = NULL;
int i;
+
for (i = 0; i < nr; i++) {
const char *ref = refs[i];
if (!strcmp("tag", ref)) {
- char *tag;
- int len;
+ struct strbuf tagref = STRBUF_INIT;
if (nr <= ++i)
die(_("tag shorthand without <tag>"));
- len = strlen(refs[i]) + 11;
- if (deleterefs) {
- tag = xmalloc(len+1);
- strcpy(tag, ":refs/tags/");
- } else {
- tag = xmalloc(len);
- strcpy(tag, "refs/tags/");
+ ref = refs[i];
+ if (deleterefs)
+ strbuf_addf(&tagref, ":refs/tags/%s", ref);
+ else
+ strbuf_addf(&tagref, "refs/tags/%s", ref);
+ ref = strbuf_detach(&tagref, NULL);
+ } else if (deleterefs) {
+ struct strbuf delref = STRBUF_INIT;
+ if (strchr(ref, ':'))
+ die(_("--delete only accepts plain target ref names"));
+ strbuf_addf(&delref, ":%s", ref);
+ ref = strbuf_detach(&delref, NULL);
+ } else if (!strchr(ref, ':')) {
+ if (!remote) {
+ /* lazily grab remote and local_refs */
+ remote = remote_get(repo);
+ local_refs = get_local_heads();
}
- strcat(tag, refs[i]);
- ref = tag;
- } else if (deleterefs && !strchr(ref, ':')) {
- char *delref;
- int len = strlen(ref)+1;
- delref = xmalloc(len+1);
- strcpy(delref, ":");
- strcat(delref, ref);
- ref = delref;
- } else if (deleterefs)
- die(_("--delete only accepts plain target ref names"));
+ ref = map_refspec(ref, remote, local_refs);
+ }
add_refspec(ref);
}
}
@@ -174,6 +214,13 @@ N_("push.default is unset; its implicit value is changing in\n"
"\n"
" git config --global push.default simple\n"
"\n"
+ "When push.default is set to 'matching', git will push local branches\n"
+ "to the remote branches that already exist with the same name.\n"
+ "\n"
+ "In Git 2.0, Git will default to the more conservative 'simple'\n"
+ "behavior, which only pushes the current branch to the corresponding\n"
+ "remote branch that 'git pull' uses to update the current branch.\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)");
@@ -494,7 +541,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
if (argc > 0) {
repo = argv[0];
- set_refspecs(argv + 1, argc - 1);
+ set_refspecs(argv + 1, argc - 1, repo);
}
rc = do_push(repo, flags);
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 0f5d7fe..0d7ef84 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -178,7 +178,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
if (1 < opts.index_only + opts.update)
die("-u and -i at the same time makes no sense");
- if ((opts.update||opts.index_only) && !opts.merge)
+ if ((opts.update || opts.index_only) && !opts.merge)
die("%s is meaningless without -m, --reset, or --prefix",
opts.update ? "-u" : "-i");
if ((opts.dir && !opts.update))
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 67ce1ef..85bba35 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -13,6 +13,7 @@
#include "string-list.h"
#include "sha1-array.h"
#include "connected.h"
+#include "argv-array.h"
#include "version.h"
static const char receive_pack_usage[] = "git receive-pack <git-dir>";
@@ -43,6 +44,8 @@ static int fix_thin = 1;
static const char *head_name;
static void *head_name_to_free;
static int sent_capabilities;
+static int shallow_update;
+static const char *alt_shallow_file;
static enum deny_action parse_deny_action(const char *var, const char *value)
{
@@ -121,6 +124,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
+ if (strcmp(var, "receive.shallowupdate") == 0) {
+ shallow_update = git_config_bool(var, value);
+ return 0;
+ }
+
return git_default_config(var, value, cb);
}
@@ -178,6 +186,8 @@ static void write_head_info(void)
if (!sent_capabilities)
show_ref("capabilities^{}", null_sha1);
+ advertise_shallow_grafts(1);
+
/* EOF */
packet_flush(1);
}
@@ -187,6 +197,7 @@ struct command {
const char *error_string;
unsigned int skip_update:1,
did_not_exist:1;
+ int index;
unsigned char old_sha1[20];
unsigned char new_sha1[20];
char ref_name[FLEX_ARRAY]; /* more */
@@ -418,7 +429,46 @@ static void refuse_unconfigured_deny_delete_current(void)
rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
}
-static const char *update(struct command *cmd)
+static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]);
+static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
+{
+ static struct lock_file shallow_lock;
+ struct sha1_array extra = SHA1_ARRAY_INIT;
+ const char *alt_file;
+ uint32_t mask = 1 << (cmd->index % 32);
+ int i;
+
+ trace_printf_key("GIT_TRACE_SHALLOW",
+ "shallow: update_shallow_ref %s\n", cmd->ref_name);
+ for (i = 0; i < si->shallow->nr; i++)
+ if (si->used_shallow[i] &&
+ (si->used_shallow[i][cmd->index / 32] & mask) &&
+ !delayed_reachability_test(si, i))
+ sha1_array_append(&extra, si->shallow->sha1[i]);
+
+ setup_alternate_shallow(&shallow_lock, &alt_file, &extra);
+ if (check_shallow_connected(command_singleton_iterator,
+ 0, cmd, alt_file)) {
+ rollback_lock_file(&shallow_lock);
+ sha1_array_clear(&extra);
+ return -1;
+ }
+
+ commit_lock_file(&shallow_lock);
+
+ /*
+ * Make sure setup_alternate_shallow() for the next ref does
+ * not lose these new roots..
+ */
+ for (i = 0; i < extra.nr; i++)
+ register_shallow(extra.sha1[i]);
+
+ si->shallow_ref[cmd->index] = 0;
+ sha1_array_clear(&extra);
+ return 0;
+}
+
+static const char *update(struct command *cmd, struct shallow_info *si)
{
const char *name = cmd->ref_name;
struct strbuf namespaced_name_buf = STRBUF_INIT;
@@ -428,7 +478,7 @@ static const char *update(struct command *cmd)
struct ref_lock *lock;
/* only refs/... are allowed */
- if (prefixcmp(name, "refs/") || check_refname_format(name + 5, 0)) {
+ if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
rp_error("refusing to create funny ref '%s' remotely", name);
return "funny refname";
}
@@ -459,7 +509,7 @@ static const char *update(struct command *cmd)
}
if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
- if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
+ if (deny_deletes && starts_with(name, "refs/heads/")) {
rp_error("denying ref deletion for %s", name);
return "deletion prohibited";
}
@@ -483,7 +533,7 @@ static const char *update(struct command *cmd)
if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
!is_null_sha1(old_sha1) &&
- !prefixcmp(name, "refs/heads/")) {
+ starts_with(name, "refs/heads/")) {
struct object *old_object, *new_object;
struct commit *old_commit, *new_commit;
@@ -526,6 +576,10 @@ static const char *update(struct command *cmd)
return NULL; /* good */
}
else {
+ if (shallow_update && si->shallow_ref[cmd->index] &&
+ update_shallow_ref(cmd, si))
+ return "shallow error";
+
lock = lock_any_ref_for_update(namespaced_name, old_sha1,
0, NULL);
if (!lock) {
@@ -666,12 +720,16 @@ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
return 0;
}
-static void set_connectivity_errors(struct command *commands)
+static void set_connectivity_errors(struct command *commands,
+ struct shallow_info *si)
{
struct command *cmd;
for (cmd = commands; cmd; cmd = cmd->next) {
struct command *singleton = cmd;
+ if (shallow_update && si->shallow_ref[cmd->index])
+ /* to be checked in update_shallow_ref() */
+ continue;
if (!check_everything_connected(command_singleton_iterator,
0, &singleton))
continue;
@@ -679,18 +737,26 @@ static void set_connectivity_errors(struct command *commands)
}
}
+struct iterate_data {
+ struct command *cmds;
+ struct shallow_info *si;
+};
+
static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
{
- struct command **cmd_list = cb_data;
+ struct iterate_data *data = cb_data;
+ struct command **cmd_list = &data->cmds;
struct command *cmd = *cmd_list;
- while (cmd) {
- if (!is_null_sha1(cmd->new_sha1)) {
+ for (; cmd; cmd = cmd->next) {
+ if (shallow_update && data->si->shallow_ref[cmd->index])
+ /* to be checked in update_shallow_ref() */
+ continue;
+ if (!is_null_sha1(cmd->new_sha1) && !cmd->skip_update) {
hashcpy(sha1, cmd->new_sha1);
*cmd_list = cmd->next;
return 0;
}
- cmd = cmd->next;
}
*cmd_list = NULL;
return -1; /* end of list */
@@ -710,10 +776,14 @@ static void reject_updates_to_hidden(struct command *commands)
}
}
-static void execute_commands(struct command *commands, const char *unpacker_error)
+static void execute_commands(struct command *commands,
+ const char *unpacker_error,
+ struct shallow_info *si)
{
+ int checked_connectivity;
struct command *cmd;
unsigned char sha1[20];
+ struct iterate_data data;
if (unpacker_error) {
for (cmd = commands; cmd; cmd = cmd->next)
@@ -721,10 +791,10 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
return;
}
- cmd = commands;
- if (check_everything_connected(iterate_receive_command_list,
- 0, &cmd))
- set_connectivity_errors(commands);
+ data.cmds = commands;
+ data.si = si;
+ if (check_everything_connected(iterate_receive_command_list, 0, &data))
+ set_connectivity_errors(commands, si);
reject_updates_to_hidden(commands);
@@ -741,6 +811,7 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
free(head_name_to_free);
head_name = head_name_to_free = resolve_refdup("HEAD", sha1, 0, NULL);
+ checked_connectivity = 1;
for (cmd = commands; cmd; cmd = cmd->next) {
if (cmd->error_string)
continue;
@@ -748,11 +819,26 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
if (cmd->skip_update)
continue;
- cmd->error_string = update(cmd);
+ cmd->error_string = update(cmd, si);
+ if (shallow_update && !cmd->error_string &&
+ si->shallow_ref[cmd->index]) {
+ error("BUG: connectivity check has not been run on ref %s",
+ cmd->ref_name);
+ checked_connectivity = 0;
+ }
+ }
+
+ if (shallow_update) {
+ if (!checked_connectivity)
+ error("BUG: run 'git fsck' for safety.\n"
+ "If there are errors, try to remove "
+ "the reported refs above");
+ if (alt_shallow_file && *alt_shallow_file)
+ unlink(alt_shallow_file);
}
}
-static struct command *read_head_info(void)
+static struct command *read_head_info(struct sha1_array *shallow)
{
struct command *commands = NULL;
struct command **p = &commands;
@@ -766,6 +852,14 @@ static struct command *read_head_info(void)
line = packet_read_line(0, &len);
if (!line)
break;
+
+ if (len == 48 && starts_with(line, "shallow ")) {
+ if (get_sha1_hex(line + 8, old_sha1))
+ die("protocol error: expected shallow sha, got '%s'", line + 8);
+ sha1_array_append(shallow, old_sha1);
+ continue;
+ }
+
if (len < 83 ||
line[40] != ' ' ||
line[81] != ' ' ||
@@ -817,11 +911,14 @@ static const char *parse_pack_header(struct pack_header *hdr)
static const char *pack_lockfile;
-static const char *unpack(int err_fd)
+static const char *unpack(int err_fd, struct shallow_info *si)
{
struct pack_header hdr;
+ struct argv_array av = ARGV_ARRAY_INIT;
const char *hdr_err;
+ int status;
char hdr_arg[38];
+ struct child_process child;
int fsck_objects = (receive_fsck_objects >= 0
? receive_fsck_objects
: transfer_fsck_objects >= 0
@@ -838,72 +935,63 @@ static const char *unpack(int err_fd)
"--pack_header=%"PRIu32",%"PRIu32,
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
+ if (si->nr_ours || si->nr_theirs) {
+ alt_shallow_file = setup_temporary_shallow(si->shallow);
+ argv_array_pushl(&av, "--shallow-file", alt_shallow_file, NULL);
+ }
+
+ memset(&child, 0, sizeof(child));
if (ntohl(hdr.hdr_entries) < unpack_limit) {
- int code, i = 0;
- struct child_process child;
- const char *unpacker[5];
- unpacker[i++] = "unpack-objects";
+ argv_array_pushl(&av, "unpack-objects", hdr_arg, NULL);
if (quiet)
- unpacker[i++] = "-q";
+ argv_array_push(&av, "-q");
if (fsck_objects)
- unpacker[i++] = "--strict";
- unpacker[i++] = hdr_arg;
- unpacker[i++] = NULL;
- memset(&child, 0, sizeof(child));
- child.argv = unpacker;
+ argv_array_push(&av, "--strict");
+ child.argv = av.argv;
child.no_stdout = 1;
child.err = err_fd;
child.git_cmd = 1;
- code = run_command(&child);
- if (!code)
- return NULL;
- return "unpack-objects abnormal exit";
+ status = run_command(&child);
+ if (status)
+ return "unpack-objects abnormal exit";
} else {
- const char *keeper[7];
- int s, status, i = 0;
+ int s;
char keep_arg[256];
- struct child_process ip;
s = sprintf(keep_arg, "--keep=receive-pack %"PRIuMAX" on ", (uintmax_t) getpid());
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
strcpy(keep_arg + s, "localhost");
- keeper[i++] = "index-pack";
- keeper[i++] = "--stdin";
+ argv_array_pushl(&av, "index-pack",
+ "--stdin", hdr_arg, keep_arg, NULL);
if (fsck_objects)
- keeper[i++] = "--strict";
+ argv_array_push(&av, "--strict");
if (fix_thin)
- keeper[i++] = "--fix-thin";
- keeper[i++] = hdr_arg;
- keeper[i++] = keep_arg;
- keeper[i++] = NULL;
- memset(&ip, 0, sizeof(ip));
- ip.argv = keeper;
- ip.out = -1;
- ip.err = err_fd;
- ip.git_cmd = 1;
- status = start_command(&ip);
- if (status) {
+ argv_array_push(&av, "--fix-thin");
+ child.argv = av.argv;
+ child.out = -1;
+ child.err = err_fd;
+ child.git_cmd = 1;
+ status = start_command(&child);
+ if (status)
return "index-pack fork failed";
- }
- pack_lockfile = index_pack_lockfile(ip.out);
- close(ip.out);
- status = finish_command(&ip);
- if (!status) {
- reprepare_packed_git();
- return NULL;
- }
- return "index-pack abnormal exit";
+ pack_lockfile = index_pack_lockfile(child.out);
+ close(child.out);
+ status = finish_command(&child);
+ if (status)
+ return "index-pack abnormal exit";
+ reprepare_packed_git();
}
+ return NULL;
}
-static const char *unpack_with_sideband(void)
+static const char *unpack_with_sideband(struct shallow_info *si)
{
struct async muxer;
const char *ret;
if (!use_sideband)
- return unpack(0);
+ return unpack(0, si);
memset(&muxer, 0, sizeof(muxer));
muxer.proc = copy_to_sideband;
@@ -911,12 +999,101 @@ static const char *unpack_with_sideband(void)
if (start_async(&muxer))
return NULL;
- ret = unpack(muxer.in);
+ ret = unpack(muxer.in, si);
finish_async(&muxer);
return ret;
}
+static void prepare_shallow_update(struct command *commands,
+ struct shallow_info *si)
+{
+ int i, j, k, bitmap_size = (si->ref->nr + 31) / 32;
+
+ si->used_shallow = xmalloc(sizeof(*si->used_shallow) *
+ si->shallow->nr);
+ assign_shallow_commits_to_refs(si, si->used_shallow, NULL);
+
+ si->need_reachability_test =
+ xcalloc(si->shallow->nr, sizeof(*si->need_reachability_test));
+ si->reachable =
+ xcalloc(si->shallow->nr, sizeof(*si->reachable));
+ si->shallow_ref = xcalloc(si->ref->nr, sizeof(*si->shallow_ref));
+
+ for (i = 0; i < si->nr_ours; i++)
+ si->need_reachability_test[si->ours[i]] = 1;
+
+ for (i = 0; i < si->shallow->nr; i++) {
+ if (!si->used_shallow[i])
+ continue;
+ for (j = 0; j < bitmap_size; j++) {
+ if (!si->used_shallow[i][j])
+ continue;
+ si->need_reachability_test[i]++;
+ for (k = 0; k < 32; k++)
+ if (si->used_shallow[i][j] & (1 << k))
+ si->shallow_ref[j * 32 + k]++;
+ }
+
+ /*
+ * true for those associated with some refs and belong
+ * in "ours" list aka "step 7 not done yet"
+ */
+ si->need_reachability_test[i] =
+ si->need_reachability_test[i] > 1;
+ }
+
+ /*
+ * keep hooks happy by forcing a temporary shallow file via
+ * env variable because we can't add --shallow-file to every
+ * command. check_everything_connected() will be done with
+ * true .git/shallow though.
+ */
+ setenv(GIT_SHALLOW_FILE_ENVIRONMENT, alt_shallow_file, 1);
+}
+
+static void update_shallow_info(struct command *commands,
+ struct shallow_info *si,
+ struct sha1_array *ref)
+{
+ struct command *cmd;
+ int *ref_status;
+ remove_nonexistent_theirs_shallow(si);
+ if (!si->nr_ours && !si->nr_theirs) {
+ shallow_update = 0;
+ return;
+ }
+
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (is_null_sha1(cmd->new_sha1))
+ continue;
+ sha1_array_append(ref, cmd->new_sha1);
+ cmd->index = ref->nr - 1;
+ }
+ si->ref = ref;
+
+ if (shallow_update) {
+ prepare_shallow_update(commands, si);
+ return;
+ }
+
+ ref_status = xmalloc(sizeof(*ref_status) * ref->nr);
+ assign_shallow_commits_to_refs(si, NULL, ref_status);
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (is_null_sha1(cmd->new_sha1))
+ continue;
+ if (ref_status[cmd->index]) {
+ cmd->error_string = "shallow update not allowed";
+ cmd->skip_update = 1;
+ }
+ }
+ if (alt_shallow_file && *alt_shallow_file) {
+ unlink(alt_shallow_file);
+ alt_shallow_file = NULL;
+ }
+ free(ref_status);
+}
+
static void report(struct command *commands, const char *unpack_status)
{
struct command *cmd;
@@ -958,6 +1135,9 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
int i;
char *dir = NULL;
struct command *commands;
+ struct sha1_array shallow = SHA1_ARRAY_INIT;
+ struct sha1_array ref = SHA1_ARRAY_INIT;
+ struct shallow_info si;
packet_trace_identity("receive-pack");
@@ -998,9 +1178,6 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (!enter_repo(dir, 0))
die("'%s' does not appear to be a git repository", dir);
- if (is_repository_shallow())
- die("attempt to push into a shallow repository");
-
git_config(receive_pack_config, NULL);
if (0 <= transfer_unpack_limit)
@@ -1014,12 +1191,17 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (advertise_refs)
return 0;
- if ((commands = read_head_info()) != NULL) {
+ if ((commands = read_head_info(&shallow)) != NULL) {
const char *unpack_status = NULL;
- if (!delete_only(commands))
- unpack_status = unpack_with_sideband();
- execute_commands(commands, unpack_status);
+ prepare_shallow_info(&si, &shallow);
+ if (!si.nr_ours && !si.nr_theirs)
+ shallow_update = 0;
+ if (!delete_only(commands)) {
+ unpack_status = unpack_with_sideband(&si);
+ update_shallow_info(commands, &si, &ref);
+ }
+ execute_commands(commands, unpack_status, &si);
if (pack_lockfile)
unlink_or_warn(pack_lockfile);
if (report_status)
@@ -1035,8 +1217,11 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
}
if (auto_update_server_info)
update_server_info(0);
+ clear_shallow_info(&si);
}
if (use_sideband)
packet_flush(1);
+ sha1_array_clear(&shallow);
+ sha1_array_clear(&ref);
return 0;
}
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 6eb24c8..852cff6 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -610,12 +610,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
const char *arg = argv[i];
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
cb.dry_run = 1;
- else if (!prefixcmp(arg, "--expire=")) {
+ else if (starts_with(arg, "--expire=")) {
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=")) {
+ else if (starts_with(arg, "--expire-unreachable=")) {
if (parse_expiry_date(arg + 21, &cb.expire_unreachable))
die(_("'%s' is not a valid timestamp"), arg);
explicit_expiry |= EXPIRE_UNREACH;
diff --git a/builtin/remote.c b/builtin/remote.c
index 4e14891..b3ab4cf 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -6,6 +6,7 @@
#include "strbuf.h"
#include "run-command.h"
#include "refs.h"
+#include "argv-array.h"
static const char * const builtin_remote_usage[] = {
N_("git remote [-v | --verbose]"),
@@ -77,17 +78,6 @@ static const char * const builtin_remote_seturl_usage[] = {
static int verbose;
-static int show_all(void);
-static int prune_remote(const char *remote, int dry_run);
-
-static inline int postfixcmp(const char *string, const char *postfix)
-{
- int len1 = strlen(string), len2 = strlen(postfix);
- if (len1 < len2)
- return 1;
- return strcmp(string + len1 - len2, postfix);
-}
-
static int fetch_remote(const char *name)
{
const char *argv[] = { "fetch", name, NULL, NULL };
@@ -269,7 +259,7 @@ static const char *abbrev_ref(const char *name, const char *prefix)
static int config_read_branches(const char *key, const char *value, void *cb)
{
- if (!prefixcmp(key, "branch.")) {
+ if (starts_with(key, "branch.")) {
const char *orig_key = key;
char *name;
struct string_list_item *item;
@@ -277,13 +267,13 @@ static int config_read_branches(const char *key, const char *value, void *cb)
enum { REMOTE, MERGE, REBASE } type;
key += 7;
- if (!postfixcmp(key, ".remote")) {
+ if (ends_with(key, ".remote")) {
name = xstrndup(key, strlen(key) - 7);
type = REMOTE;
- } else if (!postfixcmp(key, ".merge")) {
+ } else if (ends_with(key, ".merge")) {
name = xstrndup(key, strlen(key) - 6);
type = MERGE;
- } else if (!postfixcmp(key, ".rebase")) {
+ } else if (ends_with(key, ".rebase")) {
name = xstrndup(key, strlen(key) - 7);
type = REBASE;
} else
@@ -309,8 +299,13 @@ static int config_read_branches(const char *key, const char *value, void *cb)
space = strchr(value, ' ');
}
string_list_append(&info->merge, xstrdup(value));
- } else
- info->rebase = git_config_bool(orig_key, value);
+ } else {
+ int v = git_config_maybe_bool(orig_key, value);
+ if (v >= 0)
+ info->rebase = v;
+ else if (!strcmp(value, "preserve"))
+ info->rebase = 1;
+ }
}
return 0;
}
@@ -534,9 +529,9 @@ static int add_branch_for_removal(const char *refname,
}
/* don't delete non-remote-tracking refs */
- if (prefixcmp(refname, "refs/remotes/")) {
+ if (!starts_with(refname, "refs/remotes/")) {
/* advise user how to delete local branches */
- if (!prefixcmp(refname, "refs/heads/"))
+ if (starts_with(refname, "refs/heads/"))
string_list_append(branches->skipped,
abbrev_branch(refname));
/* silently skip over other non-remote refs */
@@ -571,7 +566,7 @@ static int read_remote_branches(const char *refname,
const char *symref;
strbuf_addf(&buf, "refs/remotes/%s/", rename->old);
- if (!prefixcmp(refname, buf.buf)) {
+ if (starts_with(refname, buf.buf)) {
item = string_list_append(rename->remote_branches, xstrdup(refname));
symref = resolve_ref_unsafe(refname, orig_sha1, 1, &flag);
if (flag & REF_ISSYMREF)
@@ -1084,6 +1079,64 @@ static int show_push_info_item(struct string_list_item *item, void *cb_data)
return 0;
}
+static int get_one_entry(struct remote *remote, void *priv)
+{
+ struct string_list *list = priv;
+ struct strbuf url_buf = STRBUF_INIT;
+ const char **url;
+ int i, url_nr;
+
+ if (remote->url_nr > 0) {
+ strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]);
+ string_list_append(list, remote->name)->util =
+ strbuf_detach(&url_buf, NULL);
+ } else
+ string_list_append(list, remote->name)->util = NULL;
+ if (remote->pushurl_nr) {
+ url = remote->pushurl;
+ url_nr = remote->pushurl_nr;
+ } else {
+ url = remote->url;
+ url_nr = remote->url_nr;
+ }
+ for (i = 0; i < url_nr; i++)
+ {
+ strbuf_addf(&url_buf, "%s (push)", url[i]);
+ string_list_append(list, remote->name)->util =
+ strbuf_detach(&url_buf, NULL);
+ }
+
+ return 0;
+}
+
+static int show_all(void)
+{
+ struct string_list list = STRING_LIST_INIT_NODUP;
+ int result;
+
+ list.strdup_strings = 1;
+ result = for_each_remote(get_one_entry, &list);
+
+ if (!result) {
+ int i;
+
+ sort_string_list(&list);
+ for (i = 0; i < list.nr; i++) {
+ struct string_list_item *item = list.items + i;
+ if (verbose)
+ printf("%s\t%s\n", item->string,
+ item->util ? (const char *)item->util : "");
+ else {
+ if (i && !strcmp((item - 1)->string, item->string))
+ continue;
+ printf("%s\n", item->string);
+ }
+ }
+ }
+ string_list_clear(&list, 1);
+ return result;
+}
+
static int show(int argc, const char **argv)
{
int no_query = 0, result = 0, query_flag = 0;
@@ -1246,26 +1299,6 @@ static int set_head(int argc, const char **argv)
return result;
}
-static int prune(int argc, const char **argv)
-{
- int dry_run = 0, result = 0;
- struct option options[] = {
- OPT__DRY_RUN(&dry_run, N_("dry run")),
- OPT_END()
- };
-
- argc = parse_options(argc, argv, NULL, options, builtin_remote_prune_usage,
- 0);
-
- if (argc < 1)
- usage_with_options(builtin_remote_prune_usage, options);
-
- for (; argc; argc--, argv++)
- result |= prune_remote(*argv, dry_run);
-
- return result;
-}
-
static int prune_remote(const char *remote, int dry_run)
{
int result = 0, i;
@@ -1304,6 +1337,26 @@ static int prune_remote(const char *remote, int dry_run)
return result;
}
+static int prune(int argc, const char **argv)
+{
+ int dry_run = 0, result = 0;
+ struct option options[] = {
+ OPT__DRY_RUN(&dry_run, N_("dry run")),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, NULL, options, builtin_remote_prune_usage,
+ 0);
+
+ if (argc < 1)
+ usage_with_options(builtin_remote_prune_usage, options);
+
+ for (; argc; argc--, argv++)
+ result |= prune_remote(*argv, dry_run);
+
+ return result;
+}
+
static int get_remote_default(const char *key, const char *value, void *priv)
{
if (strcmp(key, "remotes.default") == 0) {
@@ -1315,42 +1368,42 @@ static int get_remote_default(const char *key, const char *value, void *priv)
static int update(int argc, const char **argv)
{
- int i, prune = 0;
+ int i, prune = -1;
struct option options[] = {
OPT_BOOL('p', "prune", &prune,
N_("prune remotes after fetching")),
OPT_END()
};
- const char **fetch_argv;
- int fetch_argc = 0;
+ struct argv_array fetch_argv = ARGV_ARRAY_INIT;
int default_defined = 0;
-
- fetch_argv = xmalloc(sizeof(char *) * (argc+5));
+ int retval;
argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
PARSE_OPT_KEEP_ARGV0);
- fetch_argv[fetch_argc++] = "fetch";
+ argv_array_push(&fetch_argv, "fetch");
- if (prune)
- fetch_argv[fetch_argc++] = "--prune";
+ if (prune != -1)
+ argv_array_push(&fetch_argv, prune ? "--prune" : "--no-prune");
if (verbose)
- fetch_argv[fetch_argc++] = "-v";
- fetch_argv[fetch_argc++] = "--multiple";
+ argv_array_push(&fetch_argv, "-v");
+ argv_array_push(&fetch_argv, "--multiple");
if (argc < 2)
- fetch_argv[fetch_argc++] = "default";
+ argv_array_push(&fetch_argv, "default");
for (i = 1; i < argc; i++)
- fetch_argv[fetch_argc++] = argv[i];
+ argv_array_push(&fetch_argv, argv[i]);
- if (strcmp(fetch_argv[fetch_argc-1], "default") == 0) {
+ if (strcmp(fetch_argv.argv[fetch_argv.argc-1], "default") == 0) {
git_config(get_remote_default, &default_defined);
- if (!default_defined)
- fetch_argv[fetch_argc-1] = "--all";
+ if (!default_defined) {
+ argv_array_pop(&fetch_argv);
+ argv_array_push(&fetch_argv, "--all");
+ }
}
- fetch_argv[fetch_argc] = NULL;
-
- return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
+ retval = run_command_v_opt(fetch_argv.argv, RUN_GIT_CMD);
+ argv_array_clear(&fetch_argv);
+ return retval;
}
static int remove_all_fetch_refspecs(const char *remote, const char *key)
@@ -1505,64 +1558,6 @@ static int set_url(int argc, const char **argv)
return 0;
}
-static int get_one_entry(struct remote *remote, void *priv)
-{
- struct string_list *list = priv;
- struct strbuf url_buf = STRBUF_INIT;
- const char **url;
- int i, url_nr;
-
- if (remote->url_nr > 0) {
- strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]);
- string_list_append(list, remote->name)->util =
- strbuf_detach(&url_buf, NULL);
- } else
- string_list_append(list, remote->name)->util = NULL;
- if (remote->pushurl_nr) {
- url = remote->pushurl;
- url_nr = remote->pushurl_nr;
- } else {
- url = remote->url;
- url_nr = remote->url_nr;
- }
- for (i = 0; i < url_nr; i++)
- {
- strbuf_addf(&url_buf, "%s (push)", url[i]);
- string_list_append(list, remote->name)->util =
- strbuf_detach(&url_buf, NULL);
- }
-
- return 0;
-}
-
-static int show_all(void)
-{
- struct string_list list = STRING_LIST_INIT_NODUP;
- int result;
-
- list.strdup_strings = 1;
- result = for_each_remote(get_one_entry, &list);
-
- if (!result) {
- int i;
-
- sort_string_list(&list);
- for (i = 0; i < list.nr; i++) {
- struct string_list_item *item = list.items + i;
- if (verbose)
- printf("%s\t%s\n", item->string,
- item->util ? (const char *)item->util : "");
- else {
- if (i && !strcmp((item - 1)->string, item->string))
- continue;
- printf("%s\n", item->string);
- }
- }
- }
- string_list_clear(&list, 1);
- return result;
-}
-
int cmd_remote(int argc, const char **argv, const char *prefix)
{
struct option options[] = {
diff --git a/builtin/repack.c b/builtin/repack.c
index 239f278..49f5857 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -78,7 +78,7 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list)
return;
while ((e = readdir(dir)) != NULL) {
- if (suffixcmp(e->d_name, ".pack"))
+ if (!ends_with(e->d_name, ".pack"))
continue;
len = strlen(e->d_name) - strlen(".pack");
@@ -130,16 +130,16 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
struct string_list rollback = STRING_LIST_INIT_NODUP;
struct string_list existing_packs = STRING_LIST_INIT_DUP;
struct strbuf line = STRBUF_INIT;
- int nr_packs, ext, ret, failed;
+ int ext, ret, failed;
FILE *out;
/* variables to be filled by option parsing */
int pack_everything = 0;
int delete_redundant = 0;
- char *unpack_unreachable = NULL;
- int window = 0, window_memory = 0;
- int depth = 0;
- int max_pack_size = 0;
+ const char *unpack_unreachable = NULL;
+ const char *window = NULL, *window_memory = NULL;
+ const char *depth = NULL;
+ const char *max_pack_size = NULL;
int no_reuse_delta = 0, no_reuse_object = 0;
int no_update_server_info = 0;
int quiet = 0;
@@ -167,13 +167,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("write bitmap index")),
OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
N_("with -A, do not loosen objects older than this")),
- OPT_INTEGER(0, "window", &window,
+ OPT_STRING(0, "window", &window, N_("n"),
N_("size of the window used for delta compression")),
- OPT_INTEGER(0, "window-memory", &window_memory,
+ OPT_STRING(0, "window-memory", &window_memory, N_("bytes"),
N_("same as the above, but limit memory size instead of entries count")),
- OPT_INTEGER(0, "depth", &depth,
+ OPT_STRING(0, "depth", &depth, N_("n"),
N_("limits the maximum delta depth")),
- OPT_INTEGER(0, "max-pack-size", &max_pack_size,
+ OPT_STRING(0, "max-pack-size", &max_pack_size, N_("bytes"),
N_("maximum size of each packfile")),
OPT_END()
};
@@ -195,13 +195,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
argv_array_push(&cmd_args, "--all");
argv_array_push(&cmd_args, "--reflog");
if (window)
- argv_array_pushf(&cmd_args, "--window=%u", window);
+ argv_array_pushf(&cmd_args, "--window=%s", window);
if (window_memory)
- argv_array_pushf(&cmd_args, "--window-memory=%u", window_memory);
+ argv_array_pushf(&cmd_args, "--window-memory=%s", window_memory);
if (depth)
- argv_array_pushf(&cmd_args, "--depth=%u", depth);
+ argv_array_pushf(&cmd_args, "--depth=%s", depth);
if (max_pack_size)
- argv_array_pushf(&cmd_args, "--max_pack_size=%u", max_pack_size);
+ argv_array_pushf(&cmd_args, "--max-pack-size=%s", max_pack_size);
if (no_reuse_delta)
argv_array_pushf(&cmd_args, "--no-reuse-delta");
if (no_reuse_object)
@@ -246,13 +246,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (ret)
return ret;
- nr_packs = 0;
out = xfdopen(cmd.out, "r");
while (strbuf_getline(&line, out, '\n') != EOF) {
if (line.len != 40)
die("repack: Expecting 40 character sha1 lines only from pack-objects.");
string_list_append(&names, line.buf);
- nr_packs++;
}
fclose(out);
ret = finish_command(&cmd);
@@ -260,7 +258,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
return ret;
argv_array_clear(&cmd_args);
- if (!nr_packs && !quiet)
+ if (!names.nr && !quiet)
printf("Nothing new to pack.\n");
/*
@@ -273,7 +271,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
for_each_string_list_item(item, &names) {
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname, *fname_old;
- fname = mkpathdup("%s/%s%s", packdir,
+ fname = mkpathdup("%s/pack-%s%s", packdir,
item->string, exts[ext].name);
if (!file_exists(fname)) {
free(fname);
@@ -354,7 +352,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
for_each_string_list_item(item, &names) {
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname;
- fname = mkpath("%s/old-pack-%s%s",
+ fname = mkpath("%s/old-%s%s",
packdir,
item->string,
exts[ext].name);
diff --git a/builtin/replace.c b/builtin/replace.c
index b1bd3ef..2336325 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -16,27 +16,69 @@
static const char * const git_replace_usage[] = {
N_("git replace [-f] <object> <replacement>"),
N_("git replace -d <object>..."),
- N_("git replace -l [<pattern>]"),
+ N_("git replace [--format=<format>] [-l [<pattern>]]"),
NULL
};
+enum replace_format {
+ REPLACE_FORMAT_SHORT,
+ REPLACE_FORMAT_MEDIUM,
+ REPLACE_FORMAT_LONG
+};
+
+struct show_data {
+ const char *pattern;
+ enum replace_format format;
+};
+
static int show_reference(const char *refname, const unsigned char *sha1,
int flag, void *cb_data)
{
- const char *pattern = cb_data;
+ struct show_data *data = cb_data;
- if (!fnmatch(pattern, refname, 0))
- printf("%s\n", refname);
+ if (!fnmatch(data->pattern, refname, 0)) {
+ if (data->format == REPLACE_FORMAT_SHORT)
+ printf("%s\n", refname);
+ else if (data->format == REPLACE_FORMAT_MEDIUM)
+ printf("%s -> %s\n", refname, sha1_to_hex(sha1));
+ else { /* data->format == REPLACE_FORMAT_LONG */
+ unsigned char object[20];
+ enum object_type obj_type, repl_type;
+
+ if (get_sha1(refname, object))
+ return error("Failed to resolve '%s' as a valid ref.", refname);
+
+ obj_type = sha1_object_info(object, NULL);
+ repl_type = sha1_object_info(sha1, NULL);
+
+ printf("%s (%s) -> %s (%s)\n", refname, typename(obj_type),
+ sha1_to_hex(sha1), typename(repl_type));
+ }
+ }
return 0;
}
-static int list_replace_refs(const char *pattern)
+static int list_replace_refs(const char *pattern, const char *format)
{
+ struct show_data data;
+
if (pattern == NULL)
pattern = "*";
+ data.pattern = pattern;
- for_each_replace_ref(show_reference, (void *) pattern);
+ if (format == NULL || *format == '\0' || !strcmp(format, "short"))
+ data.format = REPLACE_FORMAT_SHORT;
+ else if (!strcmp(format, "medium"))
+ data.format = REPLACE_FORMAT_MEDIUM;
+ else if (!strcmp(format, "long"))
+ data.format = REPLACE_FORMAT_LONG;
+ else
+ die("invalid replace format '%s'\n"
+ "valid formats are 'short', 'medium' and 'long'\n",
+ format);
+
+ for_each_replace_ref(show_reference, (void *) &data);
return 0;
}
@@ -127,19 +169,27 @@ static int replace_object(const char *object_ref, const char *replace_ref,
int cmd_replace(int argc, const char **argv, const char *prefix)
{
int list = 0, delete = 0, force = 0;
+ const char *format = NULL;
struct option options[] = {
OPT_BOOL('l', "list", &list, N_("list replace refs")),
OPT_BOOL('d', "delete", &delete, N_("delete replace refs")),
OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")),
+ OPT_STRING(0, "format", &format, N_("format"), N_("use this format")),
OPT_END()
};
+ read_replace_refs = 0;
+
argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
if (list && delete)
usage_msg_opt("-l and -d cannot be used together",
git_replace_usage, options);
+ if (format && delete)
+ usage_msg_opt("--format and -d cannot be used together",
+ git_replace_usage, options);
+
if (force && (list || delete))
usage_msg_opt("-f cannot be used with -d or -l",
git_replace_usage, options);
@@ -157,6 +207,9 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
if (argc != 2)
usage_msg_opt("bad number of arguments",
git_replace_usage, options);
+ if (format)
+ usage_msg_opt("--format cannot be used when not listing",
+ git_replace_usage, options);
return replace_object(argv[0], argv[1], force);
}
@@ -168,5 +221,5 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
usage_msg_opt("-f needs some arguments",
git_replace_usage, options);
- return list_replace_refs(argv[0]);
+ return list_replace_refs(argv[0], format);
}
diff --git a/builtin/reset.c b/builtin/reset.c
index f2f9d55..4fd1c6c 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -116,25 +116,34 @@ static void update_index_from_diff(struct diff_queue_struct *q,
struct diff_options *opt, void *data)
{
int i;
+ int intent_to_add = *(int *)data;
for (i = 0; i < q->nr; i++) {
struct diff_filespec *one = q->queue[i]->one;
- if (one->mode && !is_null_sha1(one->sha1)) {
- struct cache_entry *ce;
- ce = make_cache_entry(one->mode, one->sha1, one->path,
- 0, 0);
- if (!ce)
- die(_("make_cache_entry failed for path '%s'"),
- one->path);
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
- ADD_CACHE_OK_TO_REPLACE);
- } else
+ int is_missing = !(one->mode && !is_null_sha1(one->sha1));
+ struct cache_entry *ce;
+
+ if (is_missing && !intent_to_add) {
remove_file_from_cache(one->path);
+ continue;
+ }
+
+ ce = make_cache_entry(one->mode, one->sha1, one->path,
+ 0, 0);
+ if (!ce)
+ die(_("make_cache_entry failed for path '%s'"),
+ one->path);
+ if (is_missing) {
+ ce->ce_flags |= CE_INTENT_TO_ADD;
+ set_object_name_for_intent_to_add_entry(ce);
+ }
+ add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
}
static int read_from_tree(const struct pathspec *pathspec,
- unsigned char *tree_sha1)
+ unsigned char *tree_sha1,
+ int intent_to_add)
{
struct diff_options opt;
@@ -142,6 +151,7 @@ static int read_from_tree(const struct pathspec *pathspec,
copy_pathspec(&opt.pathspec, pathspec);
opt.output_format = DIFF_FORMAT_CALLBACK;
opt.format_callback = update_index_from_diff;
+ opt.format_callback_data = &intent_to_add;
if (do_diff_cache(tree_sha1, &opt))
return 1;
@@ -258,6 +268,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
const char *rev;
unsigned char sha1[20];
struct pathspec pathspec;
+ int intent_to_add = 0;
const struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_SET_INT(0, "mixed", &reset_type,
@@ -270,6 +281,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
OPT_SET_INT(0, "keep", &reset_type,
N_("reset HEAD but keep local changes"), KEEP),
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
+ OPT_BOOL('N', "intent-to-add", &intent_to_add,
+ N_("record only the fact that removed paths will be added later")),
OPT_END()
};
@@ -304,7 +317,7 @@ 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(rev, "--patch=reset", &pathspec);
}
/* git reset tree [--] paths... can be used to
@@ -327,6 +340,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
die(_("%s reset is not allowed in a bare repository"),
_(reset_type_names[reset_type]));
+ if (intent_to_add && reset_type != MIXED)
+ die(_("-N can only be used with --mixed"));
+
/* Soft reset does not touch the index file nor the working tree
* at all, but requires them in a good order. Other resets reset
* the index file to the tree object we are switching to. */
@@ -338,7 +354,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
int newfd = hold_locked_index(lock, 1);
if (reset_type == MIXED) {
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
- if (read_from_tree(&pathspec, sha1))
+ if (read_from_tree(&pathspec, sha1, intent_to_add))
return 1;
refresh_index(&the_index, flags, NULL, NULL,
_("Unstaged changes after reset:"));
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 5209255..9f92905 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -345,7 +345,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
revs.commit_format = CMIT_FMT_RAW;
if ((!revs.commits &&
- (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
+ (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
!revs.pending.nr)) ||
revs.diff)
usage(rev_list_usage);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index c76b89d..45901df 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -9,6 +9,8 @@
#include "quote.h"
#include "builtin.h"
#include "parse-options.h"
+#include "diff.h"
+#include "revision.h"
#define DO_REVS 1
#define DO_NOREV 2
@@ -30,6 +32,9 @@ static int abbrev_ref;
static int abbrev_ref_strict;
static int output_sq;
+static int stuck_long;
+static struct string_list *ref_excludes;
+
/*
* Some arguments are relevant "revision" arguments,
* others are about output format or other details.
@@ -185,6 +190,8 @@ static int show_default(void)
static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
+ if (ref_excluded(ref_excludes, refname))
+ return 0;
show_rev(NORMAL, sha1, refname);
return 0;
}
@@ -279,6 +286,7 @@ static int try_difference(const char *arg)
exclude = n;
}
}
+ *dotdot = '.';
return 1;
}
*dotdot = '.';
@@ -302,8 +310,10 @@ static int try_parent_shorthands(const char *arg)
return 0;
*dotdot = 0;
- if (get_sha1_committish(arg, sha1))
+ if (get_sha1_committish(arg, sha1)) {
+ *dotdot = '^';
return 0;
+ }
if (!parents_only)
show_rev(NORMAL, sha1, arg);
@@ -312,6 +322,7 @@ static int try_parent_shorthands(const char *arg)
show_rev(parents_only ? NORMAL : REVERSED,
parents->item->object.sha1, arg);
+ *dotdot = '^';
return 1;
}
@@ -320,12 +331,15 @@ static int parseopt_dump(const struct option *o, const char *arg, int unset)
struct strbuf *parsed = o->value;
if (unset)
strbuf_addf(parsed, " --no-%s", o->long_name);
- else if (o->short_name)
+ else if (o->short_name && (o->long_name == NULL || !stuck_long))
strbuf_addf(parsed, " -%c", o->short_name);
else
strbuf_addf(parsed, " --%s", o->long_name);
if (arg) {
- strbuf_addch(parsed, ' ');
+ if (!stuck_long)
+ strbuf_addch(parsed, ' ');
+ else if (o->long_name)
+ strbuf_addch(parsed, '=');
sq_quote_buf(parsed, arg);
}
return 0;
@@ -351,6 +365,8 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
N_("stop parsing after the "
"first non-option argument")),
+ OPT_BOOL(0, "stuck-long", &stuck_long,
+ N_("output in stuck long form")),
OPT_END(),
};
@@ -476,6 +492,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 has_dashdash = 0;
int output_prefix = 0;
unsigned char sha1[20];
const char *name = NULL;
@@ -489,6 +506,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (argc > 1 && !strcmp("-h", argv[1]))
usage(builtin_rev_parse_usage);
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "--")) {
+ has_dashdash = 1;
+ break;
+ }
+ }
+
prefix = setup_git_directory();
git_config(git_default_config, NULL);
for (i = 1; i < argc; i++) {
@@ -508,7 +532,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
continue;
}
- if (!prefixcmp(arg, "-n")) {
+ if (starts_with(arg, "-n")) {
if ((filter & DO_FLAGS) && (filter & DO_REVS))
show(arg);
continue;
@@ -523,15 +547,17 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--default")) {
- def = argv[i+1];
- i++;
+ def = argv[++i];
+ if (!def)
+ die("--default requires an argument");
continue;
}
if (!strcmp(arg, "--prefix")) {
- prefix = argv[i+1];
+ prefix = argv[++i];
+ if (!prefix)
+ die("--prefix requires an argument");
startup_info->prefix = prefix;
output_prefix = 1;
- i++;
continue;
}
if (!strcmp(arg, "--revs-only")) {
@@ -560,7 +586,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--short") ||
- !prefixcmp(arg, "--short=")) {
+ starts_with(arg, "--short=")) {
filter &= ~(DO_FLAGS|DO_NOREV);
verify = 1;
abbrev = DEFAULT_ABBREV;
@@ -588,7 +614,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
symbolic = SHOW_SYMBOLIC_FULL;
continue;
}
- if (!prefixcmp(arg, "--abbrev-ref") &&
+ if (starts_with(arg, "--abbrev-ref") &&
(!arg[12] || arg[12] == '=')) {
abbrev_ref = 1;
abbrev_ref_strict = warn_ambiguous_refs;
@@ -606,7 +632,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
for_each_ref(show_reference, NULL);
continue;
}
- if (!prefixcmp(arg, "--disambiguate=")) {
+ if (starts_with(arg, "--disambiguate=")) {
for_each_abbrev(arg + 15, show_abbrev, NULL);
continue;
}
@@ -615,35 +641,46 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
for_each_ref_in("refs/bisect/good", anti_reference, NULL);
continue;
}
- if (!prefixcmp(arg, "--branches=")) {
+ if (starts_with(arg, "--branches=")) {
for_each_glob_ref_in(show_reference, arg + 11,
"refs/heads/", NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
if (!strcmp(arg, "--branches")) {
for_each_branch_ref(show_reference, NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
- if (!prefixcmp(arg, "--tags=")) {
+ if (starts_with(arg, "--tags=")) {
for_each_glob_ref_in(show_reference, arg + 7,
"refs/tags/", NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
if (!strcmp(arg, "--tags")) {
for_each_tag_ref(show_reference, NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
- if (!prefixcmp(arg, "--glob=")) {
+ if (starts_with(arg, "--glob=")) {
for_each_glob_ref(show_reference, arg + 7, NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
- if (!prefixcmp(arg, "--remotes=")) {
+ if (starts_with(arg, "--remotes=")) {
for_each_glob_ref_in(show_reference, arg + 10,
"refs/remotes/", NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
if (!strcmp(arg, "--remotes")) {
for_each_remote_ref(show_reference, NULL);
+ clear_ref_exclusion(&ref_excludes);
+ continue;
+ }
+ if (starts_with(arg, "--exclude=")) {
+ add_ref_exclusion(&ref_excludes, arg + 10);
continue;
}
if (!strcmp(arg, "--local-env-vars")) {
@@ -703,9 +740,12 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--resolve-git-dir")) {
- const char *gitdir = resolve_gitdir(argv[i+1]);
+ const char *gitdir = argv[++i];
+ if (!gitdir)
+ die("--resolve-git-dir requires an argument");
+ gitdir = resolve_gitdir(gitdir);
if (!gitdir)
- die("not a gitdir '%s'", argv[i+1]);
+ die("not a gitdir '%s'", argv[i]);
puts(gitdir);
continue;
}
@@ -724,19 +764,19 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
: "false");
continue;
}
- if (!prefixcmp(arg, "--since=")) {
+ if (starts_with(arg, "--since=")) {
show_datestring("--max-age=", arg+8);
continue;
}
- if (!prefixcmp(arg, "--after=")) {
+ if (starts_with(arg, "--after=")) {
show_datestring("--max-age=", arg+8);
continue;
}
- if (!prefixcmp(arg, "--before=")) {
+ if (starts_with(arg, "--before=")) {
show_datestring("--min-age=", arg+9);
continue;
}
- if (!prefixcmp(arg, "--until=")) {
+ if (starts_with(arg, "--until=")) {
show_datestring("--min-age=", arg+8);
continue;
}
@@ -765,6 +805,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (verify)
die_no_single_rev(quiet);
+ if (has_dashdash)
+ die("bad revision '%s'", arg);
as_is = 1;
if (!show_file(arg, output_prefix))
continue;
diff --git a/builtin/revert.c b/builtin/revert.c
index 87659c9..065d88d 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -89,6 +89,8 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
N_("option for merge strategy"), option_parse_x),
+ { OPTION_STRING, 'S', "gpg-sign", &opts->gpg_sign, N_("key id"),
+ N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_END(),
OPT_END(),
OPT_END(),
diff --git a/builtin/rm.c b/builtin/rm.c
index 3a0e0ea..960634d 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -308,10 +308,10 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
- if (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), 0, seen))
+ if (!ce_path_match(ce, &pathspec, seen))
continue;
ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
- list.entry[list.nr].name = ce->name;
+ list.entry[list.nr].name = xstrdup(ce->name);
list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
if (list.entry[list.nr++].is_submodule &&
!is_staging_gitmodules_ok())
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 4482f16..f420b74 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -10,6 +10,7 @@
#include "quote.h"
#include "transport.h"
#include "version.h"
+#include "sha1-array.h"
static const char send_pack_usage[] =
"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@ -99,7 +100,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
const char *dest = NULL;
int fd[2];
struct child_process *conn;
- struct extra_have_objects extra_have;
+ struct sha1_array extra_have = SHA1_ARRAY_INIT;
+ struct sha1_array shallow = SHA1_ARRAY_INIT;
struct ref *remote_refs, *local_refs;
int ret;
int helper_status = 0;
@@ -115,15 +117,15 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
const char *arg = *argv;
if (*arg == '-') {
- if (!prefixcmp(arg, "--receive-pack=")) {
+ if (starts_with(arg, "--receive-pack=")) {
receivepack = arg + 15;
continue;
}
- if (!prefixcmp(arg, "--exec=")) {
+ if (starts_with(arg, "--exec=")) {
receivepack = arg + 7;
continue;
}
- if (!prefixcmp(arg, "--remote=")) {
+ if (starts_with(arg, "--remote=")) {
remote_name = arg + 9;
continue;
}
@@ -181,7 +183,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
exit(1);
continue;
}
- if (!prefixcmp(arg, "--" CAS_OPT_NAME "=")) {
+ if (starts_with(arg, "--" CAS_OPT_NAME "=")) {
if (parse_push_cas_option(&cas,
strchr(arg, '=') + 1, 0) < 0)
exit(1);
@@ -228,9 +230,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
args.verbose ? CONNECT_VERBOSE : 0);
}
- memset(&extra_have, 0, sizeof(extra_have));
-
- get_remote_heads(fd[0], NULL, 0, &remote_refs, REF_NORMAL, &extra_have);
+ get_remote_heads(fd[0], NULL, 0, &remote_refs, REF_NORMAL,
+ &extra_have, &shallow);
transport_verify_remote_names(nr_refspecs, refspecs);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index c226f76..4b7e536 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -65,7 +65,7 @@ static void insert_one_record(struct shortlog *log,
eol = strchr(oneline, '\n');
if (!eol)
eol = oneline + strlen(oneline);
- if (!prefixcmp(oneline, "[PATCH")) {
+ if (starts_with(oneline, "[PATCH")) {
char *eob = strchr(oneline, ']');
if (eob && (!eol || eob < eol))
oneline = eob + 1;
@@ -95,7 +95,7 @@ static void read_from_stdin(struct shortlog *log)
while (fgets(author, sizeof(author), stdin) != NULL) {
if (!(author[0] == 'A' || author[0] == 'a') ||
- prefixcmp(author + 1, "uthor: "))
+ !starts_with(author + 1, "uthor: "))
continue;
while (fgets(oneline, sizeof(oneline), stdin) &&
oneline[0] != '\n')
@@ -123,7 +123,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
else
eol++;
- if (!prefixcmp(buffer, "author "))
+ if (starts_with(buffer, "author "))
author = buffer + 7;
buffer = eol;
}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 001f29c..d9217ce 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -227,8 +227,7 @@ static void join_revs(struct commit_list **list_p,
parents = parents->next;
if ((this_flag & flags) == flags)
continue;
- if (!p->object.parsed)
- parse_commit(p);
+ parse_commit(p);
if (mark_seen(p, seen_p) && !still_interesting)
extra--;
p->object.flags |= flags;
@@ -285,7 +284,7 @@ static void show_one_commit(struct commit *commit, int no_name)
pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
pretty_str = pretty.buf;
}
- if (!prefixcmp(pretty_str, "[PATCH] "))
+ if (starts_with(pretty_str, "[PATCH] "))
pretty_str += 8;
if (!no_name) {
@@ -396,7 +395,7 @@ static int append_head_ref(const char *refname, const unsigned char *sha1, int f
{
unsigned char tmp[20];
int ofs = 11;
- if (prefixcmp(refname, "refs/heads/"))
+ if (!starts_with(refname, "refs/heads/"))
return 0;
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
@@ -410,7 +409,7 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
{
unsigned char tmp[20];
int ofs = 13;
- if (prefixcmp(refname, "refs/remotes/"))
+ if (!starts_with(refname, "refs/remotes/"))
return 0;
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
@@ -422,7 +421,7 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
- if (prefixcmp(refname, "refs/tags/"))
+ if (!starts_with(refname, "refs/tags/"))
return 0;
return append_ref(refname + 5, sha1, 0);
}
@@ -453,9 +452,9 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1, i
return 0;
if (fnmatch(match_ref_pattern, tail, 0))
return 0;
- if (!prefixcmp(refname, "refs/heads/"))
+ if (starts_with(refname, "refs/heads/"))
return append_head_ref(refname, sha1, flag, cb_data);
- if (!prefixcmp(refname, "refs/tags/"))
+ if (starts_with(refname, "refs/tags/"))
return append_tag_ref(refname, sha1, flag, cb_data);
return append_ref(refname, sha1, 0);
}
@@ -480,11 +479,11 @@ static int rev_is_head(char *head, int headlen, char *name,
if ((!head[0]) ||
(head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
return 0;
- if (!prefixcmp(head, "refs/heads/"))
+ if (starts_with(head, "refs/heads/"))
head += 11;
- if (!prefixcmp(name, "refs/heads/"))
+ if (starts_with(name, "refs/heads/"))
name += 11;
- else if (!prefixcmp(name, "heads/"))
+ else if (starts_with(name, "heads/"))
name += 6;
return !strcmp(head, name);
}
@@ -813,7 +812,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
has_head++;
}
if (!has_head) {
- int offset = !prefixcmp(head, "refs/heads/") ? 11 : 0;
+ int offset = starts_with(head, "refs/heads/") ? 11 : 0;
append_one_rev(head + offset);
}
}
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 9f3f5e3..5ba1f30 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -37,8 +37,8 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
if (tags_only || heads_only) {
int match;
- match = heads_only && !prefixcmp(refname, "refs/heads/");
- match |= tags_only && !prefixcmp(refname, "refs/tags/");
+ match = heads_only && starts_with(refname, "refs/heads/");
+ match |= tags_only && starts_with(refname, "refs/tags/");
if (!match)
return 0;
}
@@ -210,7 +210,7 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
while (*pattern) {
unsigned char sha1[20];
- if (!prefixcmp(*pattern, "refs/") &&
+ if (starts_with(*pattern, "refs/") &&
!read_ref(*pattern, sha1)) {
if (!quiet)
show_one(*pattern, sha1);
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index f481959..b6a711d 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -47,7 +47,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options,
git_symbolic_ref_usage, 0);
- if (msg &&!*msg)
+ if (msg && !*msg)
die("Refusing to perform update with empty message");
if (delete) {
@@ -65,7 +65,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
break;
case 2:
if (!strcmp(argv[0], "HEAD") &&
- prefixcmp(argv[1], "refs/"))
+ !starts_with(argv[1], "refs/"))
die("Refusing to point HEAD outside of refs/");
create_symref(argv[0], argv[1], msg);
break;
diff --git a/builtin/tag.c b/builtin/tag.c
index ea55f1d..74d3780 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -259,7 +259,7 @@ static int git_tag_config(const char *var, const char *value, void *cb)
int status = git_gpg_config(var, value, cb);
if (status)
return status;
- if (!prefixcmp(var, "column."))
+ if (starts_with(var, "column."))
return git_column_config(var, value, "tag", &colopts);
return git_default_config(var, value, cb);
}
diff --git a/builtin/tar-tree.c b/builtin/tar-tree.c
deleted file mode 100644
index ba3ffe6..0000000
--- a/builtin/tar-tree.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2005, 2006 Rene Scharfe
- */
-#include "cache.h"
-#include "commit.h"
-#include "tar.h"
-#include "builtin.h"
-#include "quote.h"
-
-static const char tar_tree_usage[] =
-"git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n"
-"*** Note that this command is now deprecated; use \"git archive\" instead.";
-
-static const char builtin_get_tar_commit_id_usage[] =
-"git get-tar-commit-id < <tarfile>";
-
-int cmd_tar_tree(int argc, const char **argv, const char *prefix)
-{
- /*
- * "git tar-tree" is now a wrapper around "git archive --format=tar"
- *
- * $0 --remote=<repo> arg... ==>
- * git archive --format=tar --remote=<repo> arg...
- * $0 tree-ish ==>
- * git archive --format=tar tree-ish
- * $0 tree-ish basedir ==>
- * git archive --format-tar --prefix=basedir tree-ish
- */
- const char **nargv = xcalloc(sizeof(*nargv), argc + 3);
- struct strbuf sb = STRBUF_INIT;
- char *basedir_arg;
- int nargc = 0;
-
- nargv[nargc++] = "archive";
- nargv[nargc++] = "--format=tar";
-
- if (2 <= argc && !prefixcmp(argv[1], "--remote=")) {
- nargv[nargc++] = argv[1];
- argv++;
- argc--;
- }
-
- /*
- * Because it's just a compatibility wrapper, tar-tree supports only
- * the old behaviour of reading attributes from the work tree.
- */
- nargv[nargc++] = "--worktree-attributes";
-
- switch (argc) {
- default:
- usage(tar_tree_usage);
- break;
- case 3:
- /* base-path */
- basedir_arg = xmalloc(strlen(argv[2]) + 11);
- sprintf(basedir_arg, "--prefix=%s/", argv[2]);
- nargv[nargc++] = basedir_arg;
- /* fallthru */
- case 2:
- /* tree-ish */
- nargv[nargc++] = argv[1];
- }
- nargv[nargc] = NULL;
-
- fprintf(stderr,
- "*** \"git tar-tree\" is now deprecated.\n"
- "*** Running \"git archive\" instead.\n***");
- sq_quote_argv(&sb, nargv, 0);
- strbuf_addch(&sb, '\n');
- fputs(sb.buf, stderr);
- strbuf_release(&sb);
- return cmd_archive(nargc, nargv, prefix);
-}
-
-/* ustar header + extended global header content */
-#define RECORDSIZE (512)
-#define HEADERSIZE (2 * RECORDSIZE)
-
-int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
-{
- char buffer[HEADERSIZE];
- struct ustar_header *header = (struct ustar_header *)buffer;
- char *content = buffer + RECORDSIZE;
- ssize_t n;
-
- if (argc != 1)
- usage(builtin_get_tar_commit_id_usage);
-
- n = read_in_full(0, buffer, HEADERSIZE);
- if (n < HEADERSIZE)
- die("git get-tar-commit-id: read error");
- if (header->typeflag[0] != 'g')
- return 1;
- if (memcmp(content, "52 comment=", 11))
- return 1;
-
- n = write_in_full(1, content + 11, 41);
- if (n < 41)
- die_errno("git get-tar-commit-id: write error");
-
- return 0;
-}
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 2217d7b..62ff673 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -523,7 +523,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
strict = 1;
continue;
}
- if (!prefixcmp(arg, "--pack_header=")) {
+ if (starts_with(arg, "--pack_header=")) {
struct pack_header *hdr;
char *c;
diff --git a/builtin/update-index.c b/builtin/update-index.c
index e3a10d7..d12ad95 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -12,6 +12,7 @@
#include "resolve-undo.h"
#include "parse-options.h"
#include "pathspec.h"
+#include "dir.h"
/*
* Default to not allowing changes to the list of files. The
@@ -274,36 +275,32 @@ static void chmod_path(int flip, const char *path)
die("git update-index: cannot chmod %cx '%s'", flip, path);
}
-static void update_one(const char *path, const char *prefix, int prefix_length)
+static void update_one(const char *path)
{
- const char *p = prefix_path(prefix, prefix_length, path);
- if (!verify_path(p)) {
+ if (!verify_path(path)) {
fprintf(stderr, "Ignoring path %s\n", path);
- goto free_return;
+ return;
}
if (mark_valid_only) {
- if (mark_ce_flags(p, CE_VALID, mark_valid_only == MARK_FLAG))
+ if (mark_ce_flags(path, CE_VALID, mark_valid_only == MARK_FLAG))
die("Unable to mark file %s", path);
- goto free_return;
+ return;
}
if (mark_skip_worktree_only) {
- if (mark_ce_flags(p, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG))
+ if (mark_ce_flags(path, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG))
die("Unable to mark file %s", path);
- goto free_return;
+ return;
}
if (force_remove) {
- if (remove_file_from_cache(p))
+ if (remove_file_from_cache(path))
die("git update-index: unable to remove %s", path);
report("remove '%s'", path);
- goto free_return;
+ return;
}
- if (process_path(p))
+ if (process_path(path))
die("Unable to process path %s", path);
report("add '%s'", path);
- free_return:
- if (p < path || p > path + strlen(path))
- free((char *)p);
}
static void read_index_info(int line_termination)
@@ -563,8 +560,9 @@ static int do_reupdate(int ac, const char **av,
const struct cache_entry *ce = active_cache[pos];
struct cache_entry *old = NULL;
int save_nr;
+ char *path;
- if (ce_stage(ce) || !ce_path_match(ce, &pathspec))
+ if (ce_stage(ce) || !ce_path_match(ce, &pathspec, NULL))
continue;
if (has_head)
old = read_one_ent(NULL, head_sha1,
@@ -579,7 +577,9 @@ static int do_reupdate(int ac, const char **av,
* or worse yet 'allow_replace', active_nr may decrease.
*/
save_nr = active_nr;
- update_one(ce->name + prefix_length, prefix, prefix_length);
+ path = xstrdup(ce->name);
+ update_one(path);
+ free(path);
if (save_nr != active_nr)
goto redo;
}
@@ -836,11 +836,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
setup_work_tree();
p = prefix_path(prefix, prefix_length, path);
- update_one(p, NULL, 0);
+ update_one(p);
if (set_executable_bit)
chmod_path(set_executable_bit, p);
- if (p < path || p > path + strlen(path))
- free((char *)p);
+ free((char *)p);
ctx.argc--;
ctx.argv++;
break;
@@ -879,11 +878,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
strbuf_swap(&buf, &nbuf);
}
p = prefix_path(prefix, prefix_length, buf.buf);
- update_one(p, NULL, 0);
+ update_one(p);
if (set_executable_bit)
chmod_path(set_executable_bit, p);
- if (p < buf.buf || p > buf.buf + buf.len)
- free((char *)p);
+ free((char *)p);
}
strbuf_release(&nbuf);
strbuf_release(&buf);
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 702e90d..1292cfe 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -229,15 +229,15 @@ static void update_refs_stdin(void)
die("empty command in input");
else if (isspace(*cmd.buf))
die("whitespace before command: %s", cmd.buf);
- else if (!prefixcmp(cmd.buf, "update "))
+ else if (starts_with(cmd.buf, "update "))
parse_cmd_update(cmd.buf + 7);
- else if (!prefixcmp(cmd.buf, "create "))
+ else if (starts_with(cmd.buf, "create "))
parse_cmd_create(cmd.buf + 7);
- else if (!prefixcmp(cmd.buf, "delete "))
+ else if (starts_with(cmd.buf, "delete "))
parse_cmd_delete(cmd.buf + 7);
- else if (!prefixcmp(cmd.buf, "verify "))
+ else if (starts_with(cmd.buf, "verify "))
parse_cmd_verify(cmd.buf + 7);
- else if (!prefixcmp(cmd.buf, "option "))
+ else if (starts_with(cmd.buf, "option "))
parse_cmd_option(cmd.buf + 7);
else
die("unknown command: %s", cmd.buf);
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index af2da35..32ab94c 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -37,7 +37,7 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
if (sent_argv.argc > MAX_ARGS)
die("Too many options (>%d)", MAX_ARGS - 1);
- if (prefixcmp(buf, arg_cmd))
+ if (!starts_with(buf, arg_cmd))
die("'argument' token or flush expected");
argv_array_push(&sent_argv, buf + strlen(arg_cmd));
}
diff --git a/bundle.c b/bundle.c
index 3d64311..e99065c 100644
--- a/bundle.c
+++ b/bundle.c
@@ -7,6 +7,7 @@
#include "list-objects.h"
#include "run-command.h"
#include "refs.h"
+#include "argv-array.h"
static const char bundle_signature[] = "# v2 git bundle\n";
@@ -234,13 +235,13 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)
}
int create_bundle(struct bundle_header *header, const char *path,
- int argc, const char **argv)
+ int argc, const char **argv)
{
static struct lock_file lock;
int bundle_fd = -1;
int bundle_to_stdout;
- const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
- const char **argv_pack = xmalloc(6 * sizeof(const char *));
+ struct argv_array argv_boundary = ARGV_ARRAY_INIT;
+ struct argv_array argv_pack = ARGV_ARRAY_INIT;
int i, ref_count = 0;
struct strbuf buf = STRBUF_INIT;
struct rev_info revs;
@@ -262,13 +263,14 @@ int create_bundle(struct bundle_header *header, const char *path,
init_revisions(&revs, NULL);
/* write prerequisites */
- memcpy(argv_boundary + 3, argv + 1, argc * sizeof(const char *));
- argv_boundary[0] = "rev-list";
- argv_boundary[1] = "--boundary";
- argv_boundary[2] = "--pretty=oneline";
- argv_boundary[argc + 2] = NULL;
+ argv_array_pushl(&argv_boundary,
+ "rev-list", "--boundary", "--pretty=oneline",
+ NULL);
+ for (i = 1; i < argc; i++)
+ argv_array_push(&argv_boundary, argv[i]);
+
memset(&rls, 0, sizeof(rls));
- rls.argv = argv_boundary;
+ rls.argv = argv_boundary.argv;
rls.out = -1;
rls.git_cmd = 1;
if (start_command(&rls))
@@ -383,14 +385,12 @@ int create_bundle(struct bundle_header *header, const char *path,
write_or_die(bundle_fd, "\n", 1);
/* write pack */
- argv_pack[0] = "pack-objects";
- argv_pack[1] = "--all-progress-implied";
- argv_pack[2] = "--stdout";
- argv_pack[3] = "--thin";
- argv_pack[4] = "--delta-base-offset";
- argv_pack[5] = NULL;
+ argv_array_pushl(&argv_pack,
+ "pack-objects", "--all-progress-implied",
+ "--stdout", "--thin", "--delta-base-offset",
+ NULL);
memset(&rls, 0, sizeof(rls));
- rls.argv = argv_pack;
+ rls.argv = argv_pack.argv;
rls.in = -1;
rls.out = bundle_fd;
rls.git_cmd = 1;
diff --git a/cache.h b/cache.h
index f2e5aa7..db223e8 100644
--- a/cache.h
+++ b/cache.h
@@ -3,7 +3,7 @@
#include "git-compat-util.h"
#include "strbuf.h"
-#include "hash.h"
+#include "hashmap.h"
#include "advice.h"
#include "gettext.h"
#include "convert.h"
@@ -130,12 +130,12 @@ struct stat_data {
};
struct cache_entry {
+ struct hashmap_entry ent;
struct stat_data ce_stat_data;
unsigned int ce_mode;
unsigned int ce_flags;
unsigned int ce_namelen;
unsigned char sha1[20];
- struct cache_entry *next;
char name[FLEX_ARRAY]; /* more */
};
@@ -159,7 +159,6 @@ struct cache_entry {
#define CE_ADDED (1 << 19)
#define CE_HASHED (1 << 20)
-#define CE_UNHASHED (1 << 21)
#define CE_WT_REMOVE (1 << 22) /* remove in work directory */
#define CE_CONFLICTED (1 << 23)
@@ -195,17 +194,18 @@ 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,
const struct cache_entry *src)
{
- unsigned int state = dst->ce_flags & CE_STATE_MASK;
+ unsigned int state = dst->ce_flags & CE_HASHED;
/* Don't copy hash chain and name */
- memcpy(dst, src, offsetof(struct cache_entry, next));
+ memcpy(&dst->ce_stat_data, &src->ce_stat_data,
+ offsetof(struct cache_entry, name) -
+ offsetof(struct cache_entry, ce_stat_data));
/* Restore the hash state */
- dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
+ dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
}
static inline unsigned create_ce_flags(unsigned stage)
@@ -277,8 +277,8 @@ struct index_state {
struct cache_time timestamp;
unsigned name_hash_initialized : 1,
initialized : 1;
- struct hash_table name_hash;
- struct hash_table dir_hash;
+ struct hashmap name_hash;
+ struct hashmap dir_hash;
};
extern struct index_state the_index;
@@ -316,7 +316,6 @@ extern void free_name_hash(struct index_state *istate);
#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
#define cache_dir_exists(name, namelen) index_dir_exists(&the_index, (name), (namelen))
#define cache_file_exists(name, namelen, igncase) index_file_exists(&the_index, (name), (namelen), (igncase))
-#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
#define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
@@ -354,6 +353,7 @@ static inline enum object_type object_type(unsigned int mode)
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
+#define GIT_SHALLOW_FILE_ENVIRONMENT "GIT_SHALLOW_FILE"
#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
#define CONFIG_ENVIRONMENT "GIT_CONFIG"
#define CONFIG_DATA_ENVIRONMENT "GIT_CONFIG_PARAMETERS"
@@ -398,7 +398,6 @@ extern int is_bare_repository(void);
extern int is_inside_git_dir(void);
extern char *git_work_tree_cfg;
extern int is_inside_work_tree(void);
-extern int have_git_dir(void);
extern const char *get_git_dir(void);
extern int is_git_directory(const char *path);
extern char *get_object_directory(void);
@@ -467,7 +466,6 @@ extern int unmerged_index(const struct index_state *);
extern int verify_path(const char *path);
extern struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen);
extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
-extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);
extern int index_name_pos(const struct index_state *, const char *name, int namelen);
#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
@@ -487,8 +485,9 @@ extern int remove_file_from_index(struct index_state *, const char *path);
#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 struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
+extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
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 *);
@@ -498,11 +497,13 @@ extern void *read_blob_data_from_index(struct index_state *, const char *, unsig
#define CE_MATCH_RACY_IS_DIRTY 02
/* do stat comparison even if CE_SKIP_WORKTREE is true */
#define CE_MATCH_IGNORE_SKIP_WORKTREE 04
+/* ignore non-existent files during stat update */
+#define CE_MATCH_IGNORE_MISSING 0x08
+/* enable stat refresh */
+#define CE_MATCH_REFRESH 0x10
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 ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
-
#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);
@@ -737,8 +738,29 @@ enum sharedrepo {
};
int git_config_perm(const char *var, const char *value);
int adjust_shared_perm(const char *path);
-int safe_create_leading_directories(char *path);
-int safe_create_leading_directories_const(const char *path);
+
+/*
+ * Create the directory containing the named path, using care to be
+ * somewhat safe against races. Return one of the scld_error values
+ * to indicate success/failure.
+ *
+ * SCLD_VANISHED indicates that one of the ancestor directories of the
+ * path existed at one point during the function call and then
+ * suddenly vanished, probably because another process pruned the
+ * directory while we were working. To be robust against this kind of
+ * race, callers might want to try invoking the function again when it
+ * returns SCLD_VANISHED.
+ */
+enum scld_error {
+ SCLD_OK = 0,
+ SCLD_FAILED = -1,
+ SCLD_PERMS = -2,
+ SCLD_EXISTS = -3,
+ SCLD_VANISHED = -4
+};
+enum scld_error safe_create_leading_directories(char *path);
+enum scld_error safe_create_leading_directories_const(const char *path);
+
int mkdir_in_gitdir(const char *path);
extern void home_config_paths(char **global, char **xdg, char *file);
extern char *expand_user_path(const char *path);
@@ -751,6 +773,7 @@ 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 *remove_leading_path(const char *in, const char *prefix);
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);
@@ -760,11 +783,11 @@ int daemon_avoid_alias(const char *path);
int offset_1st_component(const char *path);
/* object replacement */
-#define READ_SHA1_FILE_REPLACE 1
+#define LOOKUP_REPLACE_OBJECT 1
extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
{
- return read_sha1_file_extended(sha1, type, size, READ_SHA1_FILE_REPLACE);
+ return read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);
}
extern const unsigned char *do_lookup_replace_object(const unsigned char *sha1);
static inline const unsigned char *lookup_replace_object(const unsigned char *sha1)
@@ -773,6 +796,12 @@ static inline const unsigned char *lookup_replace_object(const unsigned char *sh
return sha1;
return do_lookup_replace_object(sha1);
}
+static inline const unsigned char *lookup_replace_object_extended(const unsigned char *sha1, unsigned flag)
+{
+ if (!(flag & LOOKUP_REPLACE_OBJECT))
+ return sha1;
+ return lookup_replace_object(sha1);
+}
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
extern int sha1_object_info(const unsigned char *, unsigned long *);
@@ -888,9 +917,12 @@ extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
extern int interpret_branch_name(const char *str, int len, struct strbuf *);
extern int get_sha1_mb(const char *str, unsigned char *sha1);
-extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
-extern const char *ref_rev_parse_rules[];
-#define ref_fetch_rules ref_rev_parse_rules
+/*
+ * Return true iff abbrev_name is a possible abbreviation for
+ * full_name according to the rules defined by ref_rev_parse_rules in
+ * refs.c.
+ */
+extern int refname_match(const char *abbrev_name, const char *full_name);
extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
extern int validate_headref(const char *ref);
@@ -976,6 +1008,7 @@ struct checkout {
refresh_cache:1;
};
+#define TEMPORARY_FILENAME_LENGTH 25
extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
struct cache_def {
@@ -1074,6 +1107,7 @@ struct object_info {
enum object_type *typep;
unsigned long *sizep;
unsigned long *disk_sizep;
+ unsigned char *delta_base_sha1;
/* Response */
enum {
@@ -1098,7 +1132,7 @@ struct object_info {
} packed;
} u;
};
-extern int sha1_object_info_extended(const unsigned char *, struct object_info *);
+extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
/* Dumb servers support */
extern int update_server_info(int);
@@ -1236,6 +1270,8 @@ __attribute__((format (printf, 2, 3)))
extern void trace_argv_printf(const char **argv, const char *format, ...);
extern void trace_repo_setup(const char *prefix);
extern int trace_want(const char *key);
+__attribute__((format (printf, 2, 3)))
+extern void trace_printf_key(const char *key, const char *fmt, ...);
extern void trace_strbuf(const char *key, const struct strbuf *buf);
void packet_trace_identity(const char *prog);
diff --git a/command-list.txt b/command-list.txt
index 08b04e2..cf36c3d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -64,7 +64,6 @@ git-init mainporcelain common
git-instaweb ancillaryinterrogators
gitk mainporcelain
git-log mainporcelain common
-git-lost-found ancillarymanipulators deprecated
git-ls-files plumbinginterrogators
git-ls-remote plumbinginterrogators
git-ls-tree plumbinginterrogators
@@ -88,7 +87,6 @@ git-pack-redundant plumbinginterrogators
git-pack-refs ancillarymanipulators
git-parse-remote synchelpers
git-patch-id purehelpers
-git-peek-remote purehelpers deprecated
git-prune ancillarymanipulators
git-prune-packed plumbingmanipulators
git-pull mainporcelain common
@@ -102,7 +100,6 @@ git-relink ancillarymanipulators
git-remote ancillarymanipulators
git-repack ancillarymanipulators
git-replace ancillarymanipulators
-git-repo-config ancillarymanipulators deprecated
git-request-pull foreignscminterface
git-rerere ancillaryinterrogators
git-reset mainporcelain common
@@ -127,7 +124,6 @@ git-submodule mainporcelain
git-svn foreignscminterface
git-symbolic-ref plumbingmanipulators
git-tag mainporcelain common
-git-tar-tree plumbinginterrogators deprecated
git-unpack-file plumbinginterrogators
git-unpack-objects plumbingmanipulators
git-update-index plumbingmanipulators
diff --git a/commit-slab.h b/commit-slab.h
index d4c8286..cc114b5 100644
--- a/commit-slab.h
+++ b/commit-slab.h
@@ -22,8 +22,17 @@
*
* 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
+ * that is initialized by the variant without "_with_stride" associates
* each commit with an array of one integer.
+ *
+ * - void clear_indegree(struct indegree *);
+ *
+ * Empties the slab. The slab can be reused with the same stride
+ * without calling init_indegree() again or can be reconfigured to a
+ * different stride by calling init_indegree_with_stride().
+ *
+ * Call this function before the slab falls out of scope to avoid
+ * leaking memory.
*/
/* allocate ~512kB at once, allowing for malloc overhead */
@@ -31,6 +40,8 @@
#define COMMIT_SLAB_SIZE (512*1024-32)
#endif
+#define MAYBE_UNUSED __attribute__((__unused__))
+
#define define_commit_slab(slabname, elemtype) \
\
struct slabname { \
@@ -41,8 +52,8 @@ struct slabname { \
}; \
static int stat_ ##slabname## realloc; \
\
-static void init_ ##slabname## _with_stride(struct slabname *s, \
- unsigned stride) \
+static MAYBE_UNUSED void init_ ##slabname## _with_stride(struct slabname *s, \
+ unsigned stride) \
{ \
unsigned int elem_size; \
if (!stride) \
@@ -54,12 +65,12 @@ static void init_ ##slabname## _with_stride(struct slabname *s, \
s->slab = NULL; \
} \
\
-static void init_ ##slabname(struct slabname *s) \
+static MAYBE_UNUSED void init_ ##slabname(struct slabname *s) \
{ \
init_ ##slabname## _with_stride(s, 1); \
} \
\
-static void clear_ ##slabname(struct slabname *s) \
+static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s) \
{ \
int i; \
for (i = 0; i < s->slab_count; i++) \
@@ -69,8 +80,8 @@ static void clear_ ##slabname(struct slabname *s) \
s->slab = NULL; \
} \
\
-static elemtype *slabname## _at(struct slabname *s, \
- const struct commit *c) \
+static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \
+ const struct commit *c) \
{ \
int nth_slab, nth_slot; \
\
@@ -80,7 +91,7 @@ static elemtype *slabname## _at(struct slabname *s, \
if (s->slab_count <= nth_slab) { \
int i; \
s->slab = xrealloc(s->slab, \
- (nth_slab + 1) * sizeof(s->slab)); \
+ (nth_slab + 1) * sizeof(*s->slab)); \
stat_ ##slabname## realloc++; \
for (i = s->slab_count; i <= nth_slab; i++) \
s->slab[i] = NULL; \
@@ -94,4 +105,16 @@ static elemtype *slabname## _at(struct slabname *s, \
\
static int stat_ ##slabname## realloc
+/*
+ * Note that this seemingly redundant second declaration is required
+ * to allow a terminating semicolon, which makes instantiations look
+ * like function declarations. I.e., the expansion of
+ *
+ * define_commit_slab(indegree, int);
+ *
+ * ends in 'static int stat_indegreerealloc;'. This would otherwise
+ * be a syntax error according (at least) to ISO C. It's hard to
+ * catch because GCC silently parses it by default.
+ */
+
#endif /* COMMIT_SLAB_H */
diff --git a/commit.c b/commit.c
index de16a3c..6bf4fe0 100644
--- a/commit.c
+++ b/commit.c
@@ -79,7 +79,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
if (get_sha1_committish(name, sha1))
return NULL;
commit = lookup_commit_reference(sha1);
- if (!commit || parse_commit(commit))
+ if (parse_commit(commit))
return NULL;
return commit;
}
@@ -196,19 +196,19 @@ bad_graft_data:
static int read_graft_file(const char *graft_file)
{
FILE *fp = fopen(graft_file, "r");
- char buf[1024];
+ struct strbuf buf = STRBUF_INIT;
if (!fp)
return -1;
- while (fgets(buf, sizeof(buf), fp)) {
+ while (!strbuf_getwholeline(&buf, fp, '\n')) {
/* The format is just "Commit Parent1 Parent2 ...\n" */
- int len = strlen(buf);
- struct commit_graft *graft = read_graft_line(buf, len);
+ struct commit_graft *graft = read_graft_line(buf.buf, buf.len);
if (!graft)
continue;
if (register_commit_graft(graft, 1))
- error("duplicate graft data: %s", buf);
+ error("duplicate graft data: %s", buf.buf);
}
fclose(fp);
+ strbuf_release(&buf);
return 0;
}
@@ -341,6 +341,13 @@ int parse_commit(struct commit *item)
return ret;
}
+void parse_commit_or_die(struct commit *item)
+{
+ if (parse_commit(item))
+ die("unable to parse commit %s",
+ item ? sha1_to_hex(item->object.sha1) : "(null)");
+}
+
int find_commit_subject(const char *commit_buffer, const char **subject)
{
const char *eol;
@@ -559,7 +566,7 @@ static void record_author_date(struct author_date_slab *author_date,
buf;
buf = line_end + 1) {
line_end = strchrnul(buf, '\n');
- if (prefixcmp(buf, "author ")) {
+ if (!starts_with(buf, "author ")) {
if (!line_end[0] || line_end[1] == '\n')
return; /* end of header */
continue;
@@ -834,26 +841,26 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
struct commit_list *get_octopus_merge_bases(struct commit_list *in)
{
struct commit_list *i, *j, *k, *ret = NULL;
- struct commit_list **pptr = &ret;
- for (i = in; i; i = i->next) {
- if (!ret)
- pptr = &commit_list_insert(i->item, pptr)->next;
- else {
- struct commit_list *new = NULL, *end = NULL;
-
- for (j = ret; j; j = j->next) {
- struct commit_list *bases;
- bases = get_merge_bases(i->item, j->item, 1);
- if (!new)
- new = bases;
- else
- end->next = bases;
- for (k = bases; k; k = k->next)
- end = k;
- }
- ret = new;
+ if (!in)
+ return ret;
+
+ commit_list_insert(in->item, &ret);
+
+ for (i = in->next; i; i = i->next) {
+ struct commit_list *new = NULL, *end = NULL;
+
+ for (j = ret; j; j = j->next) {
+ struct commit_list *bases;
+ bases = get_merge_bases(i->item, j->item, 1);
+ if (!new)
+ new = bases;
+ else
+ end->next = bases;
+ for (k = bases; k; k = k->next)
+ end = k;
}
+ ret = new;
}
return ret;
}
@@ -1106,7 +1113,7 @@ int parse_signed_commit(const unsigned char *sha1,
next = next ? next + 1 : tail;
if (in_signature && line[0] == ' ')
sig = line + 1;
- else if (!prefixcmp(line, gpg_sig_header) &&
+ else if (starts_with(line, gpg_sig_header) &&
line[gpg_sig_header_len] == ' ')
sig = line + gpg_sig_header_len + 1;
if (sig) {
@@ -1186,7 +1193,7 @@ static void parse_gpg_output(struct signature_check *sigc)
for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
const char *found, *next;
- if (!prefixcmp(buf, sigcheck_gpg_status[i].check + 1)) {
+ if (starts_with(buf, sigcheck_gpg_status[i].check + 1)) {
/* At the very beginning of the buffer */
found = buf + strlen(sigcheck_gpg_status[i].check + 1);
} else {
@@ -1349,7 +1356,7 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
}
}
-int commit_tree(const struct strbuf *msg, unsigned char *tree,
+int commit_tree(const struct strbuf *msg, const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit)
{
@@ -1478,7 +1485,7 @@ static const char commit_utf8_warn[] =
"You may want to amend it after fixing the message, or set the config\n"
"variable i18n.commitencoding to the encoding your project uses.\n";
-int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
+int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit,
struct commit_extra_header *extra)
diff --git a/commit.h b/commit.h
index bd841f4..16d9c43 100644
--- a/commit.h
+++ b/commit.h
@@ -49,6 +49,7 @@ struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_n
int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size);
int parse_commit(struct commit *item);
+void parse_commit_or_die(struct commit *item);
/* Find beginning and length of commit subject. */
int find_commit_subject(const char *commit_buffer, const char **subject);
@@ -193,6 +194,8 @@ extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
/* largest positive number a signed 32-bit integer can contain */
#define INFINITE_DEPTH 0x7fffffff
+struct sha1_array;
+struct ref;
extern int register_shallow(const unsigned char *sha1);
extern int unregister_shallow(const unsigned char *sha1);
extern int for_each_commit_graft(each_commit_graft_fn, void *);
@@ -200,11 +203,38 @@ 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);
-extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol);
+extern void set_alternate_shallow_file(const char *path, int override);
+extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
+ const struct sha1_array *extra);
extern void setup_alternate_shallow(struct lock_file *shallow_lock,
- const char **alternate_shallow_file);
-extern char *setup_temporary_shallow(void);
+ const char **alternate_shallow_file,
+ const struct sha1_array *extra);
+extern char *setup_temporary_shallow(const struct sha1_array *extra);
+extern void advertise_shallow_grafts(int);
+
+struct shallow_info {
+ struct sha1_array *shallow;
+ int *ours, nr_ours;
+ int *theirs, nr_theirs;
+ struct sha1_array *ref;
+
+ /* for receive-pack */
+ uint32_t **used_shallow;
+ int *need_reachability_test;
+ int *reachable;
+ int *shallow_ref;
+ struct commit **commits;
+ int nr_commits;
+};
+
+extern void prepare_shallow_info(struct shallow_info *, struct sha1_array *);
+extern void clear_shallow_info(struct shallow_info *);
+extern void remove_nonexistent_theirs_shallow(struct shallow_info *);
+extern void assign_shallow_commits_to_refs(struct shallow_info *info,
+ uint32_t **used,
+ int *ref_status);
+extern int delayed_reachability_test(struct shallow_info *si, int c);
+extern void prune_shallow(int show_only);
int is_descendant_of(struct commit *, struct commit_list *);
int in_merge_bases(struct commit *, struct commit *);
@@ -231,11 +261,11 @@ struct commit_extra_header {
extern void append_merge_tag_headers(struct commit_list *parents,
struct commit_extra_header ***tail);
-extern int commit_tree(const struct strbuf *msg, unsigned char *tree,
+extern int commit_tree(const struct strbuf *msg, const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit);
-extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
+extern int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit,
struct commit_extra_header *);
diff --git a/compat/mingw.c b/compat/mingw.c
index fecb98b..e9892f8 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -304,23 +304,6 @@ int mingw_open (const char *filename, int oflags, ...)
return fd;
}
-#undef write
-ssize_t mingw_write(int fd, const void *buf, size_t count)
-{
- /*
- * While write() calls to a file on a local disk are translated
- * into WriteFile() calls with a maximum size of 64KB on Windows
- * XP and 256KB on Vista, no such cap is placed on writes to
- * files over the network on Windows XP. Unfortunately, there
- * seems to be a limit of 32MB-28KB on X64 and 64MB-32KB on x86;
- * bigger writes fail on Windows XP.
- * So we cap to a nice 31MB here to avoid write failures over
- * the net without changing the number of WriteFile() calls in
- * the local case.
- */
- return write(fd, buf, min(count, 31 * 1024 * 1024));
-}
-
static BOOL WINAPI ctrl_ignore(DWORD type)
{
return TRUE;
diff --git a/compat/mingw.h b/compat/mingw.h
index 92cd728..e033e72 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -180,9 +180,6 @@ int mingw_rmdir(const char *path);
int mingw_open (const char *filename, int oflags, ...);
#define open mingw_open
-ssize_t mingw_write(int fd, const void *buf, size_t count);
-#define write mingw_write
-
int mingw_fgetc(FILE *stream);
#define fgetc mingw_fgetc
diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c
index b2c5d46..06f3088 100644
--- a/compat/regex/regcomp.c
+++ b/compat/regex/regcomp.c
@@ -339,7 +339,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
p = buf;
*p++ = dfa->nodes[node].opr.c;
while (++node < dfa->nodes_len
- && dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].type == CHARACTER
&& dfa->nodes[node].mb_partial)
*p++ = dfa->nodes[node].opr.c;
memset (&state, '\0', sizeof (state));
diff --git a/compat/vcbuild/scripts/clink.pl b/compat/vcbuild/scripts/clink.pl
index 4374771..4374771 100644..100755
--- a/compat/vcbuild/scripts/clink.pl
+++ b/compat/vcbuild/scripts/clink.pl
diff --git a/compat/vcbuild/scripts/lib.pl b/compat/vcbuild/scripts/lib.pl
index d8054e4..d8054e4 100644..100755
--- a/compat/vcbuild/scripts/lib.pl
+++ b/compat/vcbuild/scripts/lib.pl
diff --git a/config.c b/config.c
index e1d66a1..314d8ee 100644
--- a/config.c
+++ b/config.c
@@ -84,8 +84,12 @@ static int handle_path_include(const char *path, struct config_include_data *inc
{
int ret = 0;
struct strbuf buf = STRBUF_INIT;
- char *expanded = expand_user_path(path);
+ char *expanded;
+ if (!path)
+ return config_error_nonbool("include.path");
+
+ expanded = expand_user_path(path);
if (!expanded)
return error("Could not expand include path '%s'", path);
path = expanded;
@@ -969,25 +973,25 @@ static int git_default_mailmap_config(const char *var, const char *value)
int git_default_config(const char *var, const char *value, void *dummy)
{
- if (!prefixcmp(var, "core."))
+ if (starts_with(var, "core."))
return git_default_core_config(var, value);
- if (!prefixcmp(var, "user."))
+ if (starts_with(var, "user."))
return git_ident_config(var, value, dummy);
- if (!prefixcmp(var, "i18n."))
+ if (starts_with(var, "i18n."))
return git_default_i18n_config(var, value);
- if (!prefixcmp(var, "branch."))
+ if (starts_with(var, "branch."))
return git_default_branch_config(var, value);
- if (!prefixcmp(var, "push."))
+ if (starts_with(var, "push."))
return git_default_push_config(var, value);
- if (!prefixcmp(var, "mailmap."))
+ if (starts_with(var, "mailmap."))
return git_default_mailmap_config(var, value);
- if (!prefixcmp(var, "advice."))
+ if (starts_with(var, "advice."))
return git_default_advice_config(var, value);
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
@@ -1210,15 +1214,14 @@ int git_config(config_fn_t fn, void *data)
* Find all the stuff for git_config_set() below.
*/
-#define MAX_MATCHES 512
-
static struct {
int baselen;
char *key;
int do_not_match;
regex_t *value_regex;
int multi_replace;
- size_t offset[MAX_MATCHES];
+ size_t *offset;
+ unsigned int offset_alloc;
enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
int seen;
} store;
@@ -1241,11 +1244,11 @@ static int store_aux(const char *key, const char *value, void *cb)
if (matches(key, value)) {
if (store.seen == 1 && store.multi_replace == 0) {
warning("%s has multiple values", key);
- } else if (store.seen >= MAX_MATCHES) {
- error("too many matches for %s", key);
- return 1;
}
+ ALLOC_GROW(store.offset, store.seen + 1,
+ store.offset_alloc);
+
store.offset[store.seen] = cf->do_ftell(cf);
store.seen++;
}
@@ -1273,11 +1276,15 @@ 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.
*/
+ ALLOC_GROW(store.offset, store.seen + 1,
+ store.offset_alloc);
store.offset[store.seen] = cf->do_ftell(cf);
/* fallthru */
case SECTION_END_SEEN:
case START:
if (matches(key, value)) {
+ ALLOC_GROW(store.offset, store.seen + 1,
+ store.offset_alloc);
store.offset[store.seen] = cf->do_ftell(cf);
store.state = KEY_SEEN;
store.seen++;
@@ -1285,6 +1292,9 @@ static int store_aux(const char *key, const char *value, void *cb)
if (strrchr(key, '.') - key == store.baselen &&
!strncmp(key, store.key, store.baselen)) {
store.state = SECTION_SEEN;
+ ALLOC_GROW(store.offset,
+ store.seen + 1,
+ store.offset_alloc);
store.offset[store.seen] = cf->do_ftell(cf);
}
}
@@ -1583,6 +1593,7 @@ int git_config_set_multivar_in_file(const char *config_filename,
}
}
+ ALLOC_GROW(store.offset, 1, store.offset_alloc);
store.offset[0] = 0;
store.state = START;
store.seen = 0;
@@ -1872,7 +1883,7 @@ int parse_config_key(const char *var,
const char *dot;
/* Does it start with "section." ? */
- if (prefixcmp(var, section) || var[section_len] != '.')
+ if (!starts_with(var, section) || var[section_len] != '.')
return -1;
/*
diff --git a/config.mak.uname b/config.mak.uname
index 82d549e..7d31fad 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -198,6 +198,13 @@ ifeq ($(uname_S),OpenBSD)
BASIC_LDFLAGS += -L/usr/local/lib
HAVE_PATHS_H = YesPlease
endif
+ifeq ($(uname_S),MirBSD)
+ NO_STRCASESTR = YesPlease
+ NO_MEMMEM = YesPlease
+ USE_ST_TIMESPEC = YesPlease
+ NEEDS_LIBICONV = YesPlease
+ HAVE_PATHS_H = YesPlease
+endif
ifeq ($(uname_S),NetBSD)
ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
NEEDS_LIBICONV = YesPlease
diff --git a/connect.c b/connect.c
index 4086861..4150412 100644
--- a/connect.c
+++ b/connect.c
@@ -7,8 +7,11 @@
#include "remote.h"
#include "connect.h"
#include "url.h"
+#include "string-list.h"
+#include "sha1-array.h"
static char *server_capabilities;
+static const char *parse_feature_value(const char *, const char *, int *);
static int check_ref(const char *name, int len, unsigned int flags)
{
@@ -43,13 +46,6 @@ int check_ref_type(const struct ref *ref, int flags)
return check_ref(ref->name, strlen(ref->name), flags);
}
-static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1)
-{
- ALLOC_GROW(extra->array, extra->nr + 1, extra->alloc);
- hashcpy(&(extra->array[extra->nr][0]), sha1);
- extra->nr++;
-}
-
static void die_initial_contact(int got_at_least_one_head)
{
if (got_at_least_one_head)
@@ -60,13 +56,70 @@ static void die_initial_contact(int got_at_least_one_head)
"and the repository exists.");
}
+static void parse_one_symref_info(struct string_list *symref, const char *val, int len)
+{
+ char *sym, *target;
+ struct string_list_item *item;
+
+ if (!len)
+ return; /* just "symref" */
+ /* e.g. "symref=HEAD:refs/heads/master" */
+ sym = xmalloc(len + 1);
+ memcpy(sym, val, len);
+ sym[len] = '\0';
+ target = strchr(sym, ':');
+ if (!target)
+ /* just "symref=something" */
+ goto reject;
+ *(target++) = '\0';
+ if (check_refname_format(sym, REFNAME_ALLOW_ONELEVEL) ||
+ check_refname_format(target, REFNAME_ALLOW_ONELEVEL))
+ /* "symref=bogus:pair */
+ goto reject;
+ item = string_list_append(symref, sym);
+ item->util = target;
+ return;
+reject:
+ free(sym);
+ return;
+}
+
+static void annotate_refs_with_symref_info(struct ref *ref)
+{
+ struct string_list symref = STRING_LIST_INIT_DUP;
+ const char *feature_list = server_capabilities;
+
+ while (feature_list) {
+ int len;
+ const char *val;
+
+ val = parse_feature_value(feature_list, "symref", &len);
+ if (!val)
+ break;
+ parse_one_symref_info(&symref, val, len);
+ feature_list = val + 1;
+ }
+ sort_string_list(&symref);
+
+ for (; ref; ref = ref->next) {
+ struct string_list_item *item;
+ item = string_list_lookup(&symref, ref->name);
+ if (!item)
+ continue;
+ ref->symref = xstrdup((char *)item->util);
+ }
+ string_list_clear(&symref, 0);
+}
+
/*
* Read all the refs from the other end
*/
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)
+ struct sha1_array *extra_have,
+ struct sha1_array *shallow_points)
{
+ struct ref **orig_list = list;
int got_at_least_one_head = 0;
*list = NULL;
@@ -87,9 +140,18 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
if (!len)
break;
- if (len > 4 && !prefixcmp(buffer, "ERR "))
+ if (len > 4 && starts_with(buffer, "ERR "))
die("remote error: %s", buffer + 4);
+ if (len == 48 && starts_with(buffer, "shallow ")) {
+ if (get_sha1_hex(buffer + 8, old_sha1))
+ die("protocol error: expected shallow sha-1, got '%s'", buffer + 8);
+ if (!shallow_points)
+ die("repository on the other end cannot be shallow");
+ sha1_array_append(shallow_points, old_sha1);
+ continue;
+ }
+
if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ')
die("protocol error: expected sha/ref, got '%s'", buffer);
name = buffer + 41;
@@ -102,7 +164,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
if (extra_have &&
name_len == 5 && !memcmp(".have", name, 5)) {
- add_extra_have(extra_have, old_sha1);
+ sha1_array_append(extra_have, old_sha1);
continue;
}
@@ -114,10 +176,13 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
list = &ref->next;
got_at_least_one_head = 1;
}
+
+ annotate_refs_with_symref_info(*orig_list);
+
return list;
}
-const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
+static const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
{
int len;
@@ -171,10 +236,34 @@ int server_supports(const char *feature)
enum protocol {
PROTO_LOCAL = 1,
+ PROTO_FILE,
PROTO_SSH,
PROTO_GIT
};
+int url_is_local_not_ssh(const char *url)
+{
+ const char *colon = strchr(url, ':');
+ const char *slash = strchr(url, '/');
+ return !colon || (slash && slash < colon) ||
+ has_dos_drive_prefix(url);
+}
+
+static const char *prot_name(enum protocol protocol)
+{
+ switch (protocol) {
+ case PROTO_LOCAL:
+ case PROTO_FILE:
+ return "file";
+ case PROTO_SSH:
+ return "ssh";
+ case PROTO_GIT:
+ return "git";