summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--.github/workflows/main.yml20
-rw-r--r--.gitignore4
-rw-r--r--Documentation/CodingGuidelines21
-rw-r--r--Documentation/Makefile13
-rw-r--r--Documentation/MyFirstContribution.txt155
-rw-r--r--Documentation/RelNotes/2.30.3.txt24
-rw-r--r--Documentation/RelNotes/2.30.4.txt21
-rw-r--r--Documentation/RelNotes/2.30.5.txt12
-rw-r--r--Documentation/RelNotes/2.31.2.txt6
-rw-r--r--Documentation/RelNotes/2.31.3.txt4
-rw-r--r--Documentation/RelNotes/2.31.4.txt6
-rw-r--r--Documentation/RelNotes/2.32.1.txt6
-rw-r--r--Documentation/RelNotes/2.32.2.txt4
-rw-r--r--Documentation/RelNotes/2.32.3.txt6
-rw-r--r--Documentation/RelNotes/2.33.2.txt15
-rw-r--r--Documentation/RelNotes/2.33.3.txt4
-rw-r--r--Documentation/RelNotes/2.33.4.txt6
-rw-r--r--Documentation/RelNotes/2.34.2.txt6
-rw-r--r--Documentation/RelNotes/2.34.3.txt4
-rw-r--r--Documentation/RelNotes/2.34.4.txt6
-rw-r--r--Documentation/RelNotes/2.35.2.txt7
-rw-r--r--Documentation/RelNotes/2.35.3.txt4
-rw-r--r--Documentation/RelNotes/2.35.4.txt7
-rw-r--r--Documentation/RelNotes/2.36.0.txt70
-rw-r--r--Documentation/RelNotes/2.36.1.txt33
-rw-r--r--Documentation/RelNotes/2.36.2.txt56
-rw-r--r--Documentation/RelNotes/2.37.0.txt337
-rw-r--r--Documentation/RelNotes/2.37.1.txt17
-rw-r--r--Documentation/RelNotes/2.37.2.txt47
-rw-r--r--Documentation/RelNotes/2.38.0.txt191
-rw-r--r--Documentation/SubmittingPatches5
-rw-r--r--Documentation/ToolsForGit.txt51
-rw-r--r--Documentation/config.txt6
-rw-r--r--Documentation/config/add.txt6
-rw-r--r--Documentation/config/advice.txt12
-rw-r--r--Documentation/config/branch.txt9
-rw-r--r--Documentation/config/core.txt107
-rw-r--r--Documentation/config/gc.txt21
-rw-r--r--Documentation/config/gpg.txt9
-rw-r--r--Documentation/config/http.txt18
-rw-r--r--Documentation/config/includeif.txt6
-rw-r--r--Documentation/config/mergetool.txt9
-rw-r--r--Documentation/config/push.txt16
-rw-r--r--Documentation/config/rebase.txt3
-rw-r--r--Documentation/config/remote.txt6
-rw-r--r--Documentation/config/repack.txt9
-rw-r--r--Documentation/config/reset.txt2
-rw-r--r--Documentation/config/revert.txt3
-rw-r--r--Documentation/config/safe.txt61
-rw-r--r--Documentation/config/transfer.txt38
-rw-r--r--Documentation/config/uploadpack.txt6
-rw-r--r--Documentation/diff-format.txt6
-rw-r--r--Documentation/fetch-options.txt10
-rw-r--r--Documentation/git-archive.txt52
-rw-r--r--Documentation/git-branch.txt18
-rw-r--r--Documentation/git-bundle.txt10
-rw-r--r--Documentation/git-cat-file.txt2
-rw-r--r--Documentation/git-config.txt97
-rw-r--r--Documentation/git-credential-cache--daemon.txt6
-rw-r--r--Documentation/git-cvsserver.txt19
-rw-r--r--Documentation/git-daemon.txt21
-rw-r--r--Documentation/git-diff-index.txt6
-rw-r--r--Documentation/git-fetch-pack.txt4
-rw-r--r--Documentation/git-fsmonitor--daemon.txt75
-rw-r--r--Documentation/git-gc.txt4
-rw-r--r--Documentation/git-grep.txt9
-rw-r--r--Documentation/git-ls-tree.txt68
-rw-r--r--Documentation/git-merge-tree.txt235
-rw-r--r--Documentation/git-mergetool.txt8
-rw-r--r--Documentation/git-p4.txt37
-rw-r--r--Documentation/git-pack-objects.txt30
-rw-r--r--Documentation/git-read-tree.txt11
-rw-r--r--Documentation/git-rebase.txt253
-rw-r--r--Documentation/git-remote.txt2
-rw-r--r--Documentation/git-repack.txt11
-rw-r--r--Documentation/git-reset.txt9
-rw-r--r--Documentation/git-revert.txt9
-rw-r--r--Documentation/git-sparse-checkout.txt317
-rw-r--r--Documentation/git-update-index.txt8
-rw-r--r--Documentation/git-worktree.txt16
-rw-r--r--Documentation/git.txt8
-rw-r--r--Documentation/mergetools/vimdiff.txt194
-rw-r--r--Documentation/rev-list-options.txt5
-rw-r--r--Documentation/revisions.txt17
-rw-r--r--Documentation/technical/api-error-handling.txt24
-rw-r--r--Documentation/technical/api-trace2.txt48
-rw-r--r--Documentation/technical/bitmap-format.txt203
-rw-r--r--Documentation/technical/cruft-packs.txt123
-rw-r--r--Documentation/technical/index-format.txt2
-rw-r--r--Documentation/technical/pack-format.txt19
-rw-r--r--Documentation/technical/partial-clone.txt3
-rw-r--r--Documentation/technical/scalar.txt127
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile270
l---------RelNotes2
-rw-r--r--add-interactive.c15
-rw-r--r--add-patch.c2
-rw-r--r--advice.c3
-rw-r--r--advice.h3
-rw-r--r--alloc.c21
-rw-r--r--alloc.h1
-rw-r--r--apply.c6
-rw-r--r--archive-tar.c77
-rw-r--r--archive.c91
-rw-r--r--archive.h2
-rw-r--r--attr.c2
-rw-r--r--bisect.c20
-rw-r--r--bisect.h9
-rw-r--r--blame.c6
-rw-r--r--branch.c232
-rw-r--r--branch.h8
-rw-r--r--builtin.h1
-rw-r--r--builtin/add.c31
-rw-r--r--builtin/am.c3
-rw-r--r--builtin/apply.c1
-rw-r--r--builtin/bisect--helper.c73
-rw-r--r--builtin/blame.c10
-rw-r--r--builtin/branch.c11
-rw-r--r--builtin/cat-file.c33
-rw-r--r--builtin/check-ref-format.c11
-rw-r--r--builtin/checkout.c43
-rw-r--r--builtin/clone.c88
-rw-r--r--builtin/commit.c17
-rw-r--r--builtin/describe.c2
-rw-r--r--builtin/diff-files.c8
-rw-r--r--builtin/diff-index.c5
-rw-r--r--builtin/diff-tree.c3
-rw-r--r--builtin/diff.c4
-rw-r--r--builtin/difftool.c6
-rw-r--r--builtin/fast-export.c2
-rw-r--r--builtin/fast-import.c2
-rw-r--r--builtin/fetch-pack.c8
-rw-r--r--builtin/fetch.c100
-rw-r--r--builtin/fsck.c39
-rw-r--r--builtin/fsmonitor--daemon.c1577
-rw-r--r--builtin/gc.c26
-rw-r--r--builtin/grep.c9
-rw-r--r--builtin/index-pack.c8
-rw-r--r--builtin/log.c75
-rw-r--r--builtin/ls-remote.c2
-rw-r--r--builtin/ls-tree.c366
-rw-r--r--builtin/mailsplit.c5
-rw-r--r--builtin/merge-file.c32
-rw-r--r--builtin/merge-tree.c187
-rw-r--r--builtin/merge.c6
-rw-r--r--builtin/mktree.c11
-rw-r--r--builtin/multi-pack-index.c53
-rw-r--r--builtin/mv.c255
-rw-r--r--builtin/name-rev.c23
-rw-r--r--builtin/pack-objects.c406
-rw-r--r--builtin/pack-redundant.c10
-rw-r--r--builtin/prune.c1
-rw-r--r--builtin/pull.c26
-rw-r--r--builtin/push.c64
-rw-r--r--builtin/rebase.c87
-rw-r--r--builtin/receive-pack.c53
-rw-r--r--builtin/reflog.c147
-rw-r--r--builtin/remote.c30
-rw-r--r--builtin/repack.c236
-rw-r--r--builtin/replace.c2
-rw-r--r--builtin/reset.c13
-rw-r--r--builtin/rev-list.c25
-rw-r--r--builtin/rev-parse.c5
-rw-r--r--builtin/revert.c10
-rw-r--r--builtin/shortlog.c10
-rw-r--r--builtin/show-branch.c4
-rw-r--r--builtin/show-ref.c17
-rw-r--r--builtin/sparse-checkout.c10
-rw-r--r--builtin/stash.c169
-rw-r--r--builtin/submodule--helper.c989
-rw-r--r--builtin/tag.c4
-rw-r--r--builtin/unpack-objects.c109
-rw-r--r--builtin/update-index.c43
-rw-r--r--builtin/worktree.c49
-rw-r--r--bulk-checkin.c119
-rw-r--r--bulk-checkin.h27
-rw-r--r--bundle.c31
-rw-r--r--bundle.h2
-rw-r--r--cache-tree.c11
-rw-r--r--cache.h52
-rw-r--r--chunk-format.c12
-rw-r--r--chunk-format.h3
-rwxr-xr-xci/install-dependencies.sh26
-rwxr-xr-xci/lib.sh92
-rwxr-xr-xci/make-test-artifacts.sh2
-rwxr-xr-xci/run-build-and-tests.sh16
-rwxr-xr-xci/run-static-analysis.sh2
-rwxr-xr-xci/run-test-slice.sh5
-rw-r--r--combine-diff.c11
-rw-r--r--commit-graph.c50
-rw-r--r--commit-graph.h7
-rw-r--r--commit.c46
-rw-r--r--commit.h1
-rw-r--r--common-main.c28
-rw-r--r--compat/fsmonitor/fsm-darwin-gcc.h92
-rw-r--r--compat/fsmonitor/fsm-health-darwin.c24
-rw-r--r--compat/fsmonitor/fsm-health-win32.c278
-rw-r--r--compat/fsmonitor/fsm-health.h47
-rw-r--r--compat/fsmonitor/fsm-listen-darwin.c513
-rw-r--r--compat/fsmonitor/fsm-listen-win32.c874
-rw-r--r--compat/fsmonitor/fsm-listen.h49
-rw-r--r--compat/fsmonitor/fsm-settings-darwin.c89
-rw-r--r--compat/fsmonitor/fsm-settings-win32.c137
-rw-r--r--compat/mingw.c98
-rw-r--r--compat/mingw.h10
-rw-r--r--compat/mkdir.c2
-rw-r--r--compat/mmap.c2
-rw-r--r--compat/nedmalloc/nedmalloc.c1
-rw-r--r--compat/terminal.c238
-rw-r--r--compat/terminal.h9
-rw-r--r--compat/win32/path-utils.h6
-rw-r--r--compat/win32/syslog.c7
-rw-r--r--config.c74
-rw-r--r--config.h17
-rw-r--r--config.mak.dev5
-rw-r--r--config.mak.uname25
-rw-r--r--configure.ac5
-rw-r--r--connect.c42
-rw-r--r--connected.c2
-rw-r--r--contrib/buildsystems/CMakeLists.txt40
-rw-r--r--contrib/coccinelle/array.cocci82
-rw-r--r--contrib/coccinelle/equals-null.cocci30
-rw-r--r--contrib/coccinelle/free.cocci27
-rw-r--r--contrib/coccinelle/object_id.cocci12
-rw-r--r--contrib/coccinelle/strbuf.cocci6
-rw-r--r--contrib/coccinelle/tests/free.c11
-rw-r--r--contrib/coccinelle/tests/free.res9
-rw-r--r--contrib/coccinelle/tests/unused.c82
-rw-r--r--contrib/coccinelle/tests/unused.res45
-rw-r--r--contrib/coccinelle/the_repository.pending.cocci15
-rw-r--r--contrib/coccinelle/unused.cocci43
-rw-r--r--contrib/coccinelle/xstrdup_or_null.cocci8
-rw-r--r--contrib/completion/git-prompt.sh91
-rw-r--r--contrib/credential/osxkeychain/git-credential-osxkeychain.c2
-rwxr-xr-xcontrib/rerere-train.sh2
-rw-r--r--contrib/scalar/Makefile2
-rw-r--r--contrib/scalar/README.md82
-rw-r--r--contrib/scalar/scalar.c292
-rw-r--r--contrib/scalar/scalar.txt21
-rwxr-xr-xcontrib/scalar/t/t9099-scalar.sh27
-rwxr-xr-xcontrib/subtree/git-subtree.sh15
-rw-r--r--contrib/vscode/README.md6
-rwxr-xr-xcontrib/vscode/init.sh9
-rw-r--r--convert.c12
-rw-r--r--convert.h6
-rw-r--r--daemon.c24
-rwxr-xr-xdetect-compiler2
-rw-r--r--diff-lib.c8
-rw-r--r--diff.c37
-rw-r--r--dir.c75
-rw-r--r--dir.h63
-rw-r--r--editor.c2
-rw-r--r--entry.c34
-rw-r--r--entry.h3
-rw-r--r--environment.c3
-rw-r--r--ewah/bitmap.c7
-rw-r--r--ewah/ewah_bitmap.c2
-rw-r--r--ewah/ewok.h1
-rw-r--r--fetch-negotiator.c5
-rw-r--r--fetch-negotiator.h8
-rw-r--r--fetch-pack.c110
-rw-r--r--fetch-pack.h1
-rw-r--r--fmt-merge-msg.c1
-rw-r--r--fsck.c23
-rw-r--r--fsmonitor--daemon.h171
-rw-r--r--fsmonitor-ipc.c171
-rw-r--r--fsmonitor-ipc.h48
-rw-r--r--fsmonitor-settings.c245
-rw-r--r--fsmonitor-settings.h54
-rw-r--r--fsmonitor.c289
-rw-r--r--fsmonitor.h26
-rw-r--r--fuzz-commit-graph.c12
-rw-r--r--git-compat-util.h101
-rwxr-xr-xgit-cvsserver.perl2
-rwxr-xr-xgit-instaweb.sh2
-rw-r--r--git-mergetool--lib.sh10
-rwxr-xr-xgit-p4.py1122
-rwxr-xr-xgit-send-email.perl7
-rw-r--r--git-sh-setup.sh16
-rwxr-xr-xgit-submodule.sh193
-rw-r--r--git.c14
-rwxr-xr-xgitk-git/gitk17
-rw-r--r--gitweb/Makefile145
-rwxr-xr-xgitweb/gitweb.perl5
-rw-r--r--gpg-interface.c30
-rw-r--r--gpg-interface.h8
-rw-r--r--grep.c2
-rw-r--r--grep.h2
-rw-r--r--hash.h4
-rw-r--r--help.c4
-rw-r--r--hook.c3
-rw-r--r--http-backend.c4
-rw-r--r--http-fetch.c2
-rw-r--r--http-push.c15
-rw-r--r--http-walker.c14
-rw-r--r--http.c100
-rw-r--r--http.h12
-rw-r--r--imap-send.c2
-rw-r--r--kwset.c4
-rw-r--r--list-objects-filter-options.c4
-rw-r--r--list-objects-filter-options.h27
-rw-r--r--ll-merge.c2
-rw-r--r--log-tree.c3
-rw-r--r--mailinfo.c4
-rw-r--r--mailmap.c14
-rw-r--r--merge-ort.c553
-rw-r--r--merge-ort.h32
-rw-r--r--merge-recursive.c17
-rw-r--r--mergetools/araxis8
-rw-r--r--mergetools/bc8
-rw-r--r--mergetools/codecompare8
-rw-r--r--mergetools/deltawalker8
-rw-r--r--mergetools/diffmerge8
-rw-r--r--mergetools/diffuse8
-rw-r--r--mergetools/ecmerge8
-rw-r--r--mergetools/emerge8
-rw-r--r--mergetools/examdiff8
-rw-r--r--mergetools/guiffy8
-rw-r--r--mergetools/kdiff38
-rw-r--r--mergetools/kompare8
-rw-r--r--mergetools/meld8
-rw-r--r--mergetools/opendiff8
-rw-r--r--mergetools/p4merge8
-rw-r--r--mergetools/smerge8
-rw-r--r--mergetools/tkdiff8
-rw-r--r--mergetools/tortoisemerge8
-rw-r--r--mergetools/vimdiff638
-rw-r--r--mergetools/winmerge8
-rw-r--r--mergetools/xxdiff8
-rw-r--r--midx.c108
-rw-r--r--notes-merge.c1
-rw-r--r--object-file.c267
-rw-r--r--object-name.c25
-rw-r--r--object-store.h24
-rw-r--r--pack-bitmap-write.c3
-rw-r--r--pack-bitmap.c135
-rw-r--r--pack-bitmap.h2
-rw-r--r--pack-mtimes.c130
-rw-r--r--pack-mtimes.h26
-rw-r--r--pack-objects.c6
-rw-r--r--pack-objects.h35
-rw-r--r--pack-write.c88
-rw-r--r--pack.h4
-rw-r--r--packfile.c24
-rw-r--r--pager.c4
-rw-r--r--parallel-checkout.c10
-rw-r--r--parallel-checkout.h4
-rw-r--r--parse-options.c53
-rw-r--r--path.c18
-rw-r--r--pathspec.c2
-rw-r--r--pkt-line.h16
-rw-r--r--po/.gitignore2
-rw-r--r--po/README.md232
-rw-r--r--po/TEAMS12
-rw-r--r--po/bg.po22080
-rw-r--r--po/ca.po22590
-rw-r--r--po/de.po21837
-rw-r--r--po/es.po22660
-rw-r--r--po/fr.po22079
-rw-r--r--po/git.pot24647
-rw-r--r--po/id.po26520
-rw-r--r--po/pt_PT.po15793
-rw-r--r--po/ru.po23312
-rw-r--r--po/sv.po23985
-rw-r--r--po/tr.po21320
-rw-r--r--po/vi.po21731
-rw-r--r--po/zh_CN.po26389
-rw-r--r--po/zh_TW.po27383
-rw-r--r--pretty.c18
-rw-r--r--prio-queue.c2
-rw-r--r--promisor-remote.c4
-rw-r--r--range-diff.c4
-rw-r--r--reachable.c58
-rw-r--r--reachable.h9
-rw-r--r--read-cache.c46
-rw-r--r--rebase-interactive.c15
-rw-r--r--ref-filter.c12
-rw-r--r--reflog-walk.c24
-rw-r--r--reflog-walk.h1
-rw-r--r--reflog.c20
-rw-r--r--refs.c30
-rw-r--r--refs.h8
-rw-r--r--refs/debug.c82
-rw-r--r--refs/files-backend.c90
-rw-r--r--refs/iterator.c18
-rw-r--r--refs/packed-backend.c156
-rw-r--r--refs/packed-backend.h7
-rw-r--r--refs/ref-cache.c8
-rw-r--r--refs/refs-internal.h1
-rw-r--r--reftable/blocksource.c9
-rw-r--r--reftable/generic.c8
-rw-r--r--reftable/record_test.c4
-rw-r--r--reftable/stack_test.c2
-rw-r--r--reftable/tree.c4
-rw-r--r--reftable/writer.c24
-rw-r--r--remote-curl.c27
-rw-r--r--remote.c173
-rw-r--r--remote.h38
-rw-r--r--repo-settings.c13
-rw-r--r--repository.h4
-rw-r--r--rerere.c2
-rw-r--r--revision.c124
-rw-r--r--revision.h74
-rw-r--r--run-command.c92
-rw-r--r--run-command.h45
-rw-r--r--send-pack.c6
-rw-r--r--send-pack.h3
-rw-r--r--sequencer.c554
-rw-r--r--sequencer.h24
-rw-r--r--serve.c1
-rw-r--r--setup.c190
-rw-r--r--sh-i18n--envsubst.c2
-rw-r--r--sha256/nettle.h31
-rw-r--r--shallow.c11
-rw-r--r--shared.mak5
-rw-r--r--sparse-index.c134
-rw-r--r--sparse-index.h14
-rw-r--r--submodule-config.c16
-rw-r--r--submodule-config.h2
-rw-r--r--submodule.c55
-rw-r--r--submodule.h6
-rw-r--r--t/Makefile4
-rw-r--r--t/README61
-rw-r--r--t/annotate-tests.sh43
-rw-r--r--t/helper/test-bloom.c2
-rw-r--r--t/helper/test-chmtime.c15
-rw-r--r--t/helper/test-delta.c21
-rw-r--r--t/helper/test-dump-cache-tree.c7
-rw-r--r--t/helper/test-fast-rebase.c23
-rw-r--r--t/helper/test-fsmonitor-client.c222
-rw-r--r--t/helper/test-hash.c1
-rw-r--r--t/helper/test-hexdump.c30
-rw-r--r--t/helper/test-json-writer.c16
-rw-r--r--t/helper/test-pack-mtimes.c56
-rw-r--r--t/helper/test-path-utils.c11
-rw-r--r--t/helper/test-ref-store.c1
-rw-r--r--t/helper/test-regex.c9
-rw-r--r--t/helper/test-revision-walking.c1
-rw-r--r--t/helper/test-run-command.c24
-rw-r--r--t/helper/test-scrap-cache-tree.c1
-rw-r--r--t/helper/test-tool.c3
-rw-r--r--t/helper/test-tool.h3
-rw-r--r--t/helper/test-trace2.c29
-rw-r--r--t/helper/test-urlmatch-normalization.c11
-rw-r--r--t/lib-git-p4.sh3
-rw-r--r--t/lib-git-svn.sh4
-rw-r--r--t/lib-httpd.sh2
-rw-r--r--t/lib-parallel-checkout.sh6
-rw-r--r--t/lib-proto-disable.sh6
-rw-r--r--t/lib-rebase.sh15
-rw-r--r--t/lib-submodule-update.sh7
-rw-r--r--t/lib-sudo.sh15
-rw-r--r--t/lib-t3100.sh10
-rwxr-xr-xt/lib-unicode-nfc-nfd.sh162
-rw-r--r--t/lib-unique-files.sh34
-rwxr-xr-xt/perf/p0008-odb-fsync.sh82
-rwxr-xr-xt/perf/p2000-sparse-operations.sh3
-rwxr-xr-xt/perf/p4220-log-grep-engines.sh3
-rwxr-xr-xt/perf/p4221-log-grep-engines-fixed.sh3
-rwxr-xr-xt/perf/p5302-pack-index.sh15
-rwxr-xr-xt/perf/p7519-fsmonitor.sh86
-rwxr-xr-xt/perf/p7527-builtin-fsmonitor.sh257
-rwxr-xr-xt/perf/p7820-grep-engines.sh6
-rw-r--r--t/perf/perf-lib.sh67
-rwxr-xr-xt/t0000-basic.sh13
-rwxr-xr-xt/t0003-attributes.sh5
-rwxr-xr-xt/t0008-ignores.sh12
-rwxr-xr-xt/t0012-help.sh2
-rwxr-xr-xt/t0015-hash.sh3
-rwxr-xr-xt/t0019-json-writer.sh2
-rwxr-xr-xt/t0021-conversion.sh22
-rwxr-xr-xt/t0027-auto-crlf.sh8
-rwxr-xr-xt/t0028-working-tree-encoding.sh3
-rwxr-xr-xt/t0029-core-unsetenvvars.sh3
-rwxr-xr-xt/t0033-safe-directory.sh73
-rwxr-xr-xt/t0034-root-safe-directory.sh93
-rwxr-xr-xt/t0035-safe-bare-repository.sh54
-rwxr-xr-xt/t0056-git-C.sh1
-rwxr-xr-xt/t0060-path-utils.sh25
-rwxr-xr-xt/t0061-run-command.sh30
-rwxr-xr-xt/t0062-revision-walking.sh1
-rwxr-xr-xt/t0090-cache-tree.sh2
-rwxr-xr-xt/t0091-bugreport.sh26
-rwxr-xr-xt/t0095-bloom.sh2
-rwxr-xr-xt/t0100-previous.sh1
-rwxr-xr-xt/t0101-at-syntax.sh2
-rwxr-xr-xt/t0110-urlmatch-normalization.sh2
-rwxr-xr-xt/t0210-trace2-normal.sh76
-rw-r--r--t/t0211/scrub_perf.perl4
-rw-r--r--t/t0212/parse_events.perl19
-rwxr-xr-xt/t1001-read-tree-m-2way.sh1
-rwxr-xr-xt/t1002-read-tree-m-u-2way.sh1
-rwxr-xr-xt/t1006-cat-file.sh10
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh48
-rwxr-xr-xt/t1051-large-conversion.sh2
-rwxr-xr-xt/t1060-object-corruption.sh2
-rwxr-xr-xt/t1090-sparse-checkout-scope.sh5
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh15
-rwxr-xr-xt/t1092-sparse-checkout-compatibility.sh241
-rwxr-xr-xt/t1300-config.sh14
-rwxr-xr-xt/t1301-shared-repo.sh3
-rwxr-xr-xt/t1350-config-hooks-path.sh4
-rwxr-xr-xt/t1401-symbolic-ref.sh2
-rwxr-xr-xt/t1402-check-ref-format.sh1
-rwxr-xr-xt/t1410-reflog.sh22
-rwxr-xr-xt/t1411-reflog-show.sh6
-rwxr-xr-xt/t1412-reflog-loop.sh2
-rwxr-xr-xt/t1415-worktree-refs.sh1
-rwxr-xr-xt/t1416-ref-transaction-hooks.sh73
-rwxr-xr-xt/t1418-reflog-exists.sh37
-rwxr-xr-xt/t1450-fsck.sh13
-rwxr-xr-xt/t1800-hook.sh76
-rwxr-xr-xt/t2015-checkout-unborn.sh1
-rwxr-xr-xt/t2016-checkout-patch.sh42
-rwxr-xr-xt/t2018-checkout-branch.sh4
-rwxr-xr-xt/t2030-unresolve-info.sh71
-rwxr-xr-xt/t2080-parallel-checkout-basics.sh48
-rwxr-xr-xt/t2107-update-index-basic.sh31
-rwxr-xr-xt/t2200-add-update.sh1
-rwxr-xr-xt/t2203-add-intent.sh1
-rwxr-xr-xt/t2205-add-worktree-config.sh265
-rwxr-xr-xt/t2400-worktree-add.sh9
-rwxr-xr-xt/t2402-worktree-list.sh19
-rwxr-xr-xt/t2407-worktree-heads.sh180
-rwxr-xr-xt/t3001-ls-files-others-exclude.sh42
-rwxr-xr-xt/t3002-ls-files-dashpath.sh86
-rwxr-xr-xt/t3020-ls-files-error-unmatch.sh12
-rwxr-xr-xt/t3060-ls-files-with-tree.sh8
-rwxr-xr-xt/t3101-ls-tree-dirname.sh55
-rwxr-xr-xt/t3103-ls-tree-misc.sh15
-rwxr-xr-xt/t3104-ls-tree-format.sh75
-rwxr-xr-xt/t3105-ls-tree-output.sh192
-rwxr-xr-xt/t3200-branch.sh53
-rwxr-xr-xt/t3202-show-branch.sh14
-rwxr-xr-xt/t3206-range-diff.sh51
-rwxr-xr-xt/t3207-branch-submodule.sh38
-rwxr-xr-xt/t3302-notes-index-expensive.sh1
-rwxr-xr-xt/t3303-notes-subtrees.sh1
-rwxr-xr-xt/t3304-notes-mixed.sh1
-rwxr-xr-xt/t3305-notes-fanout.sh1
-rwxr-xr-xt/t3400-rebase.sh18
-rwxr-xr-xt/t3404-rebase-interactive.sh283
-rwxr-xr-xt/t3408-rebase-multi-line.sh1
-rwxr-xr-xt/t3412-rebase-root.sh18
-rwxr-xr-xt/t3413-rebase-hook.sh18
-rwxr-xr-xt/t3416-rebase-onto-threedots.sh29
-rwxr-xr-xt/t3426-rebase-submodule.sh1
-rwxr-xr-xt/t3430-rebase-merges.sh6
-rwxr-xr-xt/t3501-revert-cherry-pick.sh46
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh2
-rwxr-xr-xt/t3602-rm-sparse-checkout.sh6
-rwxr-xr-xt/t3700-add.sh28
-rwxr-xr-xt/t3701-add-interactive.sh21
-rwxr-xr-xt/t3705-add-sparse-checkout.sh4
-rwxr-xr-xt/t3903-stash.sh53
-rwxr-xr-xt/t4013-diff-various.sh33
-rwxr-xr-xt/t4014-format-patch.sh33
-rwxr-xr-xt/t4020-diff-external.sh8
-rwxr-xr-xt/t4021-format-patch-numbered.sh1
-rwxr-xr-xt/t4027-diff-submodule.sh1
-rwxr-xr-xt/t4028-format-patch-mime-headers.sh2
-rwxr-xr-xt/t4036-format-patch-signer-mime.sh1
-rwxr-xr-xt/t4039-diff-assume-unchanged.sh1
-rwxr-xr-xt/t4044-diff-index-unique-abbrev.sh2
-rwxr-xr-xt/t4055-diff-context.sh1
-rwxr-xr-xt/t4066-diff-emit-delay.sh1
-rwxr-xr-xt/t4122-apply-symlink-inside.sh1
-rwxr-xr-xt/t4126-apply-empty.sh1
-rwxr-xr-xt/t4128-apply-root.sh1
-rwxr-xr-xt/t4140-apply-ita.sh1
-rwxr-xr-xt/t4150-am.sh24
-rwxr-xr-xt/t4200-rerere.sh3
-rwxr-xr-xt/t4202-log.sh11
-rwxr-xr-xt/t4206-log-follow-harder-copies.sh2
-rwxr-xr-xt/t4207-log-decoration-colors.sh1
-rwxr-xr-xt/t4212-log-corrupt.sh1
-rwxr-xr-xt/t4217-log-limit.sh41
-rwxr-xr-xt/t4301-merge-tree-write-tree.sh240
-rwxr-xr-xt/t5000-tar-tree.sh33
-rwxr-xr-xt/t5001-archive-attr.sh5
-rwxr-xr-xt/t5002-archive-attr-pattern.sh5
-rwxr-xr-xt/t5003-archive-zip.sh25
-rwxr-xr-xt/t5300-pack-object.sh41
-rwxr-xr-xt/t5301-sliding-window.sh2
-rwxr-xr-xt/t5303-pack-corruption-resilience.sh2
-rwxr-xr-xt/t5308-pack-detect-duplicates.sh2
-rwxr-xr-xt/t5309-pack-delta-cycles.sh2
-rwxr-xr-xt/t5313-pack-bounds-checks.sh2
-rwxr-xr-xt/t5314-pack-cycle-detection.sh4
-rwxr-xr-xt/t5316-pack-delta-depth.sh2
-rwxr-xr-xt/t5317-pack-objects-filter-objects.sh91
-rwxr-xr-xt/t5318-commit-graph.sh3
-rwxr-xr-xt/t5320-delta-islands.sh2
-rwxr-xr-xt/t5321-pack-large-objects.sh2
-rwxr-xr-xt/t5322-pack-objects-sparse.sh1
-rwxr-xr-xt/t5329-pack-objects-cruft.sh741
-rwxr-xr-xt/t5330-no-lazy-fetch-with-commit-graph.sh47
-rwxr-xr-xt/t5351-unpack-large-objects.sh96
-rwxr-xr-xt/t5401-update-hooks.sh64
-rwxr-xr-xt/t5402-post-merge-hook.sh16
-rwxr-xr-xt/t5403-post-checkout-hook.sh3
-rwxr-xr-xt/t5406-remote-rejects.sh2
-rwxr-xr-xt/t5407-post-rewrite-hook.sh14
-rwxr-xr-xt/t5409-colorize-remote-messages.sh2
-rwxr-xr-xt/t5411-proc-receive-hook.sh4
-rw-r--r--t/t5411/once-0010-report-status-v1.sh2
-rw-r--r--t/t5411/test-0002-pre-receive-declined.sh4
-rw-r--r--t/t5411/test-0003-pre-receive-declined--porcelain.sh2
-rw-r--r--t/t5411/test-0013-bad-protocol.sh20
-rw-r--r--t/t5411/test-0014-bad-protocol--porcelain.sh18
-rw-r--r--t/t5411/test-0020-report-ng.sh4
-rw-r--r--t/t5411/test-0021-report-ng--porcelain.sh4
-rw-r--r--t/t5411/test-0022-report-unexpect-ref.sh2
-rw-r--r--t/t5411/test-0023-report-unexpect-ref--porcelain.sh2
-rw-r--r--t/t5411/test-0024-report-unknown-ref.sh2
-rw-r--r--t/t5411/test-0025-report-unknown-ref--porcelain.sh2
-rw-r--r--t/t5411/test-0026-push-options.sh6
-rw-r--r--t/t5411/test-0027-push-options--porcelain.sh6
-rw-r--r--t/t5411/test-0030-report-ok.sh2
-rw-r--r--t/t5411/test-0031-report-ok--porcelain.sh2
-rw-r--r--t/t5411/test-0032-report-with-options.sh14
-rw-r--r--t/t5411/test-0033-report-with-options--porcelain.sh14
-rw-r--r--t/t5411/test-0034-report-ft.sh2
-rw-r--r--t/t5411/test-0035-report-ft--porcelain.sh2
-rw-r--r--t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh6
-rw-r--r--t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh6
-rw-r--r--t/t5411/test-0038-report-mixed-refs.sh2
-rw-r--r--t/t5411/test-0039-report-mixed-refs--porcelain.sh2
-rw-r--r--t/t5411/test-0040-process-all-refs.sh2
-rw-r--r--t/t5411/test-0041-process-all-refs--porcelain.sh2
-rw-r--r--t/t5411/test-0050-proc-receive-refs-with-modifiers.sh4
-rwxr-xr-xt/t5503-tagfollow.sh64
-rwxr-xr-xt/t5505-remote.sh86
-rwxr-xr-xt/t5506-remote-groups.sh1
-rwxr-xr-xt/t5510-fetch.sh41
-rwxr-xr-xt/t5512-ls-remote.sh17
-rwxr-xr-xt/t5513-fetch-track.sh1
-rwxr-xr-xt/t5515-fetch-merge-logic.sh1
-rwxr-xr-xt/t5516-fetch-push.sh280
-rwxr-xr-xt/t5518-fetch-exit-status.sh1
-rwxr-xr-xt/t5521-pull-options.sh4
-rwxr-xr-xt/t5524-pull-msg.sh1
-rwxr-xr-xt/t5526-fetch-submodules.sh27
-rwxr-xr-xt/t5528-push-default.sh77
-rwxr-xr-xt/t5532-fetch-proxy.sh2
-rwxr-xr-xt/t5534-push-signed.sh26
-rwxr-xr-xt/t5537-fetch-shallow.sh21
-rwxr-xr-xt/t5540-http-push-webdav.sh4
-rwxr-xr-xt/t5541-http-push-smart.sh51
-rwxr-xr-xt/t5543-atomic-push.sh14
-rwxr-xr-xt/t5544-pack-objects-hook.sh7
-rwxr-xr-xt/t5547-push-quarantine.sh4
-rwxr-xr-xt/t5548-push-porcelain.sh2
-rwxr-xr-xt/t5550-http-fetch-dumb.sh30
-rwxr-xr-xt/t5551-http-fetch-smart.sh17
-rwxr-xr-xt/t5571-pre-push-hook.sh38
-rwxr-xr-xt/t5572-pull-submodule.sh26
-rwxr-xr-xt/t5600-clone-fail-cleanup.sh1
-rwxr-xr-xt/t5601-clone.sh27
-rwxr-xr-xt/t5605-clone-local.sh25
-rwxr-xr-xt/t5616-partial-clone.sh81
-rwxr-xr-xt/t5702-protocol-v2.sh59
-rwxr-xr-xt/t5812-proto-disable-http.sh2
-rwxr-xr-xt/t5815-submodule-protos.sh4
-rwxr-xr-xt/t5900-repo-selection.sh2
-rwxr-xr-xt/t6001-rev-list-graft.sh1
-rwxr-xr-xt/t6002-rev-list-bisect.sh1
-rwxr-xr-xt/t6003-rev-list-topo-order.sh1
-rwxr-xr-xt/t6005-rev-list-count.sh1
-rwxr-xr-xt/t6018-rev-list-glob.sh1
-rwxr-xr-xt/t6020-bundle-misc.sh26
-rwxr-xr-xt/t6030-bisect-porcelain.sh28
-rwxr-xr-xt/t6100-rev-list-in-order.sh1
-rwxr-xr-xt/t6101-rev-parse-parents.sh3
-rwxr-xr-xt/t6110-rev-list-sparse.sh1
-rwxr-xr-xt/t6114-keep-packs.sh2
-rwxr-xr-xt/t6131-pathspec-icase.sh2
-rwxr-xr-xt/t6132-pathspec-exclude.sh181
-rwxr-xr-xt/t6403-merge-file.sh2
-rwxr-xr-xt/t6417-merge-ours-theirs.sh1
-rwxr-xr-xt/t6422-merge-rename-corner-cases.sh1
-rwxr-xr-xt/t6423-merge-rename-directories.sh105
-rwxr-xr-xt/t6424-merge-unrelated-index-changes.sh32
-rwxr-xr-xt/t6428-merge-conflicts-sparse.sh4
-rwxr-xr-xt/t6429-merge-sequence-rename-caching.sh2
-rwxr-xr-xt/t6435-merge-sparse.sh2
-rwxr-xr-xt/t6437-submodule-merge.sh2
-rwxr-xr-xt/t6500-gc.sh22
-rwxr-xr-xt/t7001-mv.sh19
-rwxr-xr-xt/t7002-mv-sparse-checkout.sh86
-rwxr-xr-xt/t7008-filter-branch-null-sha1.sh1
-rwxr-xr-xt/t7011-skip-worktree-reading.sh1
-rwxr-xr-xt/t7012-skip-worktree-writing.sh2
-rwxr-xr-xt/t7063-status-untracked-cache.sh3
-rwxr-xr-xt/t7102-reset.sh40
-rwxr-xr-xt/t7113-post-index-change-hook.sh7
-rwxr-xr-xt/t7406-submodule-update.sh97
-rwxr-xr-xt/t7418-submodule-sparse-gitmodules.sh3
-rwxr-xr-xt/t7503-pre-commit-and-pre-merge-commit-hooks.sh150
-rwxr-xr-xt/t7504-commit-msg-hook.sh43
-rwxr-xr-xt/t7505-prepare-commit-msg-hook.sh43
-rwxr-xr-xt/t7519-status-fsmonitor.sh52
-rwxr-xr-xt/t7520-ignored-hook-warning.sh11
-rwxr-xr-xt/t7524-commit-summary.sh31
-rwxr-xr-xt/t7527-builtin-fsmonitor.sh1002
-rwxr-xr-xt/t7609-mergetool--lib.sh14
-rwxr-xr-xt/t7700-repack.sh57
-rwxr-xr-xt/t7702-repack-cyclic-alternate.sh2
-rwxr-xr-xt/t7703-repack-geometric.sh75
-rwxr-xr-xt/t7810-grep.sh87
-rwxr-xr-xt/t7812-grep-icase-non-ascii.sh11
-rwxr-xr-xt/t7814-grep-recurse-submodules.sh8
-rwxr-xr-xt/t8001-annotate.sh1
-rwxr-xr-xt/t8002-blame.sh1
-rwxr-xr-xt/t8007-cat-file-textconv.sh2
-rwxr-xr-xt/t8010-cat-file-filters.sh2
-rwxr-xr-xt/t8012-blame-colors.sh1
-rwxr-xr-xt/t9001-send-email.sh5
-rwxr-xr-xt/t9100-git-svn-basic.sh1
-rwxr-xr-xt/t9101-git-svn-props.sh1
-rwxr-xr-xt/t9104-git-svn-follow-parent.sh1
-rwxr-xr-xt/t9106-git-svn-commit-diff-clobber.sh2
-rwxr-xr-xt/t9115-git-svn-dcommit-funky-renames.sh1
-rwxr-xr-xt/t9116-git-svn-log.sh1
-rwxr-xr-xt/t9122-git-svn-author.sh2
-rwxr-xr-xt/t9127-git-svn-partial-rebuild.sh1
-rwxr-xr-xt/t9129-git-svn-i18n-commitencoding.sh1
-rwxr-xr-xt/t9139-git-svn-non-utf8-commitencoding.sh1
-rwxr-xr-xt/t9146-git-svn-empty-dirs.sh2
-rwxr-xr-xt/t9148-git-svn-propset.sh1
-rwxr-xr-xt/t9160-git-svn-preserve-empty-dirs.sh1
-rwxr-xr-xt/t9162-git-svn-dcommit-interactive.sh2
-rwxr-xr-xt/t9164-git-svn-dcommit-concurrent.sh2
-rwxr-xr-xt/t9301-fast-import-notes.sh1
-rwxr-xr-xt/t9350-fast-export.sh7
-rwxr-xr-xt/t9400-git-cvsserver-server.sh2
-rwxr-xr-xt/t9501-gitweb-standalone-http-status.sh1
-rwxr-xr-xt/t9502-gitweb-standalone-parse-output.sh14
-rwxr-xr-xt/t9800-git-p4-basic.sh108
-rwxr-xr-xt/t9801-git-p4-branch.sh10
-rwxr-xr-xt/t9802-git-p4-filetype.sh34
-rwxr-xr-xt/t9835-git-p4-metadata-encoding-python2.sh213
-rwxr-xr-xt/t9836-git-p4-metadata-encoding-python3.sh214
-rwxr-xr-xt/t9902-completion.sh48
-rwxr-xr-xt/t9903-bash-prompt.sh2
-rw-r--r--t/test-lib-functions.sh131
-rw-r--r--t/test-lib-github-workflow-markup.sh56
-rw-r--r--t/test-lib-junit.sh132
-rw-r--r--t/test-lib.sh160
-rw-r--r--tempfile.c63
-rw-r--r--tempfile.h13
-rwxr-xr-xtemplates/hooks--fsmonitor-watchman.sample5
-rw-r--r--trace2.c9
-rw-r--r--trace2.h8
-rw-r--r--trailer.c4
-rw-r--r--transport-helper.c5
-rw-r--r--transport.c274
-rw-r--r--transport.h5
-rw-r--r--unpack-trees.c52
-rw-r--r--upload-pack.c27
-rw-r--r--usage.c43
-rw-r--r--wildmatch.c2
-rw-r--r--worktree.c2
-rw-r--r--wrapper.c20
-rw-r--r--wt-status.c17
-rw-r--r--xdiff-interface.c2
-rw-r--r--xdiff/xdiff.h1
-rw-r--r--xdiff/xdiffi.c2
-rw-r--r--xdiff/xemit.c2
-rw-r--r--xdiff/xhistogram.c19
-rw-r--r--xdiff/xmacros.h19
-rw-r--r--xdiff/xpatience.c9
-rw-r--r--xdiff/xprepare.c43
-rw-r--r--xdiff/xutils.c19
-rw-r--r--xdiff/xutils.h3
776 files changed, 156257 insertions, 199761 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index e114ffe..4860beb 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -9,7 +9,7 @@ freebsd_12_task:
DEFAULT_TEST_TARGET: prove
DEVELOPER: 1
freebsd_instance:
- image_family: freebsd-12-2
+ image_family: freebsd-12-3
memory: 2G
install_script:
pkg install -y gettext gmake perl5
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index c35200d..cd1f526 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -119,8 +119,8 @@ jobs:
- name: test
shell: bash
run: . /etc/profile && ci/run-test-slice.sh ${{matrix.nr}} 10
- - name: ci/print-test-failures.sh
- if: failure()
+ - name: print test failures
+ if: failure() && env.FAILED_TEST_ARTIFACTS != ''
shell: bash
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
@@ -204,8 +204,8 @@ jobs:
env:
NO_SVN_TESTS: 1
run: . /etc/profile && ci/run-test-slice.sh ${{matrix.nr}} 10
- - name: ci/print-test-failures.sh
- if: failure()
+ - name: print test failures
+ if: failure() && env.FAILED_TEST_ARTIFACTS != ''
shell: bash
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
@@ -261,8 +261,10 @@ jobs:
- uses: actions/checkout@v2
- run: ci/install-dependencies.sh
- run: ci/run-build-and-tests.sh
- - run: ci/print-test-failures.sh
- if: failure()
+ - name: print test failures
+ if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+ shell: bash
+ run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v2
@@ -292,8 +294,10 @@ jobs:
- uses: actions/checkout@v1
- run: ci/install-docker-dependencies.sh
- run: ci/run-build-and-tests.sh
- - run: ci/print-test-failures.sh
- if: failure()
+ - name: print test failures
+ if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+ shell: bash
+ run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v1
diff --git a/.gitignore b/.gitignore
index f817c50..42fd725 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,6 +72,7 @@
/git-format-patch
/git-fsck
/git-fsck-objects
+/git-fsmonitor--daemon
/git-gc
/git-get-tar-commit-id
/git-grep
@@ -184,6 +185,7 @@
/git-worktree
/git-write-tree
/git-core-*/?*
+/git.res
/gitweb/GITWEB-BUILD-OPTIONS
/gitweb/gitweb.cgi
/gitweb/static/gitweb.js
@@ -199,6 +201,7 @@
*.[aos]
*.o.json
*.py[co]
+.build/
.depend/
*.gcda
*.gcno
@@ -223,7 +226,6 @@
*.hcc
*.obj
*.lib
-*.res
*.sln
*.sp
*.suo
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 1a7bc45..4c756be 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -43,7 +43,10 @@ the overall style of existing code. Modifications to existing
code is expected to match the style the surrounding code already
uses (even if it doesn't match the overall style of existing code).
-But if you must have a list of rules, here they are.
+But if you must have a list of rules, here are some language
+specific ones. Note that Documentation/ToolsForGit.txt document
+has a collection of tips to help you use some external tools
+to conform to these guidelines.
For shell scripts specifically (not exhaustive):
@@ -227,7 +230,10 @@ For C programs:
the first statement (i.e. -Wdeclaration-after-statement).
- Declaring a variable in the for loop "for (int i = 0; i < 10; i++)"
- is still not allowed in this codebase.
+ is still not allowed in this codebase. We are in the process of
+ allowing it by waiting to see that 44ba10d6 (revision: use C99
+ declaration of variable in for() loop, 2021-11-14) does not get
+ complaints. Let's revisit this around November 2022.
- NULL pointers shall be written as NULL, not as 0.
@@ -489,17 +495,6 @@ For Perl programs:
- Learn and use Git.pm if you need that functionality.
- - For Emacs, it's useful to put the following in
- GIT_CHECKOUT/.dir-locals.el, assuming you use cperl-mode:
-
- ;; note the first part is useful for C editing, too
- ((nil . ((indent-tabs-mode . t)
- (tab-width . 8)
- (fill-column . 80)))
- (cperl-mode . ((cperl-indent-level . 8)
- (cperl-extra-newline-before-brace . nil)
- (cperl-merge-trailing-else . t))))
-
For Python scripts:
- We follow PEP-8 (http://www.python.org/dev/peps/pep-0008/).
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 1eb9192..4f801f4 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -93,7 +93,10 @@ SP_ARTICLES += $(API_DOCS)
TECH_DOCS += MyFirstContribution
TECH_DOCS += MyFirstObjectWalk
TECH_DOCS += SubmittingPatches
+TECH_DOCS += ToolsForGit
+TECH_DOCS += technical/bitmap-format
TECH_DOCS += technical/bundle-format
+TECH_DOCS += technical/cruft-packs
TECH_DOCS += technical/hash-function-transition
TECH_DOCS += technical/http-protocol
TECH_DOCS += technical/index-format
@@ -302,12 +305,12 @@ $(mergetools_txt): mergetools-list.made
mergetools-list.made: ../git-mergetool--lib.sh $(wildcard ../mergetools/*)
$(QUIET_GEN) \
- $(SHELL_PATH) -c 'MERGE_TOOLS_DIR=../mergetools && \
+ $(SHELL_PATH) -c 'MERGE_TOOLS_DIR=../mergetools && TOOL_MODE=diff && \
. ../git-mergetool--lib.sh && \
- show_tool_names can_diff "* " || :' >mergetools-diff.txt && \
- $(SHELL_PATH) -c 'MERGE_TOOLS_DIR=../mergetools && \
+ show_tool_names can_diff' | sed -e "s/\([a-z0-9]*\)/\`\1\`;;/" >mergetools-diff.txt && \
+ $(SHELL_PATH) -c 'MERGE_TOOLS_DIR=../mergetools && TOOL_MODE=merge && \
. ../git-mergetool--lib.sh && \
- show_tool_names can_merge "* " || :' >mergetools-merge.txt && \
+ show_tool_names can_merge' | sed -e "s/\([a-z0-9]*\)/\`\1\`;;/" >mergetools-merge.txt && \
date >$@
TRACK_ASCIIDOCFLAGS = $(subst ','\'',$(ASCIIDOC_COMMON):$(ASCIIDOC_HTML):$(ASCIIDOC_DOCBOOK))
@@ -390,7 +393,7 @@ gitman.texi: $(MAN_XML) cat-texi.perl texi.xsl
$(RM) $@+
gitman.info: gitman.texi
- $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi
+ $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $<
$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
$(QUIET_DB2TEXI)$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index 63a2ef5..1da15d9 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -710,13 +710,104 @@ dependencies. `prove` also makes the output nicer.
Go ahead and commit this change, as well.
[[ready-to-share]]
-== Getting Ready to Share
+== Getting Ready to Share: Anatomy of a Patch Series
You may have noticed already that the Git project performs its code reviews via
emailed patches, which are then applied by the maintainer when they are ready
-and approved by the community. The Git project does not accept patches from
+and approved by the community. The Git project does not accept contributions from
pull requests, and the patches emailed for review need to be formatted a
-specific way. At this point the tutorial diverges, in order to demonstrate two
+specific way.
+
+:patch-series: https://lore.kernel.org/git/pull.1218.git.git.1645209647.gitgitgadget@gmail.com/
+:lore: https://lore.kernel.org/git/
+
+Before taking a look at how to convert your commits into emailed patches,
+let's analyze what the end result, a "patch series", looks like. Here is an
+{patch-series}[example] of the summary view for a patch series on the web interface of
+the {lore}[Git mailing list archive]:
+
+----
+2022-02-18 18:40 [PATCH 0/3] libify reflog John Cai via GitGitGadget
+2022-02-18 18:40 ` [PATCH 1/3] reflog: libify delete reflog function and helpers John Cai via GitGitGadget
+2022-02-18 19:10 ` Ævar Arnfjörð Bjarmason [this message]
+2022-02-18 19:39 ` Taylor Blau
+2022-02-18 19:48 ` Ævar Arnfjörð Bjarmason
+2022-02-18 19:35 ` Taylor Blau
+2022-02-21 1:43 ` John Cai
+2022-02-21 1:50 ` Taylor Blau
+2022-02-23 19:50 ` John Cai
+2022-02-18 20:00 ` // other replies ellided
+2022-02-18 18:40 ` [PATCH 2/3] reflog: call reflog_delete from reflog.c John Cai via GitGitGadget
+2022-02-18 19:15 ` Ævar Arnfjörð Bjarmason
+2022-02-18 20:26 ` Junio C Hamano
+2022-02-18 18:40 ` [PATCH 3/3] stash: call reflog_delete from reflog.c John Cai via GitGitGadget
+2022-02-18 19:20 ` Ævar Arnfjörð Bjarmason
+2022-02-19 0:21 ` Taylor Blau
+2022-02-22 2:36 ` John Cai
+2022-02-22 10:51 ` Ævar Arnfjörð Bjarmason
+2022-02-18 19:29 ` [PATCH 0/3] libify reflog Ævar Arnfjörð Bjarmason
+2022-02-22 18:30 ` [PATCH v2 0/3] libify reflog John Cai via GitGitGadget
+2022-02-22 18:30 ` [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior John Cai via GitGitGadget
+2022-02-23 8:54 ` Ævar Arnfjörð Bjarmason
+2022-02-23 21:27 ` Junio C Hamano
+// continued
+----
+
+We can note a few things:
+
+- Each commit is sent as a separate email, with the commit message title as
+ subject, prefixed with "[PATCH _i_/_n_]" for the _i_-th commit of an
+ _n_-commit series.
+- Each patch is sent as a reply to an introductory email called the _cover
+ letter_ of the series, prefixed "[PATCH 0/_n_]".
+- Subsequent iterations of the patch series are labelled "PATCH v2", "PATCH
+ v3", etc. in place of "PATCH". For example, "[PATCH v2 1/3]" would be the first of
+ three patches in the second iteration. Each iteration is sent with a new cover
+ letter (like "[PATCH v2 0/3]" above), itself a reply to the cover letter of the
+ previous iteration (more on that below).
+
+NOTE: A single-patch topic is sent with "[PATCH]", "[PATCH v2]", etc. without
+_i_/_n_ numbering (in the above thread overview, no single-patch topic appears,
+though).
+
+[[cover-letter]]
+=== The cover letter
+
+In addition to an email per patch, the Git community also expects your patches
+to come with a cover letter. This is an important component of change
+submission as it explains to the community from a high level what you're trying
+to do, and why, in a way that's more apparent than just looking at your
+patches.
+
+The title of your cover letter should be something which succinctly covers the
+purpose of your entire topic branch. It's often in the imperative mood, just
+like our commit message titles. Here is how we'll title our series:
+
+---
+Add the 'psuh' command
+---
+
+The body of the cover letter is used to give additional context to reviewers.
+Be sure to explain anything your patches don't make clear on their own, but
+remember that since the cover letter is not recorded in the commit history,
+anything that might be useful to future readers of the repository's history
+should also be in your commit messages.
+
+Here's an example body for `psuh`:
+
+----
+Our internal metrics indicate widespread interest in the command
+git-psuh - that is, many users are trying to use it, but finding it is
+unavailable, using some unknown workaround instead.
+
+The following handful of patches add the psuh command and implement some
+handy features on top of it.
+
+This patchset is part of the MyFirstContribution tutorial and should not
+be merged.
+----
+
+At this point the tutorial diverges, in order to demonstrate two
different methods of formatting your patchset and getting it reviewed.
The first method to be covered is GitGitGadget, which is useful for those
@@ -808,8 +899,22 @@ https://github.com/gitgitgadget/git and open a PR either with the "New pull
request" button or the convenient "Compare & pull request" button that may
appear with the name of your newly pushed branch.
-Review the PR's title and description, as it's used by GitGitGadget as the cover
-letter for your change. When you're happy, submit your pull request.
+Review the PR's title and description, as they're used by GitGitGadget
+respectively as the subject and body of the cover letter for your change. Refer
+to <<cover-letter,"The cover letter">> above for advice on how to title your
+submission and what content to include in the description.
+
+NOTE: For single-patch contributions, your commit message should already be
+meaningful and explain at a high level the purpose (what is happening and why)
+of your patch, so you usually do not need any additional context. In that case,
+remove the PR description that GitHub automatically generates from your commit
+message (your PR description should be empty). If you do need to supply even
+more context, you can do so in that space and it will be appended to the email
+that GitGitGadget will send, between the three-dash line and the diffstat
+(see <<single-patch,Bonus Chapter: One-Patch Changes>> for how this looks once
+submitted).
+
+When you're happy, submit your pull request.
[[run-ci-ggg]]
=== Running CI and Getting Ready to Send
@@ -952,49 +1057,29 @@ but want reviewers to look at what they have so far. You can add this flag with
Check and make sure that your patches and cover letter template exist in the
directory you specified - you're nearly ready to send out your review!
-[[cover-letter]]
+[[preparing-cover-letter]]
=== Preparing Email
-In addition to an email per patch, the Git community also expects your patches
-to come with a cover letter, typically with a subject line [PATCH 0/x] (where
-x is the number of patches you're sending). Since you invoked `format-patch`
-with `--cover-letter`, you've already got a template ready. Open it up in your
-favorite editor.
+Since you invoked `format-patch` with `--cover-letter`, you've already got a
+cover letter template ready. Open it up in your favorite editor.
You should see a number of headers present already. Check that your `From:`
-header is correct. Then modify your `Subject:` to something which succinctly
-covers the purpose of your entire topic branch, for example:
+header is correct. Then modify your `Subject:` (see <<cover-letter,above>> for
+how to choose good title for your patch series):
----
-Subject: [PATCH 0/7] adding the 'psuh' command
+Subject: [PATCH 0/7] Add the 'psuh' command
----
Make sure you retain the ``[PATCH 0/X]'' part; that's what indicates to the Git
-community that this email is the beginning of a review, and many reviewers
-filter their email for this type of flag.
+community that this email is the beginning of a patch series, and many
+reviewers filter their email for this type of flag.
You'll need to add some extra parameters when you invoke `git send-email` to add
the cover letter.
-Next you'll have to fill out the body of your cover letter. This is an important
-component of change submission as it explains to the community from a high level
-what you're trying to do, and why, in a way that's more apparent than just
-looking at your diff. Be sure to explain anything your diff doesn't make clear
-on its own.
-
-Here's an example body for `psuh`:
-
-----
-Our internal metrics indicate widespread interest in the command
-git-psuh - that is, many users are trying to use it, but finding it is
-unavailable, using some unknown workaround instead.
-
-The following handful of patches add the psuh command and implement some
-handy features on top of it.
-
-This patchset is part of the MyFirstContribution tutorial and should not
-be merged.
-----
+Next you'll have to fill out the body of your cover letter. Again, see
+<<cover-letter,above>> for what content to include.
The template created by `git format-patch --cover-letter` includes a diffstat.
This gives reviewers a summary of what they're in for when reviewing your topic.
diff --git a/Documentation/RelNotes/2.30.3.txt b/Documentation/RelNotes/2.30.3.txt
new file mode 100644
index 0000000..31b2a4d
--- /dev/null
+++ b/Documentation/RelNotes/2.30.3.txt
@@ -0,0 +1,24 @@
+Git v2.30.2 Release Notes
+=========================
+
+This release addresses the security issue CVE-2022-24765.
+
+Fixes since v2.30.2
+-------------------
+
+ * Build fix on Windows.
+
+ * Fix `GIT_CEILING_DIRECTORIES` with Windows-style root directories.
+
+ * CVE-2022-24765:
+ On multi-user machines, Git users might find themselves
+ unexpectedly in a Git worktree, e.g. when another user created a
+ repository in `C:\.git`, in a mounted network drive or in a
+ scratch space. Merely having a Git-aware prompt that runs `git
+ status` (or `git diff`) and navigating to a directory which is
+ supposedly not a Git worktree, or opening such a directory in an
+ editor or IDE such as VS Code or Atom, will potentially run
+ commands defined by that other user.
+
+Credit for finding this vulnerability goes to 俞晨东; The fix was
+authored by Johannes Schindelin.
diff --git a/Documentation/RelNotes/2.30.4.txt b/Documentation/RelNotes/2.30.4.txt
new file mode 100644
index 0000000..4eedb74
--- /dev/null
+++ b/Documentation/RelNotes/2.30.4.txt
@@ -0,0 +1,21 @@
+Git v2.30.4 Release Notes
+=========================
+
+This release contains minor fix-ups for the changes that went into
+Git 2.30.3, which was made to address CVE-2022-24765.
+
+ * The code that was meant to parse the new `safe.directory`
+ configuration variable was not checking what configuration
+ variable was being fed to it, which has been corrected.
+
+ * '*' can be used as the value for the `safe.directory` variable to
+ signal that the user considers that any directory is safe.
+
+
+
+Derrick Stolee (2):
+ t0033: add tests for safe.directory
+ setup: opt-out of check with safe.directory=*
+
+Matheus Valadares (1):
+ setup: fix safe.directory key not being checked
diff --git a/Documentation/RelNotes/2.30.5.txt b/Documentation/RelNotes/2.30.5.txt
new file mode 100644
index 0000000..5191cab
--- /dev/null
+++ b/Documentation/RelNotes/2.30.5.txt
@@ -0,0 +1,12 @@
+Git v2.30.5 Release Notes
+=========================
+
+This release contains minor fix-ups for the changes that went into
+Git 2.30.3 and 2.30.4, addressing CVE-2022-29187.
+
+ * The safety check that verifies a safe ownership of the Git
+ worktree is now extended to also cover the ownership of the Git
+ directory (and the `.git` file, if there is any).
+
+Carlo Marcelo Arenas Belón (1):
+ setup: tighten ownership checks post CVE-2022-24765
diff --git a/Documentation/RelNotes/2.31.2.txt b/Documentation/RelNotes/2.31.2.txt
new file mode 100644
index 0000000..aa13a5b
--- /dev/null
+++ b/Documentation/RelNotes/2.31.2.txt
@@ -0,0 +1,6 @@
+Git v2.31.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3 to address
+the security issue CVE-2022-24765; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.31.3.txt b/Documentation/RelNotes/2.31.3.txt
new file mode 100644
index 0000000..ca143ab
--- /dev/null
+++ b/Documentation/RelNotes/2.31.3.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.31.3.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.31.3.
diff --git a/Documentation/RelNotes/2.31.4.txt b/Documentation/RelNotes/2.31.4.txt
new file mode 100644
index 0000000..97a91fd
--- /dev/null
+++ b/Documentation/RelNotes/2.31.4.txt
@@ -0,0 +1,6 @@
+Git v2.31.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5 to address
+the security issue CVE-2022-29187; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.32.1.txt b/Documentation/RelNotes/2.32.1.txt
new file mode 100644
index 0000000..7dcca13
--- /dev/null
+++ b/Documentation/RelNotes/2.32.1.txt
@@ -0,0 +1,6 @@
+Git v2.32.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3 and
+v2.31.2 to address the security issue CVE-2022-24765; see the
+release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.32.2.txt b/Documentation/RelNotes/2.32.2.txt
new file mode 100644
index 0000000..cf49695
--- /dev/null
+++ b/Documentation/RelNotes/2.32.2.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.32.2.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.32.2.
diff --git a/Documentation/RelNotes/2.32.3.txt b/Documentation/RelNotes/2.32.3.txt
new file mode 100644
index 0000000..583fabe
--- /dev/null
+++ b/Documentation/RelNotes/2.32.3.txt
@@ -0,0 +1,6 @@
+Git v2.32.3 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5 and
+v2.31.4 to address the security issue CVE-2022-29187; see the
+release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.33.2.txt b/Documentation/RelNotes/2.33.2.txt
new file mode 100644
index 0000000..e504489
--- /dev/null
+++ b/Documentation/RelNotes/2.33.2.txt
@@ -0,0 +1,15 @@
+Git v2.33.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3, v2.31.2
+and v2.32.1 to address the security issue CVE-2022-24765; see
+the release notes for these versions for details.
+
+In addition, it contains the following fixes:
+
+ * Squelch over-eager warning message added during this cycle.
+
+ * A bug in "git rebase -r" has been fixed.
+
+ * One CI task based on Fedora image noticed a not-quite-kosher
+ construct recently, which has been corrected.
diff --git a/Documentation/RelNotes/2.33.3.txt b/Documentation/RelNotes/2.33.3.txt
new file mode 100644
index 0000000..e2bada1
--- /dev/null
+++ b/Documentation/RelNotes/2.33.3.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.33.3.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.33.3.
diff --git a/Documentation/RelNotes/2.33.4.txt b/Documentation/RelNotes/2.33.4.txt
new file mode 100644
index 0000000..a145cc2
--- /dev/null
+++ b/Documentation/RelNotes/2.33.4.txt
@@ -0,0 +1,6 @@
+Git v2.33.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5, v2.31.4
+and v2.32.3 to address the security issue CVE-2022-29187; see
+the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.34.2.txt b/Documentation/RelNotes/2.34.2.txt
new file mode 100644
index 0000000..0c32cd8
--- /dev/null
+++ b/Documentation/RelNotes/2.34.2.txt
@@ -0,0 +1,6 @@
+Git v2.34.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3, v2.31.2,
+v2.32.1 and v2.33.2 to address the security issue CVE-2022-24765;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.34.3.txt b/Documentation/RelNotes/2.34.3.txt
new file mode 100644
index 0000000..10f6171
--- /dev/null
+++ b/Documentation/RelNotes/2.34.3.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.34.3.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.34.3.
diff --git a/Documentation/RelNotes/2.34.4.txt b/Documentation/RelNotes/2.34.4.txt
new file mode 100644
index 0000000..2a6b223
--- /dev/null
+++ b/Documentation/RelNotes/2.34.4.txt
@@ -0,0 +1,6 @@
+Git v2.34.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5, v2.31.4,
+v2.32.3 and v2.33.4 to address the security issue CVE-2022-29187;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.35.2.txt b/Documentation/RelNotes/2.35.2.txt
new file mode 100644
index 0000000..290bfa9
--- /dev/null
+++ b/Documentation/RelNotes/2.35.2.txt
@@ -0,0 +1,7 @@
+Git v2.35.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3,
+v2.31.2, v2.32.1, v2.33.2 and v2.34.2 to address the security
+issue CVE-2022-24765; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.35.3.txt b/Documentation/RelNotes/2.35.3.txt
new file mode 100644
index 0000000..5458ba3
--- /dev/null
+++ b/Documentation/RelNotes/2.35.3.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.35.3.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.35.3.
diff --git a/Documentation/RelNotes/2.35.4.txt b/Documentation/RelNotes/2.35.4.txt
new file mode 100644
index 0000000..47abd5a
--- /dev/null
+++ b/Documentation/RelNotes/2.35.4.txt
@@ -0,0 +1,7 @@
+Git v2.35.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5,
+v2.31.4, v2.32.3, v2.33.4 and v2.34.4 to address the security
+issue CVE-2022-29187; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.36.0.txt b/Documentation/RelNotes/2.36.0.txt
index 721b5d2..e477fba 100644
--- a/Documentation/RelNotes/2.36.0.txt
+++ b/Documentation/RelNotes/2.36.0.txt
@@ -13,6 +13,15 @@ Backward compatibility warts
top-level a partial clone, while submodules are fully cloned. This
behaviour is changed to pass the same filter down to the submodules.
+ * With the fixes for CVE-2022-24765 that are common with versions of
+ Git 2.30.4, 2.31.3, 2.32.2, 2.33.3, 2.34.3, and 2.35.3, Git has
+ been taught not to recognise repositories owned by other users, in
+ order to avoid getting affected by their config files and hooks.
+ You can list the path to the safe/trusted repositories that may be
+ owned by others on a multi-valued configuration variable
+ `safe.directory` to override this behaviour, or use '*' to declare
+ that you trust anything.
+
Note to those who build from the source
@@ -46,10 +55,10 @@ UI, Workflows & Features
* "git branch" learned the "--recurse-submodules" option.
- * A not-so-common mistake is to write a script to feed "git bisect
- run" without making it executable, in which case all tests will
- exit with 126 or 127 error codes, even on revisions that are marked
- as good. Try to recognize this situation and stop iteration early.
+ * A user can forget to make a script file executable before giving
+ it to "git bisect run". In such a case, all tests will exit with
+ 126 or 127 error codes, even on revisions that are marked as good.
+ Try to recognize this situation and stop iteration early.
* When "index-pack" dies due to incoming data exceeding the maximum
allowed input size, include the value of the limit in the error
@@ -84,6 +93,24 @@ UI, Workflows & Features
age-old "update-server-info" command, which is rarely useful these
days.
+ * "git stash" does not allow subcommands it internally runs as its
+ implementation detail, except for "git reset", to emit messages;
+ now "git reset" part has also been squelched.
+
+ * "git ls-tree" learns "--oid-only" option, similar to "--name-only",
+ and more generalized "--format" option.
+
+ * "git fetch --refetch" learned to fetch everything without telling
+ the other side what we already have, which is useful when you
+ cannot trust what you have in the local object store.
+
+ * "git branch" gives hint when branch tracking cannot be established
+ because fetch refspecs from multiple remote repositories overlap.
+
+ * "git worktree list --porcelain" did not c-quote pathnames and lock
+ reasons with unsafe bytes correctly, which is worked around by
+ introducing NUL terminated output format with "-z".
+
Performance, Internal Implementation, Development Support etc.
@@ -158,6 +185,9 @@ Performance, Internal Implementation, Development Support etc.
* Updates to refs traditionally weren't fsync'ed, but we can
configure using core.fsync variable to do so.
+ * "git reflog" command now uses parse-options API to parse its
+ command line options.
+
Fixes since v2.35
-----------------
@@ -268,12 +298,6 @@ Fixes since v2.35
future "gc" needs to clean up.
(merge 5407764069 cb/clear-quarantine-early-on-all-ref-update-errors later to maint).
- * Because a deletion of ref would need to remove it from both the
- loose ref store and the packed ref store, a delete-ref operation
- that logically removes one ref may end up invoking ref-transaction
- hook twice, which has been corrected.
- (merge 2ed1b64ebd ps/avoid-unnecessary-hook-invocation-with-packed-refs later to maint).
-
* When there is no object to write .bitmap file for, "git
multi-pack-index" triggered an error, instead of just skipping,
which has been corrected.
@@ -321,10 +345,6 @@ Fixes since v2.35
recorded the last level component of the branch name, which has
been corrected.
- * "git fetch" can make two separate fetches, but ref updates coming
- from them were in two separate ref transactions under "--atomic",
- which has been corrected.
-
* Check the return value from parse_tree_indirect() to turn segfaults
into calls to die().
(merge 8d2eaf649a gc/parse-tree-indirect-errors later to maint).
@@ -356,6 +376,26 @@ Fixes since v2.35
in the current checkout of the superproject. We now do so for all
submodules that have been run "git submodule init" on.
+ * "git rebase $base $non_branch_commit", when $base is an ancestor or
+ the $non_branch_commit, modified the current branch, which has been
+ corrected.
+
+ * When "shallow" information is updated, we forgot to update the
+ in-core equivalent, which has been corrected.
+
+ * When creating a loose object file, we didn't report the exact
+ filename of the file we failed to fsync, even though the
+ information was readily available, which has been corrected.
+
+ * "git am" can read from the standard input when no mailbox is given
+ on the command line, but the end-user gets no indication when it
+ happens, making Git appear stuck.
+ (merge 7b20af6a06 jc/mailsplit-warn-on-tty later to maint).
+
+ * "git mv" failed to refresh the cached stat information for the
+ entry it moved.
+ (merge b7f9130a06 vd/mv-refresh-stat later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge cfc5cf428b jc/find-header later to maint).
(merge 40e7cfdd46 jh/p4-fix-use-of-process-error-exception later to maint).
@@ -385,3 +425,5 @@ Fixes since v2.35
(merge c614beb933 ep/t6423-modernize later to maint).
(merge 57be9c6dee ab/reflog-prep-fix later to maint).
(merge 5327d8982a js/in-place-reverse-in-sequencer later to maint).
+ (merge 2e2c0be51e dp/worktree-repair-in-usage later to maint).
+ (merge 6563706568 jc/coding-guidelines-decl-in-for-loop later to maint).
diff --git a/Documentation/RelNotes/2.36.1.txt b/Documentation/RelNotes/2.36.1.txt
new file mode 100644
index 0000000..a961709
--- /dev/null
+++ b/Documentation/RelNotes/2.36.1.txt
@@ -0,0 +1,33 @@
+Git v2.36.1 Release Notes
+=========================
+
+Fixes since v2.36
+-----------------
+
+ * "git submodule update" without pathspec should silently skip an
+ uninitialized submodule, but it started to become noisy by mistake.
+
+ * "diff-tree --stdin" has been broken for about a year, but 2.36
+ release broke it even worse by breaking running the command with
+ <pathspec>, which in turn broke "gitk" and got noticed. This has
+ been corrected by aligning its behaviour to that of "log".
+
+ * Regression fix for 2.36 where "git name-rev" started to sometimes
+ reference strings after they are freed.
+
+ * "git show <commit1> <commit2>... -- <pathspec>" lost the pathspec
+ when showing the second and subsequent commits, which has been
+ corrected.
+
+ * "git fast-export -- <pathspec>" lost the pathspec when showing the
+ second and subsequent commits, which has been corrected.
+
+ * "git format-patch <args> -- <pathspec>" lost the pathspec when
+ showing the second and subsequent commits, which has been
+ corrected.
+
+ * Get rid of a bogus and over-eager coccinelle rule.
+
+ * Correct choices of C compilers used in various CI jobs.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.36.2.txt b/Documentation/RelNotes/2.36.2.txt
new file mode 100644
index 0000000..958f5b4
--- /dev/null
+++ b/Documentation/RelNotes/2.36.2.txt
@@ -0,0 +1,56 @@
+Git v2.36.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5, v2.31.4,
+v2.32.3, v2.33.4, v2.34.4 and v2.35.4 to address the security
+issue CVE-2022-29187; see the release notes for these versions
+for details.
+
+Apart from that, this maintenance release is primarily to merge down
+updates to the build and CI procedures from the 'master' front, in
+order to ensure that we can cut healthy maintenance releases in the
+future. It also contains a handful of small and trivially-correct
+bugfixes.
+
+Fixes since v2.36.1
+-------------------
+
+ * Fixes real problems noticed by gcc 12 and works around false
+ positives.
+
+ * Update URL to the gitk repository.
+
+ * The "--current" option of "git show-branch" should have been made
+ incompatible with the "--reflog" mode, but this was not enforced,
+ which has been corrected.
+
+ * "git archive --add-file=<path>" picked up the raw permission bits
+ from the path and propagated to zip output in some cases, without
+ normalization, which has been corrected (tar output did not have
+ this issue).
+
+ * A bit of test framework fixes with a few fixes to issues found by
+ valgrind.
+
+ * macOS CI jobs have been occasionally flaky due to tentative version
+ skew between perforce and the homebrew packager. Instead of
+ failing the whole CI job, just let it skip the p4 tests when this
+ happens.
+
+ * The commit summary shown after making a commit is matched to what
+ is given in "git status" not to use the break-rewrite heuristics.
+
+ * Avoid problems from interaction between malloc_check and address
+ sanitizer.
+
+ * "git rebase --keep-base <upstream> <branch-to-rebase>" computed the
+ commit to rebase onto incorrectly, which has been corrected.
+
+ * The path taken by "git multi-pack-index" command from the end user
+ was compared with path internally prepared by the tool withut first
+ normalizing, which lead to duplicated paths not being noticed,
+ which has been corrected.
+
+ * "git clone --origin X" leaked piece of memory that held value read
+ from the clone.defaultRemoteName configuration variable, which has
+ been plugged.
diff --git a/Documentation/RelNotes/2.37.0.txt b/Documentation/RelNotes/2.37.0.txt
new file mode 100644
index 0000000..99dc7e3
--- /dev/null
+++ b/Documentation/RelNotes/2.37.0.txt
@@ -0,0 +1,337 @@
+Git v2.37 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "vimdiff[123]" mergetool drivers have been reimplemented with a
+ more generic layout mechanism.
+
+ * "git -v" and "git -h" are now understood as "git --version" and
+ "git --help".
+
+ * The temporary files fed to external diff command are now generated
+ inside a new temporary directory under the same basename.
+
+ * "git log --since=X" will stop traversal upon seeing a commit that
+ is older than X, but there may be commits behind it that is younger
+ than X when the commit was created with a faulty clock. A new
+ option is added to keep digging without stopping, and instead
+ filter out commits with timestamp older than X.
+
+ * "git -c branch.autosetupmerge=simple branch $A $B" will set the $B
+ as $A's upstream only when $A and $B shares the same name, and "git
+ -c push.default=simple" on branch $A would push to update the
+ branch $A at the remote $B came from. Also more places use the
+ sole remote, if exists, before defaulting to 'origin'.
+
+ * A new doc has been added that lists tips for tools to work with
+ Git's codebase.
+
+ * "git remote -v" now shows the list-objects-filter used during
+ fetching from the remote, if available.
+
+ * With the new http.curloptResolve configuration, the CURLOPT_RESOLVE
+ mechanism that allows cURL based applications to use pre-resolved
+ IP addresses for the requests is exposed to the scripts.
+
+ * "git add -i" was rewritten in C some time ago and has been in
+ testing; the reimplementation is now exposed to general public by
+ default.
+
+ * Deprecate non-cone mode of the sparse-checkout feature.
+
+ * Introduce a filesystem-dependent mechanism to optimize the way the
+ bits for many loose object files are ensured to hit the disk
+ platter.
+
+ * The "do not remove the directory the user started Git in" logic,
+ when Git cannot tell where that directory is, is disabled. Earlier
+ we refused to run in such a case.
+
+ * A mechanism to pack unreachable objects into a "cruft pack",
+ instead of ejecting them into loose form to be reclaimed later, has
+ been introduced.
+
+ * Update the doctype written in gitweb output to xhtml5.
+
+ * The "transfer.credentialsInURL" configuration variable controls what
+ happens when a URL with embedded login credential is used on either
+ "fetch" or "push". Credentials are currently only detected in
+ `remote.<name>.url` config, not `remote.<name>.pushurl`.
+
+ * "git revert" learns "--reference" option to use more human-readable
+ reference to the commit it reverts in the message template it
+ prepares for the user.
+
+ * Various error messages that talk about the removal of
+ "--preserve-merges" in "rebase" have been strengthened, and "rebase
+ --abort" learned to get out of a state that was left by an earlier
+ use of the option.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The performance of the "untracked cache" feature has been improved
+ when "--untracked-files=<mode>" and "status.showUntrackedFiles"
+ are combined.
+
+ * "git stash" works better with sparse index entries.
+
+ * "git show :<path>" learned to work better with the sparse-index
+ feature.
+
+ * Introduce and apply coccinelle rule to discourage an explicit
+ comparison between a pointer and NULL, and applies the clean-up to
+ the maintenance track.
+
+ * Preliminary code refactoring around transport and bundle code.
+
+ * "sparse-checkout" learns to work better with the sparse-index
+ feature.
+
+ * A workflow change for translators are being proposed. git.pot is
+ no longer version controlled and it is local responsibility of
+ translators to generate it.
+
+ * Plug the memory leaks from the trickiest API of all, the revision
+ walker.
+
+ * Rename .env_array member to .env in the child_process structure.
+
+ * The fsmonitor--daemon handles even more corner cases when
+ watching filesystem events.
+
+ * A new bug() and BUG_if_bug() API is introduced to make it easier to
+ uniformly log "detect multiple bugs and abort in the end" pattern.
+
+
+Fixes since v2.36
+-----------------
+
+ * "git submodule update" without pathspec should silently skip an
+ uninitialized submodule, but it started to become noisy by mistake.
+ (merge 4f1ccef87c gc/submodule-update-part2 later to maint).
+
+ * "diff-tree --stdin" has been broken for about a year, but 2.36
+ release broke it even worse by breaking running the command with
+ <pathspec>, which in turn broke "gitk" and got noticed. This has
+ been corrected by aligning its behaviour to that of "log".
+ (merge f8781bfda3 jc/diff-tree-stdin-fix later to maint).
+
+ * Regression fix for 2.36 where "git name-rev" started to sometimes
+ reference strings after they are freed.
+ (merge 45a14f578e rs/name-rev-fix-free-after-use later to maint).
+
+ * "git show <commit1> <commit2>... -- <pathspec>" lost the pathspec
+ when showing the second and subsequent commits, which has been
+ corrected.
+ (merge 5cdb38458e jc/show-pathspec-fix later to maint).
+
+ * "git fast-export -- <pathspec>" lost the pathspec when showing the
+ second and subsequent commits, which has been corrected.
+ (merge d1c25272f5 rs/fast-export-pathspec-fix later to maint).
+
+ * "git format-patch <args> -- <pathspec>" lost the pathspec when
+ showing the second and subsequent commits, which has been
+ corrected.
+ (merge 91f8f7e46f rs/format-patch-pathspec-fix later to maint).
+
+ * "git clone --origin X" leaked piece of memory that held value read
+ from the clone.defaultRemoteName configuration variable, which has
+ been plugged.
+ (merge 6dfadc8981 jc/clone-remote-name-leak-fix later to maint).
+
+ * Get rid of a bogus and over-eager coccinelle rule.
+ (merge 08bdd3a185 jc/cocci-xstrdup-or-null-fix later to maint).
+
+ * The path taken by "git multi-pack-index" command from the end user
+ was compared with path internally prepared by the tool without first
+ normalizing, which lead to duplicated paths not being noticed,
+ which has been corrected.
+ (merge 11f9e8de3d ds/midx-normalize-pathname-before-comparison later to maint).
+
+ * Correct choices of C compilers used in various CI jobs.
+ (merge 3506cae04f ab/cc-package-fixes later to maint).
+
+ * Various cleanups to "git p4".
+ (merge 4ff0108d9e jh/p4-various-fixups later to maint).
+
+ * The progress meter of "git blame" was showing incorrect numbers
+ when processing only parts of the file.
+ (merge e5f5d7d42e ea/progress-partial-blame later to maint).
+
+ * "git rebase --keep-base <upstream> <branch-to-rebase>" computed the
+ commit to rebase onto incorrectly, which has been corrected.
+ (merge 9e5ebe9668 ah/rebase-keep-base-fix later to maint).
+
+ * Fix a leak of FILE * in an error codepath.
+ (merge c0befa0c03 kt/commit-graph-plug-fp-leak-on-error later to maint).
+
+ * Avoid problems from interaction between malloc_check and address
+ sanitizer.
+ (merge 067109a5e7 pw/test-malloc-with-sanitize-address later to maint).
+
+ * The commit summary shown after making a commit is matched to what
+ is given in "git status" not to use the break-rewrite heuristics.
+ (merge 84792322ed rs/commit-summary-wo-break-rewrite later to maint).
+
+ * Update a few end-user facing messages around EOL conversion.
+ (merge c970d30c2c ah/convert-warning-message later to maint).
+
+ * Trace2 documentation updates.
+ (merge a6c80c313c js/trace2-doc-fixes later to maint).
+
+ * Build procedure fixup.
+ (merge 1fbfd96f50 mg/detect-compiler-in-c-locale later to maint).
+
+ * "git pull" without "--recurse-submodules=<arg>" made
+ submodule.recurse take precedence over fetch.recurseSubmodules by
+ mistake, which has been corrected.
+ (merge 5819417365 gc/pull-recurse-submodules later to maint).
+
+ * "git bisect" was too silent before it is ready to start computing
+ the actual bisection, which has been corrected.
+ (merge f11046e6de cd/bisect-messages-from-pre-flight-states later to maint).
+
+ * macOS CI jobs have been occasionally flaky due to tentative version
+ skew between perforce and the homebrew packager. Instead of
+ failing the whole CI job, just let it skip the p4 tests when this
+ happens.
+ (merge f15e00b463 cb/ci-make-p4-optional later to maint).
+
+ * A bit of test framework fixes with a few fixes to issues found by
+ valgrind.
+ (merge 7c898554d7 ab/valgrind-fixes later to maint).
+
+ * "git archive --add-file=<path>" picked up the raw permission bits
+ from the path and propagated to zip output in some cases, without
+ normalization, which has been corrected (tar output did not have
+ this issue).
+ (merge 6a61661967 jc/archive-add-file-normalize-mode later to maint).
+
+ * "make coverage-report" without first running "make coverage" did
+ not produce any meaningful result, which has been corrected.
+ (merge 96ddfecc5b ep/coverage-report-wants-test-to-have-run later to maint).
+
+ * The "--current" option of "git show-branch" should have been made
+ incompatible with the "--reflog" mode, but this was not enforced,
+ which has been corrected.
+ (merge 41c64ae0e7 jc/show-branch-g-current later to maint).
+
+ * "git fetch" unnecessarily failed when an unexpected optional
+ section appeared in the output, which has been corrected.
+ (merge 7709acf7be jt/fetch-peek-optional-section later to maint).
+
+ * The way "git fetch" without "--update-head-ok" ensures that HEAD in
+ no worktree points at any ref being updated was too wasteful, which
+ has been optimized a bit.
+ (merge f7400da800 os/fetch-check-not-current-branch later to maint).
+
+ * "git fetch --recurse-submodules" from multiple remotes (either from
+ a remote group, or "--all") used to make one extra "git fetch" in
+ the submodules, which has been corrected.
+ (merge 0353c68818 jc/avoid-redundant-submodule-fetch later to maint).
+
+ * With a recent update to refuse access to repositories of other
+ people by default, "sudo make install" and "sudo git describe"
+ stopped working, which has been corrected.
+ (merge 6b11e3d52e cb/path-owner-check-with-sudo-plus later to maint).
+
+ * The tests that ensured merges stop when interfering local changes
+ are present did not make sure that local changes are preserved; now
+ they do.
+ (merge 4b317450ce jc/t6424-failing-merge-preserve-local-changes later to maint).
+
+ * Some real problems noticed by gcc 12 have been fixed, while false
+ positives have been worked around.
+
+ * Update the version of FreeBSD image used in Cirrus CI.
+ (merge c58bebd4c6 pb/use-freebsd-12.3-in-cirrus-ci later to maint).
+
+ * The multi-pack-index code did not protect the packfile it is going
+ to depend on from getting removed while in use, which has been
+ corrected.
+ (merge 4090511e40 tb/midx-race-in-pack-objects later to maint).
+
+ * Teach "git repack --geometric" work better with "--keep-pack" and
+ avoid corrupting the repository when packsize limit is used.
+ (merge 66731ff921 tb/geom-repack-with-keep-and-max later to maint).
+
+ * The documentation on the interaction between "--add-file" and
+ "--prefix" options of "git archive" has been improved.
+ (merge a75910602a rs/document-archive-prefix later to maint).
+
+ * A git subcommand like "git add -p" spawns a separate git process
+ while relaying its command line arguments. A pathspec with only
+ negative elements was mistakenly passed with an empty string, which
+ has been corrected.
+ (merge b02fdbc80a jc/all-negative-pathspec later to maint).
+
+ * With a more targeted workaround in http.c in another topic, we may
+ be able to lift this blanket "GCC12 dangling-pointer warning is
+ broken and unsalvageable" workaround.
+ (merge 419141e495 cb/buggy-gcc-12-workaround later to maint).
+
+ * A misconfigured 'branch..remote' led to a bug in configuration
+ parsing.
+ (merge f1dfbd9ee0 gc/zero-length-branch-config-fix later to maint).
+
+ * "git -c diff.submodule=log range-diff" did not show anything for
+ submodules that changed in the ranges being compared, and
+ "git -c diff.submodule=diff range-diff" did not work correctly.
+ Fix this by including the "--submodule=short" output
+ unconditionally to be compared.
+
+ * In Git 2.36 we revamped the way how hooks are invoked. One change
+ that is end-user visible is that the output of a hook is no longer
+ directly connected to the standard output of "git" that spawns the
+ hook, which was noticed post release. This is getting corrected.
+ (merge a082345372 ab/hooks-regression-fix later to maint).
+
+ * Updating the graft information invalidates the list of parents of
+ in-core commit objects that used to be in the graft file.
+
+ * "git show-ref --heads" (and "--tags") still iterated over all the
+ refs only to discard refs outside the specified area, which has
+ been corrected.
+ (merge c0c9d35e27 tb/show-ref-optim later to maint).
+
+ * Remove redundant copying (with index v3 and older) or possible
+ over-reading beyond end of mmapped memory (with index v4) has been
+ corrected.
+ (merge 6d858341d2 zh/read-cache-copy-name-entry-fix later to maint).
+
+ * Sample watchman interface hook sometimes failed to produce
+ correctly formatted JSON message, which has been corrected.
+ (merge 134047b500 sn/fsmonitor-missing-clock later to maint).
+
+ * Use-after-free (with another forget-to-free) fix.
+ (merge 323822c72b ab/remote-free-fix later to maint).
+
+ * Remove a coccinelle rule that is no longer relevant.
+ (merge b1299de4a1 jc/cocci-cleanup later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge e6b2582da3 cm/reftable-0-length-memset later to maint).
+ (merge 0b75e5bf22 ab/misc-cleanup later to maint).
+ (merge 52e1ab8a76 ea/rebase-code-simplify later to maint).
+ (merge 756d15923b sg/safe-directory-tests-and-docs later to maint).
+ (merge d097a23bfa ds/do-not-call-bug-on-bad-refs later to maint).
+ (merge c36c27e75c rs/t7812-pcre2-ws-bug-test later to maint).
+ (merge 1da312742d gf/unused-includes later to maint).
+ (merge 465b30a92d pb/submodule-recurse-mode-enum later to maint).
+ (merge 82b28c4ed8 km/t3501-use-test-helpers later to maint).
+ (merge 72315e431b sa/t1011-use-helpers later to maint).
+ (merge 95b3002201 cg/vscode-with-gdb later to maint).
+ (merge fbe5f6b804 tk/p4-utf8-bom later to maint).
+ (merge 17f273ffba tk/p4-with-explicity-sync later to maint).
+ (merge 944db25c60 kf/p4-multiple-remotes later to maint).
+ (merge b014cee8de jc/update-ozlabs-url later to maint).
+ (merge 4ec5008062 pb/ggg-in-mfc-doc later to maint).
+ (merge af845a604d tb/receive-pack-code-cleanup later to maint).
+ (merge 2acf4cf001 js/ci-gcc-12-fixes later to maint).
+ (merge 05e280c0a6 jc/http-clear-finished-pointer later to maint).
+ (merge 8c49d704ef fh/transport-push-leakfix later to maint).
+ (merge 1d232d38bd tl/ls-tree-oid-only later to maint).
+ (merge db7961e6a6 gc/document-config-worktree-scope later to maint).
+ (merge ce18a30bb7 fs/ssh-default-key-command-doc later to maint).
diff --git a/Documentation/RelNotes/2.37.1.txt b/Documentation/RelNotes/2.37.1.txt
new file mode 100644
index 0000000..8460932
--- /dev/null
+++ b/Documentation/RelNotes/2.37.1.txt
@@ -0,0 +1,17 @@
+Git 2.37.1 Release Notes
+========================
+
+This release merges up the fixes that appear in v2.30.5, v2.31.4,
+v2.32.3, v2.33.4, v2.34.4, v2.35.4, and v2.36.2 to address the
+security issue CVE-2022-29187; see the release notes for these
+versions for details.
+
+Fixes since Git 2.37
+--------------------
+
+ * Rewrite of "git add -i" in C that appeared in Git 2.25 didn't
+ correctly record a removed file to the index, which is an old
+ regression but has become widely known because the C version has
+ become the default in the latest release.
+
+ * Fix for CVS-2022-29187.
diff --git a/Documentation/RelNotes/2.37.2.txt b/Documentation/RelNotes/2.37.2.txt
new file mode 100644
index 0000000..d4acf9e
--- /dev/null
+++ b/Documentation/RelNotes/2.37.2.txt
@@ -0,0 +1,47 @@
+Git 2.37.2 Release Notes
+========================
+
+This primarily is to backport various fixes accumulated on the 'master'
+front since 2.37.1.
+
+Fixes since v2.37.1
+-------------------
+
+ * "git shortlog -n" relied on the underlying qsort() to be stable,
+ which shouldn't have. Fixed.
+
+ * Variable quoting fix in the vimdiff driver of "git mergetool".
+
+ * An earlier attempt to plug leaks placed a clean-up label to jump to
+ at a bogus place, which as been corrected.
+
+ * Fixes a long-standing corner case bug around directory renames in
+ the merge-ort strategy.
+
+ * Recent update to vimdiff layout code has been made more robust
+ against different end-user vim settings.
+
+ * In a non-bare repository, the behavior of Git when the
+ core.worktree configuration variable points at a directory that has
+ a repository as its subdirectory, regressed in Git 2.27 days.
+
+ * References to commands-to-be-typed-literally in "git rebase"
+ documentation mark-up have been corrected.
+
+ * Give _() markings to fatal/warning/usage: labels that are shown in
+ front of these messages.
+
+ * "git mktree --missing" lazily fetched objects that are missing from
+ the local object store, which was totally unnecessary for the purpose
+ of creating the tree object(s) from its input.
+
+ * Fixes for tests when the source directory has unusual characters in
+ its path, e.g. whitespaces, double-quotes, etc.
+
+ * Adjust technical/bitmap-format to be formatted by AsciiDoc, and
+ add some missing information to the documentation.
+
+ * Certain diff options are currently ignored when combined-diff is
+ shown; mark them as incompatible with the feature.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.38.0.txt b/Documentation/RelNotes/2.38.0.txt
new file mode 100644
index 0000000..66e278b
--- /dev/null
+++ b/Documentation/RelNotes/2.38.0.txt
@@ -0,0 +1,191 @@
+Git v2.38 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "git remote show [-n] frotz" now pays attention to negative
+ pathspec.
+
+ * "git push" sometimes perform poorly when reachability bitmaps are
+ used, even in a repository where other operations are helped by
+ bitmaps. The push.useBitmaps configuration variable is introduced
+ to allow disabling use of reachability bitmaps only for "git push".
+
+ * "git grep -m<max-hits>" is a way to limit the hits shown per file.
+
+ * "git merge-tree" learned a new mode where it takes two commits and
+ computes a tree that would result in the merge commit, if the
+ histories leading to these two commits were to be merged.
+
+ * "git mv A B" in a sparsely populated working tree can be asked to
+ move a path between directories that are "in cone" (i.e. expected
+ to be materialized in the working tree) and "out of cone"
+ (i.e. expected to be hidden). The handling of such cases has been
+ improved.
+
+ * Earlier, HTTP transport clients learned to tell the server side
+ what locale they are in by sending Accept-Language HTTP header, but
+ this was done only for some requests but not others.
+
+ * Introduce a discovery.barerepository configuration variable that
+ allows users to forbid discovery of bare repositories.
+
+ * Various messages that come from the pack-bitmap codepaths have been
+ tweaked.
+
+ * "git rebase -i" learns to update branches whose tip appear in the
+ rebased range with "--update-refs" option.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Collection of what is referenced by objects in promisor packs have
+ been optimized to inspect these objects in the in-pack order.
+
+ * Introduce a helper to see if a branch is already being worked on
+ (hence should not be newly checked out in a working tree), which
+ performs much better than the existing find_shared_symref() to
+ replace many uses of the latter.
+
+ * Teach "git archive" to (optionally and then by default) avoid
+ spawning an external "gzip" process when creating ".tar.gz" (and
+ ".tgz") archives.
+
+ * Allow large objects read from a packstream to be streamed into a
+ loose object file straight, without having to keep it in-core as a
+ whole.
+
+ * Further preparation to turn git-submodule.sh into a builtin
+ continues.
+
+ * Apply Coccinelle rule to turn raw memmove() into MOVE_ARRAY() cpp
+ macro, which would improve maintainability and readability.
+
+ * Teach "make all" to build gitweb as well.
+
+ * Tweak tests so that they still work when the "git init" template
+ did not create .git/info directory.
+
+ * Add Coccinelle rules to detect the pattern of initializing and then
+ finalizing a structure without using it in between at all, which
+ happens after code restructuring and the compilers fail to
+ recognize as an unused variable.
+
+ * The code to convert between GPG trust level strings and internal
+ constants we use to represent them have been cleaned up.
+
+ * Support for libnettle as SHA256 implementation has been added.
+
+ * The way "git multi-pack" uses parse-options API has been improved.
+
+ * A coccinelle rule (in contrib/) to encourage use of COPY_ARRAY
+ macro has been improved.
+
+ * API tweak to make it easier to run fuzz testing on commit-graph parser.
+
+ * Omit fsync-related trace2 entries when their values are all zero.
+
+
+Fixes since v2.37
+-----------------
+
+ * Rewrite of "git add -i" in C that appeared in Git 2.25 didn't
+ correctly record a removed file to the index, which was fixed.
+
+ * Certain diff options are currently ignored when combined-diff is
+ shown; mark them as incompatible with the feature.
+
+ * Adjust technical/bitmap-format to be formatted by AsciiDoc, and
+ add some missing information to the documentation.
+
+ * Fixes for tests when the source directory has unusual characters in
+ its path, e.g. whitespaces, double-quotes, etc.
+
+ * "git mktree --missing" lazily fetched objects that are missing from
+ the local object store, which was totally unnecessary for the purpose
+ of creating the tree object(s) from its input.
+
+ * Give _() markings to fatal/warning/usage: labels that are shown in
+ front of these messages.
+
+ * References to commands-to-be-typed-literally in "git rebase"
+ documentation mark-up have been corrected.
+
+ * In a non-bare repository, the behavior of Git when the
+ core.worktree configuration variable points at a directory that has
+ a repository as its subdirectory, regressed in Git 2.27 days.
+
+ * Recent update to vimdiff layout code has been made more robust
+ against different end-user vim settings.
+
+ * Plug various memory leaks.
+ (merge ece3974ba6 ab/leakfix later to maint).
+
+ * Plug various memory leaks in test-tool commands.
+ (merge f40a693450 ab/test-tool-leakfix later to maint).
+
+ * Fixes a long-standing corner case bug around directory renames in
+ the merge-ort strategy.
+
+ * The resolve-undo information in the index was not protected against
+ GC, which has been corrected.
+ (merge e0ad13977a jc/resolve-undo later to maint).
+
+ * A corner case bug where lazily fetching objects from a promisor
+ remote resulted in infinite recursion has been corrected.
+ (merge cb88b37cb9 hx/lookup-commit-in-graph-fix later to maint).
+
+ * "git clone" from a repository with some ref whose HEAD is unborn
+ did not set the HEAD in the resulting repository correctly, which
+ has been corrected.
+ (merge daf7898abb jk/clone-unborn-confusion later to maint).
+
+ * An earlier attempt to plug leaks placed a clean-up label to jump to
+ at a bogus place, which as been corrected.
+
+ * Variable quoting fix in the vimdiff driver of "git mergetool"
+
+ * "git shortlog -n" relied on the underlying qsort() to be stable,
+ which shouldn't have. Fixed.
+
+ * A fix for a regression in test framework.
+
+ * mkstemp() emulation on Windows has been improved.
+ (merge ae25974de3 rs/mingw-tighten-mkstemp later to maint).
+
+ * Add missing documentation for "include" and "includeIf" features in
+ "git config" file format, which incidentally teaches the command
+ line completion to include them in its offerings.
+ (merge 07aed58017 mb/config-document-include later to maint).
+
+ * Avoid "white/black-list" in documentation and code comments.
+ (merge f5adaa5cc3 ds/doc-wo-whitelist later to maint).
+
+ * Workaround for a compiler warning against use of die() in
+ osx-keychain (in contrib/).
+ (merge f2fc531585 ld/osx-keychain-usage-fix later to maint).
+
+ * Workaround for a false positive compiler warning.
+ (merge b4f52f09ae ds/win-syslog-compiler-fix later to maint).
+
+ * "git p4" working on UTF-16 files on Windows did not implement
+ CRLF-to-LF conversion correctly, which has been corrected.
+ (merge 4d35f74421 mb/p4-utf16-crlf later to maint).
+
+ * "git p4" did not handle non-ASCII client name well, which has been
+ corrected.
+ (merge d205483695 kk/p4-client-name-encoding-fix later to maint).
+
+ * "rerere-train" script (in contrib/) used to honor commit.gpgSign
+ while recreating the throw-away merges.
+ (merge cc391fc886 cl/rerere-train-with-no-sign later to maint).
+
+ * "git checkout" miscounted the paths it updated, which has been
+ corrected.
+ (merge 611c7785e8 mt/checkout-count-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge a700395eaf ma/t4200-update later to maint).
+ (merge ae436f283c ma/sparse-checkout-cone-doc-fix later to maint).
+ (merge a10f6e2bda sg/index-format-doc-update later to maint).
+ (merge ce5f07983d mt/pkt-line-comment-tweak later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index a6121d1..5bd795e 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -452,7 +452,10 @@ repositories.
- `gitk-git/` comes from Paul Mackerras's gitk project:
- git://ozlabs.org/~paulus/gitk
+ git://git.ozlabs.org/~paulus/gitk
+
+ Those who are interested in improve gitk can volunteer to help Paul
+ in maintaining it cf. <YntxL/fTplFm8lr6@cleo>.
- `po/` comes from the localization coordinator, Jiang Xin:
diff --git a/Documentation/ToolsForGit.txt b/Documentation/ToolsForGit.txt
new file mode 100644
index 0000000..5060d0d
--- /dev/null
+++ b/Documentation/ToolsForGit.txt
@@ -0,0 +1,51 @@
+Tools for developing Git
+========================
+:sectanchors:
+
+[[summary]]
+== Summary
+
+This document gathers tips, scripts and configuration file to help people
+working on Git's codebase use their favorite tools while following Git's
+coding style.
+
+[[author]]
+=== Author
+
+The Git community.
+
+[[table_of_contents]]
+== Table of contents
+
+- <<vscode>>
+- <<emacs>>
+
+[[vscode]]
+=== Visual Studio Code (VS Code)
+
+The contrib/vscode/init.sh script creates configuration files that enable
+several valuable VS Code features. See contrib/vscode/README.md for more
+information on using the script.
+
+[[emacs]]
+=== Emacs
+
+This is adapted from Linux's suggestion in its CodingStyle document:
+
+- To follow rules of the CodingGuideline, it's useful to put the following in
+GIT_CHECKOUT/.dir-locals.el, assuming you use cperl-mode:
+----
+;; note the first part is useful for C editing, too
+((nil . ((indent-tabs-mode . t)
+ (tab-width . 8)
+ (fill-column . 80)))
+ (cperl-mode . ((cperl-indent-level . 8)
+ (cperl-extra-newline-before-brace . nil)
+ (cperl-merge-trailing-else . t))))
+----
+
+For a more complete setup, since Git's codebase uses a coding style
+similar to the Linux kernel's style, tips given in Linux's CodingStyle
+document can be applied here too.
+
+==== https://www.kernel.org/doc/html/v4.10/process/coding-style.html#you-ve-made-a-mess-of-it
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f0fb25a..5b5b976 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -445,6 +445,8 @@ include::config/i18n.txt[]
include::config/imap.txt[]
+include::config/includeif.txt[]
+
include::config/index.txt[]
include::config/init.txt[]
@@ -495,7 +497,9 @@ include::config/repack.txt[]
include::config/rerere.txt[]
-include::config/reset.txt[]
+include::config/revert.txt[]
+
+include::config/safe.txt[]
include::config/sendemail.txt[]
diff --git a/Documentation/config/add.txt b/Documentation/config/add.txt
index c9f748f..3e859f3 100644
--- a/Documentation/config/add.txt
+++ b/Documentation/config/add.txt
@@ -7,6 +7,6 @@ add.ignore-errors (deprecated)::
variables.
add.interactive.useBuiltin::
- [EXPERIMENTAL] Set to `true` to use the experimental built-in
- implementation of the interactive version of linkgit:git-add[1]
- instead of the Perl script version. Is `false` by default.
+ Set to `false` to fall back to the original Perl implementation of
+ the interactive version of linkgit:git-add[1] instead of the built-in
+ version. Is `true` by default.
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index c40eb09..a00d010 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -4,6 +4,10 @@ advice.*::
can tell Git that you do not need help by setting these to 'false':
+
--
+ ambiguousFetchRefspec::
+ Advice shown when fetch refspec for multiple remotes map to
+ the same remote-tracking branch namespace and causes branch
+ tracking set-up to fail.
fetchShowForcedUpdates::
Advice shown when linkgit:git-fetch[1] takes a long time
to calculate forced updates after ref updates, or to warn
@@ -67,10 +71,10 @@ advice.*::
commitBeforeMerge::
Advice shown when linkgit:git-merge[1] refuses to
merge to avoid overwriting local changes.
- resetQuiet::
- Advice to consider using the `--quiet` option to linkgit:git-reset[1]
- when the command takes more than 2 seconds to enumerate unstaged
- changes after reset.
+ resetNoRefresh::
+ Advice to consider using the `--no-refresh` option to
+ linkgit:git-reset[1] when the command takes more than 2 seconds
+ to refresh the index after reset.
resolveConflict::
Advice shown by various commands when conflicts
prevent the operation from being performed.
diff --git a/Documentation/config/branch.txt b/Documentation/config/branch.txt
index 1e0c7af..445341a 100644
--- a/Documentation/config/branch.txt
+++ b/Documentation/config/branch.txt
@@ -9,7 +9,9 @@ branch.autoSetupMerge::
automatic setup is done when the starting point is either a
local branch or remote-tracking branch; `inherit` -- if the starting point
has a tracking configuration, it is copied to the new
- branch. This option defaults to true.
+ branch; `simple` -- automatic setup is done only when the starting point
+ is a remote-tracking branch and the new branch has the same name as the
+ remote branch. This option defaults to true.
branch.autoSetupRebase::
When a new branch is created with 'git branch', 'git switch' or 'git checkout'
@@ -38,8 +40,9 @@ branch.<name>.remote::
may be overridden with `remote.pushDefault` (for all branches).
The remote to push to, for the current branch, may be further
overridden by `branch.<name>.pushRemote`. If no remote is
- configured, or if you are not on any branch, it defaults to
- `origin` for fetching and `remote.pushDefault` for pushing.
+ configured, or if you are not on any branch and there is more than
+ one remote defined in the repository, it defaults to `origin` for
+ fetching and `remote.pushDefault` for pushing.
Additionally, `.` (a period) is the current local repository
(a dot-repository), see `branch.<name>.merge`'s final note below.
diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
index 9da3e5d..37afbaf 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -62,22 +62,54 @@ core.protectNTFS::
Defaults to `true` on Windows, and `false` elsewhere.
core.fsmonitor::
- If set, the value of this variable is used as a command which
- will identify all files that may have changed since the
- requested date/time. This information is used to speed up git by
- avoiding unnecessary processing of files that have not changed.
- See the "fsmonitor-watchman" section of linkgit:githooks[5].
+ If set to true, enable the built-in file system monitor
+ daemon for this working directory (linkgit:git-fsmonitor{litdd}daemon[1]).
++
+Like hook-based file system monitors, the built-in file system monitor
+can speed up Git commands that need to refresh the Git index
+(e.g. `git status`) in a working directory with many files. The
+built-in monitor eliminates the need to install and maintain an
+external third-party tool.
++
+The built-in file system monitor is currently available only on a
+limited set of supported platforms. Currently, this includes Windows
+and MacOS.
++
+ Otherwise, this variable contains the pathname of the "fsmonitor"
+ hook command.
++
+This hook command is used to identify all files that may have changed
+since the requested date/time. This information is used to speed up
+git by avoiding unnecessary scanning of files that have not changed.
++
+See the "fsmonitor-watchman" section of linkgit:githooks[5].
++
+Note that if you concurrently use multiple versions of Git, such
+as one version on the command line and another version in an IDE
+tool, that the definition of `core.fsmonitor` was extended to
+allow boolean values in addition to hook pathnames. Git versions
+2.35.1 and prior will not understand the boolean values and will
+consider the "true" or "false" values as hook pathnames to be
+invoked. Git versions 2.26 thru 2.35.1 default to hook protocol
+V2 and will fall back to no fsmonitor (full scan). Git versions
+prior to 2.26 default to hook protocol V1 and will silently
+assume there were no changes to report (no scan), so status
+commands may report incomplete results. For this reason, it is
+best to upgrade all of your Git versions before using the built-in
+file system monitor.
core.fsmonitorHookVersion::
- Sets the version of hook that is to be used when calling fsmonitor.
- There are currently versions 1 and 2. When this is not set,
- version 2 will be tried first and if it fails then version 1
- will be tried. Version 1 uses a timestamp as input to determine
- which files have changes since that time but some monitors
- like watchman have race conditions when used with a timestamp.
- Version 2 uses an opaque string so that the monitor can return
- something that can be used to determine what files have changed
- without race conditions.
+ Sets the protocol version to be used when invoking the
+ "fsmonitor" hook.
++
+There are currently versions 1 and 2. When this is not set,
+version 2 will be tried first and if it fails then version 1
+will be tried. Version 1 uses a timestamp as input to determine
+which files have changes since that time but some monitors
+like Watchman have race conditions when used with a timestamp.
+Version 2 uses an opaque string so that the monitor can return
+something that can be used to determine what files have changed
+without race conditions.
core.trustctime::
If false, the ctime differences between the index and the
@@ -412,17 +444,32 @@ You probably do not need to adjust this value.
Common unit suffixes of 'k', 'm', or 'g' are supported.
core.bigFileThreshold::
- Files larger than this size are stored deflated, without
- attempting delta compression. Storing large files without
- delta compression avoids excessive memory usage, at the
- slight expense of increased disk usage. Additionally files
- larger than this size are always treated as binary.
+ The size of files considered "big", which as discussed below
+ changes the behavior of numerous git commands, as well as how
+ such files are stored within the repository. The default is
+ 512 MiB. Common unit suffixes of 'k', 'm', or 'g' are
+ supported.
+
-Default is 512 MiB on all platforms. This should be reasonable
-for most projects as source code and other text files can still
-be delta compressed, but larger binary media files won't be.
+Files above the configured limit will be:
+
-Common unit suffixes of 'k', 'm', or 'g' are supported.
+* Stored deflated in packfiles, without attempting delta compression.
++
+The default limit is primarily set with this use-case in mind. With it,
+most projects will have their source code and other text files delta
+compressed, but not larger binary media files.
++
+Storing large files without delta compression avoids excessive memory
+usage, at the slight expense of increased disk usage.
++
+* Will be treated as if they were labeled "binary" (see
+ linkgit:gitattributes[5]). e.g. linkgit:git-log[1] and
+ linkgit:git-diff[1] will not compute diffs for files above this limit.
++
+* Will generally be streamed when written, which avoids excessive
+memory usage, at the cost of some fixed overhead. Commands that make
+use of this include linkgit:git-archive[1],
+linkgit:git-fast-import[1], linkgit:git-index-pack[1],
+linkgit:git-unpack-objects[1] and linkgit:git-fsck[1].
core.excludesFile::
Specifies the pathname to the file that contains patterns to
@@ -596,6 +643,14 @@ core.fsyncMethod::
* `writeout-only` issues pagecache writeback requests, but depending on the
filesystem and storage hardware, data added to the repository may not be
durable in the event of a system crash. This is the default mode on macOS.
+* `batch` enables a mode that uses writeout-only flushes to stage multiple
+ updates in the disk writeback cache and then does a single full fsync of
+ a dummy file to trigger the disk cache flush at the end of the operation.
++
+Currently `batch` mode only applies to loose-object files. Other repository
+data is made durable as if `fsync` was specified. This mode is expected to
+be as safe as `fsync` on macOS for repos stored on HFS+ or APFS filesystems
+and on Windows for repos stored on NTFS or ReFS filesystems.
core.fsyncObjectFiles::
This boolean will enable 'fsync()' when writing object files.
@@ -666,8 +721,10 @@ core.sparseCheckout::
core.sparseCheckoutCone::
Enables the "cone mode" of the sparse checkout feature. When the
- sparse-checkout file contains a limited set of patterns, then this
- mode provides significant performance advantages. See
+ sparse-checkout file contains a limited set of patterns, this
+ mode provides significant performance advantages. The "non-cone
+ mode" can be requested to allow specifying more flexible
+ patterns by setting this variable to 'false'. See
linkgit:git-sparse-checkout[1] for more information.
core.abbrev::
diff --git a/Documentation/config/gc.txt b/Documentation/config/gc.txt
index c834e07..38fea07 100644
--- a/Documentation/config/gc.txt
+++ b/Documentation/config/gc.txt
@@ -81,14 +81,21 @@ gc.packRefs::
to enable it within all non-bare repos or it can be set to a
boolean value. The default is `true`.
+gc.cruftPacks::
+ Store unreachable objects in a cruft pack (see
+ linkgit:git-repack[1]) instead of as loose objects. The default
+ is `false`.
+
gc.pruneExpire::
- When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'.
- Override the grace period with this config variable. The value
- "now" may be used to disable this grace period and always prune
- unreachable objects immediately, or "never" may be used to
- suppress pruning. This feature helps prevent corruption when
- 'git gc' runs concurrently with another process writing to the
- repository; see the "NOTES" section of linkgit:git-gc[1].
+ When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'
+ (and 'repack --cruft --cruft-expiration 2.weeks.ago' if using
+ cruft packs via `gc.cruftPacks` or `--cruft`). Override the
+ grace period with this config variable. The value "now" may be
+ used to disable this grace period and always prune unreachable
+ objects immediately, or "never" may be used to suppress pruning.
+ This feature helps prevent corruption when 'git gc' runs
+ concurrently with another process writing to the repository; see
+ the "NOTES" section of linkgit:git-gc[1].
gc.worktreePruneExpire::
When 'git gc' is run, it calls
diff --git a/Documentation/config/gpg.txt b/Documentation/config/gpg.txt
index 86892ad..86f6308 100644
--- a/Documentation/config/gpg.txt
+++ b/Documentation/config/gpg.txt
@@ -36,9 +36,12 @@ gpg.minTrustLevel::
gpg.ssh.defaultKeyCommand::
This command that will be run when user.signingkey is not set and a ssh
- signature is requested. On successful exit a valid ssh public key is
- expected in the first line of its output. To automatically use the first
- available key from your ssh-agent set this to "ssh-add -L".
+ signature is requested. On successful exit a valid ssh public key
+ prefixed with `key::` is expected in the first line of its output.
+ This allows for a script doing a dynamic lookup of the correct public
+ key when it is impractical to statically configure `user.signingKey`.
+ For example when keys or SSH Certificates are rotated frequently or
+ selection of the right key depends on external factors unknown to git.
gpg.ssh.allowedSignersFile::
A file containing ssh public keys which you are willing to trust.
diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt
index 7003661..afeeccf 100644
--- a/Documentation/config/http.txt
+++ b/Documentation/config/http.txt
@@ -98,6 +98,22 @@ http.version::
- HTTP/2
- HTTP/1.1
+http.curloptResolve::
+ Hostname resolution information that will be used first by
+ libcurl when sending HTTP requests. This information should
+ be in one of the following formats:
+
+ - [+]HOST:PORT:ADDRESS[,ADDRESS]
+ - -HOST:PORT
+
++
+The first format redirects all requests to the given `HOST:PORT`
+to the provided `ADDRESS`(s). The second format clears all
+previous config values for that `HOST:PORT` combination. To
+allow easy overriding of all the settings inherited from the
+system config, an empty value will reset all resolution
+information to the empty list.
+
http.sslVersion::
The SSL version to use when negotiating an SSL connection, if you
want to force the default. The available and default version
@@ -187,7 +203,7 @@ http.schannelUseSSLCAInfo::
when the `schannel` backend was configured via `http.sslBackend`,
unless `http.schannelUseSSLCAInfo` overrides this behavior.
-http.pinnedpubkey::
+http.pinnedPubkey::
Public key of the https service. It may either be the filename of
a PEM or DER encoded public key file or a string starting with
'sha256//' followed by the base64 encoded sha256 hash of the
diff --git a/Documentation/config/includeif.txt b/Documentation/config/includeif.txt
new file mode 100644
index 0000000..82fe431
--- /dev/null
+++ b/Documentation/config/includeif.txt
@@ -0,0 +1,6 @@
+include.path::
+includeIf.<condition>.path::
+ Special variables to include other configuration files. See
+ the "CONFIGURATION FILE" section in the main
+ linkgit:git-config[1] documentation,
+ specifically the "Includes" and "Conditional Includes" subsections.
diff --git a/Documentation/config/mergetool.txt b/Documentation/config/mergetool.txt
index cafbbef..90b3809 100644
--- a/Documentation/config/mergetool.txt
+++ b/Documentation/config/mergetool.txt
@@ -45,6 +45,15 @@ mergetool.meld.useAutoMerge::
value of `false` avoids using `--auto-merge` altogether, and is the
default value.
+mergetool.vimdiff.layout::
+ The vimdiff backend uses this variable to control how its split
+ windows look like. Applies even if you are using Neovim (`nvim`) or
+ gVim (`gvim`) as the merge tool. See BACKEND SPECIFIC HINTS section
+ifndef::git-mergetool[]
+ in linkgit:git-mergetool[1].
+endif::[]
+ for details.
+
mergetool.hideResolved::
During a merge Git will automatically resolve as many conflicts as
possible and write the 'MERGED' file containing conflict markers around
diff --git a/Documentation/config/push.txt b/Documentation/config/push.txt
index 6320336..7386fea 100644
--- a/Documentation/config/push.txt
+++ b/Documentation/config/push.txt
@@ -1,3 +1,14 @@
+push.autoSetupRemote::
+ If set to "true" assume `--set-upstream` on default push when no
+ upstream tracking exists for the current branch; this option
+ takes effect with push.default options 'simple', 'upstream',
+ and 'current'. It is useful if by default you want new branches
+ to be pushed to the default remote (like the behavior of
+ 'push.default=current') and you also want the upstream tracking
+ to be set. Workflows most likely to benefit from this option are
+ 'simple' central workflows where all branches are expected to
+ have the same name on the remote.
+
push.default::
Defines the action `git push` should take if no refspec is
given (whether from the command-line, config, or elsewhere).
@@ -126,3 +137,8 @@ push.negotiate::
server attempt to find commits in common. If "false", Git will
rely solely on the server's ref advertisement to find commits
in common.
+
+push.useBitmaps::
+ If set to "false", disable use of bitmaps for "git push" even if
+ `pack.useBitmaps` is "true", without preventing other git operations
+ from using bitmaps. Default is true.
diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index 8c979cb..f19bd0e 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -21,6 +21,9 @@ rebase.autoStash::
`--autostash` options of linkgit:git-rebase[1].
Defaults to false.
+rebase.updateRefs::
+ If set to true enable `--update-refs` option by default.
+
rebase.missingCommitsCheck::
If set to "warn", git rebase -i will print a warning if some
commits are removed (e.g. a line was deleted), however the
diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt
index a8e6437..0678b4b 100644
--- a/Documentation/config/remote.txt
+++ b/Documentation/config/remote.txt
@@ -82,5 +82,7 @@ remote.<name>.promisor::
objects.
remote.<name>.partialclonefilter::
- The filter that will be applied when fetching from this
- promisor remote.
+ The filter that will be applied when fetching from this promisor remote.
+ Changing or clearing this value will only affect fetches for new commits.
+ To fetch associated objects for commits already present in the local object
+ database, use the `--refetch` option of linkgit:git-fetch[1].
diff --git a/Documentation/config/repack.txt b/Documentation/config/repack.txt
index 41ac695..c79af6d 100644
--- a/Documentation/config/repack.txt
+++ b/Documentation/config/repack.txt
@@ -30,3 +30,12 @@ repack.updateServerInfo::
If set to false, linkgit:git-repack[1] will not run
linkgit:git-update-server-info[1]. Defaults to true. Can be overridden
when true by the `-n` option of linkgit:git-repack[1].
+
+repack.cruftWindow::
+repack.cruftWindowMemory::
+repack.cruftDepth::
+repack.cruftThreads::
+ Parameters used by linkgit:git-pack-objects[1] when generating
+ a cruft pack and the respective parameters are not given over
+ the command line. See similarly named `pack.*` configuration
+ variables for defaults and meaning.
diff --git a/Documentation/config/reset.txt b/Documentation/config/reset.txt
deleted file mode 100644
index 63b7c45..0000000
--- a/Documentation/config/reset.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-reset.quiet::
- When set to true, 'git reset' will default to the '--quiet' option.
diff --git a/Documentation/config/revert.txt b/Documentation/config/revert.txt
new file mode 100644
index 0000000..802d6fa
--- /dev/null
+++ b/Documentation/config/revert.txt
@@ -0,0 +1,3 @@
+revert.reference::
+ Setting this variable to true makes `git revert` behave
+ as if the `--reference` option is given.
diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt
new file mode 100644
index 0000000..bde7f31
--- /dev/null
+++ b/Documentation/config/safe.txt
@@ -0,0 +1,61 @@
+safe.bareRepository::
+ Specifies which bare repositories Git will work with. The currently
+ supported values are:
++
+* `all`: Git works with all bare repositories. This is the default.
+* `explicit`: Git only works with bare repositories specified via
+ the top-level `--git-dir` command-line option, or the `GIT_DIR`
+ environment variable (see linkgit:git[1]).
++
+If you do not use bare repositories in your workflow, then it may be
+beneficial to set `safe.bareRepository` to `explicit` in your global
+config. This will protect you from attacks that involve cloning a
+repository that contains a bare repository and running a Git command
+within that directory.
++
+This config setting is only respected in protected configuration (see
+<<SCOPES>>). This prevents the untrusted repository from tampering with
+this value.
+
+safe.directory::
+ These config entries specify Git-tracked directories that are
+ considered safe even if they are owned by someone other than the
+ current user. By default, Git will refuse to even parse a Git
+ config of a repository owned by someone else, let alone run its
+ hooks, and this config setting allows users to specify exceptions,
+ e.g. for intentionally shared repositories (see the `--shared`
+ option in linkgit:git-init[1]).
++
+This is a multi-valued setting, i.e. you can add more than one directory
+via `git config --add`. To reset the list of safe directories (e.g. to
+override any such directories specified in the system config), add a
+`safe.directory` entry with an empty value.
++
+This config setting is only respected in protected configuration (see
+<<SCOPES>>). This prevents the untrusted repository from tampering with this
+value.
++
+The value of this setting is interpolated, i.e. `~/<path>` expands to a
+path relative to the home directory and `%(prefix)/<path>` expands to a
+path relative to Git's (runtime) prefix.
++
+To completely opt-out of this security check, set `safe.directory` to the
+string `*`. This will allow all repositories to be treated as if their
+directory was listed in the `safe.directory` list. If `safe.directory=*`
+is set in system config and you want to re-enable this protection, then
+initialize your list with an empty value before listing the repositories
+that you deem safe.
++
+As explained, Git only allows you to access repositories owned by
+yourself, i.e. the user who is running Git, by default. When Git
+is running as 'root' in a non Windows platform that provides sudo,
+however, git checks the SUDO_UID environment variable that sudo creates
+and will allow access to the uid recorded as its value in addition to
+the id from 'root'.
+This is to make it easy to perform a common sequence during installation
+"make && sudo make install". A git process running under 'sudo' runs as
+'root' but the 'sudo' command exports the environment variable to record
+which id the original user has.
+If that is not what you would prefer and want git to only trust
+repositories that are owned by root instead, then you can remove
+the `SUDO_UID` variable from root's environment before invoking git.
diff --git a/Documentation/config/transfer.txt b/Documentation/config/transfer.txt
index b49429e..7ed917f 100644
--- a/Documentation/config/transfer.txt
+++ b/Documentation/config/transfer.txt
@@ -1,3 +1,41 @@
+transfer.credentialsInUrl::
+ A configured URL can contain plaintext credentials in the form
+ `<protocol>://<user>:<password>@<domain>/<path>`. You may want
+ to warn or forbid the use of such configuration (in favor of
+ using linkgit:git-credential[1]). This will be used on
+ linkgit:git-clone[1], linkgit:git-fetch[1], linkgit:git-push[1],
+ and any other direct use of the configured URL.
++
+Note that this is currently limited to detecting credentials in
+`remote.<name>.url` configuration, it won't detect credentials in
+`remote.<name>.pushurl` configuration.
++
+You might want to enable this to prevent inadvertent credentials
+exposure, e.g. because:
++
+* The OS or system where you're running git may not provide way way or
+ otherwise allow you to configure the permissions of the
+ configuration file where the username and/or password are stored.
+* Even if it does, having such data stored "at rest" might expose you
+ in other ways, e.g. a backup process might copy the data to another
+ system.
+* The git programs will pass the full URL to one another as arguments
+ on the command-line, meaning the credentials will be exposed to other
+ users on OS's or systems that allow other users to see the full
+ process list of other users. On linux the "hidepid" setting
+ documented in procfs(5) allows for configuring this behavior.
++
+If such concerns don't apply to you then you probably don't need to be
+concerned about credentials exposure due to storing that sensitive
+data in git's configuration files. If you do want to use this, set
+`transfer.credentialsInUrl` to one of these values:
++
+* `allow` (default): Git will proceed with its activity without warning.
+* `warn`: Git will write a warning message to `stderr` when parsing a URL
+ with a plaintext credential.
+* `die`: Git will write a failure message to `stderr` when parsing a URL
+ with a plaintext credential.
+
transfer.fsckObjects::
When `fetch.fsckObjects` or `receive.fsckObjects` are
not set, the value of this variable is used instead.
diff --git a/Documentation/config/uploadpack.txt b/Documentation/config/uploadpack.txt
index 32fad5b..16264d8 100644
--- a/Documentation/config/uploadpack.txt
+++ b/Documentation/config/uploadpack.txt
@@ -49,9 +49,9 @@ uploadpack.packObjectsHook::
`pack-objects` to the hook, and expects a completed packfile on
stdout.
+
-Note that this configuration variable is ignored if it is seen in the
-repository-level config (this is a safety measure against fetching from
-untrusted repositories).
+Note that this configuration variable is only respected when it is specified
+in protected configuration (see <<SCOPES>>). This is a safety measure
+against fetching from untrusted repositories.
uploadpack.allowFilter::
If this option is set, `upload-pack` will support partial
diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt
index 7a9c3b6..a3ae874 100644
--- a/Documentation/diff-format.txt
+++ b/Documentation/diff-format.txt
@@ -43,7 +43,7 @@ That is, from the left to the right:
. a space.
. sha1 for "src"; 0\{40\} if creation or unmerged.
. a space.
-. sha1 for "dst"; 0\{40\} if creation, unmerged or "look at work tree".
+. sha1 for "dst"; 0\{40\} if deletion, unmerged or "work tree out of sync with the index".
. a space.
. status, followed by optional "score" number.
. a tab or a NUL when `-z` option is used.
@@ -69,8 +69,8 @@ percentage of similarity between the source and target of the move or
copy). Status letter M may be followed by a score (denoting the
percentage of dissimilarity) for file rewrites.
-<sha1> is shown as all 0's if a file is new on the filesystem
-and it is out of sync with the index.
+The sha1 for "dst" is shown as all 0's if a file on the filesystem
+is out of sync with the index.
Example:
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 6cdd9d4..622bd84 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -163,6 +163,16 @@ endif::git-pull[]
behavior for a remote may be specified with the remote.<name>.tagOpt
setting. See linkgit:git-config[1].
+ifndef::git-pull[]
+--refetch::
+ Instead of negotiating with the server to avoid transferring commits and
+ associated objects that are already present locally, this option fetches
+ all objects as a fresh clone would. Use this to reapply a partial clone
+ filter from configuration or using `--filter=` when the filter
+ definition has changed. Automatic post-fetch maintenance will perform
+ object database pack consolidation to remove any duplicate objects.
+endif::git-pull[]
+
--refmap=<refspec>::
When fetching refs listed on the command line, use the
specified refspec (can be given more than once) to map the
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index bc4e76a..60c0409 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -34,10 +34,12 @@ OPTIONS
-------
--format=<fmt>::
- Format of the resulting archive: 'tar' or 'zip'. If this option
+ Format of the resulting archive. Possible values are `tar`,
+ `zip`, `tar.gz`, `tgz`, and any format defined using the
+ configuration option `tar.<format>.command`. If `--format`
is not given, and the output file is specified, the format is
- inferred from the filename if possible (e.g. writing to "foo.zip"
- makes the output to be in the zip format). Otherwise the output
+ inferred from the filename if possible (e.g. writing to `foo.zip`
+ makes the output to be in the `zip` format). Otherwise the output
format is `tar`.
-l::
@@ -49,7 +51,9 @@ OPTIONS
Report progress to stderr.
--prefix=<prefix>/::
- Prepend <prefix>/ to each filename in the archive.
+ Prepend <prefix>/ to paths in the archive. Can be repeated; its
+ rightmost value is used for all tracked files. See below which
+ value gets used by `--add-file` and `--add-virtual-file`.
-o <file>::
--output=<file>::
@@ -57,9 +61,26 @@ OPTIONS
--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 of the last `--prefix` option (if any)
+ before this `--add-file` and the basename of <file>.
+
+--add-virtual-file=<path>:<content>::
+ Add the specified contents 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>.
+ by concatenating the value of the last `--prefix` option (if any)
+ before this `--add-virtual-file` and `<path>`.
++
+The `<path>` argument can start and end with a literal double-quote
+character; the contained file name is interpreted as a C-style string,
+i.e. the backslash is interpreted as escape character. The path must
+be quoted if it contains a colon, to avoid the colon from being
+misinterpreted as the separator between the path and the contents, or
+if the path begins or ends with a double-quote character.
++
+The file mode is limited to a regular file, and the option may be
+subject to platform-dependent command-line limits. For non-trivial
+cases, write an untracked file and use `--add-file` instead.
--worktree-attributes::
Look for attributes in .gitattributes files in the working tree
@@ -124,17 +145,16 @@ tar.<format>.command::
is executed using the shell with the generated tar file on its
standard input, and should produce the final output on its
standard output. Any compression-level options will be passed
- to the command (e.g., "-9"). An output file with the same
- extension as `<format>` will be use this format if no other
- format is given.
+ to the command (e.g., `-9`).
+
-The "tar.gz" and "tgz" formats are defined automatically and default to
-`gzip -cn`. You may override them with custom commands.
+The `tar.gz` and `tgz` formats are defined automatically and use the
+magic command `git archive gzip` by default, which invokes an internal
+implementation of gzip.
tar.<format>.remote::
- If true, enable `<format>` for use by remote clients via
+ If true, enable the format for use by remote clients via
linkgit:git-upload-archive[1]. Defaults to false for
- user-defined formats, but true for the "tar.gz" and "tgz"
+ user-defined formats, but true for the `tar.gz` and `tgz`
formats.
[[ATTRIBUTES]]
@@ -194,6 +214,12 @@ EXAMPLES
commit on the current branch. Note that the output format is
inferred by the extension of the output file.
+`git archive -o latest.tar --prefix=build/ --add-file=configure --prefix= HEAD`::
+
+ Creates a tar archive that contains the contents of the latest
+ commit on the current branch with no prefix and the untracked
+ file 'configure' with the prefix 'build/'.
+
`git config tar.tar.xz.command "xz -c"`::
Configure a "tar.xz" format for making LZMA-compressed tarfiles.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index c8b4f9c..ae82378 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -221,13 +221,17 @@ The exact upstream branch is chosen depending on the optional argument:
itself as the upstream; `--track=inherit` means to copy the upstream
configuration of the start-point branch.
+
-`--track=direct` is the default when the start point is a remote-tracking branch.
-Set the branch.autoSetupMerge configuration variable to `false` if you
-want `git switch`, `git checkout` and `git branch` to always behave as if `--no-track`
-were given. Set it to `always` if you want this behavior when the
-start-point is either a local or remote-tracking branch. Set it to
-`inherit` if you want to copy the tracking configuration from the
-branch point.
+The branch.autoSetupMerge configuration variable specifies how `git switch`,
+`git checkout` and `git branch` should behave when neither `--track` nor
+`--no-track` are specified:
++
+The default option, `true`, behaves as though `--track=direct`
+were given whenever the start-point is a remote-tracking branch.
+`false` behaves as if `--no-track` were given. `always` behaves as though
+`--track=direct` were given. `inherit` behaves as though `--track=inherit`
+were given. `simple` behaves as though `--track=direct` were given only when
+the start-point is a remote-tracking branch and the new branch has the same
+name as the remote branch.
+
See linkgit:git-pull[1] and linkgit:git-config[1] for additional discussion on
how the `branch.<name>.remote` and `branch.<name>.merge` options are used.
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index ac4c435..7685b57 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -75,11 +75,11 @@ verify <file>::
cleanly to the current repository. This includes checks on the
bundle format itself as well as checking that the prerequisite
commits exist and are fully linked in the current repository.
- Information about additional capabilities, such as "object filter",
- is printed. See "Capabilities" in link:technical/bundle-format.html
- for more information. Finally, 'git bundle' prints a list of
- missing commits, if any. The exit code is zero for success, but
- will be nonzero if the bundle file is invalid.
+ Then, 'git bundle' prints a list of missing commits, if any.
+ Finally, information about additional capabilities, such as "object
+ filter", is printed. See "Capabilities" in link:technical/bundle-format.html
+ for more information. The exit code is zero for success, but will
+ be nonzero if the bundle file is invalid.
list-heads <file>::
Lists the references defined in the bundle. If followed by a
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 70c5b4f..24a811f 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -12,7 +12,7 @@ SYNOPSIS
'git cat-file' <type> <object>
'git cat-file' (-e | -p) <object>
'git cat-file' (-t | -s) [--allow-unknown-type] <object>
-'git cat-file' (--batch | --batch-check) [--batch-all-objects]
+'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
[--buffer] [--follow-symlinks] [--unordered]
[--textconv | --filters]
'git cat-file' (--textconv | --filters)
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index bdcfd94..7a2bcb2 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -248,7 +248,7 @@ Valid `<type>`'s include:
--show-scope::
Similar to `--show-origin` in that it augments the output of
all queried config options with the scope of that value
- (local, global, system, command).
+ (worktree, local, global, system, command).
--get-colorbool <name> [<stdout-is-tty>]::
@@ -297,23 +297,20 @@ The default is to use a pager.
FILES
-----
-If not set explicitly with `--file`, there are four files where
-'git config' will search for configuration options:
+By default, 'git config' will read configuration options from multiple
+files:
$(prefix)/etc/gitconfig::
System-wide configuration file.
$XDG_CONFIG_HOME/git/config::
- Second user-specific configuration file. If $XDG_CONFIG_HOME is not set
- or empty, `$HOME/.config/git/config` will be used. Any single-valued
- variable set in this file will be overwritten by whatever is in
- `~/.gitconfig`. It is a good idea not to create this file if
- you sometimes use older versions of Git, as support for this
- file was added fairly recently.
-
~/.gitconfig::
- User-specific configuration file. Also called "global"
- configuration file.
+ User-specific configuration files. When the XDG_CONFIG_HOME environment
+ variable is not set or empty, $HOME/.config/ is used as
+ $XDG_CONFIG_HOME.
++
+These are also called "global" configuration files. If both files exist, both
+files are read in the order given above.
$GIT_DIR/config::
Repository specific configuration file.
@@ -322,28 +319,80 @@ $GIT_DIR/config.worktree::
This is optional and is only searched when
`extensions.worktreeConfig` is present in $GIT_DIR/config.
-If no further options are given, all reading options will read all of these
-files that are available. If the global or the system-wide configuration
-file are not available they will be ignored. If the repository configuration
-file is not available or readable, 'git config' will exit with a non-zero
-error code. However, in neither case will an error message be issued.
+You may also provide additional configuration parameters when running any
+git command by using the `-c` option. See linkgit:git[1] for details.
+
+Options will be read from all of these files that are available. If the
+global or the system-wide configuration files are missing or unreadable they
+will be ignored. If the repository configuration file is missing or unreadable,
+'git config' will exit with a non-zero error code. An error message is produced
+if the file is unreadable, but not if it is missing.
The files are read in the order given above, with last value found taking
precedence over values read earlier. When multiple values are taken then all
values of a key from all files will be used.
-You may override individual configuration parameters when running any git
-command by using the `-c` option. See linkgit:git[1] for details.
-
-All writing options will per default write to the repository specific
+By default, options are only written to the repository specific
configuration file. Note that this also affects options like `--replace-all`
and `--unset`. *'git config' will only ever change one file at a time*.
-You can override these rules using the `--global`, `--system`,
-`--local`, `--worktree`, and `--file` command-line options; see
-<<OPTIONS>> above.
+You can limit which configuration sources are read from or written to by
+specifying the path of a file with the `--file` option, or by specifying a
+configuration scope with `--system`, `--global`, `--local`, or `--worktree`.
+For more, see <<OPTIONS>> above.
+
+[[SCOPES]]
+SCOPES
+------
+
+Each configuration source falls within a configuration scope. The scopes
+are:
+
+system::
+ $(prefix)/etc/gitconfig
+
+global::
+ $XDG_CONFIG_HOME/git/config
++
+~/.gitconfig
+
+local::
+ $GIT_DIR/config
+
+worktree::
+ $GIT_DIR/config.worktree
+
+command::
+ GIT_CONFIG_{COUNT,KEY,VALUE} environment variables (see <<ENVIRONMENT>>
+ below)
++
+the `-c` option
+
+With the exception of 'command', each scope corresponds to a command line
+option: `--system`, `--global`, `--local`, `--worktree`.
+
+When reading options, specifying a scope will only read options from the
+files within that scope. When writing options, specifying a scope will write
+to the files within that scope (instead of the repository specific
+configuration file). See <<OPTIONS>> above for a complete description.
+
+Most configuration options are respected regardless of the scope it is
+defined in, but some options are only respected in certain scopes. See the
+respective option's documentation for the full details.
+
+Protected configuration
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Protected configuration refers to the 'system', 'global', and 'command' scopes.
+For security reasons, certain options are only respected when they are
+specified in protected configuration, and ignored otherwise.
+Git treats these scopes as if they are controlled by the user or a trusted
+administrator. This is because an attacker who controls these scopes can do
+substantial harm without using Git, so it is assumed that the user's environment
+protects these scopes against attackers.
+[[ENVIRONMENT]]
ENVIRONMENT
-----------
diff --git a/Documentation/git-credential-cache--daemon.txt b/Documentation/git-credential-cache--daemon.txt
index 7051c6b..01e1c21 100644
--- a/Documentation/git-credential-cache--daemon.txt
+++ b/Documentation/git-credential-cache--daemon.txt
@@ -1,5 +1,5 @@
-git-credential-cache--daemon(1)
-===============================
+git-credential-cache{litdd}daemon(1)
+====================================
NAME
----
@@ -8,7 +8,7 @@ git-credential-cache--daemon - Temporarily store user credentials in memory
SYNOPSIS
--------
[verse]
-git credential-cache--daemon [--debug] <socket>
+'git credential-cache{litdd}daemon' [--debug] <socket>
DESCRIPTION
-----------
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index 4dc57ed..53f111b 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -63,11 +63,10 @@ Print version information and exit
Print usage information and exit
<directory>::
-You can specify a list of allowed directories. If no directories
-are given, all are allowed. This is an additional restriction, gitcvs
-access still needs to be enabled by the `gitcvs.enabled` config option
-unless `--export-all` was given, too.
-
+The remaining arguments provide a list of directories. If no directories
+are given, then all are allowed. Repositories within these directories
+still require the `gitcvs.enabled` config option, unless `--export-all`
+is specified.
LIMITATIONS
-----------
@@ -311,11 +310,13 @@ ENVIRONMENT
These variables obviate the need for command-line options in some
circumstances, allowing easier restricted usage through git-shell.
-GIT_CVSSERVER_BASE_PATH takes the place of the argument to --base-path.
+GIT_CVSSERVER_BASE_PATH::
+ This variable replaces the argument to --base-path.
-GIT_CVSSERVER_ROOT specifies a single-directory whitelist. The
-repository must still be configured to allow access through
-git-cvsserver, as described above.
+GIT_CVSSERVER_ROOT::
+ This variable specifies a single directory, replacing the
+ `<directory>...` argument list. The repository still requires the
+ `gitcvs.enabled` config option, unless `--export-all` is specified.
When these environment variables are set, the corresponding
command-line arguments may not be used.
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index fdc28c0..236df51 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -32,8 +32,8 @@ that service if it is enabled.
It verifies that the directory has the magic file "git-daemon-export-ok", and
it will refuse to export any Git directory that hasn't explicitly been marked
for export this way (unless the `--export-all` parameter is specified). If you
-pass some directory paths as 'git daemon' arguments, you can further restrict
-the offers to a whitelist comprising of those.
+pass some directory paths as 'git daemon' arguments, the offers are limited to
+repositories within those directories.
By default, only `upload-pack` service is enabled, which serves
'git fetch-pack' and 'git ls-remote' clients, which are invoked
@@ -50,7 +50,7 @@ OPTIONS
Match paths exactly (i.e. don't allow "/foo/repo" when the real path is
"/foo/repo.git" or "/foo/repo/.git") and don't do user-relative paths.
'git daemon' will refuse to start when this option is enabled and no
- whitelist is specified.
+ directory arguments are provided.
--base-path=<path>::
Remap all the path requests as relative to the given path.
@@ -73,7 +73,7 @@ OPTIONS
%IP for the server's IP address, %P for the port number,
and %D for the absolute path of the named repository.
After interpolation, the path is validated against the directory
- whitelist.
+ list.
--export-all::
Allow pulling from all directories that look like Git repositories
@@ -218,9 +218,11 @@ standard output to be sent to the requestor as an error message when
it declines the service.
<directory>::
- A directory to add to the whitelist of allowed directories. Unless
- --strict-paths is specified this will also include subdirectories
- of each named directory.
+ The remaining arguments provide a list of directories. If any
+ directories are specified, then the `git-daemon` process will
+ serve a requested directory only if it is contained in one of
+ these directories. If `--strict-paths` is specified, then the
+ requested directory must match one of these directories exactly.
SERVICES
--------
@@ -264,9 +266,8 @@ git 9418/tcp # Git Version Control System
'git daemon' as inetd server::
To set up 'git daemon' as an inetd service that handles any
- repository under the whitelisted set of directories, /pub/foo
- and /pub/bar, place an entry like the following into
- /etc/inetd all on one line:
+ repository within `/pub/foo` or `/pub/bar`, place an entry like
+ the following into `/etc/inetd` all on one line:
+
------------------------------------------------
git stream tcp nowait nobody /usr/bin/git
diff --git a/Documentation/git-diff-index.txt b/Documentation/git-diff-index.txt
index 679cae2..c30d8f0 100644
--- a/Documentation/git-diff-index.txt
+++ b/Documentation/git-diff-index.txt
@@ -69,8 +69,8 @@ done an `update-index` to make that effective in the index file.
matches my working directory. But doing a 'git diff-index' does:
torvalds@ppc970:~/git> git diff-index --cached HEAD
- -100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 commit.c
- +100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 git-commit.c
+ :100644 000000 4161aecc6700a2eb579e842af0b7f22b98443f74 0000000000000000000000000000000000000000 D commit.c
+ :000000 100644 0000000000000000000000000000000000000000 4161aecc6700a2eb579e842af0b7f22b98443f74 A git-commit.c
You can see easily that the above is a rename.
@@ -103,7 +103,7 @@ have not actually done a 'git update-index' on it yet - there is no
"object" associated with the new state, and you get:
torvalds@ppc970:~/v2.6/linux> git diff-index --abbrev HEAD
- :100644 100664 7476bb... 000000... kernel/sched.c
+ :100644 100644 7476bb5ba 000000000 M kernel/sched.c
i.e., it shows that the tree has changed, and that `kernel/sched.c` is
not up to date and may contain new stuff. The all-zero sha1 means that to
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index c975884..46747d5 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -101,6 +101,10 @@ be in a separate packet, and the list must end with a flush packet.
current shallow boundary instead of from the tip of each
remote branch history.
+--refetch::
+ Skips negotiating commits with the server in order to fetch all matching
+ objects. Use to reapply a new partial clone blob/tree filter.
+
--no-progress::
Do not show the progress.
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
new file mode 100644
index 0000000..cc142fb
--- /dev/null
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -0,0 +1,75 @@
+git-fsmonitor{litdd}daemon(1)
+=============================
+
+NAME
+----
+git-fsmonitor--daemon - A Built-in File System Monitor
+
+SYNOPSIS
+--------
+[verse]
+'git fsmonitor{litdd}daemon' start
+'git fsmonitor{litdd}daemon' run
+'git fsmonitor{litdd}daemon' stop
+'git fsmonitor{litdd}daemon' status
+
+DESCRIPTION
+-----------
+
+A daemon to watch the working directory for file and directory
+changes using platform-specific file system notification facilities.
+
+This daemon communicates directly with commands like `git status`
+using the link:technical/api-simple-ipc.html[simple IPC] interface
+instead of the slower linkgit:githooks[5] interface.
+
+This daemon is built into Git so that no third-party tools are
+required.
+
+OPTIONS
+-------
+
+start::
+ Starts a daemon in the background.
+
+run::
+ Runs a daemon in the foreground.
+
+stop::
+ Stops the daemon running in the current working
+ directory, if present.
+
+status::
+ Exits with zero status if a daemon is watching the
+ current working directory.
+
+REMARKS
+-------
+
+This daemon is a long running process used to watch a single working
+directory and maintain a list of the recently changed files and
+directories. Performance of commands such as `git status` can be
+increased if they just ask for a summary of changes to the working
+directory and can avoid scanning the disk.
+
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+commands, such as `git status`, will ask the daemon for changes and
+automatically start it (if necessary).
+
+For more information see the "File System Monitor" section in
+linkgit:git-update-index[1].
+
+CAVEATS
+-------
+
+The fsmonitor daemon does not currently know about submodules and does
+not know to filter out file system events that happen within a
+submodule. If fsmonitor daemon is watching a super repo and a file is
+modified within the working directory of a submodule, it will report
+the change (as happening against the super repo). However, the client
+will properly ignore these extra events, so performance may be affected
+but it will not cause an incorrect result.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 853967d..0af7540 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -54,6 +54,10 @@ other housekeeping tasks (e.g. rerere, working trees, reflog...) will
be performed as well.
+--cruft::
+ When expiring unreachable objects, pack them separately into a
+ cruft pack instead of storing them as loose objects.
+
--prune=<date>::
Prune loose objects older than date (default is 2 weeks ago,
overridable by the config variable `gc.pruneExpire`).
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 3d393fb..58d944b 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -23,6 +23,7 @@ SYNOPSIS
[--break] [--heading] [-p | --show-function]
[-A <post-context>] [-B <pre-context>] [-C <context>]
[-W | --function-context]
+ [(-m | --max-count) <num>]
[--threads <num>]
[-f <file>] [-e] <pattern>
[--and|--or|--not|(|)|-e <pattern>...]
@@ -238,6 +239,14 @@ providing this option will cause it to die.
`git diff` works out patch hunk headers (see 'Defining a
custom hunk-header' in linkgit:gitattributes[5]).
+-m <num>::
+--max-count <num>::
+ Limit the amount of matches per file. When using the `-v` or
+ `--invert-match` option, the search stops after the specified
+ number of non-matches. A value of -1 will return unlimited
+ results (the default). A value of 0 will exit immediately with
+ a non-zero status.
+
--threads <num>::
Number of grep worker threads to use.
See `grep.threads` in 'CONFIGURATION' for more information.
diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt
index db02d6d..0240adb 100644
--- a/Documentation/git-ls-tree.txt
+++ b/Documentation/git-ls-tree.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git ls-tree' [-d] [-r] [-t] [-l] [-z]
- [--name-only] [--name-status] [--full-name] [--full-tree] [--abbrev[=<n>]]
+ [--name-only] [--name-status] [--object-only] [--full-name] [--full-tree] [--abbrev[=<n>]] [--format=<format>]
<tree-ish> [<path>...]
DESCRIPTION
@@ -59,6 +59,15 @@ OPTIONS
--name-only::
--name-status::
List only filenames (instead of the "long" output), one per line.
+ Cannot be combined with `--object-only`.
+
+--object-only::
+ List only names of the objects, one per line. Cannot be combined
+ with `--name-only` or `--name-status`.
+ This is equivalent to specifying `--format='%(objectname)'`, but
+ for both this option and that exact format the command takes a
+ hand-optimized codepath instead of going through the generic
+ formatting mechanism.
--abbrev[=<n>]::
Instead of showing the full 40-byte hexadecimal object
@@ -74,6 +83,16 @@ OPTIONS
Do not limit the listing to the current working directory.
Implies --full-name.
+--format=<format>::
+ A string that interpolates `%(fieldname)` from the result
+ being shown. It also interpolates `%%` to `%`, and
+ `%xx` where `xx` are hex digits interpolates to character
+ with hex code `xx`; for example `%00` interpolates to
+ `\0` (NUL), `%09` to `\t` (TAB) and `%0a` to `\n` (LF).
+ When specified, `--format` cannot be combined with other
+ format-altering options, including `--long`, `--name-only`
+ and `--object-only`.
+
[<path>...]::
When paths are given, show them (note that this isn't really raw
pathnames, but rather a list of patterns to match). Otherwise
@@ -82,16 +101,29 @@ OPTIONS
Output Format
-------------
- <mode> SP <type> SP <object> TAB <file>
+
+The output format of `ls-tree` is determined by either the `--format`
+option, or other format-altering options such as `--name-only` etc.
+(see `--format` above).
+
+The use of certain `--format` directives is equivalent to using those
+options, but invoking the full formatting machinery can be slower than
+using an appropriate formatting option.
+
+In cases where the `--format` would exactly map to an existing option
+`ls-tree` will use the appropriate faster path. Thus the default format
+is equivalent to:
+
+ %(objectmode) %(objecttype) %(objectname)%x09%(path)
This output format is compatible with what `--index-info --stdin` of
'git update-index' expects.
When the `-l` option is used, format changes to
- <mode> SP <type> SP <object> SP <object size> TAB <file>
+ %(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)
-Object size identified by <object> is given in bytes, and right-justified
+Object size identified by <objectname> is given in bytes, and right-justified
with minimum width of 7 characters. Object size is given only for blobs
(file) entries; for other entries `-` character is used in place of size.
@@ -100,6 +132,34 @@ quoted as explained for the configuration variable `core.quotePath`
(see linkgit:git-config[1]). Using `-z` the filename is output
verbatim and the line is terminated by a NUL byte.
+Customized format:
+
+It is possible to print in a custom format by using the `--format` option,
+which is able to interpolate different fields using a `%(fieldname)` notation.
+For example, if you only care about the "objectname" and "path" fields, you
+can execute with a specific "--format" like
+
+ git ls-tree --format='%(objectname) %(path)' <tree-ish>
+
+FIELD NAMES
+-----------
+
+Various values from structured fields can be used to interpolate
+into the resulting output. For each outputing line, the following
+names can be used:
+
+objectmode::
+ The mode of the object.
+objecttype::
+ The type of the object (`commit`, `blob` or `tree`).
+objectname::
+ The name of the object.
+objectsize[:padded]::
+ The size of a `blob` object ("-" if it's a `commit` or `tree`).
+ It also supports a padded format of size with "%(objectsize:padded)".
+path::
+ The pathname of the object.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index 58731c1..d6c3567 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -3,26 +3,237 @@ git-merge-tree(1)
NAME
----
-git-merge-tree - Show three-way merge without touching index
+git-merge-tree - Perform merge without touching index or working tree
SYNOPSIS
--------
[verse]
-'git merge-tree' <base-tree> <branch1> <branch2>
+'git merge-tree' [--write-tree] [<options>] <branch1> <branch2>
+'git merge-tree' [--trivial-merge] <base-tree> <branch1> <branch2> (deprecated)
+[[NEWMERGE]]
DESCRIPTION
-----------
-Reads three tree-ish, and output trivial merge results and
-conflicting stages to the standard output. This is similar to
-what three-way 'git read-tree -m' does, but instead of storing the
-results in the index, the command outputs the entries to the
-standard output.
-
-This is meant to be used by higher level scripts to compute
-merge results outside of the index, and stuff the results back into the
-index. For this reason, the output from the command omits
-entries that match the <branch1> tree.
+
+This command has a modern `--write-tree` mode and a deprecated
+`--trivial-merge` mode. With the exception of the
+<<DEPMERGE,DEPRECATED DESCRIPTION>> section at the end, the rest of
+this documentation describes modern `--write-tree` mode.
+
+Performs a merge, but does not make any new commits and does not read
+from or write to either the working tree or index.
+
+The performed merge will use the same feature as the "real"
+linkgit:git-merge[1], including:
+
+ * three way content merges of individual files
+ * rename detection
+ * proper directory/file conflict handling
+ * recursive ancestor consolidation (i.e. when there is more than one
+ merge base, creating a virtual merge base by merging the merge bases)
+ * etc.
+
+After the merge completes, a new toplevel tree object is created. See
+`OUTPUT` below for details.
+
+OPTIONS
+-------
+
+-z::
+ Do not quote filenames in the <Conflicted file info> section,
+ and end each filename with a NUL character rather than
+ newline. Also begin the messages section with a NUL character
+ instead of a newline. See <<OUTPUT>> below for more information.
+
+--name-only::
+ In the Conflicted file info section, instead of writing a list
+ of (mode, oid, stage, path) tuples to output for conflicted
+ files, just provide a list of filenames with conflicts (and
+ do not list filenames multiple times if they have multiple
+ conflicting stages).
+
+--[no-]messages::
+ Write any informational messages such as "Auto-merging <path>"
+ or CONFLICT notices to the end of stdout. If unspecified, the
+ default is to include these messages if there are merge
+ conflicts, and to omit them otherwise.
+
+--allow-unrelated-histories::
+ merge-tree will by default error out if the two branches specified
+ share no common history. This flag can be given to override that
+ check and make the merge proceed anyway.
+
+[[OUTPUT]]
+OUTPUT
+------
+
+For a successful merge, the output from git-merge-tree is simply one
+line:
+
+ <OID of toplevel tree>
+
+Whereas for a conflicted merge, the output is by default of the form:
+
+ <OID of toplevel tree>
+ <Conflicted file info>
+ <Informational messages>
+
+These are discussed individually below.
+
+[[OIDTLT]]
+OID of toplevel tree
+~~~~~~~~~~~~~~~~~~~~
+
+This is a tree object that represents what would be checked out in the
+working tree at the end of `git merge`. If there were conflicts, then
+files within this tree may have embedded conflict markers. This section
+is always followed by a newline (or NUL if `-z` is passed).
+
+[[CFI]]
+Conflicted file info
+~~~~~~~~~~~~~~~~~~~~
+
+This is a sequence of lines with the format
+
+ <mode> <object> <stage> <filename>
+
+The filename will be quoted as explained for the configuration
+variable `core.quotePath` (see linkgit:git-config[1]). However, if
+the `--name-only` option is passed, the mode, object, and stage will
+be omitted. If `-z` is passed, the "lines" are terminated by a NUL
+character instead of a newline character.
+
+[[IM]]
+Informational messages
+~~~~~~~~~~~~~~~~~~~~~~
+
+This always starts with a blank line (or NUL if `-z` is passed) to
+separate it from the previous sections, and then has free-form
+messages about the merge, such as:
+
+ * "Auto-merging <file>"
+ * "CONFLICT (rename/delete): <oldfile> renamed...but deleted in..."
+ * "Failed to merge submodule <submodule> (<reason>)"
+ * "Warning: cannot merge binary files: <filename>"
+
+Note that these free-form messages will never have a NUL character
+in or between them, even if -z is passed. It is simply a large block
+of text taking up the remainder of the output.
+
+EXIT STATUS
+-----------
+
+For a successful, non-conflicted merge, the exit status is 0. When the
+merge has conflicts, the exit status is 1. If the merge is not able to
+complete (or start) due to some kind of error, the exit status is
+something other than 0 or 1 (and the output is unspecified).
+
+USAGE NOTES
+-----------
+
+This command is intended as low-level plumbing, similar to
+linkgit:git-hash-object[1], linkgit:git-mktree[1],
+linkgit:git-commit-tree[1], linkgit:git-write-tree[1],
+linkgit:git-update-ref[1], and linkgit:git-mktag[1]. Thus, it can be
+used as a part of a series of steps such as:
+
+ NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2)
+ test $? -eq 0 || die "There were conflicts..."
+ NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2)
+ git update-ref $BRANCH1 $NEWCOMMIT
+
+Note that when the exit status is non-zero, `NEWTREE` in this sequence
+will contain a lot more output than just a tree.
+
+For conflicts, the output includes the same information that you'd get
+with linkgit:git-merge[1]:
+
+ * what would be written to the working tree (the
+ <<OIDTLT,OID of toplevel tree>>)
+ * the higher order stages that would be written to the index (the
+ <<CFI,Conflicted file info>>)
+ * any messages that would have been printed to stdout (the
+ <<IM,Informational messages>>)
+
+MISTAKES TO AVOID
+-----------------
+
+Do NOT look through the resulting toplevel tree to try to find which
+files conflict; parse the <<CFI,Conflicted file info>> section instead.
+Not only would parsing an entire tree be horrendously slow in large
+repositories, there are numerous types of conflicts not representable by
+conflict markers (modify/delete, mode conflict, binary file changed on
+both sides, file/directory conflicts, various rename conflict
+permutations, etc.)
+
+Do NOT interpret an empty <<CFI,Conflicted file info>> list as a clean
+merge; check the exit status. A merge can have conflicts without having
+individual files conflict (there are a few types of directory rename
+conflicts that fall into this category, and others might also be added
+in the future).
+
+Do NOT attempt to guess or make the user guess the conflict types from
+the <<CFI,Conflicted file info>> list. The information there is
+insufficient to do so. For example: Rename/rename(1to2) conflicts (both
+sides renamed the same file differently) will result in three different
+file having higher order stages (but each only has one higher order
+stage), with no way (short of the <<IM,Informational messages>> section)
+to determine which three files are related. File/directory conflicts
+also result in a file with exactly one higher order stage.
+Possibly-involved-in-directory-rename conflicts (when
+"merge.directoryRenames" is unset or set to "conflicts") also result in
+a file with exactly one higher order stage. In all cases, the
+<<IM,Informational messages>> section has the necessary info, though it
+is not designed to be machine parseable.
+
+Do NOT assume that each paths from <<CFI,Conflicted file info>>, and
+the logical conflicts in the <<IM,Informational messages>> have a
+one-to-one mapping, nor that there is a one-to-many mapping, nor a
+many-to-one mapping. Many-to-many mappings exist, meaning that each
+path can have many logical conflict types in a single merge, and each
+logical conflict type can affect many paths.
+
+Do NOT assume all filenames listed in the <<IM,Informational messages>>
+section had conflicts. Messages can be included for files that have no
+conflicts, such as "Auto-merging <file>".
+
+AVOID taking the OIDS from the <<CFI,Conflicted file info>> and
+re-merging them to present the conflicts to the user. This will lose
+information. Instead, look up the version of the file found within the
+<<OIDTLT,OID of toplevel tree>> and show that instead. In particular,
+the latter will have conflict markers annotated with the original
+branch/commit being merged and, if renames were involved, the original
+filename. While you could include the original branch/commit in the
+conflict marker annotations when re-merging, the original filename is
+not available from the <<CFI,Conflicted file info>> and thus you would
+be losing information that might help the user resolve the conflict.
+
+[[DEPMERGE]]
+DEPRECATED DESCRIPTION
+----------------------
+
+Per the <<NEWMERGE,DESCRIPTION>> and unlike the rest of this
+documentation, this section describes the deprecated `--trivial-merge`
+mode.
+
+Other than the optional `--trivial-merge`, this mode accepts no
+options.
+
+This mode reads three tree-ish, and outputs trivial merge results and
+conflicting stages to the standard output in a semi-diff format.
+Since this was designed for higher level scripts to consume and merge
+the results back into the index, it omits entries that match
+<branch1>. The result of this second form is similar to what
+three-way 'git read-tree -m' does, but instead of storing the results
+in the index, the command outputs the entries to the standard output.
+
+This form not only has limited applicability (a trivial merge cannot
+handle content merges of individual files, rename detection, proper
+directory/file conflict handling, etc.), the output format is also
+difficult to work with, and it will generally be less performant than
+the first form even on successful merges (especially if working in
+large repositories).
GIT
---
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
index e587c77..f784027 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.txt
@@ -101,6 +101,7 @@ success of the resolution after the custom tool has exited.
CONFIGURATION
-------------
+:git-mergetool: 1
include::config/mergetool.txt[]
TEMPORARY FILES
@@ -113,6 +114,13 @@ Setting the `mergetool.keepBackup` configuration variable to `false`
causes `git mergetool` to automatically remove the backup as files
are successfully merged.
+BACKEND SPECIFIC HINTS
+----------------------
+
+vimdiff
+~~~~~~~
+include::mergetools/vimdiff.txt[]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index e21fcd8..de5ee67 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -636,7 +636,42 @@ git-p4.pathEncoding::
Git expects paths encoded as UTF-8. Use this config to tell git-p4
what encoding Perforce had used for the paths. This encoding is used
to transcode the paths to UTF-8. As an example, Perforce on Windows
- often uses "cp1252" to encode path names.
+ often uses "cp1252" to encode path names. If this option is passed
+ into a p4 clone request, it is persisted in the resulting new git
+ repo.
+
+git-p4.metadataDecodingStrategy::
+ Perforce keeps the encoding of a changelist descriptions and user
+ full names as stored by the client on a given OS. The p4v client
+ uses the OS-local encoding, and so different users can end up storing
+ different changelist descriptions or user full names in different
+ encodings, in the same depot.
+ Git tolerates inconsistent/incorrect encodings in commit messages
+ and author names, but expects them to be specified in utf-8.
+ git-p4 can use three different decoding strategies in handling the
+ encoding uncertainty in Perforce: 'passthrough' simply passes the
+ original bytes through from Perforce to git, creating usable but
+ incorrectly-encoded data when the Perforce data is encoded as
+ anything other than utf-8. 'strict' expects the Perforce data to be
+ encoded as utf-8, and fails to import when this is not true.
+ 'fallback' attempts to interpret the data as utf-8, and otherwise
+ falls back to using a secondary encoding - by default the common
+ windows encoding 'cp-1252' - with upper-range bytes escaped if
+ decoding with the fallback encoding also fails.
+ Under python2 the default strategy is 'passthrough' for historical
+ reasons, and under python3 the default is 'fallback'.
+ When 'strict' is selected and decoding fails, the error message will
+ propose changing this config parameter as a workaround. If this
+ option is passed into a p4 clone request, it is persisted into the
+ resulting new git repo.
+
+git-p4.metadataFallbackEncoding::
+ Specify the fallback encoding to use when decoding Perforce author
+ names and changelists descriptions using the 'fallback' strategy
+ (see git-p4.metadataDecodingStrategy). The fallback encoding will
+ only be used when decoding as utf-8 fails. This option defaults to
+ cp1252, a common windows encoding. If this option is passed into a
+ p4 clone request, it is persisted into the resulting new git repo.
git-p4.largeFileSystem::
Specify the system that is used for large (binary) files. Please note
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index f8344e1..a9995a9 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -13,6 +13,7 @@ SYNOPSIS
[--no-reuse-delta] [--delta-base-offset] [--non-empty]
[--local] [--incremental] [--window=<n>] [--depth=<n>]
[--revs [--unpacked | --all]] [--keep-pack=<pack-name>]
+ [--cruft] [--cruft-expiration=<time>]
[--stdout [--filter=<filter-spec>] | <base-name>]
[--shallow] [--keep-true-parents] [--[no-]sparse] < <object-list>
@@ -95,6 +96,35 @@ base-name::
Incompatible with `--revs`, or options that imply `--revs` (such as
`--all`), with the exception of `--unpacked`, which is compatible.
+--cruft::
+ Packs unreachable objects into a separate "cruft" pack, denoted
+ by the existence of a `.mtimes` file. Typically used by `git
+ repack --cruft`. Callers provide a list of pack names and
+ indicate which packs will remain in the repository, along with
+ which packs will be deleted (indicated by the `-` prefix). The
+ contents of the cruft pack are all objects not contained in the
+ surviving packs which have not exceeded the grace period (see
+ `--cruft-expiration` below), or which have exceeded the grace
+ period, but are reachable from an other object which hasn't.
++
+When the input lists a pack containing all reachable objects (and lists
+all other packs as pending deletion), the corresponding cruft pack will
+contain all unreachable objects (with mtime newer than the
+`--cruft-expiration`) along with any unreachable objects whose mtime is
+older than the `--cruft-expiration`, but are reachable from an
+unreachable object whose mtime is newer than the `--cruft-expiration`).
++
+Incompatible with `--unpack-unreachable`, `--keep-unreachable`,
+`--pack-loose-unreachable`, `--stdin-packs`, as well as any other
+options which imply `--revs`. Also incompatible with `--max-pack-size`;
+when this option is set, the maximum pack size is not inferred from
+`pack.packSizeLimit`.
+
+--cruft-expiration=<approxidate>::
+ If specified, objects are eliminated from the cruft pack if they
+ have an mtime older than `<approxidate>`. If unspecified (and
+ given `--cruft`), then no objects are eliminated.
+
--window=<n>::
--depth=<n>::
These two options affect how the objects contained in
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index a5356a2..b9bfdc0 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -375,10 +375,13 @@ have finished your work-in-progress), attempt the merge again.
SPARSE CHECKOUT
---------------
-Note: The `update-index` and `read-tree` primitives for supporting the
-skip-worktree bit predated the introduction of
-linkgit:git-sparse-checkout[1]. Users are encouraged to use
-`sparse-checkout` in preference to these low-level primitives.
+Note: The skip-worktree capabilities in linkgit:git-update-index[1]
+and `read-tree` predated the introduction of
+linkgit:git-sparse-checkout[1]. Users are encouraged to use the
+`sparse-checkout` command in preference to these plumbing commands for
+sparse-checkout/skip-worktree related needs. However, the information
+below might be useful to users trying to understand the pattern style
+used in non-cone mode of the `sparse-checkout` command.
"Sparse checkout" allows populating the working directory sparsely.
It uses the skip-worktree bit (see linkgit:git-update-index[1]) to
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 9da4647..080658c 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -16,40 +16,40 @@ SYNOPSIS
DESCRIPTION
-----------
-If <branch> is specified, 'git rebase' will perform an automatic
+If `<branch>` is specified, `git rebase` will perform an automatic
`git switch <branch>` before doing anything else. Otherwise
it remains on the current branch.
-If <upstream> is not specified, the upstream configured in
-branch.<name>.remote and branch.<name>.merge options will be used (see
+If `<upstream>` is not specified, the upstream configured in
+`branch.<name>.remote` and `branch.<name>.merge` options will be used (see
linkgit:git-config[1] for details) and the `--fork-point` option is
assumed. If you are currently not on any branch or if the current
branch does not have a configured upstream, the rebase will abort.
All changes made by commits in the current branch but that are not
-in <upstream> are saved to a temporary area. This is the same set
+in `<upstream>` are saved to a temporary area. This is the same set
of commits that would be shown by `git log <upstream>..HEAD`; or by
`git log 'fork_point'..HEAD`, if `--fork-point` is active (see the
description on `--fork-point` below); or by `git log HEAD`, if the
`--root` option is specified.
-The current branch is reset to <upstream>, or <newbase> if the
---onto option was supplied. This has the exact same effect as
-`git reset --hard <upstream>` (or <newbase>). ORIG_HEAD is set
+The current branch is reset to `<upstream>` or `<newbase>` if the
+`--onto` option was supplied. This has the exact same effect as
+`git reset --hard <upstream>` (or `<newbase>`). `ORIG_HEAD` is set
to point at the tip of the branch before the reset.
The commits that were previously saved into the temporary area are
then reapplied to the current branch, one by one, in order. Note that
-any commits in HEAD which introduce the same textual changes as a commit
-in HEAD..<upstream> are omitted (i.e., a patch already accepted upstream
+any commits in `HEAD` which introduce the same textual changes as a commit
+in `HEAD..<upstream>` are omitted (i.e., a patch already accepted upstream
with a different commit message or timestamp will be skipped).
It is possible that a merge failure will prevent this process from being
completely automatic. You will have to resolve any such merge failure
and run `git rebase --continue`. Another option is to bypass the commit
that caused the merge failure with `git rebase --skip`. To check out the
-original <branch> and remove the .git/rebase-apply working files, use the
-command `git rebase --abort` instead.
+original `<branch>` and remove the `.git/rebase-apply` working files, use
+the command `git rebase --abort` instead.
Assume the following history exists and the current branch is "topic":
@@ -79,7 +79,7 @@ remain the checked-out branch.
If the upstream branch already contains a change you have made (e.g.,
because you mailed a patch which was applied upstream), then that commit
-will be skipped and warnings will be issued (if the `merge` backend is
+will be skipped and warnings will be issued (if the 'merge' backend is
used). For example, running `git rebase master` on the following
history (in which `A'` and `A` introduce the same set of changes, but
have different committer information):
@@ -176,11 +176,11 @@ would result in the removal of commits F and G:
------------
This is useful if F and G were flawed in some way, or should not be
-part of topicA. Note that the argument to --onto and the <upstream>
+part of topicA. Note that the argument to `--onto` and the `<upstream>`
parameter can be any valid commit-ish.
-In case of conflict, 'git rebase' will stop at the first problematic commit
-and leave conflict markers in the tree. You can use 'git diff' to locate
+In case of conflict, `git rebase` will stop at the first problematic commit
+and leave conflict markers in the tree. You can use `git diff` to locate
the markers (<<<<<<) and make edits to resolve the conflict. For each
file you edit, you need to tell Git that the conflict has been resolved,
typically this would be done with
@@ -205,8 +205,8 @@ OPTIONS
-------
--onto <newbase>::
Starting point at which to create the new commits. If the
- --onto option is not specified, the starting point is
- <upstream>. May be any valid commit, and not just an
+ `--onto` option is not specified, the starting point is
+ `<upstream>`. May be any valid commit, and not just an
existing branch name.
+
As a special case, you may use "A\...B" as a shortcut for the
@@ -215,18 +215,19 @@ leave out at most one of A and B, in which case it defaults to HEAD.
--keep-base::
Set the starting point at which to create the new commits to the
- merge base of <upstream> <branch>. Running
- 'git rebase --keep-base <upstream> <branch>' is equivalent to
- running 'git rebase --onto <upstream>... <upstream>'.
+ merge base of `<upstream>` and `<branch>`. Running
+ `git rebase --keep-base <upstream> <branch>` is equivalent to
+ running
+ `git rebase --onto <upstream>...<branch> <upstream> <branch>`.
+
This option is useful in the case where one is developing a feature on
top of an upstream branch. While the feature is being worked on, the
upstream branch may advance and it may not be the best idea to keep
rebasing on top of the upstream but to keep the base commit as-is.
+
-Although both this option and --fork-point find the merge base between
-<upstream> and <branch>, this option uses the merge base as the _starting
-point_ on which new commits will be created, whereas --fork-point uses
+Although both this option and `--fork-point` find the merge base between
+`<upstream>` and `<branch>`, this option uses the merge base as the _starting
+point_ on which new commits will be created, whereas `--fork-point` uses
the merge base to determine the _set of commits_ which will be rebased.
+
See also INCOMPATIBLE OPTIONS below.
@@ -237,23 +238,23 @@ See also INCOMPATIBLE OPTIONS below.
upstream for the current branch.
<branch>::
- Working branch; defaults to HEAD.
+ Working branch; defaults to `HEAD`.
--continue::
Restart the rebasing process after having resolved a merge conflict.
--abort::
Abort the rebase operation and reset HEAD to the original
- branch. If <branch> was provided when the rebase operation was
- started, then HEAD will be reset to <branch>. Otherwise HEAD
+ branch. If `<branch>` was provided when the rebase operation was
+ started, then `HEAD` will be reset to `<branch>`. Otherwise `HEAD`
will be reset to where it was when the rebase operation was
started.
--quit::
- Abort the rebase operation but HEAD is not reset back to the
+ Abort the rebase operation but `HEAD` is not reset back to the
original branch. The index and working tree are also left
unchanged as a result. If a temporary stash entry was created
- using --autostash, it will be saved to the stash list.
+ using `--autostash`, it will be saved to the stash list.
--apply::
Use applying strategies to rebase (calling `git-am`
@@ -268,16 +269,16 @@ See also INCOMPATIBLE OPTIONS below.
empty after rebasing (because they contain a subset of already
upstream changes). With drop (the default), commits that
become empty are dropped. With keep, such commits are kept.
- With ask (implied by --interactive), the rebase will halt when
+ With ask (implied by `--interactive`), the rebase will halt when
an empty commit is applied allowing you to choose whether to
drop it, edit files more, or just commit the empty changes.
- Other options, like --exec, will use the default of drop unless
- -i/--interactive is explicitly specified.
+ Other options, like `--exec`, will use the default of drop unless
+ `-i`/`--interactive` is explicitly specified.
+
-Note that commits which start empty are kept (unless --no-keep-empty
+Note that commits which start empty are kept (unless `--no-keep-empty`
is specified), and commits which are clean cherry-picks (as determined
by `git log --cherry-mark ...`) are detected and dropped as a
-preliminary step (unless --reapply-cherry-picks is passed).
+preliminary step (unless `--reapply-cherry-picks` is passed).
+
See also INCOMPATIBLE OPTIONS below.
@@ -286,7 +287,7 @@ See also INCOMPATIBLE OPTIONS below.
Do not keep commits that start empty before the rebase
(i.e. that do not change anything from its parent) in the
result. The default is to keep commits which start empty,
- since creating such commits requires passing the --allow-empty
+ since creating such commits requires passing the `--allow-empty`
override flag to `git commit`, signifying that a user is very
intentionally creating such a commit and thus wants to keep
it.
@@ -298,7 +299,7 @@ flag exists as a convenient shortcut, such as for cases where external
tools generate many empty commits and you want them all removed.
+
For commits which do not start empty but become empty after rebasing,
-see the --empty flag.
+see the `--empty` flag.
+
See also INCOMPATIBLE OPTIONS below.
@@ -313,7 +314,7 @@ See also INCOMPATIBLE OPTIONS below.
By default (or if `--no-reapply-cherry-picks` is given), these commits
will be automatically dropped. Because this necessitates reading all
upstream commits, this can be expensive in repos with a large number
-of upstream commits that need to be read. When using the `merge`
+of upstream commits that need to be read. When using the 'merge'
backend, warnings will be issued for each dropped commit (unless
`--quiet` is given). Advice will also be issued unless
`advice.skippedCherryPicks` is set to false (see linkgit:git-config[1]).
@@ -347,10 +348,10 @@ See also INCOMPATIBLE OPTIONS below.
Using merging strategies to rebase (default).
+
Note that a rebase merge works by replaying each commit from the working
-branch on top of the <upstream> branch. Because of this, when a merge
+branch on top of the `<upstream>` branch. Because of this, when a merge
conflict happens, the side reported as 'ours' is the so-far rebased
-series, starting with <upstream>, and 'theirs' is the working branch. In
-other words, the sides are swapped.
+series, starting with `<upstream>`, and 'theirs' is the working branch.
+In other words, the sides are swapped.
+
See also INCOMPATIBLE OPTIONS below.
@@ -359,9 +360,9 @@ See also INCOMPATIBLE OPTIONS below.
Use the given merge strategy, instead of the default `ort`.
This implies `--merge`.
+
-Because 'git rebase' replays each commit from the working branch
-on top of the <upstream> branch using the given strategy, using
-the 'ours' strategy simply empties all patches from the <branch>,
+Because `git rebase` replays each commit from the working branch
+on top of the `<upstream>` branch using the given strategy, using
+the `ours` strategy simply empties all patches from the `<branch>`,
which makes little sense.
+
See also INCOMPATIBLE OPTIONS below.
@@ -391,11 +392,11 @@ See also INCOMPATIBLE OPTIONS below.
-q::
--quiet::
- Be quiet. Implies --no-stat.
+ Be quiet. Implies `--no-stat`.
-v::
--verbose::
- Be verbose. Implies --stat.
+ Be verbose. Implies `--stat`.
--stat::
Show a diffstat of what changed upstream since the last rebase. The
@@ -410,13 +411,13 @@ See also INCOMPATIBLE OPTIONS below.
--verify::
Allows the pre-rebase hook to run, which is the default. This option can
- be used to override --no-verify. See also linkgit:githooks[5].
+ be used to override `--no-verify`. See also linkgit:githooks[5].
-C<n>::
- Ensure at least <n> lines of surrounding context match before
+ Ensure at least `<n>` lines of surrounding context match before
and after each change. When fewer lines of surrounding
context exist they all must match. By default no context is
- ever ignored. Implies --apply.
+ ever ignored. Implies `--apply`.
+
See also INCOMPATIBLE OPTIONS below.
@@ -435,21 +436,21 @@ details).
--fork-point::
--no-fork-point::
- Use reflog to find a better common ancestor between <upstream>
- and <branch> when calculating which commits have been
- introduced by <branch>.
+ Use reflog to find a better common ancestor between `<upstream>`
+ and `<branch>` when calculating which commits have been
+ introduced by `<branch>`.
+
-When --fork-point is active, 'fork_point' will be used instead of
-<upstream> to calculate the set of commits to rebase, where
+When `--fork-point` is active, 'fork_point' will be used instead of
+`<upstream>` to calculate the set of commits to rebase, where
'fork_point' is the result of `git merge-base --fork-point <upstream>
<branch>` command (see linkgit:git-merge-base[1]). If 'fork_point'
-ends up being empty, the <upstream> will be used as a fallback.
+ends up being empty, the `<upstream>` will be used as a fallback.
+
-If <upstream> is given on the command line, then the default is
+If `<upstream>` is given on the command line, then the default is
`--no-fork-point`, otherwise the default is `--fork-point`. See also
`rebase.forkpoint` in linkgit:git-config[1].
+
-If your branch was based on <upstream> but <upstream> was rewound and
+If your branch was based on `<upstream>` but `<upstream>` was rewound and
your branch contains commits which were dropped, this option can be used
with `--keep-base` in order to drop those commits from your branch.
+
@@ -457,24 +458,26 @@ See also INCOMPATIBLE OPTIONS below.
--ignore-whitespace::
Ignore whitespace differences when trying to reconcile
-differences. Currently, each backend implements an approximation of
-this behavior:
+ 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.
+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.
+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>::
- This flag is 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.
+ Implies `--apply`.
+
See also INCOMPATIBLE OPTIONS below.
@@ -536,7 +539,7 @@ See also REBASING MERGES and INCOMPATIBLE OPTIONS below.
-x <cmd>::
--exec <cmd>::
Append "exec <cmd>" after each line creating a commit in the
- final history. <cmd> will be interpreted as one or more shell
+ final history. `<cmd>` will be interpreted as one or more shell
commands. Any command that fails will interrupt the rebase,
with exit code 1.
+
@@ -549,7 +552,7 @@ or by giving more than one `--exec`:
+
git rebase -i --exec "cmd1" --exec "cmd2" --exec ...
+
-If `--autosquash` is used, "exec" lines will not be appended for
+If `--autosquash` is used, `exec` lines will not be appended for
the intermediate commits, and will only appear at the end of each
squash/fixup series.
+
@@ -559,11 +562,12 @@ without an explicit `--interactive`.
See also INCOMPATIBLE OPTIONS below.
--root::
- Rebase all commits reachable from <branch>, instead of
- limiting them with an <upstream>. This allows you to rebase
- the root commit(s) on a branch. When used with --onto, it
- will skip changes already contained in <newbase> (instead of
- <upstream>) whereas without --onto it will operate on every change.
+ Rebase all commits reachable from `<branch>`, instead of
+ limiting them with an `<upstream>`. This allows you to rebase
+ the root commit(s) on a branch. When used with `--onto`, it
+ will skip changes already contained in `<newbase>` (instead of
+ `<upstream>`) whereas without `--onto` it will operate on every
+ change.
+
See also INCOMPATIBLE OPTIONS below.
@@ -608,6 +612,15 @@ provided. Otherwise an explicit `--no-reschedule-failed-exec` at the
start would be overridden by the presence of
`rebase.rescheduleFailedExec=true` configuration.
+--update-refs::
+--no-update-refs::
+ Automatically force-update any branches that point to commits that
+ are being rebased. Any branches that are checked out in a worktree
+ are not updated in this way.
++
+If the configuration variable `rebase.updateRefs` is set, then this option
+can be used to override and disable this setting.
+
INCOMPATIBLE OPTIONS
--------------------
@@ -631,6 +644,7 @@ are incompatible with the following options:
* --empty=
* --reapply-cherry-picks
* --edit-todo
+ * --update-refs
* --root when used in combination with --onto
In addition, the following pairs of options are incompatible:
@@ -642,9 +656,9 @@ In addition, the following pairs of options are incompatible:
BEHAVIORAL DIFFERENCES
-----------------------
-git rebase has two primary backends: apply and merge. (The apply
+`git rebase` has two primary backends: 'apply' and 'merge'. (The 'apply'
backend used to be known as the 'am' backend, but the name led to
-confusion as it looks like a verb instead of a noun. Also, the merge
+confusion as it looks like a verb instead of a noun. Also, the 'merge'
backend used to be known as the interactive backend, but it is now
used for non-interactive cases as well. Both were renamed based on
lower-level functionality that underpinned each.) There are some
@@ -653,19 +667,19 @@ subtle differences in how these two backends behave:
Empty commits
~~~~~~~~~~~~~
-The apply backend unfortunately drops intentionally empty commits, i.e.
+The 'apply' backend unfortunately drops intentionally empty commits, i.e.
commits that started empty, though these are rare in practice. It
also drops commits that become empty and has no option for controlling
this behavior.
-The merge backend keeps intentionally empty commits by default (though
-with -i they are marked as empty in the todo list editor, or they can
-be dropped automatically with --no-keep-empty).
+The 'merge' backend keeps intentionally empty commits by default (though
+with `-i` they are marked as empty in the todo list editor, or they can
+be dropped automatically with `--no-keep-empty`).
Similar to the apply backend, by default the merge backend drops
-commits that become empty unless -i/--interactive is specified (in
+commits that become empty unless `-i`/`--interactive` is specified (in
which case it stops and asks the user what to do). The merge backend
-also has an --empty={drop,keep,ask} option for changing the behavior
+also has an `--empty={drop,keep,ask}` option for changing the behavior
of handling commits that become empty.
Directory rename detection
@@ -673,20 +687,20 @@ Directory rename detection
Due to the lack of accurate tree information (arising from
constructing fake ancestors with the limited information available in
-patches), directory rename detection is disabled in the apply backend.
+patches), directory rename detection is disabled in the 'apply' backend.
Disabled directory rename detection means that if one side of history
renames a directory and the other adds new files to the old directory,
then the new files will be left behind in the old directory without
any warning at the time of rebasing that you may want to move these
files into the new directory.
-Directory rename detection works with the merge backend to provide you
+Directory rename detection works with the 'merge' backend to provide you
warnings in such cases.
Context
~~~~~~~
-The apply backend works by creating a sequence of patches (by calling
+The 'apply' backend works by creating a sequence of patches (by calling
`format-patch` internally), and then applying the patches in sequence
(calling `am` internally). Patches are composed of multiple hunks,
each with line numbers, a context region, and the actual changes. The
@@ -697,11 +711,11 @@ order to apply the changes to the right lines. However, if multiple
areas of the code have the same surrounding lines of context, the
wrong one can be picked. There are real-world cases where this has
caused commits to be reapplied incorrectly with no conflicts reported.
-Setting diff.context to a larger value may prevent such types of
+Setting `diff.context` to a larger value may prevent such types of
problems, but increases the chance of spurious conflicts (since it
will require more lines of matching context to apply).
-The merge backend works with a full copy of each relevant file,
+The 'merge' backend works with a full copy of each relevant file,
insulating it from these types of problems.
Labelling of conflicts markers
@@ -709,30 +723,30 @@ Labelling of conflicts markers
When there are content conflicts, the merge machinery tries to
annotate each side's conflict markers with the commits where the
-content came from. Since the apply backend drops the original
+content came from. Since the 'apply' backend drops the original
information about the rebased commits and their parents (and instead
generates new fake commits based off limited information in the
generated patches), those commits cannot be identified; instead it has
-to fall back to a commit summary. Also, when merge.conflictStyle is
-set to diff3 or zdiff3, the apply backend will use "constructed merge
+to fall back to a commit summary. Also, when `merge.conflictStyle` is
+set to `diff3` or `zdiff3`, the 'apply' backend will use "constructed merge
base" to label the content from the merge base, and thus provide no
information about the merge base commit whatsoever.
-The merge backend works with the full commits on both sides of history
+The 'merge' backend works with the full commits on both sides of history
and thus has no such limitations.
Hooks
~~~~~
-The apply backend has not traditionally called the post-commit hook,
-while the merge backend has. Both have called the post-checkout hook,
-though the merge backend has squelched its output. Further, both
+The 'apply' backend has not traditionally called the post-commit hook,
+while the 'merge' backend has. Both have called the post-checkout hook,
+though the 'merge' backend has squelched its output. Further, both
backends only call the post-checkout hook with the starting point
commit of the rebase, not the intermediate commits nor the final
commit. In each case, the calling of these hooks was by accident of
implementation rather than by design (both backends were originally
implemented as shell scripts and happened to invoke other commands
-like 'git checkout' or 'git commit' that would call the hooks). Both
+like `git checkout` or `git commit` that would call the hooks). Both
backends should have the same behavior, though it is not entirely
clear which, if any, is correct. We will likely make rebase stop
calling either of these hooks in the future.
@@ -740,10 +754,10 @@ calling either of these hooks in the future.
Interruptability
~~~~~~~~~~~~~~~~
-The apply backend has safety problems with an ill-timed interrupt; if
+The 'apply' backend has safety problems with an ill-timed interrupt; if
the user presses Ctrl-C at the wrong time to try to abort the rebase,
the rebase can enter a state where it cannot be aborted with a
-subsequent `git rebase --abort`. The merge backend does not appear to
+subsequent `git rebase --abort`. The 'merge' backend does not appear to
suffer from the same shortcoming. (See
https://lore.kernel.org/git/20200207132152.GC2868@szeder.dev/ for
details.)
@@ -755,8 +769,8 @@ When a conflict occurs while rebasing, rebase stops and asks the user
to resolve. Since the user may need to make notable changes while
resolving conflicts, after conflicts are resolved and the user has run
`git rebase --continue`, the rebase should open an editor and ask the
-user to update the commit message. The merge backend does this, while
-the apply backend blindly applies the original commit message.
+user to update the commit message. The 'merge' backend does this, while
+the 'apply' backend blindly applies the original commit message.
Miscellaneous differences
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -776,23 +790,23 @@ completeness:
them to stderr.
* State directories: The two backends keep their state in different
- directories under .git/
+ directories under `.git/`
include::merge-strategies.txt[]
NOTES
-----
-You should understand the implications of using 'git rebase' on a
+You should understand the implications of using `git rebase` on a
repository that you share. See also RECOVERING FROM UPSTREAM REBASE
below.
-When the git-rebase command is run, it will first execute a "pre-rebase"
-hook if one exists. You can use this hook to do sanity checks and
-reject the rebase if it isn't appropriate. Please see the template
-pre-rebase hook script for an example.
+When the rebase is run, it will first execute a `pre-rebase` hook if one
+exists. You can use this hook to do sanity checks and reject the rebase
+if it isn't appropriate. Please see the template `pre-rebase` hook script
+for an example.
-Upon completion, <branch> will be the current branch.
+Upon completion, `<branch>` will be the current branch.
INTERACTIVE MODE
----------------
@@ -847,7 +861,7 @@ not look at them but at the commit names ("deadbee" and "fa1afe1" in this
example), so do not delete or edit the names.
By replacing the command "pick" with the command "edit", you can tell
-'git rebase' to stop after applying that commit, so that you can edit
+`git rebase` to stop after applying that commit, so that you can edit
the files and/or the commit message, amend the commit, and continue
rebasing.
@@ -875,14 +889,13 @@ commit, the message from the final one is used. You can also use
"fixup -C" to get the same behavior as "fixup -c" except without opening
an editor.
-
-'git rebase' will stop when "pick" has been replaced with "edit" or
+`git rebase` will stop when "pick" has been replaced with "edit" or
when a command fails due to merge errors. When you are done editing
and/or resolving conflicts you can continue with `git rebase --continue`.
For example, if you want to reorder the last 5 commits, such that what
-was HEAD~4 becomes the new HEAD. To achieve that, you would call
-'git rebase' like this:
+was `HEAD~4` becomes the new `HEAD`. To achieve that, you would call
+`git rebase` like this:
----------------------
$ git rebase -i HEAD~5
@@ -902,7 +915,7 @@ like this:
------------------
Suppose you want to rebase the side branch starting at "A" to "Q". Make
-sure that the current HEAD is "B", and call
+sure that the current `HEAD` is "B", and call
-----------------------------
$ git rebase -i -r --onto Q O
@@ -955,23 +968,23 @@ SPLITTING COMMITS
-----------------
In interactive mode, you can mark commits with the action "edit". However,
-this does not necessarily mean that 'git rebase' expects the result of this
+this does not necessarily mean that `git rebase` expects the result of this
edit to be exactly one commit. Indeed, you can undo the commit, or you can
add other commits. This can be used to split a commit into two:
- Start an interactive rebase with `git rebase -i <commit>^`, where
- <commit> is the commit you want to split. In fact, any commit range
+ `<commit>` is the commit you want to split. In fact, any commit range
will do, as long as it contains that commit.
- Mark the commit you want to split with the action "edit".
- When it comes to editing that commit, execute `git reset HEAD^`. The
- effect is that the HEAD is rewound by one, and the index follows suit.
+ effect is that the `HEAD` is rewound by one, and the index follows suit.
However, the working tree stays the same.
- Now add the changes to the index that you want to have in the first
commit. You can use `git add` (possibly interactively) or
- 'git gui' (or both) to do that.
+ `git gui` (or both) to do that.
- Commit the now-current index with whatever commit message is appropriate
now.
@@ -982,7 +995,7 @@ add other commits. This can be used to split a commit into two:
If you are not absolutely sure that the intermediate revisions are
consistent (they compile, pass the testsuite, etc.) you should use
-'git stash' to stash away the not-yet-committed changes
+`git stash` to stash away the not-yet-committed changes
after each commit, test, and amend the commit if fixes are necessary.
@@ -1086,12 +1099,12 @@ NOTE: While an "easy case recovery" sometimes appears to be successful
example, a commit that was removed via `git rebase
--interactive` will be **resurrected**!
-The idea is to manually tell 'git rebase' "where the old 'subsystem'
+The idea is to manually tell `git rebase` "where the old 'subsystem'
ended and your 'topic' began", that is, what the old merge base
between them was. You will have to find a way to name the last commit
of the old 'subsystem', for example:
-* With the 'subsystem' reflog: after 'git fetch', the old tip of
+* With the 'subsystem' reflog: after `git fetch`, the old tip of
'subsystem' is at `subsystem@{1}`. Subsequent fetches will
increase the number. (See linkgit:git-reflog[1].)
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index cde9614..1dec314 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -35,6 +35,8 @@ OPTIONS
-v::
--verbose::
Be a little more verbose and show remote url after name.
+ For promisor remotes, also show which filter (`blob:none` etc.)
+ are configured.
NOTE: This must be placed between `remote` and subcommand.
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index ee30edc..0bf1389 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -63,6 +63,17 @@ to the new separate pack will be written.
Also run 'git prune-packed' to remove redundant
loose object files.
+--cruft::
+ Same as `-a`, unless `-d` is used. Then any unreachable objects
+ are packed into a separate cruft pack. Unreachable objects can
+ be pruned using the normal expiry rules with the next `git gc`
+ invocation (see linkgit:git-gc[1]). Incompatible with `-k`.
+
+--cruft-expiration=<approxidate>::
+ Expire unreachable objects older than `<approxidate>`
+ immediately instead of waiting for the next `git gc` invocation.
+ Only useful with `--cruft -d`.
+
-l::
Pass the `--local` option to 'git pack-objects'. See
linkgit:git-pack-objects[1].
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index 6f7685f..01cb4c9 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -105,10 +105,11 @@ OPTIONS
-q::
--quiet::
---no-quiet::
- Be quiet, only report errors. The default behavior is set by the
- `reset.quiet` config option. `--quiet` and `--no-quiet` will
- override the default behavior.
+ Be quiet, only report errors.
+
+--refresh::
+--no-refresh::
+ Refresh the index after a mixed reset. Enabled by default.
--pathspec-from-file=<file>::
Pathspec is passed in `<file>` instead of commandline args. If
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index bb92a4a..8463fe9 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -117,6 +117,15 @@ effect to your index in a row.
Allow the rerere mechanism to update the index with the
result of auto-conflict resolution if possible.
+--reference::
+ Instead of starting the body of the log message with "This
+ reverts <full object name of the commit being reverted>.",
+ refer to the commit using "--pretty=reference" format
+ (cf. linkgit:git-log[1]). The `revert.reference`
+ configuration variable can be used to enable this option by
+ default.
+
+
SEQUENCER SUBCOMMANDS
---------------------
include::sequencer.txt[]
diff --git a/Documentation/git-sparse-checkout.txt b/Documentation/git-sparse-checkout.txt
index 88e55f4..3776705 100644
--- a/Documentation/git-sparse-checkout.txt
+++ b/Documentation/git-sparse-checkout.txt
@@ -15,15 +15,15 @@ SYNOPSIS
DESCRIPTION
-----------
-This command is used to create sparse checkouts, which means that it
-changes the working tree from having all tracked files present, to only
-have a subset of them. It can also switch which subset of files are
-present, or undo and go back to having all tracked files present in the
-working copy.
+This command is used to create sparse checkouts, which change the
+working tree from having all tracked files present to only having a
+subset of those files. It can also switch which subset of files are
+present, or undo and go back to having all tracked files present in
+the working copy.
The subset of files is chosen by providing a list of directories in
-cone mode (which is recommended), or by providing a list of patterns
-in non-cone mode.
+cone mode (the default), or by providing a list of patterns in
+non-cone mode.
When in a sparse-checkout, other Git commands behave a bit differently.
For example, switching branches will not update paths outside the
@@ -44,9 +44,9 @@ COMMANDS
Enable the necessary sparse-checkout config settings
(`core.sparseCheckout`, `core.sparseCheckoutCone`, and
`index.sparse`) if they are not already set to the desired values,
- and write a set of patterns to the sparse-checkout file from the
- list of arguments following the 'set' subcommand. Update the
- working directory to match the new patterns.
+ populate the sparse-checkout file from the list of arguments
+ following the 'set' subcommand, and update the working directory to
+ match.
+
To ensure that adjusting the sparse-checkout settings within a worktree
does not alter the sparse-checkout settings in other worktrees, the 'set'
@@ -60,22 +60,20 @@ When the `--stdin` option is provided, the directories or patterns are
read from standard in as a newline-delimited list instead of from the
arguments.
+
-When `--cone` is passed or `core.sparseCheckoutCone` is enabled, the
-input list is considered a list of directories. This allows for
-better performance with a limited set of patterns (see 'CONE PATTERN
-SET' below). The input format matches the output of `git ls-tree
---name-only`. This includes interpreting pathnames that begin with a
-double quote (") as C-style quoted strings. Note that the set command
-will write patterns to the sparse-checkout file to include all files
-contained in those directories (recursively) as well as files that are
-siblings of ancestor directories. This may become the default in the
-future; --no-cone can be passed to request non-cone mode.
+By default, the input list is considered a list of directories, matching
+the output of `git ls-tree -d --name-only`. This includes interpreting
+pathnames that begin with a double quote (") as C-style quoted strings.
+Note that all files under the specified directories (at any depth) will
+be included in the sparse checkout, as well as files that are siblings
+of either the given directory or any of its ancestors (see 'CONE PATTERN
+SET' below for more details). In the past, this was not the default,
+and `--cone` needed to be specified or `core.sparseCheckoutCone` needed
+to be enabled.
+
-When `--no-cone` is passed or `core.sparseCheckoutCone` is not enabled,
-the input list is considered a list of patterns. This mode is harder
-to use and less performant, and is thus not recommended. See the
-"Sparse Checkout" section of linkgit:git-read-tree[1] and the "Pattern
-Set" sections below for more details.
+When `--no-cone` is passed, the input list is considered a list of
+patterns. This mode has a number of drawbacks, including not working
+with some options like `--sparse-index`. As explained in the
+"Non-cone Problems" section below, we do not recommend using it.
+
Use the `--[no-]sparse-index` option to use a sparse index (the
default is to not use it). A sparse index reduces the size of the
@@ -137,8 +135,45 @@ paths to pass to a subsequent 'set' or 'add' command. However,
the disable command, so the easy restore of calling a plain `init`
decreased in utility.
-SPARSE CHECKOUT
----------------
+EXAMPLES
+--------
+`git sparse-checkout set MY/DIR1 SUB/DIR2`::
+
+ Change to a sparse checkout with all files (at any depth) under
+ MY/DIR1/ and SUB/DIR2/ present in the working copy (plus all
+ files immediately under MY/ and SUB/ and the toplevel
+ directory). If already in a sparse checkout, change which files
+ are present in the working copy to this new selection. Note
+ that this command will also delete all ignored files in any
+ directory that no longer has either tracked or
+ non-ignored-untracked files present.
+
+`git sparse-checkout disable`::
+
+ Repopulate the working directory with all files, disabling sparse
+ checkouts.
+
+`git sparse-checkout add SOME/DIR/ECTORY`::
+
+ Add all files under SOME/DIR/ECTORY/ (at any depth) to the
+ sparse checkout, as well as all files immediately under
+ SOME/DIR/ and immediately under SOME/. Must already be in a
+ sparse checkout before using this command.
+
+`git sparse-checkout reapply`::
+
+ It is possible for commands to update the working tree in a
+ way that does not respect the selected sparsity directories.
+ This can come from tools external to Git writing files, or
+ even affect Git commands because of either special cases (such
+ as hitting conflicts when merging/rebasing), or because some
+ commands didn't fully support sparse checkouts (e.g. the old
+ `recursive` merge backend had only limited support). This
+ command reapplies the existing sparse directory specifications
+ to make the working directory match.
+
+INTERNALS -- SPARSE CHECKOUT
+----------------------------
"Sparse checkout" allows populating the working directory sparsely. It
uses the skip-worktree bit (see linkgit:git-update-index[1]) to tell Git
@@ -155,64 +190,196 @@ directory, it updates the skip-worktree bits in the index based
on this file. The files matching the patterns in the file will
appear in the working directory, and the rest will not.
-To enable the sparse-checkout feature, run `git sparse-checkout set` to
-set the patterns you want to use.
+INTERNALS -- NON-CONE PROBLEMS
+------------------------------
+
+The `$GIT_DIR/info/sparse-checkout` file populated by the `set` and
+`add` subcommands is defined to be a bunch of patterns (one per line)
+using the same syntax as `.gitignore` files. In cone mode, these
+patterns are restricted to matching directories (and users only ever
+need supply or see directory names), while in non-cone mode any
+gitignore-style pattern is permitted. Using the full gitignore-style
+patterns in non-cone mode has a number of shortcomings:
+
+ * Fundamentally, it makes various worktree-updating processes (pull,
+ merge, rebase, switch, reset, checkout, etc.) require O(N*M) pattern
+ matches, where N is the number of patterns and M is the number of
+ paths in the index. This scales poorly.
+
+ * Avoiding the scaling issue has to be done via limiting the number
+ of patterns via specifying leading directory name or glob.
+
+ * Passing globs on the command line is error-prone as users may
+ forget to quote the glob, causing the shell to expand it into all
+ matching files and pass them all individually along to
+ sparse-checkout set/add. While this could also be a problem with
+ e.g. "git grep -- *.c", mistakes with grep/log/status appear in
+ the immediate output. With sparse-checkout, the mistake gets
+ recorded at the time the sparse-checkout command is run and might
+ not be problematic until the user later switches branches or rebases
+ or merges, thus putting a delay between the user's error and when
+ they have a chance to catch/notice it.
+
+ * Related to the previous item, sparse-checkout has an 'add'
+ subcommand but no 'remove' subcommand. Even if a 'remove'
+ subcommand were added, undoing an accidental unquoted glob runs
+ the risk of "removing too much", as it may remove entries that had
+ been included before the accidental add.
+
+ * Non-cone mode uses gitignore-style patterns to select what to
+ *include* (with the exception of negated patterns), while
+ .gitignore files use gitignore-style patterns to select what to
+ *exclude* (with the exception of negated patterns). The
+ documentation on gitignore-style patterns usually does not talk in
+ terms of matching or non-matching, but on what the user wants to
+ "exclude". This can cause confusion for users trying to learn how
+ to specify sparse-checkout patterns to get their desired behavior.
+
+ * Every other git subcommand that wants to provide "special path
+ pattern matching" of some sort uses pathspecs, but non-cone mode
+ for sparse-checkout uses gitignore patterns, which feels
+ inconsistent.
+
+ * It has edge cases where the "right" behavior is unclear. Two examples:
+
+ First, two users are in a subdirectory, and the first runs
+ git sparse-checkout set '/toplevel-dir/*.c'
+ while the second runs
+ git sparse-checkout set relative-dir
+ Should those arguments be transliterated into
+ current/subdirectory/toplevel-dir/*.c
+ and
+ current/subdirectory/relative-dir
+ before inserting into the sparse-checkout file? The user who typed
+ the first command is probably aware that arguments to set/add are
+ supposed to be patterns in non-cone mode, and probably would not be
+ happy with such a transliteration. However, many gitignore-style
+ patterns are just paths, which might be what the user who typed the
+ second command was thinking, and they'd be upset if their argument
+ wasn't transliterated.
+
+ Second, what should bash-completion complete on for set/add commands
+ for non-cone users? If it suggests paths, is it exacerbating the
+ problem above? Also, if it suggests paths, what if the user has a
+ file or directory that begins with either a '!' or '#' or has a '*',
+ '\', '?', '[', or ']' in its name? And if it suggests paths, will
+ it complete "/pro" to "/proc" (in the root filesytem) rather than to
+ "/progress.txt" in the current directory? (Note that users are
+ likely to want to start paths with a leading '/' in non-cone mode,
+ for the same reason that .gitignore files often have one.)
+ Completing on files or directories might give nasty surprises in
+ all these cases.
+
+ * The excessive flexibility made other extensions essentially
+ impractical. `--sparse-index` is likely impossible in non-cone
+ mode; even if it is somehow feasible, it would have been far more
+ work to implement and may have been too slow in practice. Some
+ ideas for adding coupling between partial clones and sparse
+ checkouts are only practical with a more restricted set of paths
+ as well.
+
+For all these reasons, non-cone mode is deprecated. Please switch to
+using cone mode.
+
+
+INTERNALS -- CONE MODE HANDLING
+-------------------------------
+
+The "cone mode", which is the default, lets you specify only what
+directories to include. For any directory specified, all paths below
+that directory will be included, and any paths immediately under
+leading directories (including the toplevel directory) will also be
+included. Thus, if you specified the directory
+ Documentation/technical/
+then your sparse checkout would contain:
+
+ * all files in the toplevel-directory
+ * all files immediately under Documentation/
+ * all files at any depth under Documentation/technical/
+
+Also, in cone mode, even if no directories are specified, then the
+files in the toplevel directory will be included.
-To repopulate the working directory with all files, use the
-`git sparse-checkout disable` command.
+When changing the sparse-checkout patterns in cone mode, Git will inspect each
+tracked directory that is not within the sparse-checkout cone to see if it
+contains any untracked files. If all of those files are ignored due to the
+`.gitignore` patterns, then the directory will be deleted. If any of the
+untracked files within that directory is not ignored, then no deletions will
+occur within that directory and a warning message will appear. If these files
+are important, then reset your sparse-checkout definition so they are included,
+use `git add` and `git commit` to store them, then remove any remaining files
+manually to ensure Git can behave optimally.
+See also the "Internals -- Cone Pattern Set" section to learn how the
+directories are transformed under the hood into a subset of the
+Full Pattern Set of sparse-checkout.
-FULL PATTERN SET
-----------------
-By default, the sparse-checkout file uses the same syntax as `.gitignore`
-files.
+INTERNALS -- FULL PATTERN SET
+-----------------------------
-While `$GIT_DIR/info/sparse-checkout` is usually used to specify what
-files are included, you can also specify what files are _not_ included,
-using negative patterns. For example, to remove the file `unwanted`:
+The full pattern set allows for arbitrary pattern matches and complicated
+inclusion/exclusion rules. These can result in O(N*M) pattern matches when
+updating the index, where N is the number of patterns and M is the number
+of paths in the index. To combat this performance issue, a more restricted
+pattern set is allowed when `core.sparseCheckoutCone` is enabled.
+
+The sparse-checkout file uses the same syntax as `.gitignore` files;
+see linkgit:gitignore[5] for details. Here, though, the patterns are
+usually being used to select which files to include rather than which
+files to exclude. (However, it can get a bit confusing since
+gitignore-style patterns have negations defined by patterns which
+begin with a '!', so you can also select files to _not_ include.)
+
+For example, to select everything, and then to remove the file
+`unwanted` (so that every file will appear in your working tree except
+the file named `unwanted`):
+
+ git sparse-checkout set --no-cone '/*' '!unwanted'
+
+These patterns are just placed into the
+`$GIT_DIR/info/sparse-checkout` as-is, so the contents of that file
+at this point would be
----------------
/*
!unwanted
----------------
+See also the "Sparse Checkout" section of linkgit:git-read-tree[1] to
+learn more about the gitignore-style patterns used in sparse
+checkouts.
-CONE PATTERN SET
-----------------
-The full pattern set allows for arbitrary pattern matches and complicated
-inclusion/exclusion rules. These can result in O(N*M) pattern matches when
-updating the index, where N is the number of patterns and M is the number
-of paths in the index. To combat this performance issue, a more restricted
-pattern set is allowed when `core.sparseCheckoutCone` is enabled.
+INTERNALS -- CONE PATTERN SET
+-----------------------------
-The accepted patterns in the cone pattern set are:
+In cone mode, only directories are accepted, but they are translated into
+the same gitignore-style patterns used in the full pattern set. We refer
+to the particular patterns used in those mode as being of one of two types:
1. *Recursive:* All paths inside a directory are included.
2. *Parent:* All files immediately inside a directory are included.
-In addition to the above two patterns, we also expect that all files in the
-root directory are included. If a recursive pattern is added, then all
-leading directories are added as parent patterns.
-
-By default, when running `git sparse-checkout init`, the root directory is
-added as a parent pattern. At this point, the sparse-checkout file contains
-the following patterns:
+Since cone mode always includes files at the toplevel, when running
+`git sparse-checkout set` with no directories specified, the toplevel
+directory is added as a parent pattern. At this point, the
+sparse-checkout file contains the following patterns:
----------------
/*
!/*/
----------------
-This says "include everything in root, but nothing two levels below root."
+This says "include everything immediately under the toplevel
+directory, but nothing at any level below that."
-When in cone mode, the `git sparse-checkout set` subcommand takes a list of
-directories instead of a list of sparse-checkout patterns. In this mode,
-the command `git sparse-checkout set A/B/C` sets the directory `A/B/C` as
-a recursive pattern, the directories `A` and `A/B` are added as parent
-patterns. The resulting sparse-checkout file is now
+When in cone mode, the `git sparse-checkout set` subcommand takes a
+list of directories. The command `git sparse-checkout set A/B/C` sets
+the directory `A/B/C` as a recursive pattern, the directories `A` and
+`A/B` are added as parent patterns. The resulting sparse-checkout file
+is now
----------------
/*
@@ -227,14 +394,18 @@ patterns. The resulting sparse-checkout file is now
Here, order matters, so the negative patterns are overridden by the positive
patterns that appear lower in the file.
-If `core.sparseCheckoutCone=true`, then Git will parse the sparse-checkout file
-expecting patterns of these types. Git will warn if the patterns do not match.
-If the patterns do match the expected format, then Git will use faster hash-
-based algorithms to compute inclusion in the sparse-checkout.
+Unless `core.sparseCheckoutCone` is explicitly set to `false`, Git will
+parse the sparse-checkout file expecting patterns of these types. Git will
+warn if the patterns do not match. If the patterns do match the expected
+format, then Git will use faster hash-based algorithms to compute inclusion
+in the sparse-checkout. If they do not match, git will behave as though
+`core.sparseCheckoutCone` was false, regardless of its setting.
-In the cone mode case, the `git sparse-checkout list` subcommand will list the
-directories that define the recursive patterns. For the example sparse-checkout
-file above, the output is as follows:
+In the cone mode case, despite the fact that full patterns are written
+to the $GIT_DIR/info/sparse-checkout file, the `git sparse-checkout
+list` subcommand will list the directories that define the recursive
+patterns. For the example sparse-checkout file above, the output is as
+follows:
--------------------------
$ git sparse-checkout list
@@ -246,19 +417,9 @@ case-insensitive check. This corrects for case mismatched filenames in the
'git sparse-checkout set' command to reflect the expected cone in the working
directory.
-When changing the sparse-checkout patterns in cone mode, Git will inspect each
-tracked directory that is not within the sparse-checkout cone to see if it
-contains any untracked files. If all of those files are ignored due to the
-`.gitignore` patterns, then the directory will be deleted. If any of the
-untracked files within that directory is not ignored, then no deletions will
-occur within that directory and a warning message will appear. If these files
-are important, then reset your sparse-checkout definition so they are included,
-use `git add` and `git commit` to store them, then remove any remaining files
-manually to ensure Git can behave optimally.
-
-SUBMODULES
-----------
+INTERNALS -- SUBMODULES
+-----------------------
If your repository contains one or more submodules, then submodules
are populated based on interactions with the `git submodule` command.
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 568dbfe..5ea2f2c 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -527,7 +527,9 @@ FILE SYSTEM MONITOR
This feature is intended to speed up git operations for repos that have
large working directories.
-It enables git to work together with a file system monitor (see the
+It enables git to work together with a file system monitor (see
+linkgit:git-fsmonitor{litdd}daemon[1]
+and the
"fsmonitor-watchman" section of linkgit:githooks[5]) that can
inform it as to what files have been modified. This enables git to avoid
having to lstat() every file to find modified files.
@@ -538,8 +540,8 @@ looking for new files.
If you want to enable (or disable) this feature, it is easier to use
the `core.fsmonitor` configuration variable (see
-linkgit:git-config[1]) than using the `--fsmonitor` option to
-`git update-index` in each repository, especially if you want to do so
+linkgit:git-config[1]) than using the `--fsmonitor` option to `git
+update-index` in each repository, especially if you want to do so
across all repositories you use, because you can set the configuration
variable in your `$HOME/.gitconfig` just once and have it affect all
repositories you touch.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 453e155..ada30c8 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason <string>]] [-b <new-branch>] <path> [<commit-ish>]
-'git worktree list' [-v | --porcelain]
+'git worktree list' [-v | --porcelain [-z]]
'git worktree lock' [--reason <string>] <worktree>
'git worktree move' <worktree> <new-path>
'git worktree prune' [-n] [-v] [--expire <expire>]
@@ -224,7 +224,14 @@ This can also be set up as the default behaviour by using the
--porcelain::
With `list`, output in an easy-to-parse format for scripts.
This format will remain stable across Git versions and regardless of user
- configuration. See below for details.
+ configuration. It is recommended to combine this with `-z`.
+ See below for details.
+
+-z::
+ Terminate each line with a NUL rather than a newline when
+ `--porcelain` is specified with `list`. This makes it possible
+ to parse the output when a worktree path contains a newline
+ character.
-q::
--quiet::
@@ -416,7 +423,8 @@ worktree itself.
Porcelain Format
~~~~~~~~~~~~~~~~
-The porcelain format has a line per attribute. Attributes are listed with a
+The porcelain format has a line per attribute. If `-z` is given then the lines
+are terminated with NUL rather than a newline. Attributes are listed with a
label and value separated by a single space. Boolean attributes (like `bare`
and `detached`) are listed as a label only, and are present only
if the value is true. Some attributes (like `locked`) can be listed as a label
@@ -454,7 +462,7 @@ prunable gitdir file points to non-existent location
------------
-If the lock reason contains "unusual" characters such as newline, they
+Unless `-z` is used any "unusual" characters in the lock reason such as newlines
are escaped and the entire reason is quoted as explained for the
configuration variable `core.quotePath` (see linkgit:git-config[1]).
For Example:
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 13f83a2..47a6095 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -9,7 +9,7 @@ git - the stupid content tracker
SYNOPSIS
--------
[verse]
-'git' [--version] [--help] [-C <path>] [-c <name>=<value>]
+'git' [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
@@ -39,6 +39,7 @@ or https://git-scm.com/docs.
OPTIONS
-------
+-v::
--version::
Prints the Git suite version that the 'git' program came from.
+
@@ -46,6 +47,7 @@ This option is internally converted to `git version ...` and accepts
the same options as the linkgit:git-version[1] command. If `--help` is
also given, it takes precedence over `--version`.
+-h::
--help::
Prints the synopsis and a list of the most commonly used
commands. If the option `--all` or `-a` is given then all
@@ -883,9 +885,7 @@ for full details.
If set to a colon-separated list of protocols, behave as if
`protocol.allow` is set to `never`, and each of the listed
protocols has `protocol.<name>.allow` set to `always`
- (overriding any existing configuration). In other words, any
- protocol not mentioned will be disallowed (i.e., this is a
- whitelist, not a blacklist). See the description of
+ (overriding any existing configuration). See the description of
`protocol.allow` in linkgit:git-config[1] for more details.
`GIT_PROTOCOL_FROM_USER`::
diff --git a/Documentation/mergetools/vimdiff.txt b/Documentation/mergetools/vimdiff.txt
new file mode 100644
index 0000000..2d631e9
--- /dev/null
+++ b/Documentation/mergetools/vimdiff.txt
@@ -0,0 +1,194 @@
+Description
+^^^^^^^^^^^
+
+When specifying `--tool=vimdiff` in `git mergetool` Git will open Vim with a 4
+windows layout distributed in the following way:
+....
+------------------------------------------
+| | | |
+| LOCAL | BASE | REMOTE |
+| | | |
+------------------------------------------
+| |
+| MERGED |
+| |
+------------------------------------------
+....
+`LOCAL`, `BASE` and `REMOTE` are read-only buffers showing the contents of the
+conflicting file in specific commits ("commit you are merging into", "common
+ancestor commit" and "commit you are merging from" respectively)
+
+`MERGED` is a writable buffer where you have to resolve the conflicts (using the
+other read-only buffers as a reference). Once you are done, save and exit Vim as
+usual (`:wq`) or, if you want to abort, exit using `:cq`.
+
+Layout configuration
+^^^^^^^^^^^^^^^^^^^^
+
+You can change the windows layout used by Vim by setting configuration variable
+`mergetool.vimdiff.layout` which accepts a string where the following separators
+have special meaning:
+
+ - `+` is used to "open a new tab"
+ - `,` is used to "open a new vertical split"
+ - `/` is used to "open a new horizontal split"
+ - `@` is used to indicate which is the file containing the final version after
+ solving the conflicts. If not present, `MERGED` will be used by default.
+
+The precedence of the operators is this one (you can use parentheses to change
+it):
+
+ `@` > `+` > `/` > `,`
+
+Let's see some examples to understand how it works:
+
+* `layout = "(LOCAL,BASE,REMOTE)/MERGED"`
++
+--
+This is exactly the same as the default layout we have already seen.
+
+Note that `/` has precedence over `,` and thus the parenthesis are not
+needed in this case. The next layout definition is equivalent:
+
+ layout = "LOCAL,BASE,REMOTE / MERGED"
+--
+* `layout = "LOCAL,MERGED,REMOTE"`
++
+--
+If, for some reason, we are not interested in the `BASE` buffer.
+....
+------------------------------------------
+| | | |
+| | | |
+| LOCAL | MERGED | REMOTE |
+| | | |
+| | | |
+------------------------------------------
+....
+--
+* `layout = "MERGED"`
++
+--
+Only the `MERGED` buffer will be shown. Note, however, that all the other
+ones are still loaded in vim, and you can access them with the "buffers"
+command.
+....
+------------------------------------------
+| |
+| |
+| MERGED |
+| |
+| |
+------------------------------------------
+....
+--
+* `layout = "@LOCAL,REMOTE"`
++
+--
+When `MERGED` is not present in the layout, you must "mark" one of the
+buffers with an asterisk. That will become the buffer you need to edit and
+save after resolving the conflicts.
+....
+------------------------------------------
+| | |
+| | |
+| | |
+| LOCAL | REMOTE |
+| | |
+| | |
+| | |
+------------------------------------------
+....
+--
+* `layout = "LOCAL,BASE,REMOTE / MERGED + BASE,LOCAL + BASE,REMOTE"`
++
+--
+Three tabs will open: the first one is a copy of the default layout, while
+the other two only show the differences between (`BASE` and `LOCAL`) and
+(`BASE` and `REMOTE`) respectively.
+....
+------------------------------------------
+| <TAB #1> | TAB #2 | TAB #3 | |
+------------------------------------------
+| | | |
+| LOCAL | BASE | REMOTE |
+| | | |
+------------------------------------------
+| |
+| MERGED |
+| |
+------------------------------------------
+....
+....
+------------------------------------------
+| TAB #1 | <TAB #2> | TAB #3 | |
+------------------------------------------
+| | |
+| | |
+| | |
+| BASE | LOCAL |
+| | |
+| | |
+| | |
+------------------------------------------
+....
+....
+------------------------------------------
+| TAB #1 | TAB #2 | <TAB #3> | |
+------------------------------------------
+| | |
+| | |
+| | |
+| BASE | REMOTE |
+| | |
+| | |
+| | |
+------------------------------------------
+....
+--
+* `layout = "LOCAL,BASE,REMOTE / MERGED + BASE,LOCAL + BASE,REMOTE + (LOCAL/BASE/REMOTE),MERGED"`
++
+--
+Same as the previous example, but adds a fourth tab with the same
+information as the first tab, with a different layout.
+....
+---------------------------------------------
+| TAB #1 | TAB #2 | TAB #3 | <TAB #4> |
+---------------------------------------------
+| LOCAL | |
+|---------------------| |
+| BASE | MERGED |
+|---------------------| |
+| REMOTE | |
+---------------------------------------------
+....
+Note how in the third tab definition we need to use parenthesis to make `,`
+have precedence over `/`.
+--
+
+Variants
+^^^^^^^^
+
+Instead of `--tool=vimdiff`, you can also use one of these other variants:
+
+ * `--tool=gvimdiff`, to open gVim instead of Vim.
+
+ * `--tool=nvimdiff`, to open Neovim instead of Vim.
+
+When using these variants, in order to specify a custom layout you will have to
+set configuration variables `mergetool.gvimdiff.layout` and
+`mergetool.nvimdiff.layout` instead of `mergetool.vimdiff.layout`
+
+In addition, for backwards compatibility with previous Git versions, you can
+also append `1`, `2` or `3` to either `vimdiff` or any of the variants (ex:
+`vimdiff3`, `nvimdiff1`, etc...) to use a predefined layout.
+In other words, using `--tool=[g,n,]vimdiffx` is the same as using
+`--tool=[g,n,]vimdiff` and setting configuration variable
+`mergetool.[g,n,]vimdiff.layout` to...
+
+ * `x=1`: `"@LOCAL, REMOTE"`
+ * `x=2`: `"LOCAL, MERGED, REMOTE"`
+ * `x=3`: `"MERGED"`
+
+Example: using `--tool=gvimdiff2` will open `gvim` with three columns (LOCAL,
+MERGED and REMOTE).
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index fd4f4e2..195e74e 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -25,6 +25,11 @@ ordering and formatting options, such as `--reverse`.
--after=<date>::
Show commits more recent than a specific date.
+--since-as-filter=<date>::
+ Show all commits more recent than a specific date. This visits
+ all commits in the range, rather than stopping at the first commit which
+ is older than a specific date.
+
--until=<date>::
--before=<date>::
Show commits older than a specific date.
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index f5f17b6..e3e3501 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -96,19 +96,16 @@ some output processing may assume ref names in UTF-8.
before the current one.
'[<branchname>]@\{upstream\}', e.g. 'master@\{upstream\}', '@\{u\}'::
- The suffix '@\{upstream\}' to a branchname (short form '<branchname>@\{u\}')
- refers to the branch that the branch specified by branchname is set to build on
- top of (configured with `branch.<name>.remote` and
- `branch.<name>.merge`). A missing branchname defaults to the
- current one. These suffixes are also accepted when spelled in uppercase, and
- they mean the same thing no matter the case.
+ A branch B may be set up to build on top of a branch X (configured with
+ `branch.<name>.merge`) at a remote R (configured with
+ `branch.<name>.remote`). B@{u} refers to the remote-tracking branch for
+ the branch X taken from remote R, typically found at `refs/remotes/R/X`.
'[<branchname>]@\{push\}', e.g. 'master@\{push\}', '@\{push\}'::
The suffix '@\{push}' reports the branch "where we would push to" if
`git push` were run while `branchname` was checked out (or the current
- `HEAD` if no branchname is specified). Since our push destination is
- in a remote repository, of course, we report the local tracking branch
- that corresponds to that branch (i.e., something in `refs/remotes/`).
+ `HEAD` if no branchname is specified). Like for '@\{upstream\}', we report
+ the remote-tracking branch that corresponds to that branch at the remote.
+
Here's an example to make it more clear:
+
@@ -283,7 +280,7 @@ The '..' (two-dot) Range Notation::
for commits that are reachable from r2 excluding those that are reachable
from r1 by '{caret}r1 r2' and it can be written as 'r1..r2'.
-The '...' (three-dot) Symmetric Difference Notation::
+The '\...' (three-dot) Symmetric Difference Notation::
A similar notation 'r1\...r2' is called symmetric difference
of 'r1' and 'r2' and is defined as
'r1 r2 --not $(git merge-base --all r1 r2)'.
diff --git a/Documentation/technical/api-error-handling.txt b/Documentation/technical/api-error-handling.txt
index 8be4f4d..70bf1d3 100644
--- a/Documentation/technical/api-error-handling.txt
+++ b/Documentation/technical/api-error-handling.txt
@@ -1,12 +1,34 @@
Error reporting in git
======================
-`BUG`, `die`, `usage`, `error`, and `warning` report errors of
+`BUG`, `bug`, `die`, `usage`, `error`, and `warning` report errors of
various kinds.
- `BUG` is for failed internal assertions that should never happen,
i.e. a bug in git itself.
+- `bug` (lower-case, not `BUG`) is supposed to be used like `BUG` but
+ prints a "BUG" message instead of calling `abort()`.
++
+A call to `bug()` will then result in a "real" call to the `BUG()`
+function, either explicitly by invoking `BUG_if_bug()` after call(s)
+to `bug()`, or implicitly at `exit()` time where we'll check if we
+encountered any outstanding `bug()` invocations.
++
+If there were no prior calls to `bug()` before invoking `BUG_if_bug()`
+the latter is a NOOP. The `BUG_if_bug()` function takes the same
+arguments as `BUG()` itself. Calling `BUG_if_bug()` explicitly isn't
+necessary, but ensures that we die as soon as possible.
++
+If you know you had prior calls to `bug()` then calling `BUG()` itself
+is equivalent to calling `BUG_if_bug()`, the latter being a wrapper
+calling `BUG()` if we've set a flag indicating that we've called
+`bug()`.
++
+This is for the convenience of APIs who'd like to potentially report
+more than one "bug", such as the optbug() validation in
+parse-options.c.
+
- `die` is for fatal application errors. It prints a message to
the user and exits with status 128.
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt
index bb13ca3..77a150b 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -5,7 +5,7 @@ information to stderr or a file. The Trace2 feature is inactive unless
explicitly enabled by enabling one or more Trace2 Targets.
The Trace2 API is intended to replace the existing (Trace1)
-printf-style tracing provided by the existing `GIT_TRACE` and
+`printf()`-style tracing provided by the existing `GIT_TRACE` and
`GIT_TRACE_PERFORMANCE` facilities. During initial implementation,
Trace2 and Trace1 may operate in parallel.
@@ -24,8 +24,8 @@ for example.
Trace2 is controlled using `trace2.*` config values in the system and
global config files and `GIT_TRACE2*` environment variables. Trace2 does
-not read from repo local or worktree config files or respect `-c`
-command line config settings.
+not read from repo local or worktree config files, nor does it respect
+`-c` command line config settings.
== Trace2 Targets
@@ -34,8 +34,8 @@ Format details are given in a later section.
=== The Normal Format Target
-The normal format target is a tradition printf format and similar
-to GIT_TRACE format. This format is enabled with the `GIT_TRACE2`
+The normal format target is a traditional `printf()` format and similar
+to the `GIT_TRACE` format. This format is enabled with the `GIT_TRACE2`
environment variable or the `trace2.normalTarget` system or global
config setting.
@@ -69,8 +69,8 @@ $ cat ~/log.normal
=== The Performance Format Target
The performance format target (PERF) is a column-based format to
-replace GIT_TRACE_PERFORMANCE and is suitable for development and
-testing, possibly to complement tools like gprof. This format is
+replace `GIT_TRACE_PERFORMANCE` and is suitable for development and
+testing, possibly to complement tools like `gprof`. This format is
enabled with the `GIT_TRACE2_PERF` environment variable or the
`trace2.perfTarget` system or global config setting.
@@ -128,7 +128,7 @@ yields
------------
$ cat ~/log.event
-{"event":"version","sid":"sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"3","exe":"2.20.1.155.g426c96fcdb"}
+{"event":"version","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"3","exe":"2.20.1.155.g426c96fcdb"}
{"event":"start","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621027Z","file":"common-main.c","line":39,"t_abs":0.001173,"argv":["git","version"]}
{"event":"cmd_name","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621122Z","file":"git.c","line":432,"name":"version","hierarchy":"version"}
{"event":"exit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621236Z","file":"git.c","line":662,"t_abs":0.001227,"code":0}
@@ -170,9 +170,9 @@ Some functions have a `_va_fl()` suffix to indicate that they also
take a `va_list` argument.
Some functions have a `_printf_fl()` suffix to indicate that they also
-take a varargs argument.
+take a `printf()` style format with a variable number of arguments.
-There are CPP wrapper macros and ifdefs to hide most of these details.
+There are CPP wrapper macros and `#ifdef`s to hide most of these details.
See `trace2.h` for more details. The following discussion will only
describe the simplified forms.
@@ -234,7 +234,7 @@ Events are written as lines of the form:
is the event name.
`<event-message>`::
- is a free-form printf message intended for human consumption.
+ is a free-form `printf()` message intended for human consumption.
+
Note that this may contain embedded LF or CRLF characters that are
not escaped, so the event may spill across multiple lines.
@@ -300,7 +300,7 @@ This field is in anticipation of in-proc submodules in the future.
indicate a broad category, such as "index" or "status".
`<perf-event-message>`::
- is a free-form printf message intended for human consumption.
+ is a free-form `printf()` message intended for human consumption.
------------
15:33:33.532712 wt-status.c:2310 | d0 | main | region_enter | r1 | 0.126064 | | status | label:print
@@ -465,8 +465,8 @@ completed.)
------------
`"error"`::
- This event is emitted when one of the `BUG()`, `error()`, `die()`,
- `warning()`, or `usage()` functions are called.
+ This event is emitted when one of the `BUG()`, `bug()`, `error()`,
+ `die()`, `warning()`, or `usage()` functions are called.
+
------------
{
@@ -533,7 +533,7 @@ these special values are used:
------------
`"cmd_mode"`::
- This event, when present, describes the command variant This
+ This event, when present, describes the command variant. This
event may be emitted more than once.
+
------------
@@ -588,7 +588,7 @@ with "?".
`"child_exit"`::
This event is generated after the current process has returned
- from the waitpid() and collected the exit information from the
+ from the `waitpid()` and collected the exit information from the
child.
+
------------
@@ -609,7 +609,7 @@ process may be a shell script which doesn't have a session-id.)
+
Note that the `t_rel` field contains the observed run time in seconds
for the child process (starting before the fork/exec/spawn and
-stopping after the waitpid() and includes OS process creation overhead).
+stopping after the `waitpid()` and includes OS process creation overhead).
So this time will be slightly larger than the atexit time reported by
the child process itself.
@@ -635,7 +635,7 @@ process may be a shell script which doesn't have a session-id.)
+
This event is generated after the child is started in the background
and given a little time to boot up and start working. If the child
-startups normally and while the parent is still waiting, the "ready"
+starts up normally while the parent is still waiting, the "ready"
field will have the value "ready".
If the child is too slow to start and the parent times out, the field
will have the value "timeout".
@@ -949,7 +949,7 @@ atexit elapsed:3.868970 code:0
Regions::
- Regions can be use to time an interesting section of code.
+ Regions can be used to time an interesting section of code.
+
----------------
void wt_status_collect(struct wt_status *s)
@@ -1103,9 +1103,9 @@ Thread Events::
Thread messages added to a thread-proc.
+
-For example, the multithreaded preload-index code can be
+For example, the multi-threaded preload-index code can be
instrumented with a region around the thread pool and then
-per-thread start and exit events within the threadproc.
+per-thread start and exit events within the thread-proc.
+
----------------
static void *preload_thread(void *_data)
@@ -1214,11 +1214,11 @@ as each thread starts and allocates TLS storage.
There are a few issues to resolve before we can completely
switch to Trace2.
-* Updating existing tests that assume GIT_TRACE format messages.
+* Updating existing tests that assume `GIT_TRACE` format messages.
-* How to best handle custom GIT_TRACE_<key> messages?
+* How to best handle custom `GIT_TRACE_<key>` messages?
-** The GIT_TRACE_<key> mechanism allows each <key> to write to a
+** The `GIT_TRACE_<key>` mechanism allows each <key> to write to a
different file (in addition to just stderr).
** Do we want to maintain that ability or simply write to the existing
diff --git a/Documentation/technical/bitmap-format.txt b/Documentation/technical/bitmap-format.txt
index 04b3ec2..a85f58f 100644
--- a/Documentation/technical/bitmap-format.txt
+++ b/Documentation/technical/bitmap-format.txt
@@ -25,9 +25,9 @@ An object is uniquely described by its bit position within a bitmap:
is defined as follows:
o1 <= o2 <==> pack(o1) <= pack(o2) /\ offset(o1) <= offset(o2)
-
- The ordering between packs is done according to the MIDX's .rev file.
- Notably, the preferred pack sorts ahead of all other packs.
++
+The ordering between packs is done according to the MIDX's .rev file.
+Notably, the preferred pack sorts ahead of all other packs.
The on-disk representation (described below) of a bitmap is the same regardless
of whether or not that bitmap belongs to a packfile or a MIDX. The only
@@ -39,97 +39,108 @@ MIDXs, both the bit-cache and rev-cache extensions are required.
== On-disk format
- - A header appears at the beginning:
-
- 4-byte signature: {'B', 'I', 'T', 'M'}
-
- 2-byte version number (network byte order)
- The current implementation only supports version 1
- of the bitmap index (the same one as JGit).
-
- 2-byte flags (network byte order)
-
- The following flags are supported:
-
- - BITMAP_OPT_FULL_DAG (0x1) REQUIRED
- This flag must always be present. It implies that the
- bitmap index has been generated for a packfile or
- multi-pack index (MIDX) with full closure (i.e. where
- every single object in the packfile/MIDX can find its
- parent links inside the same packfile/MIDX). This is a
- requirement for the bitmap index format, also present in
- JGit, that greatly reduces the complexity of the
- implementation.
-
- - BITMAP_OPT_HASH_CACHE (0x4)
- If present, the end of the bitmap file contains
- `N` 32-bit name-hash values, one per object in the
- pack/MIDX. The format and meaning of the name-hash is
- described below.
-
- 4-byte entry count (network byte order)
-
- The total count of entries (bitmapped commits) in this bitmap index.
-
- 20-byte checksum
-
- The SHA1 checksum of the pack/MIDX this bitmap index
- belongs to.
-
- - 4 EWAH bitmaps that act as type indexes
-
- Type indexes are serialized after the hash cache in the shape
- of four EWAH bitmaps stored consecutively (see Appendix A for
- the serialization format of an EWAH bitmap).
-
- There is a bitmap for each Git object type, stored in the following
- order:
-
- - Commits
- - Trees
- - Blobs
- - Tags
-
- In each bitmap, the `n`th bit is set to true if the `n`th object
- in the packfile or multi-pack index is of that type.
-
- The obvious consequence is that the OR of all 4 bitmaps will result
- in a full set (all bits set), and the AND of all 4 bitmaps will
- result in an empty bitmap (no bits set).
-
- - N entries with compressed bitmaps, one for each indexed commit
-
- Where `N` is the total amount of entries in this bitmap index.
- Each entry contains the following:
-
- - 4-byte object position (network byte order)
- The position **in the index for the packfile or
- multi-pack index** where the bitmap for this commit is
- found.
-
- - 1-byte XOR-offset
- The xor offset used to compress this bitmap. For an entry
- in position `x`, a XOR offset of `y` means that the actual
- bitmap representing this commit is composed by XORing the
- bitmap for this entry with the bitmap in entry `x-y` (i.e.
- the bitmap `y` entries before this one).
-
- Note that this compression can be recursive. In order to
- XOR this entry with a previous one, the previous entry needs
- to be decompressed first, and so on.
-
- The hard-limit for this offset is 160 (an entry can only be
- xor'ed against one of the 160 entries preceding it). This
- number is always positive, and hence entries are always xor'ed
- with **previous** bitmaps, not bitmaps that will come afterwards
- in the index.
-
- - 1-byte flags for this bitmap
- At the moment the only available flag is `0x1`, which hints
- that this bitmap can be re-used when rebuilding bitmap indexes
- for the repository.
-
- - The compressed bitmap itself, see Appendix A.
+ * A header appears at the beginning:
+
+ 4-byte signature: :: {'B', 'I', 'T', 'M'}
+
+ 2-byte version number (network byte order): ::
+
+ The current implementation only supports version 1
+ of the bitmap index (the same one as JGit).
+
+ 2-byte flags (network byte order): ::
+
+ The following flags are supported:
+
+ ** {empty}
+ BITMAP_OPT_FULL_DAG (0x1) REQUIRED: :::
+
+ This flag must always be present. It implies that the
+ bitmap index has been generated for a packfile or
+ multi-pack index (MIDX) with full closure (i.e. where
+ every single object in the packfile/MIDX can find its
+ parent links inside the same packfile/MIDX). This is a
+ requirement for the bitmap index format, also present in
+ JGit, that greatly reduces the complexity of the
+ implementation.
+
+ ** {empty}
+ BITMAP_OPT_HASH_CACHE (0x4): :::
+
+ If present, the end of the bitmap file contains
+ `N` 32-bit name-hash values, one per object in the
+ pack/MIDX. The format and meaning of the name-hash is
+ described below.
+
+ 4-byte entry count (network byte order): ::
+ The total count of entries (bitmapped commits) in this bitmap index.
+
+ 20-byte checksum: ::
+ The SHA1 checksum of the pack/MIDX this bitmap index
+ belongs to.
+
+ * 4 EWAH bitmaps that act as type indexes
++
+Type indexes are serialized after the hash cache in the shape
+of four EWAH bitmaps stored consecutively (see Appendix A for
+the serialization format of an EWAH bitmap).
++
+There is a bitmap for each Git object type, stored in the following
+order:
++
+ - Commits
+ - Trees
+ - Blobs
+ - Tags
+
++
+In each bitmap, the `n`th bit is set to true if the `n`th object
+in the packfile or multi-pack index is of that type.
++
+The obvious consequence is that the OR of all 4 bitmaps will result
+in a full set (all bits set), and the AND of all 4 bitmaps will
+result in an empty bitmap (no bits set).
+
+ * N entries with compressed bitmaps, one for each indexed commit
++
+Where `N` is the total amount of entries in this bitmap index.
+Each entry contains the following:
+
+ ** {empty}
+ 4-byte object position (network byte order): ::
+ The position **in the index for the packfile or
+ multi-pack index** where the bitmap for this commit is
+ found.
+
+ ** {empty}
+ 1-byte XOR-offset: ::
+ The xor offset used to compress this bitmap. For an entry
+ in position `x`, a XOR offset of `y` means that the actual
+ bitmap representing this commit is composed by XORing the
+ bitmap for this entry with the bitmap in entry `x-y` (i.e.
+ the bitmap `y` entries before this one).
++
+NOTE: This compression can be recursive. In order to
+XOR this entry with a previous one, the previous entry needs
+to be decompressed first, and so on.
++
+The hard-limit for this offset is 160 (an entry can only be
+xor'ed against one of the 160 entries preceding it). This
+number is always positive, and hence entries are always xor'ed
+with **previous** bitmaps, not bitmaps that will come afterwards
+in the index.
+
+ ** {empty}
+ 1-byte flags for this bitmap: ::
+ At the moment the only available flag is `0x1`, which hints
+ that this bitmap can be re-used when rebuilding bitmap indexes
+ for the repository.
+
+ ** The compressed bitmap itself, see Appendix A.
+
+ * {empty}
+ TRAILER: ::
+ Trailing checksum of the preceding contents.
== Appendix A: Serialization format for an EWAH bitmap
@@ -142,8 +153,8 @@ implementation:
- 4-byte number of words of the COMPRESSED bitmap, when stored
- N x 8-byte words, as specified by the previous field
-
- This is the actual content of the compressed bitmap.
++
+This is the actual content of the compressed bitmap.
- 4-byte position of the current RLW for the compressed
bitmap
diff --git a/Documentation/technical/cruft-packs.txt b/Documentation/technical/cruft-packs.txt
new file mode 100644
index 0000000..d81f3a8
--- /dev/null
+++ b/Documentation/technical/cruft-packs.txt
@@ -0,0 +1,123 @@
+= Cruft packs
+
+The cruft packs feature offer an alternative to Git's traditional mechanism of
+removing unreachable objects. This document provides an overview of Git's
+pruning mechanism, and how a cruft pack can be used instead to accomplish the
+same.
+
+== Background
+
+To remove unreachable objects from your repository, Git offers `git repack -Ad`
+(see linkgit:git-repack[1]). Quoting from the documentation:
+
+[quote]
+[...] unreachable objects in a previous pack become loose, unpacked objects,
+instead of being left in the old pack. [...] loose unreachable objects will be
+pruned according to normal expiry rules with the next 'git gc' invocation.
+
+Unreachable objects aren't removed immediately, since doing so could race with
+an incoming push which may reference an object which is about to be deleted.
+Instead, those unreachable objects are stored as loose objects and stay that way
+until they are older than the expiration window, at which point they are removed
+by linkgit:git-prune[1].
+
+Git must store these unreachable objects loose in order to keep track of their
+per-object mtimes. If these unreachable objects were written into one big pack,
+then either freshening that pack (because an object contained within it was
+re-written) or creating a new pack of unreachable objects would cause the pack's
+mtime to get updated, and the objects within it would never leave the expiration
+window. Instead, objects are stored loose in order to keep track of the
+individual object mtimes and avoid a situation where all cruft objects are
+freshened at once.
+
+This can lead to undesirable situations when a repository contains many
+unreachable objects which have not yet left the grace period. Having large
+directories in the shards of `.git/objects` can lead to decreased performance in
+the repository. But given enough unreachable objects, this can lead to inode
+starvation and degrade the performance of the whole system. Since we
+can never pack those objects, these repositories often take up a large amount of
+disk space, since we can only zlib compress them, but not store them in delta
+chains.
+
+== Cruft packs
+
+A cruft pack eliminates the need for storing unreachable objects in a loose
+state by including the per-object mtimes in a separate file alongside a single
+pack containing all loose objects.
+
+A cruft pack is written by `git repack --cruft` when generating a new pack.
+linkgit:git-pack-objects[1]'s `--cruft` option. Note that `git repack --cruft`
+is a classic all-into-one repack, meaning that everything in the resulting pack is
+reachable, and everything else is unreachable. Once written, the `--cruft`
+option instructs `git repack` to generate another pack containing only objects
+not packed in the previous step (which equates to packing all unreachable
+objects together). This progresses as follows:
+
+ 1. Enumerate every object, marking any object which is (a) not contained in a
+ kept-pack, and (b) whose mtime is within the grace period as a traversal
+ tip.
+
+ 2. Perform a reachability traversal based on the tips gathered in the previous
+ step, adding every object along the way to the pack.
+
+ 3. Write the pack out, along with a `.mtimes` file that records the per-object
+ timestamps.
+
+This mode is invoked internally by linkgit:git-repack[1] when instructed to
+write a cruft pack. Crucially, the set of in-core kept packs is exactly the set
+of packs which will not be deleted by the repack; in other words, they contain
+all of the repository's reachable objects.
+
+When a repository already has a cruft pack, `git repack --cruft` typically only
+adds objects to it. An exception to this is when `git repack` is given the
+`--cruft-expiration` option, which allows the generated cruft pack to omit
+expired objects instead of waiting for linkgit:git-gc[1] to expire those objects
+later on.
+
+It is linkgit:git-gc[1] that is typically responsible for removing expired
+unreachable objects.
+
+== Caution for mixed-version environments
+
+Repositories that have cruft packs in them will continue to work with any older
+version of Git. Note, however, that previous versions of Git which do not
+understand the `.mtimes` file will use the cruft pack's mtime as the mtime for
+all of the objects in it. In other words, do not expect older (pre-cruft pack)
+versions of Git to interpret or even read the contents of the `.mtimes` file.
+
+Note that having mixed versions of Git GC-ing the same repository can lead to
+unreachable objects never being completely pruned. This can happen under the
+following circumstances:
+
+ - An older version of Git running GC explodes the contents of an existing
+ cruft pack loose, using the cruft pack's mtime.
+ - A newer version running GC collects those loose objects into a cruft pack,
+ where the .mtime file reflects the loose object's actual mtimes, but the
+ cruft pack mtime is "now".
+
+Repeating this process will lead to unreachable objects not getting pruned as a
+result of repeatedly resetting the objects' mtimes to the present time.
+
+If you are GC-ing repositories in a mixed version environment, consider omitting
+the `--cruft` option when using linkgit:git-repack[1] and linkgit:git-gc[1], and
+leaving the `gc.cruftPacks` configuration unset until all writers understand
+cruft packs.
+
+== Alternatives
+
+Notable alternatives to this design include:
+
+ - The location of the per-object mtime data, and
+ - Storing unreachable objects in multiple cruft packs.
+
+On the location of mtime data, a new auxiliary file tied to the pack was chosen
+to avoid complicating the `.idx` format. If the `.idx` format were ever to gain
+support for optional chunks of data, it may make sense to consolidate the
+`.mtimes` format into the `.idx` itself.
+
+Storing unreachable objects among multiple cruft packs (e.g., creating a new
+cruft pack during each repacking operation including only unreachable objects
+which aren't already stored in an earlier cruft pack) is significantly more
+complicated to construct, and so aren't pursued here. The obvious drawback to
+the current implementation is that the entire cruft pack must be re-written from
+scratch.
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index 65da0da..f691c20 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -26,8 +26,6 @@ Git index format
Extensions are identified by signature. Optional extensions can
be ignored if Git does not understand them.
- Git currently supports cache tree and resolve undo extensions.
-
4-byte extension signature. If the first byte is 'A'..'Z' the
extension is optional and can be ignored.
diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt
index 6d3efb7..b520aa9 100644
--- a/Documentation/technical/pack-format.txt
+++ b/Documentation/technical/pack-format.txt
@@ -294,6 +294,25 @@ Pack file entry: <+
All 4-byte numbers are in network order.
+== pack-*.mtimes files have the format:
+
+All 4-byte numbers are in network byte order.
+
+ - A 4-byte magic number '0x4d544d45' ('MTME').
+
+ - A 4-byte version identifier (= 1).
+
+ - A 4-byte hash function identifier (= 1 for SHA-1, 2 for SHA-256).
+
+ - A table of 4-byte unsigned integers. The ith value is the
+ modification time (mtime) of the ith object in the corresponding
+ pack by lexicographic (index) order. The mtimes count standard
+ epoch seconds.
+
+ - A trailer, containing a checksum of the corresponding packfile,
+ and a checksum of all of the above (each having length according
+ to the specified hash function).
+
== multi-pack-index (MIDX) files have the following format:
The multi-pack-index files refer to multiple pack-files and loose objects.
diff --git a/Documentation/technical/partial-clone.txt b/Documentation/technical/partial-clone.txt
index a0dd7c6..99f0eb3 100644
--- a/Documentation/technical/partial-clone.txt
+++ b/Documentation/technical/partial-clone.txt
@@ -181,6 +181,9 @@ Fetching Missing Objects
currently fetches all objects referred to by the requested objects, even
though they are not necessary.
+- Fetching with `--refetch` will request a complete new filtered packfile from
+ the remote, which can be used to change a filter without needing to
+ dynamically fetch missing objects.
Using many promisor remotes
---------------------------
diff --git a/Documentation/technical/scalar.txt b/Documentation/technical/scalar.txt
new file mode 100644
index 0000000..08bc09c
--- /dev/null
+++ b/Documentation/technical/scalar.txt
@@ -0,0 +1,127 @@
+Scalar
+======
+
+Scalar is a repository management tool that optimizes Git for use in large
+repositories. It accomplishes this by helping users to take advantage of
+advanced performance features in Git. Unlike most other Git built-in commands,
+Scalar is not executed as a subcommand of 'git'; rather, it is built as a
+separate executable containing its own series of subcommands.
+
+Background
+----------
+
+Scalar was originally designed as an add-on to Git and implemented as a .NET
+Core application. It was created based on the learnings from the VFS for Git
+project (another application aimed at improving the experience of working with
+large repositories). As part of its initial implementation, Scalar relied on
+custom features in the Microsoft fork of Git that have since been integrated
+into core Git:
+
+* partial clone,
+* commit graphs,
+* multi-pack index,
+* sparse checkout (cone mode),
+* scheduled background maintenance,
+* etc
+
+With the requisite Git functionality in place and a desire to bring the benefits
+of Scalar to the larger Git community, the Scalar application itself was ported
+from C# to C and integrated upstream.
+
+Features
+--------
+
+Scalar is comprised of two major pieces of functionality: automatically
+configuring built-in Git performance features and managing repository
+enlistments.
+
+The Git performance features configured by Scalar (see "Background" for
+examples) confer substantial performance benefits to large repositories, but are
+either too experimental to enable for all of Git yet, or only benefit large
+repositories. As new features are introduced, Scalar should be updated
+accordingly to incorporate them. This will prevent the tool from becoming stale
+while also providing a path for more easily bringing features to the appropriate
+users.
+
+Enlistments are how Scalar knows which repositories on a user's system should
+utilize Scalar-configured features. This allows it to update performance
+settings when new ones are added to the tool, as well as centrally manage
+repository maintenance. The enlistment structure - a root directory with a
+`src/` subdirectory containing the cloned repository itself - is designed to
+encourage users to route build outputs outside of the repository to avoid the
+performance-limiting overhead of ignoring those files in Git.
+
+Design
+------
+
+Scalar is implemented in C and interacts with Git via a mix of child process
+invocations of Git and direct usage of `libgit.a`. Internally, it is structured
+much like other built-ins with subcommands (e.g., `git stash`), containing a
+`cmd_<subcommand>()` function for each subcommand, routed through a `cmd_main()`
+function. Most options are unique to each subcommand, with `scalar` respecting
+some "global" `git` options (e.g., `-c` and `-C`).
+
+Because `scalar` is not invoked as a Git subcommand (like `git scalar`), it is
+built and installed as its own executable in the `bin/` directory, alongside
+`git`, `git-gui`, etc.
+
+Roadmap
+-------
+
+NOTE: this section will be removed once the remaining tasks outlined in this
+roadmap are complete.
+
+Scalar is a large enough project that it is being upstreamed incrementally,
+living in `contrib/` until it is feature-complete. So far, the following patch
+series have been accepted:
+
+- `scalar-the-beginning`: The initial patch series which sets up
+ `contrib/scalar/` and populates it with a minimal `scalar` command that
+ demonstrates the fundamental ideas.
+
+- `scalar-c-and-C`: The `scalar` command learns about two options that can be
+ specified before the command, `-c <key>=<value>` and `-C <directory>`.
+
+- `scalar-diagnose`: The `scalar` command is taught the `diagnose` subcommand.
+
+Roughly speaking (and subject to change), the following series are needed to
+"finish" this initial version of Scalar:
+
+- Finish Scalar features: Enable the built-in FSMonitor in Scalar enlistments
+ and implement `scalar help`. At the end of this series, Scalar should be
+ feature-complete from the perspective of a user.
+
+- Generalize features not specific to Scalar: In the spirit of making Scalar
+ configure only what is needed for large repo performance, move common
+ utilities into other parts of Git. Some of this will be internal-only, but one
+ major change will be generalizing `scalar diagnose` for use with any Git
+ repository.
+
+- Move Scalar to toplevel: Move Scalar out of `contrib/` and into the root of
+ `git`, including updates to build and install it with the rest of Git. This
+ change will incorporate Scalar into the Git CI and test framework, as well as
+ expand regression and performance testing to ensure the tool is stable.
+
+Finally, there are two additional patch series that exist in Microsoft's fork of
+Git, but there is no current plan to upstream them. There are some interesting
+ideas there, but the implementation is too specific to Azure Repos and/or VFS
+for Git to be of much help in general.
+
+These still exist mainly because the GVFS protocol is what Azure Repos has
+instead of partial clone, while Git is focused on improving partial clone:
+
+- `scalar-with-gvfs`: The primary purpose of this patch series is to support
+ existing Scalar users whose repositories are hosted in Azure Repos (which does
+ not support Git's partial clones, but supports its predecessor, the GVFS
+ protocol, which is used by Scalar to emulate the partial clone).
+
+ Since the GVFS protocol will never be supported by core Git, this patch series
+ will remain in Microsoft's fork of Git.
+
+- `run-scalar-functional-tests`: The Scalar project developed a quite
+ comprehensive set of integration tests (or, "Functional Tests"). They are the
+ sole remaining part of the original C#-based Scalar project, and this patch
+ adds a GitHub workflow that runs them all.
+
+ Since the tests partially depend on features that are only provided in the
+ `scalar-with-gvfs` patch series, this patch cannot be upstreamed.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index f964f9b..6ec9e34 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.35.GIT
+DEF_VER=v2.37.GIT
LF='
'
diff --git a/Makefile b/Makefile
index e8aba29..1624471 100644
--- a/Makefile
+++ b/Makefile
@@ -182,6 +182,8 @@ include shared.mak
#
# Define BLK_SHA256 to use the built-in SHA-256 routines.
#
+# Define NETTLE_SHA256 to use the SHA-256 routines in libnettle.
+#
# Define GCRYPT_SHA256 to use the SHA-256 routines in libgcrypt.
#
# Define OPENSSL_SHA256 to use the SHA-256 routines in OpenSSL.
@@ -309,6 +311,11 @@ include shared.mak
# distributions that want to use their packaged versions of Perl
# modules, instead of the fallbacks shipped with Git.
#
+# Define NO_GITWEB if you do not want to build or install
+# 'gitweb'. Note that defining NO_PERL currently has the same effect
+# on not installing gitweb, but not on whether it's built in the
+# gitweb/ directory.
+#
# Define PYTHON_PATH to the path of your Python binary (often /usr/bin/python
# but /usr/bin/python2.7 or /usr/bin/python3 on some platforms).
#
@@ -475,6 +482,17 @@ include shared.mak
# directory, and the JSON compilation database 'compile_commands.json' will be
# created at the root of the repository.
#
+# If your platform supports a built-in fsmonitor backend, set
+# FSMONITOR_DAEMON_BACKEND to the "<name>" of the corresponding
+# `compat/fsmonitor/fsm-listen-<name>.c` and
+# `compat/fsmonitor/fsm-health-<name>.c` files
+# that implement the `fsm_listen__*()` and `fsm_health__*()` routines.
+#
+# If your platform has OS-specific ways to tell if a repo is incompatible with
+# fsmonitor (whether the hook or IPC daemon version), set FSMONITOR_OS_SETTINGS
+# to the "<name>" of the corresponding `compat/fsmonitor/fsm-settings-<name>.c`
+# that implements the `fsm_os_settings__*()` routines.
+#
# 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
@@ -533,6 +551,7 @@ gitexecdir = libexec/git-core
mergetoolsdir = $(gitexecdir)/mergetools
sharedir = $(prefix)/share
gitwebdir = $(sharedir)/gitweb
+gitwebstaticdir = $(gitwebdir)/static
perllibdir = $(sharedir)/perl5
localedir = $(sharedir)/locale
template_dir = share/git-core/templates
@@ -551,7 +570,7 @@ localedir_relative = $(patsubst $(prefix)/%,%,$(localedir))
htmldir_relative = $(patsubst $(prefix)/%,%,$(htmldir))
perllibdir_relative = $(patsubst $(prefix)/%,%,$(perllibdir))
-export prefix bindir sharedir sysconfdir gitwebdir perllibdir localedir
+export prefix bindir sharedir sysconfdir perllibdir localedir
# Set our default programs
CC = cc
@@ -564,7 +583,9 @@ INSTALL = install
TCL_PATH = tclsh
TCLTK_PATH = wish
XGETTEXT = xgettext
+MSGCAT = msgcat
MSGFMT = msgfmt
+MSGMERGE = msgmerge
CURL_CONFIG = curl-config
GCOV = gcov
STRIP = strip
@@ -716,12 +737,14 @@ TEST_BUILTINS_OBJS += test-dump-split-index.o
TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
TEST_BUILTINS_OBJS += test-example-decorate.o
TEST_BUILTINS_OBJS += test-fast-rebase.o
+TEST_BUILTINS_OBJS += test-fsmonitor-client.o
TEST_BUILTINS_OBJS += test-genrandom.o
TEST_BUILTINS_OBJS += test-genzeros.o
TEST_BUILTINS_OBJS += test-getcwd.o
TEST_BUILTINS_OBJS += test-hash-speed.o
TEST_BUILTINS_OBJS += test-hash.o
TEST_BUILTINS_OBJS += test-hashmap.o
+TEST_BUILTINS_OBJS += test-hexdump.o
TEST_BUILTINS_OBJS += test-index-version.o
TEST_BUILTINS_OBJS += test-json-writer.o
TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
@@ -732,6 +755,7 @@ TEST_BUILTINS_OBJS += test-oid-array.o
TEST_BUILTINS_OBJS += test-oidmap.o
TEST_BUILTINS_OBJS += test-oidtree.o
TEST_BUILTINS_OBJS += test-online-cpus.o
+TEST_BUILTINS_OBJS += test-pack-mtimes.o
TEST_BUILTINS_OBJS += test-parse-options.o
TEST_BUILTINS_OBJS += test-parse-pathspec-file.o
TEST_BUILTINS_OBJS += test-partial-clone.o
@@ -838,7 +862,7 @@ generated-hdrs: $(GENERATED_H)
## Exhaustive lists of our source files, either dynamically generated,
## or hardcoded.
SOURCES_CMD = ( \
- git ls-files \
+ git ls-files --deduplicate \
'*.[hcS]' \
'*.sh' \
':!*[tp][0-9][0-9][0-9][0-9]*' \
@@ -849,12 +873,13 @@ SOURCES_CMD = ( \
-o \( -name '[tp][0-9][0-9][0-9][0-9]*' -prune \) \
-o \( -name contrib -type d -prune \) \
-o \( -name build -type d -prune \) \
+ -o \( -name .build -type d -prune \) \
-o \( -name 'trash*' -type d -prune \) \
-o \( -name '*.[hcS]' -type f -print \) \
-o \( -name '*.sh' -type f -print \) \
| sed -e 's|^\./||' \
)
-FOUND_SOURCE_FILES := $(shell $(SOURCES_CMD))
+FOUND_SOURCE_FILES := $(filter-out $(GENERATED_H),$(shell $(SOURCES_CMD)))
FOUND_C_SOURCES = $(filter %.c,$(FOUND_SOURCE_FILES))
FOUND_H_SOURCES = $(filter %.h,$(FOUND_SOURCE_FILES))
@@ -933,6 +958,8 @@ LIB_OBJS += fetch-pack.o
LIB_OBJS += fmt-merge-msg.o
LIB_OBJS += fsck.o
LIB_OBJS += fsmonitor.o
+LIB_OBJS += fsmonitor-ipc.o
+LIB_OBJS += fsmonitor-settings.o
LIB_OBJS += gettext.o
LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o
@@ -985,6 +1012,7 @@ LIB_OBJS += oidtree.o
LIB_OBJS += pack-bitmap-write.o
LIB_OBJS += pack-bitmap.o
LIB_OBJS += pack-check.o
+LIB_OBJS += pack-mtimes.o
LIB_OBJS += pack-objects.o
LIB_OBJS += pack-revindex.o
LIB_OBJS += pack-write.o
@@ -1139,6 +1167,7 @@ BUILTIN_OBJS += builtin/fmt-merge-msg.o
BUILTIN_OBJS += builtin/for-each-ref.o
BUILTIN_OBJS += builtin/for-each-repo.o
BUILTIN_OBJS += builtin/fsck.o
+BUILTIN_OBJS += builtin/fsmonitor--daemon.o
BUILTIN_OBJS += builtin/gc.o
BUILTIN_OBJS += builtin/get-tar-commit-id.o
BUILTIN_OBJS += builtin/grep.o
@@ -1258,13 +1287,14 @@ PTHREAD_CFLAGS =
SPARSE_FLAGS ?= -std=gnu99
SP_EXTRA_FLAGS = -Wno-universal-initializer
-# For informing GIT-BUILD-OPTIONS of the SANITIZE=leak target
+# For informing GIT-BUILD-OPTIONS of the SANITIZE=leak,address targets
SANITIZE_LEAK =
+SANITIZE_ADDRESS =
# For the 'coccicheck' target; setting SPATCH_BATCH_SIZE higher will
# usually result in less CPU usage at the cost of higher peak memory.
# Setting it to 0 will feed all files in a single spatch invocation.
-SPATCH_FLAGS = --all-includes --patch .
+SPATCH_FLAGS = --all-includes
SPATCH_BATCH_SIZE = 1
include config.mak.uname
@@ -1305,6 +1335,7 @@ SANITIZE_LEAK = YesCompiledWithIt
endif
ifneq ($(filter address,$(SANITIZERS)),)
NO_REGEX = NeededForASAN
+SANITIZE_ADDRESS = YesCompiledWithIt
endif
endif
@@ -1819,6 +1850,10 @@ ifdef OPENSSL_SHA256
EXTLIBS += $(LIB_4_CRYPTO)
BASIC_CFLAGS += -DSHA256_OPENSSL
else
+ifdef NETTLE_SHA256
+ BASIC_CFLAGS += -DSHA256_NETTLE
+ EXTLIBS += -lnettle
+else
ifdef GCRYPT_SHA256
BASIC_CFLAGS += -DSHA256_GCRYPT
EXTLIBS += -lgcrypt
@@ -1827,6 +1862,7 @@ else
BASIC_CFLAGS += -DSHA256_BLK
endif
endif
+endif
ifdef SHA1_MAX_BLOCK_SIZE
LIB_OBJS += compat/sha1-chunked.o
@@ -1963,6 +1999,7 @@ endif
ifneq ($(findstring openssl,$(CSPRNG_METHOD)),)
BASIC_CFLAGS += -DHAVE_OPENSSL_CSPRNG
+ EXTLIBS += -lcrypto -lssl
endif
ifneq ($(PROCFS_EXECUTABLE_PATH),)
@@ -1992,6 +2029,17 @@ ifdef NEED_ACCESS_ROOT_HANDLER
COMPAT_OBJS += compat/access.o
endif
+ifdef FSMONITOR_DAEMON_BACKEND
+ COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
+ COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+endif
+
+ifdef FSMONITOR_OS_SETTINGS
+ COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
+ COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+endif
+
ifeq ($(TCLTK_PATH),)
NO_TCLTK = NoThanks
endif
@@ -2054,6 +2102,7 @@ htmldir_relative_SQ = $(subst ','\'',$(htmldir_relative))
prefix_SQ = $(subst ','\'',$(prefix))
perllibdir_relative_SQ = $(subst ','\'',$(perllibdir_relative))
gitwebdir_SQ = $(subst ','\'',$(gitwebdir))
+gitwebstaticdir_SQ = $(subst ','\'',$(gitwebstaticdir))
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
TEST_SHELL_PATH_SQ = $(subst ','\'',$(TEST_SHELL_PATH))
@@ -2382,10 +2431,6 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile
perllibdir:
@echo '$(perllibdir_SQ)'
-.PHONY: gitweb
-gitweb:
- $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
-
git-instaweb: git-instaweb.sh GIT-SCRIPT-DEFINES
$(QUIET_GEN)$(cmd_munge_script) && \
chmod +x $@+ && \
@@ -2691,17 +2736,18 @@ XGETTEXT_FLAGS = \
--force-po \
--add-comments=TRANSLATORS: \
--msgid-bugs-address="Git Mailing List <git@vger.kernel.org>" \
- --from-code=UTF-8
+ --package-name=Git
XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \
--keyword=_ --keyword=N_ --keyword="Q_:1,2"
XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
--keyword=gettextln --keyword=eval_gettextln
XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \
--keyword=__ --keyword=N__ --keyword="__n:1,2"
-LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
-LOCALIZED_SH = $(SCRIPT_SH)
-LOCALIZED_SH += git-sh-setup.sh
-LOCALIZED_PERL = $(SCRIPT_PERL)
+MSGMERGE_FLAGS = --add-location --backup=off --update
+LOCALIZED_C = $(sort $(FOUND_C_SOURCES) $(FOUND_H_SOURCES) $(SCALAR_SOURCES) \
+ $(GENERATED_H))
+LOCALIZED_SH = $(sort $(SCRIPT_SH) git-sh-setup.sh)
+LOCALIZED_PERL = $(sort $(SCRIPT_PERL))
ifdef XGETTEXT_INCLUDE_TESTS
LOCALIZED_C += t/t0200/test.c
@@ -2709,38 +2755,129 @@ LOCALIZED_SH += t/t0200/test.sh
LOCALIZED_PERL += t/t0200/test.perl
endif
-## Note that this is meant to be run only by the localization coordinator
-## under a very controlled condition, i.e. (1) it is to be run in a
-## Git repository (not a tarball extract), (2) any local modifications
-## will be lost.
+## We generate intermediate .build/pot/po/%.po files containing a
+## extract of the translations we find in each file in the source
+## tree. We will assemble them using msgcat to create the final
+## "po/git.pot" file.
+LOCALIZED_ALL_GEN_PO =
+
+LOCALIZED_C_GEN_PO = $(LOCALIZED_C:%=.build/pot/po/%.po)
+LOCALIZED_ALL_GEN_PO += $(LOCALIZED_C_GEN_PO)
+
+LOCALIZED_SH_GEN_PO = $(LOCALIZED_SH:%=.build/pot/po/%.po)
+LOCALIZED_ALL_GEN_PO += $(LOCALIZED_SH_GEN_PO)
+
+LOCALIZED_PERL_GEN_PO = $(LOCALIZED_PERL:%=.build/pot/po/%.po)
+LOCALIZED_ALL_GEN_PO += $(LOCALIZED_PERL_GEN_PO)
+
## Gettext tools cannot work with our own custom PRItime type, so
## we replace PRItime with PRIuMAX. We need to update this to
## PRIdMAX if we switch to a signed type later.
+$(LOCALIZED_C_GEN_PO): .build/pot/po/%.po: %
+ $(call mkdir_p_parent_template)
+ $(QUIET_XGETTEXT) \
+ if grep -q PRItime $<; then \
+ (\
+ sed -e 's|PRItime|PRIuMAX|g' <$< \
+ >.build/pot/po/$< && \
+ cd .build/pot/po && \
+ $(XGETTEXT) --omit-header \
+ -o $(@:.build/pot/po/%=%) \
+ $(XGETTEXT_FLAGS_C) $< && \
+ rm $<; \
+ ); \
+ else \
+ $(XGETTEXT) --omit-header \
+ -o $@ $(XGETTEXT_FLAGS_C) $<; \
+ fi
-po/git.pot: $(GENERATED_H) FORCE
- # All modifications will be reverted at the end, so we do not
- # want to have any local change.
- git diff --quiet HEAD && git diff --quiet --cached
+$(LOCALIZED_SH_GEN_PO): .build/pot/po/%.po: %
+ $(call mkdir_p_parent_template)
+ $(QUIET_XGETTEXT)$(XGETTEXT) --omit-header \
+ -o$@ $(XGETTEXT_FLAGS_SH) $<
- @for s in $(LOCALIZED_C) $(LOCALIZED_SH) $(LOCALIZED_PERL); \
- do \
- sed -e 's|PRItime|PRIuMAX|g' <"$$s" >"$$s+" && \
- cat "$$s+" >"$$s" && rm "$$s+"; \
- done
+$(LOCALIZED_PERL_GEN_PO): .build/pot/po/%.po: %
+ $(call mkdir_p_parent_template)
+ $(QUIET_XGETTEXT)$(XGETTEXT) --omit-header \
+ -o$@ $(XGETTEXT_FLAGS_PERL) $<
+
+define gen_pot_header
+$(XGETTEXT) $(XGETTEXT_FLAGS_C) \
+ -o - /dev/null | \
+sed -e 's|charset=CHARSET|charset=UTF-8|' \
+ -e 's|\(Last-Translator: \)FULL NAME <.*>|\1make by the Makefile|' \
+ -e 's|\(Language-Team: \)LANGUAGE <.*>|\1Git Mailing List <git@vger.kernel.org>|' \
+ >$@ && \
+echo '"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n"' >>$@
+endef
- $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ $(XGETTEXT_FLAGS_C) $(LOCALIZED_C)
- $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ --join-existing $(XGETTEXT_FLAGS_SH) \
- $(LOCALIZED_SH)
- $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ --join-existing $(XGETTEXT_FLAGS_PERL) \
- $(LOCALIZED_PERL)
+.build/pot/git.header: $(LOCALIZED_ALL_GEN_PO)
+ $(call mkdir_p_parent_template)
+ $(QUIET_GEN)$(gen_pot_header)
- # Reverting the munged source, leaving only the updated $@
- git reset --hard
- mv $@+ $@
+po/git.pot: .build/pot/git.header $(LOCALIZED_ALL_GEN_PO)
+ $(QUIET_GEN)$(MSGCAT) $^ >$@
.PHONY: pot
pot: po/git.pot
+define check_po_file_envvar
+ $(if $(PO_FILE), \
+ $(if $(filter po/%.po,$(PO_FILE)), , \
+ $(error PO_FILE should match pattern: "po/%.po")), \
+ $(error PO_FILE is not defined))
+endef
+
+.PHONY: po-update
+po-update: po/git.pot
+ $(check_po_file_envvar)
+ @if test ! -e $(PO_FILE); then \
+ echo >&2 "error: $(PO_FILE) does not exist"; \
+ echo >&2 'To create an initial po file, use: "make po-init PO_FILE=po/XX.po"'; \
+ exit 1; \
+ fi
+ $(QUIET_MSGMERGE)$(MSGMERGE) $(MSGMERGE_FLAGS) $(PO_FILE) po/git.pot
+
+.PHONY: check-pot
+check-pot: $(LOCALIZED_ALL_GEN_PO)
+
+### TODO FIXME: Translating everything in these files is a bad
+### heuristic for "core", as we'll translate obscure error() messages
+### along with commonly seen i18n messages. A better heuristic would
+### be to e.g. use spatch to first remove error/die/warning
+### etc. messages.
+LOCALIZED_C_CORE =
+LOCALIZED_C_CORE += builtin/checkout.c
+LOCALIZED_C_CORE += builtin/clone.c
+LOCALIZED_C_CORE += builtin/index-pack.c
+LOCALIZED_C_CORE += builtin/push.c
+LOCALIZED_C_CORE += builtin/reset.c
+LOCALIZED_C_CORE += remote.c
+LOCALIZED_C_CORE += wt-status.c
+
+LOCALIZED_C_CORE_GEN_PO = $(LOCALIZED_C_CORE:%=.build/pot/po/%.po)
+
+.build/pot/git-core.header: $(LOCALIZED_C_CORE_GEN_PO)
+ $(call mkdir_p_parent_template)
+ $(QUIET_GEN)$(gen_pot_header)
+
+po/git-core.pot: .build/pot/git-core.header $(LOCALIZED_C_CORE_GEN_PO)
+ $(QUIET_GEN)$(MSGCAT) $^ >$@
+
+.PHONY: po-init
+po-init: po/git-core.pot
+ $(check_po_file_envvar)
+ @if test -e $(PO_FILE); then \
+ echo >&2 "error: $(PO_FILE) exists already"; \
+ exit 1; \
+ fi
+ $(QUIET_MSGINIT)msginit \
+ --input=$< \
+ --output=$(PO_FILE) \
+ --no-translator \
+ --locale=$(PO_FILE:po/%.po=%)
+
+## po/*.po files & their rules
ifdef NO_GETTEXT
POFILES :=
MOFILES :=
@@ -2847,7 +2984,14 @@ GIT-BUILD-OPTIONS: FORCE
@echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+
@echo DC_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_SHA1)))'\' >>$@+
@echo SANITIZE_LEAK=\''$(subst ','\'',$(subst ','\'',$(SANITIZE_LEAK)))'\' >>$@+
+ @echo SANITIZE_ADDRESS=\''$(subst ','\'',$(subst ','\'',$(SANITIZE_ADDRESS)))'\' >>$@+
@echo X=\'$(X)\' >>$@+
+ifdef FSMONITOR_DAEMON_BACKEND
+ @echo FSMONITOR_DAEMON_BACKEND=\''$(subst ','\'',$(subst ','\'',$(FSMONITOR_DAEMON_BACKEND)))'\' >>$@+
+endif
+ifdef FSMONITOR_OS_SETTINGS
+ @echo FSMONITOR_OS_SETTINGS=\''$(subst ','\'',$(subst ','\'',$(FSMONITOR_OS_SETTINGS)))'\' >>$@+
+endif
ifdef TEST_OUTPUT_DIRECTORY
@echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+
endif
@@ -2957,6 +3101,9 @@ $(SP_OBJ): %.sp: %.c %.o
sparse: $(SP_OBJ)
EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/%
+ifndef NETTLE_SHA256
+ EXCEPT_HDRS += sha256/nettle.h
+endif
ifndef GCRYPT_SHA256
EXCEPT_HDRS += sha256/gcrypt.h
endif
@@ -2989,6 +3136,8 @@ check: $(GENERATED_H)
exit 1; \
fi
+COCCI_TEST_RES = $(wildcard contrib/coccinelle/tests/*.res)
+
%.cocci.patch: %.cocci $(COCCI_SOURCES)
$(QUIET_SPATCH) \
if test $(SPATCH_BATCH_SIZE) = 0; then \
@@ -2997,7 +3146,8 @@ check: $(GENERATED_H)
limit='-n $(SPATCH_BATCH_SIZE)'; \
fi; \
if ! echo $(COCCI_SOURCES) | xargs $$limit \
- $(SPATCH) --sp-file $< $(SPATCH_FLAGS) \
+ $(SPATCH) $(SPATCH_FLAGS) \
+ --sp-file $< --patch . \
>$@+ 2>$@.log; \
then \
cat $@.log; \
@@ -3008,13 +3158,43 @@ check: $(GENERATED_H)
then \
echo ' ' SPATCH result: $@; \
fi
+
+COCCI_TEST_RES_GEN = $(addprefix .build/,$(COCCI_TEST_RES))
+$(COCCI_TEST_RES_GEN): .build/%.res : %.c
+$(COCCI_TEST_RES_GEN): .build/%.res : %.res
+$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinelle/%.cocci
+ $(call mkdir_p_parent_template)
+ $(QUIET_SPATCH_T)$(SPATCH) $(SPATCH_FLAGS) \
+ --very-quiet --no-show-diff \
+ --sp-file $< -o $@ \
+ $(@:.build/%.res=%.c) && \
+ cmp $(@:.build/%=%) $@ || \
+ git -P diff --no-index $(@:.build/%=%) $@ 2>/dev/null; \
+
+.PHONY: coccicheck-test
+coccicheck-test: $(COCCI_TEST_RES_GEN)
+
+coccicheck: coccicheck-test
coccicheck: $(addsuffix .patch,$(filter-out %.pending.cocci,$(wildcard contrib/coccinelle/*.cocci)))
# See contrib/coccinelle/README
+coccicheck-pending: coccicheck-test
coccicheck-pending: $(addsuffix .patch,$(wildcard contrib/coccinelle/*.pending.cocci))
.PHONY: coccicheck coccicheck-pending
+# "Sub"-Makefiles, not really because they can't be run stand-alone,
+# only there to contain directory-specific rules and variables
+## gitweb/Makefile inclusion:
+MAK_DIR_GITWEB = gitweb/
+include gitweb/Makefile
+
+.PHONY: gitweb
+gitweb: $(MAK_DIR_GITWEB_ALL)
+ifndef NO_GITWEB
+all:: gitweb
+endif
+
### Installation rules
ifneq ($(filter /%,$(firstword $(template_dir))),)
@@ -3087,7 +3267,6 @@ ifndef NO_PERL
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perllibdir_SQ)'
(cd perl/build/lib && $(TAR) cf - .) | \
(cd '$(DESTDIR_SQ)$(perllibdir_SQ)' && umask 022 && $(TAR) xof -)
- $(MAKE) -C gitweb install
endif
ifndef NO_TCLTK
$(MAKE) -C gitk-git install
@@ -3142,10 +3321,8 @@ endif
cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; } \
done
-.PHONY: install-gitweb install-doc install-man install-man-perl install-html install-info install-pdf
+.PHONY: install-doc install-man install-man-perl install-html install-info install-pdf
.PHONY: quick-install-doc quick-install-man quick-install-html
-install-gitweb:
- $(MAKE) -C gitweb install
install-doc: install-man-perl
$(MAKE) -C Documentation install
@@ -3269,10 +3446,13 @@ profile-clean:
$(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
cocciclean:
+ $(RM) -r .build/contrib/coccinelle
$(RM) contrib/coccinelle/*.cocci.patch*
clean: profile-clean coverage-clean cocciclean
- $(RM) *.res
+ $(RM) -r .build
+ $(RM) po/git.pot po/git-core.pot
+ $(RM) git.res
$(RM) $(OBJECTS)
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
@@ -3289,7 +3469,6 @@ clean: profile-clean coverage-clean cocciclean
$(MAKE) -C Documentation/ clean
$(RM) Documentation/GIT-EXCLUDED-PROGRAMS
ifndef NO_PERL
- $(MAKE) -C gitweb clean
$(RM) -r perl/build/
endif
$(MAKE) -C templates/ clean
@@ -3389,6 +3568,7 @@ coverage-clean-results:
$(RM) coverage-untested-functions
$(RM) -r cover_db/
$(RM) -r cover_db_html/
+ $(RM) coverage-test.made
coverage-clean: coverage-clean-results
$(RM) $(addsuffix *.gcno,$(object_dirs))
@@ -3403,13 +3583,17 @@ coverage-compile:
coverage-test: coverage-clean-results coverage-compile
$(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
DEFAULT_TEST_TARGET=test -j1 test
+ touch coverage-test.made
+
+coverage-test.made:
+ $(MAKE) coverage-test
coverage-prove: coverage-clean-results coverage-compile
$(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
DEFAULT_TEST_TARGET=prove GIT_PROVE_OPTS="$(GIT_PROVE_OPTS) -j1" \
-j1 test
-coverage-report:
+coverage-report: coverage-test.made
$(QUIET_GCOV)for dir in $(object_dirs); do \
$(GCOV) $(GCOVFLAGS) --object-directory=$$dir $$dir*.c || exit; \
done
diff --git a/RelNotes b/RelNotes
index 8105226..d505db6 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.36.0.txt \ No newline at end of file
+Documentation/RelNotes/2.38.0.txt \ No newline at end of file
diff --git a/add-interactive.c b/add-interactive.c
index 7247210..22fcd34 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -568,8 +568,7 @@ static int get_modified_files(struct repository *r,
run_diff_files(&rev, 0);
}
- if (ps)
- clear_pathspec(&rev.prune_data);
+ release_revisions(&rev);
}
hashmap_clear_and_free(&s.file_map, struct pathname_entry, ent);
if (unmerged_count)
@@ -698,8 +697,16 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps,
for (i = 0; i < files->items.nr; i++) {
const char *name = files->items.items[i].string;
- if (files->selected[i] &&
- add_file_to_index(s->r->index, name, 0) < 0) {
+ struct stat st;
+
+ if (!files->selected[i])
+ continue;
+ if (lstat(name, &st) && is_missing_file_error(errno)) {
+ if (remove_file_from_index(s->r->index, name) < 0) {
+ res = error(_("could not stage '%s'"), name);
+ break;
+ }
+ } else if (add_file_to_index(s->r->index, name, 0) < 0) {
res = error(_("could not stage '%s'"), name);
break;
}
diff --git a/add-patch.c b/add-patch.c
index 55d719f..509ca04 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -305,7 +305,7 @@ static void setup_child_process(struct add_p_state *s,
va_end(ap);
cp->git_cmd = 1;
- strvec_pushf(&cp->env_array,
+ strvec_pushf(&cp->env,
INDEX_ENVIRONMENT "=%s", s->s.r->index_file);
}
diff --git a/advice.c b/advice.c
index 2e1fd48..6fda9ed 100644
--- a/advice.c
+++ b/advice.c
@@ -39,6 +39,7 @@ static struct {
[ADVICE_ADD_EMPTY_PATHSPEC] = { "addEmptyPathspec", 1 },
[ADVICE_ADD_IGNORED_FILE] = { "addIgnoredFile", 1 },
[ADVICE_AM_WORK_DIR] = { "amWorkDir", 1 },
+ [ADVICE_AMBIGUOUS_FETCH_REFSPEC] = { "ambiguousFetchRefspec", 1 },
[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName", 1 },
[ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge", 1 },
[ADVICE_DETACHED_HEAD] = { "detachedHead", 1 },
@@ -61,7 +62,7 @@ static struct {
[ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching", 1 },
[ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName", 1 },
[ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected", 1 },
- [ADVICE_RESET_QUIET_WARNING] = { "resetQuiet", 1 },
+ [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh", 1 },
[ADVICE_RESOLVE_CONFLICT] = { "resolveConflict", 1 },
[ADVICE_RM_HINTS] = { "rmHints", 1 },
[ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse", 1 },
diff --git a/advice.h b/advice.h
index a395712..7ddc6cb 100644
--- a/advice.h
+++ b/advice.h
@@ -17,6 +17,7 @@ struct string_list;
ADVICE_ADD_EMPTY_PATHSPEC,
ADVICE_ADD_IGNORED_FILE,
ADVICE_AM_WORK_DIR,
+ ADVICE_AMBIGUOUS_FETCH_REFSPEC,
ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
ADVICE_COMMIT_BEFORE_MERGE,
ADVICE_DETACHED_HEAD,
@@ -36,7 +37,7 @@ struct string_list;
ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
ADVICE_PUSH_UPDATE_REJECTED,
ADVICE_PUSH_REF_NEEDS_UPDATE,
- ADVICE_RESET_QUIET_WARNING,
+ ADVICE_RESET_NO_REFRESH_WARNING,
ADVICE_RESOLVE_CONFLICT,
ADVICE_RM_HINTS,
ADVICE_SEQUENCER_IN_USE,
diff --git a/alloc.c b/alloc.c
index 957a0af..27f697e 100644
--- a/alloc.c
+++ b/alloc.c
@@ -27,7 +27,6 @@ union any_object {
};
struct alloc_state {
- int count; /* total number of nodes allocated */
int nr; /* number of nodes left in current allocation */
void *p; /* first free node in current allocation */
@@ -63,7 +62,6 @@ static inline void *alloc_node(struct alloc_state *s, size_t node_size)
s->slabs[s->slab_nr++] = s->p;
}
s->nr--;
- s->count++;
ret = s->p;
s->p = (char *)s->p + node_size;
memset(ret, 0, node_size);
@@ -122,22 +120,3 @@ void *alloc_commit_node(struct repository *r)
init_commit_node(c);
return c;
}
-
-static void report(const char *name, unsigned int count, size_t size)
-{
- fprintf(stderr, "%10s: %8u (%"PRIuMAX" kB)\n",
- name, count, (uintmax_t) size);
-}
-
-#define REPORT(name, type) \
- report(#name, r->parsed_objects->name##_state->count, \
- r->parsed_objects->name##_state->count * sizeof(type) >> 10)
-
-void alloc_report(struct repository *r)
-{
- REPORT(blob, struct blob);
- REPORT(tree, struct tree);
- REPORT(commit, struct commit);
- REPORT(tag, struct tag);
- REPORT(object, union any_object);
-}
diff --git a/alloc.h b/alloc.h
index 371d388..3f4a0ad 100644
--- a/alloc.h
+++ b/alloc.h
@@ -13,7 +13,6 @@ void init_commit_node(struct commit *c);
void *alloc_commit_node(struct repository *r);
void *alloc_tag_node(struct repository *r);
void *alloc_object_node(struct repository *r);
-void alloc_report(struct repository *r);
struct alloc_state *allocate_alloc_state(void);
void clear_alloc_state(struct alloc_state *s);
diff --git a/apply.c b/apply.c
index d19c26d..2b7cd93 100644
--- a/apply.c
+++ b/apply.c
@@ -3274,11 +3274,11 @@ static struct patch *in_fn_table(struct apply_state *state, const char *name)
{
struct string_list_item *item;
- if (name == NULL)
+ if (!name)
return NULL;
item = string_list_lookup(&state->fn_table, name);
- if (item != NULL)
+ if (item)
return (struct patch *)item->util;
return NULL;
@@ -3318,7 +3318,7 @@ static void add_to_fn_table(struct apply_state *state, struct patch *patch)
* This should cover the cases for normal diffs,
* file creations and copies
*/
- if (patch->new_name != NULL) {
+ if (patch->new_name) {
item = string_list_insert(&state->fn_table, patch->new_name);
item->util = patch;
}
diff --git a/archive-tar.c b/archive-tar.c
index 042feb6..3d77e0f 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -38,11 +38,18 @@ static int write_tar_filter_archive(const struct archiver *ar,
#define USTAR_MAX_MTIME 077777777777ULL
#endif
+static void tar_write_block(const void *buf)
+{
+ write_or_die(1, buf, BLOCKSIZE);
+}
+
+static void (*write_block)(const void *) = tar_write_block;
+
/* writes out the whole block, but only if it is full */
static void write_if_needed(void)
{
if (offset == BLOCKSIZE) {
- write_or_die(1, block, BLOCKSIZE);
+ write_block(block);
offset = 0;
}
}
@@ -66,7 +73,7 @@ static void do_write_blocked(const void *data, unsigned long size)
write_if_needed();
}
while (size >= BLOCKSIZE) {
- write_or_die(1, buf, BLOCKSIZE);
+ write_block(buf);
size -= BLOCKSIZE;
buf += BLOCKSIZE;
}
@@ -101,10 +108,10 @@ static void write_trailer(void)
{
int tail = BLOCKSIZE - offset;
memset(block + offset, 0, tail);
- write_or_die(1, block, BLOCKSIZE);
+ write_block(block);
if (tail < 2 * RECORDSIZE) {
memset(block, 0, offset);
- write_or_die(1, block, BLOCKSIZE);
+ write_block(block);
}
}
@@ -383,8 +390,8 @@ static int tar_filter_config(const char *var, const char *value, void *data)
if (!strcmp(type, "command")) {
if (!value)
return config_error_nonbool(var);
- free(ar->data);
- ar->data = xstrdup(value);
+ free(ar->filter_command);
+ ar->filter_command = xstrdup(value);
return 0;
}
if (!strcmp(type, "remote")) {
@@ -425,17 +432,65 @@ static int write_tar_archive(const struct archiver *ar,
return err;
}
+static git_zstream gzstream;
+static unsigned char outbuf[16384];
+
+static void tgz_deflate(int flush)
+{
+ while (gzstream.avail_in || flush == Z_FINISH) {
+ int status = git_deflate(&gzstream, flush);
+ if (!gzstream.avail_out || status == Z_STREAM_END) {
+ write_or_die(1, outbuf, gzstream.next_out - outbuf);
+ gzstream.next_out = outbuf;
+ gzstream.avail_out = sizeof(outbuf);
+ if (status == Z_STREAM_END)
+ break;
+ }
+ if (status != Z_OK && status != Z_BUF_ERROR)
+ die(_("deflate error (%d)"), status);
+ }
+}
+
+static void tgz_write_block(const void *data)
+{
+ gzstream.next_in = (void *)data;
+ gzstream.avail_in = BLOCKSIZE;
+ tgz_deflate(Z_NO_FLUSH);
+}
+
+static const char internal_gzip_command[] = "git archive gzip";
+
static int write_tar_filter_archive(const struct archiver *ar,
struct archiver_args *args)
{
+#if ZLIB_VERNUM >= 0x1221
+ struct gz_header_s gzhead = { .os = 3 }; /* Unix, for reproducibility */
+#endif
struct strbuf cmd = STRBUF_INIT;
struct child_process filter = CHILD_PROCESS_INIT;
int r;
- if (!ar->data)
+ if (!ar->filter_command)
BUG("tar-filter archiver called with no filter defined");
- strbuf_addstr(&cmd, ar->data);
+ if (!strcmp(ar->filter_command, internal_gzip_command)) {
+ write_block = tgz_write_block;
+ git_deflate_init_gzip(&gzstream, args->compression_level);
+#if ZLIB_VERNUM >= 0x1221
+ if (deflateSetHeader(&gzstream.z, &gzhead) != Z_OK)
+ BUG("deflateSetHeader() called too late");
+#endif
+ gzstream.next_out = outbuf;
+ gzstream.avail_out = sizeof(outbuf);
+
+ r = write_tar_archive(ar, args);
+
+ tgz_deflate(Z_FINISH);
+ git_deflate_end(&gzstream);
+ return r;
+ }
+
+ strbuf_addstr(&cmd, ar->filter_command);
if (args->compression_level >= 0)
strbuf_addf(&cmd, " -%d", args->compression_level);
@@ -471,14 +526,14 @@ void init_tar_archiver(void)
int i;
register_archiver(&tar_archiver);
- tar_filter_config("tar.tgz.command", "gzip -cn", NULL);
+ tar_filter_config("tar.tgz.command", internal_gzip_command, NULL);
tar_filter_config("tar.tgz.remote", "true", NULL);
- tar_filter_config("tar.tar.gz.command", "gzip -cn", NULL);
+ tar_filter_config("tar.tar.gz.command", internal_gzip_command, NULL);
tar_filter_config("tar.tar.gz.remote", "true", NULL);
git_config(git_tar_config, NULL);
for (i = 0; i < nr_tar_filters; i++) {
/* omit any filters that never had a command configured */
- if (tar_filters[i]->data)
+ if (tar_filters[i]->filter_command)
register_archiver(tar_filters[i]);
}
}
diff --git a/archive.c b/archive.c
index e29d0e0..d5109ab 100644
--- a/archive.c
+++ b/archive.c
@@ -9,6 +9,7 @@
#include "parse-options.h"
#include "unpack-trees.h"
#include "dir.h"
+#include "quote.h"
static char const * const archive_usage[] = {
N_("git archive [<options>] <tree-ish> [<path>...]"),
@@ -263,6 +264,7 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
struct extra_file_info {
char *base;
struct stat stat;
+ void *content;
};
int write_archive_entries(struct archiver_args *args,
@@ -331,19 +333,27 @@ int write_archive_entries(struct archiver_args *args,
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(_("cannot 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 (!info->content) {
+ 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(_("cannot read '%s'"), path);
+ else
+ err = write_entry(args, &fake_oid, path_in_archive.buf,
+ path_in_archive.len,
+ canon_mode(info->stat.st_mode),
+ content.buf, content.len);
+ } else {
+ err = write_entry(args, &fake_oid,
+ path, strlen(path),
+ canon_mode(info->stat.st_mode),
+ info->content, info->stat.st_size);
+ }
+
if (err)
break;
}
@@ -465,7 +475,7 @@ static void parse_treeish_arg(const char **argv,
}
tree = parse_tree_indirect(&oid);
- if (tree == NULL)
+ if (!tree)
die(_("not a tree object: %s"), oid_to_hex(&oid));
if (prefix) {
@@ -493,6 +503,7 @@ static void extra_file_info_clear(void *util, const char *str)
{
struct extra_file_info *info = util;
free(info->base);
+ free(info->content);
free(info);
}
@@ -514,14 +525,49 @@ static int add_file_cb(const struct option *opt, const char *arg, int unset)
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 = 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);
+
+ if (!strcmp(opt->long_name, "add-file")) {
+ path = prefix_filename(args->prefix, arg);
+ 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);
+ info->content = NULL; /* read the file later */
+ } else if (!strcmp(opt->long_name, "add-virtual-file")) {
+ struct strbuf buf = STRBUF_INIT;
+ const char *p = arg;
+
+ if (*p != '"')
+ p = strchr(p, ':');
+ else if (unquote_c_style(&buf, p, &p) < 0)
+ die(_("unclosed quote: '%s'"), arg);
+
+ if (!p || *p != ':')
+ die(_("missing colon: '%s'"), arg);
+
+ if (p == arg)
+ die(_("empty file name: '%s'"), arg);
+
+ path = buf.len ?
+ strbuf_detach(&buf, NULL) : xstrndup(arg, p - arg);
+
+ if (args->prefix) {
+ char *save = path;
+ path = prefix_filename(args->prefix, path);
+ free(save);
+ }
+ memset(&info->stat, 0, sizeof(info->stat));
+ info->stat.st_mode = S_IFREG | 0644;
+ info->content = xstrdup(p + 1);
+ info->stat.st_size = strlen(info->content);
+ } else {
+ BUG("add_file_cb() called for %s", opt->long_name);
+ }
+ item = string_list_append_nodup(&args->extra_files, path);
+ item->util = info;
+
return 0;
}
@@ -554,6 +600,9 @@ static int parse_archive_args(int argc, const char **argv,
{ OPTION_CALLBACK, 0, "add-file", args, N_("file"),
N_("add untracked file to archive"), 0, add_file_cb,
(intptr_t)&base },
+ { OPTION_CALLBACK, 0, "add-virtual-file", args,
+ N_("path:content"), 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,
diff --git a/archive.h b/archive.h
index 49fab71..08bed3e 100644
--- a/archive.h
+++ b/archive.h
@@ -43,7 +43,7 @@ struct archiver {
const char *name;
int (*write_archive)(const struct archiver *, struct archiver_args *);
unsigned flags;
- void *data;
+ char *filter_command;
};
void register_archiver(struct archiver *);
diff --git a/attr.c b/attr.c
index 1626cad..21e4ad2 100644
--- a/attr.c
+++ b/attr.c
@@ -79,7 +79,7 @@ static int attr_hash_entry_cmp(const void *unused_cmp_data,
* Access to this dictionary must be surrounded with a mutex.
*/
static struct attr_hashmap g_attr_hashmap = {
- HASHMAP_INIT(attr_hash_entry_cmp, NULL)
+ .map = HASHMAP_INIT(attr_hash_entry_cmp, NULL),
};
/*
diff --git a/bisect.c b/bisect.c
index 9e6a2b7..b63669c 100644
--- a/bisect.c
+++ b/bisect.c
@@ -884,6 +884,7 @@ static int check_ancestors(struct repository *r, int rev_nr,
/* Clean up objects used, as they will be reused. */
clear_commit_marks_many(rev_nr, rev, ALL_REV_FLAGS);
+ release_revisions(&revs);
return res;
}
@@ -964,6 +965,7 @@ static void show_diff_tree(struct repository *r,
setup_revisions(ARRAY_SIZE(argv) - 1, argv, &opt, NULL);
log_tree_commit(&opt, commit);
+ release_revisions(&opt);
}
/*
@@ -1008,7 +1010,7 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
*/
enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
{
- struct rev_info revs;
+ struct rev_info revs = REV_INFO_INIT;
struct commit_list *tried;
int reaches = 0, all = 0, nr, steps;
enum bisect_error res = BISECT_OK;
@@ -1033,7 +1035,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
res = check_good_are_ancestors_of_bad(r, prefix, no_checkout);
if (res)
- return res;
+ goto cleanup;
bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1);
@@ -1058,14 +1060,16 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
term_good,
term_bad);
- return BISECT_FAILED;
+ res = BISECT_FAILED;
+ goto cleanup;
}
if (!all) {
fprintf(stderr, _("No testable commit found.\n"
"Maybe you started with bad path arguments?\n"));
- return BISECT_NO_TESTABLE_COMMIT;
+ res = BISECT_NO_TESTABLE_COMMIT;
+ goto cleanup;
}
bisect_rev = &revs.commits->item->object.oid;
@@ -1085,7 +1089,8 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
* for negative return values for early returns up
* until the cmd_bisect__helper() caller.
*/
- return BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
+ res = BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
+ goto cleanup;
}
nr = all - reaches - 1;
@@ -1104,7 +1109,10 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
/* Clean up objects used, as they will be reused. */
repo_clear_commit_marks(r, ALL_REV_FLAGS);
- return bisect_checkout(bisect_rev, no_checkout);
+ res = bisect_checkout(bisect_rev, no_checkout);
+cleanup:
+ release_revisions(&revs);
+ return res;
}
static inline int log2i(int n)
diff --git a/bisect.h b/bisect.h
index 1015aeb..ee3fd65 100644
--- a/bisect.h
+++ b/bisect.h
@@ -62,6 +62,15 @@ enum bisect_error {
BISECT_INTERNAL_SUCCESS_MERGE_BASE = -11
};
+/*
+ * Stores how many good/bad commits we have stored for a bisect. nr_bad can
+ * only be 0 or 1.
+ */
+struct bisect_state {
+ unsigned int nr_good;
+ unsigned int nr_bad;
+};
+
enum bisect_error bisect_next_all(struct repository *r, const char *prefix);
int estimate_bisect_steps(int all);
diff --git a/blame.c b/blame.c
index 186ad96..da1052a 100644
--- a/blame.c
+++ b/blame.c
@@ -1072,7 +1072,7 @@ static struct blame_entry *blame_merge(struct blame_entry *list1,
if (p1->s_lno <= p2->s_lno) {
do {
tail = &p1->next;
- if ((p1 = *tail) == NULL) {
+ if (!(p1 = *tail)) {
*tail = p2;
return list1;
}
@@ -1082,7 +1082,7 @@ static struct blame_entry *blame_merge(struct blame_entry *list1,
*tail = p2;
do {
tail = &p2->next;
- if ((p2 = *tail) == NULL) {
+ if (!(p2 = *tail)) {
*tail = p1;
return list1;
}
@@ -1090,7 +1090,7 @@ static struct blame_entry *blame_merge(struct blame_entry *list1,
*tail = p1;
do {
tail = &p1->next;
- if ((p1 = *tail) == NULL) {
+ if (!(p1 = *tail)) {
*tail = p2;
return list1;
}
diff --git a/branch.c b/branch.c
index 6b31df5..d182756 100644
--- a/branch.c
+++ b/branch.c
@@ -10,6 +10,7 @@
#include "worktree.h"
#include "submodule-config.h"
#include "run-command.h"
+#include "strmap.h"
struct tracking {
struct refspec_item spec;
@@ -18,21 +19,35 @@ struct tracking {
int matches;
};
+struct find_tracked_branch_cb {
+ struct tracking *tracking;
+ struct string_list ambiguous_remotes;
+};
+
static int find_tracked_branch(struct remote *remote, void *priv)
{
- struct tracking *tracking = priv;
+ struct find_tracked_branch_cb *ftb = priv;
+ struct tracking *tracking = ftb->tracking;
if (!remote_find_tracking(remote, &tracking->spec)) {
- if (++tracking->matches == 1) {
+ switch (++tracking->matches) {
+ case 1:
string_list_append(tracking->srcs, tracking->spec.src);
tracking->remote = remote->name;
- } else {
+ break;
+ case 2:
+ /* there are at least two remotes; backfill the first one */
+ string_list_append(&ftb->ambiguous_remotes, tracking->remote);
+ /* fall through */
+ default:
+ string_list_append(&ftb->ambiguous_remotes, remote->name);
free(tracking->spec.src);
string_list_clear(tracking->srcs, 0);
+ break;
}
+ /* remote_find_tracking() searches by src if present */
tracking->spec.src = NULL;
}
-
return 0;
}
@@ -232,38 +247,99 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
struct tracking tracking;
struct string_list tracking_srcs = STRING_LIST_INIT_DUP;
int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
+ struct find_tracked_branch_cb ftb_cb = {
+ .tracking = &tracking,
+ .ambiguous_remotes = STRING_LIST_INIT_DUP,
+ };
+
+ if (!track)
+ BUG("asked to set up tracking, but tracking is disallowed");
memset(&tracking, 0, sizeof(tracking));
tracking.spec.dst = (char *)orig_ref;
tracking.srcs = &tracking_srcs;
if (track != BRANCH_TRACK_INHERIT)
- for_each_remote(find_tracked_branch, &tracking);
+ for_each_remote(find_tracked_branch, &ftb_cb);
else if (inherit_tracking(&tracking, orig_ref))
goto cleanup;
if (!tracking.matches)
switch (track) {
+ /* If ref is not remote, still use local */
case BRANCH_TRACK_ALWAYS:
case BRANCH_TRACK_EXPLICIT:
case BRANCH_TRACK_OVERRIDE:
+ /* Remote matches not evaluated */
case BRANCH_TRACK_INHERIT:
break;
+ /* Otherwise, if no remote don't track */
default:
goto cleanup;
}
- if (tracking.matches > 1)
- die(_("not tracking: ambiguous information for ref %s"),
- orig_ref);
+ /*
+ * This check does not apply to BRANCH_TRACK_INHERIT;
+ * that supports multiple entries in tracking_srcs but
+ * leaves tracking.matches at 0.
+ */
+ if (tracking.matches > 1) {
+ int status = die_message(_("not tracking: ambiguous information for ref '%s'"),
+ orig_ref);
+ if (advice_enabled(ADVICE_AMBIGUOUS_FETCH_REFSPEC)) {
+ struct strbuf remotes_advice = STRBUF_INIT;
+ struct string_list_item *item;
+
+ for_each_string_list_item(item, &ftb_cb.ambiguous_remotes)
+ /*
+ * TRANSLATORS: This is a line listing a remote with duplicate
+ * refspecs in the advice message below. For RTL languages you'll
+ * probably want to swap the "%s" and leading " " space around.
+ */
+ strbuf_addf(&remotes_advice, _(" %s\n"), item->string);
+
+ /*
+ * TRANSLATORS: The second argument is a \n-delimited list of
+ * duplicate refspecs, composed above.
+ */
+ advise(_("There are multiple remotes whose fetch refspecs map to the remote\n"
+ "tracking ref '%s':\n"
+ "%s"
+ "\n"
+ "This is typically a configuration error.\n"
+ "\n"
+ "To support setting up tracking branches, ensure that\n"
+ "different remotes' fetch refspecs map into different\n"
+ "tracking namespaces."), orig_ref,
+ remotes_advice.buf);
+ strbuf_release(&remotes_advice);
+ }
+ exit(status);
+ }
+
+ if (track == BRANCH_TRACK_SIMPLE) {
+ /*
+ * Only track if remote branch name matches.
+ * Reaching into items[0].string is safe because
+ * we know there is at least one and not more than
+ * one entry (because only BRANCH_TRACK_INHERIT can
+ * produce more than one entry).
+ */
+ const char *tracked_branch;
+ if (!skip_prefix(tracking.srcs->items[0].string,
+ "refs/heads/", &tracked_branch) ||
+ strcmp(tracked_branch, new_ref))
+ return;
+ }
if (tracking.srcs->nr < 1)
string_list_append(tracking.srcs, orig_ref);
if (install_branch_config_multiple_remotes(config_flags, new_ref,
tracking.remote, tracking.srcs) < 0)
- exit(-1);
+ exit(1);
cleanup:
string_list_clear(&tracking_srcs, 0);
+ string_list_clear(&ftb_cb.ambiguous_remotes, 0);
}
int read_branch_desc(struct strbuf *buf, const char *branch_name)
@@ -294,6 +370,83 @@ int validate_branchname(const char *name, struct strbuf *ref)
return ref_exists(ref->buf);
}
+static int initialized_checked_out_branches;
+static struct strmap current_checked_out_branches = STRMAP_INIT;
+
+static void prepare_checked_out_branches(void)
+{
+ int i = 0;
+ struct worktree **worktrees;
+
+ if (initialized_checked_out_branches)
+ return;
+ initialized_checked_out_branches = 1;
+
+ worktrees = get_worktrees();
+
+ while (worktrees[i]) {
+ char *old;
+ struct wt_status_state state = { 0 };
+ struct worktree *wt = worktrees[i++];
+ struct string_list update_refs = STRING_LIST_INIT_DUP;
+
+ if (wt->is_bare)
+ continue;
+
+ if (wt->head_ref) {
+ old = strmap_put(&current_checked_out_branches,
+ wt->head_ref,
+ xstrdup(wt->path));
+ free(old);
+ }
+
+ if (wt_status_check_rebase(wt, &state) &&
+ (state.rebase_in_progress || state.rebase_interactive_in_progress) &&
+ state.branch) {
+ struct strbuf ref = STRBUF_INIT;
+ strbuf_addf(&ref, "refs/heads/%s", state.branch);
+ old = strmap_put(&current_checked_out_branches,
+ ref.buf,
+ xstrdup(wt->path));
+ free(old);
+ strbuf_release(&ref);
+ }
+ wt_status_state_free_buffers(&state);
+
+ if (wt_status_check_bisect(wt, &state) &&
+ state.branch) {
+ struct strbuf ref = STRBUF_INIT;
+ strbuf_addf(&ref, "refs/heads/%s", state.branch);
+ old = strmap_put(&current_checked_out_branches,
+ ref.buf,
+ xstrdup(wt->path));
+ free(old);
+ strbuf_release(&ref);
+ }
+ wt_status_state_free_buffers(&state);
+
+ if (!sequencer_get_update_refs_state(get_worktree_git_dir(wt),
+ &update_refs)) {
+ struct string_list_item *item;
+ for_each_string_list_item(item, &update_refs) {
+ old = strmap_put(&current_checked_out_branches,
+ item->string,
+ xstrdup(wt->path));
+ free(old);
+ }
+ string_list_clear(&update_refs, 1);
+ }
+ }
+
+ free_worktrees(worktrees);
+}
+
+const char *branch_checked_out(const char *refname)
+{
+ prepare_checked_out_branches();
+ return strmap_get(&current_checked_out_branches, refname);
+}
+
/*
* Check if a branch 'name' can be created as a new branch; die otherwise.
* 'force' can be used when it is OK for the named branch already exists.
@@ -302,9 +455,7 @@ int validate_branchname(const char *name, struct strbuf *ref)
*/
int validate_new_branchname(const char *name, struct strbuf *ref, int force)
{
- struct worktree **worktrees;
- const struct worktree *wt;
-
+ const char *path;
if (!validate_branchname(name, ref))
return 0;
@@ -312,13 +463,10 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force)
die(_("a branch named '%s' already exists"),
ref->buf + strlen("refs/heads/"));
- worktrees = get_worktrees();
- wt = find_shared_symref(worktrees, "HEAD", ref->buf);
- if (wt && !wt->is_bare)
+ if ((path = branch_checked_out(ref->buf)))
die(_("cannot force update the branch '%s' "
"checked out at '%s'"),
- ref->buf + strlen("refs/heads/"), wt->path);
- free_worktrees(worktrees);
+ ref->buf + strlen("refs/heads/"), path);
return 1;
}
@@ -385,12 +533,10 @@ static void dwim_branch_start(struct repository *r, const char *start_name,
real_ref = NULL;
if (get_oid_mb(start_name, &oid)) {
if (explicit_tracking) {
- if (advice_enabled(ADVICE_SET_UPSTREAM_FAILURE)) {
- error(_(upstream_missing), start_name);
- advise(_(upstream_advice));
- exit(1);
- }
- die(_(upstream_missing), start_name);
+ int code = die_message(_(upstream_missing), start_name);
+ advise_if_enabled(ADVICE_SET_UPSTREAM_FAILURE,
+ _(upstream_advice));
+ exit(code);
}
die(_("not a valid object name: '%s'"), start_name);
}
@@ -416,7 +562,7 @@ static void dwim_branch_start(struct repository *r, const char *start_name,
break;
}
- if ((commit = lookup_commit_reference(r, &oid)) == NULL)
+ if (!(commit = lookup_commit_reference(r, &oid)))
die(_("not a valid branch point: '%s'"), start_name);
if (out_real_ref) {
*out_real_ref = real_ref;
@@ -514,7 +660,7 @@ static int submodule_create_branch(struct repository *r,
child.err = -1;
child.stdout_to_stderr = 1;
- prepare_other_repo_env(&child.env_array, r->gitdir);
+ prepare_other_repo_env(&child.env, r->gitdir);
/*
* submodule_create_branch() is indirectly invoked by "git
* branch", but we cannot invoke "git branch" in the child
@@ -534,8 +680,29 @@ static int submodule_create_branch(struct repository *r,
strvec_push(&child.args, "--quiet");
if (reflog)
strvec_push(&child.args, "--create-reflog");
- if (track == BRANCH_TRACK_ALWAYS || track == BRANCH_TRACK_EXPLICIT)
- strvec_push(&child.args, "--track");
+
+ switch (track) {
+ case BRANCH_TRACK_NEVER:
+ strvec_push(&child.args, "--no-track");
+ break;
+ case BRANCH_TRACK_ALWAYS:
+ case BRANCH_TRACK_EXPLICIT:
+ strvec_push(&child.args, "--track=direct");
+ break;
+ case BRANCH_TRACK_OVERRIDE:
+ BUG("BRANCH_TRACK_OVERRIDE cannot be used when creating a branch.");
+ break;
+ case BRANCH_TRACK_INHERIT:
+ strvec_push(&child.args, "--track=inherit");
+ break;
+ case BRANCH_TRACK_UNSPECIFIED:
+ /* Default for "git checkout". Do not pass --track. */
+ case BRANCH_TRACK_REMOTE:
+ /* Default for "git branch". Do not pass --track. */
+ case BRANCH_TRACK_SIMPLE:
+ /* Config-driven only. Do not pass --track. */
+ break;
+ }
strvec_pushl(&child.args, name, start_oid, tracking_name, NULL);
@@ -584,12 +751,14 @@ void create_branches_recursively(struct repository *r, const char *name,
* be created in every submodule.
*/
for (i = 0; i < submodule_entry_list.entry_nr; i++) {
- if (submodule_entry_list.entries[i].repo == NULL) {
+ if (!submodule_entry_list.entries[i].repo) {
+ int code = die_message(
+ _("submodule '%s': unable to find submodule"),
+ submodule_entry_list.entries[i].submodule->name);
if (advice_enabled(ADVICE_SUBMODULES_NOT_UPDATED))
advise(_("You may try updating the submodules using 'git checkout %s && git submodule update --init'"),
start_commitish);
- die(_("submodule '%s': unable to find submodule"),
- submodule_entry_list.entries[i].submodule->name);
+ exit(code);
}
if (submodule_create_branch(
@@ -614,7 +783,8 @@ void create_branches_recursively(struct repository *r, const char *name,
* tedious to determine whether or not tracking was set up in the
* superproject.
*/
- setup_tracking(name, tracking_name, track, quiet);
+ if (track)
+ setup_tracking(name, tracking_name, track, quiet);
for (i = 0; i < submodule_entry_list.entry_nr; i++) {
if (submodule_create_branch(
diff --git a/branch.h b/branch.h
index 04df2aa5..ef56103 100644
--- a/branch.h
+++ b/branch.h
@@ -12,6 +12,7 @@ enum branch_track {
BRANCH_TRACK_EXPLICIT,
BRANCH_TRACK_OVERRIDE,
BRANCH_TRACK_INHERIT,
+ BRANCH_TRACK_SIMPLE,
};
extern enum branch_track git_branch_track;
@@ -100,6 +101,13 @@ void create_branches_recursively(struct repository *r, const char *name,
const char *tracking_name, int force,
int reflog, int quiet, enum branch_track track,
int dry_run);
+
+/*
+ * If the branch at 'refname' is currently checked out in a worktree,
+ * then return the path to that worktree.
+ */
+const char *branch_checked_out(const char *refname);
+
/*
* Check if 'name' can be a valid name for a branch; die otherwise.
* Return 1 if the named branch already exists; return 0 otherwise.
diff --git a/builtin.h b/builtin.h
index 83379f3..40e9ecc 100644
--- a/builtin.h
+++ b/builtin.h
@@ -159,6 +159,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
int cmd_for_each_repo(int argc, const char **argv, const char *prefix);
int cmd_format_patch(int argc, const char **argv, const char *prefix);
int cmd_fsck(int argc, const char **argv, const char *prefix);
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix);
int cmd_gc(int argc, const char **argv, const char *prefix);
int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
int cmd_grep(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index 3ffb86a..f843729 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -141,8 +141,17 @@ int add_files_to_cache(const char *prefix,
rev.diffopt.format_callback_data = &data;
rev.diffopt.flags.override_submodule_config = 1;
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
+
+ /*
+ * Use an ODB transaction to optimize adding multiple objects.
+ * This function is invoked from commands other than 'add', which
+ * may not have their own transaction active.
+ */
+ begin_odb_transaction();
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
- clear_pathspec(&rev.prune_data);
+ end_odb_transaction();
+
+ release_revisions(&rev);
return !!data.add_errors;
}
@@ -236,17 +245,12 @@ 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) {
- 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 < 0 &&
+ git_config_get_bool("add.interactive.usebuiltin",
+ &use_builtin_add_i))
+ use_builtin_add_i = 1;
- if (use_builtin_add_i == 1) {
+ if (use_builtin_add_i != 0) {
enum add_p_mode mode;
if (!patch_mode)
@@ -340,6 +344,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
unlink(file);
free(file);
+ release_revisions(&rev);
return 0;
}
@@ -670,7 +675,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
string_list_clear(&only_match_skip_worktree, 0);
}
- plug_bulk_checkin();
+ begin_odb_transaction();
if (add_renormalize)
exit_status |= renormalize_tracked_files(&pathspec, flags);
@@ -682,7 +687,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (chmod_arg && pathspec.nr)
exit_status |= chmod_pathspec(&pathspec, chmod_arg[0], show_only);
- unplug_bulk_checkin();
+ end_odb_transaction();
finish:
if (write_locked_index(&the_index, &lock_file,
diff --git a/builtin/am.c b/builtin/am.c
index 0f4111b..93bec62 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1397,6 +1397,7 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm
add_pending_object(&rev_info, &commit->object, "");
diff_setup_done(&rev_info.diffopt);
log_tree_commit(&rev_info, commit);
+ release_revisions(&rev_info);
}
/**
@@ -1429,6 +1430,7 @@ static void write_index_patch(const struct am_state *state)
add_pending_object(&rev_info, &tree->object, "");
diff_setup_done(&rev_info.diffopt);
run_diff_index(&rev_info, 1);
+ release_revisions(&rev_info);
}
/**
@@ -1582,6 +1584,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
diff_setup_done(&rev_info.diffopt);
run_diff_index(&rev_info, 1);
+ release_revisions(&rev_info);
}
if (run_apply(state, index_path))
diff --git a/builtin/apply.c b/builtin/apply.c
index 3f099b9..555219d 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1,7 +1,6 @@
#include "cache.h"
#include "builtin.h"
#include "parse-options.h"
-#include "lockfile.h"
#include "apply.h"
static const char * const apply_usage[] = {
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 8b2b259..8a052c7 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -329,12 +329,12 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
return 0;
}
-static int mark_good(const char *refname, const struct object_id *oid,
- int flag, void *cb_data)
+static int inc_nr(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
{
- int *m_good = (int *)cb_data;
- *m_good = 0;
- return 1;
+ unsigned int *nr = (unsigned int *)cb_data;
+ (*nr)++;
+ return 0;
}
static const char need_bad_and_good_revision_warning[] =
@@ -384,23 +384,64 @@ static int decide_next(const struct bisect_terms *terms,
vocab_good, vocab_bad, vocab_good, vocab_bad);
}
-static int bisect_next_check(const struct bisect_terms *terms,
- const char *current_term)
+static void bisect_status(struct bisect_state *state,
+ const struct bisect_terms *terms)
{
- int missing_good = 1, missing_bad = 1;
char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
char *good_glob = xstrfmt("%s-*", terms->term_good);
if (ref_exists(bad_ref))
- missing_bad = 0;
+ state->nr_bad = 1;
- for_each_glob_ref_in(mark_good, good_glob, "refs/bisect/",
- (void *) &missing_good);
+ for_each_glob_ref_in(inc_nr, good_glob, "refs/bisect/",
+ (void *) &state->nr_good);
free(good_glob);
free(bad_ref);
+}
- return decide_next(terms, current_term, missing_good, missing_bad);
+__attribute__((format (printf, 1, 2)))
+static void bisect_log_printf(const char *fmt, ...)
+{
+ struct strbuf buf = STRBUF_INIT;
+ va_list ap;
+
+ va_start(ap, fmt);
+ strbuf_vaddf(&buf, fmt, ap);
+ va_end(ap);
+
+ printf("%s", buf.buf);
+ append_to_file(git_path_bisect_log(), "# %s", buf.buf);
+
+ strbuf_release(&buf);
+}
+
+static void bisect_print_status(const struct bisect_terms *terms)
+{
+ struct bisect_state state = { 0 };
+
+ bisect_status(&state, terms);
+
+ /* If we had both, we'd already be started, and shouldn't get here. */
+ if (state.nr_good && state.nr_bad)
+ return;
+
+ if (!state.nr_good && !state.nr_bad)
+ bisect_log_printf(_("status: waiting for both good and bad commits\n"));
+ else if (state.nr_good)
+ bisect_log_printf(Q_("status: waiting for bad commit, %d good commit known\n",
+ "status: waiting for bad commit, %d good commits known\n",
+ state.nr_good), state.nr_good);
+ else
+ bisect_log_printf(_("status: waiting for good commit(s), bad commit known\n"));
+}
+
+static int bisect_next_check(const struct bisect_terms *terms,
+ const char *current_term)
+{
+ struct bisect_state state = { 0 };
+ bisect_status(&state, terms);
+ return decide_next(terms, current_term, !state.nr_good, !state.nr_bad);
}
static int get_terms(struct bisect_terms *terms)
@@ -433,7 +474,7 @@ static int bisect_terms(struct bisect_terms *terms, const char *option)
if (get_terms(terms))
return error(_("no terms defined"));
- if (option == NULL) {
+ if (!option) {
printf(_("Your current terms are %s for the old state\n"
"and %s for the new state.\n"),
terms->term_good, terms->term_bad);
@@ -555,6 +596,7 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
reset_revision_walk();
strbuf_release(&commit_name);
+ release_revisions(&revs);
fclose(fp);
return 0;
}
@@ -606,8 +648,10 @@ static enum bisect_error bisect_next(struct bisect_terms *terms, const char *pre
static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
{
- if (bisect_next_check(terms, NULL))
+ if (bisect_next_check(terms, NULL)) {
+ bisect_print_status(terms);
return BISECT_OK;
+ }
return bisect_next(terms, prefix);
}
@@ -1041,6 +1085,7 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar
oid_to_hex(&commit->object.oid));
reset_revision_walk();
+ release_revisions(&revs);
} else {
strvec_push(&argv_state, argv[i]);
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 8d15b68..02e3942 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -898,6 +898,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
unsigned int range_i;
long anchor;
const int hexsz = the_hash_algo->hexsz;
+ long num_lines = 0;
setup_default_color_by_age();
git_config(git_blame_config, &output_option);
@@ -1129,7 +1130,10 @@ parse_done:
for (range_i = ranges.nr; range_i > 0; --range_i) {
const struct range *r = &ranges.ranges[range_i - 1];
ent = blame_entry_prepend(ent, r->start, r->end, o);
+ num_lines += (r->end - r->start);
}
+ if (!num_lines)
+ num_lines = sb.num_lines;
o->suspects = ent;
prio_queue_put(&sb.commits, o->commit);
@@ -1158,7 +1162,7 @@ parse_done:
sb.found_guilty_entry = &found_guilty_entry;
sb.found_guilty_entry_data = &pi;
if (show_progress)
- pi.progress = start_delayed_progress(_("Blaming lines"), sb.num_lines);
+ pi.progress = start_delayed_progress(_("Blaming lines"), num_lines);
assign_blame(&sb, opt);
@@ -1167,7 +1171,7 @@ parse_done:
if (!incremental)
setup_pager();
else
- return 0;
+ goto cleanup;
blame_sort_final(&sb);
@@ -1201,6 +1205,8 @@ parse_done:
printf("num commits: %d\n", sb.num_commits);
}
+cleanup:
cleanup_scoreboard(&sb);
+ release_revisions(&revs);
return 0;
}
diff --git a/builtin/branch.c b/builtin/branch.c
index 5d00d0b..55cd9a6 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -204,7 +204,6 @@ static void delete_branch_config(const char *branchname)
static int delete_branches(int argc, const char **argv, int force, int kinds,
int quiet)
{
- struct worktree **worktrees;
struct commit *head_rev = NULL;
struct object_id oid;
char *name = NULL;
@@ -242,8 +241,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
die(_("Couldn't look up commit object for HEAD"));
}
- worktrees = get_worktrees();
-
for (i = 0; i < argc; i++, strbuf_reset(&bname)) {
char *target = NULL;
int flags = 0;
@@ -253,12 +250,11 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
name = mkpathdup(fmt, bname.buf);
if (kinds == FILTER_REFS_BRANCHES) {
- const struct worktree *wt =
- find_shared_symref(worktrees, "HEAD", name);
- if (wt) {
+ const char *path;
+ if ((path = branch_checked_out(name))) {
error(_("Cannot delete branch '%s' "
"checked out at '%s'"),
- bname.buf, wt->path);
+ bname.buf, path);
ret = 1;
continue;
}
@@ -315,7 +311,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
free(name);
strbuf_release(&bname);
- free_worktrees(worktrees);
return ret;
}
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 50cf389..f42782e 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -71,6 +71,7 @@ static int stream_blob(const struct object_id *oid)
static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
int unknown_type)
{
+ int ret;
struct object_id oid;
enum object_type type;
char *buf;
@@ -106,7 +107,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
if (sb.len) {
printf("%s\n", sb.buf);
strbuf_release(&sb);
- return 0;
+ ret = 0;
+ goto cleanup;
}
break;
@@ -115,7 +117,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
die("git cat-file: could not get object info");
printf("%"PRIuMAX"\n", (uintmax_t)size);
- return 0;
+ ret = 0;
+ goto cleanup;
case 'e':
return !has_object_file(&oid);
@@ -123,8 +126,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
case 'w':
if (filter_object(path, obj_context.mode,
- &oid, &buf, &size))
- return -1;
+ &oid, &buf, &size)) {
+ ret = -1;
+ goto cleanup;
+ }
break;
case 'c':
@@ -143,11 +148,14 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
const char *ls_args[3] = { NULL };
ls_args[0] = "ls-tree";
ls_args[1] = obj_name;
- return cmd_ls_tree(2, ls_args, NULL);
+ ret = cmd_ls_tree(2, ls_args, NULL);
+ goto cleanup;
}
- if (type == OBJ_BLOB)
- return stream_blob(&oid);
+ if (type == OBJ_BLOB) {
+ ret = stream_blob(&oid);
+ goto cleanup;
+ }
buf = read_object_file(&oid, &type, &size);
if (!buf)
die("Cannot read object %s", obj_name);
@@ -172,8 +180,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
} else
oidcpy(&blob_oid, &oid);
- if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB)
- return stream_blob(&blob_oid);
+ if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB) {
+ ret = stream_blob(&blob_oid);
+ goto cleanup;
+ }
/*
* we attempted to dereference a tag to a blob
* and failed; there may be new dereference
@@ -193,9 +203,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
die("git cat-file %s: bad file", obj_name);
write_or_die(1, buf, size);
+ ret = 0;
+cleanup:
free(buf);
free(obj_context.path);
- return 0;
+ return ret;
}
struct expand_data {
@@ -655,6 +667,7 @@ static void batch_objects_command(struct batch_options *opt,
free_cmds(queued_cmd, &nr);
}
+ free_cmds(queued_cmd, &nr);
free(queued_cmd);
strbuf_release(&input);
}
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index bc67d3f..fd0e5f8 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -57,6 +57,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
int normalize = 0;
int flags = 0;
const char *refname;
+ char *to_free = NULL;
+ int ret = 1;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_check_ref_format_usage);
@@ -81,11 +83,14 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
refname = argv[i];
if (normalize)
- refname = collapse_slashes(refname);
+ refname = to_free = collapse_slashes(refname);
if (check_refname_format(refname, flags))
- return 1;
+ goto cleanup;
if (normalize)
printf("%s\n", refname);
- return 0;
+ ret = 0;
+cleanup:
+ free(to_free);
+ return ret;
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 7976814..29c74f8 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -417,7 +417,7 @@ static int checkout_worktree(const struct checkout_opts *opts,
mem_pool_discard(&ce_mem_pool, should_validate_cache_entries());
remove_marked_cache_entries(&the_index, 1);
remove_scheduled_dirs();
- errs |= finish_delayed_checkout(&state, &nr_checkouts, opts->show_progress);
+ errs |= finish_delayed_checkout(&state, opts->show_progress);
if (opts->count_checkout_paths) {
if (nr_unmerged)
@@ -629,7 +629,7 @@ static void show_local_changes(struct object *head,
diff_setup_done(&rev.diffopt);
add_pending_object(&rev, head, NULL);
run_diff_index(&rev, 0);
- object_array_clear(&rev.pending);
+ release_revisions(&rev);
}
static void describe_detached_head(const char *msg, struct commit *commit)
@@ -710,6 +710,26 @@ static void setup_branch_path(struct branch_info *branch)
branch->path = strbuf_detach(&buf, NULL);
}
+static void init_topts(struct unpack_trees_options *topts, int merge,
+ int show_progress, int overwrite_ignore,
+ struct commit *old_commit)
+{
+ memset(topts, 0, sizeof(*topts));
+ topts->head_idx = -1;
+ topts->src_index = &the_index;
+ topts->dst_index = &the_index;
+
+ setup_unpack_trees_porcelain(topts, "checkout");
+
+ topts->initial_checkout = is_cache_unborn();
+ topts->update = 1;
+ topts->merge = 1;
+ topts->quiet = merge && old_commit;
+ topts->verbose_update = show_progress;
+ topts->fn = twoway_merge;
+ topts->preserve_ignored = !overwrite_ignore;
+}
+
static int merge_working_tree(const struct checkout_opts *opts,
struct branch_info *old_branch_info,
struct branch_info *new_branch_info,
@@ -740,13 +760,6 @@ static int merge_working_tree(const struct checkout_opts *opts,
struct unpack_trees_options topts;
const struct object_id *old_commit_oid;
- memset(&topts, 0, sizeof(topts));
- topts.head_idx = -1;
- topts.src_index = &the_index;
- topts.dst_index = &the_index;
-
- setup_unpack_trees_porcelain(&topts, "checkout");
-
refresh_cache(REFRESH_QUIET);
if (unmerged_cache()) {
@@ -755,17 +768,12 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
/* 2-way merge to the new branch */
- topts.initial_checkout = is_cache_unborn();
- topts.update = 1;
- topts.merge = 1;
- topts.quiet = opts->merge && old_branch_info->commit;
- topts.verbose_update = opts->show_progress;
- topts.fn = twoway_merge;
+ init_topts(&topts, opts->merge, opts->show_progress,
+ opts->overwrite_ignore, old_branch_info->commit);
init_checkout_metadata(&topts.meta, new_branch_info->refname,
new_branch_info->commit ?
&new_branch_info->commit->object.oid :
&new_branch_info->oid, NULL);
- topts.preserve_ignored = !opts->overwrite_ignore;
old_commit_oid = old_branch_info->commit ?
&old_branch_info->commit->object.oid :
@@ -834,7 +842,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
if (ret)
return ret;
o.ancestor = old_branch_info->name;
- if (old_branch_info->name == NULL) {
+ if (!old_branch_info->name) {
strbuf_add_unique_abbrev(&old_commit_shortname,
&old_branch_info->commit->object.oid,
DEFAULT_ABBREV);
@@ -1082,6 +1090,7 @@ static void orphaned_commit_warning(struct commit *old_commit, struct commit *ne
/* Clean up objects used, as they will be reused. */
repo_clear_commit_marks(the_repository, ALL_REV_FLAGS);
+ release_revisions(&revs);
}
static int switch_branches(const struct checkout_opts *opts,
diff --git a/builtin/clone.c b/builtin/clone.c
index 5231656..c4ff464 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -494,6 +494,7 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
/* if --branch=tag, pull the requested tag explicitly */
get_fetch_map(remote_head, tag_refspec, &tail, 0);
}
+ free_refs(remote_head);
} else {
int i;
for (i = 0; i < refspec->nr; i++)
@@ -606,7 +607,7 @@ static void update_remote_refs(const struct ref *refs,
}
static void update_head(const struct ref *our, const struct ref *remote,
- const char *msg)
+ const char *unborn, const char *msg)
{
const char *head;
if (our && skip_prefix(our->name, "refs/heads/", &head)) {
@@ -632,6 +633,15 @@ static void update_head(const struct ref *our, const struct ref *remote,
*/
update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
UPDATE_REFS_DIE_ON_ERR);
+ } else if (unborn && skip_prefix(unborn, "refs/heads/", &head)) {
+ /*
+ * Unborn head from remote; same as "our" case above except
+ * that we have no ref to update.
+ */
+ if (create_symref("HEAD", unborn, NULL) < 0)
+ die(_("unable to update HEAD"));
+ if (!option_bare)
+ install_branch_config(0, head, remote_name, unborn);
}
}
@@ -672,7 +682,7 @@ static int checkout(int submodule_progress, int filter_submodules)
head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL);
if (!head) {
warning(_("remote HEAD refers to nonexistent ref, "
- "unable to checkout.\n"));
+ "unable to checkout"));
return 0;
}
if (!strcmp(head, "HEAD")) {
@@ -876,6 +886,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
const struct ref *refs, *remote_head;
struct ref *remote_head_points_at = NULL;
const struct ref *our_head_points_at;
+ char *unborn_head = NULL;
struct ref *mapped_refs = NULL;
const struct ref *ref;
struct strbuf key = STRBUF_INIT;
@@ -1106,10 +1117,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
* 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)
+ if (option_origin) {
+ free(remote_name);
remote_name = xstrdup(option_origin);
+ }
- if (remote_name == NULL)
+ if (!remote_name)
remote_name = xstrdup("origin");
if (!valid_remote_name(remote_name))
@@ -1264,51 +1277,49 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (transport_fetch_refs(transport, mapped_refs))
die(_("remote transport reported error"));
}
-
- remote_head = find_ref_by_name(refs, "HEAD");
- remote_head_points_at =
- guess_remote_head(remote_head, mapped_refs, 0);
-
- if (option_branch) {
- our_head_points_at =
- find_remote_branch(mapped_refs, option_branch);
-
- if (!our_head_points_at)
- die(_("Remote branch %s not found in upstream %s"),
- option_branch, remote_name);
- }
- else
- our_head_points_at = remote_head_points_at;
}
- else {
- const char *branch;
- const char *ref;
- char *ref_free = NULL;
- if (option_branch)
- die(_("Remote branch %s not found in upstream %s"),
- option_branch, remote_name);
+ remote_head = find_ref_by_name(refs, "HEAD");
+ remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
- warning(_("You appear to have cloned an empty repository."));
+ if (option_branch) {
+ our_head_points_at = find_remote_branch(mapped_refs, option_branch);
+ if (!our_head_points_at)
+ die(_("Remote branch %s not found in upstream %s"),
+ option_branch, remote_name);
+ } else if (remote_head_points_at) {
+ our_head_points_at = remote_head_points_at;
+ } else if (remote_head) {
our_head_points_at = NULL;
- remote_head_points_at = NULL;
- remote_head = NULL;
- option_no_checkout = 1;
+ } else {
+ const char *branch;
+
+ if (!mapped_refs) {
+ warning(_("You appear to have cloned an empty repository."));
+ option_no_checkout = 1;
+ }
if (transport_ls_refs_options.unborn_head_target &&
skip_prefix(transport_ls_refs_options.unborn_head_target,
"refs/heads/", &branch)) {
- ref = transport_ls_refs_options.unborn_head_target;
- create_symref("HEAD", ref, reflog_msg.buf);
+ unborn_head = xstrdup(transport_ls_refs_options.unborn_head_target);
} else {
branch = git_default_branch_name(0);
- ref_free = xstrfmt("refs/heads/%s", branch);
- ref = ref_free;
+ unborn_head = xstrfmt("refs/heads/%s", branch);
}
- if (!option_bare)
- install_branch_config(0, branch, remote_name, ref);
- free(ref_free);
+ /*
+ * We may have selected a local default branch name "foo",
+ * and even though the remote's HEAD does not point there,
+ * it may still have a "foo" branch. If so, set it up so
+ * that we can follow the usual checkout code later.
+ *
+ * Note that for an empty repo we'll already have set
+ * option_no_checkout above, which would work against us here.
+ * But for an empty repo, find_remote_branch() can never find
+ * a match.
+ */
+ our_head_points_at = find_remote_branch(mapped_refs, branch);
}
write_refspec_config(src_ref_prefix, our_head_points_at,
@@ -1328,7 +1339,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
branch_top.buf, reflog_msg.buf, transport,
!is_local);
- update_head(our_head_points_at, remote_head, reflog_msg.buf);
+ update_head(our_head_points_at, remote_head, unborn_head, reflog_msg.buf);
/*
* We want to show progress for recursive submodule clones iff
@@ -1355,6 +1366,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_release(&key);
free_refs(mapped_refs);
free_refs(remote_head_points_at);
+ free(unborn_head);
free(dir);
free(path);
UNLEAK(repo);
diff --git a/builtin/commit.c b/builtin/commit.c
index 009a1de..fcf9c85 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -861,7 +861,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
}
s->fp = fopen_for_writing(git_path_commit_editmsg());
- if (s->fp == NULL)
+ if (!s->fp)
die_errno(_("could not open '%s'"), git_path_commit_editmsg());
/* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */
@@ -1100,7 +1100,6 @@ static const char *find_author_by_nickname(const char *name)
struct rev_info revs;
struct commit *commit;
struct strbuf buf = STRBUF_INIT;
- struct string_list mailmap = STRING_LIST_INIT_NODUP;
const char *av[20];
int ac = 0;
@@ -1111,7 +1110,8 @@ static const char *find_author_by_nickname(const char *name)
av[++ac] = buf.buf;
av[++ac] = NULL;
setup_revisions(ac, av, &revs, NULL);
- revs.mailmap = &mailmap;
+ revs.mailmap = xmalloc(sizeof(struct string_list));
+ string_list_init_nodup(revs.mailmap);
read_mailmap(revs.mailmap);
if (prepare_revision_walk(&revs))
@@ -1122,7 +1122,7 @@ static const char *find_author_by_nickname(const char *name)
ctx.date_mode.type = DATE_NORMAL;
strbuf_release(&buf);
format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
- clear_mailmap(&mailmap);
+ release_revisions(&revs);
return strbuf_detach(&buf, NULL);
}
die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
@@ -1687,6 +1687,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
struct strbuf err = STRBUF_INIT;
+ int ret = 0;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_commit_usage, builtin_commit_options);
@@ -1721,8 +1722,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
running hooks, writing the trees, and interacting with the user. */
if (!prepare_to_commit(index_file, prefix,
current_head, &s, &author_ident)) {
+ ret = 1;
rollback_index_files();
- return 1;
+ goto cleanup;
}
/* Determine parents */
@@ -1820,7 +1822,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
rollback_index_files();
die(_("failed to write commit object"));
}
- strbuf_release(&author_ident);
free_commit_extra_headers(extra);
if (update_head_with_reflog(current_head, &oid, reflog_msg, &sb,
@@ -1862,7 +1863,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
apply_autostash(git_path_merge_autostash(the_repository));
+cleanup:
+ UNLEAK(author_ident);
UNLEAK(err);
UNLEAK(sb);
- return 0;
+ return ret;
}
diff --git a/builtin/describe.c b/builtin/describe.c
index 42159cd..a76f1a1 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -517,6 +517,7 @@ static void describe_blob(struct object_id oid, struct strbuf *dst)
traverse_commit_list(&revs, process_commit, process_object, &pcd);
reset_revision_walk();
+ release_revisions(&revs);
}
static void describe(const char *arg, int last_one)
@@ -667,6 +668,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
suffix = NULL;
else
suffix = dirty;
+ release_revisions(&revs);
}
describe("HEAD", 1);
} else if (dirty) {
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 70103c4..92cf6e1 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -77,8 +77,12 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
perror("read_cache_preload");
- return -1;
+ result = -1;
+ goto cleanup;
}
result = run_diff_files(&rev, options);
- return diff_result_code(&rev.diffopt, result);
+ result = diff_result_code(&rev.diffopt, result);
+cleanup:
+ release_revisions(&rev);
+ return result;
}
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 5fd23ab..7d158af 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -70,6 +70,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
return -1;
}
result = run_diff_index(&rev, option);
- UNLEAK(rev);
- return diff_result_code(&rev.diffopt, result);
+ result = diff_result_code(&rev.diffopt, result);
+ release_revisions(&rev);
+ return result;
}
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 0e0ac1f..116097a 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -195,6 +195,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
int saved_dcctc = 0;
opt->diffopt.rotate_to_strict = 0;
+ opt->diffopt.no_free = 1;
if (opt->diffopt.detect_rename) {
if (!the_index.cache)
repo_read_index(the_repository);
@@ -217,6 +218,8 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
}
opt->diffopt.degraded_cc_to_c = saved_dcctc;
opt->diffopt.needed_rename_limit = saved_nrl;
+ opt->diffopt.no_free = 0;
+ diff_free(&opt->diffopt);
}
return diff_result_code(&opt->diffopt, 0);
diff --git a/builtin/diff.c b/builtin/diff.c
index bb7fafc..54bb3de 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -352,7 +352,7 @@ static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym)
othercount++;
continue;
}
- if (map == NULL)
+ if (!map)
map = bitmap_new();
bitmap_set(map, i);
}
@@ -594,7 +594,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
result = diff_result_code(&rev.diffopt, result);
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
- UNLEAK(rev);
+ release_revisions(&rev);
UNLEAK(ent);
UNLEAK(blob);
return result;
diff --git a/builtin/difftool.c b/builtin/difftool.c
index faa3507..b3c509b 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -217,7 +217,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
update_index.use_shell = 0;
update_index.clean_on_exit = 1;
update_index.dir = workdir;
- strvec_pushf(&update_index.env_array, "GIT_INDEX_FILE=%s", index_path);
+ strvec_pushf(&update_index.env, "GIT_INDEX_FILE=%s", index_path);
/* Ignore any errors of update-index */
run_command(&update_index);
@@ -230,7 +230,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
diff_files.clean_on_exit = 1;
diff_files.out = -1;
diff_files.dir = workdir;
- strvec_pushf(&diff_files.env_array, "GIT_INDEX_FILE=%s", index_path);
+ strvec_pushf(&diff_files.env, "GIT_INDEX_FILE=%s", index_path);
if (start_command(&diff_files))
die("could not obtain raw diff");
fp = xfdopen(diff_files.out, "r");
@@ -675,7 +675,7 @@ static int run_file_diff(int prompt, const char *prefix,
child->git_cmd = 1;
child->dir = prefix;
- strvec_pushv(&child->env_array, env);
+ strvec_pushv(&child->env, env);
return run_command(child);
}
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index a7d7269..e1748fb 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -1261,6 +1261,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
revs.diffopt.format_callback = show_filemodify;
revs.diffopt.format_callback_data = &paths_of_changed_objects;
revs.diffopt.flags.recursive = 1;
+ revs.diffopt.no_free = 1;
while ((commit = get_revision(&revs)))
handle_commit(commit, &revs, &paths_of_changed_objects);
@@ -1275,6 +1276,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
printf("done\n");
refspec_clear(&refspecs);
+ release_revisions(&revs);
return 0;
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 28d3193..14113cf 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -3465,7 +3465,7 @@ static void git_pack_config(void)
pack_idx_opts.version = indexversion_value;
if (pack_idx_opts.version > 2)
git_die_config("pack.indexversion",
- "bad pack.indexversion=%"PRIu32, pack_idx_opts.version);
+ "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
}
if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
max_packsize = packsizelimit_value;
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index c2d96f4..f045bbb 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -153,11 +153,15 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.from_promisor = 1;
continue;
}
- if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
+ if (!strcmp("--refetch", arg)) {
+ args.refetch = 1;
+ continue;
+ }
+ if (skip_prefix(arg, ("--filter="), &arg)) {
parse_list_objects_filter(&args.filter_options, arg);
continue;
}
- if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) {
+ if (!strcmp(arg, ("--no-filter"))) {
list_objects_filter_set_no_filter(&args.filter_options);
continue;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 9b4018f..fc5cecb 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -59,7 +59,7 @@ static int prune_tags = -1; /* unspecified */
static int all, append, dry_run, force, keep, multiple, update_head_ok;
static int write_fetch_head = 1;
-static int verbosity, deepen_relative, set_upstream;
+static int verbosity, deepen_relative, set_upstream, refetch;
static int progress = -1;
static int enable_auto_gc = 1;
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
@@ -190,6 +190,9 @@ static struct option builtin_fetch_options[] = {
OPT_SET_INT_F(0, "unshallow", &unshallow,
N_("convert to a complete repository"),
1, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "refetch", &refetch,
+ N_("re-fetch without negotiating common commits"),
+ 1, PARSE_OPT_NONEG),
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
OPT_CALLBACK_F(0, "recurse-submodules-default",
@@ -878,11 +881,9 @@ static void format_display(struct strbuf *display, char code,
static int update_local_ref(struct ref *ref,
struct ref_transaction *transaction,
const char *remote, const struct ref *remote_ref,
- struct strbuf *display, int summary_width,
- struct worktree **worktrees)
+ struct strbuf *display, int summary_width)
{
struct commit *current = NULL, *updated;
- const struct worktree *wt;
const char *pretty_ref = prettify_refname(ref->name);
int fast_forward = 0;
@@ -897,16 +898,14 @@ static int update_local_ref(struct ref *ref,
}
if (!update_head_ok &&
- (wt = find_shared_symref(worktrees, "HEAD", ref->name)) &&
- !wt->is_bare && !is_null_oid(&ref->old_oid)) {
+ !is_null_oid(&ref->old_oid) &&
+ branch_checked_out(ref->name)) {
/*
* If this is the head, and it's not okay to update
* the head, and the old value of the head isn't empty...
*/
format_display(display, '!', _("[rejected]"),
- wt->is_current ?
- _("can't fetch in current branch") :
- _("checked out in another worktree"),
+ _("can't fetch into checked-out branch"),
remote, pretty_ref, summary_width);
return 1;
}
@@ -1107,10 +1106,10 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
static int store_updated_refs(const char *raw_url, const char *remote_name,
int connectivity_checked,
struct ref_transaction *transaction, struct ref *ref_map,
- struct fetch_head *fetch_head, struct worktree **worktrees)
+ struct fetch_head *fetch_head)
{
int url_len, i, rc = 0;
- struct strbuf note = STRBUF_INIT, err = STRBUF_INIT;
+ struct strbuf note = STRBUF_INIT;
const char *what, *kind;
struct ref *rm;
char *url;
@@ -1237,8 +1236,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
strbuf_reset(&note);
if (ref) {
rc |= update_local_ref(ref, transaction, what,
- rm, &note, summary_width,
- worktrees);
+ rm, &note, summary_width);
free(ref);
} else if (write_fetch_head || dry_run) {
/*
@@ -1278,7 +1276,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
abort:
strbuf_release(&note);
- strbuf_release(&err);
free(url);
return rc;
}
@@ -1305,6 +1302,14 @@ static int check_exist_and_connected(struct ref *ref_map)
return -1;
/*
+ * Similarly, if we need to refetch, we always want to perform a full
+ * fetch ignoring existing objects.
+ */
+ if (refetch)
+ return -1;
+
+
+ /*
* check_connected() allows objects to merely be promised, but
* we need all direct targets to exist.
*/
@@ -1321,8 +1326,7 @@ static int check_exist_and_connected(struct ref *ref_map)
static int fetch_and_consume_refs(struct transport *transport,
struct ref_transaction *transaction,
struct ref *ref_map,
- struct fetch_head *fetch_head,
- struct worktree **worktrees)
+ struct fetch_head *fetch_head)
{
int connectivity_checked = 1;
int ret;
@@ -1345,7 +1349,7 @@ static int fetch_and_consume_refs(struct transport *transport,
trace2_region_enter("fetch", "consume_refs", the_repository);
ret = store_updated_refs(transport->url, transport->remote->name,
connectivity_checked, transaction, ref_map,
- fetch_head, worktrees);
+ fetch_head);
trace2_region_leave("fetch", "consume_refs", the_repository);
out:
@@ -1423,18 +1427,16 @@ cleanup:
return result;
}
-static void check_not_current_branch(struct ref *ref_map,
- struct worktree **worktrees)
+static void check_not_current_branch(struct ref *ref_map)
{
- const struct worktree *wt;
+ const char *path;
for (; ref_map; ref_map = ref_map->next)
if (ref_map->peer_ref &&
- (wt = find_shared_symref(worktrees, "HEAD",
- ref_map->peer_ref->name)) &&
- !wt->is_bare)
+ starts_with(ref_map->peer_ref->name, "refs/heads/") &&
+ (path = branch_checked_out(ref_map->peer_ref->name)))
die(_("refusing to fetch into branch '%s' "
"checked out at '%s'"),
- ref_map->peer_ref->name, wt->path);
+ ref_map->peer_ref->name, path);
}
static int truncate_fetch_head(void)
@@ -1517,6 +1519,8 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, "yes");
if (update_shallow)
set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
+ if (refetch)
+ set_option(transport, TRANS_OPT_REFETCH, "yes");
if (filter_options.choice) {
const char *spec =
expand_list_objects_filter_spec(&filter_options);
@@ -1535,8 +1539,7 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
static int backfill_tags(struct transport *transport,
struct ref_transaction *transaction,
struct ref *ref_map,
- struct fetch_head *fetch_head,
- struct worktree **worktrees)
+ struct fetch_head *fetch_head)
{
int retcode, cannot_reuse;
@@ -1557,7 +1560,7 @@ static int backfill_tags(struct transport *transport,
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
transport_set_option(transport, TRANS_OPT_DEPTH, "0");
transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
- retcode = fetch_and_consume_refs(transport, transaction, ref_map, fetch_head, worktrees);
+ retcode = fetch_and_consume_refs(transport, transaction, ref_map, fetch_head);
if (gsecondary) {
transport_disconnect(gsecondary);
@@ -1578,7 +1581,6 @@ static int do_fetch(struct transport *transport,
struct transport_ls_refs_options transport_ls_refs_options =
TRANSPORT_LS_REFS_OPTIONS_INIT;
int must_list_refs = 1;
- struct worktree **worktrees = get_worktrees();
struct fetch_head fetch_head = { 0 };
struct strbuf err = STRBUF_INIT;
@@ -1636,7 +1638,7 @@ static int do_fetch(struct transport *transport,
ref_map = get_ref_map(transport->remote, remote_refs, rs,
tags, &autotags);
if (!update_head_ok)
- check_not_current_branch(ref_map, worktrees);
+ check_not_current_branch(ref_map);
retcode = open_fetch_head(&fetch_head);
if (retcode)
@@ -1669,7 +1671,7 @@ static int do_fetch(struct transport *transport,
retcode = 1;
}
- if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head, worktrees)) {
+ if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head)) {
retcode = 1;
goto cleanup;
}
@@ -1692,7 +1694,7 @@ static int do_fetch(struct transport *transport,
* the transaction and don't commit anything.
*/
if (backfill_tags(transport, transaction, tags_ref_map,
- &fetch_head, worktrees))
+ &fetch_head))
retcode = 1;
}
@@ -1777,7 +1779,6 @@ cleanup:
close_fetch_head(&fetch_head);
strbuf_release(&err);
free_refs(ref_map);
- free_worktrees(worktrees);
return retcode;
}
@@ -2174,6 +2175,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
else if (argc > 1)
die(_("fetch --all does not make sense with refspecs"));
(void) for_each_remote(get_one_remote_for_fetch, &list);
+
+ /* do not do fetch_multiple() of one */
+ if (list.nr == 1)
+ remote = remote_get(list.items[0].string);
} else if (argc == 0) {
/* No arguments -- use default remote */
remote = remote_get(NULL);
@@ -2248,7 +2253,17 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
result = fetch_multiple(&list, max_children);
}
- if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
+
+ /*
+ * This is only needed after fetch_one(), which does not fetch
+ * submodules by itself.
+ *
+ * When we fetch from multiple remotes, fetch_multiple() has
+ * already updated submodules to grab commits necessary for
+ * the fetched history from each remote, so there is no need
+ * to fetch submodules from here.
+ */
+ if (!result && remote && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
struct strvec options = STRVEC_INIT;
int max_children = max_jobs;
@@ -2293,8 +2308,25 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
NULL);
}
- if (enable_auto_gc)
+ if (enable_auto_gc) {
+ if (refetch) {
+ /*
+ * Hint auto-maintenance strongly to encourage repacking,
+ * but respect config settings disabling it.
+ */
+ int opt_val;
+ if (git_config_get_int("gc.autopacklimit", &opt_val))
+ opt_val = -1;
+ if (opt_val != 0)
+ git_config_push_parameter("gc.autoPackLimit=1");
+
+ if (git_config_get_int("maintenance.incremental-repack.auto", &opt_val))
+ opt_val = -1;
+ if (opt_val != 0)
+ git_config_push_parameter("maintenance.incremental-repack.auto=-1");
+ }
run_auto_maintenance(verbosity < 0);
+ }
cleanup:
string_list_clear(&list, 0);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 9e54892..6c73092 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -19,6 +19,7 @@
#include "decorate.h"
#include "packfile.h"
#include "object-store.h"
+#include "resolve-undo.h"
#include "run-command.h"
#include "worktree.h"
@@ -757,6 +758,43 @@ static int fsck_cache_tree(struct cache_tree *it)
return err;
}
+static int fsck_resolve_undo(struct index_state *istate)
+{
+ struct string_list_item *item;
+ struct string_list *resolve_undo = istate->resolve_undo;
+
+ if (!resolve_undo)
+ return 0;
+
+ for_each_string_list_item(item, resolve_undo) {
+ const char *path = item->string;
+ struct resolve_undo_info *ru = item->util;
+ int i;
+
+ if (!ru)
+ continue;
+ for (i = 0; i < 3; i++) {
+ struct object *obj;
+
+ if (!ru->mode[i] || !S_ISREG(ru->mode[i]))
+ continue;
+
+ obj = parse_object(the_repository, &ru->oid[i]);
+ if (!obj) {
+ error(_("%s: invalid sha1 pointer in resolve-undo"),
+ oid_to_hex(&ru->oid[i]));
+ errors_found |= ERROR_REFS;
+ continue;
+ }
+ obj->flags |= USED;
+ fsck_put_object_name(&fsck_walk_options, &ru->oid[i],
+ ":(%d):%s", i, path);
+ mark_object_reachable(obj);
+ }
+ }
+ return 0;
+}
+
static void mark_object_for_connectivity(const struct object_id *oid)
{
struct object *obj = lookup_unknown_object(the_repository, oid);
@@ -938,6 +976,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
if (active_cache_tree)
fsck_cache_tree(active_cache_tree);
+ fsck_resolve_undo(&the_index);
}
check_connectivity();
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
new file mode 100644
index 0000000..2c109cf
--- /dev/null
+++ b/builtin/fsmonitor--daemon.c
@@ -0,0 +1,1577 @@
+#include "builtin.h"
+#include "config.h"
+#include "parse-options.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "compat/fsmonitor/fsm-health.h"
+#include "compat/fsmonitor/fsm-listen.h"
+#include "fsmonitor--daemon.h"
+#include "simple-ipc.h"
+#include "khash.h"
+#include "pkt-line.h"
+
+static const char * const builtin_fsmonitor__daemon_usage[] = {
+ N_("git fsmonitor--daemon start [<options>]"),
+ N_("git fsmonitor--daemon run [<options>]"),
+ N_("git fsmonitor--daemon stop"),
+ N_("git fsmonitor--daemon status"),
+ NULL
+};
+
+#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
+/*
+ * Global state loaded from config.
+ */
+#define FSMONITOR__IPC_THREADS "fsmonitor.ipcthreads"
+static int fsmonitor__ipc_threads = 8;
+
+#define FSMONITOR__START_TIMEOUT "fsmonitor.starttimeout"
+static int fsmonitor__start_timeout_sec = 60;
+
+#define FSMONITOR__ANNOUNCE_STARTUP "fsmonitor.announcestartup"
+static int fsmonitor__announce_startup = 0;
+
+static int fsmonitor_config(const char *var, const char *value, void *cb)
+{
+ if (!strcmp(var, FSMONITOR__IPC_THREADS)) {
+ int i = git_config_int(var, value);
+ if (i < 1)
+ return error(_("value of '%s' out of range: %d"),
+ FSMONITOR__IPC_THREADS, i);
+ fsmonitor__ipc_threads = i;
+ return 0;
+ }
+
+ if (!strcmp(var, FSMONITOR__START_TIMEOUT)) {
+ int i = git_config_int(var, value);
+ if (i < 0)
+ return error(_("value of '%s' out of range: %d"),
+ FSMONITOR__START_TIMEOUT, i);
+ fsmonitor__start_timeout_sec = i;
+ return 0;
+ }
+
+ if (!strcmp(var, FSMONITOR__ANNOUNCE_STARTUP)) {
+ int is_bool;
+ int i = git_config_bool_or_int(var, value, &is_bool);
+ if (i < 0)
+ return error(_("value of '%s' not bool or int: %d"),
+ var, i);
+ fsmonitor__announce_startup = i;
+ return 0;
+ }
+
+ return git_default_config(var, value, cb);
+}
+
+/*
+ * Acting as a CLIENT.
+ *
+ * Send a "quit" command to the `git-fsmonitor--daemon` (if running)
+ * and wait for it to shutdown.
+ */
+static int do_as_client__send_stop(void)
+{
+ struct strbuf answer = STRBUF_INIT;
+ int ret;
+
+ ret = fsmonitor_ipc__send_command("quit", &answer);
+
+ /* The quit command does not return any response data. */
+ strbuf_release(&answer);
+
+ if (ret)
+ return ret;
+
+ trace2_region_enter("fsm_client", "polling-for-daemon-exit", NULL);
+ while (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
+ sleep_millisec(50);
+ trace2_region_leave("fsm_client", "polling-for-daemon-exit", NULL);
+
+ return 0;
+}
+
+static int do_as_client__status(void)
+{
+ enum ipc_active_state state = fsmonitor_ipc__get_state();
+
+ switch (state) {
+ case IPC_STATE__LISTENING:
+ printf(_("fsmonitor-daemon is watching '%s'\n"),
+ the_repository->worktree);
+ return 0;
+
+ default:
+ printf(_("fsmonitor-daemon is not watching '%s'\n"),
+ the_repository->worktree);
+ return 1;
+ }
+}
+
+enum fsmonitor_cookie_item_result {
+ FCIR_ERROR = -1, /* could not create cookie file ? */
+ FCIR_INIT,
+ FCIR_SEEN,
+ FCIR_ABORT,
+};
+
+struct fsmonitor_cookie_item {
+ struct hashmap_entry entry;
+ char *name;
+ enum fsmonitor_cookie_item_result result;
+};
+
+static int cookies_cmp(const void *data, const struct hashmap_entry *he1,
+ const struct hashmap_entry *he2, const void *keydata)
+{
+ const struct fsmonitor_cookie_item *a =
+ container_of(he1, const struct fsmonitor_cookie_item, entry);
+ const struct fsmonitor_cookie_item *b =
+ container_of(he2, const struct fsmonitor_cookie_item, entry);
+
+ return strcmp(a->name, keydata ? keydata : b->name);
+}
+
+static enum fsmonitor_cookie_item_result with_lock__wait_for_cookie(
+ struct fsmonitor_daemon_state *state)
+{
+ /* assert current thread holding state->main_lock */
+
+ int fd;
+ struct fsmonitor_cookie_item *cookie;
+ struct strbuf cookie_pathname = STRBUF_INIT;
+ struct strbuf cookie_filename = STRBUF_INIT;
+ enum fsmonitor_cookie_item_result result;
+ int my_cookie_seq;
+
+ CALLOC_ARRAY(cookie, 1);
+
+ my_cookie_seq = state->cookie_seq++;
+
+ strbuf_addf(&cookie_filename, "%i-%i", getpid(), my_cookie_seq);
+
+ strbuf_addbuf(&cookie_pathname, &state->path_cookie_prefix);
+ strbuf_addbuf(&cookie_pathname, &cookie_filename);
+
+ cookie->name = strbuf_detach(&cookie_filename, NULL);
+ cookie->result = FCIR_INIT;
+ hashmap_entry_init(&cookie->entry, strhash(cookie->name));
+
+ hashmap_add(&state->cookies, &cookie->entry);
+
+ trace_printf_key(&trace_fsmonitor, "cookie-wait: '%s' '%s'",
+ cookie->name, cookie_pathname.buf);
+
+ /*
+ * Create the cookie file on disk and then wait for a notification
+ * that the listener thread has seen it.
+ */
+ fd = open(cookie_pathname.buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
+ if (fd < 0) {
+ error_errno(_("could not create fsmonitor cookie '%s'"),
+ cookie->name);
+
+ cookie->result = FCIR_ERROR;
+ goto done;
+ }
+
+ /*
+ * Technically, close() and unlink() can fail, but we don't
+ * care here. We only created the file to trigger a watch
+ * event from the FS to know that when we're up to date.
+ */
+ close(fd);
+ unlink(cookie_pathname.buf);
+
+ /*
+ * Technically, this is an infinite wait (well, unless another
+ * thread sends us an abort). I'd like to change this to
+ * use `pthread_cond_timedwait()` and return an error/timeout
+ * and let the caller do the trivial response thing, but we
+ * don't have that routine in our thread-utils.
+ *
+ * After extensive beta testing I'm not really worried about
+ * this. Also note that the above open() and unlink() calls
+ * will cause at least two FS events on that path, so the odds
+ * of getting stuck are pretty slim.
+ */
+ while (cookie->result == FCIR_INIT)
+ pthread_cond_wait(&state->cookies_cond,
+ &state->main_lock);
+
+done:
+ hashmap_remove(&state->cookies, &cookie->entry, NULL);
+
+ result = cookie->result;
+
+ free(cookie->name);
+ free(cookie);
+ strbuf_release(&cookie_pathname);
+
+ return result;
+}
+
+/*
+ * Mark these cookies as _SEEN and wake up the corresponding client threads.
+ */
+static void with_lock__mark_cookies_seen(struct fsmonitor_daemon_state *state,
+ const struct string_list *cookie_names)
+{
+ /* assert current thread holding state->main_lock */
+
+ int k;
+ int nr_seen = 0;
+
+ for (k = 0; k < cookie_names->nr; k++) {
+ struct fsmonitor_cookie_item key;
+ struct fsmonitor_cookie_item *cookie;
+
+ key.name = cookie_names->items[k].string;
+ hashmap_entry_init(&key.entry, strhash(key.name));
+
+ cookie = hashmap_get_entry(&state->cookies, &key, entry, NULL);
+ if (cookie) {
+ trace_printf_key(&trace_fsmonitor, "cookie-seen: '%s'",
+ cookie->name);
+ cookie->result = FCIR_SEEN;
+ nr_seen++;
+ }
+ }
+
+ if (nr_seen)
+ pthread_cond_broadcast(&state->cookies_cond);
+}
+
+/*
+ * Set _ABORT on all pending cookies and wake up all client threads.
+ */
+static void with_lock__abort_all_cookies(struct fsmonitor_daemon_state *state)
+{
+ /* assert current thread holding state->main_lock */
+
+ struct hashmap_iter iter;
+ struct fsmonitor_cookie_item *cookie;
+ int nr_aborted = 0;
+
+ hashmap_for_each_entry(&state->cookies, &iter, cookie, entry) {
+ trace_printf_key(&trace_fsmonitor, "cookie-abort: '%s'",
+ cookie->name);
+ cookie->result = FCIR_ABORT;
+ nr_aborted++;
+ }
+
+ if (nr_aborted)
+ pthread_cond_broadcast(&state->cookies_cond);
+}
+
+/*
+ * Requests to and from a FSMonitor Protocol V2 provider use an opaque
+ * "token" as a virtual timestamp. Clients can request a summary of all
+ * created/deleted/modified files relative to a token. In the response,
+ * clients receive a new token for the next (relative) request.
+ *
+ *
+ * Token Format
+ * ============
+ *
+ * The contents of the token are private and provider-specific.
+ *
+ * For the built-in fsmonitor--daemon, we define a token as follows:
+ *
+ * "builtin" ":" <token_id> ":" <sequence_nr>
+ *
+ * The "builtin" prefix is used as a namespace to avoid conflicts
+ * with other providers (such as Watchman).
+ *
+ * The <token_id> is an arbitrary OPAQUE string, such as a GUID,
+ * UUID, or {timestamp,pid}. It is used to group all filesystem
+ * events that happened while the daemon was monitoring (and in-sync
+ * with the filesystem).
+ *
+ * Unlike FSMonitor Protocol V1, it is not defined as a timestamp
+ * and does not define less-than/greater-than relationships.
+ * (There are too many race conditions to rely on file system
+ * event timestamps.)
+ *
+ * The <sequence_nr> is a simple integer incremented whenever the
+ * daemon needs to make its state public. For example, if 1000 file
+ * system events come in, but no clients have requested the data,
+ * the daemon can continue to accumulate file changes in the same
+ * bin and does not need to advance the sequence number. However,
+ * as soon as a client does arrive, the daemon needs to start a new
+ * bin and increment the sequence number.
+ *
+ * The sequence number serves as the boundary between 2 sets
+ * of bins -- the older ones that the client has already seen
+ * and the newer ones that it hasn't.
+ *
+ * When a new <token_id> is created, the <sequence_nr> is reset to
+ * zero.
+ *
+ *
+ * About Token Ids
+ * ===============
+ *
+ * A new token_id is created:
+ *
+ * [1] each time the daemon is started.
+ *
+ * [2] any time that the daemon must re-sync with the filesystem
+ * (such as when the kernel drops or we miss events on a very
+ * active volume).
+ *
+ * [3] in response to a client "flush" command (for dropped event
+ * testing).
+ *
+ * When a new token_id is created, the daemon is free to discard all
+ * cached filesystem events associated with any previous token_ids.
+ * Events associated with a non-current token_id will never be sent
+ * to a client. A token_id change implicitly means that the daemon
+ * has gap in its event history.
+ *
+ * Therefore, clients that present a token with a stale (non-current)
+ * token_id will always be given a trivial response.
+ */
+struct fsmonitor_token_data {
+ struct strbuf token_id;
+ struct fsmonitor_batch *batch_head;
+ struct fsmonitor_batch *batch_tail;
+ uint64_t client_ref_count;
+};
+
+struct fsmonitor_batch {
+ struct fsmonitor_batch *next;
+ uint64_t batch_seq_nr;
+ const char **interned_paths;
+ size_t nr, alloc;
+ time_t pinned_time;
+};
+
+static struct fsmonitor_token_data *fsmonitor_new_token_data(void)
+{
+ static int test_env_value = -1;
+ static uint64_t flush_count = 0;
+ struct fsmonitor_token_data *token;
+ struct fsmonitor_batch *batch;
+
+ CALLOC_ARRAY(token, 1);
+ batch = fsmonitor_batch__new();
+
+ strbuf_init(&token->token_id, 0);
+ token->batch_head = batch;
+ token->batch_tail = batch;
+ token->client_ref_count = 0;
+
+ if (test_env_value < 0)
+ test_env_value = git_env_bool("GIT_TEST_FSMONITOR_TOKEN", 0);
+
+ if (!test_env_value) {
+ struct timeval tv;
+ struct tm tm;
+ time_t secs;
+
+ gettimeofday(&tv, NULL);
+ secs = tv.tv_sec;
+ gmtime_r(&secs, &tm);
+
+ strbuf_addf(&token->token_id,
+ "%"PRIu64".%d.%4d%02d%02dT%02d%02d%02d.%06ldZ",
+ flush_count++,
+ getpid(),
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ (long)tv.tv_usec);
+ } else {
+ strbuf_addf(&token->token_id, "test_%08x", test_env_value++);
+ }
+
+ /*
+ * We created a new <token_id> and are starting a new series
+ * of tokens with a zero <seq_nr>.
+ *
+ * Since clients cannot guess our new (non test) <token_id>
+ * they will always receive a trivial response (because of the
+ * mismatch on the <token_id>). The trivial response will
+ * tell them our new <token_id> so that subsequent requests
+ * will be relative to our new series. (And when sending that
+ * response, we pin the current head of the batch list.)
+ *
+ * Even if the client correctly guesses the <token_id>, their
+ * request of "builtin:<token_id>:0" asks for all changes MORE
+ * RECENT than batch/bin 0.
+ *
+ * This implies that it is a waste to accumulate paths in the
+ * initial batch/bin (because they will never be transmitted).
+ *
+ * So the daemon could be running for days and watching the
+ * file system, but doesn't need to actually accumulate any
+ * paths UNTIL we need to set a reference point for a later
+ * relative request.
+ *
+ * However, it is very useful for testing to always have a
+ * reference point set. Pin batch 0 to force early file system
+ * events to accumulate.
+ */
+ if (test_env_value)
+ batch->pinned_time = time(NULL);
+
+ return token;
+}
+
+struct fsmonitor_batch *fsmonitor_batch__new(void)
+{
+ struct fsmonitor_batch *batch;
+
+ CALLOC_ARRAY(batch, 1);
+
+ return batch;
+}
+
+void fsmonitor_batch__free_list(struct fsmonitor_batch *batch)
+{
+ while (batch) {
+ struct fsmonitor_batch *next = batch->next;
+
+ /*
+ * The actual strings within the array of this batch
+ * are interned, so we don't own them. We only own
+ * the array.
+ */
+ free(batch->interned_paths);
+ free(batch);
+
+ batch = next;
+ }
+}
+
+void fsmonitor_batch__add_path(struct fsmonitor_batch *batch,
+ const char *path)
+{
+ const char *interned_path = strintern(path);
+
+ trace_printf_key(&trace_fsmonitor, "event: %s", interned_path);
+
+ ALLOC_GROW(batch->interned_paths, batch->nr + 1, batch->alloc);
+ batch->interned_paths[batch->nr++] = interned_path;
+}
+
+static void fsmonitor_batch__combine(struct fsmonitor_batch *batch_dest,
+ const struct fsmonitor_batch *batch_src)
+{
+ size_t k;
+
+ ALLOC_GROW(batch_dest->interned_paths,
+ batch_dest->nr + batch_src->nr + 1,
+ batch_dest->alloc);
+
+ for (k = 0; k < batch_src->nr; k++)
+ batch_dest->interned_paths[batch_dest->nr++] =
+ batch_src->interned_paths[k];
+}
+
+/*
+ * To keep the batch list from growing unbounded in response to filesystem
+ * activity, we try to truncate old batches from the end of the list as
+ * they become irrelevant.
+ *
+ * We assume that the .git/index will be updated with the most recent token
+ * any time the index is updated. And future commands will only ask for
+ * recent changes *since* that new token. So as tokens advance into the
+ * future, older batch items will never be requested/needed. So we can
+ * truncate them without loss of functionality.
+ *
+ * However, multiple commands may be talking to the daemon concurrently
+ * or perform a slow command, so a little "token skew" is possible.
+ * Therefore, we want this to be a little bit lazy and have a generous
+ * delay.
+ *
+ * The current reader thread walked backwards in time from `token->batch_head`
+ * back to `batch_marker` somewhere in the middle of the batch list.
+ *
+ * Let's walk backwards in time from that marker an arbitrary delay
+ * and truncate the list there. Note that these timestamps are completely
+ * artificial (based on when we pinned the batch item) and not on any
+ * filesystem activity.
+ *
+ * Return the obsolete portion of the list after we have removed it from
+ * the official list so that the caller can free it after leaving the lock.
+ */
+#define MY_TIME_DELAY_SECONDS (5 * 60) /* seconds */
+
+static struct fsmonitor_batch *with_lock__truncate_old_batches(
+ struct fsmonitor_daemon_state *state,
+ const struct fsmonitor_batch *batch_marker)
+{
+ /* assert current thread holding state->main_lock */
+
+ const struct fsmonitor_batch *batch;
+ struct fsmonitor_batch *remainder;
+
+ if (!batch_marker)
+ return NULL;
+
+ trace_printf_key(&trace_fsmonitor, "Truncate: mark (%"PRIu64",%"PRIu64")",
+ batch_marker->batch_seq_nr,
+ (uint64_t)batch_marker->pinned_time);
+
+ for (batch = batch_marker; batch; batch = batch->next) {
+ time_t t;
+
+ if (!batch->pinned_time) /* an overflow batch */
+ continue;
+
+ t = batch->pinned_time + MY_TIME_DELAY_SECONDS;
+ if (t > batch_marker->pinned_time) /* too close to marker */
+ continue;
+
+ goto truncate_past_here;
+ }
+
+ return NULL;
+
+truncate_past_here:
+ state->current_token_data->batch_tail = (struct fsmonitor_batch *)batch;
+
+ remainder = ((struct fsmonitor_batch *)batch)->next;
+ ((struct fsmonitor_batch *)batch)->next = NULL;
+
+ return remainder;
+}
+
+static void fsmonitor_free_token_data(struct fsmonitor_token_data *token)
+{
+ if (!token)
+ return;
+
+ assert(token->client_ref_count == 0);
+
+ strbuf_release(&token->token_id);
+
+ fsmonitor_batch__free_list(token->batch_head);
+
+ free(token);
+}
+
+/*
+ * Flush all of our cached data about the filesystem. Call this if we
+ * lose sync with the filesystem and miss some notification events.
+ *
+ * [1] If we are missing events, then we no longer have a complete
+ * history of the directory (relative to our current start token).
+ * We should create a new token and start fresh (as if we just
+ * booted up).
+ *
+ * [2] Some of those lost events may have been for cookie files. We
+ * should assume the worst and abort them rather letting them starve.
+ *
+ * If there are no concurrent threads reading the current token data
+ * series, we can free it now. Otherwise, let the last reader free
+ * it.
+ *
+ * Either way, the old token data series is no longer associated with
+ * our state data.
+ */
+static void with_lock__do_force_resync(struct fsmonitor_daemon_state *state)
+{
+ /* assert current thread holding state->main_lock */
+
+ struct fsmonitor_token_data *free_me = NULL;
+ struct fsmonitor_token_data *new_one = NULL;
+
+ new_one = fsmonitor_new_token_data();
+
+ if (state->current_token_data->client_ref_count == 0)
+ free_me = state->current_token_data;
+ state->current_token_data = new_one;
+
+ fsmonitor_free_token_data(free_me);
+
+ with_lock__abort_all_cookies(state);
+}
+
+void fsmonitor_force_resync(struct fsmonitor_daemon_state *state)
+{
+ pthread_mutex_lock(&state->main_lock);
+ with_lock__do_force_resync(state);
+ pthread_mutex_unlock(&state->main_lock);
+}
+
+/*
+ * Format an opaque token string to send to the client.
+ */
+static void with_lock__format_response_token(
+ struct strbuf *response_token,
+ const struct strbuf *response_token_id,
+ const struct fsmonitor_batch *batch)
+{
+ /* assert current thread holding state->main_lock */
+
+ strbuf_reset(response_token);
+ strbuf_addf(response_token, "builtin:%s:%"PRIu64,
+ response_token_id->buf, batch->batch_seq_nr);
+}
+
+/*
+ * Parse an opaque token from the client.
+ * Returns -1 on error.
+ */
+static int fsmonitor_parse_client_token(const char *buf_token,
+ struct strbuf *requested_token_id,
+ uint64_t *seq_nr)
+{
+ const char *p;
+ char *p_end;
+
+ strbuf_reset(requested_token_id);
+ *seq_nr = 0;
+
+ if (!skip_prefix(buf_token, "builtin:", &p))
+ return -1;
+
+ while (*p && *p != ':')
+ strbuf_addch(requested_token_id, *p++);
+ if (!*p++)
+ return -1;
+
+ *seq_nr = (uint64_t)strtoumax(p, &p_end, 10);
+ if (*p_end)
+ return -1;
+
+ return 0;
+}
+
+KHASH_INIT(str, const char *, int, 0, kh_str_hash_func, kh_str_hash_equal)
+
+static int do_handle_client(struct fsmonitor_daemon_state *state,
+ const char *command,
+ ipc_server_reply_cb *reply,
+ struct ipc_server_reply_data *reply_data)
+{
+ struct fsmonitor_token_data *token_data = NULL;
+ struct strbuf response_token = STRBUF_INIT;
+ struct strbuf requested_token_id = STRBUF_INIT;
+ struct strbuf payload = STRBUF_INIT;
+ uint64_t requested_oldest_seq_nr = 0;
+ uint64_t total_response_len = 0;
+ const char *p;
+ const struct fsmonitor_batch *batch_head;
+ const struct fsmonitor_batch *batch;
+ struct fsmonitor_batch *remainder = NULL;
+ intmax_t count = 0, duplicates = 0;
+ kh_str_t *shown;
+ int hash_ret;
+ int do_trivial = 0;
+ int do_flush = 0;
+ int do_cookie = 0;
+ enum fsmonitor_cookie_item_result cookie_result;
+
+ /*
+ * We expect `command` to be of the form:
+ *
+ * <command> := quit NUL
+ * | flush NUL
+ * | <V1-time-since-epoch-ns> NUL
+ * | <V2-opaque-fsmonitor-token> NUL
+ */
+
+ if (!strcmp(command, "quit")) {
+ /*
+ * A client has requested over the socket/pipe that the
+ * daemon shutdown.
+ *
+ * Tell the IPC thread pool to shutdown (which completes
+ * the await in the main thread (which can stop the
+ * fsmonitor listener thread)).
+ *
+ * There is no reply to the client.
+ */
+ return SIMPLE_IPC_QUIT;
+
+ } else if (!strcmp(command, "flush")) {
+ /*
+ * Flush all of our cached data and generate a new token
+ * just like if we lost sync with the filesystem.
+ *
+ * Then send a trivial response using the new token.
+ */
+ do_flush = 1;
+ do_trivial = 1;
+
+ } else if (!skip_prefix(command, "builtin:", &p)) {
+ /* assume V1 timestamp or garbage */
+
+ char *p_end;
+
+ strtoumax(command, &p_end, 10);
+ trace_printf_key(&trace_fsmonitor,
+ ((*p_end) ?
+ "fsmonitor: invalid command line '%s'" :
+ "fsmonitor: unsupported V1 protocol '%s'"),
+ command);
+ do_trivial = 1;
+
+ } else {
+ /* We have "builtin:*" */
+ if (fsmonitor_parse_client_token(command, &requested_token_id,
+ &requested_oldest_seq_nr)) {
+ trace_printf_key(&trace_fsmonitor,
+ "fsmonitor: invalid V2 protocol token '%s'",
+ command);
+ do_trivial = 1;
+
+ } else {
+ /*
+ * We have a V2 valid token:
+ * "builtin:<token_id>:<seq_nr>"
+ */
+ do_cookie = 1;
+ }
+ }
+
+ pthread_mutex_lock(&state->main_lock);
+
+ if (!state->current_token_data)
+ BUG("fsmonitor state does not have a current token");
+
+ /*
+ * Write a cookie file inside the directory being watched in
+ * an effort to flush out existing filesystem events that we
+ * actually care about. Suspend this client thread until we
+ * see the filesystem events for this cookie file.
+ *
+ * Creating the cookie lets us guarantee that our FS listener
+ * thread has drained the kernel queue and we are caught up
+ * with the kernel.
+ *
+ * If we cannot create the cookie (or otherwise guarantee that
+ * we are caught up), we send a trivial response. We have to
+ * assume that there might be some very, very recent activity
+ * on the FS still in flight.
+ */
+ if (do_cookie) {
+ cookie_result = with_lock__wait_for_cookie(state);
+ if (cookie_result != FCIR_SEEN) {
+ error(_("fsmonitor: cookie_result '%d' != SEEN"),
+ cookie_result);
+ do_trivial = 1;
+ }
+ }
+
+ if (do_flush)
+ with_lock__do_force_resync(state);
+
+ /*
+ * We mark the current head of the batch list as "pinned" so
+ * that the listener thread will treat this item as read-only
+ * (and prevent any more paths from being added to it) from
+ * now on.
+ */
+ token_data = state->current_token_data;
+ batch_head = token_data->batch_head;
+ ((struct fsmonitor_batch *)batch_head)->pinned_time = time(NULL);
+
+ /*
+ * FSMonitor Protocol V2 requires that we send a response header
+ * with a "new current token" and then all of the paths that changed
+ * since the "requested token". We send the seq_nr of the just-pinned
+ * head batch so that future requests from a client will be relative
+ * to it.
+ */
+ with_lock__format_response_token(&response_token,
+ &token_data->token_id, batch_head);
+
+ reply(reply_data, response_token.buf, response_token.len + 1);
+ total_response_len += response_token.len + 1;
+
+ trace2_data_string("fsmonitor", the_repository, "response/token",
+ response_token.buf);
+ trace_printf_key(&trace_fsmonitor, "response token: %s",
+ response_token.buf);
+
+ if (!do_trivial) {
+ if (strcmp(requested_token_id.buf, token_data->token_id.buf)) {
+ /*
+ * The client last spoke to a different daemon
+ * instance -OR- the daemon had to resync with
+ * the filesystem (and lost events), so reject.
+ */
+ trace2_data_string("fsmonitor", the_repository,
+ "response/token", "different");
+ do_trivial = 1;
+
+ } else if (requested_oldest_seq_nr <
+ token_data->batch_tail->batch_seq_nr) {
+ /*
+ * The client wants older events than we have for
+ * this token_id. This means that the end of our
+ * batch list was truncated and we cannot give the
+ * client a complete snapshot relative to their
+ * request.
+ */
+ trace_printf_key(&trace_fsmonitor,
+ "client requested truncated data");
+ do_trivial = 1;
+ }
+ }
+
+ if (do_trivial) {
+ pthread_mutex_unlock(&state->main_lock);
+
+ reply(reply_data, "/", 2);
+
+ trace2_data_intmax("fsmonitor", the_repository,
+ "response/trivial", 1);
+
+ goto cleanup;
+ }
+
+ /*
+ * We're going to hold onto a pointer to the current
+ * token-data while we walk the list of batches of files.
+ * During this time, we will NOT be under the lock.
+ * So we ref-count it.
+ *
+ * This allows the listener thread to continue prepending
+ * new batches of items to the token-data (which we'll ignore).
+ *
+ * AND it allows the listener thread to do a token-reset
+ * (and install a new `current_token_data`).
+ */
+ token_data->client_ref_count++;
+
+ pthread_mutex_unlock(&state->main_lock);
+
+ /*
+ * The client request is relative to the token that they sent,
+ * so walk the batch list backwards from the current head back
+ * to the batch (sequence number) they named.
+ *
+ * We use khash to de-dup the list of pathnames.
+ *
+ * NEEDSWORK: each batch contains a list of interned strings,
+ * so we only need to do pointer comparisons here to build the
+ * hash table. Currently, we're still comparing the string
+ * values.
+ */
+ shown = kh_init_str();
+ for (batch = batch_head;
+ batch && batch->batch_seq_nr > requested_oldest_seq_nr;
+ batch = batch->next) {
+ size_t k;
+
+ for (k = 0; k < batch->nr; k++) {
+ const char *s = batch->interned_paths[k];
+ size_t s_len;
+
+ if (kh_get_str(shown, s) != kh_end(shown))
+ duplicates++;
+ else {
+ kh_put_str(shown, s, &hash_ret);
+
+ trace_printf_key(&trace_fsmonitor,
+ "send[%"PRIuMAX"]: %s",
+ count, s);
+
+ /* Each path gets written with a trailing NUL */
+ s_len = strlen(s) + 1;
+
+ if (payload.len + s_len >=
+ LARGE_PACKET_DATA_MAX) {
+ reply(reply_data, payload.buf,
+ payload.len);
+ total_response_len += payload.len;
+ strbuf_reset(&payload);
+ }
+
+ strbuf_add(&payload, s, s_len);
+ count++;
+ }
+ }
+ }
+
+ if (payload.len) {
+ reply(reply_data, payload.buf, payload.len);
+ total_response_len += payload.len;
+ }
+
+ kh_release_str(shown);
+
+ pthread_mutex_lock(&state->main_lock);
+
+ if (token_data->client_ref_count > 0)
+ token_data->client_ref_count--;
+
+ if (token_data->client_ref_count == 0) {
+ if (token_data != state->current_token_data) {
+ /*
+ * The listener thread did a token-reset while we were
+ * walking the batch list. Therefore, this token is
+ * stale and can be discarded completely. If we are
+ * the last reader thread using this token, we own
+ * that work.
+ */
+ fsmonitor_free_token_data(token_data);
+ } else if (batch) {
+ /*
+ * We are holding the lock and are the only
+ * reader of the ref-counted portion of the
+ * list, so we get the honor of seeing if the
+ * list can be truncated to save memory.
+ *
+ * The main loop did not walk to the end of the
+ * list, so this batch is the first item in the
+ * batch-list that is older than the requested
+ * end-point sequence number. See if the tail
+ * end of the list is obsolete.
+ */
+ remainder = with_lock__truncate_old_batches(state,
+ batch);
+ }
+ }
+
+ pthread_mutex_unlock(&state->main_lock);
+
+ if (remainder)
+ fsmonitor_batch__free_list(remainder);
+
+ trace2_data_intmax("fsmonitor", the_repository, "response/length", total_response_len);
+ trace2_data_intmax("fsmonitor", the_repository, "response/count/files", count);
+ trace2_data_intmax("fsmonitor", the_repository, "response/count/duplicates", duplicates);
+
+cleanup:
+ strbuf_release(&response_token);
+ strbuf_release(&requested_token_id);
+ strbuf_release(&payload);
+
+ return 0;
+}
+
+static ipc_server_application_cb handle_client;
+
+static int handle_client(void *data,
+ const char *command, size_t command_len,
+ ipc_server_reply_cb *reply,
+ struct ipc_server_reply_data *reply_data)
+{
+ struct fsmonitor_daemon_state *state = data;
+ int result;
+
+ /*
+ * The Simple IPC API now supports {char*, len} arguments, but
+ * FSMonitor always uses proper null-terminated strings, so
+ * we can ignore the command_len argument. (Trust, but verify.)
+ */
+ if (command_len != strlen(command))
+ BUG("FSMonitor assumes text messages");
+
+ trace_printf_key(&trace_fsmonitor, "requested token: %s", command);
+
+ trace2_region_enter("fsmonitor", "handle_client", the_repository);
+ trace2_data_string("fsmonitor", the_repository, "request", command);
+
+ result = do_handle_client(state, command, reply, reply_data);
+
+ trace2_region_leave("fsmonitor", "handle_client", the_repository);
+
+ return result;
+}
+
+#define FSMONITOR_DIR "fsmonitor--daemon"
+#define FSMONITOR_COOKIE_DIR "cookies"
+#define FSMONITOR_COOKIE_PREFIX (FSMONITOR_DIR "/" FSMONITOR_COOKIE_DIR "/")
+
+enum fsmonitor_path_type fsmonitor_classify_path_workdir_relative(
+ const char *rel)
+{
+ if (fspathncmp(rel, ".git", 4))
+ return IS_WORKDIR_PATH;
+ rel += 4;
+
+ if (!*rel)
+ return IS_DOT_GIT;
+ if (*rel != '/')
+ return IS_WORKDIR_PATH; /* e.g. .gitignore */
+ rel++;
+
+ if (!fspathncmp(rel, FSMONITOR_COOKIE_PREFIX,
+ strlen(FSMONITOR_COOKIE_PREFIX)))
+ return IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX;
+
+ return IS_INSIDE_DOT_GIT;
+}
+
+enum fsmonitor_path_type fsmonitor_classify_path_gitdir_relative(
+ const char *rel)
+{
+ if (!fspathncmp(rel, FSMONITOR_COOKIE_PREFIX,
+ strlen(FSMONITOR_COOKIE_PREFIX)))
+ return IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX;
+
+ return IS_INSIDE_GITDIR;
+}
+
+static enum fsmonitor_path_type try_classify_workdir_abs_path(
+ struct fsmonitor_daemon_state *state,
+ const char *path)
+{
+ const char *rel;
+
+ if (fspathncmp(path, state->path_worktree_watch.buf,
+ state->path_worktree_watch.len))
+ return IS_OUTSIDE_CONE;
+
+ rel = path + state->path_worktree_watch.len;
+
+ if (!*rel)
+ return IS_WORKDIR_PATH; /* it is the root dir exactly */
+ if (*rel != '/')
+ return IS_OUTSIDE_CONE;
+ rel++;
+
+ return fsmonitor_classify_path_workdir_relative(rel);
+}
+
+enum fsmonitor_path_type fsmonitor_classify_path_absolute(
+ struct fsmonitor_daemon_state *state,
+ const char *path)
+{
+ const char *rel;
+ enum fsmonitor_path_type t;
+
+ t = try_classify_workdir_abs_path(state, path);
+ if (state->nr_paths_watching == 1)
+ return t;
+ if (t != IS_OUTSIDE_CONE)
+ return t;
+
+ if (fspathncmp(path, state->path_gitdir_watch.buf,
+ state->path_gitdir_watch.len))
+ return IS_OUTSIDE_CONE;
+
+ rel = path + state->path_gitdir_watch.len;
+
+ if (!*rel)
+ return IS_GITDIR; /* it is the <gitdir> exactly */
+ if (*rel != '/')
+ return IS_OUTSIDE_CONE;
+ rel++;
+
+ return fsmonitor_classify_path_gitdir_relative(rel);
+}
+
+/*
+ * We try to combine small batches at the front of the batch-list to avoid
+ * having a long list. This hopefully makes it a little easier when we want
+ * to truncate and maintain the list. However, we don't want the paths array
+ * to just keep growing and growing with realloc, so we insert an arbitrary
+ * limit.
+ */
+#define MY_COMBINE_LIMIT (1024)
+
+void fsmonitor_publish(struct fsmonitor_daemon_state *state,
+ struct fsmonitor_batch *batch,
+ const struct string_list *cookie_names)
+{
+ if (!batch && !cookie_names->nr)
+ return;
+
+ pthread_mutex_lock(&state->main_lock);
+
+ if (batch) {
+ struct fsmonitor_batch *head;
+
+ head = state->current_token_data->batch_head;
+ if (!head) {
+ BUG("token does not have batch");
+ } else if (head->pinned_time) {
+ /*
+ * We cannot alter the current batch list
+ * because:
+ *
+ * [a] it is being transmitted to at least one
+ * client and the handle_client() thread has a
+ * ref-count, but not a lock on the batch list
+ * starting with this item.
+ *
+ * [b] it has been transmitted in the past to
+ * at least one client such that future
+ * requests are relative to this head batch.
+ *
+ * So, we can only prepend a new batch onto
+ * the front of the list.
+ */
+ batch->batch_seq_nr = head->batch_seq_nr + 1;
+ batch->next = head;
+ state->current_token_data->batch_head = batch;
+ } else if (!head->batch_seq_nr) {
+ /*
+ * Batch 0 is unpinned. See the note in
+ * `fsmonitor_new_token_data()` about why we
+ * don't need to accumulate these paths.
+ */
+ fsmonitor_batch__free_list(batch);
+ } else if (head->nr + batch->nr > MY_COMBINE_LIMIT) {
+ /*
+ * The head batch in the list has never been
+ * transmitted to a client, but folding the
+ * contents of the new batch onto it would
+ * exceed our arbitrary limit, so just prepend
+ * the new batch onto the list.
+ */
+ batch->batch_seq_nr = head->batch_seq_nr + 1;
+ batch->next = head;
+ state->current_token_data->batch_head = batch;
+ } else {
+ /*
+ * We are free to add the paths in the given
+ * batch onto the end of the current head batch.
+ */
+ fsmonitor_batch__combine(head, batch);
+ fsmonitor_batch__free_list(batch);
+ }
+ }
+
+ if (cookie_names->nr)
+ with_lock__mark_cookies_seen(state, cookie_names);
+
+ pthread_mutex_unlock(&state->main_lock);
+}
+
+static void *fsm_health__thread_proc(void *_state)
+{
+ struct fsmonitor_daemon_state *state = _state;
+
+ trace2_thread_start("fsm-health");
+
+ fsm_health__loop(state);
+
+ trace2_thread_exit();
+ return NULL;
+}
+
+static void *fsm_listen__thread_proc(void *_state)
+{
+ struct fsmonitor_daemon_state *state = _state;
+
+ trace2_thread_start("fsm-listen");
+
+ trace_printf_key(&trace_fsmonitor, "Watching: worktree '%s'",
+ state->path_worktree_watch.buf);
+ if (state->nr_paths_watching > 1)
+ trace_printf_key(&trace_fsmonitor, "Watching: gitdir '%s'",
+ state->path_gitdir_watch.buf);
+
+ fsm_listen__loop(state);
+
+ pthread_mutex_lock(&state->main_lock);
+ if (state->current_token_data &&
+ state->current_token_data->client_ref_count == 0)
+ fsmonitor_free_token_data(state->current_token_data);
+ state->current_token_data = NULL;
+ pthread_mutex_unlock(&state->main_lock);
+
+ trace2_thread_exit();
+ return NULL;
+}
+
+static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
+{
+ struct ipc_server_opts ipc_opts = {
+ .nr_threads = fsmonitor__ipc_threads,
+
+ /*
+ * We know that there are no other active threads yet,
+ * so we can let the IPC layer temporarily chdir() if
+ * it needs to when creating the server side of the
+ * Unix domain socket.
+ */
+ .uds_disallow_chdir = 0
+ };
+ int health_started = 0;
+ int listener_started = 0;
+ int err = 0;
+
+ /*
+ * Start the IPC thread pool before the we've started the file
+ * system event listener thread so that we have the IPC handle
+ * before we need it.
+ */
+ if (ipc_server_run_async(&state->ipc_server_data,
+ state->path_ipc.buf, &ipc_opts,
+ handle_client, state))
+ return error_errno(
+ _("could not start IPC thread pool on '%s'"),
+ state->path_ipc.buf);
+
+ /*
+ * Start the fsmonitor listener thread to collect filesystem
+ * events.
+ */
+ if (pthread_create(&state->listener_thread, NULL,
+ fsm_listen__thread_proc, state) < 0) {
+ ipc_server_stop_async(state->ipc_server_data);
+ err = error(_("could not start fsmonitor listener thread"));
+ goto cleanup;
+ }
+ listener_started = 1;
+
+ /*
+ * Start the health thread to watch over our process.
+ */
+ if (pthread_create(&state->health_thread, NULL,
+ fsm_health__thread_proc, state) < 0) {
+ ipc_server_stop_async(state->ipc_server_data);
+ err = error(_("could not start fsmonitor health thread"));
+ goto cleanup;
+ }
+ health_started = 1;
+
+ /*
+ * The daemon is now fully functional in background threads.
+ * Our primary thread should now just wait while the threads
+ * do all the work.
+ */
+cleanup:
+ /*
+ * Wait for the IPC thread pool to shutdown (whether by client
+ * request, from filesystem activity, or an error).
+ */
+ ipc_server_await(state->ipc_server_data);
+
+ /*
+ * The fsmonitor listener thread may have received a shutdown
+ * event from the IPC thread pool, but it doesn't hurt to tell
+ * it again. And wait for it to shutdown.
+ */
+ if (listener_started) {
+ fsm_listen__stop_async(state);
+ pthread_join(state->listener_thread, NULL);
+ }
+
+ if (health_started) {
+ fsm_health__stop_async(state);
+ pthread_join(state->health_thread, NULL);
+ }
+
+ if (err)
+ return err;
+ if (state->listen_error_code)
+ return state->listen_error_code;
+ if (state->health_error_code)
+ return state->health_error_code;
+ return 0;
+}
+
+static int fsmonitor_run_daemon(void)
+{
+ struct fsmonitor_daemon_state state;
+ const char *home;
+ int err;
+
+ memset(&state, 0, sizeof(state));
+
+ hashmap_init(&state.cookies, cookies_cmp, NULL, 0);
+ pthread_mutex_init(&state.main_lock, NULL);
+ pthread_cond_init(&state.cookies_cond, NULL);
+ state.listen_error_code = 0;
+ state.health_error_code = 0;
+ state.current_token_data = fsmonitor_new_token_data();
+
+ /* Prepare to (recursively) watch the <worktree-root> directory. */
+ strbuf_init(&state.path_worktree_watch, 0);
+ strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
+ state.nr_paths_watching = 1;
+
+ /*
+ * We create and delete cookie files somewhere inside the .git
+ * directory to help us keep sync with the file system. If
+ * ".git" is not a directory, then <gitdir> is not inside the
+ * cone of <worktree-root>, so set up a second watch to watch
+ * the <gitdir> so that we get events for the cookie files.
+ */
+ strbuf_init(&state.path_gitdir_watch, 0);
+ strbuf_addbuf(&state.path_gitdir_watch, &state.path_worktree_watch);
+ strbuf_addstr(&state.path_gitdir_watch, "/.git");
+ if (!is_directory(state.path_gitdir_watch.buf)) {
+ strbuf_reset(&state.path_gitdir_watch);
+ strbuf_addstr(&state.path_gitdir_watch, absolute_path(get_git_dir()));
+ state.nr_paths_watching = 2;
+ }
+
+ /*
+ * We will write filesystem syncing cookie files into
+ * <gitdir>/<fsmonitor-dir>/<cookie-dir>/<pid>-<seq>.
+ *
+ * The extra layers of subdirectories here keep us from
+ * changing the mtime on ".git/" or ".git/foo/" when we create
+ * or delete cookie files.
+ *
+ * There have been problems with some IDEs that do a
+ * non-recursive watch of the ".git/" directory and run a
+ * series of commands any time something happens.
+ *
+ * For example, if we place our cookie files directly in
+ * ".git/" or ".git/foo/" then a `git status` (or similar
+ * command) from the IDE will cause a cookie file to be
+ * created in one of those dirs. This causes the mtime of
+ * those dirs to change. This triggers the IDE's watch
+ * notification. This triggers the IDE to run those commands
+ * again. And the process repeats and the machine never goes
+ * idle.
+ *
+ * Adding the extra layers of subdirectories prevents the
+ * mtime of ".git/" and ".git/foo" from changing when a
+ * cookie file is created.
+ */
+ strbuf_init(&state.path_cookie_prefix, 0);
+ strbuf_addbuf(&state.path_cookie_prefix, &state.path_gitdir_watch);
+
+ strbuf_addch(&state.path_cookie_prefix, '/');
+ strbuf_addstr(&state.path_cookie_prefix, FSMONITOR_DIR);
+ mkdir(state.path_cookie_prefix.buf, 0777);
+
+ strbuf_addch(&state.path_cookie_prefix, '/');
+ strbuf_addstr(&state.path_cookie_prefix, FSMONITOR_COOKIE_DIR);
+ mkdir(state.path_cookie_prefix.buf, 0777);
+
+ strbuf_addch(&state.path_cookie_prefix, '/');
+
+ /*
+ * We create a named-pipe or unix domain socket inside of the
+ * ".git" directory. (Well, on Windows, we base our named
+ * pipe in the NPFS on the absolute path of the git
+ * directory.)
+ */
+ strbuf_init(&state.path_ipc, 0);
+ strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+
+ /*
+ * Confirm that we can create platform-specific resources for the
+ * filesystem listener before we bother starting all the threads.
+ */
+ if (fsm_listen__ctor(&state)) {
+ err = error(_("could not initialize listener thread"));
+ goto done;
+ }
+
+ if (fsm_health__ctor(&state)) {
+ err = error(_("could not initialize health thread"));
+ goto done;
+ }
+
+ /*
+ * CD out of the worktree root directory.
+ *
+ * The common Git startup mechanism causes our CWD to be the
+ * root of the worktree. On Windows, this causes our process
+ * to hold a locked handle on the CWD. This prevents the
+ * worktree from being moved or deleted while the daemon is
+ * running.
+ *
+ * We assume that our FS and IPC listener threads have either
+ * opened all of the handles that they need or will do
+ * everything using absolute paths.
+ */
+ home = getenv("HOME");
+ if (home && *home && chdir(home))
+ die_errno(_("could not cd home '%s'"), home);
+
+ err = fsmonitor_run_daemon_1(&state);
+
+done:
+ pthread_cond_destroy(&state.cookies_cond);
+ pthread_mutex_destroy(&state.main_lock);
+ fsm_listen__dtor(&state);
+ fsm_health__dtor(&state);
+
+ ipc_server_free(state.ipc_server_data);
+
+ strbuf_release(&state.path_worktree_watch);
+ strbuf_release(&state.path_gitdir_watch);
+ strbuf_release(&state.path_cookie_prefix);
+ strbuf_release(&state.path_ipc);
+
+ return err;
+}
+
+static int try_to_run_foreground_daemon(int detach_console)
+{
+ /*
+ * Technically, we don't need to probe for an existing daemon
+ * process, since we could just call `fsmonitor_run_daemon()`
+ * and let it fail if the pipe/socket is busy.
+ *
+ * However, this method gives us a nicer error message for a
+ * common error case.
+ */
+ if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
+ die(_("fsmonitor--daemon is already running '%s'"),
+ the_repository->worktree);
+
+ if (fsmonitor__announce_startup) {
+ fprintf(stderr, _("running fsmonitor-daemon in '%s'\n"),
+ the_repository->worktree);
+ fflush(stderr);
+ }
+
+#ifdef GIT_WINDOWS_NATIVE
+ if (detach_console)
+ FreeConsole();
+#endif
+
+ return !!fsmonitor_run_daemon();
+}
+
+static start_bg_wait_cb bg_wait_cb;
+
+static int bg_wait_cb(const struct child_process *cp, void *cb_data)
+{
+ enum ipc_active_state s = fsmonitor_ipc__get_state();
+
+ switch (s) {
+ case IPC_STATE__LISTENING:
+ /* child is "ready" */
+ return 0;
+
+ case IPC_STATE__NOT_LISTENING:
+ case IPC_STATE__PATH_NOT_FOUND:
+ /* give child more time */
+ return 1;
+
+ default:
+ case IPC_STATE__INVALID_PATH:
+ case IPC_STATE__OTHER_ERROR:
+ /* all the time in world won't help */
+ return -1;
+ }
+}
+
+static int try_to_start_background_daemon(void)
+{
+ struct child_process cp = CHILD_PROCESS_INIT;
+ enum start_bg_result sbgr;
+
+ /*
+ * Before we try to create a background daemon process, see
+ * if a daemon process is already listening. This makes it
+ * easier for us to report an already-listening error to the
+ * console, since our spawn/daemon can only report the success
+ * of creating the background process (and not whether it
+ * immediately exited).
+ */
+ if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
+ die(_("fsmonitor--daemon is already running '%s'"),
+ the_repository->worktree);
+
+ if (fsmonitor__announce_startup) {
+ fprintf(stderr, _("starting fsmonitor-daemon in '%s'\n"),
+ the_repository->worktree);
+ fflush(stderr);
+ }
+
+ cp.git_cmd = 1;
+
+ strvec_push(&cp.args, "fsmonitor--daemon");
+ strvec_push(&cp.args, "run");
+ strvec_push(&cp.args, "--detach");
+ strvec_pushf(&cp.args, "--ipc-threads=%d", fsmonitor__ipc_threads);
+
+ cp.no_stdin = 1;
+ cp.no_stdout = 1;
+ cp.no_stderr = 1;
+
+ sbgr = start_bg_command(&cp, bg_wait_cb, NULL,
+ fsmonitor__start_timeout_sec);
+
+ switch (sbgr) {
+ case SBGR_READY:
+ return 0;
+
+ default:
+ case SBGR_ERROR:
+ case SBGR_CB_ERROR:
+ return error(_("daemon failed to start"));
+
+ case SBGR_TIMEOUT:
+ return error(_("daemon not online yet"));
+
+ case SBGR_DIED:
+ return error(_("daemon terminated"));
+ }
+}
+
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
+{
+ const char *subcmd;
+ enum fsmonitor_reason reason;
+ int detach_console = 0;
+
+ struct option options[] = {
+ OPT_BOOL(0, "detach", &detach_console, N_("detach from console")),
+ OPT_INTEGER(0, "ipc-threads",
+ &fsmonitor__ipc_threads,
+ N_("use <n> ipc worker threads")),
+ OPT_INTEGER(0, "start-timeout",
+ &fsmonitor__start_timeout_sec,
+ N_("max seconds to wait for background daemon startup")),
+
+ OPT_END()
+ };
+
+ git_config(fsmonitor_config, NULL);
+
+ argc = parse_options(argc, argv, prefix, options,
+ builtin_fsmonitor__daemon_usage, 0);
+ if (argc != 1)
+ usage_with_options(builtin_fsmonitor__daemon_usage, options);
+ subcmd = argv[0];
+
+ if (fsmonitor__ipc_threads < 1)
+ die(_("invalid 'ipc-threads' value (%d)"),
+ fsmonitor__ipc_threads);
+
+ prepare_repo_settings(the_repository);
+ /*
+ * If the repo is fsmonitor-compatible, explicitly set IPC-mode
+ * (without bothering to load the `core.fsmonitor` config settings).
+ *
+ * If the repo is not compatible, the repo-settings will be set to
+ * incompatible rather than IPC, so we can use one of the __get
+ * routines to detect the discrepancy.
+ */
+ fsm_settings__set_ipc(the_repository);
+
+ reason = fsm_settings__get_reason(the_repository);
+ if (reason > FSMONITOR_REASON_OK)
+ die("%s",
+ fsm_settings__get_incompatible_msg(the_repository,
+ reason));
+
+ if (!strcmp(subcmd, "start"))
+ return !!try_to_start_background_daemon();
+
+ if (!strcmp(subcmd, "run"))
+ return !!try_to_run_foreground_daemon(detach_console);
+
+ if (!strcmp(subcmd, "stop"))
+ return !!do_as_client__send_stop();
+
+ if (!strcmp(subcmd, "status"))
+ return !!do_as_client__status();
+
+ die(_("Unhandled subcommand '%s'"), subcmd);
+}
+
+#else
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+
+ if (argc == 2 && !strcmp(argv[1], "-h"))
+ usage_with_options(builtin_fsmonitor__daemon_usage, options);
+
+ die(_("fsmonitor--daemon not supported on this platform"));
+}
+#endif
diff --git a/builtin/gc.c b/builtin/gc.c
index b335cff..eeff2b7 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -42,6 +42,7 @@ static const char * const builtin_gc_usage[] = {
static int pack_refs = 1;
static int prune_reflogs = 1;
+static int cruft_packs = 0;
static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
@@ -152,6 +153,7 @@ static void gc_config(void)
git_config_get_int("gc.auto", &gc_auto_threshold);
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
git_config_get_bool("gc.autodetach", &detach_auto);
+ git_config_get_bool("gc.cruftpacks", &cruft_packs);
git_config_get_expiry("gc.pruneexpire", &prune_expire);
git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
git_config_get_expiry("gc.logexpiry", &gc_log_expire);
@@ -166,9 +168,15 @@ struct maintenance_run_opts;
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
{
struct strvec pack_refs_cmd = STRVEC_INIT;
+ int ret;
+
strvec_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
- return run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD);
+ ret = run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD);
+
+ strvec_clear(&pack_refs_cmd);
+
+ return ret;
}
static int too_many_loose_objects(void)
@@ -331,7 +339,11 @@ static void add_repack_all_option(struct string_list *keep_pack)
{
if (prune_expire && !strcmp(prune_expire, "now"))
strvec_push(&repack, "-a");
- else {
+ else if (cruft_packs) {
+ strvec_push(&repack, "--cruft");
+ if (prune_expire)
+ strvec_pushf(&repack, "--cruft-expiration=%s", prune_expire);
+ } else {
strvec_push(&repack, "-A");
if (prune_expire)
strvec_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
@@ -446,7 +458,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
fscanf(fp, scan_fmt, &pid, locking_host) == 2 &&
/* be gentle to concurrent "gc" on remote hosts */
(strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM);
- if (fp != NULL)
+ if (fp)
fclose(fp);
if (should_exit) {
if (fd >= 0)
@@ -551,6 +563,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
{ OPTION_STRING, 0, "prune", &prune_expire, N_("date"),
N_("prune unreferenced objects"),
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
+ OPT_BOOL(0, "cruft", &cruft_packs, N_("pack unreferenced objects separately")),
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
PARSE_OPT_NOCOMPLETE),
@@ -574,7 +587,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
/* default expiry time, overwritten in gc_config */
gc_config();
if (parse_expiry_date(gc_log_expire, &gc_log_expire_time))
- die(_("failed to parse gc.logexpiry value %s"), gc_log_expire);
+ die(_("failed to parse gc.logExpiry value %s"), gc_log_expire);
if (pack_refs < 0)
pack_refs = !is_bare_repository();
@@ -670,6 +683,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
die(FAILED_RUN, repack.v[0]);
if (prune_expire) {
+ /* run `git prune` even if using cruft packs */
strvec_push(&prune, prune_expire);
if (quiet)
strvec_push(&prune, "--no-progress");
@@ -2238,7 +2252,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
goto error;
}
file = fopen_or_warn(filename, "w");
- if (file == NULL)
+ if (!file)
goto error;
unit = "# This file was created and is maintained by Git.\n"
@@ -2267,7 +2281,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
filename = xdg_config_home_systemd("git-maintenance@.service");
file = fopen_or_warn(filename, "w");
- if (file == NULL)
+ if (!file)
goto error;
unit = "# This file was created and is maintained by Git.\n"
diff --git a/builtin/grep.c b/builtin/grep.c
index bcb07ea..e6bcdf8 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -961,6 +961,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored,
N_("allow calling of grep(1) (ignored by this build)"),
PARSE_OPT_NOCOMPLETE),
+ OPT_INTEGER('m', "max-count", &opt.max_count,
+ N_("maximum number of results per file")),
OPT_END()
};
grep_prefix = prefix;
@@ -1101,6 +1103,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (recurse_submodules && untracked)
die(_("--untracked not supported with --recurse-submodules"));
+ /*
+ * Optimize out the case where the amount of matches is limited to zero.
+ * We do this to keep results consistent with GNU grep(1).
+ */
+ if (opt.max_count == 0)
+ return 1;
+
if (show_in_pager) {
if (num_threads > 1)
warning(_("invalid option combination, ignoring --threads"));
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 680b66b..6648f2d 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1575,7 +1575,7 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
if (!strcmp(k, "pack.indexversion")) {
opts->version = git_config_int(k, v);
if (opts->version > 2)
- die(_("bad pack.indexversion=%"PRIu32), opts->version);
+ die(_("bad pack.indexVersion=%"PRIu32), opts->version);
return 0;
}
if (!strcmp(k, "pack.threads")) {
@@ -1942,11 +1942,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
free(objects);
strbuf_release(&index_name_buf);
strbuf_release(&rev_index_name_buf);
- if (pack_name == NULL)
+ if (!pack_name)
free((void *) curr_pack);
- if (index_name == NULL)
+ if (!index_name)
free((void *) curr_index);
- if (rev_index_name == NULL)
+ if (!rev_index_name)
free((void *) curr_rev_index);
/*
diff --git a/builtin/log.c b/builtin/log.c
index c211d66..88a5e98 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -231,7 +231,8 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
}
if (mailmap) {
- rev->mailmap = xcalloc(1, sizeof(struct string_list));
+ rev->mailmap = xmalloc(sizeof(struct string_list));
+ string_list_init_nodup(rev->mailmap);
read_mailmap(rev->mailmap);
}
@@ -294,6 +295,12 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
cmd_log_init_finish(argc, argv, prefix, rev, opt);
}
+static int cmd_log_deinit(int ret, struct rev_info *rev)
+{
+ release_revisions(rev);
+ return ret;
+}
+
/*
* This gives a rough estimate for how many commits we
* will print out in the list.
@@ -417,7 +424,7 @@ static void finish_early_output(struct rev_info *rev)
show_early_header(rev, "done", n);
}
-static int cmd_log_walk(struct rev_info *rev)
+static int cmd_log_walk_no_free(struct rev_info *rev)
{
struct commit *commit;
int saved_nrl = 0;
@@ -444,7 +451,6 @@ static int cmd_log_walk(struct rev_info *rev)
* and HAS_CHANGES being accumulated in rev->diffopt, so be careful to
* retain that state information if replacing rev->diffopt in this loop
*/
- rev->diffopt.no_free = 1;
while ((commit = get_revision(rev)) != NULL) {
if (!log_tree_commit(rev, commit) && rev->max_count >= 0)
/*
@@ -469,8 +475,6 @@ static int cmd_log_walk(struct rev_info *rev)
}
rev->diffopt.degraded_cc_to_c = saved_dcctc;
rev->diffopt.needed_rename_limit = saved_nrl;
- rev->diffopt.no_free = 0;
- diff_free(&rev->diffopt);
if (rev->remerge_diff) {
tmp_objdir_destroy(rev->remerge_objdir);
@@ -484,6 +488,17 @@ static int cmd_log_walk(struct rev_info *rev)
return diff_result_code(&rev->diffopt, 0);
}
+static int cmd_log_walk(struct rev_info *rev)
+{
+ int retval;
+
+ rev->diffopt.no_free = 1;
+ retval = cmd_log_walk_no_free(rev);
+ rev->diffopt.no_free = 0;
+ diff_free(&rev->diffopt);
+ return retval;
+}
+
static int git_log_config(const char *var, const char *value, void *cb)
{
const char *slot_name;
@@ -557,7 +572,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
cmd_log_init(argc, argv, prefix, &rev, &opt);
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
- return cmd_log_walk(&rev);
+ return cmd_log_deinit(cmd_log_walk(&rev), &rev);
}
static void show_tagger(const char *buf, struct rev_info *rev)
@@ -661,6 +676,11 @@ int cmd_show(int argc, const char **argv, const char *prefix)
init_log_defaults();
git_config(git_log_config, NULL);
+ if (the_repository->gitdir) {
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+ }
+
memset(&match_all, 0, sizeof(match_all));
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
@@ -676,10 +696,11 @@ int cmd_show(int argc, const char **argv, const char *prefix)
cmd_log_init(argc, argv, prefix, &rev, &opt);
if (!rev.no_walk)
- return cmd_log_walk(&rev);
+ return cmd_log_deinit(cmd_log_walk(&rev), &rev);
count = rev.pending.nr;
objects = rev.pending.objects;
+ rev.diffopt.no_free = 1;
for (i = 0; i < count && !ret; i++) {
struct object *o = objects[i].item;
const char *name = objects[i].name;
@@ -725,14 +746,17 @@ int cmd_show(int argc, const char **argv, const char *prefix)
rev.pending.nr = rev.pending.alloc = 0;
rev.pending.objects = NULL;
add_object_array(o, name, &rev.pending);
- ret = cmd_log_walk(&rev);
+ ret = cmd_log_walk_no_free(&rev);
break;
default:
ret = error(_("unknown type: %d"), o->type);
}
}
- free(objects);
- return ret;
+
+ rev.diffopt.no_free = 0;
+ diff_free(&rev.diffopt);
+
+ return cmd_log_deinit(ret, &rev);
}
/*
@@ -760,7 +784,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
rev.always_show_header = 1;
cmd_log_init_finish(argc, argv, prefix, &rev, &opt);
- return cmd_log_walk(&rev);
+ return cmd_log_deinit(cmd_log_walk(&rev), &rev);
}
static void log_setup_revisions_tweak(struct rev_info *rev,
@@ -791,7 +815,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)
opt.revarg_opt = REVARG_COMMITTISH;
opt.tweak = log_setup_revisions_tweak;
cmd_log_init(argc, argv, prefix, &rev, &opt);
- return cmd_log_walk(&rev);
+ return cmd_log_deinit(cmd_log_walk(&rev), &rev);
}
/* format-patch */
@@ -1012,7 +1036,7 @@ static int open_next_file(struct commit *commit, const char *subject,
if (!quiet)
printf("%s\n", filename.buf + outdir_offset);
- if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) {
+ if (!(rev->diffopt.file = fopen(filename.buf, "w"))) {
error_errno(_("cannot open patch file %s"), filename.buf);
strbuf_release(&filename);
return -1;
@@ -1746,6 +1770,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct commit *commit;
struct commit **list = NULL;
struct rev_info rev;
+ char *to_free = NULL;
struct setup_revision_opt s_r_opt;
int nr = 0, total, i;
int use_stdout = 0;
@@ -1883,6 +1908,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.diff = 1;
rev.max_parents = 1;
rev.diffopt.flags.recursive = 1;
+ rev.diffopt.no_free = 1;
rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";
@@ -1946,7 +1972,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
strbuf_addch(&buf, '\n');
}
- rev.extra_headers = strbuf_detach(&buf, NULL);
+ rev.extra_headers = to_free = strbuf_detach(&buf, NULL);
if (from) {
if (split_ident_line(&rev.from_ident, from, strlen(from)))
@@ -2008,13 +2034,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (use_stdout) {
setup_pager();
- } else if (rev.diffopt.close_file) {
- /*
- * The diff code parsed --output; it has already opened the
- * file, but we must instruct it not to close after each diff.
- */
- rev.diffopt.no_free = 1;
- } else {
+ } else if (!rev.diffopt.close_file) {
int saved;
if (!output_directory)
@@ -2173,8 +2193,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
prepare_bases(&bases, base, list, nr);
}
- if (in_reply_to || thread || cover_letter)
- rev.ref_message_ids = xcalloc(1, sizeof(struct string_list));
+ if (in_reply_to || thread || cover_letter) {
+ rev.ref_message_ids = xmalloc(sizeof(*rev.ref_message_ids));
+ string_list_init_nodup(rev.ref_message_ids);
+ }
if (in_reply_to) {
const char *msgid = clean_message_id(in_reply_to);
string_list_append(rev.ref_message_ids, msgid);
@@ -2281,8 +2303,11 @@ done:
strbuf_release(&rdiff1);
strbuf_release(&rdiff2);
strbuf_release(&rdiff_title);
- UNLEAK(rev);
- return 0;
+ free(to_free);
+ if (rev.ref_message_ids)
+ string_list_clear(rev.ref_message_ids, 0);
+ free(rev.ref_message_ids);
+ return cmd_log_deinit(0, &rev);
}
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index d856085..df44e5c 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -114,7 +114,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
}
transport = transport_get(remote, NULL);
- if (uploadpack != NULL)
+ if (uploadpack)
transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
if (server_options.nr)
transport->server_options = &server_options;
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 6cb554c..e279be8 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -16,22 +16,102 @@
static int line_termination = '\n';
#define LS_RECURSIVE 1
-#define LS_TREE_ONLY 2
-#define LS_SHOW_TREES 4
-#define LS_NAME_ONLY 8
-#define LS_SHOW_SIZE 16
+#define LS_TREE_ONLY (1 << 1)
+#define LS_SHOW_TREES (1 << 2)
static int abbrev;
static int ls_options;
static struct pathspec pathspec;
static int chomp_prefix;
static const char *ls_tree_prefix;
+static const char *format;
+struct show_tree_data {
+ unsigned mode;
+ enum object_type type;
+ const struct object_id *oid;
+ const char *pathname;
+ struct strbuf *base;
+};
static const char * const ls_tree_usage[] = {
N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
NULL
};
-static int show_recursive(const char *base, int baselen, const char *pathname)
+static enum ls_tree_cmdmode {
+ MODE_DEFAULT = 0,
+ MODE_LONG,
+ MODE_NAME_ONLY,
+ MODE_NAME_STATUS,
+ MODE_OBJECT_ONLY,
+} cmdmode;
+
+static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
+ const enum object_type type, unsigned int padded)
+{
+ if (type == OBJ_BLOB) {
+ unsigned long size;
+ if (oid_object_info(the_repository, oid, &size) < 0)
+ die(_("could not get object info about '%s'"),
+ oid_to_hex(oid));
+ if (padded)
+ strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
+ else
+ strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
+ } else if (padded) {
+ strbuf_addf(line, "%7s", "-");
+ } else {
+ strbuf_addstr(line, "-");
+ }
+}
+
+static size_t expand_show_tree(struct strbuf *sb, const char *start,
+ void *context)
+{
+ struct show_tree_data *data = context;
+ const char *end;
+ const char *p;
+ unsigned int errlen;
+ size_t len = strbuf_expand_literal_cb(sb, start, NULL);
+
+ if (len)
+ return len;
+ if (*start != '(')
+ die(_("bad ls-tree format: element '%s' does not start with '('"), start);
+
+ end = strchr(start + 1, ')');
+ if (!end)
+ die(_("bad ls-tree format: element '%s' does not end in ')'"), start);
+
+ len = end - start + 1;
+ if (skip_prefix(start, "(objectmode)", &p)) {
+ strbuf_addf(sb, "%06o", data->mode);
+ } else if (skip_prefix(start, "(objecttype)", &p)) {
+ strbuf_addstr(sb, type_name(data->type));
+ } else if (skip_prefix(start, "(objectsize:padded)", &p)) {
+ expand_objectsize(sb, data->oid, data->type, 1);
+ } else if (skip_prefix(start, "(objectsize)", &p)) {
+ expand_objectsize(sb, data->oid, data->type, 0);
+ } else if (skip_prefix(start, "(objectname)", &p)) {
+ strbuf_add_unique_abbrev(sb, data->oid, abbrev);
+ } else if (skip_prefix(start, "(path)", &p)) {
+ const char *name = data->base->buf;
+ const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
+ struct strbuf quoted = STRBUF_INIT;
+ struct strbuf sbuf = STRBUF_INIT;
+ strbuf_addstr(data->base, data->pathname);
+ name = relative_path(data->base->buf, prefix, &sbuf);
+ quote_c_style(name, &quoted, NULL, 0);
+ strbuf_addbuf(sb, &quoted);
+ strbuf_release(&sbuf);
+ strbuf_release(&quoted);
+ } else {
+ errlen = (unsigned long)len;
+ die(_("bad ls-tree format: %%%.*s"), errlen, start);
+ }
+ return len;
+}
+
+static int show_recursive(const char *base, size_t baselen, const char *pathname)
{
int i;
@@ -43,7 +123,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
for (i = 0; i < pathspec.nr; i++) {
const char *spec = pathspec.items[i].match;
- int len, speclen;
+ size_t len, speclen;
if (strncmp(base, spec, baselen))
continue;
@@ -61,69 +141,197 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
return 0;
}
-static int show_tree(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *context)
+static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode, void *context)
{
- int retval = 0;
- int baselen;
- const char *type = blob_type;
-
- if (S_ISGITLINK(mode)) {
- /*
- * Maybe we want to have some recursive version here?
- *
- * Something similar to this incomplete example:
- *
- if (show_subprojects(base, baselen, pathname))
- retval = READ_TREE_RECURSIVE;
- *
- */
- type = commit_type;
- } else if (S_ISDIR(mode)) {
- if (show_recursive(base->buf, base->len, pathname)) {
- retval = READ_TREE_RECURSIVE;
- if (!(ls_options & LS_SHOW_TREES))
- return retval;
- }
- type = tree_type;
- }
- else if (ls_options & LS_TREE_ONLY)
+ size_t baselen;
+ int recurse = 0;
+ struct strbuf sb = STRBUF_INIT;
+ enum object_type type = object_type(mode);
+
+ struct show_tree_data data = {
+ .mode = mode,
+ .type = type,
+ .oid = oid,
+ .pathname = pathname,
+ .base = base,
+ };
+
+ if (type == OBJ_TREE && show_recursive(base->buf, base->len, pathname))
+ recurse = READ_TREE_RECURSIVE;
+ if (type == OBJ_TREE && recurse && !(ls_options & LS_SHOW_TREES))
+ return recurse;
+ if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY))
return 0;
- if (!(ls_options & LS_NAME_ONLY)) {
- if (ls_options & LS_SHOW_SIZE) {
- char size_text[24];
- if (!strcmp(type, blob_type)) {
- unsigned long size;
- if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
- xsnprintf(size_text, sizeof(size_text),
- "BAD");
- else
- xsnprintf(size_text, sizeof(size_text),
- "%"PRIuMAX, (uintmax_t)size);
- } else
- xsnprintf(size_text, sizeof(size_text), "-");
- printf("%06o %s %s %7s\t", mode, type,
- find_unique_abbrev(oid, abbrev),
- size_text);
- } else
- printf("%06o %s %s\t", mode, type,
- find_unique_abbrev(oid, abbrev));
- }
baselen = base->len;
+ strbuf_expand(&sb, format, expand_show_tree, &data);
+ strbuf_addch(&sb, line_termination);
+ fwrite(sb.buf, sb.len, 1, stdout);
+ strbuf_release(&sb);
+ strbuf_setlen(base, baselen);
+ return recurse;
+}
+
+static int show_tree_common(struct show_tree_data *data, int *recurse,
+ const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode)
+{
+ enum object_type type = object_type(mode);
+ int ret = -1;
+
+ *recurse = 0;
+ data->mode = mode;
+ data->type = type;
+ data->oid = oid;
+ data->pathname = pathname;
+ data->base = base;
+
+ if (type == OBJ_BLOB) {
+ if (ls_options & LS_TREE_ONLY)
+ ret = 0;
+ } else if (type == OBJ_TREE &&
+ show_recursive(base->buf, base->len, pathname)) {
+ *recurse = READ_TREE_RECURSIVE;
+ if (!(ls_options & LS_SHOW_TREES))
+ ret = *recurse;
+ }
+
+ return ret;
+}
+
+static void show_tree_common_default_long(struct strbuf *base,
+ const char *pathname,
+ const size_t baselen)
+{
+ strbuf_addstr(base, pathname);
+ write_name_quoted_relative(base->buf,
+ chomp_prefix ? ls_tree_prefix : NULL, stdout,
+ line_termination);
+ strbuf_setlen(base, baselen);
+}
+
+static int show_tree_default(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode,
+ void *context)
+{
+ int early;
+ int recurse;
+ struct show_tree_data data = { 0 };
+
+ early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ if (early >= 0)
+ return early;
+
+ printf("%06o %s %s\t", data.mode, type_name(data.type),
+ find_unique_abbrev(data.oid, abbrev));
+ show_tree_common_default_long(base, pathname, data.base->len);
+ return recurse;
+}
+
+static int show_tree_long(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode, void *context)
+{
+ int early;
+ int recurse;
+ struct show_tree_data data = { 0 };
+ char size_text[24];
+
+ early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ if (early >= 0)
+ return early;
+
+ if (data.type == OBJ_BLOB) {
+ unsigned long size;
+ if (oid_object_info(the_repository, data.oid, &size) == OBJ_BAD)
+ xsnprintf(size_text, sizeof(size_text), "BAD");
+ else
+ xsnprintf(size_text, sizeof(size_text),
+ "%" PRIuMAX, (uintmax_t)size);
+ } else {
+ xsnprintf(size_text, sizeof(size_text), "-");
+ }
+
+ printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
+ find_unique_abbrev(data.oid, abbrev), size_text);
+ show_tree_common_default_long(base, pathname, data.base->len);
+ return recurse;
+}
+
+static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode, void *context)
+{
+ int early;
+ int recurse;
+ const size_t baselen = base->len;
+ struct show_tree_data data = { 0 };
+
+ early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ if (early >= 0)
+ return early;
+
strbuf_addstr(base, pathname);
write_name_quoted_relative(base->buf,
chomp_prefix ? ls_tree_prefix : NULL,
stdout, line_termination);
strbuf_setlen(base, baselen);
- return retval;
+ return recurse;
+}
+
+static int show_tree_object(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode, void *context)
+{
+ int early;
+ int recurse;
+ struct show_tree_data data = { 0 };
+
+ early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ if (early >= 0)
+ return early;
+
+ printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
+ return recurse;
}
+struct ls_tree_cmdmode_to_fmt {
+ enum ls_tree_cmdmode mode;
+ const char *const fmt;
+ read_tree_fn_t fn;
+};
+
+static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
+ {
+ .mode = MODE_DEFAULT,
+ .fmt = "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
+ .fn = show_tree_default,
+ },
+ {
+ .mode = MODE_LONG,
+ .fmt = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
+ .fn = show_tree_long,
+ },
+ {
+ .mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
+ .fmt = "%(path)",
+ .fn = show_tree_name_only,
+ },
+ {
+ .mode = MODE_OBJECT_ONLY,
+ .fmt = "%(objectname)",
+ .fn = show_tree_object
+ },
+ {
+ /* fallback */
+ .fn = show_tree_default,
+ },
+};
+
int cmd_ls_tree(int argc, const char **argv, const char *prefix)
{
struct object_id oid;
struct tree *tree;
int i, full_tree = 0;
+ read_tree_fn_t fn = NULL;
const struct option ls_tree_options[] = {
OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
LS_TREE_ONLY),
@@ -133,20 +341,26 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
LS_SHOW_TREES),
OPT_SET_INT('z', NULL, &line_termination,
N_("terminate entries with NUL byte"), 0),
- OPT_BIT('l', "long", &ls_options, N_("include object size"),
- LS_SHOW_SIZE),
- OPT_BIT(0, "name-only", &ls_options, N_("list only filenames"),
- LS_NAME_ONLY),
- OPT_BIT(0, "name-status", &ls_options, N_("list only filenames"),
- LS_NAME_ONLY),
+ OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
+ MODE_LONG),
+ OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
+ MODE_NAME_ONLY),
+ OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
+ MODE_NAME_STATUS),
+ OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
+ MODE_OBJECT_ONLY),
OPT_SET_INT(0, "full-name", &chomp_prefix,
N_("use full path names"), 0),
OPT_BOOL(0, "full-tree", &full_tree,
N_("list entire tree; not just current directory "
"(implies --full-name)")),
+ OPT_STRING_F(0, "format", &format, N_("format"),
+ N_("format to use for the output"),
+ PARSE_OPT_NONEG),
OPT__ABBREV(&abbrev),
OPT_END()
};
+ struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
git_config(git_default_config, NULL);
ls_tree_prefix = prefix;
@@ -159,11 +373,23 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
ls_tree_prefix = prefix = NULL;
chomp_prefix = 0;
}
+ /*
+ * We wanted to detect conflicts between --name-only and
+ * --name-status, but once we're done with that subsequent
+ * code should only need to check the primary name.
+ */
+ if (cmdmode == MODE_NAME_STATUS)
+ cmdmode = MODE_NAME_ONLY;
+
/* -d -r should imply -t, but -d by itself should not have to. */
if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
ls_options |= LS_SHOW_TREES;
+ if (format && cmdmode)
+ usage_msg_opt(
+ _("--format can't be combined with other format-altering options"),
+ ls_tree_usage, ls_tree_options);
if (argc < 1)
usage_with_options(ls_tree_usage, ls_tree_options);
if (get_oid(argv[0], &oid))
@@ -185,6 +411,24 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
tree = parse_tree_indirect(&oid);
if (!tree)
die("not a tree object");
- return !!read_tree(the_repository, tree,
- &pathspec, show_tree, NULL);
+ /*
+ * The generic show_tree_fmt() is slower than show_tree(), so
+ * take the fast path if possible.
+ */
+ while (m2f) {
+ if (!m2f->fmt) {
+ fn = format ? show_tree_fmt : show_tree_default;
+ } else if (format && !strcmp(format, m2f->fmt)) {
+ cmdmode = m2f->mode;
+ fn = m2f->fn;
+ } else if (!format && cmdmode == m2f->mode) {
+ fn = m2f->fn;
+ } else {
+ m2f++;
+ continue;
+ }
+ break;
+ }
+
+ return !!read_tree(the_repository, tree, &pathspec, fn, NULL);
}
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 7baef30..73509f6 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -120,7 +120,7 @@ static int populate_maildir_list(struct string_list *list, const char *path)
for (sub = subs; *sub; ++sub) {
free(name);
name = xstrfmt("%s/%s", path, *sub);
- if ((dir = opendir(name)) == NULL) {
+ if (!(dir = opendir(name))) {
if (errno == ENOENT)
continue;
error_errno("cannot opendir %s", name);
@@ -223,6 +223,9 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
int file_done = 0;
+ if (isatty(fileno(f)))
+ warning(_("reading patches from stdin/tty..."));
+
if (!f) {
error_errno("cannot open mbox %s", file);
goto out;
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index e695867..c923bbf 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -25,10 +25,10 @@ static int label_cb(const struct option *opt, const char *arg, int unset)
int cmd_merge_file(int argc, const char **argv, const char *prefix)
{
- const char *names[3] = { NULL, NULL, NULL };
- mmfile_t mmfs[3];
- mmbuffer_t result = {NULL, 0};
- xmparam_t xmp = {{0}};
+ const char *names[3] = { 0 };
+ mmfile_t mmfs[3] = { 0 };
+ mmbuffer_t result = { 0 };
+ xmparam_t xmp = { 0 };
int ret = 0, i = 0, to_stdout = 0;
int quiet = 0;
struct option options[] = {
@@ -71,21 +71,24 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
for (i = 0; i < 3; i++) {
char *fname;
- int ret;
+ mmfile_t *mmf = mmfs + i;
if (!names[i])
names[i] = argv[i];
fname = prefix_filename(prefix, argv[i]);
- ret = read_mmfile(mmfs + i, fname);
+
+ if (read_mmfile(mmf, fname))
+ ret = -1;
+ else if (mmf->size > MAX_XDIFF_SIZE ||
+ buffer_