summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/check-whitespace.yml71
-rw-r--r--.github/workflows/main.yml98
-rw-r--r--.gitignore4
-rw-r--r--Documentation/MyFirstContribution.txt11
-rw-r--r--Documentation/RelNotes/2.29.0.txt354
-rw-r--r--Documentation/RelNotes/2.29.1.txt11
-rw-r--r--Documentation/RelNotes/2.29.2.txt12
-rw-r--r--Documentation/RelNotes/2.30.0.txt201
-rw-r--r--Documentation/SubmittingPatches43
-rw-r--r--Documentation/config.txt6
-rw-r--r--Documentation/config/advice.txt9
-rw-r--r--Documentation/config/checkout.txt21
-rw-r--r--Documentation/config/clone.txt4
-rw-r--r--Documentation/config/commitgraph.txt8
-rw-r--r--Documentation/config/core.txt2
-rw-r--r--Documentation/config/feature.txt4
-rw-r--r--Documentation/config/fetch.txt5
-rw-r--r--Documentation/config/fmt-merge-msg.txt2
-rw-r--r--Documentation/config/format.txt6
-rw-r--r--Documentation/config/mergetool.txt10
-rw-r--r--Documentation/config/protocol.txt3
-rw-r--r--Documentation/config/push.txt6
-rw-r--r--Documentation/config/receive.txt22
-rw-r--r--Documentation/config/uploadpack.txt2
-rw-r--r--Documentation/diff-generate-patch.txt3
-rw-r--r--Documentation/diff-options.txt24
-rw-r--r--Documentation/fetch-options.txt2
-rw-r--r--Documentation/git-am.txt2
-rw-r--r--Documentation/git-apply.txt20
-rw-r--r--Documentation/git-archive.txt6
-rw-r--r--Documentation/git-bisect-lk2009.txt16
-rw-r--r--Documentation/git-bisect.txt2
-rw-r--r--Documentation/git-blame.txt4
-rw-r--r--Documentation/git-branch.txt18
-rw-r--r--Documentation/git-checkout.txt10
-rw-r--r--Documentation/git-cherry-pick.txt2
-rw-r--r--Documentation/git-clone.txt5
-rw-r--r--Documentation/git-commit-graph.txt11
-rw-r--r--Documentation/git-commit.txt10
-rw-r--r--Documentation/git-diff-index.txt9
-rw-r--r--Documentation/git-diff-tree.txt7
-rw-r--r--Documentation/git-diff.txt36
-rw-r--r--Documentation/git-fast-import.txt2
-rw-r--r--Documentation/git-fetch.txt4
-rw-r--r--Documentation/git-filter-branch.txt2
-rw-r--r--Documentation/git-for-each-ref.txt23
-rw-r--r--Documentation/git-format-patch.txt2
-rw-r--r--Documentation/git-grep.txt2
-rw-r--r--Documentation/git-imap-send.txt34
-rw-r--r--Documentation/git-index-pack.txt2
-rw-r--r--Documentation/git-init.txt4
-rw-r--r--Documentation/git-ls-files.txt5
-rw-r--r--Documentation/git-ls-tree.txt3
-rw-r--r--Documentation/git-mailinfo.txt7
-rw-r--r--Documentation/git-multi-pack-index.txt11
-rw-r--r--Documentation/git-p4.txt2
-rw-r--r--Documentation/git-push.txt26
-rw-r--r--Documentation/git-rebase.txt36
-rw-r--r--Documentation/git-remote.txt31
-rw-r--r--Documentation/git-restore.txt4
-rw-r--r--Documentation/git-revert.txt2
-rw-r--r--Documentation/git-send-email.txt4
-rw-r--r--Documentation/git-shortlog.txt31
-rw-r--r--Documentation/git-show-index.txt2
-rw-r--r--Documentation/git-svn.txt4
-rw-r--r--Documentation/git-switch.txt3
-rw-r--r--Documentation/git-tag.txt11
-rw-r--r--Documentation/git-worktree.txt44
-rw-r--r--Documentation/git.txt18
-rw-r--r--Documentation/gitattributes.txt3
-rw-r--r--Documentation/gitfaq.txt86
-rw-r--r--Documentation/githooks.txt70
-rw-r--r--Documentation/gitsubmodules.txt23
-rw-r--r--Documentation/merge-options.txt11
-rw-r--r--Documentation/object-format-disclaimer.txt6
-rw-r--r--Documentation/pretty-options.txt10
-rw-r--r--Documentation/pull-fetch-param.txt16
-rw-r--r--Documentation/ref-reachability-filters.txt7
-rw-r--r--Documentation/signoff-option.txt18
-rw-r--r--Documentation/technical/commit-graph-format.txt13
-rw-r--r--Documentation/technical/commit-graph.txt6
-rw-r--r--Documentation/technical/directory-rename-detection.txt15
-rw-r--r--Documentation/technical/hash-function-transition.txt2
-rw-r--r--Documentation/technical/http-protocol.txt5
-rw-r--r--Documentation/technical/index-format.txt34
-rw-r--r--Documentation/technical/pack-format.txt43
-rw-r--r--Documentation/technical/pack-protocol.txt41
-rw-r--r--Documentation/technical/partial-clone.txt13
-rw-r--r--Documentation/technical/protocol-capabilities.txt29
-rw-r--r--Documentation/technical/shallow.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile224
l---------RelNotes2
-rw-r--r--add-patch.c203
-rw-r--r--advice.c3
-rw-r--r--advice.h2
-rw-r--r--apply.c13
-rw-r--r--archive-tar.c25
-rw-r--r--archive-zip.c22
-rw-r--r--archive.c147
-rw-r--r--archive.h10
-rw-r--r--bisect.c13
-rw-r--r--blame.c19
-rw-r--r--bloom.c59
-rw-r--r--bloom.h29
-rw-r--r--branch.c2
-rw-r--r--builtin.h5
-rw-r--r--builtin/add.c20
-rw-r--r--builtin/am.c21
-rw-r--r--builtin/bisect--helper.c453
-rw-r--r--builtin/blame.c31
-rw-r--r--builtin/branch.c6
-rw-r--r--builtin/bugreport.c (renamed from bugreport.c)14
-rw-r--r--builtin/check-ignore.c4
-rw-r--r--builtin/checkout-index.c16
-rw-r--r--builtin/checkout.c34
-rw-r--r--builtin/clean.c34
-rw-r--r--builtin/clone.c80
-rw-r--r--builtin/commit-graph.c65
-rw-r--r--builtin/commit.c44
-rw-r--r--builtin/config.c29
-rw-r--r--builtin/credential-cache--daemon.c (renamed from credential-cache--daemon.c)29
-rw-r--r--builtin/credential-cache.c (renamed from credential-cache.c)37
-rw-r--r--builtin/credential-store.c (renamed from credential-store.c)6
-rw-r--r--builtin/credential.c3
-rw-r--r--builtin/diff-index.c10
-rw-r--r--builtin/diff-tree.c17
-rw-r--r--builtin/diff.c52
-rw-r--r--builtin/env--helper.c13
-rw-r--r--builtin/fast-export.c12
-rw-r--r--builtin/fast-import.c (renamed from fast-import.c)53
-rw-r--r--builtin/fetch-pack.c4
-rw-r--r--builtin/fetch.c80
-rw-r--r--builtin/for-each-ref.c2
-rw-r--r--builtin/gc.c14
-rw-r--r--builtin/grep.c16
-rw-r--r--builtin/index-pack.c496
-rw-r--r--builtin/init-db.c37
-rw-r--r--builtin/log.c197
-rw-r--r--builtin/ls-files.c4
-rw-r--r--builtin/ls-remote.c8
-rw-r--r--builtin/merge-tree.c1
-rw-r--r--builtin/merge.c6
-rw-r--r--builtin/name-rev.c2
-rw-r--r--builtin/pack-objects.c2
-rw-r--r--builtin/pull.c5
-rw-r--r--builtin/push.c85
-rw-r--r--builtin/rebase.c69
-rw-r--r--builtin/receive-pack.c472
-rw-r--r--builtin/remote.c52
-rw-r--r--builtin/repack.c12
-rw-r--r--builtin/reset.c2
-rw-r--r--builtin/rev-parse.c2
-rw-r--r--builtin/revert.c2
-rw-r--r--builtin/send-pack.c30
-rw-r--r--builtin/shortlog.c213
-rw-r--r--builtin/show-branch.c2
-rw-r--r--builtin/sparse-checkout.c37
-rw-r--r--builtin/stash.c36
-rw-r--r--builtin/submodule--helper.c447
-rw-r--r--builtin/tag.c8
-rw-r--r--builtin/worktree.c45
-rw-r--r--bundle.c2
-rw-r--r--cache.h33
-rw-r--r--checkout.c3
-rwxr-xr-xci/lib.sh3
-rw-r--r--combine-diff.c64
-rw-r--r--commit-graph.c171
-rw-r--r--commit-graph.h17
-rw-r--r--commit-reach.c8
-rw-r--r--commit.c15
-rw-r--r--commit.h10
-rw-r--r--compat/bswap.h26
-rw-r--r--compat/mingw.c3
-rw-r--r--compat/mingw.h2
-rw-r--r--compat/vcbuild/README4
-rwxr-xr-xcompat/vcbuild/scripts/clink.pl2
-rw-r--r--config.c47
-rw-r--r--config.h15
-rw-r--r--config.mak.dev3
-rw-r--r--connect.c4
-rw-r--r--connected.c21
-rw-r--r--contrib/buildsystems/CMakeLists.txt104
-rw-r--r--contrib/buildsystems/Generators/Vcxproj.pm1
-rwxr-xr-xcontrib/buildsystems/engine.pl2
-rw-r--r--contrib/completion/git-completion.bash240
-rw-r--r--contrib/completion/git-completion.zsh141
-rw-r--r--contrib/completion/git-prompt.sh12
-rw-r--r--contrib/diff-highlight/DiffHighlight.pm2
-rwxr-xr-xcontrib/git-resurrect.sh13
-rwxr-xr-xcontrib/mw-to-git/git-mw.perl2
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki.perl80
-rw-r--r--contrib/mw-to-git/git-remote-mediawiki.txt2
-rw-r--r--contrib/mw-to-git/t/.gitignore2
-rw-r--r--contrib/mw-to-git/t/README10
-rw-r--r--contrib/mw-to-git/t/install-wiki/.gitignore1
-rw-r--r--contrib/mw-to-git/t/install-wiki/LocalSettings.php129
-rw-r--r--contrib/mw-to-git/t/install-wiki/db_install.php120
-rwxr-xr-xcontrib/mw-to-git/t/t9360-mw-to-git-clone.sh8
-rwxr-xr-xcontrib/mw-to-git/t/t9363-mw-to-git-export-import.sh9
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw-lib.sh162
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw.pl22
-rw-r--r--contrib/mw-to-git/t/test.config23
-rw-r--r--contrib/subtree/git-subtree.txt6
-rw-r--r--contrib/svn-fe/.gitignore4
-rw-r--r--contrib/svn-fe/Makefile105
-rw-r--r--contrib/svn-fe/svn-fe.c18
-rw-r--r--contrib/svn-fe/svn-fe.txt71
-rwxr-xr-xcontrib/svn-fe/svnrdump_sim.py68
-rw-r--r--convert.c9
-rw-r--r--credential.c6
-rw-r--r--diff-lib.c122
-rw-r--r--diff.c88
-rw-r--r--diff.h26
-rw-r--r--dir.c40
-rw-r--r--dir.h21
-rw-r--r--editor.c2
-rw-r--r--entry.c2
-rw-r--r--environment.c4
-rw-r--r--fetch-negotiator.c5
-rw-r--r--fetch-pack.c212
-rw-r--r--fetch-pack.h18
-rw-r--r--fmt-merge-msg.c4
-rw-r--r--fuzz-commit-graph.c5
-rwxr-xr-xgenerate-cmdlist.sh2
-rwxr-xr-xgit-add--interactive.perl98
-rwxr-xr-xgit-bisect.sh149
-rw-r--r--git-compat-util.h12
-rwxr-xr-xgit-cvsexportcommit.perl16
-rwxr-xr-xgit-gui/git-gui.sh103
-rw-r--r--git-gui/lib/blame.tcl1
-rw-r--r--git-gui/lib/themed.tcl38
-rwxr-xr-xgit-p4.py6
-rw-r--r--git-rebase--preserve-merges.sh10
-rwxr-xr-xgit-submodule.sh192
-rwxr-xr-xgit-svn.perl2
-rw-r--r--git.c24
-rwxr-xr-xgitk-git/gitk10654
-rw-r--r--hashmap.h3
-rw-r--r--help.c4
-rw-r--r--help.h1
-rw-r--r--ident.c72
-rw-r--r--interdiff.c28
-rw-r--r--interdiff.h8
-rw-r--r--line-log.c4
-rw-r--r--list-objects-filter-options.c10
-rw-r--r--log-tree.c27
-rw-r--r--mem-pool.c69
-rw-r--r--mem-pool.h14
-rw-r--r--merge.c3
-rw-r--r--mergetools/meld85
-rw-r--r--midx.c70
-rw-r--r--negotiator/noop.c44
-rw-r--r--negotiator/noop.h8
-rw-r--r--object.c6
-rw-r--r--object.h5
-rw-r--r--oidset.c9
-rw-r--r--oidset.h9
-rw-r--r--pack-bitmap-write.c3
-rw-r--r--pack-write.c16
-rw-r--r--packfile.c60
-rw-r--r--packfile.h1
-rw-r--r--parse-options-cb.c2
-rw-r--r--parse-options.c26
-rw-r--r--parse-options.h2
-rw-r--r--path.c2
-rw-r--r--path.h9
-rw-r--r--perl/FromCPAN/Error.pm2
-rw-r--r--perl/Git.pm2
-rw-r--r--perl/Git/I18N.pm2
-rw-r--r--perl/Git/IndexInfo.pm2
-rw-r--r--perl/Git/LoadCPAN.pm2
-rw-r--r--perl/Git/LoadCPAN/Error.pm2
-rw-r--r--perl/Git/LoadCPAN/Mail/Address.pm2
-rw-r--r--perl/Git/Packet.pm2
-rw-r--r--perl/Git/SVN.pm2
-rw-r--r--perl/Git/SVN/Editor.pm2
-rw-r--r--perl/Git/SVN/Fetcher.pm2
-rw-r--r--perl/Git/SVN/GlobSpec.pm2
-rw-r--r--perl/Git/SVN/Log.pm4
-rw-r--r--perl/Git/SVN/Memoize/YAML.pm2
-rw-r--r--perl/Git/SVN/Migration.pm2
-rw-r--r--perl/Git/SVN/Prompt.pm2
-rw-r--r--perl/Git/SVN/Ra.pm2
-rw-r--r--perl/Git/SVN/Utils.pm2
-rw-r--r--pkt-line.c17
-rw-r--r--po/TEAMS5
-rw-r--r--po/bg.po7784
-rw-r--r--po/ca.po7924
-rw-r--r--po/de.po7269
-rw-r--r--po/fr.po7304
-rw-r--r--po/git.pot7038
-rw-r--r--po/it.po7332
-rw-r--r--po/pt_PT.po19947
-rw-r--r--po/sv.po7272
-rw-r--r--po/tr.po8379
-rw-r--r--po/vi.po7301
-rw-r--r--po/zh_CN.po7220
-rw-r--r--po/zh_TW.po7317
-rw-r--r--pretty.c20
-rw-r--r--pretty.h3
-rw-r--r--promisor-remote.c51
-rw-r--r--promisor-remote.h2
-rw-r--r--protocol.c8
-rw-r--r--quote.c47
-rw-r--r--quote.h11
-rw-r--r--read-cache.c21
-rw-r--r--ref-filter.c275
-rw-r--r--ref-filter.h9
-rw-r--r--refs.c67
-rw-r--r--refs.h14
-rw-r--r--refs/debug.c398
-rw-r--r--refs/files-backend.c56
-rw-r--r--refs/packed-backend.c1
-rw-r--r--refs/refs-internal.h23
-rw-r--r--refspec.c62
-rw-r--r--refspec.h32
-rw-r--r--remote-curl.c23
-rw-r--r--remote-testsvn.c341
-rw-r--r--remote.c304
-rw-r--r--remote.h30
-rw-r--r--repo-settings.c5
-rw-r--r--repository.h2
-rw-r--r--revision.c56
-rw-r--r--revision.h1
-rw-r--r--send-pack.c160
-rw-r--r--sequencer.c222
-rw-r--r--sequencer.h9
-rw-r--r--sha1-name.c45
-rw-r--r--shortlog.h8
-rw-r--r--sideband.c31
-rw-r--r--sideband.h6
-rw-r--r--split-index.c6
-rw-r--r--submodule-config.c8
-rw-r--r--submodule.c46
-rw-r--r--submodule.h2
-rw-r--r--t/Makefile7
-rw-r--r--t/README52
-rw-r--r--t/chainlint.sed66
-rw-r--r--t/helper/.gitignore2
-rw-r--r--t/helper/test-advise.c4
-rw-r--r--t/helper/test-bloom.c4
-rw-r--r--t/helper/test-config.c2
-rw-r--r--t/helper/test-line-buffer.c81
-rw-r--r--t/helper/test-pkt-line.c23
-rw-r--r--t/helper/test-proc-receive.c176
-rw-r--r--t/helper/test-reach.c2
-rw-r--r--t/helper/test-read-graph.c3
-rw-r--r--t/helper/test-read-midx.c8
-rw-r--r--t/helper/test-submodule-nested-repo-config.c6
-rw-r--r--t/helper/test-svn-fe.c52
-rw-r--r--t/helper/test-tool.c1
-rw-r--r--t/helper/test-tool.h1
-rw-r--r--t/lib-merge.sh13
-rw-r--r--t/lib-submodule-update.sh2
-rw-r--r--t/perf/Makefile5
-rw-r--r--t/perf/README11
-rwxr-xr-xt/perf/p1400-update-ref.sh13
-rwxr-xr-xt/perf/p3400-rebase.sh6
-rwxr-xr-xt/perf/p5302-pack-index.sh47
-rwxr-xr-xt/perf/p5303-many-packs.sh4
-rwxr-xr-xt/perf/p7519-fsmonitor.sh156
-rw-r--r--t/perf/perf-lib.sh2
-rwxr-xr-xt/t0000-basic.sh55
-rwxr-xr-xt/t0001-init.sh54
-rwxr-xr-xt/t0021-conversion.sh36
-rwxr-xr-xt/t0040-parse-options.sh2
-rwxr-xr-xt/t0070-fundamental.sh18
-rwxr-xr-xt/t0081-line-buffer.sh90
-rwxr-xr-xt/t0095-bloom.sh8
-rwxr-xr-xt/t0300-credentials.sh26
-rwxr-xr-xt/t0410-partial-clone.sh9
-rwxr-xr-xt/t1004-read-tree-m-u-wf.sh2
-rwxr-xr-xt/t1050-large.sh8
-rwxr-xr-xt/t1300-config.sh13
-rwxr-xr-xt/t1400-update-ref.sh10
-rwxr-xr-xt/t1415-worktree-refs.sh18
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh18
-rwxr-xr-xt/t2004-checkout-cache-temp.sh10
-rwxr-xr-xt/t2006-checkout-index-basic.sh11
-rwxr-xr-xt/t2016-checkout-patch.sh11
-rwxr-xr-xt/t2024-checkout-dwim.sh11
-rwxr-xr-xt/t2025-checkout-no-overlay.sh12
-rwxr-xr-xt/t2060-switch.sh5
-rwxr-xr-xt/t2071-restore-patch.sh8
-rwxr-xr-xt/t2072-restore-pathspec-file.sh19
-rwxr-xr-xt/t2200-add-update.sh3
-rwxr-xr-xt/t2402-worktree-list.sh10
-rwxr-xr-xt/t2406-worktree-repair.sh179
-rwxr-xr-xt/t3000-ls-files-others.sh24
-rwxr-xr-xt/t3200-branch.sh45
-rwxr-xr-xt/t3201-branch-contains.sh82
-rwxr-xr-xt/t3203-branch-output.sh4
-rwxr-xr-xt/t3205-branch-color.sh8
-rwxr-xr-xt/t3206-range-diff.sh12
-rwxr-xr-xt/t3404-rebase-interactive.sh19
-rwxr-xr-xt/t3406-rebase-message.sh16
-rwxr-xr-xt/t3422-rebase-incompatible-options.sh2
-rwxr-xr-xt/t3427-rebase-subtree.sh44
-rwxr-xr-xt/t3435-rebase-gpg-sign.sh56
-rwxr-xr-xt/t3436-rebase-more-options.sh180
-rwxr-xr-xt/t3500-cherry.sh23
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh20
-rwxr-xr-xt/t3701-add-interactive.sh46
-rwxr-xr-xt/t3920-crlf-messages.sh126
-rwxr-xr-xt/t4013-diff-various.sh104
-rw-r--r--t/t4013/diff.diff-tree_--root_-p_--abbrev=10_initial29
-rw-r--r--t/t4013/diff.diff-tree_--root_-p_--full-index_--abbrev=10_initial29
-rw-r--r--t/t4013/diff.diff-tree_--root_-p_--full-index_initial29
-rw-r--r--t/t4013/diff.log_-IA_-IB_-I1_-I2_-p_master99
-rwxr-xr-xt/t4014-format-patch.sh55
-rwxr-xr-xt/t4015-diff-whitespace.sh38
-rwxr-xr-xt/t4018-diff-funcname.sh1
-rw-r--r--t/t4018/bash-arithmetic-function4
-rw-r--r--t/t4018/bash-bashism-style-compact6
-rw-r--r--t/t4018/bash-bashism-style-function4
-rw-r--r--t/t4018/bash-bashism-style-whitespace4
-rw-r--r--t/t4018/bash-conditional-function4
-rw-r--r--t/t4018/bash-missing-parentheses6
-rw-r--r--t/t4018/bash-mixed-style-compact4
-rw-r--r--t/t4018/bash-mixed-style-function4
-rw-r--r--t/t4018/bash-nested-functions6
-rw-r--r--t/t4018/bash-other-characters4
-rw-r--r--t/t4018/bash-posix-style-compact4
-rw-r--r--t/t4018/bash-posix-style-function4
-rw-r--r--t/t4018/bash-posix-style-whitespace4
-rw-r--r--t/t4018/bash-subshell-function4
-rw-r--r--t/t4018/bash-trailing-comment4
-rw-r--r--t/t4018/css-attribute-value-selector4
-rw-r--r--t/t4018/css-block-level-@-statements10
-rw-r--r--t/t4018/css-class-selector4
-rw-r--r--t/t4018/css-id-selector4
-rw-r--r--t/t4018/css-root-selector4
-rw-r--r--t/t4018/fortran-block-data5
-rw-r--r--t/t4018/fortran-comment13
-rw-r--r--t/t4018/fortran-comment-keyword14
-rw-r--r--t/t4018/fortran-comment-legacy13
-rw-r--r--t/t4018/fortran-comment-legacy-star13
-rw-r--r--t/t4018/fortran-external-function9
-rw-r--r--t/t4018/fortran-external-subroutine5
-rw-r--r--t/t4018/fortran-module5
-rw-r--r--t/t4018/fortran-module-procedure13
-rw-r--r--t/t4018/fortran-program5
-rw-r--r--t/t4018/php-abstract-method7
-rw-r--r--t/t4018/php-final-method7
-rw-r--r--t/t4018/rust-macro-rules6
-rwxr-xr-xt/t4064-diff-oidfind.sh55
-rwxr-xr-xt/t4067-diff-partial-clone.sh8
-rwxr-xr-xt/t4068-diff-symmetric-merge-base.sh193
-rwxr-xr-xt/t4068-diff-symmetric.sh91
-rwxr-xr-xt/t4114-apply-typechange.sh7
-rwxr-xr-xt/t4127-apply-same-fn.sh9
-rwxr-xr-xt/t4150-am.sh8
-rwxr-xr-xt/t4201-shortlog.sh141
-rwxr-xr-xt/t4202-log.sh10
-rwxr-xr-xt/t4211-line-log.sh22
-rwxr-xr-xt/t4216-log-bloom.sh251
-rwxr-xr-xt/t5000-tar-tree.sh29
-rwxr-xr-xt/t5003-archive-zip.sh28
-rwxr-xr-xt/t5300-pack-object.sh2
-rwxr-xr-xt/t5302-pack-index.sh7
-rwxr-xr-xt/t5315-pack-objects-compression.sh8
-rwxr-xr-xt/t5318-commit-graph.sh38
-rwxr-xr-xt/t5319-multi-pack-index.sh105
-rwxr-xr-xt/t5324-split-commit-graph.sh31
-rwxr-xr-xt/t5400-send-pack.sh153
-rwxr-xr-xt/t5402-post-merge-hook.sh16
-rwxr-xr-xt/t5411-proc-receive-hook.sh120
-rw-r--r--t/t5411/common-functions.sh56
-rw-r--r--t/t5411/once-0010-report-status-v1.sh94
-rw-r--r--t/t5411/test-0000-standard-git-push.sh143
-rw-r--r--t/t5411/test-0001-standard-git-push--porcelain.sh147
-rw-r--r--t/t5411/test-0002-pre-receive-declined.sh33
-rw-r--r--t/t5411/test-0003-pre-receive-declined--porcelain.sh34
-rw-r--r--t/t5411/test-0010-proc-receive-settings.sh7
-rw-r--r--t/t5411/test-0011-no-hook-error.sh64
-rw-r--r--t/t5411/test-0012-no-hook-error--porcelain.sh66
-rw-r--r--t/t5411/test-0013-bad-protocol.sh217
-rw-r--r--t/t5411/test-0014-bad-protocol--porcelain.sh160
-rw-r--r--t/t5411/test-0020-report-ng.sh67
-rw-r--r--t/t5411/test-0021-report-ng--porcelain.sh69
-rw-r--r--t/t5411/test-0022-report-unexpect-ref.sh45
-rw-r--r--t/t5411/test-0023-report-unexpect-ref--porcelain.sh46
-rw-r--r--t/t5411/test-0024-report-unknown-ref.sh34
-rw-r--r--t/t5411/test-0025-report-unknown-ref--porcelain.sh35
-rw-r--r--t/t5411/test-0026-push-options.sh79
-rw-r--r--t/t5411/test-0027-push-options--porcelain.sh82
-rw-r--r--t/t5411/test-0030-report-ok.sh35
-rw-r--r--t/t5411/test-0031-report-ok--porcelain.sh36
-rw-r--r--t/t5411/test-0032-report-with-options.sh256
-rw-r--r--t/t5411/test-0033-report-with-options--porcelain.sh265
-rw-r--r--t/t5411/test-0034-report-ft.sh44
-rw-r--r--t/t5411/test-0035-report-ft--porcelain.sh45
-rw-r--r--t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh227
-rw-r--r--t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh172
-rw-r--r--t/t5411/test-0038-report-mixed-refs.sh89
-rw-r--r--t/t5411/test-0039-report-mixed-refs--porcelain.sh91
-rw-r--r--t/t5411/test-0040-process-all-refs.sh113
-rw-r--r--t/t5411/test-0041-process-all-refs--porcelain.sh114
-rw-r--r--t/t5411/test-0050-proc-receive-refs-with-modifiers.sh135
-rwxr-xr-xt/t5505-remote.sh59
-rwxr-xr-xt/t5510-fetch.sh26
-rwxr-xr-xt/t5515-fetch-merge-logic.sh27
-rw-r--r--t/t5515/fetch.br-branches-default4
-rw-r--r--t/t5515/fetch.br-branches-default-merge4
-rw-r--r--t/t5515/fetch.br-branches-default-merge_branches-default4
-rw-r--r--t/t5515/fetch.br-branches-default-octopus4
-rw-r--r--t/t5515/fetch.br-branches-default-octopus_branches-default4
-rw-r--r--t/t5515/fetch.br-branches-default_branches-default4
-rw-r--r--t/t5515/fetch.br-branches-one2
-rw-r--r--t/t5515/fetch.br-branches-one-merge2
-rw-r--r--t/t5515/fetch.br-branches-one-merge_branches-one2
-rw-r--r--t/t5515/fetch.br-branches-one-octopus2
-rw-r--r--t/t5515/fetch.br-branches-one-octopus_branches-one2
-rw-r--r--t/t5515/fetch.br-branches-one_branches-one2
-rw-r--r--t/t5515/fetch.br-config-explicit4
-rw-r--r--t/t5515/fetch.br-config-explicit-merge4
-rw-r--r--t/t5515/fetch.br-config-explicit-merge_config-explicit4
-rw-r--r--t/t5515/fetch.br-config-explicit-octopus4
-rw-r--r--t/t5515/fetch.br-config-explicit-octopus_config-explicit4
-rw-r--r--t/t5515/fetch.br-config-explicit_config-explicit4
-rw-r--r--t/t5515/fetch.br-config-glob4
-rw-r--r--t/t5515/fetch.br-config-glob-merge4
-rw-r--r--t/t5515/fetch.br-config-glob-merge_config-glob4
-rw-r--r--t/t5515/fetch.br-config-glob-octopus4
-rw-r--r--t/t5515/fetch.br-config-glob-octopus_config-glob4
-rw-r--r--t/t5515/fetch.br-config-glob_config-glob4
-rw-r--r--t/t5515/fetch.br-remote-explicit4
-rw-r--r--t/t5515/fetch.br-remote-explicit-merge4
-rw-r--r--t/t5515/fetch.br-remote-explicit-merge_remote-explicit4
-rw-r--r--t/t5515/fetch.br-remote-explicit-octopus4
-rw-r--r--t/t5515/fetch.br-remote-explicit-octopus_remote-explicit4
-rw-r--r--t/t5515/fetch.br-remote-explicit_remote-explicit4
-rw-r--r--t/t5515/fetch.br-remote-glob4
-rw-r--r--t/t5515/fetch.br-remote-glob-merge4
-rw-r--r--t/t5515/fetch.br-remote-glob-merge_remote-glob4
-rw-r--r--t/t5515/fetch.br-remote-glob-octopus4
-rw-r--r--t/t5515/fetch.br-remote-glob-octopus_remote-glob4
-rw-r--r--t/t5515/fetch.br-remote-glob_remote-glob4
-rw-r--r--t/t5515/fetch.br-unconfig4
-rw-r--r--t/t5515/fetch.br-unconfig_--tags_.._.git2
-rw-r--r--t/t5515/fetch.br-unconfig_.._.git_one_tag_tag-one_tag_tag-three-file2
-rw-r--r--t/t5515/fetch.br-unconfig_.._.git_tag_tag-one-tree_tag_tag-three-file2
-rw-r--r--t/t5515/fetch.br-unconfig_.._.git_tag_tag-one_tag_tag-three2
-rw-r--r--t/t5515/fetch.br-unconfig_branches-default4
-rw-r--r--t/t5515/fetch.br-unconfig_branches-one2
-rw-r--r--t/t5515/fetch.br-unconfig_config-explicit4
-rw-r--r--t/t5515/fetch.br-unconfig_config-glob4
-rw-r--r--t/t5515/fetch.br-unconfig_remote-explicit4
-rw-r--r--t/t5515/fetch.br-unconfig_remote-glob4
-rw-r--r--t/t5515/fetch.main (renamed from t/t5515/fetch.master)6
-rw-r--r--t/t5515/fetch.main_--tags_.._.git (renamed from t/t5515/fetch.master_--tags_.._.git)4
-rw-r--r--t/t5515/fetch.main_.._.git (renamed from t/t5515/fetch.master_.._.git)2
-rw-r--r--t/t5515/fetch.main_.._.git_one (renamed from t/t5515/fetch.master_.._.git_one)2
-rw-r--r--t/t5515/fetch.main_.._.git_one_tag_tag-one_tag_tag-three-file (renamed from t/t5515/fetch.master_.._.git_one_tag_tag-one_tag_tag-three-file)4
-rw-r--r--t/t5515/fetch.main_.._.git_one_two (renamed from t/t5515/fetch.master_.._.git_one_two)2
-rw-r--r--t/t5515/fetch.main_.._.git_tag_tag-one-tree_tag_tag-three-file (renamed from t/t5515/fetch.master_.._.git_tag_tag-one-tree_tag_tag-three-file)4
-rw-r--r--t/t5515/fetch.main_.._.git_tag_tag-one_tag_tag-three (renamed from t/t5515/fetch.master_.._.git_tag_tag-one_tag_tag-three)4
-rw-r--r--t/t5515/fetch.main_branches-default (renamed from t/t5515/fetch.master_branches-default)6
-rw-r--r--t/t5515/fetch.main_branches-one (renamed from t/t5515/fetch.master_branches-one)4
-rw-r--r--t/t5515/fetch.main_config-explicit (renamed from t/t5515/fetch.master_config-explicit)6
-rw-r--r--t/t5515/fetch.main_config-glob (renamed from t/t5515/fetch.master_config-glob)6
-rw-r--r--t/t5515/fetch.main_remote-explicit (renamed from t/t5515/fetch.master_remote-explicit)6
-rw-r--r--t/t5515/fetch.main_remote-glob11
-rw-r--r--t/t5515/fetch.master_remote-glob11
-rw-r--r--t/t5515/refs.br-branches-default6
-rw-r--r--t/t5515/refs.br-branches-default-merge6
-rw-r--r--t/t5515/refs.br-branches-default-merge_branches-default6
-rw-r--r--t/t5515/refs.br-branches-default-octopus6
-rw-r--r--t/t5515/refs.br-branches-default-octopus_branches-default6
-rw-r--r--t/t5515/refs.br-branches-default_branches-default6
-rw-r--r--t/t5515/refs.br-branches-one4
-rw-r--r--t/t5515/refs.br-branches-one-merge4
-rw-r--r--t/t5515/refs.br-branches-one-merge_branches-one4
-rw-r--r--t/t5515/refs.br-branches-one-octopus4
-rw-r--r--t/t5515/refs.br-branches-one-octopus_branches-one4
-rw-r--r--t/t5515/refs.br-branches-one_branches-one4
-rw-r--r--t/t5515/refs.br-config-explicit6
-rw-r--r--t/t5515/refs.br-config-explicit-merge6
-rw-r--r--t/t5515/refs.br-config-explicit-merge_config-explicit6
-rw-r--r--t/t5515/refs.br-config-explicit-octopus6
-rw-r--r--t/t5515/refs.br-config-explicit-octopus_config-explicit6
-rw-r--r--t/t5515/refs.br-config-explicit_config-explicit6
-rw-r--r--t/t5515/refs.br-config-glob6
-rw-r--r--t/t5515/refs.br-config-glob-merge6
-rw-r--r--t/t5515/refs.br-config-glob-merge_config-glob6
-rw-r--r--t/t5515/refs.br-config-glob-octopus6
-rw-r--r--t/t5515/refs.br-config-glob-octopus_config-glob6
-rw-r--r--t/t5515/refs.br-config-glob_config-glob6
-rw-r--r--t/t5515/refs.br-remote-explicit6
-rw-r--r--t/t5515/refs.br-remote-explicit-merge6
-rw-r--r--t/t5515/refs.br-remote-explicit-merge_remote-explicit6
-rw-r--r--t/t5515/refs.br-remote-explicit-octopus6
-rw-r--r--t/t5515/refs.br-remote-explicit-octopus_remote-explicit6
-rw-r--r--t/t5515/refs.br-remote-explicit_remote-explicit6
-rw-r--r--t/t5515/refs.br-remote-glob6
-rw-r--r--t/t5515/refs.br-remote-glob-merge6
-rw-r--r--t/t5515/refs.br-remote-glob-merge_remote-glob6
-rw-r--r--t/t5515/refs.br-remote-glob-octopus6
-rw-r--r--t/t5515/refs.br-remote-glob-octopus_remote-glob6
-rw-r--r--t/t5515/refs.br-remote-glob_remote-glob6
-rw-r--r--t/t5515/refs.br-unconfig4
-rw-r--r--t/t5515/refs.br-unconfig_--tags_.._.git4
-rw-r--r--t/t5515/refs.br-unconfig_.._.git2
-rw-r--r--t/t5515/refs.br-unconfig_.._.git_one2
-rw-r--r--t/t5515/refs.br-unconfig_.._.git_one_tag_tag-one_tag_tag-three-file4
-rw-r--r--t/t5515/refs.br-unconfig_.._.git_one_two2
-rw-r--r--t/t5515/refs.br-unconfig_.._.git_tag_tag-one-tree_tag_tag-three-file4
-rw-r--r--t/t5515/refs.br-unconfig_.._.git_tag_tag-one_tag_tag-three4
-rw-r--r--t/t5515/refs.br-unconfig_branches-default6
-rw-r--r--t/t5515/refs.br-unconfig_branches-one4
-rw-r--r--t/t5515/refs.br-unconfig_config-explicit6
-rw-r--r--t/t5515/refs.br-unconfig_config-glob6
-rw-r--r--t/t5515/refs.br-unconfig_remote-explicit6
-rw-r--r--t/t5515/refs.br-unconfig_remote-glob6
-rw-r--r--t/t5515/refs.main (renamed from t/t5515/refs.master_.._.git_one_tag_tag-one_tag_tag-three-file)4
-rw-r--r--t/t5515/refs.main_--tags_.._.git (renamed from t/t5515/refs.master_.._.git_tag_tag-one-tree_tag_tag-three-file)4
-rw-r--r--t/t5515/refs.main_.._.git (renamed from t/t5515/refs.master_.._.git_one_two)2
-rw-r--r--t/t5515/refs.main_.._.git_one (renamed from t/t5515/refs.master_.._.git_one)2
-rw-r--r--t/t5515/refs.main_.._.git_one_tag_tag-one_tag_tag-three-file (renamed from t/t5515/refs.master)4
-rw-r--r--t/t5515/refs.main_.._.git_one_two (renamed from t/t5515/refs.master_.._.git)2
-rw-r--r--t/t5515/refs.main_.._.git_tag_tag-one-tree_tag_tag-three-file (renamed from t/t5515/refs.master_--tags_.._.git)4
-rw-r--r--t/t5515/refs.main_.._.git_tag_tag-one_tag_tag-three11
-rw-r--r--t/t5515/refs.main_branches-default (renamed from t/t5515/refs.master_branches-default)6
-rw-r--r--t/t5515/refs.main_branches-one (renamed from t/t5515/refs.master_branches-one)4
-rw-r--r--t/t5515/refs.main_config-explicit (renamed from t/t5515/refs.master_config-explicit)6
-rw-r--r--t/t5515/refs.main_config-glob (renamed from t/t5515/refs.master_config-glob)6
-rw-r--r--t/t5515/refs.main_remote-explicit (renamed from t/t5515/refs.master_remote-explicit)6
-rw-r--r--t/t5515/refs.main_remote-glob (renamed from t/t5515/refs.master_remote-glob)6
-rw-r--r--t/t5515/refs.master_.._.git_tag_tag-one_tag_tag-three11
-rwxr-xr-xt/t5516-fetch-push.sh2
-rwxr-xr-xt/t5523-push-upstream.sh20
-rwxr-xr-xt/t5526-fetch-submodules.sh70
-rwxr-xr-xt/t5530-upload-pack-error.sh17
-rwxr-xr-xt/t5533-push-cas.sh137
-rwxr-xr-xt/t5534-push-signed.sh22
-rwxr-xr-xt/t5554-noop-fetch-negotiator.sh22
-rwxr-xr-xt/t5570-git-daemon.sh12
-rwxr-xr-xt/t5582-fetch-negative-refspec.sh189
-rwxr-xr-xt/t5601-clone.sh19
-rwxr-xr-xt/t5606-clone-options.sh71
-rwxr-xr-xt/t5616-partial-clone.sh36
-rwxr-xr-xt/t5702-protocol-v2.sh53
-rwxr-xr-xt/t5703-upload-pack-ref-in-want.sh6
-rwxr-xr-xt/t6006-rev-list-format.sh2
-rwxr-xr-xt/t6012-rev-list-simplify.sh10
-rwxr-xr-xt/t6018-rev-list-glob.sh11
-rwxr-xr-xt/t6030-bisect-porcelain.sh7
-rwxr-xr-xt/t6040-tracking-info.sh20
-rwxr-xr-xt/t6200-fmt-merge-msg.sh2
-rwxr-xr-xt/t6300-for-each-ref.sh91
-rwxr-xr-xt/t6302-for-each-ref-filter.sh28
-rwxr-xr-xt/t6400-merge-df.sh (renamed from t/t6020-merge-df.sh)22
-rwxr-xr-xt/t6401-merge-criss-cross.sh (renamed from t/t6021-merge-criss-cross.sh)0
-rwxr-xr-xt/t6402-merge-rename.sh (renamed from t/t6022-merge-rename.sh)122
-rwxr-xr-xt/t6403-merge-file.sh (renamed from t/t6023-merge-file.sh)0
-rwxr-xr-xt/t6404-recursive-merge.sh (renamed from t/t6024-recursive-merge.sh)14
-rwxr-xr-xt/t6405-merge-symlinks.sh (renamed from t/t6025-merge-symlinks.sh)0
-rwxr-xr-xt/t6406-merge-attr.sh (renamed from t/t6026-merge-attr.sh)0
-rwxr-xr-xt/t6407-merge-binary.sh (renamed from t/t6027-merge-binary.sh)0
-rwxr-xr-xt/t6408-merge-up-to-date.sh (renamed from t/t6028-merge-up-to-date.sh)0
-rwxr-xr-xt/t6409-merge-subtree.sh (renamed from t/t6029-merge-subtree.sh)26
-rwxr-xr-xt/t6411-merge-filemode.sh (renamed from t/t6031-merge-filemode.sh)0
-rwxr-xr-xt/t6412-merge-large-rename.sh (renamed from t/t6032-merge-large-rename.sh)0
-rwxr-xr-xt/t6413-merge-crlf.sh (renamed from t/t6033-merge-crlf.sh)0
-rwxr-xr-xt/t6414-merge-rename-nocruft.sh (renamed from t/t6034-merge-rename-nocruft.sh)0
-rwxr-xr-xt/t6415-merge-dir-to-symlink.sh (renamed from t/t6035-merge-dir-to-symlink.sh)0
-rwxr-xr-xt/t6416-recursive-corner-cases.sh (renamed from t/t6036-recursive-corner-cases.sh)204
-rwxr-xr-xt/t6417-merge-ours-theirs.sh (renamed from t/t6037-merge-ours-theirs.sh)0
-rwxr-xr-xt/t6418-merge-text-auto.sh (renamed from t/t6038-merge-text-auto.sh)3
-rwxr-xr-xt/t6419-merge-ignorecase.sh (renamed from t/t6039-merge-ignorecase.sh)0
-rwxr-xr-xt/t6422-merge-rename-corner-cases.sh (renamed from t/t6042-merge-rename-corner-cases.sh)105
-rwxr-xr-xt/t6423-merge-rename-directories.sh (renamed from t/t6043-merge-rename-directories.sh)1269
-rwxr-xr-xt/t6424-merge-unrelated-index-changes.sh (renamed from t/t6044-merge-unrelated-index-changes.sh)0
-rwxr-xr-xt/t6425-merge-rename-delete.sh (renamed from t/t6045-merge-rename-delete.sh)3
-rwxr-xr-xt/t6426-merge-skip-unneeded-updates.sh (renamed from t/t6046-merge-skip-unneeded-updates.sh)5
-rwxr-xr-xt/t6427-diff3-conflict-markers.sh (renamed from t/t6047-diff3-conflict-markers.sh)0
-rwxr-xr-xt/t6430-merge-recursive.sh (renamed from t/t3030-merge-recursive.sh)7
-rwxr-xr-xt/t6431-merge-criscross.sh (renamed from t/t3031-merge-criscross.sh)0
-rwxr-xr-xt/t6432-merge-recursive-space-options.sh (renamed from t/t3032-merge-recursive-space-options.sh)0
-rwxr-xr-xt/t6433-merge-toplevel.sh (renamed from t/t3033-merge-toplevel.sh)0
-rwxr-xr-xt/t6434-merge-recursive-rename-options.sh (renamed from t/t3034-merge-recursive-rename-options.sh)0
-rwxr-xr-xt/t6435-merge-sparse.sh (renamed from t/t3035-merge-sparse.sh)0
-rwxr-xr-xt/t6436-merge-overwrite.sh (renamed from t/t7607-merge-overwrite.sh)18
-rwxr-xr-xt/t6437-submodule-merge.sh (renamed from t/t7405-submodule-merge.sh)25
-rwxr-xr-xt/t6438-submodule-directory-file-conflicts.sh (renamed from t/t7613-merge-submodule.sh)0
-rwxr-xr-xt/t6439-merge-co-error-msgs.sh (renamed from t/t7609-merge-co-error-msgs.sh)0
-rwxr-xr-xt/t6600-test-reach.sh30
-rwxr-xr-xt/t7004-tag.sh4
-rwxr-xr-xt/t7006-pager.sh84
-rwxr-xr-xt/t7101-reset-empty-subdirs.sh66
-rwxr-xr-xt/t7102-reset.sh307
-rwxr-xr-xt/t7201-co.sh102
-rwxr-xr-xt/t7401-submodule-summary.sh155
-rwxr-xr-xt/t7406-submodule-update.sh12
-rwxr-xr-xt/t7421-submodule-summary-add.sh69
-rwxr-xr-xt/t7508-status.sh39
-rwxr-xr-xt/t7518-ident-corner-cases.sh15
-rwxr-xr-xt/t7601-merge-pull-config.sh21
-rwxr-xr-xt/t7602-merge-octopus-many.sh6
-rwxr-xr-xt/t7610-mergetool.sh32
-rwxr-xr-xt/t7900-maintenance.sh37
-rwxr-xr-xt/t8003-blame-corner-cases.sh28
-rwxr-xr-xt/t8013-blame-ignore-revs.sh61
-rwxr-xr-xt/t9010-svn-fe.sh1105
-rwxr-xr-xt/t9011-svn-da.sh248
-rwxr-xr-xt/t9020-remote-svn.sh95
-rwxr-xr-xt/t9303-fast-import-compression.sh10
-rwxr-xr-xt/t9304-fast-import-marks.sh51
-rwxr-xr-xt/t9603-cvsimport-patchsets.sh24
-rwxr-xr-xt/t9801-git-p4-branch.sh12
-rwxr-xr-xt/t9832-unshelve.sh8
-rwxr-xr-xt/t9902-completion.sh70
-rw-r--r--t/test-lib-functions.sh22
-rw-r--r--t/test-lib.sh35
-rwxr-xr-xt/test-terminal.perl32
-rwxr-xr-xtemplates/hooks--pre-push.sample18
-rwxr-xr-xtemplates/hooks--push-to-checkout.sample78
-rwxr-xr-xtemplates/hooks--update.sample2
-rw-r--r--trailer.c40
-rw-r--r--trailer.h45
-rw-r--r--transport-helper.c142
-rw-r--r--transport.c169
-rw-r--r--transport.h24
-rw-r--r--tree-diff.c5
-rw-r--r--upload-pack.c36
-rw-r--r--usage.c18
-rw-r--r--userdiff.c33
-rw-r--r--vcs-svn/LICENSE32
-rw-r--r--vcs-svn/fast_export.c365
-rw-r--r--vcs-svn/line_buffer.c126
-rw-r--r--vcs-svn/line_buffer.txt77
-rw-r--r--vcs-svn/sliding_window.c79
-rw-r--r--vcs-svn/svndiff.c309
-rw-r--r--vcs-svn/svndump.c540
-rw-r--r--worktree.c181
-rw-r--r--worktree.h30
-rw-r--r--wrapper.c7
-rw-r--r--wt-status.c125
-rw-r--r--wt-status.h7
-rw-r--r--xdiff/xdiff.h4
-rw-r--r--xdiff/xdiffi.c47
-rw-r--r--xdiff/xhistogram.c2
-rw-r--r--xdiff/xpatience.c2
744 files changed, 82189 insertions, 58585 deletions
diff --git a/.github/workflows/check-whitespace.yml b/.github/workflows/check-whitespace.yml
new file mode 100644
index 0000000..f148305
--- /dev/null
+++ b/.github/workflows/check-whitespace.yml
@@ -0,0 +1,71 @@
+name: check-whitespace
+
+# Get the repo with the commits(+1) in the series.
+# Process `git log --check` output to extract just the check errors.
+# Add a comment to the pull request with the check errors.
+
+on:
+ pull_request:
+ types: [opened, synchronize]
+
+jobs:
+ check-whitespace:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Set commit count
+ shell: bash
+ run: echo "COMMIT_DEPTH=$((1+$COMMITS))" >>$GITHUB_ENV
+ env:
+ COMMITS: ${{ github.event.pull_request.commits }}
+
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: ${{ env.COMMIT_DEPTH }}
+
+ - name: git log --check
+ id: check_out
+ run: |
+ log=
+ commit=
+ while read dash etc
+ do
+ case "${dash}" in
+ "---")
+ commit="${etc}"
+ ;;
+ "")
+ ;;
+ *)
+ if test -n "${commit}"
+ then
+ log="${log}\n${commit}"
+ echo ""
+ echo "--- ${commit}"
+ fi
+ commit=
+ log="${log}\n${dash} ${etc}"
+ echo "${dash} ${etc}"
+ ;;
+ esac
+ done <<< $(git log --check --pretty=format:"---% h% s" -${{github.event.pull_request.commits}})
+
+ if test -n "${log}"
+ then
+ echo "::set-output name=checkout::"${log}""
+ exit 2
+ fi
+
+ - name: Add Check Output as Comment
+ uses: actions/github-script@v3
+ id: add-comment
+ env:
+ log: ${{ steps.check_out.outputs.checkout }}
+ with:
+ script: |
+ await github.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: `Whitespace errors found in workflow ${{ github.workflow }}:\n\n\`\`\`\n${process.env.log.replace(/\\n/g, "\n")}\n\`\`\``
+ })
+ if: ${{ failure() }}
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 44e0fe5..6c3453a 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -7,34 +7,74 @@ env:
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"
+ runs-on: ubuntu-latest
+ outputs:
+ enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }}
+ steps:
+ - name: try to clone ci-config branch
+ 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 || : ignore
+ - 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"
+ - name: skip if the commit or tree was already tested
+ id: skip-if-redundant
+ uses: actions/github-script@v3
+ if: steps.check-ref.outputs.enabled == 'yes'
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ try {
+ // Figure out workflow ID, commit and tree
+ const { data: run } = await github.actions.getWorkflowRun({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ run_id: context.runId,
+ });
+ const workflow_id = run.workflow_id;
+ const head_sha = run.head_sha;
+ const tree_id = run.head_commit.tree_id;
+
+ // See whether there is a successful run for that commit or tree
+ const { data: runs } = await github.actions.listWorkflowRuns({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ per_page: 500,
+ status: 'success',
+ workflow_id,
+ });
+ for (const run of runs.workflow_runs) {
+ if (head_sha === run.head_sha) {
+ core.warning(`Successful run for the commit ${head_sha}: ${run.html_url}`);
+ core.setOutput('enabled', ' but skip');
+ break;
+ }
+ if (run.head_commit && tree_id === run.head_commit.tree_id) {
+ core.warning(`Successful run for the tree ${tree_id}: ${run.html_url}`);
+ core.setOutput('enabled', ' but skip');
+ break;
+ }
+ }
+ } catch (e) {
+ core.warning(e);
+ }
windows-build:
needs: ci-config
@@ -155,7 +195,7 @@ jobs:
Expand-Archive compat.zip -DestinationPath . -Force
Remove-Item compat.zip
- name: add msbuild to PATH
- uses: microsoft/setup-msbuild@v1.0.0
+ uses: microsoft/setup-msbuild@v1
- name: copy dlls to root
shell: powershell
run: |
diff --git a/.gitignore b/.gitignore
index 5eb2a2b..f85d02c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -136,7 +136,6 @@
/git-remote-fd
/git-remote-ext
/git-remote-testpy
-/git-remote-testsvn
/git-repack
/git-replace
/git-request-pull
@@ -199,6 +198,7 @@
/git.spec
*.exe
*.[aos]
+*.o.json
*.py[co]
.depend/
*.gcda
@@ -220,6 +220,7 @@
/tags
/TAGS
/cscope*
+/compile_commands.json
*.hcc
*.obj
*.lib
@@ -242,3 +243,4 @@ Release/
/git.VC.VC.opendb
/git.VC.db
*.dSYM
+/contrib/buildsystems/out
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index d85c9b5..60eed5e 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -249,7 +249,7 @@ component you're working on, followed by a blank line (always required) and then
the body of your commit message, which should provide the bulk of the context.
Remember to be explicit and provide the "Why" of your change, especially if it
couldn't easily be understood from your diff. When editing your commit message,
-don't remove the Signed-off-by line which was added by `-s` above.
+don't remove the `Signed-off-by` trailer which was added by `-s` above.
----
psuh: add a built-in by popular demand
@@ -319,14 +319,14 @@ function body:
...
git_config(git_default_config, NULL);
- if (git_config_get_string_const("user.name", &cfg_name) > 0)
+ if (git_config_get_string_tmp("user.name", &cfg_name) > 0)
printf(_("No name is found in config\n"));
else
printf(_("Your name: %s\n"), cfg_name);
----
`git_config()` will grab the configuration from config files known to Git and
-apply standard precedence rules. `git_config_get_string_const()` will look up
+apply standard precedence rules. `git_config_get_string_tmp()` will look up
a specific key ("user.name") and give you the value. There are a number of
single-key lookup functions like this one; you can see them all (and more info
about how to use `git_config()`) in `Documentation/technical/api-config.txt`.
@@ -507,6 +507,9 @@ documentation is consistent with other Git and UNIX manpages; this makes life
easier for your user, who can skip to the section they know contains the
information they need.
+NOTE: Before trying to build the docs, make sure you have the package `asciidoc`
+installed.
+
Now that you've written your manpage, you'll need to build it explicitly. We
convert your AsciiDoc to troff which is man-readable like so:
@@ -522,8 +525,6 @@ $ make -C Documentation/ git-psuh.1
$ man Documentation/git-psuh.1
----
-NOTE: You may need to install the package `asciidoc` to get this to work.
-
While this isn't as satisfying as running through `git help`, you can at least
check that your help page looks right.
diff --git a/Documentation/RelNotes/2.29.0.txt b/Documentation/RelNotes/2.29.0.txt
index 783cba3..06ba2f8 100644
--- a/Documentation/RelNotes/2.29.0.txt
+++ b/Documentation/RelNotes/2.29.0.txt
@@ -33,6 +33,95 @@ UI, Workflows & Features
been made to imply "-m". Use "--no-diff-merges" to restore the
previous behaviour to omit patches for merge commits.
+ * The commit labels used to explain each side of conflicted hunks
+ placed by the sequencer machinery have been made more readable by
+ humans.
+
+ * The "--batch-size" option of "git multi-pack-index repack" command
+ is now used to specify that very small packfiles are collected into
+ one until the total size roughly exceeds it.
+
+ * The recent addition of SHA-256 support is marked as experimental in
+ the documentation.
+
+ * "git fetch" learned --no-write-fetch-head option to avoid writing
+ the FETCH_HEAD file.
+
+ * Command line completion (in contrib/) usually omits redundant,
+ deprecated and/or dangerous options from its output; it learned to
+ optionally include all of them.
+
+ * The output from the "diff" family of the commands had abbreviated
+ object names of blobs involved in the patch, but its length was not
+ affected by the --abbrev option. Now it is.
+
+ * "git worktree" gained a "repair" subcommand to help users recover
+ after moving the worktrees or repository manually without telling
+ Git. Also, "git init --separate-git-dir" no longer corrupts
+ administrative data related to linked worktrees.
+
+ * The "--format=" option to the "for-each-ref" command and friends
+ learned a few more tricks, e.g. the ":short" suffix that applies to
+ "objectname" now also can be used for "parent", "tree", etc.
+
+ * "git worktree add" learns that the "-d" is a synonym to "--detach"
+ option to create a new worktree without being on a branch.
+
+ * "format-patch --range-diff=<prev> <origin>..HEAD" has been taught
+ not to ignore <origin> when <prev> is a single version.
+
+ * "add -p" now allows editing paths that were only added in intent.
+
+ * The 'meld' backend of the "git mergetool" learned to give the
+ underlying 'meld' the '--auto-merge' option, which would help
+ reduce the amount of text that requires manual merging.
+
+ * "git for-each-ref" and friends that list refs used to allow only
+ one --merged or --no-merged to filter them; they learned to take
+ combination of both kind of filtering.
+
+ * "git maintenance", a "git gc"'s big brother, has been introduced to
+ take care of more repository maintenance tasks, not limited to the
+ object database cleaning.
+
+ * "git receive-pack" that accepts requests by "git push" learned to
+ outsource most of the ref updates to the new "proc-receive" hook.
+
+ * "git push" that wants to be atomic and wants to send push
+ certificate learned not to prepare and sign the push certificate
+ when it fails the local check (hence due to atomicity it is known
+ that no certificate is needed).
+
+ * "git commit-graph write" learned to limit the number of bloom
+ filters that are computed from scratch with the --max-new-filters
+ option.
+
+ * The transport protocol v2 has become the default again.
+
+ * The installation procedure learned to optionally omit "git-foo"
+ executable files for each 'foo' built-in subcommand, which are only
+ required by old timers that still rely on the age old promise that
+ prepending "git --exec-path" output to PATH early in their script
+ will keep the "git-foo" calls they wrote working.
+
+ * The command line completion (in contrib/) learned that "git restore
+ -s <TAB>" is often followed by a refname.
+
+ * "git shortlog" has been taught to group commits by the contents of
+ the trailer lines, like "Reviewed-by:", "Coauthored-by:", etc.
+
+ * "git archive" learns the "--add-file" option to include untracked
+ files into a snapshot from a tree-ish.
+
+ * "git fetch" and "git push" support negative refspecs.
+
+ * "git format-patch" learns to take "whenAble" as a possible value
+ for the format.useAutoBase configuration variable to become no-op
+ when the automatically computed base does not make sense.
+
+ * Credential helpers are now allowed to terminate lines with CRLF
+ line ending, as well as LF line ending.
+
Performance, Internal Implementation, Development Support etc.
@@ -66,7 +155,9 @@ Performance, Internal Implementation, Development Support etc.
to a certain degree. It has been renamed to "strvec" to reduce the
barrier to adoption.
- * The final leg of SHA-256 transition.
+ * The final leg of SHA-256 transition plus doc updates. Note that
+ there is no interoperability between SHA-1 and SHA-256
+ repositories yet.
* CMake support to build with MSVC for Windows bypassing the Makefile.
@@ -82,10 +173,64 @@ Performance, Internal Implementation, Development Support etc.
* Test framework update.
(merge d572f52a64 es/test-cmp-typocatcher later to maint).
+ * Updates to "git merge" tests, in preparation for a new merge
+ strategy backend.
+
+ * midx and commit-graph files now use the byte defined in their file
+ format specification for identifying the hash function used for
+ object names.
+
+ * The FETCH_HEAD is now always read from the filesystem regardless of
+ the ref backend in use, as its format is much richer than the
+ normal refs, and written directly by "git fetch" as a plain file..
+
+ * An unused binary has been discarded, and and a bunch of commands
+ have been turned into into built-in.
+
+ * A handful of places in in-tree code still relied on being able to
+ execute the git subcommands, especially built-ins, in "git-foo"
+ form, which have been corrected.
+
+ * When a packfile is removed by "git repack", multi-pack-index gets
+ cleared; the code was taught to do so less aggressively by first
+ checking if the midx actually refers to a pack that no longer
+ exists.
+
+ * Internal API clean-up to handle two options "diff-index" and "log"
+ have, which happen to share the same short form, more sensibly.
+
+ * The "add -i/-p" machinery has been written in C but it is not used
+ by default yet. It is made default to those who are participating
+ in feature.experimental experiment.
+
+ * Allow maintainers to tweak $(TAR) invocations done while making
+ distribution tarballs.
+
+ * "git index-pack" learned to resolve deltified objects with greater
+ parallelism.
+
+ * "diff-highlight" (in contrib/) had a logic to flush its output upon
+ seeing a blank line but the way it detected a blank line was broken.
+
+ * The logic to skip testing on the tagged commit and the tag itself
+ was not quite consistent which led to failure of Windows test
+ tasks. It has been revamped to consistently skip revisions that
+ have already been tested, based on the tree object of the revision.
+
Fixes since v2.28
-----------------
+ * The "mediawiki" remote backend which lives in contrib/mw-to-git/
+ and is not built with git by default, had an RCE bug allowing a
+ malicious MediaWiki server operator to inject arbitrary commands
+ for execution by a cloning client. This has been fixed.
+
+ The bug was discovered and reported by Joern Schneeweisz of GitLab
+ to the git-security mailing list. Its practical impact due to the
+ obscurity of git-remote-mediawiki was deemed small enough to forgo
+ a dedicated security release.
+
* "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.
@@ -145,6 +290,194 @@ Fixes since v2.28
command failed to do so for such a path.
(merge 4c025c667e rp/apply-cached-with-i-t-a later to maint).
+ * "git diff [<tree-ish>] $path" for a $path that is marked with i-t-a
+ bit was not showing the mode bits from the working tree.
+ (merge cb0dd22b82 rp/ita-diff-modefix later to maint).
+
+ * Ring buffer with size 4 used for bin-hex translation resulted in a
+ wrong object name in the sequencer's todo output, which has been
+ corrected.
+ (merge 5da69c0dac ak/sequencer-fix-find-uniq-abbrev later to maint).
+
+ * When given more than one target line ranges, "git blame -La,b
+ -Lc,d" was over-eager to coalesce groups of original lines and
+ showed incorrect results, which has been corrected.
+ (merge c2ebaa27d6 jk/blame-coalesce-fix later to maint).
+
+ * The regexp to identify the function boundary for FORTRAN programs
+ has been updated.
+ (merge 75c3b6b2e8 pb/userdiff-fortran-update later to maint).
+
+ * A few end-user facing messages have been updated to be
+ hash-algorithm agnostic.
+ (merge 4279000d3e jc/object-names-are-not-sha-1 later to maint).
+
+ * "unlink" emulation on MinGW has been optimized.
+ (merge 680e0b4524 jh/mingw-unlink later to maint).
+
+ * The purpose of "git init --separate-git-dir" is to initialize a
+ new project with the repository separate from the working tree,
+ or, in the case of an existing project, to move the repository
+ (the .git/ directory) out of the working tree. It does not make
+ sense to use --separate-git-dir with a bare repository for which
+ there is no working tree, so disallow its use with bare
+ repositories.
+ (merge ccf236a23a es/init-no-separate-git-dir-in-bare later to maint).
+
+ * "ls-files -o" mishandled the top-level directory of another git
+ working tree that hangs in the current git working tree.
+ (merge ab282aa548 en/dir-nonbare-embedded later to maint).
+
+ * Fix some incorrect UNLEAK() annotations.
+ (merge 3e19816dc0 jk/unleak-fixes later to maint).
+
+ * Use more buffered I/O where we used to call many small write(2)s.
+ (merge a698d67b08 rs/more-buffered-io later to maint).
+
+ * The patch-id computation did not ignore the "incomplete last line"
+ marker like whitespaces.
+ (merge 82a62015a7 rs/patch-id-with-incomplete-line later to maint).
+
+ * Updates into a lazy/partial clone with a submodule did not work
+ well with transfer.fsckobjects set.
+
+ * The parser for "git for-each-ref --format=..." was too loose when
+ parsing the "%(trailers...)" atom, and forgot that "trailers" and
+ "trailers:<modifiers>" are the only two allowed forms, which has
+ been corrected.
+ (merge 2c22e102f8 hv/ref-filter-trailers-atom-parsing-fix later to maint).
+
+ * Long ago, we decided to use 3 threads by default when running the
+ index-pack task in parallel, which has been adjusted a bit upwards.
+ (merge fbff95b67f jk/index-pack-w-more-threads later to maint).
+
+ * "git restore/checkout --no-overlay" with wildcarded pathspec
+ mistakenly removed matching paths in subdirectories, which has been
+ corrected.
+ (merge bfda204ade rs/checkout-no-overlay-pathspec-fix later to maint).
+
+ * The description of --cached/--index options in "git apply --help"
+ has been updated.
+ (merge d064702be3 rp/apply-cached-doc later to maint).
+
+ * Feeding "$ZERO_OID" to "git log --ignore-missing --stdin", and
+ running "git log --ignore-missing $ZERO_OID" fell back to start
+ digging from HEAD; it has been corrected to become a no-op, like
+ "git log --tags=no-tag-matches-this-pattern" does.
+ (merge 04a0e98515 jk/rev-input-given-fix later to maint).
+
+ * Various callers of run_command API have been modernized.
+ (merge afbdba391e jc/run-command-use-embedded-args later to maint).
+
+ * List of options offered and accepted by "git add -i/-p" were
+ inconsistent, which have been corrected.
+ (merge ce910287e7 pw/add-p-allowed-options-fix later to maint).
+
+ * "git diff --stat -w" showed 0-line changes for paths whose changes
+ were only whitespaces, which was not intuitive. We now omit such
+ paths from the stat output.
+ (merge 1cf3d5db9b mr/diff-hide-stat-wo-textual-change later to maint).
+
+ * It was possible for xrealloc() to send a non-NULL pointer that has
+ been freed, which has been fixed.
+ (merge 6479ea4a8a jk/xrealloc-avoid-use-after-free later to maint).
+
+ * "git status" has trouble showing where it came from by interpreting
+ reflog entries that record certain events, e.g. "checkout @{u}", and
+ gives a hard/fatal error. Even though it inherently is impossible
+ to give a correct answer because the reflog entries lose some
+ information (e.g. "@{u}" does not record what branch the user was
+ on hence which branch 'the upstream' needs to be computed, and even
+ if the record were available, the relationship between branches may
+ have changed), at least hide the error and allow "status" to show its
+ output.
+
+ * "git status --short" quoted a path with SP in it when tracked, but
+ not those that are untracked, ignored or unmerged. They are all
+ shown quoted consistently.
+
+ * "git diff/show" on a change that involves a submodule used to read
+ the information on commits in the submodule from a wrong repository
+ and gave a wrong information when the commit-graph is involved.
+ (merge 85a1ec2c32 mf/submodule-summary-with-correct-repository later to maint).
+
+ * Unlike "git config --local", "git config --worktree" did not fail
+ early and cleanly when started outside a git repository.
+ (merge 378fe5fc3d mt/config-fail-nongit-early later to maint).
+
+ * There is a logic to estimate how many objects are in the
+ repository, which is meant to run once per process invocation, but
+ it ran every time the estimated value was requested.
+ (merge 67bb65de5d jk/dont-count-existing-objects-twice later to maint).
+
+ * "git remote set-head" that failed still said something that hints
+ the operation went through, which was misleading.
+ (merge 5a07c6c3c2 cs/don-t-pretend-a-failed-remote-set-head-succeeded later to maint).
+
+ * "git fetch --all --ipv4/--ipv6" forgot to pass the protocol options
+ to instances of the "git fetch" that talk to individual remotes,
+ which has been corrected.
+ (merge 4e735c1326 ar/fetch-ipversion-in-all later to maint).
+
+ * The "unshelve" subcommand of "git p4" incorrectly used commit^N
+ where it meant to say commit~N to name the Nth generation
+ ancestor, which has been corrected.
+ (merge 0acbf5997f ld/p4-unshelve-fix later to maint).
+
+ * "git clone" that clones from SHA-1 repository, while
+ GIT_DEFAULT_HASH set to use SHA-256 already, resulted in an
+ unusable repository that half-claims to be SHA-256 repository
+ with SHA-1 objects and refs. This has been corrected.
+
+ * Adjust sample hooks for hash algorithm other than SHA-1.
+ (merge d8d3d632f4 dl/zero-oid-in-hooks later to maint).
+
+ * "git range-diff" showed incorrect diffstat, which has been
+ corrected.
+
+ * Earlier we taught "git pull" to warn when the user does not say the
+ histories need to be merged, rebased or accepts only fast-
+ forwarding, but the warning triggered for those who have set the
+ pull.ff configuration variable.
+ (merge 54200cef86 ah/pull later to maint).
+
+ * Compilation fix around type punning.
+ (merge 176380fd11 jk/drop-unaligned-loads later to maint).
+
+ * "git blame --ignore-rev/--ignore-revs-file" failed to validate
+ their input are valid revision, and failed to take into account
+ that the user may want to give an annotated tag instead of a
+ commit, which has been corrected.
+ (merge 610e2b9240 jc/blame-ignore-fix later to maint).
+
+ * "git bisect start X Y", when X and Y are not valid committish
+ object names, should take X and Y as pathspec, but didn't.
+ (merge 73c6de06af cc/bisect-start-fix later to maint).
+
+ * The explanation of the "scissors line" has been clarified.
+ (merge 287416dba6 eg/mailinfo-doc-scissors later to maint).
+
+ * A race that leads to an access to a free'd data was corrected in
+ the codepath that reads pack files.
+ (merge bda959c476 mt/delta-base-cache-races later to maint).
+
+ * in_merge_bases_many(), a way to see if a commit is reachable from
+ any commit in a set of commits, was totally broken when the
+ commit-graph feature was in use, which has been corrected.
+ (merge 8791bf1841 ds/in-merge-bases-many-optim-bug later to maint).
+
+ * "git submodule update --quiet" did not squelch underlying "rebase"
+ and "pull" commands.
+ (merge 3ad0401e9e td/submodule-update-quiet later to maint).
+
+ * The lazy fetching done internally to make missing objects available
+ in a partial clone incorrectly made permanent damage to the partial
+ clone filter in the repository, which has been corrected.
+
+ * "log -c --find-object=X" did not work well to find a merge that
+ involves a change to an object X from only one parent.
+ (merge 957876f17d jk/diff-cc-oidfind-fix 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).
@@ -160,3 +493,22 @@ Fixes since v2.28
(merge f649aaaf82 so/rev-parser-errormessage-fix later to maint).
(merge 6103d58b7f bc/sha-256-cvs-svn-updates later to maint).
(merge ac900fddb7 ma/stop-progress-null-fix later to maint).
+ (merge e767963ab6 rs/upload-pack-sigchain-fix later to maint).
+ (merge a831908599 rs/preserve-merges-unused-code-removal later to maint).
+ (merge 6dfefe70a9 jb/commit-graph-doc-fix later to maint).
+ (merge 847b37271e pb/set-url-docfix later to maint).
+ (merge 748f733d54 mt/checkout-entry-dead-code-removal later to maint).
+ (merge ce820cbd58 dl/subtree-docs later to maint).
+ (merge 55fe225dde jk/leakfix later to maint).
+ (merge ee22a29215 so/pretty-abbrev-doc later to maint).
+ (merge 3100fd5588 jc/post-checkout-doc later to maint).
+ (merge 17bae89476 pb/doc-external-diff-env later to maint).
+ (merge 27ed6ccc12 jk/worktree-check-clean-leakfix later to maint).
+ (merge 1302badd16 ea/blame-use-oideq later to maint).
+ (merge e6d5a11fed al/t3200-back-on-a-branch later to maint).
+ (merge 324efcf6b6 pw/add-p-leakfix later to maint).
+ (merge 1c6ffb546b jk/add-i-fixes later to maint).
+ (merge e40e936551 cd/commit-graph-doc later to maint).
+ (merge 0512eabd91 jc/sequencer-stopped-sha-simplify later to maint).
+ (merge d01141de5a so/combine-diff-simplify later to maint).
+ (merge 3be01e5ab1 sn/fast-import-doc later to maint).
diff --git a/Documentation/RelNotes/2.29.1.txt b/Documentation/RelNotes/2.29.1.txt
new file mode 100644
index 0000000..295ee21
--- /dev/null
+++ b/Documentation/RelNotes/2.29.1.txt
@@ -0,0 +1,11 @@
+Git v2.29.1 Release Notes
+=========================
+
+This is to fix the build procedure change in 2.28 where we failed to
+install a few programs that should be installed in /usr/bin (namely,
+receive-pack, upload-archive and upload-pack) when the non-default
+SKIP_DASHED_BUILT_INS installation option is in effect.
+
+A minor glitch in a non-default installation may usually not deserve
+a hotfix, but I know Git for Windows ship binaries built with this
+option, so let's make an exception.
diff --git a/Documentation/RelNotes/2.29.2.txt b/Documentation/RelNotes/2.29.2.txt
new file mode 100644
index 0000000..632b5b5
--- /dev/null
+++ b/Documentation/RelNotes/2.29.2.txt
@@ -0,0 +1,12 @@
+Git v2.29.2 Release Notes
+=========================
+
+This release is primarily to fix brown-paper-bag breakages in the
+2.29.0 release.
+
+Fixes since v2.29.1
+-------------------
+
+ * In 2.29, "--committer-date-is-author-date" option of "rebase" and
+ "am" subcommands lost the e-mail address by mistake, which has been
+ corrected.
diff --git a/Documentation/RelNotes/2.30.0.txt b/Documentation/RelNotes/2.30.0.txt
new file mode 100644
index 0000000..defa865
--- /dev/null
+++ b/Documentation/RelNotes/2.30.0.txt
@@ -0,0 +1,201 @@
+Git 2.30 Release Notes
+======================
+
+Updates since v2.29
+-------------------
+
+UI, Workflows & Features
+
+ * Userdiff for PHP update.
+
+ * Userdiff for Rust update.
+
+ * Userdiff for CSS update.
+
+ * The command line completion script (in contrib/) learned that "git
+ stash show" takes the options "git diff" takes.
+
+ * "git worktree list" now shows if each worktree is locked. This
+ possibly may open us to show other kinds of states in the future.
+
+ * "git maintenance", an extended big brother of "git gc", continues
+ to evolve.
+
+ * "git push --force-with-lease[=<ref>]" can easily be misused to lose
+ commits unless the user takes good care of their own "git fetch".
+ A new option "--force-if-includes" attempts to ensure that what is
+ being force-pushed was created after examining the commit at the
+ tip of the remote ref that is about to be force-replaced.
+
+ * "git clone" learned clone.defaultremotename configuration variable
+ to customize what nickname to use to call the remote the repository
+ was cloned from.
+
+ * "git checkout" learned to use checkout.guess configuration variable
+ and enable/disable its "--[no-]guess" option accordingly.
+
+ * "git resurrect" script (in contrib/) learned that the object names
+ may be longer than 40-hex depending on the hash function in use.
+
+ * "git diff A...B" learned "git diff --merge-base A B", which is a
+ longer short-hand to say the same thing.
+
+ * A sample 'push-to-checkout' hook, that performs the same as
+ what the built-in default action does, has been added.
+
+ * "git diff" family of commands learned the "-I<regex>" option to
+ ignore hunks whose changed lines all match the given pattern.
+
+ * The userdiff pattern learned to identify the function definition in
+ POSIX shells and bash.
+
+ * "git checkout-index" did not consistently signal an error with its
+ exit status, but now it does.
+
+ * A commit and tag object may have CR at the end of each and
+ every line (you can create such an object with hash-object or
+ using --cleanup=verbatim to decline the default clean-up
+ action), but it would make it impossible to have a blank line
+ to separate the title from the body of the message. We are now
+ more lenient and accept a line with lone CR on it as a blank line,
+ too.
+
+ * Exit codes from "git remote add" etc. were not usable by scripted
+ callers, but now they are.
+
+ * Zsh autocompletion (in contrib/) update.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Use "git archive" more to produce the release tarball.
+
+ * GitHub Actions automated test improvement to skip tests on a tree
+ identical to what has already been tested.
+
+ * Test-coverage for running commit-graph task "git maintenance" has
+ been extended.
+
+ * Our test scripts can be told to run only individual pieces while
+ skipping others with the "--run=..." option; they were taught to
+ take a substring of test title, in addition to numbers, to name the
+ test pieces to run.
+
+ * Adjust tests so that they won't scream when the default initial
+ branch name is changed to 'main'.
+
+ * Rewriting "git bisect" in C continues.
+
+ * More preliminary tests have been added to document desired outcome
+ of various "directory rename" situations.
+
+ * Micro clean-up of a couple of test scripts.
+
+ * "git diff" and other commands that share the same machinery to
+ compare with working tree files have been taught to take advantage
+ of the fsmonitor data when available.
+
+ * The code to detect premature EOF in the sideband demultiplexer has
+ been cleaned up.
+
+ * Test scripts are being prepared to transition of the default branch
+ name to 'main'.
+
+
+
+Fixes since v2.29
+-----------------
+
+ * In 2.29, "--committer-date-is-author-date" option of "rebase" and
+ "am" subcommands lost the e-mail address by mistake, which has been
+ corrected.
+ (merge 5f35edd9d7 jk/committer-date-is-author-date-fix later to maint).
+
+ * "git checkout -p A...B [-- <path>]" did not work, even though the
+ same command without "-p" correctly used the merge-base between
+ commits A and B.
+ (merge 35166b1fb5 dl/checkout-p-merge-base later to maint).
+
+ * The side-band status report can be sent at the same time as the
+ primary payload multiplexed, but the demultiplexer on the receiving
+ end incorrectly split a single status report into two, which has
+ been corrected.
+ (merge 712b0377db js/avoid-split-sideband-message later to maint).
+
+ * "git fast-import" wasted a lot of memory when many marks were in use.
+ (merge 3f018ec716 jk/fast-import-marks-alloc-fix later to maint).
+
+ * A test helper "test_cmp A B" was taught to diagnose missing files A
+ or B as a bug in test, but some tests legitimately wanted to notice
+ a failure to even create file B as an error, in addition to leaving
+ the expected result in it, and were misdiagnosed as a bug. This
+ has been corrected.
+ (merge 262d5ad5a5 es/test-cmp-typocatcher later to maint).
+
+ * When "git commit-graph" detects the same commit recorded more than
+ once while it is merging the layers, it used to die. The code now
+ ignores all but one of them and continues.
+ (merge 85102ac71b ds/commit-graph-merging-fix later to maint).
+
+ * The meaning of a Signed-off-by trailer can vary from project to
+ project; this and also what it means to this project has been
+ clarified in the documentation.
+ (merge 3abd4a67d9 bk/sob-dco later to maint).
+
+ * "git credential' didn't honor the core.askPass configuration
+ variable (among other things), which has been corrected.
+ (merge 567ad2c0f9 tk/credential-config later to maint).
+
+ * Dev support to catch a tentative definition of a variable in our C
+ code as an error.
+ (merge 5539183622 jk/no-common later to maint).
+
+ * "git rebase --rebase-merges" did not correctly pass --gpg-sign
+ command line option to underlying "git merge" when replaying a merge
+ using non-default merge strategy or when replaying an octopus merge
+ (because replaying a two-head merge with the default strategy was
+ done in a separate codepath, the problem did not trigger for most
+ users), which has been corrected.
+ (merge 43ad4f2eca sc/sequencer-gpg-octopus later to maint).
+
+ * "git apply -R" did not handle patches that touch the same path
+ twice correctly, which has been corrected. This is most relevant
+ in a patch that changes a path from a regular file to a symbolic
+ link (and vice versa).
+ (merge b0f266de11 jt/apply-reverse-twice later to maint).
+
+ * A recent oid->hash conversion missed one spot, breaking "git svn".
+ (merge 03bb366de4 bc/svn-hash-oid-fix later to maint).
+
+ * The documentation on the "--abbrev=<n>" option did not say the
+ output may be longer than "<n>" hexdigits, which has been
+ clarified.
+ (merge cda34e0d0c jc/abbrev-doc later to maint).
+
+ * "git p4" now honors init.defaultBranch configuration.
+ (merge 1b09d1917f js/p4-default-branch later to maint).
+
+ * Recently the format of an internal state file "rebase -i" uses has
+ been tightened up for consistency, which would hurt those who start
+ "rebase -i" with old git and then continue with new git. Loosen
+ the reader side a bit (which we may want to tighten again in a year
+ or so).
+ (merge c779386182 jc/sequencer-stopped-sha-simplify later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 3e0a5dc9af cc/doc-filter-branch-typofix later to maint).
+ (merge 32c83afc2c cw/ci-ghwf-check-ws-errors later to maint).
+ (merge 5eb2ed691b rs/tighten-callers-of-deref-tag later to maint).
+ (merge 6db29ab213 jk/fast-import-marks-cleanup later to maint).
+ (merge e5cf6d3df4 nk/dir-c-comment-update later to maint).
+ (merge 5710dcce74 jk/report-fn-typedef later to maint).
+ (merge 9a82db1056 en/sequencer-rollback-lock-cleanup later to maint).
+ (merge 4e1bee9a99 js/t7006-cleanup later to maint).
+ (merge f5bcde6c58 es/tutorial-mention-asciidoc-early later to maint).
+ (merge 714d491af0 so/format-patch-doc-on-default-diff-format later to maint).
+ (merge 0795df4b9b rs/clear-commit-marks-in-repo later to maint).
+ (merge 9542d56379 sd/prompt-local-variable later to maint).
+ (merge 06d43fad18 rs/pack-write-hashwrite-simplify later to maint).
+ (merge b7e20b4373 mc/typofix later to maint).
+ (merge f6bcd9a8a4 js/test-whitespace-fixes later to maint).
+ (merge 53b67a801b js/test-file-size later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 291b61e..d12094b 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -209,7 +209,7 @@ send them as replies to either an additional "cover letter" message
(see below), the first patch, or the respective preceding patch.
If your log message (including your name on the
-Signed-off-by line) is not writable in ASCII, make sure that
+`Signed-off-by` trailer) is not writable in ASCII, make sure that
you send off a message in the correct encoding.
WARNING: Be wary of your MUAs word-wrap
@@ -229,7 +229,7 @@ previously sent.
The `git format-patch` command follows the best current practice to
format the body of an e-mail message. At the beginning of the
patch should come your commit message, ending with the
-Signed-off-by: lines, and a line that consists of three dashes,
+`Signed-off-by` trailers, and a line that consists of three dashes,
followed by the diffstat information and the patch itself. If
you are forwarding a patch from somebody else, optionally, at
the beginning of the e-mail message just before the commit
@@ -290,25 +290,24 @@ identify them), to solicit comments and reviews.
:git-ml: footnote:[The mailing list: git@vger.kernel.org]
After the list reached a consensus that it is a good idea to apply the
-patch, re-send it with "To:" set to the maintainer{current-maintainer} and "cc:" the
-list{git-ml} for inclusion.
+patch, re-send it with "To:" set to the maintainer{current-maintainer}
+and "cc:" the list{git-ml} for inclusion. This is especially relevant
+when the maintainer did not heavily participate in the discussion and
+instead left the review to trusted others.
Do not forget to add trailers such as `Acked-by:`, `Reviewed-by:` and
`Tested-by:` lines as necessary to credit people who helped your
-patch.
+patch, and "cc:" them when sending such a final version for inclusion.
[[sign-off]]
-=== Certify your work by adding your "Signed-off-by: " line
+=== Certify your work by adding your `Signed-off-by` trailer
-To improve tracking of who did what, we've borrowed the
-"sign-off" procedure from the Linux kernel project on patches
-that are being emailed around. Although core Git is a lot
-smaller project it is a good discipline to follow it.
+To improve tracking of who did what, we ask you to certify that you
+wrote the patch or have the right to pass it on under the same license
+as ours, by "signing off" your patch. Without sign-off, we cannot
+accept your patches.
-The sign-off is a simple line at the end of the explanation for
-the patch, which certifies that you wrote it or otherwise have
-the right to pass it on as an open-source patch. The rules are
-pretty simple: if you can certify the below D-C-O:
+If you can certify the below D-C-O:
[[dco]]
.Developer's Certificate of Origin 1.1
@@ -338,23 +337,29 @@ d. I understand and agree that this project and the contribution
this project or the open source license(s) involved.
____
-then you just add a line saying
+you add a "Signed-off-by" trailer to your commit, that looks like
+this:
....
Signed-off-by: Random J Developer <random@developer.example.org>
....
-This line can be automatically added by Git if you run the git-commit
-command with the -s option.
+This line can be added by Git if you run the git-commit command with
+the -s option.
-Notice that you can place your own Signed-off-by: line when
+Notice that you can place your own `Signed-off-by` trailer when
forwarding somebody else's patch with the above rules for
D-C-O. Indeed you are encouraged to do so. Do not forget to
place an in-body "From: " line at the beginning to properly attribute
the change to its true author (see (2) above).
+This procedure originally came from the Linux kernel project, so our
+rule is quite similar to theirs, but what exactly it means to sign-off
+your patch differs from project to project, so it may be different
+from that of the project you are accustomed to.
+
[[real-name]]
-Also notice that a real name is used in the Signed-off-by: line. Please
+Also notice that a real name is used in the `Signed-off-by` trailer. Please
don't hide your real name.
[[commit-trailers]]
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f93b683..f292c26 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -265,7 +265,7 @@ color::
The basic colors accepted are `normal`, `black`, `red`, `green`, `yellow`,
`blue`, `magenta`, `cyan` and `white`. The first color given is the
foreground; the second is the background. All the basic colors except
-`normal` have a bright variant that can be speficied by prefixing the
+`normal` have a bright variant that can be specified by prefixing the
color with `bright`, like `brightred`.
+
Colors may also be given as numbers between 0 and 255; these use ANSI
@@ -334,12 +334,16 @@ include::config/checkout.txt[]
include::config/clean.txt[]
+include::config/clone.txt[]
+
include::config/color.txt[]
include::config/column.txt[]
include::config/commit.txt[]
+include::config/commitgraph.txt[]
+
include::config/credential.txt[]
include::config/completion.txt[]
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index bdd37c3..acbd0c0 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -10,9 +10,8 @@ advice.*::
that the check is disabled.
pushUpdateRejected::
Set this variable to 'false' if you want to disable
- 'pushNonFFCurrent',
- 'pushNonFFMatching', 'pushAlreadyExists',
- 'pushFetchFirst', and 'pushNeedsForce'
+ 'pushNonFFCurrent', 'pushNonFFMatching', 'pushAlreadyExists',
+ 'pushFetchFirst', 'pushNeedsForce', and 'pushRefNeedsUpdate'
simultaneously.
pushNonFFCurrent::
Advice shown when linkgit:git-push[1] fails due to a
@@ -41,6 +40,10 @@ advice.*::
we can still suggest that the user push to either
refs/heads/* or refs/tags/* based on the type of the
source object.
+ pushRefNeedsUpdate::
+ Shown when linkgit:git-push[1] rejects a forced update of
+ a branch when its remote-tracking ref has updates that we
+ do not have locally.
statusAheadBehind::
Shown when linkgit:git-status[1] computes the ahead/behind
counts for a local ref compared to its remote tracking ref,
diff --git a/Documentation/config/checkout.txt b/Documentation/config/checkout.txt
index 6b64681..2cddf7b 100644
--- a/Documentation/config/checkout.txt
+++ b/Documentation/config/checkout.txt
@@ -1,18 +1,23 @@
checkout.defaultRemote::
- When you run 'git checkout <something>'
- or 'git switch <something>' and only have one
+ When you run `git checkout <something>`
+ or `git switch <something>` and only have one
remote, it may implicitly fall back on checking out and
- tracking e.g. 'origin/<something>'. This stops working as soon
- as you have more than one remote with a '<something>'
+ tracking e.g. `origin/<something>`. This stops working as soon
+ as you have more than one remote with a `<something>`
reference. This setting allows for setting the name of a
preferred remote that should always win when it comes to
disambiguation. The typical use-case is to set this to
`origin`.
+
Currently this is used by linkgit:git-switch[1] and
-linkgit:git-checkout[1] when 'git checkout <something>'
-or 'git switch <something>'
-will checkout the '<something>' branch on another remote,
-and by linkgit:git-worktree[1] when 'git worktree add' refers to a
+linkgit:git-checkout[1] when `git checkout <something>`
+or `git switch <something>`
+will checkout the `<something>` branch on another remote,
+and by linkgit:git-worktree[1] when `git worktree add` refers to a
remote branch. This setting might be used for other checkout-like
commands or functionality in the future.
+
+checkout.guess::
+ Provides the default value for the `--guess` or `--no-guess`
+ option in `git checkout` and `git switch`. See
+ linkgit:git-switch[1] and linkgit:git-checkout[1].
diff --git a/Documentation/config/clone.txt b/Documentation/config/clone.txt
new file mode 100644
index 0000000..47de36a
--- /dev/null
+++ b/Documentation/config/clone.txt
@@ -0,0 +1,4 @@
+clone.defaultRemoteName::
+ The name of the remote to create when cloning a repository. Defaults to
+ `origin`, and can be overridden by passing the `--origin` command-line
+ option to linkgit:git-clone[1].
diff --git a/Documentation/config/commitgraph.txt b/Documentation/config/commitgraph.txt
new file mode 100644
index 0000000..4582c39
--- /dev/null
+++ b/Documentation/config/commitgraph.txt
@@ -0,0 +1,8 @@
+commitGraph.maxNewFilters::
+ Specifies the default value for the `--max-new-filters` option of `git
+ commit-graph write` (c.f., linkgit:git-commit-graph[1]).
+
+commitGraph.readChangedPaths::
+ If true, then git will use the changed-path Bloom filters in the
+ commit-graph file (if it exists, and they are present). Defaults to
+ true. See linkgit:git-commit-graph[1] for more information.
diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
index 86c91d5..160aaca 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -399,7 +399,7 @@ the largest projects. You probably do not need to adjust this value.
Common unit suffixes of 'k', 'm', or 'g' are supported.
core.deltaBaseCacheLimit::
- Maximum number of bytes to reserve for caching base objects
+ Maximum number of bytes per thread to reserve for caching base objects
that may be referenced by multiple deltified objects. By storing the
entire decompressed base objects in a cache Git is able
to avoid unpacking and decompressing frequently used base
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index c0cbf2b..cdecd04 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -14,10 +14,6 @@ feature.experimental::
+
* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
skipping more commits at a time, reducing the number of round trips.
-+
-* `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 b203940..6af6f5e 100644
--- a/Documentation/config/fetch.txt
+++ b/Documentation/config/fetch.txt
@@ -60,7 +60,10 @@ fetch.negotiationAlgorithm::
sent when negotiating the contents of the packfile to be sent by the
server. Set to "skipping" to use an algorithm that skips commits in an
effort to converge faster, but may result in a larger-than-necessary
- packfile; The default is "default" which instructs Git to use the default algorithm
+ packfile; or set to "noop" to not send any information at all, which
+ will almost certainly result in a larger-than-necessary packfile, but
+ will skip the negotiation step.
+ The default is "default" which instructs Git to use the default algorithm
that never skips commits (unless the server has acknowledged it or one
of its descendants). If `feature.experimental` is enabled, then this
setting defaults to "skipping".
diff --git a/Documentation/config/fmt-merge-msg.txt b/Documentation/config/fmt-merge-msg.txt
index a8e8f74..3fbf40e 100644
--- a/Documentation/config/fmt-merge-msg.txt
+++ b/Documentation/config/fmt-merge-msg.txt
@@ -13,7 +13,7 @@ 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
+ integration branches will omit "into <branch name>" from
its title.
+
An element with an empty value can be used to clear the list
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index 564e809..851bf41 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -79,7 +79,7 @@ format.thread::
format.signOff::
A boolean value which lets you enable the `-s/--signoff` option of
- format-patch by default. *Note:* Adding the Signed-off-by: line to a
+ format-patch by default. *Note:* Adding the `Signed-off-by` trailer to a
patch should be a conscious act and means that you certify you have
the rights to submit this work under the same open source license.
Please see the 'SubmittingPatches' document for further discussion.
@@ -96,7 +96,9 @@ format.outputDirectory::
format.useAutoBase::
A boolean value which lets you enable the `--base=auto` option of
- format-patch by default.
+ format-patch by default. Can also be set to "whenAble" to allow
+ enabling `--base=auto` if a suitable base is available, but to skip
+ adding base info otherwise without the format dying.
format.notes::
Provides the default value for the `--notes` option to
diff --git a/Documentation/config/mergetool.txt b/Documentation/config/mergetool.txt
index 09ed31d..16a2744 100644
--- a/Documentation/config/mergetool.txt
+++ b/Documentation/config/mergetool.txt
@@ -30,6 +30,16 @@ mergetool.meld.hasOutput::
to `true` tells Git to unconditionally use the `--output` option,
and `false` avoids using `--output`.
+mergetool.meld.useAutoMerge::
+ When the `--auto-merge` is given, meld will merge all non-conflicting
+ parts automatically, highlight the conflicting parts and wait for
+ user decision. Setting `mergetool.meld.useAutoMerge` to `true` tells
+ Git to unconditionally use the `--auto-merge` option with `meld`.
+ Setting this value to `auto` makes git detect whether `--auto-merge`
+ is supported and will only use `--auto-merge` when available. A
+ value of `false` avoids using `--auto-merge` altogether, and is the
+ default value.
+
mergetool.keepBackup::
After performing a merge, the original file with conflict markers
can be saved as a file with a `.orig` extension. If this variable
diff --git a/Documentation/config/protocol.txt b/Documentation/config/protocol.txt
index c46e9b3..756591d 100644
--- a/Documentation/config/protocol.txt
+++ b/Documentation/config/protocol.txt
@@ -48,8 +48,7 @@ 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 `0`, unless `feature.experimental`
- is enabled, in which case the default is `2`.
+ If unset, the default is `2`.
Supported versions:
+
--
diff --git a/Documentation/config/push.txt b/Documentation/config/push.txt
index f5e5b38..21b256e 100644
--- a/Documentation/config/push.txt
+++ b/Documentation/config/push.txt
@@ -114,3 +114,9 @@ push.recurseSubmodules::
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').
+
+push.useForceIfIncludes::
+ If set to "true", it is equivalent to specifying
+ `--force-if-includes` as an option to linkgit:git-push[1]
+ in the command line. Adding `--no-force-if-includes` at the
+ time of push overrides this configuration setting.
diff --git a/Documentation/config/receive.txt b/Documentation/config/receive.txt
index 65f78aa..85d5b5a 100644
--- a/Documentation/config/receive.txt
+++ b/Documentation/config/receive.txt
@@ -114,6 +114,28 @@ receive.hideRefs::
An attempt to update or delete a hidden ref by `git push` is
rejected.
+receive.procReceiveRefs::
+ This is a multi-valued variable that defines reference prefixes
+ to match the commands in `receive-pack`. Commands matching the
+ prefixes will be executed by an external hook "proc-receive",
+ instead of the internal `execute_commands` function. If this
+ variable is not defined, the "proc-receive" hook will never be
+ used, and all commands will be executed by the internal
+ `execute_commands` function.
++
+For example, if this variable is set to "refs/for", pushing to reference
+such as "refs/for/master" will not create or update a reference named
+"refs/for/master", but may create or update a pull request directly by
+running the hook "proc-receive".
++
+Optional modifiers can be provided in the beginning of the value to filter
+commands for specific actions: create (a), modify (m), delete (d).
+A `!` can be included in the modifiers to negate the reference prefix entry.
+E.g.:
++
+ git config --system --add receive.procReceiveRefs ad:refs/heads
+ git config --system --add receive.procReceiveRefs !:refs/heads
+
receive.updateServerInfo::
If set to true, git-receive-pack will run git-update-server-info
after receiving data from git-push and updating refs.
diff --git a/Documentation/config/uploadpack.txt b/Documentation/config/uploadpack.txt
index ee7b3ac..b0d7612 100644
--- a/Documentation/config/uploadpack.txt
+++ b/Documentation/config/uploadpack.txt
@@ -70,7 +70,7 @@ uploadpackfilter.<filter>.allow::
kinds must be allowed. Defaults to `uploadpackfilter.allow`.
uploadpackfilter.tree.maxDepth::
- Only allow `--filter=tree=<n>` when `n` is no more than the value of
+ Only allow `--filter=tree:<n>` when `<n>` is no more than the value of
`uploadpackfilter.tree.maxDepth`. If set, this also implies
`uploadpackfilter.tree.allow=true`, unless this configuration
variable had already been set. Has no effect if unset.
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index e8ed647..b10ff4c 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -10,7 +10,8 @@ linkgit:git-diff-tree[1], or
linkgit:git-diff-files[1]
with the `-p` option produces patch text.
You can customize the creation of patch text via the
-`GIT_EXTERNAL_DIFF` and the `GIT_DIFF_OPTS` environment variables.
+`GIT_EXTERNAL_DIFF` and the `GIT_DIFF_OPTS` environment variables
+(see linkgit:git[1]).
What the -p option produces is slightly different from the traditional
diff format:
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index b7af973..2e7a938 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -36,9 +36,9 @@ endif::git-format-patch[]
-U<n>::
--unified=<n>::
Generate diffs with <n> lines of context instead of
- the usual three. Implies `--patch`.
+ the usual three.
ifndef::git-format-patch[]
- Implies `-p`.
+ Implies `--patch`.
endif::git-format-patch[]
--output=<file>::
@@ -441,15 +441,20 @@ endif::git-format-patch[]
--binary::
In addition to `--full-index`, output a binary diff that
- can be applied with `git-apply`. Implies `--patch`.
+ can be applied with `git-apply`.
+ifndef::git-format-patch[]
+ Implies `--patch`.
+endif::git-format-patch[]
--abbrev[=<n>]::
Instead of showing the full 40-byte hexadecimal object
name in diff-raw format output and diff-tree header
- lines, show only a partial prefix. This is
- independent of the `--full-index` option above, which controls
- the diff-patch output format. Non default number of
- digits can be specified with `--abbrev=<n>`.
+ lines, show the shortest prefix that is at least '<n>'
+ hexdigits long that uniquely refers the object.
+ In diff-patch output format, `--full-index` takes higher
+ precedence, i.e. if `--full-index` is specified, full blob
+ names will be shown regardless of `--abbrev`.
+ Non default number of digits can be specified with `--abbrev=<n>`.
-B[<n>][/<m>]::
--break-rewrites[=[<n>][/<m>]]::
@@ -686,6 +691,11 @@ endif::git-format-patch[]
--ignore-blank-lines::
Ignore changes whose lines are all blank.
+-I<regex>::
+--ignore-matching-lines=<regex>::
+ Ignore changes whose all lines match <regex>. This option may
+ be specified more than once.
+
--inter-hunk-context=<lines>::
Show the context between diff hunks, up to the specified number
of lines, thereby fusing hunks that are close to each other.
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index b65a758..2bf77b4 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -197,7 +197,7 @@ ifndef::git-pull[]
endif::git-pull[]
--set-upstream::
- If the remote is fetched successfully, pull and add upstream
+ If the remote is fetched successfully, add upstream
(tracking) reference, used by argument-less
linkgit:git-pull[1] and other commands. For more information,
see `branch.<name>.merge` and `branch.<name>.remote` in
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 38c0852..06bc063 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -33,7 +33,7 @@ OPTIONS
-s::
--signoff::
- Add a `Signed-off-by:` line to the commit message, using
+ Add a `Signed-off-by` trailer to the commit message, using
the committer identity of yourself.
See the signoff option in linkgit:git-commit[1] for more information.
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index b9aa390..91d9a86 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -61,18 +61,18 @@ OPTIONS
file and detects errors. Turns off "apply".
--index::
- When `--check` is in effect, or when applying the patch
- (which is the default when none of the options that
- disables it is in effect), make sure the patch is
- applicable to what the current index file records. If
- the file to be patched in the working tree is not
- up to date, it is flagged as an error. This flag also
- causes the index file to be updated.
+ Apply the patch to both the index and the working tree (or
+ merely check that it would apply cleanly to both if `--check` is
+ in effect). Note that `--index` expects index entries and
+ working tree copies for relevant paths to be identical (their
+ contents and metadata such as file mode must match), and will
+ raise an error if they are not, even if the patch would apply
+ cleanly to both the index and the working tree in isolation.
--cached::
- Apply a patch without touching the working tree. Instead take the
- cached data, apply the patch, and store the result in the index
- without using the working tree. This implies `--index`.
+ Apply the patch to just the index, without touching the working
+ tree. If `--check` is in effect, merely check that it would
+ apply cleanly to the index entry.
--intent-to-add::
When applying the patch only to the working tree, mark new
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index cfa1e4e..9f81728 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -55,6 +55,12 @@ OPTIONS
--output=<file>::
Write the archive to <file> instead of stdout.
+--add-file=<file>::
+ Add a non-tracked file to the archive. Can be repeated to add
+ multiple files. The path of the file in the archive is built
+ by concatenating the value for `--prefix` (if any) and the
+ basename of <file>.
+
--worktree-attributes::
Look for attributes in .gitattributes files in the working tree
as well (see <<ATTRIBUTES>>).
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt
index 3ba49e8..f3d9566 100644
--- a/Documentation/git-bisect-lk2009.txt
+++ b/Documentation/git-bisect-lk2009.txt
@@ -473,7 +473,7 @@ Z-Z
-------------
2) starting from the "good" ends of the graph, associate to each
-commit the number of ancestors it has plus one
+ commit the number of ancestors it has plus one
For example with the following graph where H is the "bad" commit and A
and D are some parents of some "good" commits:
@@ -514,7 +514,7 @@ D---E
-------------
4) the best bisection point is the commit with the highest associated
-number
+ number
So in the above example the best bisection point is commit C.
@@ -580,8 +580,8 @@ good or a bad commit does not give more or less information).
Let's also suppose that we have a cleaned up graph like one after step
1) in the bisection algorithm above. This means that we can measure
-the information we get in terms of number of commit we can remove from
-the graph..
+ the information we get in terms of number of commit we can remove
+ from the graph..
And let's take a commit X in the graph.
@@ -689,18 +689,18 @@ roughly the following steps:
6) sort the commit by decreasing associated value
7) if the first commit has not been skipped, we can return it and stop
-here
+ here
8) otherwise filter out all the skipped commits in the sorted list
9) use a pseudo random number generator (PRNG) to generate a random
-number between 0 and 1
+ number between 0 and 1
10) multiply this random number with its square root to bias it toward
-0
+ 0
11) multiply the result by the number of commits in the filtered list
-to get an index into this list
+ to get an index into this list
12) return the commit at the computed index
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 0e993e4..fbb39fb 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -16,7 +16,7 @@ DESCRIPTION
The command takes various subcommands, and different options depending
on the subcommand:
- git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
+ git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
[--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
git bisect (bad|new|<term-new>) [<rev>]
git bisect (good|old|<term-old>) [<rev>...]
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 7e81541..34b496d 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -87,7 +87,9 @@ include::blame-options.txt[]
--abbrev=<n>::
Instead of using the default 7+1 hexadecimal digits as the
- abbreviated object name, use <n>+1 digits. Note that 1 column
+ abbreviated object name, use <m>+1 digits, where <m> is at
+ least <n> but ensures the commit object names are unique.
+ Note that 1 column
is used for a caret to mark the boundary commit.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 03c0824..adaa178 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -9,9 +9,9 @@ SYNOPSIS
--------
[verse]
'git branch' [--color[=<when>] | --no-color] [--show-current]
- [-v [--abbrev=<length> | --no-abbrev]]
+ [-v [--abbrev=<n> | --no-abbrev]]
[--column[=<options>] | --no-column] [--sort=<key>]
- [(--merged | --no-merged) [<commit>]]
+ [--merged [<commit>]] [--no-merged [<commit>]]
[--contains [<commit>]] [--no-contains [<commit>]]
[--points-at <object>] [--format=<format>]
[(-r | --remotes) | (-a | --all)]
@@ -194,8 +194,10 @@ This option is only applicable in non-verbose mode.
Be more quiet when creating or deleting a branch, suppressing
non-error messages.
---abbrev=<length>::
- Alter the sha1's minimum display length in the output listing.
+--abbrev=<n>::
+ In the verbose listing that show the commit object name,
+ show the shortest prefix that is at least '<n>' hexdigits
+ long that uniquely refers the object.
The default value is 7 and can be overridden by the `core.abbrev`
config option.
@@ -252,13 +254,11 @@ start-point is either a local or remote-tracking branch.
--merged [<commit>]::
Only list branches whose tips are reachable from the
- specified commit (HEAD if not specified). Implies `--list`,
- incompatible with `--no-merged`.
+ specified commit (HEAD if not specified). Implies `--list`.
--no-merged [<commit>]::
Only list branches whose tips are not reachable from the
- specified commit (HEAD if not specified). Implies `--list`,
- incompatible with `--merged`.
+ specified commit (HEAD if not specified). Implies `--list`.
<branchname>::
The name of the branch to create or delete.
@@ -370,6 +370,8 @@ serve four related but different purposes:
- `--no-merged` is used to find branches which are candidates for merging
into HEAD, since those branches are not fully contained by HEAD.
+include::ref-reachability-filters.txt[]
+
SEE ALSO
--------
linkgit:git-check-ref-format[1],
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 5b697ee..b1a6fe4 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -192,12 +192,16 @@ branches from there if `<branch>` is ambiguous but exists on the
'origin' remote. See also `checkout.defaultRemote` in
linkgit:git-config[1].
+
-Use `--no-guess` to disable this.
+`--guess` is the default behavior. Use `--no-guess` to disable it.
++
+The default behavior can be set via the `checkout.guess` configuration
+variable.
-l::
Create the new branch's reflog; see linkgit:git-branch[1] for
details.
+-d::
--detach::
Rather than checking out a branch to work on it, check out a
commit for inspection and discardable experiments.
@@ -350,6 +354,10 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
<tree-ish>::
Tree to checkout from (when paths are given). If not specified,
the index will be used.
++
+As a special case, you may use `"A...B"` as a shortcut for the
+merge base of `A` and `B` if there is exactly one merge base. You can
+leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
\--::
Do not interpret any more arguments as options.
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 75feeef..5d75031 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -104,7 +104,7 @@ effect to your index in a row.
-s::
--signoff::
- Add Signed-off-by line at the end of the commit message.
+ Add a `Signed-off-by` trailer at the end of the commit message.
See the signoff option in linkgit:git-commit[1] for more information.
-S[<keyid>]::
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 097e6a8..876aedc 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -183,8 +183,9 @@ objects from the source repository into a pack in the cloned repository.
-o <name>::
--origin <name>::
- Instead of using the remote name `origin` to keep track
- of the upstream repository, use `<name>`.
+ Instead of using the remote name `origin` to keep track of the upstream
+ repository, use `<name>`. Overrides `clone.defaultRemoteName` from the
+ config.
-b <name>::
--branch <name>::
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index 17405c7..e1f48c9 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -39,7 +39,9 @@ COMMANDS
--------
'write'::
-Write a commit-graph file based on the commits found in packfiles.
+Write a commit-graph file based on the commits found in packfiles. If
+the config option `core.commitGraph` is disabled, then this command will
+output a warning, then return success without writing a commit-graph file.
+
With the `--stdin-packs` option, generate the new commit graph by
walking objects only in the specified pack-indexes. (Cannot be combined
@@ -67,6 +69,13 @@ 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 `--max-new-filters=<n>` option, generate at most `n` new Bloom
+filters (if `--changed-paths` is specified). If `n` is `-1`, no limit is
+enforced. Only commits present in the new layer count against this
+limit. To retroactively compute Bloom filters over earlier layers, it is
+advised to use `--split=replace`. Overrides the `commitGraph.maxNewFilters`
+configuration.
++
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
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index a3baea3..17150fa 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -59,6 +59,7 @@ commit by giving the same set of parameters (options and paths).
If you make a commit and then find a mistake immediately after
that, you can recover from it with 'git reset'.
+:git-commit: 1
OPTIONS
-------
@@ -163,14 +164,7 @@ The `-m` option is mutually exclusive with `-c`, `-C`, and `-F`.
message, the commit is aborted. This has no effect when a message
is given by other means, e.g. with the `-m` or `-F` options.
--s::
---signoff::
- Add Signed-off-by line by the committer at the end of the commit
- log message. The meaning of a signoff depends on the project,
- but it typically certifies that committer has
- the rights to submit this work under the same license and
- agrees to a Developer Certificate of Origin
- (see http://developercertificate.org/ for more information).
+include::signoff-option.txt[]
-n::
--no-verify::
diff --git a/Documentation/git-diff-index.txt b/Documentation/git-diff-index.txt
index f4bd815..27acb31 100644
--- a/Documentation/git-diff-index.txt
+++ b/Documentation/git-diff-index.txt
@@ -9,7 +9,7 @@ git-diff-index - Compare a tree to the working tree or index
SYNOPSIS
--------
[verse]
-'git diff-index' [-m] [--cached] [<common diff options>] <tree-ish> [<path>...]
+'git diff-index' [-m] [--cached] [--merge-base] [<common diff options>] <tree-ish> [<path>...]
DESCRIPTION
-----------
@@ -27,7 +27,12 @@ include::diff-options.txt[]
The id of a tree object to diff against.
--cached::
- do not consider the on-disk file at all
+ Do not consider the on-disk file at all.
+
+--merge-base::
+ Instead of comparing <tree-ish> directly, use the merge base
+ between <tree-ish> and HEAD instead. <tree-ish> must be a
+ commit.
-m::
By default, files recorded in the index but not checked
diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt
index 5c8a2a5..2fc24c5 100644
--- a/Documentation/git-diff-tree.txt
+++ b/Documentation/git-diff-tree.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git diff-tree' [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty]
- [-t] [-r] [-c | --cc] [--combined-all-paths] [--root]
+ [-t] [-r] [-c | --cc] [--combined-all-paths] [--root] [--merge-base]
[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]
DESCRIPTION
@@ -43,6 +43,11 @@ include::diff-options.txt[]
When `--root` is specified the initial commit will be shown as a big
creation event. This is equivalent to a diff against the NULL tree.
+--merge-base::
+ Instead of comparing the <tree-ish>s directly, use the merge
+ base between the two <tree-ish>s as the "before" side. There
+ must be two <tree-ish>s given and they must both be commits.
+
--stdin::
When `--stdin` is specified, the command does not take
<tree-ish> arguments from the command line. Instead, it
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 727f24d..7f4c8a8 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -10,8 +10,8 @@ SYNOPSIS
--------
[verse]
'git diff' [<options>] [<commit>] [--] [<path>...]
-'git diff' [<options>] --cached [<commit>] [--] [<path>...]
-'git diff' [<options>] <commit> [<commit>...] <commit> [--] [<path>...]
+'git diff' [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]
+'git diff' [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]
'git diff' [<options>] <commit>...<commit> [--] [<path>...]
'git diff' [<options>] <blob> <blob>
'git diff' [<options>] --no-index [--] <path> <path>
@@ -40,7 +40,7 @@ files on disk.
or when running the command outside a working tree
controlled by Git. This form implies `--exit-code`.
-'git diff' [<options>] --cached [<commit>] [--] [<path>...]::
+'git diff' [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]::
This form is to view the changes you staged for the next
commit relative to the named <commit>. Typically you
@@ -49,6 +49,10 @@ files on disk.
If HEAD does not exist (e.g. unborn branches) and
<commit> is not given, it shows all staged changes.
--staged is a synonym of --cached.
++
+If --merge-base is given, instead of using <commit>, use the merge base
+of <commit> and HEAD. `git diff --merge-base A` is equivalent to
+`git diff $(git merge-base A HEAD)`.
'git diff' [<options>] <commit> [--] [<path>...]::
@@ -58,23 +62,27 @@ files on disk.
branch name to compare with the tip of a different
branch.
-'git diff' [<options>] <commit> <commit> [--] [<path>...]::
+'git diff' [<options>] [--merge-base] <commit> <commit> [--] [<path>...]::
This is to view the changes between two arbitrary
<commit>.
++
+If --merge-base is given, use the merge base of the two commits for the
+"before" side. `git diff --merge-base A B` is equivalent to
+`git diff $(git merge-base A B) B`.
'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.
+ the desired set of revisions is to use the `^@` 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 earlier form (without the "..") for
+ 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.
@@ -83,20 +91,20 @@ files on disk.
This form is to view the changes on the branch containing
and up to the second <commit>, starting at a common ancestor
- of both <commit>. "git diff A\...B" is equivalent to
- "git diff $(git merge-base A B) B". You can omit any one
+ of both <commit>. `git diff A...B` is equivalent to
+ `git diff $(git merge-base A B) B`. You can omit any one
of <commit>, which has the same effect as using HEAD instead.
Just in case you are doing something exotic, it should be
noted that all of the <commit> in the above description, except
-in the last two forms that use ".." notations, can be any
-<tree>.
+in the `--merge-base` case and in the last two forms that use `..`
+notations, can be any <tree>.
For a more complete list of ways to spell <commit>, see
"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
However, "diff" is about comparing two _endpoints_, not ranges,
-and the range notations ("<commit>..<commit>" and
-"<commit>\...<commit>") do not mean a range as defined in the
+and the range notations (`<commit>..<commit>` and
+`<commit>...<commit>`) do not mean a range as defined in the
"SPECIFYING RANGES" section in linkgit:gitrevisions[7].
'git diff' [<options>] <blob> <blob>::
@@ -144,9 +152,9 @@ $ git diff HEAD <3>
+
<1> Changes in the working tree not yet staged for the next commit.
<2> Changes between the index and your last commit; what you
- would be committing if you run "git commit" without "-a" option.
+ would be committing if you run `git commit` without `-a` option.
<3> Changes in the working tree since your last commit; what you
- would be committing if you run "git commit -a"
+ would be committing if you run `git commit -a`
Comparing with arbitrary commits::
+
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 7d9aad2..39cfa05 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -814,7 +814,7 @@ may have uses for this information
'original-oid' SP <object-identifier> LF
....
-where `<object-identifer>` is any string not containing LF.
+where `<object-identifier>` is any string not containing LF.
`tag`
~~~~~
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index 45b6d8e..9067c20 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -48,6 +48,10 @@ include::fetch-options.txt[]
include::pull-fetch-param.txt[]
+--stdin::
+ Read refspecs, one per line, from stdin in addition to those provided
+ as arguments. The "tag <name>" format is not supported.
+
include::urls-remotes.txt[]
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 40ba4aa..62e482a 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -532,7 +532,7 @@ The https://github.com/newren/git-filter-repo/[git filter-repo] tool is
an alternative to git-filter-branch which does not suffer from these
performance problems or the safety problems (mentioned below). For those
with existing tooling which relies upon git-filter-branch, 'git
-repo-filter' also provides
+filter-repo' also provides
https://github.com/newren/git-filter-repo/blob/master/contrib/filter-repo-demos/filter-lamely[filter-lamely],
a drop-in git-filter-branch replacement (with a few caveats). While
filter-lamely suffers from all the same safety issues as
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 2ea71c5..2962f85 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -11,7 +11,7 @@ SYNOPSIS
'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
[(--sort=<key>)...] [--format=<format>] [<pattern>...]
[--points-at=<object>]
- (--merged[=<object>] | --no-merged[=<object>])
+ [--merged[=<object>]] [--no-merged[=<object>]]
[--contains[=<object>]] [--no-contains[=<object>]]
DESCRIPTION
@@ -76,13 +76,11 @@ OPTIONS
--merged[=<object>]::
Only list refs whose tips are reachable from the
- specified commit (HEAD if not specified),
- incompatible with `--no-merged`.
+ specified commit (HEAD if not specified).
--no-merged[=<object>]::
Only list refs whose tips are not reachable from the
- specified commit (HEAD if not specified),
- incompatible with `--merged`.
+ specified commit (HEAD if not specified).
--contains[=<object>]::
Only list refs which contain the specified commit (HEAD if not
@@ -222,6 +220,8 @@ worktreepath::
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
be used to specify the value in the header field.
+Fields `tree` and `parent` can also be used with modifier `:short` and
+`:short=<length>` just like `objectname`.
For commit and tag objects, the special `creatordate` and `creator`
fields will correspond to the appropriate date or name-email-date tuple
@@ -230,7 +230,10 @@ These are intended for working on a mix of annotated and lightweight tags.
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.
+and `date` to extract the named component. For email fields (`authoremail`,
+`committeremail` and `taggeremail`), `:trim` can be appended to get the email
+without angle brackets, and `:localpart` to get the part before the `@` symbol
+out of the trimmed email.
The message in a commit or a tag object is `contents`, from which
`contents:<part>` can be used to extract various parts out of:
@@ -242,6 +245,9 @@ 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.
+ Instead of `contents:subject`, field `subject` can also be used to
+ obtain same results. `:sanitize` can be appended to `subject` for
+ subject line suitable for filename.
contents:body::
The remainder of the commit or the tag message that follows
@@ -400,6 +406,11 @@ Note also that multiple copies of an object may be present in the object
database; in this case, it is undefined which copy's size or delta base
will be reported.
+NOTES
+-----
+
+include::ref-reachability-filters.txt[]
+
SEE ALSO
--------
linkgit:git-show-ref[1]
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 0f81d04..bf1bb40 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -119,7 +119,7 @@ include::diff-options.txt[]
-s::
--signoff::
- Add `Signed-off-by:` line to the commit message, using
+ Add a `Signed-off-by` trailer to the commit message, using
the committer identity of yourself.
See the signoff option in linkgit:git-commit[1] for more information.
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index a7f9bc9..6077ff0 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -209,7 +209,7 @@ providing this option will cause it to die.
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)).
+ variable core.quotePath (see linkgit:git-config[1]).
-o::
--only-matching::
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index 65b53fc..63cf498 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -51,17 +51,13 @@ OPTIONS
CONFIGURATION
-------------
-To use the tool, imap.folder and either imap.tunnel or imap.host must be set
+To use the tool, `imap.folder` and either `imap.tunnel` or `imap.host` must be set
to appropriate values.
-Variables
-~~~~~~~~~
-
include::config/imap.txt[]
-Examples
-~~~~~~~~
-
+EXAMPLES
+--------
Using tunnel mode:
..........................
@@ -89,14 +85,18 @@ Using direct mode with SSL:
user = bob
pass = p4ssw0rd
port = 123
- sslverify = false
+ ; sslVerify = false
.........................
-EXAMPLES
---------
-To submit patches using GMail's IMAP interface, first, edit your ~/.gitconfig
-to specify your account settings:
+[NOTE]
+You may want to use `sslVerify=false`
+while troubleshooting, if you suspect that the reason you are
+having trouble connecting is because the certificate you use at
+the private server `example.com` you are trying to set up (or
+have set up) may not be verified correctly.
+
+Using Gmail's IMAP interface:
---------
[imap]
@@ -104,17 +104,21 @@ to specify your account settings:
host = imaps://imap.gmail.com
user = user@gmail.com
port = 993
- sslverify = false
---------
-You might need to instead use: folder = "[Google Mail]/Drafts" if you get an error
+[NOTE]
+You might need to instead use: `folder = "[Google Mail]/Drafts"` if you get an error
that the "Folder doesn't exist".
+[NOTE]
+If your Gmail account is set to another language than English, the name of the "Drafts"
+folder will be localized.
+
Once the commits are ready to be sent, run the following command:
$ git format-patch --cover-letter -M --stdout origin/master | git imap-send
-Just make sure to disable line wrapping in the email client (GMail's web
+Just make sure to disable line wrapping in the email client (Gmail's web
interface will wrap lines no matter what, so you need to use a real
IMAP client).
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index ac74d05..af0c262 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -100,6 +100,8 @@ OPTIONS
value is set or outside a repository.
+
This option cannot be used with --stdin.
++
+include::object-format-disclaimer.txt[]
NOTES
-----
diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index ddfe265..59ecda6 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -53,6 +53,8 @@ current working directory.
Specify the given object format (hash algorithm) for the repository. The valid
values are 'sha1' and (if enabled) 'sha256'. 'sha1' is the default.
++
+include::object-format-disclaimer.txt[]
--template=<template_directory>::
@@ -68,7 +70,7 @@ repository.
+
If this is reinitialization, the repository will be moved to the specified path.
--b <branch-name::
+-b <branch-name>::
--initial-branch=<branch-name>::
Use the specified name for the initial branch in the newly created repository.
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 3cb2ebb..cbcf526 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -19,7 +19,7 @@ SYNOPSIS
[--exclude-standard]
[--error-unmatch] [--with-tree=<tree-ish>]
[--full-name] [--recurse-submodules]
- [--abbrev] [--] [<file>...]
+ [--abbrev[=<n>]] [--] [<file>...]
DESCRIPTION
-----------
@@ -153,7 +153,8 @@ a space) at the start of each line:
--abbrev[=<n>]::
Instead of showing the full 40-byte hexadecimal object
- lines, show only a partial prefix.
+ lines, show the shortest prefix that is at least '<n>'
+ hexdigits long that uniquely refers the object.
Non default number of digits can be specified with --abbrev=<n>.
--debug::
diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt
index a751571..db02d6d 100644
--- a/Documentation/git-ls-tree.txt
+++ b/Documentation/git-ls-tree.txt
@@ -62,7 +62,8 @@ OPTIONS
--abbrev[=<n>]::
Instead of showing the full 40-byte hexadecimal object
- lines, show only a partial prefix.
+ lines, show the shortest prefix that is at least '<n>'
+ hexdigits long that uniquely refers the object.
Non default number of digits can be specified with --abbrev=<n>.
--full-name::
diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.txt
index 3bbc731..7a6aed0 100644
--- a/Documentation/git-mailinfo.txt
+++ b/Documentation/git-mailinfo.txt
@@ -72,10 +72,9 @@ conversion, even with this flag.
is useful in order to associate commits with mailing list discussions.
--scissors::
- Remove everything in body before a scissors line. A line that
- mainly consists of scissors (either ">8" or "8<") and perforation
- (dash "-") marks is called a scissors line, and is used to request
- the reader to cut the message at that line. If such a line
+ Remove everything in body before a scissors line (e.g. "-- >8 --").
+ The line represents scissors and perforation marks, and is used to
+ request the reader to cut the message at that line. If that line
appears in the body of the message before the patch, everything
before it (including the scissors line itself) is ignored when
this option is used.
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index 0c66194..eb0caa0 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -51,11 +51,12 @@ repack::
multi-pack-index, then divide by the total number of objects in
the pack and multiply by the pack size. We select packs with
expected size below the batch size until the set of packs have
- total expected size at least the batch size. If the total size
- does not reach the batch size, then do nothing. If a new pack-
- 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.
+ total expected size at least the batch size, or all pack-files
+ are considered. If only one pack-file is selected, then do
+ nothing. If a new pack-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.
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index dab9609..ec233ac 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -417,7 +417,7 @@ 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
+successfully occurred in P4. It takes no parameters and is meant
primarily for notification and cannot affect the outcome of the
git p4 submit action.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 3b80534..ab103c8 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -13,7 +13,7 @@ SYNOPSIS
[--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
[-u | --set-upstream] [-o <string> | --push-option=<string>]
[--[no-]signed|--signed=(true|false|if-asked)]
- [--force-with-lease[=<refname>[:<expect>]]]
+ [--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]]
[--no-verify] [<repository> [<refspec>...]]
DESCRIPTION
@@ -320,6 +320,14 @@ seen and are willing to overwrite, then rewrite history, and finally
force push changes to `master` if the remote version is still at
`base`, regardless of what your local `remotes/origin/master` has been
updated to in the background.
++
+Alternatively, specifying `--force-if-includes` as an ancillary option
+along with `--force-with-lease[=<refname>]` (i.e., without saying what
+exact commit the ref on the remote side must be pointing at, or which
+refs on the remote side are being protected) at the time of "push" will
+verify if updates from the remote-tracking refs that may have been
+implicitly updated in the background are integrated locally before
+allowing a forced update.
-f::
--force::
@@ -341,6 +349,22 @@ one branch, use a `+` in front of the refspec to push (e.g `git push
origin +master` to force a push to the `master` branch). See the
`<refspec>...` section above for details.
+--[no-]force-if-includes::
+ Force an update only if the tip of the remote-tracking ref
+ has been integrated locally.
++
+This option enables a check that verifies if the tip of the
+remote-tracking ref is reachable from one of the "reflog" entries of
+the local branch based in it for a rewrite. The check ensures that any
+updates from the remote have been incorporated locally by rejecting the
+forced update if that is not the case.
++
+If the option is passed without specifying `--force-with-lease`, or
+specified along with `--force-with-lease=<refname>:<expect>`, it is
+a "no-op".
++
+Specifying `--no-force-if-includes` disables this behavior.
+
--repo=<repository>::
This option is equivalent to the <repository> argument. If both
are specified, the command-line argument takes precedence.
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 374d248..a0487b5 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -204,6 +204,7 @@ CONFIGURATION
-------------
include::config/rebase.txt[]
+include::config/sequencer.txt[]
OPTIONS
-------
@@ -459,22 +460,43 @@ with `--keep-base` in order to drop those commits from your branch.
See also INCOMPATIBLE OPTIONS below.
--ignore-whitespace::
+ Ignore whitespace differences when trying to reconcile
+differences. Currently, each backend implements an approximation of
+this behavior:
++
+apply backend: When applying a patch, ignore changes in whitespace in
+context lines. Unfortunately, this means that if the "old" lines being
+replaced by the patch differ only in whitespace from the existing
+file, you will get a merge conflict instead of a successful patch
+application.
++
+merge backend: Treat lines with only whitespace changes as unchanged
+when merging. Unfortunately, this means that any patch hunks that were
+intended to modify whitespace and nothing else will be dropped, even
+if the other side had no changes that conflicted.
+
--whitespace=<option>::
- These flags are passed to the 'git apply' program
+ This flag is passed to the 'git apply' program
(see linkgit:git-apply[1]) that applies the patch.
Implies --apply.
+
See also INCOMPATIBLE OPTIONS below.
--committer-date-is-author-date::
+ Instead of using the current time as the committer date, use
+ the author date of the commit being rebased as the committer
+ date. This option implies `--force-rebase`.
+
--ignore-date::
- These flags are passed to 'git am' to easily change the dates
- of the rebased commits (see linkgit:git-am[1]).
+--reset-author-date::
+ Instead of using the author date of the original commit, use
+ the current time as the author date of the rebased commit. This
+ option implies `--force-rebase`.
+
See also INCOMPATIBLE OPTIONS below.
--signoff::
- Add a Signed-off-by: trailer to all the rebased commits. Note
+ Add a `Signed-off-by` trailer to all the rebased commits. Note
that if `--interactive` is given then only commits marked to be
picked, edited or reworded will have the trailer added.
+
@@ -607,9 +629,6 @@ INCOMPATIBLE OPTIONS
The following options:
* --apply
- * --committer-date-is-author-date
- * --ignore-date
- * --ignore-whitespace
* --whitespace
* -C
@@ -636,6 +655,9 @@ In addition, the following pairs of options are incompatible:
* --preserve-merges and --signoff
* --preserve-merges and --rebase-merges
* --preserve-merges and --empty=
+ * --preserve-merges and --ignore-whitespace
+ * --preserve-merges and --committer-date-is-author-date
+ * --preserve-merges and --ignore-date
* --keep-base and --onto
* --keep-base and --root
* --fork-point and --root
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 9659abb..31c29c9 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git remote' [-v | --verbose]
-'git remote add' [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=<fetch|push>] <name> <url>
+'git remote add' [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=(fetch|push)] <name> <url>
'git remote rename' <old> <new>
'git remote remove' <name>
'git remote set-head' <name> (-a | --auto | -d | --delete | <branch>)
@@ -35,7 +35,7 @@ OPTIONS
-v::
--verbose::
Be a little more verbose and show remote url after name.
- NOTE: This must be placed between `remote` and `subcommand`.
+ NOTE: This must be placed between `remote` and subcommand.
COMMANDS
@@ -46,7 +46,7 @@ subcommands are available to perform operations on the remotes.
'add'::
-Adds a remote named <name> for the repository at
+Add a remote named <name> for the repository at
<url>. The command `git fetch <name>` can then be used to create and
update remote-tracking branches <name>/<branch>.
+
@@ -109,13 +109,13 @@ With `-d` or `--delete`, the symbolic ref `refs/remotes/<name>/HEAD` is deleted.
+
With `-a` or `--auto`, the remote is queried to determine its `HEAD`, then the
symbolic-ref `refs/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote
-`HEAD` is pointed at `next`, "`git remote set-head origin -a`" will set
+`HEAD` is pointed at `next`, `git remote set-head origin -a` will set
the symbolic-ref `refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will
only work if `refs/remotes/origin/next` already exists; if not it must be
fetched first.
+
-Use `<branch>` to set the symbolic-ref `refs/remotes/<name>/HEAD` explicitly. e.g., "git
-remote set-head origin master" will set the symbolic-ref `refs/remotes/origin/HEAD` to
+Use `<branch>` to set the symbolic-ref `refs/remotes/<name>/HEAD` explicitly. e.g., `git
+remote set-head origin master` will set the symbolic-ref `refs/remotes/origin/HEAD` to
`refs/remotes/origin/master`. This will only work if
`refs/remotes/origin/master` already exists; if not it must be fetched first.
+
@@ -127,7 +127,7 @@ This can be used to track a subset of the available remote branches
after the initial setup for a remote.
+
The named branches will be interpreted as if specified with the
-`-t` option on the 'git remote add' command line.
+`-t` option on the `git remote add` command line.
+
With `--add`, instead of replacing the list of currently tracked
branches, adds to that list.
@@ -181,16 +181,16 @@ fetch --prune <name>`, except that no new references will be fetched.
See the PRUNING section of linkgit:git-fetch[1] for what it'll prune
depending on various configuration.
+
-With `--dry-run` option, report what branches will be pruned, but do not
+With `--dry-run` option, report what branches would be pruned, but do not
actually prune them.
'update'::
Fetch updates for remotes or remote groups in the repository as defined by
-remotes.<group>. If neither group nor remote is specified on the command line,
+`remotes.<group>`. If neither group nor remote is specified on the command line,
the configuration parameter remotes.default will be used; if
remotes.default is not defined, all remotes which do not have the
-configuration parameter remote.<name>.skipDefaultUpdate set to true will
+configuration parameter `remote.<name>.skipDefaultUpdate` set to true will
be updated. (See linkgit:git-config[1]).
+
With `--prune` option, run pruning against all the remotes that are updated.
@@ -203,6 +203,17 @@ The remote configuration is achieved using the `remote.origin.url` and
`remote.origin.fetch` configuration variables. (See
linkgit:git-config[1]).
+EXIT STATUS
+-----------
+
+On success, the exit status is `0`.
+
+When subcommands such as 'add', 'rename', and 'remove' can't find the
+remote in question, the exit status is `2`. When the remote already
+exists, the exit status is `3`.
+
+On any other error, the exit status may be any other non-zero value.
+
EXAMPLES
--------
diff --git a/Documentation/git-restore.txt b/Documentation/git-restore.txt
index 84c6c40..55bde91 100644
--- a/Documentation/git-restore.txt
+++ b/Documentation/git-restore.txt
@@ -40,6 +40,10 @@ OPTIONS
+
If not specified, the contents are restored from `HEAD` if `--staged` is
given, otherwise from the index.
++
+As a special case, you may use `"A...B"` as a shortcut for the
+merge base of `A` and `B` if there is exactly one merge base. You can
+leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
-p::
--patch::
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 044276e..bb92a4a 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -99,7 +99,7 @@ effect to your index in a row.
-s::
--signoff::
- Add Signed-off-by line at the end of the commit message.
+ Add a `Signed-off-by` trailer at the end of the commit message.
See the signoff option in linkgit:git-commit[1] for more information.
--strategy=<strategy>::
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 0a69810..b7bbbea 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -313,7 +313,7 @@ Automating
the value of `sendemail.identity`.
--[no-]signed-off-by-cc::
- If this is set, add emails found in Signed-off-by: or Cc: lines to the
+ If this is set, add emails found in the `Signed-off-by` trailer or Cc: lines to the
cc list. Default is the value of `sendemail.signedoffbycc` configuration
value; if that is unspecified, default to --signed-off-by-cc.
@@ -340,7 +340,7 @@ Automating
except for self (use 'self' for that).
- 'bodycc' will avoid including anyone mentioned in Cc lines in the
patch body (commit message) except for self (use 'self' for that).
-- 'sob' will avoid including anyone mentioned in Signed-off-by lines except
+- 'sob' will avoid including anyone mentioned in the Signed-off-by trailers except
for self (use 'self' for that).
- 'misc-by' will avoid including anyone mentioned in Acked-by,
Reviewed-by, Tested-by and other "-by" lines in the patch body,
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index a72ea7f..fd93cd4 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -47,9 +47,38 @@ OPTIONS
Each pretty-printed commit will be rewrapped before it is shown.
+--group=<type>::
+ Group commits based on `<type>`. If no `--group` option is
+ specified, the default is `author`. `<type>` is one of:
++
+--
+ - `author`, commits are grouped by author
+ - `committer`, commits are grouped by committer (the same as `-c`)
+ - `trailer:<field>`, the `<field>` is interpreted as a case-insensitive
+ commit message trailer (see linkgit:git-interpret-trailers[1]). For
+ example, if your project uses `Reviewed-by` trailers, you might want
+ to see who has been reviewing with
+ `git shortlog -ns --group=trailer:reviewed-by`.
++
+Note that commits that do not include the trailer will not be counted.
+Likewise, commits with multiple trailers (e.g., multiple signoffs) may
+be counted more than once (but only once per unique trailer value in
+that commit).
++
+Shortlog will attempt to parse each trailer value as a `name <email>`
+identity. If successful, the mailmap is applied and the email is omitted
+unless the `--email` option is specified. If the value cannot be parsed
+as an identity, it will be taken literally and completely.
+--
++
+If `--group` is specified multiple times, commits are counted under each
+value (but again, only once per unique value in that commit). For
+example, `git shortlog --group=author --group=trailer:co-authored-by`
+counts both authors and co-authors.
+
-c::
--committer::
- Collect and show committer identities instead of authors.
+ This is an alias for `--group=committer`.
-w[<width>[,<indent1>[,<indent2>]]]::
Linewrap the output by wrapping each line at `width`. The first
diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.txt
index 39b1d8e..e49318a 100644
--- a/Documentation/git-show-index.txt
+++ b/Documentation/git-show-index.txt
@@ -44,6 +44,8 @@ OPTIONS
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..
++
+include::object-format-disclaimer.txt[]
GIT
---
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 6624a14..67b143c 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -701,7 +701,7 @@ creating the branch or tag.
--use-log-author::
When retrieving svn commits into Git (as part of 'fetch', 'rebase', or
- 'dcommit' operations), look for the first `From:` or `Signed-off-by:` line
+ 'dcommit' operations), look for the first `From:` line or `Signed-off-by` trailer
in the log message and use that as the author string.
+
[verse]
@@ -710,7 +710,7 @@ config key: svn.useLogAuthor
--add-author-from::
When committing to svn from Git (as part of 'set-tree' or 'dcommit'
operations), if the existing log message doesn't already have a
- `From:` or `Signed-off-by:` line, append a `From:` line based on the
+ `From:` or `Signed-off-by` trailer, append a `From:` line based on the
Git commit's author string. If you use this, then `--use-log-author`
will retrieve a valid author string for all commits.
+
diff --git a/Documentation/git-switch.txt b/Documentation/git-switch.txt
index 3759c3a..5c438cd 100644
--- a/Documentation/git-switch.txt
+++ b/Documentation/git-switch.txt
@@ -103,6 +103,9 @@ ambiguous but exists on the 'origin' remote. See also
`checkout.defaultRemote` in linkgit:git-config[1].
+
`--guess` is the default behavior. Use `--no-guess` to disable it.
++
+The default behavior can be set via the `checkout.guess` configuration
+variable.
-f::
--force::
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index f6d9791..56656d1 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -15,7 +15,7 @@ SYNOPSIS
'git tag' [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
[--points-at <object>] [--column[=<options>] | --no-column]
[--create-reflog] [--sort=<key>] [--format=<format>]
- [--[no-]merged [<commit>]] [<pattern>...]
+ [--merged <commit>] [--no-merged <commit>] [<pattern>...]
'git tag' -v [--format=<format>] <tagname>...
DESCRIPTION
@@ -149,11 +149,11 @@ This option is only applicable when listing tags without annotation lines.
--merged [<commit>]::
Only list tags whose commits are reachable from the specified
- commit (`HEAD` if not specified), incompatible with `--no-merged`.
+ commit (`HEAD` if not specified).
--no-merged [<commit>]::
Only list tags whose commits are not reachable from the specified
- commit (`HEAD` if not specified), incompatible with `--merged`.
+ commit (`HEAD` if not specified).
--points-at <object>::
Only list tags of the given object (HEAD if not
@@ -377,6 +377,11 @@ $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
include::date-formats.txt[]
+NOTES
+-----
+
+include::ref-reachability-filters.txt[]
+
SEE ALSO
--------
linkgit:git-check-ref-format[1].
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 6ee6ec7..af06128 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -15,6 +15,7 @@ SYNOPSIS
'git worktree move' <worktree> <new-path>
'git worktree prune' [-n] [-v] [--expire <expire>]
'git worktree remove' [-f] <worktree>
+'git worktree repair' [<path>...]
'git worktree unlock' <worktree>
DESCRIPTION
@@ -31,6 +32,18 @@ A repository has one main working tree (if it's not a
bare repository) and zero or more linked working trees. When you are done
with a linked working tree, remove it with `git worktree remove`.
+In its simplest form, `git worktree add <path>` automatically creates a
+new branch whose name is the final component of `<path>`, which is
+convenient if you plan to work on a new topic. For instance, `git
+worktree add ../hotfix` creates new branch `hotfix` and checks it out at
+path `../hotfix`. To instead work on an existing branch in a new working
+tree, use `git worktree add <path> <branch>`. On the other hand, if you
+just plan to make some experimental changes or do testing without
+disturbing existing development, it is often convenient to create a
+'throwaway' working tree not associated with any branch. For instance,
+`git worktree add -d <path>` creates a new working tree with a detached
+`HEAD` at the same commit as the current branch.
+
If a working tree is deleted without using `git worktree remove`, then
its associated administrative files, which reside in the repository
(see "DETAILS" below), will eventually be removed automatically (see
@@ -83,8 +96,9 @@ list::
List details of each working tree. The main working tree is listed first,
followed by each of the linked working trees. The output details include
-whether the working tree is bare, the revision currently checked out, and the
-branch currently checked out (or "detached HEAD" if none).
+whether the working tree is bare, the revision currently checked out, the
+branch currently checked out (or "detached HEAD" if none), and "locked" if
+the worktree is locked.
lock::
@@ -97,7 +111,10 @@ with `--reason`.
move::
Move a working tree to a new location. Note that the main working tree
-or linked working trees containing submodules cannot be moved.
+or linked working trees containing submodules cannot be moved with this
+command. (The `git worktree repair` command, however, can reestablish
+the connection with linked working trees if you move the main working
+tree manually.)
prune::
@@ -110,6 +127,23 @@ and no modification in tracked files) can be removed. Unclean working
trees or ones with submodules can be removed with `--force`. The main
working tree cannot be removed.
+repair [<path>...]::
+
+Repair working tree administrative files, if possible, if they have
+become corrupted or outdated due to external factors.
++
+For instance, if the main working tree (or bare repository) is moved,
+linked working trees will be unable to locate it. Running `repair` in
+the main working tree will reestablish the connection from linked
+working trees back to the main working tree.
++
+Similarly, if a linked working tree is moved without using `git worktree
+move`, the main working tree (or bare repository) will be unable to
+locate it. Running `repair` within the recently-moved working tree will
+reestablish the connection. If multiple linked working trees are moved,
+running `repair` from any working tree with each tree's new `<path>` as
+an argument, will reestablish the connection to all the specified paths.
+
unlock::
Unlock a working tree, allowing it to be pruned, moved or deleted.
@@ -143,6 +177,7 @@ To remove a locked working tree, specify `--force` twice.
exists. `-B` overrides this safeguard, resetting `<new-branch>` to
`<commit-ish>`.
+-d::
--detach::
With `add`, detach `HEAD` in the new working tree. See "DETACHED HEAD"
in linkgit:git-checkout[1].
@@ -303,7 +338,8 @@ in the entry's directory. For example, if a linked working tree is moved
to `/newpath/test-next` and its `.git` file points to
`/path/main/.git/worktrees/test-next`, then update
`/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next`
-instead.
+instead. Better yet, run `git worktree repair` to reestablish the connection
+automatically.
To prevent a `$GIT_DIR/worktrees` entry from being pruned (which
can be useful in some situations, such as when the
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 81349a8..c463b93 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -504,7 +504,8 @@ double-quotes and respecting backslash escapes. E.g., the value
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".
+ is used instead. The default is "sha1". THIS VARIABLE IS
+ EXPERIMENTAL! See `--object-format` in linkgit:git-init[1].
Git Commits
~~~~~~~~~~~
@@ -550,8 +551,9 @@ Git Diffs
`GIT_EXTERNAL_DIFF`::
When the environment variable `GIT_EXTERNAL_DIFF` is set, the
- program named by it is called, instead of the diff invocation
- described above. For a path that is added, removed, or modified,
+ program named by it is called to generate diffs, and Git
+ does not use its builtin diff machinery.
+ For a path that is added, removed, or modified,
`GIT_EXTERNAL_DIFF` is called with 7 parameters:
path old-file old-hex old-mode new-file new-hex new-mode
@@ -604,6 +606,12 @@ other
an editor is to be launched. See also linkgit:git-var[1]
and the `core.editor` option in linkgit:git-config[1].
+`GIT_SEQUENCE_EDITOR`::
+ This environment variable overrides the configured Git editor
+ when editing the todo list of an interactive rebase. See also
+ linkit::git-rebase[1] and the `sequence.editor` option in
+ linkit::git-config[1].
+
`GIT_SSH`::
`GIT_SSH_COMMAND`::
If either of these environment variables is set then 'git fetch'
@@ -714,6 +722,10 @@ of clones and fetches.
time of each Git command.
See `GIT_TRACE` for available trace output options.
+`GIT_TRACE_REFS`::
+ Enables trace messages for operations on the ref database.
+ See `GIT_TRACE` for available trace output options.
+
`GIT_TRACE_SETUP`::
Enables trace messages printing the .git, working tree and current
working directory after Git has completed its setup phase.
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 2d0a037..e84e104 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -802,6 +802,9 @@ patterns are available:
- `ada` suitable for source code in the Ada language.
+- `bash` suitable for source code in the Bourne-Again SHell language.
+ Covers a superset of POSIX shell function definitions.
+
- `bibtex` suitable for files with BibTeX coded references.
- `cpp` suitable for source code in the C and C++ languages.
diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 9cd7a59..afdaeab 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -241,6 +241,59 @@ How do I know if I want to do a fetch or a pull?::
ignore the upstream changes. A pull consists of a fetch followed
immediately by either a merge or rebase. See linkgit:git-pull[1].
+Merging and Rebasing
+--------------------
+
+[[long-running-squash-merge]]
+What kinds of problems can occur when merging long-lived branches with squash merges?::
+ In general, there are a variety of problems that can occur when using squash
+ merges to merge two branches multiple times. These can include seeing extra
+ commits in `git log` output, with a GUI, or when using the `...` notation to
+ express a range, as well as the possibility of needing to re-resolve conflicts
+ again and again.
++
+When Git does a normal merge between two branches, it considers exactly three
+points: the two branches and a third commit, called the _merge base_, which is
+usually the common ancestor of the commits. The result of the merge is the sum
+of the changes between the merge base and each head. When you merge two
+branches with a regular merge commit, this results in a new commit which will
+end up as a merge base when they're merged again, because there is now a new
+common ancestor. Git doesn't have to consider changes that occurred before the
+merge base, so you don't have to re-resolve any conflicts you resolved before.
++
+When you perform a squash merge, a merge commit isn't created; instead, the
+changes from one side are applied as a regular commit to the other side. This
+means that the merge base for these branches won't have changed, and so when Git
+goes to perform its next merge, it considers all of the changes that it
+considered the last time plus the new changes. That means any conflicts may
+need to be re-resolved. Similarly, anything using the `...` notation in `git
+diff`, `git log`, or a GUI will result in showing all of the changes since the
+original merge base.
++
+As a consequence, if you want to merge two long-lived branches repeatedly, it's
+best to always use a regular merge commit.
+
+[[merge-two-revert-one]]
+If I make a change on two branches but revert it on one, why does the merge of those branches include the change?::
+ By default, when Git does a merge, it uses a strategy called the recursive
+ strategy, which does a fancy three-way merge. In such a case, when Git
+ performs the merge, it considers exactly three points: the two heads and a
+ third point, called the _merge base_, which is usually the common ancestor of
+ those commits. Git does not consider the history or the individual commits
+ that have happened on those branches at all.
++
+As a result, if both sides have a change and one side has reverted that change,
+the result is to include the change. This is because the code has changed on
+one side and there is no net change on the other, and in this scenario, Git
+adopts the change.
++
+If this is a problem for you, you can do a rebase instead, rebasing the branch
+with the revert onto the other branch. A rebase in this scenario will revert
+the change, because a rebase applies each individual commit, including the
+revert. Note that rebases rewrite history, so you should avoid rebasing
+published branches unless you're sure you're comfortable with that. See the
+NOTES section in linkgit:git-rebase[1] for more details.
+
Hooks
-----
@@ -310,6 +363,39 @@ 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.
+[[always-modified-files-case]]
+Why do I have a file that's always modified?::
+ Internally, Git always stores file names as sequences of bytes and doesn't
+ perform any encoding or case folding. However, Windows and macOS by default
+ both perform case folding on file names. As a result, it's possible to end up
+ with multiple files or directories whose names differ only in case. Git can
+ handle this just fine, but the file system can store only one of these files,
+ so when Git reads the other file to see its contents, it looks modified.
++
+It's best to remove one of the files such that you only have one file. You can
+do this with commands like the following (assuming two files `AFile.txt` and
+`afile.txt`) on an otherwise clean working tree:
++
+----
+$ git rm --cached AFile.txt
+$ git commit -m 'Remove files conflicting in case'
+$ git checkout .
+----
++
+This avoids touching the disk, but removes the additional file. Your project
+may prefer to adopt a naming convention, such as all-lowercase names, to avoid
+this problem from occurring again; such a convention can be checked using a
+`pre-receive` hook or as part of a continuous integration (CI) system.
++
+It is also possible for perpetually modified files to occur on any platform if a
+smudge or clean filter is in use on your system but a file was previously
+committed without running the smudge or clean filter. To fix this, run the
+following on an otherwise clean working tree:
++
+----
+$ git add --renormalize .
+----
+
[[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
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 31b601e..ffccfc7 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -164,7 +164,7 @@ can also be used to refuse the commit after inspecting the message
file.
The default 'commit-msg' hook, when enabled, detects duplicate
-"Signed-off-by" lines, and aborts the commit if one is found.
+`Signed-off-by` trailers, and aborts the commit if one is found.
post-commit
~~~~~~~~~~~
@@ -193,7 +193,9 @@ worktree. The hook is given three parameters: the ref of the previous HEAD,
the ref of the new HEAD (which may or may not have changed), and a flag
indicating whether the checkout was a branch checkout (changing branches,
flag=1) or a file checkout (retrieving a file from the index, flag=0).
-This hook cannot affect the outcome of `git switch` or `git checkout`.
+This hook cannot affect the outcome of `git switch` or `git checkout`,
+other than that the hook's exit status becomes the exit status of
+these two commands.
It is also run after linkgit:git-clone[1], unless the `--no-checkout` (`-n`) option is
used. The first parameter given to the hook is the null-ref, the second the
@@ -333,6 +335,68 @@ The default 'update' hook, when enabled--and with
`hooks.allowunannotated` config option unset or set to false--prevents
unannotated tags to be pushed.
+[[proc-receive]]
+proc-receive
+~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-receive-pack[1]. If the server has
+set the multi-valued config variable `receive.procReceiveRefs`, and the
+commands sent to 'receive-pack' have matching reference names, these
+commands will be executed by this hook, instead of by the internal
+`execute_commands()` function. This hook is responsible for updating
+the relevant references and reporting the results back to 'receive-pack'.
+
+This hook executes once for the receive operation. It takes no
+arguments, but uses a pkt-line format protocol to communicate with
+'receive-pack' to read commands, push-options and send results. In the
+following example for the protocol, the letter 'S' stands for
+'receive-pack' and the letter 'H' stands for this hook.
+
+ # Version and features negotiation.
+ S: PKT-LINE(version=1\0push-options atomic...)
+ S: flush-pkt
+ H: PKT-LINE(version=1\0push-options...)
+ H: flush-pkt
+
+ # Send commands from server to the hook.
+ S: PKT-LINE(<old-oid> <new-oid> <ref>)
+ S: ... ...
+ S: flush-pkt
+ # Send push-options only if the 'push-options' feature is enabled.
+ S: PKT-LINE(push-option)
+ S: ... ...
+ S: flush-pkt
+
+ # Receive result from the hook.
+ # OK, run this command successfully.
+ H: PKT-LINE(ok <ref>)
+ # NO, I reject it.
+ H: PKT-LINE(ng <ref> <reason>)
+ # Fall through, let 'receive-pack' to execute it.
+ H: PKT-LINE(ok <ref>)
+ H: PKT-LINE(option fall-through)
+ # OK, but has an alternate reference. The alternate reference name
+ # and other status can be given in option directives.
+ H: PKT-LINE(ok <ref>)
+ H: PKT-LINE(option refname <refname>)
+ H: PKT-LINE(option old-oid <old-oid>)
+ H: PKT-LINE(option new-oid <new-oid>)
+ H: PKT-LINE(option forced-update)
+ H: ... ...
+ H: flush-pkt
+
+Each command for the 'proc-receive' hook may point to a pseudo-reference
+and always has a zero-old as its old-oid, while the 'proc-receive' hook
+may update an alternate reference and the alternate reference may exist
+already with a non-zero old-oid. For this case, this hook will use
+"option" directives to report extended attributes for the reference given
+by the leading "ok" directive.
+
+The report of the commands of this hook should have the same order as
+the input. The exit status of the 'proc-receive' hook only determines
+the success or failure of the group of commands sent to it, unless
+atomic push is in use.
+
[[post-receive]]
post-receive
~~~~~~~~~~~~
@@ -591,7 +655,7 @@ 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
+successfully occurred in P4. It takes no parameters and is meant
primarily for notification and cannot affect the outcome of the
git p4 submit action.
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt
index f9f4e65..891c8da 100644
--- a/Documentation/gitsubmodules.txt
+++ b/Documentation/gitsubmodules.txt
@@ -225,10 +225,10 @@ presence of the .url field.
Workflow for a third party library
----------------------------------
- # add a submodule
+ # Add a submodule
git submodule add <url> <path>
- # occasionally update the submodule to a new version:
+ # Occasionally update the submodule to a new version:
git -C <path> checkout <new version>
git add <path>
git commit -m "update submodule to new version"
@@ -246,20 +246,23 @@ Workflow for an artificially split repo
# regular commands recurse into submodules by default
git config --global submodule.recurse true
- # Unlike the other commands below clone still needs
+ # Unlike most other commands below, clone still needs
# its own recurse flag:
git clone --recurse <URL> <directory>
cd <directory>
# Get to know the code:
git grep foo
- git ls-files
+ git ls-files --recurse-submodules
+
+[NOTE]
+`git ls-files` also requires its own `--recurse-submodules` flag.
# Get new code
git fetch
git pull --rebase
- # change worktree
+ # Change worktree
git checkout
git reset
@@ -267,12 +270,12 @@ Implementation details
----------------------
When cloning or pulling a repository containing submodules the submodules
-will not be checked out by default; You can instruct 'clone' to recurse
-into submodules. The 'init' and 'update' subcommands of 'git submodule'
+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 (note that 'submodule.recurse' also
-affects other git commands, see linkgit:git-config[1] for a complete list).
+your working tree. Alternatively you can set `submodule.recurse` to have
+`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/merge-options.txt b/Documentation/merge-options.txt
index 80d4831..eb0aabd 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -77,16 +77,7 @@ When not possible, refuse to merge and exit with a non-zero status.
With --no-log do not list one-line descriptions from the
actual commits being merged.
---signoff::
---no-signoff::
- Add Signed-off-by line by the committer at the end of the commit
- log message. The meaning of a signoff depends on the project,
- but it typically certifies that committer has
- the rights to submit this work under the same license and
- agrees to a Developer Certificate of Origin
- (see http://developercertificate.org/ for more information).
-+
-With --no-signoff do not add a Signed-off-by line.
+include::signoff-option.txt[]
--stat::
-n::
diff --git a/Documentation/object-format-disclaimer.txt b/Documentation/object-format-disclaimer.txt
new file mode 100644
index 0000000..4cb106f
--- /dev/null
+++ b/Documentation/object-format-disclaimer.txt
@@ -0,0 +1,6 @@
+THIS OPTION IS EXPERIMENTAL! SHA-256 support is experimental and still
+in an early stage. A SHA-256 repository will in general not be able to
+share work with "regular" SHA-1 repositories. It should be assumed
+that, e.g., Git internal file formats in relation to SHA-256
+repositories may change in backwards-incompatible ways. Only use
+`--object-format=sha256` for testing purposes.
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 7a6da6d..27ddaf8 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -16,17 +16,17 @@ configuration (see linkgit:git-config[1]).
--abbrev-commit::
Instead of showing the full 40-byte hexadecimal commit object
- name, show only a partial prefix. Non default number of
- digits can be specified with "--abbrev=<n>" (which also modifies
- diff output, if it is displayed).
+ name, show a prefix that names the object uniquely.
+ "--abbrev=<n>" (which also modifies diff output, if it is displayed)
+ option can be used to specify the minimum length of the prefix.
+
This should make "--pretty=oneline" a whole lot more readable for
people using 80-column terminals.
--no-abbrev-commit::
Show the full 40-byte hexadecimal commit object name. This negates
- `--abbrev-commit` and those options which imply it such as
- "--oneline". It also overrides the `log.abbrevCommit` variable.
+ `--abbrev-commit`, either explicit or implied by other options such
+ as "--oneline". It also overrides the `log.abbrevCommit` variable.
--oneline::
This is a shorthand for "--pretty=oneline --abbrev-commit"
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt
index 95ea849..95a7390 100644
--- a/Documentation/pull-fetch-param.txt
+++ b/Documentation/pull-fetch-param.txt
@@ -30,6 +30,22 @@ The colon can be omitted when <dst> is empty. <src> is
typically a ref, but it can also be a fully spelled hex object
name.
+
+A <refspec> may contain a `*` in its <src> to indicate a simple pattern
+match. Such a refspec functions like a glob that matches any ref with the
+same prefix. A pattern <refspec> must have a `*` in both the <src> and
+<dst>. It will map refs to the destination by replacing the `*` with the
+contents matched from the source.
++
+If a refspec is prefixed by `^`, it will be interpreted as a negative
+refspec. Rather than specifying which refs to fetch or which local refs to
+update, such a refspec will instead specify refs to exclude. A ref will be
+considered to match if it matches at least one positive refspec, and does
+not match any negative refspec. Negative refspecs can be useful to restrict
+the scope of a pattern refspec so that it will not include specific refs.
+Negative refspecs can themselves be pattern refspecs. However, they may only
+contain a <src> and do not specify a <dst>. Fully spelled out hex object
+names are also not supported.
++
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`;
it requests fetching everything up to the given tag.
+
diff --git a/Documentation/ref-reachability-filters.txt b/Documentation/ref-reachability-filters.txt
new file mode 100644
index 0000000..9bae46d
--- /dev/null
+++ b/Documentation/ref-reachability-filters.txt
@@ -0,0 +1,7 @@
+When combining multiple `--contains` and `--no-contains` filters, only
+references that contain at least one of the `--contains` commits and
+contain none of the `--no-contains` commits are shown.
+
+When combining multiple `--merged` and `--no-merged` filters, only
+references that are reachable from at least one of the `--merged`
+commits and from none of the `--no-merged` commits are shown.
diff --git a/Documentation/signoff-option.txt b/Documentation/signoff-option.txt
new file mode 100644
index 0000000..12aa233
--- /dev/null
+++ b/Documentation/signoff-option.txt
@@ -0,0 +1,18 @@
+ifdef::git-commit[]
+-s::
+endif::git-commit[]
+--signoff::
+--no-signoff::
+ Add a `Signed-off-by` trailer by the committer at the end of the commit
+ log message. The meaning of a signoff depends on the project
+ to which you're committing. For example, it may certify that
+ the committer has the rights to submit the work under the
+ project's license or agrees to some contributor representation,
+ such as a Developer Certificate of Origin.
+ (See http://developercertificate.org for the one used by the
+ Linux kernel and Git projects.) Consult the documentation or
+ leadership of the project to which you're contributing to
+ understand how the signoffs are used in that project.
++
+The --no-signoff option can be used to countermand an earlier --signoff
+option on the command line.
diff --git a/Documentation/technical/commit-graph-format.txt b/Documentation/technical/commit-graph-format.txt
index 4405410..b3b5888 100644
--- a/Documentation/technical/commit-graph-format.txt
+++ b/Documentation/technical/commit-graph-format.txt
@@ -42,8 +42,13 @@ HEADER:
1-byte version number:
Currently, the only valid version is 1.
- 1-byte Hash Version (1 = SHA-1)
- We infer the hash length (H) from this value.
+ 1-byte Hash Version
+ We infer the hash length (H) from this value:
+ 1 => SHA-1
+ 2 => SHA-256
+ If the hash type does not match the repository's hash algorithm, the
+ commit-graph file should be ignored with a warning presented to the
+ user.
1-byte number (C) of "chunks"
@@ -77,7 +82,7 @@ CHUNK DATA:
Commit Data (ID: {'C', 'D', 'A', 'T' }) (N * (H + 16) bytes)
* The first H bytes are for the OID of the root tree.
* The next 8 bytes are for the positions of the first two parents
- of the ith commit. Stores value 0x7000000 if no parent in that
+ of the ith commit. Stores value 0x70000000 if no parent in that
position. If there are more than two parents, the second value
has its most-significant bit on and the other bits store an array
position into the Extra Edge List chunk.
@@ -120,7 +125,7 @@ CHUNK DATA:
* 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.
+ of length one, with either all bits set to zero or one respectively.
* The BDAT chunk is present if and only if BIDX is present.
Base Graphs List (ID: {'B', 'A', 'S', 'E'}) [Optional]
diff --git a/Documentation/technical/commit-graph.txt b/Documentation/technical/commit-graph.txt
index 808fa30..f14a765 100644
--- a/Documentation/technical/commit-graph.txt
+++ b/Documentation/technical/commit-graph.txt
@@ -210,12 +210,12 @@ file.
+---------------------+
| |
+-----------------------+ +---------------------+
- | graph-{hash2} |->| |
+ | graph-{hash2} |->| |
+-----------------------+ +---------------------+
| | |
+-----------------------+ +---------------------+
| | | |
- | graph-{hash1} |->| |
+ | graph-{hash1} |->| |
| | | |
+-----------------------+ +---------------------+
| tmp_graphXXX
@@ -223,7 +223,7 @@ file.
| |
| |
| |
- | graph-{hash0} |
+ | graph-{hash0} |
| |
| |
| |
diff --git a/Documentation/technical/directory-rename-detection.txt b/Documentation/technical/directory-rename-detection.txt
index 844629c..49b83ef 100644
--- a/Documentation/technical/directory-rename-detection.txt
+++ b/Documentation/technical/directory-rename-detection.txt
@@ -18,7 +18,8 @@ It is perhaps easiest to start with an example:
More interesting possibilities exist, though, such as:
* one side of history renames x -> z, and the other renames some file to
- x/e, causing the need for the merge to do a transitive rename.
+ x/e, causing the need for the merge to do a transitive rename so that
+ the rename ends up at z/e.
* one side of history renames x -> z, but also renames all files within x.
For example, x/a -> z/alpha, x/b -> z/bravo, etc.
@@ -35,7 +36,7 @@ More interesting possibilities exist, though, such as:
directory itself contained inner directories that were renamed to yet
other locations).
- * combinations of the above; see t/t6043-merge-rename-directories.sh for
+ * combinations of the above; see t/t6423-merge-rename-directories.sh for
various interesting cases.
Limitations -- applicability of directory renames
@@ -62,19 +63,19 @@ directory rename detection applies:
Limitations -- detailed rules and testcases
-------------------------------------------
-t/t6043-merge-rename-directories.sh contains extensive tests and commentary
+t/t6423-merge-rename-directories.sh contains extensive tests and commentary
which generate and explore the rules listed above. It also lists a few
additional rules:
a) If renames split a directory into two or more others, the directory
with the most renames, "wins".
- b) Avoid directory-rename-detection for a path, if that path is the
- source of a rename on either side of a merge.
-
- c) Only apply implicit directory renames to directories if the other side
+ b) Only apply implicit directory renames to directories if the other side
of history is the one doing the renaming.
+ c) Do not perform directory rename detection for directories which had no
+ new paths added to them.
+
Limitations -- support in different commands
--------------------------------------------
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.txt
index 5b2db3b..6fd20eb 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.txt
@@ -650,7 +650,6 @@ Some initial steps can be implemented independently of one another:
The first user-visible change is the introduction of the objectFormat
extension (without compatObjectFormat). This requires:
-- implementing the loose-object-idx
- teaching fsck about this mode of operation
- using the hash function API (vtable) when computing object names
- signing objects and verifying signatures
@@ -658,6 +657,7 @@ extension (without compatObjectFormat). This requires:
repository
Next comes introduction of compatObjectFormat:
+- implementing the loose-object-idx
- translating object names between object formats
- translating object content between object formats
- generating and verifying signatures in the compat format
diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt
index 51a79e6..96d89ea 100644
--- a/Documentation/technical/http-protocol.txt
+++ b/Documentation/technical/http-protocol.txt
@@ -401,8 +401,9 @@ at all in the request stream:
The stream is terminated by a pkt-line flush (`0000`).
A single "want" or "have" command MUST have one hex formatted
-SHA-1 as its value. Multiple SHA-1s MUST be sent by sending
-multiple commands.
+object name as its value. Multiple object names MUST be sent by sending
+multiple commands. Object names MUST be given using the object format
+negotiated through the `object-format` capability (default SHA-1).
The `have` list is created by popping the first 32 commits
from `c_pending`. Less can be supplied if `c_pending` empties.
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index faa25c5..f9a3644 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -3,8 +3,11 @@ Git index format
== The Git index file has the following format
- All binary numbers are in network byte order. Version 2 is described
- here unless stated otherwise.
+ All binary numbers are in network byte order.
+ In a repository using the traditional SHA-1, checksums and object IDs
+ (object names) mentioned below are all computed using SHA-1. Similarly,
+ in SHA-256 repositories, these values are computed using SHA-256.
+ Version 2 is described here unless stated otherwise.
- A 12-byte header consisting of
@@ -32,8 +35,7 @@ Git index format
Extension data
- - 160-bit SHA-1 over the content of the index file before this
- checksum.
+ - Hash checksum over the content of the index file before this checksum.
== Index entry
@@ -80,7 +82,7 @@ Git index format
32-bit file size
This is the on-disk size from stat(2), truncated to 32-bit.
- 160-bit SHA-1 for the represented object
+ Object name for the represented object
A 16-bit 'flags' field split into (high to low bits)
@@ -160,8 +162,8 @@ Git index format
- A newline (ASCII 10); and
- - 160-bit object name for the object that would result from writing
- this span of index as a tree.
+ - Object name for the object that would result from writing this span
+ of index as a tree.
An entry can be in an invalidated state and is represented by having
a negative number in the entry_count field. In this case, there is no
@@ -198,7 +200,7 @@ Git index format
stage 1 to 3 (a missing stage is represented by "0" in this field);
and
- - At most three 160-bit object names of the entry in stages from 1 to 3
+ - At most three object names of the entry in stages from 1 to 3
(nothing is written for a missing stage).
=== Split index
@@ -211,8 +213,8 @@ Git index format
The extension consists of:
- - 160-bit SHA-1 of the shared index file. The shared index file path
- is $GIT_DIR/sharedindex.<SHA-1>. If all 160 bits are zero, the
+ - Hash of the shared index file. The shared index file path
+ is $GIT_DIR/sharedindex.<hash>. If all bits are zero, the
index does not require a shared index file.
- An ewah-encoded delete bitmap, each bit represents an entry in the
@@ -253,10 +255,10 @@ Git index format
- 32-bit dir_flags (see struct dir_struct)
- - 160-bit SHA-1 of $GIT_DIR/info/exclude. Null SHA-1 means the file
+ - Hash of $GIT_DIR/info/exclude. A null hash means the file
does not exist.
- - 160-bit SHA-1 of core.excludesfile. Null SHA-1 means the file does
+ - Hash of core.excludesfile. A null hash means the file does
not exist.
- NUL-terminated string of per-dir exclude file name. This usually
@@ -285,13 +287,13 @@ The remaining data of each directory block is grouped by type:
- An ewah bitmap, the n-th bit records "check-only" bit of
read_directory_recursive() for the n-th directory.
- - An ewah bitmap, the n-th bit indicates whether SHA-1 and stat data
+ - An ewah bitmap, the n-th bit indicates whether hash and stat data
is valid for the n-th directory and exists in the next data.
- An array of stat data. The n-th data corresponds with the n-th
"one" bit in the previous ewah bitmap.
- - An array of SHA-1. The n-th SHA-1 corresponds with the n-th "one" bit
+ - An array of hashes. The n-th hash corresponds with the n-th "one" bit
in the previous ewah bitmap.
- One NUL.
@@ -330,12 +332,12 @@ The remaining data of each directory block is grouped by type:
- 32-bit offset to the end of the index entries
- - 160-bit SHA-1 over the extension types and their sizes (but not
+ - Hash over the extension types and their sizes (but not
their contents). E.g. if we have "TREE" extension that is N-bytes
long, "REUC" extension that is M-bytes long, followed by "EOIE",
then the hash would be:
- SHA-1("TREE" + <binary representation of N> +
+ Hash("TREE" + <binary representation of N> +
"REUC" + <binary representation of M>)
== Index Entry Offset Table
diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt
index d3a142c..f96b2e6 100644
--- a/Documentation/technical/pack-format.txt
+++ b/Documentation/technical/pack-format.txt
@@ -1,6 +1,12 @@
Git pack format
===============
+== Checksums and object IDs
+
+In a repository using the traditional SHA-1, pack checksums, index checksums,
+and object IDs (object names) mentioned below are all computed using SHA-1.
+Similarly, in SHA-256 repositories, these values are computed using SHA-256.
+
== pack-*.pack files have the following format:
- A header appears at the beginning and consists of the following:
@@ -26,7 +32,7 @@ Git pack format
(deltified representation)
n-byte type and length (3-bit type, (n-1)*7+4-bit length)
- 20-byte base object name if OBJ_REF_DELTA or a negative relative
+ base object name if OBJ_REF_DELTA or a negative relative
offset from the delta object's position in the pack if this
is an OBJ_OFS_DELTA object
compressed delta data
@@ -34,7 +40,7 @@ Git pack format
Observation: length of each object is encoded in a variable
length format and is not constrained to 32-bit or anything.
- - The trailer records 20-byte SHA-1 checksum of all of the above.
+ - The trailer records a pack checksum of all of the above.
=== Object types
@@ -58,8 +64,8 @@ ofs-delta and ref-delta, which is only valid in a pack file.
Both ofs-delta and ref-delta store the "delta" to be applied to
another object (called 'base object') to reconstruct the object. The
-difference between them is, ref-delta directly encodes 20-byte base
-object name. If the base object is in the same pack, ofs-delta encodes
+difference between them is, ref-delta directly encodes base object
+name. If the base object is in the same pack, ofs-delta encodes
the offset of the base object in the pack instead.
The base object could also be deltified if it's in the same pack.
@@ -143,14 +149,14 @@ This is the instruction reserved for future expansion.
object is stored in the packfile as the offset from the
beginning.
- 20-byte object name.
+ one object name of the appropriate size.
- The file is concluded with a trailer:
- A copy of the 20-byte SHA-1 checksum at the end of
- corresponding packfile.
+ A copy of the pack checksum at the end of the corresponding
+ packfile.
- 20-byte SHA-1-checksum of all of the above.
+ Index checksum of all of the above.
Pack Idx file:
@@ -198,7 +204,7 @@ Pack file entry: <+
If it is not DELTA, then deflated bytes (the size above
is the size before compression).
If it is REF_DELTA, then
- 20-byte base object name SHA-1 (the size above is the
+ base object name (the size above is the
size of the delta data that follows).
delta data, deflated.
If it is OFS_DELTA, then
@@ -227,9 +233,9 @@ Pack file entry: <+
- A 256-entry fan-out table just like v1.
- - A table of sorted 20-byte SHA-1 object names. These are
- packed together without offset values to reduce the cache
- footprint of the binary search for a specific object name.
+ - A table of sorted object names. These are packed together
+ without offset values to reduce the cache footprint of the
+ binary search for a specific object name.
- A table of 4-byte CRC32 values of the packed object data.
This is new in v2 so compressed data can be copied directly
@@ -248,10 +254,10 @@ Pack file entry: <+
- The same trailer as a v1 pack file:
- A copy of the 20-byte SHA-1 checksum at the end of
+ A copy of the pack checksum at the end of
corresponding packfile.
- 20-byte SHA-1-checksum of all of the above.
+ Index checksum of all of the above.
== multi-pack-index (MIDX) files have the following format:
@@ -273,7 +279,12 @@ HEADER:
Git only writes or recognizes version 1.
1-byte Object Id Version
- Git only writes or recognizes version 1 (SHA1).
+ We infer the length of object IDs (OIDs) from this value:
+ 1 => SHA-1
+ 2 => SHA-256
+ If the hash type does not match the repository's hash algorithm,
+ the multi-pack-index file should be ignored with a warning
+ presented to the user.
1-byte number of "chunks"
@@ -329,4 +340,4 @@ CHUNK DATA:
TRAILER:
- 20-byte SHA1-checksum of the above contents.
+ Index checksum of the above contents.
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index a4573d1..e13a2c0 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -503,8 +503,8 @@ The reference discovery phase is done nearly the same way as it is in the
fetching protocol. Each reference obj-id and name on the server is sent
in packet-line format to the client, followed by a flush-pkt. The only
real difference is that the capability listing is different - the only
-possible values are 'report-status', 'delete-refs', 'ofs-delta' and
-'push-options'.
+possible values are 'report-status', 'report-status-v2', 'delete-refs',
+'ofs-delta', 'atomic' and 'push-options'.
Reference Update Request and Packfile Transfer
----------------------------------------------
@@ -625,7 +625,7 @@ Report Status
-------------
After receiving the pack data from the sender, the receiver sends a
-report if 'report-status' capability is in effect.
+report if 'report-status' or 'report-status-v2' capability is in effect.
It is a short listing of what happened in that update. It will first
list the status of the packfile unpacking as either 'unpack ok' or
'unpack [error]'. Then it will list the status for each of the references
@@ -647,6 +647,41 @@ update was successful, or 'ng [refname] [error]' if the update was not.
error-msg = 1*(OCTET) ; where not "ok"
----
+The 'report-status-v2' capability extends the protocol by adding new option
+lines in order to support reporting of reference rewritten by the
+'proc-receive' hook. The 'proc-receive' hook may handle a command for a
+pseudo-reference which may create or update one or more references, and each
+reference may have different name, different new-oid, and different old-oid.
+
+----
+ report-status-v2 = unpack-status
+ 1*(command-status-v2)
+ flush-pkt
+
+ unpack-status = PKT-LINE("unpack" SP unpack-result)
+ unpack-result = "ok" / error-msg
+
+ command-status-v2 = command-ok-v2 / command-fail
+ command-ok-v2 = command-ok
+ *option-line
+
+ command-ok = PKT-LINE("ok" SP refname)
+ command-fail = PKT-LINE("ng" SP refname SP error-msg)
+
+ error-msg = 1*(OCTET) ; where not "ok"
+
+ option-line = *1(option-refname)
+ *1(option-old-oid)
+ *1(option-new-oid)
+ *1(option-forced-update)
+
+ option-refname = PKT-LINE("option" SP "refname" SP refname)
+ option-old-oid = PKT-LINE("option" SP "old-oid" SP obj-id)
+ option-new-oid = PKT-LINE("option" SP "new-oid" SP obj-id)
+ option-force = PKT-LINE("option" SP "forced-update")
+
+----
+
Updates can be unsuccessful for a number of reasons. The reference can have
changed since the reference discovery phase was originally sent, meaning
someone pushed in the meantime. The reference being pushed could be a
diff --git a/Documentation/technical/partial-clone.txt b/Documentation/technical/partial-clone.txt
index b9e17e7..0780d30 100644
--- a/Documentation/technical/partial-clone.txt
+++ b/Documentation/technical/partial-clone.txt
@@ -171,20 +171,13 @@ additional flag.
Fetching Missing Objects
------------------------
-- Fetching of objects is done using the existing transport mechanism using
- transport_fetch_refs(), setting a new transport option
- TRANS_OPT_NO_DEPENDENTS to indicate that only the objects themselves are
- desired, not any object that they refer to.
-+
-Because some transports invoke fetch_pack() in the same process, fetch_pack()
-has been updated to not use any object flags when the corresponding argument
-(no_dependents) is set.
+- Fetching of objects is done by invoking a "git fetch" subprocess.
- The local repository sends a request with the hashes of all requested
- objects as "want" lines, and does not perform any packfile negotiation.
+ objects, and does not perform any packfile negotiation.
It then receives a packfile.
-- Because we are reusing the existing fetch-pack mechanism, fetching
+- Because we are reusing the existing fetch mechanism, fetching
currently fetches all objects referred to by the requested objects, even
though they are not necessary.
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index 36ccd14..ba869a7 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -22,9 +22,9 @@ was sent. Server MUST NOT ignore capabilities that client requested
and server advertised. As a consequence of these rules, server MUST
NOT advertise capabilities it does not understand.
-The 'atomic', 'report-status', 'delete-refs', 'quiet', and 'push-cert'
-capabilities are sent and recognized by the receive-pack (push to server)
-process.
+The 'atomic', 'report-status', 'report-status-v2', 'delete-refs', 'quiet',
+and 'push-cert' capabilities are sent and recognized by the receive-pack
+(push to server) process.
The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized
by both upload-pack and receive-pack protocols. The 'agent' capability
@@ -284,6 +284,17 @@ each reference was updated successfully. If any of those were not
successful, it will send back an error message. See pack-protocol.txt
for example messages.
+report-status-v2
+----------------
+
+Capability 'report-status-v2' extends capability 'report-status' by
+adding new "option" directives in order to support reference rewritten by
+the "proc-receive" hook. The "proc-receive" hook may handle a command
+for a pseudo-reference which may create or update a reference with
+different name, new-oid, and old-oid. While the capability
+'report-status' cannot report for such case. See pack-protocol.txt
+for details.
+
delete-refs
-----------
@@ -324,15 +335,19 @@ allow-tip-sha1-in-want
----------------------
If the upload-pack server advertises this capability, fetch-pack may
-send "want" lines with SHA-1s that exist at the server but are not
-advertised by upload-pack.
+send "want" lines with object names that exist at the server but are not
+advertised by upload-pack. For historical reasons, the name of this
+capability contains "sha1". Object names are always given using the
+object format negotiated through the 'object-format' capability.
allow-reachable-sha1-in-want
----------------------------
If the upload-pack server advertises this capability, fetch-pack may
-send "want" lines with SHA-1s that exist at the server but are not
-advertised by upload-pack.
+send "want" lines with object names that exist at the server but are not
+advertised by upload-pack. For historical reasons, the name of this
+capability contains "sha1". Object names are always given using the
+object format negotiated through the 'object-format' capability.
push-cert=<nonce>
-----------------
diff --git a/Documentation/technical/shallow.txt b/Documentation/technical/shallow.txt
index 01dedfe..f3738ba 100644
--- a/Documentation/technical/shallow.txt
+++ b/Documentation/technical/shallow.txt
@@ -13,7 +13,7 @@ pretend as if they are root commits (e.g. "git log" traversal
stops after showing them; "git fsck" does not complain saying
the commits listed on their "parent" lines do not exist).
-Each line contains exactly one SHA-1. When read, a commit_graft
+Each line contains exactly one object name. When read, a commit_graft
will be constructed, which has nr_parent < 0 to make it easier
to discern from user provided grafts.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 9db2f4f..82bcd13 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.28.0
+DEF_VER=v2.29.GIT
LF='
'
diff --git a/Makefile b/Makefile
index c39b39b..fea5ade 100644
--- a/Makefile
+++ b/Makefile
@@ -348,6 +348,9 @@ all::
# Define NO_INSTALL_HARDLINKS if you prefer to use either symbolic links or
# copies to install built-in git commands e.g. git-cat-file.
#
+# Define SKIP_DASHED_BUILT_INS if you do not need the dashed versions of the
+# built-ins to be linked/copied at all.
+#
# Define USE_NED_ALLOCATOR if you want to replace the platforms default
# memory allocators with the nedmalloc allocator written by Niall Douglas.
#
@@ -462,6 +465,12 @@ all::
# the global variable _wpgmptr containing the absolute path of the current
# executable (this is the case on Windows).
#
+# Define GENERATE_COMPILATION_DATABASE to "yes" to generate JSON compilation
+# database entries during compilation if your compiler supports it, using the
+# `-MJ` flag. The JSON entries will be placed in the `compile_commands/`
+# directory, and the JSON compilation database 'compile_commands.json' will be
+# created at the root of the repository.
+#
# Define DEVELOPER to enable more compiler warnings. Compiler version
# and family are auto detected, but could be overridden by defining
# COMPILER_FEATURES (see config.mak.dev). You can still set
@@ -569,7 +578,6 @@ BUILT_INS =
COMPAT_CFLAGS =
COMPAT_OBJS =
XDIFF_OBJS =
-VCSSVN_OBJS =
GENERATED_H =
EXTRA_CPPFLAGS =
FUZZ_OBJS =
@@ -671,13 +679,9 @@ 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
@@ -720,6 +724,7 @@ TEST_BUILTINS_OBJS += test-parse-pathspec-file.o
TEST_BUILTINS_OBJS += test-path-utils.o
TEST_BUILTINS_OBJS += test-pkt-line.o
TEST_BUILTINS_OBJS += test-prio-queue.o
+TEST_BUILTINS_OBJS += test-proc-receive.o
TEST_BUILTINS_OBJS += test-progress.o
TEST_BUILTINS_OBJS += test-reach.o
TEST_BUILTINS_OBJS += test-read-cache.o
@@ -750,8 +755,6 @@ 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.
TEST_PROGRAMS_NEED_X += test-fake-ssh
-TEST_PROGRAMS_NEED_X += test-line-buffer
-TEST_PROGRAMS_NEED_X += test-svn-fe
TEST_PROGRAMS_NEED_X += test-tool
TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
@@ -776,6 +779,16 @@ BUILT_INS += git-whatchanged$X
# what 'all' will build and 'install' will install in gitexecdir,
# excluding programs for built-in commands
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
+ALL_COMMANDS_TO_INSTALL = $(ALL_PROGRAMS)
+ifeq (,$(SKIP_DASHED_BUILT_INS))
+ALL_COMMANDS_TO_INSTALL += $(BUILT_INS)
+else
+# git-upload-pack, git-receive-pack and git-upload-archive are special: they
+# are _expected_ to be present in the `bin/` directory in their dashed form.
+ALL_COMMANDS_TO_INSTALL += git-receive-pack$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-archive$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X)
+endif
# what 'all' will build but not install in gitexecdir
OTHER_PROGRAMS = git$X
@@ -807,10 +820,9 @@ TEST_SHELL_PATH = $(SHELL_PATH)
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
+GENERATED_H += config-list.h
LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \
$(FIND) . \
@@ -892,7 +904,6 @@ LIB_OBJS += hashmap.o
LIB_OBJS += help.o
LIB_OBJS += hex.o
LIB_OBJS += ident.o
-LIB_OBJS += interdiff.o
LIB_OBJS += json-writer.o
LIB_OBJS += kwset.o
LIB_OBJS += levenshtein.o
@@ -917,6 +928,7 @@ LIB_OBJS += mergesort.o
LIB_OBJS += midx.o
LIB_OBJS += name-hash.o
LIB_OBJS += negotiator/default.o
+LIB_OBJS += negotiator/noop.o
LIB_OBJS += negotiator/skipping.o
LIB_OBJS += notes-cache.o
LIB_OBJS += notes-merge.o
@@ -958,6 +970,7 @@ LIB_OBJS += rebase.o
LIB_OBJS += ref-filter.o
LIB_OBJS += reflog-walk.o
LIB_OBJS += refs.o
+LIB_OBJS += refs/debug.o
LIB_OBJS += refs/files-backend.o
LIB_OBJS += refs/iterator.o
LIB_OBJS += refs/packed-backend.o
@@ -986,9 +999,9 @@ LIB_OBJS += sigchain.o
LIB_OBJS += split-index.o
LIB_OBJS += stable-qsort.o
LIB_OBJS += strbuf.o
-LIB_OBJS += strvec.o
LIB_OBJS += streaming.o
LIB_OBJS += string-list.o
+LIB_OBJS += strvec.o
LIB_OBJS += sub-process.o
LIB_OBJS += submodule-config.o
LIB_OBJS += submodule.o
@@ -1043,6 +1056,7 @@ BUILTIN_OBJS += builtin/archive.o
BUILTIN_OBJS += builtin/bisect--helper.o
BUILTIN_OBJS += builtin/blame.o
BUILTIN_OBJS += builtin/branch.o
+BUILTIN_OBJS += builtin/bugreport.o
BUILTIN_OBJS += builtin/bundle.o
BUILTIN_OBJS += builtin/cat-file.o
BUILTIN_OBJS += builtin/check-attr.o
@@ -1059,6 +1073,9 @@ BUILTIN_OBJS += builtin/commit-tree.o
BUILTIN_OBJS += builtin/commit.o
BUILTIN_OBJS += builtin/config.o
BUILTIN_OBJS += builtin/count-objects.o
+BUILTIN_OBJS += builtin/credential-cache--daemon.o
+BUILTIN_OBJS += builtin/credential-cache.o
+BUILTIN_OBJS += builtin/credential-store.o
BUILTIN_OBJS += builtin/credential.o
BUILTIN_OBJS += builtin/describe.o
BUILTIN_OBJS += builtin/diff-files.o
@@ -1068,6 +1085,7 @@ BUILTIN_OBJS += builtin/diff.o
BUILTIN_OBJS += builtin/difftool.o
BUILTIN_OBJS += builtin/env--helper.o
BUILTIN_OBJS += builtin/fast-export.o
+BUILTIN_OBJS += builtin/fast-import.o
BUILTIN_OBJS += builtin/fetch-pack.o
BUILTIN_OBJS += builtin/fetch.o
BUILTIN_OBJS += builtin/fmt-merge-msg.o
@@ -1216,7 +1234,6 @@ SANITIZERS := $(foreach flag,$(subst $(comma),$(space),$(SANITIZE)),$(flag))
BASIC_CFLAGS += -fsanitize=$(SANITIZE) -fno-sanitize-recover=$(SANITIZE)
BASIC_CFLAGS += -fno-omit-frame-pointer
ifneq ($(filter undefined,$(SANITIZERS)),)
-BASIC_CFLAGS += -DNO_UNALIGNED_LOADS
BASIC_CFLAGS += -DSHA1DC_FORCE_ALIGNED_ACCESS
endif
ifneq ($(filter leak,$(SANITIZERS)),)
@@ -1260,6 +1277,27 @@ $(error please set COMPUTE_HEADER_DEPENDENCIES to yes, no, or auto \
endif
endif
+ifndef GENERATE_COMPILATION_DATABASE
+GENERATE_COMPILATION_DATABASE = no
+endif
+
+ifeq ($(GENERATE_COMPILATION_DATABASE),yes)
+compdb_check = $(shell $(CC) $(ALL_CFLAGS) \
+ -c -MJ /dev/null \
+ -x c /dev/null -o /dev/null 2>&1; \
+ echo $$?)
+ifneq ($(compdb_check),0)
+override GENERATE_COMPILATION_DATABASE = no
+$(warning GENERATE_COMPILATION_DATABASE is set to "yes", but your compiler does not \
+support generating compilation database entries)
+endif
+else
+ifneq ($(GENERATE_COMPILATION_DATABASE),no)
+$(error please set GENERATE_COMPILATION_DATABASE to "yes" or "no" \
+(not "$(GENERATE_COMPILATION_DATABASE)"))
+endif
+endif
+
ifdef SANE_TOOL_PATH
SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH))
BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|'
@@ -1636,11 +1674,8 @@ ifdef NO_INET_PTON
endif
ifdef NO_UNIX_SOCKETS
BASIC_CFLAGS += -DNO_UNIX_SOCKETS
- EXCLUDED_PROGRAMS += git-credential-cache git-credential-cache--daemon
else
LIB_OBJS += unix-socket.o
- PROGRAM_OBJS += credential-cache.o
- PROGRAM_OBJS += credential-cache--daemon.o
endif
ifdef NO_ICONV
@@ -2068,9 +2103,9 @@ profile-fast: profile-clean
$(MAKE) PROFILE=USE all
-all:: $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
+all:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
ifneq (,$X)
- $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
+ $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
endif
all::
@@ -2348,16 +2383,9 @@ XDIFF_OBJS += xdiff/xpatience.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/svndiff.o
-VCSSVN_OBJS += vcs-svn/svndump.o
-
TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
$(XDIFF_OBJS) \
- $(VCSSVN_OBJS) \
$(FUZZ_OBJS) \
common-main.o \
git.o
@@ -2383,16 +2411,30 @@ missing_dep_dirs =
dep_args =
endif
+compdb_dir = compile_commands
+
+ifeq ($(GENERATE_COMPILATION_DATABASE),yes)
+missing_compdb_dir = $(compdb_dir)
+$(missing_compdb_dir):
+ @mkdir -p $@
+
+compdb_file = $(compdb_dir)/$(subst /,-,$@.json)
+compdb_args = -MJ $(compdb_file)
+else
+missing_compdb_dir =
+compdb_args =
+endif
+
ASM_SRC := $(wildcard $(OBJECTS:o=S))
ASM_OBJ := $(ASM_SRC:S=o)
C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
.SUFFIXES:
-$(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
- $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
-$(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
- $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(missing_compdb_dir)
+ $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(compdb_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+$(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(missing_compdb_dir)
+ $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(compdb_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
%.s: %.c GIT-CFLAGS FORCE
$(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
@@ -2415,6 +2457,14 @@ else
$(OBJECTS): $(LIB_H) $(GENERATED_H)
endif
+ifeq ($(GENERATE_COMPILATION_DATABASE),yes)
+all:: compile_commands.json
+compile_commands.json:
+ @$(RM) $@
+ $(QUIET_GEN)sed -e '1s/^/[/' -e '$$s/,$$/]/' $(compdb_dir)/*.o.json > $@+
+ @if test -s $@+; then mv $@+ $@; else $(RM) $@+; fi
+endif
+
exec-cmd.sp exec-cmd.s exec-cmd.o: GIT-PREFIX
exec-cmd.sp exec-cmd.s exec-cmd.o: EXTRA_CPPFLAGS = \
'-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
@@ -2461,10 +2511,6 @@ 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)
@@ -2476,10 +2522,6 @@ git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
-git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
- $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) \
- $(VCSSVN_LIB)
-
$(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
$(QUIET_LNCP)$(RM) $@ && \
ln $< $@ 2>/dev/null || \
@@ -2496,9 +2538,6 @@ $(LIB_FILE): $(LIB_OBJS)
$(XDIFF_LIB): $(XDIFF_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-$(VCSSVN_LIB): $(VCSSVN_OBJS)
- $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-
export DEFAULT_EDITOR DEFAULT_PAGER
Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
@@ -2731,6 +2770,9 @@ endif
ifdef GIT_TEST_INDEX_VERSION
@echo GIT_TEST_INDEX_VERSION=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_INDEX_VERSION)))'\' >>$@+
endif
+ifdef GIT_TEST_PERL_FATAL_WARNINGS
+ @echo GIT_TEST_PERL_FATAL_WARNINGS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_PERL_FATAL_WARNINGS)))'\' >>$@+
+endif
@if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
### Detect Python interpreter path changes
@@ -2773,10 +2815,6 @@ perf: all
.PHONY: test perf
-t/helper/test-line-buffer$X: $(VCSSVN_LIB)
-
-t/helper/test-svn-fe$X: $(VCSSVN_LIB)
-
.PRECIOUS: $(TEST_OBJS)
t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
@@ -2901,20 +2939,8 @@ ifdef MSVC
# have already been rolled up into the exe's pdb file.
# We DO NOT have pdb files for the builtin commands (like git-status.exe)
# because it is just a copy/hardlink of git.exe, rather than a unique binary.
- $(INSTALL) git.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
- $(INSTALL) git-shell.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
- $(INSTALL) git-upload-pack.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
- $(INSTALL) git-credential-store.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-daemon.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-fast-import.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-http-backend.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-http-fetch.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-http-push.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-imap-send.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-remote-http.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-remote-testsvn.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-sh-i18n--envsubst.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-show-index.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+ $(INSTALL) $(patsubst %.exe,%.pdb,$(filter-out $(BUILT_INS),$(patsubst %,%$X,$(BINDIR_PROGRAMS_NEED_X)))) '$(DESTDIR_SQ)$(bindir_SQ)'
+ $(INSTALL) $(patsubst %.exe,%.pdb,$(filter-out $(BUILT_INS) $(REMOTE_CURL_ALIASES),$(PROGRAMS))) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
ifndef DEBUG
$(INSTALL) $(vcpkg_rel_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
$(INSTALL) $(vcpkg_rel_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
@@ -2942,7 +2968,7 @@ ifndef NO_TCLTK
$(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
endif
ifneq (,$X)
- $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
+ $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
endif
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
@@ -2965,16 +2991,19 @@ endif
{ test -z "$(NO_INSTALL_HARDLINKS)" && \
ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
- cp "$$bindir/git$X" "$$bindir/$$p" || exit; } \
+ cp "$$bindir/git$X" "$$bindir/$$p" || exit; }; \
done && \
for p in $(BUILT_INS); do \
$(RM) "$$execdir/$$p" && \
- test -n "$(INSTALL_SYMLINKS)" && \
- ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/git$X" "$$execdir/$$p" || \
- { test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
- ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
- cp "$$execdir/git$X" "$$execdir/$$p" || exit; } \
+ if test -z "$(SKIP_DASHED_BUILT_INS)"; \
+ then \
+ test -n "$(INSTALL_SYMLINKS)" && \
+ ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/git$X" "$$execdir/$$p" || \
+ { test -z "$(NO_INSTALL_HARDLINKS)" && \
+ ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
+ ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
+ cp "$$execdir/git$X" "$$execdir/$$p" || exit; }; \
+ fi \
done && \
remote_curl_aliases="$(REMOTE_CURL_ALIASES)" && \
for p in $$remote_curl_aliases; do \
@@ -3027,32 +3056,29 @@ quick-install-html:
### Maintainer's dist rules
GIT_TARNAME = git-$(GIT_VERSION)
+GIT_ARCHIVE_EXTRA_FILES = \
+ --prefix=$(GIT_TARNAME)/ \
+ --add-file=configure \
+ --add-file=$(GIT_TARNAME)/version \
+ --prefix=$(GIT_TARNAME)/git-gui/ \
+ --add-file=$(GIT_TARNAME)/git-gui/version
+ifdef DC_SHA1_SUBMODULE
+GIT_ARCHIVE_EXTRA_FILES += \
+ --prefix=$(GIT_TARNAME)/sha1collisiondetection/ \
+ --add-file=sha1collisiondetection/LICENSE.txt \
+ --prefix=$(GIT_TARNAME)/sha1collisiondetection/lib/ \
+ --add-file=sha1collisiondetection/lib/sha1.c \
+ --add-file=sha1collisiondetection/lib/sha1.h \
+ --add-file=sha1collisiondetection/lib/ubc_check.c \
+ --add-file=sha1collisiondetection/lib/ubc_check.h
+endif
dist: git-archive$(X) configure
- ./git-archive --format=tar \
- --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
@mkdir -p $(GIT_TARNAME)
- @cp configure $(GIT_TARNAME)
@echo $(GIT_VERSION) > $(GIT_TARNAME)/version
@$(MAKE) -C git-gui TARDIR=../$(GIT_TARNAME)/git-gui dist-version
- $(TAR) rf $(GIT_TARNAME).tar \
- $(GIT_TARNAME)/configure \
- $(GIT_TARNAME)/version \
- $(GIT_TARNAME)/git-gui/version
-ifdef DC_SHA1_SUBMODULE
- @mkdir -p $(GIT_TARNAME)/sha1collisiondetection/lib
- @cp sha1collisiondetection/LICENSE.txt \
- $(GIT_TARNAME)/sha1collisiondetection/
- @cp sha1collisiondetection/LICENSE.txt \
- $(GIT_TARNAME)/sha1collisiondetection/
- @cp sha1collisiondetection/lib/sha1.[ch] \
- $(GIT_TARNAME)/sha1collisiondetection/lib/
- @cp sha1collisiondetection/lib/ubc_check.[ch] \
- $(GIT_TARNAME)/sha1collisiondetection/lib/
- $(TAR) rf $(GIT_TARNAME).tar \
- $(GIT_TARNAME)/sha1collisiondetection/LICENSE.txt \
- $(GIT_TARNAME)/sha1collisiondetection/lib/sha1.[ch] \
- $(GIT_TARNAME)/sha1collisiondetection/lib/ubc_check.[ch]
-endif
+ ./git-archive --format=tar \
+ $(GIT_ARCHIVE_EXTRA_FILES) \
+ --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
@$(RM) -r $(GIT_TARNAME)
gzip -f -9 $(GIT_TARNAME).tar
@@ -3065,7 +3091,7 @@ ifneq ($(INCLUDE_DLLS_IN_ARTIFACTS),)
OTHER_PROGRAMS += $(shell echo *.dll t/helper/*.dll)
endif
-artifacts-tar:: $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) \
+artifacts-tar:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) \
GIT-BUILD-OPTIONS $(TEST_PROGRAMS) $(test_bindir_programs) \
$(MOFILES)
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) \
@@ -3078,11 +3104,15 @@ artifacts-tar:: $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) \
htmldocs = git-htmldocs-$(GIT_VERSION)
manpages = git-manpages-$(GIT_VERSION)
.PHONY: dist-doc distclean
-dist-doc:
+dist-doc: git$X
$(RM) -r .doc-tmp-dir
mkdir .doc-tmp-dir
$(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
- cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
+ ./git -C .doc-tmp-dir init
+ ./git -C .doc-tmp-dir add .
+ ./git -C .doc-tmp-dir commit -m htmldocs
+ ./git -C .doc-tmp-dir archive --format=tar --prefix=./ HEAD^{tree} \
+ > $(htmldocs).tar
gzip -n -9 -f $(htmldocs).tar
:
$(RM) -r .doc-tmp-dir
@@ -3092,7 +3122,11 @@ dist-doc:
man5dir=../.doc-tmp-dir/man5 \
man7dir=../.doc-tmp-dir/man7 \
install
- cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
+ ./git -C .doc-tmp-dir init
+ ./git -C .doc-tmp-dir add .
+ ./git -C .doc-tmp-dir commit -m manpages
+ ./git -C .doc-tmp-dir archive --format=tar --prefix=./ HEAD^{tree} \
+ > $(manpages).tar
gzip -n -9 -f $(manpages).tar
$(RM) -r .doc-tmp-dir
@@ -3114,12 +3148,12 @@ cocciclean:
clean: profile-clean coverage-clean cocciclean
$(RM) *.res
$(RM) $(OBJECTS)
- $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
+ $(RM) $(LIB_FILE) $(XDIFF_LIB)
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
$(RM) $(TEST_PROGRAMS)
$(RM) $(FUZZ_PROGRAMS)
$(RM) $(HCC)
- $(RM) -r bin-wrappers $(dep_dirs)
+ $(RM) -r bin-wrappers $(dep_dirs) $(compdb_dir) compile_commands.json
$(RM) -r po/build/
$(RM) *.pyc *.pyo */*.pyc */*.pyo $(GENERATED_H) $(ETAGS_TARGET) tags cscope*
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
@@ -3160,7 +3194,7 @@ endif
### Check documentation
#
-ALL_COMMANDS = $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS)
+ALL_COMMANDS = $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB)
ALL_COMMANDS += git
ALL_COMMANDS += git-citool
ALL_COMMANDS += git-gui
@@ -3200,7 +3234,7 @@ check-docs::
-e 's/\.txt//'; \
) | while read how cmd; \
do \
- case " $(patsubst %$X,%,$(ALL_COMMANDS) $(EXCLUDED_PROGRAMS)) " in \
+ case " $(patsubst %$X,%,$(ALL_COMMANDS) $(BUILT_INS) $(EXCLUDED_PROGRAMS)) " in \
*" $$cmd "*) ;; \
*) echo "removed but $$how: $$cmd" ;; \
esac; \
diff --git a/RelNotes b/RelNotes
index 9143650..dc8c04b 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.29.0.txt \ No newline at end of file
+Documentation/RelNotes/2.30.0.txt \ No newline at end of file
diff --git a/add-patch.c b/add-patch.c
index f67b304..be4cf6e 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -266,6 +266,20 @@ struct add_p_state {
const char *revision;
};
+static void add_p_state_clear(struct add_p_state *s)
+{
+ size_t i;
+
+ strbuf_release(&s->answer);
+ strbuf_release(&s->buf);
+ strbuf_release(&s->plain);
+ strbuf_release(&s->colored);
+ for (i = 0; i < s->file_diff_nr; i++)
+ free(s->file_diff[i].hunk);
+ free(s->file_diff);
+ clear_add_i_state(&s->s);
+}
+
static void err(struct add_p_state *s, const char *fmt, ...)
{
va_list args;
@@ -451,17 +465,15 @@ 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, *added = NULL, *mode_change = NULL;
+ const char *deleted = NULL, *mode_change = NULL;
if (!eol)
eol = pend;
if (starts_with(p, "diff ")) {
- s->file_diff_nr++;
- ALLOC_GROW(s->file_diff, s->file_diff_nr,
+ ALLOC_GROW_BY(s->file_diff, s->file_diff_nr, 1,
file_diff_alloc);
file_diff = s->file_diff + s->file_diff_nr - 1;
- memset(file_diff, 0, sizeof(*file_diff));
hunk = &file_diff->head;
hunk->start = p - plain->buf;
if (colored_p)
@@ -470,12 +482,11 @@ 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 || file_diff->added)
+ else if (file_diff->deleted)
; /* 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, "new file", &added)))) {
+ (skip_prefix(p, "deleted file", &deleted)))) {
if (marker == '-' || marker == '+')
/*
* Should not happen; previous hunk did not end
@@ -483,11 +494,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
*/
hunk->splittable_into++;
- file_diff->hunk_nr++;
- ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
+ ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
file_diff->hunk_alloc);
hunk = file_diff->hunk + file_diff->hunk_nr - 1;
- memset(hunk, 0, sizeof(*hunk));
hunk->start = p - plain->buf;
if (colored)
@@ -495,8 +504,6 @@ 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;
@@ -506,12 +513,15 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
*/
marker = *p;
} else if (hunk == &file_diff->head &&
+ starts_with(p, "new file")) {
+ file_diff->added = 1;
+ } else if (hunk == &file_diff->head &&
skip_prefix(p, "old mode ", &mode_change) &&
is_octal(mode_change, eol - mode_change)) {
if (file_diff->mode_change)
BUG("double mode change?\n\n%.*s",
(int)(eol - plain->buf), plain->buf);
- if (file_diff->hunk_nr++)
+ if (file_diff->hunk_nr)
BUG("mode change in the middle?\n\n%.*s",
(int)(eol - plain->buf), plain->buf);
@@ -520,9 +530,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
* is _part of_ the header "hunk".
*/
file_diff->mode_change = 1;
- ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
+ ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
file_diff->hunk_alloc);
- memset(file_diff->hunk, 0, sizeof(struct hunk));
file_diff->hunk->start = p - plain->buf;
if (colored_p)
file_diff->hunk->colored_start =
@@ -1357,8 +1366,18 @@ static int patch_update_file(struct add_p_state *s,
struct child_process cp = CHILD_PROCESS_INIT;
int colored = !!s->colored.len, quit = 0;
enum prompt_mode_type prompt_mode_type;
-
- if (!file_diff->hunk_nr)
+ enum {
+ ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
+ ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK = 1 << 1,
+ ALLOW_GOTO_NEXT_HUNK = 1 << 2,
+ ALLOW_GOTO_NEXT_UNDECIDED_HUNK = 1 << 3,
+ ALLOW_SEARCH_AND_GOTO = 1 << 4,
+ ALLOW_SPLIT = 1 << 5,
+ ALLOW_EDIT = 1 << 6
+ } permitted = 0;
+
+ /* Empty added files have no hunks */
+ if (!file_diff->hunk_nr && !file_diff->added)
return 0;
strbuf_reset(&s->buf);
@@ -1367,21 +1386,25 @@ static int patch_update_file(struct add_p_state *s,
for (;;) {
if (hunk_index >= file_diff->hunk_nr)
hunk_index = 0;
- hunk = file_diff->hunk + hunk_index;
-
+ hunk = file_diff->hunk_nr
+ ? file_diff->hunk + hunk_index
+ : &file_diff->head;
undecided_previous = -1;
- for (i = hunk_index - 1; i >= 0; i--)
- if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
- undecided_previous = i;
- break;
- }
-
undecided_next = -1;
- for (i = hunk_index + 1; i < file_diff->hunk_nr; i++)
- if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
- undecided_next = i;
- break;
- }
+
+ if (file_diff->hunk_nr) {
+ for (i = hunk_index - 1; i >= 0; i--)
+ if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
+ undecided_previous = i;
+ break;
+ }
+
+ for (i = hunk_index + 1; i < file_diff->hunk_nr; i++)
+ if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
+ undecided_next = i;
+ break;
+ }
+ }
/* Everything decided? */
if (undecided_previous < 0 && undecided_next < 0 &&
@@ -1389,26 +1412,41 @@ static int patch_update_file(struct add_p_state *s,
break;
strbuf_reset(&s->buf);
- render_hunk(s, hunk, 0, colored, &s->buf);
- fputs(s->buf.buf, stdout);
-
- strbuf_reset(&s->buf);
- if (undecided_previous >= 0)
- strbuf_addstr(&s->buf, ",k");
- if (hunk_index)
- strbuf_addstr(&s->buf, ",K");
- if (undecided_next >= 0)
- strbuf_addstr(&s->buf, ",j");
- if (hunk_index + 1 < file_diff->hunk_nr)
- strbuf_addstr(&s->buf, ",J");
- if (file_diff->hunk_nr > 1)
- strbuf_addstr(&s->buf, ",g,/");
- if (hunk->splittable_into > 1)
- strbuf_addstr(&s->buf, ",s");
- if (hunk_index + 1 > file_diff->mode_change &&
- !file_diff->deleted)
- strbuf_addstr(&s->buf, ",e");
+ if (file_diff->hunk_nr) {
+ render_hunk(s, hunk, 0, colored, &s->buf);
+ fputs(s->buf.buf, stdout);
+ strbuf_reset(&s->buf);
+ if (undecided_previous >= 0) {
+ permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK;
+ strbuf_addstr(&s->buf, ",k");
+ }
+ if (hunk_index) {
+ permitted |= ALLOW_GOTO_PREVIOUS_HUNK;
+ strbuf_addstr(&s->buf, ",K");
+ }
+ if (undecided_next >= 0) {
+ permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK;
+ strbuf_addstr(&s->buf, ",j");
+ }
+ if (hunk_index + 1 < file_diff->hunk_nr) {
+ permitted |= ALLOW_GOTO_NEXT_HUNK;
+ strbuf_addstr(&s->buf, ",J");
+ }
+ if (file_diff->hunk_nr > 1) {
+ permitted |= ALLOW_SEARCH_AND_GOTO;
+ strbuf_addstr(&s->buf, ",g,/");
+ }
+ if (hunk->splittable_into > 1) {
+ permitted |= ALLOW_SPLIT;
+ strbuf_addstr(&s->buf, ",s");
+ }
+ if (hunk_index + 1 > file_diff->mode_change &&
+ !file_diff->deleted) {
+ permitted |= ALLOW_EDIT;
+ strbuf_addstr(&s->buf, ",e");
+ }
+ }
if (file_diff->deleted)
prompt_mode_type = PROMPT_DELETION;
else if (file_diff->added)
@@ -1421,7 +1459,9 @@ static int patch_update_file(struct add_p_state *s,
color_fprintf(stdout, s->s.prompt_color,
"(%"PRIuMAX"/%"PRIuMAX") ",
(uintmax_t)hunk_index + 1,
- (uintmax_t)file_diff->hunk_nr);
+ (uintmax_t)(file_diff->hunk_nr
+ ? file_diff->hunk_nr
+ : 1));
color_fprintf(stdout, s->s.prompt_color,
_(s->mode->prompt_mode[prompt_mode_type]),
s->buf.buf);
@@ -1441,38 +1481,46 @@ soft_increment:
hunk->use = SKIP_HUNK;
goto soft_increment;
} else if (ch == 'a') {
- for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
- hunk = file_diff->hunk + hunk_index;
- if (hunk->use == UNDECIDED_HUNK)
- hunk->use = USE_HUNK;
+ if (file_diff->hunk_nr) {
+ for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
+ hunk = file_diff->hunk + hunk_index;
+ if (hunk->use == UNDECIDED_HUNK)
+ hunk->use = USE_HUNK;
+ }
+ } else if (hunk->use == UNDECIDED_HUNK) {
+ hunk->use = USE_HUNK;
}
} else if (ch == 'd' || ch == 'q') {
- for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
- hunk = file_diff->hunk + hunk_index;
- if (hunk->use == UNDECIDED_HUNK)
- hunk->use = SKIP_HUNK;
+ if (file_diff->hunk_nr) {
+ for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
+ hunk = file_diff->hunk + hunk_index;
+ if (hunk->use == UNDECIDED_HUNK)
+ hunk->use = SKIP_HUNK;
+ }
+ } else if (hunk->use == UNDECIDED_HUNK) {
+ hunk->use = SKIP_HUNK;
}
if (ch == 'q') {
quit = 1;
break;
}
} else if (s->answer.buf[0] == 'K') {
- if (hunk_index)
+ if (permitted & ALLOW_GOTO_PREVIOUS_HUNK)
hunk_index--;
else
err(s, _("No previous hunk"));
} else if (s->answer.buf[0] == 'J') {
- if (hunk_index + 1 < file_diff->hunk_nr)
+ if (permitted & ALLOW_GOTO_NEXT_HUNK)
hunk_index++;
else
err(s, _("No next hunk"));
} else if (s->answer.buf[0] == 'k') {
- if (undecided_previous >= 0)
+ if (permitted & ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK)
hunk_index = undecided_previous;
else
err(s, _("No previous hunk"));
} else if (s->answer.buf[0] == 'j') {
- if (undecided_next >= 0)
+ if (permitted & ALLOW_GOTO_NEXT_UNDECIDED_HUNK)
hunk_index = undecided_next;
else
err(s, _("No next hunk"));
@@ -1480,7 +1528,7 @@ soft_increment:
char *pend;
unsigned long response;
- if (file_diff->hunk_nr < 2) {
+ if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
err(s, _("No other hunks to goto"));
continue;
}
@@ -1517,7 +1565,7 @@ soft_increment:
regex_t regex;
int ret;
- if (file_diff->hunk_nr < 2) {
+ if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
err(s, _("No other hunks to search"));
continue;
}
@@ -1562,7 +1610,7 @@ soft_increment:
hunk_index = i;
} else if (s->answer.buf[0] == 's') {
size_t splittable_into = hunk->splittable_into;
- if (splittable_into < 2)
+ if (!(permitted & ALLOW_SPLIT))
err(s, _("Sorry, cannot split this hunk"));
else if (!split_hunk(s, file_diff,
hunk - file_diff->hunk))
@@ -1570,7 +1618,7 @@ soft_increment:
_("Split into %d hunks."),
(int)splittable_into);
} else if (s->answer.buf[0] == 'e') {
- if (hunk_index + 1 == file_diff->mode_change)
+ if (!(permitted & ALLOW_EDIT))
err(s, _("Sorry, cannot edit this hunk"));
else if (edit_hunk_loop(s, file_diff, hunk) >= 0) {
hunk->use = USE_HUNK;
@@ -1608,7 +1656,8 @@ soft_increment:
if (file_diff->hunk[i].use == USE_HUNK)
break;
- if (i < file_diff->hunk_nr) {
+ if (i < file_diff->hunk_nr ||
+ (!file_diff->hunk_nr && file_diff->head.use == USE_HUNK)) {
/* At least one hunk selected: apply */
strbuf_reset(&s->buf);
reassemble_patch(s, file_diff, 0, &s->buf);
@@ -1624,7 +1673,7 @@ soft_increment:
NULL, 0, NULL, 0))
error(_("'git apply' failed"));
}
- if (!repo_read_index(s->s.r))
+ if (repo_read_index(s->s.r) >= 0)
repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
1, NULL, NULL, NULL);
}
@@ -1646,6 +1695,14 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
if (mode == ADD_P_STASH)
s.mode = &patch_mode_stash;
else if (mode == ADD_P_RESET) {
+ /*
+ * NEEDSWORK: Instead of comparing to the literal "HEAD",
+ * compare the commit objects instead so that other ways of
+ * saying the same thing (such as "@") are also handled
+ * appropriately.
+ *
+ * This applies to the cases below too.
+ */
if (!revision || !strcmp(revision, "HEAD"))
s.mode = &patch_mode_reset_head;
else
@@ -1673,9 +1730,7 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
NULL, NULL, NULL) < 0) ||
parse_diff(&s, ps) < 0) {
- strbuf_release(&s.plain);
- strbuf_release(&s.colored);
- clear_add_i_state(&s.s);
+ add_p_state_clear(&s);
return -1;
}
@@ -1690,10 +1745,6 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
else if (binary_count == s.file_diff_nr)
fprintf(stderr, _("Only binary files changed.\n"));
- strbuf_release(&s.answer);
- strbuf_release(&s.buf);
- strbuf_release(&s.plain);
- strbuf_release(&s.colored);
- clear_add_i_state(&s.s);
+ add_p_state_clear(&s);
return 0;
}
diff --git a/advice.c b/advice.c
index f0a3d32..1647423 100644
--- a/advice.c
+++ b/advice.c
@@ -11,6 +11,7 @@ int advice_push_already_exists = 1;
int advice_push_fetch_first = 1;
int advice_push_needs_force = 1;
int advice_push_unqualified_ref_name = 1;
+int advice_push_ref_needs_update = 1;
int advice_status_hints = 1;
int advice_status_u_option = 1;
int advice_status_ahead_behind_warning = 1;
@@ -72,6 +73,7 @@ static struct {
{ "pushFetchFirst", &advice_push_fetch_first },
{ "pushNeedsForce", &advice_push_needs_force },
{ "pushUnqualifiedRefName", &advice_push_unqualified_ref_name },
+ { "pushRefNeedsUpdate", &advice_push_ref_needs_update },
{ "statusHints", &advice_status_hints },
{ "statusUoption", &advice_status_u_option },
{ "statusAheadBehindWarning", &advice_status_ahead_behind_warning },
@@ -116,6 +118,7 @@ static struct {
[ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists", 1 },
[ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst", 1 },
[ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce", 1 },
+ [ADVICE_PUSH_REF_NEEDS_UPDATE] = { "pushRefNeedsUpdate", 1 },
/* make this an alias for backward compatibility */
[ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward", 1 },
diff --git a/advice.h b/advice.h
index 16f2c11..bc24329 100644
--- a/advice.h
+++ b/advice.h
@@ -11,6 +11,7 @@ extern int advice_push_already_exists;
extern int advice_push_fetch_first;
extern int advice_push_needs_force;
extern int advice_push_unqualified_ref_name;
+extern int advice_push_ref_needs_update;
extern int advice_status_hints;
extern int advice_status_u_option;
extern int advice_status_ahead_behind_warning;
@@ -60,6 +61,7 @@ extern int advice_add_empty_pathspec;
ADVICE_PUSH_UNQUALIFIED_REF_NAME,
ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
ADVICE_PUSH_UPDATE_REJECTED,
+ ADVICE_PUSH_REF_NEEDS_UPDATE,
ADVICE_RESET_QUIET_WARNING,
ADVICE_RESOLVE_CONFLICT,
ADVICE_RM_HINTS,
diff --git a/apply.c b/apply.c
index 57afee5..359ceb6 100644
--- a/apply.c
+++ b/apply.c
@@ -30,8 +30,8 @@ struct gitdiff_data {
static void git_apply_config(void)
{
- git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
- git_config_get_string_const("apply.ignorewhitespace", &apply_default_ignorewhitespace);
+ git_config_get_string("apply.whitespace", &apply_default_whitespace);
+ git_config_get_string("apply.ignorewhitespace", &apply_default_ignorewhitespace);
git_config(git_xmerge_config, NULL);
}
@@ -4699,8 +4699,13 @@ static int apply_patch(struct apply_state *state,
reverse_patches(patch);
if (use_patch(state, patch)) {
patch_stats(state, patch);
- *listp = patch;
- listp = &patch->next;
+ if (!list || !state->apply_in_reverse) {
+ *listp = patch;
+ listp = &patch->next;
+ } else {
+ patch->next = list;
+ list = patch;
+ }
if ((patch->new_name &&
ends_with_path_components(patch->new_name,
diff --git a/archive-tar.c b/archive-tar.c
index 5ceec36..a971fdc 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -242,13 +242,12 @@ static void write_extended_header(struct archiver_args *args,
static int write_tar_entry(struct archiver_args *args,
const struct object_id *oid,
const char *path, size_t pathlen,
- unsigned int mode)
+ unsigned int mode,
+ void *buffer, unsigned long size)
{
struct ustar_header header;
struct strbuf ext_header = STRBUF_INIT;
- unsigned int old_mode = mode;
- unsigned long size, size_in_header;
- void *buffer;
+ unsigned long size_in_header;
int err = 0;
memset(&header, 0, sizeof(header));
@@ -282,20 +281,6 @@ static int write_tar_entry(struct archiver_args *args,
} else
memcpy(header.name, path, pathlen);
- if (S_ISREG(mode) && !args->convert &&
- oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
- size > big_file_threshold)
- buffer = NULL;
- else if (S_ISLNK(mode) || S_ISREG(mode)) {
- enum object_type type;
- buffer = object_file_to_archive(args, path, oid, old_mode, &type, &size);
- if (!buffer)
- return error(_("cannot read %s"), oid_to_hex(oid));
- } else {
- buffer = NULL;
- size = 0;
- }
-
if (S_ISLNK(mode)) {
if (size > sizeof(header.linkname)) {
xsnprintf(header.linkname, sizeof(header.linkname),
@@ -326,7 +311,6 @@ static int write_tar_entry(struct archiver_args *args,
else
err = stream_blocked(args->repo, oid);
}
- free(buffer);
return err;
}
@@ -390,7 +374,8 @@ static int tar_filter_config(const char *var, const char *value, void *data)
ar = xcalloc(1, sizeof(*ar));
ar->name = xmemdupz(name, namelen);
ar->write_archive = write_tar_filter_archive;
- ar->flags = ARCHIVER_WANT_COMPRESSION_LEVELS;
+ ar->flags = ARCHIVER_WANT_COMPRESSION_LEVELS |
+ ARCHIVER_HIGH_COMPRESSION_LEVELS;
ALLOC_GROW(tar_filters, nr_tar_filters + 1, alloc_tar_filters);
tar_filters[nr_tar_filters++] = ar;
}
diff --git a/archive-zip.c b/archive-zip.c
index e9f4262..2961e01 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -285,7 +285,8 @@ static int entry_is_binary(struct index_state *istate, const char *path,
static int write_zip_entry(struct archiver_args *args,
const struct object_id *oid,
const char *path, size_t pathlen,
- unsigned int mode)
+ unsigned int mode,
+ void *buffer, unsigned long size)
{
struct zip_local_header header;
uintmax_t offset = zip_offset;
@@ -299,10 +300,8 @@ static int write_zip_entry(struct archiver_args *args,
enum zip_method method;
unsigned char *out;
void *deflated = NULL;
- void *buffer;
struct git_istream *stream = NULL;
unsigned long flags = 0;
- unsigned long size;
int is_binary = -1;
const char *path_without_prefix = path + args->baselen;
unsigned int creator_version = 0;
@@ -328,13 +327,8 @@ static int write_zip_entry(struct archiver_args *args,
method = ZIP_METHOD_STORE;
attr2 = 16;
out = NULL;
- size = 0;
compressed_size = 0;
- buffer = NULL;
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
- enum object_type type = oid_object_info(args->repo, oid,
- &size);
-
method = ZIP_METHOD_STORE;
attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
(mode & 0111) ? ((mode) << 16) : 0;
@@ -343,21 +337,16 @@ static int write_zip_entry(struct archiver_args *args,
if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
method = ZIP_METHOD_DEFLATE;
- if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert &&
- size > big_file_threshold) {
+ if (!buffer) {
+ enum object_type type;
stream = open_istream(args->repo, oid, &type, &size,
NULL);
if (!stream)
return error(_("cannot stream blob %s"),
oid_to_hex(oid));
flags |= ZIP_STREAM;
- out = buffer = NULL;
+ out = NULL;
} else {
- buffer = object_file_to_archive(args, path, oid, mode,
- &type, &size);
- if (!buffer)
- return error(_("cannot read %s"),
- oid_to_hex(oid));
crc = crc32(crc, buffer, size);
is_binary = entry_is_binary(args->repo->index,
path_without_prefix,
@@ -511,7 +500,6 @@ static int write_zip_entry(struct archiver_args *args,
}
free(deflated);
- free(buffer);
if (compressed_size > 0xffffffff || size > 0xffffffff ||
offset > 0xffffffff) {
diff --git a/archive.c b/archive.c
index fb39706..7a888c5 100644
--- a/archive.c
+++ b/archive.c
@@ -70,10 +70,12 @@ static void format_subst(const struct commit *commit,
free(to_free);
}
-void *object_file_to_archive(const struct archiver_args *args,
- const char *path, const struct object_id *oid,
- unsigned int mode, enum object_type *type,
- unsigned long *sizep)
+static void *object_file_to_archive(const struct archiver_args *args,
+ const char *path,
+ const struct object_id *oid,
+ unsigned int mode,
+ enum object_type *type,
+ unsigned long *sizep)
{
void *buffer;
const struct commit *commit = args->convert ? args->commit : NULL;
@@ -145,6 +147,9 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
write_archive_entry_fn_t write_entry = c->write_entry;
int err;
const char *path_without_prefix;
+ unsigned long size;
+ void *buffer;
+ enum object_type type;
args->convert = 0;
strbuf_reset(&path);
@@ -167,7 +172,7 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
- err = write_entry(args, oid, path.buf, path.len, mode);
+ err = write_entry(args, oid, path.buf, path.len, mode, NULL, 0);
if (err)
return err;
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
@@ -175,7 +180,19 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
- return write_entry(args, oid, path.buf, path.len, mode);
+
+ /* Stream it? */
+ if (S_ISREG(mode) && !args->convert &&
+ oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
+ size > big_file_threshold)
+ return write_entry(args, oid, path.buf, path.len, mode, NULL, size);
+
+ buffer = object_file_to_archive(args, path.buf, oid, mode, &type, &size);
+ if (!buffer)
+ return error(_("cannot read %s"), oid_to_hex(oid));
+ err = write_entry(args, oid, path.buf, path.len, mode, buffer, size);
+ free(buffer);
+ return err;
}
static void queue_directory(const unsigned char *sha1,
@@ -249,6 +266,11 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
stage, context);
}
+struct extra_file_info {
+ char *base;
+ struct stat stat;
+};
+
int write_archive_entries(struct archiver_args *args,
write_archive_entry_fn_t write_entry)
{
@@ -256,6 +278,10 @@ int write_archive_entries(struct archiver_args *args,
struct unpack_trees_options opts;
struct tree_desc t;
int err;
+ struct strbuf path_in_archive = STRBUF_INIT;
+ struct strbuf content = STRBUF_INIT;
+ struct object_id fake_oid = null_oid;
+ int i;
if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
size_t len = args->baselen;
@@ -265,7 +291,7 @@ int write_archive_entries(struct archiver_args *args,
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)len, args->base);
err = write_entry(args, &args->tree->object.oid, args->base,
- len, 040777);
+ len, 040777, NULL, 0);
if (err)
return err;
}
@@ -301,6 +327,33 @@ int write_archive_entries(struct archiver_args *args,
free(context.bottom);
context.bottom = next;
}
+
+ for (i = 0; i < args->extra_files.nr; i++) {
+ struct string_list_item *item = args->extra_files.items + i;
+ char *path = item->string;
+ struct extra_file_info *info = item->util;
+
+ put_be64(fake_oid.hash, i + 1);
+
+ strbuf_reset(&path_in_archive);
+ if (info->base)
+ strbuf_addstr(&path_in_archive, info->base);
+ strbuf_addstr(&path_in_archive, basename(path));
+
+ strbuf_reset(&content);
+ if (strbuf_read_file(&content, path, info->stat.st_size) < 0)
+ err = error_errno(_("could not read '%s'"), path);
+ else
+ err = write_entry(args, &fake_oid, path_in_archive.buf,
+ path_in_archive.len,
+ info->stat.st_mode,
+ content.buf, content.len);
+ if (err)
+ break;
+ }
+ strbuf_release(&path_in_archive);
+ strbuf_release(&content);
+
return err;
}
@@ -397,10 +450,10 @@ static void parse_treeish_arg(const char **argv,
const char *colon = strchrnul(name, ':');
int refnamelen = colon - name;
- if (!dwim_ref(name, refnamelen, &oid, &ref))
+ if (!dwim_ref(name, refnamelen, &oid, &ref, 0))
die(_("no such ref: %.*s"), refnamelen, name);
} else {
- dwim_ref(name, strlen(name), &oid, &ref);
+ dwim_ref(name, strlen(name), &oid, &ref, 0);
}
if (get_oid(name, &oid))
@@ -440,10 +493,48 @@ static void parse_treeish_arg(const char **argv,
ar_args->time = archive_time;
}
-#define OPT__COMPR(s, v, h, p) \
- OPT_SET_INT_F(s, NULL, v, h, p, PARSE_OPT_NONEG)
-#define OPT__COMPR_HIDDEN(s, v, p) \
- OPT_SET_INT_F(s, NULL, v, "", p, PARSE_OPT_NONEG | PARSE_OPT_HIDDEN)
+static void extra_file_info_clear(void *util, const char *str)
+{
+ struct extra_file_info *info = util;
+ free(info->base);
+ free(info);
+}
+
+static int add_file_cb(const struct option *opt, const char *arg, int unset)
+{
+ struct archiver_args *args = opt->value;
+ const char **basep = (const char **)opt->defval;
+ const char *base = *basep;
+ char *path;
+ struct string_list_item *item;
+ struct extra_file_info *info;
+
+ if (unset) {
+ string_list_clear_func(&args->extra_files,
+ extra_file_info_clear);
+ return 0;
+ }
+
+ if (!arg)
+ return -1;
+
+ path = prefix_filename(args->prefix, arg);
+ item = string_list_append_nodup(&args->extra_files, path);
+ item->util = info = xmalloc(sizeof(*info));
+ info->base = xstrdup_or_null(base);
+ if (stat(path, &info->stat))
+ die(_("File not found: %s"), path);
+ if (!S_ISREG(info->stat.st_mode))
+ die(_("Not a regular file: %s"), path);
+ return 0;
+}
+
+static int number_callback(const struct option *opt, const char *arg, int unset)
+{
+ BUG_ON_OPT_NEG(unset);
+ *(int *)opt->value = strtol(arg, NULL, 10);
+ return 0;
+}
static int parse_archive_args(int argc, const char **argv,
const struct archiver **ar, struct archiver_args *args,
@@ -464,21 +555,16 @@ static int parse_archive_args(int argc, const char **argv,
OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")),
OPT_STRING(0, "prefix", &base, N_("prefix"),
N_("prepend prefix to each pathname in the archive")),
+ { OPTION_CALLBACK, 0, "add-file", args, N_("file"),
+ N_("add untracked file to archive"), 0, add_file_cb,
+ (intptr_t)&base },
OPT_STRING('o', "output", &output, N_("file"),
N_("write the archive to this file")),
OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
N_("read .gitattributes in working directory")),
OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
- OPT__COMPR('0', &compression_level, N_("store only"), 0),
- OPT__COMPR('1', &compression_level, N_("compress faster"), 1),
- OPT__COMPR_HIDDEN('2', &compression_level, 2),
- OPT__COMPR_HIDDEN('3', &compression_level, 3),
- OPT__COMPR_HIDDEN('4', &compression_level, 4),
- OPT__COMPR_HIDDEN('5', &compression_level, 5),
- OPT__COMPR_HIDDEN('6', &compression_level, 6),
- OPT__COMPR_HIDDEN('7', &compression_level, 7),
- OPT__COMPR_HIDDEN('8', &compression_level, 8),
- OPT__COMPR('9', &compression_level, N_("compress better"), 9),
+ OPT_NUMBER_CALLBACK(&compression_level,
+ N_("set compression level"), number_callback),
OPT_GROUP(""),
OPT_BOOL('l', "list", &list,
N_("list supported archive formats")),
@@ -498,6 +584,8 @@ static int parse_archive_args(int argc, const char **argv,
die(_("Option --exec can only be used together with --remote"));
if (output)
die(_("Unexpected option --output"));
+ if (is_remote && args->extra_files.nr)
+ die(_("Options --add-file and --remote cannot be used together"));
if (!base)
base = "";
@@ -523,7 +611,9 @@ static int parse_archive_args(int argc, const char **argv,
args->compression_level = Z_DEFAULT_COMPRESSION;
if (compression_level != -1) {
- if ((*ar)->flags & ARCHIVER_WANT_COMPRESSION_LEVELS)
+ int levels_ok = (*ar)->flags & ARCHIVER_WANT_COMPRESSION_LEVELS;
+ int high_ok = (*ar)->flags & ARCHIVER_HIGH_COMPRESSION_LEVELS;
+ if (levels_ok && (compression_level <= 9 || high_ok))
args->compression_level = compression_level;
else {
die(_("Argument not supported for format '%s': -%d"),
@@ -544,11 +634,14 @@ int write_archive(int argc, const char **argv, const char *prefix,
{
const struct archiver *ar = NULL;
struct archiver_args args;
+ int rc;
git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
git_config(git_default_config, NULL);
args.repo = repo;
+ args.prefix = prefix;
+ string_list_init(&args.extra_files, 1);
argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
if (!startup_info->have_repository) {
/*
@@ -562,7 +655,11 @@ int write_archive(int argc, const char **argv, const char *prefix,
parse_treeish_arg(argv, &args, prefix, remote);
parse_pathspec_arg(argv + 1, &args);
- return ar->write_archive(ar, &args);
+ rc = ar->write_archive(ar, &args);
+
+ string_list_clear_func(&args.extra_files, extra_file_info_clear);
+
+ return rc;
}
static int match_extension(const char *filename, const char *ext)
diff --git a/archive.h b/archive.h
index 3bd96bf..e3d04e8 100644
--- a/archive.h
+++ b/archive.h
@@ -9,6 +9,7 @@ struct repository;
struct archiver_args {
struct repository *repo;
const char *refname;
+ const char *prefix;
const char *base;
size_t baselen;
struct tree *tree;
@@ -20,6 +21,7 @@ struct archiver_args {
unsigned int worktree_attributes : 1;
unsigned int convert : 1;
int compression_level;
+ struct string_list extra_files;
};
/* main api */
@@ -34,6 +36,7 @@ const char *archive_format_from_filename(const char *filename);
#define ARCHIVER_WANT_COMPRESSION_LEVELS 1
#define ARCHIVER_REMOTE 2
+#define ARCHIVER_HIGH_COMPRESSION_LEVELS 4
struct archiver {
const char *name;
int (*write_archive)(const struct archiver *, struct archiver_args *);
@@ -49,12 +52,9 @@ void init_archivers(void);
typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
const struct object_id *oid,
const char *path, size_t pathlen,
- unsigned int mode);
+ unsigned int mode,
+ void *buffer, unsigned long size);
int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
-void *object_file_to_archive(const struct archiver_args *args,
- const char *path, const struct object_id *oid,
- unsigned int mode, enum object_type *type,
- unsigned long *sizep);
#endif /* ARCHIVE_H */
diff --git a/bisect.c b/bisect.c
index d42a3a3..58bc9c7 100644
--- a/bisect.c
+++ b/bisect.c
@@ -988,8 +988,11 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
* the bisection process finished successfully.
* In this case the calling function or command should not turn a
* BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND return code into an error or a non zero exit code.
- * If no_checkout is non-zero, the bisection process does not
- * checkout the trial commit but instead simply updates BISECT_HEAD.
+ *
+ * Checking BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND
+ * in bisect_helper::bisect_next() and only transforming it to 0 at
+ * the end of bisect_helper::cmd_bisect__helper() helps bypassing
+ * all the code related to finding a commit to test.
*/
enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
{
@@ -999,6 +1002,10 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
enum bisect_error res = BISECT_OK;
struct object_id *bisect_rev;
char *steps_msg;
+ /*
+ * If no_checkout is non-zero, the bisection process does not
+ * checkout the trial commit but instead simply updates BISECT_HEAD.
+ */
int no_checkout = ref_exists("BISECT_HEAD");
unsigned bisect_flags = 0;
@@ -1082,6 +1089,8 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
"Bisecting: %d revisions left to test after this %s\n",
nr), nr, steps_msg);
free(steps_msg);
+ /* Clean up objects used, as they will be reused. */
+ repo_clear_commit_marks(r, ALL_REV_FLAGS);
return bisect_checkout(bisect_rev, no_checkout);
}
diff --git a/blame.c b/blame.c
index 82fa16d..de7b5d4 100644
--- a/blame.c
+++ b/blame.c
@@ -1184,6 +1184,7 @@ void blame_coalesce(struct blame_scoreboard *sb)
for (ent = sb->ent; ent && (next = ent->next); ent = next) {
if (ent->suspect == next->suspect &&
ent->s_lno + ent->num_lines == next->s_lno &&
+ ent->lno + ent->num_lines == next->lno &&
ent->ignored == next->ignored &&
ent->unblamable == next->unblamable) {
ent->num_lines += next->num_lines;
@@ -1275,7 +1276,7 @@ static int maybe_changed_path(struct repository *r,
if (commit_graph_generation(origin->commit) == GENERATION_NUMBER_INFINITY)
return 1;
- filter = get_bloom_filter(r, origin->commit, 0);
+ filter = get_bloom_filter(r, origin->commit);
if (!filter)
return 1;
@@ -1352,8 +1353,8 @@ static struct blame_origin *find_origin(struct repository *r,
else {
int compute_diff = 1;
if (origin->commit->parents &&
- !oidcmp(&parent->object.oid,
- &origin->commit->parents->item->object.oid))
+ oideq(&parent->object.oid,
+ &origin->commit->parents->item->object.oid))
compute_diff = maybe_changed_path(r, origin, bd);
if (compute_diff)
@@ -2669,7 +2670,7 @@ static struct commit *find_single_final(struct rev_info *revs,
if (obj->flags & UNINTERESTING)
continue;
obj = deref_tag(revs->repo, obj, NULL, 0);
- if (obj->type != OBJ_COMMIT)
+ if (!obj || obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (found)
die("More than one commit to dig from %s and %s?",
@@ -2700,7 +2701,7 @@ static struct commit *dwim_reverse_initial(struct rev_info *revs,
/* Is that sole rev a committish? */
obj = revs->pending.objects[0].item;
obj = deref_tag(revs->repo, obj, NULL, 0);
- if (obj->type != OBJ_COMMIT)
+ if (!obj || obj->type != OBJ_COMMIT)
return NULL;
/* Do we have HEAD? */
@@ -2736,7 +2737,7 @@ static struct commit *find_single_initial(struct rev_info *revs,
if (!(obj->flags & UNINTERESTING))
continue;
obj = deref_tag(revs->repo, obj, NULL, 0);
- if (obj->type != OBJ_COMMIT)
+ if (!obj || obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (found)
die("More than one commit to dig up from, %s and %s?",
@@ -2891,16 +2892,18 @@ void setup_blame_bloom_data(struct blame_scoreboard *sb,
const char *path)
{
struct blame_bloom_data *bd;
+ struct bloom_filter_settings *bs;
if (!sb->repo->objects->commit_graph)
return;
- if (!sb->repo->objects->commit_graph->bloom_filter_settings)
+ bs = get_bloom_filter_settings(sb->repo);
+ if (!bs)
return;
bd = xmalloc(sizeof(struct blame_bloom_data));
- bd->settings = sb->repo->objects->commit_graph->bloom_filter_settings;
+ bd->settings = bs;
bd->alloc = 4;
bd->nr = 0;
diff --git a/bloom.c b/bloom.c
index 1a57322..68c7320 100644
--- a/bloom.c
+++ b/bloom.c
@@ -38,7 +38,7 @@ static int load_bloom_filter_from_graph(struct commit_graph *g,
while (graph_pos < g->num_commits_in_base)
g = g->base_graph;
- /* The commit graph commit 'c' lives in doesn't carry bloom filters. */
+ /* The commit graph commit 'c' lives in doesn't carry Bloom filters. */
if (!g->chunk_bloom_indexes)
return 0;
@@ -177,15 +177,25 @@ static int pathmap_cmp(const void *hashmap_cmp_fn_data,
return strcmp(e1->path, e2->path);
}
-struct bloom_filter *get_bloom_filter(struct repository *r,
- struct commit *c,
- int compute_if_not_present)
+static void init_truncated_large_filter(struct bloom_filter *filter)
+{
+ filter->data = xmalloc(1);
+ filter->data[0] = 0xFF;
+ filter->len = 1;
+}
+
+struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
+ struct commit *c,
+ int compute_if_not_present,
+ const struct bloom_filter_settings *settings,
+ enum bloom_filter_computed *computed)
{
struct bloom_filter *filter;
- struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
int i;
struct diff_options diffopt;
- int max_changes = 512;
+
+ if (computed)
+ *computed = BLOOM_NOT_COMPUTED;
if (!bloom_filters.slab_size)
return NULL;
@@ -194,12 +204,11 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
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)
+ if (commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH)
load_bloom_filter_from_graph(r->objects->commit_graph, filter, c);
}
- if (filter->data)
+ if (filter->data && filter->len)
return filter;
if (!compute_if_not_present)
return NULL;
@@ -207,7 +216,7 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
repo_diff_setup(r, &diffopt);
diffopt.flags.recursive = 1;
diffopt.detect_rename = 0;
- diffopt.max_changes = max_changes;
+ diffopt.max_changes = settings->max_changed_paths;
diff_setup_done(&diffopt);
/* ensure commit is parsed so we have parent information */
@@ -219,7 +228,7 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
diff_tree_oid(NULL, &c->object.oid, "", &diffopt);
diffcore_std(&diffopt);
- if (diffopt.num_changes <= max_changes) {
+ if (diff_queued_diff.nr <= settings->max_changed_paths) {
struct hashmap pathmap;
struct pathmap_hash_entry *e;
struct hashmap_iter iter;
@@ -256,23 +265,41 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
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;
+ if (hashmap_get_size(&pathmap) > settings->max_changed_paths) {
+ init_truncated_large_filter(filter);
+ if (computed)
+ *computed |= BLOOM_TRUNC_LARGE;
+ goto cleanup;
+ }
+
+ filter->len = (hashmap_get_size(&pathmap) * settings->bits_per_entry + BITS_PER_WORD - 1) / BITS_PER_WORD;
+ if (!filter->len) {
+ if (computed)
+ *computed |= BLOOM_TRUNC_EMPTY;
+ filter->len = 1;
+ }
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);
+ fill_bloom_key(e->path, strlen(e->path), &key, settings);
+ add_key_to_filter(&key, filter, settings);
}
+ cleanup:
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;
+ init_truncated_large_filter(filter);
+
+ if (computed)
+ *computed |= BLOOM_TRUNC_LARGE;
}
+ if (computed)
+ *computed |= BLOOM_COMPUTED;
+
free(diff_queued_diff.queue);
DIFF_QUEUE_CLEAR(&diff_queued_diff);
diff --git a/bloom.h b/bloom.h
index d8fbb0f..adde6df 100644
--- a/bloom.h
+++ b/bloom.h
@@ -28,9 +28,18 @@ struct bloom_filter_settings {
* that contain n*b bits.
*/
uint32_t bits_per_entry;
+
+ /*
+ * The maximum number of changed paths per commit
+ * before declaring a Bloom filter to be too-large.
+ *
+ * Not written to the commit-graph file.
+ */
+ uint32_t max_changed_paths;
};
-#define DEFAULT_BLOOM_FILTER_SETTINGS { 1, 7, 10 }
+#define DEFAULT_BLOOM_MAX_CHANGES 512
+#define DEFAULT_BLOOM_FILTER_SETTINGS { 1, 7, 10, DEFAULT_BLOOM_MAX_CHANGES }
#define BITS_PER_WORD 8
#define BLOOMDATA_CHUNK_HEADER_SIZE 3 * sizeof(uint32_t)
@@ -80,9 +89,21 @@ void add_key_to_filter(const struct bloom_key *key,
void init_bloom_filters(void);
-struct bloom_filter *get_bloom_filter(struct repository *r,
- struct commit *c,
- int compute_if_not_present);
+enum bloom_filter_computed {
+ BLOOM_NOT_COMPUTED = (1 << 0),
+ BLOOM_COMPUTED = (1 << 1),
+ BLOOM_TRUNC_LARGE = (1 << 2),
+ BLOOM_TRUNC_EMPTY = (1 << 3),
+};
+
+struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
+ struct commit *c,
+ int compute_if_not_present,
+ const struct bloom_filter_settings *settings,
+ enum bloom_filter_computed *computed);
+
+#define get_bloom_filter(r, c) get_or_compute_bloom_filter( \
+ (r), (c), 0, NULL, NULL)
int bloom_filter_contains(const struct bloom_filter *filter,
const struct bloom_key *key,
diff --git a/branch.c b/branch.c
index 7095f78..9c9dae1 100644
--- a/branch.c
+++ b/branch.c
@@ -281,7 +281,7 @@ void create_branch(struct repository *r,
die(_("Not a valid object name: '%s'."), start_name);
}
- switch (dwim_ref(start_name, strlen(start_name), &oid, &real_ref)) {
+ switch (dwim_ref(start_name, strlen(start_name), &oid, &real_ref, 0)) {
case 0:
/* Not branching from any existing branch */
if (explicit_tracking)
diff --git a/builtin.h b/builtin.h
index ff7c6e5..b6ce981 100644
--- a/builtin.h
+++ b/builtin.h
@@ -119,6 +119,7 @@ int cmd_archive(int argc, const char **argv, const char *prefix);
int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
int cmd_blame(int argc, const char **argv, const char *prefix);
int cmd_branch(int argc, const char **argv, const char *prefix);
+int cmd_bugreport(int argc, const char **argv, const char *prefix);
int cmd_bundle(int argc, const char **argv, const char *prefix);
int cmd_cat_file(int argc, const char **argv, const char *prefix);
int cmd_checkout(int argc, const char **argv, const char *prefix);
@@ -138,6 +139,9 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix);
int cmd_config(int argc, const char **argv, const char *prefix);
int cmd_count_objects(int argc, const char **argv, const char *prefix);
int cmd_credential(int argc, const char **argv, const char *prefix);
+int cmd_credential_cache(int argc, const char **argv, const char *prefix);
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
+int cmd_credential_store(int argc, const char **argv, const char *prefix);
int cmd_describe(int argc, const char **argv, const char *prefix);
int cmd_diff_files(int argc, const char **argv, const char *prefix);
int cmd_diff_index(int argc, const char **argv, const char *prefix);
@@ -146,6 +150,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix);
int cmd_difftool(int argc, const char **argv, const char *prefix);
int cmd_env__helper(int argc, const char **argv, const char *prefix);
int cmd_fast_export(int argc, const char **argv, const char *prefix);
+int cmd_fast_import(int argc, const char **argv, const char *prefix);
int cmd_fetch(int argc, const char **argv, const char *prefix);
int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index ab39a60..a825887 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -192,9 +192,15 @@ int run_add_interactive(const char *revision, const char *patch_mode,
int use_builtin_add_i =
git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
- if (use_builtin_add_i < 0)
- git_config_get_bool("add.interactive.usebuiltin",
- &use_builtin_add_i);
+ if (use_builtin_add_i < 0) {
+ int experimental;
+ if (!git_config_get_bool("add.interactive.usebuiltin",
+ &use_builtin_add_i))
+ ; /* ok */
+ else if (!git_config_get_bool("feature.experimental", &experimental) &&
+ experimental)
+ use_builtin_add_i = 1;
+ }
if (use_builtin_add_i == 1) {
enum add_p_mode mode;
@@ -233,7 +239,7 @@ int run_add_interactive(const char *revision, const char *patch_mode,
return status;
}
-int interactive_add(int argc, const char **argv, const char *prefix, int patch)
+int interactive_add(const char **argv, const char *prefix, int patch)
{
struct pathspec pathspec;
@@ -445,7 +451,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (add_interactive) {
if (pathspec_from_file)
die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
- exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
+ exit(interactive_add(argv + 1, prefix, patch_interactive));
}
if (legacy_stash_p) {
struct pathspec pathspec;
@@ -534,11 +540,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die_in_unpopulated_submodule(&the_index, prefix);
die_path_inside_submodule(&the_index, &pathspec);
+ dir_init(&dir);
if (add_new_files) {
int baselen;
/* Set up the default git porcelain excludes */
- memset(&dir, 0, sizeof(dir));
if (!ignored_too) {
dir.flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(&dir);
@@ -611,7 +617,7 @@ finish:
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));
+ dir_clear(&dir);
UNLEAK(pathspec);
- UNLEAK(dir);
return exit_status;
}
diff --git a/builtin/am.c b/builtin/am.c
index 68e9d17..f22c73a 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1556,7 +1556,7 @@ static void do_commit(const struct am_state *state)
struct object_id tree, parent, commit;
const struct object_id *old_oid;
struct commit_list *parents = NULL;
- const char *reflog_msg, *author;
+ const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
if (run_hook_le(NULL, "pre-applypatch", NULL))
@@ -1580,11 +1580,16 @@ static void do_commit(const struct am_state *state)
IDENT_STRICT);
if (state->committer_date_is_author_date)
- setenv("GIT_COMMITTER_DATE",
- state->ignore_date ? "" : state->author_date, 1);
-
- if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
- author, state->sign_commit))
+ committer = fmt_ident(getenv("GIT_COMMITTER_NAME"),
+ getenv("GIT_COMMITTER_EMAIL"),
+ WANT_COMMITTER_IDENT,
+ state->ignore_date ? NULL
+ : state->author_date,
+ IDENT_STRICT);
+
+ if (commit_tree_extended(state->msg, state->msg_len, &tree, parents,
+ &commit, author, committer, state->sign_commit,
+ NULL))
die(_("failed to write commit object"));
reflog_msg = getenv("GIT_REFLOG_ACTION");
@@ -2162,6 +2167,8 @@ static int parse_opt_show_current_patch(const struct option *opt, const char *ar
};
int new_value = SHOW_PATCH_RAW;
+ BUG_ON_OPT_NEG(unset);
+
if (arg) {
for (new_value = 0; new_value < ARRAY_SIZE(valid_modes); new_value++) {
if (!strcmp(arg, valid_modes[new_value]))
@@ -2217,7 +2224,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
N_("allow fall back on 3way merging if needed")),
OPT__QUIET(&state.quiet, N_("be quiet")),
OPT_SET_INT('s', "signoff", &state.signoff,
- N_("add a Signed-off-by line to the commit message"),
+ N_("add a Signed-off-by trailer to the commit message"),
SIGNOFF_EXPLICIT),
OPT_BOOL('u', "utf8", &state.utf8,
N_("recode into utf8 (default)")),
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index cdda279..709eb71 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "prompt.h"
#include "quote.h"
+#include "revision.h"
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
@@ -19,19 +20,25 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
static const char * const git_bisect_helper_usage[] = {
- N_("git bisect--helper --next-all"),
- N_("git bisect--helper --write-terms <bad_term> <good_term>"),
- N_("git bisect--helper --bisect-clean-state"),
N_("git bisect--helper --bisect-reset [<commit>]"),
N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
- N_("git bisect--helper --bisect-start [--term-{old,good}=<term> --term-{new,bad}=<term>]"
+ N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
+ N_("git bisect--helper --bisect-next"),
+ N_("git bisect--helper --bisect-auto-next"),
+ N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
+ N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
NULL
};
+struct add_bisect_ref_data {
+ struct rev_info *revs;
+ unsigned int object_flags;
+};
+
struct bisect_terms {
char *term_good;
char *term_bad;
@@ -55,6 +62,8 @@ static void set_terms(struct bisect_terms *terms, const char *bad,
static const char vocab_bad[] = "bad|new";
static const char vocab_good[] = "good|old";
+static int bisect_autostart(struct bisect_terms *terms);
+
/*
* Check whether the string `term` belongs to the set of strings
* included in the variable arguments.
@@ -74,6 +83,65 @@ static int one_of(const char *term, ...)
return res;
}
+/*
+ * return code BISECT_INTERNAL_SUCCESS_MERGE_BASE
+ * and BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND are codes
+ * that indicate special success.
+ */
+
+static int is_bisect_success(enum bisect_error res)
+{
+ return !res ||
+ res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ||
+ res == BISECT_INTERNAL_SUCCESS_MERGE_BASE;
+}
+
+static int write_in_file(const char *path, const char *mode, const char *format, va_list args)
+{
+ FILE *fp = NULL;
+ int res = 0;
+
+ if (strcmp(mode, "w") && strcmp(mode, "a"))
+ BUG("write-in-file does not support '%s' mode", mode);
+ fp = fopen(path, mode);
+ if (!fp)
+ return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode);
+ res = vfprintf(fp, format, args);
+
+ if (res < 0) {
+ int saved_errno = errno;
+ fclose(fp);
+ errno = saved_errno;
+ return error_errno(_("could not write to file '%s'"), path);
+ }
+
+ return fclose(fp);
+}
+
+static int write_to_file(const char *path, const char *format, ...)
+{
+ int res;
+ va_list args;
+
+ va_start(args, format);
+ res = write_in_file(path, "w", format, args);
+ va_end(args);
+
+ return res;
+}
+
+static int append_to_file(const char *path, const char *format, ...)
+{
+ int res;
+ va_list args;
+
+ va_start(args, format);
+ res = write_in_file(path, "a", format, args);
+ va_end(args);
+
+ return res;
+}
+
static int check_term_format(const char *term, const char *orig_term)
{
int res;
@@ -104,7 +172,6 @@ static int check_term_format(const char *term, const char *orig_term)
static int write_terms(const char *bad, const char *good)
{
- FILE *fp = NULL;
int res;
if (!strcmp(bad, good))
@@ -113,39 +180,11 @@ static int write_terms(const char *bad, const char *good)
if (check_term_format(bad, "bad") || check_term_format(good, "good"))
return -1;
- fp = fopen(git_path_bisect_terms(), "w");
- if (!fp)
- return error_errno(_("could not open the file BISECT_TERMS"));
-
- res = fprintf(fp, "%s\n%s\n", bad, good);
- res |= fclose(fp);
- return (res < 0) ? -1 : 0;
-}
+ res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good);
-static int is_expected_rev(const char *expected_hex)
-{
- struct strbuf actual_hex = STRBUF_INIT;
- int res = 0;
- if (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 40) {
- strbuf_trim(&actual_hex);
- res = !strcmp(actual_hex.buf, expected_hex);
- }
- strbuf_release(&actual_hex);
return res;
}
-static void check_expected_revs(const char **revs, int rev_nr)
-{
- int i;
-
- for (i = 0; i < rev_nr; i++) {
- if (!is_expected_rev(revs[i])) {
- unlink_or_warn(git_path_bisect_ancestors_ok());
- unlink_or_warn(git_path_bisect_expected_rev());
- }
- }
-}
-
static int bisect_reset(const char *commit)
{
struct strbuf branch = STRBUF_INIT;
@@ -421,12 +460,149 @@ finish:
return res;
}
-static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
+static int add_bisect_ref(const char *refname, const struct object_id *oid,
+ int flags, void *cb)
+{
+ struct add_bisect_ref_data *data = cb;
+
+ add_pending_oid(data->revs, refname, oid, data->object_flags);
+
+ return 0;
+}
+
+static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
+{
+ int res = 0;
+ struct add_bisect_ref_data cb = { revs };
+ char *good = xstrfmt("%s-*", terms->term_good);
+
+ /*
+ * We cannot use terms->term_bad directly in
+ * for_each_glob_ref_in() and we have to append a '*' to it,
+ * otherwise for_each_glob_ref_in() will append '/' and '*'.
+ */
+ char *bad = xstrfmt("%s*", terms->term_bad);
+
+ /*
+ * It is important to reset the flags used by revision walks
+ * as the previous call to bisect_next_all() in turn
+ * sets up a revision walk.
+ */
+ reset_revision_walk();
+ init_revisions(revs, NULL);
+ setup_revisions(0, NULL, revs, NULL);
+ for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
+ cb.object_flags = UNINTERESTING;
+ for_each_glob_ref_in(add_bisect_ref, good, "refs/bisect/", &cb);
+ if (prepare_revision_walk(revs))
+ res = error(_("revision walk setup failed\n"));
+
+ free(good);
+ free(bad);
+ return res;
+}
+
+static int bisect_skipped_commits(struct bisect_terms *terms)
+{
+ int res;
+ FILE *fp = NULL;
+ struct rev_info revs;
+ struct commit *commit;
+ struct pretty_print_context pp = {0};
+ struct strbuf commit_name = STRBUF_INIT;
+
+ res = prepare_revs(terms, &revs);
+ if (res)
+ return res;
+
+ fp = fopen(git_path_bisect_log(), "a");
+ if (!fp)
+ return error_errno(_("could not open '%s' for appending"),
+ git_path_bisect_log());
+
+ if (fprintf(fp, "# only skipped commits left to test\n") < 0)
+ return error_errno(_("failed to write to '%s'"), git_path_bisect_log());
+
+ while ((commit = get_revision(&revs)) != NULL) {
+ strbuf_reset(&commit_name);
+ format_commit_message(commit, "%s",
+ &commit_name, &pp);
+ fprintf(fp, "# possible first %s commit: [%s] %s\n",
+ terms->term_bad, oid_to_hex(&commit->object.oid),
+ commit_name.buf);
+ }
+
+ /*
+ * Reset the flags used by revision walks in case
+ * there is another revision walk after this one.
+ */
+ reset_revision_walk();
+
+ strbuf_release(&commit_name);
+ fclose(fp);
+ return 0;
+}
+
+static int bisect_successful(struct bisect_terms *terms)
+{
+ struct object_id oid;
+ struct commit *commit;
+ struct pretty_print_context pp = {0};
+ struct strbuf commit_name = STRBUF_INIT;
+ char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
+ int res;
+
+ read_ref(bad_ref, &oid);
+ commit = lookup_commit_reference_by_name(bad_ref);
+ format_commit_message(commit, "%s", &commit_name, &pp);
+
+ res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
+ terms->term_bad, oid_to_hex(&commit->object.oid),
+ commit_name.buf);
+
+ strbuf_release(&commit_name);
+ free(bad_ref);
+ return res;
+}
+
+static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
+{
+ enum bisect_error res;
+
+ if (bisect_autostart(terms))
+ return BISECT_FAILED;
+
+ if (bisect_next_check(terms, terms->term_good))
+ return BISECT_FAILED;
+
+ /* Perform all bisection computation */
+ res = bisect_next_all(the_repository, prefix);
+
+ if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
+ res = bisect_successful(terms);
+ return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
+ } else if (res == BISECT_ONLY_SKIPPED_LEFT) {
+ res = bisect_skipped_commits(terms);
+ return res ? res : BISECT_ONLY_SKIPPED_LEFT;
+ }
+ return res;
+}
+
+static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
+{
+ if (bisect_next_check(terms, NULL))
+ return BISECT_OK;
+
+ return bisect_next(terms, prefix);
+}
+
+static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
{
int no_checkout = 0;
int first_parent_only = 0;
int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
- int flags, pathspec_pos, res = 0;
+ int flags, pathspec_pos;
+ enum bisect_error res = BISECT_OK;
struct string_list revs = STRING_LIST_INIT_DUP;
struct string_list states = STRING_LIST_INIT_DUP;
struct strbuf start_head = STRBUF_INIT;
@@ -484,14 +660,13 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
terms->term_bad = xstrdup(arg);
} else if (starts_with(arg, "--")) {
return error(_("unrecognized option: '%s'"), arg);
- } else {
- char *commit_id = xstrfmt("%s^{commit}", arg);
- if (get_oid(commit_id, &oid) && has_double_dash)
- die(_("'%s' does not appear to be a valid "
- "revision"), arg);
-
+ } else if (!get_oidf(&oid, "%s^{commit}", arg)) {
string_list_append(&revs, oid_to_hex(&oid));
- free(commit_id);
+ } else if (has_double_dash) {
+ die(_("'%s' does not appear to be a valid "
+ "revision"), arg);
+ } else {
+ break;
}
}
pathspec_pos = i;
@@ -566,14 +741,7 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
* Get rid of any old bisect state.
*/
if (bisect_clean_state())
- return -1;
-
- /*
- * In case of mistaken revs or checkout error, or signals received,
- * "bisect_auto_next" below may exit or misbehave.
- * We have to trap this to be able to clean up using
- * "bisect_clean_state".
- */
+ return BISECT_FAILED;
/*
* Write new start state
@@ -590,7 +758,7 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
}
if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
UPDATE_REFS_MSG_ON_ERR)) {
- res = -1;
+ res = BISECT_FAILED;
goto finish;
}
}
@@ -602,52 +770,156 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
for (i = 0; i < states.nr; i++)
if (bisect_write(states.items[i].string,
revs.items[i].string, terms, 1)) {
- res = -1;
+ res = BISECT_FAILED;
goto finish;
}
if (must_write_terms && write_terms(terms->term_bad,
terms->term_good)) {
- res = -1;
+ res = BISECT_FAILED;
goto finish;
}
res = bisect_append_log_quoted(argv);
if (res)
- res = -1;
+ res = BISECT_FAILED;
finish:
string_list_clear(&revs, 0);
string_list_clear(&states, 0);
strbuf_release(&start_head);
strbuf_release(&bisect_names);
+ if (res)
+ return res;
+
+ res = bisect_auto_next(terms, NULL);
+ if (!is_bisect_success(res))
+ bisect_clean_state();
return res;
}
+static inline int file_is_not_empty(const char *path)
+{
+ return !is_empty_or_missing_file(path);
+}
+
+static int bisect_autostart(struct bisect_terms *terms)
+{
+ int res;
+ const char *yesno;
+
+ if (file_is_not_empty(git_path_bisect_start()))
+ return 0;
+
+ fprintf_ln(stderr, _("You need to start by \"git bisect "
+ "start\"\n"));
+
+ if (!isatty(STDIN_FILENO))
+ return -1;
+
+ /*
+ * TRANSLATORS: Make sure to include [Y] and [n] in your
+ * translation. The program will only accept English input
+ * at this point.
+ */
+ yesno = git_prompt(_("Do you want me to do it for you "
+ "[Y/n]? "), PROMPT_ECHO);
+ res = tolower(*yesno) == 'n' ?
+ -1 : bisect_start(terms, empty_strvec, 0);
+
+ return res;
+}
+
+static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
+ int argc)
+{
+ const char *state;
+ int i, verify_expected = 1;
+ struct object_id oid, expected;
+ struct strbuf buf = STRBUF_INIT;
+ struct oid_array revs = OID_ARRAY_INIT;
+
+ if (!argc)
+ return error(_("Please call `--bisect-state` with at least one argument"));
+
+ if (bisect_autostart(terms))
+ return BISECT_FAILED;
+
+ state = argv[0];
+ if (check_and_set_terms(terms, state) ||
+ !one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
+ return BISECT_FAILED;
+
+ argv++;
+ argc--;
+ if (argc > 1 && !strcmp(state, terms->term_bad))
+ return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
+
+ if (argc == 0) {
+ const char *head = "BISECT_HEAD";
+ enum get_oid_result res_head = get_oid(head, &oid);
+
+ if (res_head == MISSING_OBJECT) {
+ head = "HEAD";
+ res_head = get_oid(head, &oid);
+ }
+
+ if (res_head)
+ error(_("Bad rev input: %s"), head);
+ oid_array_append(&revs, &oid);
+ }
+
+ /*
+ * All input revs must be checked before executing bisect_write()
+ * to discard junk revs.
+ */
+
+ for (; argc; argc--, argv++) {
+ if (get_oid(*argv, &oid)){
+ error(_("Bad rev input: %s"), *argv);
+ oid_array_clear(&revs);
+ return BISECT_FAILED;
+ }
+ oid_array_append(&revs, &oid);
+ }
+
+ if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
+ get_oid_hex(buf.buf, &expected) < 0)
+ verify_expected = 0; /* Ignore invalid file contents */
+ strbuf_release(&buf);
+
+ for (i = 0; i < revs.nr; i++) {
+ if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
+ oid_array_clear(&revs);
+ return BISECT_FAILED;
+ }
+ if (verify_expected && !oideq(&revs.oid[i], &expected)) {
+ unlink_or_warn(git_path_bisect_ancestors_ok());
+ unlink_or_warn(git_path_bisect_expected_rev());
+ verify_expected = 0;
+ }
+ }
+
+ oid_array_clear(&revs);
+ return bisect_auto_next(terms, NULL);
+}
+
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
enum {
- NEXT_ALL = 1,
- WRITE_TERMS,
- BISECT_CLEAN_STATE,
- CHECK_EXPECTED_REVS,
- BISECT_RESET,
+ BISECT_RESET = 1,
BISECT_WRITE,
CHECK_AND_SET_TERMS,
BISECT_NEXT_CHECK,
BISECT_TERMS,
- BISECT_START
+ BISECT_START,
+ BISECT_AUTOSTART,
+ BISECT_NEXT,
+ BISECT_AUTO_NEXT,
+ BISECT_STATE
} cmdmode = 0;
int res = 0, nolog = 0;
struct option options[] = {
- OPT_CMDMODE(0, "next-all", &cmdmode,
- N_("perform 'git bisect next'"), NEXT_ALL),
- OPT_CMDMODE(0, "write-terms", &cmdmode,
- N_("write the terms to .git/BISECT_TERMS"), WRITE_TERMS),
- OPT_CMDMODE(0, "bisect-clean-state", &cmdmode,
- N_("cleanup the bisection state"), BISECT_CLEAN_STATE),
- OPT_CMDMODE(0, "check-expected-revs", &cmdmode,
- N_("check for expected revs"), CHECK_EXPECTED_REVS),
OPT_CMDMODE(0, "bisect-reset", &cmdmode,
N_("reset the bisection state"), BISECT_RESET),
OPT_CMDMODE(0, "bisect-write", &cmdmode,
@@ -660,6 +932,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
N_("print out the bisect terms"), BISECT_TERMS),
OPT_CMDMODE(0, "bisect-start", &cmdmode,
N_("start the bisect session"), BISECT_START),
+ OPT_CMDMODE(0, "bisect-next", &cmdmode,
+ N_("find the next bisection commit"), BISECT_NEXT),
+ OPT_CMDMODE(0, "bisect-auto-next", &cmdmode,
+ N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT),
+ OPT_CMDMODE(0, "bisect-state", &cmdmode,
+ N_("mark the state of ref (or refs)"), BISECT_STATE),
OPT_BOOL(0, "no-log", &nolog,
N_("no log for BISECT_WRITE")),
OPT_END()
@@ -674,20 +952,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
usage_with_options(git_bisect_helper_usage, options);
switch (cmdmode) {
- case NEXT_ALL:
- res = bisect_next_all(the_repository, prefix);
- break;
- case WRITE_TERMS:
- if (argc != 2)
- return error(_("--write-terms requires two arguments"));
- return write_terms(argv[0], argv[1]);
- case BISECT_CLEAN_STATE:
- if (argc != 0)
- return error(_("--bisect-clean-state requires no arguments"));
- return bisect_clean_state();
- case CHECK_EXPECTED_REVS:
- check_expected_revs(argv, argc);
- return 0;
case BISECT_RESET:
if (argc > 1)
return error(_("--bisect-reset requires either no argument or a commit"));
@@ -719,8 +983,25 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
set_terms(&terms, "bad", "good");
res = bisect_start(&terms, argv, argc);
break;
+ case BISECT_NEXT:
+ if (argc)
+ return error(_("--bisect-next requires 0 arguments"));
+ get_terms(&terms);
+ res = bisect_next(&terms, prefix);
+ break;
+ case BISECT_AUTO_NEXT:
+ if (argc)
+ return error(_("--bisect-auto-next requires 0 arguments"));
+ get_terms(&terms);
+ res = bisect_auto_next(&terms, prefix);
+ break;
+ case BISECT_STATE:
+ set_terms(&terms, "bad", "good");
+ get_terms(&terms);
+ res = bisect_state(&terms, argv, argc);
+ break;
default:
- return error("BUG: unknown subcommand '%d'", cmdmode);
+ BUG("unknown subcommand %d", cmdmode);
}
free_terms(&terms);
@@ -728,8 +1009,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
* Handle early success
* From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
*/
- if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE)
+ if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
res = BISECT_OK;
- return abs(res);
+ return -res;
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 94ef57c..b5036ab 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -27,6 +27,7 @@
#include "object-store.h"
#include "blame.h"
#include "refs.h"
+#include "tag.h"
static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
@@ -803,6 +804,28 @@ static int is_a_rev(const char *name)
return OBJ_NONE < oid_object_info(the_repository, &oid, NULL);
}
+static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)
+{
+ struct repository *r = ((struct blame_scoreboard *)cbdata)->repo;
+ struct object_id oid;
+
+ oidcpy(&oid, oid_ret);
+ while (1) {
+ struct object *obj;
+ int kind = oid_object_info(r, &oid, NULL);
+ if (kind == OBJ_COMMIT) {
+ oidcpy(oid_ret, &oid);
+ return 0;
+ }
+ if (kind != OBJ_TAG)
+ return -1;
+ obj = deref_tag(r, parse_object(r, &oid), NULL, 0);
+ if (!obj)
+ return -1;
+ oidcpy(&oid, &obj->oid);
+ }
+}
+
static void build_ignorelist(struct blame_scoreboard *sb,
struct string_list *ignore_revs_file_list,
struct string_list *ignore_rev_list)
@@ -815,10 +838,12 @@ static void build_ignorelist(struct blame_scoreboard *sb,
if (!strcmp(i->string, ""))
oidset_clear(&sb->ignore_list);
else
- oidset_parse_file(&sb->ignore_list, i->string);
+ oidset_parse_file_carefully(&sb->ignore_list, i->string,
+ peel_to_commit_oid, sb);
}
for_each_string_list_item(i, ignore_rev_list) {
- if (get_oid_committish(i->string, &oid))
+ if (get_oid_committish(i->string, &oid) ||
+ peel_to_commit_oid(&oid, sb))
die(_("cannot find revision %s to ignore"), i->string);
oidset_insert(&sb->ignore_list, &oid);
}
@@ -842,7 +867,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
const char *contents_from = NULL;
const struct option options[] = {
OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
- OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
+ OPT_BOOL('b', NULL, &blank_boundary, N_("Do not show object names of boundary commits (Default: off)")),
OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")),
OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")),
diff --git a/builtin/branch.c b/builtin/branch.c
index e82301f..efb30b8 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -26,7 +26,7 @@
#include "commit-reach.h"
static const char * const builtin_branch_usage[] = {
- N_("git branch [<options>] [-r | -a] [--merged | --no-merged]"),
+ N_("git branch [<options>] [-r | -a] [--merged] [--no-merged]"),
N_("git branch [<options>] [-l] [-f] <branch-name> [<start-point>]"),
N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
@@ -688,8 +688,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
!show_current && !unset_upstream && argc == 0)
list = 1;
- if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr ||
- filter.no_commit)
+ if (filter.with_commit || filter.no_commit ||
+ filter.reachable_from || filter.unreachable_from || filter.points_at.nr)
list = 1;
if (!!delete + !!rename + !!copy + !!new_upstream + !!show_current +
diff --git a/bugreport.c b/builtin/bugreport.c
index 09579e2..3ad4b9b 100644
--- a/bugreport.c
+++ b/builtin/bugreport.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
#include "parse-options.h"
#include "strbuf.h"
#include "help.h"
@@ -119,7 +119,7 @@ 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)
+int cmd_bugreport(int argc, const char **argv, const char *prefix)
{
struct strbuf buffer = STRBUF_INIT;
struct strbuf report_path = STRBUF_INIT;
@@ -127,8 +127,6 @@ int cmd_main(int argc, const char **argv)
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[] = {
@@ -139,8 +137,6 @@ int cmd_main(int argc, const char **argv)
OPT_END()
};
- prefix = setup_git_directory_gently(&nongit_ok);
-
argc = parse_options(argc, argv, prefix, bugreport_options,
bugreport_usage, 0);
@@ -170,15 +166,13 @@ int cmd_main(int argc, const char **argv)
get_system_info(&buffer);
get_header(&buffer, _("Enabled Hooks"));
- get_populated_hooks(&buffer, nongit_ok);
+ get_populated_hooks(&buffer, !startup_info->have_repository);
/* 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);
+ if (report < 0)
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);
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index ea5d0ae..3c65274 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -180,7 +180,7 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
if (!no_index && read_cache() < 0)
die(_("index file corrupt"));
- memset(&dir, 0, sizeof(dir));
+ dir_init(&dir);
setup_standard_excludes(&dir);
if (stdin_paths) {
@@ -190,7 +190,7 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
maybe_flush_or_die(stdout, "ignore to stdout");
}
- clear_directory(&dir);
+ dir_clear(&dir);
return !num_ignored;
}
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index a854fd1..4bbfc92 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -79,6 +79,14 @@ static int checkout_file(const char *name, const char *prefix)
return errs > 0 ? -1 : 0;
}
+ /*
+ * At this point we know we didn't try to check anything out. If it was
+ * because we did find an entry but it was stage 0, that's not an
+ * error.
+ */
+ if (has_same_name && checkout_stage == CHECKOUT_ALL)
+ return 0;
+
if (!state.quiet) {
fprintf(stderr, "git checkout-index: %s ", name);
if (!has_same_name)
@@ -159,6 +167,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
int prefix_length;
int force = 0, quiet = 0, not_new = 0;
int index_opt = 0;
+ int err = 0;
struct option builtin_checkout_index_options[] = {
OPT_BOOL('a', "all", &all,
N_("check out all files in the index")),
@@ -223,7 +232,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
if (read_from_stdin)
die("git checkout-index: don't mix '--stdin' and explicit filenames");
p = prefix_path(prefix, prefix_length, arg);
- checkout_file(p, prefix);
+ err |= checkout_file(p, prefix);
free(p);
}
@@ -245,13 +254,16 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
strbuf_swap(&buf, &unquoted);
}
p = prefix_path(prefix, prefix_length, buf.buf);
- checkout_file(p, prefix);
+ err |= checkout_file(p, prefix);
free(p);
}
strbuf_release(&unquoted);
strbuf_release(&buf);
}
+ if (err)
+ return 1;
+
if (all)
checkout_all(prefix, prefix_length);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2837195..9b82119 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -471,6 +471,19 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->patch_mode) {
const char *patch_mode;
+ const char *rev = new_branch_info->name;
+ char rev_oid[GIT_MAX_HEXSZ + 1];
+
+ /*
+ * Since rev can be in the form of `<a>...<b>` (which is not
+ * recognized by diff-index), we will always replace the name
+ * with the hex of the commit (whether it's in `...` form or
+ * not) for the run_add_interactive() machinery to work
+ * properly. However, there is special logic for the HEAD case
+ * so we mustn't replace that.
+ */
+ if (rev && strcmp(rev, "HEAD"))
+ rev = oid_to_hex_r(rev_oid, &new_branch_info->commit->object.oid);
if (opts->checkout_index && opts->checkout_worktree)
patch_mode = "--patch=checkout";
@@ -481,7 +494,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(new_branch_info->name, patch_mode, &opts->pathspec);
+ return run_add_interactive(rev, patch_mode, &opts->pathspec);
}
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
@@ -651,7 +664,7 @@ static void setup_branch_path(struct branch_info *branch)
* 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))
+ if (!dwim_ref(branch->name, strlen(branch->name), &branch->oid, &branch->refname, 0))
repo_get_oid_committish(the_repository, branch->name, &branch->oid);
strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
@@ -1029,7 +1042,7 @@ static void orphaned_commit_warning(struct commit *old_commit, struct commit *ne
describe_detached_head(_("Previous HEAD position was"), old_commit);
/* Clean up objects used, as they will be reused. */
- clear_commit_marks_all(ALL_REV_FLAGS);
+ repo_clear_commit_marks(the_repository, ALL_REV_FLAGS);
}
static int switch_branches(const struct checkout_opts *opts,
@@ -1093,11 +1106,16 @@ static int switch_branches(const struct checkout_opts *opts,
static int git_checkout_config(const char *var, const char *value, void *cb)
{
+ struct checkout_opts *opts = cb;
+
if (!strcmp(var, "diff.ignoresubmodules")) {
- struct checkout_opts *opts = cb;
handle_ignore_submodules_arg(&opts->diff_options, value);
return 0;
}
+ if (!strcmp(var, "checkout.guess")) {
+ opts->dwim_new_local_branch = git_config_bool(var, value);
+ return 0;
+ }
if (starts_with(var, "submodule."))
return git_default_submodule_config(var, value, NULL);
@@ -1120,8 +1138,10 @@ static void setup_new_branch_info_and_source_tree(
if (!check_refname_format(new_branch_info->path, 0) &&
!read_ref(new_branch_info->path, &branch_rev))
oidcpy(rev, &branch_rev);
- else
+ else {
+ free((char *)new_branch_info->path);
new_branch_info->path = NULL; /* not an existing branch */
+ }
new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
if (!new_branch_info->commit) {
@@ -1343,7 +1363,7 @@ static void die_expecting_a_branch(const struct branch_info *branch_info)
struct object_id oid;
char *to_free;
- if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free) == 1) {
+ if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free, 0) == 1) {
const char *ref = to_free;
if (skip_prefix(ref, "refs/tags/", &ref))
@@ -1707,6 +1727,8 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
+ opts->pathspec.recursive = 1;
+
if (opts->pathspec.nr) {
if (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)
die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
diff --git a/builtin/clean.c b/builtin/clean.c
index 5a9c29a..687ab47 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -162,7 +162,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
is_nonbare_repository_dir(path)) {
if (!quiet) {
- quote_path_relative(path->buf, prefix, &quoted);
+ quote_path(path->buf, prefix, &quoted, 0);
printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
quoted.buf);
}
@@ -177,7 +177,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
res = dry_run ? 0 : rmdir(path->buf);
if (res) {
int saved_errno = errno;
- quote_path_relative(path->buf, prefix, &quoted);
+ quote_path(path->buf, prefix, &quoted, 0);
errno = saved_errno;
warning_errno(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
@@ -202,7 +202,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
ret = 1;
if (gone) {
- quote_path_relative(path->buf, prefix, &quoted);
+ quote_path(path->buf, prefix, &quoted, 0);
string_list_append(&dels, quoted.buf);
} else
*dir_gone = 0;
@@ -210,11 +210,11 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
} else {
res = dry_run ? 0 : unlink(path->buf);
if (!res) {
- quote_path_relative(path->buf, prefix, &quoted);
+ quote_path(path->buf, prefix, &quoted, 0);
string_list_append(&dels, quoted.buf);
} else {
int saved_errno = errno;
- quote_path_relative(path->buf, prefix, &quoted);
+ quote_path(path->buf, prefix, &quoted, 0);
errno = saved_errno;
warning_errno(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
@@ -238,7 +238,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
*dir_gone = 1;
else {
int saved_errno = errno;
- quote_path_relative(path->buf, prefix, &quoted);
+ quote_path(path->buf, prefix, &quoted, 0);
errno = saved_errno;
warning_errno(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
@@ -266,7 +266,7 @@ static void pretty_print_dels(void)
struct column_options copts;
for_each_string_list_item(item, &del_list) {
- qname = quote_path_relative(item->string, NULL, &buf);
+ qname = quote_path(item->string, NULL, &buf, 0);
string_list_append(&list, qname);
}
@@ -667,7 +667,7 @@ static int filter_by_patterns_cmd(void)
if (!confirm.len)
break;
- memset(&dir, 0, sizeof(dir));
+ dir_init(&dir);
pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
ignore_list = strbuf_split_max(&confirm, ' ', 0);
@@ -698,7 +698,7 @@ static int filter_by_patterns_cmd(void)
}
strbuf_list_free(ignore_list);
- clear_directory(&dir);
+ dir_clear(&dir);
}
strbuf_release(&confirm);
@@ -753,7 +753,7 @@ static int ask_each_cmd(void)
for_each_string_list_item(item, &del_list) {
/* Ctrl-D should stop removing files */
if (!eof) {
- qname = quote_path_relative(item->string, NULL, &buf);
+ qname = quote_path(item->string, NULL, &buf, 0);
/* TRANSLATORS: Make sure to keep [y/N] as is */
printf(_("Remove %s [y/N]? "), qname);
if (git_read_line_interactively(&confirm) == EOF) {
@@ -923,7 +923,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
0);
- memset(&dir, 0, sizeof(dir));
+ dir_init(&dir);
if (!interactive && !dry_run && !force) {
if (config_set)
die(_("clean.requireForce set to true and neither -i, -n, nor -f given; "
@@ -1021,11 +1021,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
string_list_append(&del_list, rel);
}
- for (i = 0; i < dir.nr; i++)
- free(dir.entries[i]);
-
- for (i = 0; i < dir.ignored_nr; i++)
- free(dir.ignored[i]);
+ dir_clear(&dir);
if (interactive && del_list.nr > 0)
interactive_main_loop();
@@ -1051,19 +1047,19 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (remove_dirs(&abs_path, prefix, rm_flags, dry_run, quiet, &gone))
errors++;
if (gone && !quiet) {
- qname = quote_path_relative(item->string, NULL, &buf);
+ qname = quote_path(item->string, NULL, &buf, 0);
printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
}
} else {
res = dry_run ? 0 : unlink(abs_path.buf);
if (res) {
int saved_errno = errno;
- qname = quote_path_relative(item->string, NULL, &buf);
+ qname = quote_path(item->string, NULL, &buf, 0);
errno = saved_errno;
warning_errno(_(msg_warn_remove_failed), qname);
errors++;
} else if (!quiet) {
- qname = quote_path_relative(item->string, NULL, &buf);
+ qname = quote_path(item->string, NULL, &buf, 0);
printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
}
}
diff --git a/builtin/clone.c b/builtin/clone.c
index b087ee4..a084192 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -53,6 +53,7 @@ static int option_shallow_submodules;
static int deepen;
static char *option_template, *option_depth, *option_since;
static char *option_origin = NULL;
+static char *remote_name = NULL;
static char *option_branch = NULL;
static struct string_list option_not = STRING_LIST_INIT_NODUP;
static const char *real_git_dir;
@@ -721,7 +722,7 @@ static void update_head(const struct ref *our, const struct ref *remote,
if (!option_bare) {
update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
- install_branch_config(0, head, option_origin, our->name);
+ install_branch_config(0, head, remote_name, our->name);
}
} else if (our) {
struct commit *c = lookup_commit_reference(the_repository,
@@ -851,8 +852,26 @@ static int checkout(int submodule_progress)
return err;
}
+static int git_clone_config(const char *k, const char *v, void *cb)
+{
+ if (!strcmp(k, "clone.defaultremotename")) {
+ free(remote_name);
+ remote_name = xstrdup(v);
+ }
+ return git_default_config(k, v, cb);
+}
+
static int write_one_config(const char *key, const char *value, void *data)
{
+ /*
+ * give git_clone_config a chance to write config values back to the
+ * environment, since git_config_set_multivar_gently only deals with
+ * config-file writes
+ */
+ int apply_failed = git_clone_config(key, value, data);
+ if (apply_failed)
+ return apply_failed;
+
return git_config_set_multivar_gently(key,
value ? value : "true",
CONFIG_REGEX_NONE, 0);
@@ -905,12 +924,12 @@ static void write_refspec_config(const char *src_ref_prefix,
}
/* Configure the remote */
if (value.len) {
- strbuf_addf(&key, "remote.%s.fetch", option_origin);
+ strbuf_addf(&key, "remote.%s.fetch", remote_name);
git_config_set_multivar(key.buf, value.buf, "^$", 0);
strbuf_reset(&key);
if (option_mirror) {
- strbuf_addf(&key, "remote.%s.mirror", option_origin);
+ strbuf_addf(&key, "remote.%s.mirror", remote_name);
git_config_set(key.buf, "true");
strbuf_reset(&key);
}
@@ -953,7 +972,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct ref *mapped_refs;
const struct ref *ref;
struct strbuf key = STRBUF_INIT;
- struct strbuf default_refspec = STRBUF_INIT;
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
const char *src_ref_prefix = "refs/heads/";
@@ -964,6 +982,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct strvec ref_prefixes = STRVEC_INIT;
packet_trace_identity("clone");
+
+ git_config(git_clone_config, NULL);
+
argc = parse_options(argc, argv, prefix, builtin_clone_options,
builtin_clone_usage, 0);
@@ -992,9 +1013,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
option_no_checkout = 1;
}
- if (!option_origin)
- option_origin = "origin";
-
repo_name = argv[0];
path = get_repo_path(repo_name, &is_bundle);
@@ -1125,9 +1143,30 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (real_git_dir)
git_dir = real_git_dir;
+ /*
+ * additional config can be injected with -c, make sure it's included
+ * after init_db, which clears the entire config environment.
+ */
write_config(&option_config);
- git_config(git_default_config, NULL);
+ /*
+ * re-read config after init_db and write_config to pick up any config
+ * injected by --template and --config, respectively.
+ */
+ git_config(git_clone_config, NULL);
+
+ /*
+ * apply the remote name provided by --origin only after this second
+ * call to git_config, to ensure it overrides all config-based values.
+ */
+ if (option_origin != NULL)
+ remote_name = xstrdup(option_origin);
+
+ if (remote_name == NULL)
+ remote_name = xstrdup("origin");
+
+ if (!valid_remote_name(remote_name))
+ die(_("'%s' is not a valid remote name"), remote_name);
if (option_bare) {
if (option_mirror)
@@ -1136,15 +1175,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
git_config_set("core.bare", "true");
} else {
- strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
+ strbuf_addf(&branch_top, "refs/remotes/%s/", remote_name);
}
- strbuf_addf(&key, "remote.%s.url", option_origin);
+ strbuf_addf(&key, "remote.%s.url", remote_name);
git_config_set(key.buf, repo);
strbuf_reset(&key);
if (option_no_tags) {
- strbuf_addf(&key, "remote.%s.tagOpt", option_origin);
+ strbuf_addf(&key, "remote.%s.tagOpt", remote_name);
git_config_set(key.buf, "--no-tags");
strbuf_reset(&key);
}
@@ -1155,11 +1194,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_sparse_checkout && git_sparse_checkout_init(dir))
return 1;
- remote = remote_get(option_origin);
+ remote = remote_get(remote_name);
- strbuf_addf(&default_refspec, "+%s*:%s*", src_ref_prefix,
- branch_top.buf);
- refspec_append(&remote->fetch, default_refspec.buf);
+ refspec_appendf(&remote->fetch, "+%s*:%s*", src_ref_prefix,
+ branch_top.buf);
transport = transport_get(remote, remote->url[0]);
transport_set_verbosity(transport, option_verbosity, option_progress);
@@ -1235,7 +1273,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
* Now that we know what algorithm the remote side is using,
* let's set ours to the same thing.
*/
- initialize_repository_version(hash_algo);
+ initialize_repository_version(hash_algo, 1);
repo_set_hash_algo(the_repository, hash_algo);
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
@@ -1268,7 +1306,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (!our_head_points_at)
die(_("Remote branch %s not found in upstream %s"),
- option_branch, option_origin);
+ option_branch, remote_name);
}
else
our_head_points_at = remote_head_points_at;
@@ -1276,7 +1314,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
else {
if (option_branch)
die(_("Remote branch %s not found in upstream %s"),
- option_branch, option_origin);
+ option_branch, remote_name);
warning(_("You appear to have cloned an empty repository."));
mapped_refs = NULL;
@@ -1288,7 +1326,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
const char *branch = git_default_branch_name();
char *ref = xstrfmt("refs/heads/%s", branch);
- install_branch_config(0, branch, option_origin, ref);
+ install_branch_config(0, branch, remote_name, ref);
free(ref);
}
}
@@ -1297,7 +1335,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote_head_points_at, &branch_top);
if (filter_options.choice)
- partial_clone_register(option_origin, &filter_options);
+ partial_clone_register(remote_name, &filter_options);
if (is_local)
clone_local(path, git_dir);
@@ -1329,10 +1367,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
junk_mode = JUNK_LEAVE_REPO;
err = checkout(submodule_progress);
+ free(remote_name);
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
strbuf_release(&key);
- strbuf_release(&default_refspec);
junk_mode = JUNK_LEAVE_ALL;
strvec_clear(&ref_prefixes);
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 523501f..78fa08f 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -13,7 +13,8 @@ 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[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
- "[--changed-paths] [--[no-]progress] <split options>"),
+ "[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] "
+ "<split options>"),
NULL
};
@@ -25,7 +26,8 @@ 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[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
- "[--changed-paths] [--[no-]progress] <split options>"),
+ "[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] "
+ "<split options>"),
NULL
};
@@ -106,7 +108,7 @@ static int graph_verify(int argc, const char **argv)
FREE_AND_NULL(graph_name);
if (open_ok)
- graph = load_commit_graph_one_fd_st(fd, &st, odb);
+ graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
else
graph = read_commit_graph_one(the_repository, odb);
@@ -119,13 +121,15 @@ static int graph_verify(int argc, const char **argv)
}
extern int read_replace_refs;
-static struct split_commit_graph_opts split_opts;
+static struct commit_graph_opts write_opts;
static int write_option_parse_split(const struct option *opt, const char *arg,
int unset)
{
enum commit_graph_split_flags *flags = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
opts.split = 1;
if (!arg)
return 0;
@@ -162,6 +166,35 @@ static int read_one_commit(struct oidset *commits, struct progress *progress,
return 0;
}
+static int write_option_max_new_filters(const struct option *opt,
+ const char *arg,
+ int unset)
+{
+ int *to = opt->value;
+ if (unset)
+ *to = -1;
+ else {
+ const char *s;
+ *to = strtol(arg, (char **)&s, 10);
+ if (*s)
+ return error(_("%s expects a numerical value"),
+ optname(opt, opt->flags));
+ }
+ return 0;
+}
+
+static int git_commit_graph_write_config(const char *var, const char *value,
+ void *cb)
+{
+ if (!strcmp(var, "commitgraph.maxnewfilters"))
+ write_opts.max_new_filters = git_config_int(var, value);
+ /*
+ * No need to fall-back to 'git_default_config', since this was already
+ * called in 'cmd_commit_graph()'.
+ */
+ return 0;
+}
+
static int graph_write(int argc, const char **argv)
{
struct string_list pack_indexes = STRING_LIST_INIT_NODUP;
@@ -187,27 +220,33 @@ static int graph_write(int argc, const char **argv)
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_CALLBACK_F(0, "split", &split_opts.flags, NULL,
+ OPT_CALLBACK_F(0, "split", &write_opts.split_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,
+ OPT_INTEGER(0, "max-commits", &write_opts.max_commits,
N_("maximum number of commits in a non-base split commit-graph")),
- OPT_INTEGER(0, "size-multiple", &split_opts.size_multiple,
+ OPT_INTEGER(0, "size-multiple", &write_opts.size_multiple,
N_("maximum ratio between two levels of a split commit-graph")),
- OPT_EXPIRY_DATE(0, "expire-time", &split_opts.expire_time,
+ OPT_EXPIRY_DATE(0, "expire-time", &write_opts.expire_time,
N_("only expire files older than a given date-time")),
+ OPT_CALLBACK_F(0, "max-new-filters", &write_opts.max_new_filters,
+ NULL, N_("maximum number of changed-path Bloom filters to compute"),
+ 0, write_option_max_new_filters),
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;
+ write_opts.size_multiple = 2;
+ write_opts.max_commits = 0;
+ write_opts.expire_time = 0;
+ write_opts.max_new_filters = -1;
trace2_cmd_mode("write");
+ git_config(git_commit_graph_write_config, &opts);
+
argc = parse_options(argc, argv, NULL,
builtin_commit_graph_write_options,
builtin_commit_graph_write_usage, 0);
@@ -232,7 +271,7 @@ static int graph_write(int argc, const char **argv)
odb = find_odb(the_repository, opts.obj_dir);
if (opts.reachable) {
- if (write_commit_graph_reachable(odb, flags, &split_opts))
+ if (write_commit_graph_reachable(odb, flags, &write_opts))
return 1;
return 0;
}
@@ -261,7 +300,7 @@ static int graph_write(int argc, const char **argv)
opts.stdin_packs ? &pack_indexes : NULL,
opts.stdin_commits ? &commits : NULL,
flags,
- &split_opts))
+ &write_opts))
result = 1;
cleanup:
diff --git a/builtin/commit.c b/builtin/commit.c
index f9b0a0c..505fe60 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -326,7 +326,7 @@ static void refresh_cache_or_die(int refresh_flags)
die_resolve_conflict("commit");
}
-static const char *prepare_index(int argc, const char **argv, const char *prefix,
+static const char *prepare_index(const char **argv, const char *prefix,
const struct commit *current_head, int is_status)
{
struct string_list partial = STRING_LIST_INIT_DUP;
@@ -378,7 +378,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
- if (interactive_add(argc, argv, prefix, patch_interactive) != 0)
+ if (interactive_add(argv, prefix, patch_interactive) != 0)
die(_("interactive add failed"));
the_repository->index_file = old_repo_index_file;
@@ -847,21 +847,19 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
!merge_contains_scissors)
wt_status_add_cut_line(s->fp);
- status_printf_ln(s, GIT_COLOR_NORMAL,
- whence == FROM_MERGE
- ? _("\n"
- "It looks like you may be committing a merge.\n"
- "If this is not correct, please remove the file\n"
- " %s\n"
- "and try again.\n")
- : _("\n"
- "It looks like you may be committing a cherry-pick.\n"
- "If this is not correct, please remove the file\n"
- " %s\n"
- "and try again.\n"),
+ status_printf_ln(
+ s, GIT_COLOR_NORMAL,
whence == FROM_MERGE ?
- git_path_merge_head(the_repository) :
- git_path_cherry_pick_head(the_repository));
+ _("\n"
+ "It looks like you may be committing a merge.\n"
+ "If this is not correct, please run\n"
+ " git update-ref -d MERGE_HEAD\n"
+ "and try again.\n") :
+ _("\n"
+ "It looks like you may be committing a cherry-pick.\n"
+ "If this is not correct, please run\n"
+ " git update-ref -d CHERRY_PICK_HEAD\n"
+ "and try again.\n"));
}
fprintf(s->fp, "\n");
@@ -1243,13 +1241,13 @@ static int parse_and_validate_options(int argc, const char *argv[],
return argc;
}
-static int dry_run_commit(int argc, const char **argv, const char *prefix,
+static int dry_run_commit(const char **argv, const char *prefix,
const struct commit *current_head, struct wt_status *s)
{
int committable;
const char *index_file;
- index_file = prepare_index(argc, argv, prefix, current_head, 1);
+ index_file = prepare_index(argv, prefix, current_head, 1);
committable = run_status(stdout, index_file, prefix, 0, s);
rollback_index_files();
@@ -1509,7 +1507,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
OPT_STRING(0, "fixup", &fixup_message, N_("commit"), N_("use autosquash formatted message to fixup specified commit")),
OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
- OPT_BOOL('s', "signoff", &signoff, N_("add Signed-off-by:")),
+ OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")),
OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
OPT_CLEANUP(&cleanup_arg),
@@ -1586,8 +1584,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
verbose = (config_commit_verbose < 0) ? 0 : config_commit_verbose;
if (dry_run)
- return dry_run_commit(argc, argv, prefix, current_head, &s);
- index_file = prepare_index(argc, argv, prefix, current_head, 0);
+ return dry_run_commit(argv, prefix, current_head, &s);
+ index_file = prepare_index(argv, prefix, current_head, 0);
/* Set up everything for writing the commit object. This includes
running hooks, writing the trees, and interacting with the user. */
@@ -1674,8 +1672,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
- parents, &oid, author_ident.buf, sign_commit,
- extra)) {
+ parents, &oid, author_ident.buf, NULL,
+ sign_commit, extra)) {
rollback_index_files();
die(_("failed to write commit object"));
}
diff --git a/builtin/config.c b/builtin/config.c
index 5e39f61..963d65f 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -65,6 +65,7 @@ static int show_scope;
#define TYPE_PATH 4
#define TYPE_EXPIRY_DATE 5
#define TYPE_COLOR 6
+#define TYPE_BOOL_OR_STR 7
#define OPT_CALLBACK_VALUE(s, l, v, h, i) \
{ OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \
@@ -94,6 +95,8 @@ static int option_parse_type(const struct option *opt, const char *arg,
new_type = TYPE_INT;
else if (!strcmp(arg, "bool-or-int"))
new_type = TYPE_BOOL_OR_INT;
+ else if (!strcmp(arg, "bool-or-str"))
+ new_type = TYPE_BOOL_OR_STR;
else if (!strcmp(arg, "path"))
new_type = TYPE_PATH;
else if (!strcmp(arg, "expiry-date"))
@@ -149,6 +152,7 @@ static struct option builtin_config_options[] = {
OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL),
OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT),
OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
+ OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR),
OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
OPT_GROUP(N_("Other")),
@@ -250,6 +254,12 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
strbuf_addstr(buf, v ? "true" : "false");
else
strbuf_addf(buf, "%d", v);
+ } else if (type == TYPE_BOOL_OR_STR) {
+ int v = git_parse_maybe_bool(value_);
+ if (v < 0)
+ strbuf_addstr(buf, value_);
+ else
+ strbuf_addstr(buf, v ? "true" : "false");
} else if (type == TYPE_PATH) {
const char *v;
if (git_config_pathname(&v, key_, value_) < 0)
@@ -411,6 +421,13 @@ static char *normalize_value(const char *key, const char *value)
else
return xstrdup(v ? "true" : "false");
}
+ if (type == TYPE_BOOL_OR_STR) {
+ int v = git_parse_maybe_bool(value);
+ if (v < 0)
+ return xstrdup(value);
+ else
+ return xstrdup(v ? "true" : "false");
+ }
if (type == TYPE_COLOR) {
char v[COLOR_MAXLEN];
if (git_config_color(v, key, value))
@@ -628,11 +645,15 @@ int cmd_config(int argc, const char **argv, const char *prefix)
usage_builtin_config();
}
- if (use_local_config && nongit)
- die(_("--local can only be used inside a git repository"));
+ if (nongit) {
+ if (use_local_config)
+ die(_("--local can only be used inside a git repository"));
+ if (given_config_source.blob)
+ die(_("--blob can only be used inside a git repository"));
+ if (use_worktree_config)
+ die(_("--worktree can only be used inside a git repository"));
- if (given_config_source.blob && nongit)
- die(_("--blob can only be used inside a git repository"));
+ }
if (given_config_source.file &&
!strcmp(given_config_source.file, "-")) {
diff --git a/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index ec1271f..c61f123 100644
--- a/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -1,9 +1,12 @@
-#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+
+#ifndef NO_UNIX_SOCKETS
+
#include "config.h"
#include "tempfile.h"
#include "credential.h"
#include "unix-socket.h"
-#include "parse-options.h"
struct credential_cache_entry {
struct credential item;
@@ -257,7 +260,7 @@ static void init_socket_directory(const char *path)
free(path_copy);
}
-int cmd_main(int argc, const char **argv)
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
{
struct tempfile *socket_file;
const char *socket_path;
@@ -275,7 +278,7 @@ int cmd_main(int argc, const char **argv)
git_config_get_bool("credentialcache.ignoresighup", &ignore_sighup);
- argc = parse_options(argc, argv, NULL, options, usage, 0);
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
socket_path = argv[0];
if (!socket_path)
@@ -295,3 +298,21 @@ int cmd_main(int argc, const char **argv)
return 0;
}
+
+#else
+
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
+{
+ const char * const usage[] = {
+ "git credential-cache--daemon [options] <action>",
+ "",
+ "credential-cache--daemon is disabled in this build of Git",
+ NULL
+ };
+ struct option options[] = { OPT_END() };
+
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
+ die(_("credential-cache--daemon unavailable; no unix socket support"));
+}
+
+#endif /* NO_UNIX_SOCKET */
diff --git a/credential-cache.c b/builtin/credential-cache.c
index 1cccc3a..9b3f709 100644
--- a/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+
+#ifndef NO_UNIX_SOCKETS
+
#include "credential.h"
#include "string-list.h"
-#include "parse-options.h"
#include "unix-socket.h"
#include "run-command.h"
@@ -39,13 +42,13 @@ static int send_request(const char *socket, const struct strbuf *out)
static void spawn_daemon(const char *socket)
{
struct child_process daemon = CHILD_PROCESS_INIT;
- const char *argv[] = { NULL, NULL, NULL };
char buf[128];
int r;
- argv[0] = "git-credential-cache--daemon";
- argv[1] = socket;
- daemon.argv = argv;
+ strvec_pushl(&daemon.args,
+ "credential-cache--daemon", socket,
+ NULL);
+ daemon.git_cmd = 1;
daemon.no_stdin = 1;
daemon.out = -1;
@@ -96,7 +99,7 @@ static char *get_socket_path(void)
return socket;
}
-int cmd_main(int argc, const char **argv)
+int cmd_credential_cache(int argc, const char **argv, const char *prefix)
{
char *socket_path = NULL;
int timeout = 900;
@@ -113,7 +116,7 @@ int cmd_main(int argc, const char **argv)
OPT_END()
};
- argc = parse_options(argc, argv, NULL, options, usage, 0);
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
if (!argc)
usage_with_options(usage, options);
op = argv[0];
@@ -134,3 +137,21 @@ int cmd_main(int argc, const char **argv)
return 0;
}
+
+#else
+
+int cmd_credential_cache(int argc, const char **argv, const char *prefix)
+{
+ const char * const usage[] = {
+ "git credential-cache [options] <action>",
+ "",
+ "credential-cache is disabled in this build of Git",
+ NULL
+ };
+ struct option options[] = { OPT_END() };
+
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
+ die(_("credential-cache unavailable; no unix socket support"));
+}
+
+#endif /* NO_UNIX_SOCKETS */
diff --git a/credential-store.c b/builtin/credential-store.c
index 294e771..5331ab1 100644
--- a/credential-store.c
+++ b/builtin/credential-store.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
#include "lockfile.h"
#include "credential.h"
#include "string-list.h"
@@ -143,7 +143,7 @@ static void lookup_credential(const struct string_list *fns, struct credential *
return; /* Found credential */
}
-int cmd_main(int argc, const char **argv)
+int cmd_credential_store(int argc, const char **argv, const char *prefix)
{
const char * const usage[] = {
"git credential-store [<options>] <action>",
@@ -161,7 +161,7 @@ int cmd_main(int argc, const char **argv)
umask(077);
- argc = parse_options(argc, (const char **)argv, NULL, options, usage, 0);
+ argc = parse_options(argc, (const char **)argv, prefix, options, usage, 0);
if (argc != 1)
usage_with_options(usage, options);
op = argv[0];
diff --git a/builtin/credential.c b/builtin/credential.c
index 879acfb..d75dcdc 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -1,6 +1,7 @@
#include "git-compat-util.h"
#include "credential.h"
#include "builtin.h"
+#include "config.h"
static const char usage_msg[] =
"git credential [fill|approve|reject]";
@@ -10,6 +11,8 @@ int cmd_credential(int argc, const char **argv, const char *prefix)
const char *op;
struct credential c = CREDENTIAL_INIT;
+ git_config(git_default_config, NULL);
+
if (argc != 2 || !strcmp(argv[1], "-h"))
usage(usage_msg);
op = argv[1];
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 93ec642..7f5281c 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -15,7 +15,7 @@ COMMON_DIFF_OPTIONS_HELP;
int cmd_diff_index(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
- int cached = 0;
+ unsigned int option = 0;
int i;
int result;
@@ -32,7 +32,9 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
const char *arg = argv[i];
if (!strcmp(arg, "--cached"))
- cached = 1;
+ option |= DIFF_INDEX_CACHED;
+ else if (!strcmp(arg, "--merge-base"))
+ option |= DIFF_INDEX_MERGE_BASE;
else
usage(diff_cache_usage);
}
@@ -46,7 +48,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
if (rev.pending.nr != 1 ||
rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
usage(diff_cache_usage);
- if (!cached) {
+ if (!(option & DIFF_INDEX_CACHED)) {
setup_work_tree();
if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
perror("read_cache_preload");
@@ -56,7 +58,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
perror("read_cache");
return -1;
}
- result = run_diff_index(&rev, cached);
+ result = run_diff_index(&rev, option);
UNLEAK(rev);
return diff_result_code(&rev.diffopt, result);
}
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 802363d..9fc95e9 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -111,6 +111,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
struct setup_revision_opt s_r_opt;
struct userformat_want w;
int read_stdin = 0;
+ int merge_base = 0;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(diff_tree_usage);
@@ -143,9 +144,18 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
read_stdin = 1;
continue;
}
+ if (!strcmp(arg, "--merge-base")) {
+ merge_base = 1;
+ continue;
+ }
usage(diff_tree_usage);
}
+ if (read_stdin && merge_base)
+ die(_("--stdin and --merge-base are mutually exclusive"));
+ if (merge_base && opt->pending.nr != 2)
+ die(_("--merge-base only works with two commits"));
+
/*
* NOTE! We expect "a..b" to expand to "^a b" but it is
* perfectly valid for revision range parser to yield "b ^a",
@@ -165,7 +175,12 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
case 2:
tree1 = opt->pending.objects[0].item;
tree2 = opt->pending.objects[1].item;
- if (tree2->flags & UNINTERESTING) {
+ if (merge_base) {
+ struct object_id oid;
+
+ diff_get_merge_base(opt, &oid);
+ tree1 = lookup_object(the_repository, &oid);
+ } else if (tree2->flags & UNINTERESTING) {
SWAP(tree2, tree1);
}
diff_tree_oid(&tree1->oid, &tree2->oid, "", &opt->diffopt);
diff --git a/builtin/diff.c b/builtin/diff.c
index cb98811..780c338 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -26,7 +26,7 @@
static const char builtin_diff_usage[] =
"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> [--merge-base] [<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"
@@ -134,11 +134,13 @@ static int builtin_diff_blobs(struct rev_info *revs,
static int builtin_diff_index(struct rev_info *revs,
int argc, const char **argv)
{
- int cached = 0;
+ unsigned int option = 0;
while (1 < argc) {
const char *arg = argv[1];
if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged"))
- cached = 1;
+ option |= DIFF_INDEX_CACHED;
+ else if (!strcmp(arg, "--merge-base"))
+ option |= DIFF_INDEX_MERGE_BASE;
else
usage(builtin_diff_usage);
argv++; argc--;
@@ -151,7 +153,7 @@ static int builtin_diff_index(struct rev_info *revs,
revs->max_count != -1 || revs->min_age != -1 ||
revs->max_age != -1)
usage(builtin_diff_usage);
- if (!cached) {
+ if (!(option & DIFF_INDEX_CACHED)) {
setup_work_tree();
if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
perror("read_cache_preload");
@@ -161,7 +163,7 @@ static int builtin_diff_index(struct rev_info *revs,
perror("read_cache");
return -1;
}
- return run_diff_index(revs, cached);
+ return run_diff_index(revs, option);
}
static int builtin_diff_tree(struct rev_info *revs,
@@ -170,19 +172,34 @@ static int builtin_diff_tree(struct rev_info *revs,
struct object_array_entry *ent1)
{
const struct object_id *(oid[2]);
- int swap = 0;
+ struct object_id mb_oid;
+ int merge_base = 0;
- if (argc > 1)
- usage(builtin_diff_usage);
+ while (1 < argc) {
+ const char *arg = argv[1];
+ if (!strcmp(arg, "--merge-base"))
+ merge_base = 1;
+ else
+ usage(builtin_diff_usage);
+ argv++; argc--;
+ }
- /*
- * We saw two trees, ent0 and ent1. If ent1 is uninteresting,
- * swap them.
- */
- if (ent1->item->flags & UNINTERESTING)
- swap = 1;
- oid[swap] = &ent0->item->oid;
- oid[1 - swap] = &ent1->item->oid;
+ if (merge_base) {
+ diff_get_merge_base(revs, &mb_oid);
+ oid[0] = &mb_oid;
+ oid[1] = &revs->pending.objects[1].item->oid;
+ } else {
+ int swap = 0;
+
+ /*
+ * We saw two trees, ent0 and ent1. If ent1 is uninteresting,
+ * swap them.
+ */
+ if (ent1->item->flags & UNINTERESTING)
+ swap = 1;
+ oid[swap] = &ent0->item->oid;
+ oid[1 - swap] = &ent1->item->oid;
+ }
diff_tree_oid(oid[0], oid[1], "", &revs->diffopt);
log_tree_diff_flush(revs);
return 0;
@@ -203,8 +220,7 @@ static int builtin_diff_combined(struct rev_info *revs,
revs->dense_combined_merges = revs->combine_merges = 1;
for (i = 1; i < ents; i++)
oid_array_append(&parents, &ent[i].item->oid);
- diff_tree_combined(&ent[0].item->oid, &parents,
- revs->dense_combined_merges, revs);
+ diff_tree_combined(&ent[0].item->oid, &parents, revs);
oid_array_clear(&parents);
return 0;
}
diff --git a/builtin/env--helper.c b/builtin/env--helper.c
index 23c214f..2734909 100644
--- a/builtin/env--helper.c
+++ b/builtin/env--helper.c
@@ -7,18 +7,22 @@ static char const * const env__helper_usage[] = {
NULL
};
-static enum {
+enum cmdmode {
ENV_HELPER_TYPE_BOOL = 1,
ENV_HELPER_TYPE_ULONG
-} cmdmode = 0;
+};
static int option_parse_type(const struct option *opt, const char *arg,
int unset)
{
+ enum cmdmode *cmdmode = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
if (!strcmp(arg, "bool"))
- cmdmode = ENV_HELPER_TYPE_BOOL;
+ *cmdmode = ENV_HELPER_TYPE_BOOL;
else if (!strcmp(arg, "ulong"))
- cmdmode = ENV_HELPER_TYPE_ULONG;
+ *cmdmode = ENV_HELPER_TYPE_ULONG;
else
die(_("unrecognized --type argument, %s"), arg);
@@ -33,6 +37,7 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)
int ret;
int ret_int, default_int;
unsigned long ret_ulong, default_ulong;
+ enum cmdmode cmdmode = 0;
struct option opts[] = {
OPT_CALLBACK_F(0, "type", &cmdmode, N_("type"),
N_("value is given this type"), PARSE_OPT_NONEG,
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 9f37895..d2e33f5 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -405,12 +405,12 @@ 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[GIT_MAX_RAWSZ];
+ struct object_id oid;
char *hex = xmallocz(GIT_MAX_HEXSZ);
- hashclr(out);
- put_be32(out + hashsz - 4, counter++);
- return hash_to_hex_algop_r(hex, out, the_hash_algo);
+ oidclr(&oid);
+ put_be32(oid.hash + hashsz - 4, counter++);
+ return oid_to_hex_r(hex, &oid);
}
static const char *anonymize_oid(const char *oid_hex)
@@ -943,7 +943,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
if (e->flags & UNINTERESTING)
continue;
- if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
+ if (dwim_ref(e->name, strlen(e->name), &oid, &full_name, 0) != 1)
continue;
if (refspecs.nr) {
@@ -1026,7 +1026,7 @@ static void handle_tags_and_duplicates(struct string_list *extras)
/*
* Getting here means we have a commit which
* was excluded by a negative refspec (e.g.
- * fast-export ^master master). If we are
+ * fast-export ^HEAD HEAD). If we are
* referencing excluded commits, set the ref
* to the exact commit. Otherwise, the user
* wants the branch exported but every commit
diff --git a/fast-import.c b/builtin/fast-import.c
index ce47794..dd4d09c 100644
--- a/fast-import.c
+++ b/builtin/fast-import.c
@@ -150,7 +150,7 @@ struct recent_command {
char *buf;
};
-typedef void (*mark_set_inserter_t)(struct mark_set *s, struct object_id *oid, uintmax_t mark);
+typedef void (*mark_set_inserter_t)(struct mark_set **s, struct object_id *oid, uintmax_t mark);
typedef void (*each_mark_fn_t)(uintmax_t mark, void *obj, void *cbp);
/* Configured limits on output */
@@ -526,21 +526,15 @@ static unsigned int hc_str(const char *s, size_t len)
return r;
}
-static char *pool_strdup(const char *s)
+static void insert_mark(struct mark_set **top, uintmax_t idnum, struct object_entry *oe)
{
- size_t len = strlen(s) + 1;
- char *r = mem_pool_alloc(&fi_mem_pool, len);
- memcpy(r, s, len);
- return r;
-}
+ struct mark_set *s = *top;
-static void insert_mark(struct mark_set *s, uintmax_t idnum, struct object_entry *oe)
-{
while ((idnum >> s->shift) >= 1024) {
s = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct mark_set));
- s->shift = marks->shift + 10;
- s->data.sets[0] = marks;
- marks = s;
+ s->shift = (*top)->shift + 10;
+ s->data.sets[0] = *top;
+ *top = s;
}
while (s->shift) {
uintmax_t i = idnum >> s->shift;
@@ -615,7 +609,7 @@ static struct branch *new_branch(const char *name)
die("Branch name doesn't conform to GIT standards: %s", name);
b = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));
- b->name = pool_strdup(name);
+ b->name = mem_pool_strdup(&fi_mem_pool, name);
b->table_next_branch = branch_table[hc];
b->branch_tree.versions[0].mode = S_IFDIR;
b->branch_tree.versions[1].mode = S_IFDIR;
@@ -747,7 +741,6 @@ static void start_packfile(void)
{
struct strbuf tmp_file = STRBUF_INIT;
struct packed_git *p;
- struct pack_header hdr;
int pack_fd;
pack_fd = odb_mkstemp(&tmp_file, "pack/tmp_pack_XXXXXX");
@@ -758,13 +751,8 @@ static void start_packfile(void)
p->do_not_close = 1;
pack_file = hashfd(pack_fd, p->pack_name);
- hdr.hdr_signature = htonl(PACK_SIGNATURE);
- hdr.hdr_version = htonl(2);
- hdr.hdr_entries = 0;
- hashwrite(pack_file, &hdr, sizeof(hdr));
-
pack_data = p;
- pack_size = sizeof(hdr);
+ pack_size = write_pack_header(pack_file, 0);
object_count = 0;
REALLOC_ARRAY(all_packs, pack_id + 1);
@@ -958,7 +946,7 @@ static int store_object(
e = insert_object(&oid);
if (mark)
- insert_mark(marks, mark, e);
+ insert_mark(&marks, mark, e);
if (e->idx.offset) {
duplicate_count_by_type[type]++;
return 1;
@@ -1156,7 +1144,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
e = insert_object(&oid);
if (mark)
- insert_mark(marks, mark, e);
+ insert_mark(&marks, mark, e);
if (e->idx.offset) {
duplicate_count_by_type[OBJ_BLOB]++;
@@ -1731,7 +1719,7 @@ static void dump_marks(void)
}
}
-static void insert_object_entry(struct mark_set *s, struct object_id *oid, uintmax_t mark)
+static void insert_object_entry(struct mark_set **s, struct object_id *oid, uintmax_t mark)
{
struct object_entry *e;
e = find_object(oid);
@@ -1748,12 +1736,12 @@ static void insert_object_entry(struct mark_set *s, struct object_id *oid, uintm
insert_mark(s, mark, e);
}
-static void insert_oid_entry(struct mark_set *s, struct object_id *oid, uintmax_t mark)
+static void insert_oid_entry(struct mark_set **s, struct object_id *oid, uintmax_t mark)
{
insert_mark(s, mark, xmemdupz(oid, sizeof(*oid)));
}
-static void read_mark_file(struct mark_set *s, FILE *f, mark_set_inserter_t inserter)
+static void read_mark_file(struct mark_set **s, FILE *f, mark_set_inserter_t inserter)
{
char line[512];
while (fgets(line, sizeof(line), f)) {
@@ -1786,7 +1774,7 @@ static void read_marks(void)
goto done; /* Marks file does not exist */
else
die_errno("cannot read '%s'", import_marks_file);
- read_mark_file(marks, f, insert_object_entry);
+ read_mark_file(&marks, f, insert_object_entry);
fclose(f);
done:
import_marks_file_done = 1;
@@ -2806,7 +2794,7 @@ static void parse_new_tag(const char *arg)
t = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));
memset(t, 0, sizeof(struct tag));
- t->name = pool_strdup(arg);
+ t->name = mem_pool_strdup(&fi_mem_pool, arg);
if (last_tag)
last_tag->next_tag = t;
else
@@ -3242,7 +3230,7 @@ static void parse_alias(void)
die(_("Expected 'to' command, got %s"), command_buf.buf);
e = find_object(&b.oid);
assert(e);
- insert_mark(marks, next_mark, e);
+ insert_mark(&marks, next_mark, e);
}
static char* make_fast_import_path(const char *path)
@@ -3335,13 +3323,14 @@ static void option_rewrite_submodules(const char *arg, struct string_list *list)
*f = '\0';
f++;
ms = xcalloc(1, sizeof(*ms));
- string_list_insert(list, s)->util = ms;
fp = fopen(f, "r");
if (!fp)
die_errno("cannot read '%s'", f);
- read_mark_file(ms, fp, insert_oid_entry);
+ read_mark_file(&ms, fp, insert_oid_entry);
fclose(fp);
+
+ string_list_insert(list, s)->util = ms;
}
static int parse_one_option(const char *option)
@@ -3410,7 +3399,6 @@ static int parse_one_feature(const char *feature, int from_stream)
option_rewrite_submodules(arg, &sub_marks_to);
} else if (skip_prefix(feature, "rewrite-submodules-from=", &arg)) {
option_rewrite_submodules(arg, &sub_marks_from);
- } else if (skip_prefix(feature, "rewrite-submodules-from=", &arg)) {
} else if (!strcmp(feature, "get-mark")) {
; /* Don't die - this feature is supported */
} else if (!strcmp(feature, "cat-blob")) {
@@ -3519,14 +3507,13 @@ static void parse_argv(void)
build_mark_map(&sub_marks_from, &sub_marks_to);
}
-int cmd_main(int argc, const char **argv)
+int cmd_fast_import(int argc, const char **argv, const char *prefix)
{
unsigned int i;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(fast_import_usage);
- setup_git_directory();
reset_pack_idx_option(&pack_idx_opts);
git_pack_config();
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index bbb5c96..58b7c1f 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -153,10 +153,6 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.from_promisor = 1;
continue;
}
- if (!strcmp("--no-dependents", arg)) {
- args.no_dependents = 1;
- continue;
- }
if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
parse_list_objects_filter(&args.filter_options, arg);
continue;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index cb38e6f..f9c3c49 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -80,6 +80,7 @@ static struct list_objects_filter_options filter_options;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
static int fetch_write_commit_graph = -1;
+static int stdin_refspecs = 0;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
@@ -207,6 +208,8 @@ static struct option builtin_fetch_options[] = {
N_("check for forced-updates on all updated branches")),
OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
N_("write the commit-graph after fetching")),
+ OPT_BOOL(0, "stdin", &stdin_refspecs,
+ N_("accept refspecs from stdin")),
OPT_END()
};
@@ -444,6 +447,7 @@ static struct ref *get_ref_map(struct remote *remote,
struct ref *orefs = NULL, **oref_tail = &orefs;
struct hashmap existing_refs;
+ int existing_refs_populated = 0;
if (rs->nr) {
struct refspec *fetch_refspec;
@@ -535,10 +539,17 @@ static struct ref *get_ref_map(struct remote *remote,
tail = &rm->next;
}
- ref_map = ref_remove_duplicates(ref_map);
+ /*
+ * apply negative refspecs first, before we remove duplicates. This is
+ * necessary as negative refspecs might remove an otherwise conflicting
+ * duplicate.
+ */
+ if (rs->nr)
+ ref_map = apply_negative_refspecs(ref_map, rs);
+ else
+ ref_map = apply_negative_refspecs(ref_map, &remote->fetch);
- refname_hash_init(&existing_refs);
- for_each_ref(add_one_refname, &existing_refs);
+ ref_map = ref_remove_duplicates(ref_map);
for (rm = ref_map; rm; rm = rm->next) {
if (rm->peer_ref) {
@@ -546,6 +557,12 @@ static struct ref *get_ref_map(struct remote *remote,
struct refname_hash_entry *peer_item;
unsigned int hash = strhash(refname);
+ if (!existing_refs_populated) {
+ refname_hash_init(&existing_refs);
+ for_each_ref(add_one_refname, &existing_refs);
+ existing_refs_populated = 1;
+ }
+
peer_item = hashmap_get_entry_from_hash(&existing_refs,
hash, refname,
struct refname_hash_entry, ent);
@@ -555,7 +572,8 @@ static struct ref *get_ref_map(struct remote *remote,
}
}
}
- hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
+ if (existing_refs_populated)
+ hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
return ref_map;
}
@@ -650,7 +668,7 @@ static void prepare_format_display(struct ref *ref_map)
struct ref *rm;
const char *format = "full";
- git_config_get_string_const("fetch.output", &format);
+ git_config_get_string_tmp("fetch.output", &format);
if (!strcasecmp(format, "full"))
compact_format = 0;
else if (!strcasecmp(format, "compact"))
@@ -960,8 +978,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
ref->force = rm->peer_ref->force;
}
- if (recurse_submodules != RECURSE_SUBMODULES_OFF)
+ if (recurse_submodules != RECURSE_SUBMODULES_OFF &&
+ (!rm->peer_ref || !oideq(&ref->old_oid, &ref->new_oid))) {
check_for_new_submodule_commits(&rm->old_oid);
+ }
if (!strcmp(rm->name, "HEAD")) {
kind = "";
@@ -1017,11 +1037,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
rc |= update_local_ref(ref, what, rm, &note,
summary_width);
free(ref);
- } else
+ } else if (write_fetch_head || dry_run) {
+ /*
+ * Display fetches written to FETCH_HEAD (or
+ * would be written to FETCH_HEAD, if --dry-run
+ * is set).
+ */
format_display(&note, '*',
*kind ? kind : "branch", NULL,
*what ? what : "HEAD",
"FETCH_HEAD", summary_width);
+ }
if (note.len) {
if (verbosity >= 0 && !shown_url) {
fprintf(stderr, _("From %.*s\n"),
@@ -1538,7 +1564,10 @@ static void add_options_to_argv(struct strvec *argv)
strvec_push(argv, "-v");
else if (verbosity < 0)
strvec_push(argv, "-q");
-
+ if (family == TRANSPORT_FAMILY_IPV4)
+ strvec_push(argv, "--ipv4");
+ else if (family == TRANSPORT_FAMILY_IPV6)
+ strvec_push(argv, "--ipv6");
}
/* Fetch multiple remotes in parallel */
@@ -1665,7 +1694,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)
* If this is a partial-fetch request, we enable partial on
* this repo if not already enabled and remember the given
* filter-spec as the default for subsequent fetches to this
- * remote.
+ * remote if there is currently no default filter-spec.
*/
if (filter_options.choice) {
partial_clone_register(remote->name, &filter_options);
@@ -1682,7 +1711,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)
return;
}
-static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
+static int fetch_one(struct remote *remote, int argc, const char **argv,
+ int prune_tags_ok, int use_stdin_refspecs)
{
struct refspec rs = REFSPEC_INIT_FETCH;
int i;
@@ -1725,20 +1755,24 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "tag")) {
- char *tag;
i++;
if (i >= argc)
die(_("You need to specify a tag name."));
- tag = xstrfmt("refs/tags/%s:refs/tags/%s",
- argv[i], argv[i]);
- refspec_append(&rs, tag);
- free(tag);
+ refspec_appendf(&rs, "refs/tags/%s:refs/tags/%s",
+ argv[i], argv[i]);
} else {
refspec_append(&rs, argv[i]);
}
}
+ if (use_stdin_refspecs) {
+ struct strbuf line = STRBUF_INIT;
+ while (strbuf_getline_lf(&line, stdin) != EOF)
+ refspec_append(&rs, line.buf);
+ strbuf_release(&line);
+ }
+
if (server_options.nr)
gtransport->server_options = &server_options;
@@ -1773,12 +1807,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
free(anon);
}
- fetch_config_from_gitmodules(&submodule_fetch_jobs_config,
- &recurse_submodules);
git_config(git_fetch_config, NULL);
argc = parse_options(argc, argv, prefix,
builtin_fetch_options, builtin_fetch_usage, 0);
+ if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
+ int *sfjc = submodule_fetch_jobs_config == -1
+ ? &submodule_fetch_jobs_config : NULL;
+ int *rs = recurse_submodules == RECURSE_SUBMODULES_DEFAULT
+ ? &recurse_submodules : NULL;
+
+ fetch_config_from_gitmodules(sfjc, rs);
+ }
if (deepen_relative) {
if (deepen_relative < 0)
@@ -1839,7 +1879,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (remote) {
if (filter_options.choice || has_promisor_remote())
fetch_one_setup_partial(remote);
- result = fetch_one(remote, argc, argv, prune_tags_ok);
+ result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs);
} else {
int max_children = max_jobs;
@@ -1847,6 +1887,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
die(_("--filter can only be used with the remote "
"configured in extensions.partialclone"));
+ if (stdin_refspecs)
+ die(_("--stdin can only be used when fetching "
+ "from one remote"));
+
if (max_children < 0)
max_children = fetch_parallel_config;
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 57489e4..9d1ecda 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -9,7 +9,7 @@
static char const * const for_each_ref_usage[] = {
N_("git for-each-ref [<options>] [<pattern>]"),
N_("git for-each-ref [--points-at <object>]"),
- N_("git for-each-ref [(--merged | --no-merged) [<commit>]]"),
+ N_("git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"),
N_("git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"),
NULL
};
diff --git a/builtin/gc.c b/builtin/gc.c
index e3098ef..3d258b6 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -777,9 +777,15 @@ static int dfs_on_ref(const char *refname,
commit = lookup_commit(the_repository, oid);
if (!commit)
return 0;
- if (parse_commit(commit))
+ if (parse_commit(commit) ||
+ commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
return 0;
+ data->num_not_in_graph++;
+
+ if (data->num_not_in_graph >= data->limit)
+ return 1;
+
commit_list_append(commit, &stack);
while (!result && stack) {
@@ -826,7 +832,7 @@ static int should_write_commit_graph(void)
result = for_each_ref(dfs_on_ref, &data);
- clear_commit_marks_all(SEEN);
+ repo_clear_commit_marks(the_repository, SEEN);
return result;
}
@@ -847,6 +853,10 @@ static int run_write_commit_graph(struct maintenance_run_opts *opts)
static int maintenance_task_commit_graph(struct maintenance_run_opts *opts)
{
+ prepare_repo_settings(the_repository);
+ if (!the_repository->settings.core_commit_graph)
+ return 0;
+
close_object_store(the_repository->objects);
if (run_write_commit_graph(opts)) {
error(_("failed to write commit-graph"));
diff --git a/builtin/grep.c b/builtin/grep.c
index cee9db3..e58e575 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -319,7 +319,7 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,
}
if (opt->relative && opt->prefix_length)
- quote_path_relative(filename + tree_name_len, opt->prefix, out);
+ quote_path(filename + tree_name_len, opt->prefix, out, 0);
else
quote_c_style(filename + tree_name_len, out, NULL, 0);
@@ -670,6 +670,17 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
NULL, 0);
obj_read_unlock();
+ if (!real_obj) {
+ char hex[GIT_MAX_HEXSZ + 1];
+ const char *name = list->objects[i].name;
+
+ if (!name) {
+ oid_to_hex_r(hex, &list->objects[i].item->oid);
+ name = hex;
+ }
+ die(_("invalid object '%s' given."), name);
+ }
+
/* load the gitmodules file for this rev */
if (recurse_submodules) {
submodule_free(opt->repo);
@@ -693,7 +704,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
struct dir_struct dir;
int i, hit = 0;
- memset(&dir, 0, sizeof(dir));
+ dir_init(&dir);
if (!use_index)
dir.flags |= DIR_NO_GITLINKS;
if (exc_std)
@@ -705,6 +716,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
if (hit && opt->status_only)
break;
}
+ dir_clear(&dir);
return hit;
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index f865666..0d03cb4 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -33,19 +33,61 @@ struct object_stat {
};
struct base_data {
+ /* Initialized by make_base(). */
struct base_data *base;
- struct base_data *child;
struct object_entry *obj;
- void *data;
- unsigned long size;
int ref_first, ref_last;
int ofs_first, ofs_last;
+ /*
+ * Threads should increment retain_data if they are about to call
+ * patch_delta() using this struct's data as a base, and decrement this
+ * when they are done. While retain_data is nonzero, this struct's data
+ * will not be freed even if the delta base cache limit is exceeded.
+ */
+ int retain_data;
+ /*
+ * The number of direct children that have not been fully processed
+ * (entered work_head, entered done_head, left done_head). When this
+ * number reaches zero, this struct base_data can be freed.
+ */
+ int children_remaining;
+
+ /* Not initialized by make_base(). */
+ struct list_head list;
+ void *data;
+ unsigned long size;
};
+/*
+ * Stack of struct base_data that have unprocessed children.
+ * threaded_second_pass() uses this as a source of work (the other being the
+ * objects array).
+ *
+ * Guarded by work_mutex.
+ */
+static LIST_HEAD(work_head);
+
+/*
+ * Stack of struct base_data that have children, all of whom have been
+ * processed or are being processed, and at least one child is being processed.
+ * These struct base_data must be kept around until the last child is
+ * processed.
+ *
+ * Guarded by work_mutex.
+ */
+static LIST_HEAD(done_head);
+
+/*
+ * All threads share one delta base cache.
+ *
+ * base_cache_used is guarded by work_mutex, and base_cache_limit is read-only
+ * in a thread.
+ */
+static size_t base_cache_used;
+static size_t base_cache_limit;
+
struct thread_local {
pthread_t thread;
- struct base_data *base_cache;
- size_t base_cache_used;
int pack_fd;
};
@@ -117,10 +159,6 @@ static pthread_mutex_t deepest_delta_mutex;
#define deepest_delta_lock() lock_mutex(&deepest_delta_mutex)
#define deepest_delta_unlock() unlock_mutex(&deepest_delta_mutex)
-static pthread_mutex_t type_cas_mutex;
-#define type_cas_lock() lock_mutex(&type_cas_mutex)
-#define type_cas_unlock() unlock_mutex(&type_cas_mutex)
-
static pthread_key_t key;
static inline void lock_mutex(pthread_mutex_t *mutex)
@@ -144,7 +182,6 @@ static void init_thread(void)
init_recursive_mutex(&read_mutex);
pthread_mutex_init(&counter_mutex, NULL);
pthread_mutex_init(&work_mutex, NULL);
- pthread_mutex_init(&type_cas_mutex, NULL);
if (show_stat)
pthread_mutex_init(&deepest_delta_mutex, NULL);
pthread_key_create(&key, NULL);
@@ -167,7 +204,6 @@ static void cleanup_thread(void)
pthread_mutex_destroy(&read_mutex);
pthread_mutex_destroy(&counter_mutex);
pthread_mutex_destroy(&work_mutex);
- pthread_mutex_destroy(&type_cas_mutex);
if (show_stat)
pthread_mutex_destroy(&deepest_delta_mutex);
for (i = 0; i < nr_threads; i++)
@@ -364,56 +400,42 @@ static void set_thread_data(struct thread_local *data)
pthread_setspecific(key, data);
}
-static struct base_data *alloc_base_data(void)
-{
- struct base_data *base = xcalloc(1, sizeof(struct base_data));
- base->ref_last = -1;
- base->ofs_last = -1;
- return base;
-}
-
static void free_base_data(struct base_data *c)
{
if (c->data) {
FREE_AND_NULL(c->data);
- get_thread_data()->base_cache_used -= c->size;
+ base_cache_used -= c->size;
}
}
static void prune_base_data(struct base_data *retain)
{
- struct base_data *b;
- struct thread_local *data = get_thread_data();
- for (b = data->base_cache;
- data->base_cache_used > delta_base_cache_limit && b;
- b = b->child) {
- if (b->data && b != retain)
- free_base_data(b);
- }
-}
+ struct list_head *pos;
-static void link_base_data(struct base_data *base, struct base_data *c)
-{
- if (base)
- base->child = c;
- else
- get_thread_data()->base_cache = c;
+ if (base_cache_used <= base_cache_limit)
+ return;
- c->base = base;
- c->child = NULL;
- if (c->data)
- get_thread_data()->base_cache_used += c->size;
- prune_base_data(c);
-}
+ list_for_each_prev(pos, &done_head) {
+ struct base_data *b = list_entry(pos, struct base_data, list);
+ if (b->retain_data || b == retain)
+ continue;
+ if (b->data) {
+ free_base_data(b);
+ if (base_cache_used <= base_cache_limit)
+ return;
+ }
+ }
-static void unlink_base_data(struct base_data *c)
-{
- struct base_data *base = c->base;
- if (base)
- base->child = NULL;
- else
- get_thread_data()->base_cache = NULL;
- free_base_data(c);
+ list_for_each_prev(pos, &work_head) {
+ struct base_data *b = list_entry(pos, struct base_data, list);
+ if (b->retain_data || b == retain)
+ continue;
+ if (b->data) {
+ free_base_data(b);
+ if (base_cache_used <= base_cache_limit)
+ return;
+ }
+ }
}
static int is_delta_type(enum object_type type)
@@ -614,7 +636,7 @@ static int compare_ofs_delta_bases(off_t offset1, off_t offset2,
0;
}
-static int find_ofs_delta(const off_t offset, enum object_type type)
+static int find_ofs_delta(const off_t offset)
{
int first = 0, last = nr_ofs_deltas;
@@ -624,7 +646,8 @@ static int find_ofs_delta(const off_t offset, enum object_type type)
int cmp;
cmp = compare_ofs_delta_bases(offset, delta->offset,
- type, objects[delta->obj_no].type);
+ OBJ_OFS_DELTA,
+ objects[delta->obj_no].type);
if (!cmp)
return next;
if (cmp < 0) {
@@ -637,10 +660,9 @@ static int find_ofs_delta(const off_t offset, enum object_type type)
}
static void find_ofs_delta_children(off_t offset,
- int *first_index, int *last_index,
- enum object_type type)
+ int *first_index, int *last_index)
{
- int first = find_ofs_delta(offset, type);
+ int first = find_ofs_delta(offset);
int last = first;
int end = nr_ofs_deltas - 1;
@@ -668,7 +690,7 @@ static int compare_ref_delta_bases(const struct object_id *oid1,
return oidcmp(oid1, oid2);
}
-static int find_ref_delta(const struct object_id *oid, enum object_type type)
+static int find_ref_delta(const struct object_id *oid)
{
int first = 0, last = nr_ref_deltas;
@@ -678,7 +700,8 @@ static int find_ref_delta(const struct object_id *oid, enum object_type type)
int cmp;
cmp = compare_ref_delta_bases(oid, &delta->oid,
- type, objects[delta->obj_no].type);
+ OBJ_REF_DELTA,
+ objects[delta->obj_no].type);
if (!cmp)
return next;
if (cmp < 0) {
@@ -691,10 +714,9 @@ static int find_ref_delta(const struct object_id *oid, enum object_type type)
}
static void find_ref_delta_children(const struct object_id *oid,
- int *first_index, int *last_index,
- enum object_type type)
+ int *first_index, int *last_index)
{
- int first = find_ref_delta(oid, type);
+ int first = find_ref_delta(oid);
int last = first;
int end = nr_ref_deltas - 1;
@@ -866,26 +888,15 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
}
/*
- * This function is part of find_unresolved_deltas(). There are two
- * walkers going in the opposite ways.
- *
- * The first one in find_unresolved_deltas() traverses down from
- * parent node to children, deflating nodes along the way. However,
- * memory for deflated nodes is limited by delta_base_cache_limit, so
- * at some point parent node's deflated content may be freed.
- *
- * The second walker is this function, which goes from current node up
- * to top parent if necessary to deflate the node. In normal
- * situation, its parent node would be already deflated, so it just
- * needs to apply delta.
- *
- * In the worst case scenario, parent node is no longer deflated because
- * we're running out of delta_base_cache_limit; we need to re-deflate
- * parents, possibly up to the top base.
+ * Ensure that this node has been reconstructed and return its contents.
*
- * All deflated objects here are subject to be freed if we exceed
- * delta_base_cache_limit, just like in find_unresolved_deltas(), we
- * just need to make sure the last node is not freed.
+ * In the typical and best case, this node would already be reconstructed
+ * (through the invocation to resolve_delta() in threaded_second_pass()) and it
+ * would not be pruned. However, if pruning of this node was necessary due to
+ * reaching delta_base_cache_limit, this function will find the closest
+ * ancestor with reconstructed data that has not been pruned (or if there is
+ * none, the ultimate base object), and reconstruct each node in the delta
+ * chain in order to generate the reconstructed data for this node.
*/
static void *get_base_data(struct base_data *c)
{
@@ -902,7 +913,7 @@ static void *get_base_data(struct base_data *c)
if (!delta_nr) {
c->data = get_data_from_pack(obj);
c->size = obj->size;
- get_thread_data()->base_cache_used += c->size;
+ base_cache_used += c->size;
prune_base_data(c);
}
for (; delta_nr > 0; delta_nr--) {
@@ -918,7 +929,7 @@ static void *get_base_data(struct base_data *c)
free(raw);
if (!c->data)
bad_object(obj->idx.offset, _("failed to apply delta"));
- get_thread_data()->base_cache_used += c->size;
+ base_cache_used += c->size;
prune_base_data(c);
}
free(delta);
@@ -926,10 +937,27 @@ static void *get_base_data(struct base_data *c)
return c->data;
}
-static void resolve_delta(struct object_entry *delta_obj,
- struct base_data *base, struct base_data *result)
+static struct base_data *make_base(struct object_entry *obj,
+ struct base_data *parent)
{
- void *base_data, *delta_data;
+ struct base_data *base = xcalloc(1, sizeof(struct base_data));
+ base->base = parent;
+ base->obj = obj;
+ find_ref_delta_children(&obj->idx.oid,
+ &base->ref_first, &base->ref_last);
+ find_ofs_delta_children(obj->idx.offset,
+ &base->ofs_first, &base->ofs_last);
+ base->children_remaining = base->ref_last - base->ref_first +
+ base->ofs_last - base->ofs_first + 2;
+ return base;
+}
+
+static struct base_data *resolve_delta(struct object_entry *delta_obj,
+ struct base_data *base)
+{
+ void *delta_data, *result_data;
+ struct base_data *result;
+ unsigned long result_size;
if (show_stat) {
int i = delta_obj - objects;
@@ -942,115 +970,26 @@ static void resolve_delta(struct object_entry *delta_obj,
obj_stat[i].base_object_no = j;
}
delta_data = get_data_from_pack(delta_obj);
- base_data = get_base_data(base);
- result->obj = delta_obj;
- result->data = patch_delta(base_data, base->size,
- delta_data, delta_obj->size, &result->size);
+ assert(base->data);
+ result_data = patch_delta(base->data, base->size,
+ delta_data, delta_obj->size, &result_size);
free(delta_data);
- if (!result->data)
+ if (!result_data)
bad_object(delta_obj->idx.offset, _("failed to apply delta"));
- hash_object_file(the_hash_algo, result->data, result->size,
+ hash_object_file(the_hash_algo, result_data, result_size,
type_name(delta_obj->real_type), &delta_obj->idx.oid);
- sha1_object(result->data, NULL, result->size, delta_obj->real_type,
+ sha1_object(result_data, NULL, result_size, delta_obj->real_type,
&delta_obj->idx.oid);
+
+ result = make_base(delta_obj, base);
+ result->data = result_data;
+ result->size = result_size;
+
counter_lock();
nr_resolved_deltas++;
counter_unlock();
-}
-
-/*
- * Standard boolean compare-and-swap: atomically check whether "*type" is
- * "want"; if so, swap in "set" and return true. Otherwise, leave it untouched
- * and return false.
- */
-static int compare_and_swap_type(signed char *type,
- enum object_type want,
- enum object_type set)
-{
- enum object_type old;
-
- type_cas_lock();
- old = *type;
- if (old == want)
- *type = set;
- type_cas_unlock();
- return old == want;
-}
-
-static struct base_data *find_unresolved_deltas_1(struct base_data *base,
- struct base_data *prev_base)
-{
- if (base->ref_last == -1 && base->ofs_last == -1) {
- find_ref_delta_children(&base->obj->idx.oid,
- &base->ref_first, &base->ref_last,
- OBJ_REF_DELTA);
-
- find_ofs_delta_children(base->obj->idx.offset,
- &base->ofs_first, &base->ofs_last,
- OBJ_OFS_DELTA);
-
- if (base->ref_last == -1 && base->ofs_last == -1) {
- free(base->data);
- return NULL;
- }
-
- link_base_data(prev_base, base);
- }
-
- if (base->ref_first <= base->ref_last) {
- struct object_entry *child = objects + ref_deltas[base->ref_first].obj_no;
- struct base_data *result = alloc_base_data();
-
- if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
- base->obj->real_type))
- die("REF_DELTA at offset %"PRIuMAX" already resolved (duplicate base %s?)",
- (uintmax_t)child->idx.offset,
- oid_to_hex(&base->obj->idx.oid));
-
- resolve_delta(child, base, result);
- if (base->ref_first == base->ref_last && base->ofs_last == -1)
- free_base_data(base);
-
- base->ref_first++;
- return result;
- }
-
- if (base->ofs_first <= base->ofs_last) {
- struct object_entry *child = objects + ofs_deltas[base->ofs_first].obj_no;
- struct base_data *result = alloc_base_data();
-
- assert(child->real_type == OBJ_OFS_DELTA);
- child->real_type = base->obj->real_type;
- resolve_delta(child, base, result);
- if (base->ofs_first == base->ofs_last)
- free_base_data(base);
-
- base->ofs_first++;
- return result;
- }
-
- unlink_base_data(base);
- return NULL;
-}
-
-static void find_unresolved_deltas(struct base_data *base)
-{
- struct base_data *new_base, *prev_base = NULL;
- for (;;) {
- new_base = find_unresolved_deltas_1(base, prev_base);
-
- if (new_base) {
- prev_base = base;
- base = new_base;
- } else {
- free(base);
- base = prev_base;
- if (!base)
- return;
- prev_base = base->base;
- }
- }
+ return result;
}
static int compare_ofs_delta_entry(const void *a, const void *b)
@@ -1071,34 +1010,135 @@ static int compare_ref_delta_entry(const void *a, const void *b)
return oidcmp(&delta_a->oid, &delta_b->oid);
}
-static void resolve_base(struct object_entry *obj)
-{
- struct base_data *base_obj = alloc_base_data();
- base_obj->obj = obj;
- base_obj->data = NULL;
- find_unresolved_deltas(base_obj);
-}
-
static void *threaded_second_pass(void *data)
{
- set_thread_data(data);
+ if (data)
+ set_thread_data(data);
for (;;) {
- int i;
+ struct base_data *parent = NULL;
+ struct object_entry *child_obj;
+ struct base_data *child;
+
counter_lock();
display_progress(progress, nr_resolved_deltas);
counter_unlock();
+
work_lock();
- while (nr_dispatched < nr_objects &&
- is_delta_type(objects[nr_dispatched].type))
- nr_dispatched++;
- if (nr_dispatched >= nr_objects) {
- work_unlock();
- break;
+ if (list_empty(&work_head)) {
+ /*
+ * Take an object from the object array.
+ */
+ while (nr_dispatched < nr_objects &&
+ is_delta_type(objects[nr_dispatched].type))
+ nr_dispatched++;
+ if (nr_dispatched >= nr_objects) {
+ work_unlock();
+ break;
+ }
+ child_obj = &objects[nr_dispatched++];
+ } else {
+ /*
+ * Peek at the top of the stack, and take a child from
+ * it.
+ */
+ parent = list_first_entry(&work_head, struct base_data,
+ list);
+
+ if (parent->ref_first <= parent->ref_last) {
+ int offset = ref_deltas[parent->ref_first++].obj_no;
+ child_obj = objects + offset;
+ if (child_obj->real_type != OBJ_REF_DELTA)
+ die("REF_DELTA at offset %"PRIuMAX" already resolved (duplicate base %s?)",
+ (uintmax_t) child_obj->idx.offset,
+ oid_to_hex(&parent->obj->idx.oid));
+ child_obj->real_type = parent->obj->real_type;
+ } else {
+ child_obj = objects +
+ ofs_deltas[parent->ofs_first++].obj_no;
+ assert(child_obj->real_type == OBJ_OFS_DELTA);
+ child_obj->real_type = parent->obj->real_type;
+ }
+
+ if (parent->ref_first > parent->ref_last &&
+ parent->ofs_first > parent->ofs_last) {
+ /*
+ * This parent has run out of children, so move
+ * it to done_head.
+ */
+ list_del(&parent->list);
+ list_add(&parent->list, &done_head);
+ }
+
+ /*
+ * Ensure that the parent has data, since we will need
+ * it later.
+ *
+ * NEEDSWORK: If parent data needs to be reloaded, this
+ * prolongs the time that the current thread spends in
+ * the mutex. A mitigating factor is that parent data
+ * needs to be reloaded only if the delta base cache
+ * limit is exceeded, so in the typical case, this does
+ * not happen.
+ */
+ get_base_data(parent);
+ parent->retain_data++;
}
- i = nr_dispatched++;
work_unlock();
- resolve_base(&objects[i]);
+ if (parent) {
+ child = resolve_delta(child_obj, parent);
+ if (!child->children_remaining)
+ FREE_AND_NULL(child->data);
+ } else {
+ child = make_base(child_obj, NULL);
+ if (child->children_remaining) {
+ /*
+ * Since this child has its own delta children,
+ * we will need this data in the future.
+ * Inflate now so that future iterations will
+ * have access to this object's data while
+ * outside the work mutex.
+ */
+ child->data = get_data_from_pack(child_obj);
+ child->size = child_obj->size;
+ }
+ }
+
+ work_lock();
+ if (parent)
+ parent->retain_data--;
+ if (child->data) {
+ /*
+ * This child has its own children, so add it to
+ * work_head.
+ */
+ list_add(&child->list, &work_head);
+ base_cache_used += child->size;
+ prune_base_data(NULL);
+ } else {
+ /*
+ * This child does not have its own children. It may be
+ * the last descendant of its ancestors; free those
+ * that we can.
+ */
+ struct base_data *p = parent;
+
+ while (p) {
+ struct base_data *next_p;
+
+ p->children_remaining--;
+ if (p->children_remaining)
+ break;
+
+ next_p = p->base;
+ free_base_data(p);
+ list_del(&p->list);
+ free(p);
+
+ p = next_p;
+ }
+ }
+ work_unlock();
}
return NULL;
}
@@ -1199,6 +1239,7 @@ static void resolve_deltas(void)
nr_ref_deltas + nr_ofs_deltas);
nr_dispatched = 0;
+ base_cache_limit = delta_base_cache_limit * nr_threads;
if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) {
init_thread();
for (i = 0; i < nr_threads; i++) {
@@ -1213,15 +1254,7 @@ static void resolve_deltas(void)
cleanup_thread();
return;
}
-
- for (i = 0; i < nr_objects; i++) {
- struct object_entry *obj = &objects[i];
-
- if (is_delta_type(obj->type))
- continue;
- resolve_base(obj);
- display_progress(progress, nr_resolved_deltas);
- }
+ threaded_second_pass(&nothread_data);
}
/*
@@ -1376,22 +1409,28 @@ static void fix_unresolved_deltas(struct hashfile *f)
for (i = 0; i < nr_ref_deltas; i++) {
struct ref_delta_entry *d = sorted_by_pos[i];
enum object_type type;
- struct base_data *base_obj = alloc_base_data();
+ void *data;
+ unsigned long size;
if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
continue;
- base_obj->data = read_object_file(&d->oid, &type,
- &base_obj->size);
- if (!base_obj->data)
+ data = read_object_file(&d->oid, &type, &size);
+ if (!data)
continue;
if (check_object_signature(the_repository, &d->oid,
- base_obj->data, base_obj->size,
+ data, size,
type_name(type)))
die(_("local object %s is corrupt"), oid_to_hex(&d->oid));
- base_obj->obj = append_obj_to_pack(f, d->oid.hash,
- base_obj->data, base_obj->size, type);
- find_unresolved_deltas(base_obj);
+
+ /*
+ * Add this as an object to the objects array and call
+ * threaded_second_pass() (which will pick up the added
+ * object).
+ */
+ append_obj_to_pack(f, d->oid.hash, data, size, type);
+ threaded_second_pass(NULL);
+
display_progress(progress, nr_resolved_deltas);
}
free(sorted_by_pos);
@@ -1798,9 +1837,22 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (HAVE_THREADS && !nr_threads) {
nr_threads = online_cpus();
- /* An experiment showed that more threads does not mean faster */
- if (nr_threads > 3)
- nr_threads = 3;
+ /*
+ * Experiments show that going above 20 threads doesn't help,
+ * no matter how many cores you have. Below that, we tend to
+ * max at half the number of online_cpus(), presumably because
+ * half of those are hyperthreads rather than full cores. We'll
+ * never reduce the level below "3", though, to match a
+ * historical value that nobody complained about.
+ */
+ if (nr_threads < 4)
+ ; /* too few cores to consider capping */
+ else if (nr_threads < 6)
+ nr_threads = 3; /* historic cap */
+ else if (nr_threads < 40)
+ nr_threads /= 2;
+ else
+ nr_threads = 20; /* hard cap */
}
curr_pack = open_pack_file(pack_name);
diff --git a/builtin/init-db.c b/builtin/init-db.c
index f70076d..01bc648 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "exec-cmd.h"
#include "parse-options.h"
+#include "worktree.h"
#ifndef DEFAULT_GIT_TEMPLATE_DIR
#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
@@ -178,7 +179,7 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree)
return 1;
}
-void initialize_repository_version(int hash_algo)
+void initialize_repository_version(int hash_algo, int reinit)
{
char repo_version_string[10];
int repo_version = GIT_REPO_VERSION;
@@ -194,6 +195,8 @@ void initialize_repository_version(int hash_algo)
if (hash_algo != GIT_HASH_SHA1)
git_config_set("extensions.objectformat",
hash_algos[hash_algo].name);
+ else if (reinit)
+ git_config_set_gently("extensions.objectformat", NULL);
}
static int create_default_files(const char *template_path,
@@ -276,7 +279,7 @@ static int create_default_files(const char *template_path,
free(ref);
}
- initialize_repository_version(fmt->hash_algo);
+ initialize_repository_version(fmt->hash_algo, 0);
/* Check filemode trustability */
path = git_path_buf(&buf, "config");
@@ -364,6 +367,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
if (rename(src, git_dir))
die_errno(_("unable to move %s to %s"), src, git_dir);
+ repair_worktrees(NULL, NULL);
}
write_file(git_link, "gitdir: %s", git_dir);
@@ -563,6 +567,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
+ if (real_git_dir && is_bare_repository_cfg == 1)
+ die(_("--separate-git-dir and --bare are mutually exclusive"));
+
if (real_git_dir && !is_absolute_path(real_git_dir))
real_git_dir = real_pathdup(real_git_dir, 1);
@@ -637,6 +644,30 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
if (!git_dir)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
+ /*
+ * When --separate-git-dir is used inside a linked worktree, take
+ * care to ensure that the common .git/ directory is relocated, not
+ * the worktree-specific .git/worktrees/<id>/ directory.
+ */
+ if (real_git_dir) {
+ int err;
+ const char *p;
+ struct strbuf sb = STRBUF_INIT;
+
+ p = read_gitfile_gently(git_dir, &err);
+ if (p && get_common_dir(&sb, p)) {
+ struct strbuf mainwt = STRBUF_INIT;
+
+ strbuf_addbuf(&mainwt, &sb);
+ strbuf_strip_suffix(&mainwt, "/.git");
+ if (chdir(mainwt.buf) < 0)
+ die_errno(_("cannot chdir to %s"), mainwt.buf);
+ strbuf_release(&mainwt);
+ git_dir = strbuf_detach(&sb, NULL);
+ }
+ strbuf_release(&sb);
+ }
+
if (is_bare_repository_cfg < 0)
is_bare_repository_cfg = guess_repository_type(git_dir);
@@ -658,6 +689,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
get_git_work_tree());
}
else {
+ if (real_git_dir)
+ die(_("--separate-git-dir incompatible with bare repository"));
if (work_tree)
set_git_work_tree(work_tree);
}
diff --git a/builtin/log.c b/builtin/log.c
index b58f8da..6619e10 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -33,7 +33,6 @@
#include "commit-slab.h"
#include "repository.h"
#include "commit-reach.h"
-#include "interdiff.h"
#include "range-diff.h"
#define MAIL_DEFAULT_WRAP 72
@@ -207,6 +206,9 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
if (argc > 1)
die(_("unrecognized argument: %s"), argv[1]);
+ if (rev->line_level_traverse && rev->prune_data.nr)
+ die(_("-L<range>:<file> cannot be used with pathspec"));
+
memset(&w, 0, sizeof(w));
userformat_find_requirements(NULL, &w);
@@ -806,9 +808,15 @@ enum cover_from_description {
COVER_FROM_AUTO
};
+enum auto_base_setting {
+ AUTO_BASE_NEVER,
+ AUTO_BASE_ALWAYS,
+ AUTO_BASE_WHEN_ABLE
+};
+
static enum thread_level thread;
static int do_signoff;
-static int base_auto;
+static enum auto_base_setting auto_base;
static char *from;
static const char *signature = git_version_string;
static const char *signature_file;
@@ -907,7 +915,11 @@ static int git_format_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "format.outputdirectory"))
return git_config_string(&config_output_directory, var, value);
if (!strcmp(var, "format.useautobase")) {
- base_auto = git_config_bool(var, value);
+ if (value && !strcasecmp(value, "whenAble")) {
+ auto_base = AUTO_BASE_WHEN_ABLE;
+ return 0;
+ }
+ auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
return 0;
}
if (!strcmp(var, "format.from")) {
@@ -1061,7 +1073,7 @@ static char *find_branch_name(struct rev_info *rev)
return NULL;
ref = rev->cmdline.rev[positive].name;
tip_oid = &rev->cmdline.rev[positive].item->oid;
- if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) &&
+ if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref, 0) &&
skip_prefix(full_ref, "refs/heads/", &v) &&
oideq(tip_oid, &branch_oid))
branch = xstrdup(v);
@@ -1144,7 +1156,7 @@ static void get_notes_args(struct strvec *arg, struct rev_info *rev)
}
}
-static void make_cover_letter(struct rev_info *rev, int use_stdout,
+static void make_cover_letter(struct rev_info *rev, int use_separate_file,
struct commit *origin,
int nr, struct commit **list,
const char *branch_name,
@@ -1164,7 +1176,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
committer = git_committer_info(0);
- if (!use_stdout &&
+ if (use_separate_file &&
open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
die(_("failed to create cover-letter file"));
@@ -1196,6 +1208,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
log.in1 = 2;
log.in2 = 4;
log.file = rev->diffopt.file;
+ log.groups = SHORTLOG_GROUP_AUTHOR;
for (i = 0; i < nr; i++)
shortlog_add_commit(&log, list[i]);
@@ -1207,7 +1220,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
if (rev->idiff_oid1) {
fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title);
- show_interdiff(rev, 0);
+ show_interdiff(rev->idiff_oid1, rev->idiff_oid2, 0,
+ &rev->diffopt);
}
if (rev->rdiff1) {
@@ -1424,6 +1438,23 @@ static int from_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int base_callback(const struct option *opt, const char *arg, int unset)
+{
+ const char **base_commit = opt->value;
+
+ if (unset) {
+ auto_base = AUTO_BASE_NEVER;
+ *base_commit = NULL;
+ } else if (!strcmp(arg, "auto")) {
+ auto_base = AUTO_BASE_ALWAYS;
+ *base_commit = NULL;
+ } else {
+ auto_base = AUTO_BASE_NEVER;
+ *base_commit = arg;
+ }
+ return 0;
+}
+
struct base_tree_info {
struct object_id base_commit;
int nr_patch_id, alloc_patch_id;
@@ -1436,13 +1467,36 @@ static struct commit *get_base_commit(const char *base_commit,
{
struct commit *base = NULL;
struct commit **rev;
- int i = 0, rev_nr = 0;
+ int i = 0, rev_nr = 0, auto_select, die_on_failure;
- if (base_commit && strcmp(base_commit, "auto")) {
+ switch (auto_base) {
+ case AUTO_BASE_NEVER:
+ if (base_commit) {
+ auto_select = 0;
+ die_on_failure = 1;
+ } else {
+ /* no base information is requested */
+ return NULL;
+ }
+ break;
+ case AUTO_BASE_ALWAYS:
+ case AUTO_BASE_WHEN_ABLE:
+ if (base_commit) {
+ BUG("requested automatic base selection but a commit was provided");
+ } else {
+ auto_select = 1;
+ die_on_failure = auto_base == AUTO_BASE_ALWAYS;
+ }
+ break;
+ default:
+ BUG("unexpected automatic base selection method");
+ }
+
+ if (!auto_select) {
base = lookup_commit_reference_by_name(base_commit);
if (!base)
die(_("unknown commit %s"), base_commit);
- } else if ((base_commit && !strcmp(base_commit, "auto"))) {
+ } else {
struct branch *curr_branch = branch_get(NULL);
const char *upstream = branch_get_upstream(curr_branch, NULL);
if (upstream) {
@@ -1450,19 +1504,32 @@ static struct commit *get_base_commit(const char *base_commit,
struct commit *commit;
struct object_id oid;
- if (get_oid(upstream, &oid))
- die(_("failed to resolve '%s' as a valid ref"), upstream);
+ if (get_oid(upstream, &oid)) {
+ if (die_on_failure)
+ die(_("failed to resolve '%s' as a valid ref"), upstream);
+ else
+ return NULL;
+ }
commit = lookup_commit_or_die(&oid, "upstream base");
base_list = get_merge_bases_many(commit, total, list);
/* There should be one and only one merge base. */
- if (!base_list || base_list->next)
- die(_("could not find exact merge base"));
+ if (!base_list || base_list->next) {
+ if (die_on_failure) {
+ die(_("could not find exact merge base"));
+ } else {
+ free_commit_list(base_list);
+ return NULL;
+ }
+ }
base = base_list->item;
free_commit_list(base_list);
} else {
- die(_("failed to get upstream, if you want to record base commit automatically,\n"
- "please use git branch --set-upstream-to to track a remote branch.\n"
- "Or you could specify base commit by --base=<base-commit-id> manually"));
+ if (die_on_failure)
+ die(_("failed to get upstream, if you want to record base commit automatically,\n"
+ "please use git branch --set-upstream-to to track a remote branch.\n"
+ "Or you could specify base commit by --base=<base-commit-id> manually"));
+ else
+ return NULL;
}
}
@@ -1479,8 +1546,14 @@ static struct commit *get_base_commit(const char *base_commit,
for (i = 0; i < rev_nr / 2; i++) {
struct commit_list *merge_base;
merge_base = get_merge_bases(rev[2 * i], rev[2 * i + 1]);
- if (!merge_base || merge_base->next)
- die(_("failed to find exact merge base"));
+ if (!merge_base || merge_base->next) {
+ if (die_on_failure) {
+ die(_("failed to find exact merge base"));
+ } else {
+ free(rev);
+ return NULL;
+ }
+ }
rev[i] = merge_base->item;
}
@@ -1490,12 +1563,24 @@ static struct commit *get_base_commit(const char *base_commit,
rev_nr = DIV_ROUND_UP(rev_nr, 2);
}
- if (!in_merge_bases(base, rev[0]))
- die(_("base commit should be the ancestor of revision list"));
+ if (!in_merge_bases(base, rev[0])) {
+ if (die_on_failure) {
+ die(_("base commit should be the ancestor of revision list"));
+ } else {
+ free(rev);
+ return NULL;
+ }
+ }
for (i = 0; i < total; i++) {
- if (base == list[i])
- die(_("base commit shouldn't be in revision list"));
+ if (base == list[i]) {
+ if (die_on_failure) {
+ die(_("base commit shouldn't be in revision list"));
+ } else {
+ free(rev);
+ return NULL;
+ }
+ }
}
free(rev);
@@ -1595,16 +1680,20 @@ static void infer_range_diff_ranges(struct strbuf *r1,
struct commit *head)
{
const char *head_oid = oid_to_hex(&head->object.oid);
+ int prev_is_range = !!strstr(prev, "..");
- if (!strstr(prev, "..")) {
+ if (prev_is_range)
+ strbuf_addstr(r1, prev);
+ else
strbuf_addf(r1, "%s..%s", head_oid, prev);
+
+ if (origin)
+ strbuf_addf(r2, "%s..%s", oid_to_hex(&origin->object.oid), head_oid);
+ else if (prev_is_range)
+ die(_("failed to infer range-diff origin of current series"));
+ else {
+ warning(_("using '%s' as range-diff origin of current series"), prev);
strbuf_addf(r2, "%s..%s", prev, head_oid);
- } else if (!origin) {
- die(_("failed to infer range-diff ranges"));
- } else {
- strbuf_addstr(r1, prev);
- strbuf_addf(r2, "%s..%s",
- oid_to_hex(&origin->object.oid), head_oid);
}
}
@@ -1634,6 +1723,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
char *branch_name = NULL;
char *base_commit = NULL;
struct base_tree_info bases;
+ struct commit *base;
int show_progress = 0;
struct progress *progress = NULL;
struct oid_array idiff_prev = OID_ARRAY_INIT;
@@ -1651,7 +1741,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F('N', "no-numbered", &numbered, NULL,
N_("use [PATCH] even with multiple patches"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback),
- OPT_BOOL('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
+ OPT_BOOL('s', "signoff", &do_signoff, N_("add a Signed-off-by trailer")),
OPT_BOOL(0, "stdout", &use_stdout,
N_("print patches to standard out")),
OPT_BOOL(0, "cover-letter", &cover_letter,
@@ -1710,8 +1800,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
PARSE_OPT_OPTARG, thread_callback),
OPT_STRING(0, "signature", &signature, N_("signature"),
N_("add a signature")),
- OPT_STRING(0, "base", &base_commit, N_("base-commit"),
- N_("add prerequisite tree info to the patch series")),
+ OPT_CALLBACK_F(0, "base", &base_commit, N_("base-commit"),
+ N_("add prerequisite tree info to the patch series"),
+ 0, base_callback),
OPT_FILENAME(0, "signature-file", &signature_file,
N_("add a signature from a file")),
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
@@ -1748,9 +1839,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
- if (base_auto)
- base_commit = "auto";
-
if (default_attach) {
rev.mime_boundary = default_attach;
rev.no_inline = 1;
@@ -1857,20 +1945,27 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (rev.show_notes)
load_display_notes(&rev.notes_opt);
- if (!output_directory && !use_stdout)
- output_directory = config_output_directory;
+ if (use_stdout + rev.diffopt.close_file + !!output_directory > 1)
+ die(_("--stdout, --output, and --output-directory are mutually exclusive"));
- if (!use_stdout)
- output_directory = set_outdir(prefix, output_directory);
- else
+ if (use_stdout) {
setup_pager();
-
- if (output_directory) {
+ } else if (rev.diffopt.close_file) {
+ /*
+ * The diff code parsed --output; it has already opened the
+ * file, but but we must instruct it not to close after each
+ * diff.
+ */
+ rev.diffopt.close_file = 0;
+ } else {
int saved;
+
+ if (!output_directory)
+ output_directory = config_output_directory;
+ output_directory = set_outdir(prefix, output_directory);
+
if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
rev.diffopt.use_color = GIT_COLOR_NEVER;
- if (use_stdout)
- die(_("standard output, or directory, which one?"));
/*
* We consider <outdir> as 'outside of gitdir', therefore avoid
* applying adjust_shared_perm in s-c-l-d.
@@ -2014,8 +2109,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
memset(&bases, 0, sizeof(bases));
- if (base_commit) {
- struct commit *base = get_base_commit(base_commit, list, nr);
+ base = get_base_commit(base_commit, list, nr);
+ if (base) {
reset_revision_walk();
clear_object_flags(UNINTERESTING);
prepare_bases(&bases, base, list, nr);
@@ -2032,7 +2127,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (cover_letter) {
if (thread)
gen_message_id(&rev, "cover");
- make_cover_letter(&rev, use_stdout,
+ make_cover_letter(&rev, !!output_directory,
origin, nr, list, branch_name, quiet);
print_bases(&bases, rev.diffopt.file);
print_signature(rev.diffopt.file);
@@ -2087,7 +2182,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
gen_message_id(&rev, oid_to_hex(&commit->object.oid));
}
- if (!use_stdout &&
+ if (output_directory &&
open_next_file(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
die(_("failed to create output files"));
shown = log_tree_commit(&rev, commit);
@@ -2100,7 +2195,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
* the log; when using one file per patch, we do
* not want the extra blank line.
*/
- if (!use_stdout)
+ if (output_directory)
rev.shown_one = 0;
if (shown) {
print_bases(&bases, rev.diffopt.file);
@@ -2111,7 +2206,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
else
print_signature(rev.diffopt.file);
}
- if (!use_stdout)
+ if (output_directory)
fclose(rev.diffopt.file);
}
stop_progress(&progress);
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 30a4c10..c8eae89 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -584,7 +584,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(ls_files_usage, builtin_ls_files_options);
- memset(&dir, 0, sizeof(dir));
+ dir_init(&dir);
prefix = cmd_prefix;
if (prefix)
prefix_len = strlen(prefix);
@@ -688,6 +688,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
return bad ? 1 : 0;
}
- UNLEAK(dir);
+ dir_clear(&dir);
return 0;
}
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index ea91679..092917e 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -83,6 +83,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
PARSE_OPT_STOP_AT_NON_OPTION);
dest = argv[0];
+ UNLEAK(sorting);
+
if (argc > 1) {
int i;
pattern = xcalloc(argc, sizeof(const char *));
@@ -107,7 +109,6 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
if (get_url) {
printf("%s\n", *remote->url);
- UNLEAK(sorting);
return 0;
}
@@ -122,10 +123,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
repo_set_hash_algo(the_repository, hash_algo);
}
- if (transport_disconnect(transport)) {
- UNLEAK(sorting);
+ if (transport_disconnect(transport))
return 1;
- }
if (!dest && !quiet)
fprintf(stderr, "From %s\n", *remote->url);
@@ -150,7 +149,6 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
status = 0; /* we found something */
}
- UNLEAK(sorting);
ref_array_clear(&ref_array);
return status;
}
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index e72714a..de85207 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -109,6 +109,7 @@ static void show_diff(struct merge_list *entry)
xdemitconf_t xecfg;
xdemitcb_t ecb;
+ memset(&xpp, 0, sizeof(xpp));
xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
diff --git a/builtin/merge.c b/builtin/merge.c
index 8f31bfa..4c13340 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -289,7 +289,7 @@ static struct option builtin_merge_options[] = {
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_AUTOSTASH(&autostash),
OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
- OPT_BOOL(0, "signoff", &signoff, N_("add Signed-off-by:")),
+ OPT_BOOL(0, "signoff", &signoff, N_("add a Signed-off-by trailer")),
OPT_BOOL(0, "no-verify", &no_verify, N_("bypass pre-merge-commit and commit-msg hooks")),
OPT_END()
};
@@ -500,7 +500,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!remote_head)
die(_("'%s' does not point to a commit"), remote);
- if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref) > 0) {
+ if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref, 0) > 0) {
if (starts_with(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
oid_to_hex(&branch_head), remote);
@@ -1348,7 +1348,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
die(_("You have not concluded your merge (MERGE_HEAD exists)."));
}
- if (file_exists(git_path_cherry_pick_head(the_repository))) {
+ if (ref_exists("CHERRY_PICK_HEAD")) {
if (advice_resolve_conflict)
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge."));
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index a9dcd25..725dd04 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -521,7 +521,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
struct option opts[] = {
- OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
+ OPT_BOOL(0, "name-only", &data.name_only, N_("print only ref-based names (no object names)")),
OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
N_("only use refs matching <pattern>")),
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index a8692d2..5617c01 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -3357,7 +3357,7 @@ static void get_object_list(int ac, const char **av)
if (starts_with(line, "--shallow ")) {
struct object_id oid;
if (get_oid_hex(line + 10, &oid))
- die("not an SHA-1 '%s'", line + 10);
+ die("not an object name '%s'", line + 10);
register_shallow(the_repository, &oid);
use_bitmap_index = 0;
continue;
diff --git a/builtin/pull.c b/builtin/pull.c
index 015f6de..17aa63c 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -142,7 +142,7 @@ static struct option pull_options[] = {
N_("add (at most <n>) entries from shortlog to merge commit message"),
PARSE_OPT_OPTARG),
OPT_PASSTHRU(0, "signoff", &opt_signoff, NULL,
- N_("add Signed-off-by:"),
+ N_("add a Signed-off-by trailer"),
PARSE_OPT_OPTARG),
OPT_PASSTHRU(0, "squash", &opt_squash, NULL,
N_("create a single commit instead of doing a merge"),
@@ -344,8 +344,7 @@ static enum rebase_type config_get_rebase(void)
if (!git_config_get_value("pull.rebase", &value))
return parse_config_rebase("pull.rebase", value, 1);
- if (opt_verbosity >= 0 &&
- (!opt_ff || strcmp(opt_ff, "--ff-only"))) {
+ if (opt_verbosity >= 0 && !opt_ff) {
warning(_("Pulling without specifying how to reconcile divergent branches is\n"
"discouraged. You can squelch this message by running one of the following\n"
"commands sometime before your next pull:\n"
diff --git a/builtin/push.c b/builtin/push.c
index bc94078..03adb58 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -61,26 +61,27 @@ static struct refspec rs = REFSPEC_INIT_PUSH;
static struct string_list push_options_config = STRING_LIST_INIT_DUP;
-static const char *map_refspec(const char *ref,
- struct remote *remote, struct ref *local_refs)
+static void refspec_append_mapped(struct refspec *refspec, const char *ref,
+ struct remote *remote, struct ref *local_refs)
{
const char *branch_name;
struct ref *matched = NULL;
/* Does "ref" uniquely name our ref? */
- if (count_refspec_match(ref, local_refs, &matched) != 1)
- return ref;
+ if (count_refspec_match(ref, local_refs, &matched) != 1) {
+ refspec_append(refspec, ref);
+ return;
+ }
if (remote->push.nr) {
struct refspec_item query;
memset(&query, 0, sizeof(struct refspec_item));
query.src = matched->name;
if (!query_refspecs(&remote->push, &query) && query.dst) {
- struct strbuf buf = STRBUF_INIT;
- strbuf_addf(&buf, "%s%s:%s",
- query.force ? "+" : "",
- query.src, query.dst);
- return strbuf_detach(&buf, NULL);
+ refspec_appendf(refspec, "%s%s:%s",
+ query.force ? "+" : "",
+ query.src, query.dst);
+ return;
}
}
@@ -88,14 +89,13 @@ static const char *map_refspec(const char *ref,
skip_prefix(matched->name, "refs/heads/", &branch_name)) {
struct branch *branch = branch_get(branch_name);
if (branch->merge_nr == 1 && branch->merge[0]->src) {
- struct strbuf buf = STRBUF_INIT;
- strbuf_addf(&buf, "%s:%s",
- ref, branch->merge[0]->src);
- return strbuf_detach(&buf, NULL);
+ refspec_appendf(refspec, "%s:%s",
+ ref, branch->merge[0]->src);
+ return;
}
}
- return ref;
+ refspec_append(refspec, ref);
}
static void set_refspecs(const char **refs, int nr, const char *repo)
@@ -107,30 +107,26 @@ static void set_refspecs(const char **refs, int nr, const char *repo)
for (i = 0; i < nr; i++) {
const char *ref = refs[i];
if (!strcmp("tag", ref)) {
- struct strbuf tagref = STRBUF_INIT;
if (nr <= ++i)
die(_("tag shorthand without <tag>"));
ref = refs[i];
if (deleterefs)
- strbuf_addf(&tagref, ":refs/tags/%s", ref);
+ refspec_appendf(&rs, ":refs/tags/%s", ref);
else
- strbuf_addf(&tagref, "refs/tags/%s", ref);
- ref = strbuf_detach(&tagref, NULL);
+ refspec_appendf(&rs, "refs/tags/%s", ref);
} else if (deleterefs) {
- struct strbuf delref = STRBUF_INIT;
if (strchr(ref, ':'))
die(_("--delete only accepts plain target ref names"));
- strbuf_addf(&delref, ":%s", ref);
- ref = strbuf_detach(&delref, NULL);
+ refspec_appendf(&rs, ":%s", ref);
} else if (!strchr(ref, ':')) {
if (!remote) {
/* lazily grab remote and local_refs */
remote = remote_get(repo);
local_refs = get_local_heads();
}
- ref = map_refspec(ref, remote, local_refs);
- }
- refspec_append(&rs, ref);
+ refspec_append_mapped(&rs, ref, remote, local_refs);
+ } else
+ refspec_append(&rs, ref);
}
}
@@ -192,8 +188,6 @@ static const char message_detached_head_die[] =
static void setup_push_upstream(struct remote *remote, struct branch *branch,
int triangular, int simple)
{
- struct strbuf refspec = STRBUF_INIT;
-
if (!branch)
die(_(message_detached_head_die), remote->name);
if (!branch->merge_nr || !branch->merge || !branch->remote_name)
@@ -219,18 +213,14 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch,
die_push_simple(branch, remote);
}
- strbuf_addf(&refspec, "%s:%s", branch->refname, branch->merge[0]->src);
- refspec_append(&rs, refspec.buf);
+ refspec_appendf(&rs, "%s:%s", branch->refname, branch->merge[0]->src);
}
static void setup_push_current(struct remote *remote, struct branch *branch)
{
- struct strbuf refspec = STRBUF_INIT;
-
if (!branch)
die(_(message_detached_head_die), remote->name);
- strbuf_addf(&refspec, "%s:%s", branch->refname, branch->refname);
- refspec_append(&rs, refspec.buf);
+ refspec_appendf(&rs, "%s:%s", branch->refname, branch->refname);
}
static int is_workflow_triangular(struct remote *remote)
@@ -300,6 +290,12 @@ static const char message_advice_ref_needs_force[] =
"or update a remote ref to make it point at a non-commit object,\n"
"without using the '--force' option.\n");
+static const char message_advice_ref_needs_update[] =
+ N_("Updates were rejected because the tip of the remote-tracking\n"
+ "branch has been updated since the last checkout. You may want\n"
+ "to integrate those changes locally (e.g., 'git pull ...')\n"
+ "before forcing an update.\n");
+
static void advise_pull_before_push(void)
{
if (!advice_push_non_ff_current || !advice_push_update_rejected)
@@ -335,6 +331,13 @@ static void advise_ref_needs_force(void)
advise(_(message_advice_ref_needs_force));
}
+static void advise_ref_needs_update(void)
+{
+ if (!advice_push_ref_needs_update || !advice_push_update_rejected)
+ return;
+ advise(_(message_advice_ref_needs_update));
+}
+
static int push_with_options(struct transport *transport, struct refspec *rs,
int flags)
{
@@ -384,12 +387,14 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
advise_ref_fetch_first();
} else if (reject_reasons & REJECT_NEEDS_FORCE) {
advise_ref_needs_force();
+ } else if (reject_reasons & REJECT_REF_NEEDS_UPDATE) {
+ advise_ref_needs_update();
}
return 1;
}
-static int do_push(const char *repo, int flags,
+static int do_push(int flags,
const struct string_list *push_options,
struct remote *remote)
{
@@ -520,6 +525,12 @@ static int git_push_config(const char *k, const char *v, void *cb)
if (!v)
return config_error_nonbool(k);
return color_parse(v, push_colors[slot]);
+ } else if (!strcmp(k, "push.useforceifincludes")) {
+ if (git_config_bool(k, v))
+ *flags |= TRANSPORT_PUSH_FORCE_IF_INCLUDES;
+ else
+ *flags &= ~TRANSPORT_PUSH_FORCE_IF_INCLUDES;
+ return 0;
}
return git_default_config(k, v, NULL);
@@ -551,6 +562,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option),
+ OPT_BIT(0, TRANS_OPT_FORCE_IF_INCLUDES, &flags,
+ N_("require remote updates to be integrated locally"),
+ TRANSPORT_PUSH_FORCE_IF_INCLUDES),
OPT_CALLBACK(0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)",
N_("control recursive pushing of submodules"), option_parse_recurse_submodules),
OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE),
@@ -635,11 +649,14 @@ int cmd_push(int argc, const char **argv, const char *prefix)
if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
die(_("--all and --mirror are incompatible"));
+ if (!is_empty_cas(&cas) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES))
+ cas.use_force_if_includes = 1;
+
for_each_string_list_item(item, push_options)
if (strchr(item->string, '\n'))
die(_("push options must not have new line characters"));
- rc = do_push(repo, flags, push_options, remote);
+ rc = do_push(flags, push_options, remote);
string_list_clear(&push_options_cmdline, 0);
string_list_clear(&push_options_config, 0);
if (rc == -1)
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 9ffba90..4bd9f25 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -92,6 +92,8 @@ struct rebase_options {
int autosquash;
char *gpg_sign_opt;
int autostash;
+ int committer_date_is_author_date;
+ int ignore_date;
char *cmd;
int allow_empty_message;
int rebase_merges, rebase_cousins;
@@ -130,8 +132,12 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.quiet = !(opts->flags & REBASE_NO_QUIET);
replay.verbose = opts->flags & REBASE_VERBOSE;
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
+ replay.committer_date_is_author_date =
+ opts->committer_date_is_author_date;
+ replay.ignore_date = opts->ignore_date;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.strategy = opts->strategy;
+
if (opts->strategy_opts)
parse_strategy_opts(&replay, opts->strategy_opts);
@@ -264,15 +270,14 @@ static int edit_todo_file(unsigned flags)
}
static int get_revision_ranges(struct commit *upstream, struct commit *onto,
- struct object_id *orig_head, const char **head_hash,
- char **revisions, char **shortrevisions)
+ struct object_id *orig_head, char **revisions,
+ char **shortrevisions)
{
struct commit *base_rev = upstream ? upstream : onto;
const char *shorthead;
- *head_hash = find_unique_abbrev(orig_head, GIT_MAX_HEXSZ);
*revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid),
- *head_hash);
+ oid_to_hex(orig_head));
shorthead = find_unique_abbrev(orig_head, DEFAULT_ABBREV);
@@ -290,7 +295,8 @@ static int get_revision_ranges(struct commit *upstream, struct commit *onto,
}
static int init_basic_state(struct replay_opts *opts, const char *head_name,
- struct commit *onto, const char *orig_head)
+ struct commit *onto,
+ const struct object_id *orig_head)
{
FILE *interactive;
@@ -321,7 +327,6 @@ static void split_exec_commands(const char *cmd, struct string_list *commands)
static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
{
int ret;
- const char *head_hash = NULL;
char *revisions = NULL, *shortrevisions = NULL;
struct strvec make_script_args = STRVEC_INIT;
struct todo_list todo_list = TODO_LIST_INIT;
@@ -329,12 +334,12 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
struct string_list commands = STRING_LIST_INIT_DUP;
if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head,
- &head_hash, &revisions, &shortrevisions))
+ &revisions, &shortrevisions))
return -1;
if (init_basic_state(&replay,
opts->head_name ? opts->head_name : "detached HEAD",
- opts->onto, head_hash)) {
+ opts->onto, &opts->orig_head)) {
free(revisions);
free(shortrevisions);
@@ -364,8 +369,9 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
split_exec_commands(opts->cmd, &commands);
ret = complete_action(the_repository, &replay, flags,
- shortrevisions, opts->onto_name, opts->onto, head_hash,
- &commands, opts->autosquash, &todo_list);
+ shortrevisions, opts->onto_name, opts->onto,
+ &opts->orig_head, &commands, opts->autosquash,
+ &todo_list);
}
string_list_clear(&commands, 0);
@@ -1289,6 +1295,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct strbuf revisions = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
struct object_id merge_base;
+ int ignore_whitespace = 0;
enum action action = ACTION_NONE;
const char *gpg_sign = NULL;
struct string_list exec = STRING_LIST_INIT_NODUP;
@@ -1317,17 +1324,18 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
N_("do not show diffstat of what changed upstream"),
PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
OPT_BOOL(0, "signoff", &options.signoff,
- N_("add a Signed-off-by: line to each commit")),
- OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
- NULL, N_("passed to 'git am'"),
- PARSE_OPT_NOARG),
- OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
- &options.git_am_opts, NULL,
- N_("passed to 'git am'"), PARSE_OPT_NOARG),
- OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
- N_("passed to 'git am'"), PARSE_OPT_NOARG),
+ N_("add a Signed-off-by trailer to each commit")),
+ OPT_BOOL(0, "committer-date-is-author-date",
+ &options.committer_date_is_author_date,
+ N_("make committer date match author date")),
+ OPT_BOOL(0, "reset-author-date", &options.ignore_date,
+ N_("ignore author date and use current date")),
+ OPT_HIDDEN_BOOL(0, "ignore-date", &options.ignore_date,
+ N_("synonym of --reset-author-date")),
OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
N_("passed to 'git apply'"), 0),
+ OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
+ N_("ignore changes in whitespace")),
OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
N_("action"), N_("passed to 'git apply'"), 0),
OPT_BIT('f', "force-rebase", &options.flags,
@@ -1624,12 +1632,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.autosquash) {
allow_preemptive_ff = 0;
}
+ if (options.committer_date_is_author_date || options.ignore_date)
+ options.flags |= REBASE_FORCE;
for (i = 0; i < options.git_am_opts.nr; i++) {
const char *option = options.git_am_opts.v[i], *p;
- if (!strcmp(option, "--committer-date-is-author-date") ||
- !strcmp(option, "--ignore-date") ||
- !strcmp(option, "--whitespace=fix") ||
+ if (!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
allow_preemptive_ff = 0;
else if (skip_prefix(option, "-C", &p)) {
@@ -1682,6 +1690,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
imply_merge(&options, "--rebase-merges");
}
+ if (options.type == REBASE_APPLY) {
+ if (ignore_whitespace)
+ strvec_push(&options.git_am_opts,
+ "--ignore-whitespace");
+ if (options.committer_date_is_author_date)
+ strvec_push(&options.git_am_opts,
+ "--committer-date-is-author-date");
+ if (options.ignore_date)
+ strvec_push(&options.git_am_opts, "--ignore-date");
+ } else {
+ /* REBASE_MERGE and PRESERVE_MERGES */
+ if (ignore_whitespace) {
+ string_list_append(&strategy_options,
+ "ignore-space-change");
+ }
+ }
+
if (strategy_options.nr) {
int i;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 439f29d..bb9909c 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -57,6 +57,7 @@ static int advertise_push_options;
static int unpack_limit = 100;
static off_t max_input_size;
static int report_status;
+static int report_status_v2;
static int use_sideband;
static int use_atomic;
static int use_push_options;
@@ -97,6 +98,17 @@ static int keepalive_in_sec = 5;
static struct tmp_objdir *tmp_objdir;
+static struct proc_receive_ref {
+ unsigned int want_add:1,
+ want_delete:1,
+ want_modify:1,
+ negative_ref:1;
+ char *ref_prefix;
+ struct proc_receive_ref *next;
+} *proc_receive_ref;
+
+static void proc_receive_ref_append(const char *prefix);
+
static enum deny_action parse_deny_action(const char *var, const char *value)
{
if (value) {
@@ -229,6 +241,13 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
+ if (strcmp(var, "receive.procreceiverefs") == 0) {
+ if (!value)
+ return config_error_nonbool(var);
+ proc_receive_ref_append(value);
+ return 0;
+ }
+
return git_default_config(var, value, cb);
}
@@ -240,7 +259,7 @@ static void show_ref(const char *path, const struct object_id *oid)
struct strbuf cap = STRBUF_INIT;
strbuf_addstr(&cap,
- "report-status delete-refs side-band-64k quiet");
+ "report-status report-status-v2 delete-refs side-band-64k quiet");
if (advertise_atomic_push)
strbuf_addstr(&cap, " atomic");
if (prefer_ofs_delta)
@@ -310,17 +329,94 @@ static void write_head_info(void)
packet_flush(1);
}
+#define RUN_PROC_RECEIVE_SCHEDULED 1
+#define RUN_PROC_RECEIVE_RETURNED 2
struct command {
struct command *next;
const char *error_string;
+ struct ref_push_report *report;
unsigned int skip_update:1,
- did_not_exist:1;
+ did_not_exist:1,
+ run_proc_receive:2;
int index;
struct object_id old_oid;
struct object_id new_oid;
char ref_name[FLEX_ARRAY]; /* more */
};
+static void proc_receive_ref_append(const char *prefix)
+{
+ struct proc_receive_ref *ref_pattern;
+ char *p;
+ int len;
+
+ ref_pattern = xcalloc(1, sizeof(struct proc_receive_ref));
+ p = strchr(prefix, ':');
+ if (p) {
+ while (prefix < p) {
+ if (*prefix == 'a')
+ ref_pattern->want_add = 1;
+ else if (*prefix == 'd')
+ ref_pattern->want_delete = 1;
+ else if (*prefix == 'm')
+ ref_pattern->want_modify = 1;
+ else if (*prefix == '!')
+ ref_pattern->negative_ref = 1;
+ prefix++;
+ }
+ prefix++;
+ } else {
+ ref_pattern->want_add = 1;
+ ref_pattern->want_delete = 1;
+ ref_pattern->want_modify = 1;
+ }
+ len = strlen(prefix);
+ while (len && prefix[len - 1] == '/')
+ len--;
+ ref_pattern->ref_prefix = xmemdupz(prefix, len);
+ if (!proc_receive_ref) {
+ proc_receive_ref = ref_pattern;
+ } else {
+ struct proc_receive_ref *end;
+
+ end = proc_receive_ref;
+ while (end->next)
+ end = end->next;
+ end->next = ref_pattern;
+ }
+}
+
+static int proc_receive_ref_matches(struct command *cmd)
+{
+ struct proc_receive_ref *p;
+
+ if (!proc_receive_ref)
+ return 0;
+
+ for (p = proc_receive_ref; p; p = p->next) {
+ const char *match = p->ref_prefix;
+ const char *remains;
+
+ if (!p->want_add && is_null_oid(&cmd->old_oid))
+ continue;
+ else if (!p->want_delete && is_null_oid(&cmd->new_oid))
+ continue;
+ else if (!p->want_modify &&
+ !is_null_oid(&cmd->old_oid) &&
+ !is_null_oid(&cmd->new_oid))
+ continue;
+
+ if (skip_prefix(cmd->ref_name, match, &remains) &&
+ (!*remains || *remains == '/')) {
+ if (!p->negative_ref)
+ return 1;
+ } else if (p->negative_ref) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2)));
static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
@@ -692,6 +788,7 @@ static void prepare_push_cert_sha1(struct child_process *proc)
struct receive_hook_feed_state {
struct command *cmd;
+ struct ref_push_report *report;
int skip_broken;
struct strbuf buf;
const struct string_list *push_options;
@@ -779,11 +876,31 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
cmd = cmd->next;
if (!cmd)
return -1; /* EOF */
+ if (!bufp)
+ return 0; /* OK, can feed something. */
strbuf_reset(&state->buf);
- strbuf_addf(&state->buf, "%s %s %s\n",
- oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid),
- cmd->ref_name);
- state->cmd = cmd->next;
+ if (!state->report)
+ state->report = cmd->report;
+ if (state->report) {
+ struct object_id *old_oid;
+ struct object_id *new_oid;
+ const char *ref_name;
+
+ old_oid = state->report->old_oid ? state->report->old_oid : &cmd->old_oid;
+ new_oid = state->report->new_oid ? state->report->new_oid : &cmd->new_oid;
+ ref_name = state->report->ref_name ? state->report->ref_name : cmd->ref_name;
+ strbuf_addf(&state->buf, "%s %s %s\n",
+ oid_to_hex(old_oid), oid_to_hex(new_oid),
+ ref_name);
+ state->report = state->report->next;
+ if (!state->report)
+ state->cmd = cmd->next;
+ } else {
+ strbuf_addf(&state->buf, "%s %s %s\n",
+ oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid),
+ cmd->ref_name);
+ state->cmd = cmd->next;
+ }
if (bufp) {
*bufp = state->buf.buf;
*sizep = state->buf.len;
@@ -802,6 +919,7 @@ static int run_receive_hook(struct command *commands,
strbuf_init(&state.buf, 0);
state.cmd = commands;
state.skip_broken = skip_broken;
+ state.report = NULL;
if (feed_receive_hook(&state, NULL, NULL))
return 0;
state.cmd = commands;
@@ -840,6 +958,268 @@ static int run_update_hook(struct command *cmd)
return finish_command(&proc);
}
+static struct command *find_command_by_refname(struct command *list,
+ const char *refname)
+{
+ for (; list; list = list->next)
+ if (!strcmp(list->ref_name, refname))
+ return list;
+ return NULL;
+}
+
+static int read_proc_receive_report(struct packet_reader *reader,
+ struct command *commands,
+ struct strbuf *errmsg)
+{
+ struct command *cmd;
+ struct command *hint = NULL;
+ struct ref_push_report *report = NULL;
+ int new_report = 0;
+ int code = 0;
+ int once = 0;
+
+ for (;;) {
+ struct object_id old_oid, new_oid;
+ const char *head;
+ const char *refname;
+ char *p;
+
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+ break;
+
+ head = reader->line;
+ p = strchr(head, ' ');
+ if (!p) {
+ strbuf_addf(errmsg, "proc-receive reported incomplete status line: '%s'\n", head);
+ code = -1;
+ continue;
+ }
+ *p++ = '\0';
+ if (!strcmp(head, "option")) {
+ const char *key, *val;
+
+ if (!hint || !(report || new_report)) {
+ if (!once++)
+ strbuf_addstr(errmsg, "proc-receive reported 'option' without a matching 'ok/ng' directive\n");
+ code = -1;
+ continue;
+ }
+ if (new_report) {
+ if (!hint->report) {
+ hint->report = xcalloc(1, sizeof(struct ref_push_report));
+ report = hint->report;
+ } else {
+ report = hint->report;
+ while (report->next)
+ report = report->next;
+ report->next = xcalloc(1, sizeof(struct ref_push_report));
+ report = report->next;
+ }
+ new_report = 0;
+ }
+ key = p;
+ p = strchr(key, ' ');
+ if (p)
+ *p++ = '\0';
+ val = p;
+ if (!strcmp(key, "refname"))
+ report->ref_name = xstrdup_or_null(val);
+ else if (!strcmp(key, "old-oid") && val &&
+ !parse_oid_hex(val, &old_oid, &val))
+ report->old_oid = oiddup(&old_oid);
+ else if (!strcmp(key, "new-oid") && val &&
+ !parse_oid_hex(val, &new_oid, &val))
+ report->new_oid = oiddup(&new_oid);
+ else if (!strcmp(key, "forced-update"))
+ report->forced_update = 1;
+ else if (!strcmp(key, "fall-through"))
+ /* Fall through, let 'receive-pack' to execute it. */
+ hint->run_proc_receive = 0;
+ continue;
+ }
+
+ report = NULL;
+ new_report = 0;
+ refname = p;
+ p = strchr(refname, ' ');
+ if (p)
+ *p++ = '\0';
+ if (strcmp(head, "ok") && strcmp(head, "ng")) {
+ strbuf_addf(errmsg, "proc-receive reported bad status '%s' on ref '%s'\n",
+ head, refname);
+ code = -1;
+ continue;
+ }
+
+ /* first try searching at our hint, falling back to all refs */
+ if (hint)
+ hint = find_command_by_refname(hint, refname);
+ if (!hint)
+ hint = find_command_by_refname(commands, refname);
+ if (!hint) {
+ strbuf_addf(errmsg, "proc-receive reported status on unknown ref: %s\n",
+ refname);
+ code = -1;
+ continue;
+ }
+ if (!hint->run_proc_receive) {
+ strbuf_addf(errmsg, "proc-receive reported status on unexpected ref: %s\n",
+ refname);
+ code = -1;
+ continue;
+ }
+ hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED;
+ if (!strcmp(head, "ng")) {
+ if (p)
+ hint->error_string = xstrdup(p);
+ else
+ hint->error_string = "failed";
+ code = -1;
+ continue;
+ }
+ new_report = 1;
+ }
+
+ for (cmd = commands; cmd; cmd = cmd->next)
+ if (cmd->run_proc_receive && !cmd->error_string &&
+ !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED)) {
+ cmd->error_string = "proc-receive failed to report status";
+ code = -1;
+ }
+ return code;
+}
+
+static int run_proc_receive_hook(struct command *commands,
+ const struct string_list *push_options)
+{
+ struct child_process proc = CHILD_PROCESS_INIT;
+ struct async muxer;
+ struct command *cmd;
+ const char *argv[2];
+ struct packet_reader reader;
+ struct strbuf cap = STRBUF_INIT;
+ struct strbuf errmsg = STRBUF_INIT;
+ int hook_use_push_options = 0;
+ int version = 0;
+ int code;
+
+ argv[0] = find_hook("proc-receive");
+ if (!argv[0]) {
+ rp_error("cannot find hook 'proc-receive'");
+ return -1;
+ }
+ argv[1] = NULL;
+
+ proc.argv = argv;
+ proc.in = -1;
+ proc.out = -1;
+ proc.trace2_hook_name = "proc-receive";
+
+ if (use_sideband) {
+ memset(&muxer, 0, sizeof(muxer));
+ muxer.proc = copy_to_sideband;
+ muxer.in = -1;
+ code = start_async(&muxer);
+ if (code)
+ return code;
+ proc.err = muxer.in;
+ } else {
+ proc.err = 0;
+ }
+
+ code = start_command(&proc);
+ if (code) {
+ if (use_sideband)
+ finish_async(&muxer);
+ return code;
+ }
+
+ sigchain_push(SIGPIPE, SIG_IGN);
+
+ /* Version negotiaton */
+ packet_reader_init(&reader, proc.out, NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_GENTLE_ON_EOF);
+ if (use_atomic)
+ strbuf_addstr(&cap, " atomic");
+ if (use_push_options)
+ strbuf_addstr(&cap, " push-options");
+ if (cap.len) {
+ packet_write_fmt(proc.in, "version=1%c%s\n", '\0', cap.buf + 1);
+ strbuf_release(&cap);
+ } else {
+ packet_write_fmt(proc.in, "version=1\n");
+ }
+ packet_flush(proc.in);
+
+ for (;;) {
+ int linelen;
+
+ if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
+ break;
+
+ if (reader.pktlen > 8 && starts_with(reader.line, "version=")) {
+ version = atoi(reader.line + 8);
+ linelen = strlen(reader.line);
+ if (linelen < reader.pktlen) {
+ const char *feature_list = reader.line + linelen + 1;
+ if (parse_feature_request(feature_list, "push-options"))
+ hook_use_push_options = 1;
+ }
+ }
+ }
+
+ if (version != 1) {
+ strbuf_addf(&errmsg, "proc-receive version '%d' is not supported",
+ version);
+ code = -1;
+ goto cleanup;
+ }
+
+ /* Send commands */
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (!cmd->run_proc_receive || cmd->skip_update || cmd->error_string)
+ continue;
+ packet_write_fmt(proc.in, "%s %s %s",
+ oid_to_hex(&cmd->old_oid),
+ oid_to_hex(&cmd->new_oid),
+ cmd->ref_name);
+ }
+ packet_flush(proc.in);
+
+ /* Send push options */
+ if (hook_use_push_options) {
+ struct string_list_item *item;
+
+ for_each_string_list_item(item, push_options)
+ packet_write_fmt(proc.in, "%s", item->string);
+ packet_flush(proc.in);
+ }
+
+ /* Read result from proc-receive */
+ code = read_proc_receive_report(&reader, commands, &errmsg);
+
+cleanup:
+ close(proc.in);
+ close(proc.out);
+ if (use_sideband)
+ finish_async(&muxer);
+ if (finish_command(&proc))
+ code = -1;
+ if (errmsg.len >0) {
+ char *p = errmsg.buf;
+
+ p += errmsg.len - 1;
+ if (*p == '\n')
+ *p = '\0';
+ rp_error("%s", errmsg.buf);
+ strbuf_release(&errmsg);
+ }
+ sigchain_pop(SIGPIPE);
+
+ return code;
+}
+
static char *refuse_unconfigured_deny_msg =
N_("By default, updating the current branch in a non-bare repository\n"
"is denied, because it will make the index and work tree inconsistent\n"
@@ -1415,7 +1795,7 @@ static void execute_commands_non_atomic(struct command *commands,
struct strbuf err = STRBUF_INIT;
for (cmd = commands; cmd; cmd = cmd->next) {
- if (!should_process_cmd(cmd))
+ if (!should_process_cmd(cmd) || cmd->run_proc_receive)
continue;
transaction = ref_transaction_begin(&err);
@@ -1455,7 +1835,7 @@ static void execute_commands_atomic(struct command *commands,
}
for (cmd = commands; cmd; cmd = cmd->next) {
- if (!should_process_cmd(cmd))
+ if (!should_process_cmd(cmd) || cmd->run_proc_receive)
continue;
cmd->error_string = update(cmd, si);
@@ -1491,6 +1871,7 @@ static void execute_commands(struct command *commands,
struct iterate_data data;
struct async muxer;
int err_fd = 0;
+ int run_proc_receive = 0;
if (unpacker_error) {
for (cmd = commands; cmd; cmd = cmd->next)
@@ -1520,6 +1901,22 @@ static void execute_commands(struct command *commands,
reject_updates_to_hidden(commands);
+ /*
+ * Try to find commands that have special prefix in their reference names,
+ * and mark them to run an external "proc-receive" hook later.
+ */
+ if (proc_receive_ref) {
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (!should_process_cmd(cmd))
+ continue;
+
+ if (proc_receive_ref_matches(cmd)) {
+ cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED;
+ run_proc_receive = 1;
+ }
+ }
+ }
+
if (run_receive_hook(commands, "pre-receive", 0, push_options)) {
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string)
@@ -1546,6 +1943,14 @@ static void execute_commands(struct command *commands,
free(head_name_to_free);
head_name = head_name_to_free = resolve_refdup("HEAD", 0, NULL, NULL);
+ if (run_proc_receive &&
+ run_proc_receive_hook(commands, push_options))
+ for (cmd = commands; cmd; cmd = cmd->next)
+ if (!cmd->error_string &&
+ !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED) &&
+ (cmd->run_proc_receive || use_atomic))
+ cmd->error_string = "fail to run proc-receive hook";
+
if (use_atomic)
execute_commands_atomic(commands, si);
else
@@ -1629,6 +2034,8 @@ static struct command *read_head_info(struct packet_reader *reader,
int len = 0;
if (parse_feature_request(feature_list, "report-status"))
report_status = 1;
+ if (parse_feature_request(feature_list, "report-status-v2"))
+ report_status_v2 = 1;
if (parse_feature_request(feature_list, "side-band-64k"))
use_sideband = LARGE_PACKET_MAX;
if (parse_feature_request(feature_list, "quiet"))
@@ -1947,6 +2354,51 @@ static void report(struct command *commands, const char *unpack_status)
strbuf_release(&buf);
}
+static void report_v2(struct command *commands, const char *unpack_status)
+{
+ struct command *cmd;
+ struct strbuf buf = STRBUF_INIT;
+ struct ref_push_report *report;
+
+ packet_buf_write(&buf, "unpack %s\n",
+ unpack_status ? unpack_status : "ok");
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ int count = 0;
+
+ if (cmd->error_string) {
+ packet_buf_write(&buf, "ng %s %s\n",
+ cmd->ref_name,
+ cmd->error_string);
+ continue;
+ }
+ packet_buf_write(&buf, "ok %s\n",
+ cmd->ref_name);
+ for (report = cmd->report; report; report = report->next) {
+ if (count++ > 0)
+ packet_buf_write(&buf, "ok %s\n",
+ cmd->ref_name);
+ if (report->ref_name)
+ packet_buf_write(&buf, "option refname %s\n",
+ report->ref_name);
+ if (report->old_oid)
+ packet_buf_write(&buf, "option old-oid %s\n",
+ oid_to_hex(report->old_oid));
+ if (report->new_oid)
+ packet_buf_write(&buf, "option new-oid %s\n",
+ oid_to_hex(report->new_oid));
+ if (report->forced_update)
+ packet_buf_write(&buf, "option forced-update\n");
+ }
+ }
+ packet_buf_flush(&buf);
+
+ if (use_sideband)
+ send_sideband(1, 1, buf.buf, buf.len, use_sideband);
+ else
+ write_or_die(1, buf.buf, buf.len);
+ strbuf_release(&buf);
+}
+
static int delete_only(struct command *commands)
{
struct command *cmd;
@@ -2055,7 +2507,9 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
&push_options);
if (pack_lockfile)
unlink_or_warn(pack_lockfile);
- if (report_status)
+ if (report_status_v2)
+ report_v2(commands, unpack_status);
+ else if (report_status)
report(commands, unpack_status);
run_receive_hook(commands, "post-receive", 1,
&push_options);
diff --git a/builtin/remote.c b/builtin/remote.c
index c8240e9..c1b211b 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -191,11 +191,12 @@ static int add(int argc, const char **argv)
url = argv[1];
remote = remote_get(name);
- if (remote_is_configured(remote, 1))
- die(_("remote %s already exists."), name);
+ if (remote_is_configured(remote, 1)) {
+ error(_("remote %s already exists."), name);
+ exit(3);
+ }
- strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name);
- if (!valid_fetch_refspec(buf2.buf))
+ if (!valid_remote_name(name))
die(_("'%s' is not a valid remote name"), name);
strbuf_addf(&buf, "remote.%s.url", name);
@@ -478,6 +479,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
struct refspec_item refspec;
+ memset(&refspec, 0, sizeof(refspec));
refspec.force = 0;
refspec.pattern = 1;
refspec.src = refspec.dst = "refs/heads/*";
@@ -685,21 +687,23 @@ static int mv(int argc, const char **argv)
rename.remote_branches = &remote_branches;
oldremote = remote_get(rename.old_name);
- if (!remote_is_configured(oldremote, 1))
- die(_("No such remote: '%s'"), rename.old_name);
+ if (!remote_is_configured(oldremote, 1)) {
+ error(_("No such remote: '%s'"), rename.old_name);
+ exit(2);
+ }
if (!strcmp(rename.old_name, rename.new_name) && oldremote->origin != REMOTE_CONFIG)
return migrate_file(oldremote);
newremote = remote_get(rename.new_name);
- if (remote_is_configured(newremote, 1))
- die(_("remote %s already exists."), rename.new_name);
+ if (remote_is_configured(newremote, 1)) {
+ error(_("remote %s already exists."), rename.new_name);
+ exit(3);
+ }
- strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new_name);
- if (!valid_fetch_refspec(buf.buf))
+ if (!valid_remote_name(rename.new_name))
die(_("'%s' is not a valid remote name"), rename.new_name);
- strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s", rename.old_name);
strbuf_addf(&buf2, "remote.%s", rename.new_name);
if (git_config_rename_section(buf.buf, buf2.buf) < 1)
@@ -828,8 +832,10 @@ static int rm(int argc, const char **argv)
usage_with_options(builtin_remote_rm_usage, options);
remote = remote_get(argv[1]);
- if (!remote_is_configured(remote, 1))
- die(_("No such remote: '%s'"), argv[1]);
+ if (!remote_is_configured(remote, 1)) {
+ error(_("No such remote: '%s'"), argv[1]);
+ exit(2);
+ }
known_remotes.to_delete = remote;
for_each_remote(add_known_remote, &known_remotes);
@@ -1355,7 +1361,7 @@ static int set_head(int argc, const char **argv)
result |= error(_("Not a valid ref: %s"), buf2.buf);
else if (create_symref(buf.buf, buf2.buf, "remote set-head"))
result |= error(_("Could not setup %s"), buf.buf);
- if (opt_a)
+ else if (opt_a)
printf("%s/HEAD set to %s\n", argv[0], head_name);
free(head_name);
}
@@ -1510,8 +1516,10 @@ static int set_remote_branches(const char *remotename, const char **branches,
strbuf_addf(&key, "remote.%s.fetch", remotename);
remote = remote_get(remotename);
- if (!remote_is_configured(remote, 1))
- die(_("No such remote '%s'"), remotename);
+ if (!remote_is_configured(remote, 1)) {
+ error(_("No such remote '%s'"), remotename);
+ exit(2);
+ }
if (!add_mode && remove_all_fetch_refspecs(key.buf)) {
strbuf_release(&key);
@@ -1564,8 +1572,10 @@ static int get_url(int argc, const char **argv)
remotename = argv[0];
remote = remote_get(remotename);
- if (!remote_is_configured(remote, 1))
- die(_("No such remote '%s'"), remotename);
+ if (!remote_is_configured(remote, 1)) {
+ error(_("No such remote '%s'"), remotename);
+ exit(2);
+ }
url_nr = 0;
if (push_mode) {
@@ -1632,8 +1642,10 @@ static int set_url(int argc, const char **argv)
oldurl = newurl;
remote = remote_get(remotename);
- if (!remote_is_configured(remote, 1))
- die(_("No such remote '%s'"), remotename);
+ if (!remote_is_configured(remote, 1)) {
+ error(_("No such remote '%s'"), remotename);
+ exit(2);
+ }
if (push_mode) {
strbuf_addf(&name_buf, "remote.%s.pushurl", remotename);
diff --git a/builtin/repack.c b/builtin/repack.c
index 04c5cea..01e7767 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -133,7 +133,11 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list,
static void remove_redundant_pack(const char *dir_name, const char *base_name)
{
struct strbuf buf = STRBUF_INIT;
- strbuf_addf(&buf, "%s/%s.pack", dir_name, base_name);
+ struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
+ strbuf_addf(&buf, "%s.pack", base_name);
+ if (m && midx_contains_pack(m, buf.buf))
+ clear_midx_file(the_repository);
+ strbuf_insertf(&buf, 0, "%s/", dir_name);
unlink_pack_path(buf.buf, 1);
strbuf_release(&buf);
}
@@ -286,7 +290,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
int keep_unreachable = 0;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
int no_update_server_info = 0;
- int midx_cleared = 0;
struct pack_objects_args po_args = {NULL};
struct option builtin_repack_options[] = {
@@ -439,11 +442,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname, *fname_old;
- if (!midx_cleared) {
- clear_midx_file(the_repository);
- midx_cleared = 1;
- }
-
fname = mkpathdup("%s/pack-%s%s", packdir,
item->string, exts[ext].name);
if (!file_exists(fname)) {
diff --git a/builtin/reset.c b/builtin/reset.c
index 8ae69d6..c635b06 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -423,7 +423,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
char *ref = NULL;
int err;
- dwim_ref(rev, strlen(rev), &dummy, &ref);
+ dwim_ref(rev, strlen(rev), &dummy, &ref, 0);
if (ref && !starts_with(ref, "refs/"))
ref = NULL;
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 669dd2f..ed200c8 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -136,7 +136,7 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
struct object_id discard;
char *full;
- switch (dwim_ref(name, strlen(name), &discard, &full)) {
+ switch (dwim_ref(name, strlen(name), &discard, &full, 0)) {
case 0:
/*
* Not found -- not a ref. We could
diff --git a/builtin/revert.c b/builtin/revert.c
index f61cc5d..da8997d 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -107,7 +107,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
OPT_NOOP_NOARG('r', NULL),
- OPT_BOOL('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
+ OPT_BOOL('s', "signoff", &opts->signoff, N_("add a Signed-off-by trailer")),
OPT_CALLBACK('m', "mainline", opts, N_("parent-number"),
N_("select mainline parent"), option_parse_m),
OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 2b9610f..a7e0166 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -29,10 +29,12 @@ static struct send_pack_args args;
static void print_helper_status(struct ref *ref)
{
struct strbuf buf = STRBUF_INIT;
+ struct ref_push_report *report;
for (; ref; ref = ref->next) {
const char *msg = NULL;
const char *res;
+ int count = 0;
switch(ref->status) {
case REF_STATUS_NONE:
@@ -69,6 +71,11 @@ static void print_helper_status(struct ref *ref)
msg = "stale info";
break;
+ case REF_STATUS_REJECT_REMOTE_UPDATED:
+ res = "error";
+ msg = "remote ref updated since checkout";
+ break;
+
case REF_STATUS_REJECT_ALREADY_EXISTS:
res = "error";
msg = "already exists";
@@ -94,6 +101,23 @@ static void print_helper_status(struct ref *ref)
}
strbuf_addch(&buf, '\n');
+ if (ref->status == REF_STATUS_OK) {
+ for (report = ref->report; report; report = report->next) {
+ if (count++ > 0)
+ strbuf_addf(&buf, "ok %s\n", ref->name);
+ if (report->ref_name)
+ strbuf_addf(&buf, "option refname %s\n",
+ report->ref_name);
+ if (report->old_oid)
+ strbuf_addf(&buf, "option old-oid %s\n",
+ oid_to_hex(report->old_oid));
+ if (report->new_oid)
+ strbuf_addf(&buf, "option new-oid %s\n",
+ oid_to_hex(report->new_oid));
+ if (report->forced_update)
+ strbuf_addstr(&buf, "option forced-update\n");
+ }
+ }
write_or_die(1, buf.buf, buf.len);
}
strbuf_release(&buf);
@@ -154,6 +178,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
int progress = -1;
int from_stdin = 0;
struct push_cas_option cas = {0};
+ int force_if_includes = 0;
struct packet_reader reader;
struct option options[] = {
@@ -179,6 +204,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG, parseopt_push_cas_option),
+ OPT_BOOL(0, TRANS_OPT_FORCE_IF_INCLUDES, &force_if_includes,
+ N_("require remote updates to be integrated locally")),
OPT_END()
};
@@ -280,6 +307,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
if (!is_empty_cas(&cas))
apply_push_cas(&cas, remote, remote_refs);
+ if (!is_empty_cas(&cas) && force_if_includes)
+ cas.use_force_if_includes = 1;
+
set_ref_status_for_push(remote_refs, args.send_mirror,
args.force_update);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index c856c58..0a5c496 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -9,6 +9,7 @@
#include "mailmap.h"
#include "shortlog.h"
#include "parse-options.h"
+#include "trailer.h"
static char const * const shortlog_usage[] = {
N_("git shortlog [<options>] [<revision-range>] [[--] <path>...]"),
@@ -49,12 +50,12 @@ static int compare_by_list(const void *a1, const void *a2)
}
static void insert_one_record(struct shortlog *log,
- const char *author,
+ const char *ident,
const char *oneline)
{
struct string_list_item *item;
- item = string_list_insert(&log->list, author);
+ item = string_list_insert(&log->list, ident);
if (log->summary)
item->util = (void *)(UTIL_TO_INT(item) + 1);
@@ -97,8 +98,8 @@ static void insert_one_record(struct shortlog *log,
}
}
-static int parse_stdin_author(struct shortlog *log,
- struct strbuf *out, const char *in)
+static int parse_ident(struct shortlog *log,
+ struct strbuf *out, const char *in)
{
const char *mailbuf, *namebuf;
size_t namelen, maillen;
@@ -122,18 +123,33 @@ static int parse_stdin_author(struct shortlog *log,
static void read_from_stdin(struct shortlog *log)
{
- struct strbuf author = STRBUF_INIT;
- struct strbuf mapped_author = STRBUF_INIT;
+ struct strbuf ident = STRBUF_INIT;
+ struct strbuf mapped_ident = STRBUF_INIT;
struct strbuf oneline = STRBUF_INIT;
static const char *author_match[2] = { "Author: ", "author " };
static const char *committer_match[2] = { "Commit: ", "committer " };
const char **match;
- match = log->committer ? committer_match : author_match;
- while (strbuf_getline_lf(&author, stdin) != EOF) {
+ if (HAS_MULTI_BITS(log->groups))
+ die(_("using multiple --group options with stdin is not supported"));
+
+ switch (log->groups) {
+ case SHORTLOG_GROUP_AUTHOR:
+ match = author_match;
+ break;
+ case SHORTLOG_GROUP_COMMITTER:
+ match = committer_match;
+ break;
+ case SHORTLOG_GROUP_TRAILER:
+ die(_("using --group=trailer with stdin is not supported"));
+ default:
+ BUG("unhandled shortlog group");
+ }
+
+ while (strbuf_getline_lf(&ident, stdin) != EOF) {
const char *v;
- if (!skip_prefix(author.buf, match[0], &v) &&
- !skip_prefix(author.buf, match[1], &v))
+ if (!skip_prefix(ident.buf, match[0], &v) &&
+ !skip_prefix(ident.buf, match[1], &v))
continue;
while (strbuf_getline_lf(&oneline, stdin) != EOF &&
oneline.len)
@@ -142,23 +158,118 @@ static void read_from_stdin(struct shortlog *log)
!oneline.len)
; /* discard blanks */
- strbuf_reset(&mapped_author);
- if (parse_stdin_author(log, &mapped_author, v) < 0)
+ strbuf_reset(&mapped_ident);
+ if (parse_ident(log, &mapped_ident, v) < 0)
continue;
- insert_one_record(log, mapped_author.buf, oneline.buf);
+ insert_one_record(log, mapped_ident.buf, oneline.buf);
}
- strbuf_release(&author);
- strbuf_release(&mapped_author);
+ strbuf_release(&ident);
+ strbuf_release(&mapped_ident);
strbuf_release(&oneline);
}
+struct strset_item {
+ struct hashmap_entry ent;
+ char value[FLEX_ARRAY];
+};
+
+struct strset {
+ struct hashmap map;
+};
+
+#define STRSET_INIT { { NULL } }
+
+static int strset_item_hashcmp(const void *hash_data,
+ const struct hashmap_entry *entry,
+ const struct hashmap_entry *entry_or_key,
+ const void *keydata)
+{
+ const struct strset_item *a, *b;
+
+ a = container_of(entry, const struct strset_item, ent);
+ if (keydata)
+ return strcmp(a->value, keydata);
+
+ b = container_of(entry_or_key, const struct strset_item, ent);
+ return strcmp(a->value, b->value);
+}
+
+/*
+ * Adds "str" to the set if it was not already present; returns true if it was
+ * already there.
+ */
+static int strset_check_and_add(struct strset *ss, const char *str)
+{
+ unsigned int hash = strhash(str);
+ struct strset_item *item;
+
+ if (!ss->map.table)
+ hashmap_init(&ss->map, strset_item_hashcmp, NULL, 0);
+
+ if (hashmap_get_from_hash(&ss->map, hash, str))
+ return 1;
+
+ FLEX_ALLOC_STR(item, value, str);
+ hashmap_entry_init(&item->ent, hash);
+ hashmap_add(&ss->map, &item->ent);
+ return 0;
+}
+
+static void strset_clear(struct strset *ss)
+{
+ if (!ss->map.table)
+ return;
+ hashmap_free_entries(&ss->map, struct strset_item, ent);
+}
+
+static void insert_records_from_trailers(struct shortlog *log,
+ struct strset *dups,
+ struct commit *commit,
+ struct pretty_print_context *ctx,
+ const char *oneline)
+{
+ struct trailer_iterator iter;
+ const char *commit_buffer, *body;
+ struct strbuf ident = STRBUF_INIT;
+
+ /*
+ * Using format_commit_message("%B") would be simpler here, but
+ * this saves us copying the message.
+ */
+ commit_buffer = logmsg_reencode(commit, NULL, ctx->output_encoding);
+ body = strstr(commit_buffer, "\n\n");
+ if (!body)
+ return;
+
+ trailer_iterator_init(&iter, body);
+ while (trailer_iterator_advance(&iter)) {
+ const char *value = iter.val.buf;
+
+ if (!string_list_has_string(&log->trailers, iter.key.buf))
+ continue;
+
+ strbuf_reset(&ident);
+ if (!parse_ident(log, &ident, value))
+ value = ident.buf;
+
+ if (strset_check_and_add(dups, value))
+ continue;
+ insert_one_record(log, value, oneline);
+ }
+ trailer_iterator_release(&iter);
+
+ strbuf_release(&ident);
+ unuse_commit_buffer(commit, commit_buffer);
+}
+
void shortlog_add_commit(struct shortlog *log, struct commit *commit)
{
- struct strbuf author = STRBUF_INIT;
+ struct strbuf ident = STRBUF_INIT;
struct strbuf oneline = STRBUF_INIT;
+ struct strset dups = STRSET_INIT;
struct pretty_print_context ctx = {0};
- const char *fmt;
+ const char *oneline_str;
ctx.fmt = CMIT_FMT_USERFORMAT;
ctx.abbrev = log->abbrev;
@@ -166,21 +277,38 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.date_mode.type = DATE_NORMAL;
ctx.output_encoding = get_log_output_encoding();
- fmt = log->committer ?
- (log->email ? "%cN <%cE>" : "%cN") :
- (log->email ? "%aN <%aE>" : "%aN");
-
- format_commit_message(commit, fmt, &author, &ctx);
if (!log->summary) {
if (log->user_format)
pretty_print_commit(&ctx, commit, &oneline);
else
format_commit_message(commit, "%s", &oneline, &ctx);
}
+ oneline_str = oneline.len ? oneline.buf : "<none>";
+
+ if (log->groups & SHORTLOG_GROUP_AUTHOR) {
+ strbuf_reset(&ident);
+ format_commit_message(commit,
+ log->email ? "%aN <%aE>" : "%aN",
+ &ident, &ctx);
+ if (!HAS_MULTI_BITS(log->groups) ||
+ !strset_check_and_add(&dups, ident.buf))
+ insert_one_record(log, ident.buf, oneline_str);
+ }
+ if (log->groups & SHORTLOG_GROUP_COMMITTER) {
+ strbuf_reset(&ident);
+ format_commit_message(commit,
+ log->email ? "%cN <%cE>" : "%cN",
+ &ident, &ctx);
+ if (!HAS_MULTI_BITS(log->groups) ||
+ !strset_check_and_add(&dups, ident.buf))
+ insert_one_record(log, ident.buf, oneline_str);
+ }
+ if (log->groups & SHORTLOG_GROUP_TRAILER) {
+ insert_records_from_trailers(log, &dups, commit, &ctx, oneline_str);
+ }
- insert_one_record(log, author.buf, oneline.len ? oneline.buf : "<none>");
-
- strbuf_release(&author);
+ strset_clear(&dups);
+ strbuf_release(&ident);
strbuf_release(&oneline);
}
@@ -241,6 +369,28 @@ static int parse_wrap_args(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int parse_group_option(const struct option *opt, const char *arg, int unset)
+{
+ struct shortlog *log = opt->value;
+ const char *field;
+
+ if (unset) {
+ log->groups = 0;
+ string_list_clear(&log->trailers, 0);
+ } else if (!strcasecmp(arg, "author"))
+ log->groups |= SHORTLOG_GROUP_AUTHOR;
+ else if (!strcasecmp(arg, "committer"))
+ log->groups |= SHORTLOG_GROUP_COMMITTER;
+ else if (skip_prefix(arg, "trailer:", &field)) {
+ log->groups |= SHORTLOG_GROUP_TRAILER;
+ string_list_append(&log->trailers, field);
+ } else
+ return error(_("unknown group type: %s"), arg);
+
+ return 0;
+}
+
+
void shortlog_init(struct shortlog *log)
{
memset(log, 0, sizeof(*log));
@@ -251,6 +401,8 @@ void shortlog_init(struct shortlog *log)
log->wrap = DEFAULT_WRAPLEN;
log->in1 = DEFAULT_INDENT1;
log->in2 = DEFAULT_INDENT2;
+ log->trailers.strdup_strings = 1;
+ log->trailers.cmp = strcasecmp;
}
int cmd_shortlog(int argc, const char **argv, const char *prefix)
@@ -260,8 +412,9 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
int nongit = !startup_info->have_repository;
const struct option options[] = {
- OPT_BOOL('c', "committer", &log.committer,
- N_("Group by committer rather than author")),
+ OPT_BIT('c', "committer", &log.groups,
+ N_("Group by committer rather than author"),
+ SHORTLOG_GROUP_COMMITTER),
OPT_BOOL('n', "numbered", &log.sort_by_number,
N_("sort output according to the number of commits per author")),
OPT_BOOL('s', "summary", &log.summary,
@@ -271,6 +424,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F('w', NULL, &log, N_("<w>[,<i1>[,<i2>]]"),
N_("Linewrap output"), PARSE_OPT_OPTARG,
&parse_wrap_args),
+ OPT_CALLBACK(0, "group", &log, N_("field"),
+ N_("Group by field"), parse_group_option),
OPT_END(),
};
@@ -311,6 +466,10 @@ parse_done:
log.abbrev = rev.abbrev;
log.file = rev.diffopt.file;
+ if (!log.groups)
+ log.groups = SHORTLOG_GROUP_AUTHOR;
+ string_list_sort(&log.trailers);
+
/* assume HEAD if from a tty */
if (!nongit && !rev.pending.nr && isatty(0))
add_head_to_pending(&rev);
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 7eae5f3..d6d2dab 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -741,7 +741,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
die(Q_("only %d entry can be shown at one time.",
"only %d entries can be shown at one time.",
MAX_REVS), MAX_REVS);
- if (!dwim_ref(*av, strlen(*av), &oid, &ref))
+ if (!dwim_ref(*av, strlen(*av), &oid, &ref, 0))
die(_("no such ref %s"), *av);
/* Has the base been specified? */
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 4003f4d..e3140db 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -46,12 +46,24 @@ static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
}
}
+static char const * const builtin_sparse_checkout_list_usage[] = {
+ N_("git sparse-checkout list"),
+ NULL
+};
+
static int sparse_checkout_list(int argc, const char **argv)
{
+ static struct option builtin_sparse_checkout_list_options[] = {
+ OPT_END(),
+ };
struct pattern_list pl;
char *sparse_filename;
int res;
+ argc = parse_options(argc, argv, NULL,
+ builtin_sparse_checkout_list_options,
+ builtin_sparse_checkout_list_usage, 0);
+
memset(&pl, 0, sizeof(pl));
pl.use_cone_patterns = core_sparse_checkout_cone;
@@ -560,17 +572,42 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix,
return modify_pattern_list(argc, argv, m);
}
+static char const * const builtin_sparse_checkout_reapply_usage[] = {
+ N_("git sparse-checkout reapply"),
+ NULL
+};
+
static int sparse_checkout_reapply(int argc, const char **argv)
{
+ static struct option builtin_sparse_checkout_reapply_options[] = {
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, NULL,
+ builtin_sparse_checkout_reapply_options,
+ builtin_sparse_checkout_reapply_usage, 0);
+
repo_read_index(the_repository);
return update_working_directory(NULL);
}
+static char const * const builtin_sparse_checkout_disable_usage[] = {
+ N_("git sparse-checkout disable"),
+ NULL
+};
+
static int sparse_checkout_disable(int argc, const char **argv)
{
+ static struct option builtin_sparse_checkout_disable_options[] = {
+ OPT_END(),
+ };
struct pattern_list pl;
struct strbuf match_all = STRBUF_INIT;
+ argc = parse_options(argc, argv, NULL,
+ builtin_sparse_checkout_disable_options,
+ builtin_sparse_checkout_disable_usage, 0);
+
repo_read_index(the_repository);
memset(&pl, 0, sizeof(pl));
diff --git a/builtin/stash.c b/builtin/stash.c
index 10d8763..24ddb1b 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -185,7 +185,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
end_of_rev = strchrnul(revision, '@');
strbuf_add(&symbolic, revision, end_of_rev - revision);
- ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref);
+ ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref, 0);
strbuf_release(&symbolic);
switch (ret) {
case 0: /* Not found, but valid ref */
@@ -534,11 +534,22 @@ static int apply_stash(int argc, const char **argv, const char *prefix)
return ret;
}
+static int reject_reflog_ent(struct object_id *ooid, struct object_id *noid,
+ const char *email, timestamp_t timestamp, int tz,
+ const char *message, void *cb_data)
+{
+ return 1;
+}
+
+static int reflog_is_empty(const char *refname)
+{
+ return !for_each_reflog_ent(refname, reject_reflog_ent, NULL);
+}
+
static int do_drop_stash(struct stash_info *info, int quiet)
{
int ret;
struct child_process cp_reflog = CHILD_PROCESS_INIT;
- struct child_process cp = CHILD_PROCESS_INIT;
/*
* reflog does not provide a simple function for deleting refs. One will
@@ -559,19 +570,7 @@ static int do_drop_stash(struct stash_info *info, int quiet)
info->revision.buf);
}
- /*
- * This could easily be replaced by get_oid, but currently it will throw
- * a fatal error when a reflog is empty, which we can not recover from.
- */
- cp.git_cmd = 1;
- /* Even though --quiet is specified, rev-parse still outputs the hash */
- cp.no_stdout = 1;
- strvec_pushl(&cp.args, "rev-parse", "--verify", "--quiet", NULL);
- strvec_pushf(&cp.args, "%s@{0}", ref_stash);
- ret = run_command(&cp);
-
- /* do_clear_stash if we just dropped the last stash entry */
- if (ret)
+ if (reflog_is_empty(ref_stash))
do_clear_stash();
return 0;
@@ -864,7 +863,7 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
int found = 0;
struct dir_struct dir;
- memset(&dir, 0, sizeof(dir));
+ dir_init(&dir);
if (include_untracked != INCLUDE_ALL_FILES)
setup_standard_excludes(&dir);
@@ -875,12 +874,9 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
strbuf_addstr(untracked_files, ent->name);
/* NUL-terminate: will be fed to update-index -z */
strbuf_addch(untracked_files, '\0');
- free(ent);
}