summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/CONTRIBUTING.md3
-rw-r--r--.github/workflows/main.yml305
-rw-r--r--.gitignore3
-rw-r--r--.travis.yml12
-rw-r--r--Documentation/CodingGuidelines25
-rw-r--r--Documentation/Makefile25
-rw-r--r--Documentation/MyFirstContribution.txt4
-rw-r--r--Documentation/MyFirstObjectWalk.txt3
-rw-r--r--Documentation/RelNotes/2.27.0.txt525
-rw-r--r--Documentation/RelNotes/2.28.0.txt236
-rw-r--r--Documentation/RelNotes/2.29.0.txt77
-rw-r--r--Documentation/SubmittingPatches15
-rw-r--r--Documentation/asciidoc.conf19
-rw-r--r--Documentation/config.txt23
-rw-r--r--Documentation/config/credential.txt10
-rw-r--r--Documentation/config/diff.txt4
-rw-r--r--Documentation/config/feature.txt13
-rw-r--r--Documentation/config/fetch.txt16
-rw-r--r--Documentation/config/fmt-merge-msg.txt12
-rw-r--r--Documentation/config/format.txt5
-rw-r--r--Documentation/config/http.txt21
-rw-r--r--Documentation/config/init.txt4
-rw-r--r--Documentation/config/log.txt6
-rw-r--r--Documentation/config/merge.txt10
-rw-r--r--Documentation/config/pack.txt4
-rw-r--r--Documentation/config/protocol.txt3
-rw-r--r--Documentation/config/push.txt2
-rw-r--r--Documentation/config/stash.txt18
-rw-r--r--Documentation/config/submodule.txt12
-rw-r--r--Documentation/config/tag.txt7
-rw-r--r--Documentation/config/tar.txt6
-rw-r--r--Documentation/config/trace2.txt9
-rw-r--r--Documentation/date-formats.txt4
-rw-r--r--Documentation/diff-options.txt5
-rw-r--r--Documentation/fetch-options.txt15
-rw-r--r--Documentation/git-am.txt5
-rw-r--r--Documentation/git-branch.txt2
-rw-r--r--Documentation/git-bugreport.txt54
-rw-r--r--Documentation/git-cat-file.txt2
-rw-r--r--Documentation/git-checkout.txt4
-rw-r--r--Documentation/git-cherry-pick.txt5
-rw-r--r--Documentation/git-clone.txt15
-rw-r--r--Documentation/git-commit-graph.txt32
-rw-r--r--Documentation/git-commit-tree.txt8
-rw-r--r--Documentation/git-commit.txt9
-rw-r--r--Documentation/git-credential-store.txt4
-rw-r--r--Documentation/git-credential.txt34
-rw-r--r--Documentation/git-diff.txt23
-rw-r--r--Documentation/git-fast-export.txt29
-rw-r--r--Documentation/git-fast-import.txt29
-rw-r--r--Documentation/git-fetch.txt8
-rw-r--r--Documentation/git-for-each-ref.txt27
-rw-r--r--Documentation/git-format-patch.txt8
-rw-r--r--Documentation/git-grep.txt8
-rw-r--r--Documentation/git-help.txt4
-rw-r--r--Documentation/git-http-fetch.txt9
-rw-r--r--Documentation/git-index-pack.txt12
-rw-r--r--Documentation/git-init.txt14
-rw-r--r--Documentation/git-log.txt13
-rw-r--r--Documentation/git-ls-files.txt2
-rw-r--r--Documentation/git-ls-remote.txt4
-rw-r--r--Documentation/git-merge.txt11
-rw-r--r--Documentation/git-multi-pack-index.txt3
-rw-r--r--Documentation/git-p4.txt45
-rw-r--r--Documentation/git-pack-objects.txt10
-rw-r--r--Documentation/git-pull.txt20
-rw-r--r--Documentation/git-read-tree.txt4
-rw-r--r--Documentation/git-rebase.txt103
-rw-r--r--Documentation/git-reset.txt6
-rw-r--r--Documentation/git-restore.txt22
-rw-r--r--Documentation/git-rev-list.txt40
-rw-r--r--Documentation/git-revert.txt5
-rw-r--r--Documentation/git-show-index.txt11
-rw-r--r--Documentation/git-sparse-checkout.txt40
-rw-r--r--Documentation/git-submodule.txt12
-rw-r--r--Documentation/git-switch.txt4
-rw-r--r--Documentation/git-update-ref.txt28
-rw-r--r--Documentation/git-worktree.txt4
-rw-r--r--Documentation/git.txt17
-rw-r--r--Documentation/gitattributes.txt2
-rw-r--r--Documentation/gitcredentials.txt42
-rw-r--r--Documentation/giteveryday.txt10
-rw-r--r--Documentation/gitfaq.txt355
-rw-r--r--Documentation/githooks.txt80
-rw-r--r--Documentation/gitmodules.txt6
-rw-r--r--Documentation/gitremote-helpers.txt37
-rw-r--r--Documentation/gitsubmodules.txt3
-rw-r--r--Documentation/gitworkflows.txt18
-rw-r--r--Documentation/howto/maintain-git.txt104
-rw-r--r--Documentation/howto/rebase-from-internal-branch.txt32
-rw-r--r--Documentation/howto/revert-branch-rebase.txt32
-rw-r--r--Documentation/howto/update-hook-example.txt6
-rw-r--r--Documentation/manpage-1.72.xsl14
-rw-r--r--Documentation/manpage-base.xsl35
-rw-r--r--Documentation/manpage-bold-literal.xsl6
-rw-r--r--Documentation/manpage-normal.xsl25
-rw-r--r--Documentation/manpage-suppress-sp.xsl21
-rw-r--r--Documentation/merge-options.txt13
-rw-r--r--Documentation/pretty-formats.txt10
-rw-r--r--Documentation/pull-fetch-param.txt3
-rw-r--r--Documentation/rev-list-description.txt61
-rw-r--r--Documentation/rev-list-options.txt137
-rw-r--r--Documentation/revisions.txt5
-rw-r--r--Documentation/technical/api-trace2.txt3
-rw-r--r--Documentation/technical/commit-graph-format.txt32
-rw-r--r--Documentation/technical/http-protocol.txt2
-rw-r--r--Documentation/technical/pack-protocol.txt6
-rw-r--r--Documentation/technical/packfile-uri.txt78
-rw-r--r--Documentation/technical/protocol-capabilities.txt15
-rw-r--r--Documentation/technical/protocol-v2.txt59
-rw-r--r--Documentation/technical/reftable.txt1083
-rw-r--r--Documentation/user-manual.conf10
-rw-r--r--Documentation/user-manual.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL4
-rw-r--r--Makefile133
-rw-r--r--README.md2
l---------RelNotes2
-rw-r--r--abspath.c18
-rw-r--r--add-interactive.c4
-rw-r--r--add-patch.c36
-rw-r--r--advice.c97
-rw-r--r--advice.h52
-rw-r--r--alloc.c18
-rw-r--r--alloc.h2
-rw-r--r--apply.c30
-rw-r--r--archive-tar.c4
-rw-r--r--archive.c13
-rw-r--r--archive.h1
-rw-r--r--azure-pipelines.yml558
-rw-r--r--bisect.c8
-rw-r--r--blame.c137
-rw-r--r--blame.h6
-rw-r--r--blob.c2
-rw-r--r--bloom.c300
-rw-r--r--bloom.h91
-rw-r--r--branch.c3
-rw-r--r--bugreport.c200
-rw-r--r--builtin.h16
-rw-r--r--builtin/add.c4
-rw-r--r--builtin/am.c3
-rw-r--r--builtin/bisect--helper.c16
-rw-r--r--builtin/blame.c14
-rw-r--r--builtin/branch.c12
-rw-r--r--builtin/cat-file.c17
-rw-r--r--builtin/checkout-index.c4
-rw-r--r--builtin/checkout.c88
-rw-r--r--builtin/clean.c73
-rw-r--r--builtin/clone.c71
-rw-r--r--builtin/commit-graph.c115
-rw-r--r--builtin/commit-tree.c12
-rw-r--r--builtin/commit.c59
-rw-r--r--builtin/config.c2
-rw-r--r--builtin/describe.c15
-rw-r--r--builtin/diff-files.c7
-rw-r--r--builtin/diff-tree.c9
-rw-r--r--builtin/diff.c149
-rw-r--r--builtin/fast-export.c162
-rw-r--r--builtin/fetch-pack.c21
-rw-r--r--builtin/fetch.c42
-rw-r--r--builtin/fmt-merge-msg.c655
-rw-r--r--builtin/for-each-ref.c2
-rw-r--r--builtin/fsck.c7
-rw-r--r--builtin/grep.c76
-rw-r--r--builtin/help.c88
-rw-r--r--builtin/index-pack.c19
-rw-r--r--builtin/init-db.c106
-rw-r--r--builtin/interpret-trailers.c4
-rw-r--r--builtin/log.c78
-rw-r--r--builtin/ls-files.c17
-rw-r--r--builtin/ls-remote.c4
-rw-r--r--builtin/merge-base.c12
-rw-r--r--builtin/merge.c49
-rw-r--r--builtin/mv.c7
-rw-r--r--builtin/notes.c32
-rw-r--r--builtin/pack-objects.c137
-rw-r--r--builtin/prune-packed.c44
-rw-r--r--builtin/prune.c2
-rw-r--r--builtin/pull.c62
-rw-r--r--builtin/push.c27
-rw-r--r--builtin/read-tree.c12
-rw-r--r--builtin/rebase.c365
-rw-r--r--builtin/receive-pack.c48
-rw-r--r--builtin/reflog.c4
-rw-r--r--builtin/remote.c4
-rw-r--r--builtin/repack.c2
-rw-r--r--builtin/reset.c20
-rw-r--r--builtin/rev-parse.c13
-rw-r--r--builtin/send-pack.c12
-rw-r--r--builtin/shortlog.c4
-rw-r--r--builtin/show-branch.c4
-rw-r--r--builtin/show-index.c29
-rw-r--r--builtin/show-ref.c12
-rw-r--r--builtin/sparse-checkout.c59
-rw-r--r--builtin/stash.c69
-rw-r--r--builtin/submodule--helper.c86
-rw-r--r--builtin/tag.c13
-rw-r--r--builtin/update-index.c16
-rw-r--r--builtin/update-ref.c245
-rw-r--r--builtin/worktree.c167
-rw-r--r--bundle.c22
-rw-r--r--bundle.h1
-rw-r--r--cache.h34
-rwxr-xr-xci/config/allow-ref.sample27
-rwxr-xr-xci/install-dependencies.sh16
-rwxr-xr-xci/install-docker-dependencies.sh18
-rwxr-xr-xci/lib.sh40
-rwxr-xr-xci/print-test-failures.sh7
-rwxr-xr-xci/run-build-and-tests.sh1
-rwxr-xr-xci/run-docker-build.sh (renamed from ci/run-linux32-build.sh)39
-rwxr-xr-xci/run-docker.sh47
-rwxr-xr-xci/run-linux32-docker.sh31
-rw-r--r--column.c2
-rw-r--r--combine-diff.c2
-rw-r--r--command-list.txt4
-rw-r--r--commit-graph.c746
-rw-r--r--commit-graph.h52
-rw-r--r--commit-reach.c93
-rw-r--r--commit-reach.h4
-rw-r--r--commit-slab-decl.h7
-rw-r--r--commit-slab-impl.h13
-rw-r--r--commit-slab.h17
-rw-r--r--commit.c75
-rw-r--r--commit.h50
-rw-r--r--compat/compiler.h41
-rw-r--r--compat/gmtime.c29
-rw-r--r--compat/mingw.c62
-rw-r--r--compat/regex/regex.c1
-rw-r--r--compat/regex/regex_internal.h1
-rw-r--r--compat/vcbuild/README4
-rwxr-xr-xcompat/vcbuild/scripts/clink.pl4
-rw-r--r--compat/win32/path-utils.h11
-rw-r--r--config.c42
-rw-r--r--config.h4
-rw-r--r--config.mak.dev2
-rw-r--r--config.mak.uname21
-rw-r--r--connect.c158
-rw-r--r--connect.h7
-rw-r--r--connected.c21
-rw-r--r--connected.h9
-rw-r--r--contrib/coccinelle/commit.cocci18
-rw-r--r--contrib/completion/git-completion.bash281
-rw-r--r--contrib/completion/git-completion.zsh2
-rw-r--r--contrib/completion/git-prompt.sh26
-rwxr-xr-xcontrib/fast-import/import-tars.perl2
-rw-r--r--contrib/subtree/Makefile6
-rwxr-xr-xcontrib/subtree/t/t7900-subtree.sh6
-rw-r--r--convert.c68
-rw-r--r--convert.h29
-rw-r--r--credential-store.c4
-rw-r--r--credential.c82
-rw-r--r--credential.h8
-rw-r--r--csum-file.c2
-rw-r--r--date.c67
-rw-r--r--delta-islands.c2
-rw-r--r--diff-lib.c3
-rw-r--r--diff.c178
-rw-r--r--diff.h15
-rw-r--r--diffcore-break.c12
-rw-r--r--diffcore-rename.c64
-rw-r--r--diffcore.h30
-rw-r--r--dir.c465
-rw-r--r--editor.c11
-rw-r--r--entry.c10
-rw-r--r--environment.c19
-rw-r--r--fast-import.c332
-rw-r--r--fetch-pack.c229
-rw-r--r--fetch-pack.h2
-rw-r--r--fmt-merge-msg.c686
-rw-r--r--fmt-merge-msg.h13
-rw-r--r--fsck.c74
-rw-r--r--fsmonitor.c2
-rw-r--r--fuzz-commit-graph.c7
-rwxr-xr-xgenerate-cmdlist.sh19
-rwxr-xr-xgenerate-configlist.sh21
-rwxr-xr-xgit-add--interactive.perl21
-rwxr-xr-xgit-bisect.sh10
-rw-r--r--git-compat-util.h21
-rwxr-xr-xgit-cvsexportcommit.perl14
-rwxr-xr-xgit-cvsimport.perl8
-rwxr-xr-xgit-cvsserver.perl37
-rwxr-xr-xgit-gui/git-gui.sh6
-rw-r--r--git-gui/lib/choose_repository.tcl27
-rw-r--r--git-gui/lib/index.tcl6
-rw-r--r--git-gui/lib/mergetool.tcl2
-rwxr-xr-xgit-legacy-stash.sh798
-rwxr-xr-xgit-p4.py517
-rwxr-xr-xgit-send-email.perl8
-rwxr-xr-xgit-submodule.sh56
-rwxr-xr-xgit-svn.perl25
-rw-r--r--git.c17
-rwxr-xr-xgitweb/gitweb.perl18
-rw-r--r--gpg-interface.c97
-rw-r--r--gpg-interface.h9
-rw-r--r--graph.c2
-rw-r--r--grep.c2
-rw-r--r--hash.h21
-rw-r--r--hashmap.h2
-rw-r--r--help.c132
-rw-r--r--help.h2
-rw-r--r--hex.c55
-rw-r--r--http-fetch.c126
-rw-r--r--http-push.c16
-rw-r--r--http-walker.c5
-rw-r--r--http.c200
-rw-r--r--http.h31
-rw-r--r--imap-send.c2
-rw-r--r--line-log.c49
-rw-r--r--line-log.h5
-rw-r--r--list-objects-filter-options.c3
-rw-r--r--list-objects-filter-options.h6
-rw-r--r--list-objects-filter.c3
-rw-r--r--ll-merge.c2
-rw-r--r--lockfile.c18
-rw-r--r--lockfile.h32
-rw-r--r--log-tree.c92
-rw-r--r--log-tree.h4
-rw-r--r--ls-refs.c5
-rw-r--r--mailinfo.c11
-rw-r--r--merge-recursive.c14
-rw-r--r--merge.c1
-rw-r--r--midx.c61
-rw-r--r--midx.h2
-rw-r--r--object-store.h3
-rw-r--r--object.c4
-rw-r--r--object.h10
-rw-r--r--oid-array.c (renamed from sha1-array.c)10
-rw-r--r--oid-array.h (renamed from sha1-array.h)6
-rw-r--r--oidset.c5
-rw-r--r--oidset.h8
-rw-r--r--pack-bitmap.c72
-rw-r--r--pack-write.c5
-rw-r--r--packfile.c1
-rw-r--r--parse-options-cb.c2
-rw-r--r--parse-options.c9
-rw-r--r--parse-options.h1
-rw-r--r--path.c7
-rw-r--r--path.h4
-rw-r--r--perl/Git/IndexInfo.pm6
-rw-r--r--perl/Git/SVN.pm83
-rw-r--r--perl/Git/SVN/Editor.pm8
-rw-r--r--perl/Git/SVN/Fetcher.pm6
-rw-r--r--perl/Git/SVN/Log.pm2
-rw-r--r--perl/Git/SVN/Ra.pm4
-rw-r--r--pkt-line.c18
-rw-r--r--pkt-line.h14
-rw-r--r--po/bg.po7130
-rw-r--r--po/ca.po12136
-rw-r--r--po/de.po8080
-rw-r--r--po/es.po8112
-rw-r--r--po/fr.po7992
-rw-r--r--po/git.pot7761
-rw-r--r--po/it.po8140
-rw-r--r--po/sv.po8093
-rw-r--r--po/tr.po8013
-rw-r--r--po/vi.po8168
-rw-r--r--po/zh_CN.po7918
-rw-r--r--po/zh_TW.po8769
-rw-r--r--pretty.c6
-rw-r--r--pretty.h1
-rw-r--r--progress.c15
-rw-r--r--progress.h8
-rw-r--r--promisor-remote.c5
-rw-r--r--promisor-remote.h8
-rw-r--r--prompt.c12
-rw-r--r--prompt.h2
-rw-r--r--protocol.c6
-rw-r--r--prune-packed.c43
-rw-r--r--prune-packed.h9
-rw-r--r--range-diff.c18
-rw-r--r--read-cache.c14
-rw-r--r--ref-filter.c31
-rw-r--r--ref-filter.h4
-rw-r--r--refs.c211
-rw-r--r--refs.h39
-rw-r--r--refs/files-backend.c24
-rw-r--r--refs/refs-internal.h24
-rw-r--r--remote-curl.c124
-rw-r--r--remote-testsvn.c10
-rw-r--r--remote.c51
-rw-r--r--remote.h3
-rw-r--r--repo-settings.c11
-rw-r--r--repository.c4
-rw-r--r--repository.h14
-rw-r--r--reset.c141
-rw-r--r--reset.h20
-rw-r--r--revision.c274
-rw-r--r--revision.h29
-rw-r--r--run-command.c24
-rw-r--r--run-command.h6
-rw-r--r--send-pack.c43
-rw-r--r--sequencer.c279
-rw-r--r--sequencer.h27
-rw-r--r--serve.c29
-rw-r--r--setup.c169
-rw-r--r--sha1-file.c35
-rw-r--r--sha1-name.c6
-rw-r--r--sha256/gcrypt.h6
-rw-r--r--shallow.c74
-rw-r--r--shallow.h81
-rw-r--r--shell.c4
-rw-r--r--strbuf.c19
-rw-r--r--strbuf.h13
-rw-r--r--submodule-config.c3
-rw-r--r--submodule.c24
-rw-r--r--submodule.h4
-rw-r--r--t/README67
-rw-r--r--t/helper/test-advise.c22
-rw-r--r--t/helper/test-bloom.c93
-rw-r--r--t/helper/test-dump-split-index.c2
-rw-r--r--t/helper/test-oid-array.c (renamed from t/helper/test-sha1-array.c)11
-rw-r--r--t/helper/test-parse-pathspec-file.c6
-rw-r--r--t/helper/test-path-utils.c5
-rw-r--r--t/helper/test-pkt-line.c6
-rw-r--r--t/helper/test-progress.c9
-rw-r--r--t/helper/test-reach.c4
-rw-r--r--t/helper/test-read-graph.c17
-rw-r--r--t/helper/test-ref-store.c2
-rw-r--r--t/helper/test-regex.c94
-rw-r--r--t/helper/test-repository.c14
-rw-r--r--t/helper/test-tool.c5
-rw-r--r--t/helper/test-tool.h4
-rw-r--r--[-rwxr-xr-x]t/lib-credential.sh3
-rw-r--r--t/lib-git-svn.sh17
-rw-r--r--[-rwxr-xr-x]t/lib-gpg.sh110
-rw-r--r--t/lib-httpd.sh2
-rw-r--r--t/lib-httpd/apache.conf8
-rw-r--r--t/lib-httpd/incomplete-body-upload-pack-v2-http.sh3
-rw-r--r--t/lib-httpd/incomplete-length-upload-pack-v2-http.sh3
-rw-r--r--[-rwxr-xr-x]t/lib-log-graph.sh0
-rw-r--r--[-rwxr-xr-x]t/lib-submodule-update.sh143
-rw-r--r--t/lib-t6000.sh5
-rwxr-xr-xt/perf/p1400-update-ref.sh32
-rwxr-xr-xt/perf/p5310-pack-bitmaps.sh14
-rwxr-xr-xt/perf/p9300-fast-import-export.sh23
-rwxr-xr-xt/t0000-basic.sh39
-rwxr-xr-xt/t0001-init.sh35
-rwxr-xr-xt/t0002-gitfile.sh2
-rwxr-xr-xt/t0006-date.sh6
-rwxr-xr-xt/t0007-git-var.sh2
-rwxr-xr-xt/t0018-advice.sh32
-rwxr-xr-xt/t0021-conversion.sh198
-rw-r--r--t/t0021/rot13-filter.pl6
-rwxr-xr-xt/t0040-parse-options.sh2
-rwxr-xr-xt/t0060-path-utils.sh2
-rwxr-xr-xt/t0064-sha1-array.sh16
-rwxr-xr-xt/t0091-bugreport.sh76
-rwxr-xr-xt/t0095-bloom.sh117
-rwxr-xr-xt/t0212-trace2-event.sh37
-rwxr-xr-xt/t0300-credentials.sh119
-rwxr-xr-xt/t0302-credential-store.sh91
-rwxr-xr-xt/t0410-partial-clone.sh34
-rwxr-xr-xt/t0500-progress-display.sh26
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh23
-rwxr-xr-xt/t1013-read-tree-submodule.sh4
-rwxr-xr-xt/t1050-large.sh6
-rwxr-xr-xt/t1090-sparse-checkout-scope.sh1
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh135
-rwxr-xr-xt/t1302-repo-version.sh9
-rwxr-xr-xt/t1400-update-ref.sh172
-rwxr-xr-xt/t1416-ref-transaction-hooks.sh109
-rwxr-xr-xt/t1450-fsck.sh53
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh2
-rwxr-xr-xt/t1509-root-work-tree.sh4
-rwxr-xr-xt/t2013-checkout-submodule.sh4
-rwxr-xr-xt/t2018-checkout-branch.sh32
-rwxr-xr-xt/t2027-checkout-track.sh24
-rwxr-xr-xt/t2060-switch.sh8
-rwxr-xr-xt/t2070-restore.sh11
-rwxr-xr-xt/t2203-add-intent.sh52
-rwxr-xr-xt/t2401-worktree-prune.sh24
-rwxr-xr-xt/t2402-worktree-list.sh2
-rwxr-xr-xt/t2403-worktree-move.sh21
-rwxr-xr-xt/t2404-worktree-config.sh4
-rwxr-xr-xt/t3000-ls-files-others.sh121
-rwxr-xr-xt/t3033-merge-toplevel.sh22
-rwxr-xr-xt/t3200-branch.sh69
-rwxr-xr-xt/t3206-range-diff.sh10
-rwxr-xr-xt/t3402-rebase-merge.sh77
-rwxr-xr-xt/t3403-rebase-skip.sh79
-rwxr-xr-xt/t3404-rebase-interactive.sh64
-rwxr-xr-xt/t3406-rebase-message.sh16
-rwxr-xr-xt/t3415-rebase-autosquash.sh16
-rwxr-xr-xt/t3417-rebase-whitespace-fix.sh4
-rwxr-xr-xt/t3419-rebase-patch-id.sh114
-rwxr-xr-xt/t3420-rebase-autostash.sh20
-rwxr-xr-xt/t3421-rebase-topology-linear.sh10
-rwxr-xr-xt/t3424-rebase-empty.sh36
-rwxr-xr-xt/t3426-rebase-submodule.sh10
-rwxr-xr-xt/t3430-rebase-merges.sh2
-rwxr-xr-xt/t3431-rebase-fork-point.sh20
-rwxr-xr-xt/t3432-rebase-fast-forward.sh31
-rwxr-xr-xt/t3435-rebase-gpg-sign.sh71
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh23
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh3
-rwxr-xr-xt/t3512-cherry-pick-submodule.sh2
-rwxr-xr-xt/t3513-revert-submodule.sh9
-rwxr-xr-xt/t3514-cherry-pick-revert-gpg.sh86
-rwxr-xr-xt/t3700-add.sh2
-rwxr-xr-xt/t3701-add-interactive.sh34
-rwxr-xr-xt/t3903-stash.sh14
-rwxr-xr-xt/t3904-stash-patch.sh6
-rwxr-xr-xt/t3906-stash-submodule.sh9
-rwxr-xr-xt/t4010-diff-pathspec.sh4
-rwxr-xr-xt/t4013-diff-various.sh12
-rw-r--r--t/t4013/diff.diff-tree_--format=%N_note6
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--notes_note12
-rw-r--r--t/t4013/diff.diff-tree_--pretty_note9
-rw-r--r--t/t4013/diff.log_--decorate=full_--all15
-rw-r--r--t/t4013/diff.log_--decorate_--all15
-rwxr-xr-xt/t4014-format-patch.sh74
-rwxr-xr-xt/t4018-diff-funcname.sh1
-rw-r--r--t/t4018/markdown-heading-indented6
-rw-r--r--t/t4018/markdown-heading-non-headings17
-rwxr-xr-xt/t4045-diff-relative.sh82
-rwxr-xr-xt/t4057-diff-combined-paths.sh2
-rwxr-xr-xt/t4061-diff-indent.sh2
-rwxr-xr-xt/t4067-diff-partial-clone.sh52
-rwxr-xr-xt/t4068-diff-symmetric.sh91
-rwxr-xr-xt/t4124-apply-ws-rule.sh7
-rwxr-xr-xt/t4137-apply-submodule.sh12
-rwxr-xr-xt/t4150-am.sh2
-rwxr-xr-xt/t4202-log.sh156
-rwxr-xr-xt/t4208-log-magic-pathspec.sh4
-rwxr-xr-xt/t4210-log-i18n.sh77
-rwxr-xr-xt/t4211-line-log.sh76
-rwxr-xr-xt/t4216-log-bloom.sh194
-rwxr-xr-xt/t4254-am-corrupt.sh53
-rwxr-xr-xt/t4255-am-submodule.sh12
-rwxr-xr-xt/t5003-archive-zip.sh24
-rwxr-xr-xt/t5300-pack-object.sh45
-rwxr-xr-xt/t5302-pack-index.sh356
-rwxr-xr-xt/t5318-commit-graph.sh78
-rwxr-xr-xt/t5319-multi-pack-index.sh48
-rw-r--r--t/t5319/no-objects.midxbin0 -> 1116 bytes
-rwxr-xr-xt/t5322-pack-objects-sparse.sh4
-rwxr-xr-xt/t5324-split-commit-graph.sh76
-rwxr-xr-xt/t5500-fetch-pack.sh54
-rwxr-xr-xt/t5504-fetch-receive-strict.sh1
-rwxr-xr-xt/t5505-remote.sh8
-rwxr-xr-xt/t5510-fetch.sh2
-rwxr-xr-xt/t5512-ls-remote.sh80
-rwxr-xr-xt/t5516-fetch-push.sh17
-rwxr-xr-xt/t5520-pull.sh57
-rwxr-xr-xt/t5521-pull-options.sh22
-rwxr-xr-xt/t5528-push-default.sh6
-rwxr-xr-xt/t5537-fetch-shallow.sh115
-rwxr-xr-xt/t5539-fetch-http-shallow.sh4
-rwxr-xr-xt/t5540-http-push-webdav.sh16
-rwxr-xr-xt/t5541-http-push-smart.sh42
-rwxr-xr-xt/t5543-atomic-push.sh89
-rwxr-xr-xt/t5548-push-porcelain.sh279
-rwxr-xr-xt/t5550-http-fetch-dumb.sh52
-rwxr-xr-xt/t5551-http-fetch-smart.sh56
-rwxr-xr-xt/t5562-http-backend-content-length.sh20
-rwxr-xr-xt/t5572-pull-submodule.sh20
-rwxr-xr-xt/t5581-http-curl-verbose.sh2
-rwxr-xr-xt/t5601-clone.sh4
-rwxr-xr-xt/t5604-clone-reference.sh2
-rwxr-xr-xt/t5606-clone-options.sh24
-rwxr-xr-xt/t5607-clone-bundle.sh2
-rwxr-xr-xt/t5608-clone-2gb.sh11
-rwxr-xr-xt/t5611-clone-config.sh13
-rwxr-xr-xt/t5612-clone-refspec.sh26
-rwxr-xr-xt/t5616-partial-clone.sh55
-rwxr-xr-xt/t5701-git-serve.sh25
-rwxr-xr-xt/t5702-protocol-v2.sh138
-rwxr-xr-xt/t5703-upload-pack-ref-in-want.sh33
-rwxr-xr-xt/t5704-protocol-violations.sh35
-rwxr-xr-xt/t5801-remote-helpers.sh10
-rwxr-xr-xt/t5801/git-remote-testgit6
-rwxr-xr-xt/t6000-rev-list-misc.sh7
-rwxr-xr-xt/t6012-rev-list-simplify.sh120
-rwxr-xr-xt/t6030-bisect-porcelain.sh17
-rwxr-xr-xt/t6041-bisect-submodule.sh9
-rwxr-xr-xt/t6042-merge-rename-corner-cases.sh55
-rwxr-xr-xt/t6046-merge-skip-unneeded-updates.sh2
-rwxr-xr-xt/t6050-replace.sh2
-rwxr-xr-xt/t6113-rev-list-bitmap-filters.sh21
-rwxr-xr-xt/t6120-describe.sh20
-rwxr-xr-xt/t6132-pathspec-exclude.sh33
-rwxr-xr-xt/t6200-fmt-merge-msg.sh43
-rwxr-xr-xt/t6300-for-each-ref.sh157
-rwxr-xr-xt/t6600-test-reach.sh2
-rwxr-xr-xt/t7001-mv.sh17
-rwxr-xr-xt/t7004-tag.sh1
-rwxr-xr-xt/t7061-wtstatus-ignore.sh25
-rwxr-xr-xt/t7063-status-untracked-cache.sh54
-rwxr-xr-xt/t7107-reset-pathspec-file.sh9
-rwxr-xr-xt/t7112-reset-submodule.sh7
-rwxr-xr-xt/t7400-submodule-basic.sh4
-rwxr-xr-xt/t7406-submodule-update.sh16
-rwxr-xr-xt/t7408-submodule-reference.sh8
-rwxr-xr-xt/t7419-submodule-set-branch.sh7
-rwxr-xr-xt/t7508-status.sh2
-rwxr-xr-xt/t7510-signed-commit.sh16
-rwxr-xr-xt/t7600-merge.sh154
-rwxr-xr-xt/t7601-merge-pull-config.sh38
-rwxr-xr-xt/t7609-merge-co-error-msgs.sh2
-rwxr-xr-xt/t7613-merge-submodule.sh8
-rwxr-xr-xt/t7800-difftool.sh8
-rwxr-xr-xt/t7810-grep.sh47
-rwxr-xr-xt/t8014-blame-ignore-fuzzy.sh2
-rwxr-xr-xt/t9001-send-email.sh14
-rwxr-xr-xt/t9010-svn-fe.sh2
-rwxr-xr-xt/t9020-remote-svn.sh10
-rwxr-xr-xt/t9100-git-svn-basic.sh24
-rwxr-xr-xt/t9101-git-svn-props.sh12
-rwxr-xr-xt/t9104-git-svn-follow-parent.sh3
-rwxr-xr-xt/t9108-git-svn-glob.sh4
-rwxr-xr-xt/t9109-git-svn-multi-glob.sh6
-rwxr-xr-xt/t9141-git-svn-multiple-branches.sh8
-rwxr-xr-xt/t9160-git-svn-preserve-empty-dirs.sh4
-rwxr-xr-xt/t9164-git-svn-dcommit-concurrent.sh4
-rwxr-xr-xt/t9168-git-svn-partially-globbed-names.sh8
-rwxr-xr-xt/t9300-fast-import.sh137
-rwxr-xr-xt/t9351-fast-export-anonymize.sh54
-rwxr-xr-xt/t9400-git-cvsserver-server.sh2
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh70
-rwxr-xr-xt/t9700/test.pl6
-rwxr-xr-xt/t9819-git-p4-case-folding.sh2
-rwxr-xr-xt/t9831-git-p4-triggers.sh2
-rwxr-xr-xt/t9834-git-p4-file-dir-bug.sh70
-rwxr-xr-xt/t9902-completion.sh464
-rw-r--r--t/test-lib-functions.sh81
-rw-r--r--t/test-lib.sh128
-rw-r--r--tag.c2
-rw-r--r--tempfile.c6
-rw-r--r--tempfile.h10
-rw-r--r--trace.c20
-rw-r--r--trace.h6
-rw-r--r--trace2.c9
-rw-r--r--trace2.h13
-rw-r--r--trace2/tr2_cfg.c58
-rw-r--r--trace2/tr2_cfg.h8
-rw-r--r--trace2/tr2_sysenv.c2
-rw-r--r--trace2/tr2_sysenv.h1
-rw-r--r--transport-helper.c54
-rw-r--r--transport.c82
-rw-r--r--transport.h17
-rw-r--r--tree-diff.c36
-rw-r--r--tree-walk.c9
-rw-r--r--tree.c2
-rw-r--r--unpack-trees.c268
-rw-r--r--unpack-trees.h29
-rw-r--r--upload-pack.c871
-rw-r--r--urlmatch.c10
-rw-r--r--urlmatch.h5
-rw-r--r--userdiff.c7
-rw-r--r--worktree.c48
-rw-r--r--worktree.h11
-rw-r--r--wrapper.c12
-rw-r--r--wt-status.c49
-rw-r--r--wt-status.h17
654 files changed, 75142 insertions, 54313 deletions
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index e7b4e2f..c8755e3 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -16,4 +16,7 @@ If you prefer video, then [this talk](https://www.youtube.com/watch?v=Q7i_qQW__q
might be useful to you as the presenter walks you through the contribution
process by example.
+Or, you can follow the ["My First Contribution"](https://git-scm.com/docs/MyFirstContribution)
+tutorial for another example of the contribution process.
+
Your friendly Git community!
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..84a5dcf
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,305 @@
+name: CI/PR
+
+on: [push, pull_request]
+
+env:
+ DEVELOPER: 1
+
+jobs:
+ ci-config:
+ runs-on: ubuntu-latest
+ outputs:
+ enabled: ${{ steps.check-ref.outputs.enabled }}
+ steps:
+ - name: try to clone ci-config branch
+ continue-on-error: true
+ run: |
+ git -c protocol.version=2 clone \
+ --no-tags \
+ --single-branch \
+ -b ci-config \
+ --depth 1 \
+ --no-checkout \
+ --filter=blob:none \
+ https://github.com/${{ github.repository }} \
+ config-repo &&
+ cd config-repo &&
+ git checkout HEAD -- ci/config
+ - id: check-ref
+ name: check whether CI is enabled for ref
+ run: |
+ enabled=yes
+ if test -x config-repo/ci/config/allow-ref &&
+ ! config-repo/ci/config/allow-ref '${{ github.ref }}'
+ then
+ enabled=no
+ fi
+ echo "::set-output name=enabled::$enabled"
+
+ windows-build:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
+ runs-on: windows-latest
+ steps:
+ - uses: actions/checkout@v1
+ - name: download git-sdk-64-minimal
+ shell: bash
+ run: |
+ ## Get artifact
+ urlbase=https://dev.azure.com/git-for-windows/git/_apis/build/builds
+ id=$(curl "$urlbase?definitions=22&statusFilter=completed&resultFilter=succeeded&\$top=1" |
+ jq -r ".value[] | .id")
+ download_url="$(curl "$urlbase/$id/artifacts" |
+ jq -r '.value[] | select(.name == "git-sdk-64-minimal").resource.downloadUrl')"
+ curl --connect-timeout 10 --retry 5 --retry-delay 0 --retry-max-time 240 \
+ -o artifacts.zip "$download_url"
+
+ ## Unzip and remove the artifact
+ unzip artifacts.zip
+ rm artifacts.zip
+ - name: build
+ shell: powershell
+ env:
+ HOME: ${{runner.workspace}}
+ MSYSTEM: MINGW64
+ NO_PERL: 1
+ run: |
+ & .\git-sdk-64-minimal\usr\bin\bash.exe -lc @"
+ printf '%s\n' /git-sdk-64-minimal/ >>.git/info/exclude
+
+ ci/make-test-artifacts.sh artifacts
+ "@
+ - name: upload build artifacts
+ uses: actions/upload-artifact@v1
+ with:
+ name: windows-artifacts
+ path: artifacts
+ - name: upload git-sdk-64-minimal
+ uses: actions/upload-artifact@v1
+ with:
+ name: git-sdk-64-minimal
+ path: git-sdk-64-minimal
+ windows-test:
+ runs-on: windows-latest
+ needs: [windows-build]
+ strategy:
+ matrix:
+ nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ steps:
+ - uses: actions/checkout@v1
+ - name: download build artifacts
+ uses: actions/download-artifact@v1
+ with:
+ name: windows-artifacts
+ path: ${{github.workspace}}
+ - name: extract build artifacts
+ shell: bash
+ run: tar xf artifacts.tar.gz
+ - name: download git-sdk-64-minimal
+ uses: actions/download-artifact@v1
+ with:
+ name: git-sdk-64-minimal
+ path: ${{github.workspace}}/git-sdk-64-minimal/
+ - name: test
+ shell: powershell
+ run: |
+ & .\git-sdk-64-minimal\usr\bin\bash.exe -lc @"
+ # Let Git ignore the SDK
+ printf '%s\n' /git-sdk-64-minimal/ >>.git/info/exclude
+
+ ci/run-test-slice.sh ${{matrix.nr}} 10
+ "@
+ - name: ci/print-test-failures.sh
+ if: failure()
+ shell: powershell
+ run: |
+ & .\git-sdk-64-minimal\usr\bin\bash.exe -lc ci/print-test-failures.sh
+ - name: Upload failed tests' directories
+ if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+ uses: actions/upload-artifact@v1
+ with:
+ name: failed-tests-windows
+ path: ${{env.FAILED_TEST_ARTIFACTS}}
+ vs-build:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
+ env:
+ MSYSTEM: MINGW64
+ NO_PERL: 1
+ GIT_CONFIG_PARAMETERS: "'user.name=CI' 'user.email=ci@git'"
+ runs-on: windows-latest
+ steps:
+ - uses: actions/checkout@v1
+ - name: download git-sdk-64-minimal
+ shell: bash
+ run: |
+ ## Get artifact
+ urlbase=https://dev.azure.com/git-for-windows/git/_apis/build/builds
+ id=$(curl "$urlbase?definitions=22&statusFilter=completed&resultFilter=succeeded&\$top=1" |
+ jq -r ".value[] | .id")
+ download_url="$(curl "$urlbase/$id/artifacts" |
+ jq -r '.value[] | select(.name == "git-sdk-64-minimal").resource.downloadUrl')"
+ curl --connect-timeout 10 --retry 5 --retry-delay 0 --retry-max-time 240 \
+ -o artifacts.zip "$download_url"
+
+ ## Unzip and remove the artifact
+ unzip artifacts.zip
+ rm artifacts.zip
+ - name: generate Visual Studio solution
+ shell: powershell
+ run: |
+ & .\git-sdk-64-minimal\usr\bin\bash.exe -lc @"
+ make NDEBUG=1 DEVELOPER=1 vcxproj
+ "@
+ if (!$?) { exit(1) }
+ - name: download vcpkg artifacts
+ shell: powershell
+ run: |
+ $urlbase = "https://dev.azure.com/git/git/_apis/build/builds"
+ $id = ((Invoke-WebRequest -UseBasicParsing "${urlbase}?definitions=9&statusFilter=completed&resultFilter=succeeded&`$top=1").content | ConvertFrom-JSON).value[0].id
+ $downloadUrl = ((Invoke-WebRequest -UseBasicParsing "${urlbase}/$id/artifacts").content | ConvertFrom-JSON).value[0].resource.downloadUrl
+ (New-Object Net.WebClient).DownloadFile($downloadUrl, "compat.zip")
+ Expand-Archive compat.zip -DestinationPath . -Force
+ Remove-Item compat.zip
+ - name: add msbuild to PATH
+ uses: microsoft/setup-msbuild@v1.0.0
+ - name: MSBuild
+ run: msbuild git.sln -property:Configuration=Release -property:Platform=x64 -maxCpuCount:4 -property:PlatformToolset=v142
+ - name: bundle artifact tar
+ shell: powershell
+ env:
+ MSVC: 1
+ VCPKG_ROOT: ${{github.workspace}}\compat\vcbuild\vcpkg
+ run: |
+ & compat\vcbuild\vcpkg_copy_dlls.bat release
+ if (!$?) { exit(1) }
+ & git-sdk-64-minimal\usr\bin\bash.exe -lc @"
+ mkdir -p artifacts &&
+ eval \"`$(make -n artifacts-tar INCLUDE_DLLS_IN_ARTIFACTS=YesPlease ARTIFACTS_DIRECTORY=artifacts 2>&1 | grep ^tar)\"
+ "@
+ - name: upload build artifacts
+ uses: actions/upload-artifact@v1
+ with:
+ name: vs-artifacts
+ path: artifacts
+ vs-test:
+ runs-on: windows-latest
+ needs: [vs-build, windows-build]
+ strategy:
+ matrix:
+ nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ steps:
+ - uses: actions/checkout@v1
+ - name: download git-sdk-64-minimal
+ uses: actions/download-artifact@v1
+ with:
+ name: git-sdk-64-minimal
+ path: ${{github.workspace}}/git-sdk-64-minimal/
+ - name: download build artifacts
+ uses: actions/download-artifact@v1
+ with:
+ name: vs-artifacts
+ path: ${{github.workspace}}
+ - name: extract build artifacts
+ shell: bash
+ run: tar xf artifacts.tar.gz
+ - name: test (parallel)
+ shell: powershell
+ env:
+ MSYSTEM: MINGW64
+ NO_SVN_TESTS: 1
+ GIT_TEST_SKIP_REBASE_P: 1
+ run: |
+ & .\git-sdk-64-minimal\usr\bin\bash.exe -lc @"
+ # Let Git ignore the SDK and the test-cache
+ printf '%s\n' /git-sdk-64-minimal/ /test-cache/ >>.git/info/exclude
+
+ cd t &&
+ PATH=\"`$PWD/helper:`$PATH\" &&
+ test-tool.exe run-command testsuite --jobs=10 -V -x --write-junit-xml \
+ `$(test-tool.exe path-utils slice-tests \
+ ${{matrix.nr}} 10 t[0-9]*.sh)
+ "@
+ regular:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
+ strategy:
+ matrix:
+ vector:
+ - jobname: linux-clang
+ cc: clang
+ pool: ubuntu-latest
+ - jobname: linux-gcc
+ cc: gcc
+ pool: ubuntu-latest
+ - jobname: osx-clang
+ cc: clang
+ pool: macos-latest
+ - jobname: osx-gcc
+ cc: gcc
+ pool: macos-latest
+ - jobname: GETTEXT_POISON
+ cc: gcc
+ pool: ubuntu-latest
+ env:
+ CC: ${{matrix.vector.cc}}
+ jobname: ${{matrix.vector.jobname}}
+ runs-on: ${{matrix.vector.pool}}
+ steps:
+ - uses: actions/checkout@v1
+ - run: ci/install-dependencies.sh
+ - run: ci/run-build-and-tests.sh
+ - run: ci/print-test-failures.sh
+ if: failure()
+ - name: Upload failed tests' directories
+ if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+ uses: actions/upload-artifact@v1
+ with:
+ name: failed-tests-${{matrix.vector.jobname}}
+ path: ${{env.FAILED_TEST_ARTIFACTS}}
+ dockerized:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
+ strategy:
+ matrix:
+ vector:
+ - jobname: linux-musl
+ image: alpine
+ - jobname: Linux32
+ image: daald/ubuntu32:xenial
+ env:
+ jobname: ${{matrix.vector.jobname}}
+ runs-on: ubuntu-latest
+ container: ${{matrix.vector.image}}
+ steps:
+ - uses: actions/checkout@v1
+ - run: ci/install-docker-dependencies.sh
+ - run: ci/run-build-and-tests.sh
+ - run: ci/print-test-failures.sh
+ if: failure()
+ - name: Upload failed tests' directories
+ if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+ uses: actions/upload-artifact@v1
+ with:
+ name: failed-tests-${{matrix.vector.jobname}}
+ path: ${{env.FAILED_TEST_ARTIFACTS}}
+ static-analysis:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
+ env:
+ jobname: StaticAnalysis
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ - run: ci/install-dependencies.sh
+ - run: ci/run-static-analysis.sh
+ documentation:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
+ env:
+ jobname: Documentation
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ - run: ci/install-dependencies.sh
+ - run: ci/test-documentation.sh
diff --git a/.gitignore b/.gitignore
index aebe7c0..ee509a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,7 @@
/git-bisect--helper
/git-blame
/git-branch
+/git-bugreport
/git-bundle
/git-cat-file
/git-check-attr
@@ -83,7 +84,6 @@
/git-init-db
/git-interpret-trailers
/git-instaweb
-/git-legacy-stash
/git-log
/git-ls-files
/git-ls-remote
@@ -189,6 +189,7 @@
/gitweb/gitweb.cgi
/gitweb/static/gitweb.js
/gitweb/static/gitweb.min.*
+/config-list.h
/command-list.h
*.tar.gz
*.dsc
diff --git a/.travis.yml b/.travis.yml
index fc5730b..05f3e3f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,7 +16,7 @@ compiler:
matrix:
include:
- - env: jobname=GIT_TEST_GETTEXT_POISON
+ - env: jobname=GETTEXT_POISON
os: linux
compiler:
addons:
@@ -32,7 +32,15 @@ matrix:
services:
- docker
before_install:
- script: ci/run-linux32-docker.sh
+ script: ci/run-docker.sh
+ - env: jobname=linux-musl
+ os: linux
+ compiler:
+ addons:
+ services:
+ - docker
+ before_install:
+ script: ci/run-docker.sh
- env: jobname=StaticAnalysis
os: linux
compiler:
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index ed4e443..45465bc 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -91,16 +91,10 @@ For shell scripts specifically (not exhaustive):
- No shell arrays.
- - No strlen ${#parameter}.
-
- No pattern replacement ${parameter/pattern/string}.
- We use Arithmetic Expansion $(( ... )).
- - Inside Arithmetic Expansion, spell shell variables with $ in front
- of them, as some shells do not grok $((x)) while accepting $(($x))
- just fine (e.g. dash older than 0.5.4).
-
- We do not use Process Substitution <(list) or >(list).
- Do not write control structures on a single line with semicolon.
@@ -238,6 +232,18 @@ For C programs:
while( condition )
func (bar+1);
+ - Do not explicitly compare an integral value with constant 0 or '\0',
+ or a pointer value with constant NULL. For instance, to validate that
+ counted array <ptr, cnt> is initialized but has no elements, write:
+
+ if (!ptr || cnt)
+ BUG("empty array expected");
+
+ and not:
+
+ if (ptr == NULL || cnt != 0);
+ BUG("empty array expected");
+
- We avoid using braces unnecessarily. I.e.
if (bla) {
@@ -483,16 +489,11 @@ For Python scripts:
- We follow PEP-8 (http://www.python.org/dev/peps/pep-0008/).
- - As a minimum, we aim to be compatible with Python 2.6 and 2.7.
+ - As a minimum, we aim to be compatible with Python 2.7.
- Where required libraries do not restrict us to Python 2, we try to
also be compatible with Python 3.1 and later.
- - When you must differentiate between Unicode literals and byte string
- literals, it is OK to use the 'b' prefix. Even though the Python
- documentation for version 2.6 does not mention this prefix, it has
- been supported since version 2.6.0.
-
Error Messages
- Do not end error messages with a full stop.
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 8fe829c..ecd0b34 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -30,6 +30,7 @@ MAN7_TXT += gitcredentials.txt
MAN7_TXT += gitcvs-migration.txt
MAN7_TXT += gitdiffcore.txt
MAN7_TXT += giteveryday.txt
+MAN7_TXT += gitfaq.txt
MAN7_TXT += gitglossary.txt
MAN7_TXT += gitnamespaces.txt
MAN7_TXT += gitremote-helpers.txt
@@ -92,6 +93,7 @@ TECH_DOCS += technical/protocol-capabilities
TECH_DOCS += technical/protocol-common
TECH_DOCS += technical/protocol-v2
TECH_DOCS += technical/racy-git
+TECH_DOCS += technical/reftable
TECH_DOCS += technical/send-pack-pipeline
TECH_DOCS += technical/shallow
TECH_DOCS += technical/signature-format
@@ -149,32 +151,9 @@ endif
-include ../config.mak.autogen
-include ../config.mak
-#
-# For docbook-xsl ...
-# -1.68.1, no extra settings are needed?
-# 1.69.0, set ASCIIDOC_ROFF?
-# 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP?
-# 1.71.1, set ASCIIDOC_ROFF?
-# 1.72.0, set DOCBOOK_XSL_172.
-# 1.73.0-, no extra settings are needed
-#
-
-ifdef DOCBOOK_XSL_172
-ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
-MANPAGE_XSL = manpage-1.72.xsl
-else
- ifndef ASCIIDOC_ROFF
- # docbook-xsl after 1.72 needs the regular XSL, but will not
- # pass-thru raw roff codes from asciidoc.conf, so turn them off.
- ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
- endif
-endif
ifndef NO_MAN_BOLD_LITERAL
XMLTO_EXTRA += -m manpage-bold-literal.xsl
endif
-ifdef DOCBOOK_SUPPRESS_SP
-XMLTO_EXTRA += -m manpage-suppress-sp.xsl
-endif
# Newer DocBook stylesheet emits warning cruft in the output when
# this is not set, and if set it shows an absolute link. Older
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index 427274d..d85c9b5 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -1179,8 +1179,8 @@ look at the section below this one for some context.)
[[after-approval]]
=== After Review Approval
-The Git project has four integration branches: `pu`, `next`, `master`, and
-`maint`. Your change will be placed into `pu` fairly early on by the maintainer
+The Git project has four integration branches: `seen`, `next`, `master`, and
+`maint`. Your change will be placed into `seen` fairly early on by the maintainer
while it is still in the review process; from there, when it is ready for wider
testing, it will be merged into `next`. Plenty of early testers use `next` and
may report issues. Eventually, changes in `next` will make it to `master`,
diff --git a/Documentation/MyFirstObjectWalk.txt b/Documentation/MyFirstObjectWalk.txt
index aa828df..c3f2d1a 100644
--- a/Documentation/MyFirstObjectWalk.txt
+++ b/Documentation/MyFirstObjectWalk.txt
@@ -357,9 +357,6 @@ static void walken_commit_walk(struct rev_info *rev)
...
while ((commit = get_revision(rev))) {
- if (!commit)
- continue;
-
strbuf_reset(&prettybuf);
pp_commit_easy(CMIT_FMT_ONELINE, commit, &prettybuf);
puts(prettybuf.buf);
diff --git a/Documentation/RelNotes/2.27.0.txt b/Documentation/RelNotes/2.27.0.txt
new file mode 100644
index 0000000..15518d0
--- /dev/null
+++ b/Documentation/RelNotes/2.27.0.txt
@@ -0,0 +1,525 @@
+Git 2.27 Release Notes
+======================
+
+Updates since v2.26
+-------------------
+
+Backward compatibility notes
+
+ * When "git describe C" finds that commit C is pointed by a signed or
+ annotated tag, which records T as its tagname in the object, the
+ command gives T as its answer. Even if the user renames or moves
+ such a tag from its natural location in the "refs/tags/" hierarchy,
+ "git describe C" would still give T as the answer, but in such a
+ case "git show T^0" would no longer work as expected. There may be
+ nothing at "refs/tags/T" or even worse there may be a different tag
+ instead.
+
+ Starting from this version, "git describe" will always use the
+ "long" version, as if the "--long" option were given, when giving
+ its output based on such a misplaced tag to work around the problem.
+
+ * "git pull" issues a warning message until the pull.rebase
+ configuration variable is explicitly given, which some existing
+ users may find annoying---those who prefer not to rebase need to
+ set the variable to false to squelch the warning.
+
+ * The transport protocol version 2, which was promoted to the default
+ in Git 2.26 release, turned out to have some remaining rough edges,
+ so it has been demoted from the default.
+
+
+UI, Workflows & Features
+
+ * A handful of options to configure SSL when talking to proxies have
+ been added.
+
+ * Smudge/clean conversion filters are now given more information
+ (e.g. the object of the tree-ish in which the blob being converted
+ appears, in addition to its path, which has already been given).
+
+ * When "git describe C" finds an annotated tag with tagname A to be
+ the best name to explain commit C, and the tag is stored in a
+ "wrong" place in the refs/tags hierarchy, e.g. refs/tags/B, the
+ command gave a warning message but used A (not B) to describe C.
+ If C is exactly at the tag, the describe output would be "A", but
+ "git rev-parse A^0" would not be equal as "git rev-parse C^0". The
+ behavior of the command has been changed to use the "long" form
+ i.e. A-0-gOBJECTNAME, which is correctly interpreted by rev-parse.
+
+ * "git pull" learned to warn when no pull.rebase configuration
+ exists, and neither --[no-]rebase nor --ff-only is given (which
+ would result a merge).
+
+ * "git p4" learned four new hooks and also "--no-verify" option to
+ bypass them (and the existing "p4-pre-submit" hook).
+
+ * "git pull" shares many options with underlying "git fetch", but
+ some of them were not documented and some of those that would make
+ sense to pass down were not passed down.
+
+ * "git rebase" learned the "--no-gpg-sign" option to countermand
+ commit.gpgSign the user may have.
+
+ * The output from "git format-patch" uses RFC 2047 encoding for
+ non-ASCII letters on From: and Subject: headers, so that it can
+ directly be fed to e-mail programs. A new option has been added
+ to produce these headers in raw.
+
+ * "git log" learned "--show-pulls" that helps pathspec limited
+ history views; a merge commit that takes the whole change from a
+ side branch, which is normally omitted from the output, is shown
+ in addition to the commits that introduce real changes.
+
+ * The interactive input from various codepaths are consolidated and
+ any prompt possibly issued earlier are fflush()ed before we read.
+
+ * Allow "git rebase" to reapply all local commits, even if the may be
+ already in the upstream, without checking first.
+
+ * The 'pack.useSparse' configuration variable now defaults to 'true',
+ enabling an optimization that has been experimental since Git 2.21.
+
+ * "git rebase" happens to call some hooks meant for "checkout" and
+ "commit" by this was not a designed behaviour than historical
+ accident. This has been documented.
+
+ * "git merge" learns the "--autostash" option.
+
+ * "sparse-checkout" UI improvements.
+
+ * "git update-ref --stdin" learned a handful of new verbs to let the
+ user control ref update transactions more explicitly, which helps
+ as an ingredient to implement two-phase commit-style atomic
+ ref-updates across multiple repositories.
+
+ * "git commit-graph write" learned different ways to write out split
+ files.
+
+ * Introduce an extension to the commit-graph to make it efficient to
+ check for the paths that were modified at each commit using Bloom
+ filters.
+
+ * The approxidate parser learns to parse seconds with fraction and
+ ignore fractional part.
+
+ * The userdiff patterns for Markdown documents have been added.
+
+ * The sparse-checkout patterns have been forbidden from excluding all
+ paths, leaving an empty working tree, for a long time. This
+ limitation has been lifted.
+
+ * "git restore --staged --worktree" now defaults to take the contents
+ out of "HEAD", instead of erring out.
+
+ * "git p4" learned to recover from a (broken) state where a directory
+ and a file are recorded at the same path in the Perforce repository
+ the same way as their clients do.
+
+ * "git multi-pack-index repack" has been taught to honor some
+ repack.* configuration variables.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The advise API has been revamped to allow more systematic enumeration of
+ advice knobs in the future.
+
+ * SHA-256 transition continues.
+
+ * The code to interface with GnuPG has been refactored.
+
+ * "git stash" has kept an escape hatch to use the scripted version
+ for a few releases, which got stale. It has been removed.
+
+ * Enable tests that require GnuPG on Windows.
+
+ * Minor test usability improvement.
+
+ * Trace2 enhancement to allow logging of the environment variables.
+
+ * Test clean-up continues.
+
+ * Perf-test update.
+
+ * A Windows-specific test element has been made more robust against
+ misuse from both user's environment and programmer's errors.
+
+ * Various tests have been updated to work around issues found with
+ shell utilities that come with busybox etc.
+
+ * The config API made mixed uses of int and size_t types to represent
+ length of various pieces of text it parsed, which has been updated
+ to use the correct type (i.e. size_t) throughout.
+
+ * The "--decorate-refs" and "--decorate-refs-exclude" options "git
+ log" takes have learned a companion configuration variable
+ log.excludeDecoration that sits at the lowest priority in the
+ family.
+
+ * A new CI job to build and run test suite on linux with musl libc
+ has been added.
+
+ * Update the CI configuration to use GitHub Actions, retiring the one
+ based on Azure Pipelines.
+
+ * The directory traversal code had redundant recursive calls which
+ made its performance characteristics exponential with respect to
+ the depth of the tree, which was corrected.
+
+ * "git blame" learns to take advantage of the "changed-paths" Bloom
+ filter stored in the commit-graph file.
+
+ * The "bugreport" tool has been added.
+
+ * The object walk with object filter "--filter=tree:0" can now take
+ advantage of the pack bitmap when available.
+
+ * Instead of always building all branches at GitHub via Actions,
+ users can specify which branches to build.
+
+ * Codepaths that show progress meter have been taught to also use the
+ start_progress() and the stop_progress() calls as a "region" to be
+ traced.
+
+ * Instead of downloading Windows SDK for CI jobs for windows builds
+ from an external site (wingit.blob.core.windows.net), use the one
+ created in the windows-build job, to work around quota issues at
+ the external site.
+
+
+Fixes since v2.26
+-----------------
+
+ * The real_path() convenience function can easily be misused; with a
+ bit of code refactoring in the callers' side, its use has been
+ eliminated.
+ (merge 49d3c4b481 am/real-path-fix later to maint).
+
+ * Update "git p4" to work with Python 3.
+ (merge 6bb40ed20a yz/p4-py3 later to maint).
+
+ * The mechanism to prevent "git commit" from making an empty commit
+ or amending during an interrupted cherry-pick was broken during the
+ rewrite of "git rebase" in C, which has been corrected.
+ (merge 430b75f720 pw/advise-rebase-skip later to maint).
+
+ * Fix "git checkout --recurse-submodules" of a nested submodule
+ hierarchy.
+ (merge 846f34d351 pb/recurse-submodules-fix later to maint).
+
+ * The "--fork-point" mode of "git rebase" regressed when the command
+ was rewritten in C back in 2.20 era, which has been corrected.
+ (merge f08132f889 at/rebase-fork-point-regression-fix later to maint).
+
+ * The import-tars importer (in contrib/fast-import/) used to create
+ phony files at the top-level of the repository when the archive
+ contains global PAX headers, which made its own logic to detect and
+ omit the common leading directory ineffective, which has been
+ corrected.
+ (merge c839fcff65 js/import-tars-do-not-make-phony-files-from-pax-headers later to maint).
+
+ * Simplify the commit ancestry connectedness check in a partial clone
+ repository in which "promised" objects are assumed to be obtainable
+ lazily on-demand from promisor remote repositories.
+ (merge 2b98478c6f jt/connectivity-check-optim-in-partial-clone later to maint).
+
+ * The server-end of the v2 protocol to serve "git clone" and "git
+ fetch" was not prepared to see a delim packets at unexpected
+ places, which led to a crash.
+ (merge cacae4329f jk/harden-protocol-v2-delim-handling later to maint).
+
+ * When fed a midx that records no objects, some codepaths tried to
+ loop from 0 through (num_objects-1), which, due to integer
+ arithmetic wrapping around, made it nonsense operation with out of
+ bounds array accesses. The code has been corrected to reject such
+ an midx file.
+ (merge 796d61cdc0 dr/midx-avoid-int-underflow later to maint).
+
+ * Utitiles run via the run_command() API were not spawned correctly
+ on Cygwin, when the paths to them are given as a full path with
+ backslashes.
+ (merge 05ac8582bc ak/run-command-on-cygwin-fix later to maint).
+
+ * "git pull --rebase" tried to run a rebase even after noticing that
+ the pull results in a fast-forward and no rebase is needed nor
+ sensible, for the past few years due to a mistake nobody noticed.
+ (merge fbae70ddc6 en/pull-do-not-rebase-after-fast-forwarding later to maint).
+
+ * "git rebase" with the merge backend did not work well when the
+ rebase.abbreviateCommands configuration was set.
+ (merge de9f1d3ef4 ag/rebase-merge-allow-ff-under-abbrev-command later to maint).
+
+ * The logic to auto-follow tags by "git clone --single-branch" was
+ not careful to avoid lazy-fetching unnecessary tags, which has been
+ corrected.
+ (merge 167a575e2d jk/use-quick-lookup-in-clone-for-tag-following later to maint).
+
+ * "git rebase -i" did not leave the reflog entries correctly.
+ (merge 1f6965f994 en/sequencer-reflog-action later to maint).
+
+ * The more aggressive updates to remote-tracking branches we had for
+ the past 7 years or so were not reflected in the documentation,
+ which has been corrected.
+ (merge a44088435c pb/pull-fetch-doc later to maint).
+
+ * We've left the command line parsing of "git log :/a/b/" broken for
+ about a full year without anybody noticing, which has been
+ corrected.
+ (merge 0220461071 jc/missing-ref-store-fix later to maint).
+
+ * Misc fixes for Windows.
+ (merge 3efc128cd5 js/mingw-fixes later to maint).
+
+ * "git rebase" (again) learns to honor "--no-keep-empty", which lets
+ the user to discard commits that are empty from the beginning (as
+ opposed to the ones that become empty because of rebasing). The
+ interactive rebase also marks commits that are empty in the todo.
+ (merge 50ed76148a en/rebase-no-keep-empty later to maint).
+
+ * Parsing the host part out of URL for the credential helper has been corrected.
+ (merge 4c5971e18a jk/credential-parsing-end-of-host-in-URL later to maint).
+
+ * Document the recommended way to abort a failing test early (e.g. by
+ exiting a loop), which is to say "return 1".
+ (merge 7cc112dc95 jc/doc-test-leaving-early later to maint).
+
+ * The code that refreshes the last access and modified time of
+ on-disk packfiles and loose object files have been updated.
+ (merge 312cd76130 lr/freshen-file-fix later to maint).
+
+ * Validation of push certificate has been made more robust against
+ timing attacks.
+ (merge 719483e547 bc/constant-memequal later to maint).
+
+ * The custom hash function used by "git fast-import" has been
+ replaced with the one from hashmap.c, which gave us a nice
+ performance boost.
+ (merge d8410a816b jk/fast-import-use-hashmap later to maint).
+
+ * The "git submodule" command did not initialize a few variables it
+ internally uses and was affected by variable settings leaked from
+ the environment.
+ (merge 65d100c4dd lx/submodule-clear-variables later to maint).
+
+ * Raise the minimum required version of docbook-xsl package to 1.74,
+ as 1.74.0 was from late 2008, which is more than 10 years old, and
+ drop compatibility cruft from our documentation suite.
+ (merge 3c255ad660 ma/doc-discard-docbook-xsl-1.73 later to maint).
+
+ * "git log" learns "--[no-]mailmap" as a synonym to "--[no-]use-mailmap"
+ (merge 88acccda38 jc/log-no-mailmap later to maint).
+
+ * "git commit-graph write --expire-time=<timestamp>" did not use the
+ given timestamp correctly, which has been corrected.
+ (merge b09b785c78 ds/commit-graph-expiry-fix later to maint).
+
+ * Tests update to use "test-chmtime" instead of "touch -t".
+ (merge e892a56845 ds/t5319-touch-fix later to maint).
+
+ * "git diff" in a partial clone learned to avoid lazy loading blob
+ objects in more casese when they are not needed.
+ (merge 95acf11a3d jt/avoid-prefetch-when-able-in-diff later to maint).
+
+ * "git push --atomic" used to show failures for refs that weren't
+ even pushed, which has been corrected.
+ (merge dfe1b7f19c jx/atomic-push later to maint).
+
+ * Code in builtin/*, i.e. those can only be called from within
+ built-in subcommands, that implements bulk of a couple of
+ subcommands have been moved to libgit.a so that they could be used
+ by others.
+ (merge 9460fd48b5 dl/libify-a-few later to maint).
+
+ * Allowing the user to split a patch hunk while "git stash -p" does
+ not work well; a band-aid has been added to make this (partially)
+ work better.
+
+ * "git diff-tree --pretty --notes" used to hit an assertion failure,
+ as it forgot to initialize the notes subsystem.
+ (merge 5778b22b3d tb/diff-tree-with-notes later to maint).
+
+ * "git range-diff" fixes.
+ (merge 8d1675eb7f vd/range-diff-with-custom-pretty-format-fix later to maint).
+
+ * "git grep" did not quote a path with unusual character like other
+ commands (like "git diff", "git status") do, but did quote when run
+ from a subdirectory, both of which has been corrected.
+ (merge 45115d8490 mt/grep-cquote-path later to maint).
+
+ * GNU/Hurd is also among the ones that need the fopen() wrapper.
+ (merge 274a1328fb jc/gnu-hurd-lets-fread-read-dirs later to maint).
+
+ * Those fetching over protocol v2 from linux-next and other kernel
+ repositories are reporting that v2 often fetches way too much than
+ needed.
+ (merge 11c7f2a30b jn/demote-proto2-from-default later to maint).
+
+ * The upload-pack protocol v2 gave up too early before finding a
+ common ancestor, resulting in a wasteful fetch from a fork of a
+ project. This has been corrected to match the behaviour of v0
+ protocol.
+ (merge 2f0a093dd6 jt/v2-fetch-nego-fix later to maint).
+
+ * The build procedure did not use the libcurl library and its include
+ files correctly for a custom-built installation.
+ (merge 0573831950 jk/build-with-right-curl later to maint).
+
+ * Tighten "git mailinfo" to notice and error out when decoded result
+ contains NUL in it.
+ (merge 3919997447 dd/mailinfo-with-nul later to maint).
+
+ * Fix in-core inconsistency after fetching into a shallow repository
+ that broke the code to write out commit-graph.
+ (merge 37b9dcabfc tb/reset-shallow later to maint).
+
+ * The commit-graph code exhausted file descriptors easily when it
+ does not have to.
+ (merge c8828530b7 tb/commit-graph-fd-exhaustion-fix later to maint).
+
+ * The multi-pack-index left mmapped file descriptors open when it
+ does not have to.
+ (merge 6c7ff7cf7f ds/multi-pack-index later to maint).
+
+ * Recent update to Homebrew used by macOS folks breaks build by
+ moving gettext library and necessary headers.
+ (merge a0b3108618 ds/build-homebrew-gettext-fix later to maint).
+
+ * Incompatible options "--root" and "--fork-point" of "git rebase"
+ have been marked and documented as being incompatible.
+ (merge a35413c378 en/rebase-root-and-fork-point-are-incompatible later to maint).
+
+ * Error and verbose trace messages from "git push" did not redact
+ credential material embedded in URLs.
+ (merge d192fa5006 js/anonymise-push-url-in-errors later to maint).
+
+ * Update the parser used for credential.<URL>.<variable>
+ configuration, to handle <URL>s with '/' in them correctly.
+ (merge b44d0118ac bc/wildcard-credential later to maint).
+
+ * Recent updates broke parsing of "credential.<url>.<key>" where
+ <url> is not a full URL (e.g. [credential "https://"] helper = ...)
+ stopped working, which has been corrected.
+ (merge 9a121b0d22 js/partial-urlmatch-2.17 later to maint).
+ (merge cd93e6c029 js/partial-urlmatch later to maint).
+
+ * Some of the files commit-graph subsystem keeps on disk did not
+ correctly honor the core.sharedRepository settings and some were
+ left read-write.
+
+ * In error messages that "git switch" mentions its option to create a
+ new branch, "-b/-B" options were shown, where "-c/-C" options
+ should be, which has been corrected.
+ (merge 7c16ef7577 dl/switch-c-option-in-error-message later to maint).
+
+ * With the recent tightening of the code that is used to parse
+ various parts of a URL for use in the credential subsystem, a
+ hand-edited credential-store file causes the credential helper to
+ die, which is a bit too harsh to the users. Demote the error
+ behaviour to just ignore and keep using well-formed lines instead.
+ (merge c03859a665 cb/credential-store-ignore-bogus-lines later to maint).
+
+ * The samples in the credential documentation has been updated to
+ make it clear that we depict what would appear in the .git/config
+ file, by adding appropriate quotes as needed..
+ (merge 177681a07e jk/credential-sample-update later to maint).
+
+ * "git branch" and other "for-each-ref" variants accepted multiple
+ --sort=<key> options in the increasing order of precedence, but it
+ had a few breakages around "--ignore-case" handling, and tie-breaking
+ with the refname, which have been fixed.
+ (merge 7c5045fc18 jk/for-each-ref-multi-key-sort-fix later to maint).
+
+ * The coding guideline for shell scripts instructed to refer to a
+ variable with dollar-sign inside arithmetic expansion to work
+ around a bug in old versions of dash, which is a thing of the past.
+ Now we are not forbidden from writing $((var+1)).
+ (merge 32b5fe7f0e jk/arith-expansion-coding-guidelines later to maint).
+
+ * The <stdlib.h> header on NetBSD brings in its own definition of
+ hmac() function (eek), which conflicts with our own and unrelated
+ function with the same name. Our function has been renamed to work
+ around the issue.
+ (merge 3013118eb8 cb/avoid-colliding-with-netbsd-hmac later to maint).
+
+ * The basic test did not honor $TEST_SHELL_PATH setting, which has
+ been corrected.
+ (merge 0555e4af58 cb/t0000-use-the-configured-shell later to maint).
+
+ * Minor in-code comments and documentation updates around credential
+ API.
+ (merge 1aed817f99 cb/credential-doc-fixes later to maint).
+
+ * Teach "am", "commit", "merge" and "rebase", when they are run with
+ the "--quiet" option, to pass "--quiet" down to "gc --auto".
+ (merge 7c3e9e8cfb jc/auto-gc-quiet later to maint).
+
+ * The code to skip unmerged paths in the index when sparse checkout
+ is in use would have made out-of-bound access of the in-core index
+ when the last path was unmerged, which has been corrected.
+
+ * Serving a "git fetch" client over "git://" and "ssh://" protocols
+ using the on-wire protocol version 2 was buggy on the server end
+ when the client needs to make a follow-up request to
+ e.g. auto-follow tags.
+ (merge 08450ef791 cc/upload-pack-v2-fetch-fix later to maint).
+
+ * "git bisect replay" had trouble with input files when they used
+ CRLF line ending, which has been corrected.
+ (merge 6c722cbe5a cw/bisect-replay-with-dos later to maint).
+
+ * "rebase -i" segfaulted when rearranging a sequence that has a
+ fix-up that applies another fix-up (which may or may not be a
+ fix-up of yet another step).
+ (merge 02471e7e20 js/rebase-autosquash-double-fixup-fix later to maint).
+
+ * "git fsck" ensures that the paths recorded in tree objects are
+ sorted and without duplicates, but it failed to notice a case where
+ a blob is followed by entries that sort before a tree with the same
+ name. This has been corrected.
+ (merge 9068cfb20f rs/fsck-duplicate-names-in-trees later to maint).
+
+ * Code clean-up by removing a compatibility implementation of a
+ function we no longer use.
+ (merge 84b0115f0d cb/no-more-gmtime later to maint).
+
+ * When a binary file gets modified and renamed on both sides of history
+ to different locations, both files would be written to the working
+ tree but both would have the contents from "ours". This has been
+ corrected so that the path from each side gets their original content.
+
+ * Fix for a copy-and-paste error introduced during 2.20 era.
+ (merge e68a5272b1 ds/multi-pack-verify later to maint).
+
+ * Update an unconditional use of "grep -a" with a perl script in a test.
+ (merge 1eb7371236 dd/t5703-grep-a-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 564956f358 jc/maintain-doc later to maint).
+ (merge 7422b2a0a1 sg/commit-slab-clarify-peek later to maint).
+ (merge 9c688735f6 rs/doc-passthru-fetch-options later to maint).
+ (merge 757c2ba3e2 en/oidset-uninclude-hashmap later to maint).
+ (merge 8312aa7d74 jc/config-tar later to maint).
+ (merge d00a5bdd50 ss/submodule-foreach-cb later to maint).
+ (merge 64d1022e14 ar/test-style-fixes later to maint).
+ (merge 4a465443a6 ds/doc-clone-filter later to maint).
+ (merge bb2dbe301b jk/t3419-drop-expensive-tests later to maint).
+ (merge d3507cc712 js/test-junit-finalization-fix later to maint).
+ (merge 2149b6748f bc/faq later to maint).
+ (merge 12dc0879f1 jk/test-cleanup later to maint).
+ (merge 344420bf0f pb/rebase-doc-typofix later to maint).
+ (merge 7cd54d37dc dl/wrapper-fix-indentation later to maint).
+ (merge 78725ebda9 jc/allow-strlen-substitution-in-shell-scripts later to maint).
+ (merge 2ecfcdecc6 jm/gitweb-fastcgi-utf8 later to maint).
+ (merge 0740d0a5d3 jk/oid-array-cleanups later to maint).
+ (merge a1aba0c95c js/t0007-typofix later to maint).
+ (merge 76ba7fa225 ma/config-doc-fix later to maint).
+ (merge 826f0c0df2 js/subtree-doc-update-to-asciidoctor-2 later to maint).
+ (merge 88eaf361e0 eb/mboxrd-doc later to maint).
+ (merge 051cc54941 tm/zsh-complete-switch-restore later to maint).
+ (merge 39102cf4fe ms/doc-revision-illustration-fix later to maint).
+ (merge 4d9378bfad eb/gitweb-more-trailers later to maint).
+ (merge bdccbf7047 mt/doc-worktree-ref later to maint).
+ (merge ce9baf234f dl/push-recurse-submodules-fix later to maint).
+ (merge 4153274052 bc/doc-credential-helper-value later to maint).
+ (merge 5c7bb0146e jc/codingstyle-compare-with-null later to maint).
diff --git a/Documentation/RelNotes/2.28.0.txt b/Documentation/RelNotes/2.28.0.txt
new file mode 100644
index 0000000..6baf781
--- /dev/null
+++ b/Documentation/RelNotes/2.28.0.txt
@@ -0,0 +1,236 @@
+Git 2.28 Release Notes
+======================
+
+Updates since v2.27
+-------------------
+
+Backward compatibility notes
+
+ * "fetch.writeCommitGraph" is deemed to be still a bit too risky and
+ is no longer part of the "feature.experimental" set.
+
+
+UI, Workflows & Features
+
+ * The commands in the "diff" family learned to honor "diff.relative"
+ configuration variable.
+
+ * The check in "git fsck" to ensure that the tree objects are sorted
+ still had corner cases it missed unsorted entries.
+
+ * The interface to redact sensitive information in the trace output
+ has been simplified.
+
+ * The command line completion (in contrib/) learned to complete
+ options that the "git switch" command takes.
+
+ * "git diff" used to take arguments in random and nonsense range
+ notation, e.g. "git diff A..B C", "git diff A..B C...D", etc.,
+ which has been cleaned up.
+
+ * "git diff-files" has been taught to say paths that are marked as
+ intent-to-add are new files, not modified from an empty blob.
+
+ * "git status" learned to report the status of sparse checkout.
+
+ * "git difftool" has trouble dealing with paths added to the index
+ with the intent-to-add bit.
+
+ * "git fast-export --anonymize" learned to take customized mapping to
+ allow its users to tweak its output more usable for debugging.
+
+ * The command line completion support (in contrib/) used to be
+ prepared to work with "set -u" but recent changes got a bit more
+ sloppy. This has been corrected.
+
+ * "git gui" now allows opening work trees from the start-up dialog.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Code optimization for a common case.
+ (merge 8777616e4d an/merge-single-strategy-optim later to maint).
+
+ * We've adopted a convention that any on-stack structure can be
+ initialized to have zero values in all fields with "= { 0 }",
+ even when the first field happens to be a pointer, but sparse
+ complained that a null pointer should be spelled NULL for a long
+ time. Start using -Wno-universal-initializer option to squelch
+ it (the latest sparse has it on by default).
+
+ * "git log -L..." now takes advantage of the "which paths are touched
+ by this commit?" info stored in the commit-graph system.
+
+ * As FreeBSD is not the only platform whose regexp library reports
+ a REG_ILLSEQ error when fed invalid UTF-8, add logic to detect that
+ automatically and skip the affected tests.
+
+ * "git bugreport" learns to report what shell is in use.
+
+ * Support for GIT_CURL_VERBOSE has been rewritten in terms of
+ GIT_TRACE_CURL.
+
+ * Preliminary clean-ups around refs API, plus file format
+ specification documentation for the reftable backend.
+
+ * Workaround breakage in MSVC build, where "curl-config --cflags"
+ gives settings appropriate for GCC build.
+
+ * Code clean-up of "git clean" resulted in a fix of recent
+ performance regression.
+
+ * Code clean-up in the codepath that serves "git fetch" continues.
+
+ * "git merge-base --is-ancestor" is taught to take advantage of the
+ commit graph.
+
+ * Rewrite of parts of the scripted "git submodule" Porcelain command
+ continues; this time it is "git submodule set-branch" subcommand's
+ turn.
+
+ * The "fetch/clone" protocol has been updated to allow the server to
+ instruct the clients to grab pre-packaged packfile(s) in addition
+ to the packed object data coming over the wire.
+
+ * A misdesigned strbuf_write_fd() function has been retired.
+
+ * SHA-256 migration work continues, including CVS/SVN interface.
+
+ * A few fields in "struct commit" that do not have to always be
+ present have been moved to commit slabs.
+
+ * API cleanup for get_worktrees()
+
+ * By renumbering object flag bits, "struct object" managed to lose
+ bloated inter-field padding.
+
+ * The name of the primary branch in existing repositories, and the
+ default name used for the first branch in newly created
+ repositories, is made configurable, so that we can eventually wean
+ ourselves off of the hardcoded 'master'.
+
+ * The effort to avoid using test_must_fail on non-git command continues.
+
+ * In 2.28-rc0, we corrected a bug that some repository extensions are
+ honored by mistake even in a version 0 repositories (these
+ configuration variables in extensions.* namespace were supposed to
+ have special meaning in repositories whose version numbers are 1 or
+ higher), but this was a bit too big a change. The behaviour in
+ recent versions of Git where certain extensions.* were honored by
+ mistake even in version 0 repositories has been restored.
+
+
+Fixes since v2.27
+-----------------
+
+ * The "--prepare-p4-only" option of "git p4" is supposed to stop
+ after replaying one changeset, but kept going (by mistake?)
+
+ * The error message from "git checkout -b foo -t bar baz" was
+ confusing.
+
+ * Some repositories in the wild have commits that record nonsense
+ committer timezone (e.g. rails.git); "git fast-import" learned an
+ option to pass these nonsense timestamps intact to allow recreating
+ existing repositories as-is.
+ (merge d42a2fb72f en/fast-import-looser-date later to maint).
+
+ * The command line completion script (in contrib/) tried to complete
+ "git stash -p" as if it were "git stash push -p", but it was too
+ aggressive and also affected "git stash show -p", which has been
+ corrected.
+ (merge fffd0cf520 vs/complete-stash-show-p-fix later to maint).
+
+ * On-the-wire protocol v2 easily falls into a deadlock between the
+ remote-curl helper and the fetch-pack process when the server side
+ prematurely throws an error and disconnects. The communication has
+ been updated to make it more robust.
+
+ * "git checkout -p" did not handle a newly added path at all.
+ (merge 2c8bd8471a js/checkout-p-new-file later to maint).
+
+ * The code to parse "git bisect start" command line was lax in
+ validating the arguments.
+ (merge 4d9005ff5d cb/bisect-helper-parser-fix later to maint).
+
+ * Reduce memory usage during "diff --quiet" in a worktree with too
+ many stat-unmatched paths.
+ (merge d2d7fbe129 jk/diff-memuse-optim-with-stat-unmatch later to maint).
+
+ * The reflog entries for "git clone" and "git fetch" did not
+ anonymize the URL they operated on.
+ (merge 46da295a77 js/reflog-anonymize-for-clone-and-fetch later to maint).
+
+ * The behaviour of "sparse-checkout" in the state "git clone
+ --no-checkout" left was changed accidentally in 2.27, which has
+ been corrected.
+
+ * Use of negative pathspec, while collecting paths including
+ untracked ones in the working tree, was broken.
+
+ * The same worktree directory must be registered only once, but
+ "git worktree move" allowed this invariant to be violated, which
+ has been corrected.
+ (merge 810382ed37 es/worktree-duplicate-paths later to maint).
+
+ * The effect of sparse checkout settings on submodules is documented.
+ (merge e7d7c73249 en/sparse-with-submodule-doc later to maint).
+
+ * Code clean-up around "git branch" with a minor bugfix.
+ (merge dc44639904 dl/branch-cleanup later to maint).
+
+ * A branch name used in a test has been clarified to match what is
+ going on.
+ (merge 08dc26061f pb/t4014-unslave later to maint).
+
+ * An in-code comment in "git diff" has been updated.
+ (merge c592fd4c83 dl/diff-usage-comment-update later to maint).
+
+ * The documentation and some tests have been adjusted for the recent
+ renaming of "pu" branch to "seen".
+ (merge 6dca5dbf93 js/pu-to-seen later to maint).
+
+ * The code to push changes over "dumb" HTTP had a bad interaction
+ with the commit reachability code due to incorrect allocation of
+ object flag bits, which has been corrected.
+ (merge 64472d15e9 bc/http-push-flagsfix later to maint).
+
+ * "git send-email --in-reply-to=<msg>" did not use the In-Reply-To:
+ header with the value given from the command line, and let it be
+ overridden by the value on In-Reply-To: header in the messages
+ being sent out (if exists).
+ (merge f9f60d7066 ra/send-email-in-reply-to-from-command-line-wins later to maint).
+
+ * "git log -Lx,y:path --before=date" lost track of where the range
+ should be because it didn't take the changes made by the youngest
+ commits that are omitted from the output into account.
+
+ * When "fetch.writeCommitGraph" configuration is set in a shallow
+ repository and a fetch moves the shallow boundary, we wrote out
+ broken commit-graph files that do not match the reality, which has
+ been corrected.
+
+ * "git checkout" failed to catch an error from fstat() after updating
+ a path in the working tree.
+ (merge 35e6e212fd mt/entry-fstat-fallback-fix later to maint).
+
+ * When an aliased command, whose output is piped to a pager by git,
+ gets killed by a signal, the pager got into a funny state, which
+ has been corrected (again).
+ (merge c0d73a59c9 ta/wait-on-aliased-commands-upon-signal later to maint).
+
+ * The code to produce progress output from "git commit-graph --write"
+ had a few breakages, which have been fixed.
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 2c31a7aa44 jx/pkt-line-doc-count-fix later to maint).
+ (merge d63ae31962 cb/t5608-cleanup later to maint).
+ (merge 788db145c7 dl/t-readme-spell-git-correctly later to maint).
+ (merge 45a87a83bb dl/python-2.7-is-the-floor-version later to maint).
+ (merge b75a219904 es/advertise-contribution-doc later to maint).
+ (merge 0c9a4f638a rs/pull-leakfix later to maint).
+ (merge d546fe2874 rs/commit-reach-leakfix later to maint).
+ (merge 087bf5409c mk/pb-pretty-email-without-domain-part-fix later to maint).
+ (merge 5f4ee57ad9 es/worktree-code-cleanup later to maint).
+ (merge 0172f7834a cc/cat-file-usage-update later to maint).
+ (merge 81de0c01cf ma/rebase-doc-typofix later to maint).
diff --git a/Documentation/RelNotes/2.29.0.txt b/Documentation/RelNotes/2.29.0.txt
new file mode 100644
index 0000000..7f6b582
--- /dev/null
+++ b/Documentation/RelNotes/2.29.0.txt
@@ -0,0 +1,77 @@
+Git 2.29 Release Notes
+======================
+
+Updates since v2.28
+-------------------
+
+UI, Workflows & Features
+
+ * "git help log" has been enhanced by sharing more material from the
+ documentation for the underlying "git rev-list" command.
+
+ * "git for-each-ref --format=<>" learned %(contents:size).
+
+ * "git merge" learned to selectively omit " into <branch>" at the end
+ of the title of default merge message with merge.suppressDest
+ configuration.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The changed-path Bloom filter is improved using ideas from an
+ independent implementation.
+
+ * Updates to the changed-paths bloom filter.
+
+ * The test framework has been updated so that most tests will run
+ with predictable (artificial) timestamps.
+
+ * Preliminary clean-up of the refs API in preparation for adding a
+ new refs backend "reftable".
+
+ * Dev support to limit the use of test_must_fail to only git commands.
+
+
+Fixes since v2.28
+-----------------
+
+ * "git clone --separate-git-dir=$elsewhere" used to stomp on the
+ contents of the existing directory $elsewhere, which has been
+ taught to fail when $elsewhere is not an empty directory.
+ (merge dfaa209a79 bw/fail-cloning-into-non-empty later to maint).
+
+
+ * With the base fix to 2.27 regresion, any new extensions in a v0
+ repository would still be silently honored, which is not quite
+ right. Instead, complain and die loudly.
+ (merge ec91ffca04 jk/reject-newer-extensions-in-v0 later to maint).
+
+ * Fetching from a lazily cloned repository resulted at the server
+ side in attempts to lazy fetch objects that the client side has,
+ many of which will not be available from the third-party anyway.
+ (merge 77aa0941ce jt/avoid-lazy-fetching-upon-have-check later to maint).
+
+ * Fix to an ancient bug caused by an over-eager attempt for
+ optimization.
+ (merge a98f7fb366 rs/add-index-entry-optim-fix later to maint).
+
+ * Pushing a ref whose name contains non-ASCII character with the
+ "--force-with-lease" option did not work over smart HTTP protocol,
+ which has been corrected.
+ (merge cd85b447bf bc/push-cas-cquoted-refname later to maint).
+
+ * "git mv src dst", when src is an unmerged path, errored out
+ correctly but with an incorrect error message to claim that src is
+ not tracked, which has been clarified.
+ (merge 9b906af657 ct/mv-unmerged-path-error later to maint).
+
+ * Fix to a regression introduced during 2.27 cycle.
+ (merge cada7308ad en/fill-directory-exponential later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 84544f2ea3 sk/typofixes later to maint).
+ (merge b17f411ab5 ar/help-guides-doc later to maint).
+ (merge 98c6871fad rs/grep-simpler-parse-object-or-die-call later to maint).
+ (merge 861c4ce141 en/typofixes later to maint).
+ (merge 60e47f6773 sg/ci-git-path-fix-with-pyenv later to maint).
+ (merge e2bfa50ac3 jb/doc-packfile-name later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 4515cab..291b61e 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -3,8 +3,9 @@ Submitting Patches
== Guidelines
-Here are some guidelines for people who want to contribute their code
-to this software.
+Here are some guidelines for people who want to contribute their code to this
+software. There is also a link:MyFirstContribution.html[step-by-step tutorial]
+available which covers many of these same guidelines.
[[base-branch]]
=== Decide what to base your work on.
@@ -18,7 +19,7 @@ change is relevant to.
base your work on the tip of the topic.
* A new feature should be based on `master` in general. If the new
- feature depends on a topic that is in `pu`, but not in `master`,
+ feature depends on a topic that is in `seen`, but not in `master`,
base your work on the tip of that topic.
* Corrections and enhancements to a topic not yet in `master` should
@@ -27,7 +28,7 @@ change is relevant to.
into the series.
* In the exceptional case that a new feature depends on several topics
- not in `master`, start working on `next` or `pu` privately and send
+ not in `master`, start working on `next` or `seen` privately and send
out patches for discussion. Before the final merge, you may have to
wait until some of the dependent topics graduate to `master`, and
rebase your work.
@@ -37,7 +38,7 @@ change is relevant to.
these parts should be based on their trees.
To find the tip of a topic branch, run `git log --first-parent
-master..pu` and look for the merge commit. The second parent of this
+master..seen` and look for the merge commit. The second parent of this
commit is the tip of the topic branch.
[[separate-commits]]
@@ -423,7 +424,7 @@ help you find out who they are.
and cooked further and eventually graduates to `master`.
In any time between the (2)-(3) cycle, the maintainer may pick it up
-from the list and queue it to `pu`, in order to make it easier for
+from the list and queue it to `seen`, in order to make it easier for
people play with it without having to pick up and apply the patch to
their trees themselves.
@@ -434,7 +435,7 @@ their trees themselves.
master. `git pull --rebase` will automatically skip already-applied
patches, and will let you know. This works only if you rebase on top
of the branch in which your patch has been merged (i.e. it will not
- tell you if your patch is merged in pu if you rebase on top of
+ tell you if your patch is merged in `seen` if you rebase on top of
master).
* Read the Git mailing list, the maintainer regularly posts messages
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
index 8fc4b67..3e4c139 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf
@@ -31,24 +31,6 @@ ifdef::backend-docbook[]
endif::backend-docbook[]
ifdef::backend-docbook[]
-ifndef::git-asciidoc-no-roff[]
-# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
-# v1.72 breaks with this because it replaces dots not in roff requests.
-[listingblock]
-<example><title>{title}</title>
-<literallayout class="monospaced">
-ifdef::doctype-manpage[]
-&#10;.ft C&#10;
-endif::doctype-manpage[]
-|
-ifdef::doctype-manpage[]
-&#10;.ft&#10;
-endif::doctype-manpage[]
-</literallayout>
-{title#}</example>
-endif::git-asciidoc-no-roff[]
-
-ifdef::git-asciidoc-no-roff[]
ifdef::doctype-manpage[]
# The following two small workarounds insert a simple paragraph after screen
[listingblock]
@@ -67,7 +49,6 @@ ifdef::doctype-manpage[]
{title#}</para></formalpara>
{title%}<simpara></simpara>
endif::doctype-manpage[]
-endif::git-asciidoc-no-roff[]
endif::backend-docbook[]
ifdef::doctype-manpage[]
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 08b13ba..ef0768b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -3,11 +3,12 @@ CONFIGURATION FILE
The Git configuration file contains a number of variables that affect
the Git commands' behavior. The files `.git/config` and optionally
-`config.worktree` (see `extensions.worktreeConfig` below) in each
-repository are used to store the configuration for that repository, and
-`$HOME/.gitconfig` is used to store a per-user configuration as
-fallback values for the `.git/config` file. The file `/etc/gitconfig`
-can be used to store a system-wide default configuration.
+`config.worktree` (see the "CONFIGURATION FILE" section of
+linkgit:git-worktree[1]) in each repository are used to store the
+configuration for that repository, and `$HOME/.gitconfig` is used to
+store a per-user configuration as fallback values for the `.git/config`
+file. The file `/etc/gitconfig` can be used to store a system-wide
+default configuration.
The configuration variables are used by both the Git plumbing
and the porcelains. The variables are divided into sections, wherein
@@ -220,12 +221,12 @@ Example
; affected by the condition
[includeIf "gitdir:/path/to/group/"]
path = foo.inc
-----
- ; include only if we are in a worktree where foo-branch is
- ; currently checked out
- [includeIf "onbranch:foo-branch"]
- path = foo.inc
+; include only if we are in a worktree where foo-branch is
+; currently checked out
+[includeIf "onbranch:foo-branch"]
+ path = foo.inc
+----
Values
~~~~~~
@@ -447,6 +448,8 @@ include::config/submodule.txt[]
include::config/tag.txt[]
+include::config/tar.txt[]
+
include::config/trace2.txt[]
include::config/transfer.txt[]
diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.txt
index 60fb318..9d01641 100644
--- a/Documentation/config/credential.txt
+++ b/Documentation/config/credential.txt
@@ -1,9 +1,13 @@
credential.helper::
Specify an external helper to be called when a username or
password credential is needed; the helper may consult external
- storage to avoid prompting the user for the credentials. Note
- that multiple helpers may be defined. See linkgit:gitcredentials[7]
- for details.
+ storage to avoid prompting the user for the credentials. This is
+ normally the name of a credential helper with possible
+ arguments, but may also be an absolute path with arguments or, if
+ preceded by `!`, shell commands.
++
+Note that multiple helpers may be defined. See linkgit:gitcredentials[7]
+for details and examples.
credential.useHttpPath::
When acquiring credentials, consider the "path" component of an http
diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.txt
index ff09f1c..c3ae136 100644
--- a/Documentation/config/diff.txt
+++ b/Documentation/config/diff.txt
@@ -105,6 +105,10 @@ diff.mnemonicPrefix::
diff.noprefix::
If set, 'git diff' does not show any source or destination prefix.
+diff.relative::
+ If set to 'true', 'git diff' does not show changes outside of the directory
+ and show pathnames relative to the current directory.
+
diff.orderFile::
File indicating how to order files within a diff.
See the '-O' option to linkgit:git-diff[1] for details.
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index 875f8c8..c0cbf2b 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -12,19 +12,12 @@ feature.experimental::
setting if you are interested in providing feedback on experimental
features. The new default values are:
+
-* `pack.useSparse=true` uses a new algorithm when constructing a pack-file
-which can improve `git push` performance in repos with many files.
-+
* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
skipping more commits at a time, reducing the number of round trips.
+
-* `fetch.writeCommitGraph=true` writes a commit-graph after every `git fetch`
-command that downloads a pack-file from a remote. Using the `--split` option,
-most executions will create a very small commit-graph file on top of the
-existing commit-graph file(s). Occasionally, these files will merge and the
-write may take longer. Having an updated commit-graph file helps performance
-of many Git commands, including `git merge-base`, `git push -f`, and
-`git log --graph`.
+* `protocol.version=2` speeds up fetches from repositories with many refs by
+allowing the client to specify which refs to list before the server lists
+them.
feature.manyFiles::
Enable config options that optimize for repos with many files in the
diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt
index f119402..b203940 100644
--- a/Documentation/config/fetch.txt
+++ b/Documentation/config/fetch.txt
@@ -1,11 +1,14 @@
fetch.recurseSubmodules::
- This option can be either set to a boolean value or to 'on-demand'.
+ This option controls whether `git fetch` (and the underlying fetch
+ in `git pull`) will recursively fetch into populated submodules.
+ This option can be set either to a boolean value or to 'on-demand'.
Setting it to a boolean changes the behavior of fetch and pull to
- unconditionally recurse into submodules when set to true or to not
- recurse at all when set to false. When set to 'on-demand' (the default
- value), fetch and pull will only recurse into a populated submodule
- when its superproject retrieves a commit that updates the submodule's
+ recurse unconditionally into submodules when set to true or to not
+ recurse at all when set to false. When set to 'on-demand', fetch and
+ pull will only recurse into a populated submodule when its
+ superproject retrieves a commit that updates the submodule's
reference.
+ Defaults to 'on-demand', or to the value of 'submodule.recurse' if set.
fetch.fsckObjects::
If it is set to true, git-fetch-pack will check all fetched
@@ -87,5 +90,4 @@ fetch.writeCommitGraph::
the existing commit-graph file(s). Occasionally, these files will
merge and the write may take longer. Having an updated commit-graph
file helps performance of many Git commands, including `git merge-base`,
- `git push -f`, and `git log --graph`. Defaults to false, unless
- `feature.experimental` is true.
+ `git push -f`, and `git log --graph`. Defaults to false.
diff --git a/Documentation/config/fmt-merge-msg.txt b/Documentation/config/fmt-merge-msg.txt
index c73cfa9..a8e8f74 100644
--- a/Documentation/config/fmt-merge-msg.txt
+++ b/Documentation/config/fmt-merge-msg.txt
@@ -8,3 +8,15 @@ merge.log::
most the specified number of one-line descriptions from the
actual commits that are being merged. Defaults to false, and
true is a synonym for 20.
+
+merge.suppressDest::
+ By adding a glob that matches the names of integration
+ branches to this multi-valued configuration variable, the
+ default merge message computed for merges into these
+ integration branches will omit " into <branch name>" from
+ its title.
++
+An element with an empty value can be used to clear the list
+of globs accumulated from previous configuration entries.
+When there is no `merge.suppressDest` variable defined, the
+default value of `master` is used for backward compatibility.
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index 45c7bd5..564e809 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -57,6 +57,11 @@ format.suffix::
`.patch`. Use this variable to change that suffix (make sure to
include the dot if you want it).
+format.encodeEmailHeaders::
+ Encode email headers that have non-ASCII characters with
+ "Q-encoding" (described in RFC 2047) for email transmission.
+ Defaults to true.
+
format.pretty::
The default pretty format for log/show/whatchanged command,
See linkgit:git-log[1], linkgit:git-show[1],
diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt
index e806033..3968fbb 100644
--- a/Documentation/config/http.txt
+++ b/Documentation/config/http.txt
@@ -29,6 +29,27 @@ http.proxyAuthMethod::
* `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`)
--
+http.proxySSLCert::
+ The pathname of a file that stores a client certificate to use to authenticate
+ with an HTTPS proxy. Can be overridden by the `GIT_PROXY_SSL_CERT` environment
+ variable.
+
+http.proxySSLKey::
+ The pathname of a file that stores a private key to use to authenticate with
+ an HTTPS proxy. Can be overridden by the `GIT_PROXY_SSL_KEY` environment
+ variable.
+
+http.proxySSLCertPasswordProtected::
+ Enable Git's password prompt for the proxy SSL certificate. Otherwise OpenSSL
+ will prompt the user, possibly many times, if the certificate or private key
+ is encrypted. Can be overriden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
+ environment variable.
+
+http.proxySSLCAInfo::
+ Pathname to the file containing the certificate bundle that should be used to
+ verify the proxy with when using an HTTPS proxy. Can be overriden by the
+ `GIT_PROXY_SSL_CAINFO` environment variable.
+
http.emptyAuth::
Attempt authentication without seeking a username or password. This
can be used to attempt GSS-Negotiate authentication without specifying
diff --git a/Documentation/config/init.txt b/Documentation/config/init.txt
index 46fa8c6..dc77f8c 100644
--- a/Documentation/config/init.txt
+++ b/Documentation/config/init.txt
@@ -1,3 +1,7 @@
init.templateDir::
Specify the directory from which templates will be copied.
(See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
+
+init.defaultBranch::
+ Allows overriding the default branch name e.g. when initializing
+ a new repository or when cloning an empty repository.
diff --git a/Documentation/config/log.txt b/Documentation/config/log.txt
index e9e1e39..208d5fd 100644
--- a/Documentation/config/log.txt
+++ b/Documentation/config/log.txt
@@ -18,6 +18,12 @@ log.decorate::
names are shown. This is the same as the `--decorate` option
of the `git log`.
+log.excludeDecoration::
+ Exclude the specified patterns from the log decorations. This is
+ similar to the `--decorate-refs-exclude` command-line option, but
+ the config option can be overridden by the `--decorate-refs`
+ option.
+
log.follow::
If `true`, `git log` will act as if the `--follow` option was used when
a single <path> is given. This has the same limitations as `--follow`,
diff --git a/Documentation/config/merge.txt b/Documentation/config/merge.txt
index 6a31393..cb2ed58 100644
--- a/Documentation/config/merge.txt
+++ b/Documentation/config/merge.txt
@@ -70,6 +70,16 @@ merge.stat::
Whether to print the diffstat between ORIG_HEAD and the merge result
at the end of the merge. True by default.
+merge.autoStash::
+ When set to true, automatically create a temporary stash entry
+ before the operation begins, and apply it after the operation
+ ends. This means that you can run merge on a dirty worktree.
+ However, use with care: the final stash application after a
+ successful merge might result in non-trivial conflicts.
+ This option can be overridden by the `--no-autostash` and
+ `--autostash` options of linkgit:git-merge[1].
+ Defaults to false.
+
merge.tool::
Controls which merge tool is used by linkgit:git-mergetool[1].
The list below shows the valid built-in values.
diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.txt
index 0dac580..837f1b1 100644
--- a/Documentation/config/pack.txt
+++ b/Documentation/config/pack.txt
@@ -119,8 +119,8 @@ pack.useSparse::
objects. This can have significant performance benefits when
computing a pack to send a small change. However, it is possible
that extra objects are added to the pack-file if the included
- commits contain certain types of direct renames. Default is `false`
- unless `feature.experimental` is enabled.
+ commits contain certain types of direct renames. Default is
+ `true`.
pack.writeBitmaps (deprecated)::
This is a deprecated synonym for `repack.writeBitmaps`.
diff --git a/Documentation/config/protocol.txt b/Documentation/config/protocol.txt
index 756591d..c46e9b3 100644
--- a/Documentation/config/protocol.txt
+++ b/Documentation/config/protocol.txt
@@ -48,7 +48,8 @@ protocol.version::
If set, clients will attempt to communicate with a server
using the specified protocol version. If the server does
not support it, communication falls back to version 0.
- If unset, the default is `2`.
+ If unset, the default is `0`, unless `feature.experimental`
+ is enabled, in which case the default is `2`.
Supported versions:
+
--
diff --git a/Documentation/config/push.txt b/Documentation/config/push.txt
index 0a7aa32..f5e5b38 100644
--- a/Documentation/config/push.txt
+++ b/Documentation/config/push.txt
@@ -112,3 +112,5 @@ push.recurseSubmodules::
is 'no' then default behavior of ignoring submodules when pushing
is retained. You may override this configuration at time of push by
specifying '--recurse-submodules=check|on-demand|no'.
+ If not set, 'no' is used by default, unless 'submodule.recurse' is
+ set (in which case a 'true' value means 'on-demand').
diff --git a/Documentation/config/stash.txt b/Documentation/config/stash.txt
index abc7ef4..00eb354 100644
--- a/Documentation/config/stash.txt
+++ b/Documentation/config/stash.txt
@@ -1,17 +1,9 @@
stash.useBuiltin::
- Set to `false` to use the legacy shell script implementation of
- linkgit:git-stash[1]. Is `true` by default, which means use
- the built-in rewrite of it in C.
-+
-The C rewrite is first included with Git version 2.22 (and Git for Windows
-version 2.19). This option serves as an escape hatch to re-enable the
-legacy version in case any bugs are found in the rewrite. This option and
-the shell script version of linkgit:git-stash[1] will be removed in some
-future release.
-+
-If you find some reason to set this option to `false`, other than
-one-off testing, you should report the behavior difference as a bug in
-Git (see https://git-scm.com/community for details).
+ Unused configuration variable. Used in Git versions 2.22 to
+ 2.26 as an escape hatch to enable the legacy shellscript
+ implementation of stash. Now the built-in rewrite of it in C
+ is always used. Setting this will emit a warning, to alert any
+ remaining users that setting this now does nothing.
stash.showPatch::
If this is set to true, the `git stash show` command without an
diff --git a/Documentation/config/submodule.txt b/Documentation/config/submodule.txt
index b331771..d7a63c8 100644
--- a/Documentation/config/submodule.txt
+++ b/Documentation/config/submodule.txt
@@ -59,9 +59,17 @@ submodule.active::
submodule.recurse::
Specifies if commands recurse into submodules by default. This
- applies to all commands that have a `--recurse-submodules` option,
- except `clone`.
+ applies to all commands that have a `--recurse-submodules` option
+ (`checkout`, `fetch`, `grep`, `pull`, `push`, `read-tree`, `reset`,
+ `restore` and `switch`) except `clone` and `ls-files`.
Defaults to false.
+ When set to true, it can be deactivated via the
+ `--no-recurse-submodules` option. Note that some Git commands
+ lacking this option may call some of the above commands affected by
+ `submodule.recurse`; for instance `git remote update` will call
+ `git fetch` but does not have a `--no-recurse-submodules` option.
+ For these commands a workaround is to temporarily change the
+ configuration value by using `git -c submodule.recurse=0`.
submodule.fetchJobs::
Specifies how many submodules are fetched/cloned at the same time.
diff --git a/Documentation/config/tag.txt b/Documentation/config/tag.txt
index 6d9110d..5062a05 100644
--- a/Documentation/config/tag.txt
+++ b/Documentation/config/tag.txt
@@ -15,10 +15,3 @@ tag.gpgSign::
convenient to use an agent to avoid typing your gpg passphrase
several times. Note that this option doesn't affect tag signing
behavior enabled by "-u <keyid>" or "--local-user=<keyid>" options.
-
-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) and
- linkgit:git-archive[1].
diff --git a/Documentation/config/tar.txt b/Documentation/config/tar.txt
new file mode 100644
index 0000000..de8ff48
--- /dev/null
+++ b/Documentation/config/tar.txt
@@ -0,0 +1,6 @@
+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) and
+ linkgit:git-archive[1].
diff --git a/Documentation/config/trace2.txt b/Documentation/config/trace2.txt
index 4ce0b9a..01d3afd 100644
--- a/Documentation/config/trace2.txt
+++ b/Documentation/config/trace2.txt
@@ -48,6 +48,15 @@ trace2.configParams::
May be overridden by the `GIT_TRACE2_CONFIG_PARAMS` environment
variable. Unset by default.
+trace2.envVars::
+ A comma-separated list of "important" environment variables that should
+ be recorded in the trace2 output. For example,
+ `GIT_HTTP_USER_AGENT,GIT_CONFIG` would cause the trace2 output to
+ contain events listing the overrides for HTTP user agent and the
+ location of the Git configuration file (assuming any are set). May be
+ overriden by the `GIT_TRACE2_ENV_VARS` environment variable. Unset by
+ default.
+
trace2.destinationDebug::
Boolean. When true Git will print error messages when a
trace target destination cannot be opened for writing.
diff --git a/Documentation/date-formats.txt b/Documentation/date-formats.txt
index 6926e0a..f1097fa 100644
--- a/Documentation/date-formats.txt
+++ b/Documentation/date-formats.txt
@@ -20,7 +20,9 @@ RFC 2822::
ISO 8601::
Time and date specified by the ISO 8601 standard, for example
`2005-04-07T22:13:13`. The parser accepts a space instead of the
- `T` character as well.
+ `T` character as well. Fractional parts of a second will be ignored,
+ for example `2005-04-07T22:13:13.019` will be treated as
+ `2005-04-07T22:13:13`.
+
NOTE: In addition, the date part is accepted in the following formats:
`YYYY.MM.DD`, `MM/DD/YYYY` and `DD.MM.YYYY`.
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index bb31f0c..7987d72 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -643,15 +643,18 @@ ifndef::git-format-patch[]
-R::
Swap two inputs; that is, show differences from index or
on-disk file to tree contents.
+endif::git-format-patch[]
--relative[=<path>]::
+--no-relative::
When run from a subdirectory of the project, it can be
told to exclude changes outside the directory and show
pathnames relative to it with this option. When you are
not in a subdirectory (e.g. in a bare repository), you
can name which subdirectory to make the output relative
to by giving a <path> as an argument.
-endif::git-format-patch[]
+ `--no-relative` can be used to countermand both `diff.relative` config
+ option and previous `--relative`.
-a::
--text::
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index a115a1a..6e2a160 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -61,10 +61,8 @@ this option multiple times, one for each matching ref name.
See also the `fetch.negotiationAlgorithm` configuration variable
documented in linkgit:git-config[1].
-ifndef::git-pull[]
--dry-run::
Show what would be done, without making any changes.
-endif::git-pull[]
-f::
--force::
@@ -95,6 +93,7 @@ ifndef::git-pull[]
--[no-]write-commit-graph::
Write a commit-graph after fetching. This overrides the config
setting `fetch.writeCommitGraph`.
+endif::git-pull[]
-p::
--prune::
@@ -107,6 +106,7 @@ ifndef::git-pull[]
was cloned with the --mirror option), then they are also
subject to pruning. Supplying `--prune-tags` is a shorthand for
providing the tag refspec.
+ifndef::git-pull[]
+
See the PRUNING section below for more details.
@@ -133,7 +133,6 @@ endif::git-pull[]
behavior for a remote may be specified with the remote.<name>.tagOpt
setting. See linkgit:git-config[1].
-ifndef::git-pull[]
--refmap=<refspec>::
When fetching refs listed on the command line, use the
specified refspec (can be given more than once) to map the
@@ -154,6 +153,7 @@ ifndef::git-pull[]
is used (though tags may be pruned anyway if they are also the
destination of an explicit refspec; see `--prune`).
+ifndef::git-pull[]
--recurse-submodules[=yes|on-demand|no]::
This option controls if and under what conditions new commits of
populated submodules should be fetched too. It can be used as a
@@ -163,7 +163,9 @@ ifndef::git-pull[]
value. Use 'on-demand' to only recurse into a populated submodule
when the superproject retrieves a commit that updates the submodule's
reference to a commit that isn't already in the local submodule
- clone.
+ clone. By default, 'on-demand' is used, unless
+ `fetch.recurseSubmodules` is set (see linkgit:git-config[1]).
+endif::git-pull[]
-j::
--jobs=<n>::
@@ -177,9 +179,11 @@ parallel. To control them independently, use the config settings
Typically, parallel recursive and multi-remote fetches will be faster. By
default fetches are performed sequentially, not in parallel.
+ifndef::git-pull[]
--no-recurse-submodules::
Disable recursive fetching of submodules (this has the same effect as
using the `--recurse-submodules=no` option).
+endif::git-pull[]
--set-upstream::
If the remote is fetched successfully, pull and add upstream
@@ -188,6 +192,7 @@ default fetches are performed sequentially, not in parallel.
see `branch.<name>.merge` and `branch.<name>.remote` in
linkgit:git-config[1].
+ifndef::git-pull[]
--submodule-prefix=<path>::
Prepend <path> to paths printed in informative messages
such as "Fetching submodule foo". This option is used
@@ -200,7 +205,6 @@ default fetches are performed sequentially, not in parallel.
recursion (such as settings in linkgit:gitmodules[5] and
linkgit:git-config[1]) override this option, as does
specifying --[no-]recurse-submodules directly.
-endif::git-pull[]
-u::
--update-head-ok::
@@ -210,6 +214,7 @@ endif::git-pull[]
to communicate with 'git fetch', and unless you are
implementing your own Porcelain you are not supposed to
use it.
+endif::git-pull[]
--upload-pack <upload-pack>::
When given, and the repository to fetch from is handled
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index ab5754e..38c0852 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -148,9 +148,12 @@ default. You can use `--no-utf8` to override this.
-S[<keyid>]::
--gpg-sign[=<keyid>]::
+--no-gpg-sign::
GPG-sign commits. The `keyid` argument is optional and
defaults to the committer identity; if specified, it must be
- stuck to the option without a space.
+ stuck to the option without a space. `--no-gpg-sign` is useful to
+ countermand both `commit.gpgSign` configuration variable, and
+ earlier `--gpg-sign`.
--continue::
-r::
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 135206f..03c0824 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -12,7 +12,7 @@ SYNOPSIS
[-v [--abbrev=<length> | --no-abbrev]]
[--column[=<options>] | --no-column] [--sort=<key>]
[(--merged | --no-merged) [<commit>]]
- [--contains [<commit]] [--no-contains [<commit>]]
+ [--contains [<commit>]] [--no-contains [<commit>]]
[--points-at <object>] [--format=<format>]
[(-r | --remotes) | (-a | --all)]
[--list] [<pattern>...]
diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
new file mode 100644
index 0000000..66e88c2
--- /dev/null
+++ b/Documentation/git-bugreport.txt
@@ -0,0 +1,54 @@
+git-bugreport(1)
+================
+
+NAME
+----
+git-bugreport - Collect information for user to file a bug report
+
+SYNOPSIS
+--------
+[verse]
+'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
+
+DESCRIPTION
+-----------
+Captures information about the user's machine, Git client, and repository state,
+as well as a form requesting information about the behavior the user observed,
+into a single text file which the user can then share, for example to the Git
+mailing list, in order to report an observed bug.
+
+The following information is requested from the user:
+
+ - Reproduction steps
+ - Expected behavior
+ - Actual behavior
+
+The following information is captured automatically:
+
+ - 'git version --build-options'
+ - uname sysname, release, version, and machine strings
+ - Compiler-specific info string
+ - A list of enabled hooks
+ - $SHELL
+
+This tool is invoked via the typical Git setup process, which means that in some
+cases, it might not be able to launch - for example, if a relevant config file
+is unreadable. In this kind of scenario, it may be helpful to manually gather
+the kind of information listed above when manually asking for help.
+
+OPTIONS
+-------
+-o <path>::
+--output-directory <path>::
+ Place the resulting bug report file in `<path>` instead of the root of
+ the Git repository.
+
+-s <format>::
+--suffix <format>::
+ Specify an alternate suffix for the bugreport name, to create a file
+ named 'git-bugreport-<formatted suffix>'. This should take the form of a
+ strftime(3) format string; the current local time will be used.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 8eca671..8e192d8 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--path=<path>] <object>
-'git cat-file' (--batch | --batch-check) [ --textconv | --filters ] [--follow-symlinks]
+'git cat-file' (--batch[=<format>] | --batch-check[=<format>]) [ --textconv | --filters ] [--follow-symlinks]
DESCRIPTION
-----------
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index c8fb995..5b697ee 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -292,11 +292,11 @@ Note that this option uses the no overlay mode by default (see also
--recurse-submodules::
--no-recurse-submodules::
- Using `--recurse-submodules` will update the content of all initialized
+ Using `--recurse-submodules` will update the content of all active
submodules according to the commit recorded in the superproject. If
local modifications in a submodule would be overwritten the checkout
will fail unless `-f` is used. If nothing (or `--no-recurse-submodules`)
- is used, the work trees of submodules will not be updated.
+ is used, submodules working trees will not be updated.
Just like linkgit:git-submodule[1], this will detach `HEAD` of the
submodule.
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 83ce51a..75feeef 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -109,9 +109,12 @@ effect to your index in a row.
-S[<keyid>]::
--gpg-sign[=<keyid>]::
+--no-gpg-sign::
GPG-sign commits. The `keyid` argument is optional and
defaults to the committer identity; if specified, it must be
- stuck to the option without a space.
+ stuck to the option without a space. `--no-gpg-sign` is useful to
+ countermand both `commit.gpgSign` configuration variable, and
+ earlier `--gpg-sign`.
--ff::
If the current HEAD is the same as the parent of the
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index bf24f18..c898310 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -15,7 +15,8 @@ SYNOPSIS
[--dissociate] [--separate-git-dir <git dir>]
[--depth <depth>] [--[no-]single-branch] [--no-tags]
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
- [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--] <repository>
+ [--[no-]remote-submodules] [--jobs <n>] [--sparse]
+ [--filter=<filter>] [--] <repository>
[<directory>]
DESCRIPTION
@@ -162,6 +163,16 @@ objects from the source repository into a pack in the cloned repository.
of the repository. The sparse-checkout file can be
modified to grow the working directory as needed.
+--filter=<filter-spec>::
+ Use the partial clone feature and request that the server sends
+ a subset of reachable objects according to a given object filter.
+ When using `--filter`, the supplied `<filter-spec>` is used for
+ the partial clone filter. For example, `--filter=blob:none` will
+ filter out all blobs (file contents) until needed by Git. Also,
+ `--filter=blob:limit=<size>` will filter out all blobs of size
+ at least `<size>`. For more details on filter specifications, see
+ the `--filter` option in linkgit:git-rev-list[1].
+
--mirror::
Set up a mirror of the source repository. This implies `--bare`.
Compared to `--bare`, `--mirror` not only maps local branches of the
@@ -248,7 +259,7 @@ maintain a branch with no references other than a single cloned
branch. This is useful e.g. to maintain minimal clones of the default
branch of some repository for search indexing.
---recurse-submodules[=<pathspec]::
+--recurse-submodules[=<pathspec>]::
After the clone is created, initialize and clone submodules
within based on the provided pathspec. If no pathspec is
provided, all submodules are initialized and cloned.
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index 28d1fee..17405c7 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -47,8 +47,10 @@ with `--stdin-commits` or `--reachable`.)
+
With the `--stdin-commits` option, generate the new commit graph by
walking commits starting at the commits specified in stdin as a list
-of OIDs in hex, one OID per line. (Cannot be combined with
-`--stdin-packs` or `--reachable`.)
+of OIDs in hex, one OID per line. OIDs that resolve to non-commits
+(either directly, or by peeling tags) are silently ignored. OIDs that
+are malformed, or do not exist generate an error. (Cannot be combined
+with `--stdin-packs` or `--reachable`.)
+
With the `--reachable` option, generate the new commit graph by walking
commits starting at all refs. (Cannot be combined with `--stdin-commits`
@@ -57,11 +59,27 @@ or `--stdin-packs`.)
With the `--append` option, include all commits that are present in the
existing commit-graph file.
+
-With the `--split` option, write the commit-graph as a chain of multiple
-commit-graph files stored in `<dir>/info/commit-graphs`. The new commits
-not already in the commit-graph are added in a new "tip" file. This file
-is merged with the existing file if the following merge conditions are
-met:
+With the `--changed-paths` option, compute and write information about the
+paths changed between a commit and its first parent. This operation can
+take a while on large repositories. It provides significant performance gains
+for getting history of a directory or a file with `git log -- <path>`. If
+this option is given, future commit-graph writes will automatically assume
+that this option was intended. Use `--no-changed-paths` to stop storing this
+data.
++
+With the `--split[=<strategy>]` option, write the commit-graph as a
+chain of multiple commit-graph files stored in
+`<dir>/info/commit-graphs`. Commit-graph layers are merged based on the
+strategy and other splitting options. The new commits not already in the
+commit-graph are added in a new "tip" file. This file is merged with the
+existing file if the following merge conditions are met:
++
+* If `--split=no-merge` is specified, a merge is never performed, and
+the remaining options are ignored. `--split=replace` overwrites the
+existing chain with a new one. A bare `--split` defers to the remaining
+options. (Note that merging a chain of commit graphs replaces the
+existing chain with a length-1 chain where the first and only
+incremental holds the entire graph).
+
* If `--size-multiple=<X>` is not specified, let `X` equal 2. If the new
tip file would have `N` commits and the previous tip has `M` commits and
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index ec15ee8..2e2c581 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -61,13 +61,11 @@ OPTIONS
-S[<keyid>]::
--gpg-sign[=<keyid>]::
+--no-gpg-sign::
GPG-sign commits. The `keyid` argument is optional and
defaults to the committer identity; if specified, it must be
- stuck to the option without a space.
-
---no-gpg-sign::
- Do not GPG-sign commit, to countermand a `--gpg-sign` option
- given earlier on the command line.
+ stuck to the option without a space. `--no-gpg-sign` is useful to
+ countermand a `--gpg-sign` option given earlier on the command line.
Commit Information
------------------
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 13f6539..a3baea3 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -348,13 +348,12 @@ changes to tracked files.
-S[<keyid>]::
--gpg-sign[=<keyid>]::
+--no-gpg-sign::
GPG-sign commits. The `keyid` argument is optional and
defaults to the committer identity; if specified, it must be
- stuck to the option without a space.
-
---no-gpg-sign::
- Countermand `commit.gpgSign` configuration variable that is
- set to force each and every commit to be signed.
+ stuck to the option without a space. `--no-gpg-sign` is useful to
+ countermand both `commit.gpgSign` configuration variable, and
+ earlier `--gpg-sign`.
\--::
Do not interpret any more arguments as options.
diff --git a/Documentation/git-credential-store.txt b/Documentation/git-credential-store.txt
index 693dd9d..76b0798 100644
--- a/Documentation/git-credential-store.txt
+++ b/Documentation/git-credential-store.txt
@@ -94,6 +94,10 @@ stored on its own line as a URL like:
https://user:pass@example.com
------------------------------
+No other kinds of lines (e.g. empty lines or comment lines) are
+allowed in the file, even though some may be silently ignored. Do
+not view or edit the file with editors.
+
When Git needs authentication for a particular URL context,
credential-store will consider that context a pattern to match against
each entry in the credentials file. If the protocol, hostname, and
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index 6f0c7ca..31c81c4 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -103,17 +103,20 @@ INPUT/OUTPUT FORMAT
`git credential` reads and/or writes (depending on the action used)
credential information in its standard input/output. This information
can correspond either to keys for which `git credential` will obtain
-the login/password information (e.g. host, protocol, path), or to the
-actual credential data to be obtained (login/password).
+the login information (e.g. host, protocol, path), or to the actual
+credential data to be obtained (username/password).
The credential is split into a set of named attributes, with one
-attribute per line. Each attribute is
-specified by a key-value pair, separated by an `=` (equals) sign,
-followed by a newline. The key may contain any bytes except `=`,
-newline, or NUL. The value may contain any bytes except newline or NUL.
+attribute per line. Each attribute is specified by a key-value pair,
+separated by an `=` (equals) sign, followed by a newline.
+
+The key may contain any bytes except `=`, newline, or NUL. The value may
+contain any bytes except newline or NUL.
+
In both cases, all bytes are treated as-is (i.e., there is no quoting,
and one cannot transmit a value with newline or NUL in it). The list of
attributes is terminated by a blank line or end-of-file.
+
Git understands the following attributes:
`protocol`::
@@ -123,7 +126,8 @@ Git understands the following attributes:
`host`::
- The remote hostname for a network credential.
+ The remote hostname for a network credential. This includes
+ the port number if one was specified (e.g., "example.com:8088").
`path`::
@@ -134,7 +138,7 @@ Git understands the following attributes:
`username`::
The credential's username, if we already have one (e.g., from a
- URL, from the user, or from a previously run helper).
+ URL, the configuration, the user, or from a previously run helper).
`password`::
@@ -146,8 +150,12 @@ Git understands the following attributes:
value is parsed as a URL and treated as if its constituent parts
were read (e.g., `url=https://example.com` would behave as if
`protocol=https` and `host=example.com` had been provided). This
- can help callers avoid parsing URLs themselves. Note that any
- components which are missing from the URL (e.g., there is no
- username in the example above) will be set to empty; if you want
- to provide a URL and override some attributes, provide the URL
- attribute first, followed by any overrides.
+ can help callers avoid parsing URLs themselves.
++
+Note that specifying a protocol is mandatory and if the URL
+doesn't specify a hostname (e.g., "cert:///path/to/file") the
+credential will contain a hostname attribute whose value is an
+empty string.
++
+Components which are missing from the URL (e.g., there is no
+username in the example above) will be left unset.
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 37781cf..727f24d 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -11,15 +11,17 @@ SYNOPSIS
[verse]
'git diff' [<options>] [<commit>] [--] [<path>...]
'git diff' [<options>] --cached [<commit>] [--] [<path>...]
-'git diff' [<options>] <commit> <commit> [--] [<path>...]
+'git diff' [<options>] <commit> [<commit>...] <commit> [--] [<path>...]
+'git diff' [<options>] <commit>...<commit> [--] [<path>...]
'git diff' [<options>] <blob> <blob>
'git diff' [<options>] --no-index [--] <path> <path>
DESCRIPTION
-----------
Show changes between the working tree and the index or a tree, changes
-between the index and a tree, changes between two trees, changes between
-two blob objects, or changes between two files on disk.
+between the index and a tree, changes between two trees, changes resulting
+from a merge, changes between two blob objects, or changes between two
+files on disk.
'git diff' [<options>] [--] [<path>...]::
@@ -61,9 +63,19 @@ two blob objects, or changes between two files on disk.
This is to view the changes between two arbitrary
<commit>.
+'git diff' [<options>] <commit> <commit>... <commit> [--] [<path>...]::
+
+ This form is to view the results of a merge commit. The first
+ listed <commit> must be the merge itself; the remaining two or
+ more commits should be its parents. A convenient way to produce
+ the desired set of revisions is to use the {caret}@ suffix.
+ For instance, if `master` names a merge commit, `git diff master
+ master^@` gives the same combined diff as `git show master`.
+
'git diff' [<options>] <commit>..<commit> [--] [<path>...]::
- This is synonymous to the previous form. If <commit> on
+ This is synonymous to the earlier form (without the "..") for
+ viewing the changes between two arbitrary <commit>. If <commit> on
one side is omitted, it will have the same effect as
using HEAD instead.
@@ -196,7 +208,8 @@ linkgit:git-difftool[1],
linkgit:git-log[1],
linkgit:gitdiffcore[7],
linkgit:git-format-patch[1],
-linkgit:git-apply[1]
+linkgit:git-apply[1],
+linkgit:git-show[1]
GIT
---
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index e8950de..1978dbd 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -119,6 +119,11 @@ by keeping the marks the same across runs.
the shape of the history and stored tree. See the section on
`ANONYMIZING` below.
+--anonymize-map=<from>[:<to>]::
+ Convert token `<from>` to `<to>` in the anonymized output. If
+ `<to>` is omitted, map `<from>` to itself (i.e., do not
+ anonymize it). See the section on `ANONYMIZING` below.
+
--reference-excluded-parents::
By default, running a command such as `git fast-export
master~5..master` will not include the commit master{tilde}5
@@ -238,6 +243,30 @@ collapse "User 0", "User 1", etc into "User X"). This produces a much
smaller output, and it is usually easy to quickly confirm that there is
no private data in the stream.
+Reproducing some bugs may require referencing particular commits or
+paths, which becomes challenging after refnames and paths have been
+anonymized. You can ask for a particular token to be left as-is or
+mapped to a new value. For example, if you have a bug which reproduces
+with `git rev-list sensitive -- secret.c`, you can run:
+
+---------------------------------------------------
+$ git fast-export --anonymize --all \
+ --anonymize-map=sensitive:foo \
+ --anonymize-map=secret.c:bar.c \
+ >stream
+---------------------------------------------------
+
+After importing the stream, you can then run `git rev-list foo -- bar.c`
+in the anonymized repository.
+
+Note that paths and refnames are split into tokens at slash boundaries.
+The command above would anonymize `subdir/secret.c` as something like
+`path123/bar.c`; you could then search for `bar.c` in the anonymized
+repository to determine the final pathname.
+
+To make referencing the final pathname simpler, you can map each path
+component; so if you also anonymize `subdir` to `publicdir`, then the
+final pathname would be `publicdir/bar.c`.
LIMITATIONS
-----------
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 7889f95..7d9aad2 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -122,6 +122,26 @@ Locations of Marks Files
Relative and non-relative marks may be combined by interweaving
--(no-)-relative-marks with the --(import|export)-marks= options.
+Submodule Rewriting
+~~~~~~~~~~~~~~~~~~~
+
+--rewrite-submodules-from=<name>:<file>::
+--rewrite-submodules-to=<name>:<file>::
+ Rewrite the object IDs for the submodule specified by <name> from the values
+ used in the from <file> to those used in the to <file>. The from marks should
+ have been created by `git fast-export`, and the to marks should have been
+ created by `git fast-import` when importing that same submodule.
++
+<name> may be any arbitrary string not containing a colon character, but the
+same value must be used with both options when specifying corresponding marks.
+Multiple submodules may be specified with different values for <name>. It is an
+error not to use these options in corresponding pairs.
++
+These options are primarily useful when converting a repository from one hash
+algorithm to another; without them, fast-import will fail if it encounters a
+submodule because it has no way of writing the object ID into the new hash
+algorithm.
+
Performance and Compression Tuning
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -273,7 +293,14 @@ 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
-variation in formatting will cause fast-import to reject the value.
+variation in formatting will cause fast-import to reject the value,
+and some sanity checks on the numeric values may also be performed.
+
+`raw-permissive`::
+ This is the same as `raw` except that no sanity checks on
+ the numeric epoch and local offset are performed. This can
+ be useful when trying to filter or import an existing history
+ with e.g. bogus timezone values.
`rfc2822`::
This is the standard email format as described by RFC 2822.
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index 5b1909f..45b6d8e 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -255,14 +255,14 @@ refspec.
* Using refspecs explicitly:
+
------------------------------------------------
-$ git fetch origin +pu:pu maint:tmp
+$ git fetch origin +seen:seen maint:tmp
------------------------------------------------
+
-This updates (or creates, as necessary) branches `pu` and `tmp` in
+This updates (or creates, as necessary) branches `seen` and `tmp` in
the local repository by fetching from the branches (respectively)
-`pu` and `maint` from the remote repository.
+`seen` and `maint` from the remote repository.
+
-The `pu` branch will be updated even if it does not fast-forward,
+The `seen` branch will be updated even if it does not fast-forward,
because it is prefixed with a plus sign; `tmp` will not be.
* Peek at a remote's branch, without configuring the remote in your local
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 6dcd39f..2ea71c5 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -232,12 +232,27 @@ Fields that have name-email-date tuple as its value (`author`,
`committer`, and `tagger`) can be suffixed with `name`, `email`,
and `date` to extract the named component.
-The complete message in a commit and tag object is `contents`.
-Its first line is `contents:subject`, where subject is the concatenation
-of all lines of the commit message up to the first blank line. The next
-line is `contents:body`, where body is all of the lines after the first
-blank line. The optional GPG signature is `contents:signature`. The
-first `N` lines of the message is obtained using `contents:lines=N`.
+The message in a commit or a tag object is `contents`, from which
+`contents:<part>` can be used to extract various parts out of:
+
+contents:size::
+ The size in bytes of the commit or tag message.
+
+contents:subject::
+ The first paragraph of the message, which typically is a
+ single line, is taken as the "subject" of the commit or the
+ tag message.
+
+contents:body::
+ The remainder of the commit or the tag message that follows
+ the "subject".
+
+contents:signature::
+ The optional GPG signature of the tag.
+
+contents:lines=N::
+ The first `N` lines of the message.
+
Additionally, the trailers as interpreted by linkgit:git-interpret-trailers[1]
are obtained as `trailers` (or by using the historical alias
`contents:trailers`). Non-trailer lines from the trailer block can be omitted
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 0d4f895..0f81d04 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -24,6 +24,7 @@ SYNOPSIS
[(--reroll-count|-v) <n>]
[--to=<email>] [--cc=<email>]
[--[no-]cover-letter] [--quiet]
+ [--[no-]encode-email-headers]
[--no-notes | --notes[=<ref>]]
[--interdiff=<previous>]
[--range-diff=<previous> [--creation-factor=<percent>]]
@@ -253,6 +254,13 @@ feeding the result to `git send-email`.
containing the branch description, shortlog and the overall diffstat. You can
fill in a description in the file before sending it out.
+--encode-email-headers::
+--no-encode-email-headers::
+ Encode email headers that have non-ASCII characters with
+ "Q-encoding" (described in RFC 2047), instead of outputting the
+ headers verbatim. Defaults to the value of the
+ `format.encodeEmailHeaders` configuration variable.
+
--interdiff=<previous>::
As a reviewer aid, insert an interdiff into the cover letter,
or as commentary of the lone patch of a 1-patch series, showing
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index ddb6acc..a7f9bc9 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -93,7 +93,7 @@ OPTIONS
with `--no-index`.
--recurse-submodules::
- Recursively search in each submodule that has been initialized and
+ Recursively search in each submodule that is active and
checked out in the repository. When used in combination with the
<tree> option the prefix of all submodule output will be the name of
the parent project's <tree> object. This option has no effect
@@ -206,8 +206,10 @@ providing this option will cause it to die.
-z::
--null::
- Output \0 instead of the character that normally follows a
- file name.
+ Use \0 as the delimiter for pathnames in the output, and print
+ them verbatim. Without this option, pathnames with "unusual"
+ characters are quoted as explained for the configuration
+ variable core.quotePath (see git-config(1)).
-o::
--only-matching::
diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt
index f71db0d..69c0c5c 100644
--- a/Documentation/git-help.txt
+++ b/Documentation/git-help.txt
@@ -8,7 +8,7 @@ git-help - Display help information about Git
SYNOPSIS
--------
[verse]
-'git help' [-a|--all [--[no-]verbose]] [-g|--guide]
+'git help' [-a|--all [--[no-]verbose]] [-g|--guides]
[-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]
DESCRIPTION
@@ -21,7 +21,7 @@ on the standard output.
If the option `--all` or `-a` is given, all available commands are
printed on the standard output.
-If the option `--guide` or `-g` is given, a list of the useful
+If the option `--guides` or `-g` is given, a list of the useful
Git guides is also printed on the standard output.
If a command, or a guide, is given, a manual page for that command or
diff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt
index 666b042..4deb489 100644
--- a/Documentation/git-http-fetch.txt
+++ b/Documentation/git-http-fetch.txt
@@ -9,7 +9,7 @@ git-http-fetch - Download from a remote Git repository via HTTP
SYNOPSIS
--------
[verse]
-'git http-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [--stdin] <commit> <url>
+'git http-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [--stdin | --packfile=<hash> | <commit>] <url>
DESCRIPTION
-----------
@@ -40,6 +40,13 @@ commit-id::
<commit-id>['\t'<filename-as-in--w>]
+--packfile=<hash>::
+ Instead of a commit id on the command line (which is not expected in
+ this case), 'git http-fetch' fetches the packfile directly at the given
+ URL and uses index-pack to generate corresponding .idx and .keep files.
+ The hash is used to determine the name of the temporary file and is
+ arbitrary. The output of index-pack is printed to stdout.
+
--recover::
Verify that everything reachable from target is fetched. Used after
an earlier fetch is interrupted.
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index d5b7560..ac74d05 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -93,11 +93,19 @@ OPTIONS
--max-input-size=<size>::
Die, if the pack is larger than <size>.
+--object-format=<hash-algorithm>::
+ Specify the given object format (hash algorithm) for the pack. The valid
+ values are 'sha1' and (if enabled) 'sha256'. The default is the algorithm for
+ the current repository (set by `extensions.objectFormat`), or 'sha1' if no
+ value is set or outside a repository.
++
+This option cannot be used with --stdin.
+
NOTES
-----
-Once the index has been created, the list of object names is sorted
-and the SHA-1 hash of that list is printed to stdout. If --stdin was
+Once the index has been created, the hash that goes into the name of
+the pack/idx file is printed to stdout. If --stdin was
also used then this is prefixed by either "pack\t", or "keep\t" if a
new .keep file was successfully created. This is useful to remove a
.keep file used as a lock to prevent the race with 'git repack'
diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index 32880aa..ddfe265 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -10,7 +10,8 @@ SYNOPSIS
--------
[verse]
'git init' [-q | --quiet] [--bare] [--template=<template_directory>]
- [--separate-git-dir <git dir>]
+ [--separate-git-dir <git dir>] [--object-format=<format>]
+ [-b <branch-name> | --initial-branch=<branch-name>]
[--shared[=<permissions>]] [directory]
@@ -48,6 +49,11 @@ Only print error and warning messages; all other output will be suppressed.
Create a bare repository. If `GIT_DIR` environment is not set, it is set to the
current working directory.
+--object-format=<format>::
+
+Specify the given object format (hash algorithm) for the repository. The valid
+values are 'sha1' and (if enabled) 'sha256'. 'sha1' is the default.
+
--template=<template_directory>::
Specify the directory from which templates will be used. (See the "TEMPLATE
@@ -62,6 +68,12 @@ repository.
+
If this is reinitialization, the repository will be moved to the specified path.
+-b <branch-name::
+--initial-branch=<branch-name>::
+
+Use the specified name for the initial branch in the newly created repository.
+If not specified, fall back to the default name: `master`.
+
--shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
Specify that the Git repository is to be shared amongst several users. This
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index bed09bb..3fd26d5 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -15,9 +15,12 @@ DESCRIPTION
-----------
Shows the commit logs.
-The command takes options applicable to the `git rev-list`
+:git-log: 1
+include::rev-list-description.txt[]
+
+The command takes options applicable to the linkgit:git-rev-list[1]
command to control what is shown and how, and options applicable to
-the `git diff-*` commands to control how the changes
+the linkgit:git-diff[1] command to control how the changes
each commit introduces are shown.
@@ -43,12 +46,16 @@ OPTIONS
If no `--decorate-refs` is given, pretend as if all refs were
included. For each candidate, do not use it for decoration if it
matches any patterns given to `--decorate-refs-exclude` or if it
- doesn't match any of the patterns given to `--decorate-refs`.
+ doesn't match any of the patterns given to `--decorate-refs`. The
+ `log.excludeDecoration` config option allows excluding refs from
+ the decorations, but an explicit `--decorate-refs` pattern will
+ override a match in `log.excludeDecoration`.
--source::
Print out the ref name given on the command line by which each
commit was reached.
+--[no-]mailmap::
--[no-]use-mailmap::
Use mailmap file to map author and committer names and email
addresses to canonical real names and email addresses. See
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 8461c0e..3cb2ebb 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -148,7 +148,7 @@ a space) at the start of each line:
top directory.
--recurse-submodules::
- Recursively calls ls-files on each submodule in the repository.
+ Recursively calls ls-files on each active submodule in the repository.
Currently there is only support for the --cached mode.
--abbrev[=<n>]::
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index 0a5c8b7..492e573 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -101,9 +101,9 @@ f25a265a342aed6041ab0cc484224d9ca54b6f41 refs/tags/v0.99.1
7ceca275d047c90c0c7d5afb13ab97efdf51bd6e refs/tags/v0.99.3
c5db5456ae3b0873fc659c19fafdde22313cc441 refs/tags/v0.99.2
0918385dbd9656cab0d1d81ba7453d49bbc16250 refs/tags/junio-gpg-pub
-$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master pu rc
+$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master seen rc
5fe978a5381f1fbad26a80e682ddd2a401966740 refs/heads/master
-c781a84b5204fb294c9ccc79f8b3baceeb32c061 refs/heads/pu
+c781a84b5204fb294c9ccc79f8b3baceeb32c061 refs/heads/seen
$ git remote add korg http://www.kernel.org/pub/scm/git/git.git
$ git ls-remote --tags korg v\*
d6602ec5194c87b0fc87103ca4d67251c76f233a refs/tags/v0.99
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 092529c..3819fad 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -94,7 +94,8 @@ will be appended to the specified message.
--abort::
Abort the current conflict resolution process, and
- try to reconstruct the pre-merge state.
+ try to reconstruct the pre-merge state. If an autostash entry is
+ present, apply it to the worktree.
+
If there were uncommitted worktree changes present when the merge
started, 'git merge --abort' will in some cases be unable to
@@ -102,11 +103,15 @@ reconstruct these changes. It is therefore recommended to always
commit or stash your changes before running 'git merge'.
+
'git merge --abort' is equivalent to 'git reset --merge' when
-`MERGE_HEAD` is present.
+`MERGE_HEAD` is present unless `MERGE_AUTOSTASH` is also present in
+which case 'git merge --abort' applies the stash entry to the worktree
+whereas 'git reset --merge' will save the stashed changes in the stash
+list.
--quit::
Forget about the current merge in progress. Leave the index
- and the working tree as-is.
+ and the working tree as-is. If `MERGE_AUTOSTASH` is present, the
+ stash entry will be saved to the stash list.
--continue::
After a 'git merge' stops due to conflicts you can conclude the
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index 642d9ac..0c66194 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -56,6 +56,9 @@ repack::
file is created, rewrite the multi-pack-index to reference the
new pack-file. A later run of 'git multi-pack-index expire' will
delete the pack-files that were part of this batch.
++
+If `repack.packKeptObjects` is `false`, then any pack-files with an
+associated `.keep` file will not be selected for the batch to repack.
EXAMPLES
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index 3494a1d..dab9609 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -374,14 +374,55 @@ These options can be used to modify 'git p4 submit' behavior.
been submitted. Implies --disable-rebase. Can also be set with
git-p4.disableP4Sync. Sync with origin/master still goes ahead if possible.
-Hook for submit
-~~~~~~~~~~~~~~~
+Hooks for submit
+----------------
+
+p4-pre-submit
+~~~~~~~~~~~~~
+
The `p4-pre-submit` hook is executed if it exists and is executable.
The hook takes no parameters and nothing from standard input. Exiting with
non-zero status from this script prevents `git-p4 submit` from launching.
+It can be bypassed with the `--no-verify` command line option.
One usage scenario is to run unit tests in the hook.
+p4-prepare-changelist
+~~~~~~~~~~~~~~~~~~~~~
+
+The `p4-prepare-changelist` hook is executed right after preparing
+the default changelist message and before the editor is started.
+It takes one parameter, the name of the file that contains the
+changelist text. Exiting with a non-zero status from the script
+will abort the process.
+
+The purpose of the hook is to edit the message file in place,
+and it is not supressed by the `--no-verify` option. This hook
+is called even if `--prepare-p4-only` is set.
+
+p4-changelist
+~~~~~~~~~~~~~
+
+The `p4-changelist` hook is executed after the changelist
+message has been edited by the user. It can be bypassed with the
+`--no-verify` option. It takes a single parameter, the name
+of the file that holds the proposed changelist text. Exiting
+with a non-zero status causes the command to abort.
+
+The hook is allowed to edit the changelist file and can be used
+to normalize the text into some project standard format. It can
+also be used to refuse the Submit after inspect the message file.
+
+p4-post-changelist
+~~~~~~~~~~~~~~~~~~
+
+The `p4-post-changelist` hook is invoked after the submit has
+successfully occured in P4. It takes no parameters and is meant
+primarily for notification and cannot affect the outcome of the
+git p4 submit action.
+
+
+
Rebase options
~~~~~~~~~~~~~~
These options can be used to modify 'git p4 rebase' behavior.
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index fecdf26..eaa2f2a 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -14,7 +14,7 @@ SYNOPSIS
[--local] [--incremental] [--window=<n>] [--depth=<n>]
[--revs [--unpacked | --all]] [--keep-pack=<pack-name>]
[--stdout [--filter=<filter-spec>] | base-name]
- [--shallow] [--keep-true-parents] [--sparse] < object-list
+ [--shallow] [--keep-true-parents] [--[no-]sparse] < object-list
DESCRIPTION
@@ -196,14 +196,16 @@ depth is 4095.
Add --no-reuse-object if you want to force a uniform compression
level on all data no matter the source.
---sparse::
- Use the "sparse" algorithm to determine which objects to include in
+--[no-]sparse::
+ Toggle the "sparse" algorithm to determine which objects to include in
the pack, when combined with the "--revs" option. This algorithm
only walks trees that appear in paths that introduce new objects.
This can have significant performance benefits when computing
a pack to send a small change. However, it is possible that extra
objects are added to the pack-file if the included commits contain
- certain types of direct renames.
+ certain types of direct renames. If this option is not included,
+ it defaults to the value of `pack.useSparse`, which is true unless
+ otherwise specified.
--thin::
Create a "thin" pack by omitting the common objects between a
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index dfb901f..5c3fb67 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -85,8 +85,9 @@ OPTIONS
Pass --verbose to git-fetch and git-merge.
--[no-]recurse-submodules[=yes|on-demand|no]::
- This option controls if new commits of all populated submodules should
- be fetched and updated, too (see linkgit:git-config[1] and
+ This option controls if new commits of populated submodules should
+ be fetched, and if the working trees of active submodules should be
+ updated, too (see linkgit:git-fetch[1], linkgit:git-config[1] and
linkgit:gitmodules[5]).
+
If the checkout is done via rebase, local submodule commits are rebased as well.
@@ -133,15 +134,6 @@ unless you have read linkgit:git-rebase[1] carefully.
--no-rebase::
Override earlier --rebase.
---autostash::
---no-autostash::
- Before starting rebase, stash local modifications away (see
- linkgit:git-stash[1]) if needed, and apply the stash entry when
- done. `--no-autostash` is useful to override the `rebase.autoStash`
- configuration variable (see linkgit:git-config[1]).
-+
-This option is only valid when "--rebase" is used.
-
Options related to fetching
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -229,9 +221,9 @@ branch.<name>.merge options; see linkgit:git-config[1] for details.
$ git pull origin next
------------------------------------------------
+
-This leaves a copy of `next` temporarily in FETCH_HEAD, but
-does not update any remote-tracking branches. Using remote-tracking
-branches, the same can be done by invoking fetch and merge:
+This leaves a copy of `next` temporarily in FETCH_HEAD, and
+updates the remote-tracking branch `origin/next`.
+The same can be done by invoking fetch and merge:
+
------------------------------------------------
$ git fetch origin
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index da33f84..5fa8bab 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -116,9 +116,9 @@ OPTIONS
located in.
--[no-]recurse-submodules::
- Using --recurse-submodules will update the content of all initialized
+ Using --recurse-submodules will update the content of all active
submodules according to the commit recorded in the superproject by
- calling read-tree recursively, also setting the submodules HEAD to be
+ calling read-tree recursively, also setting the submodules' HEAD to be
detached at that commit.
--no-sparse-checkout::
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index f7a6033..374d248 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -256,9 +256,10 @@ See also INCOMPATIBLE OPTIONS below.
--quit::
Abort the rebase operation but HEAD is not reset back to the
original branch. The index and working tree are also left
- unchanged as a result.
+ unchanged as a result. If a temporary stash entry was created
+ using --autostash, it will be saved to the stash list.
---apply:
+--apply::
Use applying strategies to rebase (calling `git-am`
internally). This option may become a no-op in the future
once the merge backend handles everything the apply one does.
@@ -277,20 +278,51 @@ See also INCOMPATIBLE OPTIONS below.
Other options, like --exec, will use the default of drop unless
-i/--interactive is explicitly specified.
+
-Note that commits which start empty are kept, and commits which are
-clean cherry-picks (as determined by `git log --cherry-mark ...`) are
-always dropped.
+Note that commits which start empty are kept (unless --no-keep-empty
+is specified), and commits which are clean cherry-picks (as determined
+by `git log --cherry-mark ...`) are detected and dropped as a
+preliminary step (unless --reapply-cherry-picks is passed).
+
See also INCOMPATIBLE OPTIONS below.
+--no-keep-empty::
--keep-empty::
- No-op. Rebasing commits that started empty (had no change
- relative to their parent) used to fail and this option would
- override that behavior, allowing commits with empty changes to
- be rebased. Now commits with no changes do not cause rebasing
- to halt.
+ Do not keep commits that start empty before the rebase
+ (i.e. that do not change anything from its parent) in the
+ result. The default is to keep commits which start empty,
+ since creating such commits requires passing the --allow-empty
+ override flag to `git commit`, signifying that a user is very
+ intentionally creating such a commit and thus wants to keep
+ it.
+
-See also BEHAVIORAL DIFFERENCES and INCOMPATIBLE OPTIONS below.
+Usage of this flag will probably be rare, since you can get rid of
+commits that start empty by just firing up an interactive rebase and
+removing the lines corresponding to the commits you don't want. This
+flag exists as a convenient shortcut, such as for cases where external
+tools generate many empty commits and you want them all removed.
++
+For commits which do not start empty but become empty after rebasing,
+see the --empty flag.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--reapply-cherry-picks::
+--no-reapply-cherry-picks::
+ Reapply all clean cherry-picks of any upstream commit instead
+ of preemptively dropping them. (If these commits then become
+ empty after rebasing, because they contain a subset of already
+ upstream changes, the behavior towards them is controlled by
+ the `--empty` flag.)
++
+By default (or if `--no-reapply-cherry-picks` is given), these commits
+will be automatically dropped. Because this necessitates reading all
+upstream commits, this can be expensive in repos with a large number
+of upstream commits that need to be read.
++
+`--reapply-cherry-picks` allows rebase to forgo reading all upstream
+commits, potentially improving performance.
++
+See also INCOMPATIBLE OPTIONS below.
--allow-empty-message::
No-op. Rebasing commits with an empty message used to fail
@@ -354,9 +386,12 @@ See also INCOMPATIBLE OPTIONS below.
-S[<keyid>]::
--gpg-sign[=<keyid>]::
+--no-gpg-sign::
GPG-sign commits. The `keyid` argument is optional and
defaults to the committer identity; if specified, it must be
- stuck to the option without a space.
+ stuck to the option without a space. `--no-gpg-sign` is useful to
+ countermand both `commit.gpgSign` configuration variable, and
+ earlier `--gpg-sign`.
-q::
--quiet::
@@ -414,12 +449,14 @@ When --fork-point is active, 'fork_point' will be used instead of
<branch>` command (see linkgit:git-merge-base[1]). If 'fork_point'
ends up being empty, the <upstream> will be used as a fallback.
+
-If either <upstream> or --root is given on the command line, then the
-default is `--no-fork-point`, otherwise the default is `--fork-point`.
+If <upstream> is given on the command line, then the default is
+`--no-fork-point`, otherwise the default is `--fork-point`.
+
If your branch was based on <upstream> but <upstream> was rewound and
your branch contains commits which were dropped, this option can be used
with `--keep-base` in order to drop those commits from your branch.
++
+See also INCOMPATIBLE OPTIONS below.
--ignore-whitespace::
--whitespace=<option>::
@@ -587,8 +624,9 @@ are incompatible with the following options:
* --preserve-merges
* --interactive
* --exec
- * --keep-empty
+ * --no-keep-empty
* --empty=
+ * --reapply-cherry-picks
* --edit-todo
* --root when used in combination with --onto
@@ -600,12 +638,13 @@ In addition, the following pairs of options are incompatible:
* --preserve-merges and --empty=
* --keep-base and --onto
* --keep-base and --root
+ * --fork-point and --root
BEHAVIORAL DIFFERENCES
-----------------------
git rebase has two primary backends: apply and merge. (The apply
-backend used to known as the 'am' backend, but the name led to
+backend used to be known as the 'am' backend, but the name led to
confusion as it looks like a verb instead of a noun. Also, the merge
backend used to be known as the interactive backend, but it is now
used for non-interactive cases as well. Both were renamed based on
@@ -620,12 +659,15 @@ commits that started empty, though these are rare in practice. It
also drops commits that become empty and has no option for controlling
this behavior.
-The merge backend keeps intentionally empty commits. Similar to the
-apply backend, by default the merge backend drops commits that become
-empty unless -i/--interactive is specified (in which case it stops and
-asks the user what to do). The merge backend also has an
---empty={drop,keep,ask} option for changing the behavior of handling
-commits that become empty.
+The merge backend keeps intentionally empty commits by default (though
+with -i they are marked as empty in the todo list editor, or they can
+be dropped automatically with --no-keep-empty).
+
+Similar to the apply backend, by default the merge backend drops
+commits that become empty unless -i/--interactive is specified (in
+which case it stops and asks the user what to do). The merge backend
+also has an --empty={drop,keep,ask} option for changing the behavior
+of handling commits that become empty.
Directory rename detection
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -684,9 +726,17 @@ Hooks
~~~~~
The apply backend has not traditionally called the post-commit hook,
-while the merge backend has. However, this was by accident of
-implementation rather than by design. Both backends should have the
-same behavior, though it is not clear which one is correct.
+while the merge backend has. Both have called the post-checkout hook,
+though the merge backend has squelched its output. Further, both
+backends only call the post-checkout hook with the starting point
+commit of the rebase, not the intermediate commits nor the final
+commit. In each case, the calling of these hooks was by accident of
+implementation rather than by design (both backends were originally
+implemented as shell scripts and happened to invoke other commands
+like 'git checkout' or 'git commit' that would call the hooks). Both
+backends should have the same behavior, though it is not entirely
+clear which, if any, is correct. We will likely make rebase stop
+calling either of these hooks in the future.
Interruptability
~~~~~~~~~~~~~~~~
@@ -1002,7 +1052,8 @@ Only works if the changes (patch IDs based on the diff contents) on
'subsystem' did.
In that case, the fix is easy because 'git rebase' knows to skip
-changes that are already present in the new upstream. So if you say
+changes that are already present in the new upstream (unless
+`--reapply-cherry-picks` is given). So if you say
(assuming you're on 'topic')
------------
$ git rebase subsystem
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index 932080c..252e2d4 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -87,6 +87,12 @@ but carries forward unmerged index entries.
different between `<commit>` and `HEAD`.
If a file that is different between `<commit>` and `HEAD` has local
changes, reset is aborted.
+
+--[no-]recurse-submodules::
+ When the working tree is updated, using --recurse-submodules will
+ also recursively reset the working tree of all active submodules
+ according to the commit recorded in the superproject, also setting
+ the submodules' HEAD to be detached at that commit.
--
See "Reset, restore and revert" in linkgit:git[1] for the differences
diff --git a/Documentation/git-restore.txt b/Documentation/git-restore.txt
index 5bf60d4..84c6c40 100644
--- a/Documentation/git-restore.txt
+++ b/Documentation/git-restore.txt
@@ -22,9 +22,8 @@ The command can also be used to restore the content in the index with
`--staged`, or restore both the working tree and the index with
`--staged --worktree`.
-By default, the restore sources for working tree and the index are the
-index and `HEAD` respectively. `--source` could be used to specify a
-commit as the restore source.
+By default, if `--staged` is given, the contents are restored from `HEAD`,
+otherwise from the index. Use `--source` to restore from a different commit.
See "Reset, restore and revert" in linkgit:git[1] for the differences
between the three commands.
@@ -39,10 +38,8 @@ OPTIONS
tree. It is common to specify the source tree by naming a
commit, branch or tag associated with it.
+
-If not specified, the default restore source for the working tree is
-the index, and the default restore source for the index is
-`HEAD`. When both `--staged` and `--worktree` are specified,
-`--source` must also be specified.
+If not specified, the contents are restored from `HEAD` if `--staged` is
+given, otherwise from the index.
-p::
--patch::
@@ -107,6 +104,17 @@ in linkgit:git-checkout[1] for details.
patterns and unconditionally restores any files in
`<pathspec>`.
+--recurse-submodules::
+--no-recurse-submodules::
+ If `<pathspec>` names an active submodule and the restore location
+ includes the working tree, the submodule will only be updated if
+ this option is given, in which case its working tree will be
+ restored to the commit recorded in the superproject, and any local
+ modifications overwritten. If nothing (or
+ `--no-recurse-submodules`) is used, submodules working trees will
+ not be updated. Just like linkgit:git-checkout[1], this will detach
+ `HEAD` of the submodule.
+
--overlay::
--no-overlay::
In overlay mode, the command never removes files when
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 025c911..5da6623 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -14,44 +14,8 @@ SYNOPSIS
DESCRIPTION
-----------
-List commits that are reachable by following the `parent` links from the
-given commit(s), but exclude commits that are reachable from the one(s)
-given with a '{caret}' in front of them. The output is given in reverse
-chronological order by default.
-
-You can think of this as a set operation. Commits given on the command
-line form a set of commits that are reachable from any of them, and then
-commits reachable from any of the ones given with '{caret}' in front are
-subtracted from that set. The remaining commits are what comes out in the
-command's output. Various other options and paths parameters can be used
-to further limit the result.
-
-Thus, the following command:
-
------------------------------------------------------------------------
- $ git rev-list foo bar ^baz
------------------------------------------------------------------------
-
-means "list all the commits which are reachable from 'foo' or 'bar', but
-not from 'baz'".
-
-A special notation "'<commit1>'..'<commit2>'" can be used as a
-short-hand for "{caret}'<commit1>' '<commit2>'". For example, either of
-the following may be used interchangeably:
-
------------------------------------------------------------------------
- $ git rev-list origin..HEAD
- $ git rev-list HEAD ^origin
------------------------------------------------------------------------
-
-Another special notation is "'<commit1>'...'<commit2>'" which is useful
-for merges. The resulting set of commits is the symmetric difference
-between the two operands. The following two commands are equivalent:
-
------------------------------------------------------------------------
- $ git rev-list A B --not $(git merge-base --all A B)
- $ git rev-list A...B
------------------------------------------------------------------------
+:git-rev-list: 1
+include::rev-list-description.txt[]
'rev-list' is a very essential Git command, since it
provides the ability to build and traverse commit ancestry graphs. For
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 9d22270..044276e 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -90,9 +90,12 @@ effect to your index in a row.
-S[<keyid>]::
--gpg-sign[=<keyid>]::
+--no-gpg-sign::
GPG-sign commits. The `keyid` argument is optional and
defaults to the committer identity; if specified, it must be
- stuck to the option without a space.
+ stuck to the option without a space. `--no-gpg-sign` is useful to
+ countermand both `commit.gpgSign` configuration variable, and
+ earlier `--gpg-sign`.
-s::
--signoff::
diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.txt
index 424e4ba..39b1d8e 100644
--- a/Documentation/git-show-index.txt
+++ b/Documentation/git-show-index.txt
@@ -9,7 +9,7 @@ git-show-index - Show packed archive index
SYNOPSIS
--------
[verse]
-'git show-index'
+'git show-index' [--object-format=<hash-algorithm>]
DESCRIPTION
@@ -36,6 +36,15 @@ Note that you can get more information on a packfile by calling
linkgit:git-verify-pack[1]. However, as this command considers only the
index file itself, it's both faster and more flexible.
+OPTIONS
+-------
+
+--object-format=<hash-algorithm>::
+ Specify the given object format (hash algorithm) for the index file. The
+ valid values are 'sha1' and (if enabled) 'sha256'. The default is the
+ algorithm for the current repository (set by `extensions.objectFormat`), or
+ 'sha1' if no value is set or outside a repository..
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-sparse-checkout.txt b/Documentation/git-sparse-checkout.txt
index c0342e5..a0eeaeb 100644
--- a/Documentation/git-sparse-checkout.txt
+++ b/Documentation/git-sparse-checkout.txt
@@ -70,6 +70,16 @@ C-style quoted strings.
`core.sparseCheckoutCone` is enabled, the given patterns are interpreted
as directory names as in the 'set' subcommand.
+'reapply'::
+ Reapply the sparsity pattern rules to paths in the working tree.
+ Commands like merge or rebase can materialize paths to do their
+ work (e.g. in order to show you a conflict), and other
+ sparse-checkout commands might fail to sparsify an individual file
+ (e.g. because it has unstaged changes or conflicts). In such
+ cases, it can make sense to run `git sparse-checkout reapply` later
+ after cleaning up affected paths (e.g. resolving conflicts, undoing
+ or committing changes, etc.).
+
'disable'::
Disable the `core.sparseCheckout` config setting, and restore the
working directory to include all files. Leaves the sparse-checkout
@@ -190,10 +200,32 @@ directory.
SUBMODULES
----------
-If your repository contains one or more submodules, then those submodules will
-appear based on which you initialized with the `git submodule` command. If
-your sparse-checkout patterns exclude an initialized submodule, then that
-submodule will still appear in your working directory.
+If your repository contains one or more submodules, then submodules
+are populated based on interactions with the `git submodule` command.
+Specifically, `git submodule init -- <path>` will ensure the submodule
+at `<path>` is present, while `git submodule deinit [-f] -- <path>`
+will remove the files for the submodule at `<path>` (including any
+untracked files, uncommitted changes, and unpushed history). Similar
+to how sparse-checkout removes files from the working tree but still
+leaves entries in the index, deinitialized submodules are removed from
+the working directory but still have an entry in the index.
+
+Since submodules may have unpushed changes or untracked files,
+removing them could result in data loss. Thus, changing sparse
+inclusion/exclusion rules will not cause an already checked out
+submodule to be removed from the working copy. Said another way, just
+as `checkout` will not cause submodules to be automatically removed or
+initialized even when switching between branches that remove or add
+submodules, using `sparse-checkout` to reduce or expand the scope of
+"interesting" files will not cause submodules to be automatically
+deinitialized or initialized either.
+
+Further, the above facts mean that there are multiple reasons that
+"tracked" files might not be present in the working copy: sparsity
+pattern application from sparse-checkout, and submodule initialization
+state. Thus, commands like `git grep` that work on tracked files in
+the working copy may return results that are limited by either or both
+of these restrictions.
SEE ALSO
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index c9ed2bf..7e5f995 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -183,7 +183,7 @@ set-branch (-d|--default) [--] <path>::
Sets the default remote tracking branch for the submodule. The
`--branch` option allows the remote branch to be specified. The
`--default` option removes the submodule.<name>.branch configuration
- key, which causes the tracking branch to default to 'master'.
+ key, which causes the tracking branch to default to the remote 'HEAD'.
set-url [--] <path> <newurl>::
Sets the URL of the specified submodule to <newurl>. Then, it will
@@ -284,7 +284,7 @@ OPTIONS
`.gitmodules` for `update --remote`. A special value of `.` is used to
indicate that the name of the branch in the submodule should be the
same name as the current branch in the current repository. If the
- option is not specified, it defaults to 'master'.
+ option is not specified, it defaults to the remote 'HEAD'.
-f::
--force::
@@ -322,10 +322,10 @@ OPTIONS
the superproject's recorded SHA-1 to update the submodule, use the
status of the submodule's remote-tracking branch. The remote used
is branch's remote (`branch.<name>.remote`), defaulting to `origin`.
- The remote branch used defaults to `master`, but the branch name may
- be overridden by setting the `submodule.<name>.branch` option in
- either `.gitmodules` or `.git/config` (with `.git/config` taking
- precedence).
+ The remote branch used defaults to the remote `HEAD`, but the branch
+ name may be overridden by setting the `submodule.<name>.branch`
+ option in either `.gitmodules` or `.git/config` (with `.git/config`
+ taking precedence).
+
This works for any of the supported update procedures (`--checkout`,
`--rebase`, etc.). The only change is the source of the target SHA-1.
diff --git a/Documentation/git-switch.txt b/Documentation/git-switch.txt
index 1979003..3759c3a 100644
--- a/Documentation/git-switch.txt
+++ b/Documentation/git-switch.txt
@@ -181,9 +181,9 @@ name, the guessing is aborted. You can explicitly give a name with
--recurse-submodules::
--no-recurse-submodules::
Using `--recurse-submodules` will update the content of all
- initialized submodules according to the commit recorded in the
+ active submodules according to the commit recorded in the
superproject. If nothing (or `--no-recurse-submodules`) is
- used, the work trees of submodules will not be updated. Just
+ used, submodules working trees will not be updated. Just
like linkgit:git-submodule[1], this will detach `HEAD` of the
submodules.
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index 9671423..3e737c2 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -66,6 +66,10 @@ performs all modifications together. Specify commands of the form:
delete SP <ref> [SP <oldvalue>] LF
verify SP <ref> [SP <oldvalue>] LF
option SP <opt> LF
+ start LF
+ prepare LF
+ commit LF
+ abort LF
With `--create-reflog`, update-ref will create a reflog for each ref
even if one would not ordinarily be created.
@@ -83,6 +87,10 @@ quoting:
delete SP <ref> NUL [<oldvalue>] NUL
verify SP <ref> NUL [<oldvalue>] NUL
option SP <opt> NUL
+ start NUL
+ prepare NUL
+ commit NUL
+ abort NUL
In this format, use 40 "0" to specify a zero value, and use the empty
string to specify a missing value.
@@ -107,13 +115,31 @@ delete::
verify::
Verify <ref> against <oldvalue> but do not change it. If
- <oldvalue> zero or missing, the ref must not exist.
+ <oldvalue> is zero or missing, the ref must not exist.
option::
Modify behavior of the next command naming a <ref>.
The only valid option is `no-deref` to avoid dereferencing
a symbolic ref.
+start::
+ Start a transaction. In contrast to a non-transactional session, a
+ transaction will automatically abort if the session ends without an
+ explicit commit.
+
+prepare::
+ Prepare to commit the transaction. This will create lock files for all
+ queued reference updates. If one reference could not be locked, the
+ transaction will be aborted.
+
+commit::
+ Commit all reference updates queued for the transaction, ending the
+ transaction.
+
+abort::
+ Abort the transaction, releasing all locks if the transaction is in
+ prepared state.
+
If all <ref>s can be locked with matching <oldvalue>s
simultaneously, all modifications are performed. Otherwise, no
modifications are performed. Note that while each individual
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 85d92c9..4796c3c 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -126,7 +126,9 @@ OPTIONS
locked working tree path, specify `--force` twice.
+
`move` refuses to move a locked working tree unless `--force` is specified
-twice.
+twice. If the destination is already assigned to some other working tree but is
+missing (for instance, if `<new-path>` was deleted manually), then `--force`
+allows the move to proceed; use --force twice if the destination is locked.
+
`remove` refuses to remove an unclean working tree unless `--force` is used.
To remove a locked working tree, specify `--force` twice.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index b0672bd..3e50065 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -493,6 +493,12 @@ double-quotes and respecting backslash escapes. E.g., the value
details. This variable has lower precedence than other path
variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY...
+`GIT_DEFAULT_HASH`::
+ If this variable is set, the default hash algorithm for new
+ repositories will be set to this value. This value is currently
+ ignored when cloning; the setting of the remote repository
+ is used instead. The default is "sha1".
+
Git Commits
~~~~~~~~~~~
`GIT_AUTHOR_NAME`::
@@ -715,8 +721,6 @@ of clones and fetches.
Enables a curl full trace dump of all incoming and outgoing data,
including descriptive information, of the git transport protocol.
This is similar to doing curl `--trace-ascii` on the command line.
- This option overrides setting the `GIT_CURL_VERBOSE` environment
- variable.
See `GIT_TRACE` for available trace output options.
`GIT_TRACE_CURL_NO_DATA`::
@@ -771,11 +775,10 @@ for full details.
See `GIT_TRACE2` for available trace output options and
link:technical/api-trace2.html[Trace2 documentation] for full details.
-`GIT_REDACT_COOKIES`::
- This can be set to a comma-separated list of strings. When a curl trace
- is enabled (see `GIT_TRACE_CURL` above), whenever a "Cookies:" header
- sent by the client is dumped, values of cookies whose key is in that
- list (case-sensitive) are redacted.
+`GIT_TRACE_REDACT`::
+ By default, when tracing is activated, Git redacts the values of
+ cookies, the "Authorization:" header, and the "Proxy-Authorization:"
+ header. Set this variable to `0` to prevent this redaction.
`GIT_LITERAL_PATHSPECS`::
Setting this variable to `1` will cause Git to treat all
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 508fe71..2d0a037 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -824,6 +824,8 @@ patterns are available:
- `java` suitable for source code in the Java language.
+- `markdown` suitable for Markdown documents.
+
- `matlab` suitable for source code in the MATLAB and Octave languages.
- `objc` suitable for source code in the Objective-C language.
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 1814d2d..9e481ae 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -216,20 +216,26 @@ Here are some example specifications:
----------------------------------------------------
# run "git credential-foo"
-foo
+[credential]
+ helper = foo
# same as above, but pass an argument to the helper
-foo --bar=baz
+[credential]
+ helper = "foo --bar=baz"
# the arguments are parsed by the shell, so use shell
# quoting if necessary
-foo --bar="whitespace arg"
+[credential]
+ helper = "foo --bar='whitespace arg'"
# you can also use an absolute path, which will not use the git wrapper
-/path/to/my/helper --with-arguments
+[credential]
+ helper = "/path/to/my/helper --with-arguments"
# or you can specify your own shell snippet
-!f() { echo "password=`cat $HOME/.secret`"; }; f
+[credential "https://example.com"]
+ username = your_user
+ helper = "!f() { test \"$1\" = get && echo \"password=$(cat $HOME/.secret)\"; }; f"
----------------------------------------------------
Generally speaking, rule (3) above is the simplest for users to specify.
@@ -262,16 +268,26 @@ For a `get` operation, the helper should produce a list of attributes on
stdout in the same format (see linkgit:git-credential[1] for common
attributes). A helper is free to produce a subset, or even no values at
all if it has nothing useful to provide. Any provided attributes will
-overwrite those already known about by Git. If a helper outputs a
-`quit` attribute with a value of `true` or `1`, no further helpers will
-be consulted, nor will the user be prompted (if no credential has been
-provided, the operation will then fail).
+overwrite those already known about by Git's credential subsystem.
+
+While it is possible to override all attributes, well behaving helpers
+should refrain from doing so for any attribute other than username and
+password.
+
+If a helper outputs a `quit` attribute with a value of `true` or `1`,
+no further helpers will be consulted, nor will the user be prompted
+(if no credential has been provided, the operation will then fail).
+
+Similarly, no more helpers will be consulted once both username and
+password had been provided.
For a `store` or `erase` operation, the helper's output is ignored.
-If it fails to perform the requested operation, it may complain to
-stderr to inform the user. If it does not support the requested
-operation (e.g., a read-only store), it should silently ignore the
-request.
+
+If a helper fails to perform the requested operation or needs to notify
+the user of a potential issue, it may write to stderr.
+
+If it does not support the requested operation (e.g., a read-only store),
+it should silently ignore the request.
If a helper receives any other operation, it should silently ignore the
request. This leaves room for future operations to be added (older
diff --git a/Documentation/giteveryday.txt b/Documentation/giteveryday.txt
index 1bd919f..faba2ef 100644
--- a/Documentation/giteveryday.txt
+++ b/Documentation/giteveryday.txt
@@ -278,13 +278,13 @@ $ git am -3 -i -s ./+to-apply <4>
$ compile/test
$ git switch -c hold/linus && git am -3 -i -s ./+hold-linus <5>
$ git switch topic/one && git rebase master <6>
-$ git switch -C pu next <7>
+$ git switch -C seen next <7>
$ git merge topic/one topic/two && git merge hold/linus <8>
$ git switch maint
$ git cherry-pick master~4 <9>
$ compile/test
$ git tag -s -m "GIT 0.99.9x" v0.99.9x <10>
-$ git fetch ko && for branch in master maint next pu <11>
+$ git fetch ko && for branch in master maint next seen <11>
do
git show-branch ko/$branch $branch <12>
done
@@ -294,14 +294,14 @@ $ git push --follow-tags ko <13>
<1> see what you were in the middle of doing, if anything.
<2> see which branches haven't been merged into `master` yet.
Likewise for any other integration branches e.g. `maint`, `next`
-and `pu` (potential updates).
+and `seen`.
<3> read mails, save ones that are applicable, and save others
that are not quite ready (other mail readers are available).
<4> apply them, interactively, with your sign-offs.
<5> create topic branch as needed and apply, again with sign-offs.
<6> rebase internal topic branch that has not been merged to the
master or exposed as a part of a stable branch.
-<7> restart `pu` every time from the next.
+<7> restart `seen` every time from the next.
<8> and bundle topic branches still cooking.
<9> backport a critical fix.
<10> create a signed tag.
@@ -323,7 +323,7 @@ repository at kernel.org, and looks like this:
fetch = refs/heads/*:refs/remotes/ko/*
push = refs/heads/master
push = refs/heads/next
- push = +refs/heads/pu
+ push = +refs/heads/seen
push = refs/heads/maint
------------
diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
new file mode 100644
index 0000000..9cd7a59
--- /dev/null
+++ b/Documentation/gitfaq.txt
@@ -0,0 +1,355 @@
+gitfaq(7)
+=========
+
+NAME
+----
+gitfaq - Frequently asked questions about using Git
+
+SYNOPSIS
+--------
+gitfaq
+
+DESCRIPTION
+-----------
+
+The examples in this FAQ assume a standard POSIX shell, like `bash` or `dash`,
+and a user, A U Thor, who has the account `author` on the hosting provider
+`git.example.org`.
+
+Configuration
+-------------
+
+[[user-name]]
+What should I put in `user.name`?::
+ You should put your personal name, generally a form using a given name
+ and family name. For example, the current maintainer of Git uses "Junio
+ C Hamano". This will be the name portion that is stored in every commit
+ you make.
++
+This configuration doesn't have any effect on authenticating to remote services;
+for that, see `credential.username` in linkgit:git-config[1].
+
+[[http-postbuffer]]
+What does `http.postBuffer` really do?::
+ This option changes the size of the buffer that Git uses when pushing
+ data to a remote over HTTP or HTTPS. If the data is larger than this
+ size, libcurl, which handles the HTTP support for Git, will use chunked
+ transfer encoding since it isn't known ahead of time what the size of
+ the pushed data will be.
++
+Leaving this value at the default size is fine unless you know that either the
+remote server or a proxy in the middle doesn't support HTTP/1.1 (which
+introduced the chunked transfer encoding) or is known to be broken with chunked
+data. This is often (erroneously) suggested as a solution for generic push
+problems, but since almost every server and proxy supports at least HTTP/1.1,
+raising this value usually doesn't solve most push problems. A server or proxy
+that didn't correctly support HTTP/1.1 and chunked transfer encoding wouldn't be
+that useful on the Internet today, since it would break lots of traffic.
++
+Note that increasing this value will increase the memory used on every relevant
+push that Git does over HTTP or HTTPS, since the entire buffer is allocated
+regardless of whether or not it is all used. Thus, it's best to leave it at the
+default unless you are sure you need a different value.
+
+[[configure-editor]]
+How do I configure a different editor?::
+ If you haven't specified an editor specifically for Git, it will by default
+ use the editor you've configured using the `VISUAL` or `EDITOR` environment
+ variables, or if neither is specified, the system default (which is usually
+ `vi`). Since some people find `vi` difficult to use or prefer a different
+ editor, it may be desirable to change the editor used.
++
+If you want to configure a general editor for most programs which need one, you
+can edit your shell configuration (e.g., `~/.bashrc` or `~/.zshenv`) to contain
+a line setting the `EDITOR` or `VISUAL` environment variable to an appropriate
+value. For example, if you prefer the editor `nano`, then you could write the
+following:
++
+----
+export VISUAL=nano
+----
++
+If you want to configure an editor specifically for Git, you can either set the
+`core.editor` configuration value or the `GIT_EDITOR` environment variable. You
+can see linkgit:git-var[1] for details on the order in which these options are
+consulted.
++
+Note that in all cases, the editor value will be passed to the shell, so any
+arguments containing spaces should be appropriately quoted. Additionally, if
+your editor normally detaches from the terminal when invoked, you should specify
+it with an argument that makes it not do that, or else Git will not see any
+changes. An example of a configuration addressing both of these issues on
+Windows would be the configuration `"C:\Program Files\Vim\gvim.exe" --nofork`,
+which quotes the filename with spaces and specifies the `--nofork` option to
+avoid backgrounding the process.
+
+Credentials
+-----------
+
+[[http-credentials]]
+How do I specify my credentials when pushing over HTTP?::
+ The easiest way to do this is to use a credential helper via the
+ `credential.helper` configuration. Most systems provide a standard
+ choice to integrate with the system credential manager. For example,
+ Git for Windows provides the `wincred` credential manager, macOS has the
+ `osxkeychain` credential manager, and Unix systems with a standard
+ desktop environment can use the `libsecret` credential manager. All of
+ these store credentials in an encrypted store to keep your passwords or
+ tokens secure.
++
+In addition, you can use the `store` credential manager which stores in a file
+in your home directory, or the `cache` credential manager, which does not
+permanently store your credentials, but does prevent you from being prompted for
+them for a certain period of time.
++
+You can also just enter your password when prompted. While it is possible to
+place the password (which must be percent-encoded) in the URL, this is not
+particularly secure and can lead to accidental exposure of credentials, so it is
+not recommended.
+
+[[http-credentials-environment]]
+How do I read a password or token from an environment variable?::
+ The `credential.helper` configuration option can also take an arbitrary
+ shell command that produces the credential protocol on standard output.
+ This is useful when passing credentials into a container, for example.
++
+Such a shell command can be specified by starting the option value with an
+exclamation point. If your password or token were stored in the `GIT_TOKEN`,
+you could run the following command to set your credential helper:
++
+----
+$ git config credential.helper \
+ '!f() { echo username=author; echo "password=$GIT_TOKEN"; };f'
+----
+
+[[http-reset-credentials]]
+How do I change the password or token I've saved in my credential manager?::
+ Usually, if the password or token is invalid, Git will erase it and
+ prompt for a new one. However, there are times when this doesn't always
+ happen. To change the password or token, you can erase the existing
+ credentials and then Git will prompt for new ones. To erase
+ credentials, use a syntax like the following (substituting your username
+ and the hostname):
++
+----
+$ echo url=https://author@git.example.org | git credential reject
+----
+
+[[multiple-accounts-http]]
+How do I use multiple accounts with the same hosting provider using HTTP?::
+ Usually the easiest way to distinguish between these accounts is to use
+ the username in the URL. For example, if you have the accounts `author`
+ and `committer` on `git.example.org`, you can use the URLs
+ https://author@git.example.org/org1/project1.git and
+ https://committer@git.example.org/org2/project2.git. This way, when you
+ use a credential helper, it will automatically try to look up the
+ correct credentials for your account. If you already have a remote set
+ up, you can change the URL with something like `git remote set-url
+ origin https://author@git.example.org/org1/project1.git` (see
+ linkgit:git-remote[1] for details).
+
+[[multiple-accounts-ssh]]
+How do I use multiple accounts with the same hosting provider using SSH?::
+ With most hosting providers that support SSH, a single key pair uniquely
+ identifies a user. Therefore, to use multiple accounts, it's necessary
+ to create a key pair for each account. If you're using a reasonably
+ modern OpenSSH version, you can create a new key pair with something
+ like `ssh-keygen -t ed25519 -f ~/.ssh/id_committer`. You can then
+ register the public key (in this case, `~/.ssh/id_committer.pub`; note
+ the `.pub`) with the hosting provider.
++
+Most hosting providers use a single SSH account for pushing; that is, all users
+push to the `git` account (e.g., `git@git.example.org`). If that's the case for
+your provider, you can set up multiple aliases in SSH to make it clear which key
+pair to use. For example, you could write something like the following in
+`~/.ssh/config`, substituting the proper private key file:
++
+----
+# This is the account for author on git.example.org.
+Host example_author
+ HostName git.example.org
+ User git
+ # This is the key pair registered for author with git.example.org.
+ IdentityFile ~/.ssh/id_author
+ IdentitiesOnly yes
+# This is the account for committer on git.example.org.
+Host example_committer
+ HostName git.example.org
+ User git
+ # This is the key pair registered for committer with git.example.org.
+ IdentityFile ~/.ssh/id_committer
+ IdentitiesOnly yes
+----
++
+Then, you can adjust your push URL to use `git@example_author` or
+`git@example_committer` instead of `git@example.org` (e.g., `git remote set-url
+git@example_author:org1/project1.git`).
+
+Common Issues
+-------------
+
+[[last-commit-amend]]
+I've made a mistake in the last commit. How do I change it?::
+ You can make the appropriate change to your working tree, run `git add
+ <file>` or `git rm <file>`, as appropriate, to stage it, and then `git
+ commit --amend`. Your change will be included in the commit, and you'll
+ be prompted to edit the commit message again; if you wish to use the
+ original message verbatim, you can use the `--no-edit` option to `git
+ commit` in addition, or just save and quit when your editor opens.
+
+[[undo-previous-change]]
+I've made a change with a bug and it's been included in the main branch. How should I undo it?::
+ The usual way to deal with this is to use `git revert`. This preserves
+ the history that the original change was made and was a valuable
+ contribution, but also introduces a new commit that undoes those changes
+ because the original had a problem. The commit message of the revert
+ indicates the commit which was reverted and is usually edited to include
+ an explanation as to why the revert was made.
+
+[[ignore-tracked-files]]
+How do I ignore changes to a tracked file?::
+ Git doesn't provide a way to do this. The reason is that if Git needs
+ to overwrite this file, such as during a checkout, it doesn't know
+ whether the changes to the file are precious and should be kept, or
+ whether they are irrelevant and can safely be destroyed. Therefore, it
+ has to take the safe route and always preserve them.
++
+It's tempting to try to use certain features of `git update-index`, namely the
+assume-unchanged and skip-worktree bits, but these don't work properly for this
+purpose and shouldn't be used this way.
++
+If your goal is to modify a configuration file, it can often be helpful to have
+a file checked into the repository which is a template or set of defaults which
+can then be copied alongside and modified as appropriate. This second, modified
+file is usually ignored to prevent accidentally committing it.
+
+[[files-in-gitignore-are-tracked]]
+I asked Git to ignore various files, yet they are still tracked::
+ A `gitignore` file ensures that certain file(s) which are not
+ tracked by Git remain untracked. However, sometimes particular
+ file(s) may have been tracked before adding them into the
+ `.gitignore`, hence they still remain tracked. To untrack and
+ ignore files/patterns, use `git rm --cached <file/pattern>`
+ and add a pattern to `.gitignore` that matches the <file>.
+ See linkgit:gitignore[5] for details.
+
+[[fetching-and-pulling]]
+How do I know if I want to do a fetch or a pull?::
+ A fetch stores a copy of the latest changes from the remote
+ repository, without modifying the working tree or current branch.
+ You can then at your leisure inspect, merge, rebase on top of, or
+ ignore the upstream changes. A pull consists of a fetch followed
+ immediately by either a merge or rebase. See linkgit:git-pull[1].
+
+Hooks
+-----
+
+[[restrict-with-hooks]]
+How do I use hooks to prevent users from making certain changes?::
+ The only safe place to make these changes is on the remote repository
+ (i.e., the Git server), usually in the `pre-receive` hook or in a
+ continuous integration (CI) system. These are the locations in which
+ policy can be enforced effectively.
++
+It's common to try to use `pre-commit` hooks (or, for commit messages,
+`commit-msg` hooks) to check these things, which is great if you're working as a
+solo developer and want the tooling to help you. However, using hooks on a
+developer machine is not effective as a policy control because a user can bypass
+these hooks with `--no-verify` without being noticed (among various other ways).
+Git assumes that the user is in control of their local repositories and doesn't
+try to prevent this or tattle on the user.
++
+In addition, some advanced users find `pre-commit` hooks to be an impediment to
+workflows that use temporary commits to stage work in progress or that create
+fixup commits, so it's better to push these kinds of checks to the server
+anyway.
+
+Cross-Platform Issues
+---------------------
+
+[[windows-text-binary]]
+I'm on Windows and my text files are detected as binary.::
+ Git works best when you store text files as UTF-8. Many programs on
+ Windows support UTF-8, but some do not and only use the little-endian
+ UTF-16 format, which Git detects as binary. If you can't use UTF-8 with
+ your programs, you can specify a working tree encoding that indicates
+ which encoding your files should be checked out with, while still
+ storing these files as UTF-8 in the repository. This allows tools like
+ linkgit:git-diff[1] to work as expected, while still allowing your tools
+ to work.
++
+To do so, you can specify a linkgit:gitattributes[5] pattern with the
+`working-tree-encoding` attribute. For example, the following pattern sets all
+C files to use UTF-16LE-BOM, which is a common encoding on Windows:
++
+----
+*.c working-tree-encoding=UTF-16LE-BOM
+----
++
+You will need to run `git add --renormalize` to have this take effect. Note
+that if you are making these changes on a project that is used across platforms,
+you'll probably want to make it in a per-user configuration file or in the one
+in `$GIT_DIR/info/attributes`, since making it in a `.gitattributes` file in the
+repository will apply to all users of the repository.
++
+See the following entry for information about normalizing line endings as well,
+and see linkgit:gitattributes[5] for more information about attribute files.
+
+[[windows-diff-control-m]]
+I'm on Windows and git diff shows my files as having a `^M` at the end.::
+ By default, Git expects files to be stored with Unix line endings. As such,
+ the carriage return (`^M`) that is part of a Windows line ending is shown
+ because it is considered to be trailing whitespace. Git defaults to showing
+ trailing whitespace only on new lines, not existing ones.
++
+You can store the files in the repository with Unix line endings and convert
+them automatically to your platform's line endings. To do that, set the
+configuration option `core.eol` to `native` and see the following entry for
+information about how to configure files as text or binary.
++
+You can also control this behavior with the `core.whitespace` setting if you
+don't wish to remove the carriage returns from your line endings.
+
+[[recommended-storage-settings]]
+What's the recommended way to store files in Git?::
+ While Git can store and handle any file of any type, there are some
+ settings that work better than others. In general, we recommend that
+ text files be stored in UTF-8 without a byte-order mark (BOM) with LF
+ (Unix-style) endings. We also recommend the use of UTF-8 (again,
+ without BOM) in commit messages. These are the settings that work best
+ across platforms and with tools such as `git diff` and `git merge`.
++
+Additionally, if you have a choice between storage formats that are text based
+or non-text based, we recommend storing files in the text format and, if
+necessary, transforming them into the other format. For example, a text-based
+SQL dump with one record per line will work much better for diffing and merging
+than an actual database file. Similarly, text-based formats such as Markdown
+and AsciiDoc will work better than binary formats such as Microsoft Word and
+PDF.
++
+Similarly, storing binary dependencies (e.g., shared libraries or JAR files) or
+build products in the repository is generally not recommended. Dependencies and
+build products are best stored on an artifact or package server with only
+references, URLs, and hashes stored in the repository.
++
+We also recommend setting a linkgit:gitattributes[5] file to explicitly mark
+which files are text and which are binary. If you want Git to guess, you can
+set the attribute `text=auto`. For example, the following might be appropriate
+in some projects:
++
+----
+# By default, guess.
+* text=auto
+# Mark all C files as text.
+*.c text
+# Mark all JPEG files as binary.
+*.jpg binary
+----
++
+These settings help tools pick the right format for output such as patches and
+result in files being checked out in the appropriate line ending for the
+platform.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 3dccab5..31b601e 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -404,6 +404,35 @@ Both standard output and standard error output are forwarded to
`git send-pack` on the other end, so you can simply `echo` messages
for the user.
+reference-transaction
+~~~~~~~~~~~~~~~~~~~~~
+
+This hook is invoked by any Git command that performs reference
+updates. It executes whenever a reference transaction is prepared,
+committed or aborted and may thus get called multiple times.
+
+The hook takes exactly one argument, which is the current state the
+given reference transaction is in:
+
+ - "prepared": All reference updates have been queued to the
+ transaction and references were locked on disk.
+
+ - "committed": The reference transaction was committed and all
+ references now have their respective new value.
+
+ - "aborted": The reference transaction was aborted, no changes
+ were performed and the locks have been released.
+
+For each reference update that was added to the transaction, the hook
+receives on standard input a line of the format:
+
+ <old-value> SP <new-value> SP <ref-name> LF
+
+The exit status of the hook is ignored for any state except for the
+"prepared" state. In the "prepared" state, a non-zero exit status will
+cause the transaction to be aborted. The hook will not be called with
+"aborted" state in that case.
+
push-to-checkout
~~~~~~~~~~~~~~~~
@@ -522,12 +551,61 @@ The exit status determines whether git will use the data from the
hook to limit its search. On error, it will fall back to verifying
all files and folders.
+p4-changelist
+~~~~~~~~~~~~~
+
+This hook is invoked by `git-p4 submit`.
+
+The `p4-changelist` hook is executed after the changelist
+message has been edited by the user. It can be bypassed with the
+`--no-verify` option. It takes a single parameter, the name
+of the file that holds the proposed changelist text. Exiting
+with a non-zero status causes the command to abort.
+
+The hook is allowed to edit the changelist file and can be used
+to normalize the text into some project standard format. It can
+also be used to refuse the Submit after inspect the message file.
+
+Run `git-p4 submit --help` for details.
+
+p4-prepare-changelist
+~~~~~~~~~~~~~~~~~~~~~
+
+This hook is invoked by `git-p4 submit`.
+
+The `p4-prepare-changelist` hook is executed right after preparing
+the default changelist message and before the editor is started.
+It takes one parameter, the name of the file that contains the
+changelist text. Exiting with a non-zero status from the script
+will abort the process.
+
+The purpose of the hook is to edit the message file in place,
+and it is not supressed by the `--no-verify` option. This hook
+is called even if `--prepare-p4-only` is set.
+
+Run `git-p4 submit --help` for details.
+
+p4-post-changelist
+~~~~~~~~~~~~~~~~~~
+
+This hook is invoked by `git-p4 submit`.
+
+The `p4-post-changelist` hook is invoked after the submit has
+successfully occured in P4. It takes no parameters and is meant
+primarily for notification and cannot affect the outcome of the
+git p4 submit action.
+
+Run `git-p4 submit --help` for details.
+
p4-pre-submit
~~~~~~~~~~~~~
This hook is invoked by `git-p4 submit`. It takes no parameters and nothing
from standard input. Exiting with non-zero status from this script prevent
-`git-p4 submit` from launching. Run `git-p4 submit --help` for details.
+`git-p4 submit` from launching. It can be bypassed with the `--no-verify`
+command line option. Run `git-p4 submit --help` for details.
+
+
post-index-change
~~~~~~~~~~~~~~~~~
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index 67275fd..539b4e1 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -49,9 +49,9 @@ submodule.<name>.update::
submodule.<name>.branch::
A remote branch name for tracking updates in the upstream submodule.
- If the option is not specified, it defaults to 'master'. A special
- value of `.` is used to indicate that the name of the branch in the
- submodule should be the same name as the current branch in the
+ If the option is not specified, it defaults to the remote 'HEAD'.
+ A special value of `.` is used to indicate that the name of the branch
+ in the submodule should be the same name as the current branch in the
current repository. See the `--remote` documentation in
linkgit:git-submodule[1] for details.
diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt
index f48a031..6f1e269 100644
--- a/Documentation/gitremote-helpers.txt
+++ b/Documentation/gitremote-helpers.txt
@@ -238,6 +238,9 @@ the remote repository.
`--signed-tags=verbatim` to linkgit:git-fast-export[1]. In the
absence of this capability, Git will use `--signed-tags=warn-strip`.
+'object-format'::
+ This indicates that the helper is able to interact with the remote
+ side using an explicit hash algorithm extension.
COMMANDS
@@ -257,12 +260,14 @@ Support for this command is mandatory.
'list'::
Lists the refs, one per line, in the format "<value> <name>
[<attr> ...]". The value may be a hex sha1 hash, "@<dest>" for
- a symref, or "?" to indicate that the helper could not get the
- value of the ref. A space-separated list of attributes follows
- the name; unrecognized attributes are ignored. The list ends
- with a blank line.
+ a symref, ":<keyword> <value>" for a key-value pair, or
+ "?" to indicate that the helper could not get the value of the
+ ref. A space-separated list of attributes follows the name;
+ unrecognized attributes are ignored. The list ends with a
+ blank line.
+
See REF LIST ATTRIBUTES for a list of currently defined attributes.
+See REF LIST KEYWORDS for a list of currently defined keywords.
+
Supported if the helper has the "fetch" or "import" capability.
@@ -405,7 +410,9 @@ Supported if the helper has the "connect" capability.
trying to fall back). After line feed terminating the positive
(empty) response, the output of the service starts. Messages
(both request and response) must consist of zero or more
- PKT-LINEs, terminating in a flush packet. The client must not
+ PKT-LINEs, terminating in a flush packet. Response messages will
+ then have a response end packet after the flush packet to
+ indicate the end of a response. The client must not
expect the server to store any state in between request-response
pairs. After the connection ends, the remote helper exits.
+
@@ -430,6 +437,18 @@ attributes are defined.
This ref is unchanged since the last import or fetch, although
the helper cannot necessarily determine what value that produced.
+REF LIST KEYWORDS
+-----------------
+
+The 'list' command may produce a list of key-value pairs.
+The following keys are defined.
+
+'object-format'::
+ The refs are using the given hash algorithm. This keyword is only
+ used if the server and client both support the object-format
+ extension.
+
+
OPTIONS
-------
@@ -514,6 +533,14 @@ set by Git if the remote helper has the 'option' capability.
transaction. If successful, all refs will be updated, or none will. If the
remote side does not support this capability, the push will fail.
+'option object-format' {'true'|algorithm}::
+ If 'true', indicate that the caller wants hash algorithm information
+ to be passed back from the remote. This mode is used when fetching
+ refs.
++
+If set to an algorithm, indicate that the caller wants to interact with
+the remote side using that algorithm.
+
SEE ALSO
--------
linkgit:git-remote[1]
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt
index c476f89..f9f4e65 100644
--- a/Documentation/gitsubmodules.txt
+++ b/Documentation/gitsubmodules.txt
@@ -271,7 +271,8 @@ will not be checked out by default; You can instruct 'clone' to recurse
into submodules. The 'init' and 'update' subcommands of 'git submodule'
will maintain submodules checked out and at an appropriate revision in
your working tree. Alternatively you can set 'submodule.recurse' to have
-'checkout' recursing into submodules.
+'checkout' recursing into submodules (note that 'submodule.recurse' also
+affects other git commands, see linkgit:git-config[1] for a complete list).
SEE ALSO
diff --git a/Documentation/gitworkflows.txt b/Documentation/gitworkflows.txt
index abc0dc6..47cf97f 100644
--- a/Documentation/gitworkflows.txt
+++ b/Documentation/gitworkflows.txt
@@ -85,15 +85,15 @@ As a given feature goes from experimental to stable, it also
There is a fourth official branch that is used slightly differently:
-* 'pu' (proposed updates) is an integration branch for things that are
- not quite ready for inclusion yet (see "Integration Branches"
- below).
+* 'seen' (patches seen by the maintainer) is an integration branch for
+ things that are not quite ready for inclusion yet (see "Integration
+ Branches" below).
Each of the four branches is usually a direct descendant of the one
above it.
Conceptually, the feature enters at an unstable branch (usually 'next'
-or 'pu'), and "graduates" to 'master' for the next release once it is
+or 'seen'), and "graduates" to 'master' for the next release once it is
considered stable enough.
@@ -207,7 +207,7 @@ If you make it (very) clear that this branch is going to be deleted
right after the testing, you can even publish this branch, for example
to give the testers a chance to work with it, or other developers a
chance to see if their in-progress work will be compatible. `git.git`
-has such an official throw-away integration branch called 'pu'.
+has such an official throw-away integration branch called 'seen'.
Branch management for a release
@@ -291,8 +291,8 @@ This will not happen if the content of the branches was verified as
described in the previous section.
-Branch management for next and pu after a feature release
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Branch management for next and seen after a feature release
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After a feature release, the integration branch 'next' may optionally be
rewound and rebuilt from the tip of 'master' using the surviving
@@ -319,8 +319,8 @@ so.
If you do this, then you should make a public announcement indicating
that 'next' was rewound and rebuilt.
-The same rewind and rebuild process may be followed for 'pu'. A public
-announcement is not necessary since 'pu' is a throw-away branch, as
+The same rewind and rebuild process may be followed for 'seen'. A public
+announcement is not necessary since 'seen' is a throw-away branch, as
described above.
diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt
index ca43787..a67130d 100644
--- a/Documentation/howto/maintain-git.txt
+++ b/Documentation/howto/maintain-git.txt
@@ -66,7 +66,7 @@ this mailing list after each feature release is made.
demonstrated to be regression free. New changes are tested
in 'next' before merged to 'master'.
- - 'pu' branch is used to publish other proposed changes that do
+ - 'seen' branch is used to publish other proposed changes that do
not yet pass the criteria set for 'next'.
- The tips of 'master' and 'maint' branches will not be rewound to
@@ -76,7 +76,7 @@ this mailing list after each feature release is made.
of the cycle.
- Usually 'master' contains all of 'maint' and 'next' contains all
- of 'master'. 'pu' contains all the topics merged to 'next', but
+ of 'master'. 'seen' contains all the topics merged to 'next', but
is rebuilt directly on 'master'.
- The tip of 'master' is meant to be more stable than any
@@ -154,15 +154,17 @@ by doing the following:
- Anything unobvious that is applicable to 'master' (in other
words, does not depend on anything that is still in 'next'
and not in 'master') is applied to a new topic branch that
- is forked from the tip of 'master'. This includes both
+ is forked from the tip of 'master' (or the last feature release,
+ which is a bit older than 'master'). This includes both
enhancements and unobvious fixes to 'master'. A topic
branch is named as ai/topic where "ai" is two-letter string
named after author's initial and "topic" is a descriptive name
of the topic (in other words, "what's the series is about").
- An unobvious fix meant for 'maint' is applied to a new
- topic branch that is forked from the tip of 'maint'. The
- topic is named as ai/maint-topic.
+ topic branch that is forked from the tip of 'maint' (or the
+ oldest and still relevant maintenance branch). The
+ topic may be named as ai/maint-topic.
- Changes that pertain to an existing topic are applied to
the branch, but:
@@ -174,24 +176,40 @@ by doing the following:
- Replacement patches to an existing topic are accepted only
for commits not in 'next'.
- The above except the "replacement" are all done with:
+ The initial round is done with:
$ git checkout ai/topic ;# or "git checkout -b ai/topic master"
$ git am -sc3 mailbox
- while patch replacement is often done by:
+ and replacing an existing topic with subsequent round is done with:
- $ git format-patch ai/topic~$n..ai/topic ;# export existing
+ $ git checkout master...ai/topic ;# try to reapply to the same base
+ $ git am -sc3 mailbox
+
+ to prepare the new round on a detached HEAD, and then
+
+ $ git range-diff @{-1}...
+ $ git diff @{-1}
- then replace some parts with the new patch, and reapplying:
+ to double check what changed since the last round, and finally
- $ git checkout ai/topic
- $ git reset --hard ai/topic~$n
- $ git am -sc3 -s 000*.txt
+ $ git checkout -B @{-1}
+
+ to conclude (the last step is why a topic already in 'next' is
+ not replaced but updated incrementally).
+
+ Whether it is the initial round or a subsequent round, the topic
+ may not build even in isolation, or may break the build when
+ merged to integration branches due to bugs. There may already
+ be obvious and trivial improvements suggested on the list. The
+ maintainer often adds an extra commit, with "SQUASH???" in its
+ title, to fix things up, before publishing the integration
+ branches to make it usable by other developers for testing.
+ These changes are what the maintainer is not 100% committed to
+ (trivial typofixes etc. are often squashed directly into the
+ patches that need fixing, without being applied as a separate
+ "SQUASH???" commit), so that they can be removed easily as needed.
- The full test suite is always run for 'maint' and 'master'
- after patch application; for topic branches the tests are run
- as time permits.
- Merge maint to master as needed:
@@ -211,12 +229,12 @@ by doing the following:
series?)
- Prepare 'jch' branch, which is used to represent somewhere
- between 'master' and 'pu' and often is slightly ahead of 'next'.
+ between 'master' and 'seen' and often is slightly ahead of 'next'.
- $ Meta/Reintegrate master..pu >Meta/redo-jch.sh
+ $ Meta/Reintegrate master..seen >Meta/redo-jch.sh
The result is a script that lists topics to be merged in order to
- rebuild 'pu' as the input to Meta/Reintegrate script. Remove
+ rebuild 'seen' as the input to Meta/Reintegrate script. Remove
later topics that should not be in 'jch' yet. Add a line that
consists of '### match next' before the name of the first topic
in the output that should be in 'jch' but not in 'next' yet.
@@ -273,29 +291,29 @@ by doing the following:
merged to 'master'. This may lose '### match next' marker;
add it again to the appropriate place when it happens.
- - Rebuild 'pu'.
+ - Rebuild 'seen'.
- $ Meta/Reintegrate master..pu >Meta/redo-pu.sh
+ $ Meta/Reintegrate master..seen >Meta/redo-seen.sh
- Edit the result by adding new topics that are not still in 'pu'
+ Edit the result by adding new topics that are not still in 'seen'
in the script. Then
- $ git checkout -B pu jch
- $ sh Meta/redo-pu.sh
+ $ git checkout -B seen jch
+ $ sh Meta/redo-seen.sh
- When all is well, clean up the redo-pu.sh script with
+ When all is well, clean up the redo-seen.sh script with
- $ sh Meta/redo-pu.sh -u
+ $ sh Meta/redo-seen.sh -u
Double check by running
- $ git branch --no-merged pu
+ $ git branch --no-merged seen
to see there is no unexpected leftover topics.
At this point, build-test the result for semantic conflicts, and
if there are, prepare an appropriate merge-fix first (see
- appendix), and rebuild the 'pu' branch from scratch, starting at
+ appendix), and rebuild the 'seen' branch from scratch, starting at
the tip of 'jch'.
- Update "What's cooking" message to review the updates to
@@ -305,14 +323,14 @@ by doing the following:
$ Meta/cook
- This script inspects the history between master..pu, finds tips
+ This script inspects the history between master..seen, finds tips
of topic branches, compares what it found with the current
contents in Meta/whats-cooking.txt, and updates that file.
- Topics not listed in the file but are found in master..pu are
+ Topics not listed in the file but are found in master..seen are
added to the "New topics" section, topics listed in the file that
- are no longer found in master..pu are moved to the "Graduated to
+ are no longer found in master..seen are moved to the "Graduated to
master" section, and topics whose commits changed their states
- (e.g. used to be only in 'pu', now merged to 'next') are updated
+ (e.g. used to be only in 'seen', now merged to 'next') are updated
with change markers "<<" and ">>".
Look for lines enclosed in "<<" and ">>"; they hold contents from
@@ -342,7 +360,7 @@ Observations
Some observations to be made.
* Each topic is tested individually, and also together with other
- topics cooking first in 'pu', then in 'jch' and then in 'next'.
+ topics cooking first in 'seen', then in 'jch' and then in 'next'.
Until it matures, no part of it is merged to 'master'.
* A topic already in 'next' can get fixes while still in
@@ -371,6 +389,14 @@ Some observations to be made.
be included in the next feature release. Being in the
'master' branch typically is.
+ * Due to the nature of "SQUASH???" fix-ups, if the original author
+ agrees with the suggested changes, it is OK to squash them to
+ appropriate patches in the next round (when the suggested change
+ is small enough, the author should not even bother with
+ "Helped-by"). It is also OK to drop them from the next round
+ when the original author does not agree with the suggestion, but
+ the author is expected to say why somewhere in the discussion.
+
Appendix
--------
@@ -385,7 +411,7 @@ new use of the variable under its old name. When these two topics
are merged together, the reference to the variable newly added by
the latter topic will still use the old name in the result.
-The Meta/Reintegrate script that is used by redo-jch and redo-pu
+The Meta/Reintegrate script that is used by redo-jch and redo-seen
scripts implements a crude but usable way to work this issue around.
When the script merges branch $X, it checks if "refs/merge-fix/$X"
exists, and if so, the effect of it is squashed into the result of
@@ -405,14 +431,14 @@ commit that can be squashed into a result of mechanical merge to
correct semantic conflicts.
After finding that the result of merging branch "ai/topic" to an
-integration branch had such a semantic conflict, say pu~4, check the
+integration branch had such a semantic conflict, say seen~4, check the
problematic merge out on a detached HEAD, edit the working tree to
fix the semantic conflict, and make a separate commit to record the
fix-up:
- $ git checkout pu~4
+ $ git checkout seen~4
$ git show -s --pretty=%s ;# double check
- Merge branch 'ai/topic' to pu
+ Merge branch 'ai/topic' to seen
$ edit
$ git commit -m 'merge-fix/ai/topic' -a
@@ -424,9 +450,9 @@ result:
Then double check the result by asking Meta/Reintegrate to redo the
merge:
- $ git checkout pu~5 ;# the parent of the problem merge
+ $ git checkout seen~5 ;# the parent of the problem merge
$ echo ai/topic | Meta/Reintegrate
- $ git diff pu~4
+ $ git diff seen~4
This time, because you prepared refs/merge-fix/ai/topic, the
resulting merge should have been tweaked to include the fix for the
@@ -438,7 +464,7 @@ branch needs this merge-fix is because another branch merged earlier
to the integration branch changed the underlying assumption ai/topic
branch made (e.g. ai/topic branch added a site to refer to a
variable, while the other branch renamed that variable and adjusted
-existing use sites), and if you changed redo-jch (or redo-pu) script
+existing use sites), and if you changed redo-jch (or redo-seen) script
to merge ai/topic branch before the other branch, then the above
merge-fix should not be applied while merging ai/topic, but should
instead be applied while merging the other branch. You would need
diff --git a/Documentation/howto/rebase-from-internal-branch.txt b/Documentation/howto/rebase-from-internal-branch.txt
index 02cb5f7..f2e10a7 100644
--- a/Documentation/howto/rebase-from-internal-branch.txt
+++ b/Documentation/howto/rebase-from-internal-branch.txt
@@ -4,7 +4,7 @@ Cc: Petr Baudis <pasky@suse.cz>, Linus Torvalds <torvalds@osdl.org>
Subject: Re: sending changesets from the middle of a git tree
Date: Sun, 14 Aug 2005 18:37:39 -0700
Abstract: In this article, JC talks about how he rebases the
- public "pu" branch using the core Git tools when he updates
+ public "seen" branch using the core Git tools when he updates
the "master" branch, and how "rebase" works. Also discussed
is how this applies to individual developers who sends patches
upstream.
@@ -20,8 +20,8 @@ Petr Baudis <pasky@suse.cz> writes:
> where Junio C Hamano <junkio@cox.net> told me that...
>> Linus Torvalds <torvalds@osdl.org> writes:
>>
->> > Junio, maybe you want to talk about how you move patches from your "pu"
->> > branch to the real branches.
+>> > Junio, maybe you want to talk about how you move patches from your
+>> > "seen" branch to the real branches.
>>
> Actually, wouldn't this be also precisely for what StGIT is intended to?
--------------------------------------
@@ -33,12 +33,12 @@ the kind of task StGIT is designed to do.
I just have done a simpler one, this time using only the core
Git tools.
-I had a handful of commits that were ahead of master in pu, and I
+I had a handful of commits that were ahead of master in 'seen', and I
wanted to add some documentation bypassing my usual habit of
-placing new things in pu first. At the beginning, the commit
+placing new things in 'seen' first. At the beginning, the commit
ancestry graph looked like this:
- *"pu" head
+ *"seen" head
master --> #1 --> #2 --> #3
So I started from master, made a bunch of edits, and committed:
@@ -50,7 +50,7 @@ So I started from master, made a bunch of edits, and committed:
After the commit, the ancestry graph would look like this:
- *"pu" head
+ *"seen" head
master^ --> #1 --> #2 --> #3
\
\---> master
@@ -58,31 +58,31 @@ After the commit, the ancestry graph would look like this:
The old master is now master^ (the first parent of the master).
The new master commit holds my documentation updates.
-Now I have to deal with "pu" branch.
+Now I have to deal with "seen" branch.
This is the kind of situation I used to have all the time when
Linus was the maintainer and I was a contributor, when you look
-at "master" branch being the "maintainer" branch, and "pu"
+at "master" branch being the "maintainer" branch, and "seen"
branch being the "contributor" branch. Your work started at the
tip of the "maintainer" branch some time ago, you made a lot of
progress in the meantime, and now the maintainer branch has some
other commits you do not have yet. And "git rebase" was written
with the explicit purpose of helping to maintain branches like
-"pu". You _could_ merge master to pu and keep going, but if you
+"seen". You _could_ merge master to 'seen' and keep going, but if you
eventually want to cherrypick and merge some but not necessarily
all changes back to the master branch, it often makes later
operations for _you_ easier if you rebase (i.e. carry forward
-your changes) "pu" rather than merge. So I ran "git rebase":
+your changes) "seen" rather than merge. So I ran "git rebase":
- $ git checkout pu
- $ git rebase master pu
+ $ git checkout seen
+ $ git rebase master seen
What this does is to pick all the commits since the current
-branch (note that I now am on "pu" branch) forked from the
+branch (note that I now am on "seen" branch) forked from the
master branch, and forward port these changes.
master^ --> #1 --> #2 --> #3
- \ *"pu" head
+ \ *"seen" head
\---> master --> #1' --> #2' --> #3'
The diff between master^ and #1 is applied to master and
@@ -92,7 +92,7 @@ commits are made similarly out of #2 and #3 commits.
Old #3 is not recorded in any of the .git/refs/heads/ file
anymore, so after doing this you will have dangling commit if
-you ran fsck-cache, which is normal. After testing "pu", you
+you ran fsck-cache, which is normal. After testing "seen", you
can run "git prune" to get rid of those original three commits.
While I am talking about "git rebase", I should talk about how
diff --git a/Documentation/howto/revert-branch-rebase.txt b/Documentation/howto/revert-branch-rebase.txt
index 149508e..a3e5595 100644
--- a/Documentation/howto/revert-branch-rebase.txt
+++ b/Documentation/howto/revert-branch-rebase.txt
@@ -15,7 +15,7 @@ One of the changes I pulled into the 'master' branch turns out to
break building Git with GCC 2.95. While they were well-intentioned
portability fixes, keeping things working with gcc-2.95 was also
important. Here is what I did to revert the change in the 'master'
-branch and to adjust the 'pu' branch, using core Git tools and
+branch and to adjust the 'seen' branch, using core Git tools and
barebone Porcelain.
First, prepare a throw-away branch in case I screw things up.
@@ -104,11 +104,11 @@ $ git diff master..revert-c99
says nothing.
-Then we rebase the 'pu' branch as usual.
+Then we rebase the 'seen' branch as usual.
------------------------------------------------
-$ git checkout pu
-$ git tag pu-anchor pu
+$ git checkout seen
+$ git tag seen-anchor seen
$ git rebase master
* Applying: Redo "revert" using three-way merge machinery.
First trying simple merge strategy to cherry-pick.
@@ -127,11 +127,11 @@ First trying simple merge strategy to cherry-pick.
First trying simple merge strategy to cherry-pick.
------------------------------------------------
-The temporary tag 'pu-anchor' is me just being careful, in case 'git
+The temporary tag 'seen-anchor' is me just being careful, in case 'git
rebase' screws up. After this, I can do these for sanity check:
------------------------------------------------
-$ git diff pu-anchor..pu ;# make sure we got the master fix.
+$ git diff seen-anchor..seen ;# make sure we got the master fix.
$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage.
$ make clean test ;# make sure it did not cause other breakage.
------------------------------------------------
@@ -140,7 +140,7 @@ Everything is in the good order. I do not need the temporary branch
or tag anymore, so remove them:
------------------------------------------------
-$ rm -f .git/refs/tags/pu-anchor
+$ rm -f .git/refs/tags/seen-anchor
$ git branch -d revert-c99
------------------------------------------------
@@ -168,18 +168,18 @@ Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f
And the final repository status looks like this:
------------------------------------------------
-$ git show-branch --more=1 master pu rc
+$ git show-branch --more=1 master seen rc
! [master] Revert "Replace zero-length array decls with []."
- ! [pu] git-repack: Add option to repack all objects.
+ ! [seen] git-repack: Add option to repack all objects.
* [rc] Merge refs/heads/master from .
---
- + [pu] git-repack: Add option to repack all objects.
- + [pu~1] More documentation updates.
- + [pu~2] Show commits in topo order and name all commits.
- + [pu~3] mailinfo and applymbox updates
- + [pu~4] Document "git cherry-pick" and "git revert"
- + [pu~5] Remove git-apply-patch-script.
- + [pu~6] Redo "revert" using three-way merge machinery.
+ + [seen] git-repack: Add option to repack all objects.
+ + [seen~1] More documentation updates.
+ + [seen~2] Show commits in topo order and name all commits.
+ + [seen~3] mailinfo and applymbox updates
+ + [seen~4] Document "git cherry-pick" and "git revert"
+ + [seen~5] Remove git-apply-patch-script.
+ + [seen~6] Redo "revert" using three-way merge machinery.
- [rc] Merge refs/heads/master from .
++* [master] Revert "Replace zero-length array decls with []."
- [rc~1] Merge refs/heads/master from .
diff --git a/Documentation/howto/update-hook-example.txt b/Documentation/howto/update-hook-example.txt
index 89821ec..151ee84 100644
--- a/Documentation/howto/update-hook-example.txt
+++ b/Documentation/howto/update-hook-example.txt
@@ -179,7 +179,7 @@ allowed-groups, to describe which heads can be pushed into by
whom. The format of each file would look like this:
refs/heads/master junio
- +refs/heads/pu junio
+ +refs/heads/seen junio
refs/heads/cogito$ pasky
refs/heads/bw/.* linus
refs/heads/tmp/.* .*
@@ -187,6 +187,6 @@ whom. The format of each file would look like this:
With this, Linus can push or create "bw/penguin" or "bw/zebra"
or "bw/panda" branches, Pasky can do only "cogito", and JC can
-do master and pu branches and make versioned tags. And anybody
-can do tmp/blah branches. The '+' sign at the pu record means
+do master and "seen" branches and make versioned tags. And anybody
+can do tmp/blah branches. The '+' sign at the "seen" record means
that JC can make non-fast-forward pushes on it.
diff --git a/Documentation/manpage-1.72.xsl b/Documentation/manpage-1.72.xsl
deleted file mode 100644
index b4d315c..0000000
--- a/Documentation/manpage-1.72.xsl
+++ /dev/null
@@ -1,14 +0,0 @@
-<!-- manpage-1.72.xsl:
- special settings for manpages rendered from asciidoc+docbook
- handles peculiarities in docbook-xsl 1.72.0 -->
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- version="1.0">
-
-<xsl:import href="manpage-base.xsl"/>
-
-<!-- these are the special values for the roff control characters
- needed for docbook-xsl 1.72.0 -->
-<xsl:param name="git.docbook.backslash">&#x2593;</xsl:param>
-<xsl:param name="git.docbook.dot" >&#x2302;</xsl:param>
-
-</xsl:stylesheet>
diff --git a/Documentation/manpage-base.xsl b/Documentation/manpage-base.xsl
deleted file mode 100644
index a264fa6..0000000
--- a/Documentation/manpage-base.xsl
+++ /dev/null
@@ -1,35 +0,0 @@
-<!-- manpage-base.xsl:
- special formatting for manpages rendered from asciidoc+docbook -->
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- version="1.0">
-
-<!-- these params silence some output from xmlto -->
-<xsl:param name="man.output.quietly" select="1"/>
-<xsl:param name="refentry.meta.get.quietly" select="1"/>
-
-<!-- convert asciidoc callouts to man page format;
- git.docbook.backslash and git.docbook.dot params
- must be supplied by another XSL file or other means -->
-<xsl:template match="co">
- <xsl:value-of select="concat(
- $git.docbook.backslash,'fB(',
- substring-after(@id,'-'),')',
- $git.docbook.backslash,'fR')"/>
-</xsl:template>
-<xsl:template match="calloutlist">
- <xsl:value-of select="$git.docbook.dot"/>
- <xsl:text>sp&#10;</xsl:text>
- <xsl:apply-templates/>
- <xsl:text>&#10;</xsl:text>
-</xsl:template>
-<xsl:template match="callout">
- <xsl:value-of select="concat(
- $git.docbook.backslash,'fB',
- substring-after(@arearefs,'-'),
- '. ',$git.docbook.backslash,'fR')"/>
- <xsl:apply-templates/>
- <xsl:value-of select="$git.docbook.dot"/>
- <xsl:text>br&#10;</xsl:text>
-</xsl:template>
-
-</xsl:stylesheet>
diff --git a/Documentation/manpage-bold-literal.xsl b/Documentation/manpage-bold-literal.xsl
index 94d6c1b..e13db85 100644
--- a/Documentation/manpage-bold-literal.xsl
+++ b/Documentation/manpage-bold-literal.xsl
@@ -8,11 +8,9 @@
this makes literal text easier to distinguish in manpages
viewed on a tty -->
<xsl:template match="literal|d:literal">
- <xsl:value-of select="$git.docbook.backslash"/>
- <xsl:text>fB</xsl:text>
+ <xsl:text>\fB</xsl:text>
<xsl:apply-templates/>
- <xsl:value-of select="$git.docbook.backslash"/>
- <xsl:text>fR</xsl:text>
+ <xsl:text>\fR</xsl:text>
</xsl:template>
</xsl:stylesheet>
diff --git a/Documentation/manpage-normal.xsl b/Documentation/manpage-normal.xsl
index a48f5b1..a9c7ec6 100644
--- a/Documentation/manpage-normal.xsl
+++ b/Documentation/manpage-normal.xsl
@@ -1,13 +1,26 @@
<!-- manpage-normal.xsl:
- special settings for manpages rendered from asciidoc+docbook
- handles anything we want to keep away from docbook-xsl 1.72.0 -->
+ special settings for manpages rendered from asciidoc+docbook -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
-<xsl:import href="manpage-base.xsl"/>
-<!-- these are the normal values for the roff control characters -->
-<xsl:param name="git.docbook.backslash">\</xsl:param>
-<xsl:param name="git.docbook.dot" >.</xsl:param>
+<!-- these params silence some output from xmlto -->
+<xsl:param name="man.output.quietly" select="1"/>
+<xsl:param name="refentry.meta.get.quietly" select="1"/>
+
+<!-- convert asciidoc callouts to man page format -->
+<xsl:template match="co">
+ <xsl:value-of select="concat('\fB(',substring-after(@id,'-'),')\fR')"/>
+</xsl:template>
+<xsl:template match="calloutlist">
+ <xsl:text>.sp&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;</xsl:text>
+</xsl:template>
+<xsl:template match="callout">
+ <xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/>
+ <xsl:apply-templates/>
+ <xsl:text>.br&#10;</xsl:text>
+</xsl:template>
</xsl:stylesheet>
diff --git a/Documentation/manpage-suppress-sp.xsl b/Documentation/manpage-suppress-sp.xsl
deleted file mode 100644
index a63c763..0000000
--- a/Documentation/manpage-suppress-sp.xsl
+++ /dev/null
@@ -1,21 +0,0 @@
-<!-- manpage-suppress-sp.xsl:
- special settings for manpages rendered from asciidoc+docbook
- handles erroneous, inline .sp in manpage output of some
- versions of docbook-xsl -->
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- version="1.0">
-
-<!-- attempt to work around spurious .sp at the tail of the line
- that some versions of docbook stylesheets seem to add -->
-<xsl:template match="simpara">
- <xsl:variable name="content">
- <xsl:apply-templates/>
- </xsl:variable>
- <xsl:value-of select="normalize-space($content)"/>
- <xsl:if test="not(ancestor::authorblurb) and
- not(ancestor::personblurb)">
- <xsl:text>&#10;&#10;</xsl:text>
- </xsl:if>
-</xsl:template>
-
-</xsl:stylesheet>
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 40dc4f5..80d4831 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -61,9 +61,12 @@ When not possible, refuse to merge and exit with a non-zero status.
-S[<keyid>]::
--gpg-sign[=<keyid>]::
+--no-gpg-sign::
GPG-sign the resulting merge commit. The `keyid` argument is
optional and defaults to the committer identity; if specified,
- it must be stuck to the option without a space.
+ it must be stuck to the option without a space. `--no-gpg-sign`
+ is useful to countermand both `commit.gpgSign` configuration variable,
+ and earlier `--gpg-sign`.
--log[=<n>]::
--no-log::
@@ -157,6 +160,14 @@ ifndef::git-pull[]
endif::git-pull[]
+--autostash::
+--no-autostash::
+ Automatically create a temporary stash entry before the operation
+ begins, and apply it after the operation ends. This means
+ that you can run the operation on a dirty worktree. However, use
+ with care: the final stash application after a successful
+ merge might result in non-trivial conflicts.
+
--allow-unrelated-histories::
By default, `git merge` command refuses to merge histories
that do not share a common ancestor. This option can be
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index a4b6f49..84bbc74 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -83,6 +83,12 @@ placeholders, its output is not affected by other options like
<full commit message>
+* 'mboxrd'
++
+Like 'email', but lines in the commit message starting with "From "
+(preceded by zero or more ">") are quoted with ">" so they aren't
+confused as starting a new commit.
+
* 'raw'
+
The 'raw' format shows the entire commit exactly as
@@ -190,8 +196,8 @@ The placeholders are:
'%ce':: committer email
'%cE':: committer email (respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1])
-'%cl':: author email local-part (the part before the '@' sign)
-'%cL':: author local-part (see '%cl') respecting .mailmap, see
+'%cl':: committer email local-part (the part before the '@' sign)
+'%cL':: committer local-part (see '%cl') respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1])
'%cd':: committer date (format respects --date= option)
'%cD':: committer date, RFC2822 style
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt
index 7d3a60f..95ea849 100644
--- a/Documentation/pull-fetch-param.txt
+++ b/Documentation/pull-fetch-param.txt
@@ -19,7 +19,8 @@ ifndef::git-pull[]
(see <<CRTB,CONFIGURED REMOTE-TRACKING BRANCHES>> below).
endif::git-pull[]
ifdef::git-pull[]
- (see linkgit:git-fetch[1]).
+ (see the section "CONFIGURED REMOTE-TRACKING BRANCHES"
+ in linkgit:git-fetch[1]).
endif::git-pull[]
+
The format of a <refspec> parameter is an optional plus
diff --git a/Documentation/rev-list-description.txt b/Documentation/rev-list-description.txt
new file mode 100644
index 0000000..a9efa7f
--- /dev/null
+++ b/Documentation/rev-list-description.txt
@@ -0,0 +1,61 @@
+List commits that are reachable by following the `parent` links from the
+given commit(s), but exclude commits that are reachable from the one(s)
+given with a '{caret}' in front of them. The output is given in reverse
+chronological order by default.
+
+You can think of this as a set operation. Commits reachable from any of
+the commits given on the command line form a set, and then commits reachable
+from any of the ones given with '{caret}' in front are subtracted from that
+set. The remaining commits are what comes out in the command's output.
+Various other options and paths parameters can be used to further limit the
+result.
+
+Thus, the following command:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list foo bar ^baz
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log foo bar ^baz
+-----------------------------------------------------------------------
+endif::git-log[]
+
+means "list all the commits which are reachable from 'foo' or 'bar', but
+not from 'baz'".
+
+A special notation "'<commit1>'..'<commit2>'" can be used as a
+short-hand for "^'<commit1>' '<commit2>'". For example, either of
+the following may be used interchangeably:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list origin..HEAD
+$ git rev-list HEAD ^origin
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log origin..HEAD
+$ git log HEAD ^origin
+-----------------------------------------------------------------------
+endif::git-log[]
+
+Another special notation is "'<commit1>'...'<commit2>'" which is useful
+for merges. The resulting set of commits is the symmetric difference
+between the two operands. The following two commands are equivalent:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list A B --not $(git merge-base --all A B)
+$ git rev-list A...B
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log A B --not $(git merge-base --all A B)
+$ git log A...B
+-----------------------------------------------------------------------
+endif::git-log[]
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index bfd02ad..b01b2b6 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -342,6 +342,12 @@ Default mode::
branches if the end result is the same (i.e. merging branches
with the same content)
+--show-pulls::
+ Include all commits from the default mode, but also any merge
+ commits that are not TREESAME to the first parent but are
+ TREESAME to a later parent. This mode is helpful for showing
+ the merge commits that "first introduced" a change to a branch.
+
--full-history::
Same as the default mode, but does not prune some history.
@@ -534,7 +540,7 @@ Note the major differences in `N`, `P`, and `Q` over `--full-history`:
parent and is TREESAME.
--
-Finally, there is a fifth simplification mode available:
+There is another simplification mode available:
--ancestry-path::
Limit the displayed commits to those directly on the ancestry
@@ -573,6 +579,135 @@ option does. Applied to the 'D..M' range, it results in:
L--M
-----------------------------------------------------------------------
+Before discussing another option, `--show-pulls`, we need to
+create a new example history.
+
+A common problem users face when looking at simplified history is that a
+commit they know changed a file somehow does not appear in the file's
+simplified history. Let's demonstrate a new example and show how options
+such as `--full-history` and `--simplify-merges` works in that case:
+
+-----------------------------------------------------------------------
+ .-A---M-----C--N---O---P
+ / / \ \ \/ / /
+ I B \ R-'`-Z' /
+ \ / \/ /
+ \ / /\ /
+ `---X--' `---Y--'
+-----------------------------------------------------------------------
+
+For this example, suppose `I` created `file.txt` which was modified by
+`A`, `B`, and `X` in different ways. The single-parent commits `C`, `Z`,
+and `Y` do not change `file.txt`. The merge commit `M` was created by
+resolving the merge conflict to include both changes from `A` and `B`
+and hence is not TREESAME to either. The merge commit `R`, however, was
+created by ignoring the contents of `file.txt` at `M` and taking only
+the contents of `file.txt` at `X`. Hence, `R` is TREESAME to `X` but not
+`M`. Finally, the natural merge resolution to create `N` is to take the
+contents of `file.txt` at `R`, so `N` is TREESAME to `R` but not `C`.
+The merge commits `O` and `P` are TREESAME to their first parents, but
+not to their second parents, `Z` and `Y` respectively.
+
+When using the default mode, `N` and `R` both have a TREESAME parent, so
+those edges are walked and the others are ignored. The resulting history
+graph is:
+
+-----------------------------------------------------------------------
+ I---X
+-----------------------------------------------------------------------
+
+When using `--full-history`, Git walks every edge. This will discover
+the commits `A` and `B` and the merge `M`, but also will reveal the
+merge commits `O` and `P`. With parent rewriting, the resulting graph is:
+
+-----------------------------------------------------------------------
+ .-A---M--------N---O---P
+ / / \ \ \/ / /
+ I B \ R-'`--' /
+ \ / \/ /
+ \ / /\ /
+ `---X--' `------'
+-----------------------------------------------------------------------
+
+Here, the merge commits `O` and `P` contribute extra noise, as they did
+not actually contribute a change to `file.txt`. They only merged a topic
+that was based on an older version of `file.txt`. This is a common
+issue in repositories using a workflow where many contributors work in
+parallel and merge their topic branches along a single trunk: manu
+unrelated merges appear in the `--full-history` results.
+
+When using the `--simplify-merges` option, the commits `O` and `P`
+disappear from the results. This is because the rewritten second parents
+of `O` and `P` are reachable from their first parents. Those edges are
+removed and then the commits look like single-parent commits that are
+TREESAME to their parent. This also happens to the commit `N`, resulting
+in a history view as follows:
+
+-----------------------------------------------------------------------
+ .-A---M--.
+ / / \
+ I B R
+ \ / /
+ \ / /
+ `---X--'
+-----------------------------------------------------------------------
+
+In this view, we see all of the important single-parent changes from
+`A`, `B`, and `X`. We also see the carefully-resolved merge `M` and the
+not-so-carefully-resolved merge `R`. This is usually enough information
+to determine why the commits `A` and `B` "disappeared" from history in
+the default view. However, there are a few issues with this approach.
+
+The first issue is performance. Unlike any previous option, the
+`--simplify-merges` option requires walking the entire commit history
+before returning a single result. This can make the option difficult to
+use for very large repositories.
+
+The second issue is one of auditing. When many contributors are working
+on the same repository, it is important which merge commits introduced
+a change into an important branch. The problematic merge `R` above is
+not likely to be the merge commit that was used to merge into an
+important branch. Instead, the merge `N` was used to merge `R` and `X`
+into the important branch. This commit may have information about why
+the change `X` came to override the changes from `A` and `B` in its
+commit message.
+
+--show-pulls::
+ In addition to the commits shown in the default history, show
+ each merge commit that is not TREESAME to its first parent but
+ is TREESAME to a later parent.
++
+When a merge commit is included by `--show-pulls`, the merge is
+treated as if it "pulled" the change from another branch. When using
+`--show-pulls` on this example (and no other options) the resulting
+graph is:
++
+-----------------------------------------------------------------------
+ I---X---R---N
+-----------------------------------------------------------------------
++
+Here, the merge commits `R` and `N` are included because they pulled
+the commits `X` and `R` into the base branch, respectively. These
+merges are the reason the commits `A` and `B` do not appear in the
+default history.
++
+When `--show-pulls` is paired with `--simplify-merges`, the
+graph includes all of the necessary information:
++
+-----------------------------------------------------------------------
+ .-A---M--. N
+ / / \ /
+ I B R
+ \ / /
+ \ / /
+ `---X--'
+-----------------------------------------------------------------------
++
+Notice that since `M` is reachable from `R`, the edge from `N` to `M`
+was simplified away. However, `N` still appears in the history as an
+important commit because it "pulled" the change `R` into the main
+branch.
+
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
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 97f995e..d9169c0 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -233,7 +233,7 @@ G H I J
A = = A^0
B = A^ = A^1 = A~1
- C = A^2 = A^2
+ C = = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
@@ -254,6 +254,9 @@ specifying a single revision, using the notation described in the
previous section, means the set of commits `reachable` from the given
commit.
+Specifying several revisions means the set of commits reachable from
+any of the given commits.
+
A commit's reachable set is the commit itself and the commits in
its ancestry chain.
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt
index 4f07cea..6b60855 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -656,7 +656,8 @@ The "exec_id" field is a command-unique id and is only useful if the
------------
`"def_param"`::
- This event is generated to log a global parameter.
+ This event is generated to log a global parameter, such as a config
+ setting, command-line flag, or environment variable.
+
------------
{
diff --git a/Documentation/technical/commit-graph-format.txt b/Documentation/technical/commit-graph-format.txt
index a4f1744..4405410 100644
--- a/Documentation/technical/commit-graph-format.txt
+++ b/Documentation/technical/commit-graph-format.txt
@@ -17,6 +17,9 @@ metadata, including:
- The parents of the commit, stored using positional references within
the graph file.
+- The Bloom filter of the commit carrying the paths that were changed between
+ the commit and its first parent, if requested.
+
These positional references are stored as unsigned 32-bit integers
corresponding to the array position within the list of commit OIDs. Due
to some special constants we use to track parents, we can store at most
@@ -29,7 +32,7 @@ the body into "chunks" and provide a binary lookup table at the beginning
of the body. The header includes certain values, such as number of chunks
and hash type.
-All 4-byte numbers are in network order.
+All multi-byte numbers are in network byte order.
HEADER:
@@ -93,6 +96,33 @@ CHUNK DATA:
positions for the parents until reaching a value with the most-significant
bit on. The other bits correspond to the position of the last parent.
+ Bloom Filter Index (ID: {'B', 'I', 'D', 'X'}) (N * 4 bytes) [Optional]
+ * The ith entry, BIDX[i], stores the number of bytes in all Bloom filters
+ from commit 0 to commit i (inclusive) in lexicographic order. The Bloom
+ filter for the i-th commit spans from BIDX[i-1] to BIDX[i] (plus header
+ length), where BIDX[-1] is 0.
+ * The BIDX chunk is ignored if the BDAT chunk is not present.
+
+ Bloom Filter Data (ID: {'B', 'D', 'A', 'T'}) [Optional]
+ * It starts with header consisting of three unsigned 32-bit integers:
+ - Version of the hash algorithm being used. We currently only support
+ value 1 which corresponds to the 32-bit version of the murmur3 hash
+ implemented exactly as described in
+ https://en.wikipedia.org/wiki/MurmurHash#Algorithm and the double
+ hashing technique using seed values 0x293ae76f and 0x7e646e2 as
+ described in https://doi.org/10.1007/978-3-540-30494-4_26 "Bloom Filters
+ in Probabilistic Verification"
+ - The number of times a path is hashed and hence the number of bit positions
+ that cumulatively determine whether a file is present in the commit.
+ - The minimum number of bits 'b' per entry in the Bloom filter. If the filter
+ contains 'n' entries, then the filter size is the minimum number of 64-bit
+ words that contain n*b bits.
+ * The rest of the chunk is the concatenation of all the computed Bloom
+ filters for the commits in lexicographic order.
+ * Note: Commits with no changes or more than 512 changes have Bloom filters
+ of length zero.
+ * The BDAT chunk is present if and only if BIDX is present.
+
Base Graphs List (ID: {'B', 'A', 'S', 'E'}) [Optional]
This list of H-byte hashes describe a set of B commit-graph files that
form a commit-graph chain. The graph position for the ith commit in this
diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt
index 9c5b6f0..51a79e6 100644
--- a/Documentation/technical/http-protocol.txt
+++ b/Documentation/technical/http-protocol.txt
@@ -216,7 +216,7 @@ smart server reply:
S: 001e# service=git-upload-pack\n
S: 0000
S: 004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint\0multi_ack\n
- S: 0042d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
+ S: 003fd049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
S: 003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0\n
S: 003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}\n
S: 0000
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index d5ce4ee..a4573d1 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -96,7 +96,7 @@ Basically what the Git client is doing to connect to an 'upload-pack'
process on the server side over the Git protocol is this:
$ echo -e -n \
- "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
+ "003agit-upload-pack /schacon/gitbook.git\0host=example.com\0" |
nc -v example.com 9418
@@ -171,9 +171,9 @@ with a version number (if "version=1" is sent as an Extra Parameter),
and a listing of each reference it has (all branches and tags) along
with the object name that each reference currently points to.
- $ echo -e -n "0044git-upload-pack /schacon/gitbook.git\0host=example.com\0\0version=1\0" |
+ $ echo -e -n "0045git-upload-pack /schacon/gitbook.git\0host=example.com\0\0version=1\0" |
nc -v example.com 9418
- 000aversion 1
+ 000eversion 1
00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack
side-band side-band-64k ofs-delta shallow no-progress include-tag
00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
diff --git a/Documentation/technical/packfile-uri.txt b/Documentation/technical/packfile-uri.txt
new file mode 100644
index 0000000..318713a
--- /dev/null
+++ b/Documentation/technical/packfile-uri.txt
@@ -0,0 +1,78 @@
+Packfile URIs
+=============
+
+This feature allows servers to serve part of their packfile response as URIs.
+This allows server designs that improve scalability in bandwidth and CPU usage
+(for example, by serving some data through a CDN), and (in the future) provides
+some measure of resumability to clients.
+
+This feature is available only in protocol version 2.
+
+Protocol
+--------
+
+The server advertises the `packfile-uris` capability.
+
+If the client then communicates which protocols (HTTPS, etc.) it supports with
+a `packfile-uris` argument, the server MAY send a `packfile-uris` section
+directly before the `packfile` section (right after `wanted-refs` if it is
+sent) containing URIs of any of the given protocols. The URIs point to
+packfiles that use only features that the client has declared that it supports
+(e.g. ofs-delta and thin-pack). See protocol-v2.txt for the documentation of
+this section.
+
+Clients should then download and index all the given URIs (in addition to
+downloading and indexing the packfile given in the `packfile` section of the
+response) before performing the connectivity check.
+
+Server design
+-------------
+
+The server can be trivially made compatible with the proposed protocol by
+having it advertise `packfile-uris`, tolerating the client sending
+`packfile-uris`, and never sending any `packfile-uris` section. But we should
+include some sort of non-trivial implementation in the Minimum Viable Product,
+at least so that we can test the client.
+
+This is the implementation: a feature, marked experimental, that allows the
+server to be configured by one or more `uploadpack.blobPackfileUri=<sha1>
+<uri>` entries. Whenever the list of objects to be sent is assembled, all such
+blobs are excluded, replaced with URIs. The client will download those URIs,
+expecting them to each point to packfiles containing single blobs.
+
+Client design
+-------------
+
+The client has a config variable `fetch.uriprotocols` that determines which
+protocols the end user is willing to use. By default, this is empty.
+
+When the client downloads the given URIs, it should store them with "keep"
+files, just like it does with the packfile in the `packfile` section. These
+additional "keep" files can only be removed after the refs have been updated -
+just like the "keep" file for the packfile in the `packfile` section.
+
+The division of work (initial fetch + additional URIs) introduces convenient
+points for resumption of an interrupted clone - such resumption can be done
+after the Minimum Viable Product (see "Future work").
+
+Future work
+-----------
+
+The protocol design allows some evolution of the server and client without any
+need for protocol changes, so only a small-scoped design is included here to
+form the MVP. For example, the following can be done:
+
+ * On the server, more sophisticated means of excluding objects (e.g. by
+ specifying a commit to represent that commit and all objects that it
+ references).
+ * On the client, resumption of clone. If a clone is interrupted, information
+ could be recorded in the repository's config and a "clone-resume" command
+ can resume the clone in progress. (Resumption of subsequent fetches is more
+ difficult because that must deal with the user wanting to use the repository
+ even after the fetch was interrupted.)
+
+There are some possible features that will require a change in protocol:
+
+ * Additional HTTP headers (e.g. authentication)
+ * Byte range support
+ * Different file formats referenced by URIs (e.g. raw object)
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index 2b267c0..36ccd14 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -176,6 +176,21 @@ agent strings are purely informative for statistics and debugging
purposes, and MUST NOT be used to programmatically assume the presence
or absence of particular features.
+object-format
+-------------
+
+This capability, which takes a hash algorithm as an argument, indicates
+that the server supports the given hash algorithms. It may be sent
+multiple times; if so, the first one given is the one used in the ref
+advertisement.
+
+When provided by the client, this indicates that it intends to use the
+given hash algorithm to communicate. The algorithm provided must be one
+that the server supports.
+
+If this capability is not provided, it is assumed that the only
+supported algorithm is SHA-1.
+
symref
------
diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
index 7e3766c..e597b74 100644
--- a/Documentation/technical/protocol-v2.txt
+++ b/Documentation/technical/protocol-v2.txt
@@ -33,6 +33,8 @@ In protocol v2 these special packets will have the following semantics:
* '0000' Flush Packet (flush-pkt) - indicates the end of a message
* '0001' Delimiter Packet (delim-pkt) - separates sections of a message
+ * '0002' Message Packet (response-end-pkt) - indicates the end of a response
+ for stateless connections
Initial Client Request
----------------------
@@ -323,13 +325,26 @@ included in the client's request:
indicating its sideband (1, 2, or 3), and the server may send "0005\2"
(a PKT-LINE of sideband 2 with no payload) as a keepalive packet.
+If the 'packfile-uris' feature is advertised, the following argument
+can be included in the client's request as well as the potential
+addition of the 'packfile-uris' section in the server's response as
+explained below.
+
+ packfile-uris <comma-separated list of protocols>
+ Indicates to the server that the client is willing to receive
+ URIs of any of the given protocols in place of objects in the
+ sent packfile. Before performing the connectivity check, the
+ client should download from all given URIs. Currently, the
+ protocols supported are "http" and "https".
+
The response of `fetch` is broken into a number of sections separated by
delimiter packets (0001), with each section beginning with its section
-header.
+header. Most sections are sent only when the packfile is sent.
- output = *section
- section = (acknowledgments | shallow-info | wanted-refs | packfile)
- (flush-pkt | delim-pkt)
+ output = acknowledgements flush-pkt |
+ [acknowledgments delim-pkt] [shallow-info delim-pkt]
+ [wanted-refs delim-pkt] [packfile-uris delim-pkt]
+ packfile flush-pkt
acknowledgments = PKT-LINE("acknowledgments" LF)
(nak | *ack)
@@ -347,13 +362,17 @@ header.
*PKT-LINE(wanted-ref LF)
wanted-ref = obj-id SP refname
+ packfile-uris = PKT-LINE("packfile-uris" LF) *packfile-uri
+ packfile-uri = PKT-LINE(40*(HEXDIGIT) SP *%x20-ff LF)
+
packfile = PKT-LINE("packfile" LF)
*PKT-LINE(%x01-03 *%x00-ff)
acknowledgments section
- * If the client determines that it is finished with negotiations
- by sending a "done" line, the acknowledgments sections MUST be
- omitted from the server's response.
+ * If the client determines that it is finished with negotiations by
+ sending a "done" line (thus requiring the server to send a packfile),
+ the acknowledgments sections MUST be omitted from the server's
+ response.
* Always begins with the section header "acknowledgments"
@@ -404,9 +423,6 @@ header.
which the client has not indicated was shallow as a part of
its request.
- * This section is only included if a packfile section is also
- included in the response.
-
wanted-refs section
* This section is only included if the client has requested a
ref using a 'want-ref' line and if a packfile section is also
@@ -420,6 +436,20 @@ header.
* The server MUST NOT send any refs which were not requested
using 'want-ref' lines.
+ packfile-uris section
+ * This section is only included if the client sent
+ 'packfile-uris' and the server has at least one such URI to
+ send.
+
+ * Always begins with the section header "packfile-uris".
+
+ * For each URI the server sends, it sends a hash of the pack's
+ contents (as output by git index-pack) followed by the URI.
+
+ * The hashes are 40 hex characters long. When Git upgrades to a new
+ hash algorithm, this might need to be updated. (It should match
+ whatever index-pack outputs after "pack\t" or "keep\t".
+
packfile section
* This section is only included if the client has sent 'want'
lines in its request and either requested that no more
@@ -453,3 +483,12 @@ included in a request. This is done by sending each option as a
a request.
The provided options must not contain a NUL or LF character.
+
+ object-format
+~~~~~~~~~~~~~~~
+
+The server can advertise the `object-format` capability with a value `X` (in the
+form `object-format=X`) to notify the client that the server is able to deal
+with objects using hash algorithm X. If not specified, the server is assumed to
+only handle SHA-1. If the client would like to use a hash algorithm other than
+SHA-1, it should specify its object-format string.
diff --git a/Documentation/technical/reftable.txt b/Documentation/technical/reftable.txt
new file mode 100644
index 0000000..2951840
--- /dev/null
+++ b/Documentation/technical/reftable.txt
@@ -0,0 +1,1083 @@
+reftable
+--------
+
+Overview
+~~~~~~~~
+
+Problem statement
+^^^^^^^^^^^^^^^^^
+
+Some repositories contain a lot of references (e.g. android at 866k,
+rails at 31k). The existing packed-refs format takes up a lot of space
+(e.g. 62M), and does not scale with additional references. Lookup of a
+single reference requires linearly scanning the file.
+
+Atomic pushes modifying multiple references require copying the entire
+packed-refs file, which can be a considerable amount of data moved
+(e.g. 62M in, 62M out) for even small transactions (2 refs modified).
+
+Repositories with many loose references occupy a large number of disk
+blocks from the local file system, as each reference is its own file
+storing 41 bytes (and another file for the corresponding reflog). This
+negatively affects the number of inodes available when a large number of
+repositories are stored on the same filesystem. Readers can be penalized
+due to the larger number of syscalls required to traverse and read the
+`$GIT_DIR/refs` directory.
+
+
+Objectives
+^^^^^^^^^^
+
+* Near constant time lookup for any single reference, even when the
+repository is cold and not in process or kernel cache.
+* Near constant time verification if an object name is referred to by at least
+one reference (for allow-tip-sha1-in-want).
+* Efficient enumeration of an entire namespace, such as `refs/tags/`.
+* Support atomic push with `O(size_of_update)` operations.
+* Combine reflog storage with ref storage for small transactions.
+* Separate reflog storage for base refs and historical logs.
+
+Description
+^^^^^^^^^^^
+
+A reftable file is a portable binary file format customized for
+reference storage. References are sorted, enabling linear scans, binary
+search lookup, and range scans.
+
+Storage in the file is organized into variable sized blocks. Prefix
+compression is used within a single block to reduce disk space. Block
+size and alignment is tunable by the writer.
+
+Performance
+^^^^^^^^^^^
+
+Space used, packed-refs vs. reftable:
+
+[cols=",>,>,>,>,>",options="header",]
+|===============================================================
+|repository |packed-refs |reftable |% original |avg ref |avg obj
+|android |62.2 M |36.1 M |58.0% |33 bytes |5 bytes
+|rails |1.8 M |1.1 M |57.7% |29 bytes |4 bytes
+|git |78.7 K |48.1 K |61.0% |50 bytes |4 bytes
+|git (heads) |332 b |269 b |81.0% |33 bytes |0 bytes
+|===============================================================
+
+Scan (read 866k refs), by reference name lookup (single ref from 866k
+refs), and by SHA-1 lookup (refs with that SHA-1, from 866k refs):
+
+[cols=",>,>,>,>",options="header",]
+|=========================================================
+|format |cache |scan |by name |by SHA-1
+|packed-refs |cold |402 ms |409,660.1 usec |412,535.8 usec
+|packed-refs |hot | |6,844.6 usec |20,110.1 usec
+|reftable |cold |112 ms |33.9 usec |323.2 usec
+|reftable |hot | |20.2 usec |320.8 usec
+|=========================================================
+
+Space used for 149,932 log entries for 43,061 refs, reflog vs. reftable:
+
+[cols=",>,>",options="header",]
+|================================
+|format |size |avg entry
+|$GIT_DIR/logs |173 M |1209 bytes
+|reftable |5 M |37 bytes
+|================================
+
+Details
+~~~~~~~
+
+Peeling
+^^^^^^^
+
+References stored in a reftable are peeled, a record for an annotated
+(or signed) tag records both the tag object, and the object it refers
+to. This is analogous to storage in the packed-refs format.
+
+Reference name encoding
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Reference names are an uninterpreted sequence of bytes that must pass
+linkgit:git-check-ref-format[1] as a valid reference name.
+
+Key unicity
+^^^^^^^^^^^
+
+Each entry must have a unique key; repeated keys are disallowed.
+
+Network byte order
+^^^^^^^^^^^^^^^^^^
+
+All multi-byte, fixed width fields are in network byte order.
+
+Varint encoding
+^^^^^^^^^^^^^^^
+
+Varint encoding is identical to the ofs-delta encoding method used
+within pack files.
+
+Decoder works such as:
+
+....
+val = buf[ptr] & 0x7f
+while (buf[ptr] & 0x80) {
+ ptr++
+ val = ((val + 1) << 7) | (buf[ptr] & 0x7f)
+}
+....
+
+Ordering
+^^^^^^^^
+
+Blocks are lexicographically ordered by their first reference.
+
+Directory/file conflicts
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The reftable format accepts both `refs/heads/foo` and
+`refs/heads/foo/bar` as distinct references.
+
+This property is useful for retaining log records in reftable, but may
+confuse versions of Git using `$GIT_DIR/refs` directory tree to maintain
+references. Users of reftable may choose to continue to reject `foo` and
+`foo/bar` type conflicts to prevent problems for peers.
+
+File format
+~~~~~~~~~~~
+
+Structure
+^^^^^^^^^
+
+A reftable file has the following high-level structure:
+
+....
+first_block {
+ header
+ first_ref_block
+}
+ref_block*
+ref_index*
+obj_block*
+obj_index*
+log_block*
+log_index*
+footer
+....
+
+A log-only file omits the `ref_block`, `ref_index`, `obj_block` and
+`obj_index` sections, containing only the file header and log block:
+
+....
+first_block {
+ header
+}
+log_block*
+log_index*
+footer
+....
+
+in a log-only file the first log block immediately follows the file
+header, without padding to block alignment.
+
+Block size
+^^^^^^^^^^
+
+The file's block size is arbitrarily determined by the writer, and does
+not have to be a power of 2. The block size must be larger than the
+longest reference name or log entry used in the repository, as
+references cannot span blocks.
+
+Powers of two that are friendly to the virtual memory system or
+filesystem (such as 4k or 8k) are recommended. Larger sizes (64k) can
+yield better compression, with a possible increased cost incurred by
+readers during access.
+
+The largest block size is `16777215` bytes (15.99 MiB).
+
+Block alignment
+^^^^^^^^^^^^^^^
+
+Writers may choose to align blocks at multiples of the block size by
+including `padding` filled with NUL bytes at the end of a block to round
+out to the chosen alignment. When alignment is used, writers must
+specify the alignment with the file header's `block_size` field.
+
+Block alignment is not required by the file format. Unaligned files must
+set `block_size = 0` in the file header, and omit `padding`. Unaligned
+files with more than one ref block must include the link:#Ref-index[ref
+index] to support fast lookup. Readers must be able to read both aligned
+and non-aligned files.
+
+Very small files (e.g. a single ref block) may omit `padding` and the ref
+index to reduce total file size.
+
+Header (version 1)
+^^^^^^^^^^^^^^^^^^
+
+A 24-byte header appears at the beginning of the file:
+
+....
+'REFT'
+uint8( version_number = 1 )
+uint24( block_size )
+uint64( min_update_index )
+uint64( max_update_index )
+....
+
+Aligned files must specify `block_size` to configure readers with the
+expected block alignment. Unaligned files must set `block_size = 0`.
+
+The `min_update_index` and `max_update_index` describe bounds for the
+`update_index` field of all log records in this file. When reftables are
+used in a stack for link:#Update-transactions[transactions], these
+fields can order the files such that the prior file's
+`max_update_index + 1` is the next file's `min_update_index`.
+
+Header (version 2)
+^^^^^^^^^^^^^^^^^^
+
+A 28-byte header appears at the beginning of the file:
+
+....
+'REFT'
+uint8( version_number = 2 )
+uint24( block_size )
+uint64( min_update_index )
+uint64( max_update_index )
+uint32( hash_id )
+....
+
+The header is identical to `version_number=1`, with the 4-byte hash ID
+("sha1" for SHA1 and "s256" for SHA-256) append to the header.
+
+For maximum backward compatibility, it is recommended to use version 1 when
+writing SHA1 reftables.
+
+First ref block
+^^^^^^^^^^^^^^^
+
+The first ref block shares the same block as the file header, and is 24
+bytes smaller than all other blocks in the file. The first block
+immediately begins after the file header, at position 24.
+
+If the first block is a log block (a log-only file), its block header
+begins immediately at position 24.
+
+Ref block format
+^^^^^^^^^^^^^^^^
+
+A ref block is written as:
+
+....
+'r'
+uint24( block_len )
+ref_record+
+uint24( restart_offset )+
+uint16( restart_count )
+
+padding?
+....
+
+Blocks begin with `block_type = 'r'` and a 3-byte `block_len` which
+encodes the number of bytes in the block up to, but not including the
+optional `padding`. This is always less than or equal to the file's
+block size. In the first ref block, `block_len` includes 24 bytes for
+the file header.
+
+The 2-byte `restart_count` stores the number of entries in the
+`restart_offset` list, which must not be empty. Readers can use
+`restart_count` to binary search between restarts before starting a
+linear scan.
+
+Exactly `restart_count` 3-byte `restart_offset` values precedes the
+`restart_count`. Offsets are relative to the start of the block and
+refer to the first byte of any `ref_record` whose name has not been
+prefix compressed. Entries in the `restart_offset` list must be sorted,
+ascending. Readers can start linear scans from any of these records.
+
+A variable number of `ref_record` fill the middle of the block,
+describing reference names and values. The format is described below.
+
+As the first ref block shares the first file block with the file header,
+all `restart_offset` in the first block are relative to the start of the
+file (position 0), and include the file header. This forces the first
+`restart_offset` to be `28`.
+
+ref record
+++++++++++
+
+A `ref_record` describes a single reference, storing both the name and
+its value(s). Records are formatted as:
+
+....
+varint( prefix_length )
+varint( (suffix_length << 3) | value_type )
+suffix
+varint( update_index_delta )
+value?
+....
+
+The `prefix_length` field specifies how many leading bytes of the prior
+reference record's name should be copied to obtain this reference's
+name. This must be 0 for the first reference in any block, and also must
+be 0 for any `ref_record` whose offset is listed in the `restart_offset`
+table at the end of the block.
+
+Recovering a reference name from any `ref_record` is a simple concat:
+
+....
+this_name = prior_name[0..prefix_length] + suffix
+....
+
+The `suffix_length` value provides the number of bytes available in
+`suffix` to copy from `suffix` to complete the reference name.
+
+The `update_index` that last modified the reference can be obtained by
+adding `update_index_delta` to the `min_update_index` from the file
+header: `min_update_index + update_index_delta`.
+
+The `value` follows. Its format is determined by `value_type`, one of
+the following:
+
+* `0x0`: deletion; no value data (see transactions, below)
+* `0x1`: one object name; value of the ref
+* `0x2`: two object names; value of the ref, peeled target
+* `0x3`: symbolic reference: `varint( target_len ) target`
+
+Symbolic references use `0x3`, followed by the complete name of the
+reference target. No compression is applied to the target name.
+
+Types `0x4..0x7` are reserved for future use.
+
+Ref index
+^^^^^^^^^
+
+The ref index stores the name of the last reference from every ref block
+in the file, enabling reduced disk seeks for lookups. Any reference can
+be found by searching the index, identifying the containing block, and
+searching within that block.
+
+The index may be organized into a multi-level index, where the 1st level
+index block points to additional ref index blocks (2nd level), which may
+in turn point to either additional index blocks (e.g. 3rd level) or ref
+blocks (leaf level). Disk reads required to access a ref go up with
+higher index levels. Multi-level indexes may be required to ensure no
+single index block exceeds the file format's max block size of
+`16777215` bytes (15.99 MiB). To achieve constant O(1) disk seeks for
+lookups the index must be a single level, which is permitted to exceed
+the file's configured block size, but not the format's max block size of
+15.99 MiB.
+
+If present, the ref index block(s) appears after the last ref block.
+
+If there are at least 4 ref blocks, a ref index block should be written
+to improve lookup times. Cold reads using the index require 2 disk reads
+(read index, read block), and binary searching < 4 blocks also requires
+<= 2 reads. Omitting the index block from smaller files saves space.
+
+If the file is unaligned and contains more than one ref block, the ref
+index must be written.
+
+Index block format:
+
+....
+'i'
+uint24( block_len )
+index_record+
+uint24( restart_offset )+
+uint16( restart_count )
+
+padding?
+....
+
+The index blocks begin with `block_type = 'i'` and a 3-byte `block_len`
+which encodes the number of bytes in the block, up to but not including
+the optional `padding`.
+
+The `restart_offset` and `restart_count` fields are identical in format,
+meaning and usage as in ref blocks.
+
+To reduce the number of reads required for random access in very large
+files the index block may be larger than other blocks. However, readers
+must hold the entire index in memory to benefit from this, so it's a
+time-space tradeoff in both file size and reader memory.
+
+Increasing the file's block size decreases the index size. Alternatively
+a multi-level index may be used, keeping index blocks within the file's
+block size, but increasing the number of blocks that need to be
+accessed.
+
+index record
+++++++++++++
+
+An index record describes the last entry in another block. Index records
+are written as:
+
+....
+varint( prefix_length )
+varint( (suffix_length << 3) | 0 )
+suffix
+varint( block_position )
+....
+
+Index records use prefix compression exactly like `ref_record`.
+
+Index records store `block_position` after the suffix, specifying the
+absolute position in bytes (from the start of the file) of the block
+that ends with this reference. Readers can seek to `block_position` to
+begin reading the block header.
+
+Readers must examine the block header at `block_position` to determine
+if the next block is another level index block, or the leaf-level ref
+block.
+
+Reading the index
++++++++++++++++++
+
+Readers loading the ref index must first read the footer (below) to
+obtain `ref_index_position`. If not present, the position will be 0. The
+`ref_index_position` is for the 1st level root of the ref index.
+
+Obj block format
+^^^^^^^^^^^^^^^^
+
+Object blocks are optional. Writers may choose to omit object blocks,
+especially if readers will not use the object name to ref mapping.
+
+Object blocks use unique, abbreviated 2-32 object name keys, mapping to
+ref blocks containing references pointing to that object directly, or as
+the peeled value of an annotated tag. Like ref blocks, object blocks use
+the file's standard block size. The abbrevation length is available in
+the footer as `obj_id_len`.
+
+To save space in small files, object blocks may be omitted if the ref
+index is not present, as brute force search will only need to read a few
+ref blocks. When missing, readers should brute force a linear search of
+all references to lookup by object name.
+
+An object block is written as:
+
+....
+'o'
+uint24( block_len )
+obj_record+
+uint24( restart_offset )+
+uint16( restart_count )
+
+padding?
+....
+
+Fields are identical to ref block. Binary search using the restart table
+works the same as in reference blocks.
+
+Because object names are abbreviated by writers to the shortest unique
+abbreviation within the reftable, obj key lengths have a variable length. Their
+length must be at least 2 bytes. Readers must compare only for common prefix
+match within an obj block or obj index.
+
+obj record
+++++++++++
+
+An `obj_record` describes a single object abbreviation, and the blocks
+containing references using that unique abbreviation:
+
+....
+varint( prefix_length )
+varint( (suffix_length << 3) | cnt_3 )
+suffix
+varint( cnt_large )?
+varint( position_delta )*
+....
+
+Like in reference blocks, abbreviations are prefix compressed within an
+obj block. On large reftables with many unique objects, higher block
+sizes (64k), and higher restart interval (128), a `prefix_length` of 2
+or 3 and `suffix_length` of 3 may be common in obj records (unique
+abbreviation of 5-6 raw bytes, 10-12 hex digits).
+
+Each record contains `position_count` number of positions for matching
+ref blocks. For 1-7 positions the count is stored in `cnt_3`. When
+`cnt_3 = 0` the actual count follows in a varint, `cnt_large`.
+
+The use of `cnt_3` bets most objects are pointed to by only a single
+reference, some may be pointed to by a couple of references, and very
+few (if any) are pointed to by more than 7 references.
+
+A special case exists when `cnt_3 = 0` and `cnt_large = 0`: there are no
+`position_delta`, but at least one reference starts with this
+abbreviation. A reader that needs exact reference names must scan all
+references to find which specific references have the desired object.
+Writers should use this format when the `position_delta` list would have
+overflowed the file's block size due to a high number of references
+pointing to the same object.
+
+The first `position_delta` is the position from the start of the file.
+Additional `position_delta` entries are sorted ascending and relative to
+the prior entry, e.g. a reader would perform:
+
+....
+pos = position_delta[0]
+prior = pos
+for (j = 1; j < position_count; j++) {
+ pos = prior + position_delta[j]
+ prior = pos
+}
+....
+
+With a position in hand, a reader must linearly scan the ref block,
+starting from the first `ref_record`, testing each reference's object names
+(for `value_type = 0x1` or `0x2`) for full equality. Faster searching by
+object name within a single ref block is not supported by the reftable format.
+Smaller block sizes reduce the number of candidates this step must
+consider.
+
+Obj index
+^^^^^^^^^
+
+The obj index stores the abbreviation from the last entry for every obj
+block in the file, enabling reduced disk seeks for all lookups. It is
+formatted exactly the same as the ref index, but refers to obj blocks.
+
+The obj index should be present if obj blocks are present, as obj blocks
+should only be written in larger files.
+
+Readers loading the obj index must first read the footer (below) to
+obtain `obj_index_position`. If not present, the position will be 0.
+
+Log block format
+^^^^^^^^^^^^^^^^
+
+Unlike ref and obj blocks, log blocks are always unaligned.
+
+Log blocks are variable in size, and do not match the `block_size`
+specified in the file header or footer. Writers should choose an
+appropriate buffer size to prepare a log block for deflation, such as
+`2 * block_size`.
+
+A log block is written as:
+
+....
+'g'
+uint24( block_len )
+zlib_deflate {
+ log_record+
+ uint24( restart_offset )+
+ uint16( restart_count )
+}
+....
+
+Log blocks look similar to ref blocks, except `block_type = 'g'`.
+
+The 4-byte block header is followed by the deflated block contents using
+zlib deflate. The `block_len` in the header is the inflated size
+(including 4-byte block header), and should be used by readers to
+preallocate the inflation output buffer. A log block's `block_len` may
+exceed the file's block size.
+
+Offsets within the log block (e.g. `restart_offset`) still include the
+4-byte header. Readers may prefer prefixing the inflation output buffer
+with the 4-byte header.
+
+Within the deflate container, a variable number of `log_record` describe
+reference changes. The log record format is described below. See ref
+block format (above) for a description of `restart_offset` and
+`restart_count`.
+
+Because log blocks have no alignment or padding between blocks, readers
+must keep track of the bytes consumed by the inflater to know where the
+next log block begins.
+
+log record
+++++++++++
+
+Log record keys are structured as:
+
+....
+ref_name '\0' reverse_int64( update_index )
+....
+
+where `update_index` is the unique transaction identifier. The
+`update_index` field must be unique within the scope of a `ref_name`.
+See the update transactions section below for further details.
+
+The `reverse_int64` function inverses the value so lexicographical
+ordering the network byte order encoding sorts the more recent records
+with higher `update_index` values first:
+
+....
+reverse_int64(int64 t) {
+ return 0xffffffffffffffff - t;
+}
+....
+
+Log records have a similar starting structure to ref and index records,
+utilizing the same prefix compression scheme applied to the log record
+key described above.
+
+....
+ varint( prefix_length )
+ varint( (suffix_length << 3) | log_type )
+ suffix
+ log_data {
+ old_id
+ new_id
+ varint( name_length ) name
+ varint( email_length ) email
+ varint( time_seconds )
+ sint16( tz_offset )
+ varint( message_length ) message
+ }?
+....
+
+Log record entries use `log_type` to indicate what follows:
+
+* `0x0`: deletion; no log data.
+* `0x1`: standard git reflog data using `log_data` above.
+
+The `log_type = 0x0` is mostly useful for `git stash drop`, removing an
+entry from the reflog of `refs/stash` in a transaction file (below),
+without needing to rewrite larger files. Readers reading a stack of
+reflogs must treat this as a deletion.
+
+For `log_type = 0x1`, the `log_data` section follows
+linkgit:git-update-ref[1] logging and includes:
+
+* two object names (old id, new id)
+* varint string of committer's name
+* varint string of committer's email
+* varint time in seconds since epoch (Jan 1, 1970)
+* 2-byte timezone offset in minutes (signed)
+* varint string of message
+
+`tz_offset` is the absolute number of minutes from GMT the committer was
+at the time of the update. For example `GMT-0800` is encoded in reftable
+as `sint16(-480)` and `GMT+0230` is `sint16(150)`.
+
+The committer email does not contain `<` or `>`, it's the value normally
+found between the `<>` in a git commit object header.
+
+The `message_length` may be 0, in which case there was no message
+supplied for the update.
+
+Contrary to traditional reflog (which is a file), renames are encoded as
+a combination of ref deletion and ref creation. A deletion is a log
+record with a zero new_id, and a creation is a log record with a zero old_id.
+
+Reading the log
++++++++++++++++
+
+Readers accessing the log must first read the footer (below) to
+determine the `log_position`. The first block of the log begins at
+`log_position` bytes since the start of the file. The `log_position` is
+not block aligned.
+
+Importing logs
+++++++++++++++
+
+When importing from `$GIT_DIR/logs` writers should globally order all
+log records roughly by timestamp while preserving file order, and assign
+unique, increasing `update_index` values for each log line. Newer log
+records get higher `update_index` values.
+
+Although an import may write only a single reftable file, the reftable
+file must span many unique `update_index`, as each log line requires its
+own `update_index` to preserve semantics.
+
+Log index
+^^^^^^^^^
+
+The log index stores the log key
+(`refname \0 reverse_int64(update_index)`) for the last log record of
+every log block in the file, supporting bounded-time lookup.
+
+A log index block must be written if 2 or more log blocks are written to
+the file. If present, the log index appears after the last log block.
+There is no padding used to align the log index to block alignment.
+
+Log index format is identical to ref index, except the keys are 9 bytes
+longer to include `'\0'` and the 8-byte `reverse_int64(update_index)`.
+Records use `block_position` to refer to the start of a log block.
+
+Reading the index
++++++++++++++++++
+
+Readers loading the log index must first read the footer (below) to
+obtain `log_index_position`. If not present, the position will be 0.
+
+Footer
+^^^^^^
+
+After the last block of the file, a file footer is written. It begins
+like the file header, but is extended with additional data.
+
+....
+ HEADER
+
+ uint64( ref_index_position )
+ uint64( (obj_position << 5) | obj_id_len )
+ uint64( obj_index_position )
+
+ uint64( log_position )
+ uint64( log_index_position )
+
+ uint32( CRC-32 of above )
+....
+
+If a section is missing (e.g. ref index) the corresponding position
+field (e.g. `ref_index_position`) will be 0.
+
+* `obj_position`: byte position for the first obj block.
+* `obj_id_len`: number of bytes used to abbreviate object names in
+obj blocks.
+* `log_position`: byte position for the first log block.
+* `ref_index_position`: byte position for the start of the ref index.
+* `obj_index_position`: byte position for the start of the obj index.
+* `log_index_position`: byte position for the start of the log index.
+
+The size of the footer is 68 bytes for version 1, and 72 bytes for
+version 2.
+
+Reading the footer
+++++++++++++++++++
+
+Readers must first read the file start to determine the version
+number. Then they seek to `file_length - FOOTER_LENGTH` to access the
+footer. A trusted external source (such as `stat(2)`) is necessary to
+obtain `file_length`. When reading the footer, readers must verify:
+
+* 4-byte magic is correct
+* 1-byte version number is recognized
+* 4-byte CRC-32 matches the other 64 bytes (including magic, and
+version)
+
+Once verified, the other fields of the footer can be accessed.
+
+Empty tables
+++++++++++++
+
+A reftable may be empty. In this case, the file starts with a header
+and is immediately followed by a footer.
+
+Binary search
+^^^^^^^^^^^^^
+
+Binary search within a block is supported by the `restart_offset` fields
+at the end of the block. Readers can binary search through the restart
+table to locate between which two restart points the sought reference or
+key should appear.
+
+Each record identified by a `restart_offset` stores the complete key in
+the `suffix` field of the record, making the compare operation during
+binary search straightforward.
+
+Once a restart point lexicographically before the sought reference has
+been identified, readers can linearly scan through the following record
+entries to locate the sought record, terminating if the current record
+sorts after (and therefore the sought key is not present).
+
+Restart point selection
++++++++++++++++++++++++
+
+Writers determine the restart points at file creation. The process is
+arbitrary, but every 16 or 64 records is recommended. Every 16 may be
+more suitable for smaller block sizes (4k or 8k), every 64 for larger
+block sizes (64k).
+
+More frequent restart points reduces prefix compression and increases
+space consumed by the restart table, both of which increase file size.
+
+Less frequent restart points makes prefix compression more effective,
+decreasing overall file size, with increased penalties for readers
+walking through more records after the binary search step.
+
+A maximum of `65535` restart points per block is supported.
+
+Considerations
+~~~~~~~~~~~~~~
+
+Lightweight refs dominate
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The reftable format assumes the vast majority of references are single
+object names valued with common prefixes, such as Gerrit Code Review's
+`refs/changes/` namespace, GitHub's `refs/pulls/` namespace, or many
+lightweight tags in the `refs/tags/` namespace.
+
+Annotated tags storing the peeled object cost an additional object name per
+reference.
+
+Low overhead
+^^^^^^^^^^^^
+
+A reftable with very few references (e.g. git.git with 5 heads) is 269
+bytes for reftable, vs. 332 bytes for packed-refs. This supports
+reftable scaling down for transaction logs (below).
+
+Block size
+^^^^^^^^^^
+
+For a Gerrit Code Review type repository with many change refs, larger
+block sizes (64 KiB) and less frequent restart points (every 64) yield
+better compression due to more references within the block compressing
+against the prior reference.
+
+Larger block sizes reduce the index size, as the reftable will require
+fewer blocks to store the same number of references.
+
+Minimal disk seeks
+^^^^^^^^^^^^^^^^^^
+
+Assuming the index block has been loaded into memory, binary searching
+for any single reference requires exactly 1 disk seek to load the
+containing block.
+
+Scans and lookups dominate
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Scanning all references and lookup by name (or namespace such as
+`refs/heads/`) are the most common activities performed on repositories.
+Object names are stored directly with references to optimize this use case.
+
+Logs are infrequently read
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Logs are infrequently accessed, but can be large. Deflating log blocks
+saves disk space, with some increased penalty at read time.
+
+Logs are stored in an isolated section from refs, reducing the burden on
+reference readers that want to ignore logs. Further, historical logs can
+be isolated into log-only files.
+
+Logs are read backwards
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Logs are frequently accessed backwards (most recent N records for master
+to answer `master@{4}`), so log records are grouped by reference, and
+sorted descending by update index.
+
+Repository format
+~~~~~~~~~~~~~~~~~
+
+Version 1
+^^^^^^^^^
+
+A repository must set its `$GIT_DIR/config` to configure reftable:
+
+....
+[core]
+ repositoryformatversion = 1
+[extensions]
+ refStorage = reftable
+....
+
+Layout
+^^^^^^
+
+A collection of reftable files are stored in the `$GIT_DIR/reftable/`
+directory:
+
+....
+00000001-00000001.log
+00000002-00000002.ref
+00000003-00000003.ref
+....
+
+where reftable files are named by a unique name such as produced by the
+function `${min_update_index}-${max_update_index}.ref`.
+
+Log-only files use the `.log` extension, while ref-only and mixed ref
+and log files use `.ref`. extension.
+
+The stack ordering file is `$GIT_DIR/reftable/tables.list` and lists the
+current files, one per line, in order, from oldest (base) to newest
+(most recent):
+
+....
+$ cat .git/reftable/tables.list
+00000001-00000001.log
+00000002-00000002.ref
+00000003-00000003.ref
+....
+
+Readers must read `$GIT_DIR/reftable/tables.list` to determine which
+files are relevant right now, and search through the stack in reverse
+order (last reftable is examined first).
+
+Reftable files not listed in `tables.list` may be new (and about to be
+added to the stack by the active writer), or ancient and ready to be
+pruned.
+
+Backward compatibility
+^^^^^^^^^^^^^^^^^^^^^^
+
+Older clients should continue to recognize the directory as a git
+repository so they don't look for an enclosing repository in parent
+directories. To this end, a reftable-enabled repository must contain the
+following dummy files
+
+* `.git/HEAD`, a regular file containing `ref: refs/heads/.invalid`.
+* `.git/refs/`, a directory
+* `.git/refs/heads`, a regular file
+
+Readers
+^^^^^^^
+
+Readers can obtain a consistent snapshot of the reference space by
+following:
+
+1. Open and read the `tables.list` file.
+2. Open each of the reftable files that it mentions.
+3. If any of the files is missing, goto 1.
+4. Read from the now-open files as long as necessary.
+
+Update transactions
+^^^^^^^^^^^^^^^^^^^
+
+Although reftables are immutable, mutations are supported by writing a
+new reftable and atomically appending it to the stack:
+
+1. Acquire `tables.list.lock`.
+2. Read `tables.list` to determine current reftables.
+3. Select `update_index` to be most recent file's
+`max_update_index + 1`.
+4. Prepare temp reftable `tmp_XXXXXX`, including log entries.
+5. Rename `tmp_XXXXXX` to `${update_index}-${update_index}.ref`.
+6. Copy `tables.list` to `tables.list.lock`, appending file from (5).
+7. Rename `tables.list.lock` to `tables.list`.
+
+During step 4 the new file's `min_update_index` and `max_update_index`
+are both set to the `update_index` selected by step 3. All log records
+for the transaction use the same `update_index` in their keys. This
+enables later correlation of which references were updated by the same
+transaction.
+
+Because a single `tables.list.lock` file is used to manage locking, the
+repository is single-threaded for writers. Writers may have to busy-spin
+(with backoff) around creating `tables.list.lock`, for up to an
+acceptable wait period, aborting if the repository is too busy to
+mutate. Application servers wrapped around repositories (e.g. Gerrit
+Code Review) can layer their own lock/wait queue to improve fairness to
+writers.
+
+Reference deletions
+^^^^^^^^^^^^^^^^^^^
+
+Deletion of any reference can be explicitly stored by setting the `type`
+to `0x0` and omitting the `value` field of the `ref_record`. This serves
+as a tombstone, overriding any assertions about the existence of the
+reference from earlier files in the stack.
+
+Compaction
+^^^^^^^^^^
+
+A partial stack of reftables can be compacted by merging references
+using a straightforward merge join across reftables, selecting the most
+recent value for output, and omitting deleted references that do not
+appear in remaining, lower reftables.
+
+A compacted reftable should set its `min_update_index` to the smallest
+of the input files' `min_update_index`, and its `max_update_index`
+likewise to the largest input `max_update_index`.
+
+For sake of illustration, assume the stack currently consists of
+reftable files (from oldest to newest): A, B, C, and D. The compactor is
+going to compact B and C, leaving A and D alone.
+
+1. Obtain lock `tables.list.lock` and read the `tables.list` file.
+2. Obtain locks `B.lock` and `C.lock`. Ownership of these locks
+prevents other processes from trying to compact these files.
+3. Release `tables.list.lock`.
+4. Compact `B` and `C` into a temp file
+`${min_update_index}-${max_update_index}_XXXXXX`.
+5. Reacquire lock `tables.list.lock`.
+6. Verify that `B` and `C` are still in the stack, in that order. This
+should always be the case, assuming that other processes are adhering to
+the locking protocol.
+7. Rename `${min_update_index}-${max_update_index}_XXXXXX` to
+`${min_update_index}-${max_update_index}.ref`.
+8. Write the new stack to `tables.list.lock`, replacing `B` and `C`
+with the file from (4).
+9. Rename `tables.list.lock` to `tables.list`.
+10. Delete `B` and `C`, perhaps after a short sleep to avoid forcing
+readers to backtrack.
+
+This strategy permits compactions to proceed independently of updates.
+
+Each reftable (compacted or not) is uniquely identified by its name, so
+open reftables can be cached by their name.
+
+Alternatives considered
+~~~~~~~~~~~~~~~~~~~~~~~
+
+bzip packed-refs
+^^^^^^^^^^^^^^^^
+
+`bzip2` can significantly shrink a large packed-refs file (e.g. 62 MiB
+compresses to 23 MiB, 37%). However the bzip format does not support
+random access to a single reference. Readers must inflate and discard
+while performing a linear scan.
+
+Breaking packed-refs into chunks (individually compressing each chunk)
+would reduce the amount of data a reader must inflate, but still leaves
+the problem of indexing chunks to support readers efficiently locating
+the correct chunk.
+
+Given the compression achieved by reftable's encoding, it does not seem
+necessary to add the complexity of bzip/gzip/zlib.
+
+Michael Haggerty's alternate format
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Michael Haggerty proposed
+link:https://lore.kernel.org/git/CAMy9T_HCnyc1g8XWOOWhe7nN0aEFyyBskV2aOMb_fe%2BwGvEJ7A%40mail.gmail.com/[an
+alternate] format to reftable on the Git mailing list. This format uses
+smaller chunks, without the restart table, and avoids block alignment
+with padding. Reflog entries immediately follow each ref, and are thus
+interleaved between refs.
+
+Performance testing indicates reftable is faster for lookups (51%
+faster, 11.2 usec vs. 5.4 usec), although reftable produces a slightly
+larger file (+ ~3.2%, 28.3M vs 29.2M):
+
+[cols=">,>,>,>",options="header",]
+|=====================================
+|format |size |seek cold |seek hot
+|mh-alt |28.3 M |23.4 usec |11.2 usec
+|reftable |29.2 M |19.9 usec |5.4 usec
+|=====================================
+
+JGit Ketch RefTree
+^^^^^^^^^^^^^^^^^^
+
+https://dev.eclipse.org/mhonarc/lists/jgit-dev/msg03073.html[JGit Ketch]
+proposed
+link:https://lore.kernel.org/git/CAJo%3DhJvnAPNAdDcAAwAvU9C4RVeQdoS3Ev9WTguHx4fD0V_nOg%40mail.gmail.com/[RefTree],
+an encoding of references inside Git tree objects stored as part of the
+repository's object database.
+
+The RefTree format adds additional load on the object database storage
+layer (more loose objects, more objects in packs), and relies heavily on
+the packer's delta compression to save space. Namespaces which are flat
+(e.g. thousands of tags in refs/tags) initially create very large loose
+objects, and so RefTree does not address the problem of copying many
+references to modify a handful.
+
+Flat namespaces are not efficiently searchable in RefTree, as tree
+objects in canonical formatting cannot be binary searched. This fails
+the need to handle a large number of references in a single namespace,
+such as GitHub's `refs/pulls`, or a project with many tags.
+
+LMDB
+^^^^
+
+David Turner proposed
+https://lore.kernel.org/git/1455772670-21142-26-git-send-email-dturner@twopensource.com/[using
+LMDB], as LMDB is lightweight (64k of runtime code) and GPL-compatible
+license.
+
+A downside of LMDB is its reliance on a single C implementation. This
+makes embedding inside JGit (a popular reimplementation of Git)
+difficult, and hoisting onto virtual storage (for JGit DFS) virtually
+impossible.
+
+A common format that can be supported by all major Git implementations
+(git-core, JGit, libgit2) is strongly preferred.
diff --git a/Documentation/user-manual.conf b/Documentation/user-manual.conf
index d87294d..0148f12 100644
--- a/Documentation/user-manual.conf
+++ b/Documentation/user-manual.conf
@@ -9,13 +9,3 @@ tilde=&#126;
[linkgit-inlinemacro]
<ulink url="{target}.html">{target}{0?({0})}</ulink>
-
-ifdef::backend-docbook[]
-# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
-[listingblock]
-<example><title>{title}</title>
-<literallayout class="monospaced">
-|
-</literallayout>
-{title#}</example>
-endif::backend-docbook[]
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 8336529..fd480b8 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -347,7 +347,7 @@ $ git branch -r
origin/man
origin/master
origin/next
- origin/pu
+ origin/seen
origin/todo
------------------------------------------------
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index dafe6d0..9db2f4f 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.26.2
+DEF_VER=v2.28.0
LF='
'
diff --git a/INSTALL b/INSTALL
index 22c364f..9ba33e6 100644
--- a/INSTALL
+++ b/INSTALL
@@ -206,9 +206,7 @@ Issues of note:
clone two separate git-htmldocs and git-manpages repositories next
to the clone of git itself.
- It has been reported that docbook-xsl version 1.72 and 1.73 are
- buggy; 1.72 misformats manual pages for callouts, and 1.73 needs
- the patch in contrib/patches/docbook-xsl-manpages-charmap.patch
+ The minimum supported version of docbook-xsl is 1.74.
Users attempting to build the documentation on Cygwin may need to ensure
that the /etc/xml/catalog file looks something like this:
diff --git a/Makefile b/Makefile
index 9804a07..372139f 100644
--- a/Makefile
+++ b/Makefile
@@ -282,12 +282,6 @@ all::
# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
# field that counts the on-disk footprint in 512-byte blocks.
#
-# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72
-# (not v1.73 or v1.71).
-#
-# Define ASCIIDOC_ROFF if your DocBook XSL does not escape raw roff directives
-# (versions 1.68.1 through v1.72).
-#
# Define GNU_ROFF if your target system uses GNU groff. This forces
# apostrophes to be ASCII so that cut&pasting examples to the shell
# will work.
@@ -405,9 +399,6 @@ all::
# with a different indexfile format version. If it isn't set the index
# file format used is index-v[23].
#
-# Define GMTIME_UNRELIABLE_ERRORS if your gmtime() function does not
-# return NULL when it receives a bogus time_t.
-#
# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime.
#
# Define HAVE_CLOCK_MONOTONIC if your platform has CLOCK_MONOTONIC.
@@ -609,7 +600,6 @@ SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
SCRIPT_SH += git-mergetool.sh
SCRIPT_SH += git-quiltimport.sh
-SCRIPT_SH += git-legacy-stash.sh
SCRIPT_SH += git-request-pull.sh
SCRIPT_SH += git-submodule.sh
SCRIPT_SH += git-web--browse.sh
@@ -617,8 +607,8 @@ SCRIPT_SH += git-web--browse.sh
SCRIPT_LIB += git-mergetool--lib
SCRIPT_LIB += git-parse-remote
SCRIPT_LIB += git-rebase--preserve-merges
-SCRIPT_LIB += git-sh-setup
SCRIPT_LIB += git-sh-i18n
+SCRIPT_LIB += git-sh-setup
SCRIPT_PERL += git-add--interactive.perl
SCRIPT_PERL += git-archimport.perl
@@ -681,20 +671,23 @@ EXTRA_PROGRAMS =
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS += $(EXTRA_PROGRAMS)
+PROGRAM_OBJS += bugreport.o
PROGRAM_OBJS += credential-store.o
PROGRAM_OBJS += daemon.o
PROGRAM_OBJS += fast-import.o
PROGRAM_OBJS += http-backend.o
PROGRAM_OBJS += imap-send.o
+PROGRAM_OBJS += remote-testsvn.o
PROGRAM_OBJS += sh-i18n--envsubst.o
PROGRAM_OBJS += shell.o
-PROGRAM_OBJS += remote-testsvn.o
# Binary suffix, set to .exe for Windows builds
X =
PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
+TEST_BUILTINS_OBJS += test-advise.o
+TEST_BUILTINS_OBJS += test-bloom.o
TEST_BUILTINS_OBJS += test-chmtime.o
TEST_BUILTINS_OBJS += test-config.o
TEST_BUILTINS_OBJS += test-ctype.o
@@ -709,15 +702,16 @@ TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
TEST_BUILTINS_OBJS += test-example-decorate.o
TEST_BUILTINS_OBJS += test-genrandom.o
TEST_BUILTINS_OBJS += test-genzeros.o
+TEST_BUILTINS_OBJS += test-hash-speed.o
TEST_BUILTINS_OBJS += test-hash.o
TEST_BUILTINS_OBJS += test-hashmap.o
-TEST_BUILTINS_OBJS += test-hash-speed.o
TEST_BUILTINS_OBJS += test-index-version.o
TEST_BUILTINS_OBJS += test-json-writer.o
TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
TEST_BUILTINS_OBJS += test-match-trees.o
TEST_BUILTINS_OBJS += test-mergesort.o
TEST_BUILTINS_OBJS += test-mktemp.o
+TEST_BUILTINS_OBJS += test-oid-array.o
TEST_BUILTINS_OBJS += test-oidmap.o
TEST_BUILTINS_OBJS += test-online-cpus.o
TEST_BUILTINS_OBJS += test-parse-options.o
@@ -738,7 +732,6 @@ TEST_BUILTINS_OBJS += test-run-command.o
TEST_BUILTINS_OBJS += test-scrap-cache-tree.o
TEST_BUILTINS_OBJS += test-serve-v2.o
TEST_BUILTINS_OBJS += test-sha1.o
-TEST_BUILTINS_OBJS += test-sha1-array.o
TEST_BUILTINS_OBJS += test-sha256.o
TEST_BUILTINS_OBJS += test-sigchain.o
TEST_BUILTINS_OBJS += test-strcmp-offset.o
@@ -748,10 +741,10 @@ TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
TEST_BUILTINS_OBJS += test-subprocess.o
TEST_BUILTINS_OBJS += test-trace2.o
TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
-TEST_BUILTINS_OBJS += test-xml-encode.o
TEST_BUILTINS_OBJS += test-wildmatch.o
TEST_BUILTINS_OBJS += test-windows-named-pipe.o
TEST_BUILTINS_OBJS += test-write-cache.o
+TEST_BUILTINS_OBJS += test-xml-encode.o
# Do not add more tests here unless they have extra dependencies. Add
# them in TEST_BUILTINS_OBJS above.
@@ -788,10 +781,10 @@ OTHER_PROGRAMS = git$X
# what test wrappers are needed and 'install' will install, in bindir
BINDIR_PROGRAMS_NEED_X += git
-BINDIR_PROGRAMS_NEED_X += git-upload-pack
BINDIR_PROGRAMS_NEED_X += git-receive-pack
-BINDIR_PROGRAMS_NEED_X += git-upload-archive
BINDIR_PROGRAMS_NEED_X += git-shell
+BINDIR_PROGRAMS_NEED_X += git-upload-archive
+BINDIR_PROGRAMS_NEED_X += git-upload-pack
BINDIR_PROGRAMS_NO_X += git-cvsserver
@@ -815,6 +808,7 @@ LIB_FILE = libgit.a
XDIFF_LIB = xdiff/lib.a
VCSSVN_LIB = vcs-svn/lib.a
+GENERATED_H += config-list.h
GENERATED_H += command-list.h
LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \
@@ -831,15 +825,16 @@ LIB_OBJS += advice.o
LIB_OBJS += alias.o
LIB_OBJS += alloc.o
LIB_OBJS += apply.o
-LIB_OBJS += archive.o
LIB_OBJS += archive-tar.o
LIB_OBJS += archive-zip.o
+LIB_OBJS += archive.o
LIB_OBJS += argv-array.o
LIB_OBJS += attr.o
LIB_OBJS += base85.o
LIB_OBJS += bisect.o
LIB_OBJS += blame.o
LIB_OBJS += blob.o
+LIB_OBJS += bloom.o
LIB_OBJS += branch.o
LIB_OBJS += bulk-checkin.o
LIB_OBJS += bundle.o
@@ -849,9 +844,9 @@ LIB_OBJS += checkout.o
LIB_OBJS += color.o
LIB_OBJS += column.o
LIB_OBJS += combine-diff.o
-LIB_OBJS += commit.o
LIB_OBJS += commit-graph.o
LIB_OBJS += commit-reach.o
+LIB_OBJS += commit.o
LIB_OBJS += compat/obstack.o
LIB_OBJS += compat/terminal.o
LIB_OBJS += config.o
@@ -865,17 +860,17 @@ LIB_OBJS += ctype.o
LIB_OBJS += date.o
LIB_OBJS += decorate.o
LIB_OBJS += delta-islands.o
+LIB_OBJS += diff-delta.o
+LIB_OBJS += diff-lib.o
+LIB_OBJS += diff-no-index.o
+LIB_OBJS += diff.o
LIB_OBJS += diffcore-break.o
LIB_OBJS += diffcore-delta.o
LIB_OBJS += diffcore-order.o
LIB_OBJS += diffcore-pickaxe.o
LIB_OBJS += diffcore-rename.o
-LIB_OBJS += diff-delta.o
-LIB_OBJS += diff-lib.o
-LIB_OBJS += diff-no-index.o
-LIB_OBJS += diff.o
-LIB_OBJS += dir.o
LIB_OBJS += dir-iterator.o
+LIB_OBJS += dir.o
LIB_OBJS += editor.o
LIB_OBJS += entry.o
LIB_OBJS += environment.o
@@ -886,6 +881,7 @@ LIB_OBJS += ewah/ewah_rlw.o
LIB_OBJS += exec-cmd.o
LIB_OBJS += fetch-negotiator.o
LIB_OBJS += fetch-pack.o
+LIB_OBJS += fmt-merge-msg.o
LIB_OBJS += fsck.o
LIB_OBJS += fsmonitor.o
LIB_OBJS += gettext.o
@@ -893,7 +889,6 @@ LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o
LIB_OBJS += grep.o
LIB_OBJS += hashmap.o
-LIB_OBJS += linear-assignment.o
LIB_OBJS += help.o
LIB_OBJS += hex.o
LIB_OBJS += ident.o
@@ -903,9 +898,10 @@ LIB_OBJS += kwset.o
LIB_OBJS += levenshtein.o
LIB_OBJS += line-log.o
LIB_OBJS += line-range.o
-LIB_OBJS += list-objects.o
-LIB_OBJS += list-objects-filter.o
+LIB_OBJS += linear-assignment.o
LIB_OBJS += list-objects-filter-options.o
+LIB_OBJS += list-objects-filter.o
+LIB_OBJS += list-objects.o
LIB_OBJS += ll-merge.o
LIB_OBJS += lockfile.o
LIB_OBJS += log-tree.o
@@ -914,31 +910,32 @@ LIB_OBJS += mailinfo.o
LIB_OBJS += mailmap.o
LIB_OBJS += match-trees.o
LIB_OBJS += mem-pool.o
-LIB_OBJS += merge.o
LIB_OBJS += merge-blobs.o
LIB_OBJS += merge-recursive.o
+LIB_OBJS += merge.o
LIB_OBJS += mergesort.o
LIB_OBJS += midx.o
LIB_OBJS += name-hash.o
LIB_OBJS += negotiator/default.o
LIB_OBJS += negotiator/skipping.o
-LIB_OBJS += notes.o
LIB_OBJS += notes-cache.o
LIB_OBJS += notes-merge.o
LIB_OBJS += notes-utils.o
+LIB_OBJS += notes.o
LIB_OBJS += object.o
+LIB_OBJS += oid-array.o
LIB_OBJS += oidmap.o
LIB_OBJS += oidset.o
-LIB_OBJS += packfile.o
-LIB_OBJS += pack-bitmap.o
LIB_OBJS += pack-bitmap-write.o
+LIB_OBJS += pack-bitmap.o
LIB_OBJS += pack-check.o
LIB_OBJS += pack-objects.o
LIB_OBJS += pack-revindex.o
LIB_OBJS += pack-write.o
+LIB_OBJS += packfile.o
LIB_OBJS += pager.o
-LIB_OBJS += parse-options.o
LIB_OBJS += parse-options-cb.o
+LIB_OBJS += parse-options.o
LIB_OBJS += patch-delta.o
LIB_OBJS += patch-ids.o
LIB_OBJS += path.o
@@ -951,12 +948,14 @@ LIB_OBJS += progress.o
LIB_OBJS += promisor-remote.o
LIB_OBJS += prompt.o
LIB_OBJS += protocol.o
+LIB_OBJS += prune-packed.o
LIB_OBJS += quote.o
LIB_OBJS += range-diff.o
LIB_OBJS += reachable.o
LIB_OBJS += read-cache.o
-LIB_OBJS += rebase.o
LIB_OBJS += rebase-interactive.o
+LIB_OBJS += rebase.o
+LIB_OBJS += ref-filter.o
LIB_OBJS += reflog-walk.o
LIB_OBJS += refs.o
LIB_OBJS += refs/files-backend.o
@@ -964,12 +963,12 @@ LIB_OBJS += refs/iterator.o
LIB_OBJS += refs/packed-backend.o
LIB_OBJS += refs/ref-cache.o
LIB_OBJS += refspec.o
-LIB_OBJS += ref-filter.o
LIB_OBJS += remote.o
LIB_OBJS += replace-object.o
LIB_OBJS += repo-settings.o
LIB_OBJS += repository.o
LIB_OBJS += rerere.o
+LIB_OBJS += reset.o
LIB_OBJS += resolve-undo.o
LIB_OBJS += revision.o
LIB_OBJS += run-command.o
@@ -978,9 +977,8 @@ LIB_OBJS += sequencer.o
LIB_OBJS += serve.o
LIB_OBJS += server-info.o
LIB_OBJS += setup.o
-LIB_OBJS += sha1-array.o
-LIB_OBJS += sha1-lookup.o
LIB_OBJS += sha1-file.o
+LIB_OBJS += sha1-lookup.o
LIB_OBJS += sha1-name.o
LIB_OBJS += shallow.o
LIB_OBJS += sideband.o
@@ -990,9 +988,9 @@ LIB_OBJS += stable-qsort.o
LIB_OBJS += strbuf.o
LIB_OBJS += streaming.o
LIB_OBJS += string-list.o
-LIB_OBJS += submodule.o
-LIB_OBJS += submodule-config.o
LIB_OBJS += sub-process.o
+LIB_OBJS += submodule-config.o
+LIB_OBJS += submodule.o
LIB_OBJS += symlinks.o
LIB_OBJS += tag.o
LIB_OBJS += tempfile.o
@@ -1011,11 +1009,11 @@ LIB_OBJS += trace2/tr2_tgt_normal.o
LIB_OBJS += trace2/tr2_tgt_perf.o
LIB_OBJS += trace2/tr2_tls.o
LIB_OBJS += trailer.o
-LIB_OBJS += transport.o
LIB_OBJS += transport-helper.o
+LIB_OBJS += transport.o
LIB_OBJS += tree-diff.o
-LIB_OBJS += tree.o
LIB_OBJS += tree-walk.o
+LIB_OBJS += tree.o
LIB_OBJS += unpack-trees.o
LIB_OBJS += upload-pack.o
LIB_OBJS += url.o
@@ -1055,9 +1053,9 @@ BUILTIN_OBJS += builtin/checkout.o
BUILTIN_OBJS += builtin/clean.o
BUILTIN_OBJS += builtin/clone.o
BUILTIN_OBJS += builtin/column.o
+BUILTIN_OBJS += builtin/commit-graph.o
BUILTIN_OBJS += builtin/commit-tree.o
BUILTIN_OBJS += builtin/commit.o
-BUILTIN_OBJS += builtin/commit-graph.o
BUILTIN_OBJS += builtin/config.o
BUILTIN_OBJS += builtin/count-objects.o
BUILTIN_OBJS += builtin/credential.o
@@ -1088,13 +1086,13 @@ BUILTIN_OBJS += builtin/ls-remote.o
BUILTIN_OBJS += builtin/ls-tree.o
BUILTIN_OBJS += builtin/mailinfo.o
BUILTIN_OBJS += builtin/mailsplit.o
-BUILTIN_OBJS += builtin/merge.o
BUILTIN_OBJS += builtin/merge-base.o
BUILTIN_OBJS += builtin/merge-file.o
BUILTIN_OBJS += builtin/merge-index.o
BUILTIN_OBJS += builtin/merge-ours.o
BUILTIN_OBJS += builtin/merge-recursive.o
BUILTIN_OBJS += builtin/merge-tree.o
+BUILTIN_OBJS += builtin/merge.o
BUILTIN_OBJS += builtin/mktag.o
BUILTIN_OBJS += builtin/mktree.o
BUILTIN_OBJS += builtin/multi-pack-index.o
@@ -1114,9 +1112,9 @@ BUILTIN_OBJS += builtin/read-tree.o
BUILTIN_OBJS += builtin/rebase.o
BUILTIN_OBJS += builtin/receive-pack.o
BUILTIN_OBJS += builtin/reflog.o
-BUILTIN_OBJS += builtin/remote.o
BUILTIN_OBJS += builtin/remote-ext.o
BUILTIN_OBJS += builtin/remote-fd.o
+BUILTIN_OBJS += builtin/remote.o
BUILTIN_OBJS += builtin/repack.o
BUILTIN_OBJS += builtin/replace.o
BUILTIN_OBJS += builtin/rerere.o
@@ -1188,7 +1186,7 @@ PTHREAD_CFLAGS =
# For the 'sparse' target
SPARSE_FLAGS ?=
-SP_EXTRA_FLAGS =
+SP_EXTRA_FLAGS = -Wno-universal-initializer
# For the 'coccicheck' target; setting SPATCH_BATCH_SIZE higher will
# usually result in less CPU usage at the cost of higher peak memory.
@@ -1358,17 +1356,22 @@ ifdef NO_CURL
else
ifdef CURLDIR
# Try "-Wl,-rpath=$(CURLDIR)/$(lib)" in such a case.
- BASIC_CFLAGS += -I$(CURLDIR)/include
+ CURL_CFLAGS = -I$(CURLDIR)/include
CURL_LIBCURL = -L$(CURLDIR)/$(lib) $(CC_LD_DYNPATH)$(CURLDIR)/$(lib)
else
+ CURL_CFLAGS =
CURL_LIBCURL =
endif
-ifdef CURL_LDFLAGS
+ ifndef CURL_LDFLAGS
+ CURL_LDFLAGS = $(eval CURL_LDFLAGS := $$(shell $$(CURL_CONFIG) --libs))$(CURL_LDFLAGS)
+ endif
CURL_LIBCURL += $(CURL_LDFLAGS)
-else
- CURL_LIBCURL += $(shell $(CURL_CONFIG) --libs)
-endif
+
+ ifndef CURL_CFLAGS
+ CURL_CFLAGS = $(eval CURL_CFLAGS := $$(shell $$(CURL_CONFIG) --cflags))$(CURL_CFLAGS)
+ endif
+ BASIC_CFLAGS += $(CURL_CFLAGS)
REMOTE_CURL_PRIMARY = git-remote-http$X
REMOTE_CURL_ALIASES = git-remote-https$X git-remote-ftp$X git-remote-ftps$X
@@ -1803,11 +1806,6 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS
MSGFMT += --check --statistics
endif
-ifdef GMTIME_UNRELIABLE_ERRORS
- COMPAT_OBJS += compat/gmtime.o
- BASIC_CFLAGS += -DGMTIME_UNRELIABLE_ERRORS
-endif
-
ifdef HAVE_CLOCK_GETTIME
BASIC_CFLAGS += -DHAVE_CLOCK_GETTIME
endif
@@ -2133,7 +2131,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
help.sp help.s help.o: command-list.h
-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX
+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
@@ -2153,6 +2151,12 @@ $(BUILT_INS): git$X
ln -s $< $@ 2>/dev/null || \
cp $< $@
+config-list.h: generate-configlist.sh
+
+config-list.h:
+ $(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \
+ >$@+ && mv $@+ $@
+
command-list.h: generate-cmdlist.sh command-list.txt
command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt
@@ -2335,16 +2339,16 @@ reconfigure config.mak.autogen: config.status
endif
XDIFF_OBJS += xdiff/xdiffi.o
-XDIFF_OBJS += xdiff/xprepare.o
-XDIFF_OBJS += xdiff/xutils.o
XDIFF_OBJS += xdiff/xemit.o
+XDIFF_OBJS += xdiff/xhistogram.o
XDIFF_OBJS += xdiff/xmerge.o
XDIFF_OBJS += xdiff/xpatience.o
-XDIFF_OBJS += xdiff/xhistogram.o
+XDIFF_OBJS += xdiff/xprepare.o
+XDIFF_OBJS += xdiff/xutils.o
+VCSSVN_OBJS += vcs-svn/fast_export.o
VCSSVN_OBJS += vcs-svn/line_buffer.o
VCSSVN_OBJS += vcs-svn/sliding_window.o
-VCSSVN_OBJS += vcs-svn/fast_export.o
VCSSVN_OBJS += vcs-svn/svndiff.o
VCSSVN_OBJS += vcs-svn/svndump.o
@@ -2455,6 +2459,10 @@ endif
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
+ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+ $(LIBS)
+
git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(IMAP_SEND_LDFLAGS) $(LIBS)
@@ -2786,7 +2794,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE
.PHONY: sparse $(SP_OBJ)
sparse: $(SP_OBJ)
-EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%
+EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%
ifndef GCRYPT_SHA256
EXCEPT_HDRS += sha256/gcrypt.h
endif
@@ -2808,7 +2816,7 @@ hdr-check: $(HCO)
style:
git clang-format --style file --diff --extensions c,h
-check: command-list.h
+check: config-list.h command-list.h
@if sparse; \
then \
echo >&2 "Use 'make sparse' instead"; \
@@ -3152,9 +3160,10 @@ endif
#
ALL_COMMANDS = $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS)
ALL_COMMANDS += git
+ALL_COMMANDS += git-citool
+ALL_COMMANDS += git-gui
ALL_COMMANDS += gitk
ALL_COMMANDS += gitweb
-ALL_COMMANDS += git-gui git-citool
.PHONY: check-docs
check-docs::
diff --git a/README.md b/README.md
index 9d4564c..eb8115e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![Build Status](https://dev.azure.com/git/git/_apis/build/status/git.git)](https://dev.azure.com/git/git/_build/latest?definitionId=11)
+[![Build status](https://github.com/git/git/workflows/CI/PR/badge.svg)](https://github.com/git/git/actions?query=branch%3Amaster+event%3Apush)
Git - fast, scalable, distributed revision control system
=========================================================
diff --git a/RelNotes b/RelNotes
index 3427be6..9143650 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.26.2.txt \ No newline at end of file
+Documentation/RelNotes/2.29.0.txt \ No newline at end of file
diff --git a/abspath.c b/abspath.c
index 9857985..6f15a41 100644
--- a/abspath.c
+++ b/abspath.c
@@ -202,22 +202,6 @@ error_out:
return retval;
}
-/*
- * Resolve `path` into an absolute, cleaned-up path. The return value
- * comes from a shared buffer.
- */
-const char *real_path(const char *path)
-{
- static struct strbuf realpath = STRBUF_INIT;
- return strbuf_realpath(&realpath, path, 1);
-}
-
-const char *real_path_if_valid(const char *path)
-{
- static struct strbuf realpath = STRBUF_INIT;
- return strbuf_realpath(&realpath, path, 0);
-}
-
char *real_pathdup(const char *path, int die_on_error)
{
struct strbuf realpath = STRBUF_INIT;
@@ -233,7 +217,7 @@ char *real_pathdup(const char *path, int die_on_error)
/*
* Use this to get an absolute path from a relative one. If you want
- * to resolve links, you should use real_path.
+ * to resolve links, you should use strbuf_realpath.
*/
const char *absolute_path(const char *path)
{
diff --git a/add-interactive.c b/add-interactive.c
index 4a9bf85..29cd2fe 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -9,6 +9,7 @@
#include "lockfile.h"
#include "dir.h"
#include "run-command.h"
+#include "prompt.h"
static void init_color(struct repository *r, struct add_i_state *s,
const char *slot_name, char *dst,
@@ -289,13 +290,12 @@ static ssize_t list_and_choose(struct add_i_state *s,
fputs(singleton ? "> " : ">> ", stdout);
fflush(stdout);
- if (strbuf_getline(&input, stdin) == EOF) {
+ if (git_read_line_interactively(&input) == EOF) {
putchar('\n');
if (immediate)
res = LIST_AND_CHOOSE_QUIT;
break;
}
- strbuf_trim(&input);
if (!input.len)
break;
diff --git a/add-patch.c b/add-patch.c
index d8dafa8..a1d66c1 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -7,9 +7,10 @@
#include "color.h"
#include "diff.h"
#include "compat/terminal.h"
+#include "prompt.h"
enum prompt_mode_type {
- PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK,
+ PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_ADDITION, PROMPT_HUNK,
PROMPT_MODE_MAX, /* must be last */
};
@@ -32,6 +33,7 @@ static struct patch_mode patch_mode_add = {
.prompt_mode = {
N_("Stage mode change [y,n,q,a,d%s,?]? "),
N_("Stage deletion [y,n,q,a,d%s,?]? "),
+ N_("Stage addition [y,n,q,a,d%s,?]? "),
N_("Stage this hunk [y,n,q,a,d%s,?]? ")
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -53,6 +55,7 @@ static struct patch_mode patch_mode_stash = {
.prompt_mode = {
N_("Stash mode change [y,n,q,a,d%s,?]? "),
N_("Stash deletion [y,n,q,a,d%s,?]? "),
+ N_("Stash addition [y,n,q,a,d%s,?]? "),
N_("Stash this hunk [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -76,6 +79,7 @@ static struct patch_mode patch_mode_reset_head = {
.prompt_mode = {
N_("Unstage mode change [y,n,q,a,d%s,?]? "),
N_("Unstage deletion [y,n,q,a,d%s,?]? "),
+ N_("Unstage addition [y,n,q,a,d%s,?]? "),
N_("Unstage this hunk [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -98,6 +102,7 @@ static struct patch_mode patch_mode_reset_nothead = {
.prompt_mode = {
N_("Apply mode change to index [y,n,q,a,d%s,?]? "),
N_("Apply deletion to index [y,n,q,a,d%s,?]? "),
+ N_("Apply addition to index [y,n,q,a,d%s,?]? "),
N_("Apply this hunk to index [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -120,6 +125,7 @@ static struct patch_mode patch_mode_checkout_index = {
.prompt_mode = {
N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
+ N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -142,6 +148,7 @@ static struct patch_mode patch_mode_checkout_head = {
.prompt_mode = {
N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
+ N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -163,6 +170,7 @@ static struct patch_mode patch_mode_checkout_nothead = {
.prompt_mode = {
N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
+ N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -185,6 +193,7 @@ static struct patch_mode patch_mode_worktree_head = {
.prompt_mode = {
N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
+ N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -206,6 +215,7 @@ static struct patch_mode patch_mode_worktree_nothead = {
.prompt_mode = {
N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
+ N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -247,7 +257,7 @@ struct add_p_state {
struct hunk head;
struct hunk *hunk;
size_t hunk_nr, hunk_alloc;
- unsigned deleted:1, mode_change:1,binary:1;
+ unsigned deleted:1, added:1, mode_change:1,binary:1;
} *file_diff;
size_t file_diff_nr;
@@ -441,7 +451,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
pend = p + plain->len;
while (p != pend) {
char *eol = memchr(p, '\n', pend - p);
- const char *deleted = NULL, *mode_change = NULL;
+ const char *deleted = NULL, *added = NULL, *mode_change = NULL;
if (!eol)
eol = pend;
@@ -460,11 +470,12 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
} else if (p == plain->buf)
BUG("diff starts with unexpected line:\n"
"%.*s\n", (int)(eol - p), p);
- else if (file_diff->deleted)
+ else if (file_diff->deleted || file_diff->added)
; /* keep the rest of the file in a single "hunk" */
else if (starts_with(p, "@@ ") ||
(hunk == &file_diff->head &&
- skip_prefix(p, "deleted file", &deleted))) {
+ (skip_prefix(p, "deleted file", &deleted) ||
+ skip_prefix(p, "new file", &added)))) {
if (marker == '-' || marker == '+')
/*
* Should not happen; previous hunk did not end
@@ -484,6 +495,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
if (deleted)
file_diff->deleted = 1;
+ else if (added)
+ file_diff->added = 1;
else if (parse_hunk_header(s, hunk) < 0)
return -1;
@@ -536,8 +549,10 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
starts_with(p, "Binary files "))
file_diff->binary = 1;
- if (file_diff->deleted && file_diff->mode_change)
- BUG("diff contains delete *and* a mode change?!?\n%.*s",
+ if (!!file_diff->deleted + !!file_diff->added +
+ !!file_diff->mode_change > 1)
+ BUG("diff can only contain delete *or* add *or* a "
+ "mode change?!?\n%.*s",
(int)(eol - (plain->buf + file_diff->head.start)),
plain->buf + file_diff->head.start);
@@ -1158,9 +1173,8 @@ static int read_single_character(struct add_p_state *s)
return res;
}
- if (strbuf_getline(&s->answer, stdin) == EOF)
+ if (git_read_line_interactively(&s->answer) == EOF)
return EOF;
- strbuf_trim_trailing_newline(&s->answer);
return 0;
}
@@ -1189,7 +1203,7 @@ static int edit_hunk_loop(struct add_p_state *s,
for (;;) {
int res = edit_hunk_manually(s, hunk);
if (res == 0) {
- /* abandonded */
+ /* abandoned */
*hunk = backup;
return -1;
}
@@ -1397,6 +1411,8 @@ static int patch_update_file(struct add_p_state *s,
if (file_diff->deleted)
prompt_mode_type = PROMPT_DELETION;
+ else if (file_diff->added)
+ prompt_mode_type = PROMPT_ADDITION;
else if (file_diff->mode_change && !hunk_index)
prompt_mode_type = PROMPT_MODE_CHANGE;
else
diff --git a/advice.c b/advice.c
index 97f3f98..f0a3d32 100644
--- a/advice.c
+++ b/advice.c
@@ -29,7 +29,6 @@ int advice_ignored_hook = 1;
int advice_waiting_for_editor = 1;
int advice_graft_file_deprecated = 1;
int advice_checkout_ambiguous_remote_branch_name = 1;
-int advice_nested_tag = 1;
int advice_submodule_alternate_error_strategy_die = 1;
int advice_add_ignored_file = 1;
int advice_add_empty_pathspec = 1;
@@ -82,7 +81,7 @@ static struct {
{ "sequencerInUse", &advice_sequencer_in_use },
{ "implicitIdentity", &advice_implicit_identity },
{ "detachedHead", &advice_detached_head },
- { "setupStreamFailure", &advice_set_upstream_failure },
+ { "setUpstreamFailure", &advice_set_upstream_failure },
{ "objectNameWarning", &advice_object_name_warning },
{ "amWorkDir", &advice_amworkdir },
{ "rmHints", &advice_rm_hints },
@@ -91,7 +90,6 @@ static struct {
{ "waitingForEditor", &advice_waiting_for_editor },
{ "graftFileDeprecated", &advice_graft_file_deprecated },
{ "checkoutAmbiguousRemoteBranchName", &advice_checkout_ambiguous_remote_branch_name },
- { "nestedTag", &advice_nested_tag },
{ "submoduleAlternateErrorStrategyDie", &advice_submodule_alternate_error_strategy_die },
{ "addIgnoredFile", &advice_add_ignored_file },
{ "addEmptyPathspec", &advice_add_empty_pathspec },
@@ -100,15 +98,58 @@ static struct {
{ "pushNonFastForward", &advice_push_update_rejected }
};
-void advise(const char *advice, ...)
+static struct {
+ const char *key;
+ int enabled;
+} advice_setting[] = {
+ [ADVICE_ADD_EMBEDDED_REPO] = { "addEmbeddedRepo", 1 },
+ [ADVICE_AM_WORK_DIR] = { "amWorkDir", 1 },
+ [ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName", 1 },
+ [ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge", 1 },
+ [ADVICE_DETACHED_HEAD] = { "detachedHead", 1 },
+ [ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates", 1 },
+ [ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated", 1 },
+ [ADVICE_IGNORED_HOOK] = { "ignoredHook", 1 },
+ [ADVICE_IMPLICIT_IDENTITY] = { "implicitIdentity", 1 },
+ [ADVICE_NESTED_TAG] = { "nestedTag", 1 },
+ [ADVICE_OBJECT_NAME_WARNING] = { "objectNameWarning", 1 },
+ [ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists", 1 },
+ [ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst", 1 },
+ [ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce", 1 },
+
+ /* make this an alias for backward compatibility */
+ [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward", 1 },
+
+ [ADVICE_PUSH_NON_FF_CURRENT] = { "pushNonFFCurrent", 1 },
+ [ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching", 1 },
+ [ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName", 1 },
+ [ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected", 1 },
+ [ADVICE_RESET_QUIET_WARNING] = { "resetQuiet", 1 },
+ [ADVICE_RESOLVE_CONFLICT] = { "resolveConflict", 1 },
+ [ADVICE_RM_HINTS] = { "rmHints", 1 },
+ [ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse", 1 },
+ [ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure", 1 },
+ [ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning", 1 },
+ [ADVICE_STATUS_HINTS] = { "statusHints", 1 },
+ [ADVICE_STATUS_U_OPTION] = { "statusUoption", 1 },
+ [ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie", 1 },
+ [ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor", 1 },
+};
+
+static const char turn_off_instructions[] =
+N_("\n"
+ "Disable this message with \"git config advice.%s false\"");
+
+static void vadvise(const char *advice, int display_instructions,
+ const char *key, va_list params)
{
struct strbuf buf = STRBUF_INIT;
- va_list params;
const char *cp, *np;
- va_start(params, advice);
strbuf_vaddf(&buf, advice, params);
- va_end(params);
+
+ if (display_instructions)
+ strbuf_addf(&buf, turn_off_instructions, key);
for (cp = buf.buf; *cp; cp = np) {
np = strchrnul(cp, '\n');
@@ -122,6 +163,37 @@ void advise(const char *advice, ...)
strbuf_release(&buf);
}
+void advise(const char *advice, ...)
+{
+ va_list params;
+ va_start(params, advice);
+ vadvise(advice, 0, "", params);
+ va_end(params);
+}
+
+int advice_enabled(enum advice_type type)
+{
+ switch(type) {
+ case ADVICE_PUSH_UPDATE_REJECTED:
+ return advice_setting[ADVICE_PUSH_UPDATE_REJECTED].enabled &&
+ advice_setting[ADVICE_PUSH_UPDATE_REJECTED_ALIAS].enabled;
+ default:
+ return advice_setting[type].enabled;
+ }
+}
+
+void advise_if_enabled(enum advice_type type, const char *advice, ...)
+{
+ va_list params;
+
+ if (!advice_enabled(type))
+ return;
+
+ va_start(params, advice);
+ vadvise(advice, 1, advice_setting[type].key, params);
+ va_end(params);
+}
+
int git_default_advice_config(const char *var, const char *value)
{
const char *k, *slot_name;
@@ -148,6 +220,13 @@ int git_default_advice_config(const char *var, const char *value)
if (strcasecmp(k, advice_config[i].name))
continue;
*advice_config[i].preference = git_config_bool(var, value);
+ break;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(advice_setting); i++) {
+ if (strcasecmp(k, advice_setting[i].key))
+ continue;
+ advice_setting[i].enabled = git_config_bool(var, value);
return 0;
}
@@ -158,8 +237,8 @@ void list_config_advices(struct string_list *list, const char *prefix)
{
int i;
- for (i = 0; i < ARRAY_SIZE(advice_config); i++)
- list_config_item(list, prefix, advice_config[i].name);
+ for (i = 0; i < ARRAY_SIZE(advice_setting); i++)
+ list_config_item(list, prefix, advice_setting[i].key);
}
int error_resolve_conflict(const char *me)
diff --git a/advice.h b/advice.h
index 0e6e58d..16f2c11 100644
--- a/advice.h
+++ b/advice.h
@@ -29,14 +29,64 @@ extern int advice_ignored_hook;
extern int advice_waiting_for_editor;
extern int advice_graft_file_deprecated;
extern int advice_checkout_ambiguous_remote_branch_name;
-extern int advice_nested_tag;
extern int advice_submodule_alternate_error_strategy_die;
extern int advice_add_ignored_file;
extern int advice_add_empty_pathspec;
+/*
+ * To add a new advice, you need to:
+ * Define a new advice_type.
+ * Add a new entry to advice_setting array.
+ * Add the new config variable to Documentation/config/advice.txt.
+ * Call advise_if_enabled to print your advice.
+ */
+ enum advice_type {
+ ADVICE_ADD_EMBEDDED_REPO,
+ ADVICE_AM_WORK_DIR,
+ ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
+ ADVICE_COMMIT_BEFORE_MERGE,
+ ADVICE_DETACHED_HEAD,
+ ADVICE_FETCH_SHOW_FORCED_UPDATES,
+ ADVICE_GRAFT_FILE_DEPRECATED,
+ ADVICE_IGNORED_HOOK,
+ ADVICE_IMPLICIT_IDENTITY,
+ ADVICE_NESTED_TAG,
+ ADVICE_OBJECT_NAME_WARNING,
+ ADVICE_PUSH_ALREADY_EXISTS,
+ ADVICE_PUSH_FETCH_FIRST,
+ ADVICE_PUSH_NEEDS_FORCE,
+ ADVICE_PUSH_NON_FF_CURRENT,
+ ADVICE_PUSH_NON_FF_MATCHING,
+ ADVICE_PUSH_UNQUALIFIED_REF_NAME,
+ ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
+ ADVICE_PUSH_UPDATE_REJECTED,
+ ADVICE_RESET_QUIET_WARNING,
+ ADVICE_RESOLVE_CONFLICT,
+ ADVICE_RM_HINTS,
+ ADVICE_SEQUENCER_IN_USE,
+ ADVICE_SET_UPSTREAM_FAILURE,
+ ADVICE_STATUS_AHEAD_BEHIND_WARNING,
+ ADVICE_STATUS_HINTS,
+ ADVICE_STATUS_U_OPTION,
+ ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE,
+ ADVICE_WAITING_FOR_EDITOR,
+};
+
int git_default_advice_config(const char *var, const char *value);
__attribute__((format (printf, 1, 2)))
void advise(const char *advice, ...);
+
+/**
+ * Checks if advice type is enabled (can be printed to the user).
+ * Should be called before advise().
+ */
+int advice_enabled(enum advice_type type);
+
+/**
+ * Checks the visibility of the advice before printing.
+ */
+void advise_if_enabled(enum advice_type type, const char *advice, ...);
+
int error_resolve_conflict(const char *me);
void NORETURN die_resolve_conflict(const char *me);
void NORETURN die_conclude_merge(void);
diff --git a/alloc.c b/alloc.c
index 1c64c4d..957a0af 100644
--- a/alloc.c
+++ b/alloc.c
@@ -99,23 +99,27 @@ void *alloc_object_node(struct repository *r)
return obj;
}
-static unsigned int alloc_commit_index(struct repository *r)
+/*
+ * The returned count is to be used as an index into commit slabs,
+ * that are *NOT* maintained per repository, and that is why a single
+ * global counter is used.
+ */
+static unsigned int alloc_commit_index(void)
{
- return r->parsed_objects->commit_count++;
+ static unsigned int parsed_commits_count;
+ return parsed_commits_count++;
}
-void init_commit_node(struct repository *r, struct commit *c)
+void init_commit_node(struct commit *c)
{
c->object.type = OBJ_COMMIT;
- c->index = alloc_commit_index(r);
- c->graph_pos = COMMIT_NOT_FROM_GRAPH;
- c->generation = GENERATION_NUMBER_INFINITY;
+ c->index = alloc_commit_index();
}
void *alloc_commit_node(struct repository *r)
{
struct commit *c = alloc_node(r->parsed_objects->commit_state, sizeof(struct commit));
- init_commit_node(r, c);
+ init_commit_node(c);
return c;
}
diff --git a/alloc.h b/alloc.h
index ed1071c..371d388 100644
--- a/alloc.h
+++ b/alloc.h
@@ -9,7 +9,7 @@ struct repository;
void *alloc_blob_node(struct repository *r);
void *alloc_tree_node(struct repository *r);
-void init_commit_node(struct repository *r, struct commit *c);
+void init_commit_node(struct commit *c);
void *alloc_commit_node(struct repository *r);
void *alloc_tag_node(struct repository *r);
void *alloc_object_node(struct repository *r);
diff --git a/apply.c b/apply.c
index bdc008f..8bff604 100644
--- a/apply.c
+++ b/apply.c
@@ -4349,7 +4349,7 @@ static int try_create_file(struct apply_state *state, const char *path,
if (fd < 0)
return 1;
- if (convert_to_working_tree(state->repo->index, path, buf, size, &nbuf)) {
+ if (convert_to_working_tree(state->repo->index, path, buf, size, &nbuf, NULL)) {
size = nbuf.len;
buf = nbuf.buf;
}
@@ -4964,15 +4964,15 @@ int apply_parse_options(int argc, const char **argv,
const char * const *apply_usage)
{
struct option builtin_apply_options[] = {
- { OPTION_CALLBACK, 0, "exclude", state, N_("path"),
+ OPT_CALLBACK_F(0, "exclude", state, N_("path"),
N_("don't apply changes matching the given path"),
- PARSE_OPT_NONEG, apply_option_parse_exclude },
- { OPTION_CALLBACK, 0, "include", state, N_("path"),
+ PARSE_OPT_NONEG, apply_option_parse_exclude),
+ OPT_CALLBACK_F(0, "include", state, N_("path"),
N_("apply changes matching the given path"),
- PARSE_OPT_NONEG, apply_option_parse_include },
- { OPTION_CALLBACK, 'p', NULL, state, N_("num"),
+ PARSE_OPT_NONEG, apply_option_parse_include),
+ OPT_CALLBACK('p', NULL, state, N_("num"),
N_("remove <num> leading slashes from traditional diff paths"),
- 0, apply_option_parse_p },
+ apply_option_parse_p),
OPT_BOOL(0, "no-add", &state->no_add,
N_("ignore additions made by the patch")),
OPT_BOOL(0, "stat", &state->diffstat,
@@ -5005,15 +5005,15 @@ int apply_parse_options(int argc, const char **argv,
N_("paths are separated with NUL character"), '\0'),
OPT_INTEGER('C', NULL, &state->p_context,
N_("ensure at least <n> lines of context match")),
- { OPTION_CALLBACK, 0, "whitespace", state, N_("action"),
+ OPT_CALLBACK(0, "whitespace", state, N_("action"),
N_("detect new or modified lines that have whitespace errors"),
- 0, apply_option_parse_whitespace },
- { OPTION_CALLBACK, 0, "ignore-space-change", state, NULL,
+ apply_option_parse_whitespace),
+ OPT_CALLBACK_F(0, "ignore-space-change", state, NULL,
N_("ignore changes in whitespace when finding context"),
- PARSE_OPT_NOARG, apply_option_parse_space_change },
- { OPTION_CALLBACK, 0, "ignore-whitespace", state, NULL,
+ PARSE_OPT_NOARG, apply_option_parse_space_change),
+ OPT_CALLBACK_F(0, "ignore-whitespace", state, NULL,
N_("ignore changes in whitespace when finding context"),
- PARSE_OPT_NOARG, apply_option_parse_space_change },
+ PARSE_OPT_NOARG, apply_option_parse_space_change),
OPT_BOOL('R', "reverse", &state->apply_in_reverse,
N_("apply the patch in reverse")),
OPT_BOOL(0, "unidiff-zero", &state->unidiff_zero,
@@ -5029,9 +5029,9 @@ int apply_parse_options(int argc, const char **argv,
OPT_BIT(0, "recount", options,
N_("do not trust the line counts in the hunk headers"),
APPLY_OPT_RECOUNT),
- { OPTION_CALLBACK, 0, "directory", state, N_("root"),
+ OPT_CALLBACK(0, "directory", state, N_("root"),
N_("prepend <root> to all filenames"),
- 0, apply_option_parse_directory },
+ apply_option_parse_directory),
OPT_END()
};
diff --git a/archive-tar.c b/archive-tar.c
index 5a77701..5ceec36 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -364,7 +364,7 @@ static struct archiver **tar_filters;
static int nr_tar_filters;
static int alloc_tar_filters;
-static struct archiver *find_tar_filter(const char *name, int len)
+static struct archiver *find_tar_filter(const char *name, size_t len)
{
int i;
for (i = 0; i < nr_tar_filters; i++) {
@@ -380,7 +380,7 @@ static int tar_filter_config(const char *var, const char *value, void *data)
struct archiver *ar;
const char *name;
const char *type;
- int namelen;
+ size_t namelen;
if (parse_config_key(var, "tar", &name, &namelen, &type) < 0 || !name)
return 0;
diff --git a/archive.c b/archive.c
index a8da0fc..fb39706 100644
--- a/archive.c
+++ b/archive.c
@@ -77,6 +77,11 @@ void *object_file_to_archive(const struct archiver_args *args,
{
void *buffer;
const struct commit *commit = args->convert ? args->commit : NULL;
+ struct checkout_metadata meta;
+
+ init_checkout_metadata(&meta, args->refname,
+ args->commit_oid ? args->commit_oid :
+ (args->tree ? &args->tree->object.oid : NULL), oid);
path += args->baselen;
buffer = read_object_file(oid, type, sizep);
@@ -85,7 +90,7 @@ void *object_file_to_archive(const struct archiver_args *args,
size_t size = 0;
strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
- convert_to_working_tree(args->repo->index, path, buf.buf, buf.len, &buf);
+ convert_to_working_tree(args->repo->index, path, buf.buf, buf.len, &buf, &meta);
if (commit)
format_subst(commit, buf.buf, buf.len, &buf);
buffer = strbuf_detach(&buf, &size);
@@ -385,16 +390,17 @@ static void parse_treeish_arg(const char **argv,
struct tree *tree;
const struct commit *commit;
struct object_id oid;
+ char *ref = NULL;
/* Remotes are only allowed to fetch actual refs */
if (remote && !remote_allow_unreachable) {
- char *ref = NULL;
const char *colon = strchrnul(name, ':');
int refnamelen = colon - name;
if (!dwim_ref(name, refnamelen, &oid, &ref))
die(_("no such ref: %.*s"), refnamelen, name);
- free(ref);
+ } else {
+ dwim_ref(name, strlen(name), &oid, &ref);
}
if (get_oid(name, &oid))
@@ -427,6 +433,7 @@ static void parse_treeish_arg(const char **argv,
tree = parse_tree_indirect(&tree_oid);
}
+ ar_args->refname = ref;
ar_args->tree = tree;
ar_args->commit_oid = commit_oid;
ar_args->commit = commit;
diff --git a/archive.h b/archive.h
index e60e3dd..3bd96bf 100644
--- a/archive.h
+++ b/archive.h
@@ -8,6 +8,7 @@ struct repository;
struct archiver_args {
struct repository *repo;
+ const char *refname;
const char *base;
size_t baselen;
struct tree *tree;
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
deleted file mode 100644
index 675c3a4..0000000
--- a/azure-pipelines.yml
+++ /dev/null
@@ -1,558 +0,0 @@
-variables:
- Agent.Source.Git.ShallowFetchDepth: 1
-
-jobs:
-- job: windows_build
- displayName: Windows Build
- condition: succeeded()
- pool:
- vmImage: windows-latest
- timeoutInMinutes: 240
- steps:
- - powershell: |
- if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
- net use s: \\gitfileshare.file.core.windows.net\test-cache "$GITFILESHAREPWD" /user:AZURE\gitfileshare /persistent:no
- cmd /c mklink /d "$(Build.SourcesDirectory)\test-cache" S:\
- }
- displayName: 'Mount test-cache'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - powershell: |
- $urlbase = "https://dev.azure.com/git-for-windows/git/_apis/build/builds"
- $id = ((Invoke-WebRequest -UseBasicParsing "${urlbase}?definitions=22&statusFilter=completed&resultFilter=succeeded&`$top=1").content | ConvertFrom-JSON).value[0].id
- $downloadUrl = ((Invoke-WebRequest -UseBasicParsing "${urlbase}/$id/artifacts").content | ConvertFrom-JSON).value[1].resource.downloadUrl
- (New-Object Net.WebClient).DownloadFile($downloadUrl,"git-sdk-64-minimal.zip")
- Expand-Archive git-sdk-64-minimal.zip -DestinationPath . -Force
- Remove-Item git-sdk-64-minimal.zip
-
- # Let Git ignore the SDK and the test-cache
- "/git-sdk-64-minimal/`n/test-cache/`n" | Out-File -NoNewLine -Encoding ascii -Append "$(Build.SourcesDirectory)\.git\info\exclude"
- displayName: 'Download git-sdk-64-minimal'
- - powershell: |
- & git-sdk-64-minimal\usr\bin\bash.exe -lc @"
- ci/make-test-artifacts.sh artifacts
- "@
- if (!$?) { exit(1) }
- displayName: Build
- env:
- HOME: $(Build.SourcesDirectory)
- MSYSTEM: MINGW64
- DEVELOPER: 1
- NO_PERL: 1
- - task: PublishPipelineArtifact@0
- displayName: 'Publish Pipeline Artifact: test artifacts'
- inputs:
- artifactName: 'windows-artifacts'
- targetPath: '$(Build.SourcesDirectory)\artifacts'
- - task: PublishPipelineArtifact@0
- displayName: 'Publish Pipeline Artifact: git-sdk-64-minimal'
- inputs:
- artifactName: 'git-sdk-64-minimal'
- targetPath: '$(Build.SourcesDirectory)\git-sdk-64-minimal'
- - powershell: |
- if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
- cmd /c rmdir "$(Build.SourcesDirectory)\test-cache"
- }
- displayName: 'Unmount test-cache'
- condition: true
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
-
-- job: windows_test
- displayName: Windows Test
- dependsOn: windows_build
- condition: succeeded()
- pool:
- vmImage: windows-latest
- timeoutInMinutes: 240
- strategy:
- parallel: 10
- steps:
- - powershell: |
- if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
- net use s: \\gitfileshare.file.core.windows.net\test-cache "$GITFILESHAREPWD" /user:AZURE\gitfileshare /persistent:no
- cmd /c mklink /d "$(Build.SourcesDirectory)\test-cache" S:\
- }
- displayName: 'Mount test-cache'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: DownloadPipelineArtifact@0
- displayName: 'Download Pipeline Artifact: test artifacts'
- inputs:
- artifactName: 'windows-artifacts'
- targetPath: '$(Build.SourcesDirectory)'
- - task: DownloadPipelineArtifact@0
- displayName: 'Download Pipeline Artifact: git-sdk-64-minimal'
- inputs:
- artifactName: 'git-sdk-64-minimal'
- targetPath: '$(Build.SourcesDirectory)\git-sdk-64-minimal'
- - powershell: |
- & git-sdk-64-minimal\usr\bin\bash.exe -lc @"
- test -f artifacts.tar.gz || {
- echo No test artifacts found\; skipping >&2
- exit 0
- }
- tar xf artifacts.tar.gz || exit 1
-
- # Let Git ignore the SDK and the test-cache
- printf '%s\n' /git-sdk-64-minimal/ /test-cache/ >>.git/info/exclude
-
- ci/run-test-slice.sh `$SYSTEM_JOBPOSITIONINPHASE `$SYSTEM_TOTALJOBSINPHASE || {
- ci/print-test-failures.sh
- exit 1
- }
- "@
- if (!$?) { exit(1) }
- displayName: 'Test (parallel)'
- env:
- HOME: $(Build.SourcesDirectory)
- MSYSTEM: MINGW64
- NO_SVN_TESTS: 1
- GIT_TEST_SKIP_REBASE_P: 1
- - powershell: |
- if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
- cmd /c rmdir "$(Build.SourcesDirectory)\test-cache"
- }
- displayName: 'Unmount test-cache'
- condition: true
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: PublishTestResults@2
- displayName: 'Publish Test Results **/TEST-*.xml'
- inputs:
- mergeTestResults: true
- testRunTitle: 'windows'
- platform: Windows
- publishRunAttachments: false
- condition: succeededOrFailed()
- - task: PublishBuildArtifacts@1
- displayName: 'Publish trash directories of failed tests'
- condition: failed()
- inputs:
- PathtoPublish: t/failed-test-artifacts
- ArtifactName: failed-test-artifacts
-
-- job: vs_build
- displayName: Visual Studio Build
- condition: succeeded()
- pool:
- vmImage: windows-latest
- timeoutInMinutes: 240
- steps:
- - powershell: |
- if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
- net use s: \\gitfileshare.file.core.windows.net\test-cache "$GITFILESHAREPWD" /user:AZURE\gitfileshare /persistent:no
- cmd /c mklink /d "$(Build.SourcesDirectory)\test-cache" S:\
- }
- displayName: 'Mount test-cache'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - powershell: |
- $urlbase = "https://dev.azure.com/git-for-windows/git/_apis/build/builds"
- $id = ((Invoke-WebRequest -UseBasicParsing "${urlbase}?definitions=22&statusFilter=completed&resultFilter=succeeded&`$top=1").content | ConvertFrom-JSON).value[0].id
- $downloadUrl = ((Invoke-WebRequest -UseBasicParsing "${urlbase}/$id/artifacts").content | ConvertFrom-JSON).value[1].resource.downloadUrl
- (New-Object Net.WebClient).DownloadFile($downloadUrl,"git-sdk-64-minimal.zip")
- Expand-Archive git-sdk-64-minimal.zip -DestinationPath . -Force
- Remove-Item git-sdk-64-minimal.zip
-
- # Let Git ignore the SDK and the test-cache
- "/git-sdk-64-minimal/`n/test-cache/`n" | Out-File -NoNewLine -Encoding ascii -Append "$(Build.SourcesDirectory)\.git\info\exclude"
- displayName: 'Download git-sdk-64-minimal'
- - powershell: |
- & git-sdk-64-minimal\usr\bin\bash.exe -lc @"
- make NDEBUG=1 DEVELOPER=1 vcxproj
- "@
- if (!$?) { exit(1) }
- displayName: Generate Visual Studio Solution
- env:
- HOME: $(Build.SourcesDirectory)
- MSYSTEM: MINGW64
- DEVELOPER: 1
- NO_PERL: 1
- GIT_CONFIG_PARAMETERS: "'user.name=CI' 'user.email=ci@git'"
- - powershell: |
- $urlbase = "https://dev.azure.com/git/git/_apis/build/builds"
- $id = ((Invoke-WebRequest -UseBasicParsing "${urlbase}?definitions=9&statusFilter=completed&resultFilter=succeeded&`$top=1").content | ConvertFrom-JSON).value[0].id
- $downloadUrl = ((Invoke-WebRequest -UseBasicParsing "${urlbase}/$id/artifacts").content | ConvertFrom-JSON).value[0].resource.downloadUrl
- (New-Object Net.WebClient).DownloadFile($downloadUrl, "compat.zip")
- Expand-Archive compat.zip -DestinationPath . -Force
- Remove-Item compat.zip
- displayName: 'Download vcpkg artifacts'
- - task: MSBuild@1
- inputs:
- solution: git.sln
- platform: x64
- configuration: Release
- maximumCpuCount: 4
- msbuildArguments: /p:PlatformToolset=v142
- - powershell: |
- & compat\vcbuild\vcpkg_copy_dlls.bat release
- if (!$?) { exit(1) }
- & git-sdk-64-minimal\usr\bin\bash.exe -lc @"
- mkdir -p artifacts &&
- eval \"`$(make -n artifacts-tar INCLUDE_DLLS_IN_ARTIFACTS=YesPlease ARTIFACTS_DIRECTORY=artifacts | grep ^tar)\"
- "@
- if (!$?) { exit(1) }
- displayName: Bundle artifact tar
- env:
- HOME: $(Build.SourcesDirectory)
- MSYSTEM: MINGW64
- DEVELOPER: 1
- NO_PERL: 1
- MSVC: 1
- VCPKG_ROOT: $(Build.SourcesDirectory)\compat\vcbuild\vcpkg
- - powershell: |
- $tag = (Invoke-WebRequest -UseBasicParsing "https://gitforwindows.org/latest-tag.txt").content
- $version = (Invoke-WebRequest -UseBasicParsing "https://gitforwindows.org/latest-version.txt").content
- $url = "https://github.com/git-for-windows/git/releases/download/${tag}/PortableGit-${version}-64-bit.7z.exe"
- (New-Object Net.WebClient).DownloadFile($url,"PortableGit.exe")
- & .\PortableGit.exe -y -oartifacts\PortableGit
- # Wait until it is unpacked
- while (-not @(Remove-Item -ErrorAction SilentlyContinue PortableGit.exe; $?)) { sleep 1 }
- displayName: Download & extract portable Git
- - task: PublishPipelineArtifact@0
- displayName: 'Publish Pipeline Artifact: MSVC test artifacts'
- inputs:
- artifactName: 'vs-artifacts'
- targetPath: '$(Build.SourcesDirectory)\artifacts'
- - powershell: |
- if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
- cmd /c rmdir "$(Build.SourcesDirectory)\test-cache"
- }
- displayName: 'Unmount test-cache'
- condition: true
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
-
-- job: vs_test
- displayName: Visual Studio Test
- dependsOn: vs_build
- condition: succeeded()
- pool:
- vmImage: windows-latest
- timeoutInMinutes: 240
- strategy:
- parallel: 10
- steps:
- - powershell: |
- if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
- net use s: \\gitfileshare.file.core.windows.net\test-cache "$GITFILESHAREPWD" /user:AZURE\gitfileshare /persistent:no
- cmd /c mklink /d "$(Build.SourcesDirectory)\test-cache" S:\
- }
- displayName: 'Mount test-cache'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: DownloadPipelineArtifact@0
- displayName: 'Download Pipeline Artifact: VS test artifacts'
- inputs:
- artifactName: 'vs-artifacts'
- targetPath: '$(Build.SourcesDirectory)'
- - powershell: |
- & PortableGit\git-cmd.exe --command=usr\bin\bash.exe -lc @"
- test -f artifacts.tar.gz || {
- echo No test artifacts found\; skipping >&2
- exit 0
- }
- tar xf artifacts.tar.gz || exit 1
-
- # Let Git ignore the SDK and the test-cache
- printf '%s\n' /PortableGit/ /test-cache/ >>.git/info/exclude
-
- cd t &&
- PATH=\"`$PWD/helper:`$PATH\" &&
- test-tool.exe run-command testsuite --jobs=10 -V -x --write-junit-xml \
- `$(test-tool.exe path-utils slice-tests \
- `$SYSTEM_JOBPOSITIONINPHASE `$SYSTEM_TOTALJOBSINPHASE t[0-9]*.sh)
- "@
- if (!$?) { exit(1) }
- displayName: 'Test (parallel)'
- env:
- HOME: $(Build.SourcesDirectory)
- MSYSTEM: MINGW64
- NO_SVN_TESTS: 1
- GIT_TEST_SKIP_REBASE_P: 1
- - powershell: |
- if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
- cmd /c rmdir "$(Build.SourcesDirectory)\test-cache"
- }
- displayName: 'Unmount test-cache'
- condition: true
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: PublishTestResults@2
- displayName: 'Publish Test Results **/TEST-*.xml'
- inputs:
- mergeTestResults: true
- testRunTitle: 'vs'
- platform: Windows
- publishRunAttachments: false
- condition: succeededOrFailed()
- - task: PublishBuildArtifacts@1
- displayName: 'Publish trash directories of failed tests'
- condition: failed()
- inputs:
- PathtoPublish: t/failed-test-artifacts
- ArtifactName: failed-vs-test-artifacts
-
-- job: linux_clang
- displayName: linux-clang
- condition: succeeded()
- pool:
- vmImage: ubuntu-latest
- steps:
- - bash: |
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
-
- sudo apt-get update &&
- sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin &&
-
- export CC=clang || exit 1
-
- ci/install-dependencies.sh || exit 1
- ci/run-build-and-tests.sh || {
- ci/print-test-failures.sh
- exit 1
- }
-
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
- displayName: 'ci/run-build-and-tests.sh'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: PublishTestResults@2
- displayName: 'Publish Test Results **/TEST-*.xml'
- inputs:
- mergeTestResults: true
- testRunTitle: 'linux-clang'
- platform: Linux
- publishRunAttachments: false
- condition: succeededOrFailed()
- - task: PublishBuildArtifacts@1
- displayName: 'Publish trash directories of failed tests'
- condition: failed()
- inputs:
- PathtoPublish: t/failed-test-artifacts
- ArtifactName: failed-test-artifacts
-
-- job: linux_gcc
- displayName: linux-gcc
- condition: succeeded()
- pool:
- vmImage: ubuntu-latest
- steps:
- - bash: |
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
-
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test &&
- sudo apt-get update &&
- sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2 language-pack-is git-svn gcc-8 || exit 1
-
- ci/install-dependencies.sh || exit 1
- ci/run-build-and-tests.sh || {
- ci/print-test-failures.sh
- exit 1
- }
-
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
- displayName: 'ci/run-build-and-tests.sh'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: PublishTestResults@2
- displayName: 'Publish Test Results **/TEST-*.xml'
- inputs:
- mergeTestResults: true
- testRunTitle: 'linux-gcc'
- platform: Linux
- publishRunAttachments: false
- condition: succeededOrFailed()
- - task: PublishBuildArtifacts@1
- displayName: 'Publish trash directories of failed tests'
- condition: failed()
- inputs:
- PathtoPublish: t/failed-test-artifacts
- ArtifactName: failed-test-artifacts
-
-- job: osx_clang
- displayName: osx-clang
- condition: succeeded()
- pool:
- vmImage: macOS-latest
- steps:
- - bash: |
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
-
- export CC=clang
-
- ci/install-dependencies.sh || exit 1
- ci/run-build-and-tests.sh || {
- ci/print-test-failures.sh
- exit 1
- }
-
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
- displayName: 'ci/run-build-and-tests.sh'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: PublishTestResults@2
- displayName: 'Publish Test Results **/TEST-*.xml'
- inputs:
- mergeTestResults: true
- testRunTitle: 'osx-clang'
- platform: macOS
- publishRunAttachments: false
- condition: succeededOrFailed()
- - task: PublishBuildArtifacts@1
- displayName: 'Publish trash directories of failed tests'
- condition: failed()
- inputs:
- PathtoPublish: t/failed-test-artifacts
- ArtifactName: failed-test-artifacts
-
-- job: osx_gcc
- displayName: osx-gcc
- condition: succeeded()
- pool:
- vmImage: macOS-latest
- steps:
- - bash: |
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
-
- ci/install-dependencies.sh || exit 1
- ci/run-build-and-tests.sh || {
- ci/print-test-failures.sh
- exit 1
- }
-
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
- displayName: 'ci/run-build-and-tests.sh'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: PublishTestResults@2
- displayName: 'Publish Test Results **/TEST-*.xml'
- inputs:
- mergeTestResults: true
- testRunTitle: 'osx-gcc'
- platform: macOS
- publishRunAttachments: false
- condition: succeededOrFailed()
- - task: PublishBuildArtifacts@1
- displayName: 'Publish trash directories of failed tests'
- condition: failed()
- inputs:
- PathtoPublish: t/failed-test-artifacts
- ArtifactName: failed-test-artifacts
-
-- job: gettext_poison
- displayName: GETTEXT_POISON
- condition: succeeded()
- pool:
- vmImage: ubuntu-latest
- steps:
- - bash: |
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
-
- sudo apt-get update &&
- sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev &&
-
- export jobname=GETTEXT_POISON || exit 1
-
- ci/run-build-and-tests.sh || {
- ci/print-test-failures.sh
- exit 1
- }
-
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
- displayName: 'ci/run-build-and-tests.sh'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: PublishTestResults@2
- displayName: 'Publish Test Results **/TEST-*.xml'
- inputs:
- mergeTestResults: true
- testRunTitle: 'gettext-poison'
- platform: Linux
- publishRunAttachments: false
- condition: succeededOrFailed()
- - task: PublishBuildArtifacts@1
- displayName: 'Publish trash directories of failed tests'
- condition: failed()
- inputs:
- PathtoPublish: t/failed-test-artifacts
- ArtifactName: failed-test-artifacts
-
-- job: linux32
- displayName: Linux32
- condition: succeeded()
- pool:
- vmImage: ubuntu-latest
- steps:
- - bash: |
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
-
- res=0
- sudo AGENT_OS="$AGENT_OS" BUILD_BUILDNUMBER="$BUILD_BUILDNUMBER" BUILD_REPOSITORY_URI="$BUILD_REPOSITORY_URI" BUILD_SOURCEBRANCH="$BUILD_SOURCEBRANCH" BUILD_SOURCEVERSION="$BUILD_SOURCEVERSION" SYSTEM_PHASENAME="$SYSTEM_PHASENAME" SYSTEM_TASKDEFINITIONSURI="$SYSTEM_TASKDEFINITIONSURI" SYSTEM_TEAMPROJECT="$SYSTEM_TEAMPROJECT" CC=$CC MAKEFLAGS="$MAKEFLAGS" bash -lxc ci/run-linux32-docker.sh || res=1
-
- sudo chmod a+r t/out/TEST-*.xml
- test ! -d t/failed-test-artifacts || sudo chmod a+r t/failed-test-artifacts
-
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || res=1
- exit $res
- displayName: 'ci/run-linux32-docker.sh'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
- - task: PublishTestResults@2
- displayName: 'Publish Test Results **/TEST-*.xml'
- inputs:
- mergeTestResults: true
- testRunTitle: 'linux32'
- platform: Linux
- publishRunAttachments: false
- condition: succeededOrFailed()
- - task: PublishBuildArtifacts@1
- displayName: 'Publish trash directories of failed tests'
- condition: failed()
- inputs:
- PathtoPublish: t/failed-test-artifacts
- ArtifactName: failed-test-artifacts
-
-- job: static_analysis
- displayName: StaticAnalysis
- condition: succeeded()
- pool:
- vmImage: ubuntu-latest
- steps:
- - bash: |
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
-
- sudo apt-get update &&
- sudo apt-get install -y coccinelle libcurl4-openssl-dev libssl-dev libexpat-dev gettext &&
-
- export jobname=StaticAnalysis &&
-
- ci/run-static-analysis.sh || exit 1
-
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
- displayName: 'ci/run-static-analysis.sh'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
-
-- job: documentation
- displayName: Documentation
- condition: succeeded()
- pool:
- vmImage: ubuntu-latest
- steps:
- - bash: |
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
-
- sudo apt-get update &&
- sudo apt-get install -y asciidoc xmlto asciidoctor docbook-xsl-ns &&
-
- export ALREADY_HAVE_ASCIIDOCTOR=yes. &&
- export jobname=Documentation &&
-
- ci/test-documentation.sh || exit 1
-
- test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
- displayName: 'ci/test-documentation.sh'
- env:
- GITFILESHAREPWD: $(gitfileshare.pwd)
diff --git a/bisect.c b/bisect.c
index 9154f81..d5e8304 100644
--- a/bisect.c
+++ b/bisect.c
@@ -10,7 +10,7 @@
#include "run-command.h"
#include "log-tree.h"
#include "bisect.h"
-#include "sha1-array.h"
+#include "oid-array.h"
#include "argv-array.h"
#include "commit-slab.h"
#include "commit-reach.h"
@@ -473,7 +473,7 @@ static void read_bisect_paths(struct argv_array *array)
fclose(fp);
}
-static char *join_sha1_array_hex(struct oid_array *array, char delim)
+static char *join_oid_array_hex(struct oid_array *array, char delim)
{
struct strbuf joined_hexs = STRBUF_INIT;
int i;
@@ -765,7 +765,7 @@ static enum bisect_error handle_bad_merge_base(void)
{
if (is_expected_rev(current_bad_oid)) {
char *bad_hex = oid_to_hex(current_bad_oid);
- char *good_hex = join_sha1_array_hex(&good_revs, ' ');
+ char *good_hex = join_oid_array_hex(&good_revs, ' ');
if (!strcmp(term_bad, "bad") && !strcmp(term_good, "good")) {
fprintf(stderr, _("The merge base %s is bad.\n"
"This means the bug has been fixed "
@@ -796,7 +796,7 @@ static void handle_skipped_merge_base(const struct object_id *mb)
{
char *mb_hex = oid_to_hex(mb);
char *bad_hex = oid_to_hex(current_bad_oid);
- char *good_hex = join_sha1_array_hex(&good_revs, ' ');
+ char *good_hex = join_oid_array_hex(&good_revs, ' ');
warning(_("the merge base between %s and [%s] "
"must be skipped.\n"
diff --git a/blame.c b/blame.c
index 29770e5..82fa16d 100644
--- a/blame.c
+++ b/blame.c
@@ -9,6 +9,8 @@
#include "blame.h"
#include "alloc.h"
#include "commit-slab.h"
+#include "bloom.h"
+#include "commit-graph.h"
define_commit_slab(blame_suspects, struct blame_origin *);
static struct blame_suspects blame_suspects;
@@ -1246,13 +1248,74 @@ static int fill_blob_sha1_and_mode(struct repository *r,
return -1;
}
+struct blame_bloom_data {
+ /*
+ * Changed-path Bloom filter keys. These can help prevent
+ * computing diffs against first parents, but we need to
+ * expand the list as code is moved or files are renamed.
+ */
+ struct bloom_filter_settings *settings;
+ struct bloom_key **keys;
+ int nr;
+ int alloc;
+};
+
+static int bloom_count_queries = 0;
+static int bloom_count_no = 0;
+static int maybe_changed_path(struct repository *r,
+ struct blame_origin *origin,
+ struct blame_bloom_data *bd)
+{
+ int i;
+ struct bloom_filter *filter;
+
+ if (!bd)
+ return 1;
+
+ if (commit_graph_generation(origin->commit) == GENERATION_NUMBER_INFINITY)
+ return 1;
+
+ filter = get_bloom_filter(r, origin->commit, 0);
+
+ if (!filter)
+ return 1;
+
+ bloom_count_queries++;
+ for (i = 0; i < bd->nr; i++) {
+ if (bloom_filter_contains(filter,
+ bd->keys[i],
+ bd->settings))
+ return 1;
+ }
+
+ bloom_count_no++;
+ return 0;
+}
+
+static void add_bloom_key(struct blame_bloom_data *bd,
+ const char *path)
+{
+ if (!bd)
+ return;
+
+ if (bd->nr >= bd->alloc) {
+ bd->alloc *= 2;
+ REALLOC_ARRAY(bd->keys, bd->alloc);
+ }
+
+ bd->keys[bd->nr] = xmalloc(sizeof(struct bloom_key));
+ fill_bloom_key(path, strlen(path), bd->keys[bd->nr], bd->settings);
+ bd->nr++;
+}
+
/*
* We have an origin -- check if the same path exists in the
* parent and return an origin structure to represent it.
*/
static struct blame_origin *find_origin(struct repository *r,
struct commit *parent,
- struct blame_origin *origin)
+ struct blame_origin *origin,
+ struct blame_bloom_data *bd)
{
struct blame_origin *porigin;
struct diff_options diff_opts;
@@ -1286,10 +1349,18 @@ static struct blame_origin *find_origin(struct repository *r,
if (is_null_oid(&origin->commit->object.oid))
do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
- else
- diff_tree_oid(get_commit_tree_oid(parent),
- get_commit_tree_oid(origin->commit),
- "", &diff_opts);
+ else {
+ int compute_diff = 1;
+ if (origin->commit->parents &&
+ !oidcmp(&parent->object.oid,
+ &origin->commit->parents->item->object.oid))
+ compute_diff = maybe_changed_path(r, origin, bd);
+
+ if (compute_diff)
+ diff_tree_oid(get_commit_tree_oid(parent),
+ get_commit_tree_oid(origin->commit),
+ "", &diff_opts);
+ }
diffcore_std(&diff_opts);
if (!diff_queued_diff.nr) {
@@ -1341,7 +1412,8 @@ static struct blame_origin *find_origin(struct repository *r,
*/
static struct blame_origin *find_rename(struct repository *r,
struct commit *parent,
- struct blame_origin *origin)
+ struct blame_origin *origin,
+ struct blame_bloom_data *bd)
{
struct blame_origin *porigin = NULL;
struct diff_options diff_opts;
@@ -1366,6 +1438,7 @@ static struct blame_origin *find_rename(struct repository *r,
struct diff_filepair *p = diff_queued_diff.queue[i];
if ((p->status == 'R' || p->status == 'C') &&
!strcmp(p->two->path, origin->path)) {
+ add_bloom_key(bd, p->one->path);
porigin = get_origin(parent, p->one->path);
oidcpy(&porigin->blob_oid, &p->one->oid);
porigin->mode = p->one->mode;
@@ -2332,6 +2405,11 @@ static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *bl
#define MAXSG 16
+typedef struct blame_origin *(*blame_find_alg)(struct repository *,
+ struct commit *,
+ struct blame_origin *,
+ struct blame_bloom_data *);
+
static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin, int opt)
{
struct rev_info *revs = sb->revs;
@@ -2356,8 +2434,7 @@ static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin,
* common cases, then we look for renames in the second pass.
*/
for (pass = 0; pass < 2 - sb->no_whole_file_rename; pass++) {
- struct blame_origin *(*find)(struct repository *, struct commit *, struct blame_origin *);
- find = pass ? find_rename : find_origin;
+ blame_find_alg find = pass ? find_rename : find_origin;
for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
i < num_sg && sg;
@@ -2369,7 +2446,7 @@ static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin,
continue;
if (parse_commit(p))
continue;
- porigin = find(sb->repo, p, origin);
+ porigin = find(sb->repo, p, origin, sb->bloom_data);
if (!porigin)
continue;
if (oideq(&porigin->blob_oid, &origin->blob_oid)) {
@@ -2809,3 +2886,45 @@ struct blame_entry *blame_entry_prepend(struct blame_entry *head,
blame_origin_incref(o);
return new_head;
}
+
+void setup_blame_bloom_data(struct blame_scoreboard *sb,
+ const char *path)
+{
+ struct blame_bloom_data *bd;
+
+ if (!sb->repo->objects->commit_graph)
+ return;
+
+ if (!sb->repo->objects->commit_graph->bloom_filter_settings)
+ return;
+
+ bd = xmalloc(sizeof(struct blame_bloom_data));
+
+ bd->settings = sb->repo->objects->commit_graph->bloom_filter_settings;
+
+ bd->alloc = 4;
+ bd->nr = 0;
+ ALLOC_ARRAY(bd->keys, bd->alloc);
+
+ add_bloom_key(bd, path);
+
+ sb->bloom_data = bd;
+}
+
+void cleanup_scoreboard(struct blame_scoreboard *sb)
+{
+ if (sb->bloom_data) {
+ int i;
+ for (i = 0; i < sb->bloom_data->nr; i++) {
+ free(sb->bloom_data->keys[i]->hashes);
+ free(sb->bloom_data->keys[i]);
+ }
+ free(sb->bloom_data->keys);
+ FREE_AND_NULL(sb->bloom_data);
+
+ trace2_data_intmax("blame", sb->repo,
+ "bloom/queries", bloom_count_queries);
+ trace2_data_intmax("blame", sb->repo,
+ "bloom/response-no", bloom_count_no);
+ }
+}
diff --git a/blame.h b/blame.h
index 089b181..b6bbee4 100644
--- a/blame.h
+++ b/blame.h
@@ -100,6 +100,8 @@ struct blame_entry {
int unblamable;
};
+struct blame_bloom_data;
+
/*
* The current state of the blame assignment.
*/
@@ -156,6 +158,7 @@ struct blame_scoreboard {
void(*found_guilty_entry)(struct blame_entry *, void *);
void *found_guilty_entry_data;
+ struct blame_bloom_data *bloom_data;
};
/*
@@ -180,6 +183,9 @@ void init_scoreboard(struct blame_scoreboard *sb);
void setup_scoreboard(struct blame_scoreboard *sb,
const char *path,
struct blame_origin **orig);
+void setup_blame_bloom_data(struct blame_scoreboard *sb,
+ const char *path);
+void cleanup_scoreboard(struct blame_scoreboard *sb);
struct blame_entry *blame_entry_prepend(struct blame_entry *head,
long start, long end,
diff --git a/blob.c b/blob.c
index 36f9abd..182718a 100644
--- a/blob.c
+++ b/blob.c
@@ -10,7 +10,7 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid)
struct object *obj = lookup_object(r, oid);
if (!obj)
return create_object(r, oid, alloc_blob_node(r));
- return object_as_type(r, obj, OBJ_BLOB, 0);
+ return object_as_type(obj, OBJ_BLOB, 0);
}
int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)
diff --git a/bloom.c b/bloom.c
new file mode 100644
index 0000000..1a57322
--- /dev/null
+++ b/bloom.c
@@ -0,0 +1,300 @@
+#include "git-compat-util.h"
+#include "bloom.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "revision.h"
+#include "hashmap.h"
+#include "commit-graph.h"
+#include "commit.h"
+
+define_commit_slab(bloom_filter_slab, struct bloom_filter);
+
+static struct bloom_filter_slab bloom_filters;
+
+struct pathmap_hash_entry {
+ struct hashmap_entry entry;
+ const char path[FLEX_ARRAY];
+};
+
+static uint32_t rotate_left(uint32_t value, int32_t count)
+{
+ uint32_t mask = 8 * sizeof(uint32_t) - 1;
+ count &= mask;
+ return ((value << count) | (value >> ((-count) & mask)));
+}
+
+static inline unsigned char get_bitmask(uint32_t pos)
+{
+ return ((unsigned char)1) << (pos & (BITS_PER_WORD - 1));
+}
+
+static int load_bloom_filter_from_graph(struct commit_graph *g,
+ struct bloom_filter *filter,
+ struct commit *c)
+{
+ uint32_t lex_pos, start_index, end_index;
+ uint32_t graph_pos = commit_graph_position(c);
+
+ while (graph_pos < g->num_commits_in_base)
+ g = g->base_graph;
+
+ /* The commit graph commit 'c' lives in doesn't carry bloom filters. */
+ if (!g->chunk_bloom_indexes)
+ return 0;
+
+ lex_pos = graph_pos - g->num_commits_in_base;
+
+ end_index = get_be32(g->chunk_bloom_indexes + 4 * lex_pos);
+
+ if (lex_pos > 0)
+ start_index = get_be32(g->chunk_bloom_indexes + 4 * (lex_pos - 1));
+ else
+ start_index = 0;
+
+ filter->len = end_index - start_index;
+ filter->data = (unsigned char *)(g->chunk_bloom_data +
+ sizeof(unsigned char) * start_index +
+ BLOOMDATA_CHUNK_HEADER_SIZE);
+
+ return 1;
+}
+
+/*
+ * Calculate the murmur3 32-bit hash value for the given data
+ * using the given seed.
+ * Produces a uniformly distributed hash value.
+ * Not considered to be cryptographically secure.
+ * Implemented as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm
+ */
+uint32_t murmur3_seeded(uint32_t seed, const char *data, size_t len)
+{
+ const uint32_t c1 = 0xcc9e2d51;
+ const uint32_t c2 = 0x1b873593;
+ const uint32_t r1 = 15;
+ const uint32_t r2 = 13;
+ const uint32_t m = 5;
+ const uint32_t n = 0xe6546b64;
+ int i;
+ uint32_t k1 = 0;
+ const char *tail;
+
+ int len4 = len / sizeof(uint32_t);
+
+ uint32_t k;
+ for (i = 0; i < len4; i++) {
+ uint32_t byte1 = (uint32_t)data[4*i];
+ uint32_t byte2 = ((uint32_t)data[4*i + 1]) << 8;
+ uint32_t byte3 = ((uint32_t)data[4*i + 2]) << 16;
+ uint32_t byte4 = ((uint32_t)data[4*i + 3]) << 24;
+ k = byte1 | byte2 | byte3 | byte4;
+ k *= c1;
+ k = rotate_left(k, r1);
+ k *= c2;
+
+ seed ^= k;
+ seed = rotate_left(seed, r2) * m + n;
+ }
+
+ tail = (data + len4 * sizeof(uint32_t));
+
+ switch (len & (sizeof(uint32_t) - 1)) {
+ case 3:
+ k1 ^= ((uint32_t)tail[2]) << 16;
+ /*-fallthrough*/
+ case 2:
+ k1 ^= ((uint32_t)tail[1]) << 8;
+ /*-fallthrough*/
+ case 1:
+ k1 ^= ((uint32_t)tail[0]) << 0;
+ k1 *= c1;
+ k1 = rotate_left(k1, r1);
+ k1 *= c2;
+ seed ^= k1;
+ break;
+ }
+
+ seed ^= (uint32_t)len;
+ seed ^= (seed >> 16);
+ seed *= 0x85ebca6b;
+ seed ^= (seed >> 13);
+ seed *= 0xc2b2ae35;
+ seed ^= (seed >> 16);
+
+ return seed;
+}
+
+void fill_bloom_key(const char *data,
+ size_t len,
+ struct bloom_key *key,
+ const struct bloom_filter_settings *settings)
+{
+ int i;
+ const uint32_t seed0 = 0x293ae76f;
+ const uint32_t seed1 = 0x7e646e2c;
+ const uint32_t hash0 = murmur3_seeded(seed0, data, len);
+ const uint32_t hash1 = murmur3_seeded(seed1, data, len);
+
+ key->hashes = (uint32_t *)xcalloc(settings->num_hashes, sizeof(uint32_t));
+ for (i = 0; i < settings->num_hashes; i++)
+ key->hashes[i] = hash0 + i * hash1;
+}
+
+void clear_bloom_key(struct bloom_key *key)
+{
+ FREE_AND_NULL(key->hashes);
+}
+
+void add_key_to_filter(const struct bloom_key *key,
+ struct bloom_filter *filter,
+ const struct bloom_filter_settings *settings)
+{
+ int i;
+ uint64_t mod = filter->len * BITS_PER_WORD;
+
+ for (i = 0; i < settings->num_hashes; i++) {
+ uint64_t hash_mod = key->hashes[i] % mod;
+ uint64_t block_pos = hash_mod / BITS_PER_WORD;
+
+ filter->data[block_pos] |= get_bitmask(hash_mod);
+ }
+}
+
+void init_bloom_filters(void)
+{
+ init_bloom_filter_slab(&bloom_filters);
+}
+
+static int pathmap_cmp(const void *hashmap_cmp_fn_data,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
+ const void *keydata)
+{
+ const struct pathmap_hash_entry *e1, *e2;
+
+ e1 = container_of(eptr, const struct pathmap_hash_entry, entry);
+ e2 = container_of(entry_or_key, const struct pathmap_hash_entry, entry);
+
+ return strcmp(e1->path, e2->path);
+}
+
+struct bloom_filter *get_bloom_filter(struct repository *r,
+ struct commit *c,
+ int compute_if_not_present)
+{
+ struct bloom_filter *filter;
+ struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
+ int i;
+ struct diff_options diffopt;
+ int max_changes = 512;
+
+ if (!bloom_filters.slab_size)
+ return NULL;
+
+ filter = bloom_filter_slab_at(&bloom_filters, c);
+
+ if (!filter->data) {
+ load_commit_graph_info(r, c);
+ if (commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH &&
+ r->objects->commit_graph->chunk_bloom_indexes)
+ load_bloom_filter_from_graph(r->objects->commit_graph, filter, c);
+ }
+
+ if (filter->data)
+ return filter;
+ if (!compute_if_not_present)
+ return NULL;
+
+ repo_diff_setup(r, &diffopt);
+ diffopt.flags.recursive = 1;
+ diffopt.detect_rename = 0;
+ diffopt.max_changes = max_changes;
+ diff_setup_done(&diffopt);
+
+ /* ensure commit is parsed so we have parent information */
+ repo_parse_commit(r, c);
+
+ if (c->parents)
+ diff_tree_oid(&c->parents->item->object.oid, &c->object.oid, "", &diffopt);
+ else
+ diff_tree_oid(NULL, &c->object.oid, "", &diffopt);
+ diffcore_std(&diffopt);
+
+ if (diffopt.num_changes <= max_changes) {
+ struct hashmap pathmap;
+ struct pathmap_hash_entry *e;
+ struct hashmap_iter iter;
+ hashmap_init(&pathmap, pathmap_cmp, NULL, 0);
+
+ for (i = 0; i < diff_queued_diff.nr; i++) {
+ const char *path = diff_queued_diff.queue[i]->two->path;
+
+ /*
+ * Add each leading directory of the changed file, i.e. for
+ * 'dir/subdir/file' add 'dir' and 'dir/subdir' as well, so
+ * the Bloom filter could be used to speed up commands like
+ * 'git log dir/subdir', too.
+ *
+ * Note that directories are added without the trailing '/'.
+ */
+ do {
+ char *last_slash = strrchr(path, '/');
+
+ FLEX_ALLOC_STR(e, path, path);
+ hashmap_entry_init(&e->entry, strhash(path));
+
+ if (!hashmap_get(&pathmap, &e->entry, NULL))
+ hashmap_add(&pathmap, &e->entry);
+ else
+ free(e);
+
+ if (!last_slash)
+ last_slash = (char*)path;
+ *last_slash = '\0';
+
+ } while (*path);
+
+ diff_free_filepair(diff_queued_diff.queue[i]);
+ }
+
+ filter->len = (hashmap_get_size(&pathmap) * settings.bits_per_entry + BITS_PER_WORD - 1) / BITS_PER_WORD;
+ filter->data = xcalloc(filter->len, sizeof(unsigned char));
+
+ hashmap_for_each_entry(&pathmap, &iter, e, entry) {
+ struct bloom_key key;
+ fill_bloom_key(e->path, strlen(e->path), &key, &settings);
+ add_key_to_filter(&key, filter, &settings);
+ }
+
+ hashmap_free_entries(&pathmap, struct pathmap_hash_entry, entry);
+ } else {
+ for (i = 0; i < diff_queued_diff.nr; i++)
+ diff_free_filepair(diff_queued_diff.queue[i]);
+ filter->data = NULL;
+ filter->len = 0;
+ }
+
+ free(diff_queued_diff.queue);
+ DIFF_QUEUE_CLEAR(&diff_queued_diff);
+
+ return filter;
+}
+
+int bloom_filter_contains(const struct bloom_filter *filter,
+ const struct bloom_key *key,
+ const struct bloom_filter_settings *settings)
+{
+ int i;
+ uint64_t mod = filter->len * BITS_PER_WORD;
+
+ if (!mod)
+ return -1;
+
+ for (i = 0; i < settings->num_hashes; i++) {
+ uint64_t hash_mod = key->hashes[i] % mod;
+ uint64_t block_pos = hash_mod / BITS_PER_WORD;
+ if (!(filter->data[block_pos] & get_bitmask(hash_mod)))
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/bloom.h b/bloom.h
new file mode 100644
index 0000000..d8fbb0f
--- /dev/null
+++ b/bloom.h
@@ -0,0 +1,91 @@
+#ifndef BLOOM_H
+#define BLOOM_H
+
+struct commit;
+struct repository;
+
+struct bloom_filter_settings {
+ /*
+ * The version of the hashing technique being used.
+ * We currently only support version = 1 which is
+ * the seeded murmur3 hashing technique implemented
+ * in bloom.c.
+ */
+ uint32_t hash_version;
+
+ /*
+ * The number of times a path is hashed, i.e. the
+ * number of bit positions tht cumulatively
+ * determine whether a path is present in the
+ * Bloom filter.
+ */
+ uint32_t num_hashes;
+
+ /*
+ * The minimum number of bits per entry in the Bloom
+ * filter. If the filter contains 'n' entries, then
+ * filter size is the minimum number of 8-bit words
+ * that contain n*b bits.
+ */
+ uint32_t bits_per_entry;
+};
+
+#define DEFAULT_BLOOM_FILTER_SETTINGS { 1, 7, 10 }
+#define BITS_PER_WORD 8
+#define BLOOMDATA_CHUNK_HEADER_SIZE 3 * sizeof(uint32_t)
+
+/*
+ * A bloom_filter struct represents a data segment to
+ * use when testing hash values. The 'len' member
+ * dictates how many entries are stored in
+ * 'data'.
+ */
+struct bloom_filter {
+ unsigned char *data;
+ size_t len;
+};
+
+/*
+ * A bloom_key represents the k hash values for a
+ * given string. These can be precomputed and
+ * stored in a bloom_key for re-use when testing
+ * against a bloom_filter. The number of hashes is
+ * given by the Bloom filter settings and is the same
+ * for all Bloom filters and keys interacting with
+ * the loaded version of the commit graph file and
+ * the Bloom data chunks.
+ */
+struct bloom_key {
+ uint32_t *hashes;
+};
+
+/*
+ * Calculate the murmur3 32-bit hash value for the given data
+ * using the given seed.
+ * Produces a uniformly distributed hash value.
+ * Not considered to be cryptographically secure.
+ * Implemented as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm
+ */
+uint32_t murmur3_seeded(uint32_t seed, const char *data, size_t len);
+
+void fill_bloom_key(const char *data,
+ size_t len,
+ struct bloom_key *key,
+ const struct bloom_filter_settings *settings);
+void clear_bloom_key(struct bloom_key *key);
+
+void add_key_to_filter(const struct bloom_key *key,
+ struct bloom_filter *filter,
+ const struct bloom_filter_settings *settings);
+
+void init_bloom_filters(void);
+
+struct bloom_filter *get_bloom_filter(struct repository *r,
+ struct commit *c,
+ int compute_if_not_present);
+
+int bloom_filter_contains(const struct bloom_filter *filter,
+ const struct bloom_key *key,
+ const struct bloom_filter_settings *settings);
+
+#endif
diff --git a/branch.c b/branch.c
index 5794947..7095f78 100644
--- a/branch.c
+++ b/branch.c
@@ -344,6 +344,7 @@ void remove_merge_branch_state(struct repository *r)
unlink(git_path_merge_rr(r));
unlink(git_path_merge_msg(r));
unlink(git_path_merge_mode(r));
+ save_autostash(git_path_merge_autostash(r));
}
void remove_branch_state(struct repository *r, int verbose)
@@ -369,7 +370,7 @@ int replace_each_worktree_head_symref(const char *oldref, const char *newref,
const char *logmsg)
{
int ret = 0;
- struct worktree **worktrees = get_worktrees(0);
+ struct worktree **worktrees = get_worktrees();
int i;
for (i = 0; worktrees[i]; i++) {
diff --git a/bugreport.c b/bugreport.c
new file mode 100644
index 0000000..09579e2
--- /dev/null
+++ b/bugreport.c
@@ -0,0 +1,200 @@
+#include "cache.h"
+#include "parse-options.h"
+#include "strbuf.h"
+#include "help.h"
+#include "compat/compiler.h"
+#include "run-command.h"
+
+
+static void get_system_info(struct strbuf *sys_info)
+{
+ struct utsname uname_info;
+ char *shell = NULL;
+
+ /* get git version from native cmd */
+ strbuf_addstr(sys_info, _("git version:\n"));
+ get_version_info(sys_info, 1);
+
+ /* system call for other version info */
+ strbuf_addstr(sys_info, "uname: ");
+ if (uname(&uname_info))
+ strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
+ strerror(errno),
+ errno);
+ else
+ strbuf_addf(sys_info, "%s %s %s %s\n",
+ uname_info.sysname,
+ uname_info.release,
+ uname_info.version,
+ uname_info.machine);
+
+ strbuf_addstr(sys_info, _("compiler info: "));
+ get_compiler_info(sys_info);
+
+ strbuf_addstr(sys_info, _("libc info: "));
+ get_libc_info(sys_info);
+
+ shell = getenv("SHELL");
+ strbuf_addf(sys_info, "$SHELL (typically, interactive shell): %s\n",
+ shell ? shell : "<unset>");
+}
+
+static void get_populated_hooks(struct strbuf *hook_info, int nongit)
+{
+ /*
+ * NEEDSWORK: Doesn't look like there is a list of all possible hooks;
+ * so below is a transcription of `git help hooks`. Later, this should
+ * be replaced with some programmatically generated list (generated from
+ * doc or else taken from some library which tells us about all the
+ * hooks)
+ */
+ static const char *hook[] = {
+ "applypatch-msg",
+ "pre-applypatch",
+ "post-applypatch",
+ "pre-commit",
+ "pre-merge-commit",
+ "prepare-commit-msg",
+ "commit-msg",
+ "post-commit",
+ "pre-rebase",
+ "post-checkout",
+ "post-merge",
+ "pre-push",
+ "pre-receive",
+ "update",
+ "post-receive",
+ "post-update",
+ "push-to-checkout",
+ "pre-auto-gc",
+ "post-rewrite",
+ "sendemail-validate",
+ "fsmonitor-watchman",
+ "p4-pre-submit",
+ "post-index-change",
+ };
+ int i;
+
+ if (nongit) {
+ strbuf_addstr(hook_info,
+ _("not run from a git repository - no hooks to show\n"));
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hook); i++)
+ if (find_hook(hook[i]))
+ strbuf_addf(hook_info, "%s\n", hook[i]);
+}
+
+static const char * const bugreport_usage[] = {
+ N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
+ NULL
+};
+
+static int get_bug_template(struct strbuf *template)
+{
+ const char template_text[] = N_(
+"Thank you for filling out a Git bug report!\n"
+"Please answer the following questions to help us understand your issue.\n"
+"\n"
+"What did you do before the bug happened? (Steps to reproduce your issue)\n"
+"\n"
+"What did you expect to happen? (Expected behavior)\n"
+"\n"
+"What happened instead? (Actual behavior)\n"
+"\n"
+"What's different between what you expected and what actually happened?\n"
+"\n"
+"Anything else you want to add:\n"
+"\n"
+"Please review the rest of the bug report below.\n"
+"You can delete any lines you don't wish to share.\n");
+
+ strbuf_addstr(template, _(template_text));
+ return 0;
+}
+
+static void get_header(struct strbuf *buf, const char *title)
+{
+ strbuf_addf(buf, "\n\n[%s]\n", title);
+}
+
+int cmd_main(int argc, const char **argv)
+{
+ struct strbuf buffer = STRBUF_INIT;
+ struct strbuf report_path = STRBUF_INIT;
+ int report = -1;
+ time_t now = time(NULL);
+ char *option_output = NULL;
+ char *option_suffix = "%Y-%m-%d-%H%M";
+ int nongit_ok = 0;
+ const char *prefix = NULL;
+ const char *user_relative_path = NULL;
+
+ const struct option bugreport_options[] = {
+ OPT_STRING('o', "output-directory", &option_output, N_("path"),
+ N_("specify a destination for the bugreport file")),
+ OPT_STRING('s', "suffix", &option_suffix, N_("format"),
+ N_("specify a strftime format suffix for the filename")),
+ OPT_END()
+ };
+
+ prefix = setup_git_directory_gently(&nongit_ok);
+
+ argc = parse_options(argc, argv, prefix, bugreport_options,
+ bugreport_usage, 0);
+
+ /* Prepare the path to put the result */
+ strbuf_addstr(&report_path,
+ prefix_filename(prefix,
+ option_output ? option_output : ""));
+ strbuf_complete(&report_path, '/');
+
+ strbuf_addstr(&report_path, "git-bugreport-");
+ strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
+ strbuf_addstr(&report_path, ".txt");
+
+ switch (safe_create_leading_directories(report_path.buf)) {
+ case SCLD_OK:
+ case SCLD_EXISTS:
+ break;
+ default:
+ die(_("could not create leading directories for '%s'"),
+ report_path.buf);
+ }
+
+ /* Prepare the report contents */
+ get_bug_template(&buffer);
+
+ get_header(&buffer, _("System Info"));
+ get_system_info(&buffer);
+
+ get_header(&buffer, _("Enabled Hooks"));
+ get_populated_hooks(&buffer, nongit_ok);
+
+ /* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
+ report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+
+ if (report < 0) {
+ UNLEAK(report_path);
+ die(_("couldn't create a new file at '%s'"), report_path.buf);
+ }
+
+ if (write_in_full(report, buffer.buf, buffer.len) < 0)
+ die_errno(_("unable to write to %s"), report_path.buf);
+
+ close(report);
+
+ /*
+ * We want to print the path relative to the user, but we still need the
+ * path relative to us to give to the editor.
+ */
+ if (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))
+ user_relative_path = report_path.buf;
+ fprintf(stderr, _("Created new report at '%s'.\n"),
+ user_relative_path);
+
+ UNLEAK(buffer);
+ UNLEAK(report_path);
+ return !!launch_editor(report_path.buf, NULL, NULL);
+}
diff --git a/builtin.h b/builtin.h
index 2b25a80..a5ae15b 100644
--- a/builtin.h
+++ b/builtin.h
@@ -94,25 +94,9 @@
* command.
*/
-#define DEFAULT_MERGE_LOG_LEN 20
-
extern const char git_usage_string[];
extern const char git_more_info_string[];
-#define PRUNE_PACKED_DRY_RUN 01
-#define PRUNE_PACKED_VERBOSE 02
-
-void prune_packed_objects(int);
-
-struct fmt_merge_msg_opts {
- unsigned add_title:1,
- credit_people:1;
- int shortlog_len;
-};
-
-int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
- struct fmt_merge_msg_opts *);
-
/**
* If a built-in has DELAY_PAGER_CONFIG set, the built-in should call this early
* when it wishes to respect the `pager.foo`-config. The `cmd` is the name of
diff --git a/builtin/add.c b/builtin/add.c
index 18a0881..298e011 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -330,10 +330,10 @@ static struct option builtin_add_options[] = {
OPT_BOOL(0, "renormalize", &add_renormalize, N_("renormalize EOL of tracked files (implies -u)")),
OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
- { OPTION_CALLBACK, 0, "ignore-removal", &addremove_explicit,
+ OPT_CALLBACK_F(0, "ignore-removal", &addremove_explicit,
NULL /* takes no arguments */,
N_("ignore paths removed in the working tree (same as --no-all)"),
- PARSE_OPT_NOARG, ignore_removal_cb },
+ PARSE_OPT_NOARG, ignore_removal_cb),
OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
diff --git a/builtin/am.c b/builtin/am.c
index e3dfd93..69e50de 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1691,7 +1691,6 @@ static int do_interactive(struct am_state *state)
*/
static void am_run(struct am_state *state, int resume)
{
- const char *argv_gc_auto[] = {"gc", "--auto", NULL};
struct strbuf sb = STRBUF_INIT;
unlink(am_path(state, "dirtyindex"));
@@ -1796,7 +1795,7 @@ next:
if (!state->rebasing) {
am_destroy(state);
close_object_store(the_repository->objects);
- run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+ run_auto_gc(state->quiet);
}
}
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index c1c40b5..73f9324 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -13,7 +13,6 @@ static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
-static GIT_PATH_FUNC(git_path_bisect_head, "BISECT_HEAD")
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
static GIT_PATH_FUNC(git_path_head_name, "head-name")
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
@@ -164,7 +163,7 @@ static int bisect_reset(const char *commit)
strbuf_addstr(&branch, commit);
}
- if (!file_exists(git_path_bisect_head())) {
+ if (!ref_exists("BISECT_HEAD")) {
struct argv_array argv = ARGV_ARRAY_INIT;
argv_array_pushl(&argv, "checkout", branch.buf, "--", NULL);
@@ -455,9 +454,12 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
no_checkout = 1;
} else if (!strcmp(arg, "--term-good") ||
!strcmp(arg, "--term-old")) {
+ i++;
+ if (argc <= i)
+ return error(_("'' is not a valid term"));
must_write_terms = 1;
free((void *) terms->term_good);
- terms->term_good = xstrdup(argv[++i]);
+ terms->term_good = xstrdup(argv[i]);
} else if (skip_prefix(arg, "--term-good=", &arg) ||
skip_prefix(arg, "--term-old=", &arg)) {
must_write_terms = 1;
@@ -465,16 +467,18 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
terms->term_good = xstrdup(arg);
} else if (!strcmp(arg, "--term-bad") ||
!strcmp(arg, "--term-new")) {
+ i++;
+ if (argc <= i)
+ return error(_("'' is not a valid term"));
must_write_terms = 1;
free((void *) terms->term_bad);
- terms->term_bad = xstrdup(argv[++i]);
+ terms->term_bad = xstrdup(argv[i]);
} else if (skip_prefix(arg, "--term-bad=", &arg) ||
skip_prefix(arg, "--term-new=", &arg)) {
must_write_terms = 1;
free((void *) terms->term_bad);
terms->term_bad = xstrdup(arg);
- } else if (starts_with(arg, "--") &&
- !one_of(arg, "--term-good", "--term-bad", NULL)) {
+ } else if (starts_with(arg, "--")) {
return error(_("unrecognized option: '%s'"), arg);
} else {
char *commit_id = xstrfmt("%s^{commit}", arg);
diff --git a/builtin/blame.c b/builtin/blame.c
index bf1cecd..94ef57c 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -864,8 +864,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
- { OPTION_CALLBACK, 'C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback },
- { OPTION_CALLBACK, 'M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback },
+ OPT_CALLBACK_F('C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback),
+ OPT_CALLBACK_F('M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback),
OPT_STRING_LIST('L', NULL, &range_list, N_("n,m"), N_("Process only line range n,m, counting from 1")),
OPT__ABBREV(&abbrev),
OPT_END()
@@ -1061,6 +1061,14 @@ parse_done:
string_list_clear(&ignore_revs_file_list, 0);
string_list_clear(&ignore_rev_list, 0);
setup_scoreboard(&sb, path, &o);
+
+ /*
+ * Changed-path Bloom filters are disabled when looking
+ * for copies.
+ */
+ if (!(opt & PICKAXE_BLAME_COPY))
+ setup_blame_bloom_data(&sb, path);
+
lno = sb.num_lines;
if (lno && !range_list.nr)
@@ -1164,5 +1172,7 @@ parse_done:
printf("num get patch: %d\n", sb.num_get_patch);
printf("num commits: %d\n", sb.num_commits);
}
+
+ cleanup_scoreboard(&sb);
return 0;
}
diff --git a/builtin/branch.c b/builtin/branch.c
index d8297f8..e82301f 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -468,7 +468,7 @@ static void print_current_branch_name(void)
static void reject_rebase_or_bisect_branch(const char *target)
{
- struct worktree **worktrees = get_worktrees(0);
+ struct worktree **worktrees = get_worktrees();
int i;
for (i = 0; worktrees[i]; i++) {
@@ -653,10 +653,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_NO_MERGED(&filter, N_("print only branches that are not merged")),
OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
OPT_REF_SORT(sorting_tail),
- {
- OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
- N_("print only branches of the object"), 0, parse_opt_object_name
- },
+ OPT_CALLBACK(0, "points-at", &filter.points_at, N_("object"),
+ N_("print only branches of the object"), parse_opt_object_name),
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
OPT_END(),
@@ -695,7 +693,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
list = 1;
if (!!delete + !!rename + !!copy + !!new_upstream + !!show_current +
- list + unset_upstream > 1)
+ list + edit_description + unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
if (filter.abbrev == -1)
@@ -739,7 +737,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
*/
if (!sorting)
sorting = ref_default_sorting();
- sorting->ignore_case = icase;
+ ref_sorting_icase_all(sorting, icase);
print_ref_list(&filter, sorting, &format);
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 272f9fc..5ebf133 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -12,7 +12,7 @@
#include "userdiff.h"
#include "streaming.h"
#include "tree-walk.h"
-#include "sha1-array.h"
+#include "oid-array.h"
#include "packfile.h"
#include "object-store.h"
#include "promisor-remote.h"
@@ -42,7 +42,10 @@ static int filter_object(const char *path, unsigned mode,
oid_to_hex(oid), path);
if ((type == OBJ_BLOB) && S_ISREG(mode)) {
struct strbuf strbuf = STRBUF_INIT;
- if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf)) {
+ struct checkout_metadata meta;
+
+ init_checkout_metadata(&meta, NULL, NULL, oid);
+ if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf, &meta)) {
free(*buf);
*size = strbuf.len;
*buf = strbuf_detach(&strbuf, NULL);
@@ -593,7 +596,7 @@ static int batch_objects(struct batch_options *opt)
static const char * const cat_file_usage[] = {
N_("git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e | -p | <type> | --textconv | --filters) [--path=<path>] <object>"),
- N_("git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv | --filters]"),
+ N_("git cat-file (--batch[=<format>] | --batch-check[=<format>]) [--follow-symlinks] [--textconv | --filters]"),
NULL
};
@@ -647,14 +650,14 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "allow-unknown-type", &unknown_type,
N_("allow -s and -t to work with broken/corrupt objects")),
OPT_BOOL(0, "buffer", &batch.buffer_output, N_("buffer --batch output")),
- { OPTION_CALLBACK, 0, "batch", &batch, "format",
+ OPT_CALLBACK_F(0, "batch", &batch, "format",
N_("show info and content of objects fed from the standard input"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
- batch_option_callback },
- { OPTION_CALLBACK, 0, "batch-check", &batch, "format",
+ batch_option_callback),
+ OPT_CALLBACK_F(0, "batch-check", &batch, "format",
N_("show info about objects fed from the standard input"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
- batch_option_callback },
+ batch_option_callback),
OPT_BOOL(0, "follow-symlinks", &batch.follow_symlinks,
N_("follow in-tree symlinks (used with --batch or --batch-check)")),
OPT_BOOL(0, "batch-all-objects", &batch.all_objects,
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 1ac1cc2..a854fd1 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -177,9 +177,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
N_("write the content to temporary files")),
OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
N_("when creating files, prepend <string>")),
- { OPTION_CALLBACK, 0, "stage", NULL, "(1|2|3|all)",
+ OPT_CALLBACK_F(0, "stage", NULL, "(1|2|3|all)",
N_("copy out the files from named stage"),
- PARSE_OPT_NONEG, option_parse_stage },
+ PARSE_OPT_NONEG, option_parse_stage),
OPT_END()
};
diff --git a/builtin/checkout.c b/builtin/checkout.c
index d677381..af849c6 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -88,6 +88,19 @@ struct checkout_opts {
struct tree *source_tree;
};
+struct branch_info {
+ const char *name; /* The short name used */
+ const char *path; /* The full name of a real branch */
+ struct commit *commit; /* The named commit */
+ char *refname; /* The full name of the ref being checked out. */
+ struct object_id oid; /* The object ID of the commit being checked out. */
+ /*
+ * if not null the branch is detached because it's already
+ * checked out in this checkout
+ */
+ char *checkout;
+};
+
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
@@ -337,7 +350,8 @@ static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce,
}
}
-static int checkout_worktree(const struct checkout_opts *opts)
+static int checkout_worktree(const struct checkout_opts *opts,
+ const struct branch_info *info)
{
struct checkout state = CHECKOUT_INIT;
int nr_checkouts = 0, nr_unmerged = 0;
@@ -348,6 +362,10 @@ static int checkout_worktree(const struct checkout_opts *opts)
state.refresh_cache = 1;
state.istate = &the_index;
+ init_checkout_metadata(&state.meta, info->refname,
+ info->commit ? &info->commit->object.oid : &info->oid,
+ NULL);
+
enable_delayed_checkout(&state);
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
@@ -396,7 +414,7 @@ static int checkout_worktree(const struct checkout_opts *opts)
}
static int checkout_paths(const struct checkout_opts *opts,
- const char *revision)
+ const struct branch_info *new_branch_info)
{
int pos;
static char *ps_matched;
@@ -462,7 +480,7 @@ static int checkout_paths(const struct checkout_opts *opts,
else
BUG("either flag must have been set, worktree=%d, index=%d",
opts->checkout_worktree, opts->checkout_index);
- return run_add_interactive(revision, patch_mode, &opts->pathspec);
+ return run_add_interactive(new_branch_info->name, patch_mode, &opts->pathspec);
}
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
@@ -523,7 +541,7 @@ static int checkout_paths(const struct checkout_opts *opts,
/* Now we are committed to check them out */
if (opts->checkout_worktree)
- errs |= checkout_worktree(opts);
+ errs |= checkout_worktree(opts, new_branch_info);
else
remove_marked_cache_entries(&the_index, 1);
@@ -586,7 +604,8 @@ static void describe_detached_head(const char *msg, struct commit *commit)
}
static int reset_tree(struct tree *tree, const struct checkout_opts *o,
- int worktree, int *writeout_error)
+ int worktree, int *writeout_error,
+ struct branch_info *info)
{
struct unpack_trees_options opts;
struct tree_desc tree_desc;
@@ -601,6 +620,9 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
opts.verbose_update = o->show_progress;
opts.src_index = &the_index;
opts.dst_index = &the_index;
+ init_checkout_metadata(&opts.meta, info->refname,
+ info->commit ? &info->commit->object.oid : &null_oid,
+ NULL);
parse_tree(tree);
init_tree_desc(&tree_desc, tree->buffer, tree->size);
switch (unpack_trees(1, &tree_desc, &opts)) {
@@ -620,21 +642,17 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
}
}
-struct branch_info {
- const char *name; /* The short name used */
- const char *path; /* The full name of a real branch */
- struct commit *commit; /* The named commit */
- /*
- * if not null the branch is detached because it's already
- * checked out in this checkout
- */
- char *checkout;
-};
-
static void setup_branch_path(struct branch_info *branch)
{
struct strbuf buf = STRBUF_INIT;
+ /*
+ * If this is a ref, resolve it; otherwise, look up the OID for our
+ * expression. Failure here is okay.
+ */
+ if (!dwim_ref(branch->name, strlen(branch->name), &branch->oid, &branch->refname))
+ repo_get_oid_committish(the_repository, branch->name, &branch->oid);
+
strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
if (strcmp(buf.buf, branch->name))
branch->name = xstrdup(buf.buf);
@@ -663,7 +681,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
} else
new_tree = get_commit_tree(new_branch_info->commit);
if (opts->discard_changes) {
- ret = reset_tree(new_tree, opts, 1, writeout_error);
+ ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
if (ret)
return ret;
} else {
@@ -692,6 +710,10 @@ static int merge_working_tree(const struct checkout_opts *opts,
topts.quiet = opts->merge && old_branch_info->commit;
topts.verbose_update = opts->show_progress;
topts.fn = twoway_merge;
+ init_checkout_metadata(&topts.meta, new_branch_info->refname,
+ new_branch_info->commit ?
+ &new_branch_info->commit->object.oid :
+ &new_branch_info->oid, NULL);
if (opts->overwrite_ignore) {
topts.dir = xcalloc(1, sizeof(*topts.dir));
topts.dir->flags |= DIR_SHOW_IGNORED;
@@ -762,7 +784,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
ret = reset_tree(new_tree,
opts, 1,
- writeout_error);
+ writeout_error, new_branch_info);
if (ret)
return ret;
o.ancestor = old_branch_info->name;
@@ -782,7 +804,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
exit(128);
ret = reset_tree(new_tree,
opts, 0,
- writeout_error);
+ writeout_error, new_branch_info);
strbuf_release(&o.obuf);
strbuf_release(&old_commit_shortname);
if (ret)
@@ -1462,9 +1484,9 @@ static struct option *add_common_options(struct checkout_opts *opts,
{
struct option options[] = {
OPT__QUIET(&opts->quiet, N_("suppress progress reporting")),
- { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
+ OPT_CALLBACK_F(0, "recurse-submodules", NULL,
"checkout", "control recursive updating of submodules",
- PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
+ PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
OPT_BOOL(0, "progress", &opts->show_progress, N_("force progress reporting")),
OPT_BOOL('m', "merge", &opts->merge, N_("perform a 3-way merge with the new branch")),
OPT_STRING(0, "conflict", &opts->conflict_style, N_("style"),
@@ -1520,6 +1542,9 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,
return newopts;
}
+/* create-branch option (either b or c) */
+static char cb_option = 'b';
+
static int checkout_main(int argc, const char **argv, const char *prefix,
struct checkout_opts *opts, struct option *options,
const char * const usagestr[])
@@ -1562,7 +1587,8 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
}
if ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)
- die(_("-b, -B and --orphan are mutually exclusive"));
+ die(_("-%c, -%c and --orphan are mutually exclusive"),
+ cb_option, toupper(cb_option));
if (opts->overlay_mode == 1 && opts->patch_mode)
die(_("-p and --overlay are mutually exclusive"));
@@ -1581,16 +1607,16 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
if (opts->checkout_index < 0 || opts->checkout_worktree < 0)
BUG("these flags should be non-negative by now");
/*
- * convenient shortcut: "git restore --staged" equals
- * "git restore --staged --source HEAD"
+ * convenient shortcut: "git restore --staged [--worktree]" equals
+ * "git restore --staged [--worktree] --source HEAD"
*/
- if (!opts->from_treeish && opts->checkout_index && !opts->checkout_worktree)
+ if (!opts->from_treeish && opts->checkout_index)
opts->from_treeish = "HEAD";
/*
* From here on, new_branch will contain the branch to be checked out,
* and new_branch_force and new_orphan_branch will tell us which one of
- * -b/-B/--orphan is being used.
+ * -b/-B/-c/-C/--orphan is being used.
*/
if (opts->new_branch_force)
opts->new_branch = opts->new_branch_force;
@@ -1598,7 +1624,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
if (opts->new_orphan_branch)
opts->new_branch = opts->new_orphan_branch;
- /* --track without -b/-B/--orphan should DWIM */
+ /* --track without -c/-C/-b/-B/--orphan should DWIM */
if (opts->track != BRANCH_TRACK_UNSPECIFIED && !opts->new_branch) {
const char *argv0 = argv[0];
if (!argc || !strcmp(argv0, "--"))
@@ -1607,7 +1633,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
skip_prefix(argv0, "remotes/", &argv0);
argv0 = strchr(argv0, '/');
if (!argv0 || !argv0[1])
- die(_("missing branch name; try -b"));
+ die(_("missing branch name; try -%c"), cb_option);
opts->new_branch = argv0 + 1;
}
@@ -1661,7 +1687,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
* Try to give more helpful suggestion.
* new_branch && argc > 1 will be caught later.
*/
- if (opts->new_branch && argc == 1)
+ if (opts->new_branch && argc == 1 && !new_branch_info.commit)
die(_("'%s' is not a commit and a branch '%s' cannot be created from it"),
argv[0], opts->new_branch);
@@ -1710,7 +1736,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
UNLEAK(opts);
if (opts->patch_mode || opts->pathspec.nr)
- return checkout_paths(opts, new_branch_info.name);
+ return checkout_paths(opts, &new_branch_info);
else
return checkout_branch(opts, &new_branch_info);
}
@@ -1798,6 +1824,8 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
options = add_common_options(&opts, options);
options = add_common_switch_branch_options(&opts, options);
+ cb_option = 'c';
+
ret = checkout_main(argc, argv, prefix, &opts,
options, switch_branch_usage);
FREE_AND_NULL(options);
diff --git a/builtin/clean.c b/builtin/clean.c
index 5abf087..5a9c29a 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -18,6 +18,7 @@
#include "color.h"
#include "pathspec.h"
#include "help.h"
+#include "prompt.h"
static int force = -1; /* unset */
static int interactive;
@@ -420,7 +421,6 @@ static int find_unique(const char *choice, struct menu_stuff *menu_stuff)
return found;
}
-
/*
* Parse user input, and return choice(s) for menu (menu_stuff).
*
@@ -580,9 +580,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)
clean_get_color(CLEAN_COLOR_RESET));
}
- if (strbuf_getline_lf(&choice, stdin) != EOF) {
- strbuf_trim(&choice);
- } else {
+ if (git_read_line_interactively(&choice) == EOF) {
eof = 1;
break;
}
@@ -662,9 +660,7 @@ static int filter_by_patterns_cmd(void)
clean_print_color(CLEAN_COLOR_PROMPT);
printf(_("Input ignore patterns>> "));
clean_print_color(CLEAN_COLOR_RESET);
- if (strbuf_getline_lf(&confirm, stdin) != EOF)
- strbuf_trim(&confirm);
- else
+ if (git_read_line_interactively(&confirm) == EOF)
putchar('\n');
/* quit filter_by_pattern mode if press ENTER or Ctrl-D */
@@ -760,9 +756,7 @@ static int ask_each_cmd(void)
qname = quote_path_relative(item->string, NULL, &buf);
/* TRANSLATORS: Make sure to keep [y/N] as is */
printf(_("Remove %s [y/N]? "), qname);
- if (strbuf_getline_lf(&confirm, stdin) != EOF) {
- strbuf_trim(&confirm);
- } else {
+ if (git_read_line_interactively(&confirm) == EOF) {
putchar('\n');
eof = 1;
}
@@ -912,8 +906,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")),
OPT_BOOL('d', NULL, &remove_directories,
N_("remove whole directories")),
- { OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"),
- N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb },
+ OPT_CALLBACK_F('e', "exclude", &exclude_list, N_("pattern"),
+ N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb),
OPT_BOOL('x', NULL, &ignored, N_("remove ignored files, too")),
OPT_BOOL('X', NULL, &ignored_only,
N_("remove only ignored files")),
@@ -930,12 +924,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
0);
memset(&dir, 0, sizeof(dir));
- if (ignored_only)
- dir.flags |= DIR_SHOW_IGNORED;
-
- if (ignored && ignored_only)
- die(_("-x and -X cannot be used together"));
-
if (!interactive && !dry_run && !force) {
if (config_set)
die(_("clean.requireForce set to true and neither -i, -n, nor -f given; "
@@ -952,6 +940,13 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
+ if (ignored && ignored_only)
+ die(_("-x and -X cannot be used together"));
+ if (!ignored)
+ setup_standard_excludes(&dir);
+ if (ignored_only)
+ dir.flags |= DIR_SHOW_IGNORED;
+
if (argc) {
/*
* Remaining args implies pathspecs specified, and we should
@@ -960,15 +955,41 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
remove_directories = 1;
}
- if (remove_directories)
- dir.flags |= DIR_SHOW_IGNORED_TOO | DIR_KEEP_UNTRACKED_CONTENTS;
+ if (remove_directories && !ignored_only) {
+ /*
+ * We need to know about ignored files too:
+ *
+ * If (ignored), then we will delete ignored files as well.
+ *
+ * If (!ignored), then even though we not are doing
+ * anything with ignored files, we need to know about them
+ * so that we can avoid deleting a directory of untracked
+ * files that also contains an ignored file within it.
+ *
+ * For the (!ignored) case, since we only need to avoid
+ * deleting ignored files, we can set
+ * DIR_SHOW_IGNORED_TOO_MODE_MATCHING in order to avoid
+ * recursing into a directory which is itself ignored.
+ */
+ dir.flags |= DIR_SHOW_IGNORED_TOO;
+ if (!ignored)
+ dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;
+
+ /*
+ * Let the fill_directory() machinery know that we aren't
+ * just recursing to collect the ignored files; we want all
+ * the untracked ones so that we can delete them. (Note:
+ * we could also set DIR_KEEP_UNTRACKED_CONTENTS when
+ * ignored_only is true, since DIR_KEEP_UNTRACKED_CONTENTS
+ * only has effect in combination with DIR_SHOW_IGNORED_TOO. It makes
+ * the code clearer to exclude it, though.
+ */
+ dir.flags |= DIR_KEEP_UNTRACKED_CONTENTS;
+ }
if (read_cache() < 0)
die(_("index file corrupt"));
- if (!ignored)
- setup_standard_excludes(&dir);
-
pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
for (i = 0; i < exclude_list.nr; i++)
add_pattern(exclude_list.items[i].string, "", 0, pl, -(i+1));
@@ -989,12 +1010,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (!cache_name_is_other(ent->name, ent->len))
continue;
- if (pathspec.nr)
- matches = dir_path_match(&the_index, ent, &pathspec, 0, NULL);
-
- if (pathspec.nr && !matches)
- continue;
-
if (lstat(ent->name, &st))
die_errno("Cannot lstat '%s'", ent->name);
diff --git a/builtin/clone.c b/builtin/clone.c
index 1ad26f4..a9f3312 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -102,10 +102,10 @@ static struct option builtin_clone_options[] = {
N_("don't use local hardlinks, always copy")),
OPT_BOOL('s', "shared", &option_shared,
N_("setup as shared repository")),
- OPT_ALIAS(0, "recursive", "recurse-submodules"),
{ OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules,
N_("pathspec"), N_("initialize submodules in the clone"),
PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." },
+ OPT_ALIAS(0, "recursive", "recurse-submodules"),
OPT_INTEGER('j', "jobs", &max_jobs,
N_("number of submodules cloned in parallel")),
OPT_STRING(0, "template", &option_template, N_("template-directory"),
@@ -420,6 +420,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
struct dir_iterator *iter;
int iter_status;
unsigned int flags;
+ struct strbuf realpath = STRBUF_INIT;
mkdir_if_missing(dest->buf, 0777);
@@ -454,7 +455,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
if (unlink(dest->buf) && errno != ENOENT)
die_errno(_("failed to unlink '%s'"), dest->buf);
if (!option_no_hardlinks) {
- if (!link(real_path(src->buf), dest->buf))
+ strbuf_realpath(&realpath, src->buf, 1);
+ if (!link(realpath.buf, dest->buf))
continue;
if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
@@ -468,6 +470,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
strbuf_setlen(src, src_len);
die(_("failed to iterate over '%s'"), src->buf);
}
+
+ strbuf_release(&realpath);
}
static void clone_local(const char *src_repo, const char *dest_repo)
@@ -639,7 +643,9 @@ static void write_followtags(const struct ref *refs, const char *msg)
continue;
if (ends_with(ref->name, "^{}"))
continue;
- if (!has_object_file(&ref->old_oid))
+ if (!has_object_file_with_flags(&ref->old_oid,
+ OBJECT_INFO_QUICK |
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
continue;
update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
@@ -672,8 +678,7 @@ static void update_remote_refs(const struct ref *refs,
const char *branch_top,
const char *msg,
struct transport *transport,
- int check_connectivity,
- int check_refs_are_promisor_objects_only)
+ int check_connectivity)
{
const struct ref *rm = mapped_refs;
@@ -682,8 +687,6 @@ static void update_remote_refs(const struct ref *refs,
opt.transport = transport;
opt.progress = transport->progress;
- opt.check_refs_are_promisor_objects_only =
- !!check_refs_are_promisor_objects_only;
if (check_connected(iterate_ref_map, &rm, &opt))
die(_("remote did not send all necessary objects"));
@@ -780,11 +783,11 @@ static int checkout(int submodule_progress)
if (!strcmp(head, "HEAD")) {
if (advice_detached_head)
detach_advice(oid_to_hex(&oid));
+ FREE_AND_NULL(head);
} else {
if (!starts_with(head, "refs/heads/"))
die(_("HEAD not found below refs/heads!"));
}
- free(head);
/* We need to be in the new work tree for the checkout */
setup_work_tree();
@@ -799,6 +802,7 @@ static int checkout(int submodule_progress)
opts.verbose_update = (option_verbosity >= 0);
opts.src_index = &the_index;
opts.dst_index = &the_index;
+ init_checkout_metadata(&opts.meta, head, &oid, NULL);
tree = parse_tree_indirect(&oid);
parse_tree(tree);
@@ -806,6 +810,8 @@ static int checkout(int submodule_progress)
if (unpack_trees(1, &t, &opts) < 0)
die(_("unable to checkout working tree"));
+ free(head);
+
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
@@ -939,8 +945,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0, is_local;
const char *repo_name, *repo, *work_tree, *git_dir;
- char *path, *dir;
- int dest_exists;
+ char *path, *dir, *display_repo = NULL;
+ int dest_exists, real_dest_exists = 0;
const struct ref *refs, *remote_head;
const struct ref *remote_head_points_at;
const struct ref *our_head_points_at;
@@ -994,10 +1000,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
path = get_repo_path(repo_name, &is_bundle);
if (path)
repo = absolute_pathdup(repo_name);
- else if (!strchr(repo_name, ':'))
- die(_("repository '%s' does not exist"), repo_name);
- else
+ else if (strchr(repo_name, ':')) {
repo = repo_name;
+ display_repo = transport_anonymize_url(repo);
+ } else
+ die(_("repository '%s' does not exist"), repo_name);
/* no need to be strict, transport_set_option() will validate it again */
if (option_depth && atoi(option_depth) < 1)
@@ -1014,7 +1021,17 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die(_("destination path '%s' already exists and is not "
"an empty directory."), dir);
- strbuf_addf(&reflog_msg, "clone: from %s", repo);
+ if (real_git_dir) {
+ real_dest_exists = path_exists(real_git_dir);
+ if (real_dest_exists && !is_empty_dir(real_git_dir))
+ die(_("repository path '%s' already exists and is not "
+ "an empty directory."), real_git_dir);
+ }
+
+
+ strbuf_addf(&reflog_msg, "clone: from %s",
+ display_repo ? display_repo : repo);
+ free(display_repo);
if (option_bare)
work_tree = NULL;
@@ -1048,7 +1065,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (real_git_dir) {
- if (path_exists(real_git_dir))
+ if (real_dest_exists)
junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
junk_git_dir = real_git_dir;
} else {
@@ -1102,7 +1119,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
}
- init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET);
+ init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
+ INIT_DB_QUIET);
if (real_git_dir)
git_dir = real_git_dir;
@@ -1211,6 +1229,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
refs = transport_get_remote_refs(transport, &ref_prefixes);
if (refs) {
+ int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+
+ /*
+ * Now that we know what algorithm the remote side is using,
+ * let's set ours to the same thing.
+ */
+ initialize_repository_version(hash_algo);
+ repo_set_hash_algo(the_repository, hash_algo);
+
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
/*
* transport_get_remote_refs() may return refs with null sha-1
@@ -1257,9 +1284,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote_head_points_at = NULL;
remote_head = NULL;
option_no_checkout = 1;
- if (!option_bare)
- install_branch_config(0, "master", option_origin,
- "refs/heads/master");
+ if (!option_bare) {
+ const char *branch = git_default_branch_name();
+ char *ref = xstrfmt("refs/heads/%s", branch);
+
+ install_branch_config(0, branch, option_origin, ref);
+ free(ref);
+ }
}
write_refspec_config(src_ref_prefix, our_head_points_at,
@@ -1275,7 +1306,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
update_remote_refs(refs, mapped_refs, remote_head_points_at,
branch_top.buf, reflog_msg.buf, transport,
- !is_local, filter_options.choice);
+ !is_local);
update_head(our_head_points_at, remote_head, reflog_msg.buf);
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 4a70b33..523501f 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -6,10 +6,14 @@
#include "repository.h"
#include "commit-graph.h"
#include "object-store.h"
+#include "progress.h"
+#include "tag.h"
static char const * const builtin_commit_graph_usage[] = {
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
- N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
+ N_("git commit-graph write [--object-dir <objdir>] [--append] "
+ "[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
+ "[--changed-paths] [--[no-]progress] <split options>"),
NULL
};
@@ -19,7 +23,9 @@ static const char * const builtin_commit_graph_verify_usage[] = {
};
static const char * const builtin_commit_graph_write_usage[] = {
- N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
+ N_("git commit-graph write [--object-dir <objdir>] [--append] "
+ "[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
+ "[--changed-paths] [--[no-]progress] <split options>"),
NULL
};
@@ -32,6 +38,7 @@ static struct opts_commit_graph {
int split;
int shallow;
int progress;
+ int enable_changed_paths;
} opts;
static struct object_directory *find_odb(struct repository *r,
@@ -39,14 +46,17 @@ static struct object_directory *find_odb(struct repository *r,
{
struct object_directory *odb;
char *obj_dir_real = real_pathdup(obj_dir, 1);
+ struct strbuf odb_path_real = STRBUF_INIT;
prepare_alt_odb(r);
for (odb = r->objects->odb; odb; odb = odb->next) {
- if (!strcmp(obj_dir_real, real_path(odb->path)))
+ strbuf_realpath(&odb_path_real, odb->path, 1);
+ if (!strcmp(obj_dir_real, odb_path_real.buf))
break;
}
free(obj_dir_real);
+ strbuf_release(&odb_path_real);
if (!odb)
die(_("could not find object directory matching %s"), obj_dir);
@@ -111,14 +121,56 @@ static int graph_verify(int argc, const char **argv)
extern int read_replace_refs;
static struct split_commit_graph_opts split_opts;
+static int write_option_parse_split(const struct option *opt, const char *arg,
+ int unset)
+{
+ enum commit_graph_split_flags *flags = opt->value;
+
+ opts.split = 1;
+ if (!arg)
+ return 0;
+
+ if (!strcmp(arg, "no-merge"))
+ *flags = COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED;
+ else if (!strcmp(arg, "replace"))
+ *flags = COMMIT_GRAPH_SPLIT_REPLACE;
+ else
+ die(_("unrecognized --split argument, %s"), arg);
+
+ return 0;
+}
+
+static int read_one_commit(struct oidset *commits, struct progress *progress,
+ const char *hash)
+{
+ struct object *result;
+ struct object_id oid;
+ const char *end;
+
+ if (parse_oid_hex(hash, &oid, &end))
+ return error(_("unexpected non-hex object ID: %s"), hash);
+
+ result = deref_tag(the_repository, parse_object(the_repository, &oid),
+ NULL, 0);
+ if (!result)
+ return error(_("invalid object: %s"), hash);
+ else if (object_as_type(result, OBJ_COMMIT, 1))
+ oidset_insert(commits, &result->oid);
+
+ display_progress(progress, oidset_size(commits));
+
+ return 0;
+}
+
static int graph_write(int argc, const char **argv)
{
- struct string_list *pack_indexes = NULL;
- struct string_list *commit_hex = NULL;
+ struct string_list pack_indexes = STRING_LIST_INIT_NODUP;
+ struct strbuf buf = STRBUF_INIT;
+ struct oidset commits = OIDSET_INIT;
struct object_directory *odb = NULL;
- struct string_list lines;
int result = 0;
enum commit_graph_write_flags flags = 0;
+ struct progress *progress = NULL;
static struct option builtin_commit_graph_write_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -132,19 +184,24 @@ static int graph_write(int argc, const char **argv)
N_("start walk at commits listed by stdin")),
OPT_BOOL(0, "append", &opts.append,
N_("include all commits already in the commit-graph file")),
+ OPT_BOOL(0, "changed-paths", &opts.enable_changed_paths,
+ N_("enable computation for changed paths")),
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
- OPT_BOOL(0, "split", &opts.split,
- N_("allow writing an incremental commit-graph file")),
+ OPT_CALLBACK_F(0, "split", &split_opts.flags, NULL,
+ N_("allow writing an incremental commit-graph file"),
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+ write_option_parse_split),
OPT_INTEGER(0, "max-commits", &split_opts.max_commits,
N_("maximum number of commits in a non-base split commit-graph")),
OPT_INTEGER(0, "size-multiple", &split_opts.size_multiple,
N_("maximum ratio between two levels of a split commit-graph")),
OPT_EXPIRY_DATE(0, "expire-time", &split_opts.expire_time,
- N_("maximum number of commits in a non-base split commit-graph")),
+ N_("only expire files older than a given date-time")),
OPT_END(),
};
opts.progress = isatty(2);
+ opts.enable_changed_paths = -1;
split_opts.size_multiple = 2;
split_opts.max_commits = 0;
split_opts.expire_time = 0;
@@ -165,6 +222,11 @@ static int graph_write(int argc, const char **argv)
flags |= COMMIT_GRAPH_WRITE_SPLIT;
if (opts.progress)
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
+ if (!opts.enable_changed_paths)
+ flags |= COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS;
+ if (opts.enable_changed_paths == 1 ||
+ git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))
+ flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS;
read_replace_refs = 0;
odb = find_odb(the_repository, opts.obj_dir);
@@ -175,31 +237,36 @@ static int graph_write(int argc, const char **argv)
return 0;
}
- string_list_init(&lines, 0);
- if (opts.stdin_packs || opts.stdin_commits) {
- struct strbuf buf = STRBUF_INIT;
-
+ if (opts.stdin_packs) {
while (strbuf_getline(&buf, stdin) != EOF)
- string_list_append(&lines, strbuf_detach(&buf, NULL));
-
- if (opts.stdin_packs)
- pack_indexes = &lines;
- if (opts.stdin_commits) {
- commit_hex = &lines;
- flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
+ string_list_append(&pack_indexes,
+ strbuf_detach(&buf, NULL));
+ } else if (opts.stdin_commits) {
+ oidset_init(&commits, 0);
+ if (opts.progress)
+ progress = start_delayed_progress(
+ _("Collecting commits from input"), 0);
+
+ while (strbuf_getline(&buf, stdin) != EOF) {
+ if (read_one_commit(&commits, progress, buf.buf)) {
+ result = 1;
+ goto cleanup;
+ }
}
- UNLEAK(buf);
+ stop_progress(&progress);
}
if (write_commit_graph(odb,
- pack_indexes,
- commit_hex,
+ opts.stdin_packs ? &pack_indexes : NULL,
+ opts.stdin_commits ? &commits : NULL,
flags,
&split_opts))
result = 1;
- UNLEAK(lines);
+cleanup:
+ string_list_clear(&pack_indexes, 0);
+ strbuf_release(&buf);
return result;
}
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index b866d83..1031b9a 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -108,15 +108,15 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
struct object_id commit_oid;
struct option options[] = {
- { OPTION_CALLBACK, 'p', NULL, &parents, N_("parent"),
+ OPT_CALLBACK_F('p', NULL, &parents, N_("parent"),
N_("id of a parent commit object"), PARSE_OPT_NONEG,
- parse_parent_arg_callback },
- { OPTION_CALLBACK, 'm', NULL, &buffer, N_("message"),
+ parse_parent_arg_callback),
+ OPT_CALLBACK_F('m', NULL, &buffer, N_("message"),
N_("commit message"), PARSE_OPT_NONEG,
- parse_message_arg_callback },
- { OPTION_CALLBACK, 'F', NULL, &buffer, N_("file"),
+ parse_message_arg_callback),
+ OPT_CALLBACK_F('F', NULL, &buffer, N_("file"),
N_("read commit log message from file"), PARSE_OPT_NONEG,
- parse_file_arg_callback },
+ parse_file_arg_callback),
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_END()
diff --git a/builtin/commit.c b/builtin/commit.c
index 7ba33a3..d1b7396 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -59,6 +59,9 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
" git commit --allow-empty\n"
"\n");
+static const char empty_rebase_pick_advice[] =
+N_("Otherwise, please use 'git rebase --skip'\n");
+
static const char empty_cherry_pick_advice_single[] =
N_("Otherwise, please use 'git cherry-pick --skip'\n");
@@ -122,7 +125,6 @@ static enum commit_msg_cleanup_mode cleanup_mode;
static const char *cleanup_arg;
static enum commit_whence whence;
-static int sequencer_in_use;
static int use_editor = 1, include_status = 1;
static int have_option_m;
static struct strbuf message = STRBUF_INIT;
@@ -179,12 +181,7 @@ static void determine_whence(struct wt_status *s)
{
if (file_exists(git_path_merge_head(the_repository)))
whence = FROM_MERGE;
- else if (file_exists(git_path_cherry_pick_head(the_repository))) {
- whence = FROM_CHERRY_PICK;
- if (file_exists(git_path_seq_dir()))
- sequencer_in_use = 1;
- }
- else
+ else if (!sequencer_determine_whence(the_repository, &whence))
whence = FROM_COMMIT;
if (s)
s->whence = whence;
@@ -477,8 +474,10 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
if (whence != FROM_COMMIT) {
if (whence == FROM_MERGE)
die(_("cannot do a partial commit during a merge."));
- else if (whence == FROM_CHERRY_PICK)
+ else if (is_from_cherry_pick(whence))
die(_("cannot do a partial commit during a cherry-pick."));
+ else if (is_from_rebase(whence))
+ die(_("cannot do a partial commit during a rebase."));
}
if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec))
@@ -795,7 +794,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
*/
else if (whence == FROM_MERGE)
hook_arg1 = "merge";
- else if (whence == FROM_CHERRY_PICK) {
+ else if (is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) {
hook_arg1 = "commit";
hook_arg2 = "CHERRY_PICK_HEAD";
}
@@ -973,12 +972,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
run_status(stdout, index_file, prefix, 0, s);
if (amend)
fputs(_(empty_amend_advice), stderr);
- else if (whence == FROM_CHERRY_PICK) {
+ else if (is_from_cherry_pick(whence) ||
+ whence == FROM_REBASE_PICK) {
fputs(_(empty_cherry_pick_advice), stderr);
- if (!sequencer_in_use)
+ if (whence == FROM_CHERRY_PICK_SINGLE)
fputs(_(empty_cherry_pick_advice_single), stderr);
- else
+ else if (whence == FROM_CHERRY_PICK_MULTI)
fputs(_(empty_cherry_pick_advice_multi), stderr);
+ else
+ fputs(_(empty_rebase_pick_advice), stderr);
}
return 0;
}
@@ -1181,8 +1183,10 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (amend && whence != FROM_COMMIT) {
if (whence == FROM_MERGE)
die(_("You are in the middle of a merge -- cannot amend."));
- else if (whence == FROM_CHERRY_PICK)
+ else if (is_from_cherry_pick(whence))
die(_("You are in the middle of a cherry-pick -- cannot amend."));
+ else if (whence == FROM_REBASE_PICK)
+ die(_("You are in the middle of a rebase -- cannot amend."));
}
if (fixup_message && squash_message)
die(_("Options --squash and --fixup cannot be used together"));
@@ -1204,7 +1208,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
use_message = edit_message;
if (amend && !use_message && !fixup_message)
use_message = "HEAD";
- if (!use_message && whence != FROM_CHERRY_PICK && renew_authorship)
+ if (!use_message && !is_from_cherry_pick(whence) &&
+ !is_from_rebase(whence) && renew_authorship)
die(_("--reset-author can be used only with -C, -c or --amend."));
if (use_message) {
use_message_buffer = read_commit_message(use_message);
@@ -1213,7 +1218,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
author_message_buffer = use_message_buffer;
}
}
- if (whence == FROM_CHERRY_PICK && !renew_authorship) {
+ if ((is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) &&
+ !renew_authorship) {
author_message = "CHERRY_PICK_HEAD";
author_message_buffer = read_commit_message(author_message);
}
@@ -1366,9 +1372,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
N_("show stash information")),
OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags,
N_("compute full ahead/behind values")),
- { OPTION_CALLBACK, 0, "porcelain", &status_format,
+ OPT_CALLBACK_F(0, "porcelain", &status_format,
N_("version"), N_("machine-readable output"),
- PARSE_OPT_OPTARG, opt_parse_porcelain },
+ PARSE_OPT_OPTARG, opt_parse_porcelain),
OPT_SET_INT(0, "long", &status_format,
N_("show status in long format (default)"),
STATUS_FORMAT_LONG),
@@ -1387,9 +1393,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")),
OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")),
- { OPTION_CALLBACK, 'M', "find-renames", &rename_score_arg,
+ OPT_CALLBACK_F('M', "find-renames", &rename_score_arg,
N_("n"), N_("detect renames, optionally set similarity index"),
- PARSE_OPT_OPTARG | PARSE_OPT_NONEG, opt_parse_rename_score },
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG, opt_parse_rename_score),
OPT_END(),
};
@@ -1488,7 +1494,6 @@ static int git_commit_config(const char *k, const char *v, void *cb)
int cmd_commit(int argc, const char **argv, const char *prefix)
{
- const char *argv_gc_auto[] = {"gc", "--auto", NULL};
static struct wt_status s;
static struct option builtin_commit_options[] = {
OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
@@ -1631,8 +1636,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
reduce_heads_replace(&parents);
} else {
if (!reflog_msg)
- reflog_msg = (whence == FROM_CHERRY_PICK)
+ reflog_msg = is_from_cherry_pick(whence)
? "commit (cherry-pick)"
+ : is_from_rebase(whence)
+ ? "commit (rebase)"
: "commit";
commit_list_insert(current_head, &parents);
}
@@ -1659,7 +1666,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
if (amend) {
- const char *exclude_gpgsig[2] = { "gpgsig", NULL };
+ const char *exclude_gpgsig[3] = { "gpgsig", "gpgsig-sha256", NULL };
extra = read_commit_extra_headers(current_head, exclude_gpgsig);
} else {
struct commit_extra_header **tail = &extra;
@@ -1692,12 +1699,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
"new_index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."));
- if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
- write_commit_graph_reachable(the_repository->objects->odb, 0, NULL))
- return 1;
+ git_test_write_commit_graph_or_die();
repo_rerere(the_repository, 0);
- run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+ run_auto_gc(quiet);
run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
if (amend && !no_post_rewrite) {
commit_post_rewrite(the_repository, current_head, &oid);
@@ -1713,6 +1718,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
&oid, flags);
}
+ apply_autostash(git_path_merge_autostash(the_repository));
+
UNLEAK(err);
UNLEAK(sb);
return 0;
diff --git a/builtin/config.c b/builtin/config.c
index ee4aef6..5e39f61 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -672,7 +672,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
given_config_source.file = git_pathdup("config");
given_config_source.scope = CONFIG_SCOPE_LOCAL;
} else if (use_worktree_config) {
- struct worktree **worktrees = get_worktrees(0);
+ struct worktree **worktrees = get_worktrees();
if (repository_format_worktree_config)
given_config_source.file = git_pathdup("config.worktree");
else if (worktrees[0] && worktrees[1])
diff --git a/builtin/describe.c b/builtin/describe.c
index 420f4c6..21d2cb9 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -54,6 +54,7 @@ struct commit_name {
struct tag *tag;
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
unsigned name_checked:1;
+ unsigned misnamed:1;
struct object_id oid;
char *path;
};
@@ -132,6 +133,7 @@ static void add_to_known_names(const char *path,
e->tag = tag;
e->prio = prio;
e->name_checked = 0;
+ e->misnamed = 0;
oidcpy(&e->oid, oid);
free(e->path);
e->path = xstrdup(path);
@@ -275,10 +277,11 @@ static void append_name(struct commit_name *n, struct strbuf *dst)
die(_("annotated tag %s not available"), n->path);
}
if (n->tag && !n->name_checked) {
- if (!n->tag->tag)
- die(_("annotated tag %s has no embedded name"), n->path);
- if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
- warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path);
+ if (strcmp(n->tag->tag, all ? n->path + 5 : n->path)) {
+ warning(_("tag '%s' is externally known as '%s'"),
+ n->path, n->tag->tag);
+ n->misnamed = 1;
+ }
n->name_checked = 1;
}
@@ -314,7 +317,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
* Exact match to an existing ref.
*/
append_name(n, dst);
- if (longformat)
+ if (n->misnamed || longformat)
append_suffix(0, n->tag ? get_tagged_oid(n->tag) : oid, dst);
if (suffix)
strbuf_addstr(dst, suffix);
@@ -463,7 +466,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
}
append_name(all_matches[0].name, dst);
- if (abbrev)
+ if (all_matches[0].name->misnamed || abbrev)
append_suffix(all_matches[0].depth, &cmit->object.oid, dst);
if (suffix)
strbuf_addstr(dst, suffix);
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 86ae474..1e352dd 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -28,6 +28,13 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
repo_init_revisions(the_repository, &rev, prefix);
rev.abbrev = 0;
+
+ /*
+ * Consider "intent-to-add" files as new by default, unless
+ * explicitly specified in the command line or anywhere else.
+ */
+ rev.diffopt.ita_invisible_in_index = 1;
+
precompose_argv(argc, argv);
argc = setup_revisions(argc, argv, &rev, NULL);
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index cb9ea79..802363d 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -109,6 +109,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
struct object *tree1, *tree2;
static struct rev_info *opt = &log_tree_opt;
struct setup_revision_opt s_r_opt;
+ struct userformat_want w;
int read_stdin = 0;
if (argc == 2 && !strcmp(argv[1], "-h"))
@@ -127,6 +128,14 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
precompose_argv(argc, argv);
argc = setup_revisions(argc, argv, opt, &s_r_opt);
+ memset(&w, 0, sizeof(w));
+ userformat_find_requirements(NULL, &w);
+
+ if (!opt->show_notes_given && w.notes)
+ opt->show_notes = 1;
+ if (opt->show_notes)
+ load_display_notes(&opt->notes_opt);
+
while (--argc > 0) {
const char *arg = *++argv;
diff --git a/builtin/diff.c b/builtin/diff.c
index 42ac803..cb98811 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -6,6 +6,7 @@
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "config.h"
+#include "ewah/ewok.h"
#include "lockfile.h"
#include "color.h"
#include "commit.h"
@@ -17,13 +18,19 @@
#include "log-tree.h"
#include "builtin.h"
#include "submodule.h"
-#include "sha1-array.h"
+#include "oid-array.h"
#define DIFF_NO_INDEX_EXPLICIT 1
#define DIFF_NO_INDEX_IMPLICIT 2
static const char builtin_diff_usage[] =
-"git diff [<options>] [<commit> [<commit>]] [--] [<path>...]";
+"git diff [<options>] [<commit>] [--] [<path>...]\n"
+" or: git diff [<options>] --cached [<commit>] [--] [<path>...]\n"
+" or: git diff [<options>] <commit> [<commit>...] <commit> [--] [<path>...]\n"
+" or: git diff [<options>] <commit>...<commit>] [--] [<path>...]\n"
+" or: git diff [<options>] <blob> <blob>]\n"
+" or: git diff [<options>] --no-index [--] <path> <path>]\n"
+COMMON_DIFF_OPTIONS_HELP;
static const char *blob_path(struct object_array_entry *entry)
{
@@ -254,6 +261,108 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
return run_diff_files(revs, options);
}
+struct symdiff {
+ struct bitmap *skip;
+ int warn;
+ const char *base, *left, *right;
+};
+
+/*
+ * Check for symmetric-difference arguments, and if present, arrange
+ * everything we need to know to handle them correctly. As a bonus,
+ * weed out all bogus range-based revision specifications, e.g.,
+ * "git diff A..B C..D" or "git diff A..B C" get rejected.
+ *
+ * For an actual symmetric diff, *symdiff is set this way:
+ *
+ * - its skip is non-NULL and marks *all* rev->pending.objects[i]
+ * indices that the caller should ignore (extra merge bases, of
+ * which there might be many, and A in A...B). Note that the
+ * chosen merge base and right side are NOT marked.
+ * - warn is set if there are multiple merge bases.
+ * - base, left, and right point to the names to use in a
+ * warning about multiple merge bases.
+ *
+ * If there is no symmetric diff argument, sym->skip is NULL and
+ * sym->warn is cleared. The remaining fields are not set.
+ */
+static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym)
+{
+ int i, is_symdiff = 0, basecount = 0, othercount = 0;
+ int lpos = -1, rpos = -1, basepos = -1;
+ struct bitmap *map = NULL;
+
+ /*
+ * Use the whence fields to find merge bases and left and
+ * right parts of symmetric difference, so that we do not
+ * depend on the order that revisions are parsed. If there
+ * are any revs that aren't from these sources, we have a
+ * "git diff C A...B" or "git diff A...B C" case. Or we
+ * could even get "git diff A...B C...E", for instance.
+ *
+ * If we don't have just one merge base, we pick one
+ * at random.
+ *
+ * NB: REV_CMD_LEFT, REV_CMD_RIGHT are also used for A..B,
+ * so we must check for SYMMETRIC_LEFT too. The two arrays
+ * rev->pending.objects and rev->cmdline.rev are parallel.
+ */
+ for (i = 0; i < rev->cmdline.nr; i++) {
+ struct object *obj = rev->pending.objects[i].item;
+ switch (rev->cmdline.rev[i].whence) {
+ case REV_CMD_MERGE_BASE:
+ if (basepos < 0)
+ basepos = i;
+ basecount++;
+ break; /* do mark all bases */
+ case REV_CMD_LEFT:
+ if (lpos >= 0)
+ usage(builtin_diff_usage);
+ lpos = i;
+ if (obj->flags & SYMMETRIC_LEFT) {
+ is_symdiff = 1;
+ break; /* do mark A */
+ }
+ continue;
+ case REV_CMD_RIGHT:
+ if (rpos >= 0)
+ usage(builtin_diff_usage);
+ rpos = i;
+ continue; /* don't mark B */
+ case REV_CMD_PARENTS_ONLY:
+ case REV_CMD_REF:
+ case REV_CMD_REV:
+ othercount++;
+ continue;
+ }
+ if (map == NULL)
+ map = bitmap_new();
+ bitmap_set(map, i);
+ }
+
+ /*
+ * Forbid any additional revs for both A...B and A..B.
+ */
+ if (lpos >= 0 && othercount > 0)
+ usage(builtin_diff_usage);
+
+ if (!is_symdiff) {
+ bitmap_free(map);
+ sym->warn = 0;
+ sym->skip = NULL;
+ return;
+ }
+
+ sym->left = rev->pending.objects[lpos].name;
+ sym->right = rev->pending.objects[rpos].name;
+ if (basecount == 0)
+ die(_("%s...%s: no merge base"), sym->left, sym->right);
+ sym->base = rev->pending.objects[basepos].name;
+ bitmap_unset(map, basepos); /* unmark the base we want */
+ sym->warn = basecount > 1;
+ sym->skip = map;
+}
+
int cmd_diff(int argc, const char **argv, const char *prefix)
{
int i;
@@ -263,19 +372,29 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
struct object_array_entry *blob[2];
int nongit = 0, no_index = 0;
int result = 0;
+ struct symdiff sdiff;
/*
* We could get N tree-ish in the rev.pending_objects list.
- * Also there could be M blobs there, and P pathspecs.
+ * Also there could be M blobs there, and P pathspecs. --cached may
+ * also be present.
*
* N=0, M=0:
- * cache vs files (diff-files)
+ * cache vs files (diff-files)
+ *
+ * N=0, M=0, --cached:
+ * HEAD vs cache (diff-index --cached)
+ *
* N=0, M=2:
* compare two random blobs. P must be zero.
+ *
* N=0, M=1, P=1:
- * compare a blob with a working tree file.
+ * compare a blob with a working tree file.
*
* N=1, M=0:
+ * tree vs files (diff-index)
+ *
+ * N=1, M=0, --cached:
* tree vs cache (diff-index --cached)
*
* N=2, M=0:
@@ -382,6 +501,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
}
}
+ symdiff_prepare(&rev, &sdiff);
for (i = 0; i < rev.pending.nr; i++) {
struct object_array_entry *entry = &rev.pending.objects[i];
struct object *obj = entry->item;
@@ -396,6 +516,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
obj = &get_commit_tree(((struct commit *)obj))->object;
if (obj->type == OBJ_TREE) {
+ if (sdiff.skip && bitmap_get(sdiff.skip, i))
+ continue;
obj->flags |= flags;
add_object_array(obj, name, &ent);
} else if (obj->type == OBJ_BLOB) {
@@ -437,21 +559,12 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
usage(builtin_diff_usage);
else if (ent.nr == 1)
result = builtin_diff_index(&rev, argc, argv);
- else if (ent.nr == 2)
+ else if (ent.nr == 2) {
+ if (sdiff.warn)
+ warning(_("%s...%s: multiple merge bases, using %s"),
+ sdiff.left, sdiff.right, sdiff.base);
result = builtin_diff_tree(&rev, argc, argv,
&ent.objects[0], &ent.objects[1]);
- else if (ent.objects[0].item->flags & UNINTERESTING) {
- /*
- * diff A...B where there is at least one merge base
- * between A and B. We have ent.objects[0] ==
- * merge-base, ent.objects[ents-2] == A, and
- * ent.objects[ents-1] == B. Show diff between the
- * base and B. Note that we pick one merge base at
- * random if there are more than one.
- */
- result = builtin_diff_tree(&rev, argc, argv,
- &ent.objects[0],
- &ent.objects[ent.nr-1]);
} else
result = builtin_diff_combined(&rev, argc, argv,
ent.objects, ent.nr);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 8586816..9f37895 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -45,6 +45,7 @@ static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
static struct refspec refspecs = REFSPEC_INIT_FETCH;
static int anonymize;
+static struct hashmap anonymized_seeds;
static struct revision_sources revision_sources;
static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -120,24 +121,33 @@ static int has_unshown_parent(struct commit *commit)
struct anonymized_entry {
struct hashmap_entry hash;
+ const char *anon;
+ const char orig[FLEX_ARRAY];
+};
+
+struct anonymized_entry_key {
+ struct hashmap_entry hash;
const char *orig;
size_t orig_len;
- const char *anon;
- size_t anon_len;
};
static int anonymized_entry_cmp(const void *unused_cmp_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
- const void *unused_keydata)
+ const void *keydata)
{
const struct anonymized_entry *a, *b;
a = container_of(eptr, const struct anonymized_entry, hash);
- b = container_of(entry_or_key, const struct anonymized_entry, hash);
+ if (keydata) {
+ const struct anonymized_entry_key *key = keydata;
+ int equal = !strncmp(a->orig, key->orig, key->orig_len) &&
+ !a->orig[key->orig_len];
+ return !equal;
+ }
- return a->orig_len != b->orig_len ||
- memcmp(a->orig, b->orig, a->orig_len);
+ b = container_of(entry_or_key, const struct anonymized_entry, hash);
+ return strcmp(a->orig, b->orig);
}
/*
@@ -145,31 +155,39 @@ static int anonymized_entry_cmp(const void *unused_cmp_data,
* the same anonymized string with another. The actual generation
* is farmed out to the generate function.
*/
-static const void *anonymize_mem(struct hashmap *map,
- void *(*generate)(const void *, size_t *),
- const void *orig, size_t *len)
+static const char *anonymize_str(struct hashmap *map,
+ char *(*generate)(void *),
+ const char *orig, size_t len,
+ void *data)
{
- struct anonymized_entry key, *ret;
+ struct anonymized_entry_key key;
+ struct anonymized_entry *ret;
if (!map->cmpfn)
hashmap_init(map, anonymized_entry_cmp, NULL, 0);
- hashmap_entry_init(&key.hash, memhash(orig, *len));
+ hashmap_entry_init(&key.hash, memhash(orig, len));
key.orig = orig;
- key.orig_len = *len;
- ret = hashmap_get_entry(map, &key, hash, NULL);
+ key.orig_len = len;
+
+ /* First check if it's a token the user configured manually... */
+ if (anonymized_seeds.cmpfn)
+ ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
+ else
+ ret = NULL;
+
+ /* ...otherwise check if we've already seen it in this context... */
+ if (!ret)
+ ret = hashmap_get_entry(map, &key, hash, &key);
+ /* ...and finally generate a new mapping if necessary */
if (!ret) {
- ret = xmalloc(sizeof(*ret));
+ FLEX_ALLOC_MEM(ret, orig, orig, len);
hashmap_entry_init(&ret->hash, key.hash.hash);
- ret->orig = xstrdup(orig);
- ret->orig_len = *len;
- ret->anon = generate(orig, len);
- ret->anon_len = *len;
+ ret->anon = generate(data);
hashmap_put(map, &ret->hash);
}
- *len = ret->anon_len;
return ret->anon;
}
@@ -181,13 +199,13 @@ static const void *anonymize_mem(struct hashmap *map,
*/
static void anonymize_path(struct strbuf *out, const char *path,
struct hashmap *map,
- void *(*generate)(const void *, size_t *))
+ char *(*generate)(void *))
{
while (*path) {
const char *end_of_component = strchrnul(path, '/');
size_t len = end_of_component - path;
- const char *c = anonymize_mem(map, generate, path, &len);
- strbuf_add(out, c, len);
+ const char *c = anonymize_str(map, generate, path, len, NULL);
+ strbuf_addstr(out, c);
path = end_of_component;
if (*path)
strbuf_addch(out, *path++);
@@ -361,12 +379,12 @@ static void print_path_1(const char *path)
printf("%s", path);
}
-static void *anonymize_path_component(const void *path, size_t *len)
+static char *anonymize_path_component(void *data)
{
static int counter;
struct strbuf out = STRBUF_INIT;
strbuf_addf(&out, "path%d", counter++);
- return strbuf_detach(&out, len);
+ return strbuf_detach(&out, NULL);
}
static void print_path(const char *path)
@@ -383,20 +401,23 @@ static void print_path(const char *path)
}
}
-static void *generate_fake_oid(const void *old, size_t *len)
+static char *generate_fake_oid(void *data)
{
static uint32_t counter = 1; /* avoid null oid */
const unsigned hashsz = the_hash_algo->rawsz;
- unsigned char *out = xcalloc(hashsz, 1);
+ unsigned char out[GIT_MAX_RAWSZ];
+ char *hex = xmallocz(GIT_MAX_HEXSZ);
+
+ hashclr(out);
put_be32(out + hashsz - 4, counter++);
- return out;
+ return hash_to_hex_algop_r(hex, out, the_hash_algo);
}
-static const struct object_id *anonymize_oid(const struct object_id *oid)
+static const char *anonymize_oid(const char *oid_hex)
{
static struct hashmap objs;
- size_t len = the_hash_algo->rawsz;
- return anonymize_mem(&objs, generate_fake_oid, oid, &len);
+ size_t len = strlen(oid_hex);
+ return anonymize_str(&objs, generate_fake_oid, oid_hex, len, NULL);
}
static void show_filemodify(struct diff_queue_struct *q,
@@ -455,9 +476,9 @@ static void show_filemodify(struct diff_queue_struct *q,
*/
if (no_data || S_ISGITLINK(spec->mode))
printf("M %06o %s ", spec->mode,
- oid_to_hex(anonymize ?
- anonymize_oid(&spec->oid) :
- &spec->oid));
+ anonymize ?
+ anonymize_oid(oid_to_hex(&spec->oid)) :
+ oid_to_hex(&spec->oid));
else {
struct object *object = lookup_object(the_repository,
&spec->oid);
@@ -493,12 +514,12 @@ static const char *find_encoding(const char *begin, const char *end)
return bol;
}
-static void *anonymize_ref_component(const void *old, size_t *len)
+static char *anonymize_ref_component(void *data)
{
static int counter;
struct strbuf out = STRBUF_INIT;
strbuf_addf(&out, "ref%d", counter++);
- return strbuf_detach(&out, len);
+ return strbuf_detach(&out, NULL);
}
static const char *anonymize_refname(const char *refname)
@@ -517,13 +538,6 @@ static const char *anonymize_refname(const char *refname)
static struct strbuf anon = STRBUF_INIT;
int i;
- /*
- * We also leave "master" as a special case, since it does not reveal
- * anything interesting.
- */
- if (!strcmp(refname, "refs/heads/master"))
- return refname;
-
strbuf_reset(&anon);
for (i = 0; i < ARRAY_SIZE(prefixes); i++) {
if (skip_prefix(refname, prefixes[i], &refname)) {
@@ -546,14 +560,13 @@ static char *anonymize_commit_message(const char *old)
return xstrfmt("subject %d\n\nbody\n", counter++);
}
-static struct hashmap idents;
-static void *anonymize_ident(const void *old, size_t *len)
+static char *anonymize_ident(void *data)
{
static int counter;
struct strbuf out = STRBUF_INIT;
strbuf_addf(&out, "User %d <user%d@example.com>", counter, counter);
counter++;
- return strbuf_detach(&out, len);
+ return strbuf_detach(&out, NULL);
}
/*
@@ -563,6 +576,7 @@ static void *anonymize_ident(const void *old, size_t *len)
*/
static void anonymize_ident_line(const char **beg, const char **end)
{
+ static struct hashmap idents;
static struct strbuf buffers[] = { STRBUF_INIT, STRBUF_INIT };
static unsigned which_buffer;
@@ -588,9 +602,9 @@ static void anonymize_ident_line(const char **beg, const char **end)
size_t len;
len = split.mail_end - split.name_begin;
- ident = anonymize_mem(&idents, anonymize_ident,
- split.name_begin, &len);
- strbuf_add(out, ident, len);
+ ident = anonymize_str(&idents, anonymize_ident,
+ split.name_begin, len, NULL);
+ strbuf_addstr(out, ident);
strbuf_addch(out, ' ');
strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
} else {
@@ -712,9 +726,10 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
if (mark)
printf(":%d\n", mark);
else
- printf("%s\n", oid_to_hex(anonymize ?
- anonymize_oid(&obj->oid) :
- &obj->oid));
+ printf("%s\n",
+ anonymize ?
+ anonymize_oid(oid_to_hex(&obj->oid)) :
+ oid_to_hex(&obj->oid));
i++;
}
@@ -729,12 +744,12 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
show_progress();
}
-static void *anonymize_tag(const void *old, size_t *len)
+static char *anonymize_tag(void *data)
{
static int counter;
struct strbuf out = STRBUF_INIT;
strbuf_addf(&out, "tag message %d", counter++);
- return strbuf_detach(&out, len);
+ return strbuf_detach(&out, NULL);
}
static void handle_tail(struct object_array *commits, struct rev_info *revs,
@@ -804,8 +819,8 @@ static void handle_tag(const char *name, struct tag *tag)
name = anonymize_refname(name);
if (message) {
static struct hashmap tags;
- message = anonymize_mem(&tags, anonymize_tag,
- message, &message_size);
+ message = anonymize_str(&tags, anonymize_tag,
+ message, message_size, NULL);
}
}
@@ -1136,6 +1151,37 @@ static void handle_deletes(void)
}
}
+static char *anonymize_seed(void *data)
+{
+ return xstrdup(data);
+}
+
+static int parse_opt_anonymize_map(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct hashmap *map = opt->value;
+ const char *delim, *value;
+ size_t keylen;
+
+ BUG_ON_OPT_NEG(unset);
+
+ delim = strchr(arg, ':');
+ if (delim) {
+ keylen = delim - arg;
+ value = delim + 1;
+ } else {
+ keylen = strlen(arg);
+ value = arg;
+ }
+
+ if (!keylen || !*value)
+ return error(_("--anonymize-map token cannot be empty"));
+
+ anonymize_str(map, anonymize_seed, arg, keylen, (void *)value);
+
+ return 0;
+}
+
int cmd_fast_export(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
@@ -1177,6 +1223,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
N_("Apply refspec to exported refs")),
OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
+ OPT_CALLBACK_F(0, "anonymize-map", &anonymized_seeds, N_("from:to"),
+ N_("convert <from> to <to> in anonymized output"),
+ PARSE_OPT_NONEG, parse_opt_anonymize_map),
OPT_BOOL(0, "reference-excluded-parents",
&reference_excluded_commits, N_("Reference parents which are not in fast-export stream by object id")),
OPT_BOOL(0, "show-original-ids", &show_original_ids,
@@ -1204,6 +1253,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (argc > 1)
usage_with_options (fast_export_usage, options);
+ if (anonymized_seeds.cmpfn && !anonymize)
+ die(_("--anonymize-map without --anonymize does not make sense"));
+
if (refspecs_list.nr) {
int i;
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index dc1485c..bbb5c96 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -3,7 +3,7 @@
#include "fetch-pack.h"
#include "remote.h"
#include "connect.h"
-#include "sha1-array.h"
+#include "oid-array.h"
#include "protocol.h"
static const char fetch_pack_usage[] =
@@ -48,8 +48,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
struct ref **sought = NULL;
int nr_sought = 0, alloc_sought = 0;
int fd[2];
- char *pack_lockfile = NULL;
- char **pack_lockfile_ptr = NULL;
+ struct string_list pack_lockfiles = STRING_LIST_INIT_DUP;
+ struct string_list *pack_lockfiles_ptr = NULL;
struct child_process *conn;
struct fetch_pack_args args;
struct oid_array shallow = OID_ARRAY_INIT;
@@ -134,7 +134,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
}
if (!strcmp("--lock-pack", arg)) {
args.lock_pack = 1;
- pack_lockfile_ptr = &pack_lockfile;
+ pack_lockfiles_ptr = &pack_lockfiles;
continue;
}
if (!strcmp("--check-self-contained-and-connected", arg)) {
@@ -224,7 +224,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
version = discover_version(&reader);
switch (version) {
case protocol_v2:
- get_remote_refs(fd[1], &reader, &ref, 0, NULL, NULL);
+ get_remote_refs(fd[1], &reader, &ref, 0, NULL, NULL, args.stateless_rpc);
break;
case protocol_v1:
case protocol_v0:
@@ -235,10 +235,15 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
}
ref = fetch_pack(&args, fd, ref, sought, nr_sought,
- &shallow, pack_lockfile_ptr, version);
- if (pack_lockfile) {
- printf("lock %s\n", pack_lockfile);
+ &shallow, pack_lockfiles_ptr, version);
+ if (pack_lockfiles.nr) {
+ int i;
+
+ printf("lock %s\n", pack_lockfiles.items[0].string);
fflush(stdout);
+ for (i = 1; i < pack_lockfiles.nr; i++)
+ warning(_("Lockfile created but not reported: %s"),
+ pack_lockfiles.items[i].string);
}
if (args.check_self_contained_and_connected &&
args.self_contained_and_connected) {
diff --git a/builtin/fetch.c b/builtin/fetch.c
index bf6bab8..82ac4be 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -27,6 +27,7 @@
#include "branch.h"
#include "promisor-remote.h"
#include "commit-graph.h"
+#include "shallow.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -156,9 +157,9 @@ static struct option builtin_fetch_options[] = {
N_("prune remote-tracking branches no longer on remote")),
OPT_BOOL('P', "prune-tags", &prune_tags,
N_("prune local tags no longer on remote and clobber changed tags")),
- { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, N_("on-demand"),
+ OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules, N_("on-demand"),
N_("control recursive fetching of submodules"),
- PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules },
+ PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
OPT_BOOL(0, "dry-run", &dry_run,
N_("dry run")),
OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
@@ -178,15 +179,15 @@ static struct option builtin_fetch_options[] = {
1, PARSE_OPT_NONEG),
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
- { OPTION_CALLBACK, 0, "recurse-submodules-default",
+ OPT_CALLBACK_F(0, "recurse-submodules-default",
&recurse_submodules_default, N_("on-demand"),
N_("default for recursive fetching of submodules "
"(lower priority than config files)"),
- PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules },
+ PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
OPT_BOOL(0, "update-shallow", &update_shallow,
N_("accept refs that update .git/shallow")),
- { OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"),
- N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg },
+ OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"),
+ N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
TRANSPORT_FAMILY_IPV4),
@@ -908,13 +909,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
if (!connectivity_checked) {
struct check_connected_options opt = CHECK_CONNECTED_INIT;
- if (filter_options.choice)
- /*
- * Since a filter is specified, objects indirectly
- * referenced by refs are allowed to be absent.
- */
- opt.check_refs_are_promisor_objects_only = 1;
-
rm = ref_map;
if (check_connected(iterate_ref_map, &rm, &opt)) {
rc = error(_("%s did not send all necessary objects\n"), url);
@@ -1759,14 +1753,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
struct remote *remote = NULL;
int result = 0;
int prune_tags_ok = 1;
- struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
packet_trace_identity("fetch");
/* Record the command line for the reflog */
strbuf_addstr(&default_rla, "fetch");
- for (i = 1; i < argc; i++)
- strbuf_addf(&default_rla, " %s", argv[i]);
+ for (i = 1; i < argc; i++) {
+ /* This handles non-URLs gracefully */
+ char *anon = transport_anonymize_url(argv[i]);
+
+ strbuf_addf(&default_rla, " %s", anon);
+ free(anon);
+ }
fetch_config_from_gitmodules(&submodule_fetch_jobs_config,
&recurse_submodules);
@@ -1797,9 +1795,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (depth || deepen_since || deepen_not.nr)
deepen = 1;
- if (filter_options.choice && !has_promisor_remote())
- die("--filter can only be used when extensions.partialClone is set");
-
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
@@ -1886,13 +1881,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
close_object_store(the_repository->objects);
- if (enable_auto_gc) {
- argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL);
- if (verbosity < 0)
- argv_array_push(&argv_gc_auto, "--quiet");
- run_command_v_opt(argv_gc_auto.argv, RUN_GIT_CMD);
- argv_array_clear(&argv_gc_auto);
- }
+ if (enable_auto_gc)
+ run_auto_gc(verbosity < 0);
return result;
}
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 736f666..48a8699 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -1,666 +1,13 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
-#include "refs.h"
-#include "object-store.h"
-#include "commit.h"
-#include "diff.h"
-#include "revision.h"
-#include "tag.h"
-#include "string-list.h"
-#include "branch.h"
#include "fmt-merge-msg.h"
-#include "gpg-interface.h"
-#include "repository.h"
-#include "commit-reach.h"
+#include "parse-options.h"
static const char * const fmt_merge_msg_usage[] = {
N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
NULL
};
-static int use_branch_desc;
-
-int fmt_merge_msg_config(const char *key, const char *value, void *cb)
-{
- if (!strcmp(key, "merge.log") || !strcmp(key, "merge.summary")) {
- int is_bool;
- merge_log_config = git_config_bool_or_int(key, value, &is_bool);
- if (!is_bool && merge_log_config < 0)
- return error("%s: negative length %s", key, value);
- if (is_bool && merge_log_config)
- merge_log_config = DEFAULT_MERGE_LOG_LEN;
- } else if (!strcmp(key, "merge.branchdesc")) {
- use_branch_desc = git_config_bool(key, value);
- } else {
- return git_default_config(key, value, cb);
- }
- return 0;
-}
-
-/* merge data per repository where the merged tips came from */
-struct src_data {
- struct string_list branch, tag, r_branch, generic;
- int head_status;
-};
-
-struct origin_data {
- struct object_id oid;
- unsigned is_local_branch:1;
-};
-
-static void init_src_data(struct src_data *data)
-{
- data->branch.strdup_strings = 1;
- data->tag.strdup_strings = 1;
- data->r_branch.strdup_strings = 1;
- data->generic.strdup_strings = 1;
-}
-
-static struct string_list srcs = STRING_LIST_INIT_DUP;
-static struct string_list origins = STRING_LIST_INIT_DUP;
-
-struct merge_parents {
- int alloc, nr;
- struct merge_parent {
- struct object_id given;
- struct object_id commit;
- unsigned char used;
- } *item;
-};
-
-/*
- * I know, I know, this is inefficient, but you won't be pulling and merging
- * hundreds of heads at a time anyway.
- */
-static struct merge_parent *find_merge_parent(struct merge_parents *table,
- struct object_id *given,
- struct object_id *commit)
-{
- int i;
- for (i = 0; i < table->nr; i++) {
- if (given && !oideq(&table->item[i].given, given))
- continue;
- if (commit && !oideq(&table->item[i].commit, commit))
- continue;
- return &table->item[i];
- }
- return NULL;
-}
-
-static void add_merge_parent(struct merge_parents *table,
- struct object_id *given,
- struct object_id *commit)
-{
- if (table->nr && find_merge_parent(table, given, commit))
- return;
- ALLOC_GROW(table->item, table->nr + 1, table->alloc);
- oidcpy(&table->item[table->nr].given, given);
- oidcpy(&table->item[table->nr].commit, commit);
- table->item[table->nr].used = 0;
- table->nr++;
-}
-
-static int handle_line(char *line, struct merge_parents *merge_parents)
-{
- int i, len = strlen(line);
- struct origin_data *origin_data;
- char *src;
- const char *origin, *tag_name;
- struct src_data *src_data;
- struct string_list_item *item;
- int pulling_head = 0;
- struct object_id oid;
- const unsigned hexsz = the_hash_algo->hexsz;
-
- if (len < hexsz + 3 || line[hexsz] != '\t')
- return 1;
-
- if (starts_with(line + hexsz + 1, "not-for-merge"))
- return 0;
-
- if (line[hexsz + 1] != '\t')
- return 2;
-
- i = get_oid_hex(line, &oid);
- if (i)
- return 3;
-
- if (!find_merge_parent(merge_parents, &oid, NULL))
- return 0; /* subsumed by other parents */
-
- origin_data = xcalloc(1, sizeof(struct origin_data));
- oidcpy(&origin_data->oid, &oid);
-
- if (line[len - 1] == '\n')
- line[len - 1] = 0;
- line += hexsz + 2;
-
- /*
- * At this point, line points at the beginning of comment e.g.
- * "branch 'frotz' of git://that/repository.git".
- * Find the repository name and point it with src.
- */
- src = strstr(line, " of ");
- if (src) {
- *src = 0;
- src += 4;
- pulling_head = 0;
- } else {
- src = line;
- pulling_head = 1;
- }
-
- item = unsorted_string_list_lookup(&srcs, src);
- if (!item) {
- item = string_list_append(&srcs, src);
- item->util = xcalloc(1, sizeof(struct src_data));
- init_src_data(item->util);
- }
- src_data = item->util;
-
- if (pulling_head) {
- origin = src;
- src_data->head_status |= 1;
- } else if (skip_prefix(line, "branch ", &origin)) {
- origin_data->is_local_branch = 1;
- string_list_append(&src_data->branch, origin);
- src_data->head_status |= 2;
- } else if (skip_prefix(line, "tag ", &tag_name)) {
- origin = line;
- string_list_append(&src_data->tag, tag_name);
- src_data->head_status |= 2;
- } else if (skip_prefix(line, "remote-tracking branch ", &origin)) {
- string_list_append(&src_data->r_branch, origin);
- src_data->head_status |= 2;
- } else {
- origin = src;
- string_list_append(&src_data->generic, line);
- src_data->head_status |= 2;
- }
-
- if (!strcmp(".", src) || !strcmp(src, origin)) {
- int len = strlen(origin);
- if (origin[0] == '\'' && origin[len - 1] == '\'')
- origin = xmemdupz(origin + 1, len - 2);
- } else
- origin = xstrfmt("%s of %s", origin, src);
- if (strcmp(".", src))
- origin_data->is_local_branch = 0;
- string_list_append(&origins, origin)->util = origin_data;
- return 0;
-}
-
-static void print_joined(const char *singular, const char *plural,
- struct string_list *list, struct strbuf *out)
-{
- if (list->nr == 0)
- return;
- if (list->nr == 1) {
- strbuf_addf(out, "%s%s", singular, list->items[0].string);
- } else {
- int i;
- strbuf_addstr(out, plural);
- for (i = 0; i < list->nr - 1; i++)
- strbuf_addf(out, "%s%s", i > 0 ? ", " : "",
- list->items[i].string);
- strbuf_addf(out, " and %s", list->items[list->nr - 1].string);
- }
-}
-
-static void add_branch_desc(struct strbuf *out, const char *name)
-{
- struct strbuf desc = STRBUF_INIT;
-
- if (!read_branch_desc(&desc, name)) {
- const char *bp = desc.buf;
- while (*bp) {
- const char *ep = strchrnul(bp, '\n');
- if (*ep)
- ep++;
- strbuf_addf(out, " : %.*s", (int)(ep - bp), bp);
- bp = ep;
- }
- strbuf_complete_line(out);
- }
- strbuf_release(&desc);
-}
-
-#define util_as_integral(elem) ((intptr_t)((elem)->util))
-
-static void record_person_from_buf(int which, struct string_list *people,
- const char *buffer)
-{
- char *name_buf, *name, *name_end;
- struct string_list_item *elem;
- const char *field;
-
- field = (which == 'a') ? "\nauthor " : "\ncommitter ";
- name = strstr(buffer, field);
- if (!name)
- return;
- name += strlen(field);
- name_end = strchrnul(name, '<');
- if (*name_end)
- name_end--;
- while (isspace(*name_end) && name <= name_end)
- name_end--;
- if (name_end < name)
- return;
- name_buf = xmemdupz(name, name_end - name + 1);
-
- elem = string_list_lookup(people, name_buf);
- if (!elem) {
- elem = string_list_insert(people, name_buf);
- elem->util = (void *)0;
- }
- elem->util = (void*)(util_as_integral(elem) + 1);
- free(name_buf);
-}
-
-
-static void record_person(int which, struct string_list *people,
- struct commit *commit)
-{
- const char *buffer = get_commit_buffer(commit, NULL);
- record_person_from_buf(which, people, buffer);
- unuse_commit_buffer(commit, buffer);
-}
-
-static int cmp_string_list_util_as_integral(const void *a_, const void *b_)
-{
- const struct string_list_item *a = a_, *b = b_;
- return util_as_integral(b) - util_as_integral(a);
-}
-
-static void add_people_count(struct strbuf *out, struct string_list *people)
-{
- if (people->nr == 1)
- strbuf_addstr(out, people->items[0].string);
- else if (people->nr == 2)
- strbuf_addf(out, "%s (%d) and %s (%d)",
- people->items[0].string,
- (int)util_as_integral(&people->items[0]),
- people->items[1].string,
- (int)util_as_integral(&people->items[1]));
- else if (people->nr)
- strbuf_addf(out, "%s (%d) and others",
- people->items[0].string,
- (int)util_as_integral(&people->items[0]));
-}
-
-static void credit_people(struct strbuf *out,
- struct string_list *them,
- int kind)
-{
- const char *label;
- const char *me;
-
- if (kind == 'a') {
- label = "By";
- me = git_author_info(IDENT_NO_DATE);
- } else {
- label = "Via";
- me = git_committer_info(IDENT_NO_DATE);
- }
-
- if (!them->nr ||
- (them->nr == 1 &&
- me &&
- skip_prefix(me, them->items->string, &me) &&
- starts_with(me, " <")))
- return;
- strbuf_addf(out, "\n%c %s ", comment_line_char, label);
- add_people_count(out, them);
-}
-
-static void add_people_info(struct strbuf *out,
- struct string_list *authors,
- struct string_list *committers)
-{
- QSORT(authors->items, authors->nr,
- cmp_string_list_util_as_integral);
- QSORT(committers->items, committers->nr,
- cmp_string_list_util_as_integral);
-
- credit_people(out, authors, 'a');
- credit_people(out, committers, 'c');
-}
-
-static void shortlog(const char *name,
- struct origin_data *origin_data,
- struct commit *head,
- struct rev_info *rev,
- struct fmt_merge_msg_opts *opts,
- struct strbuf *out)
-{
- int i, count = 0;
- struct commit *commit;
- struct object *branch;
- struct string_list subjects = STRING_LIST_INIT_DUP;
- struct string_list authors = STRING_LIST_INIT_DUP;
- struct string_list committers = STRING_LIST_INIT_DUP;
- int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
- struct strbuf sb = STRBUF_INIT;
- const struct object_id *oid = &origin_data->oid;
- int