summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Documentation/.gitignore1
-rw-r--r--Documentation/CodingGuidelines8
-rw-r--r--Documentation/Makefile23
-rw-r--r--Documentation/MyFirstContribution.txt16
-rw-r--r--Documentation/MyFirstObjectWalk.txt2
-rw-r--r--Documentation/RelNotes/2.30.9.txt43
-rw-r--r--Documentation/RelNotes/2.31.8.txt6
-rw-r--r--Documentation/RelNotes/2.32.7.txt7
-rw-r--r--Documentation/RelNotes/2.33.8.txt7
-rw-r--r--Documentation/RelNotes/2.34.8.txt7
-rw-r--r--Documentation/RelNotes/2.35.8.txt7
-rw-r--r--Documentation/RelNotes/2.36.6.txt7
-rw-r--r--Documentation/RelNotes/2.37.7.txt7
-rw-r--r--Documentation/RelNotes/2.38.5.txt8
-rw-r--r--Documentation/RelNotes/2.39.3.txt12
-rw-r--r--Documentation/RelNotes/2.40.1.txt8
-rw-r--r--Documentation/RelNotes/2.41.0.txt395
-rw-r--r--Documentation/SubmittingPatches2
-rw-r--r--Documentation/asciidoc.conf19
-rw-r--r--Documentation/blame-options.txt8
-rw-r--r--Documentation/config/advice.txt6
-rw-r--r--Documentation/config/difftool.txt7
-rw-r--r--Documentation/config/feature.txt3
-rw-r--r--Documentation/config/format.txt7
-rw-r--r--Documentation/config/gc.txt25
-rw-r--r--Documentation/config/http.txt5
-rw-r--r--Documentation/config/imap.txt8
-rw-r--r--Documentation/config/log.txt9
-rw-r--r--Documentation/config/mergetool.txt7
-rw-r--r--Documentation/config/pack.txt8
-rw-r--r--Documentation/config/rebase.txt10
-rw-r--r--Documentation/config/sendemail.txt1
-rw-r--r--Documentation/config/submodule.txt12
-rw-r--r--Documentation/diff-options.txt118
-rwxr-xr-xDocumentation/doc-diff2
-rw-r--r--Documentation/fetch-options.txt7
-rw-r--r--Documentation/git-am.txt7
-rw-r--r--Documentation/git-blame.txt2
-rw-r--r--Documentation/git-branch.txt4
-rw-r--r--Documentation/git-bundle.txt26
-rw-r--r--Documentation/git-checkout.txt54
-rw-r--r--Documentation/git-clone.txt5
-rw-r--r--Documentation/git-credential.txt25
-rw-r--r--Documentation/git-diff.txt8
-rw-r--r--Documentation/git-difftool.txt10
-rw-r--r--Documentation/git-fetch.txt9
-rw-r--r--Documentation/git-for-each-ref.txt22
-rw-r--r--Documentation/git-format-patch.txt7
-rw-r--r--Documentation/git-gc.txt12
-rw-r--r--Documentation/git-imap-send.txt11
-rw-r--r--Documentation/git-interpret-trailers.txt216
-rw-r--r--Documentation/git-ls-files.txt6
-rw-r--r--Documentation/git-ls-remote.txt46
-rw-r--r--Documentation/git-merge-tree.txt2
-rw-r--r--Documentation/git-merge.txt11
-rw-r--r--Documentation/git-mergetool.txt9
-rw-r--r--Documentation/git-name-rev.txt11
-rw-r--r--Documentation/git-notes.txt42
-rw-r--r--Documentation/git-pack-redundant.txt14
-rw-r--r--Documentation/git-push.txt3
-rw-r--r--Documentation/git-rebase.txt19
-rw-r--r--Documentation/git-rev-parse.txt9
-rw-r--r--Documentation/git-send-email.txt21
-rw-r--r--Documentation/git-show-branch.txt16
-rw-r--r--Documentation/git-show-ref.txt40
-rw-r--r--Documentation/git-sparse-checkout.txt25
-rw-r--r--Documentation/git-tag.txt14
-rw-r--r--Documentation/git-worktree.txt16
-rw-r--r--Documentation/git.txt14
-rw-r--r--Documentation/gitattributes.txt59
-rw-r--r--Documentation/gitformat-pack.txt4
-rw-r--r--Documentation/githooks.txt49
-rw-r--r--Documentation/gitignore.txt4
-rw-r--r--Documentation/gittutorial.txt129
-rw-r--r--Documentation/manpage-base-url.xsl.in10
-rw-r--r--Documentation/manpage-normal.xsl16
-rw-r--r--Documentation/manpage-quote-apos.xsl16
-rw-r--r--Documentation/rev-list-options.txt18
-rw-r--r--Documentation/revisions.txt15
-rw-r--r--Documentation/technical/api-merge.txt4
-rw-r--r--Documentation/user-manual.txt45
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL8
-rw-r--r--Makefile29
l---------RelNotes2
-rw-r--r--abspath.c47
-rw-r--r--abspath.h54
-rw-r--r--add-interactive.c11
-rw-r--r--add-patch.c27
-rw-r--r--advice.c14
-rw-r--r--advice.h4
-rw-r--r--alias.c22
-rw-r--r--alias.h3
-rw-r--r--alloc.c3
-rw-r--r--alloc.h75
-rw-r--r--apply.c49
-rw-r--r--apply.h2
-rw-r--r--archive-tar.c9
-rw-r--r--archive-zip.c8
-rw-r--r--archive.c103
-rw-r--r--archive.h3
-rw-r--r--attr.c48
-rw-r--r--attr.h13
-rw-r--r--banned.h4
-rw-r--r--base85.c3
-rw-r--r--base85.h7
-rw-r--r--bisect.c20
-rw-r--r--blame.c74
-rw-r--r--blame.h2
-rw-r--r--blob.c13
-rw-r--r--blob.h3
-rw-r--r--bloom.c1
-rw-r--r--branch.c52
-rw-r--r--branch.h8
-rw-r--r--builtin.h13
-rw-r--r--builtin/add.c108
-rw-r--r--builtin/am.c52
-rw-r--r--builtin/apply.c3
-rw-r--r--builtin/archive.c6
-rw-r--r--builtin/bisect.c45
-rw-r--r--builtin/blame.c27
-rw-r--r--builtin/branch.c129
-rw-r--r--builtin/bugreport.c7
-rw-r--r--builtin/bundle.c49
-rw-r--r--builtin/cat-file.c48
-rw-r--r--builtin/check-attr.c24
-rw-r--r--builtin/check-ignore.c4
-rw-r--r--builtin/check-mailmap.c4
-rw-r--r--builtin/check-ref-format.c6
-rw-r--r--builtin/checkout--worker.c3
-rw-r--r--builtin/checkout-index.c5
-rw-r--r--builtin/checkout.c118
-rw-r--r--builtin/clean.c7
-rw-r--r--builtin/clone.c45
-rw-r--r--builtin/column.c2
-rw-r--r--builtin/commit-graph.c8
-rw-r--r--builtin/commit-tree.c22
-rw-r--r--builtin/commit.c50
-rw-r--r--builtin/config.c11
-rw-r--r--builtin/count-objects.c14
-rw-r--r--builtin/credential-cache--daemon.c7
-rw-r--r--builtin/credential-cache.c5
-rw-r--r--builtin/credential-store.c22
-rw-r--r--builtin/credential.c2
-rw-r--r--builtin/describe.c23
-rw-r--r--builtin/diagnose.c3
-rw-r--r--builtin/diff-files.c9
-rw-r--r--builtin/diff-index.c7
-rw-r--r--builtin/diff-tree.c8
-rw-r--r--builtin/diff.c17
-rw-r--r--builtin/difftool.c34
-rw-r--r--builtin/fast-export.c97
-rw-r--r--builtin/fast-import.c40
-rw-r--r--builtin/fetch-pack.c10
-rw-r--r--builtin/fetch.c812
-rw-r--r--builtin/fmt-merge-msg.c2
-rw-r--r--builtin/for-each-ref.c43
-rw-r--r--builtin/for-each-repo.c20
-rw-r--r--builtin/fsck.c171
-rw-r--r--builtin/fsmonitor--daemon.c11
-rw-r--r--builtin/gc.c61
-rw-r--r--builtin/get-tar-commit-id.c10
-rw-r--r--builtin/grep.c21
-rw-r--r--builtin/hash-object.c9
-rw-r--r--builtin/help.c7
-rw-r--r--builtin/hook.c2
-rw-r--r--builtin/index-pack.c29
-rw-r--r--builtin/init-db.c480
-rw-r--r--builtin/interpret-trailers.c2
-rw-r--r--builtin/log.c77
-rw-r--r--builtin/ls-files.c181
-rw-r--r--builtin/ls-remote.c6
-rw-r--r--builtin/ls-tree.c18
-rw-r--r--builtin/mailinfo.c4
-rw-r--r--builtin/mailsplit.c4
-rw-r--r--builtin/merge-base.c13
-rw-r--r--builtin/merge-file.c4
-rw-r--r--builtin/merge-index.c6
-rw-r--r--builtin/merge-ours.c3
-rw-r--r--builtin/merge-recursive.c14
-rw-r--r--builtin/merge-tree.c27
-rw-r--r--builtin/merge.c50
-rw-r--r--builtin/mktag.c11
-rw-r--r--builtin/mktree.c6
-rw-r--r--builtin/multi-pack-index.c7
-rw-r--r--builtin/mv.c10
-rw-r--r--builtin/name-rev.c25
-rw-r--r--builtin/notes.c195
-rw-r--r--builtin/pack-objects.c78
-rw-r--r--builtin/pack-redundant.c7
-rw-r--r--builtin/pack-refs.c1
-rw-r--r--builtin/patch-id.c4
-rw-r--r--builtin/prune-packed.c1
-rw-r--r--builtin/prune.c21
-rw-r--r--builtin/pull.c30
-rw-r--r--builtin/push.c21
-rw-r--r--builtin/range-diff.c16
-rw-r--r--builtin/read-tree.c21
-rw-r--r--builtin/rebase.c160
-rw-r--r--builtin/receive-pack.c60
-rw-r--r--builtin/reflog.c4
-rw-r--r--builtin/remote-ext.c2
-rw-r--r--builtin/remote-fd.c2
-rw-r--r--builtin/remote.c6
-rw-r--r--builtin/repack.c80
-rw-r--r--builtin/replace.c34
-rw-r--r--builtin/rerere.c4
-rw-r--r--builtin/reset.c37
-rw-r--r--builtin/rev-list.c27
-rw-r--r--builtin/rev-parse.c31
-rw-r--r--builtin/revert.c34
-rw-r--r--builtin/rm.c10
-rw-r--r--builtin/send-pack.c7
-rw-r--r--builtin/shortlog.c18
-rw-r--r--builtin/show-branch.c29
-rw-r--r--builtin/show-index.c5
-rw-r--r--builtin/show-ref.c12
-rw-r--r--builtin/sparse-checkout.c149
-rw-r--r--builtin/stash.c38
-rw-r--r--builtin/stripspace.c10
-rw-r--r--builtin/submodule--helper.c34
-rw-r--r--builtin/symbolic-ref.c2
-rw-r--r--builtin/tag.c76
-rw-r--r--builtin/unpack-file.c11
-rw-r--r--builtin/unpack-objects.c15
-rw-r--r--builtin/update-index.c14
-rw-r--r--builtin/update-ref.c15
-rw-r--r--builtin/update-server-info.c5
-rw-r--r--builtin/upload-archive.c5
-rw-r--r--builtin/upload-pack.c4
-rw-r--r--builtin/var.c5
-rw-r--r--builtin/verify-commit.c19
-rw-r--r--builtin/verify-pack.c3
-rw-r--r--builtin/verify-tag.c17
-rw-r--r--builtin/worktree.c252
-rw-r--r--builtin/write-tree.c8
-rw-r--r--bulk-checkin.c12
-rw-r--r--bulk-checkin.h2
-rw-r--r--bundle-uri.c18
-rw-r--r--bundle.c13
-rw-r--r--bundle.h1
-rw-r--r--cache-tree.c27
-rw-r--r--cache-tree.h1
-rw-r--r--cache.h1950
-rw-r--r--cbtree.c1
-rw-r--r--cbtree.h2
-rw-r--r--chdir-notify.c5
-rw-r--r--checkout.c7
-rw-r--r--checkout.h2
-rw-r--r--chunk-format.c6
-rw-r--r--chunk-format.h3
-rwxr-xr-xci/run-build-and-tests.sh2
-rw-r--r--color.c7
-rw-r--r--column.c3
-rw-r--r--combine-diff.c18
-rw-r--r--commit-graph.c220
-rw-r--r--commit-graph.h11
-rw-r--r--commit-reach.c249
-rw-r--r--commit-reach.h49
-rw-r--r--commit-slab-impl.h2
-rw-r--r--commit.c128
-rw-r--r--commit.h36
-rw-r--r--common-main.c7
-rw-r--r--compat/disk.h2
-rw-r--r--compat/fsmonitor/fsm-health-darwin.c4
-rw-r--r--compat/fsmonitor/fsm-health-win32.c5
-rw-r--r--compat/fsmonitor/fsm-ipc-darwin.c8
-rw-r--r--compat/fsmonitor/fsm-ipc-win32.c2
-rw-r--r--compat/fsmonitor/fsm-listen-darwin.c7
-rw-r--r--compat/fsmonitor/fsm-listen-win32.c6
-rw-r--r--compat/fsmonitor/fsm-path-utils-darwin.c5
-rw-r--r--compat/fsmonitor/fsm-path-utils-win32.c6
-rw-r--r--compat/fsmonitor/fsm-settings-darwin.c3
-rw-r--r--compat/fsmonitor/fsm-settings-win32.c4
-rw-r--r--compat/linux/procinfo.c2
-rw-r--r--compat/mingw.c8
-rw-r--r--compat/pread.c1
-rw-r--r--compat/precompose_utf8.c6
-rw-r--r--compat/sha1-chunked.c3
-rw-r--r--compat/simple-ipc/ipc-shared.c2
-rw-r--r--compat/simple-ipc/ipc-unix-socket.c4
-rw-r--r--compat/simple-ipc/ipc-win32.c39
-rw-r--r--compat/terminal.c4
-rw-r--r--compat/win32/trace2_win32_process_info.c4
-rw-r--r--config.c743
-rw-r--r--config.h73
-rw-r--r--connect.c47
-rw-r--r--connect.h6
-rw-r--r--connected.c10
-rw-r--r--contrib/coccinelle/README40
-rw-r--r--contrib/coccinelle/tests/unused.c82
-rw-r--r--contrib/coccinelle/tests/unused.res45
-rw-r--r--contrib/coccinelle/the_repository.cocci123
-rw-r--r--contrib/coccinelle/the_repository.pending.cocci128
-rw-r--r--contrib/coccinelle/unused.cocci43
-rw-r--r--contrib/completion/git-completion.bash2
-rw-r--r--contrib/completion/git-prompt.sh21
-rw-r--r--contrib/credential/gnome-keyring/.gitignore1
-rw-r--r--contrib/credential/gnome-keyring/Makefile25
-rw-r--r--contrib/credential/gnome-keyring/git-credential-gnome-keyring.c470
-rw-r--r--contrib/credential/libsecret/.gitignore1
-rw-r--r--contrib/credential/libsecret/git-credential-libsecret.c93
-rw-r--r--contrib/credential/osxkeychain/git-credential-osxkeychain.c10
-rw-r--r--contrib/credential/wincred/git-credential-wincred.c107
-rwxr-xr-xcontrib/subtree/git-subtree.sh4
-rw-r--r--contrib/subtree/t/Makefile4
-rw-r--r--convert.c16
-rw-r--r--convert.h2
-rw-r--r--copy.c5
-rw-r--r--copy.h10
-rw-r--r--credential.c16
-rw-r--r--credential.h17
-rw-r--r--csum-file.c4
-rw-r--r--csum-file.h4
-rw-r--r--daemon.c11
-rw-r--r--date.c19
-rw-r--r--date.h1
-rw-r--r--decorate.c2
-rw-r--r--delta-islands.c10
-rwxr-xr-xdetect-compiler10
-rw-r--r--diagnose.c11
-rw-r--r--diagnose.h3
-rw-r--r--diff-lib.c135
-rw-r--r--diff-merges.c82
-rw-r--r--diff-merges.h4
-rw-r--r--diff-no-index.c5
-rw-r--r--diff.c120
-rw-r--r--diff.h17
-rw-r--r--diffcore-break.c6
-rw-r--r--diffcore-delta.c2
-rw-r--r--diffcore-order.c4
-rw-r--r--diffcore-pickaxe.c5
-rw-r--r--diffcore-rename.c13
-rw-r--r--diffcore-rotate.c3
-rw-r--r--diffcore.h4
-rw-r--r--dir-iterator.c3
-rw-r--r--dir.c137
-rw-r--r--dir.h144
-rw-r--r--editor.c38
-rw-r--r--editor.h34
-rw-r--r--entry.c14
-rw-r--r--entry.h4
-rw-r--r--environment.c18
-rw-r--r--environment.h222
-rw-r--r--ewah/bitmap.c3
-rw-r--r--ewah/ewah_bitmap.c2
-rw-r--r--exec-cmd.c9
-rw-r--r--fetch-pack.c26
-rw-r--r--fmt-merge-msg.c37
-rw-r--r--fsck.c15
-rw-r--r--fsck.h1
-rw-r--r--fsmonitor--daemon.h1
-rw-r--r--fsmonitor-ipc.c6
-rw-r--r--fsmonitor-ll.h52
-rw-r--r--fsmonitor-settings.c3
-rw-r--r--fsmonitor.c4
-rw-r--r--fsmonitor.h52
-rw-r--r--gettext.c8
-rw-r--r--gettext.h6
-rw-r--r--git-compat-util.h47
-rwxr-xr-xgit-difftool--helper.sh5
-rw-r--r--git-mergetool--lib.sh40
-rwxr-xr-xgit-mergetool.sh9
-rwxr-xr-xgit-send-email.perl207
-rw-r--r--git-zlib.c (renamed from zlib.c)3
-rw-r--r--git-zlib.h28
-rw-r--r--git.c26
-rwxr-xr-xgitk-git/gitk36
-rw-r--r--gpg-interface.c40
-rw-r--r--gpg-interface.h1
-rw-r--r--graph.c3
-rw-r--r--grep.c17
-rw-r--r--grep.h3
-rw-r--r--hash-ll.h295
-rw-r--r--hash-lookup.c4
-rw-r--r--hash.h240
-rw-r--r--hashmap.c2
-rw-r--r--hashmap.h23
-rw-r--r--help.c7
-rw-r--r--hex.c4
-rw-r--r--hex.h84
-rw-r--r--hook.c19
-rw-r--r--http-backend.c21
-rw-r--r--http-fetch.c5
-rw-r--r--http-push.c27
-rw-r--r--http-walker.c20
-rw-r--r--http.c128
-rw-r--r--http.h4
-rw-r--r--ident.c5
-rw-r--r--ident.h67
-rw-r--r--imap-send.c188
-rw-r--r--json-writer.c2
-rw-r--r--khash.h5
-rw-r--r--kwset.c2
-rw-r--r--levenshtein.c2
-rw-r--r--line-log.c9
-rw-r--r--line-log.h1
-rw-r--r--linear-assignment.c2
-rw-r--r--list-objects-filter-options.c12
-rw-r--r--list-objects-filter-options.h8
-rw-r--r--list-objects-filter.c8
-rw-r--r--list-objects.c26
-rw-r--r--lockfile.c4
-rw-r--r--log-tree.c45
-rw-r--r--log-tree.h2
-rw-r--r--ls-refs.c50
-rw-r--r--mailinfo.c8
-rw-r--r--mailmap.c53
-rw-r--r--mailmap.h3
-rw-r--r--match-trees.c11
-rw-r--r--match-trees.h10
-rw-r--r--mem-pool.c2
-rw-r--r--merge-blobs.c12
-rw-r--r--merge-ll.c (renamed from ll-merge.c)11
-rw-r--r--merge-ll.h (renamed from ll-merge.h)0
-rw-r--r--merge-ort-wrappers.c6
-rw-r--r--merge-ort.c31
-rw-r--r--merge-ort.h2
-rw-r--r--merge-recursive.c27
-rw-r--r--merge.c8
-rw-r--r--merge.h17
-rw-r--r--midx.c17
-rw-r--r--name-hash.c8
-rw-r--r--name-hash.h16
-rw-r--r--negotiator/default.c48
-rw-r--r--negotiator/noop.c2
-rw-r--r--negotiator/skipping.c30
-rw-r--r--notes-cache.c11
-rw-r--r--notes-merge.c25
-rw-r--r--notes-utils.c7
-rw-r--r--notes.c42
-rw-r--r--object-file.c26
-rw-r--r--object-file.h131
-rw-r--r--object-name.c66
-rw-r--r--object-name.h130
-rw-r--r--object-store-ll.h533
-rw-r--r--object-store.h534
-rw-r--r--object.c26
-rw-r--r--object.h69
-rw-r--r--oid-array.c3
-rw-r--r--oidmap.c3
-rw-r--r--oidmap.h2
-rw-r--r--oidset.c4
-rw-r--r--oidtree.c1
-rw-r--r--oidtree.h2
-rw-r--r--oss-fuzz/fuzz-commit-graph.c1
-rw-r--r--oss-fuzz/fuzz-pack-headers.c1
-rw-r--r--oss-fuzz/fuzz-pack-idx.c3
-rw-r--r--pack-bitmap-write.c15
-rw-r--r--pack-bitmap.c93
-rw-r--r--pack-bitmap.h2
-rw-r--r--pack-check.c7
-rw-r--r--pack-mtimes.c5
-rw-r--r--pack-mtimes.h2
-rw-r--r--pack-objects.c3
-rw-r--r--pack-objects.h2
-rw-r--r--pack-revindex.c63
-rw-r--r--pack-revindex.h22
-rw-r--r--pack-write.c24
-rw-r--r--pack.h2
-rw-r--r--packfile.c30
-rw-r--r--packfile.h17
-rw-r--r--pager.c6
-rw-r--r--pager.h17
-rw-r--r--parallel-checkout.c9
-rw-r--r--parse-options-cb.c40
-rw-r--r--parse-options.c16
-rw-r--r--parse-options.h330
-rw-r--r--patch-ids.c4
-rw-r--r--path.c33
-rw-r--r--path.h67
-rw-r--r--pathspec.c12
-rw-r--r--pathspec.h5
-rw-r--r--pkt-line.c8
-rw-r--r--pkt-line.h3
-rw-r--r--preload-index.c8
-rw-r--r--preload-index.h15
-rw-r--r--pretty.c22
-rw-r--r--pretty.h8
-rw-r--r--prio-queue.c3
-rw-r--r--progress.c8
-rw-r--r--promisor-remote.c7
-rw-r--r--promisor-remote.h15
-rw-r--r--prompt.c3
-rw-r--r--protocol-caps.c8
-rw-r--r--protocol.c4
-rw-r--r--protocol.h21
-rw-r--r--prune-packed.c5
-rw-r--r--quote.c5
-rw-r--r--quote.h2
-rw-r--r--range-diff.c19
-rw-r--r--reachable.c106
-rw-r--r--read-cache-ll.h481
-rw-r--r--read-cache.c480
-rw-r--r--read-cache.h45
-rw-r--r--rebase-interactive.c25
-rw-r--r--rebase.c1
-rw-r--r--ref-filter.c243
-rw-r--r--ref-filter.h42
-rw-r--r--reflog-walk.c4
-rw-r--r--reflog-walk.h2
-rw-r--r--reflog.c14
-rw-r--r--refs.c77
-rw-r--r--refs.h22
-rw-r--r--refs/debug.c9
-rw-r--r--refs/files-backend.c20
-rw-r--r--refs/iterator.c2
-rw-r--r--refs/packed-backend.c237
-rw-r--r--refs/ref-cache.c5
-rw-r--r--refs/ref-cache.h3
-rw-r--r--refs/refs-internal.h8
-rw-r--r--refspec.c7
-rw-r--r--reftable/dump.c2
-rw-r--r--reftable/error.c1
-rw-r--r--reftable/publicbasics.c2
-rw-r--r--reftable/system.h2
-rw-r--r--reftable/tree.c2
-rw-r--r--reftable/tree_test.c1
-rw-r--r--remote-curl.c16
-rw-r--r--remote.c28
-rw-r--r--remote.h4
-rw-r--r--replace-object.c6
-rw-r--r--replace-object.h10
-rw-r--r--repo-settings.c7
-rw-r--r--repository.c9
-rw-r--r--repository.h11
-rw-r--r--rerere.c20
-rw-r--r--rerere.h4
-rw-r--r--reset.c7
-rw-r--r--reset.h2
-rw-r--r--resolve-undo.c5
-rw-r--r--resolve-undo.h7
-rw-r--r--revision.c56
-rw-r--r--revision.h13
-rw-r--r--run-command.c30
-rw-r--r--run-command.h29
-rw-r--r--scalar.c7
-rw-r--r--send-pack.c20
-rw-r--r--sequencer.c450
-rw-r--r--sequencer.h14
-rw-r--r--serve.c16
-rw-r--r--server-info.c11
-rw-r--r--server-info.h7
-rw-r--r--setup.c507
-rw-r--r--setup.h177
-rw-r--r--sha1dc_git.c4
-rw-r--r--shallow.c31
-rw-r--r--shallow.h2
-rw-r--r--shell.c2
-rw-r--r--sideband.c5
-rw-r--r--sigchain.c3
-rw-r--r--sparse-index.c9
-rw-r--r--sparse-index.h2
-rw-r--r--split-index.c8
-rw-r--r--split-index.h2
-rw-r--r--statinfo.c87
-rw-r--r--statinfo.h75
-rw-r--r--strbuf.c144
-rw-r--r--strbuf.h89
-rw-r--r--streaming.c8
-rw-r--r--streaming.h4
-rw-r--r--string-list.c16
-rw-r--r--string-list.h12
-rw-r--r--strvec.c4
-rw-r--r--sub-process.c1
-rw-r--r--sub-process.h1
-rw-r--r--submodule-config.c16
-rw-r--r--submodule-config.h1
-rw-r--r--submodule.c285
-rw-r--r--submodule.h9
-rw-r--r--symlinks.c5
-rw-r--r--symlinks.h28
-rw-r--r--t/Makefile8
-rw-r--r--t/README2
-rwxr-xr-xt/aggregate-results.sh2
-rw-r--r--t/annotate-tests.sh21
-rwxr-xr-xt/chainlint.pl15
-rw-r--r--t/chainlint/unclosed-here-doc-indent.expect4
-rw-r--r--t/chainlint/unclosed-here-doc-indent.test4
-rw-r--r--t/chainlint/unclosed-here-doc.expect7
-rw-r--r--t/chainlint/unclosed-here-doc.test7
-rw-r--r--t/helper/test-advise.c2
-rw-r--r--t/helper/test-bitmap.c3
-rw-r--r--t/helper/test-bloom.c6
-rw-r--r--t/helper/test-bundle-uri.c1
-rw-r--r--t/helper/test-cache-tree.c6
-rw-r--r--t/helper/test-chmtime.c2
-rw-r--r--t/helper/test-config.c47
-rw-r--r--t/helper/test-crontab.c1
-rw-r--r--t/helper/test-ctype.c5
-rw-r--r--t/helper/test-date.c8
-rw-r--r--t/helper/test-delta.c2
-rw-r--r--t/helper/test-drop-caches.c2
-rw-r--r--t/helper/test-dump-cache-tree.c9
-rw-r--r--t/helper/test-dump-fsmonitor.c6
-rw-r--r--t/helper/test-dump-split-index.c7
-rw-r--r--t/helper/test-dump-untracked-cache.c7
-rw-r--r--t/helper/test-example-decorate.c5
-rw-r--r--t/helper/test-fast-rebase.c27
-rw-r--r--t/helper/test-fsmonitor-client.c7
-rw-r--r--t/helper/test-hash-speed.c2
-rw-r--r--t/helper/test-hash.c2
-rw-r--r--t/helper/test-hashmap.c22
-rw-r--r--t/helper/test-hexdump.c2
-rw-r--r--t/helper/test-index-version.c4
-rw-r--r--t/helper/test-json-writer.c77
-rw-r--r--t/helper/test-lazy-init-name-hash.c7
-rw-r--r--t/helper/test-match-trees.c12
-rw-r--r--t/helper/test-mergesort.c3
-rw-r--r--t/helper/test-oid-array.c6
-rw-r--r--t/helper/test-oidmap.c33
-rw-r--r--t/helper/test-oidtree.c8
-rw-r--r--t/helper/test-online-cpus.c2
-rw-r--r--t/helper/test-pack-mtimes.c5
-rw-r--r--t/helper/test-parse-options.c6
-rw-r--r--t/helper/test-parse-pathspec-file.c4
-rw-r--r--t/helper/test-partial-clone.c5
-rw-r--r--t/helper/test-path-utils.c7
-rw-r--r--t/helper/test-pcre2-config.c1
-rw-r--r--t/helper/test-pkt-line.c3
-rw-r--r--t/helper/test-prio-queue.c5
-rw-r--r--t/helper/test-proc-receive.c5
-rw-r--r--t/helper/test-progress.c1
-rw-r--r--t/helper/test-reach.c20
-rw-r--r--t/helper/test-read-cache.c5
-rw-r--r--t/helper/test-read-graph.c6
-rw-r--r--t/helper/test-read-midx.c6
-rw-r--r--t/helper/test-ref-store.c22
-rw-r--r--t/helper/test-reftable.c1
-rw-r--r--t/helper/test-repository.c6
-rw-r--r--t/helper/test-revision-walking.c6
-rw-r--r--t/helper/test-run-command.c37
-rw-r--r--t/helper/test-scrap-cache-tree.c6
-rw-r--r--t/helper/test-serve-v2.c3
-rw-r--r--t/helper/test-sha1.c2
-rw-r--r--t/helper/test-sha256.c2
-rw-r--r--t/helper/test-sigchain.c3
-rw-r--r--t/helper/test-simple-ipc.c3
-rw-r--r--t/helper/test-strcmp-offset.c4
-rw-r--r--t/helper/test-string-list.c6
-rw-r--r--t/helper/test-submodule-config.c9
-rw-r--r--t/helper/test-submodule-nested-repo-config.c2
-rw-r--r--t/helper/test-submodule.c5
-rw-r--r--t/helper/test-subprocess.c2
-rw-r--r--t/helper/test-trace2.c9
-rw-r--r--t/helper/test-userdiff.c2
-rw-r--r--t/helper/test-wildmatch.c2
-rw-r--r--t/helper/test-write-cache.c4
-rw-r--r--t/helper/test-xml-encode.c2
-rw-r--r--t/lib-credential.sh89
-rw-r--r--t/lib-diff-alternative.sh31
-rw-r--r--t/lib-httpd.sh9
-rw-r--r--t/lib-httpd/apache.conf8
-rw-r--r--t/lib-httpd/apply-one-time-perl.sh2
-rw-r--r--t/lib-httpd/nph-custom-auth.sh39
-rw-r--r--t/lib-patch-mode.sh11
-rw-r--r--t/lib-submodule-update.sh28
-rwxr-xr-xt/perf/p1500-graph-walks.sh50
-rwxr-xr-xt/perf/p2000-sparse-operations.sh8
-rwxr-xr-xt/perf/p5312-pack-bitmaps-revs.sh3
-rwxr-xr-xt/t0001-init.sh9
-rwxr-xr-xt/t0002-gitfile.sh4
-rwxr-xr-xt/t0003-attributes.sh11
-rwxr-xr-xt/t0020-crlf.sh38
-rwxr-xr-xt/t0027-auto-crlf.sh66
-rwxr-xr-xt/t0035-safe-bare-repository.sh32
-rwxr-xr-xt/t0041-usage.sh1
-rwxr-xr-xt/t0055-beyond-symlinks.sh14
-rwxr-xr-xt/t0060-path-utils.sh108
-rwxr-xr-xt/t0061-run-command.sh39
-rwxr-xr-xt/t0063-string-list.sh51
-rwxr-xr-xt/t0068-for-each-repo.sh19
-rwxr-xr-xt/t0100-previous.sh8
-rwxr-xr-xt/t0300-credentials.sh20
-rwxr-xr-xt/t0301-credential-cache.sh2
-rwxr-xr-xt/t0303-credential-external.sh2
-rwxr-xr-xt/t1005-read-tree-reset.sh15
-rwxr-xr-xt/t1006-cat-file.sh3
-rwxr-xr-xt/t1010-mktree.sh4
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh167
-rwxr-xr-xt/t1092-sparse-checkout-compatibility.sh129
-rwxr-xr-xt/t1300-config.sh73
-rwxr-xr-xt/t1301-shared-repo.sh26
-rwxr-xr-xt/t1302-repo-version.sh2
-rwxr-xr-xt/t1308-config-set.sh117
-rwxr-xr-xt/t1400-update-ref.sh3
-rwxr-xr-xt/t1401-symbolic-ref.sh3
-rwxr-xr-xt/t1404-update-ref-errors.sh1
-rwxr-xr-xt/t1419-exclude-refs.sh131
-rwxr-xr-xt/t1450-fsck.sh35
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh6
-rwxr-xr-xt/t1504-ceiling-dirs.sh8
-rwxr-xr-xt/t1507-rev-parse-upstream.sh14
-rwxr-xr-xt/t2005-checkout-index-symlinks.sh8
-rwxr-xr-xt/t2019-checkout-ambiguous-ref.sh4
-rwxr-xr-xt/t2021-checkout-overwrite.sh16
-rwxr-xr-xt/t2024-checkout-dwim.sh7
-rwxr-xr-xt/t2060-switch.sh29
-rwxr-xr-xt/t2070-restore.sh16
-rwxr-xr-xt/t2107-update-index-basic.sh2
-rwxr-xr-xt/t2400-worktree-add.sh541
-rwxr-xr-xt/t3013-ls-files-format.sh51
-rwxr-xr-xt/t3060-ls-files-with-tree.sh4
-rwxr-xr-xt/t3070-wildmatch.sh11
-rwxr-xr-xt/t3200-branch.sh37
-rwxr-xr-xt/t3202-show-branch.sh18
-rwxr-xr-xt/t3203-branch-output.sh38
-rwxr-xr-xt/t3301-notes.sh126
-rwxr-xr-xt/t3309-notes-merge-auto-resolve.sh7
-rwxr-xr-xt/t3321-notes-stripspace.sh577
-rwxr-xr-xt/t3400-rebase.sh14
-rwxr-xr-xt/t3402-rebase-merge.sh22
-rwxr-xr-xt/t3404-rebase-interactive.sh49
-rwxr-xr-xt/t3418-rebase-continue.sh62
-rwxr-xr-xt/t3422-rebase-incompatible-options.sh17
-rwxr-xr-xt/t3427-rebase-subtree.sh12
-rwxr-xr-xt/t3430-rebase-merges.sh79
-rwxr-xr-xt/t3501-revert-cherry-pick.sh18
-rwxr-xr-xt/t3700-add.sh18
-rwxr-xr-xt/t3701-add-interactive.sh35
-rwxr-xr-xt/t4000-diff-format.sh34
-rwxr-xr-xt/t4013-diff-various.sh113
-rw-r--r--t/t4013/diff.log_--diff-merges=first-parent_--diff-merges=hide_master34
-rwxr-xr-xt/t4014-format-patch.sh87
-rwxr-xr-xt/t4018-diff-funcname.sh19
-rwxr-xr-xt/t4022-diff-rewrite.sh2
-rwxr-xr-xt/t4027-diff-submodule.sh31
-rwxr-xr-xt/t4034-diff-words.sh4
-rwxr-xr-xt/t4047-diff-dirstat.sh2
-rwxr-xr-xt/t4062-diff-pickaxe.sh2
-rwxr-xr-xt/t4067-diff-partial-clone.sh4
-rwxr-xr-xt/t4115-apply-symlink.sh17
-rwxr-xr-xt/t4150-am.sh8
-rwxr-xr-xt/t4202-log.sh15
-rwxr-xr-xt/t4212-log-corrupt.sh51
-rw-r--r--t/t4258/mbox2
-rwxr-xr-xt/t4300-merge-tree.sh18
-rwxr-xr-xt/t5000-tar-tree.sh22
-rwxr-xr-xt/t5001-archive-attr.sh16
-rw-r--r--t/t5100/msg00022
-rw-r--r--t/t5100/msg00032
-rw-r--r--t/t5100/msg0012--message-id2
-rw-r--r--t/t5100/quoted-cr.mbox4
-rw-r--r--t/t5100/sample.mbox6
-rwxr-xr-xt/t5300-pack-object.sh135
-rwxr-xr-xt/t5304-prune.sh70
-rwxr-xr-xt/t5310-pack-bitmaps.sh20
-rwxr-xr-xt/t5318-commit-graph.sh2
-rwxr-xr-xt/t5319-multi-pack-index.sh12
-rwxr-xr-xt/t5325-reverse-index.sh90
-rwxr-xr-xt/t5326-multi-pack-bitmaps.sh44
-rwxr-xr-xt/t5328-commit-graph-64bit-time.sh9
-rwxr-xr-xt/t5329-pack-objects-cruft.sh171
-rwxr-xr-xt/t5331-pack-objects-stdin.sh240
-rwxr-xr-xt/t5407-post-rewrite-hook.sh11
-rwxr-xr-xt/t5510-fetch.sh60
-rwxr-xr-xt/t5512-ls-remote.sh156
-rwxr-xr-xt/t5514-fetch-multiple.sh7
-rwxr-xr-xt/t5516-fetch-push.sh12
-rwxr-xr-xt/t5522-pull-symlink.sh4
-rwxr-xr-xt/t5523-push-upstream.sh12
-rwxr-xr-xt/t5526-fetch-submodules.sh26
-rwxr-xr-xt/t5543-atomic-push.sh5
-rwxr-xr-xt/t5551-http-fetch-smart.sh27
-rwxr-xr-xt/t5552-skipping-fetch-negotiator.sh16
-rwxr-xr-xt/t5558-clone-bundle-uri.sh34
-rwxr-xr-xt/t5563-simple-http-auth.sh323
-rwxr-xr-xt/t5572-pull-submodule.sh4
-rwxr-xr-xt/t5574-fetch-output.sh293
-rwxr-xr-xt/t5583-push-branches.sh115
-rwxr-xr-xt/t5604-clone-reference.sh2
-rwxr-xr-xt/t5605-clone-local.sh12
-rwxr-xr-xt/t5606-clone-options.sh10
-rwxr-xr-xt/t5700-protocol-v1.sh31
-rwxr-xr-xt/t5702-protocol-v2.sh38
-rwxr-xr-xt/t6006-rev-list-format.sh2
-rwxr-xr-xt/t6018-rev-list-glob.sh2
-rwxr-xr-xt/t6020-bundle-misc.sh39
-rwxr-xr-xt/t6021-rev-list-exclude-hidden.sh2
-rwxr-xr-xt/t6030-bisect-porcelain.sh23
-rwxr-xr-xt/t6102-rev-list-unexpected-objects.sh146
-rwxr-xr-xt/t6300-for-each-ref.sh93
-rwxr-xr-xt/t6301-for-each-ref-errors.sh14
-rwxr-xr-xt/t6500-gc.sh133
-rwxr-xr-xt/t6501-freshen-objects.sh12
-rwxr-xr-xt/t6600-test-reach.sh169
-rwxr-xr-xt/t7001-mv.sh37
-rwxr-xr-xt/t7004-tag.sh80
-rwxr-xr-xt/t7031-verify-tag-signed-ssh.sh10
-rwxr-xr-xt/t7300-clean.sh4
-rwxr-xr-xt/t7402-submodule-rebase.sh23
-rwxr-xr-xt/t7413-submodule-is-active.sh16
-rwxr-xr-xt/t7504-commit-msg-hook.sh4
-rwxr-xr-xt/t7506-status-submodule.sh25
-rwxr-xr-xt/t7510-signed-commit.sh21
-rwxr-xr-xt/t7516-commit-races.sh3
-rwxr-xr-xt/t7527-builtin-fsmonitor.sh37
-rwxr-xr-xt/t7610-mergetool.sh38
-rwxr-xr-xt/t7700-repack.sh17
-rwxr-xr-xt/t7701-repack-unpack-unreachable.sh31
-rwxr-xr-xt/t7703-repack-geometric.sh164
-rwxr-xr-xt/t7800-difftool.sh52
-rwxr-xr-xt/t7810-grep.sh4
-rwxr-xr-xt/t7900-maintenance.sh38
-rwxr-xr-xt/t9001-send-email.sh184
-rwxr-xr-xt/t9300-fast-import.sh13
-rwxr-xr-xt/t9304-fast-import-marks.sh29
-rwxr-xr-xt/t9351-fast-export-anonymize.sh2
-rwxr-xr-xt/t9800-git-p4-basic.sh2
-rwxr-xr-xt/t9902-completion.sh36
-rwxr-xr-xt/t9903-bash-prompt.sh8
-rw-r--r--t/test-lib-functions.sh9
-rw-r--r--t/test-lib.sh31
-rw-r--r--tag.c40
-rw-r--r--tag.h2
-rw-r--r--tempfile.c5
-rwxr-xr-xtemplates/hooks--sendemail-validate.sample77
-rw-r--r--thread-utils.c2
-rw-r--r--tmp-objdir.c8
-rw-r--r--trace.c7
-rw-r--r--trace.h1
-rw-r--r--trace2.c5
-rw-r--r--trace2.h2
-rw-r--r--trace2/tr2_cfg.c5
-rw-r--r--trace2/tr2_cmd_name.c3
-rw-r--r--trace2/tr2_ctr.c7
-rw-r--r--trace2/tr2_dst.c4
-rw-r--r--trace2/tr2_sid.c4
-rw-r--r--trace2/tr2_sysenv.c2
-rw-r--r--trace2/tr2_tbuf.c2
-rw-r--r--trace2/tr2_tgt_event.c3
-rw-r--r--trace2/tr2_tgt_normal.c3
-rw-r--r--trace2/tr2_tgt_perf.c3
-rw-r--r--trace2/tr2_tls.c4
-rw-r--r--trace2/tr2_tmr.c3
-rw-r--r--trailer.c5
-rw-r--r--transport-helper.c10
-rw-r--r--transport.c30
-rw-r--r--transport.h1
-rw-r--r--tree-diff.c17
-rw-r--r--tree-walk.c9
-rw-r--r--tree-walk.h5
-rw-r--r--tree.c92
-rw-r--r--tree.h13
-rw-r--r--unicode-width.h33
-rw-r--r--unix-socket.c3
-rw-r--r--unix-stream-server.c2
-rw-r--r--unpack-trees.c264
-rw-r--r--unpack-trees.h45
-rw-r--r--upload-pack.c96
-rw-r--r--url.c4
-rw-r--r--urlmatch.c5
-rw-r--r--usage.c4
-rw-r--r--userdiff.c37
-rw-r--r--userdiff.h1
-rw-r--r--versioncmp.c25
-rw-r--r--versioncmp.h6
-rw-r--r--walker.c13
-rw-r--r--wildmatch.c25
-rw-r--r--wildmatch.h2
-rw-r--r--worktree.c72
-rw-r--r--worktree.h7
-rw-r--r--wrapper.c9
-rw-r--r--wrapper.h36
-rw-r--r--write-or-die.c4
-rw-r--r--write-or-die.h78
-rw-r--r--ws.c8
-rw-r--r--ws.h33
-rw-r--r--wt-status.c41
-rw-r--r--xdiff-interface.c8
-rw-r--r--xdiff-interface.h2
872 files changed, 21598 insertions, 10345 deletions
diff --git a/.mailmap b/.mailmap
index 95aaa1c833..733e047aa8 100644
--- a/.mailmap
+++ b/.mailmap
@@ -65,6 +65,7 @@ Derrick Stolee <derrickstolee@github.com> <dstolee@microsoft.com>
Deskin Miller <deskinm@umich.edu>
Đoàn Trần Công Danh <congdanhqx@gmail.com> Doan Tran Cong Danh
Dirk Süsserott <newsletter@dirk.my1.cc>
+Emily Shaffer <nasamuffin@google.com> <emilyshaffer@google.com>
Eric Blake <eblake@redhat.com> <ebb9@byu.net>
Eric Hanchrow <eric.hanchrow@gmail.com> <offby1@blarg.net>
Eric S. Raymond <esr@thyrsus.com>
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
index 1c3771e7d7..a48448de32 100644
--- a/Documentation/.gitignore
+++ b/Documentation/.gitignore
@@ -10,7 +10,6 @@ howto-index.txt
doc.dep
cmds-*.txt
mergetools-*.txt
-manpage-base-url.xsl
SubmittingPatches.txt
tmp-doc-diff/
GIT-ASCIIDOCFLAGS
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 9d5c27807a..2b472df29d 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -442,8 +442,12 @@ For C programs:
detail.
- The first #include in C files, except in platform specific compat/
- implementations, must be either "git-compat-util.h", "cache.h" or
- "builtin.h". You do not have to include more than one of these.
+ implementations and sha1dc/, must be either "git-compat-util.h" or
+ one of the approved headers that includes it first for you. (The
+ approved headers currently include "builtin.h",
+ "t/helper/test-tool.h", "xdiff/xinclude.h", or
+ "reftable/system.h"). You do not have to include more than one of
+ these.
- A C file must directly include the header files that declare the
functions and the types it uses, except for the functions and types
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 9c67c3a1c5..b629176d7d 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -144,14 +144,16 @@ man5dir = $(mandir)/man5
man7dir = $(mandir)/man7
# DESTDIR =
+GIT_DATE := $(shell git show --quiet --pretty='%as')
+
ASCIIDOC = asciidoc
ASCIIDOC_EXTRA =
ASCIIDOC_HTML = xhtml11
ASCIIDOC_DOCBOOK = docbook
ASCIIDOC_CONF = -f asciidoc.conf
ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF) \
- -amanversion=$(GIT_VERSION) \
- -amanmanual='Git Manual' -amansource='Git'
+ -amanmanual='Git Manual' -amansource='Git $(GIT_VERSION)' \
+ -arevdate='$(GIT_DATE)'
ASCIIDOC_DEPS = asciidoc.conf GIT-ASCIIDOCFLAGS
TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML)
TXT_TO_XML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_DOCBOOK)
@@ -189,15 +191,7 @@ endif
ifndef MAN_BASE_URL
MAN_BASE_URL = file://$(htmldir)/
endif
-XMLTO_EXTRA += -m manpage-base-url.xsl
-
-# If your target system uses GNU groff, it may try to render
-# apostrophes as a "pretty" apostrophe using unicode. This breaks
-# cut&paste, so you should set GNU_ROFF to force them to be ASCII
-# apostrophes. Unfortunately does not work with non-GNU roff.
-ifdef GNU_ROFF
-XMLTO_EXTRA += -m manpage-quote-apos.xsl
-endif
+XMLTO_EXTRA += --stringparam man.base.url.for.relative.links='$(MAN_BASE_URL)'
ifdef USE_ASCIIDOCTOR
ASCIIDOC = asciidoctor
@@ -339,7 +333,6 @@ clean:
$(RM) technical/*.html technical/api-index.txt
$(RM) SubmittingPatches.txt
$(RM) $(cmds_txt) $(mergetools_txt) *.made
- $(RM) manpage-base-url.xsl
$(RM) GIT-ASCIIDOCFLAGS
$(MAN_HTML): %.html : %.txt $(ASCIIDOC_DEPS)
@@ -348,11 +341,7 @@ $(MAN_HTML): %.html : %.txt $(ASCIIDOC_DEPS)
$(OBSOLETE_HTML): %.html : %.txto $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC)$(TXT_TO_HTML) -o $@ $<
-manpage-base-url.xsl: manpage-base-url.xsl.in
- $(QUIET_GEN)sed "s|@@MAN_BASE_URL@@|$(MAN_BASE_URL)|" $< > $@
-
-
-manpage-prereqs := manpage-base-url.xsl $(wildcard manpage*.xsl)
+manpage-prereqs := $(wildcard manpage*.xsl)
manpage-cmd = $(QUIET_XMLTO)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
%.1 : %.xml $(manpage-prereqs)
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index ccfd0cb5f3..56130e4bec 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -1164,28 +1164,28 @@ After you run this command, `format-patch` will output the patches to the `psuh/
directory, alongside the v1 patches. Using a single directory makes it easy to
refer to the old v1 patches while proofreading the v2 patches, but you will need
to be careful to send out only the v2 patches. We will use a pattern like
-"psuh/v2-*.patch" (not "psuh/*.patch", which would match v1 and v2 patches).
+`psuh/v2-*.patch` (not `psuh/*.patch`, which would match v1 and v2 patches).
Edit your cover letter again. Now is a good time to mention what's different
between your last version and now, if it's something significant. You do not
need the exact same body in your second cover letter; focus on explaining to
reviewers the changes you've made that may not be as visible.
-You will also need to go and find the Message-Id of your previous cover letter.
+You will also need to go and find the Message-ID of your previous cover letter.
You can either note it when you send the first series, from the output of `git
send-email`, or you can look it up on the
https://lore.kernel.org/git[mailing list]. Find your cover letter in the
-archives, click on it, then click "permalink" or "raw" to reveal the Message-Id
+archives, click on it, then click "permalink" or "raw" to reveal the Message-ID
header. It should match:
----
-Message-Id: <foo.12345.author@example.com>
+Message-ID: <foo.12345.author@example.com>
----
-Your Message-Id is `<foo.12345.author@example.com>`. This example will be used
-below as well; make sure to replace it with the correct Message-Id for your
-**previous cover letter** - that is, if you're sending v2, use the Message-Id
-from v1; if you're sending v3, use the Message-Id from v2.
+Your Message-ID is `<foo.12345.author@example.com>`. This example will be used
+below as well; make sure to replace it with the correct Message-ID for your
+**previous cover letter** - that is, if you're sending v2, use the Message-ID
+from v1; if you're sending v3, use the Message-ID from v2.
While you're looking at the email, you should also note who is CC'd, as it's
common practice in the mailing list to keep all CCs on a thread. You can add
diff --git a/Documentation/MyFirstObjectWalk.txt b/Documentation/MyFirstObjectWalk.txt
index eee513e86f..200e628e30 100644
--- a/Documentation/MyFirstObjectWalk.txt
+++ b/Documentation/MyFirstObjectWalk.txt
@@ -124,7 +124,7 @@ parameters provided by the user over the CLI.
`nr` represents the number of `rev_cmdline_entry` present in the array.
-`alloc` is used by the `ALLOC_GROW` macro. Check `cache.h` - this variable is
+`alloc` is used by the `ALLOC_GROW` macro. Check `alloc.h` - this variable is
used to track the allocated size of the list.
Per entry, we find:
diff --git a/Documentation/RelNotes/2.30.9.txt b/Documentation/RelNotes/2.30.9.txt
new file mode 100644
index 0000000000..708d626ce6
--- /dev/null
+++ b/Documentation/RelNotes/2.30.9.txt
@@ -0,0 +1,43 @@
+Git v2.30.9 Release Notes
+=========================
+
+This release addresses the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007.
+
+
+Fixes since v2.30.8
+-------------------
+
+ * CVE-2023-25652:
+
+ By feeding specially crafted input to `git apply --reject`, a
+ path outside the working tree can be overwritten with partially
+ controlled contents (corresponding to the rejected hunk(s) from
+ the given patch).
+
+ * CVE-2023-25815:
+
+ When Git is compiled with runtime prefix support and runs without
+ translated messages, it still used the gettext machinery to
+ display messages, which subsequently potentially looked for
+ translated messages in unexpected places. This allowed for
+ malicious placement of crafted messages.
+
+ * CVE-2023-29007:
+
+ When renaming or deleting a section from a configuration file,
+ certain malicious configuration values may be misinterpreted as
+ the beginning of a new configuration section, leading to arbitrary
+ configuration injection.
+
+Credit for finding CVE-2023-25652 goes to Ry0taK, and the fix was
+developed by Taylor Blau, Junio C Hamano and Johannes Schindelin,
+with the help of Linus Torvalds.
+
+Credit for finding CVE-2023-25815 goes to Maxime Escourbiac and
+Yassine BENGANA of Michelin, and the fix was developed by Johannes
+Schindelin.
+
+Credit for finding CVE-2023-29007 goes to André Baptista and Vítor Pinho
+of Ethiack, and the fix was developed by Taylor Blau, and Johannes
+Schindelin, with help from Jeff King, and Patrick Steinhardt.
diff --git a/Documentation/RelNotes/2.31.8.txt b/Documentation/RelNotes/2.31.8.txt
new file mode 100644
index 0000000000..0aa3080780
--- /dev/null
+++ b/Documentation/RelNotes/2.31.8.txt
@@ -0,0 +1,6 @@
+Git v2.31.8 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9 to address the
+security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007;
+see the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.32.7.txt b/Documentation/RelNotes/2.32.7.txt
new file mode 100644
index 0000000000..7bb35388b5
--- /dev/null
+++ b/Documentation/RelNotes/2.32.7.txt
@@ -0,0 +1,7 @@
+Git v2.32.7 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9 and v2.31.8 to
+address the security issues CVE-2023-25652, CVE-2023-25815, and
+CVE-2023-29007; see the release notes for these versions for
+details.
diff --git a/Documentation/RelNotes/2.33.8.txt b/Documentation/RelNotes/2.33.8.txt
new file mode 100644
index 0000000000..d8cf4c7f3a
--- /dev/null
+++ b/Documentation/RelNotes/2.33.8.txt
@@ -0,0 +1,7 @@
+Git v2.33.8 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9, v2.31.8 and
+v2.32.7 to address the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007; see the release notes for these
+versions for details.
diff --git a/Documentation/RelNotes/2.34.8.txt b/Documentation/RelNotes/2.34.8.txt
new file mode 100644
index 0000000000..2b5bd7d9a3
--- /dev/null
+++ b/Documentation/RelNotes/2.34.8.txt
@@ -0,0 +1,7 @@
+Git v2.34.8 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9, v2.31.8,
+v2.32.7 and v2.33.8 to address the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007; see the release notes for these
+versions for details.
diff --git a/Documentation/RelNotes/2.35.8.txt b/Documentation/RelNotes/2.35.8.txt
new file mode 100644
index 0000000000..3c9c094c2b
--- /dev/null
+++ b/Documentation/RelNotes/2.35.8.txt
@@ -0,0 +1,7 @@
+Git v2.35.8 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8 and v2.34.8 to address the security issues
+CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; see the release
+notes for these versions for details.
diff --git a/Documentation/RelNotes/2.36.6.txt b/Documentation/RelNotes/2.36.6.txt
new file mode 100644
index 0000000000..e1edebcc43
--- /dev/null
+++ b/Documentation/RelNotes/2.36.6.txt
@@ -0,0 +1,7 @@
+Git v2.36.6 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8 and v2.35.8 to address the security issues
+CVE-2023-25652, CVS-2023-25815, and CVE-2023-29007; see the release
+notes for these versions for details.
diff --git a/Documentation/RelNotes/2.37.7.txt b/Documentation/RelNotes/2.37.7.txt
new file mode 100644
index 0000000000..4b8165f4b5
--- /dev/null
+++ b/Documentation/RelNotes/2.37.7.txt
@@ -0,0 +1,7 @@
+Git v2.37.7 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8 and v2.36.6 to address the
+security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.38.5.txt b/Documentation/RelNotes/2.38.5.txt
new file mode 100644
index 0000000000..2d1f3b1249
--- /dev/null
+++ b/Documentation/RelNotes/2.38.5.txt
@@ -0,0 +1,8 @@
+Git v2.38.5 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6 and v2.37.7 to address
+the security issues CVE-2023-25652, CVE-2023-25815, and
+CVE-2023-29007; see the release notes for these versions for
+details.
diff --git a/Documentation/RelNotes/2.39.3.txt b/Documentation/RelNotes/2.39.3.txt
index dddff53627..66351b65c2 100644
--- a/Documentation/RelNotes/2.39.3.txt
+++ b/Documentation/RelNotes/2.39.3.txt
@@ -1,9 +1,15 @@
Git v2.39.3 Release Notes
=========================
-This release is primarily to merge fixes accumulated on the 'master'
-front to prepare for 2.40 release that are still relevant to 2.39.x
-maintenance track.
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6, v2.37.7 and v2.38.5 to
+address the security issues CVE-2023-25652, CVE-2023-25815, and
+CVE-2023-29007; see the release notes for these versions for
+details.
+
+This release also merges fixes that have accumulated on the 'master'
+front to prepare for the 2.40 release that are still relevant to
+2.39.x maintenance track.
Fixes since v2.39.2
-------------------
diff --git a/Documentation/RelNotes/2.40.1.txt b/Documentation/RelNotes/2.40.1.txt
new file mode 100644
index 0000000000..e72f6b1b25
--- /dev/null
+++ b/Documentation/RelNotes/2.40.1.txt
@@ -0,0 +1,8 @@
+Git v2.40.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6, v2.37.7, v2.38.5
+and v2.39.3 to address the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007; see the release notes for these
+versions for details.
diff --git a/Documentation/RelNotes/2.41.0.txt b/Documentation/RelNotes/2.41.0.txt
new file mode 100644
index 0000000000..a4b4b1d826
--- /dev/null
+++ b/Documentation/RelNotes/2.41.0.txt
@@ -0,0 +1,395 @@
+Git v2.41 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * Allow information carried on the WWW-Authenticate header to be
+ passed to the credential helpers.
+
+ * A new "fetch.hideRefs" option can be used to exclude specified refs
+ from "rev-list --objects --stdin --not --all" traversal for
+ checking object connectivity, most useful when there are many
+ unrelated histories in a single repository.
+
+ * "git push" has been taught to allow deletion of refs with one-level
+ names to help repairing a repository who acquired such a ref by
+ mistake. In general, we don't encourage use of such a ref, and
+ creation or update to such a ref is rejected as before.
+
+ * Allow "git bisect reset" to check out the original branch when the
+ branch is already checked out in a different worktree linked to the
+ same repository.
+
+ * A few subcommands have been taught to stop users from working on a
+ branch that is being used in another worktree linked to the same
+ repository.
+
+ * "git format-patch" learned to write a log-message only output file
+ for empty commits.
+
+ * "git format-patch" honors the src/dst prefixes set to nonstandard
+ values with configuration variables like "diff.noprefix", causing
+ receiving end of the patch that expects the standard -p1 format to
+ break. "format-patch" has been taught to ignore end-user configuration
+ and always use the standard prefixes.
+
+ This is a backward compatibility breaking change.
+
+ * Lift the limitation that colored prompts can only be used with
+ PROMPT_COMMAND mode.
+
+ * "git blame --contents=<file> <rev> -- <path>" used to be forbidden,
+ but now it finds the origins of lines starting at <file> contents
+ through the history that leads to <rev>.
+
+ * "git pack-redundant" gave a warning when run, as the command has
+ outlived its usefulness long ago and is nominated for future
+ removal. Now we escalate to give an error.
+
+ * "git clone" from an empty repository learned to propagate the
+ choice of the hash algorithm from the source repository to the
+ newly created repository.
+
+ * "git mergetool" and "git difftool" learns a new configuration
+ guiDefault to optionally favor configured guitool over non-gui-tool
+ automatically when $DISPLAY is set.
+
+ * "git branch -d origin/master" would say "no such branch", but it is
+ likely a missed "-r" if refs/remotes/origin/master exists. The
+ command has been taught to give such a hint in its error message.
+
+ * Clean-up of the code path that deals with merge strategy option
+ handling in "git rebase".
+
+ * "git clone --local" stops copying from an original repository that
+ has symbolic links inside its $GIT_DIR; an error message when that
+ happens has been updated.
+
+ * "git branch --format=..." and "git format-patch --format=..."
+ learns "--omit-empty" to hide refs that whose formatting result
+ becomes an empty string from the output.
+
+ * The sendemail-validate validate hook learned to pass the total
+ number of input files and where in the sequence each invocation is
+ via environment variables.
+
+ * When "gc" needs to retain unreachable objects, packing them into
+ cruft packs (instead of exploding them into loose object files) has
+ been offered as a more efficient option for some time. Now the use
+ of cruft packs has been made the default and no longer considered
+ an experimental feature.
+
+ * The output given by "git blame" that attributes a line to contents
+ taken from the file specified by the "--contents" option shows it
+ differently from a line attributed to the working tree file.
+
+ * "git send-email" learned to give the e-mail headers to the validate
+ hook by passing an extra argument from the command line.
+
+ * The credential subsystem learns to help OAuth framework.
+
+ * The titles of manual pages used to be chomped at an unreasonably
+ short limit, which has been removed.
+
+ * Error messages given when working on an unborn branch that is
+ checked out in another worktree have been improved.
+
+ * The documentation was misleading about the interaction between
+ GIT_DEFAULT_HASH and "git clone", which has been clarified to
+ stress that the variable is to be ignored by the command.
+
+ * "git send-email" learned "--header-cmd=<cmd>" that can inject
+ arbitrary e-mail header lines to the outgoing messages.
+
+ * "git fsck" learned to detect bit-flip breakages in the reachability
+ bitmap files.
+
+ * The "--stdin" option of "git name-rev" has been replaced with
+ the "--annotate-stdin" option more than a year ago. We stop
+ advertising it in the "git name-rev -h" output.
+
+ * "git push --all" gained an alias "git push --branches".
+
+ * "git fetch" learned the "--porcelain" option that emits what it did
+ in a machine-parseable format.
+
+ * "git --attr-source=<tree> cmd $args" is a new way to have any
+ command to read attributes not from the working tree but from the
+ given tree object.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Code clean-up to clarify directory traversal API.
+
+ * Code clean-up to clarify the rule that "git-compat-util.h" must be
+ the first to be included.
+
+ * More work towards -Wunused.
+
+ * Instead of forcing each command to choose to honor GPG related
+ configuration variables, make the subsystem lazily initialize
+ itself.
+
+ * Remove workaround for ancient versions of DocBook to make it work
+ correctly with groff, which has not been necessary since docbook
+ 1.76 from 2010.
+
+ * Code clean-up to include and/or uninclude parse-options.h file as
+ needed.
+
+ * The code path that reports what "git fetch" did to each ref has
+ been cleaned up.
+
+ * Assorted config API updates.
+
+ * A few configuration variables to tell the cURL library that
+ different types of ssl-cert and ssl-key are in use have been added.
+
+ * Split key function and data structure definitions out of cache.h to
+ new header files and adjust the users.
+
+ * "git fetch --all" does not have to download and handle the same
+ bundleURI over and over, which has been corrected.
+
+ * "git sparse-checkout" command learns a debugging aid for the sparse
+ rule definitions.
+
+ * "git write-tree" learns to work better with sparse-index.
+
+ * The on-disk reverse index that allows mapping from the pack offset
+ to the object name for the object stored at the offset has been
+ enabled by default.
+
+ * "git fsck" learned to validate the on-disk pack reverse index files.
+
+ * strtok() and strtok_r() are banned in this codebase.
+
+ * The detect-compilers script to help auto-tweaking the build system
+ had trouble working with compilers whose version number has extra
+ suffixes. The script has been taught that certain suffixes (like
+ "-win32" in "gcc 10-win32") can be safely stripped as they share
+ the same features and bugs with the version without the suffix.
+
+ * ctype tests have been taught to test EOF, too.
+
+ * The implementation of credential helpers used fgets() over fixed
+ size buffers to read protocol messages, causing the remainder of
+ the folded long line to trigger unexpected behaviour, which has
+ been corrected.
+
+ * The implementation of the default "negotiator", used to find common
+ ancestor over the network for object tranfer, used to be recursive;
+ it was updated to be iterative to conserve stackspace usage.
+
+ * Our custom callout formatter is no longer used in the documentation
+ formatting toolchain, as the upstream default ones give better
+ output these days.
+
+ * The tracing mechanism learned to notice and report when
+ auto-discovered bare repositories are being used, as allowing so
+ without explicitly stating the user intends to do so (with setting
+ GIT_DIR for example) can be used with social engineering as an
+ attack vector.
+
+ * "git diff-files" learned not to expand sparse-index unless needed.
+
+
+Fixes since v2.40
+-----------------
+
+ * "git fsck" learned to check the index files in other worktrees,
+ just like "git gc" honors them as anchoring points.
+ (merge 8d3e7eac52 jk/fsck-indices-in-worktrees later to maint).
+
+ * Fix a segfaulting loop. The function and its caller may need
+ further clean-up.
+ (merge c5773dc078 ew/commit-reach-clean-up-flags-fix later to maint).
+
+ * "git restore" supports options like "--ours" that are only
+ meaningful during a conflicted merge, but these options are only
+ meaningful when updating the working tree files. These options are
+ marked to be incompatible when both "--staged" and "--worktree" are
+ in effect.
+ (merge ee8a88826a ak/restore-both-incompatible-with-conflicts later to maint).
+
+ * Simplify UI to control progress meter given by "git bundle" command.
+ (merge 8b95521edb jk/bundle-progress later to maint).
+
+ * "git bundle" learned that "-" is a common way to say that the input
+ comes from the standard input and/or the output goes to the
+ standard output. It used to work only for output and only from the
+ root level of the working tree.
+ (merge 0bbe10313e jk/bundle-use-dash-for-stdfiles later to maint).
+
+ * Once we start running, we assumed that the list of alternate object
+ databases would never change. Hook into the machinery used to
+ update the list of packfiles during runtime to update this list as
+ well.
+ (merge e2d003dbed ds/reprepare-alternates-when-repreparing-packfiles later to maint).
+
+ * The code to parse "git rebase -X<opt>" was not prepared to see an
+ unparsable option string, which has been corrected.
+ (merge 15a4cc912e ab/fix-strategy-opts-parsing later to maint).
+
+ * "git add -p" while the index is unmerged sometimes failed to parse
+ the diff output it internally produces and died, which has been
+ corrected.
+ (merge 28d1122f9c jk/add-p-unmerged-fix later to maint).
+
+ * Fix for a "ls-files --format="%(path)" that produced nonsense
+ output, which was a bug in 2.38.
+ (merge cfb62dd006 aj/ls-files-format-fix later to maint).
+
+ * "git receive-pack" that responds to "git push" requests failed to
+ clean a stale lockfile when killed in the middle, which has been
+ corrected.
+ (merge c55c30669c ps/receive-pack-unlock-before-die later to maint).
+
+ * "git rev-parse --quiet foo@{u}", or anything that asks @{u} to be
+ parsed with GET_OID_QUIETLY option, did not quietly fail, which has
+ been corrected.
+ (merge dfbfdc521d fc/oid-quietly-parse-upstream later to maint).
+
+ * Transports that do not support protocol v2 did not correctly fall
+ back to protocol v0 under certain conditions, which has been
+ corrected.
+ (merge eaa0fd6584 jk/fix-proto-downgrade-to-v0 later to maint).
+
+ * time(2) on glib 2.31+, especially on Linux, goes out of sync with
+ higher resolution timers used for gettimeofday(2) and by the
+ filesystem. Replace all calls to it with a git_time() wrapper and
+ (merge 370ddcbc89 pe/time-use-gettimeofday later to maint).
+
+ * Code clean-up to use designated initializers in parse-options API.
+ (merge 353e6d4554 sg/parse-options-h-initializers later to maint).
+
+ * A recent-ish change to allow unicode character classes to be used
+ with "grep -P" triggered a JIT bug in older pcre2 libraries.
+ The problematic change in Git built with these older libraries has
+ been disabled to work around the bug.
+ (merge 14b9a04479 mk/workaround-pcre-jit-ucp-bug later to maint).
+
+ * The wildmatch library code unlearns exponential behaviour it
+ acquired some time ago since it was borrowed from rsync.
+ (merge 3dc0b7f0dc pw/wildmatch-fixes later to maint).
+
+ * The index files can become corrupt under certain conditions when
+ the split-index feature is in use, especially together with
+ fsmonitor, which have been corrected.
+ (merge 061dd722dc js/split-index-fixes later to maint).
+
+ * Document what the pathname-looking strings in "rev-list --object"
+ output are for and what they mean.
+ (merge 15364d2a3c jk/document-rev-list-object-name later to maint).
+
+ * Fix unnecessary truncation of generation numbers used in-core.
+ (merge d3af1c193d ps/ahead-behind-truncation-fix later to maint).
+
+ * Code clean-up around the use of the_repository.
+ (merge 4a93b899c1 ab/remove-implicit-use-of-the-repository later to maint).
+
+ * Consistently spell "Message-ID" as such, not "Message-Id".
+ (merge ba4324c4e1 jc/spell-id-in-both-caps-in-message-id later to maint).
+
+ * Correct use of an uninitialized structure member.
+ (merge dc12ee77ab jx/cap-object-info-uninitialized-fix later to maint).
+
+ * Tests had a few places where we ignored PERL_PATH and blindly used
+ /usr/bin/perl, which have been corrected.
+ (merge c1917156a0 jk/use-perl-path-consistently later to maint).
+
+ * Documentation mark-up fix.
+ (merge 78b6369e67 la/mfc-markup-fix later to maint).
+
+ * Doc toolchain update to remove old workaround for AsciiDoc.
+ (merge 8806120de6 fc/remove-header-workarounds-for-asciidoc later to maint).
+
+ * The userdiff regexp patterns for various filetypes that are built
+ into the system have been updated to avoid triggering regexp errors
+ from UTF-8 aware regex engines.
+ (merge be39144954 rs/userdiff-multibyte-regex later to maint).
+
+ * The approxidate() API has been simplified by losing an extra
+ function that did the same thing as another one.
+ (merge 8a7f0b666f rs/remove-approxidate-relative later to maint).
+
+ * Code clean-up to replace a hardcoded constant with a CPP macro.
+ (merge c870de6502 rs/get-tar-commit-id-use-defined-const later to maint).
+
+ * Doc build simplification.
+ (merge 9a09ed3229 fc/doc-stop-using-manversion later to maint).
+
+ * "git archive" run from a subdirectory mishandled attributes and
+ paths outside the current directory.
+ (merge 92b1dd1b9e rs/archive-from-subdirectory-fixes later to maint).
+
+ * The code to parse capability list for v0 on-wire protocol fell into
+ an infinite loop when a capability appears multiple times, which
+ has been corrected.
+
+ * Geometric repacking ("git repack --geometric=<n>") in a repository
+ that borrows from an alternate object database had various corner
+ case bugs, which have been corrected.
+ (merge d85cd18777 ps/fix-geom-repack-with-alternates later to maint).
+
+ * The "%GT" placeholder for the "--format" option of "git log" and
+ friends caused BUG() to trigger on a commit signed with an unknown
+ key, which has been corrected.
+ (merge 7891e46585 jk/gpg-trust-level-fix later to maint).
+
+ * The completion script used to use bare "read" without the "-r"
+ option to read the contents of various state files, which risked
+ getting confused with backslashes in them. This has been
+ corrected.
+ (merge 197152098a ek/completion-use-read-r-to-read-literally later to maint).
+
+ * A small API fix to the ort merge strategy backend.
+ (merge 000c4ceca7 en/ort-finalize-after-0-merges-fix later to maint).
+
+ * The commit object parser has been taught to be a bit more lenient
+ to parse timestamps on the author/committer line with a malformed
+ author/committer ident.
+ (merge 90ef0f14eb jk/parse-commit-with-malformed-ident later to maint).
+
+ * Retitle a test script with an overly narrow name.
+ (merge 8bb19c14fb ob/t3501-retitle later to maint).
+
+ * Doc update to clarify how text and eol attributes interact to
+ specify the end-of-line conversion.
+ (merge 6696077ace ah/doc-attributes-text later to maint).
+
+ * Gitk updates from GfW project.
+ (merge 99e70f3077 js/gitk-fixes-from-gfw later to maint).
+
+ * "git diff --dirstat" leaked memory, which has been plugged.
+ (merge 83973981eb jc/dirstat-plug-leaks later to maint).
+
+ * "git merge-tree" reads the basic configuration, which can be used
+ by git forges to disable replace-refs feature.
+ (merge b6551feadf ds/merge-tree-use-config later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge f7111175df as/doc-markup-fix later to maint).
+ (merge 90ff7c9898 fc/test-aggregation-clean-up later to maint).
+ (merge 9b0c7f308a jc/am-doc-refer-to-format-patch later to maint).
+ (merge b10cbdac4c bb/unicode-width-table-15 later to maint).
+ (merge 3457b50e8c ab/retire-scripted-add-p later to maint).
+ (merge d52fcf493b ds/p2000-fix-grep-sparse later to maint).
+ (merge ec063d2591 ss/hashmap-typofix later to maint).
+ (merge 1aaed69d11 rs/archive-mtime later to maint).
+ (merge 2da2cc9b28 ob/rollback-after-commit-lock-failure later to maint).
+ (merge 54dbd0933b ob/sequencer-save-head-simplify later to maint).
+ (merge a93cbe8d78 ar/test-cleanup-unused-file-creation later to maint).
+ (merge cc48ddd937 jk/chainlint-fixes later to maint).
+ (merge 4833b08426 ow/ref-format-remove-unused-member later to maint).
+ (merge d0ea2ca1cf dw/doc-submittingpatches-grammofix later to maint).
+ (merge fd72637423 ar/t2024-checkout-output-fix later to maint).
+ (merge d45cbe3fe0 ob/sequencer-i18n-fix later to maint).
+ (merge b734fe49fd ob/messages-capitalize-exception later to maint).
+ (merge ad353d7e77 ma/gittutorial-fixes later to maint).
+ (merge a5855fd8d4 ar/test-cleanup-unused-file-creation-part2 later to maint).
+ (merge 0c5308af30 sd/doc-gitignore-and-rm-cached later to maint).
+ (merge cbb83daeaf kh/doc-interpret-trailers-updates later to maint).
+ (merge 3d77fbb664 ar/config-count-tests-updates later to maint).
+ (merge b7cf25c8f4 jc/t9800-fix-use-of-show-s-raw later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 927f7329a5..b218e27357 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -543,7 +543,7 @@ trigger a new CI build to ensure all tests pass.
[[mua]]
== MUA specific hints
-Some of patches I receive or pick up from the list share common
+Some of the patches I receive or pick up from the list share common
patterns of breakage. Please make sure your MUA is set up
properly not to corrupt whitespaces.
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
index 3e4c13971b..60f76f43ed 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf
@@ -51,25 +51,6 @@ ifdef::doctype-manpage[]
endif::doctype-manpage[]
endif::backend-docbook[]
-ifdef::doctype-manpage[]
-ifdef::backend-docbook[]
-[header]
-template::[header-declarations]
-<refentry>
-<refmeta>
-<refentrytitle>{mantitle}</refentrytitle>
-<manvolnum>{manvolnum}</manvolnum>
-<refmiscinfo class="source">{mansource}</refmiscinfo>
-<refmiscinfo class="version">{manversion}</refmiscinfo>
-<refmiscinfo class="manual">{manmanual}</refmiscinfo>
-</refmeta>
-<refnamediv>
- <refname>{manname}</refname>
- <refpurpose>{manpurpose}</refpurpose>
-</refnamediv>
-endif::backend-docbook[]
-endif::doctype-manpage[]
-
ifdef::backend-xhtml11[]
[attributes]
git-relative-html-prefix=
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index 9a663535f4..552dcc60f2 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -64,11 +64,9 @@ include::line-range-format.txt[]
manual page.
--contents <file>::
- When <rev> is not specified, the command annotates the
- changes starting backwards from the working tree copy.
- This flag makes the command pretend as if the working
- tree copy has the contents of the named file (specify
- `-` to make the command read from the standard input).
+ Annotate using the contents from the named file, starting from <rev>
+ if it is specified, and HEAD otherwise. You may specify '-' to make
+ the command read from the standard input for the file contents.
--date <format>::
Specifies the format used to output dates. If --date is not
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index a00d0100a8..c548a91e67 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -136,4 +136,10 @@ advice.*::
Advice shown when either linkgit:git-add[1] or linkgit:git-rm[1]
is asked to update index entries outside the current sparse
checkout.
+ diverging::
+ Advice shown when a fast-forward is not possible.
+ worktreeAddOrphan::
+ Advice shown when a user tries to create a worktree from an
+ invalid reference, to instruct how to create a new orphan
+ branch instead.
--
diff --git a/Documentation/config/difftool.txt b/Documentation/config/difftool.txt
index a3f8211210..447c40d85a 100644
--- a/Documentation/config/difftool.txt
+++ b/Documentation/config/difftool.txt
@@ -34,3 +34,10 @@ See the `--trust-exit-code` option in linkgit:git-difftool[1] for more details.
difftool.prompt::
Prompt before each invocation of the diff tool.
+
+difftool.guiDefault::
+ Set `true` to use the `diff.guitool` by default (equivalent to specifying
+ the `--gui` argument), or `auto` to select `diff.guitool` or `diff.tool`
+ depending on the presence of a `DISPLAY` environment variable value. The
+ default is `false`, where the `--gui` argument must be provided
+ explicitly for the `diff.guitool` to be used.
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index e52bc6b858..17b4d39f89 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -14,9 +14,6 @@ feature.experimental::
+
* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
skipping more commits at a time, reducing the number of round trips.
-+
-* `gc.cruftPacks=true` reduces disk space used by unreachable objects during
-garbage collection, preventing loose object explosions.
feature.manyFiles::
Enable config options that optimize for repos with many files in the
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index 73678d88a1..8cf6f00d93 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -144,3 +144,10 @@ will only show notes from `refs/notes/bar`.
format.mboxrd::
A boolean value which enables the robust "mboxrd" format when
`--stdout` is in use to escape "^>+From " lines.
+
+format.noprefix::
+ If set, do not show any source or destination prefix in patches.
+ This is equivalent to the `diff.noprefix` option used by `git
+ diff` (but which is not respected by `format-patch`). Note that
+ by setting this, the receiver of any patches you generate will
+ have to apply them using the `-p0` option.
diff --git a/Documentation/config/gc.txt b/Documentation/config/gc.txt
index 38fea076a2..16190be877 100644
--- a/Documentation/config/gc.txt
+++ b/Documentation/config/gc.txt
@@ -43,11 +43,11 @@ gc.autoDetach::
if the system supports it. Default is true.
gc.bigPackThreshold::
- If non-zero, all packs larger than this limit are kept when
- `git gc` is run. This is very similar to `--keep-largest-pack`
- except that all packs that meet the threshold are kept, not
- just the largest pack. Defaults to zero. Common unit suffixes of
- 'k', 'm', or 'g' are supported.
+ If non-zero, all non-cruft packs larger than this limit are kept
+ when `git gc` is run. This is very similar to
+ `--keep-largest-pack` except that all non-cruft packs that meet
+ the threshold are kept, not just the largest pack. Defaults to
+ zero. Common unit suffixes of 'k', 'm', or 'g' are supported.
+
Note that if the number of kept packs is more than gc.autoPackLimit,
this configuration variable is ignored, all packs except the base pack
@@ -84,7 +84,7 @@ gc.packRefs::
gc.cruftPacks::
Store unreachable objects in a cruft pack (see
linkgit:git-repack[1]) instead of as loose objects. The default
- is `false`.
+ is `true`.
gc.pruneExpire::
When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'
@@ -130,6 +130,19 @@ or rebase occurring. Since these changes are not part of the current
project most users will want to expire them sooner, which is why the
default is more aggressive than `gc.reflogExpire`.
+gc.recentObjectsHook::
+ When considering the recency of an object (e.g., when generating
+ a cruft pack or storing unreachable objects as loose), use the
+ shell to execute the specified command(s). Interpret their
+ output as object IDs which Git will consider as "recent",
+ regardless of their age.
++
+Output must contain exactly one hex object ID per line, and nothing
+else. Objects which cannot be found in the repository are ignored.
+Multiple hooks are supported, but all must exit successfully, else the
+operation (either generating a cruft pack or unpacking unreachable
+objects) will be halted.
+
gc.rerereResolved::
Records of conflicted merge you resolved earlier are
kept for this many days when 'git rerere gc' is run.
diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt
index afeeccfbfa..51a70781e5 100644
--- a/Documentation/config/http.txt
+++ b/Documentation/config/http.txt
@@ -246,8 +246,9 @@ significantly since the entire buffer is allocated even for small
pushes.
http.lowSpeedLimit, http.lowSpeedTime::
- If the HTTP transfer speed is less than 'http.lowSpeedLimit'
- for longer than 'http.lowSpeedTime' seconds, the transfer is aborted.
+ If the HTTP transfer speed, in bytes per second, is less than
+ 'http.lowSpeedLimit' for longer than 'http.lowSpeedTime' seconds,
+ the transfer is aborted.
Can be overridden by the `GIT_HTTP_LOW_SPEED_LIMIT` and
`GIT_HTTP_LOW_SPEED_TIME` environment variables.
diff --git a/Documentation/config/imap.txt b/Documentation/config/imap.txt
index 06166fb5c0..5cc46d8721 100644
--- a/Documentation/config/imap.txt
+++ b/Documentation/config/imap.txt
@@ -26,8 +26,7 @@ imap.port::
imap.sslverify::
A boolean to enable/disable verification of the server certificate
- used by the SSL/TLS connection. Default is `true`. Ignored when
- imap.tunnel is set.
+ used by the SSL/TLS connection.
imap.preformattedHTML::
A boolean to enable/disable the use of html encoding when sending
@@ -38,7 +37,6 @@ imap.preformattedHTML::
imap.authMethod::
Specify authenticate method for authentication with IMAP server.
- If Git was built with the NO_CURL option, or if your curl version is older
- than 7.34.0, or if you're running git-imap-send with the `--no-curl`
- option, the only supported method is 'CRAM-MD5'. If this is not set
+ If you're using imap.tunnel, the only supported method is 'CRAM-MD5'.
+ If this is not set
then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
diff --git a/Documentation/config/log.txt b/Documentation/config/log.txt
index 5f96cf87fb..e1b1f723b9 100644
--- a/Documentation/config/log.txt
+++ b/Documentation/config/log.txt
@@ -37,6 +37,15 @@ log.diffMerges::
Set diff format to be used when `--diff-merges=on` is
specified, see `--diff-merges` in linkgit:git-log[1] for
details. Defaults to `separate`.
++
+When used with 'hide' or 'no-hide', sets the default hiding of
+diffs for merge commits when `-p` option is not used.
+
+log.diffMergesHide::
+ `true` implies `--diff-merges=hide` option.
+
+log.diffMerges-m-imply-p::
+ `true` enables implication of `-p` by `-m`.
log.follow::
If `true`, `git log` will act as if the `--follow` option was used when
diff --git a/Documentation/config/mergetool.txt b/Documentation/config/mergetool.txt
index e779a122d8..56a7eeeffb 100644
--- a/Documentation/config/mergetool.txt
+++ b/Documentation/config/mergetool.txt
@@ -85,3 +85,10 @@ mergetool.writeToTemp::
mergetool.prompt::
Prompt before each invocation of the merge resolution program.
+
+mergetool.guiDefault::
+ Set `true` to use the `merge.guitool` by default (equivalent to
+ specifying the `--gui` argument), or `auto` to select `merge.guitool`
+ or `merge.tool` depending on the presence of a `DISPLAY` environment
+ variable value. The default is `false`, where the `--gui` argument
+ must be provided explicitly for the `merge.guitool` to be used.
diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.txt
index 53093d9996..d4c7c9d4e4 100644
--- a/Documentation/config/pack.txt
+++ b/Documentation/config/pack.txt
@@ -171,9 +171,15 @@ pack.writeBitmapLookupTable::
beneficial in repositories that have relatively large bitmap
indexes. Defaults to false.
+pack.readReverseIndex::
+ When true, git will read any .rev file(s) that may be available
+ (see: linkgit:gitformat-pack[5]). When false, the reverse index
+ will be generated from scratch and stored in memory. Defaults to
+ true.
+
pack.writeReverseIndex::
When true, git will write a corresponding .rev file (see:
linkgit:gitformat-pack[5])
for each new packfile that it writes in all places except for
linkgit:git-fast-import[1] and in the bulk checkin mechanism.
- Defaults to false.
+ Defaults to true.
diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index f19bd0e040..afaf6dad99 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -67,3 +67,13 @@ rebase.rescheduleFailedExec::
rebase.forkPoint::
If set to false set `--no-fork-point` option by default.
+
+rebase.rebaseMerges::
+ Whether and how to set the `--rebase-merges` option by default. Can
+ be `rebase-cousins`, `no-rebase-cousins`, or a boolean. Setting to
+ true or to `no-rebase-cousins` is equivalent to
+ `--rebase-merges=no-rebase-cousins`, setting to `rebase-cousins` is
+ equivalent to `--rebase-merges=rebase-cousins`, and setting to false is
+ equivalent to `--no-rebase-merges`. Passing `--rebase-merges` on the
+ command line, with or without an argument, overrides any
+ `rebase.rebaseMerges` configuration.
diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt
index 51da7088a8..92a9ebe98c 100644
--- a/Documentation/config/sendemail.txt
+++ b/Documentation/config/sendemail.txt
@@ -61,6 +61,7 @@ sendemail.ccCmd::
sendemail.chainReplyTo::
sendemail.envelopeSender::
sendemail.from::
+sendemail.headerCmd::
sendemail.signedoffbycc::
sendemail.smtpPass::
sendemail.suppresscc::
diff --git a/Documentation/config/submodule.txt b/Documentation/config/submodule.txt
index 6490527b45..3209eb8117 100644
--- a/Documentation/config/submodule.txt
+++ b/Documentation/config/submodule.txt
@@ -93,6 +93,18 @@ submodule.fetchJobs::
in parallel. A value of 0 will give some reasonable default.
If unset, it defaults to 1.
+submodule.diffJobs::
+ Specifies how many submodules are diffed at the same time. A
+ positive integer allows up to that number of submodules diffed
+ in parallel. A value of 0 will give some reasonable default.
+ If unset, it defaults to 1. The diff operation is used by many
+ other git commands such as add, merge, diff, status, stash and
+ more. Note that the expensive part of the diff operation is
+ reading the index from cache or memory. Therefore multiple jobs
+ may be detrimental to performance if your hardware does not
+ support parallel reads or if the number of jobs greatly exceeds
+ the amount of supported reads.
+
submodule.alternateLocation::
Specifies how the submodules obtain alternates when submodules are
cloned. Possible values are `no`, `superproject`.
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 7d73e976d9..0b5d832ed6 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -35,71 +35,94 @@ endif::git-diff[]
-s::
--no-patch::
- Suppress diff output. Useful for commands like `git show` that
- show the patch by default, or to cancel the effect of `--patch`.
+ Suppress all output from the diff machinery. Useful for
+ commands like `git show` that show the patch by default to
+ squelch their output, or to cancel the effect of options like
+ `--patch`, `--stat` earlier on the command line in an alias.
+
endif::git-format-patch[]
ifdef::git-log[]
---diff-merges=(off|none|on|first-parent|1|separate|m|combined|c|dense-combined|cc|remerge|r)::
+-m::
+ Show diffs for merge commits in the default format.
+ Shortcut for '--diff-merges=on,hide' unless
+ `log.diffMerges-m-imply-p` configuration is active, in which
+ case it's a shortcut for '--diff-merges=on -p'.
+
+-c::
+ Shortcut for '--diff-merges=combined -p'.
+
+--cc::
+ Shortcut for '--diff-merges=dense-combined -p'.
+
+--remerge-diff::
+ Shortcut for '--diff-merges=remerge -p'.
+
--no-diff-merges::
- Specify diff format to be used for merge commits. Default is
+ Synonym for '--diff-merges=off'.
+
+--diff-merges=(<format>|<flag>)[,(<format>|<flag>),...]::
+ Specify diff format and flags to be used for merge commits. Default is
{diff-merges-default} unless `--first-parent` is in use, in which case
`first-parent` is the default.
+
---diff-merges=(off|none):::
---no-diff-merges:::
+The last format specified has precedence, whereas flags are
+cumulative. Comma-separated list is handy to provide flag(s) along
+with format, e.g.: `--diff-merges=first-parent,hide` is handy form of
+`--diff-merges=first-parent --diff-merges=hide`.
++
+The following formats are supported:
++
+--
+off, none::
Disable output of diffs for merge commits. Useful to override
implied value.
+
---diff-merges=on:::
---diff-merges=m:::
--m:::
- This option makes diff output for merge commits to be shown in
- the default format. `-m` will produce the output only if `-p`
- is given as well. The default format could be changed using
+on, m::
+ Make diff output for merge commits to be shown in the default
+ format. The default format could be changed using
`log.diffMerges` configuration parameter, which default value
is `separate`.
+
---diff-merges=first-parent:::
---diff-merges=1:::
- This option makes merge commits show the full diff with
- respect to the first parent only.
+first-parent, 1::
+ Show full diff with respect to first parent. This is the same
+ format as `--patch` produces for non-merge commits.
+
---diff-merges=separate:::
- This makes merge commits show the full diff with respect to
- each of the parents. Separate log entry and diff is generated
- for each parent.
+separate::
+ Show full diff with respect to each of parents.
+ Separate log entry and diff is generated for each parent.
+
---diff-merges=remerge:::
---diff-merges=r:::
---remerge-diff:::
- With this option, two-parent merge commits are remerged to
- create a temporary tree object -- potentially containing files
- with conflict markers and such. A diff is then shown between
- that temporary tree and the actual merge commit.
+remerge, r::
+ Remerge two-parent merge commits to create a temporary tree
+ object--potentially containing files with conflict markers
+ and such. A diff is then shown between that temporary tree
+ and the actual merge commit.
+
The output emitted when this option is used is subject to change, and
so is its interaction with other options (unless explicitly
documented).
+
---diff-merges=combined:::
---diff-merges=c:::
--c:::
- With this option, diff output for a merge commit shows the
- differences from each of the parents to the merge result
- simultaneously instead of showing pairwise diff between a
- parent and the result one at a time. Furthermore, it lists
- only files which were modified from all parents. `-c` implies
- `-p`.
-+
---diff-merges=dense-combined:::
---diff-merges=cc:::
---cc:::
- With this option the output produced by
- `--diff-merges=combined` is further compressed by omitting
- uninteresting hunks whose contents in the parents have only
- two variants and the merge result picks one of them without
- modification. `--cc` implies `-p`.
+combined, c::
+ Show differences from each of the parents to the merge
+ result simultaneously instead of showing pairwise diff between
+ a parent and the result one at a time. Furthermore, it lists
+ only files which were modified from all parents.
++
+dense-combined, cc::
+ Further compress output produced by `--diff-merges=combined`
+ by omitting uninteresting hunks whose contents in the parents
+ have only two variants and the merge result picks one of them
+ without modification.
+--
++
+The following flags are supported:
++
+--
+[no-]hide::
+ Hide diff for merge commits unless `-p` options is given as
+ well. The default `no-hide` could be changed using
+ `log.diffMerges` configuration parameter.
+--
--combined-all-paths::
This flag causes combined diffs (used for merge commits) to
@@ -852,6 +875,11 @@ endif::git-format-patch[]
--no-prefix::
Do not show any source or destination prefix.
+--default-prefix::
+ Use the default source and destination prefixes ("a/" and "b/").
+ This is usually the default already, but may be used to override
+ config such as `diff.noprefix`.
+
--line-prefix=<prefix>::
Prepend an additional prefix to every line of output.
diff --git a/Documentation/doc-diff b/Documentation/doc-diff
index 1694300e50..fb09e0ac0e 100755
--- a/Documentation/doc-diff
+++ b/Documentation/doc-diff
@@ -153,7 +153,7 @@ render_tree () {
make -j$parallel -C "$tmp/worktree" \
$makemanflags \
GIT_VERSION=omitted \
- SOURCE_DATE_EPOCH=0 \
+ GIT_DATE=1970-01-01 \
DESTDIR="$tmp/installed/$dname+" \
install-man &&
mv "$tmp/installed/$dname+" "$tmp/installed/$dname"
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 622bd84768..41fc7ca3c6 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -78,6 +78,13 @@ linkgit:git-config[1].
--dry-run::
Show what would be done, without making any changes.
+--porcelain::
+ Print the output to standard output in an easy-to-parse format for
+ scripts. See section OUTPUT in linkgit:git-fetch[1] for details.
++
+This is incompatible with `--recurse-submodules=[yes|on-demand]` and takes
+precedence over the `fetch.output` config option.
+
ifndef::git-pull[]
--[no-]write-fetch-head::
Write the list of remote refs fetched in the `FETCH_HEAD`
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 0c1dfb3c98..900be198b1 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -24,7 +24,9 @@ DESCRIPTION
-----------
Splits mail messages in a mailbox into commit log message,
authorship information and patches, and applies them to the
-current branch.
+current branch. You could think of it as a reverse operation
+of linkgit:git-format-patch[1] run on a branch with a straight
+history without merges.
OPTIONS
-------
@@ -273,7 +275,8 @@ include::config/am.txt[]
SEE ALSO
--------
-linkgit:git-apply[1].
+linkgit:git-apply[1],
+linkgit:git-format-patch[1].
GIT
---
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 4400a17330..f69a871a96 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -12,7 +12,7 @@ SYNOPSIS
[-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
[--ignore-rev <rev>] [--ignore-revs-file <file>]
[--color-lines] [--color-by-age] [--progress] [--abbrev=<n>]
- [<rev> | --contents <file> | --reverse <rev>..<rev>] [--] <file>
+ [ --contents <file> ] [<rev> | --reverse <rev>..<rev>] [--] <file>
DESCRIPTION
-----------
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index d382ac69f7..d207da9101 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -156,6 +156,10 @@ in another worktree linked to the same repository.
--ignore-case::
Sorting and filtering branches are case insensitive.
+--omit-empty::
+ Do not print a newline after formatted refs where the format expands
+ to the empty string.
+
--column[=<options>]::
--no-column::
Display branch listing in columns. See configuration variable
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index 18a022b4b4..3ab42a19ca 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -9,7 +9,7 @@ git-bundle - Move objects and refs by archive
SYNOPSIS
--------
[verse]
-'git bundle' create [-q | --quiet | --progress | --all-progress] [--all-progress-implied]
+'git bundle' create [-q | --quiet | --progress]
[--version=<version>] <file> <git-rev-list-args>
'git bundle' verify [-q | --quiet] <file>
'git bundle' list-heads <file> [<refname>...]
@@ -66,7 +66,7 @@ create [options] <file> <git-rev-list-args>::
Used to create a bundle named 'file'. This requires the
'<git-rev-list-args>' arguments to define the bundle contents.
'options' contains the options specific to the 'git bundle create'
- subcommand.
+ subcommand. If 'file' is `-`, the bundle is written to stdout.
verify <file>::
Used to check that a bundle file is valid and will apply
@@ -77,12 +77,13 @@ verify <file>::
Finally, information about additional capabilities, such as "object
filter", is printed. See "Capabilities" in linkgit:gitformat-bundle[5]
for more information. The exit code is zero for success, but will
- be nonzero if the bundle file is invalid.
+ be nonzero if the bundle file is invalid. If 'file' is `-`, the
+ bundle is read from stdin.
list-heads <file>::
Lists the references defined in the bundle. If followed by a
list of references, only references matching those given are
- printed out.
+ printed out. If 'file' is `-`, the bundle is read from stdin.
unbundle <file>::
Passes the objects in the bundle to 'git index-pack'
@@ -90,6 +91,7 @@ unbundle <file>::
defined references. If a list of references is given, only
references matching those in the list are printed. This command is
really plumbing, intended to be called only by 'git fetch'.
+ If 'file' is `-`, the bundle is read from stdin.
<git-rev-list-args>::
A list of arguments, acceptable to 'git rev-parse' and
@@ -115,22 +117,6 @@ unbundle <file>::
is specified. This flag forces progress status even if
the standard error stream is not directed to a terminal.
---all-progress::
- When --stdout is specified then progress report is
- displayed during the object count and compression phases
- but inhibited during the write-out phase. The reason is
- that in some cases the output stream is directly linked
- to another command which may wish to display progress
- status of its own as it processes incoming pack data.
- This flag is like --progress except that it forces progress
- report for the write-out phase as well even if --stdout is
- used.
-
---all-progress-implied::
- This is used to imply --all-progress whenever progress display
- is activated. Unlike --all-progress this flag doesn't actually
- force any progress display by itself.
-
--version=<version>::
Specify the bundle version. Version 2 is the older format and can only be
used with SHA-1 repositories; the newer version 3 contains capabilities that
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 6bb32ab460..4af0904f47 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -483,14 +483,11 @@ $ git checkout -b foo # or "git switch -c foo" <1>
$ git branch foo <2>
$ git tag foo <3>
------------
-
<1> creates a new branch `foo`, which refers to commit `f`, and then
updates `HEAD` to refer to branch `foo`. In other words, we'll no longer
be in detached `HEAD` state after this command.
-
<2> similarly creates a new branch `foo`, which refers to commit `f`,
but leaves `HEAD` detached.
-
<3> creates a new tag `foo`, which refers to commit `f`,
leaving `HEAD` detached.
@@ -519,84 +516,89 @@ to checkout these paths out of the index.
EXAMPLES
--------
-. The following sequence checks out the `master` branch, reverts
- the `Makefile` to two revisions back, deletes `hello.c` by
- mistake, and gets it back from the index.
-+
+=== 1. Paths
+
+The following sequence checks out the `master` branch, reverts
+the `Makefile` to two revisions back, deletes `hello.c` by
+mistake, and gets it back from the index.
+
------------
$ git checkout master <1>
$ git checkout master~2 Makefile <2>
$ rm -f hello.c
$ git checkout hello.c <3>
------------
-+
<1> switch branch
<2> take a file out of another commit
<3> restore `hello.c` from the index
-+
+
If you want to check out _all_ C source files out of the index,
you can say
-+
+
------------
$ git checkout -- '*.c'
------------
-+
+
Note the quotes around `*.c`. The file `hello.c` will also be
checked out, even though it is no longer in the working tree,
because the file globbing is used to match entries in the index
(not in the working tree by the shell).
-+
+
If you have an unfortunate branch that is named `hello.c`, this
step would be confused as an instruction to switch to that branch.
You should instead write:
-+
+
------------
$ git checkout -- hello.c
------------
-. After working in the wrong branch, switching to the correct
- branch would be done using:
-+
+=== 2. Merge
+
+After working in the wrong branch, switching to the correct
+branch would be done using:
+
------------
$ git checkout mytopic
------------
-+
+
However, your "wrong" branch and correct `mytopic` branch may
differ in files that you have modified locally, in which case
the above checkout would fail like this:
-+
+
------------
$ git checkout mytopic
error: You have local changes to 'frotz'; not switching branches.
------------
-+
+
You can give the `-m` flag to the command, which would try a
three-way merge:
-+
+
------------
$ git checkout -m mytopic
Auto-merging frotz
------------
-+
+
After this three-way merge, the local modifications are _not_
registered in your index file, so `git diff` would show you what
changes you made since the tip of the new branch.
-. When a merge conflict happens during switching branches with
- the `-m` option, you would see something like this:
-+
+=== 3. Merge conflict
+
+When a merge conflict happens during switching branches with
+the `-m` option, you would see something like this:
+
------------
$ git checkout -m mytopic
Auto-merging frotz
ERROR: Merge conflict in frotz
fatal: merge program failed
------------
-+
+
At this point, `git diff` shows the changes cleanly merged as in
the previous example, as well as the changes in the conflicted
files. Edit and resolve the conflict and mark it resolved with
`git add` as usual:
-+
+
------------
$ edit frotz
$ git add frotz
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index d6434d262d..c37c4a37f7 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -58,6 +58,11 @@ never use the local optimizations). Specifying `--no-local` will
override the default when `/path/to/repo` is given, using the regular
Git transport instead.
+
+If the repository's `$GIT_DIR/objects` has symbolic links or is a
+symbolic link, the clone will fail. This is a security measure to
+prevent the unintentional copying of files by dereferencing the symbolic
+links.
++
*NOTE*: this operation can race with concurrent modification to the
source repository, similar to running `cp -r src dst` while modifying
`src`.
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index 29d184ab82..0e6d9e85ec 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -113,7 +113,13 @@ separated by an `=` (equals) sign, followed by a newline.
The key may contain any bytes except `=`, newline, or NUL. The value may
contain any bytes except newline or NUL.
-In both cases, all bytes are treated as-is (i.e., there is no quoting,
+Attributes with keys that end with C-style array brackets `[]` can have
+multiple values. Each instance of a multi-valued attribute forms an
+ordered list of values - the order of the repeated attributes defines
+the order of the values. An empty multi-valued attribute (`key[]=\n`)
+acts to clear any previous entries and reset the list.
+
+In all cases, all bytes are treated as-is (i.e., there is no quoting,
and one cannot transmit a value with newline or NUL in it). The list of
attributes is terminated by a blank line or end-of-file.
@@ -150,6 +156,12 @@ Git understands the following attributes:
When reading credentials from helpers, `git credential fill` ignores expired
passwords. Represented as Unix time UTC, seconds since 1970.
+`oauth_refresh_token`::
+
+ An OAuth refresh token may accompany a password that is an OAuth access
+ token. Helpers must treat this attribute as confidential like the password
+ attribute. Git itself has no special behaviour for this attribute.
+
`url`::
When this special attribute is read by `git credential`, the
@@ -166,6 +178,17 @@ empty string.
Components which are missing from the URL (e.g., there is no
username in the example above) will be left unset.
+`wwwauth[]`::
+
+ When an HTTP response is received by Git that includes one or more
+ 'WWW-Authenticate' authentication headers, these will be passed by Git
+ to credential helpers.
++
+Each 'WWW-Authenticate' header value is passed as a multi-valued
+attribute 'wwwauth[]', where the order of the attributes is the same as
+they appear in the HTTP response. This attribute is 'one-way' from Git
+to pass additional information to credential helpers.
+
Unrecognised attributes are silently discarded.
GIT
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 52b679256c..a85cc756eb 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -102,7 +102,11 @@ If --merge-base is given, use the merge base of the two commits for the
Just in case you are doing something exotic, it should be
noted that all of the <commit> in the above description, except
in the `--merge-base` case and in the last two forms that use `..`
-notations, can be any <tree>.
+notations, can be any <tree>. A tree of interest is the one pointed to
+by the special ref `AUTO_MERGE`, which is written by the 'ort' merge
+strategy upon hitting merge conflicts (see linkgit:git-merge[1]).
+Comparing the working tree with `AUTO_MERGE` shows changes you've made
+so far to resolve conflicts (see the examples below).
For a more complete list of ways to spell <commit>, see
"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
@@ -152,6 +156,7 @@ Various ways to check your working tree::
$ git diff <1>
$ git diff --cached <2>
$ git diff HEAD <3>
+$ git diff AUTO_MERGE <4>
------------
+
<1> Changes in the working tree not yet staged for the next commit.
@@ -159,6 +164,7 @@ $ git diff HEAD <3>
would be committing if you run `git commit` without `-a` option.
<3> Changes in the working tree since your last commit; what you
would be committing if you run `git commit -a`
+<4> Changes in the working tree you've made to resolve conflicts so far.
Comparing with arbitrary commits::
+
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 9d14c3c9f0..ac0ac6fa02 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -97,10 +97,12 @@ instead. `--no-symlinks` is the default on Windows.
--[no-]gui::
When 'git-difftool' is invoked with the `-g` or `--gui` option
the default diff tool will be read from the configured
- `diff.guitool` variable instead of `diff.tool`. The `--no-gui`
- option can be used to override this setting. If `diff.guitool`
- is not set, we will fallback in the order of `merge.guitool`,
- `diff.tool`, `merge.tool` until a tool is found.
+ `diff.guitool` variable instead of `diff.tool`. This may be
+ selected automatically using the configuration variable
+ `difftool.guiDefault`. The `--no-gui` option can be used to
+ override these settings. If `diff.guitool` is not set, we will
+ fallback in the order of `merge.guitool`, `diff.tool`,
+ `merge.tool` until a tool is found.
--[no-]trust-exit-code::
'git-difftool' invokes a diff tool individually on each file.
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index fba66f1460..f123139c58 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -204,6 +204,15 @@ representing the status of a single ref. Each line is of the form:
<flag> <summary> <from> -> <to> [<reason>]
-------------------------------
+When using `--porcelain`, the output format is intended to be
+machine-parseable. In contrast to the human-readable output formats it
+thus prints to standard output instead of standard error. Each line is
+of the form:
+
+-------------------------------
+<flag> <old-object-id> <new-object-id> <local-reference>
+-------------------------------
+
The status of up-to-date refs is shown only if the --verbose option is
used.
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 6da899c629..5743eb5def 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -9,10 +9,12 @@ SYNOPSIS
--------
[verse]
'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
- [(--sort=<key>)...] [--format=<format>] [<pattern>...]
+ [(--sort=<key>)...] [--format=<format>]
+ [ --stdin | <pattern>... ]
[--points-at=<object>]
[--merged[=<object>]] [--no-merged[=<object>]]
[--contains[=<object>]] [--no-contains[=<object>]]
+ [--exclude=<pattern> ...]
DESCRIPTION
-----------
@@ -32,6 +34,10 @@ OPTIONS
literally, in the latter case matching completely or from the
beginning up to a slash.
+--stdin::
+ If `--stdin` is supplied, then the list of patterns is read from
+ standard input instead of from the argument list.
+
--count=<count>::
By default the command shows all refs that match
`<pattern>`. This option makes it stop after showing
@@ -93,6 +99,15 @@ OPTIONS
--ignore-case::
Sorting and filtering refs are case insensitive.
+--omit-empty::
+ Do not print a newline after formatted refs where the format expands
+ to the empty string.
+
+--exclude=<pattern>::
+ If one or more patterns are given, only refs which do not match
+ any excluded pattern(s) are shown. Matching is done using the
+ same rules as `<pattern>` above.
+
FIELD NAMES
-----------
@@ -217,6 +232,11 @@ worktreepath::
out, if it is checked out in any linked worktree. Empty string
otherwise.
+ahead-behind:<committish>::
+ Two integers, separated by a space, demonstrating the number of
+ commits ahead and behind, respectively, when comparing the output
+ ref to the `<committish>` specified in the format.
+
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
be used to specify the value in the header field.
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index dfcc7da4c2..b1c13fb39a 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -99,7 +99,7 @@ To omit patch numbers from the subject, use `-N`.
If given `--thread`, `git-format-patch` will generate `In-Reply-To` and
`References` headers to make the second and subsequent patch mails appear
-as replies to the first mail; this also generates a `Message-Id` header to
+as replies to the first mail; this also generates a `Message-ID` header to
reference.
OPTIONS
@@ -163,7 +163,7 @@ include::diff-options.txt[]
--no-thread::
Controls addition of `In-Reply-To` and `References` headers to
make the second and subsequent mails appear as replies to the
- first. Also controls generation of the `Message-Id` header to
+ first. Also controls generation of the `Message-ID` header to
reference.
+
The optional <style> argument can be either `shallow` or `deep`.
@@ -173,8 +173,7 @@ series, where the head is chosen from the cover letter, the
threading makes every mail a reply to the previous one.
+
The default is `--no-thread`, unless the `format.thread` configuration
-is set. If `--thread` is specified without a style, it defaults to the
-style specified by `format.thread` if any, or else `shallow`.
+is set. `--thread` without an argument is equivalent to `--thread=shallow`.
+
Beware that the default for 'git send-email' is to thread emails
itself. If you want `git format-patch` to take care of threading, you
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index a65c9aa62d..90806fd26a 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -54,9 +54,10 @@ other housekeeping tasks (e.g. rerere, working trees, reflog...) will
be performed as well.
---cruft::
+--[no-]cruft::
When expiring unreachable objects, pack them separately into a
- cruft pack instead of storing them as loose objects.
+ cruft pack instead of storing them as loose objects. `--cruft`
+ is on by default.
--prune=<date>::
Prune loose objects older than date (default is 2 weeks ago,
@@ -77,9 +78,10 @@ be performed as well.
instance running on this repository.
--keep-largest-pack::
- All packs except the largest pack and those marked with a
- `.keep` files are consolidated into a single pack. When this
- option is used, `gc.bigPackThreshold` is ignored.
+ All packs except the largest non-cruft pack, any packs marked
+ with a `.keep` file, and any cruft pack(s) are consolidated into
+ a single pack. When this option is used, `gc.bigPackThreshold`
+ is ignored.
AGGRESSIVE
----------
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index f7b1851514..ddbbe81931 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -37,17 +37,6 @@ OPTIONS
--quiet::
Be quiet.
---curl::
- Use libcurl to communicate with the IMAP server, unless tunneling
- into it. Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
- option set.
-
---no-curl::
- Talk to the IMAP server using git's own IMAP routines instead of
- using libcurl. Ignored if Git was built with the NO_OPENSSL option
- set.
-
-
CONFIGURATION
-------------
diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt
index 22ff3a603e..a45eb0a4bb 100644
--- a/Documentation/git-interpret-trailers.txt
+++ b/Documentation/git-interpret-trailers.txt
@@ -14,21 +14,37 @@ SYNOPSIS
DESCRIPTION
-----------
-Help parsing or adding 'trailers' lines, that look similar to RFC 822 e-mail
+Add or parse 'trailer' lines that look similar to RFC 822 e-mail
headers, at the end of the otherwise free-form part of a commit
-message.
+message. For example, in the following commit message
-This command reads some patches or commit messages from either the
-<file> arguments or the standard input if no <file> is specified. If
-`--parse` is specified, the output consists of the parsed trailers.
+------------------------------------------------
+subject
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+
+Signed-off-by: Alice <alice@example.com>
+Signed-off-by: Bob <bob@example.com>
+------------------------------------------------
+the last two lines starting with "Signed-off-by" are trailers.
+
+This command reads commit messages from either the
+<file> arguments or the standard input if no <file> is specified.
+If `--parse` is specified, the output consists of the parsed trailers.
Otherwise, this command applies the arguments passed using the
-`--trailer` option, if any, to the commit message part of each input
-file. The result is emitted on the standard output.
+`--trailer` option, if any, to each input file. The result is emitted on the
+standard output.
+
+This command can also operate on the output of linkgit:git-format-patch[1],
+which is more elaborate than a plain commit message. Namely, such output
+includes a commit message (as above), a "---" divider line, and a patch part.
+For these inputs, the divider and patch parts are ignored, unless `--no-divider`
+is specified.
Some configuration variables control the way the `--trailer` arguments
-are applied to each commit message and the way any existing trailer in
-the commit message is changed. They also make it possible to
+are applied to each input and the way any existing trailer in
+the input is changed. They also make it possible to
automatically add some trailers.
By default, a '<token>=<value>' or '<token>:<value>' argument given
@@ -36,41 +52,45 @@ using `--trailer` will be appended after the existing trailers only if
the last trailer has a different (<token>, <value>) pair (or if there
is no existing trailer). The <token> and <value> parts will be trimmed
to remove starting and trailing whitespace, and the resulting trimmed
-<token> and <value> will appear in the message like this:
+<token> and <value> will appear in the output like this:
------------------------------------------------
token: value
------------------------------------------------
This means that the trimmed <token> and <value> will be separated by
-`': '` (one colon followed by one space).
+`': '` (one colon followed by one space). If the <token> should have a different
+string representation than itself, then the 'key' can be configured with
+'trailer.<token>.key'.
By default the new trailer will appear at the end of all the existing
trailers. If there is no existing trailer, the new trailer will appear
-after the commit message part of the output, and, if there is no line
-with only spaces at the end of the commit message part, one blank line
-will be added before the new trailer.
+at the end of the input. A blank line will be added before the new
+trailer if there isn't one already.
-Existing trailers are extracted from the input message by looking for
+Existing trailers are extracted from the input by looking for
a group of one or more lines that (i) is all trailers, or (ii) contains at
least one Git-generated or user-configured trailer and consists of at
least 25% trailers.
The group must be preceded by one or more empty (or whitespace-only) lines.
-The group must either be at the end of the message or be the last
+The group must either be at the end of the input or be the last
non-whitespace lines before a line that starts with '---' (followed by a
-space or the end of the line). Such three minus signs start the patch
-part of the message. See also `--no-divider` below.
+space or the end of the line).
When reading trailers, there can be no whitespace before or inside the
-token, but any number of regular space and tab characters are allowed
-between the token and the separator. There can be whitespaces before,
-inside or after the value. The value may be split over multiple lines
+<token>, but any number of regular space and tab characters are allowed
+between the <token> and the separator. There can be whitespaces before,
+inside or after the <value>. The <value> may be split over multiple lines
with each subsequent line starting with at least one whitespace, like
-the "folding" in RFC 822.
+the "folding" in RFC 822. Example:
+
+------------------------------------------------
+token: This is a very long value, with spaces and
+ newlines in it.
+------------------------------------------------
-Note that 'trailers' do not follow and are not intended to follow many
-rules for RFC 822 headers. For example they do not follow
-the encoding rules and probably many other rules.
+Note that trailers do not follow (nor are they intended to follow) many of the
+rules for RFC 822 headers. For example they do not follow the encoding rule.
OPTIONS
-------
@@ -79,12 +99,12 @@ OPTIONS
--trim-empty::
If the <value> part of any trailer contains only whitespace,
- the whole trailer will be removed from the resulting message.
+ the whole trailer will be removed from the output.
This applies to existing trailers as well as new trailers.
--trailer <token>[(=|:)<value>]::
Specify a (<token>, <value>) pair that should be applied as a
- trailer to the input messages. See the description of this
+ trailer to the inputs. See the description of this
command.
--where <placement>::
@@ -98,7 +118,7 @@ OPTIONS
--if-exists <action>::
--no-if-exists::
Specify what action will be performed when there is already at
- least one trailer with the same <token> in the message. A setting
+ least one trailer with the same <token> in the input. A setting
provided with '--if-exists' overrides all configuration variables
and applies to all '--trailer' options until the next occurrence of
'--if-exists' or '--no-if-exists'. Possible actions are `addIfDifferent`,
@@ -107,7 +127,7 @@ OPTIONS
--if-missing <action>::
--no-if-missing::
Specify what action will be performed when there is no other
- trailer with the same <token> in the message. A setting
+ trailer with the same <token> in the input. A setting
provided with '--if-missing' overrides all configuration variables
and applies to all '--trailer' options until the next occurrence of
'--if-missing' or '--no-if-missing'. Possible actions are `doNothing`
@@ -174,7 +194,7 @@ first trailer with the same <token>.
trailer.ifexists::
This option makes it possible to choose what action will be
performed when there is already at least one trailer with the
- same <token> in the message.
+ same <token> in the input.
+
The valid values for this option are: `addIfDifferentNeighbor` (this
is the default), `addIfDifferent`, `add`, `replace` or `doNothing`.
@@ -184,10 +204,10 @@ trailer with the same (<token>, <value>) pair is above or below the line
where the new trailer will be added.
+
With `addIfDifferent`, a new trailer will be added only if no trailer
-with the same (<token>, <value>) pair is already in the message.
+with the same (<token>, <value>) pair is already in the input.
+
With `add`, a new trailer will be added, even if some trailers with
-the same (<token>, <value>) pair are already in the message.
+the same (<token>, <value>) pair are already in the input.
+
With `replace`, an existing trailer with the same <token> will be
deleted and the new trailer will be added. The deleted trailer will be
@@ -195,12 +215,12 @@ the closest one (with the same <token>) to the place where the new one
will be added.
+
With `doNothing`, nothing will be done; that is no new trailer will be
-added if there is already one with the same <token> in the message.
+added if there is already one with the same <token> in the input.
trailer.ifmissing::
This option makes it possible to choose what action will be
performed when there is not yet any trailer with the same
- <token> in the message.
+ <token> in the input.
+
The valid values for this option are: `add` (this is the default) and
`doNothing`.
@@ -235,13 +255,13 @@ trailer.<token>.ifmissing::
that option for trailers with the specified <token>.
trailer.<token>.command::
+ Deprecated in favor of 'trailer.<token>.cmd'.
This option behaves in the same way as 'trailer.<token>.cmd', except
that it doesn't pass anything as argument to the specified command.
Instead the first occurrence of substring $ARG is replaced by the
- value that would be passed as argument.
+ <value> that would be passed as argument.
+
-The 'trailer.<token>.command' option has been deprecated in favor of
-'trailer.<token>.cmd' due to the fact that $ARG in the user's command is
+Note that $ARG in the user's command is
only replaced once and that the original way of replacing $ARG is not safe.
+
When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given
@@ -249,10 +269,10 @@ for the same <token>, 'trailer.<token>.cmd' is used and
'trailer.<token>.command' is ignored.
trailer.<token>.cmd::
- This option can be used to specify a shell command that will be called:
+ This option can be used to specify a shell command that will be called
once to automatically add a trailer with the specified <token>, and then
- each time a '--trailer <token>=<value>' argument to modify the <value> of
- the trailer that this option would produce.
+ called each time a '--trailer <token>=<value>' argument is specified to
+ modify the <value> of the trailer that this option would produce.
+
When the specified command is first called to add a trailer
with the specified <token>, the behavior is as if a special
@@ -272,37 +292,37 @@ EXAMPLES
--------
* Configure a 'sign' trailer with a 'Signed-off-by' key, and then
- add two of these trailers to a message:
+ add two of these trailers to a commit message file:
+
------------
$ git config trailer.sign.key "Signed-off-by"
$ cat msg.txt
subject
-message
-$ cat msg.txt | git interpret-trailers --trailer 'sign: Alice <alice@example.com>' --trailer 'sign: Bob <bob@example.com>'
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+$ git interpret-trailers --trailer 'sign: Alice <alice@example.com>' --trailer 'sign: Bob <bob@example.com>' <msg.txt
subject
-message
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Signed-off-by: Alice <alice@example.com>
Signed-off-by: Bob <bob@example.com>
------------
-* Use the `--in-place` option to edit a message file in place:
+* Use the `--in-place` option to edit a commit message file in place:
+
------------
$ cat msg.txt
subject
-message
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Signed-off-by: Bob <bob@example.com>
$ git interpret-trailers --trailer 'Acked-by: Alice <alice@example.com>' --in-place msg.txt
$ cat msg.txt
subject
-message
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Signed-off-by: Bob <bob@example.com>
Acked-by: Alice <alice@example.com>
@@ -322,17 +342,30 @@ $ git interpret-trailers --trailer 'Cc: Alice <alice@example.com>' --trailer 'Re
'Signed-off-by: ' already, and show how it works:
+
------------
+$ cat msg1.txt
+subject
+
+message
$ git config trailer.sign.key "Signed-off-by: "
$ git config trailer.sign.ifmissing add
$ git config trailer.sign.ifexists doNothing
-$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'
-$ git interpret-trailers <<EOF
-> EOF
+$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"'
+$ git interpret-trailers --trailer sign <msg1.txt
+subject
+
+message
Signed-off-by: Bob <bob@example.com>
-$ git interpret-trailers <<EOF
-> Signed-off-by: Alice <alice@example.com>
-> EOF
+$ cat msg2.txt
+subject
+
+message
+
+Signed-off-by: Alice <alice@example.com>
+$ git interpret-trailers --trailer sign <msg2.txt
+subject
+
+message
Signed-off-by: Alice <alice@example.com>
------------
@@ -357,18 +390,18 @@ Fix #42
$ cat ~/bin/glog-find-author
#!/bin/sh
test -n "$1" && git log --author="$1" --pretty="%an <%ae>" -1 || true
+$ cat msg.txt
+subject
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+
$ git config trailer.help.key "Helped-by: "
$ git config trailer.help.ifExists "addIfDifferentNeighbor"
$ git config trailer.help.cmd "~/bin/glog-find-author"
-$ git interpret-trailers --trailer="help:Junio" --trailer="help:Couder" <<EOF
-> subject
->
-> message
->
-> EOF
+$ git interpret-trailers --trailer="help:Junio" --trailer="help:Couder" <msg.txt
subject
-message
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Christian Couder <christian.couder@gmail.com>
@@ -382,18 +415,17 @@ Helped-by: Christian Couder <christian.couder@gmail.com>
$ cat ~/bin/glog-grep
#!/bin/sh
test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
+$ cat msg.txt
+subject
+
+message
$ git config trailer.ref.key "Reference-to: "
$ git config trailer.ref.ifExists "replace"
$ git config trailer.ref.cmd "~/bin/glog-grep"
-$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF
-> subject
->
-> message
->
-> EOF
+$ git interpret-trailers --trailer="ref:Add copyright notices." <msg.txt
subject
-message
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
------------
@@ -402,20 +434,23 @@ Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
commit that is related, and show how it works:
+
------------
+$ cat msg.txt
+subject
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+
+see: HEAD~2
+$ cat ~/bin/glog-ref
+#!/bin/sh
+git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14
$ git config trailer.see.key "See-also: "
$ git config trailer.see.ifExists "replace"
$ git config trailer.see.ifMissing "doNothing"
-$ git config trailer.see.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG"
-$ git interpret-trailers <<EOF
-> subject
->
-> message
->
-> see: HEAD~2
-> EOF
+$ git config trailer.see.cmd "glog-ref"
+$ git interpret-trailers --trailer=see <msg.txt
subject
-message
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
See-also: fe3187489d69c4 (subject of related commit)
------------
@@ -427,22 +462,21 @@ See-also: fe3187489d69c4 (subject of related commit)
to add a 'git-version' trailer:
+
------------
-$ sed -e 's/ Z$/ /' >commit_template.txt <<EOF
-> ***subject***
->
-> ***message***
->
-> Fixes: Z
-> Cc: Z
-> Reviewed-by: Z
-> Signed-off-by: Z
-> EOF
+$ cat temp.txt
+***subject***
+
+***message***
+
+Fixes: Z
+Cc: Z
+Reviewed-by: Z
+Signed-off-by: Z
+$ sed -e 's/ Z$/ /' temp.txt > commit_template.txt
$ git config commit.template commit_template.txt
-$ cat >.git/hooks/commit-msg <<EOF
-> #!/bin/sh
-> git interpret-trailers --trim-empty --trailer "git-version: \$(git describe)" "\$1" > "\$1.new"
-> mv "\$1.new" "\$1"
-> EOF
+$ cat .git/hooks/commit-msg
+#!/bin/sh
+git interpret-trailers --trim-empty --trailer "git-version: \$(git describe)" "\$1" > "\$1.new"
+mv "\$1.new" "\$1"
$ chmod +x .git/hooks/commit-msg
------------
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 1abdd3c21c..1bc0328bb7 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -270,8 +270,14 @@ interpolated. The following "fieldname" are understood:
objectmode::
The mode of the file which is recorded in the index.
+objecttype::
+ The object type of the file which is recorded in the index.
objectname::
The name of the file which is recorded in the index.
+objectsize[:padded]::
+ The object size of the file which is recorded in the index
+ ("-" if the object is a `commit` or `tree`).
+ It also supports a padded format of size with "%(objectsize:padded)".
stage::
The stage of the file which is recorded in the index.
eolinfo:index::
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index ff3da547dd..15313f2b10 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -96,27 +96,49 @@ OPTIONS
separator (so `bar` matches `refs/heads/bar` but not
`refs/heads/foobar`).
+OUTPUT
+------
+
+The output is in the format:
+
+------------
+<oid> TAB <ref> LF
+------------
+
+When `<ref>` is a tag, it may be followed by `^{}` to show its peeled
+representation.
+
EXAMPLES
--------
+* List all references (including symbolics and pseudorefs), peeling
+ tags:
++
+----
+$ git ls-remote
+27d43aaaf50ef0ae014b88bba294f93658016a2e HEAD
+950264636c68591989456e3ba0a5442f93152c1a refs/heads/main
+d9ab777d41f92a8c1684c91cfb02053d7dd1046b refs/heads/next
+d4ca2e3147b409459955613c152220f4db848ee1 refs/tags/v2.40.0
+73876f4861cd3d187a4682290ab75c9dccadbc56 refs/tags/v2.40.0^{}
----
-$ git ls-remote --tags .
-d6602ec5194c87b0fc87103ca4d67251c76f233a refs/tags/v0.99
-f25a265a342aed6041ab0cc484224d9ca54b6f41 refs/tags/v0.99.1
-7ceca275d047c90c0c7d5afb13ab97efdf51bd6e refs/tags/v0.99.3
-c5db5456ae3b0873fc659c19fafdde22313cc441 refs/tags/v0.99.2
-0918385dbd9656cab0d1d81ba7453d49bbc16250 refs/tags/junio-gpg-pub
+* List all references matching given patterns:
++
+----
$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master seen rc
5fe978a5381f1fbad26a80e682ddd2a401966740 refs/heads/master
c781a84b5204fb294c9ccc79f8b3baceeb32c061 refs/heads/seen
+----
-$ git remote add korg http://www.kernel.org/pub/scm/git/git.git
-$ git ls-remote --tags korg v\*
-d6602ec5194c87b0fc87103ca4d67251c76f233a refs/tags/v0.99
-f25a265a342aed6041ab0cc484224d9ca54b6f41 refs/tags/v0.99.1
-c5db5456ae3b0873fc659c19fafdde22313cc441 refs/tags/v0.99.2
-7ceca275d047c90c0c7d5afb13ab97efdf51bd6e refs/tags/v0.99.3
+* List only tags matching a given wildcard pattern:
++
+----
+$ git ls-remote --tags http://www.kernel.org/pub/scm/git/git.git v\*
+485a869c64a68cc5795dd99689797c5900f4716d refs/tags/v2.39.2
+cbf04937d5b9fcf0a76c28f69e6294e9e3ecd7e6 refs/tags/v2.39.2^{}
+d4ca2e3147b409459955613c152220f4db848ee1 refs/tags/v2.40.0
+73876f4861cd3d187a4682290ab75c9dccadbc56 refs/tags/v2.40.0^{}
----
SEE ALSO
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index 88ee942101..ffc4fbf7e8 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -108,7 +108,7 @@ This is an integer status followed by a NUL character. The integer status is:
0: merge had conflicts
1: merge was clean
- &lt;0: something prevented the merge from running (e.g. access to repository
+ <0: something prevented the merge from running (e.g. access to repository
objects denied by filesystem)
[[OIDTLT]]
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 0aeff572a5..3f61389c1c 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -194,9 +194,13 @@ happens:
versions: stage 1 stores the version from the common ancestor,
stage 2 from `HEAD`, and stage 3 from `MERGE_HEAD` (you
can inspect the stages with `git ls-files -u`). The working
- tree files contain the result of the "merge" program; i.e. 3-way
+ tree files contain the result of the merge operation; i.e. 3-way
merge results with familiar conflict markers `<<<` `===` `>>>`.
-5. No other changes are made. In particular, the local
+5. A special ref `AUTO_MERGE` is written, pointing to a tree corresponding
+ to the current content of the working tree (including conflict markers).
+ Note that this ref is only written when the 'ort' merge strategy
+ is used (the default).
+6. No other changes are made. In particular, the local
modifications you had before you started merge will stay the
same and the index entries for them stay as they were,
i.e. matching `HEAD`.
@@ -336,7 +340,8 @@ You can work through the conflict with a number of tools:
* Look at the diffs. `git diff` will show a three-way diff,
highlighting changes from both the `HEAD` and `MERGE_HEAD`
- versions.
+ versions. `git diff AUTO_MERGE` will show what changes you've
+ made so far to resolve conlicts.
* Look at the diffs from each branch. `git log --merge -p <path>`
will show diffs first for the `HEAD` version and then the
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
index c44e205629..07535f6576 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.txt
@@ -85,12 +85,13 @@ success of the resolution after the custom tool has exited.
the default merge tool will be read from the configured
`merge.guitool` variable instead of `merge.tool`. If
`merge.guitool` is not set, we will fallback to the tool
- configured under `merge.tool`.
+ configured under `merge.tool`. This may be autoselected using
+ the configuration variable `mergetool.guiDefault`.
--no-gui::
- This overrides a previous `-g` or `--gui` setting and reads the
- default merge tool will be read from the configured `merge.tool`
- variable.
+ This overrides a previous `-g` or `--gui` setting or
+ `mergetool.guiDefault` configuration and reads the default merge
+ tool from the configured `merge.tool` variable.
-O<orderfile>::
Process files in the order specified in the
diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index ec8a27ce8b..5c56c87025 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git name-rev' [--tags] [--refs=<pattern>]
- ( --all | --stdin | <commit-ish>... )
+ ( --all | --annotate-stdin | <commit-ish>... )
DESCRIPTION
-----------
@@ -46,7 +46,8 @@ OPTIONS
Transform stdin by substituting all the 40-character SHA-1
hexes (say $hex) with "$hex ($rev_name)". When used with
--name-only, substitute with "$rev_name", omitting $hex
- altogether.
+ altogether. This option was called `--stdin` in older versions
+ of Git.
+
For example:
+
@@ -70,10 +71,6 @@ The full name after substitution is master,
while its tree object is 70d105cc79e63b81cfdcb08a15297c23e60b07ad
-----------
---stdin::
- This option is deprecated in favor of 'git name-rev --annotate-stdin'.
- They are functionally equivalent.
-
--name-only::
Instead of printing both the SHA-1 and the name, print only
the name. If given with --tags the usual tag prefix of
@@ -107,7 +104,7 @@ Now you are wiser, because you know that it happened 940 revisions before v0.99.
Another nice thing you can do is:
------------
-% git log | git name-rev --stdin
+% git log | git name-rev --annotate-stdin
------------
GIT
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index efbc10f0f5..5f3a9479a9 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -9,10 +9,10 @@ SYNOPSIS
--------
[verse]
'git notes' [list [<object>]]
-'git notes' add [-f] [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' add [-f] [--allow-empty] [--separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
'git notes' copy [-f] ( --stdin | <from-object> [<to-object>] )
-'git notes' append [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
-'git notes' edit [--allow-empty] [<object>]
+'git notes' append [--allow-empty] [--separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' edit [--allow-empty] [<object>] [--[no-]stripspace]
'git notes' show [<object>]
'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
'git notes' merge --commit [-v | -q]
@@ -65,7 +65,9 @@ add::
However, if you're using `add` interactively (using an editor
to supply the notes contents), then - instead of aborting -
the existing notes will be opened in the editor (like the `edit`
- subcommand).
+ subcommand). If you specify multiple `-m` and `-F`, a blank
+ line will be inserted between the messages. Use the `--separator`
+ option to insert other delimiters.
copy::
Copy the notes for the first object onto the second object (defaults to
@@ -85,8 +87,12 @@ corresponding <to-object>. (The optional `<rest>` is ignored so that
the command can read the input given to the `post-rewrite` hook.)
append::
- Append to the notes of an existing object (defaults to HEAD).
- Creates a new notes object if needed.
+ Append new message(s) given by `-m` or `-F` options to an
+ existing note, or add them as a new note if one does not
+ exist, for the object (defaults to HEAD). When appending to
+ an existing note, a blank line is added before each new
+ message as an inter-paragraph separator. The separator can
+ be customized with the `--separator` option.
edit::
Edit the notes for a given object (defaults to HEAD).
@@ -135,20 +141,26 @@ OPTIONS
If multiple `-m` options are given, their values
are concatenated as separate paragraphs.
Lines starting with `#` and empty lines other than a
- single line between paragraphs will be stripped out.
+ single line between paragraphs will be stripped out,
+ if you wish to keep them verbatim, use `--no-stripspace`.
-F <file>::
--file=<file>::
Take the note message from the given file. Use '-' to
read the note message from the standard input.
Lines starting with `#` and empty lines other than a
- single line between paragraphs will be stripped out.
+ single line between paragraphs will be stripped out,
+ if you wish to keep them verbatim, use with
+ `--no-stripspace` option.
-C <object>::
--reuse-message=<object>::
Take the given blob object (for example, another note) as the
note message. (Use `git notes copy <object>` instead to
- copy notes between objects.)
+ copy notes between objects.). By default, message will be
+ copied verbatim, but if you wish to strip out the lines
+ starting with `#` and empty lines other than a single line
+ between paragraphs, use with`--stripspace` option.
-c <object>::
--reedit-message=<object>::
@@ -159,6 +171,18 @@ OPTIONS
Allow an empty note object to be stored. The default behavior is
to automatically remove empty notes.
+--separator <paragraph-break>::
+ Specify a string used as a custom inter-paragraph separator
+ (a newline is added at the end as needed). Defaults to a
+ blank line.
+
+--[no-]stripspace::
+ Strip leading and trailing whitespace from the note message.
+ Also strip out empty lines other than a single line between
+ paragraphs. For lines starting with `#` will be stripped out
+ in non-editor cases like "-m", "-F" and "-C", but not in
+ editor case like "git notes edit", "-c", etc.
+
--ref <ref>::
Manipulate the notes tree in <ref>. This overrides
`GIT_NOTES_REF` and the "core.notesRef" configuration. The ref
diff --git a/Documentation/git-pack-redundant.txt b/Documentation/git-pack-redundant.txt
index 99ef13839d..13c3eb5ec9 100644
--- a/Documentation/git-pack-redundant.txt
+++ b/Documentation/git-pack-redundant.txt
@@ -11,6 +11,20 @@ SYNOPSIS
[verse]
'git pack-redundant' [--verbose] [--alt-odb] (--all | <pack-filename>...)
+WARNING
+-------
+`git pack-redundant` has been deprecated and is scheduled for removal in
+a future version of Git. Because it can only remove entire duplicate
+packs and not individual duplicate objects, it is generally not a useful
+tool for reducing repository size. You are better off using `git gc` to
+do so, which will put objects into a new pack, removing duplicates.
+
+Running `pack-redundant` without the `--i-still-use-this` flag will fail
+in this release. If you believe you have a use case for which
+`pack-redundant` is better suited and oppose this removal, please
+contact the Git mailing list at git@vger.kernel.org. More information
+about the list is available at https://git-scm.com/community.
+
DESCRIPTION
-----------
This program computes which packs in your repository
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 5bb1d5aae2..297927d866 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
SYNOPSIS
--------
[verse]
-'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
+'git push' [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
[-u | --set-upstream] [-o <string> | --push-option=<string>]
[--[no-]signed|--signed=(true|false|if-asked)]
@@ -147,6 +147,7 @@ already exists on the remote side.
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
--all::
+--branches::
Push all branches (i.e. refs under `refs/heads/`); cannot be
used with other <refspec>.
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 9a295bcee4..e7b39ad244 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -529,20 +529,25 @@ See also INCOMPATIBLE OPTIONS below.
-r::
--rebase-merges[=(rebase-cousins|no-rebase-cousins)]::
+--no-rebase-merges::
By default, a rebase will simply drop merge commits from the todo
list, and put the rebased commits into a single, linear branch.
With `--rebase-merges`, the rebase will instead try to preserve
the branching structure within the commits that are to be rebased,
by recreating the merge commits. Any resolved merge conflicts or
manual amendments in these merge commits will have to be
- resolved/re-applied manually.
+ resolved/re-applied manually. `--no-rebase-merges` can be used to
+ countermand both the `rebase.rebaseMerges` config option and a previous
+ `--rebase-merges`.
+
-By default, or when `no-rebase-cousins` was specified, commits which do not
-have `<upstream>` as direct ancestor will keep their original branch point,
-i.e. commits that would be excluded by linkgit:git-log[1]'s
-`--ancestry-path` option will keep their original ancestry by default. If
-the `rebase-cousins` mode is turned on, such commits are instead rebased
-onto `<upstream>` (or `<onto>`, if specified).
+When rebasing merges, there are two modes: `rebase-cousins` and
+`no-rebase-cousins`. If the mode is not specified, it defaults to
+`no-rebase-cousins`. In `no-rebase-cousins` mode, commits which do not have
+`<upstream>` as direct ancestor will keep their original branch point, i.e.
+commits that would be excluded by linkgit:git-log[1]'s `--ancestry-path`
+option will keep their original ancestry by default. In `rebase-cousins` mode,
+such commits are instead rebased onto `<upstream>` (or `<onto>`, if
+specified).
+
It is currently only possible to recreate the merge commits using the
`ort` merge strategy; different merge strategies can be used only via
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index bcd8069287..f26a7591e3 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -197,10 +197,11 @@ respectively, and they must begin with `refs/` when applied to `--glob`
or `--all`. If a trailing '/{asterisk}' is intended, it must be given
explicitly.
---exclude-hidden=[receive|uploadpack]::
- Do not include refs that would be hidden by `git-receive-pack` or
- `git-upload-pack` by consulting the appropriate `receive.hideRefs` or
- `uploadpack.hideRefs` configuration along with `transfer.hideRefs` (see
+--exclude-hidden=[fetch|receive|uploadpack]::
+ Do not include refs that would be hidden by `git-fetch`,
+ `git-receive-pack` or `git-upload-pack` by consulting the appropriate
+ `fetch.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs`
+ configuration along with `transfer.hideRefs` (see
linkgit:git-config[1]). This option affects the next pseudo-ref option
`--all` or `--glob` and is cleared after processing them.
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 765b2df853..492a82323d 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -93,7 +93,7 @@ See the CONFIGURATION section for `sendemail.multiEdit`.
--in-reply-to=<identifier>::
Make the first mail (or all the mails with `--no-thread`) appear as a
- reply to the given Message-Id, which avoids breaking threads to
+ reply to the given Message-ID, which avoids breaking threads to
provide a new patch series.
The second and subsequent emails will be sent as replies according to
the `--[no-]chain-reply-to` setting.
@@ -320,6 +320,17 @@ Automating
Output of this command must be single email address per line.
Default is the value of `sendemail.ccCmd` configuration value.
+--header-cmd=<command>::
+ Specify a command that is executed once per outgoing message
+ and output RFC 2822 style header lines to be inserted into
+ them. When the `sendemail.headerCmd` configuration variable is
+ set, its value is always used. When --header-cmd is provided
+ at the command line, its value takes precedence over the
+ `sendemail.headerCmd` configuration variable.
+
+--no-header-cmd::
+ Disable any header command in use.
+
--[no-]chain-reply-to::
If this is set, each email will be sent as a reply to the previous
email sent. If disabled with "--no-chain-reply-to", all emails after
@@ -484,14 +495,10 @@ edit ~/.gitconfig to specify your account settings:
smtpServerPort = 587
----
-If you have multi-factor authentication set up on your Gmail account, you will
-need to generate an app-specific password for use with 'git send-email'. Visit
+If you have multi-factor authentication set up on your Gmail account, you can
+generate an app-specific password for use with 'git send-email'. Visit
https://security.google.com/settings/security/apppasswords to create it.
-If you do not have multi-factor authentication set up on your Gmail account,
-you will need to allow less secure app access. Visit
-https://myaccount.google.com/lesssecureapps to enable it.
-
Once your commits are ready to be sent to the mailing list, run the
following commands:
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index 71f608b1ff..58cf6210cd 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -74,8 +74,7 @@ OPTIONS
that is the common ancestor of all the branches. This
flag tells the command to go <n> more common commits
beyond that. When <n> is negative, display only the
- <reference>s given, without showing the commit ancestry
- tree.
+ <ref>s given, without showing the commit ancestry tree.
--list::
Synonym to `--more=-1`
@@ -88,8 +87,8 @@ OPTIONS
the case of three or more commits.
--independent::
- Among the <reference>s given, display only the ones that
- cannot be reached from any other <reference>.
+ Among the <ref>s given, display only the ones that cannot be
+ reached from any other <ref>.
--no-name::
Do not show naming strings for each commit.
@@ -132,10 +131,11 @@ are mutually exclusive.
OUTPUT
------
-Given N <references>, the first N lines are the one-line
-description from their commit message. The branch head that is
-pointed at by $GIT_DIR/HEAD is prefixed with an asterisk `*`
-character while other heads are prefixed with a `!` character.
+
+Given N <ref>s, the first N lines are the one-line description from
+their commit message. The branch head that is pointed at by
+$GIT_DIR/HEAD is prefixed with an asterisk `*` character while other
+heads are prefixed with a `!` character.
Following these N lines, one-line log for each commit is
displayed, indented N places. If a commit is on the I-th
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index d1d56f68b4..be048bf181 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -23,7 +23,7 @@ particular ref exists.
By default, shows the tags, heads, and remote refs.
-The --exclude-existing form is a filter that does the inverse. It reads
+The `--exclude-existing` form is a filter that does the inverse. It reads
refs from stdin, one ref per line, and shows those that don't exist in
the local repository.
@@ -47,14 +47,14 @@ OPTIONS
-d::
--dereference::
- Dereference tags into object IDs as well. They will be shown with "{caret}{}"
+ Dereference tags into object IDs as well. They will be shown with `{caret}{}`
appended.
-s::
--hash[=<n>]::
- Only show the SHA-1 hash, not the reference name. When combined with
- --dereference the dereferenced tag will still be shown after the SHA-1.
+ Only show the OID, not the reference name. When combined with
+ `--dereference`, the dereferenced tag will still be shown after the OID.
--verify::
@@ -70,15 +70,15 @@ OPTIONS
-q::
--quiet::
- Do not print any results to stdout. When combined with `--verify` this
+ Do not print any results to stdout. When combined with `--verify`, this
can be used to silently check if a reference exists.
--exclude-existing[=<pattern>]::
- Make 'git show-ref' act as a filter that reads refs from stdin of the
- form "`^(?:<anything>\s)?<refname>(?:\^{})?$`"
+ Make `git show-ref` act as a filter that reads refs from stdin of the
+ form `^(?:<anything>\s)?<refname>(?:\^{})?$`
and performs the following actions on each:
- (1) strip "{caret}{}" at the end of line if any;
+ (1) strip `{caret}{}` at the end of line if any;
(2) ignore if pattern is provided and does not head-match refname;
(3) warn if refname is not a well-formed refname and skip;
(4) ignore if refname is a ref that exists in the local repository;
@@ -96,7 +96,13 @@ OPTIONS
OUTPUT
------
-The output is in the format: '<SHA-1 ID>' '<space>' '<reference name>'.
+The output is in the format:
+
+------------
+<oid> SP <ref> LF
+------------
+
+For example,
-----------------------------------------------------------------------------
$ git show-ref --head --dereference
@@ -110,7 +116,13 @@ $ git show-ref --head --dereference
...
-----------------------------------------------------------------------------
-When using --hash (and not --dereference) the output format is: '<SHA-1 ID>'
+When using `--hash` (and not `--dereference`), the output is in the format:
+
+------------
+<OID> LF
+------------
+
+For example,
-----------------------------------------------------------------------------
$ git show-ref --heads --hash
@@ -142,10 +154,10 @@ When using the `--verify` flag, the command requires an exact path:
will only match the exact branch called "master".
-If nothing matches, 'git show-ref' will return an error code of 1,
+If nothing matches, `git show-ref` will return an error code of 1,
and in the case of verification, it will show an error message.
-For scripting, you can ask it to be quiet with the "--quiet" flag, which
+For scripting, you can ask it to be quiet with the `--quiet` flag, which
allows you to do things like
-----------------------------------------------------------------------------
@@ -157,11 +169,11 @@ to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for it
in order to not trigger the problem with ambiguous partial matches).
-To show only tags, or only proper branch heads, use "--tags" and/or "--heads"
+To show only tags, or only proper branch heads, use `--tags` and/or `--heads`
respectively (using both means that it shows tags and heads, but not other
random references under the refs/ subdirectory).
-To do automatic tag object dereferencing, use the "-d" or "--dereference"
+To do automatic tag object dereferencing, use the `-d` or `--dereference`
flag, so you can do
-----------------------------------------------------------------------------
diff --git a/Documentation/git-sparse-checkout.txt b/Documentation/git-sparse-checkout.txt
index 68392d2a56..53dc17aa77 100644
--- a/Documentation/git-sparse-checkout.txt
+++ b/Documentation/git-sparse-checkout.txt
@@ -9,7 +9,7 @@ git-sparse-checkout - Reduce your working tree to a subset of tracked files
SYNOPSIS
--------
[verse]
-'git sparse-checkout' (init | list | set | add | reapply | disable) [<options>]
+'git sparse-checkout' (init | list | set | add | reapply | disable | check-rules) [<options>]
DESCRIPTION
@@ -135,6 +135,29 @@ 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.
+'check-rules'::
+ Check whether sparsity rules match one or more paths.
++
+By default `check-rules` reads a list of paths from stdin and outputs only
+the ones that match the current sparsity rules. The input is expected to consist
+of one path per line, matching the output of `git ls-tree --name-only` including
+that pathnames that begin with a double quote (") are interpreted as C-style
+quoted strings.
++
+When called with the `--rules-file <file>` flag the input files are matched
+against the sparse checkout rules found in `<file>` instead of the current ones.
+The rules in the files are expected to be in the same form as accepted by `git
+sparse-checkout set --stdin` (in particular, they must be newline-delimited).
++
+By default, the rules passed to the `--rules-file` option are interpreted as
+cone mode directories. To pass non-cone mode patterns with `--rules-file`,
+combine the option with the `--no-cone` option.
++
+When called with the `-z` flag, the format of the paths input on stdin as well
+as the output paths are \0 terminated and not quoted. Note that this does not
+apply to the format of the rules passed with the `--rules-file` option.
+
+
EXAMPLES
--------
`git sparse-checkout set MY/DIR1 SUB/DIR2`::
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index fdc72b5875..d42efb3112 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -131,6 +131,10 @@ options for details.
--ignore-case::
Sorting and filtering tags are case insensitive.
+--omit-empty::
+ Do not print a newline after formatted refs where the format expands
+ to the empty string.
+
--column[=<options>]::
--no-column::
Display tag listing in columns. See configuration variable
@@ -377,6 +381,16 @@ $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
include::date-formats.txt[]
+FILES
+-----
+
+`$GIT_DIR/TAG_EDITMSG`::
+ This file contains the message of an in-progress annotated
+ tag. If `git tag` exits due to an error before creating an
+ annotated tag then the tag message that has been provided by the
+ user in an editor session will be available in this file, but
+ may be overwritten by the next invocation of `git tag`.
+
NOTES
-----
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 063d6eeb99..a4fbf5e838 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>]
+ [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]
'git worktree list' [-v | --porcelain [-z]]
'git worktree lock' [--reason <string>] <worktree>
'git worktree move' <worktree> <new-path>
@@ -95,6 +95,16 @@ exist, a new branch based on `HEAD` is automatically created as if
`-b <branch>` was given. If `<branch>` does exist, it will be checked out
in the new worktree, if it's not checked out anywhere else, otherwise the
command will refuse to create the worktree (unless `--force` is used).
++
+If `<commit-ish>` is omitted, neither `--detach`, or `--orphan` is
+used, and there are no valid local branches (or remote branches if
+`--guess-remote` is specified) then, as a convenience, the new worktree is
+associated with a new orphan branch named `<branch>` (after
+`$(basename <path>)` if neither `-b` or `-B` is used) as if `--orphan` was
+passed to the command. In the event the repository has a remote and
+`--guess-remote` is used, but no remote or local branches exist, then the
+command fails with a warning reminding the user to fetch from their remote
+first (or override by using `-f/--force`).
list::
@@ -222,6 +232,10 @@ This can also be set up as the default behaviour by using the
With `prune`, do not remove anything; just report what it would
remove.
+--orphan::
+ With `add`, make the new worktree and index empty, associating
+ the worktree with a new orphan/unborn branch named `<new-branch>`.
+
--porcelain::
With `list`, output in an easy-to-parse format for scripts.
This format will remain stable across Git versions and regardless of user
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 74973d3cc4..f0cafa2290 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -212,6 +212,11 @@ If you just want to run git as if it was started in `<path>` then use
nohelpers (exclude helper commands), alias and config
(retrieve command list from config variable completion.commands)
+--attr-source=<tree-ish>::
+ Read gitattributes from <tree-ish> instead of the worktree. See
+ linkgit:gitattributes[5]. This is equivalent to setting the
+ `GIT_ATTR_SOURCE` environment variable.
+
GIT COMMANDS
------------
@@ -546,9 +551,9 @@ double-quotes and respecting backslash escapes. E.g., the value
`GIT_DEFAULT_HASH`::
If this variable is set, the default hash algorithm for new
- repositories will be set to this value. This value is currently
- ignored when cloning; the setting of the remote repository
- is used instead. The default is "sha1". THIS VARIABLE IS
+ repositories will be set to this value. This value is
+ ignored when cloning and the setting of the remote repository
+ is always used. The default is "sha1". THIS VARIABLE IS
EXPERIMENTAL! See `--object-format` in linkgit:git-init[1].
Git Commits
@@ -686,6 +691,9 @@ for further details.
tells Git not to verify the SSL certificate when fetching or
pushing over HTTPS.
+`GIT_ATTR_SOURCE`::
+ Sets the treeish that gitattributes will be read from.
+
`GIT_ASKPASS`::
If this environment variable is set, then Git commands which need to
acquire passwords or passphrases (e.g. for HTTP or IMAP authentication)
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 39bfbca1ff..02a3ec83e4 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -120,20 +120,19 @@ repository upon 'git add' and 'git commit'.
`text`
^^^^^^
-This attribute enables and controls end-of-line normalization. When a
-text file is normalized, its line endings are converted to LF in the
-repository. To control what line ending style is used in the working
-directory, use the `eol` attribute for a single file and the
-`core.eol` configuration variable for all text files.
-Note that setting `core.autocrlf` to `true` or `input` overrides
-`core.eol` (see the definitions of those options in
-linkgit:git-config[1]).
+This attribute marks the path as a text file, which enables end-of-line
+conversion: When a matching file is added to the index, the file's line
+endings are normalized to LF in the index. Conversely, when the file is
+copied from the index to the working directory, its line endings may be
+converted from LF to CRLF depending on the `eol` attribute, the Git
+config, and the platform (see explanation of `eol` below).
Set::
Setting the `text` attribute on a path enables end-of-line
- normalization and marks the path as a text file. End-of-line
- conversion takes place without guessing the content type.
+ conversion on checkin and checkout as described above. Line endings
+ are normalized to LF in the index every time the file is checked in,
+ even if the file was previously added to Git with CRLF line endings.
Unset::
@@ -142,10 +141,11 @@ Unset::
Set to string value "auto"::
- When `text` is set to "auto", the path is marked for automatic
- end-of-line conversion. If Git decides that the content is
- text, its line endings are converted to LF on checkin.
- When the file has been committed with CRLF, no conversion is done.
+ When `text` is set to "auto", Git decides by itself whether the file
+ is text or binary. If it is text and the file was not already in
+ Git with CRLF endings, line endings are converted on checkin and
+ checkout as described above. Otherwise, no conversion is done on
+ checkin or checkout.
Unspecified::
@@ -159,26 +159,29 @@ unspecified.
`eol`
^^^^^
-This attribute sets a specific line-ending style to be used in the
-working directory. This attribute has effect only if the `text`
-attribute is set or unspecified, or if it is set to `auto`, the file is
-detected as text, and it is stored with LF endings in the index. Note
-that setting this attribute on paths which are in the index with CRLF
-line endings may make the paths to be considered dirty unless
-`text=auto` is set. Adding the path to the index again will normalize
-the line endings in the index.
+This attribute marks a path to use a specific line-ending style in the
+working tree when it is checked out. It has effect only if `text` or
+`text=auto` is set (see above), but specifying `eol` automatically sets
+`text` if `text` was left unspecified.
Set to string value "crlf"::
- This setting forces Git to normalize line endings for this
- file on checkin and convert them to CRLF when the file is
- checked out.
+ This setting converts the file's line endings in the working
+ directory to CRLF when the file is checked out.
Set to string value "lf"::
- This setting forces Git to normalize line endings to LF on
- checkin and prevents conversion to CRLF when the file is
- checked out.
+ This setting uses the same line endings in the working directory as
+ in the index when the file is checked out.
+
+Unspecified::
+
+ If the `eol` attribute is unspecified for a file, its line endings
+ in the working directory are determined by the `core.autocrlf` or
+ `core.eol` configuration variable (see the definitions of those
+ options in linkgit:git-config[1]). If `text` is set but neither of
+ those variables is, the default is `eol=crlf` on Windows and
+ `eol=lf` on all other platforms.
Backwards compatibility with `crlf` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Documentation/gitformat-pack.txt b/Documentation/gitformat-pack.txt
index e06af02f21..0c1be2dbe8 100644
--- a/Documentation/gitformat-pack.txt
+++ b/Documentation/gitformat-pack.txt
@@ -611,8 +611,8 @@ 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.
+setting the `gc.cruftPacks` configuration to "false" until all writers
+understand cruft packs.
=== Alternatives
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 62908602e7..86f804720a 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -595,10 +595,51 @@ processed by rebase.
sendemail-validate
~~~~~~~~~~~~~~~~~~
-This hook is invoked by linkgit:git-send-email[1]. It takes a single parameter,
-the name of the file that holds the e-mail to be sent. Exiting with a
-non-zero status causes `git send-email` to abort before sending any
-e-mails.
+This hook is invoked by linkgit:git-send-email[1].
+
+It takes these command line arguments. They are,
+1. the name of the file which holds the contents of the email to be sent.
+2. The name of the file which holds the SMTP headers of the email.
+
+The SMTP headers are passed in the exact same way as they are passed to the
+user's Mail Transport Agent (MTA). In effect, the email given to the user's
+MTA, is the contents of $2 followed by the contents of $1.
+
+An example of a few common headers is shown below. Take notice of the
+capitalization and multi-line tab structure.
+
+ From: Example <from@example.com>
+ To: to@example.com
+ Cc: cc@example.com,
+ A <author@example.com>,
+ One <one@example.com>,
+ two@example.com
+ Subject: PATCH-STRING
+
+Exiting with a non-zero status causes `git send-email` to abort
+before sending any e-mails.
+
+The following environment variables are set when executing the hook.
+
+`GIT_SENDEMAIL_FILE_COUNTER`::
+ A 1-based counter incremented by one for every file holding an e-mail
+ to be sent (excluding any FIFOs). This counter does not follow the
+ patch series counter scheme. It will always start at 1 and will end at
+ GIT_SENDEMAIL_FILE_TOTAL.
+
+`GIT_SENDEMAIL_FILE_TOTAL`::
+ The total number of files that will be sent (excluding any FIFOs). This
+ counter does not follow the patch series counter scheme. It will always
+ be equal to the number of files being sent, whether there is a cover
+ letter or not.
+
+These variables may for instance be used to validate patch series.
+
+The sample `sendemail-validate` hook that comes with Git checks that all sent
+patches (excluding the cover letter) can be applied on top of the upstream
+repository default branch without conflicts. Some placeholders are left for
+additional validation steps to be performed after all patches of a given series
+have been applied.
fsmonitor-watchman
~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index f2738b10db..4c17f2356c 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -146,7 +146,9 @@ The purpose of gitignore files is to ensure that certain files
not tracked by Git remain untracked.
To stop tracking a file that is currently tracked, use
-'git rm --cached'.
+'git rm --cached' to remove the file from the index. The filename
+can then be added to the `.gitignore` file to stop the file from
+being reintroduced in later commits.
Git does not follow symbolic links when accessing a `.gitignore` file in
the working tree. This keeps behavior consistent when the file is
diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt
index 0e0b863105..c7cadd8aaf 100644
--- a/Documentation/gittutorial.txt
+++ b/Documentation/gittutorial.txt
@@ -49,7 +49,7 @@ $ git config --global user.email you@yourdomain.example.com
Importing a new project
-----------------------
-Assume you have a tarball project.tar.gz with your initial work. You
+Assume you have a tarball `project.tar.gz` with your initial work. You
can place it under Git revision control as follows.
------------------------------------------------
@@ -65,10 +65,10 @@ Initialized empty Git repository in .git/
------------------------------------------------
You've now initialized the working directory--you may notice a new
-directory created, named ".git".
+directory created, named `.git`.
Next, tell Git to take a snapshot of the contents of all files under the
-current directory (note the '.'), with 'git add':
+current directory (note the `.`), with `git add`:
------------------------------------------------
$ git add .
@@ -76,7 +76,7 @@ $ git add .
This snapshot is now stored in a temporary staging area which Git calls
the "index". You can permanently store the contents of the index in the
-repository with 'git commit':
+repository with `git commit`:
------------------------------------------------
$ git commit
@@ -95,21 +95,20 @@ $ git add file1 file2 file3
------------------------------------------------
You are now ready to commit. You can see what is about to be committed
-using 'git diff' with the --cached option:
+using `git diff` with the `--cached` option:
------------------------------------------------
$ git diff --cached
------------------------------------------------
-(Without --cached, 'git diff' will show you any changes that
+(Without `--cached`, `git diff` will show you any changes that
you've made but not yet added to the index.) You can also get a brief
-summary of the situation with 'git status':
+summary of the situation with `git status`:
------------------------------------------------
$ git status
On branch master
Changes to be committed:
-Your branch is up to date with 'origin/master'.
(use "git restore --staged <file>..." to unstage)
modified: file1
@@ -128,7 +127,7 @@ $ git commit
This will again prompt you for a message describing the change, and then
record a new version of the project.
-Alternatively, instead of running 'git add' beforehand, you can use
+Alternatively, instead of running `git add` beforehand, you can use
------------------------------------------------
$ git commit -a
@@ -151,7 +150,7 @@ Git tracks content not files
Many revision control systems provide an `add` command that tells the
system to start tracking changes to a new file. Git's `add` command
-does something simpler and more powerful: 'git add' is used both for new
+does something simpler and more powerful: `git add` is used both for new
and newly modified files, and in both cases it takes a snapshot of the
given files and stages that content in the index, ready for inclusion in
the next commit.
@@ -182,7 +181,7 @@ Managing branches
-----------------
A single Git repository can maintain multiple branches of
-development. To create a new branch named "experimental", use
+development. To create a new branch named `experimental`, use
------------------------------------------------
$ git branch experimental
@@ -201,8 +200,8 @@ you'll get a list of all existing branches:
* master
------------------------------------------------
-The "experimental" branch is the one you just created, and the
-"master" branch is a default branch that was created for you
+The `experimental` branch is the one you just created, and the
+`master` branch is a default branch that was created for you
automatically. The asterisk marks the branch you are currently on;
type
@@ -210,8 +209,8 @@ type
$ git switch experimental
------------------------------------------------
-to switch to the experimental branch. Now edit a file, commit the
-change, and switch back to the master branch:
+to switch to the `experimental` branch. Now edit a file, commit the
+change, and switch back to the `master` branch:
------------------------------------------------
(edit file)
@@ -220,9 +219,9 @@ $ git switch master
------------------------------------------------
Check that the change you made is no longer visible, since it was
-made on the experimental branch and you're back on the master branch.
+made on the `experimental` branch and you're back on the `master` branch.
-You can make a different change on the master branch:
+You can make a different change on the `master` branch:
------------------------------------------------
(edit file)
@@ -230,7 +229,7 @@ $ git commit -a
------------------------------------------------
at this point the two branches have diverged, with different changes
-made in each. To merge the changes made in experimental into master, run
+made in each. To merge the changes made in `experimental` into `master`, run
------------------------------------------------
$ git merge experimental
@@ -258,16 +257,16 @@ $ gitk
will show a nice graphical representation of the resulting history.
-At this point you could delete the experimental branch with
+At this point you could delete the `experimental` branch with
------------------------------------------------
$ git branch -d experimental
------------------------------------------------
-This command ensures that the changes in the experimental branch are
+This command ensures that the changes in the `experimental` branch are
already in the current branch.
-If you develop on a branch crazy-idea, then regret it, you can always
+If you develop on a branch `crazy-idea`, then regret it, you can always
delete the branch with
-------------------------------------
@@ -281,7 +280,7 @@ Using Git for collaboration
---------------------------
Suppose that Alice has started a new project with a Git repository in
-/home/alice/project, and that Bob, who has a home directory on the
+`/home/alice/project`, and that Bob, who has a home directory on the
same machine, wants to contribute.
Bob begins with:
@@ -290,7 +289,7 @@ Bob begins with:
bob$ git clone /home/alice/project myrepo
------------------------------------------------
-This creates a new directory "myrepo" containing a clone of Alice's
+This creates a new directory `myrepo` containing a clone of Alice's
repository. The clone is on an equal footing with the original
project, possessing its own copy of the original project's history.
@@ -303,31 +302,31 @@ bob$ git commit -a
------------------------------------------------
When he's ready, he tells Alice to pull changes from the repository
-at /home/bob/myrepo. She does this with:
+at `/home/bob/myrepo`. She does this with:
------------------------------------------------
alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master
------------------------------------------------
-This merges the changes from Bob's "master" branch into Alice's
+This merges the changes from Bob's `master` branch into Alice's
current branch. If Alice has made her own changes in the meantime,
then she may need to manually fix any conflicts.
-The "pull" command thus performs two operations: it fetches changes
+The `pull` command thus performs two operations: it fetches changes
from a remote branch, then merges them into the current branch.
Note that in general, Alice would want her local changes committed before
-initiating this "pull". If Bob's work conflicts with what Alice did since
+initiating this `pull`. If Bob's work conflicts with what Alice did since
their histories forked, Alice will use her working tree and the index to
resolve conflicts, and existing local changes will interfere with the
conflict resolution process (Git will still perform the fetch but will
refuse to merge -- Alice will have to get rid of her local changes in
some way and pull again when this happens).
-Alice can peek at what Bob did without merging first, using the "fetch"
+Alice can peek at what Bob did without merging first, using the `fetch`
command; this allows Alice to inspect what Bob did, using a special
-symbol "FETCH_HEAD", in order to determine if he has anything worth
+symbol `FETCH_HEAD`, in order to determine if he has anything worth
pulling, like this:
------------------------------------------------
@@ -336,10 +335,10 @@ alice$ git log -p HEAD..FETCH_HEAD
------------------------------------------------
This operation is safe even if Alice has uncommitted local changes.
-The range notation "HEAD..FETCH_HEAD" means "show everything that is reachable
-from the FETCH_HEAD but exclude anything that is reachable from HEAD".
-Alice already knows everything that leads to her current state (HEAD),
-and reviews what Bob has in his state (FETCH_HEAD) that she has not
+The range notation `HEAD..FETCH_HEAD` means "show everything that is reachable
+from the `FETCH_HEAD` but exclude anything that is reachable from `HEAD`".
+Alice already knows everything that leads to her current state (`HEAD`),
+and reviews what Bob has in his state (`FETCH_HEAD`) that she has not
seen with this command.
If Alice wants to visualize what Bob did since their histories forked
@@ -349,7 +348,7 @@ she can issue the following command:
$ gitk HEAD..FETCH_HEAD
------------------------------------------------
-This uses the same two-dot range notation we saw earlier with 'git log'.
+This uses the same two-dot range notation we saw earlier with `git log`.
Alice may want to view what both of them did since they forked.
She can use three-dot form instead of the two-dot form:
@@ -361,13 +360,13 @@ $ gitk HEAD...FETCH_HEAD
This means "show everything that is reachable from either one, but
exclude anything that is reachable from both of them".
-Please note that these range notation can be used with both gitk
-and "git log".
+Please note that these range notation can be used with both `gitk`
+and `git log`.
After inspecting what Bob did, if there is nothing urgent, Alice may
decide to continue working without pulling from Bob. If Bob's history
does have something Alice would immediately need, Alice may choose to
-stash her work-in-progress first, do a "pull", and then finally unstash
+stash her work-in-progress first, do a `pull`, and then finally unstash
her work-in-progress on top of the resulting history.
When you are working in a small closely knit group, it is not
@@ -379,8 +378,8 @@ it easier:
alice$ git remote add bob /home/bob/myrepo
------------------------------------------------
-With this, Alice can perform the first part of the "pull" operation
-alone using the 'git fetch' command without merging them with her own
+With this, Alice can perform the first part of the `pull` operation
+alone using the `git fetch` command without merging them with her own
branch, using:
-------------------------------------
@@ -388,7 +387,7 @@ alice$ git fetch bob
-------------------------------------
Unlike the longhand form, when Alice fetches from Bob using a
-remote repository shorthand set up with 'git remote', what was
+remote repository shorthand set up with `git remote`, what was
fetched is stored in a remote-tracking branch, in this case
`bob/master`. So after this:
@@ -397,10 +396,10 @@ alice$ git log -p master..bob/master
-------------------------------------
shows a list of all the changes that Bob made since he branched from
-Alice's master branch.
+Alice's `master` branch.
After examining those changes, Alice
-could merge the changes into her master branch:
+could merge the changes into her `master` branch:
-------------------------------------
alice$ git merge bob/master
@@ -432,12 +431,12 @@ bob$ git config --get remote.origin.url
/home/alice/project
-------------------------------------
-(The complete configuration created by 'git clone' is visible using
+(The complete configuration created by `git clone` is visible using
`git config -l`, and the linkgit:git-config[1] man page
explains the meaning of each option.)
-Git also keeps a pristine copy of Alice's master branch under the
-name "origin/master":
+Git also keeps a pristine copy of Alice's `master` branch under the
+name `origin/master`:
-------------------------------------
bob$ git branch -r
@@ -462,8 +461,8 @@ Exploring history
-----------------
Git history is represented as a series of interrelated commits. We
-have already seen that the 'git log' command can list those commits.
-Note that first line of each git log entry also gives a name for the
+have already seen that the `git log` command can list those commits.
+Note that first line of each `git log` entry also gives a name for the
commit:
-------------------------------------
@@ -475,7 +474,7 @@ Date: Tue May 16 17:18:22 2006 -0700
merge-base: Clarify the comments on post processing.
-------------------------------------
-We can give this name to 'git show' to see the details about this
+We can give this name to `git show` to see the details about this
commit.
-------------------------------------
@@ -514,7 +513,7 @@ You can also give commits names of your own; after running
$ git tag v2.5 1b2e1d63ff
-------------------------------------
-you can refer to 1b2e1d63ff by the name "v2.5". If you intend to
+you can refer to `1b2e1d63ff` by the name `v2.5`. If you intend to
share this name with other people (for example, to identify a release
version), you should create a "tag" object, and perhaps sign it; see
linkgit:git-tag[1] for details.
@@ -533,22 +532,22 @@ $ git reset --hard HEAD^ # reset your current branch and working
Be careful with that last command: in addition to losing any changes
in the working directory, it will also remove all later commits from
this branch. If this branch is the only branch containing those
-commits, they will be lost. Also, don't use 'git reset' on a
+commits, they will be lost. Also, don't use `git reset` on a
publicly-visible branch that other developers pull from, as it will
force needless merges on other developers to clean up the history.
-If you need to undo changes that you have pushed, use 'git revert'
+If you need to undo changes that you have pushed, use `git revert`
instead.
-The 'git grep' command can search for strings in any version of your
+The `git grep` command can search for strings in any version of your
project, so
-------------------------------------
$ git grep "hello" v2.5
-------------------------------------
-searches for all occurrences of "hello" in v2.5.
+searches for all occurrences of "hello" in `v2.5`.
-If you leave out the commit name, 'git grep' will search any of the
+If you leave out the commit name, `git grep` will search any of the
files it manages in your current directory. So
-------------------------------------
@@ -558,7 +557,7 @@ $ git grep "hello"
is a quick way to search just the files that are tracked by Git.
Many Git commands also take sets of commits, which can be specified
-in a number of ways. Here are some examples with 'git log':
+in a number of ways. Here are some examples with `git log`:
-------------------------------------
$ git log v2.5..v2.6 # commits between v2.5 and v2.6
@@ -568,16 +567,16 @@ $ git log v2.5.. Makefile # commits since v2.5 which modify
# Makefile
-------------------------------------
-You can also give 'git log' a "range" of commits where the first is not
+You can also give `git log` a "range" of commits where the first is not
necessarily an ancestor of the second; for example, if the tips of
-the branches "stable" and "master" diverged from a common
+the branches `stable` and `master` diverged from a common
commit some time ago, then
-------------------------------------
$ git log stable..master
-------------------------------------
-will list commits made in the master branch but not in the
+will list commits made in the `master` branch but not in the
stable branch, while
-------------------------------------
@@ -585,15 +584,15 @@ $ git log master..stable
-------------------------------------
will show the list of commits made on the stable branch but not
-the master branch.
+the `master` branch.
-The 'git log' command has a weakness: it must present commits in a
+The `git log` command has a weakness: it must present commits in a
list. When the history has lines of development that diverged and
-then merged back together, the order in which 'git log' presents
+then merged back together, the order in which `git log` presents
those commits is meaningless.
Most projects with multiple contributors (such as the Linux kernel,
-or Git itself) have frequent merges, and 'gitk' does a better job of
+or Git itself) have frequent merges, and `gitk` does a better job of
visualizing their history. For example,
-------------------------------------
@@ -601,7 +600,7 @@ $ gitk --since="2 weeks ago" drivers/
-------------------------------------
allows you to browse any commits from the last 2 weeks of commits
-that modified files under the "drivers" directory. (Note: you can
+that modified files under the `drivers` directory. (Note: you can
adjust gitk's fonts by holding down the control key while pressing
"-" or "+".)
@@ -613,7 +612,7 @@ of the file:
$ git diff v2.5:Makefile HEAD:Makefile.in
-------------------------------------
-You can also use 'git show' to see any such file:
+You can also use `git show` to see any such file:
-------------------------------------
$ git show v2.5:Makefile
@@ -649,7 +648,7 @@ digressions that may be interesting at this point are:
* linkgit:git-bisect[1]: When there is a regression in your
project, one way to track down the bug is by searching through
- the history to find the exact commit that's to blame. Git bisect
+ the history to find the exact commit that's to blame. `git bisect`
can help you perform a binary search for that commit. It is
smart enough to perform a close-to-optimal search even in the
case of complex non-linear history with lots of merged branches.
diff --git a/Documentation/manpage-base-url.xsl.in b/Documentation/manpage-base-url.xsl.in
deleted file mode 100644
index e800904df3..0000000000
--- a/Documentation/manpage-base-url.xsl.in
+++ /dev/null
@@ -1,10 +0,0 @@
-<!-- manpage-base-url.xsl:
- special settings for manpages rendered from newer docbook -->
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- version="1.0">
-
-<!-- set a base URL for relative links -->
-<xsl:param name="man.base.url.for.relative.links"
- >@@MAN_BASE_URL@@</xsl:param>
-
-</xsl:stylesheet>
diff --git a/Documentation/manpage-normal.xsl b/Documentation/manpage-normal.xsl
index a9c7ec69f4..beb5ff8ec2 100644
--- a/Documentation/manpage-normal.xsl
+++ b/Documentation/manpage-normal.xsl
@@ -8,19 +8,7 @@
<xsl:param name="man.output.quietly" select="1"/>
<xsl:param name="refentry.meta.get.quietly" select="1"/>
-<!-- convert asciidoc callouts to man page format -->
-<xsl:template match="co">
- <xsl:value-of select="concat('\fB(',substring-after(@id,'-'),')\fR')"/>
-</xsl:template>
-<xsl:template match="calloutlist">
- <xsl:text>.sp&#10;</xsl:text>
- <xsl:apply-templates/>
- <xsl:text>&#10;</xsl:text>
-</xsl:template>
-<xsl:template match="callout">
- <xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/>
- <xsl:apply-templates/>
- <xsl:text>.br&#10;</xsl:text>
-</xsl:template>
+<!-- unset maximum length of title -->
+<xsl:param name="man.th.title.max.length"/>
</xsl:stylesheet>
diff --git a/Documentation/manpage-quote-apos.xsl b/Documentation/manpage-quote-apos.xsl
deleted file mode 100644
index aeb8839f33..0000000000
--- a/Documentation/manpage-quote-apos.xsl
+++ /dev/null
@@ -1,16 +0,0 @@
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- version="1.0">
-
-<!-- work around newer groff/man setups using a prettier apostrophe
- that unfortunately does not quote anything when cut&pasting
- examples to the shell -->
-<xsl:template name="escape.apostrophe">
- <xsl:param name="content"/>
- <xsl:call-template name="string.subst">
- <xsl:with-param name="string" select="$content"/>
- <xsl:with-param name="target">'</xsl:with-param>
- <xsl:with-param name="replacement">\(aq</xsl:with-param>
- </xsl:call-template>
-</xsl:template>
-
-</xsl:stylesheet>
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 0d90d5b154..3000888a90 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -195,10 +195,11 @@ respectively, and they must begin with `refs/` when applied to `--glob`
or `--all`. If a trailing '/{asterisk}' is intended, it must be given
explicitly.
---exclude-hidden=[receive|uploadpack]::
- Do not include refs that would be hidden by `git-receive-pack` or
- `git-upload-pack` by consulting the appropriate `receive.hideRefs` or
- `uploadpack.hideRefs` configuration along with `transfer.hideRefs` (see
+--exclude-hidden=[fetch|receive|uploadpack]::
+ Do not include refs that would be hidden by `git-fetch`,
+ `git-receive-pack` or `git-upload-pack` by consulting the appropriate
+ `fetch.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs`
+ configuration along with `transfer.hideRefs` (see
linkgit:git-config[1]). This option affects the next pseudo-ref option
`--all` or `--glob` and is cleared after processing them.
@@ -889,7 +890,7 @@ ifdef::git-rev-list[]
Print the object IDs of any object referenced by the listed
commits. `--objects foo ^bar` thus means ``send me
all object IDs which I need to download if I have the commit
- object _bar_ but not _foo_''.
+ object _bar_ but not _foo_''. See also `--object-names` below.
--in-commit-order::
Print tree and blob ids in order of the commits. The tree
@@ -919,7 +920,12 @@ ifdef::git-rev-list[]
--object-names::
Only useful with `--objects`; print the names of the object IDs
- that are found. This is the default behavior.
+ that are found. This is the default behavior. Note that the
+ "name" of each object is ambiguous, and mostly intended as a
+ hint for packing objects. In particular: no distinction is made between
+ the names of tags, trees, and blobs; path names may be modified
+ to remove newlines; and if an object would appear multiple times
+ with different names, only one name is shown.
--no-object-names::
Only useful with `--objects`; does not print the names of the object
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 9aa58052bc..b42a2bb30a 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -32,8 +32,9 @@ characters and to avoid word splitting.
first match in the following rules:
. If '$GIT_DIR/<refname>' exists, that is what you mean (this is usually
- useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`
- and `CHERRY_PICK_HEAD`);
+ useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`,
+ `REBASE_HEAD`, `REVERT_HEAD`, `CHERRY_PICK_HEAD`, `BISECT_HEAD`
+ and `AUTO_MERGE`);
. otherwise, 'refs/<refname>' if it exists;
@@ -55,8 +56,18 @@ you can easily change the tip of the branch back to the state before you ran
them.
`MERGE_HEAD` records the commit(s) which you are merging into your branch
when you run `git merge`.
+`REBASE_HEAD`, during a rebase, records the commit at which the
+operation is currently stopped, either because of conflicts or an `edit`
+command in an interactive rebase.
+`REVERT_HEAD` records the commit which you are reverting when you
+run `git revert`.
`CHERRY_PICK_HEAD` records the commit which you are cherry-picking
when you run `git cherry-pick`.
+`BISECT_HEAD` records the current commit to be tested when you
+run `git bisect --no-checkout`.
+`AUTO_MERGE` records a tree object corresponding to the state the
+'ort' merge strategy wrote to the working tree when a merge operation
+resulted in conflicts.
+
Note that any of the 'refs/*' cases above may come either from
the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
diff --git a/Documentation/technical/api-merge.txt b/Documentation/technical/api-merge.txt
index 487d4d83ff..c2ba01828c 100644
--- a/Documentation/technical/api-merge.txt
+++ b/Documentation/technical/api-merge.txt
@@ -28,9 +28,9 @@ and `diff.c` for examples.
* `struct ll_merge_options`
-Check ll-merge.h for details.
+Check merge-ll.h for details.
Low-level (single file) merge
-----------------------------
-Check ll-merge.h for details.
+Check merge-ll.h for details.
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index dc9c6a663a..510ab4508d 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1343,6 +1343,33 @@ $ git diff -3 file.txt # diff against stage 3
$ git diff --theirs file.txt # same as the above.
-------------------------------------------------
+When using the 'ort' merge strategy (the default), before updating the working
+tree with the result of the merge, Git writes a special ref named AUTO_MERGE
+reflecting the state of the tree it is about to write. Conflicted paths that
+could not be automatically merged are written to this tree with conflict
+markers, just as in the working tree. AUTO_MERGE can thus be used with
+linkgit:git-diff[1] to show the changes you've made so far to resolve
+conflicts. Using the same example as above, after resolving the conflict we
+get:
+
+-------------------------------------------------
+$ git diff AUTO_MERGE
+diff --git a/file.txt b/file.txt
+index cd10406..8bf5ae7 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,5 +1 @@
+-<<<<<<< HEAD:file.txt
+-Hello world
+-=======
+-Goodbye
+->>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
++Goodbye world
+-------------------------------------------------
+
+Notice that the diff shows we deleted the conflict markers and both versions,
+and wrote "Goodbye world" instead.
+
The linkgit:git-log[1] and linkgit:gitk[1] commands also provide special help
for merges:
@@ -4102,13 +4129,11 @@ Note that terminology has changed since that revision. For example, the
README in that revision uses the word "changeset" to describe what we
now call a <<def_commit_object,commit>>.
-Also, we do not call it "cache" any more, but rather "index"; however, the
-file is still called `cache.h`. Remark: Not much reason to change it now,
-especially since there is no good single name for it anyway, because it is
-basically _the_ header file which is included by _all_ of Git's C sources.
+Also, we do not call it "cache" any more, but rather "index"; however,
+the file is still called `read-cache.h`.
If you grasp the ideas in that initial commit, you should check out a
-more recent version and skim `cache.h`, `object.h` and `commit.h`.
+more recent version and skim `read-cache-ll.h`, `object.h` and `commit.h`.
In the early days, Git (in the tradition of UNIX) was a bunch of programs
which were extremely simple, and which you used in scripts, piping the
@@ -4119,11 +4144,11 @@ many of these parts have become builtins, and some of the core has been
and to avoid code duplication.
By now, you know what the index is (and find the corresponding data
-structures in `cache.h`), and that there are just a couple of object types
-(blobs, trees, commits and tags) which inherit their common structure from
-`struct object`, which is their first member (and thus, you can cast e.g.
-`(struct object *)commit` to achieve the _same_ as `&commit->object`, i.e.
-get at the object name and flags).
+structures in `read-cache-ll.h`), and that there are just a couple of
+object types (blobs, trees, commits and tags) which inherit their
+common structure from `struct object`, which is their first member
+(and thus, you can cast e.g. `(struct object *)commit` to achieve the
+_same_ as `&commit->object`, i.e. get at the object name and flags).
Now is a good point to take a break to let this information sink in.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index a87f0adf80..9a1111af9b 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.40.0
+DEF_VER=v2.40.GIT
LF='
'
diff --git a/INSTALL b/INSTALL
index 4b42288882..c98ef9da7b 100644
--- a/INSTALL
+++ b/INSTALL
@@ -129,13 +129,13 @@ Issues of note:
itself, e.g. Digest::MD5, File::Spec, File::Temp, Net::Domain,
Net::SMTP, and Time::HiRes.
- - git-imap-send needs the OpenSSL library to talk IMAP over SSL if
- you are using libcurl older than 7.34.0. Otherwise you can use
- NO_OPENSSL without losing git-imap-send.
+ - git-imap-send needs libcurl 7.34.0 or newer, in addition
+ OpenSSL is needed if using the "imap.tunnel" open to tunnel
+ over SSL. Define NO_OPENSSL to omit the OpenSSL prerequisite.
- "libcurl" library is used for fetching and pushing
repositories over http:// or https://, as well as by
- git-imap-send if the curl version is >= 7.34.0. If you do
+ git-imap-send. If you do
not need that functionality, use NO_CURL to build without
it.
diff --git a/Makefile b/Makefile
index 50ee51fde3..43c295675a 100644
--- a/Makefile
+++ b/Makefile
@@ -207,10 +207,6 @@ include shared.mak
# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
# field that counts the on-disk footprint in 512-byte blocks.
#
-# Define GNU_ROFF if your target system uses GNU groff. This forces
-# apostrophes to be ASCII so that cut&pasting examples to the shell
-# will work.
-#
# Define USE_ASCIIDOCTOR to use Asciidoctor instead of AsciiDoc to build the
# documentation.
#
@@ -772,7 +768,9 @@ PROGRAMS += $(EXTRA_PROGRAMS)
PROGRAM_OBJS += daemon.o
PROGRAM_OBJS += http-backend.o
+ifndef NO_CURL
PROGRAM_OBJS += imap-send.o
+endif
PROGRAM_OBJS += sh-i18n--envsubst.o
PROGRAM_OBJS += shell.o
.PHONY: program-objs
@@ -1036,6 +1034,7 @@ LIB_OBJS += fsmonitor.o
LIB_OBJS += fsmonitor-ipc.o
LIB_OBJS += fsmonitor-settings.o
LIB_OBJS += gettext.o
+LIB_OBJS += git-zlib.o
LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o
LIB_OBJS += grep.o
@@ -1054,7 +1053,6 @@ LIB_OBJS += linear-assignment.o
LIB_OBJS += list-objects-filter-options.o
LIB_OBJS += list-objects-filter.o
LIB_OBJS += list-objects.o
-LIB_OBJS += ll-merge.o
LIB_OBJS += lockfile.o
LIB_OBJS += log-tree.o
LIB_OBJS += ls-refs.o
@@ -1063,6 +1061,7 @@ LIB_OBJS += mailmap.o
LIB_OBJS += match-trees.o
LIB_OBJS += mem-pool.o
LIB_OBJS += merge-blobs.o
+LIB_OBJS += merge-ll.o
LIB_OBJS += merge-ort.o
LIB_OBJS += merge-ort-wrappers.o
LIB_OBJS += merge-recursive.o
@@ -1145,6 +1144,7 @@ LIB_OBJS += sigchain.o
LIB_OBJS += sparse-index.o
LIB_OBJS += split-index.o
LIB_OBJS += stable-qsort.o
+LIB_OBJS += statinfo.o
LIB_OBJS += strbuf.o
LIB_OBJS += streaming.o
LIB_OBJS += string-list.o
@@ -1196,7 +1196,6 @@ LIB_OBJS += write-or-die.o
LIB_OBJS += ws.o
LIB_OBJS += wt-status.o
LIB_OBJS += xdiff-interface.o
-LIB_OBJS += zlib.o
BUILTIN_OBJS += builtin/add.o
BUILTIN_OBJS += builtin/am.o
@@ -1582,7 +1581,6 @@ ifdef HAVE_ALLOCA_H
BASIC_CFLAGS += -DHAVE_ALLOCA_H
endif
-IMAP_SEND_BUILDDEPS =
IMAP_SEND_LDFLAGS =
ifdef NO_CURL
@@ -1591,6 +1589,7 @@ ifdef NO_CURL
REMOTE_CURL_ALIASES =
REMOTE_CURL_NAMES =
EXCLUDED_PROGRAMS += git-http-fetch git-http-push
+ EXCLUDED_PROGRAMS += git-imap-send
else
ifdef CURLDIR
# Try "-Wl,-rpath=$(CURLDIR)/$(lib)" in such a case.
@@ -1616,19 +1615,9 @@ else
REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
PROGRAM_OBJS += http-fetch.o
PROGRAMS += $(REMOTE_CURL_NAMES)
+ IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
ifndef NO_EXPAT
PROGRAM_OBJS += http-push.o
- endif
- curl_check := $(shell (echo 072200; $(CURL_CONFIG) --vernum | sed -e '/^70[BC]/s/^/0/') 2>/dev/null | sort -r | sed -ne 2p)
- ifeq "$(curl_check)" "072200"
- USE_CURL_FOR_IMAP_SEND = YesPlease
- endif
- ifdef USE_CURL_FOR_IMAP_SEND
- BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND
- IMAP_SEND_BUILDDEPS = http.o
- IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
- endif
- ifndef NO_EXPAT
ifdef EXPATDIR
BASIC_CFLAGS += -I$(EXPATDIR)/include
EXPAT_LIBEXPAT = -L$(EXPATDIR)/$(lib) $(CC_LD_DYNPATH)$(EXPATDIR)/$(lib) -lexpat
@@ -1955,7 +1944,7 @@ endif
BASIC_CFLAGS += \
-DSHA1DC_NO_STANDARD_INCLUDES \
-DSHA1DC_INIT_SAFE_HASH_DEFAULT=0 \
- -DSHA1DC_CUSTOM_INCLUDE_SHA1_C="\"cache.h\"" \
+ -DSHA1DC_CUSTOM_INCLUDE_SHA1_C="\"git-compat-util.h\"" \
-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="\"git-compat-util.h\""
endif
endif
@@ -2785,7 +2774,7 @@ endif
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
-git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
+git-imap-send$X: imap-send.o http.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(IMAP_SEND_LDFLAGS) $(LIBS)
diff --git a/RelNotes b/RelNotes
index 47807bf257..4da73c9a6d 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.40.0.txt \ No newline at end of file
+Documentation/RelNotes/2.41.0.txt \ No newline at end of file
diff --git a/abspath.c b/abspath.c
index 39e06b5848..1202cde23d 100644
--- a/abspath.c
+++ b/abspath.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "strbuf.h"
/*
* Do not use this for inspecting *tracked* content. When path is a
@@ -280,3 +282,46 @@ char *prefix_filename(const char *pfx, const char *arg)
#endif
return strbuf_detach(&path, NULL);
}
+
+char *prefix_filename_except_for_dash(const char *pfx, const char *arg)
+{
+ if (!strcmp(arg, "-"))
+ return xstrdup(arg);
+ return prefix_filename(pfx, arg);
+}
+
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
+{
+ if (!*path)
+ die("The empty string is not a valid path");
+ if (!is_absolute_path(path)) {
+ struct stat cwd_stat, pwd_stat;
+ size_t orig_len = sb->len;
+ char *cwd = xgetcwd();
+ char *pwd = getenv("PWD");
+ if (pwd && strcmp(pwd, cwd) &&
+ !stat(cwd, &cwd_stat) &&
+ (cwd_stat.st_dev || cwd_stat.st_ino) &&
+ !stat(pwd, &pwd_stat) &&
+ pwd_stat.st_dev == cwd_stat.st_dev &&
+ pwd_stat.st_ino == cwd_stat.st_ino)
+ strbuf_addstr(sb, pwd);
+ else
+ strbuf_addstr(sb, cwd);
+ if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))
+ strbuf_addch(sb, '/');
+ free(cwd);
+ }
+ strbuf_addstr(sb, path);
+}
+
+void strbuf_add_real_path(struct strbuf *sb, const char *path)
+{
+ if (sb->len) {
+ struct strbuf resolved = STRBUF_INIT;
+ strbuf_realpath(&resolved, path, 1);
+ strbuf_addbuf(sb, &resolved);
+ strbuf_release(&resolved);
+ } else
+ strbuf_realpath(sb, path, 1);
+}
diff --git a/abspath.h b/abspath.h
new file mode 100644
index 0000000000..4653080d5e
--- /dev/null
+++ b/abspath.h
@@ -0,0 +1,54 @@
+#ifndef ABSPATH_H
+#define ABSPATH_H
+
+int is_directory(const char *);
+char *strbuf_realpath(struct strbuf *resolved, const char *path,
+ int die_on_error);
+char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path,
+ int die_on_error);
+char *real_pathdup(const char *path, int die_on_error);
+const char *absolute_path(const char *path);
+char *absolute_pathdup(const char *path);
+
+/*
+ * Concatenate "prefix" (if len is non-zero) and "path", with no
+ * connecting characters (so "prefix" should end with a "/").
+ * Unlike prefix_path, this should be used if the named file does
+ * not have to interact with index entry; i.e. name of a random file
+ * on the filesystem.
+ *
+ * The return value is always a newly allocated string (even if the
+ * prefix was empty).
+ */
+char *prefix_filename(const char *prefix, const char *path);
+
+/* Likewise, but path=="-" always yields "-" */
+char *prefix_filename_except_for_dash(const char *prefix, const char *path);
+
+static inline int is_absolute_path(const char *path)
+{
+ return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
+}
+
+/**
+ * Add a path to a buffer, converting a relative path to an
+ * absolute one in the process. Symbolic links are not
+ * resolved.
+ */
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
+
+/**
+ * Canonize `path` (make it absolute, resolve symlinks, remove extra
+ * slashes) and append it to `sb`. Die with an informative error
+ * message if there is a problem.
+ *
+ * The directory part of `path` (i.e., everything up to the last
+ * dir_sep) must denote a valid, existing directory, but the last
+ * component need not exist.
+ *
+ * Callers that don't mind links should use the more lightweight
+ * strbuf_add_absolute_path() instead.
+ */
+void strbuf_add_real_path(struct strbuf *sb, const char *path);
+
+#endif /* ABSPATH_H */
diff --git a/add-interactive.c b/add-interactive.c
index 00a0f6f96f..add9a1ad43 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -1,8 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "add-interactive.h"
#include "color.h"
#include "config.h"
#include "diffcore.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "preload-index.h"
+#include "read-cache-ll.h"
+#include "repository.h"
#include "revision.h"
#include "refs.h"
#include "string-list.h"
@@ -10,6 +16,7 @@
#include "dir.h"
#include "run-command.h"
#include "prompt.h"
+#include "tree.h"
static void init_color(struct repository *r, struct add_i_state *s,
const char *section_and_slot, char *dst,
@@ -551,7 +558,7 @@ static int get_modified_files(struct repository *r,
opt.def = is_initial ?
empty_tree_oid_hex() : oid_to_hex(&head_oid);
- init_revisions(&rev, NULL);
+ repo_init_revisions(r, &rev, NULL);
setup_revisions(0, NULL, &rev, &opt);
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
diff --git a/add-patch.c b/add-patch.c
index a86a92e164..ba629add62 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -1,5 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "add-interactive.h"
+#include "advice.h"
+#include "alloc.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "read-cache-ll.h"
+#include "repository.h"
#include "strbuf.h"
#include "run-command.h"
#include "strvec.h"
@@ -414,7 +422,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
strvec_push(&args,
/* could be on an unborn branch */
!strcmp("HEAD", s->revision) &&
- get_oid("HEAD", &oid) ?
+ repo_get_oid(the_repository, "HEAD", &oid) ?
empty_tree_oid_hex() : s->revision);
}
color_arg_index = args.nr;
@@ -483,7 +491,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
if (!eol)
eol = pend;
- if (starts_with(p, "diff ")) {
+ if (starts_with(p, "diff ") ||
+ starts_with(p, "* Unmerged path ")) {
complete_file(marker, hunk);
ALLOC_GROW_BY(s->file_diff, s->file_diff_nr, 1,
file_diff_alloc);
@@ -1098,10 +1107,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
size_t i;
strbuf_reset(&s->buf);
- strbuf_commented_addf(&s->buf, _("Manual hunk edit mode -- see bottom for "
- "a quick guide.\n"));
+ strbuf_commented_addf(&s->buf, comment_line_char,
+ _("Manual hunk edit mode -- see bottom for "
+ "a quick guide.\n"));
render_hunk(s, hunk, 0, 0, &s->buf);
- strbuf_commented_addf(&s->buf,
+ strbuf_commented_addf(&s->buf, comment_line_char,
_("---\n"
"To remove '%c' lines, make them ' ' lines "
"(context).\n"
@@ -1110,12 +1120,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
s->mode->is_reverse ? '+' : '-',
s->mode->is_reverse ? '-' : '+',
comment_line_char);
- strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
+ strbuf_commented_addf(&s->buf, comment_line_char, "%s",
+ _(s->mode->edit_hunk_hint));
/*
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
* messages.
*/
- strbuf_commented_addf(&s->buf,
+ strbuf_commented_addf(&s->buf, comment_line_char,
_("If it does not apply cleanly, you will be "
"given an opportunity to\n"
"edit again. If all lines of the hunk are "
diff --git a/advice.c b/advice.c
index fd18968943..e5a9bb9b44 100644
--- a/advice.c
+++ b/advice.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
#include "config.h"
#include "color.h"
+#include "gettext.h"
#include "help.h"
#include "string-list.h"
@@ -44,6 +46,7 @@ static struct {
[ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge", 1 },
[ADVICE_DETACHED_HEAD] = { "detachedHead", 1 },
[ADVICE_SUGGEST_DETACHING_HEAD] = { "suggestDetachingHead", 1 },
+ [ADVICE_DIVERGING] = { "diverging", 1 },
[ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates", 1 },
[ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated", 1 },
[ADVICE_IGNORED_HOOK] = { "ignoredHook", 1 },
@@ -75,6 +78,7 @@ static struct {
[ADVICE_SUBMODULES_NOT_UPDATED] = { "submodulesNotUpdated", 1 },
[ADVICE_UPDATE_SPARSE_PATH] = { "updateSparsePath", 1 },
[ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor", 1 },
+ [ADVICE_WORKTREE_ADD_ORPHAN] = { "worktreeAddOrphan", 1 },
};
static const char turn_off_instructions[] =
@@ -217,6 +221,14 @@ void NORETURN die_conclude_merge(void)
void NORETURN die_ff_impossible(void)
{
+ advise_if_enabled(ADVICE_DIVERGING,
+ _("Diverging branches can't be fast-forwarded, you need to either:\n"
+ "\n"
+ "\tgit merge --no-ff\n"
+ "\n"
+ "or:\n"
+ "\n"
+ "\tgit rebase\n"));
die(_("Not possible to fast-forward, aborting."));
}
diff --git a/advice.h b/advice.h
index 07e0f76833..2affbe1426 100644
--- a/advice.h
+++ b/advice.h
@@ -1,8 +1,6 @@
#ifndef ADVICE_H
#define ADVICE_H
-#include "git-compat-util.h"
-
struct string_list;
/*
@@ -21,6 +19,7 @@ struct string_list;
ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
ADVICE_COMMIT_BEFORE_MERGE,
ADVICE_DETACHED_HEAD,
+ ADVICE_DIVERGING,
ADVICE_SUGGEST_DETACHING_HEAD,
ADVICE_FETCH_SHOW_FORCED_UPDATES,
ADVICE_GRAFT_FILE_DEPRECATED,
@@ -50,6 +49,7 @@ struct string_list;
ADVICE_UPDATE_SPARSE_PATH,
ADVICE_WAITING_FOR_EDITOR,
ADVICE_SKIPPED_CHERRY_PICKS,
+ ADVICE_WORKTREE_ADD_ORPHAN,
};
int git_default_advice_config(const char *var, const char *value);
diff --git a/alias.c b/alias.c
index 00abde0817..54a1a23d2c 100644
--- a/alias.c
+++ b/alias.c
@@ -1,6 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "alias.h"
+#include "alloc.h"
#include "config.h"
+#include "gettext.h"
+#include "strbuf.h"
#include "string-list.h"
struct config_alias_data {
@@ -44,6 +47,23 @@ void list_aliases(struct string_list *list)
read_early_config(config_alias_cb, &data);
}
+void quote_cmdline(struct strbuf *buf, const char **argv)
+{
+ for (const char **argp = argv; *argp; argp++) {
+ if (argp != argv)
+ strbuf_addch(buf, ' ');
+ strbuf_addch(buf, '"');
+ for (const char *p = *argp; *p; p++) {
+ const char c = *p;
+
+ if (c == '"' || c =='\\')
+ strbuf_addch(buf, '\\');
+ strbuf_addch(buf, c);
+ }
+ strbuf_addch(buf, '"');
+ }
+}
+
#define SPLIT_CMDLINE_BAD_ENDING 1
#define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
#define SPLIT_CMDLINE_ARGC_OVERFLOW 3
diff --git a/alias.h b/alias.h
index aef4843bb7..43db736484 100644
--- a/alias.h
+++ b/alias.h
@@ -1,9 +1,12 @@
#ifndef ALIAS_H
#define ALIAS_H
+struct strbuf;
struct string_list;
char *alias_lookup(const char *alias);
+/* Quote argv so buf can be parsed by split_cmdline() */
+void quote_cmdline(struct strbuf *buf, const char **argv);
int split_cmdline(char *cmdline, const char ***argv);
/* Takes a negative value returned by split_cmdline */
const char *split_cmdline_strerror(int cmdline_errno);
diff --git a/alloc.c b/alloc.c
index 27f697e4c8..377e80f5dd 100644
--- a/alloc.c
+++ b/alloc.c
@@ -8,11 +8,12 @@
* up with maximal alignment because it doesn't know what the object alignment
* for the new allocation is.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "object.h"
#include "blob.h"
#include "tree.h"
#include "commit.h"
+#include "repository.h"
#include "tag.h"
#include "alloc.h"
diff --git a/alloc.h b/alloc.h
index 3f4a0ad310..4312db4bd0 100644
--- a/alloc.h
+++ b/alloc.h
@@ -17,4 +17,79 @@ void *alloc_object_node(struct repository *r);
struct alloc_state *allocate_alloc_state(void);
void clear_alloc_state(struct alloc_state *s);
+#define alloc_nr(x) (((x)+16)*3/2)
+
+/**
+ * Dynamically growing an array using realloc() is error prone and boring.
+ *
+ * Define your array with:
+ *
+ * - a pointer (`item`) that points at the array, initialized to `NULL`
+ * (although please name the variable based on its contents, not on its
+ * type);
+ *
+ * - an integer variable (`alloc`) that keeps track of how big the current
+ * allocation is, initialized to `0`;
+ *
+ * - another integer variable (`nr`) to keep track of how many elements the
+ * array currently has, initialized to `0`.
+ *
+ * Then before adding `n`th element to the item, call `ALLOC_GROW(item, n,
+ * alloc)`. This ensures that the array can hold at least `n` elements by
+ * calling `realloc(3)` and adjusting `alloc` variable.
+ *
+ * ------------
+ * sometype *item;
+ * size_t nr;
+ * size_t alloc
+ *
+ * for (i = 0; i < nr; i++)
+ * if (we like item[i] already)
+ * return;
+ *
+ * // we did not like any existing one, so add one
+ * ALLOC_GROW(item, nr + 1, alloc);
+ * item[nr++] = value you like;
+ * ------------
+ *
+ * You are responsible for updating the `nr` variable.
+ *
+ * If you need to specify the number of elements to allocate explicitly
+ * then use the macro `REALLOC_ARRAY(item, alloc)` instead of `ALLOC_GROW`.
+ *
+ * Consider using ALLOC_GROW_BY instead of ALLOC_GROW as it has some
+ * added niceties.
+ *
+ * DO NOT USE any expression with side-effect for 'x', 'nr', or 'alloc'.
+ */
+#define ALLOC_GROW(x, nr, alloc) \
+ do { \
+ if ((nr) > alloc) { \
+ if (alloc_nr(alloc) < (nr)) \
+ alloc = (nr); \
+ else \
+ alloc = alloc_nr(alloc); \
+ REALLOC_ARRAY(x, alloc); \
+ } \
+ } while (0)
+
+/*
+ * Similar to ALLOC_GROW but handles updating of the nr value and
+ * zeroing the bytes of the newly-grown array elements.
+ *
+ * DO NOT USE any expression with side-effect for any of the
+ * arguments.
+ */
+#define ALLOC_GROW_BY(x, nr, increase, alloc) \
+ do { \
+ if (increase) { \
+ size_t new_nr = nr + (increase); \
+ if (new_nr < nr) \
+ BUG("negative growth in ALLOC_GROW_BY"); \
+ ALLOC_GROW(x, new_nr, alloc); \
+ memset((x) + nr, 0, sizeof(*(x)) * (increase)); \
+ nr = new_nr; \
+ } \
+ } while (0)
+
#endif
diff --git a/apply.c b/apply.c
index 5cc5479c9c..8bd0109fcc 100644
--- a/apply.c
+++ b/apply.c
@@ -7,21 +7,37 @@
*
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
+#include "base85.h"
#include "config.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "blob.h"
#include "delta.h"
#include "diff.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "xdiff-interface.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
#include "lockfile.h"
+#include "name-hash.h"
+#include "object-name.h"
+#include "object-file.h"
#include "parse-options.h"
+#include "path.h"
#include "quote.h"
+#include "read-cache.h"
#include "rerere.h"
#include "apply.h"
#include "entry.h"
+#include "setup.h"
+#include "symlinks.h"
+#include "wildmatch.h"
+#include "ws.h"
+#include "wrapper.h"
struct gitdiff_data {
struct strbuf *root;
@@ -3201,7 +3217,8 @@ static int apply_binary(struct apply_state *state,
unsigned long size;
char *result;
- result = read_object_file(&oid, &type, &size);
+ result = repo_read_object_file(the_repository, &oid, &type,
+ &size);
if (!result)
return error(_("the necessary postimage %s for "
"'%s' cannot be read"),
@@ -3264,7 +3281,8 @@ static int read_blob_object(struct strbuf *buf, const struct object_id *oid, uns
unsigned long sz;
char *result;
- result = read_object_file(oid, &type, &sz);
+ result = repo_read_object_file(the_repository, oid, &type,
+ &sz);
if (!result)
return -1;
/* XXX read_sha1_file NUL-terminates */
@@ -3492,7 +3510,8 @@ static int resolve_to(struct image *image, const struct object_id *result_id)
clear_image(image);
- image->buf = read_object_file(result_id, &type, &size);
+ image->buf = repo_read_object_file(the_repository, result_id, &type,
+ &size);
if (!image->buf || type != OBJ_BLOB)
die("unable to read blob object %s", oid_to_hex(result_id));
image->len = size;
@@ -3610,7 +3629,7 @@ static int try_threeway(struct apply_state *state,
/* Preimage the patch was prepared for */
if (patch->is_new)
write_object_file("", 0, OBJ_BLOB, &pre_oid);
- else if (get_oid(patch->old_oid_prefix, &pre_oid) ||
+ else if (repo_get_oid(the_repository, patch->old_oid_prefix, &pre_oid) ||
read_blob_object(&buf, &pre_oid, patch->old_mode))
return error(_("repository lacks the necessary blob to perform 3-way merge."));
@@ -4127,7 +4146,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
else
return error(_("sha1 information is lacking or "
"useless for submodule %s"), name);
- } else if (!get_oid_blob(patch->old_oid_prefix, &oid)) {
+ } else if (!repo_get_oid_blob(the_repository, patch->old_oid_prefix, &oid)) {
; /* ok */
} else if (!patch->lines_added && !patch->lines_deleted) {
/* mode-only change: update the current */
@@ -4576,7 +4595,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
FILE *rej;
char namebuf[PATH_MAX];
struct fragment *frag;
- int cnt = 0;
+ int fd, cnt = 0;
struct strbuf sb = STRBUF_INIT;
for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
@@ -4616,7 +4635,17 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
memcpy(namebuf, patch->new_name, cnt);
memcpy(namebuf + cnt, ".rej", 5);
- rej = fopen(namebuf, "w");
+ fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (fd < 0) {
+ if (errno != EEXIST)
+ return error_errno(_("cannot open %s"), namebuf);
+ if (unlink(namebuf))
+ return error_errno(_("cannot unlink '%s'"), namebuf);
+ fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (fd < 0)
+ return error_errno(_("cannot open %s"), namebuf);
+ }
+ rej = fdopen(fd, "w");
if (!rej)
return error_errno(_("cannot open %s"), namebuf);
diff --git a/apply.h b/apply.h
index b9f18ce87d..7cd38b1443 100644
--- a/apply.h
+++ b/apply.h
@@ -1,7 +1,7 @@
#ifndef APPLY_H
#define APPLY_H
-#include "hash.h"
+#include "hash-ll.h"
#include "lockfile.h"
#include "string-list.h"
#include "strmap.h"
diff --git a/archive-tar.c b/archive-tar.c
index f8fad2946e..fc06ff4c5d 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -1,13 +1,18 @@
/*
* Copyright (c) 2005, 2006 Rene Scharfe
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
+#include "gettext.h"
+#include "git-zlib.h"
+#include "hex.h"
#include "tar.h"
#include "archive.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "streaming.h"
#include "run-command.h"
+#include "write-or-die.h"
#define RECORDSIZE (512)
#define BLOCKSIZE (RECORDSIZE * 20)
diff --git a/archive-zip.c b/archive-zip.c
index 0456f1ebf1..b438264096 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -1,13 +1,17 @@
/*
* Copyright (c) 2006 Rene Scharfe
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "archive.h"
+#include "gettext.h"
+#include "git-zlib.h"
+#include "hex.h"
#include "streaming.h"
#include "utf8.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "userdiff.h"
+#include "write-or-die.h"
#include "xdiff-interface.h"
#include "date.h"
diff --git a/archive.c b/archive.c
index 9aeaf2bd87..1817cca9f4 100644
--- a/archive.c
+++ b/archive.c
@@ -1,8 +1,18 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
+#include "convert.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "path.h"
+#include "pretty.h"
+#include "setup.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "commit.h"
+#include "tree.h"
#include "tree-walk.h"
#include "attr.h"
#include "archive.h"
@@ -59,7 +69,8 @@ static void format_subst(const struct commit *commit,
strbuf_add(&fmt, b + 8, c - b - 8);
strbuf_add(buf, src, b - src);
- format_commit_message(commit, fmt.buf, buf, ctx);
+ repo_format_commit_message(the_repository, commit, fmt.buf,
+ buf, ctx);
len -= c + 1 - src;
src = c + 1;
}
@@ -84,7 +95,7 @@ static void *object_file_to_archive(const struct archiver_args *args,
(args->tree ? &args->tree->object.oid : NULL), oid);
path += args->baselen;
- buffer = read_object_file(oid, type, sizep);
+ buffer = repo_read_object_file(the_repository, oid, type, sizep);
if (buffer && S_ISREG(mode)) {
struct strbuf buf = STRBUF_INIT;
size_t size = 0;
@@ -120,7 +131,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate,
static struct attr_check *check;
if (!check)
check = attr_check_initl("export-ignore", "export-subst", NULL);
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
return check;
}
@@ -166,6 +177,29 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
args->convert = check_attr_export_subst(check);
}
+ if (args->prefix) {
+ static struct strbuf new_path = STRBUF_INIT;
+ static struct strbuf buf = STRBUF_INIT;
+ const char *rel;
+
+ rel = relative_path(path_without_prefix, args->prefix, &buf);
+
+ /*
+ * We don't add an entry for the current working
+ * directory when we are at the root; skip it also when
+ * we're in a subdirectory or submodule. Skip entries
+ * higher up as well.
+ */
+ if (!strcmp(rel, "./") || starts_with(rel, "../"))
+ return S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0;
+
+ /* rel can refer to path, so don't edit it in place */
+ strbuf_reset(&new_path);
+ strbuf_add(&new_path, args->base, args->baselen);
+ strbuf_addstr(&new_path, rel);
+ strbuf_swap(&path, &new_path);
+ }
+
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
@@ -401,6 +435,27 @@ static int reject_entry(const struct object_id *oid UNUSED,
return ret;
}
+static int reject_outside(const struct object_id *oid UNUSED,
+ struct strbuf *base, const char *filename,
+ unsigned mode, void *context)
+{
+ struct archiver_args *args = context;
+ struct strbuf buf = STRBUF_INIT;
+ struct strbuf path = STRBUF_INIT;
+ int ret = 0;
+
+ if (S_ISDIR(mode))
+ return READ_TREE_RECURSIVE;
+
+ strbuf_addbuf(&path, base);
+ strbuf_addstr(&path, filename);
+ if (starts_with(relative_path(path.buf, args->prefix, &buf), "../"))
+ ret = -1;
+ strbuf_release(&buf);
+ strbuf_release(&path);
+ return ret;
+}
+
static int path_exists(struct archiver_args *args, const char *path)
{
const char *paths[] = { path, NULL };
@@ -408,8 +463,13 @@ static int path_exists(struct archiver_args *args, const char *path)
int ret;
ctx.args = args;
- parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
+ parse_pathspec(&ctx.pathspec, 0, PATHSPEC_PREFER_CWD,
+ args->prefix, paths);
ctx.pathspec.recursive = 1;
+ if (args->prefix && read_tree(args->repo, args->tree, &ctx.pathspec,
+ reject_outside, args))
+ die(_("pathspec '%s' matches files outside the "
+ "current directory"), path);
ret = read_tree(args->repo, args->tree,
&ctx.pathspec,
reject_entry, &ctx);
@@ -425,9 +485,8 @@ static void parse_pathspec_arg(const char **pathspec,
* Also if pathspec patterns are dependent, we're in big
* trouble as we test each one separately
*/
- parse_pathspec(&ar_args->pathspec, 0,
- PATHSPEC_PREFER_FULL,
- "", pathspec);
+ parse_pathspec(&ar_args->pathspec, 0, PATHSPEC_PREFER_CWD,
+ ar_args->prefix, pathspec);
ar_args->pathspec.recursive = 1;
if (pathspec) {
while (*pathspec) {
@@ -439,8 +498,7 @@ static void parse_pathspec_arg(const char **pathspec,
}
static void parse_treeish_arg(const char **argv,
- struct archiver_args *ar_args, const char *prefix,
- int remote)
+ struct archiver_args *ar_args, int remote)
{
const char *name = argv[0];
const struct object_id *commit_oid;
@@ -455,13 +513,14 @@ static void parse_treeish_arg(const char **argv,
const char *colon = strchrnul(name, ':');
int refnamelen = colon - name;
- if (!dwim_ref(name, refnamelen, &oid, &ref, 0))
+ if (!repo_dwim_ref(the_repository, name, refnamelen, &oid, &ref, 0))
die(_("no such ref: %.*s"), refnamelen, name);
} else {
- dwim_ref(name, strlen(name), &oid, &ref, 0);
+ repo_dwim_ref(the_repository, name, strlen(name), &oid, &ref,
+ 0);
}
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
die(_("not a valid object name: %s"), name);
commit = lookup_commit_reference_gently(ar_args->repo, &oid, 1);
@@ -479,20 +538,6 @@ static void parse_treeish_arg(const char **argv,
if (!tree)
die(_("not a tree object: %s"), oid_to_hex(&oid));
- if (prefix) {
- struct object_id tree_oid;
- unsigned short mode;
- int err;
-
- err = get_tree_entry(ar_args->repo,
- &tree->object.oid,
- prefix, &tree_oid,
- &mode);
- if (err || !S_ISDIR(mode))
- die(_("current working directory is untracked"));
-
- tree = parse_tree_indirect(&tree_oid);
- }
ar_args->refname = ref;
ar_args->tree = tree;
ar_args->commit_oid = commit_oid;
@@ -710,7 +755,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
setup_git_directory();
}
- parse_treeish_arg(argv, &args, prefix, remote);
+ parse_treeish_arg(argv, &args, remote);
parse_pathspec_arg(argv + 1, &args);
rc = ar->write_archive(ar, &args);
diff --git a/archive.h b/archive.h
index 7178e2a9a2..3a4bdfbd07 100644
--- a/archive.h
+++ b/archive.h
@@ -1,8 +1,9 @@
#ifndef ARCHIVE_H
#define ARCHIVE_H
-#include "cache.h"
+#include "object-name.h"
#include "pathspec.h"
+#include "string-list.h"
struct repository;
struct pretty_print_context;
diff --git a/attr.c b/attr.c
index 1053dfcd4b..7d39ac4a29 100644
--- a/attr.c
+++ b/attr.c
@@ -6,16 +6,24 @@
* an insanely large number of attributes.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
#include "exec-cmd.h"
#include "attr.h"
#include "dir.h"
+#include "gettext.h"
+#include "path.h"
#include "utf8.h"
#include "quote.h"
+#include "read-cache-ll.h"
#include "revision.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "setup.h"
#include "thread-utils.h"
+#include "tree-walk.h"
+#include "object-name.h"
const char git_attr__true[] = "(builtin)true";
const char git_attr__false[] = "\0(builtin)false";
@@ -1165,11 +1173,42 @@ static void collect_some_attrs(struct index_state *istate,
fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);
}
+static const char *default_attr_source_tree_object_name;
+
+void set_git_attr_source(const char *tree_object_name)
+{
+ default_attr_source_tree_object_name = xstrdup(tree_object_name);
+}
+
+static void compute_default_attr_source(struct object_id *attr_source)
+{
+ if (!default_attr_source_tree_object_name)
+ default_attr_source_tree_object_name = getenv(GIT_ATTR_SOURCE_ENVIRONMENT);
+
+ if (!default_attr_source_tree_object_name || !is_null_oid(attr_source))
+ return;
+
+ if (repo_get_oid_treeish(the_repository, default_attr_source_tree_object_name, attr_source))
+ die(_("bad --attr-source or GIT_ATTR_SOURCE"));
+}
+
+static struct object_id *default_attr_source(void)
+{
+ static struct object_id attr_source;
+
+ if (is_null_oid(&attr_source))
+ compute_default_attr_source(&attr_source);
+ if (is_null_oid(&attr_source))
+ return NULL;
+ return &attr_source;
+}
+
void git_check_attr(struct index_state *istate,
- const struct object_id *tree_oid, const char *path,
+ const char *path,
struct attr_check *check)
{
int i;
+ const struct object_id *tree_oid = default_attr_source();
collect_some_attrs(istate, tree_oid, path, check);
@@ -1182,10 +1221,11 @@ void git_check_attr(struct index_state *istate,
}
}
-void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
+void git_all_attrs(struct index_state *istate,
const char *path, struct attr_check *check)
{
int i;
+ const struct object_id *tree_oid = default_attr_source();
attr_check_reset(check);
collect_some_attrs(istate, tree_oid, path, check);
diff --git a/attr.h b/attr.h
index 9884ea2bc6..676bd17ce2 100644
--- a/attr.h
+++ b/attr.h
@@ -45,7 +45,7 @@
* const char *path;
*
* setup_check();
- * git_check_attr(&the_index, tree_oid, path, check);
+ * git_check_attr(&the_index, path, check);
* ------------
*
* - Act on `.value` member of the result, left in `check->items[]`:
@@ -120,7 +120,6 @@
#define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024)
struct index_state;
-struct object_id;
/**
* An attribute is an opaque object that is identified by its name. Pass the
@@ -136,6 +135,12 @@ struct all_attrs_item;
struct attr_stack;
/*
+ * The textual object name for the tree-ish used by git_check_attr()
+ * to read attributes from (instead of from the working tree).
+ */
+void set_git_attr_source(const char *);
+
+/*
* Given a string, return the gitattribute object that
* corresponds to it.
*/
@@ -203,14 +208,14 @@ void attr_check_free(struct attr_check *check);
const char *git_attr_name(const struct git_attr *);
void git_check_attr(struct index_state *istate,
- const struct object_id *tree_oid, const char *path,
+ const char *path,
struct attr_check *check);
/*
* Retrieve all attributes that apply to the specified path.
* check holds the attributes and their values.
*/
-void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
+void git_all_attrs(struct index_state *istate,
const char *path, struct attr_check *check);
enum git_attr_direction {
diff --git a/banned.h b/banned.h
index 6ccf46bc19..44e76bd90a 100644
--- a/banned.h
+++ b/banned.h
@@ -18,6 +18,10 @@
#define strncpy(x,y,n) BANNED(strncpy)
#undef strncat
#define strncat(x,y,n) BANNED(strncat)
+#undef strtok
+#define strtok(x,y) BANNED(strtok)
+#undef strtok_r
+#define strtok_r(x,y,z) BANNED(strtok_r)
#undef sprintf
#undef vsprintf
diff --git a/base85.c b/base85.c
index 5ca601ee14..bbacdca31b 100644
--- a/base85.c
+++ b/base85.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "base85.h"
#undef DEBUG_85
diff --git a/base85.h b/base85.h
new file mode 100644
index 0000000000..c835086e09
--- /dev/null
+++ b/base85.h
@@ -0,0 +1,7 @@
+#ifndef BASE85_H
+#define BASE85_H
+
+int decode_85(char *dst, const char *line, int linelen);
+void encode_85(char *buf, const unsigned char *data, int bytes);
+
+#endif /* BASE85_H */
diff --git a/bisect.c b/bisect.c
index ef5ee5a643..1be8e0a271 100644
--- a/bisect.c
+++ b/bisect.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "commit.h"
#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "revision.h"
#include "refs.h"
#include "list-objects.h"
@@ -14,7 +17,9 @@
#include "strvec.h"
#include "commit-slab.h"
#include "commit-reach.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "dir.h"
static struct oid_array good_revs;
@@ -148,8 +153,9 @@ static void show_list(const char *debug, int counted, int nr,
unsigned commit_flags = commit->object.flags;
enum object_type type;
unsigned long size;
- char *buf = read_object_file(&commit->object.oid, &type,
- &size);
+ char *buf = repo_read_object_file(the_repository,
+ &commit->object.oid, &type,
+ &size);
const char *subject_start;
int subject_len;
@@ -751,7 +757,8 @@ enum bisect_error bisect_checkout(const struct object_id *bisect_rev,
}
commit = lookup_commit_reference(the_repository, bisect_rev);
- format_commit_message(commit, "[%H] %s%n", &commit_msg, &pp);
+ repo_format_commit_message(the_repository, commit, "[%H] %s%n",
+ &commit_msg, &pp);
fputs(commit_msg.buf, stdout);
strbuf_release(&commit_msg);
@@ -846,7 +853,8 @@ static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int
enum bisect_error res = BISECT_OK;
struct commit_list *result;
- result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1);
+ result = repo_get_merge_bases_many(the_repository, rev[0], rev_nr - 1,
+ rev + 1);
for (; result; result = result->next) {
const struct object_id *mb = &result->item->object.oid;
diff --git a/blame.c b/blame.c
index 8bfeaa1c63..d12bd9f97b 100644
--- a/blame.c
+++ b/blame.c
@@ -1,11 +1,18 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "cache-tree.h"
#include "mergesort.h"
+#include "convert.h"
#include "diff.h"
#include "diffcore.h"
+#include "gettext.h"
+#include "hex.h"
+#include "path.h"
+#include "read-cache.h"
+#include "setup.h"
#include "tag.h"
+#include "trace2.h"
#include "blame.h"
#include "alloc.h"
#include "commit-slab.h"
@@ -176,12 +183,12 @@ static void set_commit_buffer_from_strbuf(struct repository *r,
static struct commit *fake_working_tree_commit(struct repository *r,
struct diff_options *opt,
const char *path,
- const char *contents_from)
+ const char *contents_from,
+ struct object_id *oid)
{
struct commit *commit;
struct blame_origin *origin;
struct commit_list **parent_tail, *parent;
- struct object_id head_oid;
struct strbuf buf = STRBUF_INIT;
const char *ident;
time_t now;
@@ -197,17 +204,18 @@ static struct commit *fake_working_tree_commit(struct repository *r,
commit->date = now;
parent_tail = &commit->parents;
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
- die("no such ref: HEAD");
-
- parent_tail = append_parent(r, parent_tail, &head_oid);
+ parent_tail = append_parent(r, parent_tail, oid);
append_merge_parents(r, parent_tail);
verify_working_tree_path(r, commit, path);
origin = make_origin(commit, path);
- ident = fmt_ident("Not Committed Yet", "not.committed.yet",
- WANT_BLANK_IDENT, NULL, 0);
+ if (contents_from)
+ ident = fmt_ident("External file (--contents)", "external.file",
+ WANT_BLANK_IDENT, NULL, 0);
+ else
+ ident = fmt_ident("Not Committed Yet", "not.committed.yet",
+ WANT_BLANK_IDENT, NULL, 0);
strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
for (parent = commit->parents; parent; parent = parent->next)
strbuf_addf(&msg, "parent %s\n",
@@ -1028,8 +1036,9 @@ static void fill_origin_blob(struct diff_options *opt,
&o->blob_oid, 1, &file->ptr, &file_size))
;
else
- file->ptr = read_object_file(&o->blob_oid, &type,
- &file_size);
+ file->ptr = repo_read_object_file(the_repository,
+ &o->blob_oid, &type,
+ &file_size);
file->size = file_size;
if (!file->ptr)
@@ -2429,7 +2438,7 @@ static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin,
if (sg_origin[i])
continue;
- if (parse_commit(p))
+ if (repo_parse_commit(the_repository, p))
continue;
porigin = find(sb->repo, p, origin, sb->bloom_data);
if (!porigin)
@@ -2592,7 +2601,7 @@ void assign_blame(struct blame_scoreboard *sb, int opt)
* so hold onto it in the meantime.
*/
blame_origin_incref(suspect);
- parse_commit(commit);
+ repo_parse_commit(the_repository, commit);
if (sb->reverse ||
(!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age)))
@@ -2771,22 +2780,37 @@ void setup_scoreboard(struct blame_scoreboard *sb,
sb->commits.compare = compare_commits_by_reverse_commit_date;
}
- if (sb->final && sb->contents_from)
- die(_("cannot use --contents with final commit object name"));
-
if (sb->reverse && sb->revs->first_parent_only)
sb->revs->children.name = NULL;
- if (!sb->final) {
+ if (sb->contents_from || !sb->final) {
+ struct object_id head_oid, *parent_oid;
+
/*
- * "--not A B -- path" without anything positive;
- * do not default to HEAD, but use the working tree
- * or "--contents".
+ * Build a fake commit at the top of the history, when
+ * (1) "git blame [^A] --path", i.e. with no positive end
+ * of the history range, in which case we build such
+ * a fake commit on top of the HEAD to blame in-tree
+ * modifications.
+ * (2) "git blame --contents=file [A] -- path", with or
+ * without positive end of the history range but with
+ * --contents, in which case we pretend that there is
+ * a fake commit on top of the positive end (defaulting to
+ * HEAD) that has the given contents in the path.
*/
+ if (sb->final) {
+ parent_oid = &sb->final->object.oid;
+ } else {
+ if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
+ die("no such ref: HEAD");
+ parent_oid = &head_oid;
+ }
+
setup_work_tree();
sb->final = fake_working_tree_commit(sb->repo,
&sb->revs->diffopt,
- sb->path, sb->contents_from);
+ sb->path, sb->contents_from,
+ parent_oid);
add_pending_object(sb->revs, &(sb->final->object), ":");
}
@@ -2838,8 +2862,10 @@ void setup_scoreboard(struct blame_scoreboard *sb,
&sb->final_buf_size))
;
else
- sb->final_buf = read_object_file(&o->blob_oid, &type,
- &sb->final_buf_size);
+ sb->final_buf = repo_read_object_file(the_repository,
+ &o->blob_oid,
+ &type,
+ &sb->final_buf_size);
if (!sb->final_buf)
die(_("cannot read blob %s for path %s"),
diff --git a/blame.h b/blame.h
index 38bde535b3..31ddc85f19 100644
--- a/blame.h
+++ b/blame.h
@@ -1,8 +1,8 @@
#ifndef BLAME_H
#define BLAME_H
-#include "cache.h"
#include "commit.h"
+#include "oidset.h"
#include "xdiff-interface.h"
#include "revision.h"
#include "prio-queue.h"
diff --git a/blob.c b/blob.c
index 8f83523b0c..08f9b47f77 100644
--- a/blob.c
+++ b/blob.c
@@ -1,16 +1,23 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "blob.h"
#include "repository.h"
#include "alloc.h"
const char *blob_type = "blob";
-struct blob *lookup_blob(struct repository *r, const struct object_id *oid)
+struct blob *lookup_blob_type(struct repository *r,
+ const struct object_id *oid,
+ enum object_type type)
{
struct object *obj = lookup_object(r, oid);
if (!obj)
return create_object(r, oid, alloc_blob_node(r));
- return object_as_type(obj, OBJ_BLOB, 0);
+ return object_as_type_hint(obj, OBJ_BLOB, type);
+}
+
+struct blob *lookup_blob(struct repository *r, const struct object_id *oid)
+{
+ return lookup_blob_type(r, oid, OBJ_NONE);
}
void parse_blob_buffer(struct blob *item)
diff --git a/blob.h b/blob.h
index 74555c90c4..b91b1600bd 100644
--- a/blob.h
+++ b/blob.h
@@ -10,6 +10,9 @@ struct blob {
};
struct blob *lookup_blob(struct repository *r, const struct object_id *oid);
+struct blob *lookup_blob_type(struct repository *r,
+ const struct object_id *oid,
+ enum object_type type);
/**
* Blobs do not contain references to other objects and do not have
diff --git a/bloom.c b/bloom.c
index d0730525da..aef6b5fea2 100644
--- a/bloom.c
+++ b/bloom.c
@@ -6,6 +6,7 @@
#include "hashmap.h"
#include "commit-graph.h"
#include "commit.h"
+#include "commit-slab.h"
define_commit_slab(bloom_filter_slab, struct bloom_filter);
diff --git a/branch.c b/branch.c
index e5614b53b3..20073284c8 100644
--- a/branch.c
+++ b/branch.c
@@ -1,10 +1,16 @@
#include "git-compat-util.h"
-#include "cache.h"
+#include "advice.h"
#include "config.h"
#include "branch.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "path.h"
#include "refs.h"
#include "refspec.h"
#include "remote.h"
+#include "repository.h"
#include "sequencer.h"
#include "commit.h"
#include "worktree.h"
@@ -531,7 +537,7 @@ static void dwim_branch_start(struct repository *r, const char *start_name,
explicit_tracking = 1;
real_ref = NULL;
- if (get_oid_mb(start_name, &oid)) {
+ if (repo_get_oid_mb(r, start_name, &oid)) {
if (explicit_tracking) {
int code = die_message(_(upstream_missing), start_name);
advise_if_enabled(ADVICE_SET_UPSTREAM_FAILURE,
@@ -541,7 +547,8 @@ static void dwim_branch_start(struct repository *r, const char *start_name,
die(_("not a valid object name: '%s'"), start_name);
}
- switch (dwim_ref(start_name, strlen(start_name), &oid, &real_ref, 0)) {
+ switch (repo_dwim_ref(r, start_name, strlen(start_name), &oid,
+ &real_ref, 0)) {
case 0:
/* Not branching from any existing branch */
if (explicit_tracking)
@@ -772,7 +779,7 @@ void create_branches_recursively(struct repository *r, const char *name,
name);
}
- create_branch(the_repository, name, start_commitish, force, 0, reflog, quiet,
+ create_branch(r, name, start_commitish, force, 0, reflog, quiet,
BRANCH_TRACK_NEVER, dry_run);
if (dry_run)
return;
@@ -820,40 +827,17 @@ void remove_branch_state(struct repository *r, int verbose)
void die_if_checked_out(const char *branch, int ignore_current_worktree)
{
struct worktree **worktrees = get_worktrees();
- const struct worktree *wt;
- wt = find_shared_symref(worktrees, "HEAD", branch);
- if (wt && (!ignore_current_worktree || !wt->is_current)) {
- skip_prefix(branch, "refs/heads/", &branch);
- die(_("'%s' is already checked out at '%s'"), branch, wt->path);
- }
-
- free_worktrees(worktrees);
-}
-
-int replace_each_worktree_head_symref(const char *oldref, const char *newref,
- const char *logmsg)
-{
- int ret = 0;
- struct worktree **worktrees = get_worktrees();
- int i;
-
- for (i = 0; worktrees[i]; i++) {
- struct ref_store *refs;
-
- if (worktrees[i]->is_detached)
- continue;
- if (!worktrees[i]->head_ref)
- continue;
- if (strcmp(oldref, worktrees[i]->head_ref))
+ for (int i = 0; worktrees[i]; i++) {
+ if (worktrees[i]->is_current && ignore_current_worktree)
continue;
- refs = get_worktree_ref_store(worktrees[i]);
- if (refs_create_symref(refs, "HEAD", newref, logmsg))
- ret = error(_("HEAD of working tree %s is not updated"),
- worktrees[i]->path);
+ if (is_shared_symref(worktrees[i], "HEAD", branch)) {
+ skip_prefix(branch, "refs/heads/", &branch);
+ die(_("'%s' is already checked out at '%s'"),
+ branch, worktrees[i]->path);
+ }
}
free_worktrees(worktrees);
- return ret;
}
diff --git a/branch.h b/branch.h
index ef56103c05..30c01aed73 100644
--- a/branch.h
+++ b/branch.h
@@ -155,12 +155,4 @@ int read_branch_desc(struct strbuf *, const char *branch_name);
*/
void die_if_checked_out(const char *branch, int ignore_current_worktree);
-/*
- * Update all per-worktree HEADs pointing at the old ref to point the new ref.
- * This will be used when renaming a branch. Returns 0 if successful, non-zero
- * otherwise.
- */
-int replace_each_worktree_head_symref(const char *oldref, const char *newref,
- const char *logmsg);
-
#endif
diff --git a/builtin.h b/builtin.h
index 46cc789789..d560baa661 100644
--- a/builtin.h
+++ b/builtin.h
@@ -2,9 +2,6 @@
#define BUILTIN_H
#include "git-compat-util.h"
-#include "strbuf.h"
-#include "cache.h"
-#include "commit.h"
/*
* builtin API
@@ -107,6 +104,16 @@ void setup_auto_pager(const char *cmd, int def);
int is_builtin(const char *s);
+/*
+ * Builtins which do not use RUN_SETUP should never see
+ * a prefix that is not empty; use this to protect downstream
+ * code which is not prepared to call prefix_filename(), etc.
+ */
+#define BUG_ON_NON_EMPTY_PREFIX(prefix) do { \
+ if ((prefix)) \
+ BUG("unexpected prefix in builtin: %s", (prefix)); \
+} while (0)
+
int cmd_add(int argc, const char **argv, const char *prefix);
int cmd_am(int argc, const char **argv, const char *prefix);
int cmd_annotate(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index 61dd386d10..e3ca3e4edb 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -4,18 +4,24 @@
* Copyright (C) 2006 Linus Torvalds
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "advice.h"
+#include "config.h"
#include "lockfile.h"
+#include "editor.h"
#include "dir.h"
+#include "gettext.h"
#include "pathspec.h"
#include "exec-cmd.h"
#include "cache-tree.h"
#include "run-command.h"
#include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
#include "diff.h"
#include "diffcore.h"
+#include "read-cache.h"
+#include "repository.h"
#include "revision.h"
#include "bulk-checkin.h"
#include "strvec.h"
@@ -33,11 +39,6 @@ static int pathspec_file_nul;
static int include_sparse;
static const char *pathspec_from_file;
-struct update_callback_data {
- int flags;
- int add_errors;
-};
-
static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
{
int i, ret = 0;
@@ -66,95 +67,6 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
return ret;
}
-static int fix_unmerged_status(struct diff_filepair *p,
- struct update_callback_data *data)
-{
- if (p->status != DIFF_STATUS_UNMERGED)
- return p->status;
- if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
- /*
- * This is not an explicit add request, and the
- * path is missing from the working tree (deleted)
- */
- return DIFF_STATUS_DELETED;
- else
- /*
- * Either an explicit add request, or path exists
- * in the working tree. An attempt to explicitly
- * add a path that does not exist in the working tree
- * will be caught as an error by the caller immediately.
- */
- return DIFF_STATUS_MODIFIED;
-}
-
-static void update_callback(struct diff_queue_struct *q,
- struct diff_options *opt UNUSED, void *cbdata)
-{
- int i;
- struct update_callback_data *data = cbdata;
-
- for (i = 0; i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- const char *path = p->one->path;
-
- if (!include_sparse && !path_in_sparse_checkout(path, &the_index))
- continue;
-
- switch (fix_unmerged_status(p, data)) {
- default:
- die(_("unexpected diff status %c"), p->status);
- case DIFF_STATUS_MODIFIED:
- case DIFF_STATUS_TYPE_CHANGED:
- if (add_file_to_index(&the_index, path, data->flags)) {
- if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
- die(_("updating files failed"));
- data->add_errors++;
- }
- break;
- case DIFF_STATUS_DELETED:
- if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
- break;
- if (!(data->flags & ADD_CACHE_PRETEND))
- remove_file_from_index(&the_index, path);
- if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
- printf(_("remove '%s'\n"), path);
- break;
- }
- }
-}
-
-int add_files_to_cache(const char *prefix,
- const struct pathspec *pathspec, int flags)
-{
- struct update_callback_data data;
- struct rev_info rev;
-
- memset(&data, 0, sizeof(data));
- data.flags = flags;
-
- repo_init_revisions(the_repository, &rev, prefix);
- setup_revisions(0, NULL, &rev, NULL);
- if (pathspec)
- copy_pathspec(&rev.prune_data, pathspec);
- rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
- rev.diffopt.format_callback = update_callback;
- 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);
- end_odb_transaction();
-
- release_revisions(&rev);
- return !!data.add_errors;
-}
-
static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
{
int i, retval = 0;
@@ -637,7 +549,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (add_renormalize)
exit_status |= renormalize_tracked_files(&pathspec, flags);
else
- exit_status |= add_files_to_cache(prefix, &pathspec, flags);
+ exit_status |= add_files_to_cache(the_repository, prefix,
+ &pathspec, include_sparse,
+ flags);
if (add_new_files)
exit_status |= add_files(&dir, flags);
diff --git a/builtin/am.c b/builtin/am.c
index e0848ddadf..5fab159599 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -4,10 +4,15 @@
* Based on git-am.sh by Junio C Hamano.
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
#include "exec-cmd.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
#include "dir.h"
#include "run-command.h"
@@ -22,6 +27,8 @@
#include "diffcore.h"
#include "unpack-trees.h"
#include "branch.h"
+#include "object-name.h"
+#include "preload-index.h"
#include "sequencer.h"
#include "revision.h"
#include "merge-recursive.h"
@@ -33,8 +40,11 @@
#include "apply.h"
#include "string-list.h"
#include "packfile.h"
+#include "pager.h"
+#include "path.h"
#include "repository.h"
#include "pretty.h"
+#include "wrapper.h"
/**
* Returns the length of the first line of msg.
@@ -1066,7 +1076,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
else
write_state_text(state, "applying", "");
- if (!get_oid("HEAD", &curr_head)) {
+ if (!repo_get_oid(the_repository, "HEAD", &curr_head)) {
write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
if (!state->rebasing)
update_ref("am", "ORIG_HEAD", &curr_head, NULL, 0,
@@ -1109,7 +1119,7 @@ static void am_next(struct am_state *state)
unlink(am_path(state, "original-commit"));
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
- if (!get_oid("HEAD", &head))
+ if (!repo_get_oid(the_repository, "HEAD", &head))
write_state_text(state, "abort-safety", oid_to_hex(&head));
else
write_state_text(state, "abort-safety", "");
@@ -1274,7 +1284,7 @@ static int parse_mail(struct am_state *state, const char *mail)
strbuf_addstr(&msg, "\n\n");
strbuf_addbuf(&msg, &mi.log_message);
- strbuf_stripspace(&msg, 0);
+ strbuf_stripspace(&msg, '\0');
assert(!state->author_name);
state->author_name = strbuf_detach(&author_name, NULL);
@@ -1329,7 +1339,8 @@ static void get_commit_info(struct am_state *state, struct commit *commit)
size_t ident_len;
struct ident_split id;
- buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
+ buffer = repo_logmsg_reencode(the_repository, commit, NULL,
+ get_commit_output_encoding());
ident_line = find_commit_header(buffer, "author", &ident_len);
if (!ident_line)
@@ -1361,7 +1372,7 @@ static void get_commit_info(struct am_state *state, struct commit *commit)
die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid));
state->msg = xstrdup(msg + 2);
state->msg_len = strlen(state->msg);
- unuse_commit_buffer(commit, buffer);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
}
/**
@@ -1402,9 +1413,9 @@ static void write_index_patch(const struct am_state *state)
struct rev_info rev_info;
FILE *fp;
- if (!get_oid("HEAD", &head)) {
+ if (!repo_get_oid(the_repository, "HEAD", &head)) {
struct commit *commit = lookup_commit_or_die(&head, "HEAD");
- tree = get_commit_tree(commit);
+ tree = repo_get_commit_tree(the_repository, commit);
} else
tree = lookup_tree(the_repository,
the_repository->hash_algo->empty_tree);
@@ -1556,7 +1567,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
struct commit *result;
char *their_tree_name;
- if (get_oid("HEAD", &our_tree) < 0)
+ if (repo_get_oid(the_repository, "HEAD", &our_tree) < 0)
oidcpy(&our_tree, the_hash_algo->empty_tree);
if (build_fake_ancestor(state, index_path))
@@ -1646,7 +1657,7 @@ static void do_commit(const struct am_state *state)
if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL))
die(_("git write-tree failed to write a tree"));
- if (!get_oid_commit("HEAD", &parent)) {
+ if (!repo_get_oid_commit(the_repository, "HEAD", &parent)) {
old_oid = &parent;
commit_list_insert(lookup_commit(the_repository, &parent),
&parents);
@@ -2088,7 +2099,7 @@ static void am_skip(struct am_state *state)
am_rerere_clear();
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(the_repository, "HEAD", &head))
oidcpy(&head, the_hash_algo->empty_tree);
if (clean_index(&head, &head))
@@ -2130,7 +2141,7 @@ static int safe_to_abort(const struct am_state *state)
oidclr(&abort_safety);
strbuf_release(&sb);
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(the_repository, "HEAD", &head))
oidclr(&head);
if (oideq(&head, &abort_safety))
@@ -2163,7 +2174,7 @@ static void am_abort(struct am_state *state)
if (!has_curr_head)
oidcpy(&curr_head, the_hash_algo->empty_tree);
- has_orig_head = !get_oid("ORIG_HEAD", &orig_head);
+ has_orig_head = !repo_get_oid(the_repository, "ORIG_HEAD", &orig_head);
if (!has_orig_head)
oidcpy(&orig_head, the_hash_algo->empty_tree);
@@ -2300,17 +2311,6 @@ static int parse_opt_show_current_patch(const struct option *opt, const char *ar
return 0;
}
-static int git_am_config(const char *k, const char *v, void *cb UNUSED)
-{
- int status;
-
- status = git_gpg_config(k, v, NULL);
- if (status)
- return status;
-
- return git_default_config(k, v, NULL);
-}
-
int cmd_am(int argc, const char **argv, const char *prefix)
{
struct am_state state;
@@ -2434,7 +2434,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(usage, options);
- git_config(git_am_config, NULL);
+ git_config(git_default_config, NULL);
am_state_init(&state);
diff --git a/builtin/apply.c b/builtin/apply.c
index 555219de40..c18b7ea5d3 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1,6 +1,7 @@
-#include "cache.h"
#include "builtin.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "repository.h"
#include "apply.h"
static const char * const apply_usage[] = {
diff --git a/builtin/archive.c b/builtin/archive.c
index f094390ee0..90761fdfee 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -2,12 +2,13 @@
* Copyright (c) 2006 Franck Bui-Huu
* Copyright (c) 2006 Rene Scharfe
*/
-#include "cache.h"
#include "builtin.h"
#include "archive.h"
+#include "gettext.h"
#include "transport.h"
#include "parse-options.h"
#include "pkt-line.h"
+#include "repository.h"
#include "sideband.h"
static void create_output_file(const char *output_file)
@@ -81,7 +82,7 @@ static int run_remote_archiver(int argc, const char **argv,
int cmd_archive(int argc, const char **argv, const char *prefix)
{
const char *exec = "git-upload-archive";
- const char *output = NULL;
+ char *output = NULL;
const char *remote = NULL;
struct option local_opts[] = {
OPT_FILENAME('o', "output", &output,
@@ -106,5 +107,6 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
+ UNLEAK(output);
return write_archive(argc, argv, prefix, the_repository, output, 0);
}
diff --git a/builtin/bisect.c b/builtin/bisect.c
index 7301740267..6478df3489 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -1,14 +1,21 @@
#include "builtin.h"
-#include "cache.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
#include "parse-options.h"
#include "bisect.h"
#include "refs.h"
#include "dir.h"
#include "strvec.h"
#include "run-command.h"
+#include "oid-array.h"
+#include "path.h"
#include "prompt.h"
#include "quote.h"
#include "revision.h"
+#include "wrapper.h"
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
@@ -235,7 +242,7 @@ static int bisect_reset(const char *commit)
} else {
struct object_id oid;
- if (get_oid_commit(commit, &oid))
+ if (repo_get_oid_commit(the_repository, commit, &oid))
return error(_("'%s' is not a valid commit"), commit);
strbuf_addstr(&branch, commit);
}
@@ -244,7 +251,8 @@ static int bisect_reset(const char *commit)
struct child_process cmd = CHILD_PROCESS_INIT;
cmd.git_cmd = 1;
- strvec_pushl(&cmd.args, "checkout", branch.buf, "--", NULL);
+ strvec_pushl(&cmd.args, "checkout", "--ignore-other-worktrees",
+ branch.buf, "--", NULL);
if (run_command(&cmd)) {
error(_("could not check out original"
" HEAD '%s'. Try 'git bisect"
@@ -265,7 +273,8 @@ static void log_commit(FILE *fp, char *fmt, const char *state,
struct strbuf commit_msg = STRBUF_INIT;
char *label = xstrfmt(fmt, state);
- format_commit_message(commit, "%s", &commit_msg, &pp);
+ repo_format_commit_message(the_repository, commit, "%s", &commit_msg,
+ &pp);
fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
commit_msg.buf);
@@ -292,7 +301,7 @@ static int bisect_write(const char *state, const char *rev,
goto finish;
}
- if (get_oid(rev, &oid)) {
+ if (repo_get_oid(the_repository, rev, &oid)) {
res = error(_("couldn't get the oid of the rev '%s'"), rev);
goto finish;
}
@@ -567,7 +576,7 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
* sets up a revision walk.
*/
reset_revision_walk();
- init_revisions(revs, NULL);
+ repo_init_revisions(the_repository, revs, NULL);
setup_revisions(0, NULL, revs, NULL);
for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
cb.object_flags = UNINTERESTING;
@@ -603,8 +612,8 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
while ((commit = get_revision(&revs)) != NULL) {
strbuf_reset(&commit_name);
- format_commit_message(commit, "%s",
- &commit_name, &pp);
+ repo_format_commit_message(the_repository, commit, "%s",
+ &commit_name, &pp);
fprintf(fp, "# possible first %s commit: [%s] %s\n",
terms->term_bad, oid_to_hex(&commit->object.oid),
commit_name.buf);
@@ -633,7 +642,8 @@ static int bisect_successful(struct bisect_terms *terms)
read_ref(bad_ref, &oid);
commit = lookup_commit_reference_by_name(bad_ref);
- format_commit_message(commit, "%s", &commit_name, &pp);
+ repo_format_commit_message(the_repository, commit, "%s", &commit_name,
+ &pp);
res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
terms->term_bad, oid_to_hex(&commit->object.oid),
@@ -775,7 +785,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
*/
head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
if (!head)
- if (get_oid("HEAD", &head_oid))
+ if (repo_get_oid(the_repository, "HEAD", &head_oid))
return error(_("bad HEAD - I need a HEAD"));
/*
@@ -801,11 +811,11 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
}
} else {
/* Get the rev from where we start. */
- if (!get_oid(head, &head_oid) &&
+ if (!repo_get_oid(the_repository, head, &head_oid) &&
!starts_with(head, "refs/heads/")) {
strbuf_reset(&start_head);
strbuf_addstr(&start_head, oid_to_hex(&head_oid));
- } else if (!get_oid(head, &head_oid) &&
+ } else if (!repo_get_oid(the_repository, head, &head_oid) &&
skip_prefix(head, "refs/heads/", &head)) {
strbuf_addstr(&start_head, head);
} else {
@@ -828,7 +838,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
write_file(git_path_bisect_first_parent(), "\n");
if (no_checkout) {
- if (get_oid(start_head.buf, &oid) < 0) {
+ if (repo_get_oid(the_repository, start_head.buf, &oid) < 0) {
res = error(_("invalid ref: '%s'"), start_head.buf);
goto finish;
}
@@ -933,11 +943,12 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
if (argc == 0) {
const char *head = "BISECT_HEAD";
- enum get_oid_result res_head = get_oid(head, &oid);
+ enum get_oid_result res_head = repo_get_oid(the_repository,
+ head, &oid);
if (res_head == MISSING_OBJECT) {
head = "HEAD";
- res_head = get_oid(head, &oid);
+ res_head = repo_get_oid(the_repository, head, &oid);
}
if (res_head)
@@ -953,7 +964,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
for (; argc; argc--, argv++) {
struct commit *commit;
- if (get_oid(*argv, &oid)){
+ if (repo_get_oid(the_repository, *argv, &oid)){
error(_("Bad rev input: %s"), *argv);
oid_array_clear(&revs);
return BISECT_FAILED;
@@ -1092,7 +1103,7 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
struct rev_info revs;
struct commit *commit;
- init_revisions(&revs, NULL);
+ repo_init_revisions(the_repository, &revs, NULL);
setup_revisions(2, argv + i - 1, &revs, NULL);
if (prepare_revision_walk(&revs))
diff --git a/builtin/blame.c b/builtin/blame.c
index 71f925e456..e811e7fbfb 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -5,10 +5,14 @@
* See COPYING for licensing conditions
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
#include "color.h"
#include "builtin.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "commit.h"
#include "diff.h"
@@ -24,10 +28,14 @@
#include "line-log.h"
#include "dir.h"
#include "progress.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "pager.h"
#include "blame.h"
#include "refs.h"
+#include "setup.h"
#include "tag.h"
+#include "write-or-die.h"
static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
static char annotate_usage[] = N_("git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>");
@@ -199,13 +207,13 @@ static void get_commit_info(struct commit *commit,
const char *message;
encoding = get_log_output_encoding();
- message = logmsg_reencode(commit, NULL, encoding);
+ message = repo_logmsg_reencode(the_repository, commit, NULL, encoding);
get_ac_line(message, "\nauthor ",
&ret->author, &ret->author_mail,
&ret->author_time, &ret->author_tz);
if (!detailed) {
- unuse_commit_buffer(commit, message);
+ repo_unuse_commit_buffer(the_repository, commit, message);
return;
}
@@ -219,7 +227,7 @@ static void get_commit_info(struct commit *commit,
else
strbuf_addf(&ret->summary, "(%s)", oid_to_hex(&commit->object.oid));
- unuse_commit_buffer(commit, message);
+ repo_unuse_commit_buffer(the_repository, commit, message);
}
/*
@@ -601,8 +609,9 @@ static int read_ancestry(const char *graft_file)
static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect)
{
- const char *uniq = find_unique_abbrev(&suspect->commit->object.oid,
- auto_abbrev);
+ const char *uniq = repo_find_unique_abbrev(the_repository,
+ &suspect->commit->object.oid,
+ auto_abbrev);
int len = strlen(uniq);
if (auto_abbrev < len)
return len;
@@ -802,7 +811,7 @@ static int is_a_rev(const char *name)
{
struct object_id oid;
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
return 0;
return OBJ_NONE < oid_object_info(the_repository, &oid, NULL);
}
@@ -845,7 +854,7 @@ static void build_ignorelist(struct blame_scoreboard *sb,
peel_to_commit_oid, sb);
}
for_each_string_list_item(i, ignore_rev_list) {
- if (get_oid_committish(i->string, &oid) ||
+ if (repo_get_oid_committish(the_repository, i->string, &oid) ||
peel_to_commit_oid(&oid, sb))
die(_("cannot find revision %s to ignore"), i->string);
oidset_insert(&sb->ignore_list, &oid);
diff --git a/builtin/branch.c b/builtin/branch.c
index f63fd45edb..6249fa1809 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -5,16 +5,20 @@
* Based on git-branch.sh by Junio C Hamano.
*/
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "color.h"
+#include "editor.h"
+#include "environment.h"
#include "refs.h"
#include "commit.h"
-#include "builtin.h"
+#include "gettext.h"
+#include "object-name.h"
#include "remote.h"
#include "parse-options.h"
#include "branch.h"
#include "diff.h"
+#include "path.h"
#include "revision.h"
#include "string-list.h"
#include "column.h"
@@ -24,6 +28,7 @@
#include "worktree.h"
#include "help.h"
#include "commit-reach.h"
+#include "wrapper.h"
static const char * const builtin_branch_usage[] = {
N_("git branch [<options>] [-r | -a] [--merged] [--no-merged]"),
@@ -41,6 +46,7 @@ static const char *head;
static struct object_id head_oid;
static int recurse_submodules = 0;
static int submodule_propagate_branches = 0;
+static int omit_empty = 0;
static int branch_use_color = -1;
static char branch_colors[][COLOR_MAXLEN] = {
@@ -150,17 +156,18 @@ static int branch_merged(int kind, const char *name,
if (!reference_rev)
reference_rev = head_rev;
- merged = reference_rev ? in_merge_bases(rev, reference_rev) : 0;
+ merged = reference_rev ? repo_in_merge_bases(the_repository, rev,
+ reference_rev) : 0;
/*
* After the safety valve is fully redefined to "check with
* upstream, if any, otherwise with HEAD", we should just
- * return the result of the in_merge_bases() above without
+ * return the result of the repo_in_merge_bases() above without
* any of the following code, but during the transition period,
* a gentle reminder is in order.
*/
if ((head_rev != reference_rev) &&
- (head_rev ? in_merge_bases(rev, head_rev) : 0) != merged) {
+ (head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0) != merged) {
if (merged)
warning(_("deleting branch '%s' that has been merged to\n"
" '%s', but not yet merged to HEAD."),
@@ -216,10 +223,11 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
struct string_list_item *item;
int branch_name_pos;
+ const char *fmt_remotes = "refs/remotes/%s";
switch (kinds) {
case FILTER_REFS_REMOTES:
- fmt = "refs/remotes/%s";
+ fmt = fmt_remotes;
/* For subsequent UI messages */
remote_branch = 1;
allowed_interpret = INTERPRET_BRANCH_REMOTE;
@@ -263,9 +271,25 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
| RESOLVE_REF_ALLOW_BAD_NAME,
&oid, &flags);
if (!target) {
- error(remote_branch
- ? _("remote-tracking branch '%s' not found.")
- : _("branch '%s' not found."), bname.buf);
+ if (remote_branch) {
+ error(_("remote-tracking branch '%s' not found."), bname.buf);
+ } else {
+ char *virtual_name = mkpathdup(fmt_remotes, bname.buf);
+ char *virtual_target = resolve_refdup(virtual_name,
+ RESOLVE_REF_READING
+ | RESOLVE_REF_NO_RECURSE
+ | RESOLVE_REF_ALLOW_BAD_NAME,
+ &oid, &flags);
+ FREE_AND_NULL(virtual_name);
+
+ if (virtual_target)
+ error(_("branch '%s' not found.\n"
+ "Did you forget --remote?"),
+ bname.buf);
+ else
+ error(_("branch '%s' not found."), bname.buf);
+ FREE_AND_NULL(virtual_target);
+ }
ret = 1;
continue;
}
@@ -280,7 +304,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
item = string_list_append(&refs_to_delete, name);
item->util = xstrdup((flags & REF_ISBROKEN) ? "broken"
: (flags & REF_ISSYMREF) ? target
- : find_unique_abbrev(&oid, DEFAULT_ABBREV));
+ : repo_find_unique_abbrev(the_repository, &oid, DEFAULT_ABBREV));
next:
free(target);
@@ -448,6 +472,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
if (verify_ref_format(format))
die(_("unable to parse format string"));
+ filter_ahead_behind(the_repository, format, &array);
ref_array_sort(sorting, &array);
for (i = 0; i < array.nr; i++) {
@@ -461,7 +486,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
string_list_append(output, out.buf);
} else {
fwrite(out.buf, 1, out.len, stdout);
- putchar('\n');
+ if (out.len || !omit_empty)
+ putchar('\n');
}
}
@@ -486,9 +512,9 @@ static void print_current_branch_name(void)
die(_("HEAD (%s) points outside of refs/heads/"), refname);
}
-static void reject_rebase_or_bisect_branch(const char *target)
+static void reject_rebase_or_bisect_branch(struct worktree **worktrees,
+ const char *target)
{
- struct worktree **worktrees = get_worktrees();
int i;
for (i = 0; worktrees[i]; i++) {
@@ -505,17 +531,50 @@ static void reject_rebase_or_bisect_branch(const char *target)
die(_("Branch %s is being bisected at %s"),
target, wt->path);
}
+}
- free_worktrees(worktrees);
+/*
+ * Update all per-worktree HEADs pointing at the old ref to point the new ref.
+ * This will be used when renaming a branch. Returns 0 if successful, non-zero
+ * otherwise.
+ */
+static int replace_each_worktree_head_symref(struct worktree **worktrees,
+ const char *oldref, const char *newref,
+ const char *logmsg)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; worktrees[i]; i++) {
+ struct ref_store *refs;
+
+ if (worktrees[i]->is_detached)
+ continue;
+ if (!worktrees[i]->head_ref)
+ continue;
+ if (strcmp(oldref, worktrees[i]->head_ref))
+ continue;
+
+ refs = get_worktree_ref_store(worktrees[i]);
+ if (refs_create_symref(refs, "HEAD", newref, logmsg))
+ ret = error(_("HEAD of working tree %s is not updated"),
+ worktrees[i]->path);
+ }
+
+ return ret;
}
+#define IS_HEAD 1
+#define IS_ORPHAN 2
+
static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force)
{
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
const char *interpreted_oldname = NULL;
const char *interpreted_newname = NULL;
- int recovery = 0;
+ int recovery = 0, oldref_usage = 0;
+ struct worktree **worktrees = get_worktrees();
if (strbuf_check_branch_ref(&oldref, oldname)) {
/*
@@ -528,8 +587,19 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
die(_("Invalid branch name: '%s'"), oldname);
}
- if ((copy || strcmp(head, oldname)) && !ref_exists(oldref.buf)) {
- if (copy && !strcmp(head, oldname))
+ for (int i = 0; worktrees[i]; i++) {
+ struct worktree *wt = worktrees[i];
+
+ if (wt->head_ref && !strcmp(oldref.buf, wt->head_ref)) {
+ oldref_usage |= IS_HEAD;
+ if (is_null_oid(&wt->head_oid))
+ oldref_usage |= IS_ORPHAN;
+ break;
+ }
+ }
+
+ if ((copy || !(oldref_usage & IS_HEAD)) && !ref_exists(oldref.buf)) {
+ if (oldref_usage & IS_HEAD)
die(_("No commit on branch '%s' yet."), oldname);
else
die(_("No branch named '%s'."), oldname);
@@ -544,7 +614,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
else
validate_new_branchname(newname, &newref, force);
- reject_rebase_or_bisect_branch(oldref.buf);
+ reject_rebase_or_bisect_branch(worktrees, oldref.buf);
if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
!skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
@@ -558,8 +628,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
oldref.buf, newref.buf);
- if (!copy &&
- (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
+ if (!copy && !(oldref_usage & IS_ORPHAN) &&
rename_ref(oldref.buf, newref.buf, logmsg.buf))
die(_("Branch rename failed"));
if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
@@ -574,8 +643,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
interpreted_oldname);
}
- if (!copy &&
- replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf))
+ if (!copy && (oldref_usage & IS_HEAD) &&
+ replace_each_worktree_head_symref(worktrees, oldref.buf, newref.buf,
+ logmsg.buf))
die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
strbuf_release(&logmsg);
@@ -590,6 +660,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
strbuf_release(&newref);
strbuf_release(&oldsection);
strbuf_release(&newsection);
+ free_worktrees(worktrees);
}
static GIT_PATH_FUNC(edit_description, "EDIT_DESCRIPTION")
@@ -603,7 +674,7 @@ static int edit_branch_description(const char *branch_name)
exists = !read_branch_desc(&buf, branch_name);
if (!buf.len || buf.buf[buf.len-1] != '\n')
strbuf_addch(&buf, '\n');
- strbuf_commented_addf(&buf,
+ strbuf_commented_addf(&buf, comment_line_char,
_("Please edit the description for the branch\n"
" %s\n"
"Lines starting with '%c' will be stripped.\n"),
@@ -614,7 +685,7 @@ static int edit_branch_description(const char *branch_name)
strbuf_release(&buf);
return -1;
}
- strbuf_stripspace(&buf, 1);
+ strbuf_stripspace(&buf, comment_line_char);
strbuf_addf(&name, "branch.%s.description", branch_name);
if (buf.len || exists)
@@ -636,7 +707,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int reflog = 0, quiet = 0, icase = 0, force = 0,
recurse_submodules_explicit = 0;
enum branch_track track;
- struct ref_filter filter;
+ struct ref_filter filter = REF_FILTER_INIT;
static struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
@@ -670,6 +741,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
+ OPT_BOOL(0, "omit-empty", &omit_empty,
+ N_("do not output a newline after empty formatted refs")),
OPT_BIT('c', "copy", &copy, N_("copy a branch and its reflog"), 1),
OPT_BIT('C', NULL, &copy, N_("copy a branch, even if target exists"), 2),
OPT_BOOL('l', "list", &list, N_("list branch names")),
@@ -692,7 +765,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
setup_ref_filter_porcelain_msg();
- memset(&filter, 0, sizeof(filter));
filter.kind = FILTER_REFS_BRANCHES;
filter.abbrev = -1;
@@ -786,6 +858,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
ref_sorting_release(sorting);
+ ref_filter_clear(&filter);
return 0;
} else if (edit_description) {
const char *branch_name;
@@ -806,7 +879,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
if (!ref_exists(branch_ref.buf))
- error((!argc || !strcmp(head, branch_name))
+ error((!argc || branch_checked_out(branch_ref.buf))
? _("No commit on branch '%s' yet.")
: _("No branch named '%s'."),
branch_name);
@@ -851,7 +924,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
}
if (!ref_exists(branch->refname)) {
- if (!argc || !strcmp(head, branch->name))
+ if (!argc || branch_checked_out(branch->refname))
die(_("No commit on branch '%s' yet."), branch->name);
die(_("branch '%s' does not exist"), branch->name);
}
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 5bc254be80..daf6c23657 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -1,4 +1,7 @@
#include "builtin.h"
+#include "abspath.h"
+#include "editor.h"
+#include "gettext.h"
#include "parse-options.h"
#include "strbuf.h"
#include "help.h"
@@ -6,7 +9,9 @@
#include "hook.h"
#include "hook-list.h"
#include "diagnose.h"
-
+#include "object-file.h"
+#include "setup.h"
+#include "wrapper.h"
static void get_system_info(struct strbuf *sys_info)
{
diff --git a/builtin/bundle.c b/builtin/bundle.c
index acceef6200..3f63631c03 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -1,7 +1,11 @@
#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "setup.h"
#include "strvec.h"
#include "parse-options.h"
-#include "cache.h"
+#include "pkt-line.h"
+#include "repository.h"
#include "bundle.h"
/*
@@ -12,7 +16,7 @@
*/
#define BUILTIN_BUNDLE_CREATE_USAGE \
- N_("git bundle create [-q | --quiet | --progress | --all-progress] [--all-progress-implied]\n" \
+ N_("git bundle create [-q | --quiet | --progress]\n" \
" [--version=<version>] <file> <git-rev-list-args>")
#define BUILTIN_BUNDLE_VERIFY_USAGE \
N_("git bundle verify [-q | --quiet] <file>")
@@ -59,12 +63,12 @@ static int parse_options_cmd_bundle(int argc,
PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc)
usage_msg_opt(_("need a <file> argument"), usagestr, options);
- *bundle_file = prefix_filename(prefix, argv[0]);
+ *bundle_file = prefix_filename_except_for_dash(prefix, argv[0]);
return argc;
}
static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
- int all_progress_implied = 0;
+ int all_progress_implied = 1;
int progress = isatty(STDERR_FILENO);
struct strvec pack_opts;
int version = -1;
@@ -74,11 +78,12 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
N_("do not show progress meter"), 0),
OPT_SET_INT(0, "progress", &progress,
N_("show progress meter"), 1),
- OPT_SET_INT(0, "all-progress", &progress,
- N_("show progress meter during object writing phase"), 2),
- OPT_BOOL(0, "all-progress-implied",
- &all_progress_implied,
- N_("similar to --all-progress when progress meter is shown")),
+ OPT_SET_INT_F(0, "all-progress", &progress,
+ N_("historical; same as --progress"), 2,
+ PARSE_OPT_HIDDEN),
+ OPT_HIDDEN_BOOL(0, "all-progress-implied",
+ &all_progress_implied,
+ N_("historical; does nothing")),
OPT_INTEGER(0, "version", &version,
N_("specify bundle format version")),
OPT_END()
@@ -107,6 +112,23 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
return ret;
}
+/*
+ * Similar to read_bundle_header(), but handle "-" as stdin.
+ */
+static int open_bundle(const char *path, struct bundle_header *header,
+ const char **name)
+{
+ if (!strcmp(path, "-")) {
+ if (name)
+ *name = "<stdin>";
+ return read_bundle_header_fd(0, header, "<stdin>");
+ }
+
+ if (name)
+ *name = path;
+ return read_bundle_header(path, header);
+}
+
static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
struct bundle_header header = BUNDLE_HEADER_INIT;
int bundle_fd = -1;
@@ -118,12 +140,13 @@ static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
OPT_END()
};
char *bundle_file;
+ const char *name;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_verify_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+ if ((bundle_fd = open_bundle(bundle_file, &header, &name)) < 0) {
ret = 1;
goto cleanup;
}
@@ -134,7 +157,7 @@ static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
goto cleanup;
}
- fprintf(stderr, _("%s is okay\n"), bundle_file);
+ fprintf(stderr, _("%s is okay\n"), name);
ret = 0;
cleanup:
free(bundle_file);
@@ -155,7 +178,7 @@ static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix
builtin_bundle_list_heads_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+ if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
ret = 1;
goto cleanup;
}
@@ -185,7 +208,7 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
builtin_bundle_unbundle_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+ if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
ret = 1;
goto cleanup;
}
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index cc17635e76..48ccca95a1 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -4,19 +4,28 @@
* Copyright (C) Linus Torvalds, 2005
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "alloc.h"
+#include "config.h"
+#include "convert.h"
#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "ident.h"
#include "parse-options.h"
#include "userdiff.h"
#include "streaming.h"
#include "tree-walk.h"
#include "oid-array.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
#include "promisor-remote.h"
#include "mailmap.h"
+#include "write-or-die.h"
enum batch_mode {
BATCH_MODE_CONTENTS,
@@ -60,7 +69,7 @@ static int filter_object(const char *path, unsigned mode,
{
enum object_type type;
- *buf = read_object_file(oid, &type, size);
+ *buf = repo_read_object_file(the_repository, oid, &type, size);
if (!*buf)
return error(_("cannot read object %s '%s'"),
oid_to_hex(oid), path);
@@ -152,7 +161,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
goto cleanup;
case 'e':
- return !has_object_file(&oid);
+ return !repo_has_object_file(the_repository, &oid);
case 'w':
@@ -187,7 +196,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
ret = stream_blob(&oid);
goto cleanup;
}
- buf = read_object_file(&oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &oid, &type,
+ &size);
if (!buf)
die("Cannot read object %s", obj_name);
@@ -207,8 +217,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
if (exp_type_id == OBJ_BLOB) {
struct object_id blob_oid;
if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {
- char *buffer = read_object_file(&oid, &type,
- &size);
+ char *buffer = repo_read_object_file(the_repository,
+ &oid,
+ &type,
+ &size);
const char *target;
if (!skip_prefix(buffer, "object ", &target) ||
get_oid_hex(target, &blob_oid))
@@ -383,9 +395,10 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
if (!textconv_object(the_repository,
data->rest, 0100644, oid,
1, &contents, &size))
- contents = read_object_file(oid,
- &type,
- &size);
+ contents = repo_read_object_file(the_repository,
+ oid,
+ &type,
+ &size);
if (!contents)
die("could not convert '%s' %s",
oid_to_hex(oid), data->rest);
@@ -402,7 +415,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
unsigned long size;
void *contents;
- contents = read_object_file(oid, &type, &size);
+ contents = repo_read_object_file(the_repository, oid, &type,
+ &size);
if (use_mailmap) {
size_t s = size;
@@ -559,7 +573,7 @@ static int batch_object_cb(const struct object_id *oid, void *vdata)
}
static int collect_loose_object(const struct object_id *oid,
- const char *path,
+ const char *path UNUSED,
void *data)
{
oid_array_append(data, oid);
@@ -567,8 +581,8 @@ static int collect_loose_object(const struct object_id *oid,
}
static int collect_packed_object(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED,
void *data)
{
oid_array_append(data, oid);
@@ -591,7 +605,7 @@ static int batch_unordered_object(const struct object_id *oid,
}
static int batch_unordered_loose(const struct object_id *oid,
- const char *path,
+ const char *path UNUSED,
void *data)
{
return batch_unordered_object(oid, NULL, 0, data);
@@ -787,7 +801,7 @@ static int batch_objects(struct batch_options *opt)
if (!memcmp(&data.info, &empty, sizeof(empty)))
data.skip_object_info = 1;
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
warning("This repository uses promisor remotes. Some objects may not be loaded.");
read_replace_refs = 0;
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index d7a40e674c..b22ff748c3 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -1,10 +1,15 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "attr.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-name.h"
#include "quote.h"
+#include "repository.h"
+#include "setup.h"
#include "parse-options.h"
+#include "write-or-die.h"
static int all_attrs;
static int cached_attrs;
@@ -58,7 +63,7 @@ static void output_attr(struct attr_check *check, const char *file)
}
static void check_attr(const char *prefix, struct attr_check *check,
- const struct object_id *tree_oid, int collect_all,
+ int collect_all,
const char *file)
{
@@ -66,9 +71,9 @@ static void check_attr(const char *prefix, struct attr_check *check,
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
if (collect_all) {
- git_all_attrs(&the_index, tree_oid, full_path, check);
+ git_all_attrs(&the_index, full_path, check);
} else {
- git_check_attr(&the_index, tree_oid, full_path, check);
+ git_check_attr(&the_index, full_path, check);
}
output_attr(check, file);
@@ -76,7 +81,7 @@ static void check_attr(const char *prefix, struct attr_check *check,
}
static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
- const struct object_id *tree_oid, int collect_all)
+ int collect_all)
{
struct strbuf buf = STRBUF_INIT;
struct strbuf unquoted = STRBUF_INIT;
@@ -90,7 +95,7 @@ static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
die("line is badly quoted");
strbuf_swap(&buf, &unquoted);
}
- check_attr(prefix, check, tree_oid, collect_all, buf.buf);
+ check_attr(prefix, check, collect_all, buf.buf);
maybe_flush_or_die(stdout, "attribute to stdout");
}
strbuf_release(&buf);
@@ -106,7 +111,6 @@ static NORETURN void error_with_usage(const char *msg)
int cmd_check_attr(int argc, const char **argv, const char *prefix)
{
struct attr_check *check;
- struct object_id *tree_oid = NULL;
struct object_id initialized_oid;
int cnt, i, doubledash, filei;
@@ -182,14 +186,14 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
if (source) {
if (repo_get_oid_tree(the_repository, source, &initialized_oid))
die("%s: not a valid tree-ish source", source);
- tree_oid = &initialized_oid;
+ set_git_attr_source(source);
}
if (stdin_paths)
- check_attr_stdin_paths(prefix, check, tree_oid, all_attrs);
+ check_attr_stdin_paths(prefix, check, all_attrs);
else {
for (i = filei; i < argc; i++)
- check_attr(prefix, check, tree_oid, all_attrs, argv[i]);
+ check_attr(prefix, check, all_attrs, argv[i]);
maybe_flush_or_die(stdout, "attribute to stdout");
}
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index ab776061c7..906cd96753 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -1,12 +1,14 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "dir.h"
+#include "gettext.h"
#include "quote.h"
#include "pathspec.h"
#include "parse-options.h"
+#include "repository.h"
#include "submodule.h"
+#include "write-or-die.h"
static int quiet, verbose, stdin_paths, show_non_matching, no_index;
static const char * const check_ignore_usage[] = {
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index 7dc47e4793..b8a05b8e07 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -1,8 +1,12 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
+#include "ident.h"
#include "mailmap.h"
#include "parse-options.h"
+#include "strbuf.h"
#include "string-list.h"
+#include "write-or-die.h"
static int use_stdin;
static const char * const check_mailmap_usage[] = {
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index fd0e5f8683..5eb6bdc3f6 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -2,9 +2,9 @@
* GIT - The information manager from hell
*/
-#include "cache.h"
-#include "refs.h"
#include "builtin.h"
+#include "refs.h"
+#include "setup.h"
#include "strbuf.h"
static const char builtin_check_ref_format_usage[] =
@@ -60,6 +60,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
char *to_free = NULL;
int ret = 1;
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_check_ref_format_usage);
diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c
index ede7dc32a4..c655dc4b13 100644
--- a/builtin/checkout--worker.c
+++ b/builtin/checkout--worker.c
@@ -1,9 +1,12 @@
#include "builtin.h"
+#include "alloc.h"
#include "config.h"
#include "entry.h"
+#include "gettext.h"
#include "parallel-checkout.h"
#include "parse-options.h"
#include "pkt-line.h"
+#include "read-cache-ll.h"
static void packet_to_pc_item(const char *buffer, int len,
struct parallel_checkout_item *pc_item)
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index cf6fba97ba..f62f13f2b5 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -8,12 +8,17 @@
#include "builtin.h"
#include "config.h"
#include "dir.h"
+#include "gettext.h"
#include "lockfile.h"
#include "quote.h"
+#include "repository.h"
#include "cache-tree.h"
#include "parse-options.h"
#include "entry.h"
#include "parallel-checkout.h"
+#include "read-cache-ll.h"
+#include "setup.h"
+#include "sparse-index.h"
#define CHECKOUT_ALL 4
static int nul_term_line;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index a5155cf55c..f669fe53f3 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -9,19 +9,30 @@
#include "config.h"
#include "diff.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "hook.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
#include "lockfile.h"
+#include "mem-pool.h"
#include "merge-recursive.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
#include "refs.h"
#include "remote.h"
#include "resolve-undo.h"
#include "revision.h"
#include "run-command.h"
+#include "setup.h"
#include "submodule.h"
#include "submodule-config.h"
+#include "symlinks.h"
+#include "trace2.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
@@ -75,7 +86,7 @@ struct checkout_opts {
const char *ignore_unmerged_opt;
int ignore_unmerged;
int pathspec_file_nul;
- const char *pathspec_from_file;
+ char *pathspec_from_file;
const char *new_branch;
const char *new_branch_force;
@@ -432,8 +443,8 @@ static int checkout_worktree(const struct checkout_opts *opts,
"Updated %d paths from %s",
nr_checkouts),
nr_checkouts,
- find_unique_abbrev(&opts->source_tree->object.oid,
- DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &opts->source_tree->object.oid,
+ DEFAULT_ABBREV));
else if (!nr_unmerged || nr_checkouts)
fprintf_ln(stderr, Q_("Updated %d path from the index",
"Updated %d paths from the index",
@@ -489,15 +500,28 @@ static int checkout_paths(const struct checkout_opts *opts,
die(_("'%s' must be used when '%s' is not specified"),
"--worktree", "--source");
- if (opts->checkout_index && !opts->checkout_worktree &&
- opts->writeout_stage)
- die(_("'%s' or '%s' cannot be used with %s"),
- "--ours", "--theirs", "--staged");
-
- if (opts->checkout_index && !opts->checkout_worktree &&
- opts->merge)
- die(_("'%s' or '%s' cannot be used with %s"),
- "--merge", "--conflict", "--staged");
+ /*
+ * Reject --staged option to the restore command when combined with
+ * merge-related options. Use the accept_ref flag to distinguish it
+ * from the checkout command, which does not accept --staged anyway.
+ *
+ * `restore --ours|--theirs --worktree --staged` could mean resolving
+ * conflicted paths to one side in both the worktree and the index,
+ * but does not currently.
+ *
+ * `restore --merge|--conflict=<style>` already recreates conflicts
+ * in both the worktree and the index, so adding --staged would be
+ * meaningless.
+ */
+ if (!opts->accept_ref && opts->checkout_index) {
+ if (opts->writeout_stage)
+ die(_("'%s' or '%s' cannot be used with %s"),
+ "--ours", "--theirs", "--staged");
+
+ if (opts->merge)
+ die(_("'%s' or '%s' cannot be used with %s"),
+ "--merge", "--conflict", "--staged");
+ }
if (opts->patch_mode) {
enum add_p_mode patch_mode;
@@ -640,14 +664,16 @@ static void describe_detached_head(const char *msg, struct commit *commit)
{
struct strbuf sb = STRBUF_INIT;
- if (!parse_commit(commit))
+ if (!repo_parse_commit(the_repository, commit))
pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
if (print_sha1_ellipsis()) {
fprintf(stderr, "%s %s... %s\n", msg,
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf);
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
+ sb.buf);
} else {
fprintf(stderr, "%s %s %s\n", msg,
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf);
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
+ sb.buf);
}
strbuf_release(&sb);
}
@@ -701,7 +727,8 @@ static void setup_branch_path(struct branch_info *branch)
* If this is a ref, resolve it; otherwise, look up the OID for our
* expression. Failure here is okay.
*/
- if (!dwim_ref(branch->name, strlen(branch->name), &branch->oid, &branch->refname, 0))
+ if (!repo_dwim_ref(the_repository, branch->name, strlen(branch->name),
+ &branch->oid, &branch->refname, 0))
repo_get_oid_committish(the_repository, branch->name, &branch->oid);
strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
@@ -753,7 +780,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
BUG("'switch --orphan' should never accept a commit as starting point");
new_tree = parse_tree_indirect(the_hash_algo->empty_tree);
} else
- new_tree = get_commit_tree(new_branch_info->commit);
+ new_tree = repo_get_commit_tree(the_repository,
+ new_branch_info->commit);
if (opts->discard_changes) {
ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
if (ret)
@@ -815,7 +843,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
*/
if (!old_branch_info->commit)
return 1;
- old_tree = get_commit_tree(old_branch_info->commit);
+ old_tree = repo_get_commit_tree(the_repository,
+ old_branch_info->commit);
if (repo_index_has_changes(the_repository, old_tree, &sb))
die(_("cannot continue with staged changes in "
@@ -835,7 +864,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
* entries in the index.
*/
- add_files_to_cache(NULL, NULL, 0);
+ add_files_to_cache(the_repository, NULL, NULL, 0, 0);
init_merge_options(&o, the_repository);
o.verbosity = 0;
work = write_in_core_index_as_tree(the_repository);
@@ -1004,7 +1033,7 @@ static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
strbuf_addstr(sb, " ");
strbuf_add_unique_abbrev(sb, &commit->object.oid, DEFAULT_ABBREV);
strbuf_addch(sb, ' ');
- if (!parse_commit(commit))
+ if (!repo_parse_commit(the_repository, commit))
pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
strbuf_addch(sb, '\n');
}
@@ -1060,7 +1089,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
" git branch <new-branch-name> %s\n\n",
/* Give ngettext() the count */
lost),
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
}
/*
@@ -1204,7 +1233,8 @@ static void setup_new_branch_info_and_source_tree(
*source_tree = parse_tree_indirect(rev);
} else {
parse_commit_or_die(new_branch_info->commit);
- *source_tree = get_commit_tree(new_branch_info->commit);
+ *source_tree = repo_get_commit_tree(the_repository,
+ new_branch_info->commit);
}
}
@@ -1322,7 +1352,7 @@ static int parse_branchname_arg(int argc, const char **argv,
if (!strcmp(arg, "-"))
arg = "@{-1}";
- if (get_oid_mb(arg, rev)) {
+ if (repo_get_oid_mb(the_repository, arg, rev)) {
/*
* Either case (3) or (4), with <something> not being
* a commit, or an attempt to use case (1) with an
@@ -1419,7 +1449,8 @@ static void die_expecting_a_branch(const struct branch_info *branch_info)
char *to_free;
int code;
- if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free, 0) == 1) {
+ if (repo_dwim_ref(the_repository, branch_info->name,
+ strlen(branch_info->name), &oid, &to_free, 0) == 1) {
const char *ref = to_free;
if (skip_prefix(ref, "refs/tags/", &ref))
@@ -1478,7 +1509,8 @@ static void die_if_some_operation_in_progress(void)
}
static int checkout_branch(struct checkout_opts *opts,
- struct branch_info *new_branch_info)
+ struct branch_info *new_branch_info,
+ char *check_branch_path)
{
if (opts->pathspec.nr)
die(_("paths cannot be used with switching branches"));
@@ -1537,13 +1569,13 @@ static int checkout_branch(struct checkout_opts *opts,
if (!opts->can_switch_when_in_progress)
die_if_some_operation_in_progress();
- if (new_branch_info->path && !opts->force_detach && !opts->new_branch &&
- !opts->ignore_other_worktrees) {
+ if (!opts->ignore_other_worktrees && !opts->force_detach &&
+ check_branch_path && ref_exists(check_branch_path)) {
int flag;
char *head_ref = resolve_refdup("HEAD", 0, NULL, &flag);
- if (head_ref &&
- (!(flag & REF_ISSYMREF) || strcmp(head_ref, new_branch_info->path)))
- die_if_checked_out(new_branch_info->path, 1);
+ if (opts->new_branch_force || (head_ref &&
+ (!(flag & REF_ISSYMREF) || strcmp(head_ref, check_branch_path))))
+ die_if_checked_out(check_branch_path, 1);
free(head_ref);
}
@@ -1631,7 +1663,9 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
const char * const usagestr[],
struct branch_info *new_branch_info)
{
+ int ret;
int parseopt_flags = 0;
+ char *check_branch_path = NULL;
opts->overwrite_ignore = 1;
opts->prefix = prefix;
@@ -1721,6 +1755,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->new_branch = argv0 + 1;
}
+ if (opts->new_branch && !opts->ignore_other_worktrees) {
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_branchname(&buf, opts->new_branch, INTERPRET_BRANCH_LOCAL);
+ strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
+ check_branch_path = strbuf_detach(&buf, NULL);
+ }
/*
* Extract branch name from command line arguments, so
* all that is left is pathspecs.
@@ -1745,10 +1786,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
new_branch_info, opts, &rev);
argv += n;
argc -= n;
+
+ if (!opts->ignore_other_worktrees && !check_branch_path && new_branch_info->path)
+ check_branch_path = xstrdup(new_branch_info->path);
} else if (!opts->accept_ref && opts->from_treeish) {
struct object_id rev;
- if (get_oid_mb(opts->from_treeish, &rev))
+ if (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))
die(_("could not resolve %s"), opts->from_treeish);
setup_new_branch_info_and_source_tree(new_branch_info,
@@ -1821,9 +1865,12 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
}
if (opts->patch_mode || opts->pathspec.nr)
- return checkout_paths(opts, new_branch_info);
+ ret = checkout_paths(opts, new_branch_info);
else
- return checkout_branch(opts, new_branch_info);
+ ret = checkout_branch(opts, new_branch_info, check_branch_path);
+
+ free(check_branch_path);
+ return ret;
}
int cmd_checkout(int argc, const char **argv, const char *prefix)
@@ -1876,6 +1923,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
options, checkout_usage, &new_branch_info);
branch_info_release(&new_branch_info);
clear_pathspec(&opts.pathspec);
+ free(opts.pathspec_from_file);
FREE_AND_NULL(options);
return ret;
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 10aaa8c603..1bb6b7965c 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -8,10 +8,15 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
#include "config.h"
#include "dir.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
#include "string-list.h"
#include "quote.h"
#include "column.h"
diff --git a/builtin/clone.c b/builtin/clone.c
index 65b5b7db6d..687a686269 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -10,13 +10,20 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
#include "config.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "parse-options.h"
#include "fetch-pack.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
@@ -29,12 +36,16 @@
#include "branch.h"
#include "remote.h"
#include "run-command.h"
+#include "setup.h"
#include "connected.h"
#include "packfile.h"
+#include "path.h"
+#include "pkt-line.h"
#include "list-objects-filter-options.h"
#include "hook.h"
#include "bundle.h"
#include "bundle-uri.h"
+#include "wrapper.h"
/*
* Overall FIXMEs:
@@ -326,8 +337,18 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC);
- if (!iter)
+ if (!iter) {
+ if (errno == ENOTDIR) {
+ int saved_errno = errno;
+ struct stat st;
+
+ if (!lstat(src->buf, &st) && S_ISLNK(st.st_mode))
+ die(_("'%s' is a symlink, refusing to clone with --local"),
+ src->buf);
+ errno = saved_errno;
+ }
die_errno(_("failed to start iterator over '%s'"), src->buf);
+ }
strbuf_addch(src, '/');
src_len = src->len;
@@ -547,9 +568,9 @@ static void write_followtags(const struct ref *refs, const char *msg)
continue;
if (ends_with(ref->name, "^{}"))
continue;
- if (!has_object_file_with_flags(&ref->old_oid,
- OBJECT_INFO_QUICK |
- OBJECT_INFO_SKIP_FETCH_OBJECT))
+ if (!repo_has_object_file_with_flags(the_repository, &ref->old_oid,
+ OBJECT_INFO_QUICK |
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
continue;
update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
@@ -909,6 +930,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int err = 0, complete_refs_before_fetch = 1;
int submodule_progress;
int filter_submodules = 0;
+ int hash_algo;
+ const int do_not_override_repo_unix_permissions = -1;
struct transport_ls_refs_options transport_ls_refs_options =
TRANSPORT_LS_REFS_OPTIONS_INIT;
@@ -1076,7 +1099,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
- INIT_DB_QUIET);
+ do_not_override_repo_unix_permissions, INIT_DB_QUIET);
if (real_git_dir) {
free((char *)git_dir);
@@ -1297,15 +1320,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
}
- if (mapped_refs) {
- int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
-
/*
* Now that we know what algorithm the remote side is using,
* let's set ours to the same thing.
*/
- initialize_repository_version(hash_algo, 1);
- repo_set_hash_algo(the_repository, hash_algo);
+ hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+ initialize_repository_version(hash_algo, 1);
+ repo_set_hash_algo(the_repository, hash_algo);
+
+ if (mapped_refs) {
/*
* transport_get_remote_refs() may return refs with null sha-1
* in mapped_refs (see struct transport->get_refs_list
diff --git a/builtin/column.c b/builtin/column.c
index 158fdf53d9..ce13ff0baa 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -1,6 +1,6 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "gettext.h"
#include "strbuf.h"
#include "parse-options.h"
#include "string-list.h"
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 93704f95a9..48fa9f20c9 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -1,13 +1,19 @@
#include "builtin.h"
+#include "commit.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "parse-options.h"
#include "repository.h"
#include "commit-graph.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "progress.h"
+#include "replace-object.h"
#include "tag.h"
+#include "trace2.h"
#define BUILTIN_COMMIT_GRAPH_VERIFY_USAGE \
N_("git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]")
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index cc8d584be2..02625e7176 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -3,13 +3,15 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "repository.h"
#include "commit.h"
#include "tree.h"
-#include "builtin.h"
#include "utf8.h"
#include "gpg-interface.h"
#include "parse-options.h"
@@ -37,14 +39,6 @@ static void new_parent(struct commit *parent, struct commit_list **parents_p)
commit_list_insert(parent, parents_p);
}
-static int commit_tree_config(const char *var, const char *value, void *cb)
-{
- int status = git_gpg_config(var, value, NULL);
- if (status)
- return status;
- return git_default_config(var, value, cb);
-}
-
static int parse_parent_arg_callback(const struct option *opt,
const char *arg, int unset)
{
@@ -53,7 +47,7 @@ static int parse_parent_arg_callback(const struct option *opt,
BUG_ON_OPT_NEG_NOARG(unset, arg);
- if (get_oid_commit(arg, &oid))
+ if (repo_get_oid_commit(the_repository, arg, &oid))
die(_("not a valid object name %s"), arg);
assert_oid_type(&oid, OBJ_COMMIT);
@@ -121,7 +115,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
OPT_END()
};
- git_config(commit_tree_config, NULL);
+ git_config(git_default_config, NULL);
if (argc < 2 || !strcmp(argv[1], "-h"))
usage_with_options(commit_tree_usage, options);
@@ -131,7 +125,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
if (argc != 1)
die(_("must give exactly one tree"));
- if (get_oid_tree(argv[0], &tree_oid))
+ if (repo_get_oid_tree(the_repository, argv[0], &tree_oid))
die(_("not a valid object name %s"), argv[0]);
if (!buffer.len) {
diff --git a/builtin/commit.c b/builtin/commit.c
index 985a0445b7..56a3602ffa 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -6,16 +6,19 @@
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
+#include "advice.h"
#include "config.h"
#include "lockfile.h"
#include "cache-tree.h"
#include "color.h"
#include "dir.h"
-#include "builtin.h"
+#include "editor.h"
+#include "environment.h"
#include "diff.h"
#include "diffcore.h"
#include "commit.h"
+#include "gettext.h"
#include "revision.h"
#include "wt-status.h"
#include "run-command.h"
@@ -24,7 +27,11 @@
#include "log-tree.h"
#include "strbuf.h"
#include "utf8.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
#include "string-list.h"
#include "rerere.h"
#include "unpack-trees.h"
@@ -33,6 +40,7 @@
#include "gpg-interface.h"
#include "column.h"
#include "sequencer.h"
+#include "sparse-index.h"
#include "mailmap.h"
#include "help.h"
#include "commit-reach.h"
@@ -442,7 +450,8 @@ static const char *prepare_index(const char **argv, const char *prefix,
if (all || (also && pathspec.nr)) {
repo_hold_locked_index(the_repository, &index_lock,
LOCK_DIE_ON_ERROR);
- add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
+ add_files_to_cache(the_repository, also ? prefix : NULL,
+ &pathspec, 0, 0);
refresh_cache_or_die(refresh_flags);
cache_tree_update(&the_index, WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock, 0))
@@ -557,7 +566,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
s->index_file = index_file;
s->fp = fp;
s->nowarn = nowarn;
- s->is_initial = get_oid(s->reference, &oid) ? 1 : 0;
+ s->is_initial = repo_get_oid(the_repository, s->reference, &oid) ? 1 : 0;
if (!s->is_initial)
oidcpy(&s->oid_commit, &oid);
s->status_format = status_format;
@@ -712,15 +721,15 @@ static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
{
const char *buffer, *subject, *fmt;
- buffer = get_commit_buffer(commit, NULL);
+ buffer = repo_get_commit_buffer(the_repository, commit, NULL);
find_commit_subject(buffer, &subject);
/*
* If we amend the 'amend!' commit then we don't want to
* duplicate the subject line.
*/
fmt = starts_with(subject, "amend!") ? "%b" : "%B";
- format_commit_message(commit, fmt, sb, ctx);
- unuse_commit_buffer(commit, buffer);
+ repo_format_commit_message(the_repository, commit, fmt, sb, ctx);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
}
static int prepare_to_commit(const char *index_file, const char *prefix,
@@ -760,8 +769,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (!c)
die(_("could not lookup commit %s"), squash_message);
ctx.output_encoding = get_commit_output_encoding();
- format_commit_message(c, "squash! %s\n\n", &sb,
- &ctx);
+ repo_format_commit_message(the_repository, c,
+ "squash! %s\n\n", &sb,
+ &ctx);
}
}
@@ -795,7 +805,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
die(_("could not lookup commit %s"), fixup_commit);
ctx.output_encoding = get_commit_output_encoding();
fmt = xstrfmt("%s! %%s\n\n", fixup_prefix);
- format_commit_message(commit, fmt, &sb, &ctx);
+ repo_format_commit_message(the_repository, commit, fmt, &sb,
+ &ctx);
free(fmt);
hook_arg1 = "message";
@@ -886,7 +897,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
s->hints = 0;
if (clean_message_contents)
- strbuf_stripspace(&sb, 0);
+ strbuf_stripspace(&sb, '\0');
if (signoff)
append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);
@@ -1000,7 +1011,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (amend)
parent = "HEAD^1";
- if (get_oid(parent, &oid)) {
+ if (repo_get_oid(the_repository, parent, &oid)) {
int i, ita_nr = 0;
/* TODO: audit for interaction with sparse-index. */
@@ -1135,7 +1146,8 @@ static const char *find_author_by_nickname(const char *name)
struct pretty_print_context ctx = {0};
ctx.date_mode.type = DATE_NORMAL;
strbuf_release(&buf);
- format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
+ repo_format_commit_message(the_repository, commit,
+ "%aN <%aE>", &buf, &ctx);
release_revisions(&revs);
return strbuf_detach(&buf, NULL);
}
@@ -1183,7 +1195,7 @@ static const char *read_commit_message(const char *name)
if (!commit)
die(_("could not lookup commit %s"), name);
out_enc = get_commit_output_encoding();
- return logmsg_reencode(commit, NULL, out_enc);
+ return repo_logmsg_reencode(the_repository, commit, NULL, out_enc);
}
/*
@@ -1567,7 +1579,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
else
fd = -1;
- s.is_initial = get_oid(s.reference, &oid) ? 1 : 0;
+ s.is_initial = repo_get_oid(the_repository, s.reference, &oid) ? 1 : 0;
if (!s.is_initial)
oidcpy(&s.oid_commit, &oid);
@@ -1600,7 +1612,6 @@ int cmd_status(int argc, const char **argv, const char *prefix)
static int git_commit_config(const char *k, const char *v, void *cb)
{
struct wt_status *s = cb;
- int status;
if (!strcmp(k, "commit.template"))
return git_config_pathname(&template_file, k, v);
@@ -1620,9 +1631,6 @@ static int git_commit_config(const char *k, const char *v, void *cb)
return 0;
}
- status = git_gpg_config(k, v, NULL);
- if (status)
- return status;
return git_status_config(k, v, s);
}
@@ -1714,11 +1722,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
s.colopts = 0;
- if (get_oid("HEAD", &oid))
+ if (repo_get_oid(the_repository, "HEAD", &oid))
current_head = NULL;
else {
current_head = lookup_commit_or_die(&oid, "HEAD");
- if (parse_commit(current_head))
+ if (repo_parse_commit(the_repository, current_head))
die(_("could not parse HEAD commit"));
}
verbose = -1; /* unspecified */
diff --git a/builtin/config.c b/builtin/config.c
index 060cf9f3e0..30f6d9fe67 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -1,11 +1,20 @@
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
#include "color.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "ident.h"
#include "parse-options.h"
#include "urlmatch.h"
+#include "path.h"
#include "quote.h"
+#include "setup.h"
+#include "strbuf.h"
#include "worktree.h"
+#include "wrapper.h"
static const char *const builtin_config_usage[] = {
N_("git config [<options>]"),
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 07b9419596..97cdfb0ac5 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -4,15 +4,17 @@
* Copyright (c) 2006 Junio C Hamano
*/
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "path.h"
#include "repository.h"
-#include "builtin.h"
#include "parse-options.h"
#include "quote.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
static unsigned long garbage;
static off_t size_garbage;
@@ -57,7 +59,8 @@ static void loose_garbage(const char *path)
report_garbage(PACKDIR_FILE_GARBAGE, path);
}
-static int count_loose(const struct object_id *oid, const char *path, void *data)
+static int count_loose(const struct object_id *oid, const char *path,
+ void *data UNUSED)
{
struct stat st;
@@ -72,7 +75,8 @@ static int count_loose(const struct object_id *oid, const char *path, void *data
return 0;
}
-static int count_cruft(const char *basename, const char *path, void *data)
+static int count_cruft(const char *basename UNUSED, const char *path,
+ void *data UNUSED)
{
loose_garbage(path);
return 0;
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 338058be7f..756c5f02ae 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -1,4 +1,8 @@
#include "builtin.h"
+#include "abspath.h"
+#include "alloc.h"
+#include "gettext.h"
+#include "object-file.h"
#include "parse-options.h"
#ifndef NO_UNIX_SOCKETS
@@ -130,6 +134,9 @@ static void serve_one_client(FILE *in, FILE *out)
if (e->item.password_expiry_utc != TIME_MAX)
fprintf(out, "password_expiry_utc=%"PRItime"\n",
e->item.password_expiry_utc);
+ if (e->item.oauth_refresh_token)
+ fprintf(out, "oauth_refresh_token=%s\n",
+ e->item.oauth_refresh_token);
}
}
else if (!strcmp(action.buf, "exit")) {
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index 78c02ad531..ff3a47badb 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -1,5 +1,10 @@
#include "builtin.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
+#include "strbuf.h"
+#include "wrapper.h"
+#include "write-or-die.h"
#ifndef NO_UNIX_SOCKETS
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index 62a4f3c265..5eea5bdb58 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -1,9 +1,12 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
#include "lockfile.h"
#include "credential.h"
+#include "path.h"
#include "string-list.h"
#include "parse-options.h"
+#include "write-or-die.h"
static struct lock_file credential_lock;
@@ -71,6 +74,25 @@ static void rewrite_credential_file(const char *fn, struct credential *c,
die_errno("unable to write credential store");
}
+static int is_rfc3986_unreserved(char ch)
+{
+ return isalnum(ch) ||
+ ch == '-' || ch == '_' || ch == '.' || ch == '~';
+}
+
+static int is_rfc3986_reserved_or_unreserved(char ch)
+{
+ if (is_rfc3986_unreserved(ch))
+ return 1;
+ switch (ch) {
+ case '!': case '*': case '\'': case '(': case ')': case ';':
+ case ':': case '@': case '&': case '=': case '+': case '$':
+ case ',': case '/': case '?': case '#': case '[': case ']':
+ return 1;
+ }
+ return 0;
+}
+
static void store_credential_file(const char *fn, struct credential *c)
{
struct strbuf buf = STRBUF_INIT;
diff --git a/builtin/credential.c b/builtin/credential.c
index d7b304fa08..7010752987 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -6,7 +6,7 @@
static const char usage_msg[] =
"git credential (fill|approve|reject)";
-int cmd_credential(int argc, const char **argv, const char *prefix)
+int cmd_credential(int argc, const char **argv, const char *prefix UNUSED)
{
const char *op;
struct credential c = CREDENTIAL_INIT;
diff --git a/builtin/describe.c b/builtin/describe.c
index eea1e330c0..7ce23e1b8e 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -1,22 +1,28 @@
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "commit.h"
#include "tag.h"
#include "blob.h"
#include "refs.h"
-#include "builtin.h"
#include "exec-cmd.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "read-cache-ll.h"
#include "revision.h"
#include "diff.h"
#include "hashmap.h"
+#include "setup.h"
#include "strvec.h"
#include "run-command.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "list-objects.h"
#include "commit-slab.h"
+#include "wildmatch.h"
#define MAX_TAGS (FLAG_BITS - 1)
@@ -261,7 +267,7 @@ static unsigned long finish_depth_computation(
best->depth++;
while (parents) {
struct commit *p = parents->item;
- parse_commit(p);
+ repo_parse_commit(the_repository, p);
if (!(p->object.flags & SEEN))
commit_list_insert_by_date(p, list);
p->object.flags |= c->object.flags;
@@ -298,7 +304,8 @@ static void append_name(struct commit_name *n, struct strbuf *dst)
static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
{
- strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid, abbrev));
+ strbuf_addf(dst, "-%d-g%s", depth,
+ repo_find_unique_abbrev(the_repository, oid, abbrev));
}
static void describe_commit(struct object_id *oid, struct strbuf *dst)
@@ -403,7 +410,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
}
while (parents) {
struct commit *p = parents->item;
- parse_commit(p);
+ repo_parse_commit(the_repository, p);
if (!(p->object.flags & SEEN))
commit_list_insert_by_date(p, &list);
p->object.flags |= c->object.flags;
@@ -531,7 +538,7 @@ static void describe(const char *arg, int last_one)
if (debug)
fprintf(stderr, _("describe %s\n"), arg);
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
die(_("Not a valid object name %s"), arg);
cmit = lookup_commit_reference_gently(the_repository, &oid, 1);
@@ -653,6 +660,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
int fd, result;
setup_work_tree();
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
repo_read_index(the_repository);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
NULL, NULL, NULL);
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
index d52015c67a..4f22eb2b55 100644
--- a/builtin/diagnose.c
+++ b/builtin/diagnose.c
@@ -1,4 +1,7 @@
#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "object-file.h"
#include "parse-options.h"
#include "diagnose.h"
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index dc991f753b..50330b8dd2 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -3,13 +3,14 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "diff.h"
#include "diff-merges.h"
#include "commit.h"
+#include "preload-index.h"
+#include "repository.h"
#include "revision.h"
-#include "builtin.h"
#include "submodule.h"
static const char diff_files_usage[] =
@@ -27,6 +28,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
usage(diff_files_usage);
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
repo_init_revisions(the_repository, &rev, prefix);
rev.abbrev = 0;
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 35dc9b23ee..9db7139b83 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -1,10 +1,13 @@
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "diff.h"
#include "diff-merges.h"
#include "commit.h"
+#include "preload-index.h"
+#include "repository.h"
#include "revision.h"
-#include "builtin.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
static const char diff_cache_usage[] =
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 25b853b85c..4ad55ecc3f 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -1,12 +1,16 @@
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "diff.h"
#include "commit.h"
+#include "gettext.h"
+#include "hex.h"
#include "log-tree.h"
-#include "builtin.h"
#include "submodule.h"
+#include "read-cache-ll.h"
#include "repository.h"
+#include "revision.h"
+#include "tree.h"
static struct rev_info log_tree_opt;
diff --git a/builtin/diff.c b/builtin/diff.c
index 26f1e532c6..b19530c996 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -4,22 +4,26 @@
* Copyright (c) 2006 Junio C Hamano
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "ewah/ewok.h"
#include "lockfile.h"
#include "color.h"
#include "commit.h"
#include "blob.h"
+#include "gettext.h"
#include "tag.h"
#include "diff.h"
#include "diff-merges.h"
#include "diffcore.h"
+#include "preload-index.h"
+#include "read-cache-ll.h"
#include "revision.h"
#include "log-tree.h"
-#include "builtin.h"
+#include "setup.h"
#include "submodule.h"
#include "oid-array.h"
+#include "tree.h"
#define DIFF_NO_INDEX_EXPLICIT 1
#define DIFF_NO_INDEX_IMPLICIT 2
@@ -74,7 +78,7 @@ static void stuff_change(struct diff_options *opt,
}
static int builtin_diff_b_f(struct rev_info *revs,
- int argc, const char **argv,
+ int argc, const char **argv UNUSED,
struct object_array_entry **blob)
{
/* Blob vs file in the working tree*/
@@ -109,7 +113,7 @@ static int builtin_diff_b_f(struct rev_info *revs,
}
static int builtin_diff_blobs(struct rev_info *revs,
- int argc, const char **argv,
+ int argc, const char **argv UNUSED,
struct object_array_entry **blob)
{
const unsigned mode = canon_mode(S_IFREG | 0644);
@@ -209,7 +213,7 @@ static int builtin_diff_tree(struct rev_info *revs,
}
static int builtin_diff_combined(struct rev_info *revs,
- int argc, const char **argv,
+ int argc, const char **argv UNUSED,
struct object_array_entry *ent,
int ents, int first_non_parent)
{
@@ -548,7 +552,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (!obj)
die(_("invalid object '%s' given."), name);
if (obj->type == OBJ_COMMIT)
- obj = &get_commit_tree(((struct commit *)obj))->object;
+ obj = &repo_get_commit_tree(the_repository,
+ ((struct commit *)obj))->object;
if (obj->type == OBJ_TREE) {
if (sdiff.skip && bitmap_get(sdiff.skip, i))
diff --git a/builtin/difftool.c b/builtin/difftool.c
index dbbfb19f19..e2c9ab7d5d 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -12,18 +12,27 @@
* Copyright (C) 2016 Johannes Schindelin
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "copy.h"
#include "run-command.h"
+#include "environment.h"
#include "exec-cmd.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
+#include "read-cache-ll.h"
+#include "sparse-index.h"
#include "strvec.h"
#include "strbuf.h"
#include "lockfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "dir.h"
#include "entry.h"
+#include "setup.h"
+#include "wrapper.h"
static int trust_exit_code;
@@ -295,7 +304,8 @@ static char *get_symlink(const struct object_id *oid, const char *path)
} else {
enum object_type type;
unsigned long size;
- data = read_object_file(oid, &type, &size);
+ data = repo_read_object_file(the_repository, oid, &type,
+ &size);
if (!data)
die(_("could not read object %s for symlink %s"),
oid_to_hex(oid), path);
@@ -684,7 +694,7 @@ static int run_file_diff(int prompt, const char *prefix,
int cmd_difftool(int argc, const char **argv, const char *prefix)
{
- int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0,
+ int use_gui_tool = -1, dir_diff = 0, prompt = -1, symlinks = 0,
tool_help = 0, no_index = 0;
static char *difftool_cmd = NULL, *extcmd = NULL;
struct option builtin_difftool_options[] = {
@@ -734,13 +744,21 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
} else if (dir_diff)
die(_("options '%s' and '%s' cannot be used together"), "--dir-diff", "--no-index");
- die_for_incompatible_opt3(use_gui_tool, "--gui",
+ die_for_incompatible_opt3(use_gui_tool == 1, "--gui",
!!difftool_cmd, "--tool",
!!extcmd, "--extcmd");
- if (use_gui_tool)
+ /*
+ * Explicitly specified GUI option is forwarded to git-mergetool--lib.sh;
+ * empty or unset means "use the difftool.guiDefault config or default to
+ * false".
+ */
+ if (use_gui_tool == 1)
setenv("GIT_MERGETOOL_GUI", "true", 1);
- else if (difftool_cmd) {
+ else if (use_gui_tool == 0)
+ setenv("GIT_MERGETOOL_GUI", "false", 1);
+
+ if (difftool_cmd) {
if (*difftool_cmd)
setenv("GIT_DIFF_TOOL", difftool_cmd, 1);
else
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 39a890fc00..56dc69fac1 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -4,11 +4,13 @@
* Copyright (C) 2007 Johannes E. Schindelin
*/
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "commit.h"
#include "object.h"
#include "tag.h"
@@ -109,7 +111,7 @@ static struct decoration idnums;
static uint32_t last_idnum;
struct anonymized_entry {
struct hashmap_entry hash;
- const char *anon;
+ char *anon;
const char orig[FLEX_ARRAY];
};
@@ -138,43 +140,56 @@ static int anonymized_entry_cmp(const void *cmp_data UNUSED,
return strcmp(a->orig, b->orig);
}
+static struct anonymized_entry *add_anonymized_entry(struct hashmap *map,
+ unsigned hash,
+ const char *orig, size_t len,
+ char *anon)
+{
+ struct anonymized_entry *ret, *old;
+
+ if (!map->cmpfn)
+ hashmap_init(map, anonymized_entry_cmp, NULL, 0);
+
+ FLEX_ALLOC_MEM(ret, orig, orig, len);
+ hashmap_entry_init(&ret->hash, hash);
+ ret->anon = anon;
+ old = hashmap_put_entry(map, ret, hash);
+
+ if (old) {
+ free(old->anon);
+ free(old);
+ }
+
+ return ret;
+}
+
/*
* Basically keep a cache of X->Y so that we can repeatedly replace
* the same anonymized string with another. The actual generation
* is farmed out to the generate function.
*/
static const char *anonymize_str(struct hashmap *map,
- char *(*generate)(void *),
- const char *orig, size_t len,
- void *data)
+ char *(*generate)(void),
+ const char *orig, size_t len)
{
struct anonymized_entry_key key;
struct anonymized_entry *ret;
- if (!map->cmpfn)
- hashmap_init(map, anonymized_entry_cmp, NULL, 0);
-
hashmap_entry_init(&key.hash, memhash(orig, len));
key.orig = orig;
key.orig_len = len;
/* First check if it's a token the user configured manually... */
- if (anonymized_seeds.cmpfn)
- ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
- else
- ret = NULL;
+ ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
/* ...otherwise check if we've already seen it in this context... */
if (!ret)
ret = hashmap_get_entry(map, &key, hash, &key);
/* ...and finally generate a new mapping if necessary */
- if (!ret) {
- FLEX_ALLOC_MEM(ret, orig, orig, len);
- hashmap_entry_init(&ret->hash, key.hash.hash);
- ret->anon = generate(data);
- hashmap_put(map, &ret->hash);
- }
+ if (!ret)
+ ret = add_anonymized_entry(map, key.hash.hash,
+ orig, len, generate());
return ret->anon;
}
@@ -187,12 +202,12 @@ static const char *anonymize_str(struct hashmap *map,
*/
static void anonymize_path(struct strbuf *out, const char *path,
struct hashmap *map,
- char *(*generate)(void *))
+ char *(*generate)(void))
{
while (*path) {
const char *end_of_component = strchrnul(path, '/');
size_t len = end_of_component - path;
- const char *c = anonymize_str(map, generate, path, len, NULL);
+ const char *c = anonymize_str(map, generate, path, len);
strbuf_addstr(out, c);
path = end_of_component;
if (*path)
@@ -296,7 +311,7 @@ static void export_blob(const struct object_id *oid)
object = (struct object *)lookup_blob(the_repository, oid);
eaten = 0;
} else {
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf)
die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(the_repository, oid, buf, size,
@@ -367,7 +382,7 @@ static void print_path_1(const char *path)
printf("%s", path);
}
-static char *anonymize_path_component(void *data)
+static char *anonymize_path_component(void)
{
static int counter;
struct strbuf out = STRBUF_INIT;
@@ -389,7 +404,7 @@ static void print_path(const char *path)
}
}
-static char *generate_fake_oid(void *data)
+static char *generate_fake_oid(void)
{
static uint32_t counter = 1; /* avoid null oid */
const unsigned hashsz = the_hash_algo->rawsz;
@@ -405,7 +420,7 @@ static const char *anonymize_oid(const char *oid_hex)
{
static struct hashmap objs;
size_t len = strlen(oid_hex);
- return anonymize_str(&objs, generate_fake_oid, oid_hex, len, NULL);
+ return anonymize_str(&objs, generate_fake_oid, oid_hex, len);
}
static void show_filemodify(struct diff_queue_struct *q,
@@ -502,7 +517,7 @@ static const char *find_encoding(const char *begin, const char *end)
return bol;
}
-static char *anonymize_ref_component(void *data)
+static char *anonymize_ref_component(void)
{
static int counter;
struct strbuf out = STRBUF_INIT;
@@ -542,13 +557,13 @@ static const char *anonymize_refname(const char *refname)
* We do not even bother to cache commit messages, as they are unlikely
* to be repeated verbatim, and it is not that interesting when they are.
*/
-static char *anonymize_commit_message(const char *old)
+static char *anonymize_commit_message(void)
{
static int counter;
return xstrfmt("subject %d\n\nbody\n", counter++);
}
-static char *anonymize_ident(void *data)
+static char *anonymize_ident(void)
{
static int counter;
struct strbuf out = STRBUF_INIT;
@@ -591,7 +606,7 @@ static void anonymize_ident_line(const char **beg, const char **end)
len = split.mail_end - split.name_begin;
ident = anonymize_str(&idents, anonymize_ident,
- split.name_begin, len, NULL);
+ split.name_begin, len);
strbuf_addstr(out, ident);
strbuf_addch(out, ' ');
strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
@@ -618,7 +633,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
parse_commit_or_die(commit);
- commit_buffer = get_commit_buffer(commit, NULL);
+ commit_buffer = repo_get_commit_buffer(the_repository, commit, NULL);
author = strstr(commit_buffer, "\nauthor ");
if (!author)
die("could not find author in commit %s",
@@ -669,7 +684,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
mark_next_object(&commit->object);
if (anonymize) {
- reencoded = anonymize_commit_message(message);
+ reencoded = anonymize_commit_message();
} else if (encoding) {
switch(reencode_mode) {
case REENCODE_YES:
@@ -699,7 +714,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
? strlen(message) : 0),
reencoded ? reencoded : message ? message : "");
free(reencoded);
- unuse_commit_buffer(commit, commit_buffer);
+ repo_unuse_commit_buffer(the_repository, commit, commit_buffer);
for (i = 0, p = commit->parents; p; p = p->next) {
struct object *obj = &p->item->object;
@@ -732,7 +747,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
show_progress();
}
-static char *anonymize_tag(void *data)
+static char *anonymize_tag(void)
{
static int counter;
struct strbuf out = STRBUF_INIT;
@@ -766,7 +781,8 @@ static void handle_tag(const char *name, struct tag *tag)
return;
}
- buf = read_object_file(&tag->object.oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &tag->object.oid, &type,
+ &size);
if (!buf)
die("could not read tag %s", oid_to_hex(&tag->object.oid));
message = memmem(buf, size, "\n\n", 2);
@@ -794,7 +810,7 @@ static void handle_tag(const char *name, struct tag *tag)
if (message) {
static struct hashmap tags;
message = anonymize_str(&tags, anonymize_tag,
- message, message_size, NULL);
+ message, message_size);
message_size = strlen(message);
}
}
@@ -917,7 +933,8 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
if (e->flags & UNINTERESTING)
continue;
- if (dwim_ref(e->name, strlen(e->name), &oid, &full_name, 0) != 1)
+ if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
+ &oid, &full_name, 0) != 1)
continue;
if (refspecs.nr) {
@@ -1125,11 +1142,6 @@ static void handle_deletes(void)
}
}
-static char *anonymize_seed(void *data)
-{
- return xstrdup(data);
-}
-
static int parse_opt_anonymize_map(const struct option *opt,
const char *arg, int unset)
{
@@ -1151,7 +1163,8 @@ static int parse_opt_anonymize_map(const struct option *opt,
if (!keylen || !*value)
return error(_("--anonymize-map token cannot be empty"));
- anonymize_str(map, anonymize_seed, arg, keylen, (void *)value);
+ add_anonymized_entry(map, memhash(arg, keylen), arg, keylen,
+ xstrdup(value));
return 0;
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 7134683ab9..2ee19c7373 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1,5 +1,8 @@
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "lockfile.h"
@@ -9,17 +12,21 @@
#include "commit.h"
#include "delta.h"
#include "pack.h"
+#include "path.h"
#include "refs.h"
#include "csum-file.h"
#include "quote.h"
#include "dir.h"
#include "run-command.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "mem-pool.h"
#include "commit-reach.h"
#include "khash.h"
#include "date.h"
+#include "wrapper.h"
#define PACK_ID_BITS 16
#define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
@@ -175,6 +182,7 @@ static FILE *pack_edges;
static unsigned int show_stats = 1;
static int global_argc;
static const char **global_argv;
+static const char *global_prefix;
/* Memory pools */
static struct mem_pool fi_mem_pool = {
@@ -436,7 +444,7 @@ static void set_checkpoint_signal(void)
#else
-static void checkpoint_signal(int signo)
+static void checkpoint_signal(int signo UNUSED)
{
checkpoint_requested = 1;
}
@@ -1265,7 +1273,7 @@ static void load_tree(struct tree_entry *root)
die("Can't load tree %s", oid_to_hex(oid));
} else {
enum object_type type;
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf || type != OBJ_TREE)
die("Can't load tree %s", oid_to_hex(oid));
}
@@ -1625,7 +1633,7 @@ static int update_branch(struct branch *b)
if (!old_cmit || !new_cmit)
return error("Branch %s is missing commits.", b->name);
- if (!in_merge_bases(old_cmit, new_cmit)) {
+ if (!repo_in_merge_bases(the_repository, old_cmit, new_cmit)) {
warning("Not updating %s"
" (new tip %s does not contain %s)",
b->name, oid_to_hex(&b->oid),
@@ -2486,7 +2494,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
if (commit_oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", commit_mark);
oidcpy(&commit_oid, &commit_oe->idx.oid);
- } else if (!get_oid(p, &commit_oid)) {
+ } else if (!repo_get_oid(the_repository, p, &commit_oid)) {
unsigned long size;
char *buf = read_object_with_reference(the_repository,
&commit_oid,
@@ -2599,7 +2607,7 @@ static int parse_objectish(struct branch *b, const char *objectish)
} else
parse_from_existing(b);
}
- } else if (!get_oid(objectish, &b->oid)) {
+ } else if (!repo_get_oid(the_repository, objectish, &b->oid)) {
parse_from_existing(b);
if (is_null_oid(&b->oid))
b->delete = 1;
@@ -2654,7 +2662,7 @@ static struct hash_list *parse_merge(unsigned int *count)
if (oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", idnum);
oidcpy(&n->oid, &oe->idx.oid);
- } else if (!get_oid(from, &n->oid)) {
+ } else if (!repo_get_oid(the_repository, from, &n->oid)) {
unsigned long size;
char *buf = read_object_with_reference(the_repository,
&n->oid,
@@ -2827,7 +2835,7 @@ static void parse_new_tag(const char *arg)
oe = find_mark(marks, from_mark);
type = oe->type;
oidcpy(&oid, &oe->idx.oid);
- } else if (!get_oid(from, &oid)) {
+ } else if (!repo_get_oid(the_repository, from, &oid)) {
struct object_entry *oe = find_object(&oid);
if (!oe) {
type = oid_object_info(the_repository, &oid, NULL);
@@ -2936,7 +2944,7 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)
char *buf;
if (!oe || oe->pack_id == MAX_PACK_ID) {
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
} else {
type = oe->type;
buf = gfi_unpack_entry(oe, &size);
@@ -3044,7 +3052,8 @@ static struct object_entry *dereference(struct object_entry *oe,
buf = gfi_unpack_entry(oe, &size);
} else {
enum object_type unused;
- buf = read_object_file(oid, &unused, &size);
+ buf = repo_read_object_file(the_repository, oid, &unused,
+ &size);
}
if (!buf)
die("Can't load object %s", oid_to_hex(oid));
@@ -3245,7 +3254,7 @@ static void parse_alias(void)
static char* make_fast_import_path(const char *path)
{
if (!relative_marks_paths || is_absolute_path(path))
- return xstrdup(path);
+ return prefix_filename(global_prefix, path);
return git_pathdup("info/fast-import/%s", path);
}
@@ -3316,9 +3325,11 @@ static void option_cat_blob_fd(const char *fd)
static void option_export_pack_edges(const char *edges)
{
+ char *fn = prefix_filename(global_prefix, edges);
if (pack_edges)
fclose(pack_edges);
- pack_edges = xfopen(edges, "a");
+ pack_edges = xfopen(fn, "a");
+ free(fn);
}
static void option_rewrite_submodules(const char *arg, struct string_list *list)
@@ -3333,11 +3344,13 @@ static void option_rewrite_submodules(const char *arg, struct string_list *list)
f++;
CALLOC_ARRAY(ms, 1);
+ f = prefix_filename(global_prefix, f);
fp = fopen(f, "r");
if (!fp)
die_errno("cannot read '%s'", f);
read_mark_file(&ms, fp, insert_oid_entry);
fclose(fp);
+ free(f);
string_list_insert(list, s)->util = ms;
}
@@ -3551,6 +3564,7 @@ int cmd_fast_import(int argc, const char **argv, const char *prefix)
global_argc = argc;
global_argv = argv;
+ global_prefix = prefix;
rc_free = mem_pool_alloc(&fi_mem_pool, cmd_save * sizeof(*rc_free));
for (i = 0; i < (cmd_save - 1); i++)
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index afe679368d..3ba0fe5a39 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -1,4 +1,8 @@
#include "builtin.h"
+#include "alloc.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
#include "pkt-line.h"
#include "fetch-pack.h"
#include "remote.h"
@@ -40,7 +44,7 @@ static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
(*sought)[*nr - 1] = ref;
}
-int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
+int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
{
int i, ret;
struct ref *ref = NULL;
@@ -211,8 +215,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
int flags = args.verbose ? CONNECT_VERBOSE : 0;
if (args.diag_url)
flags |= CONNECT_DIAG_URL;
- conn = git_connect(fd, dest, args.uploadpack,
- flags);
+ conn = git_connect(fd, dest, "git-upload-pack",
+ args.uploadpack, flags);
if (!conn)
return args.diag_url ? 0 : 1;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index a09606b472..951a23d733 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1,15 +1,20 @@
/*
* "git fetch"
*/
-#include "cache.h"
+#include "builtin.h"
+#include "advice.h"
#include "config.h"
+#include "gettext.h"
+#include "environment.h"
+#include "hex.h"
#include "repository.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "oidset.h"
+#include "oid-array.h"
#include "commit.h"
-#include "builtin.h"
#include "string-list.h"
#include "remote.h"
#include "transport.h"
@@ -22,12 +27,17 @@
#include "strvec.h"
#include "utf8.h"
#include "packfile.h"
+#include "pager.h"
+#include "path.h"
+#include "pkt-line.h"
#include "list-objects-filter-options.h"
#include "commit-reach.h"
#include "branch.h"
#include "promisor-remote.h"
#include "commit-graph.h"
#include "shallow.h"
+#include "trace.h"
+#include "trace2.h"
#include "worktree.h"
#include "bundle-uri.h"
@@ -47,25 +57,35 @@ enum {
TAGS_SET = 2
};
-static int fetch_prune_config = -1; /* unspecified */
-static int fetch_show_forced_updates = 1;
+enum display_format {
+ DISPLAY_FORMAT_FULL,
+ DISPLAY_FORMAT_COMPACT,
+ DISPLAY_FORMAT_PORCELAIN,
+};
+
+struct display_state {
+ struct strbuf buf;
+
+ int refcol_width;
+ enum display_format format;
+
+ char *url;
+ int url_len, shown_url;
+};
+
static uint64_t forced_updates_ms = 0;
static int prefetch = 0;
static int prune = -1; /* unspecified */
#define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
-static int fetch_prune_tags_config = -1; /* unspecified */
static int prune_tags = -1; /* unspecified */
#define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
-static int all, append, dry_run, force, keep, multiple, update_head_ok;
+static int append, dry_run, force, keep, update_head_ok;
static int write_fetch_head = 1;
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;
-static int max_jobs = -1, submodule_fetch_jobs_config = -1;
-static int fetch_parallel_config = 1;
+static int tags = TAGS_DEFAULT, update_shallow, deepen;
static int atomic_fetch;
static enum transport_family family;
static const char *depth;
@@ -75,59 +95,75 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
static struct strbuf default_rla = STRBUF_INIT;
static struct transport *gtransport;
static struct transport *gsecondary;
-static const char *submodule_prefix = "";
-static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
-static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
-static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
-static int shown_url = 0;
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
-static int fetch_write_commit_graph = -1;
-static int stdin_refspecs = 0;
-static int negotiate_only;
+
+struct fetch_config {
+ enum display_format display_format;
+ int prune;
+ int prune_tags;
+ int show_forced_updates;
+ int recurse_submodules;
+ int parallel;
+ int submodule_fetch_jobs;
+};
static int git_fetch_config(const char *k, const char *v, void *cb)
{
+ struct fetch_config *fetch_config = cb;
+
if (!strcmp(k, "fetch.prune")) {
- fetch_prune_config = git_config_bool(k, v);
+ fetch_config->prune = git_config_bool(k, v);
return 0;
}
if (!strcmp(k, "fetch.prunetags")) {
- fetch_prune_tags_config = git_config_bool(k, v);
+ fetch_config->prune_tags = git_config_bool(k, v);
return 0;
}
if (!strcmp(k, "fetch.showforcedupdates")) {
- fetch_show_forced_updates = git_config_bool(k, v);
+ fetch_config->show_forced_updates = git_config_bool(k, v);
return 0;
}
if (!strcmp(k, "submodule.recurse")) {
int r = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
- recurse_submodules = r;
+ fetch_config->recurse_submodules = r;
}
if (!strcmp(k, "submodule.fetchjobs")) {
- submodule_fetch_jobs_config = parse_submodule_fetchjobs(k, v);
+ fetch_config->submodule_fetch_jobs = parse_submodule_fetchjobs(k, v);
return 0;
} else if (!strcmp(k, "fetch.recursesubmodules")) {
- recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
+ fetch_config->recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
return 0;
}
if (!strcmp(k, "fetch.parallel")) {
- fetch_parallel_config = git_config_int(k, v);
- if (fetch_parallel_config < 0)
+ fetch_config->parallel = git_config_int(k, v);
+ if (fetch_config->parallel < 0)
die(_("fetch.parallel cannot be negative"));
- if (!fetch_parallel_config)
- fetch_parallel_config = online_cpus();
+ if (!fetch_config->parallel)
+ fetch_config->parallel = online_cpus();
return 0;
}
+ if (!strcmp(k, "fetch.output")) {
+ if (!v)
+ return config_error_nonbool(k);
+ else if (!strcasecmp(v, "full"))
+ fetch_config->display_format = DISPLAY_FORMAT_FULL;
+ else if (!strcasecmp(v, "compact"))
+ fetch_config->display_format = DISPLAY_FORMAT_COMPACT;
+ else
+ die(_("invalid value for '%s': '%s'"),
+ "fetch.output", v);
+ }
+
return git_default_config(k, v, cb);
}
@@ -144,92 +180,6 @@ static int parse_refmap_arg(const struct option *opt, const char *arg, int unset
return 0;
}
-static struct option builtin_fetch_options[] = {
- OPT__VERBOSITY(&verbosity),
- OPT_BOOL(0, "all", &all,
- N_("fetch from all remotes")),
- OPT_BOOL(0, "set-upstream", &set_upstream,
- N_("set upstream for git pull/fetch")),
- OPT_BOOL('a', "append", &append,
- N_("append to .git/FETCH_HEAD instead of overwriting")),
- OPT_BOOL(0, "atomic", &atomic_fetch,
- N_("use atomic transaction to update references")),
- OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
- N_("path to upload pack on remote end")),
- OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
- OPT_BOOL('m', "multiple", &multiple,
- N_("fetch from multiple remotes")),
- OPT_SET_INT('t', "tags", &tags,
- N_("fetch all tags and associated objects"), TAGS_SET),
- OPT_SET_INT('n', NULL, &tags,
- N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
- OPT_INTEGER('j', "jobs", &max_jobs,
- N_("number of submodules fetched in parallel")),
- OPT_BOOL(0, "prefetch", &prefetch,
- N_("modify the refspec to place all refs within refs/prefetch/")),
- OPT_BOOL('p', "prune", &prune,
- N_("prune remote-tracking branches no longer on remote")),
- OPT_BOOL('P', "prune-tags", &prune_tags,
- N_("prune local tags no longer on remote and clobber changed tags")),
- OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
- N_("control recursive fetching of submodules"),
- PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
- OPT_BOOL(0, "dry-run", &dry_run,
- N_("dry run")),
- OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
- N_("write fetched references to the FETCH_HEAD file")),
- OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
- OPT_BOOL('u', "update-head-ok", &update_head_ok,
- N_("allow updating of HEAD ref")),
- OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
- OPT_STRING(0, "depth", &depth, N_("depth"),
- N_("deepen history of shallow clone")),
- OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
- N_("deepen history of shallow repository based on time")),
- OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
- N_("deepen history of shallow clone, excluding rev")),
- OPT_INTEGER(0, "deepen", &deepen_relative,
- N_("deepen history of shallow clone")),
- 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",
- &recurse_submodules_default, N_("on-demand"),
- N_("default for recursive fetching of submodules "
- "(lower priority than config files)"),
- PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
- OPT_BOOL(0, "update-shallow", &update_shallow,
- N_("accept refs that update .git/shallow")),
- OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"),
- N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
- OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
- OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
- TRANSPORT_FAMILY_IPV4),
- OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
- TRANSPORT_FAMILY_IPV6),
- OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
- N_("report that we have only objects reachable from this object")),
- OPT_BOOL(0, "negotiate-only", &negotiate_only,
- N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
- OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
- OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
- N_("run 'maintenance --auto' after fetching")),
- OPT_BOOL(0, "auto-gc", &enable_auto_gc,
- N_("run 'maintenance --auto' after fetching")),
- OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates,
- N_("check for forced-updates on all updated branches")),
- OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
- N_("write the commit-graph after fetching")),
- OPT_BOOL(0, "stdin", &stdin_refspecs,
- N_("accept refspecs from stdin")),
- OPT_END()
-};
-
static void unlock_pack(unsigned int flags)
{
if (gtransport)
@@ -407,9 +357,9 @@ static void find_non_local_tags(const struct ref *refs,
*/
if (ends_with(ref->name, "^{}")) {
if (item &&
- !has_object_file_with_flags(&ref->old_oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &ref->old_oid, quick_flags) &&
!oidset_contains(&fetch_oids, &ref->old_oid) &&
- !has_object_file_with_flags(&item->oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
item = NULL;
@@ -423,7 +373,7 @@ static void find_non_local_tags(const struct ref *refs,
* fetch.
*/
if (item &&
- !has_object_file_with_flags(&item->oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
@@ -444,7 +394,7 @@ static void find_non_local_tags(const struct ref *refs,
* checked to see if it needs fetching.
*/
if (item &&
- !has_object_file_with_flags(&item->oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
@@ -741,76 +691,97 @@ out:
return ret;
}
-static int refcol_width = 10;
-static int compact_format;
-
-static void adjust_refcol_width(const struct ref *ref)
+static int refcol_width(const struct ref *ref_map, int compact_format)
{
- int max, rlen, llen, len;
+ const struct ref *ref;
+ int max, width = 10;
- /* uptodate lines are only shown on high verbosity level */
- if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
- return;
+ max = term_columns();
+ if (compact_format)
+ max = max * 2 / 3;
- max = term_columns();
- rlen = utf8_strwidth(prettify_refname(ref->name));
+ for (ref = ref_map; ref; ref = ref->next) {
+ int rlen, llen = 0, len;
- llen = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+ if (ref->status == REF_STATUS_REJECT_SHALLOW ||
+ !ref->peer_ref ||
+ !strcmp(ref->name, "HEAD"))
+ continue;
- /*
- * rough estimation to see if the output line is too long and
- * should not be counted (we can't do precise calculation
- * anyway because we don't know if the error explanation part
- * will be printed in update_local_ref)
- */
- if (compact_format) {
- llen = 0;
- max = max * 2 / 3;
+ /* uptodate lines are only shown on high verbosity level */
+ if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
+ continue;
+
+ rlen = utf8_strwidth(prettify_refname(ref->name));
+ if (!compact_format)
+ llen = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+
+ /*
+ * rough estimation to see if the output line is too long and
+ * should not be counted (we can't do precise calculation
+ * anyway because we don't know if the error explanation part
+ * will be printed in update_local_ref)
+ */
+ len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
+ if (len >= max)
+ continue;
+
+ if (width < rlen)
+ width = rlen;
}
- len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
- if (len >= max)
- return;
- /*
- * Not precise calculation for compact mode because '*' can
- * appear on the left hand side of '->' and shrink the column
- * back.
- */
- if (refcol_width < rlen)
- refcol_width = rlen;
+ return width;
}
-static void prepare_format_display(struct ref *ref_map)
+static void display_state_init(struct display_state *display_state, struct ref *ref_map,
+ const char *raw_url, enum display_format format)
{
- struct ref *rm;
- const char *format = "full";
+ int i;
- if (verbosity < 0)
- return;
+ memset(display_state, 0, sizeof(*display_state));
+ strbuf_init(&display_state->buf, 0);
+ display_state->format = format;
- git_config_get_string_tmp("fetch.output", &format);
- if (!strcasecmp(format, "full"))
- compact_format = 0;
- else if (!strcasecmp(format, "compact"))
- compact_format = 1;
+ if (raw_url)
+ display_state->url = transport_anonymize_url(raw_url);
else
- die(_("invalid value for '%s': '%s'"),
- "fetch.output", format);
+ display_state->url = xstrdup("foreign");
- for (rm = ref_map; rm; rm = rm->next) {
- if (rm->status == REF_STATUS_REJECT_SHALLOW ||
- !rm->peer_ref ||
- !strcmp(rm->name, "HEAD"))
- continue;
+ display_state->url_len = strlen(display_state->url);
+ for (i = display_state->url_len - 1; display_state->url[i] == '/' && 0 <= i; i--)
+ ;
+ display_state->url_len = i + 1;
+ if (4 < i && !strncmp(".git", display_state->url + i - 3, 4))
+ display_state->url_len = i - 3;
- adjust_refcol_width(rm);
+ if (verbosity < 0)
+ return;
+
+ switch (display_state->format) {
+ case DISPLAY_FORMAT_FULL:
+ case DISPLAY_FORMAT_COMPACT:
+ display_state->refcol_width = refcol_width(ref_map,
+ display_state->format == DISPLAY_FORMAT_COMPACT);
+ break;
+ case DISPLAY_FORMAT_PORCELAIN:
+ /* We don't need to precompute anything here. */
+ break;
+ default:
+ BUG("unexpected display format %d", display_state->format);
}
}
-static void print_remote_to_local(struct strbuf *display,
+static void display_state_release(struct display_state *display_state)
+{
+ strbuf_release(&display_state->buf);
+ free(display_state->url);
+}
+
+static void print_remote_to_local(struct display_state *display_state,
const char *remote, const char *local)
{
- strbuf_addf(display, "%-*s -> %s", refcol_width, remote, local);
+ strbuf_addf(&display_state->buf, "%-*s -> %s",
+ display_state->refcol_width, remote, local);
}
static int find_and_replace(struct strbuf *haystack,
@@ -840,14 +811,14 @@ static int find_and_replace(struct strbuf *haystack,
return 1;
}
-static void print_compact(struct strbuf *display,
+static void print_compact(struct display_state *display_state,
const char *remote, const char *local)
{
struct strbuf r = STRBUF_INIT;
struct strbuf l = STRBUF_INIT;
if (!strcmp(remote, local)) {
- strbuf_addf(display, "%-*s -> *", refcol_width, remote);
+ strbuf_addf(&display_state->buf, "%-*s -> *", display_state->refcol_width, remote);
return;
}
@@ -856,40 +827,74 @@ static void print_compact(struct strbuf *display,
if (!find_and_replace(&r, local, "*"))
find_and_replace(&l, remote, "*");
- print_remote_to_local(display, r.buf, l.buf);
+ print_remote_to_local(display_state, r.buf, l.buf);
strbuf_release(&r);
strbuf_release(&l);
}
-static void format_display(struct strbuf *display, char code,
- const char *summary, const char *error,
- const char *remote, const char *local,
- int summary_width)
+static void display_ref_update(struct display_state *display_state, char code,
+ const char *summary, const char *error,
+ const char *remote, const char *local,
+ const struct object_id *old_oid,
+ const struct object_id *new_oid,
+ int summary_width)
{
- int width;
+ FILE *f = stderr;
if (verbosity < 0)
return;
- width = (summary_width + strlen(summary) - gettext_width(summary));
+ strbuf_reset(&display_state->buf);
- strbuf_addf(display, "%c %-*s ", code, width, summary);
- if (!compact_format)
- print_remote_to_local(display, remote, local);
- else
- print_compact(display, remote, local);
- if (error)
- strbuf_addf(display, " (%s)", error);
+ switch (display_state->format) {
+ case DISPLAY_FORMAT_FULL:
+ case DISPLAY_FORMAT_COMPACT: {
+ int width;
+
+ if (!display_state->shown_url) {
+ strbuf_addf(&display_state->buf, _("From %.*s\n"),
+ display_state->url_len, display_state->url);
+ display_state->shown_url = 1;
+ }
+
+ width = (summary_width + strlen(summary) - gettext_width(summary));
+ remote = prettify_refname(remote);
+ local = prettify_refname(local);
+
+ strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary);
+
+ if (display_state->format != DISPLAY_FORMAT_COMPACT)
+ print_remote_to_local(display_state, remote, local);
+ else
+ print_compact(display_state, remote, local);
+
+ if (error)
+ strbuf_addf(&display_state->buf, " (%s)", error);
+
+ break;
+ }
+ case DISPLAY_FORMAT_PORCELAIN:
+ strbuf_addf(&display_state->buf, "%c %s %s %s", code,
+ oid_to_hex(old_oid), oid_to_hex(new_oid), local);
+ f = stdout;
+ break;
+ default:
+ BUG("unexpected display format %d", display_state->format);
+ };
+ strbuf_addch(&display_state->buf, '\n');
+
+ fputs(display_state->buf.buf, f);
}
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 display_state *display_state,
+ const struct ref *remote_ref,
+ int summary_width,
+ const struct fetch_config *config)
{
struct commit *current = NULL, *updated;
- const char *pretty_ref = prettify_refname(ref->name);
int fast_forward = 0;
if (!repo_has_object_file(the_repository, &ref->new_oid))
@@ -897,8 +902,9 @@ static int update_local_ref(struct ref *ref,
if (oideq(&ref->old_oid, &ref->new_oid)) {
if (verbosity > 0)
- format_display(display, '=', _("[up to date]"), NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '=', _("[up to date]"), NULL,
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 0;
}
@@ -909,9 +915,10 @@ static int update_local_ref(struct ref *ref,
* 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]"),
- _("can't fetch into checked-out branch"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '!', _("[rejected]"),
+ _("can't fetch into checked-out branch"),
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 1;
}
@@ -920,13 +927,16 @@ static int update_local_ref(struct ref *ref,
if (force || ref->force) {
int r;
r = s_update_ref("updating tag", ref, transaction, 0);
- format_display(display, r ? '!' : 't', _("[tag update]"),
- r ? _("unable to update local ref") : NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : 't', _("[tag update]"),
+ r ? _("unable to update local ref") : NULL,
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return r;
} else {
- format_display(display, '!', _("[rejected]"), _("would clobber existing tag"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '!', _("[rejected]"),
+ _("would clobber existing tag"),
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 1;
}
}
@@ -944,11 +954,10 @@ static int update_local_ref(struct ref *ref,
* Base this on the remote's ref name, as it's
* more likely to follow a standard layout.
*/
- const char *name = remote_ref ? remote_ref->name : "";
- if (starts_with(name, "refs/tags/")) {
+ if (starts_with(remote_ref->name, "refs/tags/")) {
msg = "storing tag";
what = _("[new tag]");
- } else if (starts_with(name, "refs/heads/")) {
+ } else if (starts_with(remote_ref->name, "refs/heads/")) {
msg = "storing head";
what = _("[new branch]");
} else {
@@ -957,15 +966,17 @@ static int update_local_ref(struct ref *ref,
}
r = s_update_ref(msg, ref, transaction, 0);
- format_display(display, r ? '!' : '*', what,
- r ? _("unable to update local ref") : NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : '*', what,
+ r ? _("unable to update local ref") : NULL,
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return r;
}
- if (fetch_show_forced_updates) {
+ if (config->show_forced_updates) {
uint64_t t_before = getnanotime();
- fast_forward = in_merge_bases(current, updated);
+ fast_forward = repo_in_merge_bases(the_repository, current,
+ updated);
forced_updates_ms += (getnanotime() - t_before) / 1000000;
} else {
fast_forward = 1;
@@ -979,9 +990,10 @@ static int update_local_ref(struct ref *ref,
strbuf_addstr(&quickref, "..");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
r = s_update_ref("fast-forward", ref, transaction, 1);
- format_display(display, r ? '!' : ' ', quickref.buf,
- r ? _("unable to update local ref") : NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : ' ', quickref.buf,
+ r ? _("unable to update local ref") : NULL,
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
strbuf_release(&quickref);
return r;
} else if (force || ref->force) {
@@ -991,14 +1003,16 @@ static int update_local_ref(struct ref *ref,
strbuf_addstr(&quickref, "...");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
r = s_update_ref("forced-update", ref, transaction, 1);
- format_display(display, r ? '!' : '+', quickref.buf,
- r ? _("unable to update local ref") : _("forced update"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : '+', quickref.buf,
+ r ? _("unable to update local ref") : _("forced update"),
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
strbuf_release(&quickref);
return r;
} else {
- format_display(display, '!', _("[rejected]"), _("non-fast-forward"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '!', _("[rejected]"), _("non-fast-forward"),
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 1;
}
}
@@ -1108,39 +1122,35 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
"'--no-show-forced-updates' or run 'git config fetch.showForcedUpdates false'\n"
"to avoid this check\n");
-static int store_updated_refs(const char *raw_url, const char *remote_name,
+static int store_updated_refs(struct display_state *display_state,
+ const char *remote_name,
int connectivity_checked,
struct ref_transaction *transaction, struct ref *ref_map,
- struct fetch_head *fetch_head)
+ struct fetch_head *fetch_head,
+ const struct fetch_config *config)
{
- int url_len, i, rc = 0;
+ int rc = 0;
struct strbuf note = STRBUF_INIT;
const char *what, *kind;
struct ref *rm;
- char *url;
int want_status;
int summary_width = 0;
if (verbosity >= 0)
summary_width = transport_summary_width(ref_map);
- if (raw_url)
- url = transport_anonymize_url(raw_url);
- else
- url = xstrdup("foreign");
-
if (!connectivity_checked) {
struct check_connected_options opt = CHECK_CONNECTED_INIT;
+ opt.exclude_hidden_refs_section = "fetch";
rm = ref_map;
if (check_connected(iterate_ref_map, &rm, &opt)) {
- rc = error(_("%s did not send all necessary objects\n"), url);
+ rc = error(_("%s did not send all necessary objects\n"),
+ display_state->url);
goto abort;
}
}
- prepare_format_display(ref_map);
-
/*
* We do a pass for each fetch_head_status type in their enum order, so
* merged entries are written before not-for-merge. That lets readers
@@ -1200,7 +1210,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
ref->force = rm->peer_ref->force;
}
- if (recurse_submodules != RECURSE_SUBMODULES_OFF &&
+ if (config->recurse_submodules != RECURSE_SUBMODULES_OFF &&
(!rm->peer_ref || !oideq(&ref->old_oid, &ref->new_oid))) {
check_for_new_submodule_commits(&rm->old_oid);
}
@@ -1208,25 +1218,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
if (!strcmp(rm->name, "HEAD")) {
kind = "";
what = "";
- }
- else if (skip_prefix(rm->name, "refs/heads/", &what))
+ } else if (skip_prefix(rm->name, "refs/heads/", &what)) {
kind = "branch";
- else if (skip_prefix(rm->name, "refs/tags/", &what))
+ } else if (skip_prefix(rm->name, "refs/tags/", &what)) {
kind = "tag";
- else if (skip_prefix(rm->name, "refs/remotes/", &what))
+ } else if (skip_prefix(rm->name, "refs/remotes/", &what)) {
kind = "remote-tracking branch";
- else {
+ } else {
kind = "";
what = rm->name;
}
- url_len = strlen(url);
- for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
- ;
- url_len = i + 1;
- if (4 < i && !strncmp(".git", url + i - 3, 4))
- url_len = i - 3;
-
strbuf_reset(&note);
if (*what) {
if (*kind)
@@ -1236,12 +1238,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
append_fetch_head(fetch_head, &rm->old_oid,
rm->fetch_head_status,
- note.buf, url, url_len);
+ note.buf, display_state->url,
+ display_state->url_len);
- strbuf_reset(&note);
if (ref) {
- rc |= update_local_ref(ref, transaction, what,
- rm, &note, summary_width);
+ rc |= update_local_ref(ref, transaction, display_state,
+ rm, summary_width, config);
free(ref);
} else if (write_fetch_head || dry_run) {
/*
@@ -1249,18 +1251,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
* would be written to FETCH_HEAD, if --dry-run
* is set).
*/
- format_display(&note, '*',
- *kind ? kind : "branch", NULL,
- *what ? what : "HEAD",
- "FETCH_HEAD", summary_width);
- }
- if (note.len) {
- if (!shown_url) {
- fprintf(stderr, _("From %.*s\n"),
- url_len, url);
- shown_url = 1;
- }
- fprintf(stderr, " %s\n", note.buf);
+ display_ref_update(display_state, '*',
+ *kind ? kind : "branch", NULL,
+ rm->name,
+ "FETCH_HEAD",
+ &rm->new_oid, &rm->old_oid,
+ summary_width);
}
}
}
@@ -1271,7 +1267,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
"branches"), remote_name);
if (advice_enabled(ADVICE_FETCH_SHOW_FORCED_UPDATES)) {
- if (!fetch_show_forced_updates) {
+ if (!config->show_forced_updates) {
warning(_(warn_show_forced_updates));
} else if (forced_updates_ms > FORCED_UPDATES_DELAY_WARNING_IN_MS) {
warning(_(warn_time_show_forced_updates),
@@ -1281,7 +1277,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
abort:
strbuf_release(&note);
- free(url);
return rc;
}
@@ -1319,19 +1314,22 @@ static int check_exist_and_connected(struct ref *ref_map)
* we need all direct targets to exist.
*/
for (r = rm; r; r = r->next) {
- if (!has_object_file_with_flags(&r->old_oid,
- OBJECT_INFO_SKIP_FETCH_OBJECT))
+ if (!repo_has_object_file_with_flags(the_repository, &r->old_oid,
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
return -1;
}
opt.quiet = 1;
+ opt.exclude_hidden_refs_section = "fetch";
return check_connected(iterate_ref_map, &rm, &opt);
}
-static int fetch_and_consume_refs(struct transport *transport,
+static int fetch_and_consume_refs(struct display_state *display_state,
+ struct transport *transport,
struct ref_transaction *transaction,
struct ref *ref_map,
- struct fetch_head *fetch_head)
+ struct fetch_head *fetch_head,
+ const struct fetch_config *config)
{
int connectivity_checked = 1;
int ret;
@@ -1352,9 +1350,9 @@ 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,
+ ret = store_updated_refs(display_state, transport->remote->name,
connectivity_checked, transaction, ref_map,
- fetch_head);
+ fetch_head, config);
trace2_region_leave("fetch", "consume_refs", the_repository);
out:
@@ -1362,32 +1360,18 @@ out:
return ret;
}
-static int prune_refs(struct refspec *rs,
+static int prune_refs(struct display_state *display_state,
+ struct refspec *rs,
struct ref_transaction *transaction,
- struct ref *ref_map,
- const char *raw_url)
+ struct ref *ref_map)
{
- int url_len, i, result = 0;
+ int result = 0;
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
struct strbuf err = STRBUF_INIT;
- char *url;
const char *dangling_msg = dry_run
? _(" (%s will become dangling)")
: _(" (%s has become dangling)");
- if (raw_url)
- url = transport_anonymize_url(raw_url);
- else
- url = xstrdup("foreign");
-
- url_len = strlen(url);
- for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
- ;
-
- url_len = i + 1;
- if (4 < i && !strncmp(".git", url + i - 3, 4))
- url_len = i - 3;
-
if (!dry_run) {
if (transaction) {
for (ref = stale_refs; ref; ref = ref->next) {
@@ -1411,23 +1395,16 @@ static int prune_refs(struct refspec *rs,
int summary_width = transport_summary_width(stale_refs);
for (ref = stale_refs; ref; ref = ref->next) {
- struct strbuf sb = STRBUF_INIT;
- if (!shown_url) {
- fprintf(stderr, _("From %.*s\n"), url_len, url);
- shown_url = 1;
- }
- format_display(&sb, '-', _("[deleted]"), NULL,
- _("(none)"), prettify_refname(ref->name),
- summary_width);
- fprintf(stderr, " %s\n",sb.buf);
- strbuf_release(&sb);
+ display_ref_update(display_state, '-', _("[deleted]"), NULL,
+ _("(none)"), ref->name,
+ &ref->new_oid, &ref->old_oid,
+ summary_width);
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
}
cleanup:
strbuf_release(&err);
- free(url);
free_refs(stale_refs);
return result;
}
@@ -1487,7 +1464,7 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
int old_nr;
if (!has_glob_specials(s)) {
struct object_id oid;
- if (get_oid(s, &oid))
+ if (repo_get_oid(the_repository, s, &oid))
die(_("%s is not a valid object"), s);
if (!has_object(the_repository, &oid, 0))
die(_("the object %s does not exist"), s);
@@ -1542,10 +1519,12 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
return transport;
}
-static int backfill_tags(struct transport *transport,
+static int backfill_tags(struct display_state *display_state,
+ struct transport *transport,
struct ref_transaction *transaction,
struct ref *ref_map,
- struct fetch_head *fetch_head)
+ struct fetch_head *fetch_head,
+ const struct fetch_config *config)
{
int retcode, cannot_reuse;
@@ -1566,7 +1545,8 @@ 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);
+ retcode = fetch_and_consume_refs(display_state, transport, transaction, ref_map,
+ fetch_head, config);
if (gsecondary) {
transport_disconnect(gsecondary);
@@ -1577,10 +1557,12 @@ static int backfill_tags(struct transport *transport,
}
static int do_fetch(struct transport *transport,
- struct refspec *rs)
+ struct refspec *rs,
+ const struct fetch_config *config)
{
struct ref_transaction *transaction = NULL;
struct ref *ref_map = NULL;
+ struct display_state display_state = { 0 };
int autotags = (transport->remote->fetch_tags == 1);
int retcode = 0;
const struct ref *remote_refs;
@@ -1662,6 +1644,9 @@ static int do_fetch(struct transport *transport,
if (retcode)
goto cleanup;
+ display_state_init(&display_state, ref_map, transport->url,
+ config->display_format);
+
if (atomic_fetch) {
transaction = ref_transaction_begin(&err);
if (!transaction) {
@@ -1679,17 +1664,17 @@ static int do_fetch(struct transport *transport,
* don't care whether --tags was specified.
*/
if (rs->nr) {
- retcode = prune_refs(rs, transaction, ref_map, transport->url);
+ retcode = prune_refs(&display_state, rs, transaction, ref_map);
} else {
- retcode = prune_refs(&transport->remote->fetch,
- transaction, ref_map,
- transport->url);
+ retcode = prune_refs(&display_state, &transport->remote->fetch,
+ transaction, ref_map);
}
if (retcode != 0)
retcode = 1;
}
- if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head)) {
+ if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map,
+ &fetch_head, config)) {
retcode = 1;
goto cleanup;
}
@@ -1711,8 +1696,8 @@ static int do_fetch(struct transport *transport,
* when `--atomic` is passed: in that case we'll abort
* the transaction and don't commit anything.
*/
- if (backfill_tags(transport, transaction, tags_ref_map,
- &fetch_head))
+ if (backfill_tags(&display_state, transport, transaction, tags_ref_map,
+ &fetch_head, config))
retcode = 1;
}
@@ -1794,6 +1779,7 @@ cleanup:
error("%s", err.buf);
}
+ display_state_release(&display_state);
close_fetch_head(&fetch_head);
strbuf_release(&err);
free_refs(ref_map);
@@ -1848,7 +1834,8 @@ static int add_remote_or_group(const char *name, struct string_list *list)
return 1;
}
-static void add_options_to_argv(struct strvec *argv)
+static void add_options_to_argv(struct strvec *argv,
+ const struct fetch_config *config)
{
if (dry_run)
strvec_push(argv, "--dry-run");
@@ -1862,9 +1849,11 @@ static void add_options_to_argv(struct strvec *argv)
strvec_push(argv, "--force");
if (keep)
strvec_push(argv, "--keep");
- if (recurse_submodules == RECURSE_SUBMODULES_ON)
+ if (config->recurse_submodules == RECURSE_SUBMODULES_ON)
strvec_push(argv, "--recurse-submodules");
- else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
+ else if (config->recurse_submodules == RECURSE_SUBMODULES_OFF)
+ strvec_push(argv, "--no-recurse-submodules");
+ else if (config->recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
strvec_push(argv, "--recurse-submodules=on-demand");
if (tags == TAGS_SET)
strvec_push(argv, "--tags");
@@ -1880,6 +1869,10 @@ static void add_options_to_argv(struct strvec *argv)
strvec_push(argv, "--ipv4");
else if (family == TRANSPORT_FAMILY_IPV6)
strvec_push(argv, "--ipv6");
+ if (!write_fetch_head)
+ strvec_push(argv, "--no-write-fetch-head");
+ if (config->display_format == DISPLAY_FORMAT_PORCELAIN)
+ strvec_pushf(argv, "--porcelain");
}
/* Fetch multiple remotes in parallel */
@@ -1888,9 +1881,11 @@ struct parallel_fetch_state {
const char **argv;
struct string_list *remotes;
int next, result;
+ const struct fetch_config *config;
};
-static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
+static int fetch_next_remote(struct child_process *cp,
+ struct strbuf *out UNUSED,
void *cb, void **task_cb)
{
struct parallel_fetch_state *state = cb;
@@ -1906,13 +1901,14 @@ static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
strvec_push(&cp->args, remote);
cp->git_cmd = 1;
- if (verbosity >= 0)
+ if (verbosity >= 0 && state->config->display_format != DISPLAY_FORMAT_PORCELAIN)
printf(_("Fetching %s\n"), remote);
return 1;
}
-static int fetch_failed_to_start(struct strbuf *out, void *cb, void *task_cb)
+static int fetch_failed_to_start(struct strbuf *out UNUSED,
+ void *cb, void *task_cb)
{
struct parallel_fetch_state *state = cb;
const char *remote = task_cb;
@@ -1937,7 +1933,8 @@ static int fetch_finished(int result, struct strbuf *out,
return 0;
}
-static int fetch_multiple(struct string_list *list, int max_children)
+static int fetch_multiple(struct string_list *list, int max_children,
+ const struct fetch_config *config)
{
int i, result = 0;
struct strvec argv = STRVEC_INIT;
@@ -1948,12 +1945,17 @@ static int fetch_multiple(struct string_list *list, int max_children)
return errcode;
}
- strvec_pushl(&argv, "fetch", "--append", "--no-auto-gc",
+ /*
+ * Cancel out the fetch.bundleURI config when running subprocesses,
+ * to avoid fetching from the same bundle list multiple times.
+ */
+ strvec_pushl(&argv, "-c", "fetch.bundleURI=",
+ "fetch", "--append", "--no-auto-gc",
"--no-write-commit-graph", NULL);
- add_options_to_argv(&argv);
+ add_options_to_argv(&argv, config);
if (max_children != 1 && list->nr != 1) {
- struct parallel_fetch_state state = { argv.v, list, 0, 0 };
+ struct parallel_fetch_state state = { argv.v, list, 0, 0, config };
const struct run_process_parallel_opts opts = {
.tr2_category = "fetch",
.tr2_label = "parallel/fetch",
@@ -1977,7 +1979,7 @@ static int fetch_multiple(struct string_list *list, int max_children)
strvec_pushv(&cmd.args, argv.v);
strvec_push(&cmd.args, name);
- if (verbosity >= 0)
+ if (verbosity >= 0 && config->display_format != DISPLAY_FORMAT_PORCELAIN)
printf(_("Fetching %s\n"), name);
cmd.git_cmd = 1;
if (run_command(&cmd)) {
@@ -2007,7 +2009,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)
* If no prior partial clone/fetch and the current fetch DID NOT
* request a partial-fetch, do a normal fetch.
*/
- if (!has_promisor_remote() && !filter_options.choice)
+ if (!repo_has_promisor_remote(the_repository) && !filter_options.choice)
return;
/*
@@ -2032,7 +2034,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)
}
static int fetch_one(struct remote *remote, int argc, const char **argv,
- int prune_tags_ok, int use_stdin_refspecs)
+ int prune_tags_ok, int use_stdin_refspecs,
+ const struct fetch_config *config)
{
struct refspec rs = REFSPEC_INIT_FETCH;
int i;
@@ -2050,8 +2053,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
/* no command line request */
if (0 <= remote->prune)
prune = remote->prune;
- else if (0 <= fetch_prune_config)
- prune = fetch_prune_config;
+ else if (0 <= config->prune)
+ prune = config->prune;
else
prune = PRUNE_BY_DEFAULT;
}
@@ -2060,8 +2063,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
/* no command line request */
if (0 <= remote->prune_tags)
prune_tags = remote->prune_tags;
- else if (0 <= fetch_prune_tags_config)
- prune_tags = fetch_prune_tags_config;
+ else if (0 <= config->prune_tags)
+ prune_tags = config->prune_tags;
else
prune_tags = PRUNE_TAGS_BY_DEFAULT;
}
@@ -2099,7 +2102,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack_atexit);
sigchain_push(SIGPIPE, SIG_IGN);
- exit_code = do_fetch(gtransport, &rs);
+ exit_code = do_fetch(gtransport, &rs, config);
sigchain_pop(SIGPIPE);
refspec_clear(&rs);
transport_disconnect(gtransport);
@@ -2109,12 +2112,119 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
int cmd_fetch(int argc, const char **argv, const char *prefix)
{
- int i;
+ struct fetch_config config = {
+ .display_format = DISPLAY_FORMAT_FULL,
+ .prune = -1,
+ .prune_tags = -1,
+ .show_forced_updates = 1,
+ .recurse_submodules = RECURSE_SUBMODULES_DEFAULT,
+ .parallel = 1,
+ .submodule_fetch_jobs = -1,
+ };
+ const char *submodule_prefix = "";
const char *bundle_uri;
struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote = NULL;
+ int all = 0, multiple = 0;
int result = 0;
int prune_tags_ok = 1;
+ int enable_auto_gc = 1;
+ int unshallow = 0;
+ int max_jobs = -1;
+ int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
+ int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
+ int fetch_write_commit_graph = -1;
+ int stdin_refspecs = 0;
+ int negotiate_only = 0;
+ int porcelain = 0;
+ int i;
+
+ struct option builtin_fetch_options[] = {
+ OPT__VERBOSITY(&verbosity),
+ OPT_BOOL(0, "all", &all,
+ N_("fetch from all remotes")),
+ OPT_BOOL(0, "set-upstream", &set_upstream,
+ N_("set upstream for git pull/fetch")),
+ OPT_BOOL('a', "append", &append,
+ N_("append to .git/FETCH_HEAD instead of overwriting")),
+ OPT_BOOL(0, "atomic", &atomic_fetch,
+ N_("use atomic transaction to update references")),
+ OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
+ N_("path to upload pack on remote end")),
+ OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
+ OPT_BOOL('m', "multiple", &multiple,
+ N_("fetch from multiple remotes")),
+ OPT_SET_INT('t', "tags", &tags,
+ N_("fetch all tags and associated objects"), TAGS_SET),
+ OPT_SET_INT('n', NULL, &tags,
+ N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
+ OPT_INTEGER('j', "jobs", &max_jobs,
+ N_("number of submodules fetched in parallel")),
+ OPT_BOOL(0, "prefetch", &prefetch,
+ N_("modify the refspec to place all refs within refs/prefetch/")),
+ OPT_BOOL('p', "prune", &prune,
+ N_("prune remote-tracking branches no longer on remote")),
+ OPT_BOOL('P', "prune-tags", &prune_tags,
+ N_("prune local tags no longer on remote and clobber changed tags")),
+ OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
+ N_("control recursive fetching of submodules"),
+ PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
+ OPT_BOOL(0, "dry-run", &dry_run,
+ N_("dry run")),
+ OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
+ OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
+ N_("write fetched references to the FETCH_HEAD file")),
+ OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
+ OPT_BOOL('u', "update-head-ok", &update_head_ok,
+ N_("allow updating of HEAD ref")),
+ OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+ OPT_STRING(0, "depth", &depth, N_("depth"),
+ N_("deepen history of shallow clone")),
+ OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
+ N_("deepen history of shallow repository based on time")),
+ OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
+ N_("deepen history of shallow clone, excluding rev")),
+ OPT_INTEGER(0, "deepen", &deepen_relative,
+ N_("deepen history of shallow clone")),
+ 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",
+ &recurse_submodules_default, N_("on-demand"),
+ N_("default for recursive fetching of submodules "
+ "(lower priority than config files)"),
+ PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
+ OPT_BOOL(0, "update-shallow", &update_shallow,
+ N_("accept refs that update .git/shallow")),
+ OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"),
+ N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
+ OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
+ OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
+ TRANSPORT_FAMILY_IPV4),
+ OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
+ TRANSPORT_FAMILY_IPV6),
+ OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
+ N_("report that we have only objects reachable from this object")),
+ OPT_BOOL(0, "negotiate-only", &negotiate_only,
+ N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+ OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
+ N_("run 'maintenance --auto' after fetching")),
+ OPT_BOOL(0, "auto-gc", &enable_auto_gc,
+ N_("run 'maintenance --auto' after fetching")),
+ OPT_BOOL(0, "show-forced-updates", &config.show_forced_updates,
+ N_("check for forced-updates on all updated branches")),
+ OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
+ N_("write the commit-graph after fetching")),
+ OPT_BOOL(0, "stdin", &stdin_refspecs,
+ N_("accept refspecs from stdin")),
+ OPT_END()
+ };
packet_trace_identity("fetch");
@@ -2128,7 +2238,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
free(anon);
}
- git_config(git_fetch_config, NULL);
+ git_config(git_fetch_config, &config);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
@@ -2138,7 +2248,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
builtin_fetch_options, builtin_fetch_usage, 0);
if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
- recurse_submodules = recurse_submodules_cli;
+ config.recurse_submodules = recurse_submodules_cli;
if (negotiate_only) {
switch (recurse_submodules_cli) {
@@ -2149,7 +2259,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
* submodules. Skip it by setting recurse_submodules to
* RECURSE_SUBMODULES_OFF.
*/
- recurse_submodules = RECURSE_SUBMODULES_OFF;
+ config.recurse_submodules = RECURSE_SUBMODULES_OFF;
break;
default:
@@ -2158,15 +2268,35 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
}
}
- if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
- int *sfjc = submodule_fetch_jobs_config == -1
- ? &submodule_fetch_jobs_config : NULL;
- int *rs = recurse_submodules == RECURSE_SUBMODULES_DEFAULT
- ? &recurse_submodules : NULL;
+ if (config.recurse_submodules != RECURSE_SUBMODULES_OFF) {
+ int *sfjc = config.submodule_fetch_jobs == -1
+ ? &config.submodule_fetch_jobs : NULL;
+ int *rs = config.recurse_submodules == RECURSE_SUBMODULES_DEFAULT
+ ? &config.recurse_submodules : NULL;
fetch_config_from_gitmodules(sfjc, rs);
}
+
+ if (porcelain) {
+ switch (recurse_submodules_cli) {
+ case RECURSE_SUBMODULES_OFF:
+ case RECURSE_SUBMODULES_DEFAULT:
+ /*
+ * Reference updates in submodules would be ambiguous
+ * in porcelain mode, so we reject this combination.
+ */
+ config.recurse_submodules = RECURSE_SUBMODULES_OFF;
+ break;
+
+ default:
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--porcelain", "--recurse-submodules");
+ }
+
+ config.display_format = DISPLAY_FORMAT_PORCELAIN;
+ }
+
if (negotiate_only && !negotiation_tip.nr)
die(_("--negotiate-only needs one or more --negotiation-tip=*"));
@@ -2263,9 +2393,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
printf("%s\n", oid_to_hex(oid));
oidset_clear(&acked_commits);
} else if (remote) {
- if (filter_options.choice || has_promisor_remote())
+ if (filter_options.choice || repo_has_promisor_remote(the_repository))
fetch_one_setup_partial(remote);
- result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs);
+ result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs,
+ &config);
} else {
int max_children = max_jobs;
@@ -2282,13 +2413,12 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
"from one remote"));
if (max_children < 0)
- max_children = fetch_parallel_config;
+ max_children = config.parallel;
/* TODO should this also die if we have a previous partial-clone? */
- result = fetch_multiple(&list, max_children);
+ result = fetch_multiple(&list, max_children, &config);
}
-
/*
* This is only needed after fetch_one(), which does not fetch
* submodules by itself.
@@ -2298,20 +2428,20 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
* the fetched history from each remote, so there is no need
* to fetch submodules from here.
*/
- if (!result && remote && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
+ if (!result && remote && (config.recurse_submodules != RECURSE_SUBMODULES_OFF)) {
struct strvec options = STRVEC_INIT;
int max_children = max_jobs;
if (max_children < 0)
- max_children = submodule_fetch_jobs_config;
+ max_children = config.submodule_fetch_jobs;
if (max_children < 0)
- max_children = fetch_parallel_config;
+ max_children = config.parallel;
- add_options_to_argv(&options);
+ add_options_to_argv(&options, &config);
result = fetch_submodules(the_repository,
&options,
submodule_prefix,
- recurse_submodules,
+ config.recurse_submodules,
recurse_submodules_default,
verbosity < 0,
max_children);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 8d8fd393f8..cc81241642 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -1,7 +1,9 @@
#include "builtin.h"
#include "config.h"
#include "fmt-merge-msg.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "wrapper.h"
static const char * const fmt_merge_msg_usage[] = {
N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 6f62f40d12..350bfa6e81 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -1,10 +1,13 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "gettext.h"
#include "refs.h"
#include "object.h"
#include "parse-options.h"
#include "ref-filter.h"
+#include "strbuf.h"
+#include "strvec.h"
+#include "commit-reach.h"
static char const * const for_each_ref_usage[] = {
N_("git for-each-ref [<options>] [<pattern>]"),
@@ -19,12 +22,14 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
int i;
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
- int maxcount = 0, icase = 0;
+ int maxcount = 0, icase = 0, omit_empty = 0;
struct ref_array array;
- struct ref_filter filter;
+ struct ref_filter filter = REF_FILTER_INIT;
struct ref_format format = REF_FORMAT_INIT;
struct strbuf output = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
+ int from_stdin = 0;
+ struct strvec vec = STRVEC_INIT;
struct option opts[] = {
OPT_BIT('s', "shell", &format.quote_style,
@@ -35,11 +40,14 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
N_("quote placeholders suitably for python"), QUOTE_PYTHON),
OPT_BIT(0 , "tcl", &format.quote_style,
N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
+ OPT_BOOL(0, "omit-empty", &omit_empty,
+ N_("do not output a newline after empty formatted refs")),
OPT_GROUP(""),
OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
OPT__COLOR(&format.use_color, N_("respect format colors")),
+ OPT_REF_FILTER_EXCLUDE(&filter),
OPT_REF_SORT(&sorting_options),
OPT_CALLBACK(0, "points-at", &filter.points_at,
N_("object"), N_("print only refs which points at the given object"),
@@ -49,11 +57,11 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")),
OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")),
OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
+ OPT_BOOL(0, "stdin", &from_stdin, N_("read reference patterns from stdin")),
OPT_END(),
};
memset(&array, 0, sizeof(array));
- memset(&filter, 0, sizeof(filter));
format.format = "%(objectname) %(objecttype)\t%(refname)";
@@ -75,9 +83,27 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
filter.ignore_case = icase;
- filter.name_patterns = argv;
+ if (from_stdin) {
+ struct strbuf line = STRBUF_INIT;
+
+ if (argv[0])
+ die(_("unknown arguments supplied with --stdin"));
+
+ while (strbuf_getline(&line, stdin) != EOF)
+ strvec_push(&vec, line.buf);
+
+ strbuf_release(&line);
+
+ /* vec.v is NULL-terminated, just like 'argv'. */
+ filter.name_patterns = vec.v;
+ } else {
+ filter.name_patterns = argv;
+ }
+
filter.match_as_path = 1;
filter_refs(&array, &filter, FILTER_REFS_ALL);
+ filter_ahead_behind(the_repository, &format, &array);
+
ref_array_sort(sorting, &array);
if (!maxcount || array.nr < maxcount)
@@ -88,14 +114,15 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
if (format_ref_array_item(array.items[i], &format, &output, &err))
die("%s", err.buf);
fwrite(output.buf, 1, output.len, stdout);
- putchar('\n');
+ if (output.len || !omit_empty)
+ putchar('\n');
}
strbuf_release(&err);
strbuf_release(&output);
ref_array_clear(&array);
- free_commit_list(filter.with_commit);
- free_commit_list(filter.no_commit);
+ ref_filter_clear(&filter);
ref_sorting_release(sorting);
+ strvec_clear(&vec);
return 0;
}
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
index 6aeac37148..28186b30f5 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -1,7 +1,9 @@
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
+#include "repository.h"
#include "run-command.h"
#include "string-list.h"
@@ -32,6 +34,7 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
static const char *config_key = NULL;
int i, result = 0;
const struct string_list *values;
+ int err;
const struct option options[] = {
OPT_STRING(0, "config", &config_key, N_("config"),
@@ -45,14 +48,11 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
if (!config_key)
die(_("missing --config=<config>"));
- values = repo_config_get_value_multi(the_repository,
- config_key);
-
- /*
- * Do nothing on an empty list, which is equivalent to the case
- * where the config variable does not exist at all.
- */
- if (!values)
+ err = repo_config_get_string_multi(the_repository, config_key, &values);
+ if (err < 0)
+ usage_msg_optf(_("got bad config --config=%s"),
+ for_each_repo_usage, options, config_key);
+ else if (err)
return 0;
for (i = 0; !result && i < values->nr; i++)
diff --git a/builtin/fsck.c b/builtin/fsck.c
index d207bd909b..b81f1a2010 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -1,6 +1,6 @@
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "commit.h"
@@ -18,10 +18,18 @@
#include "streaming.h"
#include "decorate.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "replace-object.h"
#include "resolve-undo.h"
#include "run-command.h"
+#include "sparse-index.h"
#include "worktree.h"
+#include "pack-revindex.h"
+#include "pack-bitmap.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
@@ -51,6 +59,8 @@ static int name_objects;
#define ERROR_REFS 010
#define ERROR_COMMIT_GRAPH 020
#define ERROR_MULTI_PACK_INDEX 040
+#define ERROR_PACK_REV_INDEX 0100
+#define ERROR_BITMAP 0200
static const char *describe_object(const struct object_id *oid)
{
@@ -233,17 +243,17 @@ static void mark_unreachable_referents(const struct object_id *oid)
}
static int mark_loose_unreachable_referents(const struct object_id *oid,
- const char *path,
- void *data)
+ const char *path UNUSED,
+ void *data UNUSED)
{
mark_unreachable_referents(oid);
return 0;
}
static int mark_packed_unreachable_referents(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
- void *data)
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED,
+ void *data UNUSED)
{
mark_unreachable_referents(oid);
return 0;
@@ -661,14 +671,15 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data)
return 0; /* keep checking other objects, even if we saw an error */
}
-static int fsck_cruft(const char *basename, const char *path, void *data)
+static int fsck_cruft(const char *basename, const char *path,
+ void *data UNUSED)
{
if (!starts_with(basename, "tmp_obj_"))
fprintf_ln(stderr, _("bad sha1 file: %s"), path);
return 0;
}
-static int fsck_subdir(unsigned int nr, const char *path, void *data)
+static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)
{
struct for_each_loose_cb *cb_data = data;
struct progress *progress = cb_data->progress;
@@ -732,19 +743,19 @@ static int fsck_head_link(const char *head_ref_name,
return 0;
}
-static int fsck_cache_tree(struct cache_tree *it)
+static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
{
int i;
int err = 0;
if (verbose)
- fprintf_ln(stderr, _("Checking cache tree"));
+ fprintf_ln(stderr, _("Checking cache tree of %s"), index_path);
if (0 <= it->entry_count) {
struct object *obj = parse_object(the_repository, &it->oid);
if (!obj) {
- error(_("%s: invalid sha1 pointer in cache-tree"),
- oid_to_hex(&it->oid));
+ error(_("%s: invalid sha1 pointer in cache-tree of %s"),
+ oid_to_hex(&it->oid), index_path);
errors_found |= ERROR_REFS;
return 1;
}
@@ -755,11 +766,12 @@ static int fsck_cache_tree(struct cache_tree *it)
err |= objerror(obj, _("non-tree in cache-tree"));
}
for (i = 0; i < it->subtree_nr; i++)
- err |= fsck_cache_tree(it->down[i]->cache_tree);
+ err |= fsck_cache_tree(it->down[i]->cache_tree, index_path);
return err;
}
-static int fsck_resolve_undo(struct index_state *istate)
+static int fsck_resolve_undo(struct index_state *istate,
+ const char *index_path)
{
struct string_list_item *item;
struct string_list *resolve_undo = istate->resolve_undo;
@@ -782,8 +794,9 @@ static int fsck_resolve_undo(struct index_state *istate)
obj = parse_object(the_repository, &ru->oid[i]);
if (!obj) {
- error(_("%s: invalid sha1 pointer in resolve-undo"),
- oid_to_hex(&ru->oid[i]));
+ error(_("%s: invalid sha1 pointer in resolve-undo of %s"),
+ oid_to_hex(&ru->oid[i]),
+ index_path);
errors_found |= ERROR_REFS;
continue;
}
@@ -796,6 +809,38 @@ static int fsck_resolve_undo(struct index_state *istate)
return 0;
}
+static void fsck_index(struct index_state *istate, const char *index_path,
+ int is_main_index)
+{
+ unsigned int i;
+
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(istate);
+ for (i = 0; i < istate->cache_nr; i++) {
+ unsigned int mode;
+ struct blob *blob;
+ struct object *obj;
+
+ mode = istate->cache[i]->ce_mode;
+ if (S_ISGITLINK(mode))
+ continue;
+ blob = lookup_blob(the_repository,
+ &istate->cache[i]->oid);
+ if (!blob)
+ continue;
+ obj = &blob->object;
+ obj->flags |= USED;
+ fsck_put_object_name(&fsck_walk_options, &obj->oid,
+ "%s:%s",
+ is_main_index ? "" : index_path,
+ istate->cache[i]->name);
+ mark_object_reachable(obj);
+ }
+ if (istate->cache_tree)
+ fsck_cache_tree(istate->cache_tree, index_path);
+ fsck_resolve_undo(istate, index_path);
+}
+
static void mark_object_for_connectivity(const struct object_id *oid)
{
struct object *obj = lookup_unknown_object(the_repository, oid);
@@ -803,22 +848,54 @@ static void mark_object_for_connectivity(const struct object_id *oid)
}
static int mark_loose_for_connectivity(const struct object_id *oid,
- const char *path,
- void *data)
+ const char *path UNUSED,
+ void *data UNUSED)
{
mark_object_for_connectivity(oid);
return 0;
}
static int mark_packed_for_connectivity(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
- void *data)
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED,
+ void *data UNUSED)
{
mark_object_for_connectivity(oid);
return 0;
}
+static int check_pack_rev_indexes(struct repository *r, int show_progress)
+{
+ struct progress *progress = NULL;
+ uint32_t pack_count = 0;
+ int res = 0;
+
+ if (show_progress) {
+ for (struct packed_git *p = get_all_packs(r); p; p = p->next)
+ pack_count++;
+ progress = start_delayed_progress("Verifying reverse pack-indexes", pack_count);
+ pack_count = 0;
+ }
+
+ for (struct packed_git *p = get_all_packs(r); p; p = p->next) {
+ int load_error = load_pack_revindex_from_disk(p);
+
+ if (load_error < 0) {
+ error(_("unable to load rev-index for pack '%s'"), p->pack_name);
+ res = ERROR_PACK_REV_INDEX;
+ } else if (!load_error &&
+ !load_pack_revindex(r, p) &&
+ verify_pack_revindex(p)) {
+ error(_("invalid rev-index for pack '%s'"), p->pack_name);
+ res = ERROR_PACK_REV_INDEX;
+ }
+ display_progress(progress, ++pack_count);
+ }
+ stop_progress(&progress);
+
+ return res;
+}
+
static char const * const fsck_usage[] = {
N_("git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
" [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
@@ -923,7 +1000,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
struct object_id oid;
- if (!get_oid(arg, &oid)) {
+ if (!repo_get_oid(the_repository, arg, &oid)) {
struct object *obj = lookup_object(the_repository,
&oid);
@@ -956,34 +1033,36 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
if (keep_cache_objects) {
+ struct worktree **worktrees, **p;
+
verify_index_checksum = 1;
verify_ce_order = 1;
- repo_read_index(the_repository);
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < the_index.cache_nr; i++) {
- unsigned int mode;
- struct blob *blob;
- struct object *obj;
- mode = the_index.cache[i]->ce_mode;
- if (S_ISGITLINK(mode))
- continue;
- blob = lookup_blob(the_repository,
- &the_index.cache[i]->oid);
- if (!blob)
- continue;
- obj = &blob->object;
- obj->flags |= USED;
- fsck_put_object_name(&fsck_walk_options, &obj->oid,
- ":%s", the_index.cache[i]->name);
- mark_object_reachable(obj);
+ worktrees = get_worktrees();
+ for (p = worktrees; *p; p++) {
+ struct worktree *wt = *p;
+ struct index_state istate =
+ INDEX_STATE_INIT(the_repository);
+ char *path;
+
+ /*
+ * Make a copy since the buffer is reusable
+ * and may get overwritten by other calls
+ * while we're examining the index.
+ */
+ path = xstrdup(worktree_git_path(wt, "index"));
+ read_index_from(&istate, path, get_worktree_git_dir(wt));
+ fsck_index(&istate, path, wt->is_current);
+ discard_index(&istate);
+ free(path);
}
- if (the_index.cache_tree)
- fsck_cache_tree(the_index.cache_tree);
- fsck_resolve_undo(&the_index);
+ free_worktrees(worktrees);
}
+ errors_found |= check_pack_rev_indexes(the_repository, show_progress);
+ if (verify_bitmap_files(the_repository))
+ errors_found |= ERROR_BITMAP;
+
check_connectivity();
if (the_repository->settings.core_commit_graph) {
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0feef8caf6..74d1d6a585 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1,15 +1,22 @@
#include "builtin.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
#include "parse-options.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
#include "fsmonitor-ipc.h"
#include "fsmonitor-path-utils.h"
+#include "fsmonitor-settings.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"
+#include "trace.h"
+#include "trace2.h"
static const char * const builtin_fsmonitor__daemon_usage[] = {
N_("git fsmonitor--daemon start [<options>]"),
@@ -1574,7 +1581,7 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
}
#else
-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED)
{
struct option options[] = {
OPT_END()
diff --git a/builtin/gc.c b/builtin/gc.c
index 02455fdcd7..91eec7703a 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -11,6 +11,10 @@
*/
#include "builtin.h"
+#include "abspath.h"
+#include "date.h"
+#include "environment.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "tempfile.h"
@@ -22,16 +26,22 @@
#include "commit.h"
#include "commit-graph.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "pack.h"
#include "pack-objects.h"
+#include "path.h"
#include "blob.h"
#include "tree.h"
#include "promisor-remote.h"
#include "refs.h"
#include "remote.h"
#include "exec-cmd.h"
+#include "gettext.h"
#include "hook.h"
+#include "setup.h"
+#include "trace2.h"
+#include "wrapper.h"
#define FAILED_RUN "failed to run %s"
@@ -42,7 +52,7 @@ static const char * const builtin_gc_usage[] = {
static int pack_refs = 1;
static int prune_reflogs = 1;
-static int cruft_packs = -1;
+static int cruft_packs = 1;
static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
@@ -213,7 +223,7 @@ static struct packed_git *find_base_packs(struct string_list *packs,
struct packed_git *p, *base = NULL;
for (p = get_all_packs(the_repository); p; p = p->next) {
- if (!p->pack_local)
+ if (!p->pack_local || p->is_cruft)
continue;
if (limit) {
if (p->pack_size >= limit)
@@ -284,7 +294,7 @@ static uint64_t total_ram(void)
static uint64_t estimate_repack_memory(struct packed_git *pack)
{
- unsigned long nr_objects = approximate_object_count();
+ unsigned long nr_objects = repo_approximate_object_count(the_repository);
size_t os_cache, heap;
if (!pack || !nr_objects)
@@ -602,10 +612,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (prune_expire && parse_expiry_date(prune_expire, &dummy))
die(_("failed to parse prune expiry value %s"), prune_expire);
- prepare_repo_settings(the_repository);
- if (cruft_packs < 0)
- cruft_packs = the_repository->settings.gc_cruft_packs;
-
if (aggressive) {
strvec_push(&repack, "-f");
if (aggressive_depth > 0)
@@ -699,7 +705,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
strvec_push(&prune, prune_expire);
if (quiet)
strvec_push(&prune, "--no-progress");
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
strvec_push(&prune,
"--exclude-promisor-objects");
prune_cmd.git_cmd = 1;
@@ -820,7 +826,7 @@ static int dfs_on_ref(const char *refname UNUSED,
commit = lookup_commit(the_repository, oid);
if (!commit)
return 0;
- if (parse_commit(commit) ||
+ if (repo_parse_commit(the_repository, commit) ||
commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
return 0;
@@ -837,7 +843,7 @@ static int dfs_on_ref(const char *refname UNUSED,
commit = pop_commit(&stack);
for (parent = commit->parents; parent; parent = parent->next) {
- if (parse_commit(parent->item) ||
+ if (repo_parse_commit(the_repository, parent->item) ||
commit_graph_position(parent->item) != COMMIT_NOT_FROM_GRAPH ||
parent->item->object.flags & SEEN)
continue;
@@ -976,9 +982,9 @@ struct write_loose_object_data {
static int loose_object_auto_limit = 100;
-static int loose_object_count(const struct object_id *oid,
- const char *path,
- void *data)
+static int loose_object_count(const struct object_id *oid UNUSED,
+ const char *path UNUSED,
+ void *data)
{
int *count = (int*)data;
if (++(*count) >= loose_object_auto_limit)
@@ -1003,15 +1009,15 @@ static int loose_object_auto_condition(void)
NULL, NULL, &count);
}
-static int bail_on_loose(const struct object_id *oid,
- const char *path,
- void *data)
+static int bail_on_loose(const struct object_id *oid UNUSED,
+ const char *path UNUSED,
+ void *data UNUSED)
{
return 1;
}
static int write_loose_object_to_stdin(const struct object_id *oid,
- const char *path,
+ const char *path UNUSED,
void *data)
{
struct write_loose_object_data *d = (struct write_loose_object_data *)data;
@@ -1493,7 +1499,6 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
};
int found = 0;
const char *key = "maintenance.repo";
- char *config_value;
char *maintpath = get_maintpath();
struct string_list_item *item;
const struct string_list *list;
@@ -1508,13 +1513,10 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
git_config_set("maintenance.auto", "false");
/* Set maintenance strategy, if unset */
- if (!git_config_get_string("maintenance.strategy", &config_value))
- free(config_value);
- else
+ if (git_config_get("maintenance.strategy"))
git_config_set("maintenance.strategy", "incremental");
- list = git_config_get_value_multi(key);
- if (list) {
+ if (!git_config_get_string_multi(key, &list)) {
for_each_string_list_item(item, list) {
if (!strcmp(maintpath, item->string)) {
found = 1;
@@ -1580,11 +1582,10 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
if (config_file) {
git_configset_init(&cs);
git_configset_add_file(&cs, config_file);
- list = git_configset_get_value_multi(&cs, key);
- } else {
- list = git_config_get_value_multi(key);
}
- if (list) {
+ if (!(config_file
+ ? git_configset_get_string_multi(&cs, key, &list)
+ : git_config_get_string_multi(key, &list))) {
for_each_string_list_item(item, list) {
if (!strcmp(maintpath, item->string)) {
found = 1;
@@ -1686,11 +1687,11 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
if (is_available)
*is_available = 0;
- string_list_split_in_place(&list, testing, ',', -1);
+ string_list_split_in_place(&list, testing, ",", -1);
for_each_string_list_item(item, &list) {
struct string_list pair = STRING_LIST_INIT_NODUP;
- if (string_list_split_in_place(&pair, item->string, ':', 2) != 2)
+ if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
continue;
if (!strcmp(*cmd, pair.items[0].string)) {
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
index 491af9202d..9303e386cc 100644
--- a/builtin/get-tar-commit-id.c
+++ b/builtin/get-tar-commit-id.c
@@ -1,11 +1,11 @@
/*
* Copyright (c) 2005, 2006 Rene Scharfe
*/
-#include "cache.h"
+#include "builtin.h"
#include "commit.h"
#include "tar.h"
-#include "builtin.h"
#include "quote.h"
+#include "wrapper.h"
static const char builtin_get_tar_commit_id_usage[] =
"git get-tar-commit-id";
@@ -14,7 +14,7 @@ static const char builtin_get_tar_commit_id_usage[] =
#define RECORDSIZE (512)
#define HEADERSIZE (2 * RECORDSIZE)
-int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
+int cmd_get_tar_commit_id(int argc, const char **argv UNUSED, const char *prefix)
{
char buffer[HEADERSIZE];
struct ustar_header *header = (struct ustar_header *)buffer;
@@ -24,6 +24,8 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
long len;
char *end;
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc != 1)
usage(builtin_get_tar_commit_id_usage);
@@ -32,7 +34,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
die_errno("git get-tar-commit-id: read error");
if (n != HEADERSIZE)
die_errno("git get-tar-commit-id: EOF before reading tar header");
- if (header->typeflag[0] != 'g')
+ if (header->typeflag[0] != TYPEFLAG_GLOBAL_HEADER)
return 1;
len = strtol(content, &end, 10);
diff --git a/builtin/grep.c b/builtin/grep.c
index f7821c5fbb..72e70b3a48 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -3,7 +3,10 @@
*
* Copyright (c) 2006 Junio C Hamano
*/
-#include "cache.h"
+#include "builtin.h"
+#include "alloc.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "blob.h"
@@ -11,7 +14,6 @@
#include "commit.h"
#include "tag.h"
#include "tree-walk.h"
-#include "builtin.h"
#include "parse-options.h"
#include "string-list.h"
#include "run-command.h"
@@ -20,10 +22,17 @@
#include "quote.h"
#include "dir.h"
#include "pathspec.h"
+#include "setup.h"
#include "submodule.h"
#include "submodule-config.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "packfile.h"
+#include "pager.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "write-or-die.h"
static const char *grep_prefix;
@@ -560,7 +569,8 @@ static int grep_cache(struct grep_opt *opt,
void *data;
unsigned long size;
- data = read_object_file(&ce->oid, &type, &size);
+ data = repo_read_object_file(the_repository, &ce->oid,
+ &type, &size);
init_tree_desc(&tree, data, size);
hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
@@ -650,7 +660,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
void *data;
unsigned long size;
- data = read_object_file(&entry.oid, &type, &size);
+ data = repo_read_object_file(the_repository,
+ &entry.oid, &type, &size);
if (!data)
die(_("unable to read tree (%s)"),
oid_to_hex(&entry.oid));
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 44db83f07f..5ffec99dce 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -5,12 +5,19 @@
* Copyright (C) Junio C Hamano, 2005
*/
#include "builtin.h"
+#include "abspath.h"
#include "config.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "blob.h"
#include "quote.h"
#include "parse-options.h"
#include "exec-cmd.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "write-or-die.h"
/*
* This is to create corrupt objects for debugging and as such it
diff --git a/builtin/help.c b/builtin/help.c
index 53f2812dfb..e93533fb09 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -1,15 +1,18 @@
/*
* Builtin help command
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
#include "exec-cmd.h"
+#include "gettext.h"
+#include "pager.h"
#include "parse-options.h"
+#include "path.h"
#include "run-command.h"
#include "config-list.h"
#include "help.h"
#include "alias.h"
+#include "setup.h"
#ifndef DEFAULT_HELP_FORMAT
#define DEFAULT_HELP_FORMAT "man"
diff --git a/builtin/hook.c b/builtin/hook.c
index f95b7965c5..09b51a6487 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -1,6 +1,6 @@
-#include "cache.h"
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
#include "hook.h"
#include "parse-options.h"
#include "strbuf.h"
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 6648f2daef..820860265d 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1,6 +1,10 @@
#include "builtin.h"
+#include "alloc.h"
#include "config.h"
#include "delta.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "pack.h"
#include "csum-file.h"
#include "blob.h"
@@ -10,11 +14,18 @@
#include "progress.h"
#include "fsck.h"
#include "exec-cmd.h"
+#include "strbuf.h"
#include "streaming.h"
#include "thread-utils.h"
#include "packfile.h"
-#include "object-store.h"
+#include "pack-revindex.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
+#include "replace-object.h"
#include "promisor-remote.h"
+#include "setup.h"
+#include "wrapper.h"
static const char index_pack_usage[] =
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
@@ -801,7 +812,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
if (startup_info->have_repository) {
read_lock();
collision_test_needed =
- has_object_file_with_flags(oid, OBJECT_INFO_QUICK);
+ repo_has_object_file_with_flags(the_repository, oid,
+ OBJECT_INFO_QUICK);
read_unlock();
}
@@ -821,7 +833,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
die(_("cannot read existing object info %s"), oid_to_hex(oid));
if (has_type != type || has_size != size)
die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
- has_data = read_object_file(oid, &has_type, &has_size);
+ has_data = repo_read_object_file(the_repository, oid,
+ &has_type, &has_size);
read_unlock();
if (!data)
data = new_data = get_data_from_pack(obj_entry);
@@ -1388,7 +1401,7 @@ static void fix_unresolved_deltas(struct hashfile *f)
sorted_by_pos[i] = &ref_deltas[i];
QSORT(sorted_by_pos, nr_ref_deltas, delta_pos_compare);
- if (has_promisor_remote()) {
+ if (repo_has_promisor_remote(the_repository)) {
/*
* Prefetch the delta bases.
*/
@@ -1414,7 +1427,8 @@ static void fix_unresolved_deltas(struct hashfile *f)
if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
continue;
- data = read_object_file(&d->oid, &type, &size);
+ data = repo_read_object_file(the_repository, &d->oid, &type,
+ &size);
if (!data)
continue;
@@ -1743,12 +1757,13 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
fsck_options.walk = mark_link;
reset_pack_idx_option(&opts);
+ opts.flags |= WRITE_REV;
git_config(git_index_pack_config, &opts);
if (prefix && chdir(prefix))
die(_("Cannot come back to cwd"));
- if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
- rev_index = 1;
+ if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+ rev_index = 0;
else
rev_index = !!(opts.flags & (WRITE_REV_VERIFY | WRITE_REV));
diff --git a/builtin/init-db.c b/builtin/init-db.c
index dcaaf102ea..0d8bd4d721 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -3,476 +3,17 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
-#include "config.h"
-#include "refs.h"
#include "builtin.h"
-#include "exec-cmd.h"
+#include "abspath.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-file.h"
#include "parse-options.h"
-#include "worktree.h"
-
-#ifndef DEFAULT_GIT_TEMPLATE_DIR
-#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
-#endif
-
-#ifdef NO_TRUSTABLE_FILEMODE
-#define TEST_FILEMODE 0
-#else
-#define TEST_FILEMODE 1
-#endif
-
-#define GIT_DEFAULT_HASH_ENVIRONMENT "GIT_DEFAULT_HASH"
-
-static int init_is_bare_repository = 0;
-static int init_shared_repository = -1;
-
-static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
- DIR *dir)
-{
- size_t path_baselen = path->len;
- size_t template_baselen = template_path->len;
- struct dirent *de;
-
- /* Note: if ".git/hooks" file exists in the repository being
- * re-initialized, /etc/core-git/templates/hooks/update would
- * cause "git init" to fail here. I think this is sane but
- * it means that the set of templates we ship by default, along
- * with the way the namespace under .git/ is organized, should
- * be really carefully chosen.
- */
- safe_create_dir(path->buf, 1);
- while ((de = readdir(dir)) != NULL) {
- struct stat st_git, st_template;
- int exists = 0;
-
- strbuf_setlen(path, path_baselen);
- strbuf_setlen(template_path, template_baselen);
-
- if (de->d_name[0] == '.')
- continue;
- strbuf_addstr(path, de->d_name);
- strbuf_addstr(template_path, de->d_name);
- if (lstat(path->buf, &st_git)) {
- if (errno != ENOENT)
- die_errno(_("cannot stat '%s'"), path->buf);
- }
- else
- exists = 1;
-
- if (lstat(template_path->buf, &st_template))
- die_errno(_("cannot stat template '%s'"), template_path->buf);
-
- if (S_ISDIR(st_template.st_mode)) {
- DIR *subdir = opendir(template_path->buf);
- if (!subdir)
- die_errno(_("cannot opendir '%s'"), template_path->buf);
- strbuf_addch(path, '/');
- strbuf_addch(template_path, '/');
- copy_templates_1(path, template_path, subdir);
- closedir(subdir);
- }
- else if (exists)
- continue;
- else if (S_ISLNK(st_template.st_mode)) {
- struct strbuf lnk = STRBUF_INIT;
- if (strbuf_readlink(&lnk, template_path->buf,
- st_template.st_size) < 0)
- die_errno(_("cannot readlink '%s'"), template_path->buf);
- if (symlink(lnk.buf, path->buf))
- die_errno(_("cannot symlink '%s' '%s'"),
- lnk.buf, path->buf);
- strbuf_release(&lnk);
- }
- else if (S_ISREG(st_template.st_mode)) {
- if (copy_file(path->buf, template_path->buf, st_template.st_mode))
- die_errno(_("cannot copy '%s' to '%s'"),
- template_path->buf, path->buf);
- }
- else
- error(_("ignoring template %s"), template_path->buf);
- }
-}
-
-static void copy_templates(const char *template_dir, const char *init_template_dir)
-{
- struct strbuf path = STRBUF_INIT;
- struct strbuf template_path = STRBUF_INIT;
- size_t template_len;
- struct repository_format template_format = REPOSITORY_FORMAT_INIT;
- struct strbuf err = STRBUF_INIT;
- DIR *dir;
- char *to_free = NULL;
-
- if (!template_dir)
- template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
- if (!template_dir)
- template_dir = init_template_dir;
- if (!template_dir)
- template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
- if (!template_dir[0]) {
- free(to_free);
- return;
- }
-
- strbuf_addstr(&template_path, template_dir);
- strbuf_complete(&template_path, '/');
- template_len = template_path.len;
-
- dir = opendir(template_path.buf);
- if (!dir) {
- warning(_("templates not found in %s"), template_dir);
- goto free_return;
- }
-
- /* Make sure that template is from the correct vintage */
- strbuf_addstr(&template_path, "config");
- read_repository_format(&template_format, template_path.buf);
- strbuf_setlen(&template_path, template_len);
-
- /*
- * No mention of version at all is OK, but anything else should be
- * verified.
- */
- if (template_format.version >= 0 &&
- verify_repository_format(&template_format, &err) < 0) {
- warning(_("not copying templates from '%s': %s"),
- template_dir, err.buf);
- strbuf_release(&err);
- goto close_free_return;
- }
-
- strbuf_addstr(&path, get_git_common_dir());
- strbuf_complete(&path, '/');
- copy_templates_1(&path, &template_path, dir);
-close_free_return:
- closedir(dir);
-free_return:
- free(to_free);
- strbuf_release(&path);
- strbuf_release(&template_path);
- clear_repository_format(&template_format);
-}
-
-/*
- * If the git_dir is not directly inside the working tree, then git will not
- * find it by default, and we need to set the worktree explicitly.
- */
-static int needs_work_tree_config(const char *git_dir, const char *work_tree)
-{
- if (!strcmp(work_tree, "/") && !strcmp(git_dir, "/.git"))
- return 0;
- if (skip_prefix(git_dir, work_tree, &git_dir) &&
- !strcmp(git_dir, "/.git"))
- return 0;
- return 1;
-}
-
-void initialize_repository_version(int hash_algo, int reinit)
-{
- char repo_version_string[10];
- int repo_version = GIT_REPO_VERSION;
-
- if (hash_algo != GIT_HASH_SHA1)
- repo_version = GIT_REPO_VERSION_READ;
-
- /* This forces creation of new config file */
- xsnprintf(repo_version_string, sizeof(repo_version_string),
- "%d", repo_version);
- git_config_set("core.repositoryformatversion", repo_version_string);
-
- if (hash_algo != GIT_HASH_SHA1)
- git_config_set("extensions.objectformat",
- hash_algos[hash_algo].name);
- else if (reinit)
- git_config_set_gently("extensions.objectformat", NULL);
-}
-
-static int create_default_files(const char *template_path,
- const char *original_git_dir,
- const char *initial_branch,
- const struct repository_format *fmt,
- int quiet)
-{
- struct stat st1;
- struct strbuf buf = STRBUF_INIT;
- char *path;
- char junk[2];
- int reinit;
- int filemode;
- struct strbuf err = STRBUF_INIT;
- const char *init_template_dir = NULL;
- const char *work_tree = get_git_work_tree();
-
- /*
- * First copy the templates -- we might have the default
- * config file there, in which case we would want to read
- * from it after installing.
- *
- * Before reading that config, we also need to clear out any cached
- * values (since we've just potentially changed what's available on
- * disk).
- */
- git_config_get_pathname("init.templatedir", &init_template_dir);
- copy_templates(template_path, init_template_dir);
- free((char *)init_template_dir);
- git_config_clear();
- reset_shared_repository();
- git_config(git_default_config, NULL);
-
- /*
- * We must make sure command-line options continue to override any
- * values we might have just re-read from the config.
- */
- is_bare_repository_cfg = init_is_bare_repository || !work_tree;
- if (init_shared_repository != -1)
- set_shared_repository(init_shared_repository);
-
- /*
- * We would have created the above under user's umask -- under
- * shared-repository settings, we would need to fix them up.
- */
- if (get_shared_repository()) {
- adjust_shared_perm(get_git_dir());
- }
-
- /*
- * We need to create a "refs" dir in any case so that older
- * versions of git can tell that this is a repository.
- */
- safe_create_dir(git_path("refs"), 1);
- adjust_shared_perm(git_path("refs"));
-
- if (refs_init_db(&err))
- die("failed to set up refs db: %s", err.buf);
-
- /*
- * Point the HEAD symref to the initial branch with if HEAD does
- * not yet exist.
- */
- path = git_path_buf(&buf, "HEAD");
- reinit = (!access(path, R_OK)
- || readlink(path, junk, sizeof(junk)-1) != -1);
- if (!reinit) {
- char *ref;
-
- if (!initial_branch)
- initial_branch = git_default_branch_name(quiet);
-
- ref = xstrfmt("refs/heads/%s", initial_branch);
- if (check_refname_format(ref, 0) < 0)
- die(_("invalid initial branch name: '%s'"),
- initial_branch);
-
- if (create_symref("HEAD", ref, NULL) < 0)
- exit(1);
- free(ref);
- }
-
- initialize_repository_version(fmt->hash_algo, 0);
-
- /* Check filemode trustability */
- path = git_path_buf(&buf, "config");
- filemode = TEST_FILEMODE;
- if (TEST_FILEMODE && !lstat(path, &st1)) {
- struct stat st2;
- filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
- !lstat(path, &st2) &&
- st1.st_mode != st2.st_mode &&
- !chmod(path, st1.st_mode));
- if (filemode && !reinit && (st1.st_mode & S_IXUSR))
- filemode = 0;
- }
- git_config_set("core.filemode", filemode ? "true" : "false");
-
- if (is_bare_repository())
- git_config_set("core.bare", "true");
- else {
- git_config_set("core.bare", "false");
- /* allow template config file to override the default */
- if (log_all_ref_updates == LOG_REFS_UNSET)
- git_config_set("core.logallrefupdates", "true");
- if (needs_work_tree_config(original_git_dir, work_tree))
- git_config_set("core.worktree", work_tree);
- }
-
- if (!reinit) {
- /* Check if symlink is supported in the work tree */
- path = git_path_buf(&buf, "tXXXXXX");
- if (!close(xmkstemp(path)) &&
- !unlink(path) &&
- !symlink("testing", path) &&
- !lstat(path, &st1) &&
- S_ISLNK(st1.st_mode))
- unlink(path); /* good */
- else
- git_config_set("core.symlinks", "false");
-
- /* Check if the filesystem is case-insensitive */
- path = git_path_buf(&buf, "CoNfIg");
- if (!access(path, F_OK))
- git_config_set("core.ignorecase", "true");
- probe_utf8_pathname_composition();
- }
-
- strbuf_release(&buf);
- return reinit;
-}
-
-static void create_object_directory(void)
-{
- struct strbuf path = STRBUF_INIT;
- size_t baselen;
-
- strbuf_addstr(&path, get_object_directory());
- baselen = path.len;
-
- safe_create_dir(path.buf, 1);
-
- strbuf_setlen(&path, baselen);
- strbuf_addstr(&path, "/pack");
- safe_create_dir(path.buf, 1);
-
- strbuf_setlen(&path, baselen);
- strbuf_addstr(&path, "/info");
- safe_create_dir(path.buf, 1);
-
- strbuf_release(&path);
-}
-
-static void separate_git_dir(const char *git_dir, const char *git_link)
-{
- struct stat st;
-
- if (!stat(git_link, &st)) {
- const char *src;
-
- if (S_ISREG(st.st_mode))
- src = read_gitfile(git_link);
- else if (S_ISDIR(st.st_mode))
- src = git_link;
- else
- die(_("unable to handle file type %d"), (int)st.st_mode);
-
- if (rename(src, git_dir))
- die_errno(_("unable to move %s to %s"), src, git_dir);
- repair_worktrees(NULL, NULL);
- }
-
- write_file(git_link, "gitdir: %s", git_dir);
-}
-
-static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
-{
- const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
- /*
- * If we already have an initialized repo, don't allow the user to
- * specify a different algorithm, as that could cause corruption.
- * Otherwise, if the user has specified one on the command line, use it.
- */
- if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
- die(_("attempt to reinitialize repository with different hash"));
- else if (hash != GIT_HASH_UNKNOWN)
- repo_fmt->hash_algo = hash;
- else if (env) {
- int env_algo = hash_algo_by_name(env);
- if (env_algo == GIT_HASH_UNKNOWN)
- die(_("unknown hash algorithm '%s'"), env);
- repo_fmt->hash_algo = env_algo;
- }
-}
-
-int init_db(const char *git_dir, const char *real_git_dir,
- const char *template_dir, int hash, const char *initial_branch,
- unsigned int flags)
-{
- int reinit;
- int exist_ok = flags & INIT_DB_EXIST_OK;
- char *original_git_dir = real_pathdup(git_dir, 1);
- struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
-
- if (real_git_dir) {
- struct stat st;
-
- if (!exist_ok && !stat(git_dir, &st))
- die(_("%s already exists"), git_dir);
-
- if (!exist_ok && !stat(real_git_dir, &st))
- die(_("%s already exists"), real_git_dir);
-
- set_git_dir(real_git_dir, 1);
- git_dir = get_git_dir();
- separate_git_dir(git_dir, original_git_dir);
- }
- else {
- set_git_dir(git_dir, 1);
- git_dir = get_git_dir();
- }
- startup_info->have_repository = 1;
-
- /* Ensure `core.hidedotfiles` is processed */
- git_config(platform_core_config, NULL);
-
- safe_create_dir(git_dir, 0);
-
- init_is_bare_repository = is_bare_repository();
-
- /* Check to see if the repository version is right.
- * Note that a newly created repository does not have
- * config file, so this will not fail. What we are catching
- * is an attempt to reinitialize new repository with an old tool.
- */
- check_repository_format(&repo_fmt);
-
- validate_hash_algorithm(&repo_fmt, hash);
-
- reinit = create_default_files(template_dir, original_git_dir,
- initial_branch, &repo_fmt,
- flags & INIT_DB_QUIET);
- if (reinit && initial_branch)
- warning(_("re-init: ignored --initial-branch=%s"),
- initial_branch);
-
- create_object_directory();
-
- if (get_shared_repository()) {
- char buf[10];
- /* We do not spell "group" and such, so that
- * the configuration can be read by older version
- * of git. Note, we use octal numbers for new share modes,
- * and compatibility values for PERM_GROUP and
- * PERM_EVERYBODY.
- */
- if (get_shared_repository() < 0)
- /* force to the mode value */
- xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
- else if (get_shared_repository() == PERM_GROUP)
- xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
- else if (get_shared_repository() == PERM_EVERYBODY)
- xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
- else
- BUG("invalid value for shared_repository");
- git_config_set("core.sharedrepository", buf);
- git_config_set("receive.denyNonFastforwards", "true");
- }
-
- if (!(flags & INIT_DB_QUIET)) {
- int len = strlen(git_dir);
-
- if (reinit)
- printf(get_shared_repository()
- ? _("Reinitialized existing shared Git repository in %s%s\n")
- : _("Reinitialized existing Git repository in %s%s\n"),
- git_dir, len && git_dir[len-1] != '/' ? "/" : "");
- else
- printf(get_shared_repository()
- ? _("Initialized empty shared Git repository in %s%s\n")
- : _("Initialized empty Git repository in %s%s\n"),
- git_dir, len && git_dir[len-1] != '/' ? "/" : "");
- }
-
- free(original_git_dir);
- return 0;
-}
+#include "path.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "wrapper.h"
static int guess_repository_type(const char *git_dir)
{
@@ -538,6 +79,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
const char *object_format = NULL;
const char *initial_branch = NULL;
int hash_algo = GIT_HASH_UNKNOWN;
+ int init_shared_repository = -1;
const struct option init_db_options[] = {
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
N_("directory from which templates will be used")),
@@ -695,5 +237,5 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
flags |= INIT_DB_EXIST_OK;
return init_db(git_dir, real_git_dir, template_dir, hash_algo,
- initial_branch, flags);
+ initial_branch, init_shared_repository, flags);
}
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index e58627c72a..c5e8345265 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -5,8 +5,8 @@
*
*/
-#include "cache.h"
#include "builtin.h"
+#include "gettext.h"
#include "parse-options.h"
#include "string-list.h"
#include "trailer.h"
diff --git a/builtin/log.c b/builtin/log.c
index a70fba198f..4e9d779537 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -4,10 +4,18 @@
* (C) Copyright 2006 Linus Torvalds
* 2006 Junio Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "pager.h"
#include "color.h"
#include "commit.h"
#include "diff.h"
@@ -15,6 +23,7 @@
#include "revision.h"
#include "log-tree.h"
#include "builtin.h"
+#include "oid-array.h"
#include "tag.h"
#include "reflog-walk.h"
#include "patch-ids.h"
@@ -35,6 +44,8 @@
#include "commit-reach.h"
#include "range-diff.h"
#include "tmp-objdir.h"
+#include "tree.h"
+#include "write-or-die.h"
#define MAIL_DEFAULT_WRAP 72
#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
@@ -56,6 +67,7 @@ static int stdout_mboxrd;
static const char *fmt_patch_subject_prefix = "PATCH";
static int fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
static const char *fmt_pretty;
+static int format_no_prefix;
static const char * const builtin_log_usage[] = {
N_("git log [<options>] [<revision-range>] [[--] <path>...]"),
@@ -182,10 +194,10 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
int i;
char *value = NULL;
struct string_list *include = decoration_filter->include_ref_pattern;
- const struct string_list *config_exclude =
- git_config_get_value_multi("log.excludeDecoration");
+ const struct string_list *config_exclude;
- if (config_exclude) {
+ if (!git_config_get_string_multi("log.excludeDecoration",
+ &config_exclude)) {
struct string_list_item *item;
for_each_string_list_item(item, config_exclude)
string_list_append(decoration_filter->exclude_ref_config_pattern,
@@ -436,7 +448,7 @@ static void log_show_early(struct rev_info *revs, struct commit_list *list)
setitimer(ITIMER_REAL, &early_output_timer, NULL);
}
-static void early_output(int signal)
+static void early_output(int signal UNUSED)
{
show_early_output = log_show_early;
}
@@ -582,6 +594,10 @@ static int git_log_config(const char *var, const char *value, void *cb)
}
if (!strcmp(var, "log.diffmerges"))
return diff_merges_config(value);
+ if (!strcmp(var, "log.diffmergeshide"))
+ return diff_merges_hide_config(git_config_bool(var, value));
+ if (!strcmp(var, "log.diffmerges-m-imply-p"))
+ return diff_merges_m_imply_p_config(git_config_bool(var, value));
if (!strcmp(var, "log.showroot")) {
default_show_root = git_config_bool(var, value);
return 0;
@@ -601,8 +617,6 @@ static int git_log_config(const char *var, const char *value, void *cb)
return 0;
}
- if (git_gpg_config(var, value, cb) < 0)
- return -1;
return git_diff_ui_config(var, value, cb);
}
@@ -675,7 +689,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
{
unsigned long size;
enum object_type type;
- char *buf = read_object_file(oid, &type, &size);
+ char *buf = repo_read_object_file(the_repository, oid, &type, &size);
int offset = 0;
if (!buf)
@@ -1084,6 +1098,19 @@ static int git_format_config(const char *var, const char *value, void *cb)
stdout_mboxrd = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "format.noprefix")) {
+ format_no_prefix = 1;
+ return 0;
+ }
+
+ /*
+ * ignore some porcelain config which would otherwise be parsed by
+ * git_diff_ui_config(), via git_log_config(); we can't just avoid
+ * diff_ui_config completely, because we do care about some ui options
+ * like color.
+ */
+ if (!strcmp(var, "diff.noprefix"))
+ return 0;
return git_log_config(var, value, cb);
}
@@ -1204,7 +1231,8 @@ static char *find_branch_name(struct rev_info *rev)
return NULL;
ref = rev->cmdline.rev[positive].name;
tip_oid = &rev->cmdline.rev[positive].item->oid;
- if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref, 0) &&
+ if (repo_dwim_ref(the_repository, ref, strlen(ref), &branch_oid,
+ &full_ref, 0) &&
skip_prefix(full_ref, "refs/heads/", &v) &&
oideq(tip_oid, &branch_oid))
branch = xstrdup(v);
@@ -1314,10 +1342,11 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte, 0);
for (i = 0; !need_8bit_cte && i < nr; i++) {
- const char *buf = get_commit_buffer(list[i], NULL);
+ const char *buf = repo_get_commit_buffer(the_repository,
+ list[i], NULL);
if (has_non_ascii(buf))
need_8bit_cte = 1;
- unuse_commit_buffer(list[i], buf);
+ repo_unuse_commit_buffer(the_repository, list[i], buf);
}
if (!branch_name)
@@ -1370,7 +1399,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
.other_arg = &other_arg
};
- diff_setup(&opts);
+ repo_diff_setup(the_repository, &opts);
opts.file = rev->diffopt.file;
opts.use_color = rev->diffopt.use_color;
diff_setup_done(&opts);
@@ -1642,14 +1671,16 @@ static struct commit *get_base_commit(const char *base_commit,
struct commit *commit;
struct object_id oid;
- if (get_oid(upstream, &oid)) {
+ if (repo_get_oid(the_repository, upstream, &oid)) {
if (die_on_failure)
die(_("failed to resolve '%s' as a valid ref"), upstream);
else
return NULL;
}
commit = lookup_commit_or_die(&oid, "upstream base");
- base_list = get_merge_bases_many(commit, total, list);
+ base_list = repo_get_merge_bases_many(the_repository,
+ commit, total,
+ list);
/* There should be one and only one merge base. */
if (!base_list || base_list->next) {
if (die_on_failure) {
@@ -1683,7 +1714,9 @@ static struct commit *get_base_commit(const char *base_commit,
while (rev_nr > 1) {
for (i = 0; i < rev_nr / 2; i++) {
struct commit_list *merge_base;
- merge_base = get_merge_bases(rev[2 * i], rev[2 * i + 1]);
+ merge_base = repo_get_merge_bases(the_repository,
+ rev[2 * i],
+ rev[2 * i + 1]);
if (!merge_base || merge_base->next) {
if (die_on_failure) {
die(_("failed to find exact merge base"));
@@ -1701,7 +1734,7 @@ static struct commit *get_base_commit(const char *base_commit,
rev_nr = DIV_ROUND_UP(rev_nr, 2);
}
- if (!in_merge_bases(base, rev[0])) {
+ if (!repo_in_merge_bases(the_repository, base, rev[0])) {
if (die_on_failure) {
die(_("base commit should be the ancestor of revision list"));
} else {
@@ -1993,6 +2026,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
+ if (format_no_prefix)
+ diff_set_noprefix(&rev.diffopt);
+
if (default_attach) {
rev.mime_boundary = default_attach;
rev.no_inline = 1;
@@ -2097,6 +2133,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
/* Always generate a patch */
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
+ rev.always_show_header = 1;
rev.zero_commit = zero_commit;
rev.patch_name_max = fmt_patch_name_max;
@@ -2396,7 +2433,7 @@ done:
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
{
struct object_id oid;
- if (get_oid(arg, &oid) == 0) {
+ if (repo_get_oid(the_repository, arg, &oid) == 0) {
struct commit *commit = lookup_commit_reference(the_repository,
&oid);
if (commit) {
@@ -2418,12 +2455,12 @@ static void print_commit(char sign, struct commit *commit, int verbose,
{
if (!verbose) {
fprintf(file, "%c %s\n", sign,
- find_unique_abbrev(&commit->object.oid, abbrev));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev));
} else {
struct strbuf buf = STRBUF_INIT;
pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
fprintf(file, "%c %s %s\n", sign,
- find_unique_abbrev(&commit->object.oid, abbrev),
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev),
buf.buf);
strbuf_release(&buf);
}
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index a03b559eca..c1ff79c559 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -5,22 +5,31 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "builtin.h"
#include "repository.h"
#include "config.h"
+#include "convert.h"
#include "quote.h"
#include "dir.h"
-#include "builtin.h"
+#include "gettext.h"
+#include "object-name.h"
#include "strbuf.h"
#include "tree.h"
#include "cache-tree.h"
#include "parse-options.h"
#include "resolve-undo.h"
#include "string-list.h"
+#include "path.h"
#include "pathspec.h"
+#include "read-cache.h"
#include "run-command.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
#include "submodule-config.h"
+#include "object-store.h"
+#include "hex.h"
+
static int abbrev;
static int show_deleted;
@@ -89,12 +98,15 @@ static void write_name(const char *name)
static void write_name_to_buf(struct strbuf *sb, const char *name)
{
- const char *rel = relative_path(name, prefix_len ? prefix : NULL, sb);
+ struct strbuf buf = STRBUF_INIT;
+ const char *rel = relative_path(name, prefix_len ? prefix : NULL, &buf);
if (line_terminator)
quote_c_style(rel, sb, NULL, 0);
else
strbuf_addstr(sb, rel);
+
+ strbuf_release(&buf);
}
static const char *get_tag(const struct cache_entry *ce, const char *tag)
@@ -234,6 +246,24 @@ static void show_submodule(struct repository *superproject,
repo_clear(&subrepo);
}
+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, "-");
+ }
+}
struct show_index_data {
const char *pathname;
struct index_state *istate;
@@ -265,6 +295,12 @@ static size_t expand_show_index(struct strbuf *sb, const char *start,
strbuf_addf(sb, "%06o", data->ce->ce_mode);
else if (skip_prefix(start, "(objectname)", &p))
strbuf_add_unique_abbrev(sb, &data->ce->oid, abbrev);
+ else if (skip_prefix(start, "(objecttype)", &p))
+ strbuf_addstr(sb, type_name(object_type(data->ce->ce_mode)));
+ else if (skip_prefix(start, "(objectsize:padded)", &p))
+ expand_objectsize(sb, &data->ce->oid, object_type(data->ce->ce_mode), 1);
+ else if (skip_prefix(start, "(objectsize)", &p))
+ expand_objectsize(sb, &data->ce->oid, object_type(data->ce->ce_mode), 0);
else if (skip_prefix(start, "(stage)", &p))
strbuf_addf(sb, "%d", ce_stage(data->ce));
else if (skip_prefix(start, "(eolinfo:index)", &p))
@@ -360,7 +396,7 @@ static void show_ru_info(struct index_state *istate)
if (!ui->mode[i])
continue;
printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
- find_unique_abbrev(&ui->oid[i], abbrev),
+ repo_find_unique_abbrev(the_repository, &ui->oid[i], abbrev),
i + 1);
write_name(path);
}
@@ -509,143 +545,6 @@ static int get_common_prefix_len(const char *common_prefix)
return common_prefix_len;
}
-static int read_one_entry_opt(struct index_state *istate,
- const struct object_id *oid,
- struct strbuf *base,
- const char *pathname,
- unsigned mode, int opt)
-{
- int len;
- struct cache_entry *ce;
-
- if (S_ISDIR(mode))
- return READ_TREE_RECURSIVE;
-
- len = strlen(pathname);
- ce = make_empty_cache_entry(istate, base->len + len);
-
- ce->ce_mode = create_ce_mode(mode);
- ce->ce_flags = create_ce_flags(1);
- ce->ce_namelen = base->len + len;
- memcpy(ce->name, base->buf, base->len);
- memcpy(ce->name + base->len, pathname, len+1);
- oidcpy(&ce->oid, oid);
- return add_index_entry(istate, ce, opt);
-}
-
-static int read_one_entry(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode,
- void *context)
-{
- struct index_state *istate = context;
- return read_one_entry_opt(istate, oid, base, pathname,
- mode,
- ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
-}
-
-/*
- * This is used when the caller knows there is no existing entries at
- * the stage that will conflict with the entry being added.
- */
-static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode,
- void *context)
-{
- struct index_state *istate = context;
- return read_one_entry_opt(istate, oid, base, pathname,
- mode, ADD_CACHE_JUST_APPEND);
-}
-
-/*
- * Read the tree specified with --with-tree option
- * (typically, HEAD) into stage #1 and then
- * squash them down to stage #0. This is used for
- * --error-unmatch to list and check the path patterns
- * that were given from the command line. We are not
- * going to write this index out.
- */
-void overlay_tree_on_index(struct index_state *istate,
- const char *tree_name, const char *prefix)
-{
- struct tree *tree;
- struct object_id oid;
- struct pathspec pathspec;
- struct cache_entry *last_stage0 = NULL;
- int i;
- read_tree_fn_t fn = NULL;
- int err;
-
- if (get_oid(tree_name, &oid))
- die("tree-ish %s not found.", tree_name);
- tree = parse_tree_indirect(&oid);
- if (!tree)
- die("bad tree-ish %s", tree_name);
-
- /* Hoist the unmerged entries up to stage #3 to make room */
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(istate);
- for (i = 0; i < istate->cache_nr; i++) {
- struct cache_entry *ce = istate->cache[i];
- if (!ce_stage(ce))
- continue;
- ce->ce_flags |= CE_STAGEMASK;
- }
-
- if (prefix) {
- static const char *(matchbuf[1]);
- matchbuf[0] = NULL;
- parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC,
- PATHSPEC_PREFER_CWD, prefix, matchbuf);
- } else
- memset(&pathspec, 0, sizeof(pathspec));
-
- /*
- * See if we have cache entry at the stage. If so,
- * do it the original slow way, otherwise, append and then
- * sort at the end.
- */
- for (i = 0; !fn && i < istate->cache_nr; i++) {
- const struct cache_entry *ce = istate->cache[i];
- if (ce_stage(ce) == 1)
- fn = read_one_entry;
- }
-
- if (!fn)
- fn = read_one_entry_quick;
- err = read_tree(the_repository, tree, &pathspec, fn, istate);
- clear_pathspec(&pathspec);
- if (err)
- die("unable to read tree entries %s", tree_name);
-
- /*
- * Sort the cache entry -- we need to nuke the cache tree, though.
- */
- if (fn == read_one_entry_quick) {
- cache_tree_free(&istate->cache_tree);
- QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
- }
-
- for (i = 0; i < istate->cache_nr; i++) {
- struct cache_entry *ce = istate->cache[i];
- switch (ce_stage(ce)) {
- case 0:
- last_stage0 = ce;
- /* fallthru */
- default:
- continue;
- case 1:
- /*
- * If there is stage #0 entry for this, we do not
- * need to show it. We use CE_UPDATE bit to mark
- * such an entry.
- */
- if (last_stage0 &&
- !strcmp(last_stage0->name, ce->name))
- ce->ce_flags |= CE_UPDATE;
- }
- }
-}
-
static const char * const ls_files_usage[] = {
N_("git ls-files [<options>] [<file>...]"),
NULL
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 6516177348..fc76575430 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -1,9 +1,13 @@
#include "builtin.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hex.h"
#include "transport.h"
+#include "pkt-line.h"
#include "ref-filter.h"
#include "remote.h"
#include "refs.h"
+#include "parse-options.h"
+#include "wildmatch.h"
static const char * const ls_remote_usage[] = {
N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 8cc8c995df..4e17f13648 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -3,14 +3,17 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "blob.h"
#include "tree.h"
#include "commit.h"
+#include "path.h"
#include "quote.h"
-#include "builtin.h"
#include "parse-options.h"
#include "pathspec.h"
@@ -228,7 +231,7 @@ static int show_tree_default(const struct object_id *oid, struct strbuf *base,
return early;
printf("%06o %s %s\t", mode, type_name(object_type(mode)),
- find_unique_abbrev(oid, options->abbrev));
+ repo_find_unique_abbrev(the_repository, oid, options->abbrev));
show_tree_common_default_long(options, base, pathname, base->len);
return recurse;
}
@@ -259,7 +262,8 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
}
printf("%06o %s %s %7s\t", mode, type_name(type),
- find_unique_abbrev(oid, options->abbrev), size_text);
+ repo_find_unique_abbrev(the_repository, oid, options->abbrev),
+ size_text);
show_tree_common_default_long(options, base, pathname, base->len);
return recurse;
}
@@ -310,7 +314,7 @@ static int show_tree_object(const struct object_id *oid, struct strbuf *base,
if (early >= 0)
return early;
- str = find_unique_abbrev(oid, options->abbrev);
+ str = repo_find_unique_abbrev(the_repository, oid, options->abbrev);
if (options->null_termination) {
fputs(str, stdout);
fputc('\0', stdout);
@@ -433,7 +437,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
ls_tree_usage, ls_tree_options);
if (argc < 1)
usage_with_options(ls_tree_usage, ls_tree_options);
- if (get_oid(argv[0], &oid))
+ if (repo_get_oid(the_repository, argv[0], &oid))
die("Not a valid object name %s", argv[0]);
/*
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 01d16ef9e5..53b55dd71c 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -2,8 +2,10 @@
* Another stupid program, this one parsing the headers of an
* email to figure out authorship and subject
*/
-#include "cache.h"
#include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
#include "utf8.h"
#include "strbuf.h"
#include "mailinfo.h"
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 73509f651b..3af9ddb8ae 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -4,8 +4,8 @@
* It just splits a mbox into a list of files: "0001" "0002" ..
* so you can process them further from there.
*/
-#include "cache.h"
#include "builtin.h"
+#include "gettext.h"
#include "string-list.h"
#include "strbuf.h"
@@ -277,6 +277,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)
const char **argp;
static const char *stdin_only[] = { "-", NULL };
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
for (argp = argv+1; *argp; argp++) {
const char *arg = *argp;
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 6f3941f2a4..e68b7fe45d 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -1,10 +1,12 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "commit.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
#include "diff.h"
#include "revision.h"
+#include "object-name.h"
#include "parse-options.h"
#include "repository.h"
#include "commit-reach.h"
@@ -13,7 +15,8 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
struct commit_list *result, *r;
- result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1);
+ result = repo_get_merge_bases_many_dirty(the_repository, rev[0],
+ rev_nr - 1, rev + 1);
if (!result)
return 1;
@@ -42,7 +45,7 @@ static struct commit *get_commit_reference(const char *arg)
struct object_id revkey;
struct commit *r;
- if (get_oid(arg, &revkey))
+ if (repo_get_oid(the_repository, arg, &revkey))
die("Not a valid object name %s", arg);
r = lookup_commit_reference(the_repository, &revkey);
if (!r)
@@ -105,7 +108,7 @@ static int handle_is_ancestor(int argc, const char **argv)
die("--is-ancestor takes exactly two commits");
one = get_commit_reference(argv[0]);
two = get_commit_reference(argv[1]);
- if (in_merge_bases(one, two))
+ if (repo_in_merge_bases(the_repository, one, two))
return 0;
else
return 1;
@@ -118,7 +121,7 @@ static int handle_fork_point(int argc, const char **argv)
const char *commitname;
commitname = (argc == 2) ? argv[1] : "HEAD";
- if (get_oid(commitname, &oid))
+ if (repo_get_oid(the_repository, commitname, &oid))
die("Not a valid object name: '%s'", commitname);
derived = lookup_commit_reference(the_repository, &oid);
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index c923bbf2ab..d7eb4c6540 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -1,6 +1,8 @@
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
#include "config.h"
+#include "gettext.h"
+#include "setup.h"
#include "xdiff/xdiff.h"
#include "xdiff-interface.h"
#include "parse-options.h"
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 452f833ac4..270d5f644a 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -1,6 +1,10 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "hex.h"
+#include "read-cache-ll.h"
+#include "repository.h"
#include "run-command.h"
+#include "sparse-index.h"
static const char *pgm;
static int one_shot, quiet;
@@ -70,7 +74,7 @@ static void merge_all(void)
}
}
-int cmd_merge_index(int argc, const char **argv, const char *prefix)
+int cmd_merge_index(int argc, const char **argv, const char *prefix UNUSED)
{
int i, force_file = 0;
diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c
index 284eb48609..932924e5d0 100644
--- a/builtin/merge-ours.c
+++ b/builtin/merge-ours.c
@@ -10,11 +10,12 @@
#include "git-compat-util.h"
#include "builtin.h"
#include "diff.h"
+#include "repository.h"
static const char builtin_merge_ours_usage[] =
"git merge-ours <base>... -- HEAD <remote>...";
-int cmd_merge_ours(int argc, const char **argv, const char *prefix)
+int cmd_merge_ours(int argc, const char **argv, const char *prefix UNUSED)
{
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_merge_ours_usage);
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index b9acbf5d34..3366699657 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -1,8 +1,12 @@
-#include "cache.h"
#include "builtin.h"
+#include "advice.h"
#include "commit.h"
+#include "gettext.h"
+#include "hash.h"
#include "tag.h"
#include "merge-recursive.h"
+#include "object-name.h"
+#include "repository.h"
#include "xdiff-interface.h"
static const char builtin_merge_recursive_usage[] =
@@ -20,7 +24,7 @@ static char *better_branch_name(const char *branch)
return xstrdup(name ? name : branch);
}
-int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
+int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
{
const struct object_id *bases[21];
unsigned bases_count = 0;
@@ -49,7 +53,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
}
if (bases_count < ARRAY_SIZE(bases)-1) {
struct object_id *oid = xmalloc(sizeof(struct object_id));
- if (get_oid(argv[i], oid))
+ if (repo_get_oid(the_repository, argv[i], oid))
die(_("could not parse object '%s'"), argv[i]);
bases[bases_count++] = oid;
}
@@ -70,9 +74,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
o.branch1 = argv[++i];
o.branch2 = argv[++i];
- if (get_oid(o.branch1, &h1))
+ if (repo_get_oid(the_repository, o.branch1, &h1))
die(_("could not resolve ref '%s'"), o.branch1);
- if (get_oid(o.branch2, &h2))
+ if (repo_get_oid(the_repository, o.branch2, &h2))
die(_("could not resolve ref '%s'"), o.branch2);
o.branch1 = better1 = better_branch_name(o.branch1);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 828dc81c42..2855792f20 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -3,16 +3,21 @@
#include "tree-walk.h"
#include "xdiff-interface.h"
#include "help.h"
+#include "gettext.h"
+#include "hex.h"
#include "commit.h"
#include "commit-reach.h"
#include "merge-ort.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "parse-options.h"
#include "repository.h"
#include "blob.h"
#include "exec-cmd.h"
#include "merge-blobs.h"
#include "quote.h"
+#include "tree.h"
+#include "config.h"
static int line_termination = '\n';
@@ -69,7 +74,9 @@ static void *result(struct merge_list *entry, unsigned long *size)
const char *path = entry->path;
if (!entry->stage)
- return read_object_file(&entry->blob->object.oid, &type, size);
+ return repo_read_object_file(the_repository,
+ &entry->blob->object.oid, &type,
+ size);
base = NULL;
if (entry->stage == 1) {
base = entry->blob;
@@ -92,8 +99,9 @@ static void *origin(struct merge_list *entry, unsigned long *size)
enum object_type type;
while (entry) {
if (entry->stage == 2)
- return read_object_file(&entry->blob->object.oid,
- &type, size);
+ return repo_read_object_file(the_repository,
+ &entry->blob->object.oid,
+ &type, size);
entry = entry->link;
}
return NULL;
@@ -443,16 +451,17 @@ static int real_merge(struct merge_tree_options *o,
die(_("could not lookup commit %s"), merge_base);
opt.ancestor = merge_base;
- base_tree = get_commit_tree(base_commit);
- parent1_tree = get_commit_tree(parent1);
- parent2_tree = get_commit_tree(parent2);
+ base_tree = repo_get_commit_tree(the_repository, base_commit);
+ parent1_tree = repo_get_commit_tree(the_repository, parent1);
+ parent2_tree = repo_get_commit_tree(the_repository, parent2);
merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
} else {
/*
* Get the merge bases, in reverse order; see comment above
* merge_incore_recursive in merge-ort.h
*/
- merge_bases = get_merge_bases(parent1, parent2);
+ merge_bases = repo_get_merge_bases(the_repository, parent1,
+ parent2);
if (!merge_bases && !o->allow_unrelated_histories)
die(_("refusing to merge unrelated histories"));
merge_bases = reverse_commit_list(merge_bases);
@@ -620,6 +629,8 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
if (argc != expected_remaining_argc)
usage_with_options(merge_tree_usage, mt_options);
+ git_config(git_default_config, NULL);
+
/* Do the relevant type of merge */
if (o.mode == MODE_REAL)
return real_merge(&o, merge_base, argv[0], argv[1], prefix);
diff --git a/builtin/merge.c b/builtin/merge.c
index 0a3c10a096..41fe0d8e5e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -7,10 +7,17 @@
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
+#include "alloc.h"
#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
#include "parse-options.h"
-#include "builtin.h"
#include "lockfile.h"
#include "run-command.h"
#include "hook.h"
@@ -20,6 +27,7 @@
#include "refspec.h"
#include "commit.h"
#include "diffcore.h"
+#include "path.h"
#include "revision.h"
#include "unpack-trees.h"
#include "cache-tree.h"
@@ -29,6 +37,7 @@
#include "color.h"
#include "rerere.h"
#include "help.h"
+#include "merge.h"
#include "merge-recursive.h"
#include "merge-ort-wrappers.h"
#include "resolve-undo.h"
@@ -44,6 +53,7 @@
#include "commit-reach.h"
#include "wt-status.h"
#include "commit-graph.h"
+#include "wrapper.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
@@ -337,7 +347,7 @@ static int save_state(struct object_id *stash)
else if (!len) /* no changes */
goto out;
strbuf_setlen(&buffer, buffer.len-1);
- if (get_oid(buffer.buf, stash))
+ if (repo_get_oid(the_repository, buffer.buf, stash))
die(_("not a valid object: %s"), buffer.buf);
rc = 0;
out:
@@ -517,7 +527,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!remote_head)
die(_("'%s' does not point to a commit"), remote);
- if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref, 0) > 0) {
+ if (repo_dwim_ref(the_repository, remote, strlen(remote), &branch_head,
+ &found_ref, 0) > 0) {
if (starts_with(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
oid_to_hex(&branch_head), remote);
@@ -661,9 +672,6 @@ static int git_merge_config(const char *k, const char *v, void *cb)
status = fmt_merge_msg_config(k, v, cb);
if (status)
return status;
- status = git_gpg_config(k, v, NULL);
- if (status)
- return status;
return git_diff_ui_config(k, v, cb);
}
@@ -872,13 +880,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)
strbuf_addch(&msg, '\n');
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
wt_status_append_cut_line(&msg);
- strbuf_commented_addf(&msg, "\n");
+ strbuf_commented_addf(&msg, comment_line_char, "\n");
}
- strbuf_commented_addf(&msg, _(merge_editor_comment));
+ strbuf_commented_addf(&msg, comment_line_char,
+ _(merge_editor_comment));
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
- strbuf_commented_addf(&msg, _(scissors_editor_comment));
+ strbuf_commented_addf(&msg, comment_line_char,
+ _(scissors_editor_comment));
else
- strbuf_commented_addf(&msg,
+ strbuf_commented_addf(&msg, comment_line_char,
_(no_scissors_editor_comment), comment_line_char);
}
if (signoff)
@@ -1531,7 +1541,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (!remoteheads)
; /* already up-to-date */
else if (!remoteheads->next)
- common = get_merge_bases(head_commit, remoteheads->item);
+ common = repo_get_merge_bases(the_repository, head_commit,
+ remoteheads->item);
else {
struct commit_list *list = remoteheads;
commit_list_insert(head_commit, &list);
@@ -1567,10 +1578,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (verbosity >= 0) {
printf(_("Updating %s..%s\n"),
- find_unique_abbrev(&head_commit->object.oid,
- DEFAULT_ABBREV),
- find_unique_abbrev(&remoteheads->item->object.oid,
- DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &head_commit->object.oid,
+ DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, &remoteheads->item->object.oid,
+ DEFAULT_ABBREV));
}
commit = remoteheads->item;
if (!commit) {
@@ -1610,7 +1621,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* Must first ensure that index matches HEAD before
* attempting a trivial merge.
*/
- struct tree *head_tree = get_commit_tree(head_commit);
+ struct tree *head_tree = repo_get_commit_tree(the_repository,
+ head_commit);
struct strbuf sb = STRBUF_INIT;
if (repo_index_has_changes(the_repository, head_tree,
@@ -1649,7 +1661,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* merge_bases again, otherwise "git merge HEAD^
* HEAD^^" would be missed.
*/
- common_one = get_merge_bases(head_commit, j->item);
+ common_one = repo_get_merge_bases(the_repository,
+ head_commit,
+ j->item);
if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
up_to_date = 0;
break;
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 5d22909122..43e2766db4 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,8 +1,12 @@
#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
+#include "strbuf.h"
#include "tag.h"
#include "replace-object.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "fsck.h"
#include "config.h"
@@ -51,7 +55,8 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
void *buffer;
const struct object_id *repl;
- buffer = read_object_file(tagged_oid, &type, &size);
+ buffer = repo_read_object_file(the_repository, tagged_oid, &type,
+ &size);
if (!buffer)
die(_("could not read tagged object '%s'"),
oid_to_hex(tagged_oid));
@@ -80,7 +85,7 @@ int cmd_mktag(int argc, const char **argv, const char *prefix)
int tagged_type;
struct object_id result;
- argc = parse_options(argc, argv, NULL,
+ argc = parse_options(argc, argv, prefix,
builtin_mktag_options,
builtin_mktag_usage, 0);
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 06d81400f5..0eea810c7e 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -4,10 +4,14 @@
* Copyright (c) Junio C Hamano, 2006, 2009
*/
#include "builtin.h"
+#include "alloc.h"
+#include "gettext.h"
+#include "hex.h"
#include "quote.h"
+#include "strbuf.h"
#include "tree.h"
#include "parse-options.h"
-#include "object-store.h"
+#include "object-store-ll.h"
static struct treeent {
unsigned mode;
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 9a18a82b05..a31dde1db9 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -1,10 +1,13 @@
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
#include "parse-options.h"
#include "midx.h"
+#include "strbuf.h"
#include "trace2.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#define BUILTIN_MIDX_WRITE_USAGE \
N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]" \
diff --git a/builtin/mv.c b/builtin/mv.c
index edd7b931fd..ae462bd7d4 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -5,13 +5,23 @@
*/
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "name-hash.h"
+#include "object-file.h"
#include "pathspec.h"
#include "lockfile.h"
#include "dir.h"
#include "cache-tree.h"
#include "string-list.h"
#include "parse-options.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
#include "submodule.h"
#include "entry.h"
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 97959bfaf9..c3b722b36f 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -1,15 +1,21 @@
#include "builtin.h"
-#include "cache.h"
+#include "alloc.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "commit.h"
#include "tag.h"
#include "refs.h"
+#include "object-name.h"
+#include "pager.h"
#include "parse-options.h"
#include "prio-queue.h"
#include "hash-lookup.h"
#include "commit-slab.h"
#include "commit-graph.h"
+#include "wildmatch.h"
/*
* One day. See the 'name a rev shortly after epoch' test in t6120 when
@@ -181,7 +187,7 @@ static void name_rev(struct commit *start_commit,
size_t parents_to_queue_nr, parents_to_queue_alloc = 0;
struct rev_name *start_name;
- parse_commit(start_commit);
+ repo_parse_commit(the_repository, start_commit);
if (commit_is_before_cutoff(start_commit))
return;
@@ -211,7 +217,7 @@ static void name_rev(struct commit *start_commit,
struct rev_name *parent_name;
int generation, distance;
- parse_commit(parent);
+ repo_parse_commit(the_repository, parent);
if (commit_is_before_cutoff(parent))
continue;
@@ -493,7 +499,8 @@ static void show_name(const struct object *obj,
else if (allow_undefined)
printf("undefined\n");
else if (always)
- printf("%s\n", find_unique_abbrev(oid, DEFAULT_ABBREV));
+ printf("%s\n",
+ repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
else
die("cannot describe '%s'", oid_to_hex(oid));
strbuf_release(&buf);
@@ -527,7 +534,7 @@ static void name_rev_line(char *p, struct name_ref_data *data)
counter = 0;
*(p+1) = 0;
- if (!get_oid(p - (hexsz - 1), &oid)) {
+ if (!repo_get_oid(the_repository, p - (hexsz - 1), &oid)) {
struct object *o =
lookup_object(the_repository, &oid);
if (o)
@@ -567,7 +574,11 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
N_("ignore refs matching <pattern>")),
OPT_GROUP(""),
OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
- OPT_BOOL(0, "stdin", &transform_stdin, N_("deprecated: use --annotate-stdin instead")),
+ OPT_BOOL_F(0,
+ "stdin",
+ &transform_stdin,
+ N_("deprecated: use --annotate-stdin instead"),
+ PARSE_OPT_HIDDEN),
OPT_BOOL(0, "annotate-stdin", &annotate_stdin, N_("annotate text from stdin")),
OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
OPT_BOOL(0, "always", &always,
@@ -604,7 +615,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
struct object *object;
struct commit *commit;
- if (get_oid(*argv, &oid)) {
+ if (repo_get_oid(the_repository, *argv, &oid)) {
fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
*argv);
continue;
diff --git a/builtin/notes.c b/builtin/notes.c
index 80d9dfd25c..d0053042c9 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -7,11 +7,17 @@
* and builtin/tag.c by Kristian Høgsberg and Carlos Rica.
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "alloc.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "notes.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "repository.h"
#include "blob.h"
#include "pretty.h"
@@ -23,12 +29,14 @@
#include "notes-merge.h"
#include "notes-utils.h"
#include "worktree.h"
+#include "write-or-die.h"
+static char *separator = "\n";
static const char * const git_notes_usage[] = {
N_("git notes [--ref <notes-ref>] [list [<object>]]"),
- N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
- N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] append [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
N_("git notes [--ref <notes-ref>] show [<object>]"),
N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
@@ -96,11 +104,26 @@ static const char * const git_notes_get_ref_usage[] = {
static const char note_template[] =
N_("Write/edit the notes for the following object:");
+enum notes_stripspace {
+ UNSPECIFIED = -1,
+ NO_STRIPSPACE = 0,
+ STRIPSPACE = 1,
+};
+
+struct note_msg {
+ enum notes_stripspace stripspace;
+ struct strbuf buf;
+};
+
struct note_data {
int given;
int use_editor;
+ int stripspace;
char *edit_path;
struct strbuf buf;
+ struct note_msg **messages;
+ size_t msg_nr;
+ size_t msg_alloc;
};
static void free_note_data(struct note_data *d)
@@ -110,11 +133,18 @@ static void free_note_data(struct note_data *d)
free(d->edit_path);
}
strbuf_release(&d->buf);
+
+ while (d->msg_nr--) {
+ strbuf_release(&d->messages[d->msg_nr]->buf);
+ free(d->messages[d->msg_nr]);
+ }
+ free(d->messages);
}
static int list_each_note(const struct object_id *object_oid,
- const struct object_id *note_oid, char *note_path,
- void *cb_data)
+ const struct object_id *note_oid,
+ char *note_path UNUSED,
+ void *cb_data UNUSED)
{
printf("%s %s\n", oid_to_hex(note_oid), oid_to_hex(object_oid));
return 0;
@@ -124,7 +154,7 @@ static void copy_obj_to_fd(int fd, const struct object_id *oid)
{
unsigned long size;
enum object_type type;
- char *buf = read_object_file(oid, &type, &size);
+ char *buf = repo_read_object_file(the_repository, oid, &type, &size);
if (buf) {
if (size)
write_or_die(fd, buf, size);
@@ -151,7 +181,7 @@ static void write_commented_object(int fd, const struct object_id *object)
if (strbuf_read(&buf, show.out, 0) < 0)
die_errno(_("could not read 'show' output"));
- strbuf_add_commented_lines(&cbuf, buf.buf, buf.len);
+ strbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);
write_or_die(fd, cbuf.buf, cbuf.len);
strbuf_release(&cbuf);
@@ -179,9 +209,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
copy_obj_to_fd(fd, old_note);
strbuf_addch(&buf, '\n');
- strbuf_add_commented_lines(&buf, "\n", strlen("\n"));
- strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));
- strbuf_add_commented_lines(&buf, "\n", strlen("\n"));
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
+ strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),
+ comment_line_char);
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
write_or_die(fd, buf.buf, buf.len);
write_commented_object(fd, object);
@@ -193,7 +224,8 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
if (launch_editor(d->edit_path, &d->buf, NULL)) {
die(_("please supply the note contents using either -m or -F option"));
}
- strbuf_stripspace(&d->buf, 1);
+ if (d->stripspace)
+ strbuf_stripspace(&d->buf, comment_line_char);
}
}
@@ -209,66 +241,98 @@ static void write_note_data(struct note_data *d, struct object_id *oid)
}
}
+static void append_separator(struct strbuf *message)
+{
+ if (separator[strlen(separator) - 1] == '\n')
+ strbuf_addstr(message, separator);
+ else
+ strbuf_addf(message, "%s%s", separator, "\n");
+}
+
+static void concat_messages(struct note_data *d)
+{
+ struct strbuf msg = STRBUF_INIT;
+
+ size_t i;
+ for (i = 0; i < d->msg_nr ; i++) {
+ if (d->buf.len)
+ append_separator(&d->buf);
+ strbuf_add(&msg, d->messages[i]->buf.buf, d->messages[i]->buf.len);
+ strbuf_addbuf(&d->buf, &msg);
+ if ((d->stripspace == UNSPECIFIED &&
+ d->messages[i]->stripspace == STRIPSPACE) ||
+ d->stripspace == STRIPSPACE)
+ strbuf_stripspace(&d->buf, 0);
+ strbuf_reset(&msg);
+ }
+ strbuf_release(&msg);
+}
+
static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ struct note_msg *msg = xmalloc(sizeof(*msg));
BUG_ON_OPT_NEG(unset);
- strbuf_grow(&d->buf, strlen(arg) + 2);
- if (d->buf.len)
- strbuf_addch(&d->buf, '\n');
- strbuf_addstr(&d->buf, arg);
- strbuf_stripspace(&d->buf, 0);
-
- d->given = 1;
+ strbuf_init(&msg->buf, strlen(arg));
+ strbuf_addstr(&msg->buf, arg);
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+ d->messages[d->msg_nr - 1] = msg;
+ msg->stripspace = STRIPSPACE;
return 0;
}
static int parse_file_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ struct note_msg *msg = xmalloc(sizeof(*msg));
BUG_ON_OPT_NEG(unset);
- if (d->buf.len)
- strbuf_addch(&d->buf, '\n');
+ strbuf_init(&msg->buf , 0);
if (!strcmp(arg, "-")) {
- if (strbuf_read(&d->buf, 0, 1024) < 0)
+ if (strbuf_read(&msg->buf, 0, 1024) < 0)
die_errno(_("cannot read '%s'"), arg);
- } else if (strbuf_read_file(&d->buf, arg, 1024) < 0)
+ } else if (strbuf_read_file(&msg->buf, arg, 1024) < 0)
die_errno(_("could not open or read '%s'"), arg);
- strbuf_stripspace(&d->buf, 0);
- d->given = 1;
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+ d->messages[d->msg_nr - 1] = msg;
+ msg->stripspace = STRIPSPACE;
return 0;
}
static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
- char *buf;
+ struct note_msg *msg = xmalloc(sizeof(*msg));
+ char *value;
struct object_id object;
enum object_type type;
unsigned long len;
BUG_ON_OPT_NEG(unset);
- if (d->buf.len)
- strbuf_addch(&d->buf, '\n');
-
- if (get_oid(arg, &object))
+ strbuf_init(&msg->buf, 0);
+ if (repo_get_oid(the_repository, arg, &object))
die(_("failed to resolve '%s' as a valid ref."), arg);
- if (!(buf = read_object_file(&object, &type, &len)))
+ if (!(value = repo_read_object_file(the_repository, &object, &type, &len)))
die(_("failed to read object '%s'."), arg);
if (type != OBJ_BLOB) {
- free(buf);
+ strbuf_release(&msg->buf);
+ free(value);
+ free(msg);
die(_("cannot read note data from non-blob object '%s'."), arg);
}
- strbuf_add(&d->buf, buf, len);
- free(buf);
- d->given = 1;
+ strbuf_add(&msg->buf, value, len);
+ free(value);
+
+ msg->buf.len = len;
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+ d->messages[d->msg_nr - 1] = msg;
+ msg->stripspace = NO_STRIPSPACE;
return 0;
}
@@ -307,9 +371,9 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
die(_("malformed input line: '%s'."), buf.buf);
strbuf_rtrim(split[0]);
strbuf_rtrim(split[1]);
- if (get_oid(split[0]->buf, &from_obj))
+ if (repo_get_oid(the_repository, split[0]->buf, &from_obj))
die(_("failed to resolve '%s' as a valid ref."), split[0]->buf);
- if (get_oid(split[1]->buf, &to_obj))
+ if (repo_get_oid(the_repository, split[1]->buf, &to_obj))
die(_("failed to resolve '%s' as a valid ref."), split[1]->buf);
if (rewrite_cmd)
@@ -377,7 +441,7 @@ static int list(int argc, const char **argv, const char *prefix)
t = init_notes_check("list", 0);
if (argc) {
- if (get_oid(argv[0], &object))
+ if (repo_get_oid(the_repository, argv[0], &object))
die(_("failed to resolve '%s' as a valid ref."), argv[0]);
note = get_note(t, &object);
if (note) {
@@ -402,7 +466,8 @@ static int add(int argc, const char **argv, const char *prefix)
struct notes_tree *t;
struct object_id object, new_note;
const struct object_id *note;
- struct note_data d = { 0, 0, NULL, STRBUF_INIT };
+ struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
+
struct option options[] = {
OPT_CALLBACK_F('m', "message", &d, N_("message"),
N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -419,6 +484,10 @@ static int add(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "allow-empty", &allow_empty,
N_("allow storing empty note")),
OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
+ OPT_STRING(0, "separator", &separator, N_("separator"),
+ N_("insert <paragraph-break> between paragraphs")),
+ OPT_BOOL(0, "stripspace", &d.stripspace,
+ N_("remove unnecessary whitespace")),
OPT_END()
};
@@ -430,9 +499,13 @@ static int add(int argc, const char **argv, const char *prefix)
usage_with_options(git_notes_add_usage, options);
}
+ if (d.msg_nr)
+ concat_messages(&d);
+ d.given = !!d.buf.len;
+
object_ref = argc > 1 ? argv[1] : "HEAD";
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("failed to resolve '%s' as a valid ref."), object_ref);
t = init_notes_check("add", NOTES_INIT_WRITABLE);
@@ -520,12 +593,12 @@ static int copy(int argc, const char **argv, const char *prefix)
usage_with_options(git_notes_copy_usage, options);
}
- if (get_oid(argv[0], &from_obj))
+ if (repo_get_oid(the_repository, argv[0], &from_obj))
die(_("failed to resolve '%s' as a valid ref."), argv[0]);
object_ref = 1 < argc ? argv[1] : "HEAD";
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("failed to resolve '%s' as a valid ref."), object_ref);
t = init_notes_check("copy", NOTES_INIT_WRITABLE);
@@ -568,7 +641,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
const struct object_id *note;
char *logmsg;
const char * const *usage;
- struct note_data d = { 0, 0, NULL, STRBUF_INIT };
+ struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
struct option options[] = {
OPT_CALLBACK_F('m', "message", &d, N_("message"),
N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -584,6 +657,10 @@ static int append_edit(int argc, const char **argv, const char *prefix)
parse_reuse_arg),
OPT_BOOL(0, "allow-empty", &allow_empty,
N_("allow storing empty note")),
+ OPT_STRING(0, "separator", &separator, N_("separator"),
+ N_("insert <paragraph-break> between paragraphs")),
+ OPT_BOOL(0, "stripspace", &d.stripspace,
+ N_("remove unnecessary whitespace")),
OPT_END()
};
int edit = !strcmp(argv[0], "edit");
@@ -597,6 +674,10 @@ static int append_edit(int argc, const char **argv, const char *prefix)
usage_with_options(usage, options);
}
+ if (d.msg_nr)
+ concat_messages(&d);
+ d.given = !!d.buf.len;
+
if (d.given && edit)
fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
"for the 'edit' subcommand.\n"
@@ -604,7 +685,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
object_ref = 1 < argc ? argv[1] : "HEAD";
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("failed to resolve '%s' as a valid ref."), object_ref);
t = init_notes_check(argv[0], NOTES_INIT_WRITABLE);
@@ -616,14 +697,17 @@ static int append_edit(int argc, const char **argv, const char *prefix)
/* Append buf to previous note contents */
unsigned long size;
enum object_type type;
- char *prev_buf = read_object_file(note, &type, &size);
+ struct strbuf buf = STRBUF_INIT;
+ char *prev_buf = repo_read_object_file(the_repository, note, &type, &size);
- strbuf_grow(&d.buf, size + 1);
- if (d.buf.len && prev_buf && size)
- strbuf_insertstr(&d.buf, 0, "\n");
if (prev_buf && size)
- strbuf_insert(&d.buf, 0, prev_buf, size);
+ strbuf_add(&buf, prev_buf, size);
+ if (d.buf.len && prev_buf && size)
+ append_separator(&buf);
+ strbuf_insert(&d.buf, 0, buf.buf, buf.len);
+
free(prev_buf);
+ strbuf_release(&buf);
}
if (d.buf.len || allow_empty) {
@@ -666,7 +750,7 @@ static int show(int argc, const char **argv, const char *prefix)
object_ref = argc ? argv[0] : "HEAD";
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("failed to resolve '%s' as a valid ref."), object_ref);
t = init_notes_check("show", 0);
@@ -716,11 +800,11 @@ static int merge_commit(struct notes_merge_options *o)
* and target notes ref from .git/NOTES_MERGE_REF.
*/
- if (get_oid("NOTES_MERGE_PARTIAL", &oid))
+ if (repo_get_oid(the_repository, "NOTES_MERGE_PARTIAL", &oid))
die(_("failed to read ref NOTES_MERGE_PARTIAL"));
else if (!(partial = lookup_commit_reference(the_repository, &oid)))
die(_("could not find commit from NOTES_MERGE_PARTIAL."));
- else if (parse_commit(partial))
+ else if (repo_parse_commit(the_repository, partial))
die(_("could not parse commit from NOTES_MERGE_PARTIAL."));
if (partial->parents)
@@ -741,7 +825,8 @@ static int merge_commit(struct notes_merge_options *o)
/* Reuse existing commit message in reflog message */
memset(&pretty_ctx, 0, sizeof(pretty_ctx));
- format_commit_message(partial, "%s", &msg, &pretty_ctx);
+ repo_format_commit_message(the_repository, partial, "%s", &msg,
+ &pretty_ctx);
strbuf_trim(&msg);
strbuf_insertstr(&msg, 0, "notes: ");
update_ref(msg.buf, o->local_ref, &oid,
@@ -895,7 +980,7 @@ static int remove_one_note(struct notes_tree *t, const char *name, unsigned flag
{
int status;
struct object_id oid;
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
return error(_("Failed to resolve '%s' as a valid ref."), name);
status = remove_note(t, oid.hash);
if (status)
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 74a167a180..af9352b228 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1,5 +1,8 @@
#include "builtin.h"
-#include "cache.h"
+#include "alloc.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "attr.h"
@@ -30,13 +33,17 @@
#include "strvec.h"
#include "list.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
#include "dir.h"
#include "midx.h"
#include "trace2.h"
#include "shallow.h"
#include "promisor-remote.h"
#include "pack-mtimes.h"
+#include "parse-options.h"
+#include "wrapper.h"
/*
* Objects we are going to pack are collected in the `to_pack` structure.
@@ -288,11 +295,13 @@ static void *get_delta(struct object_entry *entry)
void *buf, *base_buf, *delta_buf;
enum object_type type;
- buf = read_object_file(&entry->idx.oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &entry->idx.oid, &type,
+ &size);
if (!buf)
die(_("unable to read %s"), oid_to_hex(&entry->idx.oid));
- base_buf = read_object_file(&DELTA(entry)->idx.oid, &type,
- &base_size);
+ base_buf = repo_read_object_file(the_repository,
+ &DELTA(entry)->idx.oid, &type,
+ &base_size);
if (!base_buf)
die("unable to read %s",
oid_to_hex(&DELTA(entry)->idx.oid));
@@ -454,7 +463,9 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
&size, NULL)) != NULL)
buf = NULL;
else {
- buf = read_object_file(&entry->idx.oid, &type, &size);
+ buf = repo_read_object_file(the_repository,
+ &entry->idx.oid, &type,
+ &size);
if (!buf)
die(_("unable to read %s"),
oid_to_hex(&entry->idx.oid));
@@ -1320,7 +1331,7 @@ static int no_try_delta(const char *path)
if (!check)
check = attr_check_initl("delta", NULL);
- git_check_attr(the_repository->index, NULL, path, check);
+ git_check_attr(the_repository->index, path, check);
if (ATTR_FALSE(check->items[0].value))
return 1;
return 0;
@@ -1590,7 +1601,7 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
static int add_object_entry_from_bitmap(const struct object_id *oid,
enum object_type type,
- int flags, uint32_t name_hash,
+ int flags UNUSED, uint32_t name_hash,
struct packed_git *pack, off_t offset)
{
display_progress(progress_state, ++nr_seen);
@@ -1665,7 +1676,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
/* Did not find one. Either we got a bogus request or
* we need to read and perhaps cache.
*/
- data = read_object_file(oid, &type, &size);
+ data = repo_read_object_file(the_repository, oid, &type, &size);
if (!data)
return NULL;
if (type != OBJ_TREE) {
@@ -2074,7 +2085,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0) {
- if (has_promisor_remote()) {
+ if (repo_has_promisor_remote(the_repository)) {
prefetch_to_pack(object_index);
if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0)
@@ -2525,7 +2536,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
/* Load data if not already done */
if (!trg->data) {
packing_data_lock(&to_pack);
- trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz);
+ trg->data = repo_read_object_file(the_repository,
+ &trg_entry->idx.oid, &type,
+ &sz);
packing_data_unlock(&to_pack);
if (!trg->data)
die(_("object %s cannot be read"),
@@ -2538,7 +2551,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
}
if (!src->data) {
packing_data_lock(&to_pack);
- src->data = read_object_file(&src_entry->idx.oid, &type, &sz);
+ src->data = repo_read_object_file(the_repository,
+ &src_entry->idx.oid, &type,
+ &sz);
packing_data_unlock(&to_pack);
if (!src->data) {
if (src_entry->preferred_base) {
@@ -3260,13 +3275,14 @@ static int add_object_entry_from_pack(const struct object_id *oid,
return 0;
}
-static void show_commit_pack_hint(struct commit *commit, void *_data)
+static void show_commit_pack_hint(struct commit *commit UNUSED,
+ void *data UNUSED)
{
/* nothing to do; commits don't have a namehash */
}
static void show_object_pack_hint(struct object *object, const char *name,
- void *_data)
+ void *data UNUSED)
{
struct object_entry *oe = packlist_find(&to_pack, &object->oid);
if (!oe)
@@ -3344,16 +3360,16 @@ static void read_packs_list_from_stdin(void)
}
string_list_sort(&include_packs);
+ string_list_remove_duplicates(&include_packs, 0);
string_list_sort(&exclude_packs);
+ string_list_remove_duplicates(&exclude_packs, 0);
for (p = get_all_packs(the_repository); p; p = p->next) {
const char *pack_name = pack_basename(p);
- item = string_list_lookup(&include_packs, pack_name);
- if (!item)
- item = string_list_lookup(&exclude_packs, pack_name);
-
- if (item)
+ if ((item = string_list_lookup(&include_packs, pack_name)))
+ item->util = p;
+ if ((item = string_list_lookup(&exclude_packs, pack_name)))
item->util = p;
}
@@ -3464,7 +3480,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
return;
}
-static void show_cruft_object(struct object *obj, const char *name, void *data)
+static void show_cruft_object(struct object *obj, const char *name, void *data UNUSED)
{
/*
* if we did not record it earlier, it's at least as old as our
@@ -3484,7 +3500,7 @@ static void show_cruft_commit(struct commit *commit, void *data)
show_cruft_object((struct object*)commit, NULL, data);
}
-static int cruft_include_check_obj(struct object *obj, void *data)
+static int cruft_include_check_obj(struct object *obj, void *data UNUSED)
{
return !has_object_kept_pack(&obj->oid, IN_CORE_KEEP_PACKS);
}
@@ -3663,7 +3679,7 @@ static void read_object_list_from_stdin(void)
}
}
-static void show_commit(struct commit *commit, void *data)
+static void show_commit(struct commit *commit, void *data UNUSED)
{
add_object_entry(&commit->object.oid, OBJ_COMMIT, NULL, 0);
@@ -3674,7 +3690,8 @@ static void show_commit(struct commit *commit, void *data)
propagate_island_marks(commit);
}
-static void show_object(struct object *obj, const char *name, void *data)
+static void show_object(struct object *obj, const char *name,
+ void *data UNUSED)
{
add_preferred_base_object(name);
add_object_entry(&obj->oid, obj->type, name, 0);
@@ -3761,7 +3778,7 @@ static void show_edge(struct commit *commit)
static int add_object_in_unpacked_pack(const struct object_id *oid,
struct packed_git *pack,
uint32_t pos,
- void *_data)
+ void *data UNUSED)
{
if (cruft) {
off_t offset;
@@ -3795,7 +3812,7 @@ static void add_objects_in_unpacked_packs(void)
}
static int add_loose_object(const struct object_id *oid, const char *path,
- void *data)
+ void *data UNUSED)
{
enum object_type type = oid_object_info(the_repository, oid, NULL);
@@ -3946,13 +3963,13 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
}
static void record_recent_object(struct object *obj,
- const char *name,
- void *data)
+ const char *name UNUSED,
+ void *data UNUSED)
{
oid_array_append(&recent_objects, &obj->oid);
}
-static void record_recent_commit(struct commit *commit, void *data)
+static void record_recent_commit(struct commit *commit, void *data UNUSED)
{
oid_array_append(&recent_objects, &commit->object.oid);
}
@@ -4277,9 +4294,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
}
reset_pack_idx_option(&pack_idx_opts);
+ pack_idx_opts.flags |= WRITE_REV;
git_config(git_pack_config, NULL);
- if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
- pack_idx_opts.flags |= WRITE_REV;
+ if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+ pack_idx_opts.flags &= ~WRITE_REV;
progress = isatty(2);
argc = parse_options(argc, argv, prefix, pack_objects_options,
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index ecd49ca268..4c735ba069 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -7,9 +7,11 @@
*/
#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#define BLKSIZE 512
@@ -557,7 +559,7 @@ static void load_all(void)
}
}
-int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
+int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED)
{
int i;
int i_still_use_this = 0;
@@ -603,6 +605,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
"option, '--i-still-use-this', on the command line\n"
"and let us know you still use it by sending an e-mail\n"
"to <git@vger.kernel.org>. Thanks.\n"), stderr);
+ die(_("refusing to run without --i-still-use-this"));
}
if (load_all_packs)
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index 27c2ca06ac..9833815fb3 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
#include "parse-options.h"
#include "refs.h"
#include "repository.h"
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index f840fbf1c7..b7118b290b 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,7 +1,9 @@
-#include "cache.h"
#include "builtin.h"
#include "config.h"
#include "diff.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "parse-options.h"
static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index da3273a268..ca3578e158 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -1,4 +1,5 @@
#include "builtin.h"
+#include "gettext.h"
#include "parse-options.h"
#include "prune-packed.h"
diff --git a/builtin/prune.c b/builtin/prune.c
index 2719220108..cfb863ae84 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -1,13 +1,20 @@
-#include "cache.h"
+#include "builtin.h"
#include "commit.h"
#include "diff.h"
+#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "revision.h"
-#include "builtin.h"
#include "reachable.h"
#include "parse-options.h"
+#include "path.h"
#include "progress.h"
#include "prune-packed.h"
-#include "object-store.h"
+#include "replace-object.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "shallow.h"
static const char * const prune_usage[] = {
@@ -98,7 +105,8 @@ static int prune_object(const struct object_id *oid, const char *fullpath,
return 0;
}
-static int prune_cruft(const char *basename, const char *path, void *data)
+static int prune_cruft(const char *basename, const char *path,
+ void *data UNUSED)
{
if (starts_with(basename, "tmp_obj_"))
prune_tmp_file(path);
@@ -107,7 +115,8 @@ static int prune_cruft(const char *basename, const char *path, void *data)
return 0;
}
-static int prune_subdir(unsigned int nr, const char *path, void *data)
+static int prune_subdir(unsigned int nr UNUSED, const char *path,
+ void *data UNUSED)
{
if (!show_only)
rmdir(path);
@@ -168,7 +177,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
struct object_id oid;
const char *name = *argv++;
- if (!get_oid(name, &oid)) {
+ if (!repo_get_oid(the_repository, name, &oid)) {
struct object *object = parse_object_or_die(&oid,
name);
add_pending_object(&revs, object, "");
diff --git a/builtin/pull.c b/builtin/pull.c
index 1ab4de0005..7279b2a780 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -6,15 +6,21 @@
* Fetch one or more remote refs and merge it/them into the current HEAD.
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "merge.h"
+#include "object-name.h"
#include "parse-options.h"
#include "exec-cmd.h"
#include "run-command.h"
#include "oid-array.h"
#include "remote.h"
#include "dir.h"
+#include "path.h"
+#include "read-cache-ll.h"
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
@@ -359,8 +365,6 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified)
*/
static int git_pull_config(const char *var, const char *value, void *cb)
{
- int status;
-
if (!strcmp(var, "rebase.autostash")) {
config_autostash = git_config_bool(var, value);
return 0;
@@ -372,10 +376,6 @@ static int git_pull_config(const char *var, const char *value, void *cb)
check_trust_level = 0;
}
- status = git_gpg_config(var, value, cb);
- if (status)
- return status;
-
return git_default_config(var, value, cb);
}
@@ -967,13 +967,13 @@ static void show_advice_pull_non_ff(void)
"your next pull:\n"
"\n"
" git config pull.rebase false # merge\n"
- " git config pull.rebase true # rebase\n"
+ " git config pull.rebase merges # rebase\n"
" git config pull.ff only # fast-forward only\n"
"\n"
"You can replace \"git config\" with \"git config --global\" to set a default\n"
- "preference for all repositories. You can also pass --rebase, --no-rebase,\n"
- "or --ff-only on the command line to override the configured default per\n"
- "invocation.\n"));
+ "preference for all repositories. You can also pass --rebase=merges,\n"
+ "--no-rebase, or --ff-only on the command line to override the configured\n"
+ "default per invocation.\n"));
}
int cmd_pull(int argc, const char **argv, const char *prefix)
@@ -1036,7 +1036,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (file_exists(git_path_merge_head(the_repository)))
die_conclude_merge();
- if (get_oid("HEAD", &orig_head))
+ if (repo_get_oid(the_repository, "HEAD", &orig_head))
oidclr(&orig_head);
if (opt_rebase) {
@@ -1049,7 +1049,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (!opt_autostash)
require_clean_work_tree(the_repository,
N_("pull with rebase"),
- _("please commit or stash them."), 1, 0);
+ _("Please commit or stash them."), 1, 0);
if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
oidclr(&rebase_fork_point);
@@ -1061,7 +1061,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (opt_dry_run)
return 0;
- if (get_oid("HEAD", &curr_head))
+ if (repo_get_oid(the_repository, "HEAD", &curr_head))
oidclr(&curr_head);
if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
diff --git a/builtin/push.c b/builtin/push.c
index 8f7d326ab3..6f8a8dc711 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -1,19 +1,24 @@
/*
* "git push"
*/
-#include "cache.h"
+#include "builtin.h"
+#include "advice.h"
#include "branch.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
#include "refs.h"
#include "refspec.h"
#include "run-command.h"
-#include "builtin.h"
#include "remote.h"
#include "transport.h"
#include "parse-options.h"
+#include "pkt-line.h"
+#include "repository.h"
#include "submodule.h"
#include "submodule-config.h"
#include "send-pack.h"
+#include "trace2.h"
#include "color.h"
static const char * const push_usage[] = {
@@ -508,11 +513,6 @@ static int git_push_config(const char *k, const char *v, void *cb)
{
const char *slot_name;
int *flags = cb;
- int status;
-
- status = git_gpg_config(k, v, NULL);
- if (status)
- return status;
if (!strcmp(k, "push.followtags")) {
if (git_config_bool(k, v))
@@ -594,11 +594,12 @@ int cmd_push(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT__VERBOSITY(&verbosity),
OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
- OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL),
+ OPT_BIT( 0 , "all", &flags, N_("push all branches"), TRANSPORT_PUSH_ALL),
+ OPT_ALIAS( 0 , "branches", "all"),
OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"),
(TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
OPT_BOOL('d', "delete", &deleterefs, N_("delete refs")),
- OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+ OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --branches or --mirror)")),
OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
@@ -641,7 +642,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
set_push_cert_flags(&flags, push_cert);
if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
- die(_("options '%s' and '%s' cannot be used together"), "--delete", "--all/--mirror/--tags");
+ die(_("options '%s' and '%s' cannot be used together"), "--delete", "--all/--branches/--mirror/--tags");
if (deleterefs && argc < 2)
die(_("--delete doesn't make sense without any refs"));
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index aecfae12d3..e455a4795c 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -1,8 +1,10 @@
-#include "cache.h"
#include "builtin.h"
+#include "gettext.h"
+#include "object-name.h"
#include "parse-options.h"
#include "range-diff.h"
#include "config.h"
+#include "repository.h"
#include "revision.h"
static const char * const builtin_range_diff_usage[] = {
@@ -65,20 +67,20 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
if (dash_dash == 3 ||
(dash_dash < 0 && argc > 2 &&
- !get_oid_committish(argv[0], &oid) &&
- !get_oid_committish(argv[1], &oid) &&
- !get_oid_committish(argv[2], &oid))) {
+ !repo_get_oid_committish(the_repository, argv[0], &oid) &&
+ !repo_get_oid_committish(the_repository, argv[1], &oid) &&
+ !repo_get_oid_committish(the_repository, argv[2], &oid))) {
if (dash_dash < 0)
; /* already validated arguments */
- else if (get_oid_committish(argv[0], &oid))
+ else if (repo_get_oid_committish(the_repository, argv[0], &oid))
usage_msg_optf(_("not a revision: '%s'"),
builtin_range_diff_usage, options,
argv[0]);
- else if (get_oid_committish(argv[1], &oid))
+ else if (repo_get_oid_committish(the_repository, argv[1], &oid))
usage_msg_optf(_("not a revision: '%s'"),
builtin_range_diff_usage, options,
argv[1]);
- else if (get_oid_committish(argv[2], &oid))
+ else if (repo_get_oid_committish(the_repository, argv[2], &oid))
usage_msg_optf(_("not a revision: '%s'"),
builtin_range_diff_usage, options,
argv[2]);
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 3ce7541783..63c92936fa 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -5,18 +5,23 @@
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "object.h"
+#include "object-name.h"
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
#include "unpack-trees.h"
#include "dir.h"
-#include "builtin.h"
#include "parse-options.h"
+#include "repository.h"
#include "resolve-undo.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
#include "submodule-config.h"
@@ -87,9 +92,9 @@ static int debug_merge(const struct cache_entry * const *stages,
{
int i;
- printf("* %d-way merge\n", o->merge_size);
+ printf("* %d-way merge\n", o->internal.merge_size);
debug_stage("index", stages[0], o);
- for (i = 1; i <= o->merge_size; i++) {
+ for (i = 1; i <= o->internal.merge_size; i++) {
char buf[24];
xsnprintf(buf, sizeof(buf), "ent#%d", i);
debug_stage(buf, stages[i], o);
@@ -144,7 +149,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")),
OPT_BOOL(0, "no-sparse-checkout", &opts.skip_sparse_checkout,
N_("skip applying sparse checkout filter")),
- OPT_BOOL(0, "debug-unpack", &opts.debug_unpack,
+ OPT_BOOL(0, "debug-unpack", &opts.internal.debug_unpack,
N_("debug unpack-trees")),
OPT_CALLBACK_F(0, "recurse-submodules", NULL,
"checkout", "control recursive updating of submodules",
@@ -198,7 +203,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
die("Not a valid object name %s", arg);
if (list_tree(&oid) < 0)
die("failed to unpack tree object %s", arg);
@@ -247,7 +252,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
opts.head_idx = 1;
}
- if (opts.debug_unpack)
+ if (opts.internal.debug_unpack)
opts.fn = debug_merge;
/* If we're going to prime_cache_tree later, skip cache tree update */
@@ -263,7 +268,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
if (unpack_trees(nr_trees, t, &opts))
return 128;
- if (opts.debug_unpack || opts.dry_run)
+ if (opts.internal.debug_unpack || opts.dry_run)
return 0; /* do not write the index out */
/*
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 6635f10d52..555c5d3f02 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -6,6 +6,10 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "run-command.h"
#include "exec-cmd.h"
#include "strvec.h"
@@ -17,7 +21,10 @@
#include "cache-tree.h"
#include "unpack-trees.h"
#include "lockfile.h"
+#include "object-file.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
#include "commit.h"
#include "diff.h"
#include "wt-status.h"
@@ -28,7 +35,9 @@
#include "sequencer.h"
#include "rebase-interactive.h"
#include "reset.h"
+#include "trace2.h"
#include "hook.h"
+#include "wrapper.h"
static char const * const builtin_rebase_usage[] = {
N_("git rebase [-i] [options] [--exec <cmd>] "
@@ -116,13 +125,15 @@ struct rebase_options {
struct string_list exec;
int allow_empty_message;
int rebase_merges, rebase_cousins;
- char *strategy, *strategy_opts;
+ char *strategy;
+ struct string_list strategy_opts;
struct strbuf git_format_patch_opt;
int reschedule_failed_exec;
int reapply_cherry_picks;
int fork_point;
int update_refs;
int config_autosquash;
+ int config_rebase_merges;
int config_update_refs;
};
@@ -140,8 +151,11 @@ struct rebase_options {
.allow_empty_message = 1, \
.autosquash = -1, \
.config_autosquash = -1, \
+ .rebase_merges = -1, \
+ .config_rebase_merges = -1, \
.update_refs = -1, \
.config_update_refs = -1, \
+ .strategy_opts = STRING_LIST_INIT_NODUP,\
}
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
@@ -175,8 +189,8 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.default_strategy = NULL;
}
- if (opts->strategy_opts)
- parse_strategy_opts(&replay, opts->strategy_opts);
+ for (size_t i = 0; i < opts->strategy_opts.nr; i++)
+ strvec_push(&replay.xopts, opts->strategy_opts.items[i].string);
if (opts->squash_onto) {
oidcpy(&replay.squash_onto, opts->squash_onto);
@@ -196,7 +210,7 @@ static int edit_todo_file(unsigned flags)
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
return error_errno(_("could not read '%s'."), todo_file);
- strbuf_stripspace(&todo_list.buf, 1);
+ strbuf_stripspace(&todo_list.buf, comment_line_char);
res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);
if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,
NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))
@@ -218,13 +232,15 @@ static int get_revision_ranges(struct commit *upstream, struct commit *onto,
*revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid),
oid_to_hex(orig_head));
- shorthead = find_unique_abbrev(orig_head, DEFAULT_ABBREV);
+ shorthead = repo_find_unique_abbrev(the_repository, orig_head,
+ DEFAULT_ABBREV);
if (upstream) {
const char *shortrev;
- shortrev = find_unique_abbrev(&base_rev->object.oid,
- DEFAULT_ABBREV);
+ shortrev = repo_find_unique_abbrev(the_repository,
+ &base_rev->object.oid,
+ DEFAULT_ABBREV);
*shortrevisions = xstrfmt("%s..%s", shortrev, shorthead);
} else
@@ -482,24 +498,6 @@ static int read_basic_state(struct rebase_options *opts)
opts->gpg_sign_opt = xstrdup(buf.buf);
}
- if (file_exists(state_dir_path("strategy", opts))) {
- strbuf_reset(&buf);
- if (!read_oneliner(&buf, state_dir_path("strategy", opts),
- READ_ONELINER_WARN_MISSING))
- return -1;
- free(opts->strategy);
- opts->strategy = xstrdup(buf.buf);
- }
-
- if (file_exists(state_dir_path("strategy_opts", opts))) {
- strbuf_reset(&buf);
- if (!read_oneliner(&buf, state_dir_path("strategy_opts", opts),
- READ_ONELINER_WARN_MISSING))
- return -1;
- free(opts->strategy_opts);
- opts->strategy_opts = xstrdup(buf.buf);
- }
-
strbuf_release(&buf);
return 0;
@@ -517,12 +515,6 @@ static int rebase_write_basic_state(struct rebase_options *opts)
write_file(state_dir_path("quiet", opts), "%s", "");
if (opts->flags & REBASE_VERBOSE)
write_file(state_dir_path("verbose", opts), "%s", "");
- if (opts->strategy)
- write_file(state_dir_path("strategy", opts), "%s",
- opts->strategy);
- if (opts->strategy_opts)
- write_file(state_dir_path("strategy_opts", opts), "%s",
- opts->strategy_opts);
if (opts->allow_rerere_autoupdate > 0)
write_file(state_dir_path("allow_rerere_autoupdate", opts),
"-%s-rerere-autoupdate",
@@ -660,7 +652,7 @@ static int run_am(struct rebase_options *opts)
format_patch.git_cmd = 1;
strvec_pushl(&format_patch.args, "format-patch", "-k", "--stdout",
"--full-index", "--cherry-pick", "--right-only",
- "--src-prefix=a/", "--dst-prefix=b/", "--no-renames",
+ "--default-prefix", "--no-renames",
"--no-cover-letter", "--pretty=mboxrd", "--topo-order",
"--no-base", NULL);
if (opts->git_format_patch_opt.len)
@@ -771,6 +763,16 @@ static int run_specific_rebase(struct rebase_options *opts)
return status ? -1 : 0;
}
+static void parse_rebase_merges_value(struct rebase_options *options, const char *value)
+{
+ if (!strcmp("no-rebase-cousins", value))
+ options->rebase_cousins = 0;
+ else if (!strcmp("rebase-cousins", value))
+ options->rebase_cousins = 1;
+ else
+ die(_("Unknown rebase-merges mode: %s"), value);
+}
+
static int rebase_config(const char *var, const char *value, void *data)
{
struct rebase_options *opts = data;
@@ -800,6 +802,17 @@ static int rebase_config(const char *var, const char *value, void *data)
return 0;
}
+ if (!strcmp(var, "rebase.rebasemerges")) {
+ opts->config_rebase_merges = git_parse_maybe_bool(value);
+ if (opts->config_rebase_merges < 0) {
+ opts->config_rebase_merges = 1;
+ parse_rebase_merges_value(opts, value);
+ } else {
+ opts->rebase_cousins = 0;
+ }
+ return 0;
+ }
+
if (!strcmp(var, "rebase.updaterefs")) {
opts->config_update_refs = git_config_bool(var, value);
return 0;
@@ -851,7 +864,7 @@ static int checkout_up_to_date(struct rebase_options *options)
static int is_linear_history(struct commit *from, struct commit *to)
{
while (to && to != from) {
- parse_commit(to);
+ repo_parse_commit(the_repository, to);
if (!to->parents)
return 1;
if (to->parents->next)
@@ -880,7 +893,7 @@ static int can_fast_forward(struct commit *onto, struct commit *upstream,
if (!upstream)
goto done;
- merge_bases = get_merge_bases(upstream, head);
+ merge_bases = repo_get_merge_bases(the_repository, upstream, head);
if (!merge_bases || merge_bases->next)
goto done;
@@ -899,7 +912,8 @@ static void fill_branch_base(struct rebase_options *options,
{
struct commit_list *merge_bases = NULL;
- merge_bases = get_merge_bases(options->onto, options->orig_head);
+ merge_bases = repo_get_merge_bases(the_repository, options->onto,
+ options->orig_head);
if (!merge_bases || merge_bases->next)
oidcpy(branch_base, null_oid());
else
@@ -980,6 +994,28 @@ static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int parse_opt_rebase_merges(const struct option *opt, const char *arg, int unset)
+{
+ struct rebase_options *options = opt->value;
+
+ options->rebase_merges = !unset;
+ options->rebase_cousins = 0;
+
+ if (arg) {
+ if (!*arg) {
+ warning(_("--rebase-merges with an empty string "
+ "argument is deprecated and will stop "
+ "working in a future version of Git. Use "
+ "--rebase-merges without an argument "
+ "instead, which does the same thing."));
+ return 0;
+ }
+ parse_rebase_merges_value(options, arg);
+ }
+
+ return 0;
+}
+
static void NORETURN error_on_missing_default_upstream(void)
{
struct branch *current_branch = branch_get(NULL);
@@ -1035,8 +1071,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct object_id branch_base;
int ignore_whitespace = 0;
const char *gpg_sign = NULL;
- const char *rebase_merges = NULL;
- struct string_list strategy_options = STRING_LIST_INIT_NODUP;
struct object_id squash_onto;
char *squash_onto_name = NULL;
char *keep_base_onto_name = NULL;
@@ -1137,15 +1171,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
&options.allow_empty_message,
N_("allow rebasing commits with empty messages"),
PARSE_OPT_HIDDEN),
- {OPTION_STRING, 'r', "rebase-merges", &rebase_merges,
- N_("mode"),
+ OPT_CALLBACK_F('r', "rebase-merges", &options, N_("mode"),
N_("try to rebase merges instead of skipping them"),
- PARSE_OPT_OPTARG, NULL, (intptr_t)""},
+ PARSE_OPT_OPTARG, parse_opt_rebase_merges),
OPT_BOOL(0, "fork-point", &options.fork_point,
N_("use 'merge-base --fork-point' to refine upstream")),
OPT_STRING('s', "strategy", &options.strategy,
N_("strategy"), N_("use the given merge strategy")),
- OPT_STRING_LIST('X', "strategy-option", &strategy_options,
+ OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts,
N_("option"),
N_("pass the argument through to the merge "
"strategy")),
@@ -1261,7 +1294,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
int fd;
/* Sanity check */
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(the_repository, "HEAD", &head))
die(_("Cannot read HEAD"));
fd = repo_hold_locked_index(the_repository, &lock_file, 0);
@@ -1436,17 +1469,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.exec.nr)
imply_merge(&options, "--exec");
- if (rebase_merges) {
- if (!*rebase_merges)
- ; /* default mode; do nothing */
- else if (!strcmp("rebase-cousins", rebase_merges))
- options.rebase_cousins = 1;
- else if (strcmp("no-rebase-cousins", rebase_merges))
- die(_("Unknown mode: %s"), rebase_merges);
- options.rebase_merges = 1;
- imply_merge(&options, "--rebase-merges");
- }
-
if (options.type == REBASE_APPLY) {
if (ignore_whitespace)
strvec_push(&options.git_am_opts,
@@ -1459,23 +1481,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
} else {
/* REBASE_MERGE */
if (ignore_whitespace) {
- string_list_append(&strategy_options,
+ string_list_append(&options.strategy_opts,
"ignore-space-change");
}
}
- if (strategy_options.nr) {
- int i;
-
- if (!options.strategy)
- options.strategy = "ort";
-
- strbuf_reset(&buf);
- for (i = 0; i < strategy_options.nr; i++)
- strbuf_addf(&buf, " --%s",
- strategy_options.items[i].string);
- options.strategy_opts = xstrdup(buf.buf);
- }
+ if (options.strategy_opts.nr && !options.strategy)
+ options.strategy = "ort";
if (options.strategy) {
options.strategy = xstrdup(options.strategy);
@@ -1513,7 +1525,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("apply options and merge options "
"cannot be used together"));
else if (options.autosquash == -1 && options.config_autosquash == 1)
- die(_("apply options are incompatible with rebase.autosquash. Consider adding --no-autosquash"));
+ die(_("apply options are incompatible with rebase.autoSquash. Consider adding --no-autosquash"));
+ else if (options.rebase_merges == -1 && options.config_rebase_merges == 1)
+ die(_("apply options are incompatible with rebase.rebaseMerges. Consider adding --no-rebase-merges"));
else if (options.update_refs == -1 && options.config_update_refs == 1)
die(_("apply options are incompatible with rebase.updateRefs. Consider adding --no-update-refs"));
else
@@ -1526,6 +1540,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.update_refs = (options.update_refs >= 0) ? options.update_refs :
((options.config_update_refs >= 0) ? options.config_update_refs : 0);
+ if (options.rebase_merges == 1)
+ imply_merge(&options, "--rebase-merges");
+ options.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :
+ ((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);
+
if (options.autosquash == 1)
imply_merge(&options, "--autosquash");
options.autosquash = (options.autosquash >= 0) ? options.autosquash :
@@ -1680,7 +1699,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
} else if (!options.onto_name)
options.onto_name = options.upstream_name;
if (strstr(options.onto_name, "...")) {
- if (get_oid_mb(options.onto_name, &branch_base) < 0) {
+ if (repo_get_oid_mb(the_repository, options.onto_name, &branch_base) < 0) {
if (keep_base)
die(_("'%s': need exactly one merge base with branch"),
options.upstream_name);
@@ -1783,7 +1802,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
/* We want color (if set), but no pager */
- diff_setup(&opts);
+ repo_diff_setup(the_repository, &opts);
opts.stat_width = -1; /* use full terminal width */
opts.stat_graph_width = -1; /* respect statGraphWidth config */
opts.output_format |=
@@ -1850,10 +1869,9 @@ cleanup:
free(options.gpg_sign_opt);
string_list_clear(&options.exec, 0);
free(options.strategy);
- free(options.strategy_opts);
+ string_list_clear(&options.strategy_opts, 0);
strbuf_release(&options.git_format_patch_opt);
free(squash_onto_name);
free(keep_base_onto_name);
- string_list_clear(&strategy_options, 0);
return !!ret;
}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index cd5c7a28ef..2b2faa5d18 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1,6 +1,10 @@
#include "builtin.h"
+#include "abspath.h"
#include "repository.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "pack.h"
#include "refs.h"
@@ -25,11 +29,18 @@
#include "tmp-objdir.h"
#include "oidset.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "protocol.h"
#include "commit-reach.h"
+#include "server-info.h"
+#include "trace.h"
+#include "trace2.h"
#include "worktree.h"
#include "shallow.h"
+#include "parse-options.h"
+#include "wrapper.h"
static const char * const receive_pack_usage[] = {
N_("git receive-pack <git-dir>"),
@@ -80,7 +91,7 @@ static struct object_id push_cert_oid;
static struct signature_check sigcheck;
static const char *push_cert_nonce;
static const char *cert_nonce_seed;
-static struct string_list hidden_refs = STRING_LIST_INIT_DUP;
+static struct strvec hidden_refs = STRVEC_INIT;
static const char *NONCE_UNSOLICITED = "UNSOLICITED";
static const char *NONCE_BAD = "BAD";
@@ -136,10 +147,6 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
if (status)
return status;
- status = git_gpg_config(var, value, NULL);
- if (status)
- return status;
-
if (strcmp(var, "receive.denydeletes") == 0) {
deny_deletes = git_config_bool(var, value);
return 0;
@@ -331,7 +338,8 @@ static void write_head_info(void)
{
static struct oidset seen = OIDSET_INIT;
- for_each_ref(show_ref_cb, &seen);
+ refs_for_each_fullref_in(get_main_ref_store(the_repository), "",
+ hidden_refs.v, show_ref_cb, &seen);
for_each_alternate_ref(show_one_alternate_ref, &seen);
oidset_clear(&seen);
if (!sent_capabilities)
@@ -1347,7 +1355,7 @@ static int head_has_history(void)
{
struct object_id oid;
- return !get_oid("HEAD", &oid);
+ return !repo_get_oid(the_repository, "HEAD", &oid);
}
static const char *push_to_deploy(unsigned char *sha1,
@@ -1463,8 +1471,10 @@ static const char *update(struct command *cmd, struct shallow_info *si)
find_shared_symref(worktrees, "HEAD", name);
/* only refs/... are allowed */
- if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
- rp_error("refusing to create funny ref '%s' remotely", name);
+ if (!starts_with(name, "refs/") ||
+ check_refname_format(name + 5, is_null_oid(new_oid) ?
+ REFNAME_ALLOW_ONELEVEL : 0)) {
+ rp_error("refusing to update funny ref '%s' remotely", name);
ret = "funny refname";
goto out;
}
@@ -1494,7 +1504,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
}
- if (!is_null_oid(new_oid) && !has_object_file(new_oid)) {
+ if (!is_null_oid(new_oid) && !repo_has_object_file(the_repository, new_oid)) {
error("unpack should have generated %s, "
"but I can't find it!", oid_to_hex(new_oid));
ret = "bad pack";
@@ -1548,7 +1558,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
old_commit = (struct commit *)old_object;
new_commit = (struct commit *)new_object;
- if (!in_merge_bases(old_commit, new_commit)) {
+ if (!repo_in_merge_bases(the_repository, old_commit, new_commit)) {
rp_error("denying non-fast-forward %s"
" (you should pull first)", name);
ret = "non-fast-forward";
@@ -1681,11 +1691,11 @@ static void check_aliased_update_internal(struct command *cmd,
rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
" its target '%s' (%s..%s)",
cmd->ref_name,
- find_unique_abbrev(&cmd->old_oid, DEFAULT_ABBREV),
- find_unique_abbrev(&cmd->new_oid, DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, &cmd->old_oid, DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, &cmd->new_oid, DEFAULT_ABBREV),
dst_cmd->ref_name,
- find_unique_abbrev(&dst_cmd->old_oid, DEFAULT_ABBREV),
- find_unique_abbrev(&dst_cmd->new_oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &dst_cmd->old_oid, DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, &dst_cmd->new_oid, DEFAULT_ABBREV));
cmd->error_string = dst_cmd->error_string =
"inconsistent aliased update";
@@ -2089,7 +2099,7 @@ static struct command *read_head_info(struct packet_reader *reader,
const char *feature_list = reader->line + linelen + 1;
const char *hash = NULL;
const char *client_sid;
- int len = 0;
+ size_t len = 0;
if (parse_feature_request(feature_list, "report-status"))
report_status = 1;
if (parse_feature_request(feature_list, "report-status-v2"))
@@ -2184,7 +2194,7 @@ static const char *parse_pack_header(struct pack_header *hdr)
}
}
-static const char *pack_lockfile;
+static struct tempfile *pack_lockfile;
static void push_header_arg(struct strvec *args, struct pack_header *hdr)
{
@@ -2251,6 +2261,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
return "unpack-objects abnormal exit";
} else {
char hostname[HOST_NAME_MAX + 1];
+ char *lockfile;
strvec_pushl(&child.args, "index-pack", "--stdin", NULL);
push_header_arg(&child.args, &hdr);
@@ -2280,8 +2291,14 @@ static const char *unpack(int err_fd, struct shallow_info *si)
status = start_command(&child);
if (status)
return "index-pack fork failed";
- pack_lockfile = index_pack_lockfile(child.out, NULL);
+
+ lockfile = index_pack_lockfile(child.out, NULL);
+ if (lockfile) {
+ pack_lockfile = register_tempfile(lockfile);
+ free(lockfile);
+ }
close(child.out);
+
status = finish_command(&child);
if (status)
return "index-pack abnormal exit";
@@ -2568,8 +2585,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
use_keepalive = KEEPALIVE_ALWAYS;
execute_commands(commands, unpack_status, &si,
&push_options);
- if (pack_lockfile)
- unlink_or_warn(pack_lockfile);
+ delete_tempfile(&pack_lockfile);
sigchain_push(SIGPIPE, SIG_IGN);
if (report_status_v2)
report_v2(commands, unpack_status);
@@ -2605,7 +2621,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
packet_flush(1);
oid_array_clear(&shallow);
oid_array_clear(&ref);
- string_list_clear(&hidden_refs, 0);
+ strvec_clear(&hidden_refs);
free((void *)push_cert_nonce);
return 0;
}
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 270681dcdf..79b4ff04aa 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -1,9 +1,13 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
+#include "repository.h"
#include "revision.h"
#include "reachable.h"
+#include "wildmatch.h"
#include "worktree.h"
#include "reflog.h"
+#include "parse-options.h"
#define BUILTIN_REFLOG_SHOW_USAGE \
N_("git reflog [show] [<log-options>] [<ref>]")
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index ee338bf440..282782eccd 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -197,6 +197,8 @@ static int command_loop(const char *child)
int cmd_remote_ext(int argc, const char **argv, const char *prefix)
{
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc != 3)
usage(usage_msg);
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
index b2a3980b1d..9020fab9c5 100644
--- a/builtin/remote-fd.c
+++ b/builtin/remote-fd.c
@@ -59,6 +59,8 @@ int cmd_remote_fd(int argc, const char **argv, const char *prefix)
int output_fd = -1;
char *end;
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc != 3)
usage(usage_msg);
diff --git a/builtin/remote.c b/builtin/remote.c
index 729f6f3643..7d96687ec7 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1,6 +1,8 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
#include "transport.h"
#include "remote.h"
#include "string-list.h"
@@ -9,7 +11,7 @@
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "strvec.h"
#include "commit-reach.h"
#include "progress.h"
@@ -443,7 +445,7 @@ static int get_push_ref_states(const struct ref *remote_refs,
info->status = PUSH_STATUS_UPTODATE;
else if (is_null_oid(&ref->old_oid))
info->status = PUSH_STATUS_CREATE;
- else if (has_object_file(&ref->old_oid) &&
+ else if (repo_has_object_file(the_repository, &ref->old_oid) &&
ref_newer(&ref->new_oid, &ref->old_oid))
info->status = PUSH_STATUS_FASTFORWARD;
else
diff --git a/builtin/repack.c b/builtin/repack.c
index f649379531..6c896c9c80 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -1,9 +1,14 @@
#include "builtin.h"
-#include "cache.h"
+#include "alloc.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
+#include "path.h"
#include "run-command.h"
+#include "server-info.h"
#include "sigchain.h"
#include "strbuf.h"
#include "string-list.h"
@@ -11,7 +16,7 @@
#include "midx.h"
#include "packfile.h"
#include "prune-packed.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "promisor-remote.h"
#include "shallow.h"
#include "pack.h"
@@ -182,8 +187,9 @@ static void prepare_pack_objects(struct child_process *cmd,
* Write oid to the given struct child_process's stdin, starting it first if
* necessary.
*/
-static int write_oid(const struct object_id *oid, struct packed_git *pack,
- uint32_t pos, void *data)
+static int write_oid(const struct object_id *oid,
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED, void *data)
{
struct child_process *cmd = data;
@@ -321,7 +327,8 @@ static int geometry_cmp(const void *va, const void *vb)
}
static void init_pack_geometry(struct pack_geometry **geometry_p,
- struct string_list *existing_kept_packs)
+ struct string_list *existing_kept_packs,
+ const struct pack_objects_args *args)
{
struct packed_git *p;
struct pack_geometry *geometry;
@@ -331,6 +338,14 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
geometry = *geometry_p;
for (p = get_all_packs(the_repository); p; p = p->next) {
+ if (args->local && !p->pack_local)
+ /*
+ * When asked to only repack local packfiles we skip
+ * over any packfiles that are borrowed from alternate
+ * object directories.
+ */
+ continue;
+
if (!pack_kept_objects) {
/*
* Any pack that has its pack_keep bit set will appear
@@ -444,8 +459,10 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
geometry->split = split;
}
-static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry)
+static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
{
+ uint32_t i;
+
if (!geometry) {
/*
* No geometry means either an all-into-one repack (in which
@@ -460,7 +477,21 @@ static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry
}
if (geometry->split == geometry->pack_nr)
return NULL;
- return geometry->pack[geometry->pack_nr - 1];
+
+ /*
+ * The preferred pack is the largest pack above the split line. In
+ * other words, it is the largest pack that does not get rolled up in
+ * the geometric repack.
+ */
+ for (i = geometry->pack_nr; i > geometry->split; i--)
+ /*
+ * A pack that is not local would never be included in a
+ * multi-pack index. We thus skip over any non-local packs.
+ */
+ if (geometry->pack[i - 1]->pack_local)
+ return geometry->pack[i - 1];
+
+ return NULL;
}
static void clear_pack_geometry(struct pack_geometry *geometry)
@@ -554,6 +585,17 @@ static void midx_included_packs(struct string_list *include,
for (i = geometry->split; i < geometry->pack_nr; i++) {
struct packed_git *p = geometry->pack[i];
+ /*
+ * The multi-pack index never refers to packfiles part
+ * of an alternate object database, so we skip these.
+ * While git-multi-pack-index(1) would silently ignore
+ * them anyway, this allows us to skip executing the
+ * command completely when we have only non-local
+ * packfiles.
+ */
+ if (!p->pack_local)
+ continue;
+
strbuf_addstr(&buf, pack_basename(p));
strbuf_strip_suffix(&buf, ".pack");
strbuf_addstr(&buf, ".idx");
@@ -587,7 +629,7 @@ static int write_midx_included_packs(struct string_list *include,
{
struct child_process cmd = CHILD_PROCESS_INIT;
struct string_list_item *item;
- struct packed_git *largest = get_largest_active_pack(geometry);
+ struct packed_git *preferred = get_preferred_pack(geometry);
FILE *in;
int ret;
@@ -608,9 +650,9 @@ static int write_midx_included_packs(struct string_list *include,
if (write_bitmaps)
strvec_push(&cmd.args, "--bitmap");
- if (largest)
+ if (preferred)
strvec_pushf(&cmd.args, "--preferred-pack=%s",
- pack_basename(largest));
+ pack_basename(preferred));
if (refs_snapshot)
strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot);
@@ -770,7 +812,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("same as -a, pack unreachable cruft objects separately"),
PACK_CRUFT),
OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
- N_("with -C, expire objects older than this")),
+ N_("with --cruft, expire objects older than this")),
OPT_BOOL('d', NULL, &delete_redundant,
N_("remove redundant packs, and run git-prune-packed")),
OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
@@ -849,6 +891,18 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (write_bitmaps && !(pack_everything & ALL_INTO_ONE) && !write_midx)
die(_(incremental_bitmap_conflict_error));
+ if (write_bitmaps && po_args.local && has_alt_odb(the_repository)) {
+ /*
+ * When asked to do a local repack, but we have
+ * packfiles that are inherited from an alternate, then
+ * we cannot guarantee that the multi-pack-index would
+ * have full coverage of all objects. We thus disable
+ * writing bitmaps in that case.
+ */
+ warning(_("disabling bitmap writing, as some objects are not being packed"));
+ write_bitmaps = 0;
+ }
+
if (write_midx && write_bitmaps) {
struct strbuf path = STRBUF_INIT;
@@ -871,7 +925,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (geometric_factor) {
if (pack_everything)
die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
- init_pack_geometry(&geometry, &existing_kept_packs);
+ init_pack_geometry(&geometry, &existing_kept_packs, &po_args);
split_pack_geometry(geometry, geometric_factor);
}
@@ -901,7 +955,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_push(&cmd.args, "--reflog");
strvec_push(&cmd.args, "--indexed-objects");
}
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
strvec_push(&cmd.args, "--exclude-promisor-objects");
if (!write_midx) {
if (write_bitmaps > 0)
diff --git a/builtin/replace.c b/builtin/replace.c
index a29e911d30..20c67a5889 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -8,15 +8,23 @@
* git-tag.sh and mktag.c by Linus Torvalds.
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
#include "parse-options.h"
+#include "path.h"
#include "run-command.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
#include "repository.h"
#include "tag.h"
+#include "wildmatch.h"
static const char * const git_replace_usage[] = {
N_("git replace [-f] <object> <replacement>"),
@@ -54,7 +62,7 @@ static int show_reference(struct repository *r, const char *refname,
struct object_id object;
enum object_type obj_type, repl_type;
- if (get_oid(refname, &object))
+ if (repo_get_oid(r, refname, &object))
return error(_("failed to resolve '%s' as a valid ref"), refname);
obj_type = oid_object_info(r, &object, NULL);
@@ -112,7 +120,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
base_len = ref.len;
for (p = argv; *p; p++) {
- if (get_oid(*p, &oid)) {
+ if (repo_get_oid(the_repository, *p, &oid)) {
error("failed to resolve '%s' as a valid ref", *p);
had_error = 1;
continue;
@@ -206,10 +214,10 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
{
struct object_id object, repl;
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
return error(_("failed to resolve '%s' as a valid ref"),
object_ref);
- if (get_oid(replace_ref, &repl))
+ if (repo_get_oid(the_repository, replace_ref, &repl))
return error(_("failed to resolve '%s' as a valid ref"),
replace_ref);
@@ -320,7 +328,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
struct object_id old_oid, new_oid, prev;
struct strbuf ref = STRBUF_INIT;
- if (get_oid(object_ref, &old_oid) < 0)
+ if (repo_get_oid(the_repository, object_ref, &old_oid) < 0)
return error(_("not a valid object name: '%s'"), object_ref);
type = oid_object_info(the_repository, &old_oid, NULL);
@@ -375,7 +383,7 @@ static int replace_parents(struct strbuf *buf, int argc, const char **argv)
struct object_id oid;
struct commit *commit;
- if (get_oid(argv[i], &oid) < 0) {
+ if (repo_get_oid(the_repository, argv[i], &oid) < 0) {
strbuf_release(&new_parents);
return error(_("not a valid object name: '%s'"),
argv[i]);
@@ -422,7 +430,7 @@ static int check_one_mergetag(struct commit *commit,
/* iterate over new parents */
for (i = 1; i < mergetag_data->argc; i++) {
struct object_id oid;
- if (get_oid(mergetag_data->argv[i], &oid) < 0)
+ if (repo_get_oid(the_repository, mergetag_data->argv[i], &oid) < 0)
return error(_("not a valid object name: '%s'"),
mergetag_data->argv[i]);
if (oideq(get_tagged_oid(tag), &oid))
@@ -452,15 +460,15 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
const char *buffer;
unsigned long size;
- if (get_oid(old_ref, &old_oid) < 0)
+ if (repo_get_oid(the_repository, old_ref, &old_oid) < 0)
return error(_("not a valid object name: '%s'"), old_ref);
commit = lookup_commit_reference(the_repository, &old_oid);
if (!commit)
return error(_("could not parse %s"), old_ref);
- buffer = get_commit_buffer(commit, &size);
+ buffer = repo_get_commit_buffer(the_repository, commit, &size);
strbuf_add(&buf, buffer, size);
- unuse_commit_buffer(commit, buffer);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
if (replace_parents(&buf, argc - 1, &argv[1]) < 0) {
strbuf_release(&buf);
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 94ffb8c21a..0458db9cad 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -1,10 +1,12 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "dir.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "repository.h"
#include "string-list.h"
#include "rerere.h"
+#include "wrapper.h"
#include "xdiff/xdiff.h"
#include "xdiff-interface.h"
#include "pathspec.h"
diff --git a/builtin/reset.c b/builtin/reset.c
index 0697fa89de..dad2117c97 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -9,7 +9,12 @@
*/
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "advice.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "lockfile.h"
#include "tag.h"
#include "object.h"
@@ -20,11 +25,17 @@
#include "diffcore.h"
#include "tree.h"
#include "branch.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
#include "unpack-trees.h"
#include "cache-tree.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
#include "submodule-config.h"
+#include "trace.h"
+#include "trace2.h"
#include "dir.h"
#include "add-interactive.h"
@@ -89,7 +100,7 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
if (reset_type == KEEP) {
struct object_id head_oid;
- if (get_oid("HEAD", &head_oid))
+ if (repo_get_oid(the_repository, "HEAD", &head_oid))
return error(_("You do not have a valid HEAD."));
if (!fill_tree_descriptor(the_repository, desc + nr, &head_oid))
return error(_("Failed to find tree of HEAD."));
@@ -124,7 +135,7 @@ static void print_new_head_line(struct commit *commit)
struct strbuf buf = STRBUF_INIT;
printf(_("HEAD is now at %s"),
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
if (buf.len > 0)
@@ -260,8 +271,8 @@ static void parse_args(struct pathspec *pathspec,
* has to be unambiguous. If there is a single argument, it
* can not be a tree
*/
- else if ((!argv[1] && !get_oid_committish(argv[0], &unused)) ||
- (argv[1] && !get_oid_treeish(argv[0], &unused))) {
+ else if ((!argv[1] && !repo_get_oid_committish(the_repository, argv[0], &unused)) ||
+ (argv[1] && !repo_get_oid_treeish(the_repository, argv[0], &unused))) {
/*
* Ok, argv[0] looks like a commit/tree; it should not
* be a filename.
@@ -288,9 +299,9 @@ static int reset_refs(const char *rev, const struct object_id *oid)
struct object_id *orig = NULL, oid_orig,
*old_orig = NULL, oid_old_orig;
- if (!get_oid("ORIG_HEAD", &oid_old_orig))
+ if (!repo_get_oid(the_repository, "ORIG_HEAD", &oid_old_orig))
old_orig = &oid_old_orig;
- if (!get_oid("HEAD", &oid_orig)) {
+ if (!repo_get_oid(the_repository, "HEAD", &oid_orig)) {
orig = &oid_orig;
set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
@@ -317,7 +328,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
int reset_type = NONE, update_ref_status = 0, quiet = 0;
int no_refresh = 0;
int patch_mode = 0, pathspec_file_nul = 0, unborn;
- const char *rev, *pathspec_from_file = NULL;
+ const char *rev;
+ char *pathspec_from_file = NULL;
struct object_id oid;
struct pathspec pathspec;
int intent_to_add = 0;
@@ -365,13 +377,14 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
}
- unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
+ unborn = !strcmp(rev, "HEAD") && repo_get_oid(the_repository, "HEAD",
+ &oid);
if (unborn) {
/* reset on unborn branch: treat as reset to empty tree */
oidcpy(&oid, the_hash_algo->empty_tree);
} else if (!pathspec.nr && !patch_mode) {
struct commit *commit;
- if (get_oid_committish(rev, &oid))
+ if (repo_get_oid_committish(the_repository, rev, &oid))
die(_("Failed to resolve '%s' as a valid revision."), rev);
commit = lookup_commit_reference(the_repository, &oid);
if (!commit)
@@ -379,7 +392,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
oidcpy(&oid, &commit->object.oid);
} else {
struct tree *tree;
- if (get_oid_treeish(rev, &oid))
+ if (repo_get_oid_treeish(the_repository, rev, &oid))
die(_("Failed to resolve '%s' as a valid tree."), rev);
tree = parse_tree_indirect(&oid);
if (!tree)
@@ -464,7 +477,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
char *ref = NULL;
int err;
- dwim_ref(rev, strlen(rev), &dummy, &ref, 0);
+ repo_dwim_ref(the_repository, rev, strlen(rev),
+ &dummy, &ref, 0);
if (ref && !starts_with(ref, "refs/"))
FREE_AND_NULL(ref);
@@ -495,5 +509,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
cleanup:
clear_pathspec(&pathspec);
+ free(pathspec_from_file);
return update_ref_status;
}
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index d42db0b0cc..ff715d6918 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -1,16 +1,20 @@
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "commit.h"
#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "revision.h"
#include "list-objects.h"
#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "object.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "pack.h"
#include "pack-bitmap.h"
-#include "builtin.h"
#include "log-tree.h"
#include "graph.h"
#include "bisect.h"
@@ -38,7 +42,7 @@ static const char rev_list_usage[] =
" --tags\n"
" --remotes\n"
" --stdin\n"
-" --exclude-hidden=[receive|uploadpack]\n"
+" --exclude-hidden=[fetch|receive|uploadpack]\n"
" --quiet\n"
" ordering output:\n"
" --topo-order\n"
@@ -134,7 +138,7 @@ static void show_commit(struct commit *commit, void *data)
if (!revs->graph)
fputs(get_revision_mark(revs, commit), stdout);
if (revs->abbrev_commit && revs->abbrev)
- fputs(find_unique_abbrev(&commit->object.oid, revs->abbrev),
+ fputs(repo_find_unique_abbrev(the_repository, &commit->object.oid, revs->abbrev),
stdout);
else
fputs(oid_to_hex(&commit->object.oid), stdout);
@@ -257,7 +261,8 @@ static inline void finish_object__ma(struct object *obj)
}
}
-static int finish_object(struct object *obj, const char *name, void *cb_data)
+static int finish_object(struct object *obj, const char *name UNUSED,
+ void *cb_data)
{
struct rev_list_info *info = cb_data;
if (oid_object_info_extended(the_repository, &obj->oid, NULL, 0) < 0) {
@@ -362,11 +367,11 @@ static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
static int show_object_fast(
const struct object_id *oid,
- enum object_type type,
- int exclude,
- uint32_t name_hash,
- struct packed_git *found_pack,
- off_t found_offset)
+ enum object_type type UNUSED,
+ int exclude UNUSED,
+ uint32_t name_hash UNUSED,
+ struct packed_git *found_pack UNUSED,
+ off_t found_offset UNUSED)
{
fprintf(stdout, "%s\n", oid_to_hex(oid));
return 1;
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index e67999e5eb..4a219ea93b 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -4,15 +4,24 @@
* Copyright (C) Linus Torvalds, 2005
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
#include "commit.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "refs.h"
#include "quote.h"
-#include "builtin.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
#include "diff.h"
+#include "read-cache-ll.h"
#include "revision.h"
+#include "setup.h"
#include "split-index.h"
#include "submodule.h"
#include "commit-reach.h"
@@ -136,7 +145,9 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
struct object_id discard;
char *full;
- switch (dwim_ref(name, strlen(name), &discard, &full, 0)) {
+ switch (repo_dwim_ref(the_repository, name,
+ strlen(name), &discard, &full,
+ 0)) {
case 0:
/*
* Not found -- not a ref. We could
@@ -162,7 +173,8 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
}
}
else if (abbrev)
- show_with_type(type, find_unique_abbrev(oid, abbrev));
+ show_with_type(type,
+ repo_find_unique_abbrev(the_repository, oid, abbrev));
else
show_with_type(type, oid_to_hex(oid));
}
@@ -187,7 +199,7 @@ static int show_default(void)
struct object_id oid;
def = NULL;
- if (!get_oid(s, &oid)) {
+ if (!repo_get_oid(the_repository, s, &oid)) {
show_rev(NORMAL, &oid, s);
return 1;
}
@@ -279,7 +291,7 @@ static int try_difference(const char *arg)
return 0;
}
- if (!get_oid_committish(start, &start_oid) && !get_oid_committish(end, &end_oid)) {
+ if (!repo_get_oid_committish(the_repository, start, &start_oid) && !repo_get_oid_committish(the_repository, end, &end_oid)) {
show_rev(NORMAL, &end_oid, end);
show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
if (symmetric) {
@@ -291,7 +303,7 @@ static int try_difference(const char *arg)
*dotdot = '.';
return 0;
}
- exclude = get_merge_bases(a, b);
+ exclude = repo_get_merge_bases(the_repository, a, b);
while (exclude) {
struct commit *commit = pop_commit(&exclude);
show_rev(REVERSED, &commit->object.oid, NULL);
@@ -337,7 +349,7 @@ static int try_parent_shorthands(const char *arg)
return 0;
*dotdot = 0;
- if (get_oid_committish(arg, &oid) ||
+ if (repo_get_oid_committish(the_repository, arg, &oid) ||
!(commit = lookup_commit_reference(the_repository, &oid))) {
*dotdot = '^';
return 0;
@@ -868,7 +880,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (skip_prefix(arg, "--disambiguate=", &arg)) {
- for_each_abbrev(arg, show_abbrev, NULL);
+ repo_for_each_abbrev(the_repository, arg,
+ show_abbrev, NULL);
continue;
}
if (!strcmp(arg, "--bisect")) {
diff --git a/builtin/revert.c b/builtin/revert.c
index 77d2035616..f6f07d9b53 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
#include "builtin.h"
#include "parse-options.h"
#include "diff.h"
+#include "gettext.h"
+#include "repository.h"
#include "revision.h"
#include "rerere.h"
#include "dir.h"
@@ -43,20 +46,6 @@ static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
}
-static int option_parse_x(const struct option *opt,
- const char *arg, int unset)
-{
- struct replay_opts **opts_ptr = opt->value;
- struct replay_opts *opts = *opts_ptr;
-
- if (unset)
- return 0;
-
- ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
- opts->xopts[opts->xopts_nr++] = xstrdup(arg);
- return 0;
-}
-
static int option_parse_m(const struct option *opt,
const char *arg, int unset)
{
@@ -93,7 +82,8 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)
die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
}
-static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
+static int run_sequencer(int argc, const char **argv, const char *prefix,
+ struct replay_opts *opts)
{
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
@@ -113,8 +103,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
N_("select mainline parent"), option_parse_m),
OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
- OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
- N_("option for merge strategy"), option_parse_x),
+ OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"),
+ N_("option for merge strategy")),
{ OPTION_STRING, 'S', "gpg-sign", &opts->gpg_sign, N_("key-id"),
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_END()
@@ -140,7 +130,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
options = parse_options_concat(options, cp_extra);
}
- argc = parse_options(argc, argv, NULL, options, usage_str,
+ argc = parse_options(argc, argv, prefix, options, usage_str,
PARSE_OPT_KEEP_ARGV0 |
PARSE_OPT_KEEP_UNKNOWN_OPT);
@@ -175,7 +165,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
"--signoff", opts->signoff,
"--mainline", opts->mainline,
"--strategy", opts->strategy ? 1 : 0,
- "--strategy-option", opts->xopts ? 1 : 0,
+ "--strategy-option", opts->xopts.nr ? 1 : 0,
"-x", opts->record_origin,
"--ff", opts->allow_ff,
"--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE,
@@ -245,7 +235,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
opts.action = REPLAY_REVERT;
sequencer_init_config(&opts);
- res = run_sequencer(argc, argv, &opts);
+ res = run_sequencer(argc, argv, prefix, &opts);
if (res < 0)
die(_("revert failed"));
replay_opts_release(&opts);
@@ -259,7 +249,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
opts.action = REPLAY_PICK;
sequencer_init_config(&opts);
- res = run_sequencer(argc, argv, &opts);
+ res = run_sequencer(argc, argv, prefix, &opts);
if (res < 0)
die(_("cherry-pick failed"));
replay_opts_release(&opts);
diff --git a/builtin/rm.c b/builtin/rm.c
index 8844f90655..463eeabcea 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -5,14 +5,22 @@
*/
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "alloc.h"
#include "advice.h"
#include "config.h"
#include "lockfile.h"
#include "dir.h"
#include "cache-tree.h"
+#include "gettext.h"
+#include "hash.h"
#include "tree-walk.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "read-cache.h"
+#include "repository.h"
#include "string-list.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
#include "pathspec.h"
@@ -370,7 +378,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
*/
if (!force) {
struct object_id oid;
- if (get_oid("HEAD", &oid))
+ if (repo_get_oid(the_repository, "HEAD", &oid))
oidclr(&oid);
if (check_local_mod(&oid, index_only))
exit(1);
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 4c5d125fa0..4784143004 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "config.h"
#include "commit.h"
+#include "hex.h"
#include "refs.h"
#include "pkt-line.h"
#include "sideband.h"
@@ -15,6 +16,8 @@
#include "gpg-interface.h"
#include "gettext.h"
#include "protocol.h"
+#include "parse-options.h"
+#include "write-or-die.h"
static const char * const send_pack_usage[] = {
N_("git send-pack [--mirror] [--dry-run] [--force]\n"
@@ -130,8 +133,6 @@ static void print_helper_status(struct ref *ref)
static int send_pack_config(const char *k, const char *v, void *cb)
{
- git_gpg_config(k, v, NULL);
-
if (!strcmp(k, "push.gpgsign")) {
const char *value;
if (!git_config_get_value("push.gpgsign", &value)) {
@@ -275,7 +276,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
fd[0] = 0;
fd[1] = 1;
} else {
- conn = git_connect(fd, dest, receivepack,
+ conn = git_connect(fd, dest, "git-receive-pack", receivepack,
args.verbose ? CONNECT_VERBOSE : 0);
}
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 27a87167e1..1307ed2b88 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -1,12 +1,15 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "commit.h"
#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
#include "string-list.h"
+#include "repository.h"
#include "revision.h"
#include "utf8.h"
#include "mailmap.h"
+#include "setup.h"
#include "shortlog.h"
#include "parse-options.h"
#include "trailer.h"
@@ -176,10 +179,11 @@ static void insert_records_from_trailers(struct shortlog *log,
return;
/*
- * Using format_commit_message("%B") would be simpler here, but
+ * Using repo_format_commit_message("%B") would be simpler here, but
* this saves us copying the message.
*/
- commit_buffer = logmsg_reencode(commit, NULL, ctx->output_encoding);
+ commit_buffer = repo_logmsg_reencode(the_repository, commit, NULL,
+ ctx->output_encoding);
body = strstr(commit_buffer, "\n\n");
if (!body)
return;
@@ -202,7 +206,7 @@ static void insert_records_from_trailers(struct shortlog *log,
trailer_iterator_release(&iter);
strbuf_release(&ident);
- unuse_commit_buffer(commit, commit_buffer);
+ repo_unuse_commit_buffer(the_repository, commit, commit_buffer);
}
static int shortlog_needs_dedup(const struct shortlog *log)
@@ -222,7 +226,8 @@ static void insert_records_from_format(struct shortlog *log,
for_each_string_list_item(item, &log->format) {
strbuf_reset(&buf);
- format_commit_message(commit, item->string, &buf, ctx);
+ repo_format_commit_message(the_repository, commit,
+ item->string, &buf, ctx);
if (!shortlog_needs_dedup(log) || strset_add(dups, buf.buf))
insert_one_record(log, buf.buf, oneline);
@@ -248,7 +253,8 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
if (log->user_format)
pretty_print_commit(&ctx, commit, &oneline);
else
- format_commit_message(commit, "%s", &oneline, &ctx);
+ repo_format_commit_message(the_repository, commit,
+ "%s", &oneline, &ctx);
}
oneline_str = oneline.len ? oneline.buf : "<none>";
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 358ac3e519..a203f13cb0 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -1,14 +1,20 @@
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "pretty.h"
#include "refs.h"
-#include "builtin.h"
#include "color.h"
#include "strvec.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "repository.h"
#include "dir.h"
#include "commit-slab.h"
#include "date.h"
+#include "wildmatch.h"
static const char* show_branch_usage[] = {
N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
@@ -240,7 +246,7 @@ static void join_revs(struct commit_list **list_p,
parents = parents->next;
if ((this_flag & flags) == flags)
continue;
- parse_commit(p);
+ repo_parse_commit(the_repository, p);
if (mark_seen(p, seen_p) && !still_interesting)
extra--;
p->object.flags |= flags;
@@ -312,8 +318,8 @@ static void show_one_commit(struct commit *commit, int no_name)
}
else
printf("[%s] ",
- find_unique_abbrev(&commit->object.oid,
- DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid,
+ DEFAULT_ABBREV));
}
puts(pretty_str);
strbuf_release(&pretty);
@@ -414,7 +420,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
*/
- if (get_oid(refname + ofs, &tmp) || !oideq(&tmp, oid))
+ if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
ofs = 5;
return append_ref(refname + ofs, oid, 0);
}
@@ -429,7 +435,7 @@ static int append_remote_ref(const char *refname, const struct object_id *oid,
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
*/
- if (get_oid(refname + ofs, &tmp) || !oideq(&tmp, oid))
+ if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
ofs = 5;
return append_ref(refname + ofs, oid, 0);
}
@@ -533,7 +539,7 @@ static int show_independent(struct commit **rev,
static void append_one_rev(const char *av)
{
struct object_id revkey;
- if (!get_oid(av, &revkey)) {
+ if (!repo_get_oid(the_repository, av, &revkey)) {
append_ref(av, &revkey, 0);
return;
}
@@ -746,7 +752,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
die(Q_("only %d entry can be shown at one time.",
"only %d entries can be shown at one time.",
MAX_REVS), MAX_REVS);
- if (!dwim_ref(*av, strlen(*av), &oid, &ref, 0))
+ if (!repo_dwim_ref(the_repository, *av, strlen(*av), &oid,
+ &ref, 0))
die(_("no such ref %s"), *av);
/* Has the base been specified? */
@@ -836,13 +843,13 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
die(Q_("cannot handle more than %d rev.",
"cannot handle more than %d revs.",
MAX_REVS), MAX_REVS);
- if (get_oid(ref_name[num_rev], &revkey))
+ if (repo_get_oid(the_repository, ref_name[num_rev], &revkey))
die(_("'%s' is not a valid ref."), ref_name[num_rev]);
commit = lookup_commit_reference(the_repository, &revkey);
if (!commit)
die(_("cannot find commit %s (%s)"),
ref_name[num_rev], oid_to_hex(&revkey));
- parse_commit(commit);
+ repo_parse_commit(the_repository, commit);
mark_seen(commit, &seen);
/* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 0e0b9fb95b..540dc3dad1 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -1,7 +1,10 @@
#include "builtin.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "pack.h"
#include "parse-options.h"
+#include "repository.h"
static const char *const show_index_usage[] = {
"git show-index [--object-format=<hash-algorithm>]",
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 3af6a53ee9..5110814f79 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -1,8 +1,10 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "object.h"
#include "tag.h"
#include "string-list.h"
@@ -26,14 +28,14 @@ static void show_one(const char *refname, const struct object_id *oid)
const char *hex;
struct object_id peeled;
- if (!has_object_file(oid))
+ if (!repo_has_object_file(the_repository, oid))
die("git show-ref: bad ref %s (%s)", refname,
oid_to_hex(oid));
if (quiet)
return;
- hex = find_unique_abbrev(oid, abbrev);
+ hex = repo_find_unique_abbrev(the_repository, oid, abbrev);
if (hash_only)
printf("%s\n", hex);
else
@@ -43,7 +45,7 @@ static void show_one(const char *refname, const struct object_id *oid)
return;
if (!peel_iterated_oid(oid, &peeled)) {
- hex = find_unique_abbrev(&peeled, abbrev);
+ hex = repo_find_unique_abbrev(the_repository, &peeled, abbrev);
printf("%s %s^{}\n", hex, refname);
}
}
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index c373815491..5c8ffb1f75 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -1,7 +1,10 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-file.h"
+#include "object-name.h"
#include "parse-options.h"
#include "pathspec.h"
#include "repository.h"
@@ -14,13 +17,14 @@
#include "unpack-trees.h"
#include "wt-status.h"
#include "quote.h"
+#include "setup.h"
#include "sparse-index.h"
#include "worktree.h"
static const char *empty_base = "";
static char const * const builtin_sparse_checkout_usage[] = {
- N_("git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"),
+ N_("git sparse-checkout (init | list | set | add | reapply | disable | check-rules) [<options>]"),
NULL
};
@@ -57,6 +61,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
char *sparse_filename;
int res;
+ setup_work_tree();
if (!core_apply_sparse_checkout)
die(_("this worktree is not sparse"));
@@ -217,16 +222,14 @@ static int update_working_directory(struct pattern_list *pl)
o.head_idx = -1;
o.src_index = r->index;
o.dst_index = r->index;
- index_state_init(&o.result, r);
o.skip_sparse_checkout = 0;
- o.pl = pl;
setup_work_tree();
repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
setup_unpack_trees_porcelain(&o, "sparse-checkout");
- result = update_sparsity(&o);
+ result = update_sparsity(&o, pl);
clear_unpack_trees_porcelain(&o);
if (result == UPDATE_SPARSITY_WARNINGS)
@@ -383,13 +386,7 @@ static int set_config(enum sparse_checkout_mode mode)
return 0;
}
-static int update_modes(int *cone_mode, int *sparse_index)
-{
- int mode, record_mode;
-
- /* Determine if we need to record the mode; ensure sparse checkout on */
- record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout;
-
+static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {
/* If not specified, use previous definition of cone mode */
if (*cone_mode == -1 && core_apply_sparse_checkout)
*cone_mode = core_sparse_checkout_cone;
@@ -397,12 +394,21 @@ static int update_modes(int *cone_mode, int *sparse_index)
/* Set cone/non-cone mode appropriately */
core_apply_sparse_checkout = 1;
if (*cone_mode == 1 || *cone_mode == -1) {
- mode = MODE_CONE_PATTERNS;
core_sparse_checkout_cone = 1;
- } else {
- mode = MODE_ALL_PATTERNS;
- core_sparse_checkout_cone = 0;
+ return MODE_CONE_PATTERNS;
}
+ core_sparse_checkout_cone = 0;
+ return MODE_ALL_PATTERNS;
+}
+
+static int update_modes(int *cone_mode, int *sparse_index)
+{
+ int mode, record_mode;
+
+ /* Determine if we need to record the mode; ensure sparse checkout on */
+ record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout;
+
+ mode = update_cone_mode(cone_mode);
if (record_mode && set_config(mode))
return 1;
@@ -448,6 +454,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ setup_work_tree();
repo_read_index(the_repository);
init_opts.cone_mode = -1;
@@ -471,7 +478,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
return update_working_directory(NULL);
}
- if (get_oid("HEAD", &oid)) {
+ if (repo_get_oid(the_repository, "HEAD", &oid)) {
FILE *fp;
/* assume we are in a fresh repo, but update the sparse-checkout file */
@@ -545,7 +552,7 @@ static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
static void add_patterns_from_input(struct pattern_list *pl,
int argc, const char **argv,
- int use_stdin)
+ FILE *file)
{
int i;
if (core_sparse_checkout_cone) {
@@ -555,9 +562,9 @@ static void add_patterns_from_input(struct pattern_list *pl,
hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
pl->use_cone_patterns = 1;
- if (use_stdin) {
+ if (file) {
struct strbuf unquoted = STRBUF_INIT;
- while (!strbuf_getline(&line, stdin)) {
+ while (!strbuf_getline(&line, file)) {
if (line.buf[0] == '"') {
strbuf_reset(&unquoted);
if (unquote_c_style(&unquoted, line.buf, NULL))
@@ -579,10 +586,10 @@ static void add_patterns_from_input(struct pattern_list *pl,
}
}
} else {
- if (use_stdin) {
+ if (file) {
struct strbuf line = STRBUF_INIT;
- while (!strbuf_getline(&line, stdin)) {
+ while (!strbuf_getline(&line, file)) {
size_t len;
char *buf = strbuf_detach(&line, &len);
add_pattern(buf, empty_base, 0, pl, 0);
@@ -609,7 +616,8 @@ static void add_patterns_cone_mode(int argc, const char **argv,
struct pattern_list existing;
char *sparse_filename = get_sparse_checkout_filename();
- add_patterns_from_input(pl, argc, argv, use_stdin);
+ add_patterns_from_input(pl, argc, argv,
+ use_stdin ? stdin : NULL);
memset(&existing, 0, sizeof(existing));
existing.use_cone_patterns = core_sparse_checkout_cone;
@@ -646,7 +654,7 @@ static void add_patterns_literal(int argc, const char **argv,
pl, NULL, 0))
die(_("unable to load existing sparse-checkout patterns"));
free(sparse_filename);
- add_patterns_from_input(pl, argc, argv, use_stdin);
+ add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL);
}
static int modify_pattern_list(int argc, const char **argv, int use_stdin,
@@ -665,7 +673,8 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
break;
case REPLACE:
- add_patterns_from_input(pl, argc, argv, use_stdin);
+ add_patterns_from_input(pl, argc, argv,
+ use_stdin ? stdin : NULL);
break;
}
@@ -760,6 +769,7 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ setup_work_tree();
if (!core_apply_sparse_checkout)
die(_("no sparse-checkout to add to"));
@@ -806,6 +816,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ setup_work_tree();
repo_read_index(the_repository);
set_opts.cone_mode = -1;
@@ -855,6 +866,7 @@ static int sparse_checkout_reapply(int argc, const char **argv,
OPT_END(),
};
+ setup_work_tree();
if (!core_apply_sparse_checkout)
die(_("must be in a sparse-checkout to reapply sparsity patterns"));
@@ -898,6 +910,7 @@ static int sparse_checkout_disable(int argc, const char **argv,
* forcibly return to a dense checkout regardless of initial state.
*/
+ setup_work_tree();
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_disable_options,
builtin_sparse_checkout_disable_usage, 0);
@@ -923,6 +936,91 @@ static int sparse_checkout_disable(int argc, const char **argv,
return set_config(MODE_NO_PATTERNS);
}
+static char const * const builtin_sparse_checkout_check_rules_usage[] = {
+ N_("git sparse-checkout check-rules [-z] [--skip-checks]"
+ "[--[no-]cone] [--rules-file <file>]"),
+ NULL
+};
+
+static struct sparse_checkout_check_rules_opts {
+ int cone_mode;
+ int null_termination;
+ char *rules_file;
+} check_rules_opts;
+
+static int check_rules(struct pattern_list *pl, int null_terminated) {
+ struct strbuf line = STRBUF_INIT;
+ struct strbuf unquoted = STRBUF_INIT;
+ char *path;
+ int line_terminator = null_terminated ? 0 : '\n';
+ strbuf_getline_fn getline_fn = null_terminated ? strbuf_getline_nul
+ : strbuf_getline;
+ the_repository->index->sparse_checkout_patterns = pl;
+ while (!getline_fn(&line, stdin)) {
+ path = line.buf;
+ if (!null_terminated && line.buf[0] == '"') {
+ strbuf_reset(&unquoted);
+ if (unquote_c_style(&unquoted, line.buf, NULL))
+ die(_("unable to unquote C-style string '%s'"),
+ line.buf);
+
+ path = unquoted.buf;
+ }
+
+ if (path_in_sparse_checkout(path, the_repository->index))
+ write_name_quoted(path, stdout, line_terminator);
+ }
+ strbuf_release(&line);
+ strbuf_release(&unquoted);
+
+ return 0;
+}
+
+static int sparse_checkout_check_rules(int argc, const char **argv, const char *prefix)
+{
+ static struct option builtin_sparse_checkout_check_rules_options[] = {
+ OPT_BOOL('z', NULL, &check_rules_opts.null_termination,
+ N_("terminate input and output files by a NUL character")),
+ OPT_BOOL(0, "cone", &check_rules_opts.cone_mode,
+ N_("when used with --rules-file interpret patterns as cone mode patterns")),
+ OPT_FILENAME(0, "rules-file", &check_rules_opts.rules_file,
+ N_("use patterns in <file> instead of the current ones.")),
+ OPT_END(),
+ };
+
+ FILE *fp;
+ int ret;
+ struct pattern_list pl = {0};
+ char *sparse_filename;
+ check_rules_opts.cone_mode = -1;
+
+ argc = parse_options(argc, argv, prefix,
+ builtin_sparse_checkout_check_rules_options,
+ builtin_sparse_checkout_check_rules_usage,
+ PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+ if (check_rules_opts.rules_file && check_rules_opts.cone_mode < 0)
+ check_rules_opts.cone_mode = 1;
+
+ update_cone_mode(&check_rules_opts.cone_mode);
+ pl.use_cone_patterns = core_sparse_checkout_cone;
+ if (check_rules_opts.rules_file) {
+ fp = xfopen(check_rules_opts.rules_file, "r");
+ add_patterns_from_input(&pl, argc, argv, fp);
+ fclose(fp);
+ } else {
+ sparse_filename = get_sparse_checkout_filename();
+ if (add_patterns_from_file_to_list(sparse_filename, "", 0, &pl,
+ NULL, 0))
+ die(_("unable to load existing sparse-checkout patterns"));
+ free(sparse_filename);
+ }
+
+ ret = check_rules(&pl, check_rules_opts.null_termination);
+ clear_pattern_list(&pl);
+ return ret;
+}
+
int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
{
parse_opt_subcommand_fn *fn = NULL;
@@ -933,6 +1031,7 @@ int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
OPT_SUBCOMMAND("add", &fn, sparse_checkout_add),
OPT_SUBCOMMAND("reapply", &fn, sparse_checkout_reapply),
OPT_SUBCOMMAND("disable", &fn, sparse_checkout_disable),
+ OPT_SUBCOMMAND("check-rules", &fn, sparse_checkout_check_rules),
OPT_END(),
};
diff --git a/builtin/stash.c b/builtin/stash.c
index 3a4f9fd566..84e83e0627 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1,6 +1,12 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "object-name.h"
#include "parse-options.h"
#include "refs.h"
#include "lockfile.h"
@@ -12,8 +18,12 @@
#include "run-command.h"
#include "dir.h"
#include "entry.h"
+#include "preload-index.h"
+#include "read-cache.h"
#include "rerere.h"
#include "revision.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "log-tree.h"
#include "diffcore.h"
#include "exec-cmd.h"
@@ -201,7 +211,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
revision = info->revision.buf;
- if (get_oid(revision, &info->w_commit))
+ if (repo_get_oid(the_repository, revision, &info->w_commit))
return error(_("%s is not a valid reference"), revision);
assert_stash_like(info, revision);
@@ -211,7 +221,8 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
end_of_rev = strchrnul(revision, '@');
strbuf_add(&symbolic, revision, end_of_rev - revision);
- ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref, 0);
+ ret = repo_dwim_ref(the_repository, symbolic.buf, symbolic.len,
+ &dummy, &expanded_ref, 0);
strbuf_release(&symbolic);
switch (ret) {
case 0: /* Not found, but valid ref */
@@ -231,7 +242,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
static int do_clear_stash(void)
{
struct object_id obj;
- if (get_oid(ref_stash, &obj))
+ if (repo_get_oid(the_repository, ref_stash, &obj))
return 0;
return delete_ref(NULL, ref_stash, &obj, 0);
@@ -427,7 +438,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
* to the index before a merge was run) and the current index
* (reflecting the changes brought in by the merge).
*/
- diff_setup(&diff_opts);
+ repo_diff_setup(the_repository, &diff_opts);
diff_opts.flags.recursive = 1;
diff_opts.detect_rename = 0;
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -600,7 +611,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
ret = error(_("could not write index"));
if (ret) {
- rerere(0);
+ repo_rerere(the_repository, 0);
if (index)
fprintf_ln(stderr, _("Index was not unstashed."));
@@ -900,7 +911,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
init_diff_ui_defaults();
git_config(git_diff_ui_config, NULL);
- init_revisions(&rev, prefix);
+ repo_init_revisions(the_repository, &rev, prefix);
argc = parse_options(argc, argv, prefix, options, git_stash_show_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
@@ -1083,13 +1094,13 @@ static int check_changes_tracked_files(const struct pathspec *ps)
int ret = 0;
/* No initial commit. */
- if (get_oid("HEAD", &dummy))
+ if (repo_get_oid(the_repository, "HEAD", &dummy))
return -1;
if (repo_read_index(the_repository) < 0)
return -1;
- init_revisions(&rev, NULL);
+ repo_init_revisions(the_repository, &rev, NULL);
copy_pathspec(&rev.prune_data, ps);
rev.diffopt.flags.quick = 1;
@@ -1276,7 +1287,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
struct strbuf diff_output = STRBUF_INIT;
struct index_state istate = INDEX_STATE_INIT(the_repository);
- init_revisions(&rev, NULL);
+ repo_init_revisions(the_repository, &rev, NULL);
copy_pathspec(&rev.prune_data, ps);
set_alternate_index_output(stash_index_path.buf);
@@ -1355,7 +1366,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
goto done;
}
- if (get_oid("HEAD", &info->b_commit)) {
+ if (repo_get_oid(the_repository, "HEAD", &info->b_commit)) {
if (!quiet)
fprintf_ln(stderr, _("You do not have "
"the initial commit yet"));
@@ -1373,8 +1384,9 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
if (flags & REF_ISSYMREF)
skip_prefix(branch_ref, "refs/heads/", &branch_name);
- head_short_sha1 = find_unique_abbrev(&head_commit->object.oid,
- DEFAULT_ABBREV);
+ head_short_sha1 = repo_find_unique_abbrev(the_repository,
+ &head_commit->object.oid,
+ DEFAULT_ABBREV);
strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1);
pp_commit_easy(CMIT_FMT_ONELINE, head_commit, &msg);
@@ -1465,7 +1477,7 @@ done:
return ret;
}
-static int create_stash(int argc, const char **argv, const char *prefix)
+static int create_stash(int argc, const char **argv, const char *prefix UNUSED)
{
int ret;
struct strbuf stash_msg_buf = STRBUF_INIT;
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index 1e34cf2beb..7b700a9fb1 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -1,8 +1,11 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "setup.h"
#include "strbuf.h"
+#include "write-or-die.h"
static void comment_lines(struct strbuf *buf)
{
@@ -10,7 +13,7 @@ static void comment_lines(struct strbuf *buf)
size_t len;
msg = strbuf_detach(buf, &len);
- strbuf_add_commented_lines(buf, msg, len);
+ strbuf_add_commented_lines(buf, msg, len, comment_line_char);
free(msg);
}
@@ -55,7 +58,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
die_errno("could not read the input");
if (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)
- strbuf_stripspace(&buf, mode == STRIP_COMMENTS);
+ strbuf_stripspace(&buf,
+ mode == STRIP_COMMENTS ? comment_line_char : '\0');
else
comment_lines(&buf);
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 4c173d8b37..baf6ff88c3 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1,12 +1,21 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
+#include "alloc.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
-#include "cache.h"
#include "config.h"
#include "parse-options.h"
#include "quote.h"
+#include "path.h"
#include "pathspec.h"
+#include "preload-index.h"
#include "dir.h"
+#include "read-cache.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
#include "submodule-config.h"
#include "string-list.h"
@@ -18,7 +27,9 @@
#include "revision.h"
#include "diffcore.h"
#include "diff.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "advice.h"
#include "branch.h"
#include "list-objects-filter-options.h"
@@ -557,7 +568,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
- if (!argc && git_config_get_value_multi("submodule.active"))
+ if (!argc && !git_config_get("submodule.active"))
module_list_active(&list);
info.prefix = prefix;
@@ -1108,7 +1119,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
strvec_pushv(&diff_args, info->argv);
git_config(git_diff_basic_config, NULL);
- init_revisions(&rev, info->prefix);
+ repo_init_revisions(the_repository, &rev, info->prefix);
rev.abbrev = 0;
precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
setup_revisions(diff_args.nr, diff_args.v, &rev, &opt);
@@ -1174,7 +1185,7 @@ static int module_summary(int argc, const char **argv, const char *prefix)
if (!summary_limit)
return 0;
- if (!get_oid(argc ? argv[0] : "HEAD", &head_oid)) {
+ if (!repo_get_oid(the_repository, argc ? argv[0] : "HEAD", &head_oid)) {
if (argc) {
argv++;
argc--;
@@ -1187,7 +1198,7 @@ static int module_summary(int argc, const char **argv, const char *prefix)
argc--;
}
} else {
- if (get_oid("HEAD", &head_oid))
+ if (repo_get_oid(the_repository, "HEAD", &head_oid))
die(_("could not fetch a revision for HEAD"));
}
@@ -2132,9 +2143,9 @@ static int update_clone_get_next_task(struct child_process *child,
return 0;
}
-static int update_clone_start_failure(struct strbuf *err,
+static int update_clone_start_failure(struct strbuf *err UNUSED,
void *suc_cb,
- void *idx_task_cb)
+ void *idx_task_cb UNUSED)
{
struct submodule_update_clone *suc = suc_cb;
@@ -2743,7 +2754,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
- if (!argc && git_config_get_value_multi("submodule.active"))
+ if (!argc && !git_config_get("submodule.active"))
module_list_active(&list);
info.prefix = opt.prefix;
@@ -2764,7 +2775,7 @@ cleanup:
return ret;
}
-static int push_check(int argc, const char **argv, const char *prefix)
+static int push_check(int argc, const char **argv, const char *prefix UNUSED)
{
struct remote *remote;
const char *superproject_head;
@@ -3140,7 +3151,6 @@ static int config_submodule_in_gitmodules(const char *name, const char *var, con
static void configure_added_submodule(struct add_data *add_data)
{
char *key;
- const char *val;
struct child_process add_submod = CHILD_PROCESS_INIT;
struct child_process add_gitmodules = CHILD_PROCESS_INIT;
@@ -3185,7 +3195,7 @@ static void configure_added_submodule(struct add_data *add_data)
* is_submodule_active(), since that function needs to find
* out the value of "submodule.active" again anyway.
*/
- if (!git_config_get_string_tmp("submodule.active", &val)) {
+ if (!git_config_get("submodule.active")) {
/*
* If the submodule being added isn't already covered by the
* current configured pathspec, set the submodule's active flag
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index e00768a8b7..a61fa3c0f8 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -1,6 +1,6 @@
#include "builtin.h"
#include "config.h"
-#include "cache.h"
+#include "gettext.h"
#include "refs.h"
#include "parse-options.h"
diff --git a/builtin/tag.c b/builtin/tag.c
index d428c45dc8..6596997379 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -6,11 +6,17 @@
* Based on git-tag.sh and mktag.c by Linus Torvalds.
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "tag.h"
#include "run-command.h"
#include "parse-options.h"
@@ -21,6 +27,7 @@
#include "column.h"
#include "ref-filter.h"
#include "date.h"
+#include "write-or-die.h"
static const char * const git_tag_usage[] = {
N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
@@ -37,6 +44,7 @@ static const char * const git_tag_usage[] = {
static unsigned int colopts;
static int force_sign_annotate;
static int config_sign_tag = -1; /* unspecified */
+static int omit_empty = 0;
static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
struct ref_format *format)
@@ -66,6 +74,7 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
die(_("unable to parse format string"));
filter->with_commit_tag_algo = 1;
filter_refs(&array, filter, FILTER_REFS_TAGS);
+ filter_ahead_behind(the_repository, format, &array);
ref_array_sort(sorting, &array);
for (i = 0; i < array.nr; i++) {
@@ -74,7 +83,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
if (format_ref_array_item(array.items[i], format, &output, &err))
die("%s", err.buf);
fwrite(output.buf, 1, output.len, stdout);
- putchar('\n');
+ if (output.len || !omit_empty)
+ putchar('\n');
}
strbuf_release(&err);
@@ -137,7 +147,7 @@ static int delete_tags(const char **argv)
if (!ref_exists(name))
printf(_("Deleted tag '%s' (was %s)\n"),
item->string + 10,
- find_unique_abbrev(oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
free(oid);
}
@@ -180,8 +190,6 @@ static const char tag_template_nocleanup[] =
static int git_tag_config(const char *var, const char *value, void *cb)
{
- int status;
-
if (!strcmp(var, "tag.gpgsign")) {
config_sign_tag = git_config_bool(var, value);
return 0;
@@ -194,9 +202,6 @@ static int git_tag_config(const char *var, const char *value, void *cb)
return 0;
}
- status = git_gpg_config(var, value, cb);
- if (status)
- return status;
if (!strcmp(var, "tag.forcesignannotated")) {
force_sign_annotate = git_config_bool(var, value);
return 0;
@@ -215,7 +220,7 @@ static void write_tag_body(int fd, const struct object_id *oid)
struct strbuf payload = STRBUF_INIT;
struct strbuf signature = STRBUF_INIT;
- orig = buf = read_object_file(oid, &type, &size);
+ orig = buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf)
return;
if (parse_signature(buf, size, &payload, &signature)) {
@@ -266,11 +271,10 @@ static const char message_advice_nested_tag[] =
static void create_tag(const struct object_id *object, const char *object_ref,
const char *tag,
struct strbuf *buf, struct create_tag_options *opt,
- struct object_id *prev, struct object_id *result)
+ struct object_id *prev, struct object_id *result, char *path)
{
enum object_type type;
struct strbuf header = STRBUF_INIT;
- char *path = NULL;
type = oid_object_info(the_repository, object, NULL);
if (type <= OBJ_NONE)
@@ -294,7 +298,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
int fd;
/* write the template message before editing: */
- path = git_pathdup("TAG_EDITMSG");
fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (opt->message_given) {
@@ -306,9 +309,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,
struct strbuf buf = STRBUF_INIT;
strbuf_addch(&buf, '\n');
if (opt->cleanup_mode == CLEANUP_ALL)
- strbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_char,
+ _(tag_template), tag, comment_line_char);
else
- strbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_char,
+ _(tag_template_nocleanup), tag, comment_line_char);
write_or_die(fd, buf.buf, buf.len);
strbuf_release(&buf);
}
@@ -322,7 +327,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,
}
if (opt->cleanup_mode != CLEANUP_NONE)
- strbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);
+ strbuf_stripspace(buf,
+ opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\0');
if (!opt->message_given && !buf->len)
die(_("no tag message?"));
@@ -336,10 +342,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
path);
exit(128);
}
- if (path) {
- unlink_or_warn(path);
- free(path);
- }
}
static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
@@ -366,7 +368,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
strbuf_addstr(sb, "object of unknown type");
break;
case OBJ_COMMIT:
- if ((buf = read_object_file(oid, &type, &size))) {
+ if ((buf = repo_read_object_file(the_repository, oid, &type, &size))) {
subject_len = find_commit_subject(buf, &subject_start);
strbuf_insert(sb, sb->len, subject_start, subject_len);
} else {
@@ -433,11 +435,12 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
int create_reflog = 0;
int annotate = 0, force = 0;
int cmdmode = 0, create_tag_object = 0;
- const char *msgfile = NULL, *keyid = NULL;
+ char *msgfile = NULL;
+ const char *keyid = NULL;
struct msg_arg msg = { .buf = STRBUF_INIT };
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
- struct ref_filter filter;
+ struct ref_filter filter = REF_FILTER_INIT;
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
@@ -473,6 +476,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")),
OPT_MERGED(&filter, N_("print only tags that are merged")),
OPT_NO_MERGED(&filter, N_("print only tags that are not merged")),
+ OPT_BOOL(0, "omit-empty", &omit_empty,
+ N_("do not output a newline after empty formatted refs")),
OPT_REF_SORT(&sorting_options),
{
OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
@@ -487,13 +492,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
};
int ret = 0;
const char *only_in_list = NULL;
+ char *path = NULL;
setup_ref_filter_porcelain_msg();
git_config(git_tag_config, &sorting_options);
memset(&opt, 0, sizeof(opt));
- memset(&filter, 0, sizeof(filter));
filter.lines = -1;
opt.sign = -1;
@@ -593,7 +598,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (argc > 2)
die(_("too many arguments"));
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
if (strbuf_check_tag_ref(&ref, tag))
@@ -621,7 +626,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (create_tag_object) {
if (force_sign_annotate && !annotate)
opt.sign = 1;
- create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object);
+ path = git_pathdup("TAG_EDITMSG");
+ create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
+ path);
}
transaction = ref_transaction_begin(&err);
@@ -629,19 +636,30 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
ref_transaction_update(transaction, ref.buf, &object, &prev,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
reflog_msg.buf, &err) ||
- ref_transaction_commit(transaction, &err))
+ ref_transaction_commit(transaction, &err)) {
+ if (path)
+ fprintf(stderr,
+ _("The tag message has been left in %s\n"),
+ path);
die("%s", err.buf);
+ }
+ if (path) {
+ unlink_or_warn(path);
+ free(path);
+ }
ref_transaction_free(transaction);
if (force && !is_null_oid(&prev) && !oideq(&prev, &object))
printf(_("Updated tag '%s' (was %s)\n"), tag,
- find_unique_abbrev(&prev, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &prev, DEFAULT_ABBREV));
cleanup:
ref_sorting_release(sorting);
+ ref_filter_clear(&filter);
strbuf_release(&buf);
strbuf_release(&ref);
strbuf_release(&reflog_msg);
strbuf_release(&msg.buf);
strbuf_release(&err);
+ free(msgfile);
return ret;
}
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 88de32b7d7..6842a6c499 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,6 +1,9 @@
#include "builtin.h"
#include "config.h"
-#include "object-store.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "wrapper.h"
static char *create_temp_file(struct object_id *oid)
{
@@ -10,7 +13,7 @@ static char *create_temp_file(struct object_id *oid)
unsigned long size;
int fd;
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf || type != OBJ_BLOB)
die("unable to read blob object %s", oid_to_hex(oid));
@@ -23,13 +26,13 @@ static char *create_temp_file(struct object_id *oid)
return path;
}
-int cmd_unpack_file(int argc, const char **argv, const char *prefix)
+int cmd_unpack_file(int argc, const char **argv, const char *prefix UNUSED)
{
struct object_id oid;
if (argc != 2 || !strcmp(argv[1], "-h"))
usage("git unpack-file <blob>");
- if (get_oid(argv[1], &oid))
+ if (repo_get_oid(the_repository, argv[1], &oid))
die("Not a valid object name %s", argv[1]);
git_config(git_default_config, NULL);
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 43789b8ef2..b4b46ae729 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -1,13 +1,17 @@
#include "builtin.h"
-#include "cache.h"
#include "bulk-checkin.h"
#include "config.h"
-#include "object-store.h"
+#include "environment.h"
+#include "gettext.h"
+#include "git-zlib.h"
+#include "hex.h"
+#include "object-store-ll.h"
#include "object.h"
#include "delta.h"
#include "pack.h"
#include "blob.h"
#include "commit.h"
+#include "replace-object.h"
#include "tag.h"
#include "tree.h"
#include "tree-walk.h"
@@ -442,7 +446,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
delta_data = get_data(delta_size);
if (!delta_data)
return;
- if (has_object_file(&base_oid))
+ if (repo_has_object_file(the_repository, &base_oid))
; /* Ok we have this one */
else if (resolve_against_held(nr, &base_oid,
delta_data, delta_size))
@@ -508,7 +512,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
if (resolve_against_held(nr, &base_oid, delta_data, delta_size))
return;
- base = read_object_file(&base_oid, &type, &base_size);
+ base = repo_read_object_file(the_repository, &base_oid, &type,
+ &base_size);
if (!base) {
error("failed to read delta-pack base object %s",
oid_to_hex(&base_oid));
@@ -598,7 +603,7 @@ static void unpack_all(void)
die("unresolved deltas left after unpacking");
}
-int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
+int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
{
int i;
struct object_id oid;
diff --git a/builtin/update-index.c b/builtin/update-index.c
index bf38885d54..aee3cb8cbd 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -4,21 +4,31 @@
* Copyright (C) Linus Torvalds, 2005
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
#include "bulk-checkin.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "lockfile.h"
#include "quote.h"
#include "cache-tree.h"
#include "tree-walk.h"
-#include "builtin.h"
+#include "object-file.h"
#include "refs.h"
#include "resolve-undo.h"
#include "parse-options.h"
#include "pathspec.h"
#include "dir.h"
+#include "read-cache.h"
+#include "repository.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "split-index.h"
+#include "symlinks.h"
#include "fsmonitor.h"
+#include "write-or-die.h"
/*
* Default to not allowing changes to the list of files. The
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index a84e7b47a2..242102273e 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -1,9 +1,12 @@
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
+#include "gettext.h"
+#include "hash.h"
#include "refs.h"
-#include "builtin.h"
+#include "object-name.h"
#include "parse-options.h"
#include "quote.h"
+#include "repository.h"
#include "strvec.h"
static const char * const git_update_ref_usage[] = {
@@ -116,7 +119,7 @@ static int parse_next_oid(const char **next, const char *end,
(*next)++;
*next = parse_arg(*next, &arg);
if (arg.len) {
- if (get_oid(arg.buf, oid))
+ if (repo_get_oid(the_repository, arg.buf, oid))
goto invalid;
} else {
/* Without -z, an empty value means all zeros: */
@@ -134,7 +137,7 @@ static int parse_next_oid(const char **next, const char *end,
*next += arg.len;
if (arg.len) {
- if (get_oid(arg.buf, oid))
+ if (repo_get_oid(the_repository, arg.buf, oid))
goto invalid;
} else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
/* With -z, treat an empty value as all zeros: */
@@ -549,7 +552,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
refname = argv[0];
value = argv[1];
oldval = argv[2];
- if (get_oid(value, &oid))
+ if (repo_get_oid(the_repository, value, &oid))
die("%s: not a valid SHA1", value);
}
@@ -560,7 +563,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
* must not already exist:
*/
oidclr(&oldoid);
- else if (get_oid(oldval, &oldoid))
+ else if (repo_get_oid(the_repository, oldval, &oldoid))
die("%s: not a valid old SHA1", oldval);
}
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index d2239c9ef4..1dc3971ede 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -1,7 +1,8 @@
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "server-info.h"
static const char * const update_server_info_usage[] = {
"git update-server-info [-f | --force]",
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 945ee2b412..1b09e5e1aa 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -1,11 +1,12 @@
/*
* Copyright (c) 2006 Franck Bui-Huu
*/
-#include "cache.h"
#include "builtin.h"
#include "archive.h"
+#include "path.h"
#include "pkt-line.h"
#include "sideband.h"
+#include "repository.h"
#include "run-command.h"
#include "strvec.h"
@@ -79,6 +80,8 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
{
struct child_process writer = CHILD_PROCESS_INIT;
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(upload_archive_usage);
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index 25b69da2bf..b02d479248 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -1,9 +1,11 @@
-#include "cache.h"
#include "builtin.h"
#include "exec-cmd.h"
+#include "gettext.h"
#include "pkt-line.h"
#include "parse-options.h"
+#include "path.h"
#include "protocol.h"
+#include "replace-object.h"
#include "upload-pack.h"
#include "serve.h"
diff --git a/builtin/var.c b/builtin/var.c
index a80c1df86f..2149998980 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -5,6 +5,9 @@
*/
#include "builtin.h"
#include "config.h"
+#include "editor.h"
+#include "ident.h"
+#include "pager.h"
#include "refs.h"
static const char var_usage[] = "git var (-l | <variable>)";
@@ -77,7 +80,7 @@ static int show_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
-int cmd_var(int argc, const char **argv, const char *prefix)
+int cmd_var(int argc, const char **argv, const char *prefix UNUSED)
{
const struct git_var *git_var;
const char *val;
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index 3ebad32b0f..9680b58701 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -5,10 +5,11 @@
*
* Based on git-verify-tag
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
-#include "object-store.h"
+#include "config.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "repository.h"
#include "commit.h"
#include "run-command.h"
@@ -39,7 +40,7 @@ static int verify_commit(const char *name, unsigned flags)
struct object_id oid;
struct object *obj;
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
return error("commit '%s' not found.", name);
obj = parse_object(the_repository, &oid);
@@ -52,14 +53,6 @@ static int verify_commit(const char *name, unsigned flags)
return run_gpg_verify((struct commit *)obj, flags);
}
-static int git_verify_commit_config(const char *var, const char *value, void *cb)
-{
- int status = git_gpg_config(var, value, cb);
- if (status)
- return status;
- return git_default_config(var, value, cb);
-}
-
int cmd_verify_commit(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
@@ -70,7 +63,7 @@ int cmd_verify_commit(int argc, const char **argv, const char *prefix)
OPT_END()
};
- git_config(git_verify_commit_config, NULL);
+ git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, verify_commit_options,
verify_commit_usage, PARSE_OPT_KEEP_ARGV0);
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 27d6f75fd8..011dddd2dc 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -1,8 +1,9 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "gettext.h"
#include "run-command.h"
#include "parse-options.h"
+#include "strbuf.h"
#define VERIFY_PACK_VERBOSE 01
#define VERIFY_PACK_STAT_ONLY 02
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index 217566952d..d8753270eb 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -5,11 +5,12 @@
*
* Based on git-verify-tag.sh
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
#include "tag.h"
#include "run-command.h"
+#include "object-name.h"
#include "parse-options.h"
#include "gpg-interface.h"
#include "ref-filter.h"
@@ -19,14 +20,6 @@ static const char * const verify_tag_usage[] = {
NULL
};
-static int git_verify_tag_config(const char *var, const char *value, void *cb)
-{
- int status = git_gpg_config(var, value, cb);
- if (status)
- return status;
- return git_default_config(var, value, cb);
-}
-
int cmd_verify_tag(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
@@ -39,7 +32,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
OPT_END()
};
- git_config(git_verify_tag_config, NULL);
+ git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, verify_tag_options,
verify_tag_usage, PARSE_OPT_KEEP_ARGV0);
@@ -60,7 +53,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
struct object_id oid;
const char *name = argv[i++];
- if (get_oid(name, &oid)) {
+ if (repo_get_oid(the_repository, name, &oid)) {
had_error = !!error("tag '%s' not found.", name);
continue;
}
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 254283aa6f..4780b3b5f5 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1,23 +1,36 @@
-#include "cache.h"
+#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
#include "checkout.h"
#include "config.h"
-#include "builtin.h"
+#include "copy.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
#include "strvec.h"
#include "branch.h"
+#include "read-cache-ll.h"
#include "refs.h"
+#include "remote.h"
+#include "repository.h"
#include "run-command.h"
#include "hook.h"
#include "sigchain.h"
#include "submodule.h"
#include "utf8.h"
#include "worktree.h"
+#include "wrapper.h"
#include "quote.h"
#define BUILTIN_WORKTREE_ADD_USAGE \
N_("git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n" \
- " [-b <new-branch>] <path> [<commit-ish>]")
+ " [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]")
+
#define BUILTIN_WORKTREE_LIST_USAGE \
N_("git worktree list [-v | --porcelain [-z]]")
#define BUILTIN_WORKTREE_LOCK_USAGE \
@@ -33,6 +46,23 @@
#define BUILTIN_WORKTREE_UNLOCK_USAGE \
N_("git worktree unlock <worktree>")
+#define WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT \
+ _("No possible source branch, inferring '--orphan'")
+
+#define WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT \
+ _("If you meant to create a worktree containing a new orphan branch\n" \
+ "(branch with no commits) for this repository, you can do so\n" \
+ "using the --orphan flag:\n" \
+ "\n" \
+ " git worktree add --orphan -b %s %s\n")
+
+#define WORKTREE_ADD_ORPHAN_NO_DASH_B_HINT_TEXT \
+ _("If you meant to create a worktree containing a new orphan branch\n" \
+ "(branch with no commits) for this repository, you can do so\n" \
+ "using the --orphan flag:\n" \
+ "\n" \
+ " git worktree add --orphan %s\n")
+
static const char * const git_worktree_usage[] = {
BUILTIN_WORKTREE_ADD_USAGE,
BUILTIN_WORKTREE_LIST_USAGE,
@@ -90,6 +120,7 @@ struct add_opts {
int detach;
int quiet;
int checkout;
+ int orphan;
const char *keep_locked;
};
@@ -319,7 +350,6 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
if (file_exists(from_file)) {
struct config_set cs = { { 0 } };
- const char *core_worktree;
int bare;
if (safe_create_leading_directories(to_file) ||
@@ -338,7 +368,7 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
to_file, "core.bare", NULL, "true", 0))
error(_("failed to unset '%s' in '%s'"),
"core.bare", to_file);
- if (!git_configset_get_value(&cs, "core.worktree", &core_worktree) &&
+ if (!git_configset_get(&cs, "core.worktree") &&
git_config_set_in_file_gently(to_file,
"core.worktree", NULL))
error(_("failed to unset '%s' in '%s'"),
@@ -364,6 +394,22 @@ static int checkout_worktree(const struct add_opts *opts,
return run_command(&cp);
}
+static int make_worktree_orphan(const char * ref, const struct add_opts *opts,
+ struct strvec *child_env)
+{
+ struct strbuf symref = STRBUF_INIT;
+ struct child_process cp = CHILD_PROCESS_INIT;
+
+ validate_new_branchname(ref, &symref, 0);
+ strvec_pushl(&cp.args, "symbolic-ref", "HEAD", symref.buf, NULL);
+ if (opts->quiet)
+ strvec_push(&cp.args, "--quiet");
+ strvec_pushv(&cp.env, child_env->v);
+ strbuf_release(&symref);
+ cp.git_cmd = 1;
+ return run_command(&cp);
+}
+
static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
@@ -393,7 +439,7 @@ static int add_worktree(const char *path, const char *refname,
die_if_checked_out(symref.buf, 0);
}
commit = lookup_commit_reference_by_name(refname);
- if (!commit)
+ if (!commit && !opts->orphan)
die(_("invalid reference: %s"), refname);
name = worktree_basename(path, &len);
@@ -482,10 +528,10 @@ static int add_worktree(const char *path, const char *refname,
strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
cp.git_cmd = 1;
- if (!is_branch)
+ if (!is_branch && commit) {
strvec_pushl(&cp.args, "update-ref", "HEAD",
oid_to_hex(&commit->object.oid), NULL);
- else {
+ } else {
strvec_pushl(&cp.args, "symbolic-ref", "HEAD",
symref.buf, NULL);
if (opts->quiet)
@@ -497,6 +543,10 @@ static int add_worktree(const char *path, const char *refname,
if (ret)
goto done;
+ if (opts->orphan &&
+ (ret = make_worktree_orphan(refname, opts, &child_env)))
+ goto done;
+
if (opts->checkout &&
(ret = checkout_worktree(opts, &child_env)))
goto done;
@@ -516,7 +566,7 @@ done:
* Hook failure does not warrant worktree deletion, so run hook after
* is_junk is cleared, but do return appropriate code when hook fails.
*/
- if (!ret && opts->checkout) {
+ if (!ret && opts->checkout && !opts->orphan) {
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
@@ -552,7 +602,7 @@ static void print_preparing_worktree_line(int detach,
else
fprintf_ln(stderr, _("Preparing worktree (resetting branch '%s'; was at %s)"),
new_branch,
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
} else if (new_branch) {
fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch);
} else {
@@ -564,14 +614,131 @@ static void print_preparing_worktree_line(int detach,
else {
struct commit *commit = lookup_commit_reference_by_name(branch);
if (!commit)
- die(_("invalid reference: %s"), branch);
+ BUG(_("unreachable: invalid reference: %s"), branch);
fprintf_ln(stderr, _("Preparing worktree (detached HEAD %s)"),
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
}
strbuf_release(&s);
}
}
+/**
+ * Callback to short circuit iteration over refs on the first reference
+ * corresponding to a valid oid.
+ *
+ * Returns 0 on failure and non-zero on success.
+ */
+static int first_valid_ref(const char *refname,
+ const struct object_id *oid,
+ int flags,
+ void *cb_data)
+{
+ return 1;
+}
+
+/**
+ * Verifies HEAD and determines whether there exist any valid local references.
+ *
+ * - Checks whether HEAD points to a valid reference.
+ *
+ * - Checks whether any valid local branches exist.
+ *
+ * - Emits a warning if there exist any valid branches but HEAD does not point
+ * to a valid reference.
+ *
+ * Returns 1 if any of the previous checks are true, otherwise returns 0.
+ */
+static int can_use_local_refs(const struct add_opts *opts)
+{
+ if (head_ref(first_valid_ref, NULL)) {
+ return 1;
+ } else if (for_each_branch_ref(first_valid_ref, NULL)) {
+ if (!opts->quiet) {
+ struct strbuf path = STRBUF_INIT;
+ struct strbuf contents = STRBUF_INIT;
+
+ strbuf_add_real_path(&path, get_worktree_git_dir(NULL));
+ strbuf_addstr(&path, "/HEAD");
+ strbuf_read_file(&contents, path.buf, 64);
+ strbuf_stripspace(&contents, 0);
+ strbuf_strip_suffix(&contents, "\n");
+
+ warning(_("HEAD points to an invalid (or orphaned) reference.\n"
+ "HEAD path: '%s'\n"
+ "HEAD contents: '%s'"),
+ path.buf, contents.buf);
+ strbuf_release(&path);
+ strbuf_release(&contents);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Reports whether the necessary flags were set and whether the repository has
+ * remote references to attempt DWIM tracking of upstream branches.
+ *
+ * 1. Checks that `--guess-remote` was used or `worktree.guessRemote = true`.
+ *
+ * 2. Checks whether any valid remote branches exist.
+ *
+ * 3. Checks that there exists at least one remote and emits a warning/error
+ * if both checks 1. and 2. are false (can be bypassed with `--force`).
+ *
+ * Returns 1 if checks 1. and 2. are true, otherwise 0.
+ */
+static int can_use_remote_refs(const struct add_opts *opts)
+{
+ if (!guess_remote) {
+ return 0;
+ } else if (for_each_remote_ref(first_valid_ref, NULL)) {
+ return 1;
+ } else if (!opts->force && remote_get(NULL)) {
+ die(_("No local or remote refs exist despite at least one remote\n"
+ "present, stopping; use 'add -f' to overide or fetch a remote first"));
+ }
+ return 0;
+}
+
+/**
+ * Determines whether `--orphan` should be inferred in the evaluation of
+ * `worktree add path/` or `worktree add -b branch path/` and emits an error
+ * if the supplied arguments would produce an illegal combination when the
+ * `--orphan` flag is included.
+ *
+ * `opts` and `opt_track` contain the other options & flags supplied to the
+ * command.
+ *
+ * remote determines whether to check `can_use_remote_refs()` or not. This
+ * is primarily to differentiate between the basic `add` DWIM and `add -b`.
+ *
+ * Returns 1 when inferring `--orphan`, 0 otherwise, and emits an error when
+ * `--orphan` is inferred but doing so produces an illegal combination of
+ * options and flags. Additionally produces an error when remote refs are
+ * checked and the repo is in a state that looks like the user added a remote
+ * but forgot to fetch (and did not override the warning with -f).
+ */
+static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote)
+{
+ if (can_use_local_refs(opts)) {
+ return 0;
+ } else if (remote && can_use_remote_refs(opts)) {
+ return 0;
+ } else if (!opts->quiet) {
+ fprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT);
+ }
+
+ if (opt_track) {
+ die(_("'%s' and '%s' cannot be used together"), "--orphan",
+ "--track");
+ } else if (!opts->checkout) {
+ die(_("'%s' and '%s' cannot be used together"), "--orphan",
+ "--no-checkout");
+ }
+ return 1;
+}
+
static const char *dwim_branch(const char *path, const char **new_branch)
{
int n;
@@ -608,6 +775,7 @@ static int add(int ac, const char **av, const char *prefix)
const char *opt_track = NULL;
const char *lock_reason = NULL;
int keep_locked = 0;
+ int used_new_branch_options;
struct option options[] = {
OPT__FORCE(&opts.force,
N_("checkout <branch> even if already checked out in other worktree"),
@@ -616,6 +784,7 @@ static int add(int ac, const char **av, const char *prefix)
N_("create a new branch")),
OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
N_("create or reset a branch")),
+ OPT_BOOL(0, "orphan", &opts.orphan, N_("create unborn/orphaned branch")),
OPT_BOOL('d', "detach", &opts.detach, N_("detach HEAD at named commit")),
OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
OPT_BOOL(0, "lock", &keep_locked, N_("keep the new working tree locked")),
@@ -636,6 +805,17 @@ static int add(int ac, const char **av, const char *prefix)
ac = parse_options(ac, av, prefix, options, git_worktree_add_usage, 0);
if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach");
+ if (opts.detach && opts.orphan)
+ die(_("options '%s', and '%s' cannot be used together"),
+ "--orphan", "--detach");
+ if (opts.orphan && opt_track)
+ die(_("'%s' and '%s' cannot be used together"), "--orphan", "--track");
+ if (opts.orphan && !opts.checkout)
+ die(_("'%s' and '%s' cannot be used together"), "--orphan",
+ "--no-checkout");
+ if (opts.orphan && ac == 2)
+ die(_("'%s' and '%s' cannot be used together"), "--orphan",
+ _("<commit-ish>"));
if (lock_reason && !keep_locked)
die(_("the option '%s' requires '%s'"), "--reason", "--lock");
if (lock_reason)
@@ -648,6 +828,7 @@ static int add(int ac, const char **av, const char *prefix)
path = prefix_filename(prefix, av[0]);
branch = ac < 2 ? "HEAD" : av[1];
+ used_new_branch_options = new_branch || new_branch_force;
if (!strcmp(branch, "-"))
branch = "@{-1}";
@@ -664,13 +845,28 @@ static int add(int ac, const char **av, const char *prefix)
strbuf_release(&symref);
}
- if (ac < 2 && !new_branch && !opts.detach) {
+ if (opts.orphan && !new_branch) {
+ int n;
+ const char *s = worktree_basename(path, &n);
+ new_branch = xstrndup(s, n);
+ } else if (opts.orphan) {
+ // No-op
+ } else if (opts.detach) {
+ // Check HEAD
+ if (!strcmp(branch, "HEAD"))
+ can_use_local_refs(&opts);
+ } else if (ac < 2 && new_branch) {
+ // DWIM: Infer --orphan when repo has no refs.
+ opts.orphan = dwim_orphan(&opts, !!opt_track, 0);
+ } else if (ac < 2) {
+ // DWIM: Guess branch name from path.
const char *s = dwim_branch(path, &new_branch);
if (s)
branch = s;
- }
- if (ac == 2 && !new_branch && !opts.detach) {
+ // DWIM: Infer --orphan when repo has no refs.
+ opts.orphan = (!s) && dwim_orphan(&opts, !!opt_track, 1);
+ } else if (ac == 2) {
struct object_id oid;
struct commit *commit;
const char *remote;
@@ -683,11 +879,31 @@ static int add(int ac, const char **av, const char *prefix)
branch = remote;
}
}
+
+ if (!strcmp(branch, "HEAD"))
+ can_use_local_refs(&opts);
+
}
+
+ if (!opts.orphan && !lookup_commit_reference_by_name(branch)) {
+ int attempt_hint = !opts.quiet && (ac < 2);
+ if (attempt_hint && used_new_branch_options) {
+ advise_if_enabled(ADVICE_WORKTREE_ADD_ORPHAN,
+ WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT,
+ new_branch, path);
+ } else if (attempt_hint) {
+ advise_if_enabled(ADVICE_WORKTREE_ADD_ORPHAN,
+ WORKTREE_ADD_ORPHAN_NO_DASH_B_HINT_TEXT, path);
+ }
+ die(_("invalid reference: %s"), branch);
+ }
+
if (!opts.quiet)
print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force);
- if (new_branch) {
+ if (opts.orphan) {
+ branch = new_branch;
+ } else if (new_branch) {
struct child_process cp = CHILD_PROCESS_INIT;
cp.git_cmd = 1;
strvec_push(&cp.args, "branch");
@@ -756,7 +972,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
strbuf_addstr(&sb, "(bare)");
else {
strbuf_addf(&sb, "%-*s ", abbrev_len,
- find_unique_abbrev(&wt->head_oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &wt->head_oid, DEFAULT_ABBREV));
if (wt->is_detached)
strbuf_addstr(&sb, "(detached HEAD)");
else if (wt->head_ref) {
@@ -793,7 +1009,7 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
if (path_len > *maxlen)
*maxlen = path_len;
- sha1_len = strlen(find_unique_abbrev(&wt[i]->head_oid, *abbrev));
+ sha1_len = strlen(repo_find_unique_abbrev(the_repository, &wt[i]->head_oid, *abbrev));
if (sha1_len > *abbrev)
*abbrev = sha1_len;
}
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index 078010315f..66e83d0ecb 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -5,11 +5,14 @@
*/
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "tree.h"
#include "cache-tree.h"
#include "parse-options.h"
+#include "repository.h"
static const char * const write_tree_usage[] = {
N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"),
@@ -38,6 +41,9 @@ int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix)
argc = parse_options(argc, argv, cmd_prefix, write_tree_options,
write_tree_usage, 0);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
ret = write_index_as_tree(&oid, &the_index, get_index_file(), flags,
tree_prefix);
switch (ret) {
diff --git a/bulk-checkin.c b/bulk-checkin.c
index 855b68ec23..e2f71db0f6 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -1,8 +1,12 @@
/*
* Copyright (c) 2011, Google Inc.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "bulk-checkin.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "repository.h"
#include "csum-file.h"
@@ -11,7 +15,9 @@
#include "string-list.h"
#include "tmp-objdir.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "wrapper.h"
static int odb_transaction_nesting;
@@ -124,7 +130,7 @@ static int already_written(struct bulk_checkin_packfile *state, struct object_id
int i;
/* The object may already exist in the repository */
- if (has_object_file(oid))
+ if (repo_has_object_file(the_repository, oid))
return 1;
/* Might want to keep the list sorted */
diff --git a/bulk-checkin.h b/bulk-checkin.h
index 8281b9cb15..48fe9a6e91 100644
--- a/bulk-checkin.h
+++ b/bulk-checkin.h
@@ -4,7 +4,7 @@
#ifndef BULK_CHECKIN_H
#define BULK_CHECKIN_H
-#include "cache.h"
+#include "object.h"
void prepare_loose_object_bulk_checkin(void);
void fsync_loose_object_bulk_checkin(int fd, const char *filename);
diff --git a/bundle-uri.c b/bundle-uri.c
index 8a3c39ce57..a97dcbdb86 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "bundle-uri.h"
#include "bundle.h"
-#include "object-store.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-store-ll.h"
#include "refs.h"
#include "run-command.h"
#include "hashmap.h"
@@ -792,6 +795,15 @@ int fetch_bundle_uri(struct repository *r, const char *uri,
init_bundle_list(&list);
+ /*
+ * Do not fetch an empty bundle URI. An empty bundle URI
+ * could signal that a configured bundle URI has been disabled.
+ */
+ if (!*uri) {
+ result = 0;
+ goto cleanup;
+ }
+
/* If a bundle is added to this global list, then it is required. */
list.mode = BUNDLE_MODE_ALL;
@@ -884,7 +896,7 @@ int bundle_uri_command(struct repository *r,
* Read all "bundle.*" config lines to the client as key=value
* packet lines.
*/
- git_config(config_to_packet_line, &writer);
+ repo_config(r, config_to_packet_line, &writer);
packet_writer_flush(&writer);
diff --git a/bundle.c b/bundle.c
index 6ab6cd7378..8d5936c421 100644
--- a/bundle.c
+++ b/bundle.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "lockfile.h"
#include "bundle.h"
-#include "object-store.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
#include "repository.h"
#include "object.h"
#include "commit.h"
@@ -13,6 +16,7 @@
#include "strvec.h"
#include "list-objects-filter-options.h"
#include "connected.h"
+#include "write-or-die.h"
static const char v2_bundle_signature[] = "# v2 git bundle\n";
static const char v3_bundle_signature[] = "# v3 git bundle\n";
@@ -293,7 +297,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)
if (revs->max_age == -1 && revs->min_age == -1)
goto out;
- buf = read_object_file(&tag->oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &tag->oid, &type, &size);
if (!buf)
goto out;
line = memmem(buf, size, "\ntagger ", 8);
@@ -382,7 +386,8 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
if (e->item->flags & UNINTERESTING)
continue;
- if (dwim_ref(e->name, strlen(e->name), &oid, &ref, 0) != 1)
+ if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
+ &oid, &ref, 0) != 1)
goto skip_write_ref;
if (read_ref_full(e->name, RESOLVE_REF_READING, &oid, &flag))
flag = 0;
diff --git a/bundle.h b/bundle.h
index 9f2bd733a6..021adbdcbb 100644
--- a/bundle.h
+++ b/bundle.h
@@ -2,7 +2,6 @@
#define BUNDLE_H
#include "strvec.h"
-#include "cache.h"
#include "string-list.h"
#include "list-objects-filter-options.h"
diff --git a/cache-tree.c b/cache-tree.c
index 88c2c04f87..84d7491420 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -1,13 +1,20 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "environment.h"
+#include "hex.h"
#include "lockfile.h"
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
#include "bulk-checkin.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "read-cache-ll.h"
#include "replace-object.h"
#include "promisor-remote.h"
#include "sparse-index.h"
+#include "trace.h"
+#include "trace2.h"
#ifndef DEBUG_CACHE_TREE
#define DEBUG_CACHE_TREE 0
@@ -229,7 +236,7 @@ int cache_tree_fully_valid(struct cache_tree *it)
int i;
if (!it)
return 0;
- if (it->entry_count < 0 || !has_object_file(&it->oid))
+ if (it->entry_count < 0 || !repo_has_object_file(the_repository, &it->oid))
return 0;
for (i = 0; i < it->subtree_nr; i++) {
if (!cache_tree_fully_valid(it->down[i]->cache_tree))
@@ -240,7 +247,7 @@ int cache_tree_fully_valid(struct cache_tree *it)
static int must_check_existence(const struct cache_entry *ce)
{
- return !(has_promisor_remote() && ce_skip_worktree(ce));
+ return !(repo_has_promisor_remote(the_repository) && ce_skip_worktree(ce));
}
static int update_one(struct cache_tree *it,
@@ -280,7 +287,7 @@ static int update_one(struct cache_tree *it,
}
}
- if (0 <= it->entry_count && has_object_file(&it->oid))
+ if (0 <= it->entry_count && repo_has_object_file(the_repository, &it->oid))
return it->entry_count;
/*
@@ -386,7 +393,7 @@ static int update_one(struct cache_tree *it,
ce_missing_ok = mode == S_IFGITLINK || missing_ok ||
!must_check_existence(ce);
if (is_null_oid(oid) ||
- (!ce_missing_ok && !has_object_file(oid))) {
+ (!ce_missing_ok && !repo_has_object_file(the_repository, oid))) {
strbuf_release(&buffer);
if (expected_missing)
return -1;
@@ -434,7 +441,7 @@ static int update_one(struct cache_tree *it,
struct object_id oid;
hash_object_file(the_hash_algo, buffer.buf, buffer.len,
OBJ_TREE, &oid);
- if (has_object_file_with_flags(&oid, OBJECT_INFO_SKIP_FETCH_OBJECT))
+ if (repo_has_object_file_with_flags(the_repository, &oid, OBJECT_INFO_SKIP_FETCH_OBJECT))
oidcpy(&it->oid, &oid);
else
to_invalidate = 1;
@@ -470,7 +477,7 @@ int cache_tree_update(struct index_state *istate, int flags)
if (!istate->cache_tree)
istate->cache_tree = cache_tree();
- if (!(flags & WRITE_TREE_MISSING_OK) && has_promisor_remote())
+ if (!(flags & WRITE_TREE_MISSING_OK) && repo_has_promisor_remote(the_repository))
prefetch_cache_entries(istate, must_check_existence);
trace_performance_enter();
@@ -814,14 +821,14 @@ void prime_cache_tree(struct repository *r,
{
struct strbuf tree_path = STRBUF_INIT;
- trace2_region_enter("cache-tree", "prime_cache_tree", the_repository);
+ trace2_region_enter("cache-tree", "prime_cache_tree", r);
cache_tree_free(&istate->cache_tree);
istate->cache_tree = cache_tree();
prime_cache_tree_rec(r, istate->cache_tree, tree, &tree_path);
strbuf_release(&tree_path);
istate->cache_changed |= CACHE_TREE_CHANGED;
- trace2_region_leave("cache-tree", "prime_cache_tree", the_repository);
+ trace2_region_leave("cache-tree", "prime_cache_tree", r);
}
/*
diff --git a/cache-tree.h b/cache-tree.h
index bd97caa07b..faae88be63 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -1,7 +1,6 @@
#ifndef CACHE_TREE_H
#define CACHE_TREE_H
-#include "cache.h"
#include "tree.h"
#include "tree-walk.h"
diff --git a/cache.h b/cache.h
deleted file mode 100644
index 12789903e8..0000000000
--- a/cache.h
+++ /dev/null
@@ -1,1950 +0,0 @@
-#ifndef CACHE_H
-#define CACHE_H
-
-#include "git-compat-util.h"
-#include "strbuf.h"
-#include "hashmap.h"
-#include "list.h"
-#include "advice.h"
-#include "gettext.h"
-#include "convert.h"
-#include "trace.h"
-#include "trace2.h"
-#include "string-list.h"
-#include "pack-revindex.h"
-#include "hash.h"
-#include "path.h"
-#include "oid-array.h"
-#include "repository.h"
-#include "mem-pool.h"
-
-typedef struct git_zstream {
- z_stream z;
- unsigned long avail_in;
- unsigned long avail_out;
- unsigned long total_in;
- unsigned long total_out;
- unsigned char *next_in;
- unsigned char *next_out;
-} git_zstream;
-
-void git_inflate_init(git_zstream *);
-void git_inflate_init_gzip_only(git_zstream *);
-void git_inflate_end(git_zstream *);
-int git_inflate(git_zstream *, int flush);
-
-void git_deflate_init(git_zstream *, int level);
-void git_deflate_init_gzip(git_zstream *, int level);
-void git_deflate_init_raw(git_zstream *, int level);
-void git_deflate_end(git_zstream *);
-int git_deflate_abort(git_zstream *);
-int git_deflate_end_gently(git_zstream *);
-int git_deflate(git_zstream *, int flush);
-unsigned long git_deflate_bound(git_zstream *, unsigned long);
-
-#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
-#define DTYPE(de) ((de)->d_type)
-#else
-#undef DT_UNKNOWN
-#undef DT_DIR
-#undef DT_REG
-#undef DT_LNK
-#define DT_UNKNOWN 0
-#define DT_DIR 1
-#define DT_REG 2
-#define DT_LNK 3
-#define DTYPE(de) DT_UNKNOWN
-#endif
-
-/* unknown mode (impossible combination S_IFIFO|S_IFCHR) */
-#define S_IFINVALID 0030000
-
-/*
- * A "directory link" is a link to another git directory.
- *
- * The value 0160000 is not normally a valid mode, and
- * also just happens to be S_IFDIR + S_IFLNK
- */
-#define S_IFGITLINK 0160000
-#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
-
-/*
- * Some mode bits are also used internally for computations.
- *
- * They *must* not overlap with any valid modes, and they *must* not be emitted
- * to outside world - i.e. appear on disk or network. In other words, it's just
- * temporary fields, which we internally use, but they have to stay in-house.
- *
- * ( such approach is valid, as standard S_IF* fits into 16 bits, and in Git
- * codebase mode is `unsigned int` which is assumed to be at least 32 bits )
- */
-
-/* used internally in tree-diff */
-#define S_DIFFTREE_IFXMIN_NEQ 0x80000000
-
-
-/*
- * Intensive research over the course of many years has shown that
- * port 9418 is totally unused by anything else. Or
- *
- * Your search - "port 9418" - did not match any documents.
- *
- * as www.google.com puts it.
- *
- * This port has been properly assigned for git use by IANA:
- * git (Assigned-9418) [I06-050728-0001].
- *
- * git 9418/tcp git pack transfer service
- * git 9418/udp git pack transfer service
- *
- * with Linus Torvalds <torvalds@osdl.org> as the point of
- * contact. September 2005.
- *
- * See http://www.iana.org/assignments/port-numbers
- */
-#define DEFAULT_GIT_PORT 9418
-
-/*
- * Basic data structures for the directory cache
- */
-
-#define CACHE_SIGNATURE 0x44495243 /* "DIRC" */
-struct cache_header {
- uint32_t hdr_signature;
- uint32_t hdr_version;
- uint32_t hdr_entries;
-};
-
-#define INDEX_FORMAT_LB 2
-#define INDEX_FORMAT_UB 4
-
-/*
- * The "cache_time" is just the low 32 bits of the
- * time. It doesn't matter if it overflows - we only
- * check it for equality in the 32 bits we save.
- */
-struct cache_time {
- uint32_t sec;
- uint32_t nsec;
-};
-
-struct stat_data {
- struct cache_time sd_ctime;
- struct cache_time sd_mtime;
- unsigned int sd_dev;
- unsigned int sd_ino;
- unsigned int sd_uid;
- unsigned int sd_gid;
- unsigned int sd_size;
-};
-
-struct cache_entry {
- struct hashmap_entry ent;
- struct stat_data ce_stat_data;
- unsigned int ce_mode;
- unsigned int ce_flags;
- unsigned int mem_pool_allocated;
- unsigned int ce_namelen;
- unsigned int index; /* for link extension */
- struct object_id oid;
- char name[FLEX_ARRAY]; /* more */
-};
-
-#define CE_STAGEMASK (0x3000)
-#define CE_EXTENDED (0x4000)
-#define CE_VALID (0x8000)
-#define CE_STAGESHIFT 12
-
-/*
- * Range 0xFFFF0FFF in ce_flags is divided into
- * two parts: in-memory flags and on-disk ones.
- * Flags in CE_EXTENDED_FLAGS will get saved on-disk
- * if you want to save a new flag, add it in
- * CE_EXTENDED_FLAGS
- *
- * In-memory only flags
- */
-#define CE_UPDATE (1 << 16)
-#define CE_REMOVE (1 << 17)
-#define CE_UPTODATE (1 << 18)
-#define CE_ADDED (1 << 19)
-
-#define CE_HASHED (1 << 20)
-#define CE_FSMONITOR_VALID (1 << 21)
-#define CE_WT_REMOVE (1 << 22) /* remove in work directory */
-#define CE_CONFLICTED (1 << 23)
-
-#define CE_UNPACKED (1 << 24)
-#define CE_NEW_SKIP_WORKTREE (1 << 25)
-
-/* used to temporarily mark paths matched by pathspecs */
-#define CE_MATCHED (1 << 26)
-
-#define CE_UPDATE_IN_BASE (1 << 27)
-#define CE_STRIP_NAME (1 << 28)
-
-/*
- * Extended on-disk flags
- */
-#define CE_INTENT_TO_ADD (1 << 29)
-#define CE_SKIP_WORKTREE (1 << 30)
-/* CE_EXTENDED2 is for future extension */
-#define CE_EXTENDED2 (1U << 31)
-
-#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
-
-/*
- * Safeguard to avoid saving wrong flags:
- * - CE_EXTENDED2 won't get saved until its semantic is known
- * - Bits in 0x0000FFFF have been saved in ce_flags already
- * - Bits in 0x003F0000 are currently in-memory flags
- */
-#if CE_EXTENDED_FLAGS & 0x803FFFFF
-#error "CE_EXTENDED_FLAGS out of range"
-#endif
-
-#define S_ISSPARSEDIR(m) ((m) == S_IFDIR)
-
-/* Forward structure decls */
-struct pathspec;
-struct child_process;
-struct tree;
-
-/*
- * Copy the sha1 and stat state of a cache entry from one to
- * another. But we never change the name, or the hash state!
- */
-static inline void copy_cache_entry(struct cache_entry *dst,
- const struct cache_entry *src)
-{
- unsigned int state = dst->ce_flags & CE_HASHED;
- int mem_pool_allocated = dst->mem_pool_allocated;
-
- /* Don't copy hash chain and name */
- memcpy(&dst->ce_stat_data, &src->ce_stat_data,
- offsetof(struct cache_entry, name) -
- offsetof(struct cache_entry, ce_stat_data));
-
- /* Restore the hash state */
- dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
-
- /* Restore the mem_pool_allocated flag */
- dst->mem_pool_allocated = mem_pool_allocated;
-}
-
-static inline unsigned create_ce_flags(unsigned stage)
-{
- return (stage << CE_STAGESHIFT);
-}
-
-#define ce_namelen(ce) ((ce)->ce_namelen)
-#define ce_size(ce) cache_entry_size(ce_namelen(ce))
-#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
-#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
-#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
-#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
-#define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD)
-
-#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
-static inline unsigned int create_ce_mode(unsigned int mode)
-{
- if (S_ISLNK(mode))
- return S_IFLNK;
- if (S_ISSPARSEDIR(mode))
- return S_IFDIR;
- if (S_ISDIR(mode) || S_ISGITLINK(mode))
- return S_IFGITLINK;
- return S_IFREG | ce_permissions(mode);
-}
-static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce,
- unsigned int mode)
-{
- extern int trust_executable_bit, has_symlinks;
- if (!has_symlinks && S_ISREG(mode) &&
- ce && S_ISLNK(ce->ce_mode))
- return ce->ce_mode;
- if (!trust_executable_bit && S_ISREG(mode)) {
- if (ce && S_ISREG(ce->ce_mode))
- return ce->ce_mode;
- return create_ce_mode(0666);
- }
- return create_ce_mode(mode);
-}
-static inline int ce_to_dtype(const struct cache_entry *ce)
-{
- unsigned ce_mode = ntohl(ce->ce_mode);
- if (S_ISREG(ce_mode))
- return DT_REG;
- else if (S_ISDIR(ce_mode) || S_ISGITLINK(ce_mode))
- return DT_DIR;
- else if (S_ISLNK(ce_mode))
- return DT_LNK;
- else
- return DT_UNKNOWN;
-}
-static inline unsigned int canon_mode(unsigned int mode)
-{
- if (S_ISREG(mode))
- return S_IFREG | ce_permissions(mode);
- if (S_ISLNK(mode))
- return S_IFLNK;
- if (S_ISDIR(mode))
- return S_IFDIR;
- return S_IFGITLINK;
-}
-
-#define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1)
-
-#define SOMETHING_CHANGED (1 << 0) /* unclassified changes go here */
-#define CE_ENTRY_CHANGED (1 << 1)
-#define CE_ENTRY_REMOVED (1 << 2)
-#define CE_ENTRY_ADDED (1 << 3)
-#define RESOLVE_UNDO_CHANGED (1 << 4)
-#define CACHE_TREE_CHANGED (1 << 5)
-#define SPLIT_INDEX_ORDERED (1 << 6)
-#define UNTRACKED_CHANGED (1 << 7)
-#define FSMONITOR_CHANGED (1 << 8)
-
-struct split_index;
-struct untracked_cache;
-struct progress;
-struct pattern_list;
-
-enum sparse_index_mode {
- /*
- * There are no sparse directories in the index at all.
- *
- * Repositories that don't use cone-mode sparse-checkout will
- * always have their indexes in this mode.
- */
- INDEX_EXPANDED = 0,
-
- /*
- * The index has already been collapsed to sparse directories
- * whereever possible.
- */
- INDEX_COLLAPSED,
-
- /*
- * The sparse directories that exist are outside the
- * sparse-checkout boundary, but it is possible that some file
- * entries could collapse to sparse directory entries.
- */
- INDEX_PARTIALLY_SPARSE,
-};
-
-struct index_state {
- struct cache_entry **cache;
- unsigned int version;
- unsigned int cache_nr, cache_alloc, cache_changed;
- struct string_list *resolve_undo;
- struct cache_tree *cache_tree;
- struct split_index *split_index;
- struct cache_time timestamp;
- unsigned name_hash_initialized : 1,
- initialized : 1,
- drop_cache_tree : 1,
- updated_workdir : 1,
- updated_skipworktree : 1,
- fsmonitor_has_run_once : 1;
- enum sparse_index_mode sparse_index;
- struct hashmap name_hash;
- struct hashmap dir_hash;
- struct object_id oid;
- struct untracked_cache *untracked;
- char *fsmonitor_last_update;
- struct ewah_bitmap *fsmonitor_dirty;
- struct mem_pool *ce_mem_pool;
- struct progress *progress;
- struct repository *repo;
- struct pattern_list *sparse_checkout_patterns;
-};
-
-/**
- * A "struct index_state istate" must be initialized with
- * INDEX_STATE_INIT or the corresponding index_state_init().
- *
- * If the variable won't be used again, use release_index() to free()
- * its resources. If it needs to be used again use discard_index(),
- * which does the same thing, but will use use index_state_init() at
- * the end. The discard_index() will use its own "istate->repo" as the
- * "r" argument to index_state_init() in that case.
- */
-#define INDEX_STATE_INIT(r) { \
- .repo = (r), \
-}
-void index_state_init(struct index_state *istate, struct repository *r);
-void release_index(struct index_state *istate);
-
-/* Name hashing */
-int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);
-void add_name_hash(struct index_state *istate, struct cache_entry *ce);
-void remove_name_hash(struct index_state *istate, struct cache_entry *ce);
-void free_name_hash(struct index_state *istate);
-
-/* Cache entry creation and cleanup */
-
-/*
- * Create cache_entry intended for use in the specified index. Caller
- * is responsible for discarding the cache_entry with
- * `discard_cache_entry`.
- */
-struct cache_entry *make_cache_entry(struct index_state *istate,
- unsigned int mode,
- const struct object_id *oid,
- const char *path,
- int stage,
- unsigned int refresh_options);
-
-struct cache_entry *make_empty_cache_entry(struct index_state *istate,
- size_t name_len);
-
-/*
- * Create a cache_entry that is not intended to be added to an index. If
- * `ce_mem_pool` is not NULL, the entry is allocated within the given memory
- * pool. Caller is responsible for discarding "loose" entries with
- * `discard_cache_entry()` and the memory pool with
- * `mem_pool_discard(ce_mem_pool, should_validate_cache_entries())`.
- */
-struct cache_entry *make_transient_cache_entry(unsigned int mode,
- const struct object_id *oid,
- const char *path,
- int stage,
- struct mem_pool *ce_mem_pool);
-
-struct cache_entry *make_empty_transient_cache_entry(size_t len,
- struct mem_pool *ce_mem_pool);
-
-/*
- * Discard cache entry.
- */
-void discard_cache_entry(struct cache_entry *ce);
-
-/*
- * Check configuration if we should perform extra validation on cache
- * entries.
- */
-int should_validate_cache_entries(void);
-
-/*
- * Duplicate a cache_entry. Allocate memory for the new entry from a
- * memory_pool. Takes into account cache_entry fields that are meant
- * for managing the underlying memory allocation of the cache_entry.
- */
-struct cache_entry *dup_cache_entry(const struct cache_entry *ce, struct index_state *istate);
-
-/*
- * Validate the cache entries in the index. This is an internal
- * consistency check that the cache_entry structs are allocated from
- * the expected memory pool.
- */
-void validate_cache_entries(const struct index_state *istate);
-
-/*
- * Bulk prefetch all missing cache entries that are not GITLINKs and that match
- * the given predicate. This function should only be called if
- * has_promisor_remote() returns true.
- */
-typedef int (*must_prefetch_predicate)(const struct cache_entry *);
-void prefetch_cache_entries(const struct index_state *istate,
- must_prefetch_predicate must_prefetch);
-
-#ifdef USE_THE_INDEX_VARIABLE
-extern struct index_state the_index;
-#endif
-
-#define TYPE_BITS 3
-
-/*
- * Values in this enum (except those outside the 3 bit range) are part
- * of pack file format. See gitformat-pack(5) for more information.
- */
-enum object_type {
- OBJ_BAD = -1,
- OBJ_NONE = 0,
- OBJ_COMMIT = 1,
- OBJ_TREE = 2,
- OBJ_BLOB = 3,
- OBJ_TAG = 4,
- /* 5 for future expansion */
- OBJ_OFS_DELTA = 6,
- OBJ_REF_DELTA = 7,
- OBJ_ANY,
- OBJ_MAX
-};
-
-static inline enum object_type object_type(unsigned int mode)
-{
- return S_ISDIR(mode) ? OBJ_TREE :
- S_ISGITLINK(mode) ? OBJ_COMMIT :
- OBJ_BLOB;
-}
-
-/* Double-check local_repo_env below if you add to this list. */
-#define GIT_DIR_ENVIRONMENT "GIT_DIR"
-#define GIT_COMMON_DIR_ENVIRONMENT "GIT_COMMON_DIR"
-#define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
-#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
-#define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
-#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
-#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
-#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
-#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
-#define GIT_SHALLOW_FILE_ENVIRONMENT "GIT_SHALLOW_FILE"
-#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
-#define CONFIG_ENVIRONMENT "GIT_CONFIG"
-#define CONFIG_DATA_ENVIRONMENT "GIT_CONFIG_PARAMETERS"
-#define CONFIG_COUNT_ENVIRONMENT "GIT_CONFIG_COUNT"
-#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
-#define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
-#define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
-#define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE"
-#define GITATTRIBUTES_FILE ".gitattributes"
-#define INFOATTRIBUTES_FILE "info/attributes"
-#define ATTRIBUTE_MACRO_PREFIX "[attr]"
-#define GITMODULES_FILE ".gitmodules"
-#define GITMODULES_INDEX ":.gitmodules"
-#define GITMODULES_HEAD "HEAD:.gitmodules"
-#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
-#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
-#define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
-#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
-#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
-#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
-#define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS"
-#define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
-#define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
-#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
-#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
-#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
-
-/*
- * Environment variable used in handshaking the wire protocol.
- * Contains a colon ':' separated list of keys with optional values
- * 'key[=value]'. Presence of unknown keys and values must be
- * ignored.
- */
-#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
-/* HTTP header used to handshake the wire protocol */
-#define GIT_PROTOCOL_HEADER "Git-Protocol"
-
-/*
- * This environment variable is expected to contain a boolean indicating
- * whether we should or should not treat:
- *
- * GIT_DIR=foo.git git ...
- *
- * as if GIT_WORK_TREE=. was given. It's not expected that users will make use
- * of this, but we use it internally to communicate to sub-processes that we
- * are in a bare repo. If not set, defaults to true.
- */
-#define GIT_IMPLICIT_WORK_TREE_ENVIRONMENT "GIT_IMPLICIT_WORK_TREE"
-
-/*
- * Repository-local GIT_* environment variables; these will be cleared
- * when git spawns a sub-process that runs inside another repository.
- * The array is NULL-terminated, which makes it easy to pass in the "env"
- * parameter of a run-command invocation, or to do a simple walk.
- */
-extern const char * const local_repo_env[];
-
-void setup_git_env(const char *git_dir);
-
-/*
- * Returns true iff we have a configured git repository (either via
- * setup_git_directory, or in the environment via $GIT_DIR).
- */
-int have_git_dir(void);
-
-extern int is_bare_repository_cfg;
-int is_bare_repository(void);
-int is_inside_git_dir(void);
-extern char *git_work_tree_cfg;
-int is_inside_work_tree(void);
-const char *get_git_dir(void);
-const char *get_git_common_dir(void);
-const char *get_object_directory(void);
-char *get_index_file(void);
-char *get_graft_file(struct repository *r);
-void set_git_dir(const char *path, int make_realpath);
-int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
-int get_common_dir(struct strbuf *sb, const char *gitdir);
-const char *get_git_namespace(void);
-const char *strip_namespace(const char *namespaced_ref);
-const char *get_git_work_tree(void);
-
-/*
- * Return true if the given path is a git directory; note that this _just_
- * looks at the directory itself. If you want to know whether "foo/.git"
- * is a repository, you must feed that path, not just "foo".
- */
-int is_git_directory(const char *path);
-
-/*
- * Return 1 if the given path is the root of a git repository or
- * submodule, else 0. Will not return 1 for bare repositories with the
- * exception of creating a bare repository in "foo/.git" and calling
- * is_git_repository("foo").
- *
- * If we run into read errors, we err on the side of saying "yes, it is",
- * as we usually consider sub-repos precious, and would prefer to err on the
- * side of not disrupting or deleting them.
- */
-int is_nonbare_repository_dir(struct strbuf *path);
-
-#define READ_GITFILE_ERR_STAT_FAILED 1
-#define READ_GITFILE_ERR_NOT_A_FILE 2
-#define READ_GITFILE_ERR_OPEN_FAILED 3
-#define READ_GITFILE_ERR_READ_FAILED 4
-#define READ_GITFILE_ERR_INVALID_FORMAT 5
-#define READ_GITFILE_ERR_NO_PATH 6
-#define READ_GITFILE_ERR_NOT_A_REPO 7
-#define READ_GITFILE_ERR_TOO_LARGE 8
-void read_gitfile_error_die(int error_code, const char *path, const char *dir);
-const char *read_gitfile_gently(const char *path, int *return_error_code);
-#define read_gitfile(path) read_gitfile_gently((path), NULL)
-const char *resolve_gitdir_gently(const char *suspect, int *return_error_code);
-#define resolve_gitdir(path) resolve_gitdir_gently((path), NULL)
-
-void set_git_work_tree(const char *tree);
-
-#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
-
-void setup_work_tree(void);
-/*
- * Find the commondir and gitdir of the repository that contains the current
- * working directory, without changing the working directory or other global
- * state. The result is appended to commondir and gitdir. If the discovered
- * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
- * both have the same result appended to the buffer. The return value is
- * either 0 upon success and non-zero if no repository was found.
- */
-int discover_git_directory(struct strbuf *commondir,
- struct strbuf *gitdir);
-const char *setup_git_directory_gently(int *);
-const char *setup_git_directory(void);
-char *prefix_path(const char *prefix, int len, const char *path);
-char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
-
-/*
- * Concatenate "prefix" (if len is non-zero) and "path", with no
- * connecting characters (so "prefix" should end with a "/").
- * Unlike prefix_path, this should be used if the named file does
- * not have to interact with index entry; i.e. name of a random file
- * on the filesystem.
- *
- * The return value is always a newly allocated string (even if the
- * prefix was empty).
- */
-char *prefix_filename(const char *prefix, const char *path);
-
-int check_filename(const char *prefix, const char *name);
-void verify_filename(const char *prefix,
- const char *name,
- int diagnose_misspelt_rev);
-void verify_non_filename(const char *prefix, const char *name);
-int path_inside_repo(const char *prefix, const char *path);
-
-#define INIT_DB_QUIET 0x0001
-#define INIT_DB_EXIST_OK 0x0002
-
-int init_db(const char *git_dir, const char *real_git_dir,
- const char *template_dir, int hash_algo,
- const char *initial_branch, unsigned int flags);
-void initialize_repository_version(int hash_algo, int reinit);
-
-void sanitize_stdfds(void);
-int daemonize(void);
-
-#define alloc_nr(x) (((x)+16)*3/2)
-
-/**
- * Dynamically growing an array using realloc() is error prone and boring.
- *
- * Define your array with:
- *
- * - a pointer (`item`) that points at the array, initialized to `NULL`
- * (although please name the variable based on its contents, not on its
- * type);
- *
- * - an integer variable (`alloc`) that keeps track of how big the current
- * allocation is, initialized to `0`;
- *
- * - another integer variable (`nr`) to keep track of how many elements the
- * array currently has, initialized to `0`.
- *
- * Then before adding `n`th element to the item, call `ALLOC_GROW(item, n,
- * alloc)`. This ensures that the array can hold at least `n` elements by
- * calling `realloc(3)` and adjusting `alloc` variable.
- *
- * ------------
- * sometype *item;
- * size_t nr;
- * size_t alloc
- *
- * for (i = 0; i < nr; i++)
- * if (we like item[i] already)
- * return;
- *
- * // we did not like any existing one, so add one
- * ALLOC_GROW(item, nr + 1, alloc);
- * item[nr++] = value you like;
- * ------------
- *
- * You are responsible for updating the `nr` variable.
- *
- * If you need to specify the number of elements to allocate explicitly
- * then use the macro `REALLOC_ARRAY(item, alloc)` instead of `ALLOC_GROW`.
- *
- * Consider using ALLOC_GROW_BY instead of ALLOC_GROW as it has some
- * added niceties.
- *
- * DO NOT USE any expression with side-effect for 'x', 'nr', or 'alloc'.
- */
-#define ALLOC_GROW(x, nr, alloc) \
- do { \
- if ((nr) > alloc) { \
- if (alloc_nr(alloc) < (nr)) \
- alloc = (nr); \
- else \
- alloc = alloc_nr(alloc); \
- REALLOC_ARRAY(x, alloc); \
- } \
- } while (0)
-
-/*
- * Similar to ALLOC_GROW but handles updating of the nr value and
- * zeroing the bytes of the newly-grown array elements.
- *
- * DO NOT USE any expression with side-effect for any of the
- * arguments.
- */
-#define ALLOC_GROW_BY(x, nr, increase, alloc) \
- do { \
- if (increase) { \
- size_t new_nr = nr + (increase); \
- if (new_nr < nr) \
- BUG("negative growth in ALLOC_GROW_BY"); \
- ALLOC_GROW(x, new_nr, alloc); \
- memset((x) + nr, 0, sizeof(*(x)) * (increase)); \
- nr = new_nr; \
- } \
- } while (0)
-
-/* Initialize and use the cache information */
-struct lock_file;
-void preload_index(struct index_state *index,
- const struct pathspec *pathspec,
- unsigned int refresh_flags);
-int do_read_index(struct index_state *istate, const char *path,
- int must_exist); /* for testting only! */
-int read_index_from(struct index_state *, const char *path,
- const char *gitdir);
-int is_index_unborn(struct index_state *);
-
-void ensure_full_index(struct index_state *istate);
-
-/* For use with `write_locked_index()`. */
-#define COMMIT_LOCK (1 << 0)
-#define SKIP_IF_UNCHANGED (1 << 1)
-
-/*
- * Write the index while holding an already-taken lock. Close the lock,
- * and if `COMMIT_LOCK` is given, commit it.
- *
- * Unless a split index is in use, write the index into the lockfile.
- *
- * With a split index, write the shared index to a temporary file,
- * adjust its permissions and rename it into place, then write the
- * split index to the lockfile. If the temporary file for the shared
- * index cannot be created, fall back to the behavior described in
- * the previous paragraph.
- *
- * With `COMMIT_LOCK`, the lock is always committed or rolled back.
- * Without it, the lock is closed, but neither committed nor rolled
- * back.
- *
- * If `SKIP_IF_UNCHANGED` is given and the index is unchanged, nothing
- * is written (and the lock is rolled back if `COMMIT_LOCK` is given).
- */
-int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
-
-void discard_index(struct index_state *);
-void move_index_extensions(struct index_state *dst, struct index_state *src);
-int unmerged_index(const struct index_state *);
-
-/**
- * Returns 1 if istate differs from tree, 0 otherwise. If tree is NULL,
- * compares istate to HEAD. If tree is NULL and on an unborn branch,
- * returns 1 if there are entries in istate, 0 otherwise. If an strbuf is
- * provided, the space-separated list of files that differ will be appended
- * to it.
- */
-int repo_index_has_changes(struct repository *repo,
- struct tree *tree,
- struct strbuf *sb);
-
-int verify_path(const char *path, unsigned mode);
-int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
-int index_dir_exists(struct index_state *istate, const char *name, int namelen);
-void adjust_dirname_case(struct index_state *istate, char *name);
-struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
-
-/*
- * Searches for an entry defined by name and namelen in the given index.
- * If the return value is positive (including 0) it is the position of an
- * exact match. If the return value is negative, the negated value minus 1
- * is the position where the entry would be inserted.
- * Example: The current index consists of these files and its stages:
- *
- * b#0, d#0, f#1, f#3
- *
- * index_name_pos(&index, "a", 1) -> -1
- * index_name_pos(&index, "b", 1) -> 0
- * index_name_pos(&index, "c", 1) -> -2
- * index_name_pos(&index, "d", 1) -> 1
- * index_name_pos(&index, "e", 1) -> -3
- * index_name_pos(&index, "f", 1) -> -3
- * index_name_pos(&index, "g", 1) -> -5
- */
-int index_name_pos(struct index_state *, const char *name, int namelen);
-
-/*
- * Like index_name_pos, returns the position of an entry of the given name in
- * the index if one exists, otherwise returns a negative value where the negated
- * value minus 1 is the position where the index entry would be inserted. Unlike
- * index_name_pos, however, a sparse index is not expanded to find an entry
- * inside a sparse directory.
- */
-int index_name_pos_sparse(struct index_state *, const char *name, int namelen);
-
-/*
- * Determines whether an entry with the given name exists within the
- * given index. The return value is 1 if an exact match is found, otherwise
- * it is 0. Note that, unlike index_name_pos, this function does not expand
- * the index if it is sparse. If an item exists within the full index but it
- * is contained within a sparse directory (and not in the sparse index), 0 is
- * returned.
- */
-int index_entry_exists(struct index_state *, const char *name, int namelen);
-
-/*
- * Some functions return the negative complement of an insert position when a
- * precise match was not found but a position was found where the entry would
- * need to be inserted. This helper protects that logic from any integer
- * underflow.
- */
-static inline int index_pos_to_insert_pos(uintmax_t pos)
-{
- if (pos > INT_MAX)
- die("overflow: -1 - %"PRIuMAX, pos);
- return -1 - (int)pos;
-}
-
-#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
-#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
-#define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */
-#define ADD_CACHE_JUST_APPEND 8 /* Append only */
-#define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */
-#define ADD_CACHE_KEEP_CACHE_TREE 32 /* Do not invalidate cache-tree */
-#define ADD_CACHE_RENORMALIZE 64 /* Pass along HASH_RENORMALIZE */
-int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
-void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
-
-/* Remove entry, return true if there are more entries to go. */
-int remove_index_entry_at(struct index_state *, int pos);
-
-void remove_marked_cache_entries(struct index_state *istate, int invalidate);
-int remove_file_from_index(struct index_state *, const char *path);
-#define ADD_CACHE_VERBOSE 1
-#define ADD_CACHE_PRETEND 2
-#define ADD_CACHE_IGNORE_ERRORS 4
-#define ADD_CACHE_IGNORE_REMOVAL 8
-#define ADD_CACHE_INTENT 16
-/*
- * These two are used to add the contents of the file at path
- * to the index, marking the working tree up-to-date by storing
- * the cached stat info in the resulting cache entry. A caller
- * that has already run lstat(2) on the path can call
- * add_to_index(), and all others can call add_file_to_index();
- * the latter will do necessary lstat(2) internally before
- * calling the former.
- */
-int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
-int add_file_to_index(struct index_state *, const char *path, int flags);
-
-int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
-int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
-void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
-int index_name_is_other(struct index_state *, const char *, int);
-void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
-
-/* do stat comparison even if CE_VALID is true */
-#define CE_MATCH_IGNORE_VALID 01
-/* do not check the contents but report dirty on racily-clean entries */
-#define CE_MATCH_RACY_IS_DIRTY 02
-/* do stat comparison even if CE_SKIP_WORKTREE is true */
-#define CE_MATCH_IGNORE_SKIP_WORKTREE 04
-/* ignore non-existent files during stat update */
-#define CE_MATCH_IGNORE_MISSING 0x08
-/* enable stat refresh */
-#define CE_MATCH_REFRESH 0x10
-/* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */
-#define CE_MATCH_IGNORE_FSMONITOR 0X20
-int is_racy_timestamp(const struct index_state *istate,
- const struct cache_entry *ce);
-int has_racy_timestamp(struct index_state *istate);
-int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
-int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
-
-#define HASH_WRITE_OBJECT 1
-#define HASH_FORMAT_CHECK 2
-#define HASH_RENORMALIZE 4
-#define HASH_SILENT 8
-int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
-int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags);
-
-/*
- * Record to sd the data from st that we use to check whether a file
- * might have changed.
- */
-void fill_stat_data(struct stat_data *sd, struct stat *st);
-
-/*
- * Return 0 if st is consistent with a file not having been changed
- * since sd was filled. If there are differences, return a
- * combination of MTIME_CHANGED, CTIME_CHANGED, OWNER_CHANGED,
- * INODE_CHANGED, and DATA_CHANGED.
- */
-int match_stat_data(const struct stat_data *sd, struct stat *st);
-int match_stat_data_racy(const struct index_state *istate,
- const struct stat_data *sd, struct stat *st);
-
-void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, struct stat *st);
-
-#define REFRESH_REALLY (1 << 0) /* ignore_valid */
-#define REFRESH_UNMERGED (1 << 1) /* allow unmerged */
-#define REFRESH_QUIET (1 << 2) /* be quiet about it */
-#define REFRESH_IGNORE_MISSING (1 << 3) /* ignore non-existent */
-#define REFRESH_IGNORE_SUBMODULES (1 << 4) /* ignore submodules */
-#define REFRESH_IN_PORCELAIN (1 << 5) /* user friendly output, not "needs update" */
-#define REFRESH_PROGRESS (1 << 6) /* show progress bar if stderr is tty */
-#define REFRESH_IGNORE_SKIP_WORKTREE (1 << 7) /* ignore skip_worktree entries */
-int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
-/*
- * Refresh the index and write it to disk.
- *
- * 'refresh_flags' is passed directly to 'refresh_index()', while
- * 'COMMIT_LOCK | write_flags' is passed to 'write_locked_index()', so
- * the lockfile is always either committed or rolled back.
- *
- * If 'gentle' is passed, errors locking the index are ignored.
- *
- * Return 1 if refreshing the index returns an error, -1 if writing
- * the index to disk fails, 0 on success.
- *
- * Note that if refreshing the index returns an error, we still write
- * out the index (unless locking fails).
- */
-int repo_refresh_and_write_index(struct repository*, unsigned int refresh_flags, unsigned int write_flags, int gentle, const struct pathspec *, char *seen, const char *header_msg);
-
-struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int);
-
-void set_alternate_index_output(const char *);
-
-extern int verify_index_checksum;
-extern int verify_ce_order;
-
-/* Environment bits from configuration mechanism */
-extern int trust_executable_bit;
-extern int trust_ctime;
-extern int check_stat;
-extern int quote_path_fully;
-extern int has_symlinks;
-extern int minimum_abbrev, default_abbrev;
-extern int ignore_case;
-extern int assume_unchanged;
-extern int prefer_symlink_refs;
-extern int warn_ambiguous_refs;
-extern int warn_on_object_refname_ambiguity;
-extern char *apply_default_whitespace;
-extern char *apply_default_ignorewhitespace;
-extern const char *git_attributes_file;
-extern const char *git_hooks_path;
-extern int zlib_compression_level;
-extern int pack_compression_level;
-extern size_t packed_git_window_size;
-extern size_t packed_git_limit;
-extern size_t delta_base_cache_limit;
-extern unsigned long big_file_threshold;
-extern unsigned long pack_size_limit_cfg;
-
-/*
- * Accessors for the core.sharedrepository config which lazy-load the value
- * from the config (if not already set). The "reset" function can be
- * used to unset "set" or cached value, meaning that the value will be loaded
- * fresh from the config file on the next call to get_shared_repository().
- */
-void set_shared_repository(int value);
-int get_shared_repository(void);
-void reset_shared_repository(void);
-
-/*
- * Do replace refs need to be checked this run? This variable is
- * initialized to true unless --no-replace-object is used or
- * $GIT_NO_REPLACE_OBJECTS is set, but is set to false by some
- * commands that do not want replace references to be active.
- */
-extern int read_replace_refs;
-
-/*
- * These values are used to help identify parts of a repository to fsync.
- * FSYNC_COMPONENT_NONE identifies data that will not be a persistent part of the
- * repository and so shouldn't be fsynced.
- */
-enum fsync_component {
- FSYNC_COMPONENT_NONE,
- FSYNC_COMPONENT_LOOSE_OBJECT = 1 << 0,
- FSYNC_COMPONENT_PACK = 1 << 1,
- FSYNC_COMPONENT_PACK_METADATA = 1 << 2,
- FSYNC_COMPONENT_COMMIT_GRAPH = 1 << 3,
- FSYNC_COMPONENT_INDEX = 1 << 4,
- FSYNC_COMPONENT_REFERENCE = 1 << 5,
-};
-
-#define FSYNC_COMPONENTS_OBJECTS (FSYNC_COMPONENT_LOOSE_OBJECT | \
- FSYNC_COMPONENT_PACK)
-
-#define FSYNC_COMPONENTS_DERIVED_METADATA (FSYNC_COMPONENT_PACK_METADATA | \
- FSYNC_COMPONENT_COMMIT_GRAPH)
-
-#define FSYNC_COMPONENTS_DEFAULT ((FSYNC_COMPONENTS_OBJECTS | \
- FSYNC_COMPONENTS_DERIVED_METADATA) & \
- ~FSYNC_COMPONENT_LOOSE_OBJECT)
-
-#define FSYNC_COMPONENTS_COMMITTED (FSYNC_COMPONENTS_OBJECTS | \
- FSYNC_COMPONENT_REFERENCE)
-
-#define FSYNC_COMPONENTS_ADDED (FSYNC_COMPONENTS_COMMITTED | \
- FSYNC_COMPONENT_INDEX)
-
-#define FSYNC_COMPONENTS_ALL (FSYNC_COMPONENT_LOOSE_OBJECT | \
- FSYNC_COMPONENT_PACK | \
- FSYNC_COMPONENT_PACK_METADATA | \
- FSYNC_COMPONENT_COMMIT_GRAPH | \
- FSYNC_COMPONENT_INDEX | \
- FSYNC_COMPONENT_REFERENCE)
-
-#ifndef FSYNC_COMPONENTS_PLATFORM_DEFAULT
-#define FSYNC_COMPONENTS_PLATFORM_DEFAULT FSYNC_COMPONENTS_DEFAULT
-#endif
-
-/*
- * A bitmask indicating which components of the repo should be fsynced.
- */
-extern enum fsync_component fsync_components;
-extern int fsync_object_files;
-extern int use_fsync;
-
-enum fsync_method {
- FSYNC_METHOD_FSYNC,
- FSYNC_METHOD_WRITEOUT_ONLY,
- FSYNC_METHOD_BATCH,
-};
-
-extern enum fsync_method fsync_method;
-extern int core_preload_index;
-extern int precomposed_unicode;
-extern int protect_hfs;
-extern int protect_ntfs;
-
-extern int core_apply_sparse_checkout;
-extern int core_sparse_checkout_cone;
-extern int sparse_expect_files_outside_of_patterns;
-
-/*
- * Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
- */
-int use_optional_locks(void);
-
-/*
- * The character that begins a commented line in user-editable file
- * that is subject to stripspace.
- */
-extern char comment_line_char;
-extern int auto_comment_line_char;
-
-enum log_refs_config {
- LOG_REFS_UNSET = -1,
- LOG_REFS_NONE = 0,
- LOG_REFS_NORMAL,
- LOG_REFS_ALWAYS
-};
-extern enum log_refs_config log_all_ref_updates;
-
-enum rebase_setup_type {
- AUTOREBASE_NEVER = 0,
- AUTOREBASE_LOCAL,
- AUTOREBASE_REMOTE,
- AUTOREBASE_ALWAYS
-};
-
-enum push_default_type {
- PUSH_DEFAULT_NOTHING = 0,
- PUSH_DEFAULT_MATCHING,
- PUSH_DEFAULT_SIMPLE,
- PUSH_DEFAULT_UPSTREAM,
- PUSH_DEFAULT_CURRENT,
- PUSH_DEFAULT_UNSPECIFIED
-};
-
-extern enum rebase_setup_type autorebase;
-extern enum push_default_type push_default;
-
-enum object_creation_mode {
- OBJECT_CREATION_USES_HARDLINKS = 0,
- OBJECT_CREATION_USES_RENAMES = 1
-};
-
-extern enum object_creation_mode object_creation_mode;
-
-extern char *notes_ref_name;
-
-extern int grafts_replace_parents;
-
-/*
- * GIT_REPO_VERSION is the version we write by default. The
- * _READ variant is the highest number we know how to
- * handle.
- */
-#define GIT_REPO_VERSION 0
-#define GIT_REPO_VERSION_READ 1
-extern int repository_format_precious_objects;
-extern int repository_format_worktree_config;
-
-/*
- * You _have_ to initialize a `struct repository_format` using
- * `= REPOSITORY_FORMAT_INIT` before calling `read_repository_format()`.
- */
-struct repository_format {
- int version;
- int precious_objects;
- char *partial_clone; /* value of extensions.partialclone */
- int worktree_config;
- int is_bare;
- int hash_algo;
- int sparse_index;
- char *work_tree;
- struct string_list unknown_extensions;
- struct string_list v1_only_extensions;
-};
-
-/*
- * Always use this to initialize a `struct repository_format`
- * to a well-defined, default state before calling
- * `read_repository()`.
- */
-#define REPOSITORY_FORMAT_INIT \
-{ \
- .version = -1, \
- .is_bare = -1, \
- .hash_algo = GIT_HASH_SHA1, \
- .unknown_extensions = STRING_LIST_INIT_DUP, \
- .v1_only_extensions = STRING_LIST_INIT_DUP, \
-}
-
-/*
- * Read the repository format characteristics from the config file "path" into
- * "format" struct. Returns the numeric version. On error, or if no version is
- * found in the configuration, -1 is returned, format->version is set to -1,
- * and all other fields in the struct are set to the default configuration
- * (REPOSITORY_FORMAT_INIT). Always initialize the struct using
- * REPOSITORY_FORMAT_INIT before calling this function.
- */
-int read_repository_format(struct repository_format *format, const char *path);
-
-/*
- * Free the memory held onto by `format`, but not the struct itself.
- * (No need to use this after `read_repository_format()` fails.)
- */
-void clear_repository_format(struct repository_format *format);
-
-/*
- * Verify that the repository described by repository_format is something we
- * can read. If it is, return 0. Otherwise, return -1, and "err" will describe
- * any errors encountered.
- */
-int verify_repository_format(const struct repository_format *format,
- struct strbuf *err);
-
-/*
- * Check the repository format version in the path found in get_git_dir(),
- * and die if it is a version we don't understand. Generally one would
- * set_git_dir() before calling this, and use it only for "are we in a valid
- * repo?".
- *
- * If successful and fmt is not NULL, fill fmt with data.
- */
-void check_repository_format(struct repository_format *fmt);
-
-#define MTIME_CHANGED 0x0001
-#define CTIME_CHANGED 0x0002
-#define OWNER_CHANGED 0x0004
-#define MODE_CHANGED 0x0008
-#define INODE_CHANGED 0x0010
-#define DATA_CHANGED 0x0020
-#define TYPE_CHANGED 0x0040
-
-/*
- * Return an abbreviated sha1 unique within this repository's object database.
- * The result will be at least `len` characters long, and will be NUL
- * terminated.
- *
- * The non-`_r` version returns a static buffer which remains valid until 4
- * more calls to find_unique_abbrev are made.
- *
- * The `_r` variant writes to a buffer supplied by the caller, which must be at
- * least `GIT_MAX_HEXSZ + 1` bytes. The return value is the number of bytes
- * written (excluding the NUL terminator).
- *
- * Note that while this version avoids the static buffer, it is not fully
- * reentrant, as it calls into other non-reentrant git code.
- */
-const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);
-#define find_unique_abbrev(oid, len) repo_find_unique_abbrev(the_repository, oid, len)
-int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);
-#define find_unique_abbrev_r(hex, oid, len) repo_find_unique_abbrev_r(the_repository, hex, oid, len)
-
-/* set default permissions by passing mode arguments to open(2) */
-int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
-int git_mkstemp_mode(char *pattern, int mode);
-
-/*
- * NOTE NOTE NOTE!!
- *
- * PERM_UMASK, OLD_PERM_GROUP and OLD_PERM_EVERYBODY enumerations must
- * not be changed. Old repositories have core.sharedrepository written in
- * numeric format, and therefore these values are preserved for compatibility
- * reasons.
- */
-enum sharedrepo {
- PERM_UMASK = 0,
- OLD_PERM_GROUP = 1,
- OLD_PERM_EVERYBODY = 2,
- PERM_GROUP = 0660,
- PERM_EVERYBODY = 0664
-};
-int git_config_perm(const char *var, const char *value);
-int adjust_shared_perm(const char *path);
-
-/*
- * Create the directory containing the named path, using care to be
- * somewhat safe against races. Return one of the scld_error values to
- * indicate success/failure. On error, set errno to describe the
- * problem.
- *
- * SCLD_VANISHED indicates that one of the ancestor directories of the
- * path existed at one point during the function call and then
- * suddenly vanished, probably because another process pruned the
- * directory while we were working. To be robust against this kind of
- * race, callers might want to try invoking the function again when it
- * returns SCLD_VANISHED.
- *
- * safe_create_leading_directories() temporarily changes path while it
- * is working but restores it before returning.
- * safe_create_leading_directories_const() doesn't modify path, even
- * temporarily. Both these variants adjust the permissions of the
- * created directories to honor core.sharedRepository, so they are best
- * suited for files inside the git dir. For working tree files, use
- * safe_create_leading_directories_no_share() instead, as it ignores
- * the core.sharedRepository setting.
- */
-enum scld_error {
- SCLD_OK = 0,
- SCLD_FAILED = -1,
- SCLD_PERMS = -2,
- SCLD_EXISTS = -3,
- SCLD_VANISHED = -4
-};
-enum scld_error safe_create_leading_directories(char *path);
-enum scld_error safe_create_leading_directories_const(const char *path);
-enum scld_error safe_create_leading_directories_no_share(char *path);
-
-int mkdir_in_gitdir(const char *path);
-char *interpolate_path(const char *path, int real_home);
-/* NEEDSWORK: remove this synonym once in-flight topics have migrated */
-#define expand_user_path interpolate_path
-const char *enter_repo(const char *path, int strict);
-static inline int is_absolute_path(const char *path)
-{
- return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
-}
-int is_directory(const char *);
-char *strbuf_realpath(struct strbuf *resolved, const char *path,
- int die_on_error);
-char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path,
- int die_on_error);
-char *real_pathdup(const char *path, int die_on_error);
-const char *absolute_path(const char *path);
-char *absolute_pathdup(const char *path);
-const char *remove_leading_path(const char *in, const char *prefix);
-const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
-int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
-int normalize_path_copy(char *dst, const char *src);
-int longest_ancestor_length(const char *path, struct string_list *prefixes);
-char *strip_path_suffix(const char *path, const char *suffix);
-int daemon_avoid_alias(const char *path);
-
-/*
- * These functions match their is_hfs_dotgit() counterparts; see utf8.h for
- * details.
- */
-int is_ntfs_dotgit(const char *name);
-int is_ntfs_dotgitmodules(const char *name);
-int is_ntfs_dotgitignore(const char *name);
-int is_ntfs_dotgitattributes(const char *name);
-int is_ntfs_dotmailmap(const char *name);
-
-/*
- * Returns true iff "str" could be confused as a command-line option when
- * passed to a sub-program like "ssh". Note that this has nothing to do with
- * shell-quoting, which should be handled separately; we're assuming here that
- * the string makes it verbatim to the sub-program.
- */
-int looks_like_command_line_option(const char *str);
-
-/**
- * Return a newly allocated string with the evaluation of
- * "$XDG_CONFIG_HOME/$subdir/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
- * "$HOME/.config/$subdir/$filename". Return NULL upon error.
- */
-char *xdg_config_home_for(const char *subdir, const char *filename);
-
-/**
- * Return a newly allocated string with the evaluation of
- * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
- * "$HOME/.config/git/$filename". Return NULL upon error.
- */
-char *xdg_config_home(const char *filename);
-
-/**
- * Return a newly allocated string with the evaluation of
- * "$XDG_CACHE_HOME/git/$filename" if $XDG_CACHE_HOME is non-empty, otherwise
- * "$HOME/.cache/git/$filename". Return NULL upon error.
- */
-char *xdg_cache_home(const char *filename);
-
-int git_open_cloexec(const char *name, int flags);
-#define git_open(name) git_open_cloexec(name, O_RDONLY)
-
-/**
- * unpack_loose_header() initializes the data stream needed to unpack
- * a loose object header.
- *
- * Returns:
- *
- * - ULHR_OK on success
- * - ULHR_BAD on error
- * - ULHR_TOO_LONG if the header was too long
- *
- * It will only parse up to MAX_HEADER_LEN bytes unless an optional
- * "hdrbuf" argument is non-NULL. This is intended for use with
- * OBJECT_INFO_ALLOW_UNKNOWN_TYPE to extract the bad type for (error)
- * reporting. The full header will be extracted to "hdrbuf" for use
- * with parse_loose_header(), ULHR_TOO_LONG will still be returned
- * from this function to indicate that the header was too long.
- */
-enum unpack_loose_header_result {
- ULHR_OK,
- ULHR_BAD,
- ULHR_TOO_LONG,
-};
-enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
- unsigned char *map,
- unsigned long mapsize,
- void *buffer,
- unsigned long bufsiz,
- struct strbuf *hdrbuf);
-
-/**
- * parse_loose_header() parses the starting "<type> <len>\0" of an
- * object. If it doesn't follow that format -1 is returned. To check
- * the validity of the <type> populate the "typep" in the "struct
- * object_info". It will be OBJ_BAD if the object type is unknown. The
- * parsed <len> can be retrieved via "oi->sizep", and from there
- * passed to unpack_loose_rest().
- */
-struct object_info;
-int parse_loose_header(const char *hdr, struct object_info *oi);
-
-/**
- * With in-core object data in "buf", rehash it to make sure the
- * object name actually matches "oid" to detect object corruption.
- *
- * A negative value indicates an error, usually that the OID is not
- * what we expected, but it might also indicate another error.
- */
-int check_object_signature(struct repository *r, const struct object_id *oid,
- void *map, unsigned long size,
- enum object_type type);
-
-/**
- * A streaming version of check_object_signature().
- * Try reading the object named with "oid" using
- * the streaming interface and rehash it to do the same.
- */
-int stream_object_signature(struct repository *r, const struct object_id *oid);
-
-int finalize_object_file(const char *tmpfile, const char *filename);
-
-/* Helper to check and "touch" a file */
-int check_and_freshen_file(const char *fn, int freshen);
-
-extern const signed char hexval_table[256];
-static inline unsigned int hexval(unsigned char c)
-{
- return hexval_table[c];
-}
-
-/*
- * Convert two consecutive hexadecimal digits into a char. Return a
- * negative value on error. Don't run over the end of short strings.
- */
-static inline int hex2chr(const char *s)
-{
- unsigned int val = hexval(s[0]);
- return (val & ~0xf) ? val : (val << 4) | hexval(s[1]);
-}
-
-/* Convert to/from hex/sha1 representation */
-#define MINIMUM_ABBREV minimum_abbrev
-#define DEFAULT_ABBREV default_abbrev
-
-/* used when the code does not know or care what the default abbrev is */
-#define FALLBACK_DEFAULT_ABBREV 7
-
-struct object_context {
- unsigned short mode;
- /*
- * symlink_path is only used by get_tree_entry_follow_symlinks,
- * and only for symlinks that point outside the repository.
- */
- struct strbuf symlink_path;
- /*
- * If GET_OID_RECORD_PATH is set, this will record path (if any)
- * found when resolving the name. The caller is responsible for
- * releasing the memory.
- */
- char *path;
-};
-
-#define GET_OID_QUIETLY 01
-#define GET_OID_COMMIT 02
-#define GET_OID_COMMITTISH 04
-#define GET_OID_TREE 010
-#define GET_OID_TREEISH 020
-#define GET_OID_BLOB 040
-#define GET_OID_FOLLOW_SYMLINKS 0100
-#define GET_OID_RECORD_PATH 0200
-#define GET_OID_ONLY_TO_DIE 04000
-#define GET_OID_REQUIRE_PATH 010000
-
-#define GET_OID_DISAMBIGUATORS \
- (GET_OID_COMMIT | GET_OID_COMMITTISH | \
- GET_OID_TREE | GET_OID_TREEISH | \
- GET_OID_BLOB)
-
-enum get_oid_result {
- FOUND = 0,
- MISSING_OBJECT = -1, /* The requested object is missing */
- SHORT_NAME_AMBIGUOUS = -2,
- /* The following only apply when symlinks are followed */
- DANGLING_SYMLINK = -4, /*
- * The initial symlink is there, but
- * (transitively) points to a missing
- * in-tree file
- */
- SYMLINK_LOOP = -5,
- NOT_DIR = -6, /*
- * Somewhere along the symlink chain, a path is
- * requested which contains a file as a
- * non-final element.
- */
-};
-
-int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);
-__attribute__((format (printf, 2, 3)))
-int get_oidf(struct object_id *oid, const char *fmt, ...);
-int repo_get_oid_commit(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_committish(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_tree(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_treeish(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_blob(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_mb(struct repository *r, const char *str, struct object_id *oid);
-void maybe_die_on_misspelt_object_name(struct repository *repo,
- const char *name,
- const char *prefix);
-enum get_oid_result get_oid_with_context(struct repository *repo, const char *str,
- unsigned flags, struct object_id *oid,
- struct object_context *oc);
-
-#define get_oid(str, oid) repo_get_oid(the_repository, str, oid)
-#define get_oid_commit(str, oid) repo_get_oid_commit(the_repository, str, oid)
-#define get_oid_committish(str, oid) repo_get_oid_committish(the_repository, str, oid)
-#define get_oid_tree(str, oid) repo_get_oid_tree(the_repository, str, oid)
-#define get_oid_treeish(str, oid) repo_get_oid_treeish(the_repository, str, oid)
-#define get_oid_blob(str, oid) repo_get_oid_blob(the_repository, str, oid)
-#define get_oid_mb(str, oid) repo_get_oid_mb(the_repository, str, oid)
-
-typedef int each_abbrev_fn(const struct object_id *oid, void *);
-int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *);
-#define for_each_abbrev(prefix, fn, data) repo_for_each_abbrev(the_repository, prefix, fn, data)
-
-int set_disambiguate_hint_config(const char *var, const char *value);
-
-/*
- * Try to read a SHA1 in hexadecimal format from the 40 characters
- * starting at hex. Write the 20-byte result to sha1 in binary form.
- * Return 0 on success. Reading stops if a NUL is encountered in the
- * input, so it is safe to pass this function an arbitrary
- * null-terminated string.
- */
-int get_sha1_hex(const char *hex, unsigned char *sha1);
-int get_oid_hex(const char *hex, struct object_id *sha1);
-
-/* Like get_oid_hex, but for an arbitrary hash algorithm. */
-int get_oid_hex_algop(const char *hex, struct object_id *oid, const struct git_hash_algo *algop);
-
-/*
- * Read `len` pairs of hexadecimal digits from `hex` and write the
- * values to `binary` as `len` bytes. Return 0 on success, or -1 if
- * the input does not consist of hex digits).
- */
-int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
-
-/*
- * Convert a binary hash in "unsigned char []" or an object name in
- * "struct object_id *" to its hex equivalent. The `_r` variant is reentrant,
- * and writes the NUL-terminated output to the buffer `out`, which must be at
- * least `GIT_MAX_HEXSZ + 1` bytes, and returns a pointer to out for
- * convenience.
- *
- * The non-`_r` variant returns a static buffer, but uses a ring of 4
- * buffers, making it safe to make multiple calls for a single statement, like:
- *
- * printf("%s -> %s", hash_to_hex(one), hash_to_hex(two));
- * printf("%s -> %s", oid_to_hex(one), oid_to_hex(two));
- */
-char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, const struct git_hash_algo *);
-char *oid_to_hex_r(char *out, const struct object_id *oid);
-char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *); /* static buffer result! */
-char *hash_to_hex(const unsigned char *hash); /* same static buffer */
-char *oid_to_hex(const struct object_id *oid); /* same static buffer */
-
-/*
- * Parse a 40-character hexadecimal object ID starting from hex, updating the
- * pointer specified by end when parsing stops. The resulting object ID is
- * stored in oid. Returns 0 on success. Parsing will stop on the first NUL or
- * other invalid character. end is only updated on success; otherwise, it is
- * unmodified.
- */
-int parse_oid_hex(const char *hex, struct object_id *oid, const char **end);
-
-/* Like parse_oid_hex, but for an arbitrary hash algorithm. */
-int parse_oid_hex_algop(const char *hex, struct object_id *oid, const char **end,
- const struct git_hash_algo *algo);
-
-
-/*
- * These functions work like get_oid_hex and parse_oid_hex, but they will parse
- * a hex value for any algorithm. The algorithm is detected based on the length
- * and the algorithm in use is returned. If this is not a hex object ID in any
- * algorithm, returns GIT_HASH_UNKNOWN.
- */
-int get_oid_hex_any(const char *hex, struct object_id *oid);
-int parse_oid_hex_any(const char *hex, struct object_id *oid, const char **end);
-
-/*
- * This reads short-hand syntax that not only evaluates to a commit
- * object name, but also can act as if the end user spelled the name
- * of the branch from the command line.
- *
- * - "@{-N}" finds the name of the Nth previous branch we were on, and
- * places the name of the branch in the given buf and returns the
- * number of characters parsed if successful.
- *
- * - "<branch>@{upstream}" finds the name of the other ref that
- * <branch> is configured to merge with (missing <branch> defaults
- * to the current branch), and places the name of the branch in the
- * given buf and returns the number of characters parsed if
- * successful.
- *
- * If the input is not of the accepted format, it returns a negative
- * number to signal an error.
- *
- * If the input was ok but there are not N branch switches in the
- * reflog, it returns 0.
- */
-#define INTERPRET_BRANCH_LOCAL (1<<0)
-#define INTERPRET_BRANCH_REMOTE (1<<1)
-#define INTERPRET_BRANCH_HEAD (1<<2)
-struct interpret_branch_name_options {
- /*
- * If "allowed" is non-zero, it is a treated as a bitfield of allowable
- * expansions: local branches ("refs/heads/"), remote branches
- * ("refs/remotes/"), or "HEAD". If no "allowed" bits are set, any expansion is
- * allowed, even ones to refs outside of those namespaces.
- */
- unsigned allowed;
-
- /*
- * If ^{upstream} or ^{push} (or equivalent) is requested, and the
- * branch in question does not have such a reference, return -1 instead
- * of die()-ing.
- */
- unsigned nonfatal_dangling_mark : 1;
-};
-int repo_interpret_branch_name(struct repository *r,
- const char *str, int len,
- struct strbuf *buf,
- const struct interpret_branch_name_options *options);
-#define interpret_branch_name(str, len, buf, options) \
- repo_interpret_branch_name(the_repository, str, len, buf, options)
-
-int validate_headref(const char *ref);
-
-int base_name_compare(const char *name1, size_t len1, int mode1,
- const char *name2, size_t len2, int mode2);
-int df_name_compare(const char *name1, size_t len1, int mode1,
- const char *name2, size_t len2, int mode2);
-int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
-int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
-
-void *read_object_with_reference(struct repository *r,
- const struct object_id *oid,
- enum object_type required_type,
- unsigned long *size,
- struct object_id *oid_ret);
-
-struct object *repo_peel_to_type(struct repository *r,
- const char *name, int namelen,
- struct object *o, enum object_type);
-#define peel_to_type(name, namelen, obj, type) \
- repo_peel_to_type(the_repository, name, namelen, obj, type)
-
-#define IDENT_STRICT 1
-#define IDENT_NO_DATE 2
-#define IDENT_NO_NAME 4
-
-enum want_ident {
- WANT_BLANK_IDENT,
- WANT_AUTHOR_IDENT,
- WANT_COMMITTER_IDENT
-};
-
-const char *git_author_info(int);
-const char *git_committer_info(int);
-const char *fmt_ident(const char *name, const char *email,
- enum want_ident whose_ident,
- const char *date_str, int);
-const char *fmt_name(enum want_ident);
-const char *ident_default_name(void);
-const char *ident_default_email(void);
-const char *git_editor(void);
-const char *git_sequence_editor(void);
-const char *git_pager(int stdout_is_tty);
-int is_terminal_dumb(void);
-int git_ident_config(const char *, const char *, void *);
-/*
- * Prepare an ident to fall back on if the user didn't configure it.
- */
-void prepare_fallback_ident(const char *name, const char *email);
-void reset_ident_date(void);
-
-struct ident_split {
- const char *name_begin;
- const char *name_end;
- const char *mail_begin;
- const char *mail_end;
- const char *date_begin;
- const char *date_end;
- const char *tz_begin;
- const char *tz_end;
-};
-/*
- * Signals an success with 0, but time part of the result may be NULL
- * if the input lacks timestamp and zone
- */
-int split_ident_line(struct ident_split *, const char *, int);
-
-/*
- * Given a commit or tag object buffer and the commit or tag headers, replaces
- * the idents in the headers with their canonical versions using the mailmap mechanism.
- */
-void apply_mailmap_to_header(struct strbuf *, const char **, struct string_list *);
-
-/*
- * Compare split idents for equality or strict ordering. Note that we
- * compare only the ident part of the line, ignoring any timestamp.
- *
- * Because there are two fields, we must choose one as the primary key; we
- * currently arbitrarily pick the email.
- */
-int ident_cmp(const struct ident_split *, const struct ident_split *);
-
-struct cache_def {
- struct strbuf path;
- int flags;
- int track_flags;
- int prefix_len_stat_func;
-};
-#define CACHE_DEF_INIT { \
- .path = STRBUF_INIT, \
-}
-static inline void cache_def_clear(struct cache_def *cache)
-{
- strbuf_release(&cache->path);
-}
-
-int has_symlink_leading_path(const char *name, int len);
-int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
-int check_leading_path(const char *name, int len, int warn_on_lstat_err);
-int has_dirs_only_path(const char *name, int len, int prefix_len);
-void invalidate_lstat_cache(void);
-void schedule_dir_for_removal(const char *name, int len);
-void remove_scheduled_dirs(void);
-
-struct pack_window {
- struct pack_window *next;
- unsigned char *base;
- off_t offset;
- size_t len;
- unsigned int last_used;
- unsigned int inuse_cnt;
-};
-
-struct pack_entry {
- off_t offset;
- struct packed_git *p;
-};
-
-/*
- * Create a temporary file rooted in the object database directory, or
- * die on failure. The filename is taken from "pattern", which should have the
- * usual "XXXXXX" trailer, and the resulting filename is written into the
- * "template" buffer. Returns the open descriptor.
- */
-int odb_mkstemp(struct strbuf *temp_filename, const char *pattern);
-
-/*
- * Create a pack .keep file named "name" (which should generally be the output
- * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on
- * error.
- */
-int odb_pack_keep(const char *name);
-
-/*
- * Set this to 0 to prevent oid_object_info_extended() from fetching missing
- * blobs. This has a difference only if extensions.partialClone is set.
- *
- * Its default value is 1.
- */
-extern int fetch_if_missing;
-
-/* Dumb servers support */
-int update_server_info(int);
-
-const char *get_log_output_encoding(void);
-const char *get_commit_output_encoding(void);
-
-int committer_ident_sufficiently_given(void);
-int author_ident_sufficiently_given(void);
-
-extern const char *git_commit_encoding;
-extern const char *git_log_output_encoding;
-extern const char *git_mailmap_file;
-extern const char *git_mailmap_blob;
-
-/* IO helper functions */
-void maybe_flush_or_die(FILE *, const char *);
-__attribute__((format (printf, 2, 3)))
-void fprintf_or_die(FILE *, const char *fmt, ...);
-void fwrite_or_die(FILE *f, const void *buf, size_t count);
-void fflush_or_die(FILE *f);
-
-#define COPY_READ_ERROR (-2)
-#define COPY_WRITE_ERROR (-3)
-int copy_fd(int ifd, int ofd);
-int copy_file(const char *dst, const char *src, int mode);
-int copy_file_with_time(const char *dst, const char *src, int mode);
-
-void write_or_die(int fd, const void *buf, size_t count);
-void fsync_or_die(int fd, const char *);
-int fsync_component(enum fsync_component component, int fd);
-void fsync_component_or_die(enum fsync_component component, int fd, const char *msg);
-
-static inline int batch_fsync_enabled(enum fsync_component component)
-{
- return (fsync_components & component) && (fsync_method == FSYNC_METHOD_BATCH);
-}
-
-ssize_t read_in_full(int fd, void *buf, size_t count);
-ssize_t write_in_full(int fd, const void *buf, size_t count);
-ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
-
-static inline ssize_t write_str_in_full(int fd, const char *str)
-{
- return write_in_full(fd, str, strlen(str));
-}
-
-/**
- * Open (and truncate) the file at path, write the contents of buf to it,
- * and close it. Dies if any errors are encountered.
- */
-void write_file_buf(const char *path, const char *buf, size_t len);
-
-/**
- * Like write_file_buf(), but format the contents into a buffer first.
- * Additionally, write_file() will append a newline if one is not already
- * present, making it convenient to write text files:
- *
- * write_file(path, "counter: %d", ctr);
- */
-__attribute__((format (printf, 2, 3)))
-void write_file(const char *path, const char *fmt, ...);
-
-/* pager.c */
-void setup_pager(void);
-int pager_in_use(void);
-extern int pager_use_color;
-int term_columns(void);
-void term_clear_line(void);
-int decimal_width(uintmax_t);
-int check_pager_config(const char *cmd);
-void prepare_pager_args(struct child_process *, const char *pager);
-
-extern const char *editor_program;
-extern const char *askpass_program;
-extern const char *excludes_file;
-
-/* base85 */
-int decode_85(char *dst, const char *line, int linelen);
-void encode_85(char *buf, const unsigned char *data, int bytes);
-
-/* pkt-line.c */
-void packet_trace_identity(const char *prog);
-
-/* add */
-/*
- * return 0 if success, 1 - if addition of a file failed and
- * ADD_FILES_IGNORE_ERRORS was specified in flags
- */
-int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);
-
-/* diff.c */
-extern int diff_auto_refresh_index;
-
-/* match-trees.c */
-void shift_tree(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, int);
-void shift_tree_by(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, const char *);
-
-/*
- * whitespace rules.
- * used by both diff and apply
- * last two digits are tab width
- */
-#define WS_BLANK_AT_EOL 0100
-#define WS_SPACE_BEFORE_TAB 0200
-#define WS_INDENT_WITH_NON_TAB 0400
-#define WS_CR_AT_EOL 01000
-#define WS_BLANK_AT_EOF 02000
-#define WS_TAB_IN_INDENT 04000
-#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
-#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
-#define WS_TAB_WIDTH_MASK 077
-/* All WS_* -- when extended, adapt diff.c emit_symbol */
-#define WS_RULE_MASK 07777
-extern unsigned whitespace_rule_cfg;
-unsigned whitespace_rule(struct index_state *, const char *);
-unsigned parse_whitespace_rule(const char *);
-unsigned ws_check(const char *line, int len, unsigned ws_rule);
-void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
-char *whitespace_error_string(unsigned ws);
-void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
-int ws_blank_line(const char *line, int len);
-#define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK)
-
-/* ls-files */
-void overlay_tree_on_index(struct index_state *istate,
- const char *tree_name, const char *prefix);
-
-/* setup.c */
-struct startup_info {
- int have_repository;
- const char *prefix;
- const char *original_cwd;
-};
-extern struct startup_info *startup_info;
-extern const char *tmp_original_cwd;
-
-/* merge.c */
-struct commit_list;
-int try_merge_command(struct repository *r,
- const char *strategy, size_t xopts_nr,
- const char **xopts, struct commit_list *common,
- const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(struct repository *r,
- const struct object_id *from,
- const struct object_id *to,
- int overwrite_ignore);
-
-
-int sane_execvp(const char *file, char *const argv[]);
-
-/*
- * A struct to encapsulate the concept of whether a file has changed
- * since we last checked it. This uses criteria similar to those used
- * for the index.
- */
-struct stat_validity {
- struct stat_data *sd;
-};
-
-void stat_validity_clear(struct stat_validity *sv);
-
-/*
- * Returns 1 if the path is a regular file (or a symlink to a regular
- * file) and matches the saved stat_validity, 0 otherwise. A missing
- * or inaccessible file is considered a match if the struct was just
- * initialized, or if the previous update found an inaccessible file.
- */
-int stat_validity_check(struct stat_validity *sv, const char *path);
-
-/*
- * Update the stat_validity from a file opened at descriptor fd. If
- * the file is missing, inaccessible, or not a regular file, then
- * future calls to stat_validity_check will match iff one of those
- * conditions continues to be true.
- */
-void stat_validity_update(struct stat_validity *sv, int fd);
-
-int versioncmp(const char *s1, const char *s2);
-
-/*
- * Create a directory and (if share is nonzero) adjust its permissions
- * according to the shared_repository setting. Only use this for
- * directories under $GIT_DIR. Don't use it for working tree
- * directories.
- */
-void safe_create_dir(const char *dir, int share);
-
-/*
- * Should we print an ellipsis after an abbreviated SHA-1 value
- * when doing diff-raw output or indicating a detached HEAD?
- */
-int print_sha1_ellipsis(void);
-
-/* Return 1 if the file is empty or does not exists, 0 otherwise. */
-int is_empty_or_missing_file(const char *filename);
-
-#endif /* CACHE_H */
diff --git a/cbtree.c b/cbtree.c
index 336e46dbba..c1cc30a5dc 100644
--- a/cbtree.c
+++ b/cbtree.c
@@ -4,6 +4,7 @@
* Based on Adam Langley's adaptation of Dan Bernstein's public domain code
* git clone https://github.com/agl/critbit.git
*/
+#include "git-compat-util.h"
#include "cbtree.h"
static struct cb_node *cb_node_of(const void *p)
diff --git a/cbtree.h b/cbtree.h
index 0be14fb7ee..43193abdda 100644
--- a/cbtree.h
+++ b/cbtree.h
@@ -14,8 +14,6 @@
#ifndef CBTREE_H
#define CBTREE_H
-#include "git-compat-util.h"
-
struct cb_node;
struct cb_node {
struct cb_node *child[2];
diff --git a/chdir-notify.c b/chdir-notify.c
index 5f7f2c2ac2..0d7bc04607 100644
--- a/chdir-notify.c
+++ b/chdir-notify.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "chdir-notify.h"
#include "list.h"
+#include "path.h"
#include "strbuf.h"
+#include "trace.h"
struct chdir_notify_entry {
const char *name;
diff --git a/checkout.c b/checkout.c
index 2e39dae684..4256e71a7c 100644
--- a/checkout.c
+++ b/checkout.c
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "object-name.h"
#include "remote.h"
#include "refspec.h"
+#include "repository.h"
#include "checkout.h"
#include "config.h"
+#include "strbuf.h"
struct tracking_name_data {
/* const */ char *src_ref;
@@ -23,7 +26,7 @@ static int check_tracking_name(struct remote *remote, void *cb_data)
memset(&query, 0, sizeof(struct refspec_item));
query.src = cb->src_ref;
if (remote_find_tracking(remote, &query) ||
- get_oid(query.dst, cb->dst_oid)) {
+ repo_get_oid(the_repository, query.dst, cb->dst_oid)) {
free(query.dst);
return 0;
}
diff --git a/checkout.h b/checkout.h
index 1152133bd7..3c514a5ab4 100644
--- a/checkout.h
+++ b/checkout.h
@@ -1,7 +1,7 @@
#ifndef CHECKOUT_H
#define CHECKOUT_H
-#include "cache.h"
+#include "hash-ll.h"
/*
* Check if the branch name uniquely matches a branch name on a remote
diff --git a/chunk-format.c b/chunk-format.c
index 0275b74a89..e7d613c907 100644
--- a/chunk-format.c
+++ b/chunk-format.c
@@ -1,6 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "chunk-format.h"
#include "csum-file.h"
+#include "gettext.h"
+#include "hash.h"
+#include "trace2.h"
/*
* When writing a chunk-based file format, collect the chunks in
diff --git a/chunk-format.h b/chunk-format.h
index 7885aa0848..c7794e84ad 100644
--- a/chunk-format.h
+++ b/chunk-format.h
@@ -1,8 +1,7 @@
#ifndef CHUNK_FORMAT_H
#define CHUNK_FORMAT_H
-#include "git-compat-util.h"
-#include "hash.h"
+#include "hash-ll.h"
struct hashfile;
struct chunkfile;
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index b098e10f52..a18b13a41d 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -27,7 +27,7 @@ linux-TEST-vars)
export GIT_TEST_MULTI_PACK_INDEX=1
export GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=1
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
- export GIT_TEST_WRITE_REV_INDEX=1
+ export GIT_TEST_NO_WRITE_REV_INDEX=1
export GIT_TEST_CHECKOUT_WORKERS=2
;;
linux-clang)
diff --git a/color.c b/color.c
index f05d8a81d7..83abb11eda 100644
--- a/color.c
+++ b/color.c
@@ -1,6 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "color.h"
+#include "editor.h"
+#include "gettext.h"
+#include "hex.h"
+#include "pager.h"
+#include "strbuf.h"
static int git_use_color_default = GIT_COLOR_AUTO;
int color_stdout_is_tty = -1;
diff --git a/column.c b/column.c
index fbf88639aa..ff2f0abf39 100644
--- a/column.c
+++ b/column.c
@@ -1,7 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "column.h"
#include "string-list.h"
+#include "pager.h"
#include "parse-options.h"
#include "run-command.h"
#include "utf8.h"
diff --git a/combine-diff.c b/combine-diff.c
index 1a39b5dde0..11e9d7494a 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -1,17 +1,23 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "object-store-ll.h"
#include "commit.h"
+#include "convert.h"
#include "blob.h"
#include "diff.h"
#include "diffcore.h"
+#include "environment.h"
+#include "hex.h"
+#include "object-name.h"
#include "quote.h"
#include "xdiff-interface.h"
#include "xdiff/xmacros.h"
#include "log-tree.h"
#include "refs.h"
+#include "tree.h"
#include "userdiff.h"
#include "oid-array.h"
#include "revision.h"
+#include "wrapper.h"
static int compare_paths(const struct combine_diff_path *one,
const struct diff_filespec *two)
@@ -332,7 +338,7 @@ static char *grab_blob(struct repository *r,
*size = fill_textconv(r, textconv, df, &blob);
free_filespec(df);
} else {
- blob = read_object_file(oid, &type, size);
+ blob = repo_read_object_file(r, oid, &type, size);
if (type != OBJ_BLOB)
die("object '%s' is not a blob!", oid_to_hex(oid));
}
@@ -948,11 +954,11 @@ static void show_combined_header(struct combine_diff_path *elem,
"", elem->path, line_prefix, c_meta, c_reset);
printf("%s%sindex ", line_prefix, c_meta);
for (i = 0; i < num_parent; i++) {
- abb = find_unique_abbrev(&elem->parent[i].oid,
- abbrev);
+ abb = repo_find_unique_abbrev(the_repository,
+ &elem->parent[i].oid, abbrev);
printf("%s%s", i ? "," : "", abb);
}
- abb = find_unique_abbrev(&elem->oid, abbrev);
+ abb = repo_find_unique_abbrev(the_repository, &elem->oid, abbrev);
printf("..%s%s\n", abb, c_reset);
if (mode_differs) {
diff --git a/commit-graph.c b/commit-graph.c
index c11b59f28b..9e989f4349 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1,5 +1,7 @@
#include "git-compat-util.h"
#include "config.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "pack.h"
#include "packfile.h"
@@ -9,7 +11,10 @@
#include "revision.h"
#include "hash-lookup.h"
#include "commit-graph.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
+#include "path.h"
#include "alloc.h"
#include "hashmap.h"
#include "replace-object.h"
@@ -19,7 +24,9 @@
#include "shallow.h"
#include "json-writer.h"
#include "trace2.h"
+#include "tree.h"
#include "chunk-format.h"
+#include "wrapper.h"
void git_test_write_commit_graph_or_die(void)
{
@@ -116,12 +123,10 @@ timestamp_t commit_graph_generation(const struct commit *c)
struct commit_graph_data *data =
commit_graph_data_slab_peek(&commit_graph_data_slab, c);
- if (!data)
- return GENERATION_NUMBER_INFINITY;
- else if (data->graph_pos == COMMIT_NOT_FROM_GRAPH)
- return GENERATION_NUMBER_INFINITY;
+ if (data && data->generation)
+ return data->generation;
- return data->generation;
+ return GENERATION_NUMBER_INFINITY;
}
static struct commit_graph_data *commit_graph_data_at(const struct commit *c)
@@ -1446,24 +1451,52 @@ static void close_reachable(struct write_commit_graph_context *ctx)
stop_progress(&ctx->progress);
}
-static void compute_topological_levels(struct write_commit_graph_context *ctx)
+struct compute_generation_info {
+ struct repository *r;
+ struct packed_commit_list *commits;
+ struct progress *progress;
+ int progress_cnt;
+
+ timestamp_t (*get_generation)(struct commit *c, void *data);
+ void (*set_generation)(struct commit *c, timestamp_t gen, void *data);
+ void *data;
+};
+
+static timestamp_t compute_generation_from_max(struct commit *c,
+ timestamp_t max_gen,
+ int generation_version)
+{
+ switch (generation_version) {
+ case 1: /* topological levels */
+ if (max_gen > GENERATION_NUMBER_V1_MAX - 1)
+ max_gen = GENERATION_NUMBER_V1_MAX - 1;
+ return max_gen + 1;
+
+ case 2: /* corrected commit date */
+ if (c->date && c->date > max_gen)
+ max_gen = c->date - 1;
+ return max_gen + 1;
+
+ default:
+ BUG("attempting unimplemented version");
+ }
+}
+
+static void compute_reachable_generation_numbers(
+ struct compute_generation_info *info,
+ int generation_version)
{
int i;
struct commit_list *list = NULL;
- if (ctx->report_progress)
- ctx->progress = start_delayed_progress(
- _("Computing commit graph topological levels"),
- ctx->commits.nr);
- for (i = 0; i < ctx->commits.nr; i++) {
- struct commit *c = ctx->commits.list[i];
- uint32_t level;
-
- repo_parse_commit(ctx->r, c);
- level = *topo_level_slab_at(ctx->topo_levels, c);
+ for (i = 0; i < info->commits->nr; i++) {
+ struct commit *c = info->commits->list[i];
+ timestamp_t gen;
+ repo_parse_commit(info->r, c);
+ gen = info->get_generation(c, info->data);
+ display_progress(info->progress, info->progress_cnt + 1);
- display_progress(ctx->progress, i + 1);
- if (level != GENERATION_NUMBER_ZERO)
+ if (gen != GENERATION_NUMBER_ZERO && gen != GENERATION_NUMBER_INFINITY)
continue;
commit_list_insert(c, &list);
@@ -1471,41 +1504,91 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)
struct commit *current = list->item;
struct commit_list *parent;
int all_parents_computed = 1;
- uint32_t max_level = 0;
+ uint32_t max_gen = 0;
for (parent = current->parents; parent; parent = parent->next) {
- repo_parse_commit(ctx->r, parent->item);
- level = *topo_level_slab_at(ctx->topo_levels, parent->item);
+ repo_parse_commit(info->r, parent->item);
+ gen = info->get_generation(parent->item, info->data);
- if (level == GENERATION_NUMBER_ZERO) {
+ if (gen == GENERATION_NUMBER_ZERO) {
all_parents_computed = 0;
commit_list_insert(parent->item, &list);
break;
}
- if (level > max_level)
- max_level = level;
+ if (gen > max_gen)
+ max_gen = gen;
}
if (all_parents_computed) {
pop_commit(&list);
-
- if (max_level > GENERATION_NUMBER_V1_MAX - 1)
- max_level = GENERATION_NUMBER_V1_MAX - 1;
- *topo_level_slab_at(ctx->topo_levels, current) = max_level + 1;
+ gen = compute_generation_from_max(
+ current, max_gen,
+ generation_version);
+ info->set_generation(current, gen, info->data);
}
}
}
+}
+
+static timestamp_t get_topo_level(struct commit *c, void *data)
+{
+ struct write_commit_graph_context *ctx = data;
+ return *topo_level_slab_at(ctx->topo_levels, c);
+}
+
+static void set_topo_level(struct commit *c, timestamp_t t, void *data)
+{
+ struct write_commit_graph_context *ctx = data;
+ *topo_level_slab_at(ctx->topo_levels, c) = (uint32_t)t;
+}
+
+static void compute_topological_levels(struct write_commit_graph_context *ctx)
+{
+ struct compute_generation_info info = {
+ .r = ctx->r,
+ .commits = &ctx->commits,
+ .get_generation = get_topo_level,
+ .set_generation = set_topo_level,
+ .data = ctx,
+ };
+
+ if (ctx->report_progress)
+ info.progress = ctx->progress
+ = start_delayed_progress(
+ _("Computing commit graph topological levels"),
+ ctx->commits.nr);
+
+ compute_reachable_generation_numbers(&info, 1);
+
stop_progress(&ctx->progress);
}
+static timestamp_t get_generation_from_graph_data(struct commit *c, void *data)
+{
+ return commit_graph_data_at(c)->generation;
+}
+
+static void set_generation_v2(struct commit *c, timestamp_t t, void *data)
+{
+ struct commit_graph_data *g = commit_graph_data_at(c);
+ g->generation = t;
+}
+
static void compute_generation_numbers(struct write_commit_graph_context *ctx)
{
int i;
- struct commit_list *list = NULL;
+ struct compute_generation_info info = {
+ .r = ctx->r,
+ .commits = &ctx->commits,
+ .get_generation = get_generation_from_graph_data,
+ .set_generation = set_generation_v2,
+ .data = ctx,
+ };
if (ctx->report_progress)
- ctx->progress = start_delayed_progress(
+ info.progress = ctx->progress
+ = start_delayed_progress(
_("Computing commit graph generation numbers"),
ctx->commits.nr);
@@ -1517,47 +1600,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
}
}
- for (i = 0; i < ctx->commits.nr; i++) {
- struct commit *c = ctx->commits.list[i];
- timestamp_t corrected_commit_date;
-
- repo_parse_commit(ctx->r, c);
- corrected_commit_date = commit_graph_data_at(c)->generation;
-
- display_progress(ctx->progress, i + 1);
- if (corrected_commit_date != GENERATION_NUMBER_ZERO)
- continue;
-
- commit_list_insert(c, &list);
- while (list) {
- struct commit *current = list->item;
- struct commit_list *parent;
- int all_parents_computed = 1;
- timestamp_t max_corrected_commit_date = 0;
-
- for (parent = current->parents; parent; parent = parent->next) {
- repo_parse_commit(ctx->r, parent->item);
- corrected_commit_date = commit_graph_data_at(parent->item)->generation;
-
- if (corrected_commit_date == GENERATION_NUMBER_ZERO) {
- all_parents_computed = 0;
- commit_list_insert(parent->item, &list);
- break;
- }
-
- if (corrected_commit_date > max_corrected_commit_date)
- max_corrected_commit_date = corrected_commit_date;
- }
-
- if (all_parents_computed) {
- pop_commit(&list);
-
- if (current->date && current->date > max_corrected_commit_date)
- max_corrected_commit_date = current->date - 1;
- commit_graph_data_at(current)->generation = max_corrected_commit_date + 1;
- }
- }
- }
+ compute_reachable_generation_numbers(&info, 2);
for (i = 0; i < ctx->commits.nr; i++) {
struct commit *c = ctx->commits.list[i];
@@ -1568,6 +1611,35 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
stop_progress(&ctx->progress);
}
+static void set_generation_in_graph_data(struct commit *c, timestamp_t t,
+ void *data)
+{
+ commit_graph_data_at(c)->generation = t;
+}
+
+/*
+ * After this method, all commits reachable from those in the given
+ * list will have non-zero, non-infinite generation numbers.
+ */
+void ensure_generations_valid(struct repository *r,
+ struct commit **commits, size_t nr)
+{
+ int generation_version = get_configured_generation_version(r);
+ struct packed_commit_list list = {
+ .list = commits,
+ .alloc = nr,
+ .nr = nr,
+ };
+ struct compute_generation_info info = {
+ .r = r,
+ .commits = &list,
+ .get_generation = get_generation_from_graph_data,
+ .set_generation = set_generation_in_graph_data,
+ };
+
+ compute_reachable_generation_numbers(&info, generation_version);
+}
+
static void trace2_bloom_filter_write_statistics(struct write_commit_graph_context *ctx)
{
trace2_data_intmax("commit-graph", ctx->r, "filter-computed",
@@ -2360,7 +2432,7 @@ int write_commit_graph(struct object_directory *odb,
replace = ctx->opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;
}
- ctx->approx_nr_objects = approximate_object_count();
+ ctx->approx_nr_objects = repo_approximate_object_count(the_repository);
if (ctx->append && ctx->r->objects->commit_graph) {
struct commit_graph *g = ctx->r->objects->commit_graph;
@@ -2549,7 +2621,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
graph_commit = lookup_commit(r, &cur_oid);
odb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));
- if (parse_commit_internal(odb_commit, 0, 0)) {
+ if (repo_parse_commit_internal(r, odb_commit, 0, 0)) {
graph_report(_("failed to parse commit %s from object database for commit-graph"),
oid_to_hex(&cur_oid));
continue;
diff --git a/commit-graph.h b/commit-graph.h
index 37faee6b66..5e534f0fcc 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -1,8 +1,7 @@
#ifndef COMMIT_GRAPH_H
#define COMMIT_GRAPH_H
-#include "git-compat-util.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "oidset.h"
#define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
@@ -190,4 +189,12 @@ struct commit_graph_data {
*/
timestamp_t commit_graph_generation(const struct commit *);
uint32_t commit_graph_position(const struct commit *);
+
+/*
+ * After this method, all commits reachable from those in the given
+ * list will have non-zero, non-infinite generation numbers.
+ */
+void ensure_generations_valid(struct repository *r,
+ struct commit **commits, size_t nr);
+
#endif
diff --git a/commit-reach.c b/commit-reach.c
index 2e33c599a8..70bde8af05 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -1,13 +1,16 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "commit.h"
#include "commit-graph.h"
#include "decorate.h"
+#include "hex.h"
#include "prio-queue.h"
#include "tree.h"
#include "ref-filter.h"
#include "revision.h"
#include "tag.h"
#include "commit-reach.h"
+#include "ewah/ewok.h"
/* Remember to update object flag allocation in object.h */
#define PARENT1 (1u<<16)
@@ -162,7 +165,8 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
for (j = ret; j; j = j->next) {
struct commit_list *bases;
- bases = get_merge_bases(i->item, j->item);
+ bases = repo_get_merge_bases(the_repository, i->item,
+ j->item);
if (!new_commits)
new_commits = bases;
else
@@ -447,7 +451,7 @@ int repo_is_descendant_of(struct repository *r,
if (!with_commit)
return 1;
- if (generation_numbers_enabled(the_repository)) {
+ if (generation_numbers_enabled(r)) {
struct commit_list *from_list = NULL;
int result;
commit_list_insert(commit, &from_list);
@@ -584,7 +588,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
return 0;
new_commit = (struct commit *) o;
- if (parse_commit(new_commit) < 0)
+ if (repo_parse_commit(the_repository, new_commit) < 0)
return 0;
commit_list_insert(old_commit, &old_commit_list);
@@ -748,7 +752,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
}
list[nr_commits] = (struct commit *)from_one;
- if (parse_commit(list[nr_commits]) ||
+ if (repo_parse_commit(the_repository, list[nr_commits]) ||
commit_graph_generation(list[nr_commits]) < min_generation) {
result = 0;
goto cleanup;
@@ -783,7 +787,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
if (!(parent->item->object.flags & assign_flag)) {
parent->item->object.flags |= assign_flag;
- if (parse_commit(parent->item) ||
+ if (repo_parse_commit(the_repository, parent->item) ||
parent->item->date < min_commit_date ||
commit_graph_generation(parent->item) < min_generation)
continue;
@@ -807,8 +811,12 @@ cleanup:
clear_commit_marks_many(nr_commits, list, RESULT | assign_flag);
free(list);
- for (i = 0; i < from->nr; i++)
- from->objects[i].item->flags &= ~assign_flag;
+ for (i = 0; i < from->nr; i++) {
+ struct object *from_one = from->objects[i].item;
+
+ if (from_one)
+ from_one->flags &= ~assign_flag;
+ }
return result;
}
@@ -825,7 +833,7 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
while (from_iter) {
add_object_array(&from_iter->item->object, NULL, &from_objs);
- if (!parse_commit(from_iter->item)) {
+ if (!repo_parse_commit(the_repository, from_iter->item)) {
timestamp_t generation;
if (from_iter->item->date < min_commit_date)
min_commit_date = from_iter->item->date;
@@ -839,7 +847,7 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
}
while (to_iter) {
- if (!parse_commit(to_iter->item)) {
+ if (!repo_parse_commit(the_repository, to_iter->item)) {
timestamp_t generation;
if (to_iter->item->date < min_commit_date)
min_commit_date = to_iter->item->date;
@@ -889,7 +897,7 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
timestamp_t generation;
struct commit *c = *item;
- parse_commit(c);
+ repo_parse_commit(the_repository, c);
generation = commit_graph_generation(c);
if (generation < min_generation)
min_generation = generation;
@@ -904,7 +912,7 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
struct commit *c = *item;
if (!(c->object.flags & PARENT2)) {
c->object.flags |= PARENT2;
- parse_commit(c);
+ repo_parse_commit(the_repository, c);
prio_queue_put(&queue, *item);
}
@@ -923,7 +931,7 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
for (parents = current->parents; parents; parents = parents->next) {
struct commit *p = parents->item;
- parse_commit(p);
+ repo_parse_commit(the_repository, p);
if (commit_graph_generation(p) < min_generation)
continue;
@@ -941,3 +949,218 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
return found_commits;
}
+
+define_commit_slab(bit_arrays, struct bitmap *);
+static struct bit_arrays bit_arrays;
+
+static void insert_no_dup(struct prio_queue *queue, struct commit *c)
+{
+ if (c->object.flags & PARENT2)
+ return;
+ prio_queue_put(queue, c);
+ c->object.flags |= PARENT2;
+}
+
+static struct bitmap *get_bit_array(struct commit *c, int width)
+{
+ struct bitmap **bitmap = bit_arrays_at(&bit_arrays, c);
+ if (!*bitmap)
+ *bitmap = bitmap_word_alloc(width);
+ return *bitmap;
+}
+
+static void free_bit_array(struct commit *c)
+{
+ struct bitmap **bitmap = bit_arrays_at(&bit_arrays, c);
+ if (!*bitmap)
+ return;
+ bitmap_free(*bitmap);
+ *bitmap = NULL;
+}
+
+void ahead_behind(struct repository *r,
+ struct commit **commits, size_t commits_nr,
+ struct ahead_behind_count *counts, size_t counts_nr)
+{
+ struct prio_queue queue = { .compare = compare_commits_by_gen_then_commit_date };
+ size_t width = DIV_ROUND_UP(commits_nr, BITS_IN_EWORD);
+
+ if (!commits_nr || !counts_nr)
+ return;
+
+ for (size_t i = 0; i < counts_nr; i++) {
+ counts[i].ahead = 0;
+ counts[i].behind = 0;
+ }
+
+ ensure_generations_valid(r, commits, commits_nr);
+
+ init_bit_arrays(&bit_arrays);
+
+ for (size_t i = 0; i < commits_nr; i++) {
+ struct commit *c = commits[i];
+ struct bitmap *bitmap = get_bit_array(c, width);
+
+ bitmap_set(bitmap, i);
+ insert_no_dup(&queue, c);
+ }
+
+ while (queue_has_nonstale(&queue)) {
+ struct commit *c = prio_queue_get(&queue);
+ struct commit_list *p;
+ struct bitmap *bitmap_c = get_bit_array(c, width);
+
+ for (size_t i = 0; i < counts_nr; i++) {
+ int reach_from_tip = !!bitmap_get(bitmap_c, counts[i].tip_index);
+ int reach_from_base = !!bitmap_get(bitmap_c, counts[i].base_index);
+
+ if (reach_from_tip ^ reach_from_base) {
+ if (reach_from_base)
+ counts[i].behind++;
+ else
+ counts[i].ahead++;
+ }
+ }
+
+ for (p = c->parents; p; p = p->next) {
+ struct bitmap *bitmap_p;
+
+ repo_parse_commit(r, p->item);
+
+ bitmap_p = get_bit_array(p->item, width);
+ bitmap_or(bitmap_p, bitmap_c);
+
+ /*
+ * If this parent is reachable from every starting
+ * commit, then none of its ancestors can contribute
+ * to the ahead/behind count. Mark it as STALE, so
+ * we can stop the walk when every commit in the
+ * queue is STALE.
+ */
+ if (bitmap_popcount(bitmap_p) == commits_nr)
+ p->item->object.flags |= STALE;
+
+ insert_no_dup(&queue, p->item);
+ }
+
+ free_bit_array(c);
+ }
+
+ /* STALE is used here, PARENT2 is used by insert_no_dup(). */
+ repo_clear_commit_marks(r, PARENT2 | STALE);
+ clear_bit_arrays(&bit_arrays);
+ clear_prio_queue(&queue);
+}
+
+struct commit_and_index {
+ struct commit *commit;
+ unsigned int index;
+ timestamp_t generation;
+};
+
+static int compare_commit_and_index_by_generation(const void *va, const void *vb)
+{
+ const struct commit_and_index *a = (const struct commit_and_index *)va;
+ const struct commit_and_index *b = (const struct commit_and_index *)vb;
+
+ if (a->generation > b->generation)
+ return 1;
+ if (a->generation < b->generation)
+ return -1;
+ return 0;
+}
+
+void tips_reachable_from_bases(struct repository *r,
+ struct commit_list *bases,
+ struct commit **tips, size_t tips_nr,
+ int mark)
+{
+ struct commit_and_index *commits;
+ size_t min_generation_index = 0;
+ timestamp_t min_generation;
+ struct commit_list *stack = NULL;
+
+ if (!bases || !tips || !tips_nr)
+ return;
+
+ /*
+ * Do a depth-first search starting at 'bases' to search for the
+ * tips. Stop at the lowest (un-found) generation number. When
+ * finding the lowest commit, increase the minimum generation
+ * number to the next lowest (un-found) generation number.
+ */
+
+ CALLOC_ARRAY(commits, tips_nr);
+
+ for (size_t i = 0; i < tips_nr; i++) {
+ commits[i].commit = tips[i];
+ commits[i].index = i;
+ commits[i].generation = commit_graph_generation(tips[i]);
+ }
+
+ /* Sort with generation number ascending. */
+ QSORT(commits, tips_nr, compare_commit_and_index_by_generation);
+ min_generation = commits[0].generation;
+
+ while (bases) {
+ repo_parse_commit(r, bases->item);
+ commit_list_insert(bases->item, &stack);
+ bases = bases->next;
+ }
+
+ while (stack) {
+ int explored_all_parents = 1;
+ struct commit_list *p;
+ struct commit *c = stack->item;
+ timestamp_t c_gen = commit_graph_generation(c);
+
+ /* Does it match any of our tips? */
+ for (size_t j = min_generation_index; j < tips_nr; j++) {
+ if (c_gen < commits[j].generation)
+ break;
+
+ if (commits[j].commit == c) {
+ tips[commits[j].index]->object.flags |= mark;
+
+ if (j == min_generation_index) {
+ unsigned int k = j + 1;
+ while (k < tips_nr &&
+ (tips[commits[k].index]->object.flags & mark))
+ k++;
+
+ /* Terminate early if all found. */
+ if (k >= tips_nr)
+ goto done;
+
+ min_generation_index = k;
+ min_generation = commits[k].generation;
+ }
+ }
+ }
+
+ for (p = c->parents; p; p = p->next) {
+ repo_parse_commit(r, p->item);
+
+ /* Have we already explored this parent? */
+ if (p->item->object.flags & SEEN)
+ continue;
+
+ /* Is it below the current minimum generation? */
+ if (commit_graph_generation(p->item) < min_generation)
+ continue;
+
+ /* Ok, we will explore from here on. */
+ p->item->object.flags |= SEEN;
+ explored_all_parents = 0;
+ commit_list_insert(p->item, &stack);
+ break;
+ }
+
+ if (explored_all_parents)
+ pop_commit(&stack);
+ }
+
+done:
+ free(commits);
+ repo_clear_commit_marks(r, SEEN);
+}
diff --git a/commit-reach.h b/commit-reach.h
index 148b56fea5..35c4da4948 100644
--- a/commit-reach.h
+++ b/commit-reach.h
@@ -19,11 +19,6 @@ struct commit_list *repo_get_merge_bases_many(struct repository *r,
struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
struct commit *one, int n,
struct commit **twos);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define get_merge_bases(r1, r2) repo_get_merge_bases(the_repository, r1, r2)
-#define get_merge_bases_many(one, n, two) repo_get_merge_bases_many(the_repository, one, n, two)
-#define get_merge_bases_many_dirty(one, n, twos) repo_get_merge_bases_many_dirty(the_repository, one, n, twos)
-#endif
struct commit_list *get_octopus_merge_bases(struct commit_list *in);
@@ -36,10 +31,6 @@ int repo_in_merge_bases(struct repository *r,
int repo_in_merge_bases_many(struct repository *r,
struct commit *commit,
int nr_reference, struct commit **reference);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define in_merge_bases(c1, c2) repo_in_merge_bases(the_repository, c1, c2)
-#define in_merge_bases_many(c1, n, cs) repo_in_merge_bases_many(the_repository, c1, n, cs)
-#endif
/*
* Takes a list of commits and returns a new list where those
@@ -104,4 +95,44 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
struct commit **to, int nr_to,
unsigned int reachable_flag);
+struct ahead_behind_count {
+ /**
+ * As input, the *_index members indicate which positions in
+ * the 'tips' array correspond to the tip and base of this
+ * comparison.
+ */
+ size_t tip_index;
+ size_t base_index;
+
+ /**
+ * These values store the computed counts for each side of the
+ * symmetric difference:
+ *
+ * 'ahead' stores the number of commits reachable from the tip
+ * and not reachable from the base.
+ *
+ * 'behind' stores the number of commits reachable from the base
+ * and not reachable from the tip.
+ */
+ unsigned int ahead;
+ unsigned int behind;
+};
+
+/*
+ * Given an array of commits and an array of ahead_behind_count pairs,
+ * compute the ahead/behind counts for each pair.
+ */
+void ahead_behind(struct repository *r,
+ struct commit **commits, size_t commits_nr,
+ struct ahead_behind_count *counts, size_t counts_nr);
+
+/*
+ * For all tip commits, add 'mark' to their flags if and only if they
+ * are reachable from one of the commits in 'bases'.
+ */
+void tips_reachable_from_bases(struct repository *r,
+ struct commit_list *bases,
+ struct commit **tips, size_t tips_nr,
+ int mark);
+
#endif
diff --git a/commit-slab-impl.h b/commit-slab-impl.h
index 557738df27..4a414ee905 100644
--- a/commit-slab-impl.h
+++ b/commit-slab-impl.h
@@ -1,8 +1,6 @@
#ifndef COMMIT_SLAB_IMPL_H
#define COMMIT_SLAB_IMPL_H
-#include "git-compat-util.h"
-
#define implement_static_commit_slab(slabname, elemtype) \
implement_commit_slab(slabname, elemtype, MAYBE_UNUSED static)
diff --git a/commit.c b/commit.c
index e433c33bb0..2c3f53ede1 100644
--- a/commit.c
+++ b/commit.c
@@ -1,9 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "tag.h"
#include "commit.h"
#include "commit-graph.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "pkt-line.h"
#include "utf8.h"
#include "diff.h"
@@ -20,7 +24,9 @@
#include "refs.h"
#include "commit-reach.h"
#include "run-command.h"
+#include "setup.h"
#include "shallow.h"
+#include "tree.h"
#include "hook.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -67,12 +73,19 @@ struct commit *lookup_commit_object(struct repository *r,
}
-struct commit *lookup_commit(struct repository *r, const struct object_id *oid)
+struct commit *lookup_commit_type(struct repository *r,
+ const struct object_id *oid,
+ enum object_type type)
{
struct object *obj = lookup_object(r, oid);
if (!obj)
return create_object(r, oid, alloc_commit_node(r));
- return object_as_type(obj, OBJ_COMMIT, 0);
+ return object_as_type_hint(obj, OBJ_COMMIT, type);
+}
+
+struct commit *lookup_commit(struct repository *r, const struct object_id *oid)
+{
+ return lookup_commit_type(r, oid, OBJ_NONE);
}
struct commit *lookup_commit_reference_by_name(const char *name)
@@ -80,10 +93,10 @@ struct commit *lookup_commit_reference_by_name(const char *name)
struct object_id oid;
struct commit *commit;
- if (get_oid_committish(name, &oid))
+ if (repo_get_oid_committish(the_repository, name, &oid))
return NULL;
commit = lookup_commit_reference(the_repository, &oid);
- if (parse_commit(commit))
+ if (repo_parse_commit(the_repository, commit))
return NULL;
return commit;
}
@@ -91,6 +104,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
static timestamp_t parse_commit_date(const char *buf, const char *tail)
{
const char *dateptr;
+ const char *eol;
if (buf + 6 >= tail)
return 0;
@@ -102,16 +116,56 @@ static timestamp_t parse_commit_date(const char *buf, const char *tail)
return 0;
if (memcmp(buf, "committer", 9))
return 0;
- while (buf < tail && *buf++ != '>')
- /* nada */;
- if (buf >= tail)
+
+ /*
+ * Jump to end-of-line so that we can walk backwards to find the
+ * end-of-email ">". This is more forgiving of malformed cases
+ * because unexpected characters tend to be in the name and email
+ * fields.
+ */
+ eol = memchr(buf, '\n', tail - buf);
+ if (!eol)
return 0;
- dateptr = buf;
- while (buf < tail && *buf++ != '\n')
- /* nada */;
- if (buf >= tail)
+ dateptr = eol;
+ while (dateptr > buf && dateptr[-1] != '>')
+ dateptr--;
+ if (dateptr == buf)
return 0;
- /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */
+
+ /*
+ * Trim leading whitespace, but make sure we have at least one
+ * non-whitespace character, as parse_timestamp() will otherwise walk
+ * right past the newline we found in "eol" when skipping whitespace
+ * itself.
+ *
+ * In theory it would be sufficient to allow any character not matched
+ * by isspace(), but there's a catch: our isspace() does not
+ * necessarily match the behavior of parse_timestamp(), as the latter
+ * is implemented by system routines which match more exotic control
+ * codes, or even locale-dependent sequences.
+ *
+ * Since we expect the timestamp to be a number, we can check for that.
+ * Anything else (e.g., a non-numeric token like "foo") would just
+ * cause parse_timestamp() to return 0 anyway.
+ */
+ while (dateptr < eol && isspace(*dateptr))
+ dateptr++;
+ if (!isdigit(*dateptr) && *dateptr != '-')
+ return 0;
+
+ /*
+ * We know there is at least one digit (or dash), so we'll begin
+ * parsing there and stop at worst case at eol.
+ *
+ * Note that we may feed parse_timestamp() extra characters here if the
+ * commit is malformed, and it will parse as far as it can. For
+ * example, "123foo456" would return "123". That might be questionable
+ * (versus returning "0"), but it would help in a hypothetical case
+ * like "123456+0100", where the whitespace from the timezone is
+ * missing. Since such syntactic errors may be baked into history and
+ * hard to correct now, let's err on trying to make our best guess
+ * here, rather than insist on perfect syntax.
+ */
return parse_timestamp(dateptr, NULL, 10);
}
@@ -382,7 +436,7 @@ struct tree *repo_get_commit_tree(struct repository *r,
struct object_id *get_commit_tree_oid(const struct commit *commit)
{
- struct tree *tree = get_commit_tree(commit);
+ struct tree *tree = repo_get_commit_tree(the_repository, commit);
return tree ? &tree->object.oid : NULL;
}
@@ -555,7 +609,7 @@ int repo_parse_commit_gently(struct repository *r,
void parse_commit_or_die(struct commit *item)
{
- if (parse_commit(item))
+ if (repo_parse_commit(the_repository, item))
die("unable to parse commit %s",
item ? oid_to_hex(&item->object.oid) : "(null)");
}
@@ -688,7 +742,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
while (parents) {
struct commit *commit = parents->item;
- if (!parse_commit(commit) && !(commit->object.flags & mark)) {
+ if (!repo_parse_commit(the_repository, commit) && !(commit->object.flags & mark)) {
commit->object.flags |= mark;
commit_list_insert_by_date(commit, list);
}
@@ -762,7 +816,8 @@ define_commit_slab(author_date_slab, timestamp_t);
void record_author_date(struct author_date_slab *author_date,
struct commit *commit)
{
- const char *buffer = get_commit_buffer(commit, NULL);
+ const char *buffer = repo_get_commit_buffer(the_repository, commit,
+ NULL);
struct ident_split ident;
const char *ident_line;
size_t ident_len;
@@ -782,7 +837,7 @@ void record_author_date(struct author_date_slab *author_date,
*(author_date_slab_at(author_date, commit)) = date;
fail_exit:
- unuse_commit_buffer(commit, buffer);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
}
int compare_commits_by_author_date(const void *a_, const void *b_,
@@ -801,7 +856,8 @@ int compare_commits_by_author_date(const void *a_, const void *b_,
return 0;
}
-int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused)
+int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_,
+ void *unused UNUSED)
{
const struct commit *a = a_, *b = b_;
const timestamp_t generation_a = commit_graph_generation(a),
@@ -821,7 +877,8 @@ int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void
return 0;
}
-int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
+int compare_commits_by_commit_date(const void *a_, const void *b_,
+ void *unused UNUSED)
{
const struct commit *a = a_, *b = b_;
/* newer commits with larger date first */
@@ -963,7 +1020,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
commit = lookup_commit(the_repository, oid);
if (!commit ||
(commit->object.flags & TMP_MARK) ||
- parse_commit(commit))
+ repo_parse_commit(the_repository, commit))
return;
ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
@@ -995,7 +1052,8 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
struct commit *ret = NULL;
char *full_refname;
- switch (dwim_ref(refname, strlen(refname), &oid, &full_refname, 0)) {
+ switch (repo_dwim_ref(the_repository, refname, strlen(refname), &oid,
+ &full_refname, 0)) {
case 0:
die("No such ref: '%s'", refname);
case 1:
@@ -1014,7 +1072,8 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
for (i = 0; i < revs.nr; i++)
revs.commit[i]->object.flags &= ~TMP_MARK;
- bases = get_merge_bases_many(commit, revs.nr, revs.commit);
+ bases = repo_get_merge_bases_many(the_repository, commit, revs.nr,
+ revs.commit);
/*
* There should be one and only one merge base, when we found
@@ -1095,10 +1154,11 @@ int parse_signed_commit(const struct commit *commit,
const struct git_hash_algo *algop)
{
unsigned long size;
- const char *buffer = get_commit_buffer(commit, &size);
+ const char *buffer = repo_get_commit_buffer(the_repository, commit,
+ &size);
int ret = parse_buffer_signed_by_header(buffer, size, payload, signature, algop);
- unuse_commit_buffer(commit, buffer);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
return ret;
}
@@ -1209,7 +1269,8 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
desc = merge_remote_util(parent);
if (!desc || !desc->obj)
return;
- buf = read_object_file(&desc->obj->oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &desc->obj->oid, &type,
+ &size);
if (!buf || type != OBJ_TAG)
goto free_return;
if (!parse_signature(buf, size, &payload, &signature))
@@ -1271,7 +1332,8 @@ void verify_merge_signature(struct commit *commit, int verbosity,
ret = check_commit_signature(commit, &signature_check);
- find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV);
+ repo_find_unique_abbrev_r(the_repository, hex, &commit->object.oid,
+ DEFAULT_ABBREV);
switch (signature_check.result) {
case 'G':
if (ret || (check_trust && signature_check.trust_level < TRUST_MARGINAL))
@@ -1316,9 +1378,10 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit,
{
struct commit_extra_header *extra = NULL;
unsigned long size;
- const char *buffer = get_commit_buffer(commit, &size);
+ const char *buffer = repo_get_commit_buffer(the_repository, commit,
+ &size);
extra = read_commit_extra_header_lines(buffer, size, exclude);
- unuse_commit_buffer(commit, buffer);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
return extra;
}
@@ -1632,10 +1695,11 @@ struct commit *get_merge_parent(const char *name)
struct object *obj;
struct commit *commit;
struct object_id oid;
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
return NULL;
obj = parse_object(the_repository, &oid);
- commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
+ commit = (struct commit *)repo_peel_to_type(the_repository, name, 0,
+ obj, OBJ_COMMIT);
if (commit && !merge_remote_util(commit))
set_merge_remote_desc(commit, name, obj);
return commit;
diff --git a/commit.h b/commit.h
index cc2c5da7bd..e968118c88 100644
--- a/commit.h
+++ b/commit.h
@@ -2,13 +2,10 @@
#define COMMIT_H
#include "object.h"
-#include "tree.h"
-#include "strbuf.h"
-#include "decorate.h"
-#include "gpg-interface.h"
-#include "string-list.h"
-#include "pretty.h"
-#include "commit-slab.h"
+
+struct signature_check;
+struct strbuf;
+struct tree;
#define COMMIT_NOT_FROM_GRAPH 0xFFFFFFFF
#define GENERATION_NUMBER_INFINITY ((1ULL << 63) - 1)
@@ -78,6 +75,8 @@ struct commit *lookup_commit_object(struct repository *r, const struct object_id
* "oid" is not in the object cache.
*/
struct commit *lookup_commit(struct repository *r, const struct object_id *oid);
+struct commit *lookup_commit_type(struct repository *r, const struct object_id *oid,
+ enum object_type type);
struct commit *lookup_commit_reference(struct repository *r,
const struct object_id *oid);
struct commit *lookup_commit_reference_gently(struct repository *r,
@@ -109,11 +108,6 @@ static inline int repo_parse_commit_no_graph(struct repository *r,
return repo_parse_commit_internal(r, commit, 0, 0);
}
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define parse_commit_internal(item, quiet, use) repo_parse_commit_internal(the_repository, item, quiet, use)
-#define parse_commit(item) repo_parse_commit(the_repository, item)
-#endif
-
void parse_commit_or_die(struct commit *item);
struct buffer_slab;
@@ -135,27 +129,21 @@ const void *get_cached_commit_buffer(struct repository *, const struct commit *,
/*
* Get the commit's object contents, either from cache or by reading the object
* from disk. The resulting memory should not be modified, and must be given
- * to unuse_commit_buffer when the caller is done.
+ * to repo_unuse_commit_buffer when the caller is done.
*/
const void *repo_get_commit_buffer(struct repository *r,
const struct commit *,
unsigned long *size);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define get_commit_buffer(c, s) repo_get_commit_buffer(the_repository, c, s)
-#endif
/*
* Tell the commit subsystem that we are done with a particular commit buffer.
* The commit and buffer should be the input and return value, respectively,
- * from an earlier call to get_commit_buffer. The buffer may or may not be
+ * from an earlier call to repo_get_commit_buffer. The buffer may or may not be
* freed by this call; callers should not access the memory afterwards.
*/
void repo_unuse_commit_buffer(struct repository *r,
const struct commit *,
const void *buffer);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define unuse_commit_buffer(c, b) repo_unuse_commit_buffer(the_repository, c, b)
-#endif
/*
* Free any cached object buffer associated with the commit.
@@ -163,7 +151,6 @@ void repo_unuse_commit_buffer(struct repository *r,
void free_commit_buffer(struct parsed_object_pool *pool, struct commit *);
struct tree *repo_get_commit_tree(struct repository *, const struct commit *);
-#define get_commit_tree(c) repo_get_commit_tree(the_repository, c)
struct object_id *get_commit_tree_oid(const struct commit *);
/*
@@ -205,17 +192,10 @@ void free_commit_list(struct commit_list *list);
struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
-int has_non_ascii(const char *text);
-const char *logmsg_reencode(const struct commit *commit,
- char **commit_encoding,
- const char *output_encoding);
const char *repo_logmsg_reencode(struct repository *r,
const struct commit *commit,
char **commit_encoding,
const char *output_encoding);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define logmsg_reencode(c, enc, out) repo_logmsg_reencode(the_repository, c, enc, out)
-#endif
const char *skip_blank_lines(const char *msg);
diff --git a/common-main.c b/common-main.c
index 0a22861f1c..033778b3c5 100644
--- a/common-main.c
+++ b/common-main.c
@@ -1,6 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "exec-cmd.h"
+#include "gettext.h"
#include "attr.h"
+#include "repository.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "trace2.h"
/*
* Many parts of Git have subprograms communicate via pipe, expect the
diff --git a/compat/disk.h b/compat/disk.h
index 50a32e3d8a..6c979c27d8 100644
--- a/compat/disk.h
+++ b/compat/disk.h
@@ -2,6 +2,8 @@
#define COMPAT_DISK_H
#include "git-compat-util.h"
+#include "abspath.h"
+#include "gettext.h"
static int get_disk_info(struct strbuf *out)
{
diff --git a/compat/fsmonitor/fsm-health-darwin.c b/compat/fsmonitor/fsm-health-darwin.c
index b9f709e854..5b1709d63f 100644
--- a/compat/fsmonitor/fsm-health-darwin.c
+++ b/compat/fsmonitor/fsm-health-darwin.c
@@ -1,6 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
#include "fsm-health.h"
#include "fsmonitor--daemon.h"
diff --git a/compat/fsmonitor/fsm-health-win32.c b/compat/fsmonitor/fsm-health-win32.c
index 2ea08c1d4e..2d4e245beb 100644
--- a/compat/fsmonitor/fsm-health-win32.c
+++ b/compat/fsmonitor/fsm-health-win32.c
@@ -1,8 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
#include "fsm-health.h"
#include "fsmonitor--daemon.h"
+#include "gettext.h"
/*
* Every minute wake up and test our health.
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
index d67b0ee50d..6f3a95410c 100644
--- a/compat/fsmonitor/fsm-ipc-darwin.c
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -1,7 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "path.h"
+#include "repository.h"
#include "strbuf.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
#include "fsmonitor-ipc.h"
#include "fsmonitor-path-utils.h"
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
index e08c505c14..8928fa93ce 100644
--- a/compat/fsmonitor/fsm-ipc-win32.c
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -1,5 +1,7 @@
+#include "git-compat-util.h"
#include "config.h"
#include "fsmonitor-ipc.h"
+#include "path.h"
const char *fsmonitor_ipc__get_path(struct repository *r) {
static char *ret;
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 97a55a6f0a..36c7e13281 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -23,11 +23,14 @@
#endif
#endif
-#include "cache.h"
-#include "fsmonitor.h"
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
#include "fsmonitor-path-utils.h"
+#include "gettext.h"
+#include "string-list.h"
+#include "trace.h"
struct fsm_listen_data
{
diff --git a/compat/fsmonitor/fsm-listen-win32.c b/compat/fsmonitor/fsm-listen-win32.c
index 03df8d951b..a361a7db20 100644
--- a/compat/fsmonitor/fsm-listen-win32.c
+++ b/compat/fsmonitor/fsm-listen-win32.c
@@ -1,8 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "gettext.h"
+#include "trace2.h"
/*
* The documentation of ReadDirectoryChangesW() states that the maximum
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index ce5a8febe0..049f97eaaf 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
-#include "fsmonitor.h"
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
#include "fsmonitor-path-utils.h"
+#include "gettext.h"
+#include "trace.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index 0d95bbb416..c8a3e9dcdb 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -1,6 +1,8 @@
-#include "cache.h"
-#include "fsmonitor.h"
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
#include "fsmonitor-path-utils.h"
+#include "gettext.h"
+#include "trace.h"
/*
* Check remote working directory protocol.
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 6abbc7af3a..a382590635 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,5 +1,6 @@
+#include "git-compat-util.h"
#include "config.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
#include "fsmonitor-ipc.h"
#include "fsmonitor-settings.h"
#include "fsmonitor-path-utils.h"
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index a8af31b71d..b6f6744494 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,7 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
#include "fsmonitor-settings.h"
#include "fsmonitor-path-utils.h"
diff --git a/compat/linux/procinfo.c b/compat/linux/procinfo.c
index bc2f9382a1..4bb2d66227 100644
--- a/compat/linux/procinfo.c
+++ b/compat/linux/procinfo.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "strbuf.h"
#include "strvec.h"
diff --git a/compat/mingw.c b/compat/mingw.c
index e433740381..559abb1c61 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -6,10 +6,16 @@
#include <wchar.h>
#include "../strbuf.h"
#include "../run-command.h"
-#include "../cache.h"
+#include "../abspath.h"
+#include "../alloc.h"
#include "win32/lazyload.h"
#include "../config.h"
+#include "../environment.h"
+#include "../trace2.h"
+#include "../symlinks.h"
+#include "../wrapper.h"
#include "dir.h"
+#include "gettext.h"
#define SECURITY_WIN32
#include <sspi.h>
diff --git a/compat/pread.c b/compat/pread.c
index 978cac4ec9..484e6d4c71 100644
--- a/compat/pread.c
+++ b/compat/pread.c
@@ -1,4 +1,5 @@
#include "../git-compat-util.h"
+#include "../wrapper.h"
ssize_t git_pread(int fd, void *buf, size_t count, off_t offset)
{
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index cce1d57a46..0bd5c24250 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -5,8 +5,12 @@
#define PRECOMPOSE_UNICODE_C
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "path.h"
+#include "strbuf.h"
#include "utf8.h"
#include "precompose_utf8.h"
diff --git a/compat/sha1-chunked.c b/compat/sha1-chunked.c
index 6adfcfd540..a4a6f930d7 100644
--- a/compat/sha1-chunked.c
+++ b/compat/sha1-chunked.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hash-ll.h"
int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len)
{
diff --git a/compat/simple-ipc/ipc-shared.c b/compat/simple-ipc/ipc-shared.c
index 1b9d359ab6..e5e1dda8cc 100644
--- a/compat/simple-ipc/ipc-shared.c
+++ b/compat/simple-ipc/ipc-shared.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "simple-ipc.h"
#include "strbuf.h"
#include "pkt-line.h"
diff --git a/compat/simple-ipc/ipc-unix-socket.c b/compat/simple-ipc/ipc-unix-socket.c
index 28a79289d4..b2f4f22ce4 100644
--- a/compat/simple-ipc/ipc-unix-socket.c
+++ b/compat/simple-ipc/ipc-unix-socket.c
@@ -1,8 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
#include "simple-ipc.h"
#include "strbuf.h"
#include "pkt-line.h"
#include "thread-utils.h"
+#include "trace2.h"
#include "unix-socket.h"
#include "unix-stream-server.h"
diff --git a/compat/simple-ipc/ipc-win32.c b/compat/simple-ipc/ipc-win32.c
index 20ea7b65e0..5276f658a1 100644
--- a/compat/simple-ipc/ipc-win32.c
+++ b/compat/simple-ipc/ipc-win32.c
@@ -1,8 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "hex.h"
#include "simple-ipc.h"
#include "strbuf.h"
#include "pkt-line.h"
#include "thread-utils.h"
+#include "trace.h"
+#include "trace2.h"
#include "accctrl.h"
#include "aclapi.h"
@@ -17,27 +22,27 @@
static int initialize_pipe_name(const char *path, wchar_t *wpath, size_t alloc)
{
int off = 0;
- struct strbuf realpath = STRBUF_INIT;
-
- if (!strbuf_realpath(&realpath, path, 0))
- return -1;
+ int ret = 0;
+ git_SHA_CTX sha1ctx;
+ struct strbuf real_path = STRBUF_INIT;
+ struct strbuf pipe_name = STRBUF_INIT;
+ unsigned char hash[GIT_MAX_RAWSZ];
- off = swprintf(wpath, alloc, L"\\\\.\\pipe\\");
- if (xutftowcs(wpath + off, realpath.buf, alloc - off) < 0)
+ if (!strbuf_realpath(&real_path, path, 0))
return -1;
- /* Handle drive prefix */
- if (wpath[off] && wpath[off + 1] == L':') {
- wpath[off + 1] = L'_';
- off += 2;
- }
+ git_SHA1_Init(&sha1ctx);
+ git_SHA1_Update(&sha1ctx, real_path.buf, real_path.len);
+ git_SHA1_Final(hash, &sha1ctx);
+ strbuf_release(&real_path);
- for (; wpath[off]; off++)
- if (wpath[off] == L'/')
- wpath[off] = L'\\';
+ strbuf_addf(&pipe_name, "git-fsmonitor-%s", hash_to_hex(hash));
+ off = swprintf(wpath, alloc, L"\\\\.\\pipe\\");
+ if (xutftowcs(wpath + off, pipe_name.buf, alloc - off) < 0)
+ ret = -1;
- strbuf_release(&realpath);
- return 0;
+ strbuf_release(&pipe_name);
+ return ret;
}
static enum ipc_active_state get_active_state(wchar_t *pipe_path)
diff --git a/compat/terminal.c b/compat/terminal.c
index ea490a7ced..d87e321189 100644
--- a/compat/terminal.c
+++ b/compat/terminal.c
@@ -1,10 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "compat/terminal.h"
+#include "gettext.h"
#include "sigchain.h"
#include "strbuf.h"
#include "run-command.h"
#include "string-list.h"
#include "hashmap.h"
+#include "wrapper.h"
#if defined(HAVE_DEV_TTY) || defined(GIT_WINDOWS_NATIVE)
diff --git a/compat/win32/trace2_win32_process_info.c b/compat/win32/trace2_win32_process_info.c
index a53fd92434..a2b1506f9c 100644
--- a/compat/win32/trace2_win32_process_info.c
+++ b/compat/win32/trace2_win32_process_info.c
@@ -1,5 +1,7 @@
-#include "../../cache.h"
+#include "../../git-compat-util.h"
#include "../../json-writer.h"
+#include "../../repository.h"
+#include "../../trace2.h"
#include "lazyload.h"
#include <Psapi.h>
#include <tlHelp32.h>
diff --git a/config.c b/config.c
index 00090a32fc..e08e2332a6 100644
--- a/config.c
+++ b/config.c
@@ -5,24 +5,42 @@
* Copyright (C) Johannes Schindelin, 2005
*
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "advice.h"
+#include "alloc.h"
#include "date.h"
#include "branch.h"
#include "config.h"
+#include "convert.h"
#include "environment.h"
+#include "gettext.h"
+#include "ident.h"
#include "repository.h"
#include "lockfile.h"
+#include "mailmap.h"
#include "exec-cmd.h"
#include "strbuf.h"
#include "quote.h"
#include "hashmap.h"
#include "string-list.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "pager.h"
+#include "path.h"
#include "utf8.h"
#include "dir.h"
#include "color.h"
+#include "replace-object.h"
#include "refs.h"
+#include "setup.h"
+#include "strvec.h"
+#include "trace2.h"
+#include "wildmatch.h"
#include "worktree.h"
+#include "ws.h"
+#include "wrapper.h"
+#include "write-or-die.h"
struct config_source {
struct config_source *prev;
@@ -49,34 +67,79 @@ struct config_source {
int (*do_ungetc)(int c, struct config_source *conf);
long (*do_ftell)(struct config_source *c);
};
+#define CONFIG_SOURCE_INIT { 0 }
+struct config_reader {
+ /*
+ * These members record the "current" config source, which can be
+ * accessed by parsing callbacks.
+ *
+ * The "source" variable will be non-NULL only when we are actually
+ * parsing a real config source (file, blob, cmdline, etc).
+ *
+ * The "config_kvi" variable will be non-NULL only when we are feeding
+ * cached config from a configset into a callback.
+ *
+ * They cannot be non-NULL at the same time. If they are both NULL, then
+ * we aren't parsing anything (and depending on the function looking at
+ * the variables, it's either a bug for it to be called in the first
+ * place, or it's a function which can be reused for non-config
+ * purposes, and should fall back to some sane behavior).
+ */
+ struct config_source *source;
+ struct key_value_info *config_kvi;
+ /*
+ * The "scope" of the current config source being parsed (repo, global,
+ * etc). Like "source", this is only set when parsing a config source.
+ * It's not part of "source" because it transcends a single file (i.e.,
+ * a file included from .git/config is still in "repo" scope).
+ *
+ * When iterating through a configset, the equivalent value is
+ * "config_kvi.scope" (see above).
+ */
+ enum config_scope parsing_scope;
+};
/*
- * These variables record the "current" config source, which
- * can be accessed by parsing callbacks.
- *
- * The "cf" variable will be non-NULL only when we are actually parsing a real
- * config source (file, blob, cmdline, etc).
- *
- * The "current_config_kvi" variable will be non-NULL only when we are feeding
- * cached config from a configset into a callback.
- *
- * They should generally never be non-NULL at the same time. If they are both
- * NULL, then we aren't parsing anything (and depending on the function looking
- * at the variables, it's either a bug for it to be called in the first place,
- * or it's a function which can be reused for non-config purposes, and should
- * fall back to some sane behavior).
+ * Where possible, prefer to accept "struct config_reader" as an arg than to use
+ * "the_reader". "the_reader" should only be used if that is infeasible, e.g. in
+ * a public function.
*/
-static struct config_source *cf;
-static struct key_value_info *current_config_kvi;
+static struct config_reader the_reader;
-/*
- * Similar to the variables above, this gives access to the "scope" of the
- * current value (repo, global, etc). For cached values, it can be found via
- * the current_config_kvi as above. During parsing, the current value can be
- * found in this variable. It's not part of "cf" because it transcends a single
- * file (i.e., a file included from .git/config is still in "repo" scope).
- */
-static enum config_scope current_parsing_scope;
+static inline void config_reader_push_source(struct config_reader *reader,
+ struct config_source *top)
+{
+ if (reader->config_kvi)
+ BUG("source should not be set while iterating a config set");
+ top->prev = reader->source;
+ reader->source = top;
+}
+
+static inline struct config_source *config_reader_pop_source(struct config_reader *reader)
+{
+ struct config_source *ret;
+ if (!reader->source)
+ BUG("tried to pop config source, but we weren't reading config");
+ ret = reader->source;
+ reader->source = reader->source->prev;
+ return ret;
+}
+
+static inline void config_reader_set_kvi(struct config_reader *reader,
+ struct key_value_info *kvi)
+{
+ if (kvi && (reader->source || reader->parsing_scope))
+ BUG("kvi should not be set while parsing a config source");
+ reader->config_kvi = kvi;
+}
+
+static inline void config_reader_set_scope(struct config_reader *reader,
+ enum config_scope scope)
+{
+ if (scope && reader->config_kvi)
+ BUG("scope should only be set when iterating through a config source");
+ reader->parsing_scope = scope;
+}
static int pack_compression_seen;
static int zlib_compression_seen;
@@ -139,6 +202,7 @@ struct config_include_data {
void *data;
const struct config_options *opts;
struct git_config_source *config_source;
+ struct config_reader *config_reader;
/*
* All remote URLs discovered when reading all config files.
@@ -156,7 +220,8 @@ static const char include_depth_advice[] = N_(
"from\n"
" %s\n"
"This might be due to circular includes.");
-static int handle_path_include(const char *path, struct config_include_data *inc)
+static int handle_path_include(struct config_source *cs, const char *path,
+ struct config_include_data *inc)
{
int ret = 0;
struct strbuf buf = STRBUF_INIT;
@@ -177,14 +242,14 @@ static int handle_path_include(const char *path, struct config_include_data *inc
if (!is_absolute_path(path)) {
char *slash;
- if (!cf || !cf->path) {
+ if (!cs || !cs->path) {
ret = error(_("relative config includes must come from files"));
goto cleanup;
}
- slash = find_last_dir_sep(cf->path);
+ slash = find_last_dir_sep(cs->path);
if (slash)
- strbuf_add(&buf, cf->path, slash - cf->path + 1);
+ strbuf_add(&buf, cs->path, slash - cs->path + 1);
strbuf_addstr(&buf, path);
path = buf.buf;
}
@@ -192,8 +257,8 @@ static int handle_path_include(const char *path, struct config_include_data *inc
if (!access_or_die(path, R_OK, 0)) {
if (++inc->depth > MAX_INCLUDE_DEPTH)
die(_(include_depth_advice), MAX_INCLUDE_DEPTH, path,
- !cf ? "<unknown>" :
- cf->name ? cf->name :
+ !cs ? "<unknown>" :
+ cs->name ? cs->name :
"the command line");
ret = git_config_from_file(git_config_include, path, inc);
inc->depth--;
@@ -210,7 +275,8 @@ static void add_trailing_starstar_for_dir(struct strbuf *pat)
strbuf_addstr(pat, "**");
}
-static int prepare_include_condition_pattern(struct strbuf *pat)
+static int prepare_include_condition_pattern(struct config_source *cs,
+ struct strbuf *pat)
{
struct strbuf path = STRBUF_INIT;
char *expanded;
@@ -226,11 +292,11 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
if (pat->buf[0] == '.' && is_dir_sep(pat->buf[1])) {
const char *slash;
- if (!cf || !cf->path)
+ if (!cs || !cs->path)
return error(_("relative config include "
"conditionals must come from files"));
- strbuf_realpath(&path, cf->path, 1);
+ strbuf_realpath(&path, cs->path, 1);
slash = find_last_dir_sep(path.buf);
if (!slash)
BUG("how is this possible?");
@@ -245,7 +311,8 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
return prefix;
}
-static int include_by_gitdir(const struct config_options *opts,
+static int include_by_gitdir(struct config_source *cs,
+ const struct config_options *opts,
const char *cond, size_t cond_len, int icase)
{
struct strbuf text = STRBUF_INIT;
@@ -261,7 +328,7 @@ static int include_by_gitdir(const struct config_options *opts,
strbuf_realpath(&text, git_dir, 1);
strbuf_add(&pattern, cond, cond_len);
- prefix = prepare_include_condition_pattern(&pattern);
+ prefix = prepare_include_condition_pattern(cs, &pattern);
again:
if (prefix < 0)
@@ -342,24 +409,18 @@ static void populate_remote_urls(struct config_include_data *inc)
{
struct config_options opts;
- struct config_source *store_cf = cf;
- struct key_value_info *store_kvi = current_config_kvi;
- enum config_scope store_scope = current_parsing_scope;
+ enum config_scope store_scope = inc->config_reader->parsing_scope;
opts = *inc->opts;
opts.unconditional_remote_url = 1;
- cf = NULL;
- current_config_kvi = NULL;
- current_parsing_scope = 0;
+ config_reader_set_scope(inc->config_reader, 0);
inc->remote_urls = xmalloc(sizeof(*inc->remote_urls));
string_list_init_dup(inc->remote_urls);
config_with_options(add_remote_url, inc->remote_urls, inc->config_source, &opts);
- cf = store_cf;
- current_config_kvi = store_kvi;
- current_parsing_scope = store_scope;
+ config_reader_set_scope(inc->config_reader, store_scope);
}
static int forbid_remote_url(const char *var, const char *value UNUSED,
@@ -406,15 +467,16 @@ static int include_by_remote_url(struct config_include_data *inc,
inc->remote_urls);
}
-static int include_condition_is_true(struct config_include_data *inc,
+static int include_condition_is_true(struct config_source *cs,
+ struct config_include_data *inc,
const char *cond, size_t cond_len)
{
const struct config_options *opts = inc->opts;
if (skip_prefix_mem(cond, cond_len, "gitdir:", &cond, &cond_len))
- return include_by_gitdir(opts, cond, cond_len, 0);
+ return include_by_gitdir(cs, opts, cond, cond_len, 0);
else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
- return include_by_gitdir(opts, cond, cond_len, 1);
+ return include_by_gitdir(cs, opts, cond, cond_len, 1);
else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
return include_by_branch(cond, cond_len);
else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond,
@@ -428,6 +490,7 @@ static int include_condition_is_true(struct config_include_data *inc,
static int git_config_include(const char *var, const char *value, void *data)
{
struct config_include_data *inc = data;
+ struct config_source *cs = inc->config_reader->source;
const char *cond, *key;
size_t cond_len;
int ret;
@@ -441,16 +504,16 @@ static int git_config_include(const char *var, const char *value, void *data)
return ret;
if (!strcmp(var, "include.path"))
- ret = handle_path_include(value, inc);
+ ret = handle_path_include(cs, value, inc);
if (!parse_config_key(var, "includeif", &cond, &cond_len, &key) &&
- cond && include_condition_is_true(inc, cond, cond_len) &&
+ cond && include_condition_is_true(cs, inc, cond, cond_len) &&
!strcmp(key, "path")) {
config_fn_t old_fn = inc->fn;
if (inc->opts->unconditional_remote_url)
inc->fn = forbid_remote_url;
- ret = handle_path_include(value, inc);
+ ret = handle_path_include(cs, value, inc);
inc->fn = old_fn;
}
@@ -710,12 +773,10 @@ int git_config_from_parameters(config_fn_t fn, void *data)
struct strvec to_free = STRVEC_INIT;
int ret = 0;
char *envw = NULL;
- struct config_source source;
+ struct config_source source = CONFIG_SOURCE_INIT;
- memset(&source, 0, sizeof(source));
- source.prev = cf;
source.origin_type = CONFIG_ORIGIN_CMDLINE;
- cf = &source;
+ config_reader_push_source(&the_reader, &source);
env = getenv(CONFIG_COUNT_ENVIRONMENT);
if (env) {
@@ -773,25 +834,25 @@ out:
strbuf_release(&envvar);
strvec_clear(&to_free);
free(envw);
- cf = source.prev;
+ config_reader_pop_source(&the_reader);
return ret;
}
-static int get_next_char(void)
+static int get_next_char(struct config_source *cs)
{
- int c = cf->do_fgetc(cf);
+ int c = cs->do_fgetc(cs);
if (c == '\r') {
/* DOS like systems */
- c = cf->do_fgetc(cf);
+ c = cs->do_fgetc(cs);
if (c != '\n') {
if (c != EOF)
- cf->do_ungetc(c, cf);
+ cs->do_ungetc(c, cs);
c = '\r';
}
}
- if (c != EOF && ++cf->total_len > INT_MAX) {
+ if (c != EOF && ++cs->total_len > INT_MAX) {
/*
* This is an absurdly long config file; refuse to parse
* further in order to protect downstream code from integer
@@ -799,38 +860,38 @@ static int get_next_char(void)
* but we can mark EOF and put trash in the return value,
* which will trigger a parse error.
*/
- cf->eof = 1;
+ cs->eof = 1;
return 0;
}
if (c == '\n')
- cf->linenr++;
+ cs->linenr++;
if (c == EOF) {
- cf->eof = 1;
- cf->linenr++;
+ cs->eof = 1;
+ cs->linenr++;
c = '\n';
}
return c;
}
-static char *parse_value(void)
+static char *parse_value(struct config_source *cs)
{
int quote = 0, comment = 0, space = 0;
- strbuf_reset(&cf->value);
+ strbuf_reset(&cs->value);
for (;;) {
- int c = get_next_char();
+ int c = get_next_char(cs);
if (c == '\n') {
if (quote) {
- cf->linenr--;
+ cs->linenr--;
return NULL;
}
- return cf->value.buf;
+ return cs->value.buf;
}
if (comment)
continue;
if (isspace(c) && !quote) {
- if (cf->value.len)
+ if (cs->value.len)
space++;
continue;
}
@@ -841,9 +902,9 @@ static char *parse_value(void)
}
}
for (; space; space--)
- strbuf_addch(&cf->value, ' ');
+ strbuf_addch(&cs->value, ' ');
if (c == '\\') {
- c = get_next_char();
+ c = get_next_char(cs);
switch (c) {
case '\n':
continue;
@@ -863,18 +924,19 @@ static char *parse_value(void)
default:
return NULL;
}
- strbuf_addch(&cf->value, c);
+ strbuf_addch(&cs->value, c);
continue;
}
if (c == '"') {
quote = 1-quote;
continue;
}
- strbuf_addch(&cf->value, c);
+ strbuf_addch(&cs->value, c);
}
}
-static int get_value(config_fn_t fn, void *data, struct strbuf *name)
+static int get_value(struct config_source *cs, config_fn_t fn, void *data,
+ struct strbuf *name)
{
int c;
char *value;
@@ -882,8 +944,8 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
/* Get the full name */
for (;;) {
- c = get_next_char();
- if (cf->eof)
+ c = get_next_char(cs);
+ if (cs->eof)
break;
if (!iskeychar(c))
break;
@@ -891,13 +953,13 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
}
while (c == ' ' || c == '\t')
- c = get_next_char();
+ c = get_next_char(cs);
value = NULL;
if (c != '\n') {
if (c != '=')
return -1;
- value = parse_value();
+ value = parse_value(cs);
if (!value)
return -1;
}
@@ -906,20 +968,21 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
* the line we just parsed during the call to fn to get
* accurate line number in error messages.
*/
- cf->linenr--;
+ cs->linenr--;
ret = fn(name->buf, value, data);
if (ret >= 0)
- cf->linenr++;
+ cs->linenr++;
return ret;
}
-static int get_extended_base_var(struct strbuf *name, int c)
+static int get_extended_base_var(struct config_source *cs, struct strbuf *name,
+ int c)
{
- cf->subsection_case_sensitive = 0;
+ cs->subsection_case_sensitive = 0;
do {
if (c == '\n')
goto error_incomplete_line;
- c = get_next_char();
+ c = get_next_char(cs);
} while (isspace(c));
/* We require the format to be '[base "extension"]' */
@@ -928,13 +991,13 @@ static int get_extended_base_var(struct strbuf *name, int c)
strbuf_addch(name, '.');
for (;;) {
- int c = get_next_char();
+ int c = get_next_char(cs);
if (c == '\n')
goto error_incomplete_line;
if (c == '"')
break;
if (c == '\\') {
- c = get_next_char();
+ c = get_next_char(cs);
if (c == '\n')
goto error_incomplete_line;
}
@@ -942,25 +1005,25 @@ static int get_extended_base_var(struct strbuf *name, int c)
}
/* Final ']' */
- if (get_next_char() != ']')
+ if (get_next_char(cs) != ']')
return -1;
return 0;
error_incomplete_line:
- cf->linenr--;
+ cs->linenr--;
return -1;
}
-static int get_base_var(struct strbuf *name)
+static int get_base_var(struct config_source *cs, struct strbuf *name)
{
- cf->subsection_case_sensitive = 1;
+ cs->subsection_case_sensitive = 1;
for (;;) {
- int c = get_next_char();
- if (cf->eof)
+ int c = get_next_char(cs);
+ if (cs->eof)
return -1;
if (c == ']')
return 0;
if (isspace(c))
- return get_extended_base_var(name, c);
+ return get_extended_base_var(cs, name, c);
if (!iskeychar(c) && c != '.')
return -1;
strbuf_addch(name, tolower(c));
@@ -973,7 +1036,8 @@ struct parse_event_data {
const struct config_options *opts;
};
-static int do_event(enum config_event_t type, struct parse_event_data *data)
+static int do_event(struct config_source *cs, enum config_event_t type,
+ struct parse_event_data *data)
{
size_t offset;
@@ -984,7 +1048,7 @@ static int do_event(enum config_event_t type, struct parse_event_data *data)
data->previous_type == type)
return 0;
- offset = cf->do_ftell(cf);
+ offset = cs->do_ftell(cs);
/*
* At EOF, the parser always "inserts" an extra '\n', therefore
* the end offset of the event is the current file position, otherwise
@@ -1004,12 +1068,12 @@ static int do_event(enum config_event_t type, struct parse_event_data *data)
return 0;
}
-static int git_parse_source(config_fn_t fn, void *data,
- const struct config_options *opts)
+static int git_parse_source(struct config_source *cs, config_fn_t fn,
+ void *data, const struct config_options *opts)
{
int comment = 0;
size_t baselen = 0;
- struct strbuf *var = &cf->var;
+ struct strbuf *var = &cs->var;
int error_return = 0;
char *error_msg = NULL;
@@ -1024,7 +1088,7 @@ static int git_parse_source(config_fn_t fn, void *data,
for (;;) {
int c;
- c = get_next_char();
+ c = get_next_char(cs);
if (bomptr && *bomptr) {
/* We are at the file beginning; skip UTF8-encoded BOM
* if present. Sane editors won't put this in on their
@@ -1041,12 +1105,12 @@ static int git_parse_source(config_fn_t fn, void *data,
}
}
if (c == '\n') {
- if (cf->eof) {
- if (do_event(CONFIG_EVENT_EOF, &event_data) < 0)
+ if (cs->eof) {
+ if (do_event(cs, CONFIG_EVENT_EOF, &event_data) < 0)
return -1;
return 0;
}
- if (do_event(CONFIG_EVENT_WHITESPACE, &event_data) < 0)
+ if (do_event(cs, CONFIG_EVENT_WHITESPACE, &event_data) < 0)
return -1;
comment = 0;
continue;
@@ -1054,23 +1118,23 @@ static int git_parse_source(config_fn_t fn, void *data,
if (comment)
continue;
if (isspace(c)) {
- if (do_event(CONFIG_EVENT_WHITESPACE, &event_data) < 0)
+ if (do_event(cs, CONFIG_EVENT_WHITESPACE, &event_data) < 0)
return -1;
continue;
}
if (c == '#' || c == ';') {
- if (do_event(CONFIG_EVENT_COMMENT, &event_data) < 0)
+ if (do_event(cs, CONFIG_EVENT_COMMENT, &event_data) < 0)
return -1;
comment = 1;
continue;
}
if (c == '[') {
- if (do_event(CONFIG_EVENT_SECTION, &event_data) < 0)
+ if (do_event(cs, CONFIG_EVENT_SECTION, &event_data) < 0)
return -1;
/* Reset prior to determining a new stem */
strbuf_reset(var);
- if (get_base_var(var) < 0 || var->len < 1)
+ if (get_base_var(cs, var) < 0 || var->len < 1)
break;
strbuf_addch(var, '.');
baselen = var->len;
@@ -1079,7 +1143,7 @@ static int git_parse_source(config_fn_t fn, void *data,
if (!isalpha(c))
break;
- if (do_event(CONFIG_EVENT_ENTRY, &event_data) < 0)
+ if (do_event(cs, CONFIG_EVENT_ENTRY, &event_data) < 0)
return -1;
/*
@@ -1089,42 +1153,42 @@ static int git_parse_source(config_fn_t fn, void *data,
*/
strbuf_setlen(var, baselen);
strbuf_addch(var, tolower(c));
- if (get_value(fn, data, var) < 0)
+ if (get_value(cs, fn, data, var) < 0)
break;
}
- if (do_event(CONFIG_EVENT_ERROR, &event_data) < 0)
+ if (do_event(cs, CONFIG_EVENT_ERROR, &event_data) < 0)
return -1;
- switch (cf->origin_type) {
+ switch (cs->origin_type) {
case CONFIG_ORIGIN_BLOB:
error_msg = xstrfmt(_("bad config line %d in blob %s"),
- cf->linenr, cf->name);
+ cs->linenr, cs->name);
break;
case CONFIG_ORIGIN_FILE:
error_msg = xstrfmt(_("bad config line %d in file %s"),
- cf->linenr, cf->name);
+ cs->linenr, cs->name);
break;
case CONFIG_ORIGIN_STDIN:
error_msg = xstrfmt(_("bad config line %d in standard input"),
- cf->linenr);
+ cs->linenr);
break;
case CONFIG_ORIGIN_SUBMODULE_BLOB:
error_msg = xstrfmt(_("bad config line %d in submodule-blob %s"),
- cf->linenr, cf->name);
+ cs->linenr, cs->name);
break;
case CONFIG_ORIGIN_CMDLINE:
error_msg = xstrfmt(_("bad config line %d in command line %s"),
- cf->linenr, cf->name);
+ cs->linenr, cs->name);
break;
default:
error_msg = xstrfmt(_("bad config line %d in %s"),
- cf->linenr, cf->name);
+ cs->linenr, cs->name);
}
switch (opts && opts->error_action ?
opts->error_action :
- cf->default_error_action) {
+ cs->default_error_action) {
case CONFIG_ERROR_DIE:
die("%s", error_msg);
break;
@@ -1265,38 +1329,48 @@ int git_parse_ssize_t(const char *value, ssize_t *ret)
return 1;
}
+static int reader_config_name(struct config_reader *reader, const char **out);
+static int reader_origin_type(struct config_reader *reader,
+ enum config_origin_type *type);
NORETURN
-static void die_bad_number(const char *name, const char *value)
+static void die_bad_number(struct config_reader *reader, const char *name,
+ const char *value)
{
const char *error_type = (errno == ERANGE) ?
N_("out of range") : N_("invalid unit");
const char *bad_numeric = N_("bad numeric config value '%s' for '%s': %s");
+ const char *config_name = NULL;
+ enum config_origin_type config_origin = CONFIG_ORIGIN_UNKNOWN;
if (!value)
value = "";
- if (!(cf && cf->name))
+ /* Ignoring the return value is okay since we handle missing values. */
+ reader_config_name(reader, &config_name);
+ reader_origin_type(reader, &config_origin);
+
+ if (!config_name)
die(_(bad_numeric), value, name, _(error_type));
- switch (cf->origin_type) {
+ switch (config_origin) {
case CONFIG_ORIGIN_BLOB:
die(_("bad numeric config value '%s' for '%s' in blob %s: %s"),
- value, name, cf->name, _(error_type));
+ value, name, config_name, _(error_type));
case CONFIG_ORIGIN_FILE:
die(_("bad numeric config value '%s' for '%s' in file %s: %s"),
- value, name, cf->name, _(error_type));
+ value, name, config_name, _(error_type));
case CONFIG_ORIGIN_STDIN:
die(_("bad numeric config value '%s' for '%s' in standard input: %s"),
value, name, _(error_type));
case CONFIG_ORIGIN_SUBMODULE_BLOB:
die(_("bad numeric config value '%s' for '%s' in submodule-blob %s: %s"),
- value, name, cf->name, _(error_type));
+ value, name, config_name, _(error_type));
case CONFIG_ORIGIN_CMDLINE:
die(_("bad numeric config value '%s' for '%s' in command line %s: %s"),
- value, name, cf->name, _(error_type));
+ value, name, config_name, _(error_type));
default:
die(_("bad numeric config value '%s' for '%s' in %s: %s"),
- value, name, cf->name, _(error_type));
+ value, name, config_name, _(error_type));
}
}
@@ -1304,7 +1378,7 @@ int git_config_int(const char *name, const char *value)
{
int ret;
if (!git_parse_int(value, &ret))
- die_bad_number(name, value);
+ die_bad_number(&the_reader, name, value);
return ret;
}
@@ -1312,7 +1386,7 @@ int64_t git_config_int64(const char *name, const char *value)
{
int64_t ret;
if (!git_parse_int64(value, &ret))
- die_bad_number(name, value);
+ die_bad_number(&the_reader, name, value);
return ret;
}
@@ -1320,7 +1394,7 @@ unsigned long git_config_ulong(const char *name, const char *value)
{
unsigned long ret;
if (!git_parse_ulong(value, &ret))
- die_bad_number(name, value);
+ die_bad_number(&the_reader, name, value);
return ret;
}
@@ -1328,7 +1402,7 @@ ssize_t git_config_ssize_t(const char *name, const char *value)
{
ssize_t ret;
if (!git_parse_ssize_t(value, &ret))
- die_bad_number(name, value);
+ die_bad_number(&the_reader, name, value);
return ret;
}
@@ -1683,7 +1757,7 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
comment_line_char = value[0];
auto_comment_line_char = 0;
} else
- return error(_("core.commentChar should only be one character"));
+ return error(_("core.commentChar should only be one ASCII character"));
return 0;
}
@@ -1934,36 +2008,37 @@ int git_default_config(const char *var, const char *value, void *cb)
* fgetc, ungetc, ftell of top need to be initialized before calling
* this function.
*/
-static int do_config_from(struct config_source *top, config_fn_t fn, void *data,
+static int do_config_from(struct config_reader *reader,
+ struct config_source *top, config_fn_t fn, void *data,
const struct config_options *opts)
{
int ret;
/* push config-file parsing state stack */
- top->prev = cf;
top->linenr = 1;
top->eof = 0;
top->total_len = 0;
strbuf_init(&top->value, 1024);
strbuf_init(&top->var, 1024);
- cf = top;
+ config_reader_push_source(reader, top);
- ret = git_parse_source(fn, data, opts);
+ ret = git_parse_source(top, fn, data, opts);
/* pop config-file parsing state stack */
strbuf_release(&top->value);
strbuf_release(&top->var);
- cf = top->prev;
+ config_reader_pop_source(reader);
return ret;
}
-static int do_config_from_file(config_fn_t fn,
- const enum config_origin_type origin_type,
- const char *name, const char *path, FILE *f,
- void *data, const struct config_options *opts)
+static int do_config_from_file(struct config_reader *reader,
+ config_fn_t fn,
+ const enum config_origin_type origin_type,
+ const char *name, const char *path, FILE *f,
+ void *data, const struct config_options *opts)
{
- struct config_source top;
+ struct config_source top = CONFIG_SOURCE_INIT;
int ret;
top.u.file = f;
@@ -1976,15 +2051,15 @@ static int do_config_from_file(config_fn_t fn,
top.do_ftell = config_file_ftell;
flockfile(f);
- ret = do_config_from(&top, fn, data, opts);
+ ret = do_config_from(reader, &top, fn, data, opts);
funlockfile(f);
return ret;
}
static int git_config_from_stdin(config_fn_t fn, void *data)
{
- return do_config_from_file(fn, CONFIG_ORIGIN_STDIN, "", NULL, stdin,
- data, NULL);
+ return do_config_from_file(&the_reader, fn, CONFIG_ORIGIN_STDIN, "",
+ NULL, stdin, data, NULL);
}
int git_config_from_file_with_options(config_fn_t fn, const char *filename,
@@ -1998,8 +2073,8 @@ int git_config_from_file_with_options(config_fn_t fn, const char *filename,
BUG("filename cannot be NULL");
f = fopen_or_warn(filename, "r");
if (f) {
- ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename,
- filename, f, data, opts);
+ ret = do_config_from_file(&the_reader, fn, CONFIG_ORIGIN_FILE,
+ filename, filename, f, data, opts);
fclose(f);
}
return ret;
@@ -2015,7 +2090,7 @@ int git_config_from_mem(config_fn_t fn,
const char *name, const char *buf, size_t len,
void *data, const struct config_options *opts)
{
- struct config_source top;
+ struct config_source top = CONFIG_SOURCE_INIT;
top.u.buf.buf = buf;
top.u.buf.len = len;
@@ -2028,7 +2103,7 @@ int git_config_from_mem(config_fn_t fn,
top.do_ungetc = config_buf_ungetc;
top.do_ftell = config_buf_ftell;
- return do_config_from(&top, fn, data, opts);
+ return do_config_from(&the_reader, &top, fn, data, opts);
}
int git_config_from_blob_oid(config_fn_t fn,
@@ -2119,7 +2194,8 @@ int git_config_system(void)
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
}
-static int do_git_config_sequence(const struct config_options *opts,
+static int do_git_config_sequence(struct config_reader *reader,
+ const struct config_options *opts,
config_fn_t fn, void *data)
{
int ret = 0;
@@ -2127,7 +2203,7 @@ static int do_git_config_sequence(const struct config_options *opts,
char *xdg_config = NULL;
char *user_config = NULL;
char *repo_config;
- enum config_scope prev_parsing_scope = current_parsing_scope;
+ enum config_scope prev_parsing_scope = reader->parsing_scope;
if (opts->commondir)
repo_config = mkpathdup("%s/config", opts->commondir);
@@ -2136,13 +2212,13 @@ static int do_git_config_sequence(const struct config_options *opts,
else
repo_config = NULL;
- current_parsing_scope = CONFIG_SCOPE_SYSTEM;
+ config_reader_set_scope(reader, CONFIG_SCOPE_SYSTEM);
if (git_config_system() && system_config &&
!access_or_die(system_config, R_OK,
opts->system_gently ? ACCESS_EACCES_OK : 0))
ret += git_config_from_file(fn, system_config, data);
- current_parsing_scope = CONFIG_SCOPE_GLOBAL;
+ config_reader_set_scope(reader, CONFIG_SCOPE_GLOBAL);
git_global_config(&user_config, &xdg_config);
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
@@ -2151,12 +2227,12 @@ static int do_git_config_sequence(const struct config_options *opts,
if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
ret += git_config_from_file(fn, user_config, data);
- current_parsing_scope = CONFIG_SCOPE_LOCAL;
+ config_reader_set_scope(reader, CONFIG_SCOPE_LOCAL);
if (!opts->ignore_repo && repo_config &&
!access_or_die(repo_config, R_OK, 0))
ret += git_config_from_file(fn, repo_config, data);
- current_parsing_scope = CONFIG_SCOPE_WORKTREE;
+ config_reader_set_scope(reader, CONFIG_SCOPE_WORKTREE);
if (!opts->ignore_worktree && repository_format_worktree_config) {
char *path = git_pathdup("config.worktree");
if (!access_or_die(path, R_OK, 0))
@@ -2164,11 +2240,11 @@ static int do_git_config_sequence(const struct config_options *opts,
free(path);
}
- current_parsing_scope = CONFIG_SCOPE_COMMAND;
+ config_reader_set_scope(reader, CONFIG_SCOPE_COMMAND);
if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
die(_("unable to parse command-line config"));
- current_parsing_scope = prev_parsing_scope;
+ config_reader_set_scope(reader, prev_parsing_scope);
free(system_config);
free(xdg_config);
free(user_config);
@@ -2181,6 +2257,7 @@ int config_with_options(config_fn_t fn, void *data,
const struct config_options *opts)
{
struct config_include_data inc = CONFIG_INCLUDE_INIT;
+ enum config_scope prev_scope = the_reader.parsing_scope;
int ret;
if (opts->respect_includes) {
@@ -2188,12 +2265,13 @@ int config_with_options(config_fn_t fn, void *data,
inc.data = data;
inc.opts = opts;
inc.config_source = config_source;
+ inc.config_reader = &the_reader;
fn = git_config_include;
data = &inc;
}
if (config_source)
- current_parsing_scope = config_source->scope;
+ config_reader_set_scope(&the_reader, config_source->scope);
/*
* If we have a specific filename, use it. Otherwise, follow the
@@ -2209,36 +2287,38 @@ int config_with_options(config_fn_t fn, void *data,
ret = git_config_from_blob_ref(fn, repo, config_source->blob,
data);
} else {
- ret = do_git_config_sequence(opts, fn, data);
+ ret = do_git_config_sequence(&the_reader, opts, fn, data);
}
if (inc.remote_urls) {
string_list_clear(inc.remote_urls, 0);
FREE_AND_NULL(inc.remote_urls);
}
+ config_reader_set_scope(&the_reader, prev_scope);
return ret;
}
-static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
+static void configset_iter(struct config_reader *reader, struct config_set *set,
+ config_fn_t fn, void *data)
{
int i, value_index;
struct string_list *values;
struct config_set_element *entry;
- struct configset_list *list = &cs->list;
+ struct configset_list *list = &set->list;
for (i = 0; i < list->nr; i++) {
entry = list->items[i].e;
value_index = list->items[i].value_index;
values = &entry->value_list;
- current_config_kvi = values->items[value_index].util;
+ config_reader_set_kvi(reader, values->items[value_index].util);
if (fn(entry->key, values->items[value_index].string, data) < 0)
git_die_config_linenr(entry->key,
- current_config_kvi->filename,
- current_config_kvi->linenr);
+ reader->config_kvi->filename,
+ reader->config_kvi->linenr);
- current_config_kvi = NULL;
+ config_reader_set_kvi(reader, NULL);
}
}
@@ -2289,33 +2369,44 @@ void read_very_early_config(config_fn_t cb, void *data)
config_with_options(cb, data, NULL, &opts);
}
-static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
+RESULT_MUST_BE_USED
+static int configset_find_element(struct config_set *set, const char *key,
+ struct config_set_element **dest)
{
struct config_set_element k;
struct config_set_element *found_entry;
char *normalized_key;
+ int ret;
+
/*
* `key` may come from the user, so normalize it before using it
* for querying entries from the hashmap.
*/
- if (git_config_parse_key(key, &normalized_key, NULL))
- return NULL;
+ ret = git_config_parse_key(key, &normalized_key, NULL);
+ if (ret)
+ return ret;
hashmap_entry_init(&k.ent, strhash(normalized_key));
k.key = normalized_key;
- found_entry = hashmap_get_entry(&cs->config_hash, &k, ent, NULL);
+ found_entry = hashmap_get_entry(&set->config_hash, &k, ent, NULL);
free(normalized_key);
- return found_entry;
+ *dest = found_entry;
+ return 0;
}
-static int configset_add_value(struct config_set *cs, const char *key, const char *value)
+static int configset_add_value(struct config_reader *reader,
+ struct config_set *set, const char *key,
+ const char *value)
{
struct config_set_element *e;
struct string_list_item *si;
struct configset_list_item *l_item;
struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
+ int ret;
- e = configset_find_element(cs, key);
+ ret = configset_find_element(set, key, &e);
+ if (ret)
+ return ret;
/*
* Since the keys are being fed by git_config*() callback mechanism, they
* are already normalized. So simply add them without any further munging.
@@ -2325,28 +2416,28 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
hashmap_entry_init(&e->ent, strhash(key));
e->key = xstrdup(key);
string_list_init_dup(&e->value_list);
- hashmap_add(&cs->config_hash, &e->ent);
+ hashmap_add(&set->config_hash, &e->ent);
}
si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));
- ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
- l_item = &cs->list.items[cs->list.nr++];
+ ALLOC_GROW(set->list.items, set->list.nr + 1, set->list.alloc);
+ l_item = &set->list.items[set->list.nr++];
l_item->e = e;
l_item->value_index = e->value_list.nr - 1;
- if (!cf)
+ if (!reader->source)
BUG("configset_add_value has no source");
- if (cf->name) {
- kv_info->filename = strintern(cf->name);
- kv_info->linenr = cf->linenr;
- kv_info->origin_type = cf->origin_type;
+ if (reader->source->name) {
+ kv_info->filename = strintern(reader->source->name);
+ kv_info->linenr = reader->source->linenr;
+ kv_info->origin_type = reader->source->origin_type;
} else {
/* for values read from `git_config_from_parameters()` */
kv_info->filename = NULL;
kv_info->linenr = -1;
kv_info->origin_type = CONFIG_ORIGIN_CMDLINE;
}
- kv_info->scope = current_parsing_scope;
+ kv_info->scope = reader->parsing_scope;
si->util = kv_info;
return 0;
@@ -2365,84 +2456,134 @@ static int config_set_element_cmp(const void *cmp_data UNUSED,
return strcmp(e1->key, e2->key);
}
-void git_configset_init(struct config_set *cs)
+void git_configset_init(struct config_set *set)
{
- hashmap_init(&cs->config_hash, config_set_element_cmp, NULL, 0);
- cs->hash_initialized = 1;
- cs->list.nr = 0;
- cs->list.alloc = 0;
- cs->list.items = NULL;
+ hashmap_init(&set->config_hash, config_set_element_cmp, NULL, 0);
+ set->hash_initialized = 1;
+ set->list.nr = 0;
+ set->list.alloc = 0;
+ set->list.items = NULL;
}
-void git_configset_clear(struct config_set *cs)
+void git_configset_clear(struct config_set *set)
{
struct config_set_element *entry;
struct hashmap_iter iter;
- if (!cs->hash_initialized)
+ if (!set->hash_initialized)
return;
- hashmap_for_each_entry(&cs->config_hash, &iter, entry,
+ hashmap_for_each_entry(&set->config_hash, &iter, entry,
ent /* member name */) {
free(entry->key);
string_list_clear(&entry->value_list, 1);
}
- hashmap_clear_and_free(&cs->config_hash, struct config_set_element, ent);
- cs->hash_initialized = 0;
- free(cs->list.items);
- cs->list.nr = 0;
- cs->list.alloc = 0;
- cs->list.items = NULL;
+ hashmap_clear_and_free(&set->config_hash, struct config_set_element, ent);
+ set->hash_initialized = 0;
+ free(set->list.items);
+ set->list.nr = 0;
+ set->list.alloc = 0;
+ set->list.items = NULL;
}
+struct configset_add_data {
+ struct config_set *config_set;
+ struct config_reader *config_reader;
+};
+#define CONFIGSET_ADD_INIT { 0 }
+
static int config_set_callback(const char *key, const char *value, void *cb)
{
- struct config_set *cs = cb;
- configset_add_value(cs, key, value);
+ struct configset_add_data *data = cb;
+ configset_add_value(data->config_reader, data->config_set, key, value);
return 0;
}
-int git_configset_add_file(struct config_set *cs, const char *filename)
+int git_configset_add_file(struct config_set *set, const char *filename)
{
- return git_config_from_file(config_set_callback, filename, cs);
+ struct configset_add_data data = CONFIGSET_ADD_INIT;
+ data.config_reader = &the_reader;
+ data.config_set = set;
+ return git_config_from_file(config_set_callback, filename, &data);
}
-int git_configset_get_value(struct config_set *cs, const char *key, const char **value)
+int git_configset_get_value(struct config_set *set, const char *key, const char **value)
{
const struct string_list *values = NULL;
+ int ret;
+
/*
* Follows "last one wins" semantic, i.e., if there are multiple matches for the
* queried key in the files of the configset, the value returned will be the last
* value in the value list for that key.
*/
- values = git_configset_get_value_multi(cs, key);
+ if ((ret = git_configset_get_value_multi(set, key, &values)))
+ return ret;
- if (!values)
- return 1;
assert(values->nr > 0);
*value = values->items[values->nr - 1].string;
return 0;
}
-const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)
+int git_configset_get_value_multi(struct config_set *set, const char *key,
+ const struct string_list **dest)
{
- struct config_set_element *e = configset_find_element(cs, key);
- return e ? &e->value_list : NULL;
+ struct config_set_element *e;
+ int ret;
+
+ if ((ret = configset_find_element(set, key, &e)))
+ return ret;
+ else if (!e)
+ return 1;
+ *dest = &e->value_list;
+
+ return 0;
}
-int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
+static int check_multi_string(struct string_list_item *item, void *util)
+{
+ return item->string ? 0 : config_error_nonbool(util);
+}
+
+int git_configset_get_string_multi(struct config_set *cs, const char *key,
+ const struct string_list **dest)
+{
+ int ret;
+
+ if ((ret = git_configset_get_value_multi(cs, key, dest)))
+ return ret;
+ if ((ret = for_each_string_list((struct string_list *)*dest,
+ check_multi_string, (void *)key)))
+ return ret;
+
+ return 0;
+}
+
+int git_configset_get(struct config_set *set, const char *key)
+{
+ struct config_set_element *e;
+ int ret;
+
+ if ((ret = configset_find_element(set, key, &e)))
+ return ret;
+ else if (!e)
+ return 1;
+ return 0;
+}
+
+int git_configset_get_string(struct config_set *set, const char *key, char **dest)
{
const char *value;
- if (!git_configset_get_value(cs, key, &value))
+ if (!git_configset_get_value(set, key, &value))
return git_config_string((const char **)dest, key, value);
else
return 1;
}
-static int git_configset_get_string_tmp(struct config_set *cs, const char *key,
+static int git_configset_get_string_tmp(struct config_set *set, const char *key,
const char **dest)
{
const char *value;
- if (!git_configset_get_value(cs, key, &value)) {
+ if (!git_configset_get_value(set, key, &value)) {
if (!value)
return config_error_nonbool(key);
*dest = value;
@@ -2452,51 +2593,51 @@ static int git_configset_get_string_tmp(struct config_set *cs, const char *key,
}
}
-int git_configset_get_int(struct config_set *cs, const char *key, int *dest)
+int git_configset_get_int(struct config_set *set, const char *key, int *dest)
{
const char *value;
- if (!git_configset_get_value(cs, key, &value)) {
+ if (!git_configset_get_value(set, key, &value)) {
*dest = git_config_int(key, value);
return 0;
} else
return 1;
}
-int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest)
+int git_configset_get_ulong(struct config_set *set, const char *key, unsigned long *dest)
{
const char *value;
- if (!git_configset_get_value(cs, key, &value)) {
+ if (!git_configset_get_value(set, key, &value)) {
*dest = git_config_ulong(key, value);
return 0;
} else
return 1;
}
-int git_configset_get_bool(struct config_set *cs, const char *key, int *dest)
+int git_configset_get_bool(struct config_set *set, const char *key, int *dest)
{
const char *value;
- if (!git_configset_get_value(cs, key, &value)) {
+ if (!git_configset_get_value(set, key, &value)) {
*dest = git_config_bool(key, value);
return 0;
} else
return 1;
}
-int git_configset_get_bool_or_int(struct config_set *cs, const char *key,
+int git_configset_get_bool_or_int(struct config_set *set, const char *key,
int *is_bool, int *dest)
{
const char *value;
- if (!git_configset_get_value(cs, key, &value)) {
+ if (!git_configset_get_value(set, key, &value)) {
*dest = git_config_bool_or_int(key, value, is_bool);
return 0;
} else
return 1;
}
-int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest)
+int git_configset_get_maybe_bool(struct config_set *set, const char *key, int *dest)
{
const char *value;
- if (!git_configset_get_value(cs, key, &value)) {
+ if (!git_configset_get_value(set, key, &value)) {
*dest = git_parse_maybe_bool(value);
if (*dest == -1)
return -1;
@@ -2505,10 +2646,10 @@ int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *de
return 1;
}
-int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest)
+int git_configset_get_pathname(struct config_set *set, const char *key, const char **dest)
{
const char *value;
- if (!git_configset_get_value(cs, key, &value))
+ if (!git_configset_get_value(set, key, &value))
return git_config_pathname(dest, key, value);
else
return 1;
@@ -2518,6 +2659,7 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha
static void repo_read_config(struct repository *repo)
{
struct config_options opts = { 0 };
+ struct configset_add_data data = CONFIGSET_ADD_INIT;
opts.respect_includes = 1;
opts.commondir = repo->commondir;
@@ -2529,8 +2671,10 @@ static void repo_read_config(struct repository *repo)
git_configset_clear(repo->config);
git_configset_init(repo->config);
+ data.config_set = repo->config;
+ data.config_reader = &the_reader;
- if (config_with_options(config_set_callback, repo->config, NULL, &opts) < 0)
+ if (config_with_options(config_set_callback, &data, NULL, &opts) < 0)
/*
* config_with_options() normally returns only
* zero, as most errors are fatal, and
@@ -2562,7 +2706,13 @@ static void repo_config_clear(struct repository *repo)
void repo_config(struct repository *repo, config_fn_t fn, void *data)
{
git_config_check_init(repo);
- configset_iter(repo->config, fn, data);
+ configset_iter(&the_reader, repo->config, fn, data);
+}
+
+int repo_config_get(struct repository *repo, const char *key)
+{
+ git_config_check_init(repo);
+ return git_configset_get(repo->config, key);
}
int repo_config_get_value(struct repository *repo,
@@ -2572,11 +2722,18 @@ int repo_config_get_value(struct repository *repo,
return git_configset_get_value(repo->config, key, value);
}
-const struct string_list *repo_config_get_value_multi(struct repository *repo,
- const char *key)
+int repo_config_get_value_multi(struct repository *repo, const char *key,
+ const struct string_list **dest)
{
git_config_check_init(repo);
- return git_configset_get_value_multi(repo->config, key);
+ return git_configset_get_value_multi(repo->config, key, dest);
+}
+
+int repo_config_get_string_multi(struct repository *repo, const char *key,
+ const struct string_list **dest)
+{
+ git_config_check_init(repo);
+ return git_configset_get_string_multi(repo->config, key, dest);
}
int repo_config_get_string(struct repository *repo,
@@ -2656,16 +2813,19 @@ static void read_protected_config(void)
.ignore_worktree = 1,
.system_gently = 1,
};
+ struct configset_add_data data = CONFIGSET_ADD_INIT;
+
git_configset_init(&protected_config);
- config_with_options(config_set_callback, &protected_config,
- NULL, &opts);
+ data.config_set = &protected_config;
+ data.config_reader = &the_reader;
+ config_with_options(config_set_callback, &data, NULL, &opts);
}
void git_protected_config(config_fn_t fn, void *data)
{
if (!protected_config.hash_initialized)
read_protected_config();
- configset_iter(&protected_config, fn, data);
+ configset_iter(&the_reader, &protected_config, fn, data);
}
/* Functions used historically to read configuration from 'the_repository' */
@@ -2679,14 +2839,25 @@ void git_config_clear(void)
repo_config_clear(the_repository);
}
+int git_config_get(const char *key)
+{
+ return repo_config_get(the_repository, key);
+}
+
int git_config_get_value(const char *key, const char **value)
{
return repo_config_get_value(the_repository, key, value);
}
-const struct string_list *git_config_get_value_multi(const char *key)
+int git_config_get_value_multi(const char *key, const struct string_list **dest)
+{
+ return repo_config_get_value_multi(the_repository, key, dest);
+}
+
+int git_config_get_string_multi(const char *key,
+ const struct string_list **dest)
{
- return repo_config_get_value_multi(the_repository, key);
+ return repo_config_get_string_multi(the_repository, key, dest);
}
int git_config_get_string(const char *key, char **dest)
@@ -2833,7 +3004,8 @@ void git_die_config(const char *key, const char *err, ...)
error_fn(err, params);
va_end(params);
}
- values = git_config_get_value_multi(key);
+ if (git_config_get_value_multi(key, &values))
+ BUG("for key '%s' we must have a value to report on", key);
kv_info = values->items[values->nr - 1].util;
git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
}
@@ -2843,6 +3015,7 @@ void git_die_config(const char *key, const char *err, ...)
*/
struct config_store_data {
+ struct config_reader *config_reader;
size_t baselen;
char *key;
int do_not_match;
@@ -2857,6 +3030,7 @@ struct config_store_data {
unsigned int parsed_nr, parsed_alloc, *seen, seen_nr, seen_alloc;
unsigned int key_seen:1, section_seen:1, is_keys_section:1;
};
+#define CONFIG_STORE_INIT { 0 }
static void config_store_data_clear(struct config_store_data *store)
{
@@ -2891,6 +3065,7 @@ static int store_aux_event(enum config_event_t type,
size_t begin, size_t end, void *data)
{
struct config_store_data *store = data;
+ struct config_source *cs = store->config_reader->source;
ALLOC_GROW(store->parsed, store->parsed_nr + 1, store->parsed_alloc);
store->parsed[store->parsed_nr].begin = begin;
@@ -2900,10 +3075,10 @@ static int store_aux_event(enum config_event_t type,
if (type == CONFIG_EVENT_SECTION) {
int (*cmpfn)(const char *, const char *, size_t);
- if (cf->var.len < 2 || cf->var.buf[cf->var.len - 1] != '.')
- return error(_("invalid section name '%s'"), cf->var.buf);
+ if (cs->var.len < 2 || cs->var.buf[cs->var.len - 1] != '.')
+ return error(_("invalid section name '%s'"), cs->var.buf);
- if (cf->subsection_case_sensitive)
+ if (cs->subsection_case_sensitive)
cmpfn = strncasecmp;
else
cmpfn = strncmp;
@@ -2911,8 +3086,8 @@ static int store_aux_event(enum config_event_t type,
/* Is this the section we were looking for? */
store->is_keys_section =
store->parsed[store->parsed_nr].is_keys_section =
- cf->var.len - 1 == store->baselen &&
- !cmpfn(cf->var.buf, store->key, store->baselen);
+ cs->var.len - 1 == store->baselen &&
+ !cmpfn(cs->var.buf, store->key, store->baselen);
if (store->is_keys_section) {
store->section_seen = 1;
ALLOC_GROW(store->seen, store->seen_nr + 1,
@@ -3208,9 +3383,9 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
char *filename_buf = NULL;
char *contents = NULL;
size_t contents_sz;
- struct config_store_data store;
+ struct config_store_data store = CONFIG_STORE_INIT;
- memset(&store, 0, sizeof(store));
+ store.config_reader = &the_reader;
/* parse-key returns negative; flip the sign to feed exit(3) */
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
@@ -3487,9 +3662,10 @@ void git_config_set_multivar(const char *key, const char *value,
flags);
}
-static int section_name_match (const char *buf, const char *name)
+static size_t section_name_match (const char *buf, const char *name)
{
- int i = 0, j = 0, dot = 0;
+ size_t i = 0, j = 0;
+ int dot = 0;
if (buf[i] != '[')
return 0;
for (i = 1; buf[i] && buf[i] != ']'; i++) {
@@ -3542,6 +3718,8 @@ static int section_name_is_ok(const char *name)
return 1;
}
+#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024)
+
/* if new_name == NULL, the section is removed instead */
static int git_config_copy_or_rename_section_in_file(const char *config_filename,
const char *old_name,
@@ -3551,11 +3729,12 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
char *filename_buf = NULL;
struct lock_file lock = LOCK_INIT;
int out_fd;
- char buf[1024];
+ struct strbuf buf = STRBUF_INIT;
FILE *config_file = NULL;
struct stat st;
struct strbuf copystr = STRBUF_INIT;
struct config_store_data store;
+ uint32_t line_nr = 0;
memset(&store, 0, sizeof(store));
@@ -3592,16 +3771,25 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
goto out;
}
- while (fgets(buf, sizeof(buf), config_file)) {
- unsigned i;
- int length;
+ while (!strbuf_getwholeline(&buf, config_file, '\n')) {
+ size_t i, length;
int is_section = 0;
- char *output = buf;
- for (i = 0; buf[i] && isspace(buf[i]); i++)
+ char *output = buf.buf;
+
+ line_nr++;
+
+ if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) {
+ ret = error(_("refusing to work with overly long line "
+ "in '%s' on line %"PRIuMAX),
+ config_filename, (uintmax_t)line_nr);
+ goto out;
+ }
+
+ for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++)
; /* do nothing */
- if (buf[i] == '[') {
+ if (buf.buf[i] == '[') {
/* it's a section */
- int offset;
+ size_t offset;
is_section = 1;
/*
@@ -3618,7 +3806,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
strbuf_reset(&copystr);
}
- offset = section_name_match(&buf[i], old_name);
+ offset = section_name_match(&buf.buf[i], old_name);
if (offset > 0) {
ret++;
if (!new_name) {
@@ -3693,6 +3881,7 @@ out:
out_no_rollback:
free(filename_buf);
config_store_data_clear(&store);
+ strbuf_release(&buf);
return ret;
}
@@ -3766,14 +3955,23 @@ int parse_config_key(const char *var,
return 0;
}
-const char *current_config_origin_type(void)
+static int reader_origin_type(struct config_reader *reader,
+ enum config_origin_type *type)
{
- int type;
- if (current_config_kvi)
- type = current_config_kvi->origin_type;
- else if(cf)
- type = cf->origin_type;
+ if (the_reader.config_kvi)
+ *type = reader->config_kvi->origin_type;
+ else if(the_reader.source)
+ *type = reader->source->origin_type;
else
+ return 1;
+ return 0;
+}
+
+const char *current_config_origin_type(void)
+{
+ enum config_origin_type type = CONFIG_ORIGIN_UNKNOWN;
+
+ if (reader_origin_type(&the_reader, &type))
BUG("current_config_origin_type called outside config callback");
switch (type) {
@@ -3812,32 +4010,39 @@ const char *config_scope_name(enum config_scope scope)
}
}
+static int reader_config_name(struct config_reader *reader, const char **out)
+{
+ if (the_reader.config_kvi)
+ *out = reader->config_kvi->filename;
+ else if (the_reader.source)
+ *out = reader->source->name;
+ else
+ return 1;
+ return 0;
+}
+
const char *current_config_name(void)
{
const char *name;
- if (current_config_kvi)
- name = current_config_kvi->filename;
- else if (cf)
- name = cf->name;
- else
+ if (reader_config_name(&the_reader, &name))
BUG("current_config_name called outside config callback");
return name ? name : "";
}
enum config_scope current_config_scope(void)
{
- if (current_config_kvi)
- return current_config_kvi->scope;
+ if (the_reader.config_kvi)
+ return the_reader.config_kvi->scope;
else
- return current_parsing_scope;
+ return the_reader.parsing_scope;
}
int current_config_line(void)
{
- if (current_config_kvi)
- return current_config_kvi->linenr;
+ if (the_reader.config_kvi)
+ return the_reader.config_kvi->linenr;
else
- return cf->linenr;
+ return the_reader.source->linenr;
}
int lookup_config(const char **mapping, int nr_mapping, const char *var)
diff --git a/config.h b/config.h
index 7606246531..247b572b37 100644
--- a/config.h
+++ b/config.h
@@ -56,6 +56,7 @@ struct git_config_source {
};
enum config_origin_type {
+ CONFIG_ORIGIN_UNKNOWN = 0,
CONFIG_ORIGIN_BLOB,
CONFIG_ORIGIN_FILE,
CONFIG_ORIGIN_STDIN,
@@ -450,10 +451,31 @@ int git_configset_add_file(struct config_set *cs, const char *filename);
/**
* Finds and returns the value list, sorted in order of increasing priority
* for the configuration variable `key` and config set `cs`. When the
- * configuration variable `key` is not found, returns NULL. The caller
- * should not free or modify the returned pointer, as it is owned by the cache.
+ * configuration variable `key` is not found, returns 1 without touching
+ * `value`.
+ *
+ * The key will be parsed for validity with git_config_parse_key(), on
+ * error a negative value will be returned.
+ *
+ * The caller should not free or modify the returned pointer, as it is
+ * owned by the cache.
*/
-const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
+RESULT_MUST_BE_USED
+int git_configset_get_value_multi(struct config_set *cs, const char *key,
+ const struct string_list **dest);
+
+/**
+ * A validation wrapper for git_configset_get_value_multi() which does
+ * for it what git_configset_get_string() does for
+ * git_configset_get_value().
+ *
+ * The configuration syntax allows for "[section] key", which will
+ * give us a NULL entry in the "struct string_list", as opposed to
+ * "[section] key =" which is the empty string. Most users of the API
+ * are not prepared to handle NULL in a "struct string_list".
+ */
+int git_configset_get_string_multi(struct config_set *cs, const char *key,
+ const struct string_list **dest);
/**
* Clears `config_set` structure, removes all saved variable-value pairs.
@@ -465,6 +487,13 @@ void git_configset_clear(struct config_set *cs);
* value in the 'dest' pointer.
*/
+/**
+ * git_configset_get() returns negative values on error, see
+ * repo_config_get() below.
+ */
+RESULT_MUST_BE_USED
+int git_configset_get(struct config_set *cs, const char *key);
+
/*
* Finds the highest-priority value for the configuration variable `key`
* and config set `cs`, stores the pointer to it in `value` and returns 0.
@@ -485,10 +514,22 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha
/* Functions for reading a repository's config */
struct repository;
void repo_config(struct repository *repo, config_fn_t fn, void *data);
+
+/**
+ * Run only the discover part of the repo_config_get_*() functions
+ * below, in addition to 1 if not found, returns negative values on
+ * error (e.g. if the key itself is invalid).
+ */
+RESULT_MUST_BE_USED
+int repo_config_get(struct repository *repo, const char *key);
int repo_config_get_value(struct repository *repo,
const char *key, const char **value);
-const struct string_list *repo_config_get_value_multi(struct repository *repo,
- const char *key);
+RESULT_MUST_BE_USED
+int repo_config_get_value_multi(struct repository *repo, const char *key,
+ const struct string_list **dest);
+RESULT_MUST_BE_USED
+int repo_config_get_string_multi(struct repository *repo, const char *key,
+ const struct string_list **dest);
int repo_config_get_string(struct repository *repo,
const char *key, char **dest);
int repo_config_get_string_tmp(struct repository *repo,
@@ -521,8 +562,15 @@ void git_protected_config(config_fn_t fn, void *data);
* manner, the config API provides two functions `git_config_get_value`
* and `git_config_get_value_multi`. They both read values from an internal
* cache generated previously from reading the config files.
+ *
+ * For those git_config_get*() functions that aren't documented,
+ * consult the corresponding repo_config_get*() function's
+ * documentation.
*/
+RESULT_MUST_BE_USED
+int git_config_get(const char *key);
+
/**
* Finds the highest-priority value for the configuration variable `key`,
* stores the pointer to it in `value` and returns 0. When the
@@ -535,10 +583,17 @@ int git_config_get_value(const char *key, const char **value);
/**
* Finds and returns the value list, sorted in order of increasing priority
* for the configuration variable `key`. When the configuration variable
- * `key` is not found, returns NULL. The caller should not free or modify
- * the returned pointer, as it is owned by the cache.
- */
-const struct string_list *git_config_get_value_multi(const char *key);
+ * `key` is not found, returns 1 without touching `value`.
+ *
+ * The caller should not free or modify the returned pointer, as it is
+ * owned by the cache.
+ */
+RESULT_MUST_BE_USED
+int git_config_get_value_multi(const char *key,
+ const struct string_list **dest);
+RESULT_MUST_BE_USED
+int git_config_get_string_multi(const char *key,
+ const struct string_list **dest);
/**
* Resets and invalidates the config cache.
diff --git a/connect.c b/connect.c
index 63e59641c0..37674f7112 100644
--- a/connect.c
+++ b/connect.c
@@ -1,6 +1,8 @@
#include "git-compat-util.h"
-#include "cache.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "pkt-line.h"
#include "quote.h"
#include "refs.h"
@@ -10,7 +12,9 @@
#include "url.h"
#include "string-list.h"
#include "oid-array.h"
+#include "path.h"
#include "transport.h"
+#include "trace2.h"
#include "strbuf.h"
#include "version.h"
#include "protocol.h"
@@ -19,7 +23,7 @@
static char *server_capabilities_v1;
static struct strvec server_capabilities_v2 = STRVEC_INIT;
-static const char *next_server_feature_value(const char *feature, int *len, int *offset);
+static const char *next_server_feature_value(const char *feature, size_t *len, size_t *offset);
static int check_ref(const char *name, unsigned int flags)
{
@@ -30,7 +34,8 @@ static int check_ref(const char *name, unsigned int flags)
return 0;
/* REF_NORMAL means that we don't want the magic fake tag refs */
- if ((flags & REF_NORMAL) && check_refname_format(name, 0))
+ if ((flags & REF_NORMAL) && check_refname_format(name,
+ REFNAME_ALLOW_ONELEVEL))
return 0;
/* REF_HEADS means that we want regular branch heads */
@@ -201,10 +206,10 @@ reject:
static void annotate_refs_with_symref_info(struct ref *ref)
{
struct string_list symref = STRING_LIST_INIT_DUP;
- int offset = 0;
+ size_t offset = 0;
while (1) {
- int len;
+ size_t len;
const char *val;
val = next_server_feature_value("symref", &len, &offset);
@@ -227,7 +232,7 @@ static void annotate_refs_with_symref_info(struct ref *ref)
static void process_capabilities(struct packet_reader *reader, int *linelen)
{
const char *feat_val;
- int feat_len;
+ size_t feat_len;
const char *line = reader->line;
int nul_location = strlen(line);
if (nul_location == *linelen)
@@ -259,7 +264,8 @@ static int process_dummy_ref(const struct packet_reader *reader)
return 0;
name++;
- return oideq(null_oid(), &oid) && !strcmp(name, "capabilities^{}");
+ return oideq(reader->hash_algo->null_oid, &oid) &&
+ !strcmp(name, "capabilities^{}");
}
static void check_no_capabilities(const char *line, int len)
@@ -591,9 +597,10 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
return list;
}
-const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset)
+const char *parse_feature_value(const char *feature_list, const char *feature, size_t *lenp, size_t *offset)
{
- int len;
+ const char *orig_start = feature_list;
+ size_t len;
if (!feature_list)
return NULL;
@@ -612,19 +619,19 @@ const char *parse_feature_value(const char *feature_list, const char *feature, i
if (lenp)
*lenp = 0;
if (offset)
- *offset = found + len - feature_list;
+ *offset = found + len - orig_start;
return value;
}
/* feature with a value (e.g., "agent=git/1.2.3") */
else if (*value == '=') {
- int end;
+ size_t end;
value++;
end = strcspn(value, " \t\n");
if (lenp)
*lenp = end;
if (offset)
- *offset = value + end - feature_list;
+ *offset = value + end - orig_start;
return value;
}
/*
@@ -639,8 +646,8 @@ const char *parse_feature_value(const char *feature_list, const char *feature, i
int server_supports_hash(const char *desired, int *feature_supported)
{
- int offset = 0;
- int len;
+ size_t offset = 0;
+ size_t len;
const char *hash;
hash = next_server_feature_value("object-format", &len, &offset);
@@ -664,12 +671,12 @@ int parse_feature_request(const char *feature_list, const char *feature)
return !!parse_feature_value(feature_list, feature, NULL, NULL);
}
-static const char *next_server_feature_value(const char *feature, int *len, int *offset)
+static const char *next_server_feature_value(const char *feature, size_t *len, size_t *offset)
{
return parse_feature_value(server_capabilities_v1, feature, len, offset);
}
-const char *server_feature_value(const char *feature, int *len)
+const char *server_feature_value(const char *feature, size_t *len)
{
return parse_feature_value(server_capabilities_v1, feature, len, NULL);
}
@@ -1406,6 +1413,7 @@ static void fill_ssh_args(struct child_process *conn, const char *ssh_host,
* the connection failed).
*/
struct child_process *git_connect(int fd[2], const char *url,
+ const char *name,
const char *prog, int flags)
{
char *hostandport, *path;
@@ -1415,10 +1423,11 @@ struct child_process *git_connect(int fd[2], const char *url,
/*
* NEEDSWORK: If we are trying to use protocol v2 and we are planning
- * to perform a push, then fallback to v0 since the client doesn't know
- * how to push yet using v2.
+ * to perform any operation that doesn't involve upload-pack (i.e., a
+ * fetch, ls-remote, etc), then fallback to v0 since we don't know how
+ * to do anything else (like push or remote archive) via v2.
*/
- if (version == protocol_v2 && !strcmp("git-receive-pack", prog))
+ if (version == protocol_v2 && strcmp("git-upload-pack", name))
version = protocol_v0;
/* Without this we cannot rely on waitpid() to tell
diff --git a/connect.h b/connect.h
index b26f7de784..1645126c17 100644
--- a/connect.h
+++ b/connect.h
@@ -7,19 +7,19 @@
#define CONNECT_DIAG_URL (1u << 1)
#define CONNECT_IPV4 (1u << 2)
#define CONNECT_IPV6 (1u << 3)
-struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
+struct child_process *git_connect(int fd[2], const char *url, const char *name, const char *prog, int flags);
int finish_connect(struct child_process *conn);
int git_connection_is_socket(struct child_process *conn);
int server_supports(const char *feature);
int parse_feature_request(const char *features, const char *feature);
-const char *server_feature_value(const char *feature, int *len_ret);
+const char *server_feature_value(const char *feature, size_t *len_ret);
int url_is_local_not_ssh(const char *url);
struct packet_reader;
enum protocol_version discover_version(struct packet_reader *reader);
int server_supports_hash(const char *desired, int *feature_supported);
-const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset);
+const char *parse_feature_value(const char *feature_list, const char *feature, size_t *lenp, size_t *offset);
int server_supports_v2(const char *c);
void ensure_server_supports_v2(const char *c);
int server_feature_v2(const char *c, const char **v);
diff --git a/connected.c b/connected.c
index b90fd61790..8f89376dbc 100644
--- a/connected.c
+++ b/connected.c
@@ -1,5 +1,7 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
#include "run-command.h"
#include "sigchain.h"
#include "connected.h"
@@ -54,7 +56,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
strbuf_release(&idx_file);
}
- if (has_promisor_remote()) {
+ if (repo_has_promisor_remote(the_repository)) {
/*
* For partial clones, we don't want to have to do a regular
* connectivity check because we have to enumerate and exclude
@@ -97,7 +99,7 @@ no_promisor_pack_found:
strvec_push(&rev_list.args,"rev-list");
strvec_push(&rev_list.args, "--objects");
strvec_push(&rev_list.args, "--stdin");
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
strvec_push(&rev_list.args, "--exclude-promisor-objects");
if (!opt->is_deepening_fetch) {
strvec_push(&rev_list.args, "--not");
diff --git a/contrib/coccinelle/README b/contrib/coccinelle/README
index d1daa1f626..055ad0e06a 100644
--- a/contrib/coccinelle/README
+++ b/contrib/coccinelle/README
@@ -1,7 +1,9 @@
-This directory provides examples of Coccinelle (http://coccinelle.lip6.fr/)
-semantic patches that might be useful to developers.
+= coccinelle
-There are two types of semantic patches:
+This directory provides Coccinelle (http://coccinelle.lip6.fr/) semantic patches
+that might be useful to developers.
+
+== Types of semantic patches
* Using the semantic transformation to check for bad patterns in the code;
The target 'make coccicheck' is designed to check for these patterns and
@@ -42,7 +44,7 @@ There are two types of semantic patches:
This allows to expose plans of pending large scale refactorings without
impacting the bad pattern checks.
-Git-specific tips & things to know about how we run "spatch":
+== Git-specific tips & things to know about how we run "spatch":
* The "make coccicheck" will piggy-back on
"COMPUTE_HEADER_DEPENDENCIES". If you've built a given object file
@@ -90,3 +92,33 @@ Git-specific tips & things to know about how we run "spatch":
The absolute times will differ for you, but the relative speedup
from caching should be on that order.
+
+== Authoring and reviewing coccinelle changes
+
+* When a .cocci is made, both the Git changes and .cocci file should be
+ reviewed. When reviewing such a change, do your best to understand the .cocci
+ changes (e.g. by asking the author to explain the change) and be explicit
+ about your understanding of the changes. This helps us decide whether input
+ from coccinelle experts is needed or not. If you aren't sure of the cocci
+ changes, indicate what changes you actively endorse and leave an Acked-by
+ (instead of Reviewed-by).
+
+* Authors should consider that reviewers may not be coccinelle experts, thus the
+ the .cocci changes may not be self-evident. A plain text description of the
+ changes is strongly encouraged, especially when using more esoteric features
+ of the language.
+
+* .cocci rules should target only the problem it is trying to solve; "collateral
+ damage" is not allowed. Reviewers should look out and flag overly-broad rules.
+
+* Consider the cost-benefit ratio of .cocci changes. In particular, consider the
+ effect on the runtime of "make coccicheck", and how often your .cocci check
+ will catch something valuable. As a rule of thumb, rules that can bail early
+ if a file doesn't have a particular token will have a small impact on runtime,
+ and vice-versa.
+
+* .cocci files used for refactoring should be temporarily kept in-tree to aid
+ the refactoring of out-of-tree code (e.g. in-flight topics). Periodically
+ evaluate the cost-benefit ratio to determine when the file should be removed.
+ For example, consider how many out-of-tree users are left and how much this
+ slows down "make coccicheck".
diff --git a/contrib/coccinelle/tests/unused.c b/contrib/coccinelle/tests/unused.c
deleted file mode 100644
index 8294d734ba..0000000000
--- a/contrib/coccinelle/tests/unused.c
+++ /dev/null
@@ -1,82 +0,0 @@
-void test_strbuf(void)
-{
- struct strbuf sb1 = STRBUF_INIT;
- struct strbuf sb2 = STRBUF_INIT;
- struct strbuf sb3 = STRBUF_INIT;
- struct strbuf sb4 = STRBUF_INIT;
- struct strbuf sb5;
- struct strbuf sb6 = { 0 };
- struct strbuf sb7 = STRBUF_INIT;
- struct strbuf sb8 = STRBUF_INIT;
- struct strbuf *sp1;
- struct strbuf *sp2;
- struct strbuf *sp3;
- struct strbuf *sp4 = xmalloc(sizeof(struct strbuf));
- struct strbuf *sp5 = xmalloc(sizeof(struct strbuf));
- struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
- struct strbuf *sp7;
-
- strbuf_init(&sb5, 0);
- strbuf_init(sp1, 0);
- strbuf_init(sp2, 0);
- strbuf_init(sp3, 0);
- strbuf_init(sp4, 0);
- strbuf_init(sp5, 0);
- strbuf_init(sp6, 0);
- strbuf_init(sp7, 0);
- sp7 = xmalloc(sizeof(struct strbuf));
-
- use_before(&sb3);
- use_as_str("%s", sb7.buf);
- use_as_str("%s", sp1->buf);
- use_as_str("%s", sp6->buf);
- pass_pp(&sp3);
-
- strbuf_release(&sb1);
- strbuf_reset(&sb2);
- strbuf_release(&sb3);
- strbuf_release(&sb4);
- strbuf_release(&sb5);
- strbuf_release(&sb6);
- strbuf_release(&sb7);
- strbuf_release(sp1);
- strbuf_release(sp2);
- strbuf_release(sp3);
- strbuf_release(sp4);
- strbuf_release(sp5);
- strbuf_release(sp6);
- strbuf_release(sp7);
-
- use_after(&sb4);
-
- if (when_strict())
- return;
- strbuf_release(&sb8);
-}
-
-void test_other(void)
-{
- struct string_list l = STRING_LIST_INIT_DUP;
- struct strbuf sb = STRBUF_INIT;
-
- string_list_clear(&l, 0);
- string_list_clear(&sb, 0);
-}
-
-void test_worktrees(void)
-{
- struct worktree **w1 = get_worktrees();
- struct worktree **w2 = get_worktrees();
- struct worktree **w3;
- struct worktree **w4;
-
- w3 = get_worktrees();
- w4 = get_worktrees();
-
- use_it(w4);
-
- free_worktrees(w1);
- free_worktrees(w2);
- free_worktrees(w3);
- free_worktrees(w4);
-}
diff --git a/contrib/coccinelle/tests/unused.res b/contrib/coccinelle/tests/unused.res
deleted file mode 100644
index 6d3e745683..0000000000
--- a/contrib/coccinelle/tests/unused.res
+++ /dev/null
@@ -1,45 +0,0 @@
-void test_strbuf(void)
-{
- struct strbuf sb3 = STRBUF_INIT;
- struct strbuf sb4 = STRBUF_INIT;
- struct strbuf sb7 = STRBUF_INIT;
- struct strbuf *sp1;
- struct strbuf *sp3;
- struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
- strbuf_init(sp1, 0);
- strbuf_init(sp3, 0);
- strbuf_init(sp6, 0);
-
- use_before(&sb3);
- use_as_str("%s", sb7.buf);
- use_as_str("%s", sp1->buf);
- use_as_str("%s", sp6->buf);
- pass_pp(&sp3);
-
- strbuf_release(&sb3);
- strbuf_release(&sb4);
- strbuf_release(&sb7);
- strbuf_release(sp1);
- strbuf_release(sp3);
- strbuf_release(sp6);
-
- use_after(&sb4);
-
- if (when_strict())
- return;
-}
-
-void test_other(void)
-{
-}
-
-void test_worktrees(void)
-{
- struct worktree **w4;
-
- w4 = get_worktrees();
-
- use_it(w4);
-
- free_worktrees(w4);
-}
diff --git a/contrib/coccinelle/the_repository.cocci b/contrib/coccinelle/the_repository.cocci
new file mode 100644
index 0000000000..765ad68967
--- /dev/null
+++ b/contrib/coccinelle/the_repository.cocci
@@ -0,0 +1,123 @@
+// Fully migrated "the_repository" additions
+@@
+@@
+(
+// cache.h
+- get_oid
++ repo_get_oid
+|
+- get_oid_commit
++ repo_get_oid_commit
+|
+- get_oid_committish
++ repo_get_oid_committish
+|
+- get_oid_tree
++ repo_get_oid_tree
+|
+- get_oid_treeish
++ repo_get_oid_treeish
+|
+- get_oid_blob
++ repo_get_oid_blob
+|
+- get_oid_mb
++ repo_get_oid_mb
+|
+- find_unique_abbrev
++ repo_find_unique_abbrev
+|
+- find_unique_abbrev_r
++ repo_find_unique_abbrev_r
+|
+- for_each_abbrev
++ repo_for_each_abbrev
+|
+- interpret_branch_name
++ repo_interpret_branch_name
+|
+- peel_to_type
++ repo_peel_to_type
+// commit-reach.h
+|
+- get_merge_bases
++ repo_get_merge_bases
+|
+- get_merge_bases_many
++ repo_get_merge_bases_many
+|
+- get_merge_bases_many_dirty
++ repo_get_merge_bases_many_dirty
+|
+- in_merge_bases
++ repo_in_merge_bases
+|
+- in_merge_bases_many
++ repo_in_merge_bases_many
+// commit.h
+|
+- parse_commit_internal
++ repo_parse_commit_internal
+|
+- parse_commit
++ repo_parse_commit
+|
+- get_commit_buffer
++ repo_get_commit_buffer
+|
+- unuse_commit_buffer
++ repo_unuse_commit_buffer
+|
+- logmsg_reencode
++ repo_logmsg_reencode
+|
+- get_commit_tree
++ repo_get_commit_tree
+// diff.h
+|
+- diff_setup
++ repo_diff_setup
+// object-store.h
+|
+- read_object_file
++ repo_read_object_file
+|
+- has_object_file
++ repo_has_object_file
+|
+- has_object_file_with_flags
++ repo_has_object_file_with_flags
+// pretty.h
+|
+- format_commit_message
++ repo_format_commit_message
+// packfile.h
+|
+- approximate_object_count
++ repo_approximate_object_count
+// promisor-remote.h
+|
+- promisor_remote_reinit
++ repo_promisor_remote_reinit
+|
+- promisor_remote_find
++ repo_promisor_remote_find
+|
+- has_promisor_remote
++ repo_has_promisor_remote
+// refs.h
+|
+- dwim_ref
++ repo_dwim_ref
+// rerere.h
+|
+- rerere
++ repo_rerere
+// revision.h
+|
+- init_revisions
++ repo_init_revisions
+)
+ (
++ the_repository,
+ ...)
diff --git a/contrib/coccinelle/the_repository.pending.cocci b/contrib/coccinelle/the_repository.pending.cocci
deleted file mode 100644
index 747d382ff5..0000000000
--- a/contrib/coccinelle/the_repository.pending.cocci
+++ /dev/null
@@ -1,128 +0,0 @@
-// This file is used for the ongoing refactoring of
-// bringing the index or repository struct in all of
-// our code base.
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- read_object_file(
-+ repo_read_object_file(the_repository,
- E, F, G)
-
-@@
-expression E;
-@@
-- has_object_file(
-+ repo_has_object_file(the_repository,
- E)
-
-@@
-expression E;
-@@
-- has_object_file_with_flags(
-+ repo_has_object_file_with_flags(the_repository,
- E)
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- parse_commit_internal(
-+ repo_parse_commit_internal(the_repository,
- E, F, G)
-
-@@
-expression E;
-expression F;
-@@
-- parse_commit_gently(
-+ repo_parse_commit_gently(the_repository,
- E, F)
-
-@@
-expression E;
-@@
-- parse_commit(
-+ repo_parse_commit(the_repository,
- E)
-
-@@
-expression E;
-expression F;
-@@
-- get_merge_bases(
-+ repo_get_merge_bases(the_repository,
- E, F);
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- get_merge_bases_many(
-+ repo_get_merge_bases_many(the_repository,
- E, F, G);
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- get_merge_bases_many_dirty(
-+ repo_get_merge_bases_many_dirty(the_repository,
- E, F, G);
-
-@@
-expression E;
-expression F;
-@@
-- in_merge_bases(
-+ repo_in_merge_bases(the_repository,
- E, F);
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- in_merge_bases_many(
-+ repo_in_merge_bases_many(the_repository,
- E, F, G);
-
-@@
-expression E;
-expression F;
-@@
-- get_commit_buffer(
-+ repo_get_commit_buffer(the_repository,
- E, F);
-
-@@
-expression E;
-expression F;
-@@
-- unuse_commit_buffer(
-+ repo_unuse_commit_buffer(the_repository,
- E, F);
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- logmsg_reencode(
-+ repo_logmsg_reencode(the_repository,
- E, F, G);
-
-@@
-expression E;
-expression F;
-expression G;
-expression H;
-@@
-- format_commit_message(
-+ repo_format_commit_message(the_repository,
- E, F, G, H);
diff --git a/contrib/coccinelle/unused.cocci b/contrib/coccinelle/unused.cocci
deleted file mode 100644
index d84046f82e..0000000000
--- a/contrib/coccinelle/unused.cocci
+++ /dev/null
@@ -1,43 +0,0 @@
-// This rule finds sequences of "unused" declerations and uses of a
-// variable, where "unused" is defined to include only calling the
-// equivalent of alloc, init & free functions on the variable.
-@@
-type T;
-identifier I;
-// STRBUF_INIT, but also e.g. STRING_LIST_INIT_DUP (so no anchoring)
-constant INIT_MACRO =~ "_INIT";
-identifier MALLOC1 =~ "^x?[mc]alloc$";
-identifier INIT_ASSIGN1 =~ "^get_worktrees$";
-identifier INIT_CALL1 =~ "^[a-z_]*_init$";
-identifier REL1 =~ "^[a-z_]*_(release|reset|clear|free)$";
-identifier REL2 =~ "^(release|clear|free)_[a-z_]*$";
-@@
-
-(
-- T I;
-|
-- T I = { 0 };
-|
-- T I = INIT_MACRO;
-|
-- T I = MALLOC1(...);
-|
-- T I = INIT_ASSIGN1(...);
-)
-
-<... when != \( I \| &I \)
-(
-- \( INIT_CALL1 \)( \( I \| &I \), ...);
-|
-- I = \( INIT_ASSIGN1 \)(...);
-|
-- I = MALLOC1(...);
-)
-...>
-
-(
-- \( REL1 \| REL2 \)( \( I \| &I \), ...);
-|
-- \( REL1 \| REL2 \)( \( &I \| I \) );
-)
- ... when != \( I \| &I \)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index dc95c34cc8..945d2543b0 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -767,7 +767,7 @@ __git_refs ()
track=""
;;
*)
- for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
+ for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD REVERT_HEAD BISECT_HEAD AUTO_MERGE; do
case "$i" in
$match*|$umatch*)
if [ -e "$dir/$i" ]; then
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 57972c2845..2c030050ae 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -100,9 +100,7 @@
#
# If you would like a colored hint about the current dirty state, set
# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
-# the colored output of "git status -sb" and are available only when
-# using __git_ps1 for PROMPT_COMMAND or precmd in Bash,
-# but always available in Zsh.
+# the colored output of "git status -sb".
#
# If you would like __git_ps1 to do nothing in the case when the current
# directory is set up to be ignored by git, then set
@@ -259,12 +257,12 @@ __git_ps1_colorize_gitstring ()
local c_lblue='%F{blue}'
local c_clear='%f'
else
- # Using \[ and \] around colors is necessary to prevent
+ # Using \001 and \002 around colors is necessary to prevent
# issues with command line editing/browsing/completion!
- local c_red='\[\e[31m\]'
- local c_green='\[\e[32m\]'
- local c_lblue='\[\e[1;34m\]'
- local c_clear='\[\e[0m\]'
+ local c_red=$'\001\e[31m\002'
+ local c_green=$'\001\e[32m\002'
+ local c_lblue=$'\001\e[1;34m\002'
+ local c_clear=$'\001\e[0m\002'
fi
local bad_color=$c_red
local ok_color=$c_green
@@ -300,7 +298,7 @@ __git_ps1_colorize_gitstring ()
# variable, in that order.
__git_eread ()
{
- test -r "$1" && IFS=$'\r\n' read "$2" <"$1"
+ test -r "$1" && IFS=$'\r\n' read -r "$2" <"$1"
}
# see if a cherry-pick or revert is in progress, if the user has committed a
@@ -574,11 +572,8 @@ __git_ps1 ()
b="\${__git_ps1_branch_name}"
fi
- # NO color option unless in PROMPT_COMMAND mode or it's Zsh
if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
- if [ $pcmode = yes ] || [ -n "${ZSH_VERSION-}" ]; then
- __git_ps1_colorize_gitstring
- fi
+ __git_ps1_colorize_gitstring
fi
local f="$h$w$i$s$u$p"
diff --git a/contrib/credential/gnome-keyring/.gitignore b/contrib/credential/gnome-keyring/.gitignore
deleted file mode 100644
index 88d8fcdbce..0000000000
--- a/contrib/credential/gnome-keyring/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-git-credential-gnome-keyring
diff --git a/contrib/credential/gnome-keyring/Makefile b/contrib/credential/gnome-keyring/Makefile
deleted file mode 100644
index 22c19df94b..0000000000
--- a/contrib/credential/gnome-keyring/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-MAIN:=git-credential-gnome-keyring
-all:: $(MAIN)
-
-CC = gcc
-RM = rm -f
-CFLAGS = -g -O2 -Wall
-PKG_CONFIG = pkg-config
-
--include ../../../config.mak.autogen
--include ../../../config.mak
-
-INCS:=$(shell $(PKG_CONFIG) --cflags gnome-keyring-1 glib-2.0)
-LIBS:=$(shell $(PKG_CONFIG) --libs gnome-keyring-1 glib-2.0)
-
-SRCS:=$(MAIN).c
-OBJS:=$(SRCS:.c=.o)
-
-%.o: %.c
- $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -o $@ -c $<
-
-$(MAIN): $(OBJS)
- $(CC) -o $@ $(LDFLAGS) $^ $(LIBS)
-
-clean:
- @$(RM) $(MAIN) $(OBJS)
diff --git a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
deleted file mode 100644
index 5927e27ae6..0000000000
--- a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (C) 2011 John Szakmeister <john@szakmeister.net>
- * 2012 Philipp A. Hartmann <pah@qo.cx>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Credits:
- * - GNOME Keyring API handling originally written by John Szakmeister
- * - ported to credential helper API by Philipp A. Hartmann
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <gnome-keyring.h>
-
-#ifdef GNOME_KEYRING_DEFAULT
-
- /* Modern gnome-keyring */
-
-#include <gnome-keyring-memory.h>
-
-#else
-
- /*
- * Support ancient gnome-keyring, circ. RHEL 5.X.
- * GNOME_KEYRING_DEFAULT seems to have been introduced with Gnome 2.22,
- * and the other features roughly around Gnome 2.20, 6 months before.
- * Ubuntu 8.04 used Gnome 2.22 (I think). Not sure any distro used 2.20.
- * So the existence/non-existence of GNOME_KEYRING_DEFAULT seems like
- * a decent thing to use as an indicator.
- */
-
-#define GNOME_KEYRING_DEFAULT NULL
-
-/*
- * ancient gnome-keyring returns DENIED when an entry is not found.
- * Setting NO_MATCH to DENIED will prevent us from reporting DENIED
- * errors during get and erase operations, but we will still report
- * DENIED errors during a store.
- */
-#define GNOME_KEYRING_RESULT_NO_MATCH GNOME_KEYRING_RESULT_DENIED
-
-#define gnome_keyring_memory_alloc g_malloc
-#define gnome_keyring_memory_free gnome_keyring_free_password
-#define gnome_keyring_memory_strdup g_strdup
-
-static const char *gnome_keyring_result_to_message(GnomeKeyringResult result)
-{
- switch (result) {
- case GNOME_KEYRING_RESULT_OK:
- return "OK";
- case GNOME_KEYRING_RESULT_DENIED:
- return "Denied";
- case GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON:
- return "No Keyring Daemon";
- case GNOME_KEYRING_RESULT_ALREADY_UNLOCKED:
- return "Already UnLocked";
- case GNOME_KEYRING_RESULT_NO_SUCH_KEYRING:
- return "No Such Keyring";
- case GNOME_KEYRING_RESULT_BAD_ARGUMENTS:
- return "Bad Arguments";
- case GNOME_KEYRING_RESULT_IO_ERROR:
- return "IO Error";
- case GNOME_KEYRING_RESULT_CANCELLED:
- return "Cancelled";
- case GNOME_KEYRING_RESULT_ALREADY_EXISTS:
- return "Already Exists";
- default:
- return "Unknown Error";
- }
-}
-
-/*
- * Support really ancient gnome-keyring, circ. RHEL 4.X.
- * Just a guess for the Glib version. Glib 2.8 was roughly Gnome 2.12 ?
- * Which was released with gnome-keyring 0.4.3 ??
- */
-#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 8
-
-static void gnome_keyring_done_cb(GnomeKeyringResult result, gpointer user_data)
-{
- gpointer *data = (gpointer *)user_data;
- int *done = (int *)data[0];
- GnomeKeyringResult *r = (GnomeKeyringResult *)data[1];
-
- *r = result;
- *done = 1;
-}
-
-static void wait_for_request_completion(int *done)
-{
- GMainContext *mc = g_main_context_default();
- while (!*done)
- g_main_context_iteration(mc, TRUE);
-}
-
-static GnomeKeyringResult gnome_keyring_item_delete_sync(const char *keyring, guint32 id)
-{
- int done = 0;
- GnomeKeyringResult result;
- gpointer data[] = { &done, &result };
-
- gnome_keyring_item_delete(keyring, id, gnome_keyring_done_cb, data,
- NULL);
-
- wait_for_request_completion(&done);
-
- return result;
-}
-
-#endif
-#endif
-
-/*
- * This credential struct and API is simplified from git's credential.{h,c}
- */
-struct credential {
- char *protocol;
- char *host;
- unsigned short port;
- char *path;
- char *username;
- char *password;
-};
-
-#define CREDENTIAL_INIT { 0 }
-
-typedef int (*credential_op_cb)(struct credential *);
-
-struct credential_operation {
- char *name;
- credential_op_cb op;
-};
-
-#define CREDENTIAL_OP_END { NULL, NULL }
-
-/* ----------------- GNOME Keyring functions ----------------- */
-
-/* create a special keyring option string, if path is given */
-static char *keyring_object(struct credential *c)
-{
- if (!c->path)
- return NULL;
-
- if (c->port)
- return g_strdup_printf("%s:%hd/%s", c->host, c->port, c->path);
-
- return g_strdup_printf("%s/%s", c->host, c->path);
-}
-
-static int keyring_get(struct credential *c)
-{
- char *object = NULL;
- GList *entries;
- GnomeKeyringNetworkPasswordData *password_data;
- GnomeKeyringResult result;
-
- if (!c->protocol || !(c->host || c->path))
- return EXIT_FAILURE;
-
- object = keyring_object(c);
-
- result = gnome_keyring_find_network_password_sync(
- c->username,
- NULL /* domain */,
- c->host,
- object,
- c->protocol,
- NULL /* authtype */,
- c->port,
- &entries);
-
- g_free(object);
-
- if (result == GNOME_KEYRING_RESULT_NO_MATCH)
- return EXIT_SUCCESS;
-
- if (result == GNOME_KEYRING_RESULT_CANCELLED)
- return EXIT_SUCCESS;
-
- if (result != GNOME_KEYRING_RESULT_OK) {
- g_critical("%s", gnome_keyring_result_to_message(result));
- return EXIT_FAILURE;
- }
-
- /* pick the first one from the list */
- password_data = (GnomeKeyringNetworkPasswordData *)entries->data;
-
- gnome_keyring_memory_free(c->password);
- c->password = gnome_keyring_memory_strdup(password_data->password);
-
- if (!c->username)
- c->username = g_strdup(password_data->user);
-
- gnome_keyring_network_password_list_free(entries);
-
- return EXIT_SUCCESS;
-}
-
-
-static int keyring_store(struct credential *c)
-{
- guint32 item_id;
- char *object = NULL;
- GnomeKeyringResult result;
-
- /*
- * Sanity check that what we are storing is actually sensible.
- * In particular, we can't make a URL without a protocol field.
- * Without either a host or pathname (depending on the scheme),
- * we have no primary key. And without a username and password,
- * we are not actually storing a credential.
- */
- if (!c->protocol || !(c->host || c->path) ||
- !c->username || !c->password)
- return EXIT_FAILURE;
-
- object = keyring_object(c);
-
- result = gnome_keyring_set_network_password_sync(
- GNOME_KEYRING_DEFAULT,
- c->username,
- NULL /* domain */,
- c->host,
- object,
- c->protocol,
- NULL /* authtype */,
- c->port,
- c->password,
- &item_id);
-
- g_free(object);
-
- if (result != GNOME_KEYRING_RESULT_OK &&
- result != GNOME_KEYRING_RESULT_CANCELLED) {
- g_critical("%s", gnome_keyring_result_to_message(result));
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int keyring_erase(struct credential *c)
-{
- char *object = NULL;
- GList *entries;
- GnomeKeyringNetworkPasswordData *password_data;
- GnomeKeyringResult result;
-
- /*
- * Sanity check that we actually have something to match
- * against. The input we get is a restrictive pattern,
- * so technically a blank credential means "erase everything".
- * But it is too easy to accidentally send this, since it is equivalent
- * to empty input. So explicitly disallow it, and require that the
- * pattern have some actual content to match.
- */
- if (!c->protocol && !c->host && !c->path && !c->username)
- return EXIT_FAILURE;
-
- object = keyring_object(c);
-
- result = gnome_keyring_find_network_password_sync(
- c->username,
- NULL /* domain */,
- c->host,
- object,
- c->protocol,
- NULL /* authtype */,
- c->port,
- &entries);
-
- g_free(object);
-
- if (result == GNOME_KEYRING_RESULT_NO_MATCH)
- return EXIT_SUCCESS;
-
- if (result == GNOME_KEYRING_RESULT_CANCELLED)
- return EXIT_SUCCESS;
-
- if (result != GNOME_KEYRING_RESULT_OK) {
- g_critical("%s", gnome_keyring_result_to_message(result));
- return EXIT_FAILURE;
- }
-
- /* pick the first one from the list (delete all matches?) */
- password_data = (GnomeKeyringNetworkPasswordData *)entries->data;
-
- result = gnome_keyring_item_delete_sync(
- password_data->keyring, password_data->item_id);
-
- gnome_keyring_network_password_list_free(entries);
-
- if (result != GNOME_KEYRING_RESULT_OK) {
- g_critical("%s", gnome_keyring_result_to_message(result));
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-/*
- * Table with helper operation callbacks, used by generic
- * credential helper main function.
- */
-static struct credential_operation const credential_helper_ops[] = {
- { "get", keyring_get },
- { "store", keyring_store },
- { "erase", keyring_erase },
- CREDENTIAL_OP_END
-};
-
-/* ------------------ credential functions ------------------ */
-
-static void credential_init(struct credential *c)
-{
- memset(c, 0, sizeof(*c));
-}
-
-static void credential_clear(struct credential *c)
-{
- g_free(c->protocol);
- g_free(c->host);
- g_free(c->path);
- g_free(c->username);
- gnome_keyring_memory_free(c->password);
-
- credential_init(c);
-}
-
-static int credential_read(struct credential *c)
-{
- char *buf;
- size_t line_len;
- char *key;
- char *value;
-
- key = buf = gnome_keyring_memory_alloc(1024);
-
- while (fgets(buf, 1024, stdin)) {
- line_len = strlen(buf);
-
- if (line_len && buf[line_len-1] == '\n')
- buf[--line_len] = '\0';
-
- if (!line_len)
- break;
-
- value = strchr(buf, '=');
- if (!value) {
- g_warning("invalid credential line: %s", key);
- gnome_keyring_memory_free(buf);
- return -1;
- }
- *value++ = '\0';
-
- if (!strcmp(key, "protocol")) {
- g_free(c->protocol);
- c->protocol = g_strdup(value);
- } else if (!strcmp(key, "host")) {
- g_free(c->host);
- c->host = g_strdup(value);
- value = strrchr(c->host, ':');
- if (value) {
- *value++ = '\0';
- c->port = atoi(value);
- }
- } else if (!strcmp(key, "path")) {
- g_free(c->path);
- c->path = g_strdup(value);
- } else if (!strcmp(key, "username")) {
- g_free(c->username);
- c->username = g_strdup(value);
- } else if (!strcmp(key, "password")) {
- gnome_keyring_memory_free(c->password);
- c->password = gnome_keyring_memory_strdup(value);
- while (*value)
- *value++ = '\0';
- }
- /*
- * Ignore other lines; we don't know what they mean, but
- * this future-proofs us when later versions of git do
- * learn new lines, and the helpers are updated to match.
- */
- }
-
- gnome_keyring_memory_free(buf);
-
- return 0;
-}
-
-static void credential_write_item(FILE *fp, const char *key, const char *value)
-{
- if (!value)
- return;
- fprintf(fp, "%s=%s\n", key, value);
-}
-
-static void credential_write(const struct credential *c)
-{
- /* only write username/password, if set */
- credential_write_item(stdout, "username", c->username);
- credential_write_item(stdout, "password", c->password);
-}
-
-static void usage(const char *name)
-{
- struct credential_operation const *try_op = credential_helper_ops;
- const char *basename = strrchr(name, '/');
-
- basename = (basename) ? basename + 1 : name;
- fprintf(stderr, "usage: %s <", basename);
- while (try_op->name) {
- fprintf(stderr, "%s", (try_op++)->name);
- if (try_op->name)
- fprintf(stderr, "%s", "|");
- }
- fprintf(stderr, "%s", ">\n");
-}
-
-int main(int argc, char *argv[])
-{
- int ret = EXIT_SUCCESS;
-
- struct credential_operation const *try_op = credential_helper_ops;
- struct credential cred = CREDENTIAL_INIT;
-
- if (!argv[1]) {
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- g_set_application_name("Git Credential Helper");
-
- /* lookup operation callback */
- while (try_op->name && strcmp(argv[1], try_op->name))
- try_op++;
-
- /* unsupported operation given -- ignore silently */
- if (!try_op->name || !try_op->op)
- goto out;
-
- ret = credential_read(&cred);
- if (ret)
- goto out;
-
- /* perform credential operation */
- ret = (*try_op->op)(&cred);
-
- credential_write(&cred);
-
-out:
- credential_clear(&cred);
- return ret;
-}
diff --git a/contrib/credential/libsecret/.gitignore b/contrib/credential/libsecret/.gitignore
new file mode 100644
index 0000000000..4fa22359e2
--- /dev/null
+++ b/contrib/credential/libsecret/.gitignore
@@ -0,0 +1 @@
+git-credential-libsecret
diff --git a/contrib/credential/libsecret/git-credential-libsecret.c b/contrib/credential/libsecret/git-credential-libsecret.c
index 2c5d76d789..31cf32ad96 100644
--- a/contrib/credential/libsecret/git-credential-libsecret.c
+++ b/contrib/credential/libsecret/git-credential-libsecret.c
@@ -39,6 +39,8 @@ struct credential {
char *path;
char *username;
char *password;
+ char *password_expiry_utc;
+ char *oauth_refresh_token;
};
#define CREDENTIAL_INIT { 0 }
@@ -54,6 +56,25 @@ struct credential_operation {
/* ----------------- Secret Service functions ----------------- */
+static const SecretSchema schema = {
+ "org.git.Password",
+ /* Ignore schema name during search for backwards compatibility */
+ SECRET_SCHEMA_DONT_MATCH_NAME,
+ {
+ /*
+ * libsecret assumes attribute values are non-confidential and
+ * unchanging, so we can't include oauth_refresh_token or
+ * password_expiry_utc.
+ */
+ { "user", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "object", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "protocol", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "port", SECRET_SCHEMA_ATTRIBUTE_INTEGER },
+ { "server", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { NULL, 0 },
+ }
+};
+
static char *make_label(struct credential *c)
{
if (c->port)
@@ -101,7 +122,7 @@ static int keyring_get(struct credential *c)
attributes = make_attr_list(c);
items = secret_service_search_sync(service,
- SECRET_SCHEMA_COMPAT_NETWORK,
+ &schema,
attributes,
SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_UNLOCK,
NULL,
@@ -117,6 +138,7 @@ static int keyring_get(struct credential *c)
SecretItem *item;
SecretValue *secret;
const char *s;
+ gchar **parts;
item = items->data;
secret = secret_item_get_secret(item);
@@ -130,8 +152,27 @@ static int keyring_get(struct credential *c)
s = secret_value_get_text(secret);
if (s) {
- g_free(c->password);
- c->password = g_strdup(s);
+ /*
+ * Passwords and other attributes encoded in following format:
+ * hunter2
+ * password_expiry_utc=1684189401
+ * oauth_refresh_token=xyzzy
+ */
+ parts = g_strsplit(s, "\n", 0);
+ if (g_strv_length(parts) >= 1) {
+ g_free(c->password);
+ c->password = g_strdup(parts[0]);
+ }
+ for (int i = 1; i < g_strv_length(parts); i++) {
+ if (g_str_has_prefix(parts[i], "password_expiry_utc=")) {
+ g_free(c->password_expiry_utc);
+ c->password_expiry_utc = g_strdup(&parts[i][20]);
+ } else if (g_str_has_prefix(parts[i], "oauth_refresh_token=")) {
+ g_free(c->oauth_refresh_token);
+ c->oauth_refresh_token = g_strdup(&parts[i][20]);
+ }
+ }
+ g_strfreev(parts);
}
g_hash_table_unref(attributes);
@@ -148,6 +189,7 @@ static int keyring_store(struct credential *c)
char *label = NULL;
GHashTable *attributes = NULL;
GError *error = NULL;
+ GString *secret = NULL;
/*
* Sanity check that what we are storing is actually sensible.
@@ -162,13 +204,23 @@ static int keyring_store(struct credential *c)
label = make_label(c);
attributes = make_attr_list(c);
- secret_password_storev_sync(SECRET_SCHEMA_COMPAT_NETWORK,
+ secret = g_string_new(c->password);
+ if (c->password_expiry_utc) {
+ g_string_append_printf(secret, "\npassword_expiry_utc=%s",
+ c->password_expiry_utc);
+ }
+ if (c->oauth_refresh_token) {
+ g_string_append_printf(secret, "\noauth_refresh_token=%s",
+ c->oauth_refresh_token);
+ }
+ secret_password_storev_sync(&schema,
attributes,
NULL,
label,
- c->password,
+ secret->str,
NULL,
&error);
+ g_string_free(secret, TRUE);
g_free(label);
g_hash_table_unref(attributes);
@@ -198,7 +250,7 @@ static int keyring_erase(struct credential *c)
return EXIT_FAILURE;
attributes = make_attr_list(c);
- secret_password_clearv_sync(SECRET_SCHEMA_COMPAT_NETWORK,
+ secret_password_clearv_sync(&schema,
attributes,
NULL,
&error);
@@ -238,23 +290,24 @@ static void credential_clear(struct credential *c)
g_free(c->path);
g_free(c->username);
g_free(c->password);
+ g_free(c->password_expiry_utc);
+ g_free(c->oauth_refresh_token);
credential_init(c);
}
static int credential_read(struct credential *c)
{
- char *buf;
- size_t line_len;
+ char *buf = NULL;
+ size_t alloc;
+ ssize_t line_len;
char *key;
char *value;
- key = buf = g_malloc(1024);
+ while ((line_len = getline(&buf, &alloc, stdin)) > 0) {
+ key = buf;
- while (fgets(buf, 1024, stdin)) {
- line_len = strlen(buf);
-
- if (line_len && buf[line_len-1] == '\n')
+ if (buf[line_len-1] == '\n')
buf[--line_len] = '\0';
if (!line_len)
@@ -285,11 +338,19 @@ static int credential_read(struct credential *c)
} else if (!strcmp(key, "username")) {
g_free(c->username);
c->username = g_strdup(value);
+ } else if (!strcmp(key, "password_expiry_utc")) {
+ g_free(c->password_expiry_utc);
+ c->password_expiry_utc = g_strdup(value);
} else if (!strcmp(key, "password")) {
g_free(c->password);
c->password = g_strdup(value);
while (*value)
*value++ = '\0';
+ } else if (!strcmp(key, "oauth_refresh_token")) {
+ g_free(c->oauth_refresh_token);
+ c->oauth_refresh_token = g_strdup(value);
+ while (*value)
+ *value++ = '\0';
}
/*
* Ignore other lines; we don't know what they mean, but
@@ -298,7 +359,7 @@ static int credential_read(struct credential *c)
*/
}
- g_free(buf);
+ free(buf);
return 0;
}
@@ -315,6 +376,10 @@ static void credential_write(const struct credential *c)
/* only write username/password, if set */
credential_write_item(stdout, "username", c->username);
credential_write_item(stdout, "password", c->password);
+ credential_write_item(stdout, "password_expiry_utc",
+ c->password_expiry_utc);
+ credential_write_item(stdout, "oauth_refresh_token",
+ c->oauth_refresh_token);
}
static void usage(const char *name)
diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
index e29cc28779..5f2e5f16c8 100644
--- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c
+++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
@@ -113,14 +113,16 @@ static void add_internet_password(void)
static void read_credential(void)
{
- char buf[1024];
+ char *buf = NULL;
+ size_t alloc;
+ ssize_t line_len;
- while (fgets(buf, sizeof(buf), stdin)) {
+ while ((line_len = getline(&buf, &alloc, stdin)) > 0) {
char *v;
if (!strcmp(buf, "\n"))
break;
- buf[strlen(buf)-1] = '\0';
+ buf[line_len-1] = '\0';
v = strchr(buf, '=');
if (!v)
@@ -165,6 +167,8 @@ static void read_credential(void)
* learn new lines, and the helpers are updated to match.
*/
}
+
+ free(buf);
}
int main(int argc, const char **argv)
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index ead6e267c7..96f10613ae 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
+#include <wincred.h>
/* common helpers */
@@ -33,65 +34,8 @@ static void *xmalloc(size_t size)
return ret;
}
-/* MinGW doesn't have wincred.h, so we need to define stuff */
-
-typedef struct _CREDENTIAL_ATTRIBUTEW {
- LPWSTR Keyword;
- DWORD Flags;
- DWORD ValueSize;
- LPBYTE Value;
-} CREDENTIAL_ATTRIBUTEW, *PCREDENTIAL_ATTRIBUTEW;
-
-typedef struct _CREDENTIALW {
- DWORD Flags;
- DWORD Type;
- LPWSTR TargetName;
- LPWSTR Comment;
- FILETIME LastWritten;
- DWORD CredentialBlobSize;
- LPBYTE CredentialBlob;
- DWORD Persist;
- DWORD AttributeCount;
- PCREDENTIAL_ATTRIBUTEW Attributes;
- LPWSTR TargetAlias;
- LPWSTR UserName;
-} CREDENTIALW, *PCREDENTIALW;
-
-#define CRED_TYPE_GENERIC 1
-#define CRED_PERSIST_LOCAL_MACHINE 2
-#define CRED_MAX_ATTRIBUTES 64
-
-typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
-typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
- PCREDENTIALW **);
-typedef VOID (WINAPI *CredFreeT)(PVOID);
-typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
-
-static HMODULE advapi;
-static CredWriteWT CredWriteW;
-static CredEnumerateWT CredEnumerateW;
-static CredFreeT CredFree;
-static CredDeleteWT CredDeleteW;
-
-static void load_cred_funcs(void)
-{
- /* load DLLs */
- advapi = LoadLibraryExA("advapi32.dll", NULL,
- LOAD_LIBRARY_SEARCH_SYSTEM32);
- if (!advapi)
- die("failed to load advapi32.dll");
-
- /* get function pointers */
- CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW");
- CredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi,
- "CredEnumerateW");
- CredFree = (CredFreeT)GetProcAddress(advapi, "CredFree");
- CredDeleteW = (CredDeleteWT)GetProcAddress(advapi, "CredDeleteW");
- if (!CredWriteW || !CredEnumerateW || !CredFree || !CredDeleteW)
- die("failed to load functions");
-}
-
-static WCHAR *wusername, *password, *protocol, *host, *path, target[1024];
+static WCHAR *wusername, *password, *protocol, *host, *path, target[1024],
+ *password_expiry_utc;
static void write_item(const char *what, LPCWSTR wbuf, int wlen)
{
@@ -183,6 +127,7 @@ static void get_credential(void)
CREDENTIALW **creds;
DWORD num_creds;
int i;
+ CREDENTIAL_ATTRIBUTEW *attr;
if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
return;
@@ -195,6 +140,14 @@ static void get_credential(void)
write_item("password",
(LPCWSTR)creds[i]->CredentialBlob,
creds[i]->CredentialBlobSize / sizeof(WCHAR));
+ for (int j = 0; j < creds[i]->AttributeCount; j++) {
+ attr = creds[i]->Attributes + j;
+ if (!wcscmp(attr->Keyword, L"git_password_expiry_utc")) {
+ write_item("password_expiry_utc", (LPCWSTR)attr->Value,
+ attr->ValueSize / sizeof(WCHAR));
+ break;
+ }
+ }
break;
}
@@ -204,6 +157,7 @@ static void get_credential(void)
static void store_credential(void)
{
CREDENTIALW cred;
+ CREDENTIAL_ATTRIBUTEW expiry_attr;
if (!wusername || !password)
return;
@@ -217,6 +171,14 @@ static void store_credential(void)
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
cred.AttributeCount = 0;
cred.Attributes = NULL;
+ if (password_expiry_utc != NULL) {
+ expiry_attr.Keyword = L"git_password_expiry_utc";
+ expiry_attr.Value = (LPVOID)password_expiry_utc;
+ expiry_attr.ValueSize = (wcslen(password_expiry_utc)) * sizeof(WCHAR);
+ expiry_attr.Flags = 0;
+ cred.Attributes = &expiry_attr;
+ cred.AttributeCount = 1;
+ }
cred.TargetAlias = NULL;
cred.UserName = wusername;
@@ -249,17 +211,28 @@ static WCHAR *utf8_to_utf16_dup(const char *str)
return wstr;
}
+#define KB (1024)
+
static void read_credential(void)
{
- char buf[1024];
+ size_t alloc = 100 * KB;
+ char *buf = calloc(alloc, sizeof(*buf));
- while (fgets(buf, sizeof(buf), stdin)) {
+ while (fgets(buf, alloc, stdin)) {
char *v;
- int len = strlen(buf);
+ size_t len = strlen(buf);
+ int ends_in_newline = 0;
/* strip trailing CR / LF */
- while (len && strchr("\r\n", buf[len - 1]))
+ if (len && buf[len - 1] == '\n') {
+ buf[--len] = 0;
+ ends_in_newline = 1;
+ }
+ if (len && buf[len - 1] == '\r')
buf[--len] = 0;
+ if (!ends_in_newline)
+ die("bad input: %s", buf);
+
if (!*buf)
break;
@@ -278,12 +251,16 @@ static void read_credential(void)
wusername = utf8_to_utf16_dup(v);
} else if (!strcmp(buf, "password"))
password = utf8_to_utf16_dup(v);
+ else if (!strcmp(buf, "password_expiry_utc"))
+ password_expiry_utc = utf8_to_utf16_dup(v);
/*
* Ignore other lines; we don't know what they mean, but
* this future-proofs us when later versions of git do
* learn new lines, and the helpers are updated to match.
*/
}
+
+ free(buf);
}
int main(int argc, char *argv[])
@@ -292,7 +269,7 @@ int main(int argc, char *argv[])
"usage: git credential-wincred <get|store|erase>\n";
if (!argv[1])
- die(usage);
+ die("%s", usage);
/* git use binary pipes to avoid CRLF-issues */
_setmode(_fileno(stdin), _O_BINARY);
@@ -300,8 +277,6 @@ int main(int argc, char *argv[])
read_credential();
- load_cred_funcs();
-
if (!protocol || !(host || path))
return 0;
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 10c9c87839..7db4c45676 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -34,8 +34,8 @@ git subtree pull --prefix=<prefix> <repository> <ref>
git subtree push --prefix=<prefix> <repository> <refspec>
--
h,help show the help
-q quiet
-d show debug messages
+q,quiet quiet
+d,debug show debug messages
P,prefix= the name of the subdir to split out
options for 'split' (also: 'push')
annotate= add a prefix to commit message of new commits
diff --git a/contrib/subtree/t/Makefile b/contrib/subtree/t/Makefile
index 4655e0987b..093399c788 100644
--- a/contrib/subtree/t/Makefile
+++ b/contrib/subtree/t/Makefile
@@ -74,9 +74,7 @@ aggregate-results-and-cleanup: $(T)
$(MAKE) clean
aggregate-results:
- for f in '$(TEST_RESULTS_DIRECTORY_SQ)'/t*-*.counts; do \
- echo "$$f"; \
- done | '$(SHELL_PATH_SQ)' ../../../t/aggregate-results.sh
+ @'$(SHELL_PATH_SQ)' ../../../t/aggregate-results.sh '$(TEST_RESULTS_DIRECTORY_SQ)'
valgrind:
$(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind"
diff --git a/convert.c b/convert.c
index a54d1690c0..3d8325d49e 100644
--- a/convert.c
+++ b/convert.c
@@ -1,14 +1,22 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
#include "config.h"
-#include "object-store.h"
+#include "convert.h"
+#include "copy.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
#include "attr.h"
#include "run-command.h"
#include "quote.h"
+#include "read-cache-ll.h"
#include "sigchain.h"
#include "pkt-line.h"
#include "sub-process.h"
+#include "trace.h"
#include "utf8.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
+#include "wrapper.h"
/*
* convert.c - convert a file when checking it out and checking it in.
@@ -1308,7 +1316,7 @@ void convert_attrs(struct index_state *istate,
git_config(read_convert_config, NULL);
}
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
ccheck = check->items;
ca->crlf_action = git_path_check_crlf(ccheck + 4);
if (ca->crlf_action == CRLF_UNDEFINED)
diff --git a/convert.h b/convert.h
index 0a6e4086b8..d925589444 100644
--- a/convert.h
+++ b/convert.h
@@ -4,7 +4,7 @@
#ifndef CONVERT_H
#define CONVERT_H
-#include "hash.h"
+#include "hash-ll.h"
#include "string-list.h"
struct index_state;
diff --git a/copy.c b/copy.c
index 4de6a110f0..882c79cffb 100644
--- a/copy.c
+++ b/copy.c
@@ -1,4 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "copy.h"
+#include "path.h"
+#include "wrapper.h"
int copy_fd(int ifd, int ofd)
{
diff --git a/copy.h b/copy.h
new file mode 100644
index 0000000000..2af77cba86
--- /dev/null
+++ b/copy.h
@@ -0,0 +1,10 @@
+#ifndef COPY_H
+#define COPY_H
+
+#define COPY_READ_ERROR (-2)
+#define COPY_WRITE_ERROR (-3)
+int copy_fd(int ifd, int ofd);
+int copy_file(const char *dst, const char *src, int mode);
+int copy_file_with_time(const char *dst, const char *src, int mode);
+
+#endif /* COPY_H */
diff --git a/credential.c b/credential.c
index f32011343f..023b59d571 100644
--- a/credential.c
+++ b/credential.c
@@ -1,11 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "config.h"
#include "credential.h"
+#include "gettext.h"
#include "string-list.h"
#include "run-command.h"
#include "url.h"
#include "prompt.h"
#include "sigchain.h"
+#include "strbuf.h"
#include "urlmatch.h"
#include "git-compat-util.h"
@@ -22,7 +25,9 @@ void credential_clear(struct credential *c)
free(c->path);
free(c->username);
free(c->password);
+ free(c->oauth_refresh_token);
string_list_clear(&c->helpers, 0);
+ strvec_clear(&c->wwwauth_headers);
credential_init(c);
}
@@ -235,11 +240,16 @@ int credential_read(struct credential *c, FILE *fp)
} else if (!strcmp(key, "path")) {
free(c->path);
c->path = xstrdup(value);
+ } else if (!strcmp(key, "wwwauth[]")) {
+ strvec_push(&c->wwwauth_headers, value);
} else if (!strcmp(key, "password_expiry_utc")) {
errno = 0;
c->password_expiry_utc = parse_timestamp(value, NULL, 10);
if (c->password_expiry_utc == 0 || errno == ERANGE)
c->password_expiry_utc = TIME_MAX;
+ } else if (!strcmp(key, "oauth_refresh_token")) {
+ free(c->oauth_refresh_token);
+ c->oauth_refresh_token = xstrdup(value);
} else if (!strcmp(key, "url")) {
credential_from_url(c, value);
} else if (!strcmp(key, "quit")) {
@@ -275,11 +285,14 @@ void credential_write(const struct credential *c, FILE *fp)
credential_write_item(fp, "path", c->path, 0);
credential_write_item(fp, "username", c->username, 0);
credential_write_item(fp, "password", c->password, 0);
+ credential_write_item(fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
if (c->password_expiry_utc != TIME_MAX) {
char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
credential_write_item(fp, "password_expiry_utc", s, 0);
free(s);
}
+ for (size_t i = 0; i < c->wwwauth_headers.nr; i++)
+ credential_write_item(fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
}
static int run_credential_helper(struct credential *c,
@@ -398,6 +411,7 @@ void credential_reject(struct credential *c)
FREE_AND_NULL(c->username);
FREE_AND_NULL(c->password);
+ FREE_AND_NULL(c->oauth_refresh_token);
c->password_expiry_utc = TIME_MAX;
c->approved = 0;
}
diff --git a/credential.h b/credential.h
index 935b28a70f..b8e2936d1d 100644
--- a/credential.h
+++ b/credential.h
@@ -2,6 +2,7 @@
#define CREDENTIAL_H
#include "string-list.h"
+#include "strvec.h"
/**
* The credentials API provides an abstracted way of gathering username and
@@ -115,6 +116,20 @@ struct credential {
*/
struct string_list helpers;
+ /**
+ * A `strvec` of WWW-Authenticate header values. Each string
+ * is the value of a WWW-Authenticate header in an HTTP response,
+ * in the order they were received in the response.
+ */
+ struct strvec wwwauth_headers;
+
+ /**
+ * Internal use only. Keeps track of if we previously matched against a
+ * WWW-Authenticate header line in order to re-fold future continuation
+ * lines into one value.
+ */
+ unsigned header_is_last_match:1;
+
unsigned approved:1,
configured:1,
quit:1,
@@ -126,12 +141,14 @@ struct credential {
char *protocol;
char *host;
char *path;
+ char *oauth_refresh_token;
timestamp_t password_expiry_utc;
};
#define CREDENTIAL_INIT { \
.helpers = STRING_LIST_INIT_DUP, \
.password_expiry_utc = TIME_MAX, \
+ .wwwauth_headers = STRVEC_INIT, \
}
/* Initialize a credential structure, setting all fields to empty. */
diff --git a/csum-file.c b/csum-file.c
index cce13c0f04..daf9b06dff 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -7,9 +7,11 @@
* files. Useful when you write a file that you want to be
* able to verify hasn't been messed with afterwards.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "progress.h"
#include "csum-file.h"
+#include "hash.h"
+#include "wrapper.h"
static void verify_buffer_or_die(struct hashfile *f,
const void *buf,
diff --git a/csum-file.h b/csum-file.h
index 793a59da12..bc5bec27ac 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -1,8 +1,8 @@
#ifndef CSUM_FILE_H
#define CSUM_FILE_H
-#include "cache.h"
-#include "hash.h"
+#include "hash-ll.h"
+#include "write-or-die.h"
struct progress;
diff --git a/daemon.c b/daemon.c
index 0ae7d12b5c..7139cc201d 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1,9 +1,16 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
+#include "path.h"
#include "pkt-line.h"
+#include "protocol.h"
#include "run-command.h"
+#include "setup.h"
#include "strbuf.h"
#include "string-list.h"
+#include "wrapper.h"
#ifdef NO_INITGROUPS
#define initgroups(x, y) (0) /* nothing */
@@ -928,7 +935,7 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
add_child(&cld, addr, addrlen);
}
-static void child_handler(int signo)
+static void child_handler(int signo UNUSED)
{
/*
* Otherwise empty handler because systemcalls will get interrupted
diff --git a/date.c b/date.c
index 6f45eeb356..619ada5b20 100644
--- a/date.c
+++ b/date.c
@@ -4,8 +4,11 @@
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "date.h"
+#include "gettext.h"
+#include "pager.h"
+#include "strbuf.h"
/*
* This is like mktime, but without normalization of tm_wday and tm_yday.
@@ -1365,20 +1368,6 @@ static timestamp_t approxidate_str(const char *date,
return (timestamp_t)update_tm(&tm, &now, 0);
}
-timestamp_t approxidate_relative(const char *date)
-{
- struct timeval tv;
- timestamp_t timestamp;
- int offset;
- int errors = 0;
-
- if (!parse_date_basic(date, &timestamp, &offset))
- return timestamp;
-
- get_time(&tv);
- return approxidate_str(date, (const struct timeval *) &tv, &errors);
-}
-
timestamp_t approxidate_careful(const char *date, int *error_ret)
{
struct timeval tv;
diff --git a/date.h b/date.h
index 5d4eaba0a9..6136212a19 100644
--- a/date.h
+++ b/date.h
@@ -68,7 +68,6 @@ int parse_expiry_date(const char *date, timestamp_t *timestamp);
void datestamp(struct strbuf *out);
#define approxidate(s) approxidate_careful((s), NULL)
timestamp_t approxidate_careful(const char *, int *);
-timestamp_t approxidate_relative(const char *date);
int date_overflows(timestamp_t date);
time_t tm_to_time_t(const struct tm *tm);
#endif
diff --git a/decorate.c b/decorate.c
index 2036d15967..a5c43c0c14 100644
--- a/decorate.c
+++ b/decorate.c
@@ -2,7 +2,7 @@
* decorate.c - decorate a git object with some arbitrary
* data.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "object.h"
#include "decorate.h"
diff --git a/delta-islands.c b/delta-islands.c
index afdec0a878..c824a5f6a4 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "attr.h"
#include "object.h"
#include "blob.h"
#include "commit.h"
+#include "gettext.h"
+#include "hex.h"
#include "tag.h"
#include "tree.h"
#include "delta.h"
@@ -506,8 +509,9 @@ void propagate_island_marks(struct commit *commit)
struct commit_list *p;
struct island_bitmap *root_marks = kh_value(island_marks, pos);
- parse_commit(commit);
- set_island_marks(&get_commit_tree(commit)->object, root_marks);
+ repo_parse_commit(the_repository, commit);
+ set_island_marks(&repo_get_commit_tree(the_repository, commit)->object,
+ root_marks);
for (p = commit->parents; p; p = p->next)
set_island_marks(&p->item->object, root_marks);
}
diff --git a/detect-compiler b/detect-compiler
index 50087f5670..a87650b71b 100755
--- a/detect-compiler
+++ b/detect-compiler
@@ -17,7 +17,15 @@ get_family() {
}
get_version() {
- get_version_line | sed 's/^.* version \([0-9][^ ]*\).*/\1/'
+ # A string that begins with a digit up to the next SP
+ ver=$(get_version_line | sed 's/^.* version \([0-9][^ ]*\).*/\1/')
+
+ # There are known -variant suffixes that do not affect the
+ # meaning of the main version number. Strip them.
+ ver=${ver%-win32}
+ ver=${ver%-posix}
+
+ echo "$ver"
}
print_flags() {
diff --git a/diagnose.c b/diagnose.c
index 8f26569896..8430064000 100644
--- a/diagnose.c
+++ b/diagnose.c
@@ -1,12 +1,16 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "diagnose.h"
#include "compat/disk.h"
#include "archive.h"
#include "dir.h"
#include "help.h"
+#include "gettext.h"
+#include "hex.h"
#include "strvec.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "packfile.h"
+#include "parse-options.h"
+#include "write-or-die.h"
struct archive_dir {
const char *path;
@@ -43,7 +47,8 @@ int option_parse_diagnose(const struct option *opt, const char *arg, int unset)
return error(_("invalid --%s value '%s'"), opt->long_name, arg);
}
-static void dir_file_stats_objects(const char *full_path, size_t full_path_len,
+static void dir_file_stats_objects(const char *full_path,
+ size_t full_path_len UNUSED,
const char *file_name, void *data)
{
struct strbuf *buf = data;
diff --git a/diagnose.h b/diagnose.h
index 7a4951a786..f525219ab0 100644
--- a/diagnose.h
+++ b/diagnose.h
@@ -2,7 +2,8 @@
#define DIAGNOSE_H
#include "strbuf.h"
-#include "parse-options.h"
+
+struct option;
enum diagnose_mode {
DIAGNOSE_NONE,
diff --git a/diff-lib.c b/diff-lib.c
index dec040c366..9c2b0134e6 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -1,19 +1,28 @@
/*
* Copyright (C) 2005 Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "quote.h"
#include "commit.h"
#include "diff.h"
#include "diffcore.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "object-name.h"
+#include "read-cache.h"
#include "revision.h"
#include "cache-tree.h"
#include "unpack-trees.h"
#include "refs.h"
+#include "repository.h"
#include "submodule.h"
+#include "symlinks.h"
+#include "trace.h"
#include "dir.h"
#include "fsmonitor.h"
#include "commit-reach.h"
+#include "config.h"
/*
* diff-files
@@ -65,29 +74,72 @@ static int check_removed(const struct index_state *istate, const struct cache_en
* Return 1 when changes are detected, 0 otherwise. If the DIRTY_SUBMODULES
* option is set, the caller does not only want to know if a submodule is
* modified at all but wants to know all the conditions that are met (new
- * commits, untracked content and/or modified content).
+ * commits, untracked content and/or modified content). If
+ * defer_submodule_status bit is set, dirty_submodule will be left to the
+ * caller to set. defer_submodule_status can also be set to 0 in this
+ * function if there is no need to check if the submodule is modified.
*/
static int match_stat_with_submodule(struct diff_options *diffopt,
const struct cache_entry *ce,
struct stat *st, unsigned ce_option,
- unsigned *dirty_submodule)
+ unsigned *dirty_submodule, int *defer_submodule_status,
+ unsigned *ignore_untracked)
{
int changed = ie_match_stat(diffopt->repo->index, ce, st, ce_option);
+ int defer = 0;
+
if (S_ISGITLINK(ce->ce_mode)) {
struct diff_flags orig_flags = diffopt->flags;
if (!diffopt->flags.override_submodule_config)
set_diffopt_flags_from_submodule_config(diffopt, ce->name);
- if (diffopt->flags.ignore_submodules)
+ if (diffopt->flags.ignore_submodules) {
changed = 0;
- else if (!diffopt->flags.ignore_dirty_submodules &&
- (!changed || diffopt->flags.dirty_submodules))
- *dirty_submodule = is_submodule_modified(ce->name,
- diffopt->flags.ignore_untracked_in_submodules);
+ } else if (!diffopt->flags.ignore_dirty_submodules &&
+ (!changed || diffopt->flags.dirty_submodules)) {
+ if (defer_submodule_status && *defer_submodule_status) {
+ defer = 1;
+ *ignore_untracked = diffopt->flags.ignore_untracked_in_submodules;
+ } else {
+ *dirty_submodule = is_submodule_modified(ce->name,
+ diffopt->flags.ignore_untracked_in_submodules);
+ }
+ }
diffopt->flags = orig_flags;
}
+
+ if (defer_submodule_status)
+ *defer_submodule_status = defer;
return changed;
}
+/**
+ * Records diff_change if there is a change in the entry from run_diff_files.
+ * If there is no change, then the cache entry is marked CE_UPTODATE and
+ * CE_FSMONITOR_VALID. If there is no change and the find_copies_harder flag
+ * is not set, then the function returns early.
+ */
+static void record_file_diff(struct diff_options *options, unsigned newmode,
+ unsigned dirty_submodule, int changed,
+ struct index_state *istate,
+ struct cache_entry *ce)
+{
+ unsigned int oldmode;
+ const struct object_id *old_oid, *new_oid;
+
+ if (!changed && !dirty_submodule) {
+ ce_mark_uptodate(ce);
+ mark_fsmonitor_valid(istate, ce);
+ if (!options->flags.find_copies_harder)
+ return;
+ }
+ oldmode = ce->ce_mode;
+ old_oid = &ce->oid;
+ new_oid = changed ? null_oid() : &ce->oid;
+ diff_change(options, oldmode, newmode, old_oid, new_oid,
+ !is_null_oid(old_oid), !is_null_oid(new_oid),
+ ce->name, 0, dirty_submodule);
+}
+
int run_diff_files(struct rev_info *revs, unsigned int option)
{
int entries, i;
@@ -96,6 +148,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
? CE_MATCH_RACY_IS_DIRTY : 0);
uint64_t start = getnanotime();
struct index_state *istate = revs->diffopt.repo->index;
+ struct string_list submodules = STRING_LIST_INIT_NODUP;
diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
@@ -105,11 +158,10 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
diff_unmerged_stage = 2;
entries = istate->cache_nr;
for (i = 0; i < entries; i++) {
- unsigned int oldmode, newmode;
+ unsigned int newmode;
struct cache_entry *ce = istate->cache[i];
int changed;
- unsigned dirty_submodule = 0;
- const struct object_id *old_oid, *new_oid;
+ int defer_submodule_status = 1;
if (diff_can_quit_early(&revs->diffopt))
break;
@@ -220,6 +272,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
newmode = ce->ce_mode;
} else {
struct stat st;
+ unsigned ignore_untracked = 0;
changed = check_removed(istate, ce, &st);
if (changed) {
@@ -241,26 +294,52 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
}
changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
- ce_option, &dirty_submodule);
+ ce_option, NULL,
+ &defer_submodule_status,
+ &ignore_untracked);
newmode = ce_mode_from_stat(ce, st.st_mode);
- }
-
- if (!changed && !dirty_submodule) {
- ce_mark_uptodate(ce);
- mark_fsmonitor_valid(istate, ce);
- if (!revs->diffopt.flags.find_copies_harder)
+ if (defer_submodule_status) {
+ struct submodule_status_util tmp = {
+ .changed = changed,
+ .dirty_submodule = 0,
+ .ignore_untracked = ignore_untracked,
+ .newmode = newmode,
+ .ce = ce,
+ .path = ce->name,
+ };
+ struct string_list_item *item;
+
+ item = string_list_append(&submodules, ce->name);
+ item->util = xmalloc(sizeof(tmp));
+ memcpy(item->util, &tmp, sizeof(tmp));
continue;
+ }
}
- oldmode = ce->ce_mode;
- old_oid = &ce->oid;
- new_oid = changed ? null_oid() : &ce->oid;
- diff_change(&revs->diffopt, oldmode, newmode,
- old_oid, new_oid,
- !is_null_oid(old_oid),
- !is_null_oid(new_oid),
- ce->name, 0, dirty_submodule);
+ if (!defer_submodule_status)
+ record_file_diff(&revs->diffopt, newmode, 0,
+ changed,istate, ce);
+ }
+ if (submodules.nr) {
+ unsigned long parallel_jobs;
+ struct string_list_item *item;
+
+ if (git_config_get_ulong("submodule.diffjobs", &parallel_jobs))
+ parallel_jobs = 1;
+ else if (!parallel_jobs)
+ parallel_jobs = online_cpus();
+
+ if (get_submodules_status(&submodules, parallel_jobs))
+ die(_("submodule status failed"));
+ for_each_string_list_item(item, &submodules) {
+ struct submodule_status_util *util = item->util;
+
+ record_file_diff(&revs->diffopt, util->newmode,
+ util->dirty_submodule, util->changed,
+ istate, util->ce);
+ }
}
+ string_list_clear(&submodules, 1);
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
trace_performance_since(start, "diff-files");
@@ -308,7 +387,7 @@ static int get_stat_data(const struct index_state *istate,
return -1;
}
changed = match_stat_with_submodule(diffopt, ce, &st,
- 0, dirty_submodule);
+ 0, dirty_submodule, NULL, NULL);
if (changed) {
mode = ce_mode_from_stat(ce, st.st_mode);
oid = null_oid();
@@ -581,7 +660,7 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
if (revs->pending.nr == 1) {
struct object_id oid;
- if (get_oid("HEAD", &oid))
+ if (repo_get_oid(the_repository, "HEAD", &oid))
die(_("unable to get HEAD"));
mb_child[1] = lookup_commit_reference(the_repository, &oid);
diff --git a/diff-merges.c b/diff-merges.c
index 85cbefa5af..4641332510 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -1,12 +1,18 @@
+#include "git-compat-util.h"
#include "diff-merges.h"
+#include "gettext.h"
#include "revision.h"
+#include "strbuf.h"
typedef void (*diff_merges_setup_func_t)(struct rev_info *);
static void set_separate(struct rev_info *revs);
static diff_merges_setup_func_t set_to_default = set_separate;
static int suppress_m_parsing;
+static int hide = 0;
+static int m_imply_p = 0;
+static int got_m = 0;
static void suppress(struct rev_info *revs)
{
@@ -20,10 +26,15 @@ static void suppress(struct rev_info *revs)
revs->remerge_diff = 0;
}
+static void set_need_diff(struct rev_info *revs)
+{
+ revs->merges_need_diff = !hide;
+}
+
static void common_setup(struct rev_info *revs)
{
suppress(revs);
- revs->merges_need_diff = 1;
+ set_need_diff(revs);
}
static void set_none(struct rev_info *revs)
@@ -31,6 +42,18 @@ static void set_none(struct rev_info *revs)
suppress(revs);
}
+static void set_hide(struct rev_info *revs)
+{
+ hide = 1;
+ set_need_diff(revs);
+}
+
+static void set_no_hide(struct rev_info *revs)
+{
+ hide = 0;
+ set_need_diff(revs);
+}
+
static void set_separate(struct rev_info *revs)
{
common_setup(revs);
@@ -69,6 +92,10 @@ static diff_merges_setup_func_t func_by_opt(const char *optarg)
{
if (!strcmp(optarg, "off") || !strcmp(optarg, "none"))
return set_none;
+ if (!strcmp(optarg, "hide"))
+ return set_hide;
+ if (!strcmp(optarg, "no-hide"))
+ return set_no_hide;
if (!strcmp(optarg, "1") || !strcmp(optarg, "first-parent"))
return set_first_parent;
if (!strcmp(optarg, "separate"))
@@ -86,12 +113,25 @@ static diff_merges_setup_func_t func_by_opt(const char *optarg)
static void set_diff_merges(struct rev_info *revs, const char *optarg)
{
- diff_merges_setup_func_t func = func_by_opt(optarg);
-
- if (!func)
- die(_("invalid value for '%s': '%s'"), "--diff-merges", optarg);
-
- func(revs);
+ char const delim = ',';
+ struct strbuf **opts = strbuf_split_str(optarg, delim, -1);
+ struct strbuf **p;
+
+ for (p = opts; *p; p++) {
+ diff_merges_setup_func_t func;
+ char *opt = (*p)->buf;
+ int len = (*p)->len;
+
+ if (opt[len - 1] == delim)
+ opt[len - 1] = '\0';
+ func = func_by_opt(opt);
+ if (!func) {
+ strbuf_list_free(opts);
+ die(_("invalid value for '%s': '%s'"), "--diff-merges", opt);
+ }
+ func(revs);
+ }
+ strbuf_list_free(opts);
}
/*
@@ -105,7 +145,25 @@ int diff_merges_config(const char *value)
if (!func)
return -1;
- set_to_default = func;
+ if (func == set_hide)
+ hide = 1;
+ else if (func == set_no_hide)
+ hide = 0;
+ else
+ set_to_default = func;
+
+ return 0;
+}
+
+int diff_merges_hide_config(int on)
+{
+ hide = on;
+ return 0;
+}
+
+int diff_merges_m_imply_p_config(int on)
+{
+ m_imply_p = on;
return 0;
}
@@ -122,7 +180,9 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
if (!suppress_m_parsing && !strcmp(arg, "-m")) {
set_to_default(revs);
- revs->merges_need_diff = 0;
+ set_hide(revs);
+ revs->merges_imply_patch = m_imply_p;
+ got_m = 1;
} else if (!strcmp(arg, "-c")) {
set_combined(revs);
revs->merges_imply_patch = 1;
@@ -183,5 +243,7 @@ void diff_merges_setup_revs(struct rev_info *revs)
if (revs->merges_imply_patch || revs->merges_need_diff) {
if (!revs->diffopt.output_format)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
- }
+ } else if (got_m)
+ warning(_("legacy use of lone '-m' detected: please use '--diff-merges=on,hide' instead, as '-m' may imply '-p'"));
+
}
diff --git a/diff-merges.h b/diff-merges.h
index 19639689bb..9f0b3901fe 100644
--- a/diff-merges.h
+++ b/diff-merges.h
@@ -11,6 +11,10 @@ struct rev_info;
int diff_merges_config(const char *value);
+int diff_merges_hide_config(int hide);
+
+int diff_merges_m_imply_p_config(int on);
+
void diff_merges_suppress_m_parsing(void);
int diff_merges_parse_opts(struct rev_info *revs, const char **argv);
diff --git a/diff-no-index.c b/diff-no-index.c
index 05fafd0019..4296940f90 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -4,16 +4,17 @@
* Copyright (c) 2008 by Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "color.h"
#include "commit.h"
#include "blob.h"
#include "tag.h"
#include "diff.h"
#include "diffcore.h"
+#include "gettext.h"
#include "revision.h"
#include "log-tree.h"
-#include "builtin.h"
#include "parse-options.h"
#include "string-list.h"
#include "dir.h"
diff --git a/diff.c b/diff.c
index 469e18aed2..351d1d0591 100644
--- a/diff.c
+++ b/diff.c
@@ -1,34 +1,49 @@
/*
* Copyright (C) 2005 Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
+#include "base85.h"
#include "config.h"
+#include "convert.h"
+#include "environment.h"
+#include "gettext.h"
#include "tempfile.h"
#include "quote.h"
#include "diff.h"
#include "diffcore.h"
#include "delta.h"
+#include "hex.h"
#include "xdiff-interface.h"
#include "color.h"
#include "attr.h"
#include "run-command.h"
#include "utf8.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "userdiff.h"
#include "submodule-config.h"
#include "submodule.h"
#include "hashmap.h"
#include "mem-pool.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
#include "string-list.h"
#include "strvec.h"
#include "graph.h"
+#include "oid-array.h"
#include "packfile.h"
+#include "pager.h"
#include "parse-options.h"
#include "help.h"
#include "promisor-remote.h"
#include "dir.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "read-cache-ll.h"
+#include "setup.h"
#include "strmap.h"
+#include "ws.h"
+#include "wrapper.h"
#ifdef NO_FAST_WORKING_DIRECTORY
#define FAST_WORKING_DIRECTORY 0
@@ -127,7 +142,7 @@ static int parse_dirstat_params(struct diff_options *options, const char *params
int i;
if (*params_copy)
- string_list_split_in_place(&params, params_copy, ',', -1);
+ string_list_split_in_place(&params, params_copy, ",", -1);
for (i = 0; i < params.nr; i++) {
const char *p = params.items[i].string;
if (!strcmp(p, "changes")) {
@@ -2993,6 +3008,24 @@ static int dirstat_compare(const void *_a, const void *_b)
return strcmp(a->name, b->name);
}
+static void conclude_dirstat(struct diff_options *options,
+ struct dirstat_dir *dir,
+ unsigned long changed)
+{
+ struct dirstat_file *to_free = dir->files;
+
+ if (!changed) {
+ /* This can happen even with many files, if everything was renames */
+ ;
+ } else {
+ /* Show all directories with more than x% of the changes */
+ QSORT(dir->files, dir->nr, dirstat_compare);
+ gather_dirstat(options, dir, changed, "", 0);
+ }
+
+ free(to_free);
+}
+
static void show_dirstat(struct diff_options *options)
{
int i;
@@ -3082,13 +3115,7 @@ found_damage:
dir.nr++;
}
- /* This can happen even with many files, if everything was renames */
- if (!changed)
- return;
-
- /* Show all directories with more than x% of the changes */
- QSORT(dir.files, dir.nr, dirstat_compare);
- gather_dirstat(options, &dir, changed, "", 0);
+ conclude_dirstat(options, &dir, changed);
}
static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *options)
@@ -3126,13 +3153,7 @@ static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *o
dir.nr++;
}
- /* This can happen even with many files, if everything was renames */
- if (!changed)
- return;
-
- /* Show all directories with more than x% of the changes */
- QSORT(dir.files, dir.nr, dirstat_compare);
- gather_dirstat(options, &dir, changed, "", 0);
+ conclude_dirstat(options, &dir, changed);
}
static void free_diffstat_file(struct diffstat_file *f)
@@ -3374,6 +3395,17 @@ void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const
options->b_prefix = b;
}
+void diff_set_noprefix(struct diff_options *options)
+{
+ options->a_prefix = options->b_prefix = "";
+}
+
+void diff_set_default_prefix(struct diff_options *options)
+{
+ options->a_prefix = "a/";
+ options->b_prefix = "b/";
+}
+
struct userdiff_driver *get_textconv(struct repository *r,
struct diff_filespec *one)
{
@@ -4351,7 +4383,7 @@ static int similarity_index(struct diff_filepair *p)
static const char *diff_abbrev_oid(const struct object_id *oid, int abbrev)
{
if (startup_info->have_repository)
- return find_unique_abbrev(oid, abbrev);
+ return repo_find_unique_abbrev(the_repository, oid, abbrev);
else {
char *hex = oid_to_hex(oid);
if (abbrev < 0)
@@ -4674,10 +4706,9 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
options->flags.ignore_untracked_in_submodules = 1;
if (diff_no_prefix) {
- options->a_prefix = options->b_prefix = "";
+ diff_set_noprefix(options);
} else if (!diff_mnemonic_prefix) {
- options->a_prefix = "a/";
- options->b_prefix = "b/";
+ diff_set_default_prefix(options);
}
options->color_moved = diff_color_moved_default;
@@ -4906,6 +4937,7 @@ static int diff_opt_stat(const struct option *opt, const char *value, int unset)
} else
BUG("%s should not get here", opt->long_name);
+ options->output_format &= ~DIFF_FORMAT_NO_OUTPUT;
options->output_format |= DIFF_FORMAT_DIFFSTAT;
options->stat_name_width = name_width;
options->stat_graph_width = graph_width;
@@ -4925,6 +4957,7 @@ static int parse_dirstat_opt(struct diff_options *options, const char *params)
* The caller knows a dirstat-related option is given from the command
* line; allow it to say "return this_function();"
*/
+ options->output_format &= ~DIFF_FORMAT_NO_OUTPUT;
options->output_format |= DIFF_FORMAT_DIRSTAT;
return 1;
}
@@ -4988,7 +5021,7 @@ static int diff_opt_find_object(const struct option *option,
struct object_id oid;
BUG_ON_OPT_NEG(unset);
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
return error(_("unable to resolve '%s'"), arg);
if (!opt->objfind)
@@ -5124,6 +5157,7 @@ static int diff_opt_compact_summary(const struct option *opt,
options->flags.stat_with_summary = 0;
} else {
options->flags.stat_with_summary = 1;
+ options->output_format &= ~DIFF_FORMAT_NO_OUTPUT;
options->output_format |= DIFF_FORMAT_DIFFSTAT;
}
return 0;
@@ -5261,8 +5295,18 @@ static int diff_opt_no_prefix(const struct option *opt,
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(optarg);
- options->a_prefix = "";
- options->b_prefix = "";
+ diff_set_noprefix(options);
+ return 0;
+}
+
+static int diff_opt_default_prefix(const struct option *opt,
+ const char *optarg, int unset)
+{
+ struct diff_options *options = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(optarg);
+ diff_set_default_prefix(options);
return 0;
}
@@ -5459,9 +5503,8 @@ struct option *add_diff_options(const struct option *opts,
OPT_BITOP('p', "patch", &options->output_format,
N_("generate patch"),
DIFF_FORMAT_PATCH, DIFF_FORMAT_NO_OUTPUT),
- OPT_BIT_F('s', "no-patch", &options->output_format,
- N_("suppress diff output"),
- DIFF_FORMAT_NO_OUTPUT, PARSE_OPT_NONEG),
+ OPT_SET_INT('s', "no-patch", &options->output_format,
+ N_("suppress diff output"), DIFF_FORMAT_NO_OUTPUT),
OPT_BITOP('u', NULL, &options->output_format,
N_("generate patch"),
DIFF_FORMAT_PATCH, DIFF_FORMAT_NO_OUTPUT),
@@ -5470,9 +5513,9 @@ struct option *add_diff_options(const struct option *opts,
PARSE_OPT_NONEG | PARSE_OPT_OPTARG, diff_opt_unified),
OPT_BOOL('W', "function-context", &options->flags.funccontext,
N_("generate diffs with <n> lines context")),
- OPT_BIT_F(0, "raw", &options->output_format,
+ OPT_BITOP(0, "raw", &options->output_format,
N_("generate the diff in raw format"),
- DIFF_FORMAT_RAW, PARSE_OPT_NONEG),
+ DIFF_FORMAT_RAW, DIFF_FORMAT_NO_OUTPUT),
OPT_BITOP(0, "patch-with-raw", &options->output_format,
N_("synonym for '-p --raw'"),
DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW,
@@ -5481,12 +5524,12 @@ struct option *add_diff_options(const struct option *opts,
N_("synonym for '-p --stat'"),
DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT,
DIFF_FORMAT_NO_OUTPUT),
- OPT_BIT_F(0, "numstat", &options->output_format,
+ OPT_BITOP(0, "numstat", &options->output_format,
N_("machine friendly --stat"),
- DIFF_FORMAT_NUMSTAT, PARSE_OPT_NONEG),
- OPT_BIT_F(0, "shortstat", &options->output_format,
+ DIFF_FORMAT_NUMSTAT, DIFF_FORMAT_NO_OUTPUT),
+ OPT_BITOP(0, "shortstat", &options->output_format,
N_("output only the last line of --stat"),
- DIFF_FORMAT_SHORTSTAT, PARSE_OPT_NONEG),
+ DIFF_FORMAT_SHORTSTAT, DIFF_FORMAT_NO_OUTPUT),
OPT_CALLBACK_F('X', "dirstat", options, N_("<param1,param2>..."),
N_("output the distribution of relative amount of changes for each sub-directory"),
PARSE_OPT_NONEG | PARSE_OPT_OPTARG,
@@ -5502,9 +5545,9 @@ struct option *add_diff_options(const struct option *opts,
OPT_BIT_F(0, "check", &options->output_format,
N_("warn if changes introduce conflict markers or whitespace errors"),
DIFF_FORMAT_CHECKDIFF, PARSE_OPT_NONEG),
- OPT_BIT_F(0, "summary", &options->output_format,
+ OPT_BITOP(0, "summary", &options->output_format,
N_("condensed summary such as creations, renames and mode changes"),
- DIFF_FORMAT_SUMMARY, PARSE_OPT_NONEG),
+ DIFF_FORMAT_SUMMARY, DIFF_FORMAT_NO_OUTPUT),
OPT_BIT_F(0, "name-only", &options->output_format,
N_("show only names of changed files"),
DIFF_FORMAT_NAME, PARSE_OPT_NONEG),
@@ -5555,6 +5598,9 @@ struct option *add_diff_options(const struct option *opts,
OPT_CALLBACK_F(0, "no-prefix", options, NULL,
N_("do not show any source or destination prefix"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_no_prefix),
+ OPT_CALLBACK_F(0, "default-prefix", options, NULL,
+ N_("use default prefixes a/ and b/"),
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_default_prefix),
OPT_INTEGER_F(0, "inter-hunk-context", &options->interhunkcontext,
N_("show context between diff hunks up to the specified number of lines"),
PARSE_OPT_NONEG),
@@ -6860,7 +6906,7 @@ void diffcore_std(struct diff_options *options)
* If no prefetching occurs, diffcore_rename() will prefetch if it
* decides that it needs inexact rename detection.
*/
- if (options->repo == the_repository && has_promisor_remote() &&
+ if (options->repo == the_repository && repo_has_promisor_remote(the_repository) &&
(options->output_format & output_formats_to_prefetch ||
options->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK))
diff_queued_diff_prefetch(options->repo);
diff --git a/diff.h b/diff.h
index 8d770b1d57..c2e0e63609 100644
--- a/diff.h
+++ b/diff.h
@@ -4,10 +4,11 @@
#ifndef DIFF_H
#define DIFF_H
-#include "tree-walk.h"
+#include "hash-ll.h"
#include "pathspec.h"
-#include "object.h"
-#include "oidset.h"
+#include "strbuf.h"
+
+struct oidset;
/**
* The diff API is for programs that compare two sets of files (e.g. two trees,
@@ -71,7 +72,6 @@ struct oid_array;
struct option;
struct repository;
struct rev_info;
-struct strbuf;
struct userdiff_driver;
typedef int (*pathchange_fn_t)(struct diff_options *options,
@@ -497,6 +497,8 @@ void diff_tree_combined(const struct object_id *oid, const struct oid_array *par
void diff_tree_combined_merge(const struct commit *commit, struct rev_info *rev);
void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b);
+void diff_set_noprefix(struct diff_options *options);
+void diff_set_default_prefix(struct diff_options *options);
int diff_can_quit_early(struct diff_options *);
@@ -535,9 +537,6 @@ int git_diff_basic_config(const char *var, const char *value, void *cb);
int git_diff_heuristic_config(const char *var, const char *value, void *cb);
void init_diff_ui_defaults(void);
int git_diff_ui_config(const char *var, const char *value, void *cb);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define diff_setup(diffopts) repo_diff_setup(the_repository, diffopts)
-#endif
void repo_diff_setup(struct repository *, struct diff_options *);
struct option *add_diff_options(const struct option *, struct diff_options *);
int diff_opt_parse(struct diff_options *, const char **, int, const char *);
@@ -617,7 +616,7 @@ void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc);
#define DIFF_STATUS_FILTER_BROKEN 'B'
/*
- * This is different from find_unique_abbrev() in that
+ * This is different from repo_find_unique_abbrev() in that
* it stuffs the result with dots for alignment.
*/
const char *diff_aligned_abbrev(const struct object_id *sha1, int);
@@ -697,4 +696,6 @@ void print_stat_summary(FILE *fp, int files,
int insertions, int deletions);
void setup_diff_pager(struct diff_options *);
+extern int diff_auto_refresh_index;
+
#endif /* DIFF_H */
diff --git a/diffcore-break.c b/diffcore-break.c
index 0d4a14964d..f57ece2757 100644
--- a/diffcore-break.c
+++ b/diffcore-break.c
@@ -1,9 +1,11 @@
/*
* Copyright (C) 2005 Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "diff.h"
#include "diffcore.h"
+#include "hash.h"
+#include "object.h"
#include "promisor-remote.h"
static int should_break(struct repository *r,
@@ -65,7 +67,7 @@ static int should_break(struct repository *r,
oideq(&src->oid, &dst->oid))
return 0; /* they are the same */
- if (r == the_repository && has_promisor_remote()) {
+ if (r == the_repository && repo_has_promisor_remote(the_repository)) {
options.missing_object_cb = diff_queued_diff_prefetch;
options.missing_object_data = r;
}
diff --git a/diffcore-delta.c b/diffcore-delta.c
index 18d8f766d7..c30b56e983 100644
--- a/diffcore-delta.c
+++ b/diffcore-delta.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "diff.h"
#include "diffcore.h"
diff --git a/diffcore-order.c b/diffcore-order.c
index 19e73311f9..e7d20ebd2d 100644
--- a/diffcore-order.c
+++ b/diffcore-order.c
@@ -1,9 +1,11 @@
/*
* Copyright (C) 2005 Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
#include "diff.h"
#include "diffcore.h"
+#include "wildmatch.h"
static char **order;
static int order_cnt;
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index 03fcbcb40b..b195fa4eb3 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -2,12 +2,13 @@
* Copyright (C) 2005 Junio C Hamano
* Copyright (C) 2010 Google Inc.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "diff.h"
#include "diffcore.h"
#include "xdiff-interface.h"
#include "kwset.h"
-#include "commit.h"
+#include "oidset.h"
+#include "pretty.h"
#include "quote.h"
typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two,
diff --git a/diffcore-rename.c b/diffcore-rename.c
index c0422d9e70..926b554bd5 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -2,14 +2,19 @@
*
* Copyright (C) 2005 Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "diff.h"
#include "diffcore.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "hashmap.h"
+#include "mem-pool.h"
+#include "oid-array.h"
#include "progress.h"
#include "promisor-remote.h"
+#include "string-list.h"
#include "strmap.h"
+#include "trace2.h"
/* Table of rename/copy destinations */
@@ -981,7 +986,7 @@ static int find_basename_matches(struct diff_options *options,
strintmap_set(&dests, base, i);
}
- if (options->repo == the_repository && has_promisor_remote()) {
+ if (options->repo == the_repository && repo_has_promisor_remote(the_repository)) {
dpf_options.missing_object_cb = basename_prefetch;
dpf_options.missing_object_data = &prefetch_options;
}
@@ -1567,7 +1572,7 @@ void diffcore_rename_extended(struct diff_options *options,
/* Finish setting up dpf_options */
prefetch_options.skip_unmodified = skip_unmodified;
- if (options->repo == the_repository && has_promisor_remote()) {
+ if (options->repo == the_repository && repo_has_promisor_remote(the_repository)) {
dpf_options.missing_object_cb = inexact_prefetch;
dpf_options.missing_object_data = &prefetch_options;
}
diff --git a/diffcore-rotate.c b/diffcore-rotate.c
index 445f060ab0..533986cf63 100644
--- a/diffcore-rotate.c
+++ b/diffcore-rotate.c
@@ -2,7 +2,8 @@
* Copyright (C) 2021, Google LLC.
* Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
#include "diff.h"
#include "diffcore.h"
diff --git a/diffcore.h b/diffcore.h
index 9b588a1ee1..5ffe4ec788 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -4,9 +4,11 @@
#ifndef DIFFCORE_H
#define DIFFCORE_H
-#include "cache.h"
+#include "hash-ll.h"
struct diff_options;
+struct mem_pool;
+struct oid_array;
struct repository;
struct strintmap;
struct strmap;
diff --git a/dir-iterator.c b/dir-iterator.c
index cedd304759..fb7c47f0e8 100644
--- a/dir-iterator.c
+++ b/dir-iterator.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "dir.h"
#include "iterator.h"
#include "dir-iterator.h"
diff --git a/dir.c b/dir.c
index 4e99f0c868..3acac7beb1 100644
--- a/dir.c
+++ b/dir.c
@@ -5,10 +5,18 @@
* Copyright (C) Linus Torvalds, 2005-2006
* Junio Hamano, 2005-2006
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
+#include "convert.h"
#include "dir.h"
-#include "object-store.h"
+#include "environment.h"
+#include "gettext.h"
+#include "name-hash.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "attr.h"
#include "refs.h"
#include "wildmatch.h"
@@ -16,8 +24,15 @@
#include "utf8.h"
#include "varint.h"
#include "ewah/ewok.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
+#include "read-cache-ll.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule-config.h"
+#include "symlinks.h"
+#include "trace2.h"
+#include "tree.h"
+#include "wrapper.h"
/*
* Tells read_directory_recursive how a file or directory should be treated.
@@ -267,7 +282,7 @@ static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,
*size_out = 0;
*data_out = NULL;
- data = read_object_file(oid, &type, &sz);
+ data = repo_read_object_file(the_repository, oid, &type, &sz);
if (!data || type != OBJ_BLOB) {
free(data);
return -1;
@@ -1190,7 +1205,7 @@ struct pattern_list *add_pattern_list(struct dir_struct *dir,
struct pattern_list *pl;
struct exclude_list_group *group;
- group = &dir->exclude_list_group[group_type];
+ group = &dir->internal.exclude_list_group[group_type];
ALLOC_GROW(group->pl, group->nr + 1, group->alloc);
pl = &group->pl[group->nr++];
memset(pl, 0, sizeof(*pl));
@@ -1211,7 +1226,7 @@ static void add_patterns_from_file_1(struct dir_struct *dir, const char *fname,
* differently when dir->untracked is non-NULL.
*/
if (!dir->untracked)
- dir->unmanaged_exclude_files++;
+ dir->internal.unmanaged_exclude_files++;
pl = add_pattern_list(dir, EXC_FILE, fname);
if (add_patterns(fname, "", 0, pl, NULL, 0, oid_stat) < 0)
die(_("cannot use %s as an exclude file"), fname);
@@ -1219,7 +1234,7 @@ static void add_patterns_from_file_1(struct dir_struct *dir, const char *fname,
void add_patterns_from_file(struct dir_struct *dir, const char *fname)
{
- dir->unmanaged_exclude_files++; /* see validate_untracked_cache() */
+ dir->internal.unmanaged_exclude_files++; /* see validate_untracked_cache() */
add_patterns_from_file_1(dir, fname, NULL);
}
@@ -1519,7 +1534,7 @@ static struct path_pattern *last_matching_pattern_from_lists(
struct exclude_list_group *group;
struct path_pattern *pattern;
for (i = EXC_CMDL; i <= EXC_FILE; i++) {
- group = &dir->exclude_list_group[i];
+ group = &dir->internal.exclude_list_group[i];
for (j = group->nr - 1; j >= 0; j--) {
pattern = last_matching_pattern_from_list(
pathname, pathlen, basename, dtype_p,
@@ -1545,20 +1560,20 @@ static void prep_exclude(struct dir_struct *dir,
struct untracked_cache_dir *untracked;
int current;
- group = &dir->exclude_list_group[EXC_DIRS];
+ group = &dir->internal.exclude_list_group[EXC_DIRS];
/*
* Pop the exclude lists from the EXCL_DIRS exclude_list_group
* which originate from directories not in the prefix of the
* path being checked.
*/
- while ((stk = dir->exclude_stack) != NULL) {
+ while ((stk = dir->internal.exclude_stack) != NULL) {
if (stk->baselen <= baselen &&
- !strncmp(dir->basebuf.buf, base, stk->baselen))
+ !strncmp(dir->internal.basebuf.buf, base, stk->baselen))
break;
- pl = &group->pl[dir->exclude_stack->exclude_ix];
- dir->exclude_stack = stk->prev;
- dir->pattern = NULL;
+ pl = &group->pl[dir->internal.exclude_stack->exclude_ix];
+ dir->internal.exclude_stack = stk->prev;
+ dir->internal.pattern = NULL;
free((char *)pl->src); /* see strbuf_detach() below */
clear_pattern_list(pl);
free(stk);
@@ -1566,7 +1581,7 @@ static void prep_exclude(struct dir_struct *dir,
}
/* Skip traversing into sub directories if the parent is excluded */
- if (dir->pattern)
+ if (dir->internal.pattern)
return;
/*
@@ -1574,12 +1589,12 @@ static void prep_exclude(struct dir_struct *dir,
* memset(dir, 0, sizeof(*dir)) before use. Changing all of
* them seems lots of work for little benefit.
*/
- if (!dir->basebuf.buf)
- strbuf_init(&dir->basebuf, PATH_MAX);
+ if (!dir->internal.basebuf.buf)
+ strbuf_init(&dir->internal.basebuf, PATH_MAX);
/* Read from the parent directories and push them down. */
current = stk ? stk->baselen : -1;
- strbuf_setlen(&dir->basebuf, current < 0 ? 0 : current);
+ strbuf_setlen(&dir->internal.basebuf, current < 0 ? 0 : current);
if (dir->untracked)
untracked = stk ? stk->ucd : dir->untracked->root;
else
@@ -1599,32 +1614,33 @@ static void prep_exclude(struct dir_struct *dir,
die("oops in prep_exclude");
cp++;
untracked =
- lookup_untracked(dir->untracked, untracked,
+ lookup_untracked(dir->untracked,
+ untracked,
base + current,
cp - base - current);
}
- stk->prev = dir->exclude_stack;
+ stk->prev = dir->internal.exclude_stack;
stk->baselen = cp - base;
stk->exclude_ix = group->nr;
stk->ucd = untracked;
pl = add_pattern_list(dir, EXC_DIRS, NULL);
- strbuf_add(&dir->basebuf, base + current, stk->baselen - current);
- assert(stk->baselen == dir->basebuf.len);
+ strbuf_add(&dir->internal.basebuf, base + current, stk->baselen - current);
+ assert(stk->baselen == dir->internal.basebuf.len);
/* Abort if the directory is excluded */
if (stk->baselen) {
int dt = DT_DIR;
- dir->basebuf.buf[stk->baselen - 1] = 0;
- dir->pattern = last_matching_pattern_from_lists(dir,
+ dir->internal.basebuf.buf[stk->baselen - 1] = 0;
+ dir->internal.pattern = last_matching_pattern_from_lists(dir,
istate,
- dir->basebuf.buf, stk->baselen - 1,
- dir->basebuf.buf + current, &dt);
- dir->basebuf.buf[stk->baselen - 1] = '/';
- if (dir->pattern &&
- dir->pattern->flags & PATTERN_FLAG_NEGATIVE)
- dir->pattern = NULL;
- if (dir->pattern) {
- dir->exclude_stack = stk;
+ dir->internal.basebuf.buf, stk->baselen - 1,
+ dir->internal.basebuf.buf + current, &dt);
+ dir->internal.basebuf.buf[stk->baselen - 1] = '/';
+ if (dir->internal.pattern &&
+ dir->internal.pattern->flags & PATTERN_FLAG_NEGATIVE)
+ dir->internal.pattern = NULL;
+ if (dir->internal.pattern) {
+ dir->internal.exclude_stack = stk;
return;
}
}
@@ -1647,15 +1663,15 @@ static void prep_exclude(struct dir_struct *dir,
*/
!is_null_oid(&untracked->exclude_oid))) {
/*
- * dir->basebuf gets reused by the traversal, but we
- * need fname to remain unchanged to ensure the src
- * member of each struct path_pattern correctly
+ * dir->internal.basebuf gets reused by the traversal,
+ * but we need fname to remain unchanged to ensure the
+ * src member of each struct path_pattern correctly
* back-references its source file. Other invocations
* of add_pattern_list provide stable strings, so we
* strbuf_detach() and free() here in the caller.
*/
struct strbuf sb = STRBUF_INIT;
- strbuf_addbuf(&sb, &dir->basebuf);
+ strbuf_addbuf(&sb, &dir->internal.basebuf);
strbuf_addstr(&sb, dir->exclude_per_dir);
pl->src = strbuf_detach(&sb, NULL);
add_patterns(pl->src, pl->src, stk->baselen, pl, istate,
@@ -1681,10 +1697,10 @@ static void prep_exclude(struct dir_struct *dir,
invalidate_gitignore(dir->untracked, untracked);
oidcpy(&untracked->exclude_oid, &oid_stat.oid);
}
- dir->exclude_stack = stk;
+ dir->internal.exclude_stack = stk;
current = stk->baselen;
}
- strbuf_setlen(&dir->basebuf, baselen);
+ strbuf_setlen(&dir->internal.basebuf, baselen);
}
/*
@@ -1704,8 +1720,8 @@ struct path_pattern *last_matching_pattern(struct dir_struct *dir,
prep_exclude(dir, istate, pathname, basename-pathname);
- if (dir->pattern)
- return dir->pattern;
+ if (dir->internal.pattern)
+ return dir->internal.pattern;
return last_matching_pattern_from_lists(dir, istate, pathname, pathlen,
basename, dtype_p);
@@ -1742,7 +1758,7 @@ static struct dir_entry *dir_add_name(struct dir_struct *dir,
if (index_file_exists(istate, pathname, len, ignore_case))
return NULL;
- ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
+ ALLOC_GROW(dir->entries, dir->nr+1, dir->internal.alloc);
return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
}
@@ -1753,7 +1769,7 @@ struct dir_entry *dir_add_ignored(struct dir_struct *dir,
if (!index_name_is_other(istate, pathname, len))
return NULL;
- ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
+ ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->internal.ignored_alloc);
return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len);
}
@@ -2569,7 +2585,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
if (open_cached_dir(&cdir, dir, untracked, istate, &path, check_only))
goto out;
- dir->visited_directories++;
+ dir->internal.visited_directories++;
if (untracked)
untracked->check_only = !!check_only;
@@ -2578,7 +2594,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
/* check how the file or directory should be treated */
state = treat_path(dir, untracked, &cdir, istate, &path,
baselen, pathspec);
- dir->visited_paths++;
+ dir->internal.visited_paths++;
if (state > dir_state)
dir_state = state;
@@ -2586,7 +2602,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
/* recurse into subdir if instructed by treat_path */
if (state == path_recurse) {
struct untracked_cache_dir *ud;
- ud = lookup_untracked(dir->untracked, untracked,
+ ud = lookup_untracked(dir->untracked,
+ untracked,
path.buf + baselen,
path.len - baselen);
subdir_state =
@@ -2846,7 +2863,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
* condition also catches running setup_standard_excludes()
* before setting dir->untracked!
*/
- if (dir->unmanaged_exclude_files)
+ if (dir->internal.unmanaged_exclude_files)
return NULL;
/*
@@ -2875,7 +2892,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
* EXC_CMDL is not considered in the cache. If people set it,
* skip the cache.
*/
- if (dir->exclude_list_group[EXC_CMDL].nr)
+ if (dir->internal.exclude_list_group[EXC_CMDL].nr)
return NULL;
if (!ident_in_untracked(dir->untracked)) {
@@ -2935,15 +2952,15 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
/* Validate $GIT_DIR/info/exclude and core.excludesfile */
root = dir->untracked->root;
- if (!oideq(&dir->ss_info_exclude.oid,
+ if (!oideq(&dir->internal.ss_info_exclude.oid,
&dir->untracked->ss_info_exclude.oid)) {
invalidate_gitignore(dir->untracked, root);
- dir->untracked->ss_info_exclude = dir->ss_info_exclude;
+ dir->untracked->ss_info_exclude = dir->internal.ss_info_exclude;
}
- if (!oideq(&dir->ss_excludes_file.oid,
+ if (!oideq(&dir->internal.ss_excludes_file.oid,
&dir->untracked->ss_excludes_file.oid)) {
invalidate_gitignore(dir->untracked, root);
- dir->untracked->ss_excludes_file = dir->ss_excludes_file;
+ dir->untracked->ss_excludes_file = dir->internal.ss_excludes_file;
}
/* Make sure this directory is not dropped out at saving phase */
@@ -2969,9 +2986,9 @@ static void emit_traversal_statistics(struct dir_struct *dir,
}
trace2_data_intmax("read_directory", repo,
- "directories-visited", dir->visited_directories);
+ "directories-visited", dir->internal.visited_directories);
trace2_data_intmax("read_directory", repo,
- "paths-visited", dir->visited_paths);
+ "paths-visited", dir->internal.visited_paths);
if (!dir->untracked)
return;
@@ -2993,8 +3010,8 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
struct untracked_cache_dir *untracked;
trace2_region_enter("dir", "read_directory", istate->repo);
- dir->visited_paths = 0;
- dir->visited_directories = 0;
+ dir->internal.visited_paths = 0;
+ dir->internal.visited_directories = 0;
if (has_symlink_leading_path(path, len)) {
trace2_region_leave("dir", "read_directory", istate->repo);
@@ -3342,14 +3359,14 @@ void setup_standard_excludes(struct dir_struct *dir)
excludes_file = xdg_config_home("ignore");
if (excludes_file && !access_or_warn(excludes_file, R_OK, 0))
add_patterns_from_file_1(dir, excludes_file,
- dir->untracked ? &dir->ss_excludes_file : NULL);
+ dir->untracked ? &dir->internal.ss_excludes_file : NULL);
/* per repository user preference */
if (startup_info->have_repository) {
const char *path = git_path_info_exclude();
if (!access_or_warn(path, R_OK, 0))
add_patterns_from_file_1(dir, path,
- dir->untracked ? &dir->ss_info_exclude : NULL);
+ dir->untracked ? &dir->internal.ss_info_exclude : NULL);
}
}
@@ -3405,7 +3422,7 @@ void dir_clear(struct dir_struct *dir)
struct dir_struct new = DIR_INIT;
for (i = EXC_CMDL; i <= EXC_FILE; i++) {
- group = &dir->exclude_list_group[i];
+ group = &dir->internal.exclude_list_group[i];
for (j = 0; j < group->nr; j++) {
pl = &group->pl[j];
if (i == EXC_DIRS)
@@ -3422,13 +3439,13 @@ void dir_clear(struct dir_struct *dir)
free(dir->ignored);
free(dir->entries);
- stk = dir->exclude_stack;
+ stk = dir->internal.exclude_stack;
while (stk) {
struct exclude_stack *prev = stk->prev;
free(stk);
stk = prev;
}
- strbuf_release(&dir->basebuf);
+ strbuf_release(&dir->internal.basebuf);
memcpy(dir, &new, sizeof(*dir));
}
diff --git a/dir.h b/dir.h
index 8acfc04418..80def6fc08 100644
--- a/dir.h
+++ b/dir.h
@@ -1,10 +1,14 @@
#ifndef DIR_H
#define DIR_H
-#include "cache.h"
+#include "hash-ll.h"
#include "hashmap.h"
+#include "pathspec.h"
+#include "statinfo.h"
#include "strbuf.h"
+struct repository;
+
/**
* The directory listing API is used to enumerate paths in the work tree,
* optionally taking `.git/info/exclude` and `.gitignore` files per directory
@@ -212,17 +216,6 @@ struct untracked_cache {
*/
struct dir_struct {
- /* The number of members in `entries[]` array. */
- int nr;
-
- /* Internal use; keeps track of allocation of `entries[]` array.*/
- int alloc;
-
- /* The number of members in `ignored[]` array. */
- int ignored_nr;
-
- int ignored_alloc;
-
/* bit-field of options */
enum {
@@ -287,60 +280,81 @@ struct dir_struct {
DIR_SKIP_NESTED_GIT = 1<<9
} flags;
+ /* The number of members in `entries[]` array. */
+ int nr; /* output only */
+
+ /* The number of members in `ignored[]` array. */
+ int ignored_nr; /* output only */
+
/* An array of `struct dir_entry`, each element of which describes a path. */
- struct dir_entry **entries;
+ struct dir_entry **entries; /* output only */
/**
* used for ignored paths with the `DIR_SHOW_IGNORED_TOO` and
* `DIR_COLLECT_IGNORED` flags.
*/
- struct dir_entry **ignored;
+ struct dir_entry **ignored; /* output only */
+
+ /* Enable/update untracked file cache if set */
+ struct untracked_cache *untracked;
/**
- * The name of the file to be read in each directory for excluded files
- * (typically `.gitignore`).
+ * Deprecated: ls-files is the only allowed caller; all other callers
+ * should leave this as NULL; it pre-dated the
+ * setup_standard_excludes() mechanism that replaces this.
+ *
+ * This field tracks the name of the file to be read in each directory
+ * for excluded files (typically `.gitignore`).
*/
const char *exclude_per_dir;
- /*
- * We maintain three groups of exclude pattern lists:
- *
- * EXC_CMDL lists patterns explicitly given on the command line.
- * EXC_DIRS lists patterns obtained from per-directory ignore files.
- * EXC_FILE lists patterns from fallback ignore files, e.g.
- * - .git/info/exclude
- * - core.excludesfile
- *
- * Each group contains multiple exclude lists, a single list
- * per source.
- */
+ struct dir_struct_internal {
+ /* Keeps track of allocation of `entries[]` array.*/
+ int alloc;
+
+ /* Keeps track of allocation of `ignored[]` array. */
+ int ignored_alloc;
+
+ /*
+ * We maintain three groups of exclude pattern lists:
+ *
+ * EXC_CMDL lists patterns explicitly given on the command line.
+ * EXC_DIRS lists patterns obtained from per-directory ignore
+ * files.
+ * EXC_FILE lists patterns from fallback ignore files, e.g.
+ * - .git/info/exclude
+ * - core.excludesfile
+ *
+ * Each group contains multiple exclude lists, a single list
+ * per source.
+ */
#define EXC_CMDL 0
#define EXC_DIRS 1
#define EXC_FILE 2
- struct exclude_list_group exclude_list_group[3];
-
- /*
- * Temporary variables which are used during loading of the
- * per-directory exclude lists.
- *
- * exclude_stack points to the top of the exclude_stack, and
- * basebuf contains the full path to the current
- * (sub)directory in the traversal. Exclude points to the
- * matching exclude struct if the directory is excluded.
- */
- struct exclude_stack *exclude_stack;
- struct path_pattern *pattern;
- struct strbuf basebuf;
-
- /* Enable untracked file cache if set */
- struct untracked_cache *untracked;
- struct oid_stat ss_info_exclude;
- struct oid_stat ss_excludes_file;
- unsigned unmanaged_exclude_files;
+ struct exclude_list_group exclude_list_group[3];
- /* Stats about the traversal */
- unsigned visited_paths;
- unsigned visited_directories;
+ /*
+ * Temporary variables which are used during loading of the
+ * per-directory exclude lists.
+ *
+ * exclude_stack points to the top of the exclude_stack, and
+ * basebuf contains the full path to the current
+ * (sub)directory in the traversal. Exclude points to the
+ * matching exclude struct if the directory is excluded.
+ */
+ struct exclude_stack *exclude_stack;
+ struct path_pattern *pattern;
+ struct strbuf basebuf;
+
+ /* Additional metadata related to 'untracked' */
+ struct oid_stat ss_info_exclude;
+ struct oid_stat ss_excludes_file;
+ unsigned unmanaged_exclude_files;
+
+ /* Stats about the traversal */
+ unsigned visited_paths;
+ unsigned visited_directories;
+ } internal;
};
#define DIR_INIT { 0 }
@@ -363,10 +377,6 @@ int count_slashes(const char *s);
int simple_length(const char *match);
int no_wildcard(const char *string);
char *common_prefix(const struct pathspec *pathspec);
-int match_pathspec(struct index_state *istate,
- const struct pathspec *pathspec,
- const char *name, int namelen,
- int prefix, char *seen, int is_dir);
int report_path_error(const char *ps_matched, const struct pathspec *pathspec);
int within_depth(const char *name, int namelen, int depth, int max_depth);
@@ -533,15 +543,6 @@ int submodule_path_match(struct index_state *istate,
const char *submodule_name,
char *seen);
-static inline int ce_path_match(struct index_state *istate,
- const struct cache_entry *ce,
- const struct pathspec *pathspec,
- char *seen)
-{
- return match_pathspec(istate, pathspec, ce->name, ce_namelen(ce), 0, seen,
- S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode));
-}
-
static inline int dir_path_match(struct index_state *istate,
const struct dir_entry *ent,
const struct pathspec *pathspec,
@@ -642,4 +643,19 @@ static inline int starts_with_dot_dot_slash_native(const char *const path)
return path_match_flags(path, what | PATH_MATCH_NATIVE);
}
+
+#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
+#define DTYPE(de) ((de)->d_type)
+#else
+#undef DT_UNKNOWN
+#undef DT_DIR
+#undef DT_REG
+#undef DT_LNK
+#define DT_UNKNOWN 0
+#define DT_DIR 1
+#define DT_REG 2
+#define DT_LNK 3
+#define DTYPE(de) DT_UNKNOWN
+#endif
+
#endif
diff --git a/editor.c b/editor.c
index 008c04fe2f..38c5dbbb79 100644
--- a/editor.c
+++ b/editor.c
@@ -1,9 +1,17 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "advice.h"
#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "pager.h"
+#include "path.h"
#include "strbuf.h"
#include "strvec.h"
#include "run-command.h"
#include "sigchain.h"
+#include "wrapper.h"
#ifndef DEFAULT_EDITOR
#define DEFAULT_EDITOR "vi"
@@ -126,3 +134,31 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
{
return launch_specified_editor(git_sequence_editor(), path, buffer, env);
}
+
+int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+ const char *const *env)
+{
+ char *path2 = NULL;
+ int fd, res = 0;
+
+ if (!is_absolute_path(path))
+ path = path2 = xstrdup(git_path("%s", path));
+
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0)
+ res = error_errno(_("could not open '%s' for writing"), path);
+ else if (write_in_full(fd, buffer->buf, buffer->len) < 0) {
+ res = error_errno(_("could not write to '%s'"), path);
+ close(fd);
+ } else if (close(fd) < 0)
+ res = error_errno(_("could not close '%s'"), path);
+ else {
+ strbuf_reset(buffer);
+ if (launch_editor(path, buffer, env) < 0)
+ res = error_errno(_("could not edit '%s'"), path);
+ unlink(path);
+ }
+
+ free(path2);
+ return res;
+}
diff --git a/editor.h b/editor.h
new file mode 100644
index 0000000000..8016bb5e00
--- /dev/null
+++ b/editor.h
@@ -0,0 +1,34 @@
+#ifndef EDITOR_H
+#define EDITOR_H
+
+struct strbuf;
+
+const char *git_editor(void);
+const char *git_sequence_editor(void);
+int is_terminal_dumb(void);
+
+/**
+ * Launch the user preferred editor to edit a file and fill the buffer
+ * with the file's contents upon the user completing their editing. The
+ * third argument can be used to set the environment which the editor is
+ * run in. If the buffer is NULL the editor is launched as usual but the
+ * file's contents are not read into the buffer upon completion.
+ */
+int launch_editor(const char *path, struct strbuf *buffer,
+ const char *const *env);
+
+int launch_sequence_editor(const char *path, struct strbuf *buffer,
+ const char *const *env);
+
+/*
+ * In contrast to `launch_editor()`, this function writes out the contents
+ * of the specified file first, then clears the `buffer`, then launches
+ * the editor and reads back in the file contents into the `buffer`.
+ * Finally, it deletes the temporary file.
+ *
+ * If `path` is relative, it refers to a file in the `.git` directory.
+ */
+int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+ const char *const *env);
+
+#endif
diff --git a/entry.c b/entry.c
index 971ab26871..f9a7c726a4 100644
--- a/entry.c
+++ b/entry.c
@@ -1,13 +1,20 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "blob.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "name-hash.h"
+#include "sparse-index.h"
#include "streaming.h"
#include "submodule.h"
+#include "symlinks.h"
#include "progress.h"
#include "fsmonitor.h"
#include "entry.h"
#include "parallel-checkout.h"
+#include "wrapper.h"
static void create_directories(const char *path, int path_len,
const struct checkout *state)
@@ -86,7 +93,8 @@ void *read_blob_entry(const struct cache_entry *ce, size_t *size)
{
enum object_type type;
unsigned long ul;
- void *blob_data = read_object_file(&ce->oid, &type, &ul);
+ void *blob_data = repo_read_object_file(the_repository, &ce->oid,
+ &type, &ul);
*size = ul;
if (blob_data) {
diff --git a/entry.h b/entry.h
index 2d4fbb88c8..7329f918a9 100644
--- a/entry.h
+++ b/entry.h
@@ -1,9 +1,11 @@
#ifndef ENTRY_H
#define ENTRY_H
-#include "cache.h"
#include "convert.h"
+struct cache_entry;
+struct index_state;
+
struct checkout {
struct index_state *istate;
const char *base_dir;
diff --git a/environment.c b/environment.c
index 1ee3686fd8..5e9b331279 100644
--- a/environment.c
+++ b/environment.c
@@ -7,19 +7,29 @@
* even if you might want to know where the git directory etc
* are.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "branch.h"
+#include "convert.h"
#include "environment.h"
+#include "gettext.h"
#include "repository.h"
#include "config.h"
#include "refs.h"
#include "fmt-merge-msg.h"
#include "commit.h"
#include "strvec.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "path.h"
+#include "replace-object.h"
#include "tmp-objdir.h"
#include "chdir-notify.h"
+#include "setup.h"
#include "shallow.h"
+#include "trace.h"
+#include "wrapper.h"
+#include "write-or-die.h"
int trust_executable_bit = 1;
int trust_ctime = 1;
@@ -50,7 +60,6 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
size_t delta_base_cache_limit = 96 * 1024 * 1024;
unsigned long big_file_threshold = 512 * 1024 * 1024;
-int pager_use_color = 1;
const char *editor_program;
const char *askpass_program;
const char *excludes_file;
@@ -59,7 +68,6 @@ int read_replace_refs = 1;
enum eol core_eol = EOL_UNSET;
int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
char *check_roundtrip_encoding = "SHIFT-JIS";
-unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
@@ -103,7 +111,7 @@ char *git_work_tree_cfg;
static char *git_namespace;
/*
- * Repository-local GIT_* environment variables; see cache.h for details.
+ * Repository-local GIT_* environment variables; see environment.h for details.
*/
const char * const local_repo_env[] = {
ALTERNATE_DB_ENVIRONMENT,
diff --git a/environment.h b/environment.h
index d438b5c8f3..ae4b6b91ec 100644
--- a/environment.h
+++ b/environment.h
@@ -1,7 +1,15 @@
#ifndef ENVIRONMENT_H
#define ENVIRONMENT_H
-#include "strvec.h"
+struct repository;
+struct strvec;
+
+/*
+ * The character that begins a commented line in user-editable file
+ * that is subject to stripspace.
+ */
+extern char comment_line_char;
+extern int auto_comment_line_char;
/*
* Wrapper of getenv() that returns a strdup value. This value is kept
@@ -9,4 +17,216 @@
*/
const char *getenv_safe(struct strvec *argv, const char *name);
+/* Double-check local_repo_env below if you add to this list. */
+#define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define GIT_COMMON_DIR_ENVIRONMENT "GIT_COMMON_DIR"
+#define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
+#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
+#define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
+#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
+#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
+#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
+#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
+#define GIT_SHALLOW_FILE_ENVIRONMENT "GIT_SHALLOW_FILE"
+#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
+#define CONFIG_ENVIRONMENT "GIT_CONFIG"
+#define CONFIG_DATA_ENVIRONMENT "GIT_CONFIG_PARAMETERS"
+#define CONFIG_COUNT_ENVIRONMENT "GIT_CONFIG_COUNT"
+#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
+#define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
+#define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
+#define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE"
+#define GITATTRIBUTES_FILE ".gitattributes"
+#define INFOATTRIBUTES_FILE "info/attributes"
+#define ATTRIBUTE_MACRO_PREFIX "[attr]"
+#define GITMODULES_FILE ".gitmodules"
+#define GITMODULES_INDEX ":.gitmodules"
+#define GITMODULES_HEAD "HEAD:.gitmodules"
+#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
+#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
+#define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
+#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
+#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
+#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
+#define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS"
+#define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
+#define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
+#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
+#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
+#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
+#define GIT_ATTR_SOURCE_ENVIRONMENT "GIT_ATTR_SOURCE"
+
+/*
+ * Environment variable used in handshaking the wire protocol.
+ * Contains a colon ':' separated list of keys with optional values
+ * 'key[=value]'. Presence of unknown keys and values must be
+ * ignored.
+ */
+#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
+/* HTTP header used to handshake the wire protocol */
+#define GIT_PROTOCOL_HEADER "Git-Protocol"
+
+/*
+ * This environment variable is expected to contain a boolean indicating
+ * whether we should or should not treat:
+ *
+ * GIT_DIR=foo.git git ...
+ *
+ * as if GIT_WORK_TREE=. was given. It's not expected that users will make use
+ * of this, but we use it internally to communicate to sub-processes that we
+ * are in a bare repo. If not set, defaults to true.
+ */
+#define GIT_IMPLICIT_WORK_TREE_ENVIRONMENT "GIT_IMPLICIT_WORK_TREE"
+
+/*
+ * Repository-local GIT_* environment variables; these will be cleared
+ * when git spawns a sub-process that runs inside another repository.
+ * The array is NULL-terminated, which makes it easy to pass in the "env"
+ * parameter of a run-command invocation, or to do a simple walk.
+ */
+extern const char * const local_repo_env[];
+
+void setup_git_env(const char *git_dir);
+
+/*
+ * Returns true iff we have a configured git repository (either via
+ * setup_git_directory, or in the environment via $GIT_DIR).
+ */
+int have_git_dir(void);
+
+extern int is_bare_repository_cfg;
+int is_bare_repository(void);
+extern char *git_work_tree_cfg;
+const char *get_git_dir(void);
+const char *get_git_common_dir(void);
+const char *get_object_directory(void);
+char *get_index_file(void);
+char *get_graft_file(struct repository *r);
+void set_git_dir(const char *path, int make_realpath);
+const char *get_git_namespace(void);
+const char *strip_namespace(const char *namespaced_ref);
+const char *get_git_work_tree(void);
+void set_git_work_tree(const char *tree);
+
+#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
+
+/* Environment bits from configuration mechanism */
+extern int trust_executable_bit;
+extern int trust_ctime;
+extern int check_stat;
+extern int has_symlinks;
+extern int minimum_abbrev, default_abbrev;
+extern int ignore_case;
+extern int assume_unchanged;
+extern int prefer_symlink_refs;
+extern int warn_ambiguous_refs;
+extern int warn_on_object_refname_ambiguity;
+extern char *apply_default_whitespace;
+extern char *apply_default_ignorewhitespace;
+extern const char *git_attributes_file;
+extern const char *git_hooks_path;
+extern int zlib_compression_level;
+extern int pack_compression_level;
+extern size_t packed_git_window_size;
+extern size_t packed_git_limit;
+extern size_t delta_base_cache_limit;
+extern unsigned long big_file_threshold;
+extern unsigned long pack_size_limit_cfg;
+
+/*
+ * Accessors for the core.sharedrepository config which lazy-load the value
+ * from the config (if not already set). The "reset" function can be
+ * used to unset "set" or cached value, meaning that the value will be loaded
+ * fresh from the config file on the next call to get_shared_repository().
+ */
+void set_shared_repository(int value);
+int get_shared_repository(void);
+void reset_shared_repository(void);
+
+extern int core_preload_index;
+extern int precomposed_unicode;
+extern int protect_hfs;
+extern int protect_ntfs;
+
+extern int core_apply_sparse_checkout;
+extern int core_sparse_checkout_cone;
+extern int sparse_expect_files_outside_of_patterns;
+
+/*
+ * Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
+ */
+int use_optional_locks(void);
+
+enum log_refs_config {
+ LOG_REFS_UNSET = -1,
+ LOG_REFS_NONE = 0,
+ LOG_REFS_NORMAL,
+ LOG_REFS_ALWAYS
+};
+extern enum log_refs_config log_all_ref_updates;
+
+enum rebase_setup_type {
+ AUTOREBASE_NEVER = 0,
+ AUTOREBASE_LOCAL,
+ AUTOREBASE_REMOTE,
+ AUTOREBASE_ALWAYS
+};
+
+enum push_default_type {
+ PUSH_DEFAULT_NOTHING = 0,
+ PUSH_DEFAULT_MATCHING,
+ PUSH_DEFAULT_SIMPLE,
+ PUSH_DEFAULT_UPSTREAM,
+ PUSH_DEFAULT_CURRENT,
+ PUSH_DEFAULT_UNSPECIFIED
+};
+
+extern enum rebase_setup_type autorebase;
+extern enum push_default_type push_default;
+
+enum object_creation_mode {
+ OBJECT_CREATION_USES_HARDLINKS = 0,
+ OBJECT_CREATION_USES_RENAMES = 1
+};
+
+extern enum object_creation_mode object_creation_mode;
+
+extern char *notes_ref_name;
+
+extern int grafts_replace_parents;
+
+extern int repository_format_precious_objects;
+extern int repository_format_worktree_config;
+
+/*
+ * Create a temporary file rooted in the object database directory, or
+ * die on failure. The filename is taken from "pattern", which should have the
+ * usual "XXXXXX" trailer, and the resulting filename is written into the
+ * "template" buffer. Returns the open descriptor.
+ */
+int odb_mkstemp(struct strbuf *temp_filename, const char *pattern);
+
+/*
+ * Create a pack .keep file named "name" (which should generally be the output
+ * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on
+ * error.
+ */
+int odb_pack_keep(const char *name);
+
+const char *get_log_output_encoding(void);
+const char *get_commit_output_encoding(void);
+
+extern const char *git_commit_encoding;
+extern const char *git_log_output_encoding;
+
+extern const char *editor_program;
+extern const char *askpass_program;
+extern const char *excludes_file;
+
+/*
+ * Should we print an ellipsis after an abbreviated SHA-1 value
+ * when doing diff-raw output or indicating a detached HEAD?
+ */
+int print_sha1_ellipsis(void);
+
#endif
diff --git a/ewah/bitmap.c b/ewah/bitmap.c
index ac61864163..12d6aa398e 100644
--- a/ewah/bitmap.c
+++ b/ewah/bitmap.c
@@ -16,7 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "ewok.h"
#define EWAH_MASK(x) ((eword_t)1 << (x % BITS_IN_EWORD))
diff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c
index 6fe48d3ae0..c6d4ffc87c 100644
--- a/ewah/ewah_bitmap.c
+++ b/ewah/ewah_bitmap.c
@@ -17,9 +17,9 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "git-compat-util.h"
+#include "alloc.h"
#include "ewok.h"
#include "ewok_rlw.h"
-#include "cache.h"
static inline size_t min_size(size_t a, size_t b)
{
diff --git a/exec-cmd.c b/exec-cmd.c
index 0232bbc990..1d597e84ea 100644
--- a/exec-cmd.c
+++ b/exec-cmd.c
@@ -1,7 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "environment.h"
#include "exec-cmd.h"
+#include "gettext.h"
+#include "path.h"
#include "quote.h"
+#include "run-command.h"
#include "strvec.h"
+#include "trace.h"
+#include "trace2.h"
#if defined(RUNTIME_PREFIX)
diff --git a/fetch-pack.c b/fetch-pack.c
index 04016d1e32..a432eacab9 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -1,6 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "repository.h"
#include "config.h"
+#include "date.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "refs.h"
#include "pkt-line.h"
@@ -13,12 +18,14 @@
#include "remote.h"
#include "run-command.h"
#include "connect.h"
+#include "trace2.h"
#include "transport.h"
#include "version.h"
#include "oid-array.h"
#include "oidset.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "connected.h"
#include "fetch-negotiator.h"
#include "fsck.h"
@@ -27,6 +34,7 @@
#include "commit-graph.h"
#include "sigchain.h"
#include "mergesort.h"
+#include "wrapper.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@@ -722,7 +730,7 @@ static void filter_refs(struct fetch_pack_args *args,
*refs = newlist;
}
-static void mark_alternate_complete(struct fetch_negotiator *unused,
+static void mark_alternate_complete(struct fetch_negotiator *negotiator UNUSED,
struct object *obj)
{
mark_complete(&obj->oid);
@@ -762,9 +770,9 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
if (!commit) {
struct object *o;
- if (!has_object_file_with_flags(&ref->old_oid,
- OBJECT_INFO_QUICK |
- OBJECT_INFO_SKIP_FETCH_OBJECT))
+ if (!repo_has_object_file_with_flags(the_repository, &ref->old_oid,
+ OBJECT_INFO_QUICK |
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
continue;
o = parse_object(the_repository, &ref->old_oid);
if (!o || o->type != OBJ_COMMIT)
@@ -1094,7 +1102,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
struct ref *ref = copy_ref_list(orig_ref);
struct object_id oid;
const char *agent_feature;
- int agent_len;
+ size_t agent_len;
struct fetch_negotiator negotiator_alloc;
struct fetch_negotiator *negotiator;
@@ -1112,7 +1120,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
agent_supported = 1;
if (agent_len)
print_verbose(args, _("Server version is %.*s"),
- agent_len, agent_feature);
+ (int)agent_len, agent_feature);
}
if (!server_supports("session-id"))
@@ -1963,7 +1971,7 @@ static void update_shallow(struct fetch_pack_args *args,
struct oid_array extra = OID_ARRAY_INIT;
struct object_id *oid = si->shallow->oid;
for (i = 0; i < si->shallow->nr; i++)
- if (has_object_file(&oid[i]))
+ if (repo_has_object_file(the_repository, &oid[i]))
oid_array_append(&extra, &oid[i]);
if (extra.nr) {
setup_alternate_shallow(&shallow_lock,
diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
index f48f44f9cd..ac9c1b9c6c 100644
--- a/fmt-merge-msg.c
+++ b/fmt-merge-msg.c
@@ -1,8 +1,13 @@
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "diff.h"
#include "diff-merges.h"
+#include "hex.h"
#include "revision.h"
#include "tag.h"
#include "string-list.h"
@@ -10,6 +15,7 @@
#include "fmt-merge-msg.h"
#include "commit-reach.h"
#include "gpg-interface.h"
+#include "wildmatch.h"
static int use_branch_desc;
static int suppress_dest_pattern_seen;
@@ -17,8 +23,6 @@ static struct string_list suppress_dest_patterns = STRING_LIST_INIT_DUP;
int fmt_merge_msg_config(const char *key, const char *value, void *cb)
{
- int status = 0;
-
if (!strcmp(key, "merge.log") || !strcmp(key, "merge.summary")) {
int is_bool;
merge_log_config = git_config_bool_or_int(key, value, &is_bool);
@@ -37,9 +41,6 @@ int fmt_merge_msg_config(const char *key, const char *value, void *cb)
string_list_append(&suppress_dest_patterns, value);
suppress_dest_pattern_seen = 1;
} else {
- status = git_gpg_config(key, value, NULL);
- if (status)
- return status;
return git_default_config(key, value, cb);
}
return 0;
@@ -271,9 +272,10 @@ static void record_person_from_buf(int which, struct string_list *people,
static void record_person(int which, struct string_list *people,
struct commit *commit)
{
- const char *buffer = get_commit_buffer(commit, NULL);
+ const char *buffer = repo_get_commit_buffer(the_repository, commit,
+ NULL);
record_person_from_buf(which, people, buffer);
- unuse_commit_buffer(commit, buffer);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
}
static int cmp_string_list_util_as_integral(const void *a_, const void *b_)
@@ -384,7 +386,8 @@ static void shortlog(const char *name,
if (subjects.nr > limit)
continue;
- format_commit_message(commit, "%s", &sb, &ctx);
+ repo_format_commit_message(the_repository, commit, "%s", &sb,
+ &ctx);
strbuf_ltrim(&sb);
if (!sb.len)
@@ -506,7 +509,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,
strbuf_complete_line(tagbuf);
if (sig->len) {
strbuf_addch(tagbuf, '\n');
- strbuf_add_commented_lines(tagbuf, sig->buf, sig->len);
+ strbuf_add_commented_lines(tagbuf, sig->buf, sig->len,
+ comment_line_char);
}
}
@@ -519,7 +523,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
struct object_id *oid = origins.items[i].util;
enum object_type type;
unsigned long size;
- char *buf = read_object_file(oid, &type, &size);
+ char *buf = repo_read_object_file(the_repository, oid, &type,
+ &size);
char *origbuf = buf;
unsigned long len = size;
struct signature_check sigc = { NULL };
@@ -551,7 +556,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
strbuf_addch(&tagline, '\n');
strbuf_add_commented_lines(&tagline,
origins.items[first_tag].string,
- strlen(origins.items[first_tag].string));
+ strlen(origins.items[first_tag].string),
+ comment_line_char);
strbuf_insert(&tagbuf, 0, tagline.buf,
tagline.len);
strbuf_release(&tagline);
@@ -559,7 +565,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
strbuf_addch(&tagbuf, '\n');
strbuf_add_commented_lines(&tagbuf,
origins.items[i].string,
- strlen(origins.items[i].string));
+ strlen(origins.items[i].string),
+ comment_line_char);
fmt_tag_signature(&tagbuf, &sig, buf, len);
}
strbuf_release(&payload);
@@ -605,7 +612,9 @@ static void find_merge_parents(struct merge_parents *result,
* util field yet.
*/
obj = parse_object(the_repository, &oid);
- parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
+ parent = (struct commit *)repo_peel_to_type(the_repository,
+ NULL, 0, obj,
+ OBJ_COMMIT);
if (!parent)
continue;
commit_list_insert(parent, &parents);
diff --git a/fsck.c b/fsck.c
index 2b18717ee8..a219d6f2c0 100644
--- a/fsck.c
+++ b/fsck.c
@@ -1,5 +1,10 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "date.h"
+#include "dir.h"
+#include "hex.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "repository.h"
#include "object.h"
#include "attr.h"
@@ -353,7 +358,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
int result;
const char *name;
- if (parse_commit(commit))
+ if (repo_parse_commit(the_repository, commit))
return -1;
name = fsck_get_object_name(options, &commit->object.oid);
@@ -361,7 +366,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
fsck_put_object_name(options, get_commit_tree_oid(commit),
"%s:", name);
- result = options->walk((struct object *)get_commit_tree(commit),
+ result = options->walk((struct object *) repo_get_commit_tree(the_repository, commit),
OBJ_TREE, data, options);
if (result < 0)
return result;
@@ -1332,7 +1337,7 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,
if (oidset_contains(blobs_done, oid))
continue;
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf) {
if (is_promisor_object(oid))
continue;
diff --git a/fsck.h b/fsck.h
index 668330880e..e17730e9da 100644
--- a/fsck.h
+++ b/fsck.h
@@ -1,6 +1,7 @@
#ifndef GIT_FSCK_H
#define GIT_FSCK_H
+#include "object.h"
#include "oidset.h"
enum fsck_msg_type {
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index e24838f9a8..70d776c54f 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -3,7 +3,6 @@
#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
-#include "cache.h"
#include "dir.h"
#include "run-command.h"
#include "simple-ipc.h"
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 19d772f0f3..88575aa54c 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -1,7 +1,9 @@
-#include "cache.h"
-#include "fsmonitor.h"
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
+#include "gettext.h"
#include "simple-ipc.h"
#include "fsmonitor-ipc.h"
+#include "repository.h"
#include "run-command.h"
#include "strbuf.h"
#include "trace2.h"
diff --git a/fsmonitor-ll.h b/fsmonitor-ll.h
new file mode 100644
index 0000000000..0504ca07d6
--- /dev/null
+++ b/fsmonitor-ll.h
@@ -0,0 +1,52 @@
+#ifndef FSMONITOR_LL_H
+#define FSMONITOR_LL_H
+
+struct index_state;
+struct strbuf;
+
+extern struct trace_key trace_fsmonitor;
+
+/*
+ * Read the fsmonitor index extension and (if configured) restore the
+ * CE_FSMONITOR_VALID state.
+ */
+int read_fsmonitor_extension(struct index_state *istate, const void *data, unsigned long sz);
+
+/*
+ * Fill the fsmonitor_dirty ewah bits with their state from the index,
+ * before it is split during writing.
+ */
+void fill_fsmonitor_bitmap(struct index_state *istate);
+
+/*
+ * Write the CE_FSMONITOR_VALID state into the fsmonitor index
+ * extension. Reads from the fsmonitor_dirty ewah in the index.
+ */
+void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate);
+
+/*
+ * Add/remove the fsmonitor index extension
+ */
+void add_fsmonitor(struct index_state *istate);
+void remove_fsmonitor(struct index_state *istate);
+
+/*
+ * Add/remove the fsmonitor index extension as necessary based on the current
+ * core.fsmonitor setting.
+ */
+void tweak_fsmonitor(struct index_state *istate);
+
+/*
+ * Run the configured fsmonitor integration script and clear the
+ * CE_FSMONITOR_VALID bit for any files returned as dirty. Also invalidate
+ * any corresponding untracked cache directory structures. Optimized to only
+ * run the first time it is called.
+ */
+void refresh_fsmonitor(struct index_state *istate);
+
+/*
+ * Does the received result contain the "trivial" response?
+ */
+int fsmonitor_is_trivial_response(const struct strbuf *query_result);
+
+#endif /* FSMONITOR_LL_H */
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 899bfe9c81..b62acf44ae 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "gettext.h"
#include "repository.h"
#include "fsmonitor-ipc.h"
#include "fsmonitor-settings.h"
diff --git a/fsmonitor.c b/fsmonitor.c
index a5b9e75437..f670c50937 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -1,11 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
#include "ewah/ewok.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
#include "run-command.h"
#include "strbuf.h"
+#include "trace2.h"
#define INDEX_EXTENSION_VERSION1 (1)
#define INDEX_EXTENSION_VERSION2 (2)
diff --git a/fsmonitor.h b/fsmonitor.h
index edf7ce5203..5195a8624d 100644
--- a/fsmonitor.h
+++ b/fsmonitor.h
@@ -1,54 +1,12 @@
#ifndef FSMONITOR_H
#define FSMONITOR_H
-#include "cache.h"
+#include "fsmonitor-ll.h"
#include "dir.h"
#include "fsmonitor-settings.h"
-
-extern struct trace_key trace_fsmonitor;
-
-/*
- * Read the fsmonitor index extension and (if configured) restore the
- * CE_FSMONITOR_VALID state.
- */
-int read_fsmonitor_extension(struct index_state *istate, const void *data, unsigned long sz);
-
-/*
- * Fill the fsmonitor_dirty ewah bits with their state from the index,
- * before it is split during writing.
- */
-void fill_fsmonitor_bitmap(struct index_state *istate);
-
-/*
- * Write the CE_FSMONITOR_VALID state into the fsmonitor index
- * extension. Reads from the fsmonitor_dirty ewah in the index.
- */
-void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate);
-
-/*
- * Add/remove the fsmonitor index extension
- */
-void add_fsmonitor(struct index_state *istate);
-void remove_fsmonitor(struct index_state *istate);
-
-/*
- * Add/remove the fsmonitor index extension as necessary based on the current
- * core.fsmonitor setting.
- */
-void tweak_fsmonitor(struct index_state *istate);
-
-/*
- * Run the configured fsmonitor integration script and clear the
- * CE_FSMONITOR_VALID bit for any files returned as dirty. Also invalidate
- * any corresponding untracked cache directory structures. Optimized to only
- * run the first time it is called.
- */
-void refresh_fsmonitor(struct index_state *istate);
-
-/*
- * Does the received result contain the "trivial" response?
- */
-int fsmonitor_is_trivial_response(const struct strbuf *query_result);
+#include "object.h"
+#include "read-cache-ll.h"
+#include "trace.h"
/*
* Check if refresh_fsmonitor has been called at least once.
@@ -86,7 +44,7 @@ static inline void mark_fsmonitor_valid(struct index_state *istate, struct cache
!(ce->ce_flags & CE_FSMONITOR_VALID)) {
if (S_ISGITLINK(ce->ce_mode))
return;
- istate->cache_changed = 1;
+ istate->cache_changed |= FSMONITOR_CHANGED;
ce->ce_flags |= CE_FSMONITOR_VALID;
trace_printf_key(&trace_fsmonitor, "mark_fsmonitor_clean '%s'", ce->name);
}
diff --git a/gettext.c b/gettext.c
index f139008d0a..f27e94407b 100644
--- a/gettext.c
+++ b/gettext.c
@@ -2,7 +2,9 @@
* Copyright (c) 2010 Ævar Arnfjörð Bjarmason
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "environment.h"
#include "exec-cmd.h"
#include "gettext.h"
#include "strbuf.h"
@@ -100,6 +102,8 @@ static void init_gettext_charset(const char *domain)
setlocale(LC_CTYPE, "C");
}
+int git_gettext_enabled = 0;
+
void git_setup_gettext(void)
{
const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT);
@@ -119,6 +123,8 @@ void git_setup_gettext(void)
init_gettext_charset("git");
textdomain("git");
+ git_gettext_enabled = 1;
+
free(p);
}
diff --git a/gettext.h b/gettext.h
index d209911ebb..484cafa562 100644
--- a/gettext.h
+++ b/gettext.h
@@ -29,9 +29,11 @@
#define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))
#ifndef NO_GETTEXT
+extern int git_gettext_enabled;
void git_setup_gettext(void);
int gettext_width(const char *s);
#else
+#define git_gettext_enabled (0)
static inline void git_setup_gettext(void)
{
}
@@ -45,12 +47,16 @@ static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
{
if (!*msgid)
return "";
+ if (!git_gettext_enabled)
+ return msgid;
return gettext(msgid);
}
static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
const char *Q_(const char *msgid, const char *plu, unsigned long n)
{
+ if (!git_gettext_enabled)
+ return n == 1 ? msgid : plu;
return ngettext(msgid, plu, n);
}
diff --git a/git-compat-util.h b/git-compat-util.h
index 4f0028ce60..1889da7986 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -339,6 +339,25 @@ static inline const char *precompose_string_if_needed(const char *in)
int compat_mkdir_wo_trailing_slash(const char*, mode_t);
#endif
+#ifdef time
+#undef time
+#endif
+static inline time_t git_time(time_t *tloc)
+{
+ struct timeval tv;
+
+ /*
+ * Avoid time(NULL), which can disagree with gettimeofday(2)
+ * and filesystem timestamps.
+ */
+ gettimeofday(&tv, NULL);
+
+ if (tloc)
+ *tloc = tv.tv_sec;
+ return tv.tv_sec;
+}
+#define time git_time
+
#ifdef NO_STRUCT_ITIMERVAL
struct itimerval {
struct timeval it_interval;
@@ -606,8 +625,6 @@ static inline int git_has_dir_sep(const char *path)
#include "compat/bswap.h"
-#include "wildmatch.h"
-
struct strbuf;
/* General helper functions */
@@ -859,12 +876,6 @@ int git_lstat(const char *, struct stat *);
#define pread git_pread
ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
#endif
-/*
- * Forward decl that will remind us if its twin in cache.h changes.
- * This function is used in compat/pread.c. But we can't include
- * cache.h there.
- */
-ssize_t read_in_full(int fd, void *buf, size_t count);
#ifdef NO_SETENV
#define setenv gitsetenv
@@ -1225,6 +1236,7 @@ extern const unsigned char tolower_trans_tbl[256];
#undef isxdigit
extern const unsigned char sane_ctype[256];
+extern const signed char hexval_table[256];
#define GIT_SPACE 0x01
#define GIT_DIGIT 0x02
#define GIT_ALPHA 0x04
@@ -1287,6 +1299,25 @@ static inline int skip_iprefix(const char *str, const char *prefix,
return 0;
}
+/*
+ * Like skip_prefix_mem, but compare case-insensitively. Note that the
+ * comparison is done via tolower(), so it is strictly ASCII (no multi-byte
+ * characters or locale-specific conversions).
+ */
+static inline int skip_iprefix_mem(const char *buf, size_t len,
+ const char *prefix,
+ const char **out, size_t *outlen)
+{
+ do {
+ if (!*prefix) {
+ *out = buf;
+ *outlen = len;
+ return 1;
+ }
+ } while (len-- > 0 && tolower(*buf++) == tolower(*prefix++));
+ return 0;
+}
+
static inline int strtoul_ui(char const *s, int base, unsigned int *result)
{
unsigned long ul;
diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
index 992124cc67..e4e820e680 100755
--- a/git-difftool--helper.sh
+++ b/git-difftool--helper.sh
@@ -75,6 +75,11 @@ then
merge_tool="$GIT_DIFF_TOOL"
else
merge_tool="$(get_merge_tool)"
+ subshell_exit_status=$?
+ if test $subshell_exit_status -gt 1
+ then
+ exit $subshell_exit_status
+ fi
fi
fi
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index 9f99201bcc..1ff26170ff 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -97,7 +97,42 @@ merge_mode () {
test "$TOOL_MODE" = merge
}
+get_gui_default () {
+ if diff_mode
+ then
+ GUI_DEFAULT_KEY="difftool.guiDefault"
+ else
+ GUI_DEFAULT_KEY="mergetool.guiDefault"
+ fi
+ GUI_DEFAULT_CONFIG_LCASE=$(git config --default false --get "$GUI_DEFAULT_KEY" | tr 'A-Z' 'a-z')
+ if test "$GUI_DEFAULT_CONFIG_LCASE" = "auto"
+ then
+ if test -n "$DISPLAY"
+ then
+ GUI_DEFAULT=true
+ else
+ GUI_DEFAULT=false
+ fi
+ else
+ GUI_DEFAULT=$(git config --default false --bool --get "$GUI_DEFAULT_KEY")
+ subshell_exit_status=$?
+ if test $subshell_exit_status -ne 0
+ then
+ exit $subshell_exit_status
+ fi
+ fi
+ echo $GUI_DEFAULT
+}
+
gui_mode () {
+ if test -z "$GIT_MERGETOOL_GUI"
+ then
+ GIT_MERGETOOL_GUI=$(get_gui_default)
+ if test $? -ne 0
+ then
+ exit 2
+ fi
+ fi
test "$GIT_MERGETOOL_GUI" = true
}
@@ -467,6 +502,11 @@ get_merge_tool () {
is_guessed=false
# Check if a merge tool has been configured
merge_tool=$(get_configured_merge_tool)
+ subshell_exit_status=$?
+ if test $subshell_exit_status -gt "1"
+ then
+ exit $subshell_exit_status
+ fi
# Try to guess an appropriate merge tool if no tool has been set.
if test -z "$merge_tool"
then
diff --git a/git-mergetool.sh b/git-mergetool.sh
index f751d9cfe2..8a922893f7 100755
--- a/git-mergetool.sh
+++ b/git-mergetool.sh
@@ -451,7 +451,7 @@ print_noop_and_exit () {
main () {
prompt=$(git config --bool mergetool.prompt)
- GIT_MERGETOOL_GUI=false
+ GIT_MERGETOOL_GUI=
guessed_merge_tool=false
orderfile=
@@ -511,9 +511,14 @@ main () {
if test -z "$merge_tool"
then
- if ! merge_tool=$(get_merge_tool)
+ merge_tool=$(get_merge_tool)
+ subshell_exit_status=$?
+ if test $subshell_exit_status = 1
then
guessed_merge_tool=true
+ elif test $subshell_exit_status -gt 1
+ then
+ exit $subshell_exit_status
fi
fi
merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
diff --git a/git-send-email.perl b/git-send-email.perl
index 07f2a0cbea..affbb88509 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -87,8 +87,10 @@ git send-email --dump-aliases
Automating:
--identity <str> * Use the sendemail.<id> options.
- --to-cmd <str> * Email To: via `<str> \$patch_path`
- --cc-cmd <str> * Email Cc: via `<str> \$patch_path`
+ --to-cmd <str> * Email To: via `<str> \$patch_path`.
+ --cc-cmd <str> * Email Cc: via `<str> \$patch_path`.
+ --header-cmd <str> * Add headers via `<str> \$patch_path`.
+ --no-header-cmd * Disable any header command in use.
--suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.
--[no-]cc-cover * Email Cc: addresses in the cover letter.
--[no-]to-cover * Email To: addresses in the cover letter.
@@ -202,7 +204,7 @@ my (@to,@cc,@xh,$envelope_sender,
$author,$sender,$smtp_authpass,$annotate,$compose,$time);
# Things we either get from config, *or* are overridden on the
# command-line.
-my ($no_cc, $no_to, $no_bcc, $no_identity);
+my ($no_cc, $no_to, $no_bcc, $no_identity, $no_header_cmd);
my (@config_to, @getopt_to);
my (@config_cc, @getopt_cc);
my (@config_bcc, @getopt_bcc);
@@ -269,7 +271,7 @@ sub do_edit {
# Variables with corresponding config settings
my ($suppress_from, $signed_off_by_cc);
my ($cover_cc, $cover_to);
-my ($to_cmd, $cc_cmd);
+my ($to_cmd, $cc_cmd, $header_cmd);
my ($smtp_server, $smtp_server_port, @smtp_server_options);
my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
my ($batch_size, $relogin_delay);
@@ -318,6 +320,7 @@ my %config_settings = (
"tocmd" => \$to_cmd,
"cc" => \@config_cc,
"cccmd" => \$cc_cmd,
+ "headercmd" => \$header_cmd,
"aliasfiletype" => \$aliasfiletype,
"bcc" => \@config_bcc,
"suppresscc" => \@suppress_cc,
@@ -519,6 +522,8 @@ my %options = (
"compose" => \$compose,
"quiet" => \$quiet,
"cc-cmd=s" => \$cc_cmd,
+ "header-cmd=s" => \$header_cmd,
+ "no-header-cmd" => \$no_header_cmd,
"suppress-from!" => \$suppress_from,
"no-suppress-from" => sub {$suppress_from = 0},
"suppress-cc=s" => \@suppress_cc,
@@ -792,16 +797,46 @@ if (@rev_list_opts) {
@rev_list_opts);
}
-@files = handle_backup_files(@files);
+if (defined $sender) {
+ $sender =~ s/^\s+|\s+$//g;
+ ($sender) = expand_aliases($sender);
+} else {
+ $sender = $repoauthor->() || $repocommitter->() || '';
+}
+
+# $sender could be an already sanitized address
+# (e.g. sendemail.from could be manually sanitized by user).
+# But it's a no-op to run sanitize_address on an already sanitized address.
+$sender = sanitize_address($sender);
+
+$time = time - scalar $#files;
if ($validate) {
+ # FIFOs can only be read once, exclude them from validation.
+ my @real_files = ();
foreach my $f (@files) {
unless (-p $f) {
- validate_patch($f, $target_xfer_encoding);
+ push(@real_files, $f);
}
}
+
+ # Run the loop once again to avoid gaps in the counter due to FIFO
+ # arguments provided by the user.
+ my $num = 1;
+ my $num_files = scalar @real_files;
+ $ENV{GIT_SENDEMAIL_FILE_TOTAL} = "$num_files";
+ foreach my $r (@real_files) {
+ $ENV{GIT_SENDEMAIL_FILE_COUNTER} = "$num";
+ pre_process_file($r, 1);
+ validate_patch($r, $target_xfer_encoding);
+ $num += 1;
+ }
+ delete $ENV{GIT_SENDEMAIL_FILE_COUNTER};
+ delete $ENV{GIT_SENDEMAIL_FILE_TOTAL};
}
+@files = handle_backup_files(@files);
+
if (@files) {
unless ($quiet) {
print $_,"\n" for (@files);
@@ -1050,18 +1085,6 @@ if (!$force) {
}
}
-if (defined $sender) {
- $sender =~ s/^\s+|\s+$//g;
- ($sender) = expand_aliases($sender);
-} else {
- $sender = $repoauthor->() || $repocommitter->() || '';
-}
-
-# $sender could be an already sanitized address
-# (e.g. sendemail.from could be manually sanitized by user).
-# But it's a no-op to run sanitize_address on an already sanitized address.
-$sender = sanitize_address($sender);
-
my $to_whom = __("To whom should the emails be sent (if anyone)?");
my $prompting = 0;
if (!@initial_to && !defined $to_cmd) {
@@ -1221,10 +1244,6 @@ sub make_message_id {
#print "new message id = $message_id\n"; # Was useful for debugging
}
-
-
-$time = time - scalar $#files;
-
sub unquote_rfc2047 {
local ($_) = @_;
my $charset;
@@ -1502,16 +1521,7 @@ sub file_name_is_absolute {
return File::Spec::Functions::file_name_is_absolute($path);
}
-# Prepares the email, then asks the user what to do.
-#
-# If the user chooses to send the email, it's sent and 1 is returned.
-# If the user chooses not to send the email, 0 is returned.
-# If the user decides they want to make further edits, -1 is returned and the
-# caller is expected to call send_message again after the edits are performed.
-#
-# If an error occurs sending the email, this just dies.
-
-sub send_message {
+sub gen_header {
my @recipients = unique_email_list(@to);
@cc = (grep { my $cc = extract_valid_address_or_die($_);
not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
@@ -1537,7 +1547,7 @@ sub send_message {
To: $to${ccline}
Subject: $subject
Date: $date
-Message-Id: $message_id
+Message-ID: $message_id
";
if ($use_xmailer) {
$header .= "X-Mailer: git-send-email $gitversion\n";
@@ -1553,6 +1563,22 @@ Message-Id: $message_id
if (@xh) {
$header .= join("\n", @xh) . "\n";
}
+ my $recipients_ref = \@recipients;
+ return ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header);
+}
+
+# Prepares the email, then asks the user what to do.
+#
+# If the user chooses to send the email, it's sent and 1 is returned.
+# If the user chooses not to send the email, 0 is returned.
+# If the user decides they want to make further edits, -1 is returned and the
+# caller is expected to call send_message again after the edits are performed.
+#
+# If an error occurs sending the email, this just dies.
+
+sub send_message {
+ my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
+ my @recipients = @$recipients_ref;
my @sendmail_parameters = ('-i', @recipients);
my $raw_from = $sender;
@@ -1742,11 +1768,8 @@ $in_reply_to = $initial_in_reply_to;
$references = $initial_in_reply_to || '';
$message_num = 0;
-# Prepares the email, prompts the user, sends it out
-# Returns 0 if an edit was done and the function should be called again, or 1
-# otherwise.
-sub process_file {
- my ($t) = @_;
+sub pre_process_file {
+ my ($t, $quiet) = @_;
open my $fh, "<", $t or die sprintf(__("can't open file %s"), $t);
@@ -1765,16 +1788,17 @@ sub process_file {
$subject = $initial_subject;
$message = "";
$message_num++;
- # First unfold multiline header fields
+ undef $message_id;
+ # Retrieve and unfold header fields.
+ my @header_lines = ();
while(<$fh>) {
last if /^\s*$/;
- if (/^\s+\S/ and @header) {
- chomp($header[$#header]);
- s/^\s+/ /;
- $header[$#header] .= $_;
- } else {
- push(@header, $_);
- }
+ push(@header_lines, $_);
+ }
+ @header = unfold_headers(@header_lines);
+ # Add computed headers, if applicable.
+ unless ($no_header_cmd || ! $header_cmd) {
+ push @header, invoke_header_cmd($header_cmd, $t);
}
# Now parse the header
foreach(@header) {
@@ -1832,7 +1856,7 @@ sub process_file {
$has_mime_version = 1;
push @xh, $_;
}
- elsif (/^Message-Id: (.*)/i) {
+ elsif (/^Message-ID: (.*)/i) {
$message_id = $1;
}
elsif (/^Content-Transfer-Encoding: (.*)/i) {
@@ -1900,9 +1924,9 @@ sub process_file {
}
close $fh;
- push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
+ push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t, $quiet)
if defined $to_cmd;
- push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t)
+ push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t, $quiet)
if defined $cc_cmd && !$suppress_cc{'cccmd'};
if ($broken_encoding{$t} && !$has_content_type) {
@@ -1961,6 +1985,15 @@ sub process_file {
@initial_to = @to;
}
}
+}
+
+# Prepares the email, prompts the user, and sends it out
+# Returns 0 if an edit was done and the function should be called again, or 1
+# on the email being successfully sent out.
+sub process_file {
+ my ($t) = @_;
+
+ pre_process_file($t, $quiet);
my $message_was_sent = send_message();
if ($message_was_sent == -1) {
@@ -2006,15 +2039,64 @@ foreach my $t (@files) {
}
}
+# Execute a command and return its output lines as an array. Blank
+# lines which do not appear at the end of the output are reported as
+# errors.
+sub execute_cmd {
+ my ($prefix, $cmd, $file) = @_;
+ my @lines = ();
+ my $seen_blank_line = 0;
+ open my $fh, "-|", "$cmd \Q$file\E"
+ or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd);
+ while (my $line = <$fh>) {
+ die sprintf(__("(%s) Malformed output from '%s'"), $prefix, $cmd)
+ if $seen_blank_line;
+ if ($line =~ /^$/) {
+ $seen_blank_line = $line =~ /^$/;
+ next;
+ }
+ push @lines, $line;
+ }
+ close $fh
+ or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
+ return @lines;
+}
+
+# Process headers lines, unfolding multiline headers as defined by RFC
+# 2822.
+sub unfold_headers {
+ my @headers;
+ foreach(@_) {
+ last if /^\s*$/;
+ if (/^\s+\S/ and @headers) {
+ chomp($headers[$#headers]);
+ s/^\s+/ /;
+ $headers[$#headers] .= $_;
+ } else {
+ push(@headers, $_);
+ }
+ }
+ return @headers;
+}
+
+# Invoke the provided CMD with FILE as an argument, which should
+# output RFC 2822 email headers. Fold multiline headers and return the
+# headers as an array.
+sub invoke_header_cmd {
+ my ($cmd, $file) = @_;
+ my @lines = execute_cmd("header-cmd", $header_cmd, $file);
+ return unfold_headers(@lines);
+}
+
# Execute a command (e.g. $to_cmd) to get a list of email addresses
# and return a results array
sub recipients_cmd {
- my ($prefix, $what, $cmd, $file) = @_;
-
+ my ($prefix, $what, $cmd, $file, $quiet) = @_;
+ my @lines = ();
my @addresses = ();
- open my $fh, "-|", "$cmd \Q$file\E"
- or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd);
- while (my $address = <$fh>) {
+
+ @lines = execute_cmd($prefix, $cmd, $file);
+ for my $address (@lines) {
$address =~ s/^\s*//g;
$address =~ s/\s*$//g;
$address = sanitize_address($address);
@@ -2023,8 +2105,6 @@ sub recipients_cmd {
printf(__("(%s) Adding %s: %s from: '%s'\n"),
$prefix, $what, $address, $cmd) unless $quiet;
}
- close $fh
- or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
return @addresses;
}
@@ -2095,10 +2175,21 @@ sub validate_patch {
chdir($repo->wc_path() or $repo->repo_path())
or die("chdir: $!");
local $ENV{"GIT_DIR"} = $repo->repo_path();
+
+ my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
+
+ require File::Temp;
+ my ($header_filehandle, $header_filename) = File::Temp::tempfile(
+ TEMPLATE => ".gitsendemail.header.XXXXXX",
+ DIR => $repo->repo_path(),
+ UNLINK => 1,
+ );
+ print $header_filehandle $header;
+
my @cmd = ("git", "hook", "run", "--ignore-missing",
$hook_name, "--");
- my @cmd_msg = (@cmd, "<patch>");
- my @cmd_run = (@cmd, $target);
+ my @cmd_msg = (@cmd, "<patch>", "<header>");
+ my @cmd_run = (@cmd, $target, $header_filename);
$hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
chdir($cwd_save) or die("chdir: $!");
}
diff --git a/zlib.c b/git-zlib.c
index d594cba3fc..d43bbeb6da 100644
--- a/zlib.c
+++ b/git-zlib.c
@@ -2,7 +2,8 @@
* zlib wrappers to make sure we don't silently miss errors
* at init time.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "git-zlib.h"
static const char *zerr_to_string(int status)
{
diff --git a/git-zlib.h b/git-zlib.h
new file mode 100644
index 0000000000..d8a670aff9
--- /dev/null
+++ b/git-zlib.h
@@ -0,0 +1,28 @@
+#ifndef GIT_ZLIB_H
+#define GIT_ZLIB_H
+
+typedef struct git_zstream {
+ z_stream z;
+ unsigned long avail_in;
+ unsigned long avail_out;
+ unsigned long total_in;
+ unsigned long total_out;
+ unsigned char *next_in;
+ unsigned char *next_out;
+} git_zstream;
+
+void git_inflate_init(git_zstream *);
+void git_inflate_init_gzip_only(git_zstream *);
+void git_inflate_end(git_zstream *);
+int git_inflate(git_zstream *, int flush);
+
+void git_deflate_init(git_zstream *, int level);
+void git_deflate_init_gzip(git_zstream *, int level);
+void git_deflate_init_raw(git_zstream *, int level);
+void git_deflate_end(git_zstream *);
+int git_deflate_abort(git_zstream *);
+int git_deflate_end_gently(git_zstream *);
+int git_deflate(git_zstream *, int flush);
+unsigned long git_deflate_bound(git_zstream *, unsigned long);
+
+#endif /* GIT_ZLIB_H */
diff --git a/git.c b/git.c
index 6171fd6769..eb69f4f997 100644
--- a/git.c
+++ b/git.c
@@ -1,10 +1,19 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "exec-cmd.h"
+#include "gettext.h"
#include "help.h"
+#include "pager.h"
+#include "read-cache-ll.h"
#include "run-command.h"
#include "alias.h"
+#include "replace-object.h"
+#include "setup.h"
+#include "attr.h"
#include "shallow.h"
+#include "trace.h"
+#include "trace2.h"
#define RUN_SETUP (1<<0)
#define RUN_SETUP_GENTLY (1<<1)
@@ -307,6 +316,21 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
} else {
exit(list_cmds(cmd));
}
+ } else if (!strcmp(cmd, "--attr-source")) {
+ if (*argc < 2) {
+ fprintf(stderr, _("no attribute source given for --attr-source\n" ));
+ usage(git_usage_string);
+ }
+ setenv(GIT_ATTR_SOURCE_ENVIRONMENT, (*argv)[1], 1);
+ if (envchanged)
+ *envchanged = 1;
+ (*argv)++;
+ (*argc)--;
+ } else if (skip_prefix(cmd, "--attr-source=", &cmd)) {
+ set_git_attr_source(cmd);
+ setenv(GIT_ATTR_SOURCE_ENVIRONMENT, cmd, 1);
+ if (envchanged)
+ *envchanged = 1;
} else {
fprintf(stderr, _("unknown option: %s\n"), cmd);
usage(git_usage_string);
@@ -583,7 +607,7 @@ static struct cmd_struct commands[] = {
{ "show-branch", cmd_show_branch, RUN_SETUP },
{ "show-index", cmd_show_index, RUN_SETUP_GENTLY },
{ "show-ref", cmd_show_ref, RUN_SETUP },
- { "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
+ { "sparse-checkout", cmd_sparse_checkout, RUN_SETUP },
{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
{ "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 0ae7d68590..df3ba2ea99 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -353,6 +353,16 @@ proc parseviewrevs {view revs} {
return $ret
}
+# Escapes a list of filter paths to be passed to git log via stdin. Note that
+# paths must not be quoted.
+proc escape_filter_paths {paths} {
+ set escaped [list]
+ foreach path $paths {
+ lappend escaped [string map {\\ \\\\ "\ " "\\\ "} $path]
+ }
+ return $escaped
+}
+
# Start off a git log process and arrange to read its output
proc start_rev_list {view} {
global startmsecs commitidx viewcomplete curview
@@ -405,14 +415,17 @@ proc start_rev_list {view} {
if {$revs eq {}} {
return 0
}
- set args [concat $vflags($view) $revs]
+ set args $vflags($view)
} else {
+ set revs {}
set args $vorigargs($view)
}
if {[catch {
set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
- --parents --boundary $args "--" $files] r]
+ --parents --boundary $args --stdin \
+ "<<[join [concat $revs "--" \
+ [escape_filter_paths $files]] "\\n"]"] r]
} err]} {
error_popup "[mc "Error executing git log:"] $err"
return 0
@@ -554,13 +567,20 @@ proc updatecommits {} {
set revs $newrevs
set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]]
}
- set args [concat $vflags($view) $revs --not $oldpos]
+ set args $vflags($view)
+ foreach r $oldpos {
+ lappend revs "^$r"
+ }
} else {
+ set revs {}
set args $vorigargs($view)
}
if {[catch {
set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
- --parents --boundary $args "--" $vfilelimit($view)] r]
+ --parents --boundary $args --stdin \
+ "<<[join [concat $revs "--" \
+ [escape_filter_paths \
+ $vfilelimit($view)]] "\\n"]"] r]
} err]} {
error_popup "[mc "Error executing git log:"] $err"
return
@@ -10231,10 +10251,16 @@ proc getallcommits {} {
foreach id $seeds {
lappend ids "^$id"
}
+ lappend ids "--"
}
}
if {$ids ne {}} {
- set fd [open [concat $cmd $ids] r]
+ if {$ids eq "--all"} {
+ set cmd [concat $cmd "--all"]
+ } else {
+ set cmd [concat $cmd --stdin "<<[join $ids "\\n"]"]
+ }
+ set fd [open $cmd r]
fconfigure $fd -blocking 0
incr allcommits
nowbusy allcommits
diff --git a/gpg-interface.c b/gpg-interface.c
index 5cd66d3a78..6a3817bbca 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -1,13 +1,31 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "commit.h"
#include "config.h"
+#include "date.h"
+#include "gettext.h"
#include "run-command.h"
#include "strbuf.h"
#include "dir.h"
+#include "ident.h"
#include "gpg-interface.h"
+#include "path.h"
#include "sigchain.h"
#include "tempfile.h"
#include "alias.h"
+#include "wrapper.h"
+#include "environment.h"
+
+static int git_gpg_config(const char *, const char *, void *);
+
+static void gpg_interface_lazy_init(void)
+{
+ static int done;
+
+ if (done)
+ return;
+ done = 1;
+ git_config(git_gpg_config, NULL);
+}
static char *configured_signing_key;
static const char *ssh_default_key_command, *ssh_allowed_signers, *ssh_revocation_file;
@@ -569,8 +587,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
}
}
- strbuf_stripspace(&ssh_keygen_out, 0);
- strbuf_stripspace(&ssh_keygen_err, 0);
+ strbuf_stripspace(&ssh_keygen_out, '\0');
+ strbuf_stripspace(&ssh_keygen_err, '\0');
/* Add stderr outputs to show the user actual ssh-keygen errors */
strbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);
strbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);
@@ -632,8 +650,10 @@ int check_signature(struct signature_check *sigc,
struct gpg_format *fmt;
int status;
+ gpg_interface_lazy_init();
+
sigc->result = 'N';
- sigc->trust_level = -1;
+ sigc->trust_level = TRUST_UNDEFINED;
fmt = get_format_by_sig(signature);
if (!fmt)
@@ -695,11 +715,13 @@ int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct
void set_signing_key(const char *key)
{
+ gpg_interface_lazy_init();
+
free(configured_signing_key);
configured_signing_key = xstrdup(key);
}
-int git_gpg_config(const char *var, const char *value, void *cb UNUSED)
+static int git_gpg_config(const char *var, const char *value, void *cb UNUSED)
{
struct gpg_format *fmt = NULL;
char *fmtname = NULL;
@@ -888,6 +910,8 @@ static const char *get_ssh_key_id(void) {
/* Returns a textual but unique representation of the signing key */
const char *get_signing_key_id(void)
{
+ gpg_interface_lazy_init();
+
if (use_format->get_key_id) {
return use_format->get_key_id();
}
@@ -898,6 +922,8 @@ const char *get_signing_key_id(void)
const char *get_signing_key(void)
{
+ gpg_interface_lazy_init();
+
if (configured_signing_key)
return configured_signing_key;
if (use_format->get_default_key) {
@@ -923,6 +949,8 @@ const char *gpg_trust_level_to_str(enum signature_trust_level level)
int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
{
+ gpg_interface_lazy_init();
+
return use_format->sign_buffer(buffer, signature, signing_key);
}
@@ -1025,7 +1053,7 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
ssh_signing_key_file = strbuf_detach(&key_file->filename, NULL);
} else {
/* We assume a file */
- ssh_signing_key_file = expand_user_path(signing_key, 1);
+ ssh_signing_key_file = interpolate_path(signing_key, 1);
}
buffer_file = mks_tempfile_t(".git_signing_buffer_tmpXXXXXX");
diff --git a/gpg-interface.h b/gpg-interface.h
index 8a9ef41779..143cdc1c02 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -79,7 +79,6 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
*/
const char *gpg_trust_level_to_str(enum signature_trust_level level);
-int git_gpg_config(const char *, const char *, void *);
void set_signing_key(const char *);
const char *get_signing_key(void);
diff --git a/graph.c b/graph.c
index 568b6e7cd4..2a9dc430fa 100644
--- a/graph.c
+++ b/graph.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
#include "config.h"
#include "commit.h"
#include "color.h"
diff --git a/grep.c b/grep.c
index cee44a78d0..ebcd647478 100644
--- a/grep.c
+++ b/grep.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "gettext.h"
#include "grep.h"
-#include "object-store.h"
+#include "hex.h"
+#include "object-store-ll.h"
+#include "pretty.h"
#include "userdiff.h"
#include "xdiff-interface.h"
#include "diff.h"
@@ -9,6 +12,7 @@
#include "commit.h"
#include "quote.h"
#include "help.h"
+#include "wrapper.h"
static int grep_source_load(struct grep_source *gs);
static int grep_source_is_binary(struct grep_source *gs,
@@ -320,6 +324,15 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
if (!opt->ignore_locale && is_utf8_locale() && !literal)
options |= (PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_INVALID_UTF);
+#ifndef GIT_PCRE2_VERSION_10_35_OR_HIGHER
+ /*
+ * Work around a JIT bug related to invalid Unicode character handling
+ * fixed in 10.35:
+ * https://github.com/PCRE2Project/pcre2/commit/c21bd977547d
+ */
+ options &= ~PCRE2_UCP;
+#endif
+
#ifndef GIT_PCRE2_VERSION_10_36_OR_HIGHER
/* Work around https://bugs.exim.org/show_bug.cgi?id=2642 fixed in 10.36 */
if (PCRE2_MATCH_INVALID_UTF && options & (PCRE2_UTF | PCRE2_CASELESS))
diff --git a/grep.h b/grep.h
index 6075f997e6..c59592e3bd 100644
--- a/grep.h
+++ b/grep.h
@@ -7,6 +7,9 @@
#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 36) || PCRE2_MAJOR >= 11
#define GIT_PCRE2_VERSION_10_36_OR_HIGHER
#endif
+#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 35) || PCRE2_MAJOR >= 11
+#define GIT_PCRE2_VERSION_10_35_OR_HIGHER
+#endif
#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 34) || PCRE2_MAJOR >= 11
#define GIT_PCRE2_VERSION_10_34_OR_HIGHER
#endif
diff --git a/hash-ll.h b/hash-ll.h
new file mode 100644
index 0000000000..8d7973769f
--- /dev/null
+++ b/hash-ll.h
@@ -0,0 +1,295 @@
+#ifndef HASH_LL_H
+#define HASH_LL_H
+
+#if defined(SHA1_APPLE)
+#include <CommonCrypto/CommonDigest.h>
+#elif defined(SHA1_OPENSSL)
+#include <openssl/sha.h>
+#elif defined(SHA1_DC)
+#include "sha1dc_git.h"
+#else /* SHA1_BLK */
+#include "block-sha1/sha1.h"
+#endif
+
+#if defined(SHA256_NETTLE)
+#include "sha256/nettle.h"
+#elif defined(SHA256_GCRYPT)
+#define SHA256_NEEDS_CLONE_HELPER
+#include "sha256/gcrypt.h"
+#elif defined(SHA256_OPENSSL)
+#include <openssl/sha.h>
+#else
+#include "sha256/block/sha256.h"
+#endif
+
+#ifndef platform_SHA_CTX
+/*
+ * platform's underlying implementation of SHA-1; could be OpenSSL,
+ * blk_SHA, Apple CommonCrypto, etc... Note that the relevant
+ * SHA-1 header may have already defined platform_SHA_CTX for our
+ * own implementations like block-sha1, so we list
+ * the default for OpenSSL compatible SHA-1 implementations here.
+ */
+#define platform_SHA_CTX SHA_CTX
+#define platform_SHA1_Init SHA1_Init
+#define platform_SHA1_Update SHA1_Update
+#define platform_SHA1_Final SHA1_Final
+#endif
+
+#define git_SHA_CTX platform_SHA_CTX
+#define git_SHA1_Init platform_SHA1_Init
+#define git_SHA1_Update platform_SHA1_Update
+#define git_SHA1_Final platform_SHA1_Final
+
+#ifndef platform_SHA256_CTX
+#define platform_SHA256_CTX SHA256_CTX
+#define platform_SHA256_Init SHA256_Init
+#define platform_SHA256_Update SHA256_Update
+#define platform_SHA256_Final SHA256_Final
+#endif
+
+#define git_SHA256_CTX platform_SHA256_CTX
+#define git_SHA256_Init platform_SHA256_Init
+#define git_SHA256_Update platform_SHA256_Update
+#define git_SHA256_Final platform_SHA256_Final
+
+#ifdef platform_SHA256_Clone
+#define git_SHA256_Clone platform_SHA256_Clone
+#endif
+
+#ifdef SHA1_MAX_BLOCK_SIZE
+#include "compat/sha1-chunked.h"
+#undef git_SHA1_Update
+#define git_SHA1_Update git_SHA1_Update_Chunked
+#endif
+
+static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+
+#ifndef SHA256_NEEDS_CLONE_HELPER
+static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+#endif
+
+/*
+ * Note that these constants are suitable for indexing the hash_algos array and
+ * comparing against each other, but are otherwise arbitrary, so they should not
+ * be exposed to the user or serialized to disk. To know whether a
+ * git_hash_algo struct points to some usable hash function, test the format_id
+ * field for being non-zero. Use the name field for user-visible situations and
+ * the format_id field for fixed-length fields on disk.
+ */
+/* An unknown hash function. */
+#define GIT_HASH_UNKNOWN 0
+/* SHA-1 */
+#define GIT_HASH_SHA1 1
+/* SHA-256 */
+#define GIT_HASH_SHA256 2
+/* Number of algorithms supported (including unknown). */
+#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
+
+/* "sha1", big-endian */
+#define GIT_SHA1_FORMAT_ID 0x73686131
+
+/* The length in bytes and in hex digits of an object name (SHA-1 value). */
+#define GIT_SHA1_RAWSZ 20
+#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
+/* The block size of SHA-1. */
+#define GIT_SHA1_BLKSZ 64
+
+/* "s256", big-endian */
+#define GIT_SHA256_FORMAT_ID 0x73323536
+
+/* The length in bytes and in hex digits of an object name (SHA-256 value). */
+#define GIT_SHA256_RAWSZ 32
+#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
+/* The block size of SHA-256. */
+#define GIT_SHA256_BLKSZ 64
+
+/* The length in byte and in hex digits of the largest possible hash value. */
+#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
+#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
+/* The largest possible block size for any supported hash. */
+#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
+
+struct object_id {
+ unsigned char hash[GIT_MAX_RAWSZ];
+ int algo; /* XXX requires 4-byte alignment */
+};
+
+#define GET_OID_QUIETLY 01
+#define GET_OID_COMMIT 02
+#define GET_OID_COMMITTISH 04
+#define GET_OID_TREE 010
+#define GET_OID_TREEISH 020
+#define GET_OID_BLOB 040
+#define GET_OID_FOLLOW_SYMLINKS 0100
+#define GET_OID_RECORD_PATH 0200
+#define GET_OID_ONLY_TO_DIE 04000
+#define GET_OID_REQUIRE_PATH 010000
+
+#define GET_OID_DISAMBIGUATORS \
+ (GET_OID_COMMIT | GET_OID_COMMITTISH | \
+ GET_OID_TREE | GET_OID_TREEISH | \
+ GET_OID_BLOB)
+
+enum get_oid_result {
+ FOUND = 0,
+ MISSING_OBJECT = -1, /* The requested object is missing */
+ SHORT_NAME_AMBIGUOUS = -2,
+ /* The following only apply when symlinks are followed */
+ DANGLING_SYMLINK = -4, /*
+ * The initial symlink is there, but
+ * (transitively) points to a missing
+ * in-tree file
+ */
+ SYMLINK_LOOP = -5,
+ NOT_DIR = -6, /*
+ * Somewhere along the symlink chain, a path is
+ * requested which contains a file as a
+ * non-final element.
+ */
+};
+
+/* A suitably aligned type for stack allocations of hash contexts. */
+union git_hash_ctx {
+ git_SHA_CTX sha1;
+ git_SHA256_CTX sha256;
+};
+typedef union git_hash_ctx git_hash_ctx;
+
+typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
+typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
+typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
+typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
+typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);
+
+struct git_hash_algo {
+ /*
+ * The name of the algorithm, as appears in the config file and in
+ * messages.
+ */
+ const char *name;
+
+ /* A four-byte version identifier, used in pack indices. */
+ uint32_t format_id;
+
+ /* The length of the hash in binary. */
+ size_t rawsz;
+
+ /* The length of the hash in hex characters. */
+ size_t hexsz;
+
+ /* The block size of the hash. */
+ size_t blksz;
+
+ /* The hash initialization function. */
+ git_hash_init_fn init_fn;
+
+ /* The hash context cloning function. */
+ git_hash_clone_fn clone_fn;
+
+ /* The hash update function. */
+ git_hash_update_fn update_fn;
+
+ /* The hash finalization function. */
+ git_hash_final_fn final_fn;
+
+ /* The hash finalization function for object IDs. */
+ git_hash_final_oid_fn final_oid_fn;
+
+ /* The OID of the empty tree. */
+ const struct object_id *empty_tree;
+
+ /* The OID of the empty blob. */
+ const struct object_id *empty_blob;
+
+ /* The all-zeros OID. */
+ const struct object_id *null_oid;
+};
+extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];
+
+/*
+ * Return a GIT_HASH_* constant based on the name. Returns GIT_HASH_UNKNOWN if
+ * the name doesn't match a known algorithm.
+ */
+int hash_algo_by_name(const char *name);
+/* Identical, except based on the format ID. */
+int hash_algo_by_id(uint32_t format_id);
+/* Identical, except based on the length. */
+int hash_algo_by_length(int len);
+/* Identical, except for a pointer to struct git_hash_algo. */
+static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
+{
+ return p - hash_algos;
+}
+
+const struct object_id *null_oid(void);
+
+static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
+{
+ /*
+ * Teach the compiler that there are only two possibilities of hash size
+ * here, so that it can optimize for this case as much as possible.
+ */
+ if (algop->rawsz == GIT_MAX_RAWSZ)
+ return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
+ return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
+}
+
+static inline int hasheq_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
+{
+ /*
+ * We write this here instead of deferring to hashcmp so that the
+ * compiler can properly inline it and avoid calling memcmp.
+ */
+ if (algop->rawsz == GIT_MAX_RAWSZ)
+ return !memcmp(sha1, sha2, GIT_MAX_RAWSZ);
+ return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
+}
+
+static inline void oidcpy(struct object_id *dst, const struct object_id *src)
+{
+ memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
+ dst->algo = src->algo;
+}
+
+static inline struct object_id *oiddup(const struct object_id *src)
+{
+ struct object_id *dst = xmalloc(sizeof(struct object_id));
+ oidcpy(dst, src);
+ return dst;
+}
+
+static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop)
+{
+ oid->algo = hash_algo_by_ptr(algop);
+}
+
+/*
+ * Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code
+ * for use in hash tables. Cryptographic hashes are supposed to have
+ * uniform distribution, so in contrast to `memhash()`, this just copies
+ * the first `sizeof(int)` bytes without shuffling any bits. Note that
+ * the results will be different on big-endian and little-endian
+ * platforms, so they should not be stored or transferred over the net.
+ */
+static inline unsigned int oidhash(const struct object_id *oid)
+{
+ /*
+ * Equivalent to 'return *(unsigned int *)oid->hash;', but safe on
+ * platforms that don't support unaligned reads.
+ */
+ unsigned int hash;
+ memcpy(&hash, oid->hash, sizeof(hash));
+ return hash;
+}
+
+const char *empty_tree_oid_hex(void);
+const char *empty_blob_oid_hex(void);
+
+#endif
diff --git a/hash-lookup.c b/hash-lookup.c
index b98ed5e11e..9f0f95e2b9 100644
--- a/hash-lookup.c
+++ b/hash-lookup.c
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hash.h"
#include "hash-lookup.h"
+#include "read-cache-ll.h"
static uint32_t take2(const struct object_id *oid, size_t ofs)
{
diff --git a/hash.h b/hash.h
index 36b64165fc..615ae0691d 100644
--- a/hash.h
+++ b/hash.h
@@ -1,217 +1,11 @@
#ifndef HASH_H
#define HASH_H
-#include "git-compat-util.h"
+#include "hash-ll.h"
#include "repository.h"
-#if defined(SHA1_APPLE)
-#include <CommonCrypto/CommonDigest.h>
-#elif defined(SHA1_OPENSSL)
-#include <openssl/sha.h>
-#elif defined(SHA1_DC)
-#include "sha1dc_git.h"
-#else /* SHA1_BLK */
-#include "block-sha1/sha1.h"
-#endif
-
-#if defined(SHA256_NETTLE)
-#include "sha256/nettle.h"
-#elif defined(SHA256_GCRYPT)
-#define SHA256_NEEDS_CLONE_HELPER
-#include "sha256/gcrypt.h"
-#elif defined(SHA256_OPENSSL)
-#include <openssl/sha.h>
-#else
-#include "sha256/block/sha256.h"
-#endif
-
-#ifndef platform_SHA_CTX
-/*
- * platform's underlying implementation of SHA-1; could be OpenSSL,
- * blk_SHA, Apple CommonCrypto, etc... Note that the relevant
- * SHA-1 header may have already defined platform_SHA_CTX for our
- * own implementations like block-sha1, so we list
- * the default for OpenSSL compatible SHA-1 implementations here.
- */
-#define platform_SHA_CTX SHA_CTX
-#define platform_SHA1_Init SHA1_Init
-#define platform_SHA1_Update SHA1_Update
-#define platform_SHA1_Final SHA1_Final
-#endif
-
-#define git_SHA_CTX platform_SHA_CTX
-#define git_SHA1_Init platform_SHA1_Init
-#define git_SHA1_Update platform_SHA1_Update
-#define git_SHA1_Final platform_SHA1_Final
-
-#ifndef platform_SHA256_CTX
-#define platform_SHA256_CTX SHA256_CTX
-#define platform_SHA256_Init SHA256_Init
-#define platform_SHA256_Update SHA256_Update
-#define platform_SHA256_Final SHA256_Final
-#endif
-
-#define git_SHA256_CTX platform_SHA256_CTX
-#define git_SHA256_Init platform_SHA256_Init
-#define git_SHA256_Update platform_SHA256_Update
-#define git_SHA256_Final platform_SHA256_Final
-
-#ifdef platform_SHA256_Clone
-#define git_SHA256_Clone platform_SHA256_Clone
-#endif
-
-#ifdef SHA1_MAX_BLOCK_SIZE
-#include "compat/sha1-chunked.h"
-#undef git_SHA1_Update
-#define git_SHA1_Update git_SHA1_Update_Chunked
-#endif
-
-static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-
-#ifndef SHA256_NEEDS_CLONE_HELPER
-static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-#endif
-
-/*
- * Note that these constants are suitable for indexing the hash_algos array and
- * comparing against each other, but are otherwise arbitrary, so they should not
- * be exposed to the user or serialized to disk. To know whether a
- * git_hash_algo struct points to some usable hash function, test the format_id
- * field for being non-zero. Use the name field for user-visible situations and
- * the format_id field for fixed-length fields on disk.
- */
-/* An unknown hash function. */
-#define GIT_HASH_UNKNOWN 0
-/* SHA-1 */
-#define GIT_HASH_SHA1 1
-/* SHA-256 */
-#define GIT_HASH_SHA256 2
-/* Number of algorithms supported (including unknown). */
-#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
-
-/* "sha1", big-endian */
-#define GIT_SHA1_FORMAT_ID 0x73686131
-
-/* The length in bytes and in hex digits of an object name (SHA-1 value). */
-#define GIT_SHA1_RAWSZ 20
-#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
-/* The block size of SHA-1. */
-#define GIT_SHA1_BLKSZ 64
-
-/* "s256", big-endian */
-#define GIT_SHA256_FORMAT_ID 0x73323536
-
-/* The length in bytes and in hex digits of an object name (SHA-256 value). */
-#define GIT_SHA256_RAWSZ 32
-#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
-/* The block size of SHA-256. */
-#define GIT_SHA256_BLKSZ 64
-
-/* The length in byte and in hex digits of the largest possible hash value. */
-#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
-#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
-/* The largest possible block size for any supported hash. */
-#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
-
-struct object_id {
- unsigned char hash[GIT_MAX_RAWSZ];
- int algo; /* XXX requires 4-byte alignment */
-};
-
-/* A suitably aligned type for stack allocations of hash contexts. */
-union git_hash_ctx {
- git_SHA_CTX sha1;
- git_SHA256_CTX sha256;
-};
-typedef union git_hash_ctx git_hash_ctx;
-
-typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
-typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
-typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
-typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
-typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);
-
-struct git_hash_algo {
- /*
- * The name of the algorithm, as appears in the config file and in
- * messages.
- */
- const char *name;
-
- /* A four-byte version identifier, used in pack indices. */
- uint32_t format_id;
-
- /* The length of the hash in binary. */
- size_t rawsz;
-
- /* The length of the hash in hex characters. */
- size_t hexsz;
-
- /* The block size of the hash. */
- size_t blksz;
-
- /* The hash initialization function. */
- git_hash_init_fn init_fn;
-
- /* The hash context cloning function. */
- git_hash_clone_fn clone_fn;
-
- /* The hash update function. */
- git_hash_update_fn update_fn;
-
- /* The hash finalization function. */
- git_hash_final_fn final_fn;
-
- /* The hash finalization function for object IDs. */
- git_hash_final_oid_fn final_oid_fn;
-
- /* The OID of the empty tree. */
- const struct object_id *empty_tree;
-
- /* The OID of the empty blob. */
- const struct object_id *empty_blob;
-
- /* The all-zeros OID. */
- const struct object_id *null_oid;
-};
-extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];
-
-/*
- * Return a GIT_HASH_* constant based on the name. Returns GIT_HASH_UNKNOWN if
- * the name doesn't match a known algorithm.
- */
-int hash_algo_by_name(const char *name);
-/* Identical, except based on the format ID. */
-int hash_algo_by_id(uint32_t format_id);
-/* Identical, except based on the length. */
-int hash_algo_by_length(int len);
-/* Identical, except for a pointer to struct git_hash_algo. */
-static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
-{
- return p - hash_algos;
-}
-
#define the_hash_algo the_repository->hash_algo
-const struct object_id *null_oid(void);
-
-static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
-{
- /*
- * Teach the compiler that there are only two possibilities of hash size
- * here, so that it can optimize for this case as much as possible.
- */
- if (algop->rawsz == GIT_MAX_RAWSZ)
- return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
- return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
-}
-
static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
{
return hashcmp_algop(sha1, sha2, the_hash_algo);
@@ -227,17 +21,6 @@ static inline int oidcmp(const struct object_id *oid1, const struct object_id *o
return hashcmp_algop(oid1->hash, oid2->hash, algop);
}
-static inline int hasheq_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
-{
- /*
- * We write this here instead of deferring to hashcmp so that the
- * compiler can properly inline it and avoid calling memcmp.
- */
- if (algop->rawsz == GIT_MAX_RAWSZ)
- return !memcmp(sha1, sha2, GIT_MAX_RAWSZ);
- return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
-}
-
static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
{
return hasheq_algop(sha1, sha2, the_hash_algo);
@@ -263,12 +46,6 @@ static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
memcpy(sha_dst, sha_src, the_hash_algo->rawsz);
}
-static inline void oidcpy(struct object_id *dst, const struct object_id *src)
-{
- memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
- dst->algo = src->algo;
-}
-
/* Like oidcpy() but zero-pads the unused bytes in dst's hash array. */
static inline void oidcpy_with_padding(struct object_id *dst,
const struct object_id *src)
@@ -285,13 +62,6 @@ static inline void oidcpy_with_padding(struct object_id *dst,
dst->algo = src->algo;
}
-static inline struct object_id *oiddup(const struct object_id *src)
-{
- struct object_id *dst = xmalloc(sizeof(struct object_id));
- oidcpy(dst, src);
- return dst;
-}
-
static inline void hashclr(unsigned char *hash)
{
memset(hash, 0, the_hash_algo->rawsz);
@@ -329,12 +99,4 @@ static inline int is_empty_tree_oid(const struct object_id *oid)
return oideq(oid, the_hash_algo->empty_tree);
}
-static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop)
-{
- oid->algo = hash_algo_by_ptr(algop);
-}
-
-const char *empty_tree_oid_hex(void);
-const char *empty_blob_oid_hex(void);
-
#endif
diff --git a/hashmap.c b/hashmap.c
index cf5fea87eb..ee45ef0085 100644
--- a/hashmap.c
+++ b/hashmap.c
@@ -1,7 +1,7 @@
/*
* Generic implementation of hash-based key value mappings.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "hashmap.h"
#define FNV32_BASE ((unsigned int) 0x811c9dc5)
diff --git a/hashmap.h b/hashmap.h
index 7251687d73..c8216e47bb 100644
--- a/hashmap.h
+++ b/hashmap.h
@@ -1,8 +1,6 @@
#ifndef HASHMAP_H
#define HASHMAP_H
-#include "hash.h"
-
/*
* Generic implementation of hash-based key-value mappings.
*
@@ -121,25 +119,6 @@ unsigned int memihash(const void *buf, size_t len);
unsigned int memihash_cont(unsigned int hash_seed, const void *buf, size_t len);
/*
- * Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code
- * for use in hash tables. Cryptographic hashes are supposed to have
- * uniform distribution, so in contrast to `memhash()`, this just copies
- * the first `sizeof(int)` bytes without shuffling any bits. Note that
- * the results will be different on big-endian and little-endian
- * platforms, so they should not be stored or transferred over the net.
- */
-static inline unsigned int oidhash(const struct object_id *oid)
-{
- /*
- * Equivalent to 'return *(unsigned int *)oid->hash;', but safe on
- * platforms that don't support unaligned reads.
- */
- unsigned int hash;
- memcpy(&hash, oid->hash, sizeof(hash));
- return hash;
-}
-
-/*
* struct hashmap_entry is an opaque structure representing an entry in the
* hash table.
* Ideally it should be followed by an int-sized member to prevent unused
@@ -270,7 +249,7 @@ void hashmap_clear_(struct hashmap *map, ssize_t offset);
#define hashmap_clear(map) hashmap_clear_(map, -1)
/*
- * Similar to hashmap_clear(), except that the table is no deallocated; it
+ * Similar to hashmap_clear(), except that the table is not deallocated; it
* is merely zeroed out but left the same size as before. If the hashmap
* will be reused, this avoids the overhead of deallocating and
* reallocating map->table. As with hashmap_clear(), you may need to free
diff --git a/help.c b/help.c
index 812af4cdea..5d7637dce9 100644
--- a/help.c
+++ b/help.c
@@ -1,9 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
#include "builtin.h"
#include "exec-cmd.h"
#include "run-command.h"
#include "levenshtein.h"
+#include "gettext.h"
#include "help.h"
#include "command-list.h"
#include "string-list.h"
@@ -540,7 +542,8 @@ static struct cmdnames aliases;
#define AUTOCORRECT_NEVER (-2)
#define AUTOCORRECT_IMMEDIATELY (-1)
-static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
+static int git_unknown_cmd_config(const char *var, const char *value,
+ void *cb UNUSED)
{
const char *p;
diff --git a/hex.c b/hex.c
index 4f64d34696..7bb440e794 100644
--- a/hex.c
+++ b/hex.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hash.h"
+#include "hex.h"
const signed char hexval_table[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, /* 00-07 */
diff --git a/hex.h b/hex.h
new file mode 100644
index 0000000000..7df4b3c460
--- /dev/null
+++ b/hex.h
@@ -0,0 +1,84 @@
+#ifndef HEX_H
+#define HEX_H
+
+#include "hash-ll.h"
+
+extern const signed char hexval_table[256];
+static inline unsigned int hexval(unsigned char c)
+{
+ return hexval_table[c];
+}
+
+/*
+ * Convert two consecutive hexadecimal digits into a char. Return a
+ * negative value on error. Don't run over the end of short strings.
+ */
+static inline int hex2chr(const char *s)
+{
+ unsigned int val = hexval(s[0]);
+ return (val & ~0xf) ? val : (val << 4) | hexval(s[1]);
+}
+
+/*
+ * Try to read a SHA1 in hexadecimal format from the 40 characters
+ * starting at hex. Write the 20-byte result to sha1 in binary form.
+ * Return 0 on success. Reading stops if a NUL is encountered in the
+ * input, so it is safe to pass this function an arbitrary
+ * null-terminated string.
+ */
+int get_sha1_hex(const char *hex, unsigned char *sha1);
+int get_oid_hex(const char *hex, struct object_id *sha1);
+
+/* Like get_oid_hex, but for an arbitrary hash algorithm. */
+int get_oid_hex_algop(const char *hex, struct object_id *oid, const struct git_hash_algo *algop);
+
+/*
+ * Read `len` pairs of hexadecimal digits from `hex` and write the
+ * values to `binary` as `len` bytes. Return 0 on success, or -1 if
+ * the input does not consist of hex digits).
+ */
+int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
+
+/*
+ * Convert a binary hash in "unsigned char []" or an object name in
+ * "struct object_id *" to its hex equivalent. The `_r` variant is reentrant,
+ * and writes the NUL-terminated output to the buffer `out`, which must be at
+ * least `GIT_MAX_HEXSZ + 1` bytes, and returns a pointer to out for
+ * convenience.
+ *
+ * The non-`_r` variant returns a static buffer, but uses a ring of 4
+ * buffers, making it safe to make multiple calls for a single statement, like:
+ *
+ * printf("%s -> %s", hash_to_hex(one), hash_to_hex(two));
+ * printf("%s -> %s", oid_to_hex(one), oid_to_hex(two));
+ */
+char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, const struct git_hash_algo *);
+char *oid_to_hex_r(char *out, const struct object_id *oid);
+char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *); /* static buffer result! */
+char *hash_to_hex(const unsigned char *hash); /* same static buffer */
+char *oid_to_hex(const struct object_id *oid); /* same static buffer */
+
+/*
+ * Parse a 40-character hexadecimal object ID starting from hex, updating the
+ * pointer specified by end when parsing stops. The resulting object ID is
+ * stored in oid. Returns 0 on success. Parsing will stop on the first NUL or
+ * other invalid character. end is only updated on success; otherwise, it is
+ * unmodified.
+ */
+int parse_oid_hex(const char *hex, struct object_id *oid, const char **end);
+
+/* Like parse_oid_hex, but for an arbitrary hash algorithm. */
+int parse_oid_hex_algop(const char *hex, struct object_id *oid, const char **end,
+ const struct git_hash_algo *algo);
+
+
+/*
+ * These functions work like get_oid_hex and parse_oid_hex, but they will parse
+ * a hex value for any algorithm. The algorithm is detected based on the length
+ * and the algorithm in use is returned. If this is not a hex object ID in any
+ * algorithm, returns GIT_HASH_UNKNOWN.
+ */
+int get_oid_hex_any(const char *hex, struct object_id *oid);
+int parse_oid_hex_any(const char *hex, struct object_id *oid, const char **end);
+
+#endif
diff --git a/hook.c b/hook.c
index 1a84831863..f6306d72b3 100644
--- a/hook.c
+++ b/hook.c
@@ -1,7 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "advice.h"
+#include "gettext.h"
#include "hook.h"
+#include "path.h"
#include "run-command.h"
#include "config.h"
+#include "strbuf.h"
const char *find_hook(const char *name)
{
@@ -43,9 +48,9 @@ int hook_exists(const char *name)
}
static int pick_next_hook(struct child_process *cp,
- struct strbuf *out,
+ struct strbuf *out UNUSED,
void *pp_cb,
- void **pp_task_cb)
+ void **pp_task_cb UNUSED)
{
struct hook_cb_data *hook_cb = pp_cb;
const char *hook_path = hook_cb->hook_path;
@@ -77,9 +82,9 @@ static int pick_next_hook(struct child_process *cp,
return 1;
}
-static int notify_start_failure(struct strbuf *out,
+static int notify_start_failure(struct strbuf *out UNUSED,
void *pp_cb,
- void *pp_task_cp)
+ void *pp_task_cp UNUSED)
{
struct hook_cb_data *hook_cb = pp_cb;
@@ -89,9 +94,9 @@ static int notify_start_failure(struct strbuf *out,
}
static int notify_hook_finished(int result,
- struct strbuf *out,
+ struct strbuf *out UNUSED,
void *pp_cb,
- void *pp_task_cb)
+ void *pp_task_cb UNUSED)
{
struct hook_cb_data *hook_cb = pp_cb;
struct run_hooks_opt *opt = hook_cb->options;
diff --git a/http-backend.c b/http-backend.c
index 8ab58e55f8..895fac35f7 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -1,5 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
+#include "git-zlib.h"
+#include "hex.h"
+#include "path.h"
#include "repository.h"
#include "refs.h"
#include "pkt-line.h"
@@ -11,9 +16,11 @@
#include "url.h"
#include "strvec.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "protocol.h"
#include "date.h"
+#include "wrapper.h"
+#include "write-or-die.h"
static const char content_type[] = "Content-Type";
static const char content_length[] = "Content-Length";
@@ -524,7 +531,7 @@ static int show_text_ref(const char *name, const struct object_id *oid,
return 0;
}
-static void get_info_refs(struct strbuf *hdr, char *arg)
+static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)
{
const char *service_name = get_parameter("service");
struct strbuf buf = STRBUF_INIT;
@@ -553,7 +560,7 @@ static void get_info_refs(struct strbuf *hdr, char *arg)
} else {
select_getanyfile(hdr);
- for_each_namespaced_ref(show_text_ref, &buf);
+ for_each_namespaced_ref(NULL, show_text_ref, &buf);
send_strbuf(hdr, "text/plain", &buf);
}
strbuf_release(&buf);
@@ -578,7 +585,7 @@ static int show_head_ref(const char *refname, const struct object_id *oid,
return 0;
}
-static void get_head(struct strbuf *hdr, char *arg)
+static void get_head(struct strbuf *hdr, char *arg UNUSED)
{
struct strbuf buf = STRBUF_INIT;
@@ -588,7 +595,7 @@ static void get_head(struct strbuf *hdr, char *arg)
strbuf_release(&buf);
}
-static void get_info_packs(struct strbuf *hdr, char *arg)
+static void get_info_packs(struct strbuf *hdr, char *arg UNUSED)
{
size_t objdirlen = strlen(get_object_directory());
struct strbuf buf = STRBUF_INIT;
@@ -736,7 +743,7 @@ static int bad_request(struct strbuf *hdr, const struct service_cmd *c)
return 0;
}
-int cmd_main(int argc, const char **argv)
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
{
char *method = getenv("REQUEST_METHOD");
const char *proto_header;
diff --git a/http-fetch.c b/http-fetch.c
index 258fec2068..fffda59267 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "exec-cmd.h"
+#include "gettext.h"
+#include "hex.h"
#include "http.h"
#include "walker.h"
+#include "setup.h"
#include "strvec.h"
#include "urlmatch.h"
#include "trace2.h"
diff --git a/http-push.c b/http-push.c
index 7f71316456..9ab2383d2b 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "hex.h"
#include "repository.h"
#include "commit.h"
#include "tag.h"
@@ -10,10 +12,13 @@
#include "exec-cmd.h"
#include "remote.h"
#include "list-objects.h"
+#include "setup.h"
#include "sigchain.h"
#include "strvec.h"
+#include "tree.h"
+#include "tree-walk.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "commit-reach.h"
#ifdef EXPAT_NEEDS_XMLPARSE_H
@@ -362,7 +367,8 @@ static void start_put(struct transfer_request *request)
ssize_t size;
git_zstream stream;
- unpacked = read_object_file(&request->obj->oid, &type, &len);
+ unpacked = repo_read_object_file(the_repository, &request->obj->oid,
+ &type, &len);
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
/* Set it up */
@@ -601,7 +607,7 @@ static void finish_request(struct transfer_request *request)
}
static int is_running_queue;
-static int fill_active_slot(void *unused)
+static int fill_active_slot(void *data UNUSED)
{
struct transfer_request *request;
@@ -1331,7 +1337,8 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
int count = 0;
while ((commit = get_revision(revs)) != NULL) {
- p = process_tree(get_commit_tree(commit), p);
+ p = process_tree(repo_get_commit_tree(the_repository, commit),
+ p);
commit->object.flags |= LOCAL;
if (!(commit->object.flags & UNINTERESTING))
count += add_send_request(&commit->object, lock);
@@ -1426,7 +1433,7 @@ static void one_remote_ref(const char *refname)
* Fetch a copy of the object if it doesn't exist locally - it
* may be required for updating server info later.
*/
- if (repo->can_update_info_refs && !has_object_file(&ref->old_oid)) {
+ if (repo->can_update_info_refs && !repo_has_object_file(the_repository, &ref->old_oid)) {
obj = lookup_unknown_object(the_repository, &ref->old_oid);
fprintf(stderr, " fetch %s for %s\n",
oid_to_hex(&ref->old_oid), refname);
@@ -1570,7 +1577,7 @@ static int verify_merge_base(struct object_id *head_oid, struct ref *remote)
struct commit *branch = lookup_commit_or_die(&remote->old_oid,
remote->name);
- return in_merge_bases(branch, head);
+ return repo_in_merge_bases(the_repository, branch, head);
}
static int delete_remote_branch(const char *pattern, int force)
@@ -1627,14 +1634,14 @@ static int delete_remote_branch(const char *pattern, int force)
return error("Remote HEAD symrefs too deep");
if (is_null_oid(&head_oid))
return error("Unable to resolve remote HEAD");
- if (!has_object_file(&head_oid))
+ if (!repo_has_object_file(the_repository, &head_oid))
return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", oid_to_hex(&head_oid));
/* Remote branch must resolve to a known object */
if (is_null_oid(&remote_ref->old_oid))
return error("Unable to resolve remote branch %s",
remote_ref->name);
- if (!has_object_file(&remote_ref->old_oid))
+ if (!repo_has_object_file(the_repository, &remote_ref->old_oid))
return error("Remote branch %s resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", remote_ref->name, oid_to_hex(&remote_ref->old_oid));
/* Remote branch must be an ancestor of remote HEAD */
@@ -1854,7 +1861,7 @@ int cmd_main(int argc, const char **argv)
if (!force_all &&
!is_null_oid(&ref->old_oid) &&
!ref->force) {
- if (!has_object_file(&ref->old_oid) ||
+ if (!repo_has_object_file(the_repository, &ref->old_oid) ||
!ref_newer(&ref->peer_ref->new_oid,
&ref->old_oid)) {
/*
diff --git a/http-walker.c b/http-walker.c
index b8f0f98ae1..78d99f7c4b 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -1,12 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "repository.h"
#include "commit.h"
+#include "hex.h"
#include "walker.h"
#include "http.h"
#include "list.h"
#include "transport.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
struct alt_base {
char *base;
@@ -52,8 +53,7 @@ static void fetch_alternates(struct walker *walker, const char *base);
static void process_object_response(void *callback_data);
-static void start_object_request(struct walker *walker,
- struct object_request *obj_req)
+static void start_object_request(struct object_request *obj_req)
{
struct active_request_slot *slot;
struct http_object_request *req;
@@ -110,7 +110,7 @@ static void process_object_response(void *callback_data)
obj_req->repo =
obj_req->repo->next;
release_http_object_request(obj_req->req);
- start_object_request(walker, obj_req);
+ start_object_request(obj_req);
return;
}
}
@@ -127,7 +127,7 @@ static void release_object_request(struct object_request *obj_req)
free(obj_req);
}
-static int fill_active_slot(struct walker *walker)
+static int fill_active_slot(void *data UNUSED)
{
struct object_request *obj_req;
struct list_head *pos, *tmp, *head = &object_queue_head;
@@ -135,10 +135,10 @@ static int fill_active_slot(struct walker *walker)
list_for_each_safe(pos, tmp, head) {
obj_req = list_entry(pos, struct object_request, node);
if (obj_req->state == WAITING) {
- if (has_object_file(&obj_req->oid))
+ if (repo_has_object_file(the_repository, &obj_req->oid))
obj_req->state = COMPLETE;
else {
- start_object_request(walker, obj_req);
+ start_object_request(obj_req);
return 1;
}
}
@@ -492,7 +492,7 @@ static int fetch_object(struct walker *walker, unsigned char *hash)
if (!obj_req)
return error("Couldn't find request for %s in the queue", hex);
- if (has_object_file(&obj_req->oid)) {
+ if (repo_has_object_file(the_repository, &obj_req->oid)) {
if (obj_req->req)
abort_http_object_request(obj_req->req);
abort_object_request(obj_req);
@@ -613,7 +613,7 @@ struct walker *get_http_walker(const char *url)
walker->cleanup = cleanup;
walker->data = data;
- add_fill_function(walker, (int (*)(void *)) fill_active_slot);
+ add_fill_function(NULL, fill_active_slot);
return walker;
}
diff --git a/http.c b/http.c
index c4b6ddef28..25e4c8a1ae 100644
--- a/http.c
+++ b/http.c
@@ -1,5 +1,6 @@
#include "git-compat-util.h"
#include "git-curl-compat.h"
+#include "hex.h"
#include "http.h"
#include "config.h"
#include "pack.h"
@@ -11,11 +12,13 @@
#include "version.h"
#include "pkt-line.h"
#include "gettext.h"
+#include "trace.h"
#include "transport.h"
#include "packfile.h"
#include "protocol.h"
#include "string-list.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
static int trace_curl_data = 1;
@@ -39,6 +42,7 @@ static int curl_ssl_verify = -1;
static int curl_ssl_try;
static const char *curl_http_version = NULL;
static const char *ssl_cert;
+static const char *ssl_cert_type;
static const char *ssl_cipherlist;
static const char *ssl_version;
static struct {
@@ -58,6 +62,7 @@ static struct {
#endif
};
static const char *ssl_key;
+static const char *ssl_key_type;
static const char *ssl_capath;
static const char *curl_no_proxy;
#ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
@@ -181,6 +186,115 @@ size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
return nmemb;
}
+/*
+ * A folded header continuation line starts with any number of spaces or
+ * horizontal tab characters (SP or HTAB) as per RFC 7230 section 3.2.
+ * It is not a continuation line if the line starts with any other character.
+ */
+static inline int is_hdr_continuation(const char *ptr, const size_t size)
+{
+ return size && (*ptr == ' ' || *ptr == '\t');
+}
+
+static size_t fwrite_wwwauth(char *ptr, size_t eltsize, size_t nmemb, void *p)
+{
+ size_t size = eltsize * nmemb;
+ struct strvec *values = &http_auth.wwwauth_headers;
+ struct strbuf buf = STRBUF_INIT;
+ const char *val;
+ size_t val_len;
+
+ /*
+ * Header lines may not come NULL-terminated from libcurl so we must
+ * limit all scans to the maximum length of the header line, or leverage
+ * strbufs for all operations.
+ *
+ * In addition, it is possible that header values can be split over
+ * multiple lines as per RFC 7230. 'Line folding' has been deprecated
+ * but older servers may still emit them. A continuation header field
+ * value is identified as starting with a space or horizontal tab.
+ *
+ * The formal definition of a header field as given in RFC 7230 is:
+ *
+ * header-field = field-name ":" OWS field-value OWS
+ *
+ * field-name = token
+ * field-value = *( field-content / obs-fold )
+ * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+ * field-vchar = VCHAR / obs-text
+ *
+ * obs-fold = CRLF 1*( SP / HTAB )
+ * ; obsolete line folding
+ * ; see Section 3.2.4
+ */
+
+ /* Start of a new WWW-Authenticate header */
+ if (skip_iprefix_mem(ptr, size, "www-authenticate:", &val, &val_len)) {
+ strbuf_add(&buf, val, val_len);
+
+ /*
+ * Strip the CRLF that should be present at the end of each
+ * field as well as any trailing or leading whitespace from the
+ * value.
+ */
+ strbuf_trim(&buf);
+
+ strvec_push(values, buf.buf);
+ http_auth.header_is_last_match = 1;
+ goto exit;
+ }
+
+ /*
+ * This line could be a continuation of the previously matched header
+ * field. If this is the case then we should append this value to the
+ * end of the previously consumed value.
+ */
+ if (http_auth.header_is_last_match && is_hdr_continuation(ptr, size)) {
+ /*
+ * Trim the CRLF and any leading or trailing from this line.
+ */
+ strbuf_add(&buf, ptr, size);
+ strbuf_trim(&buf);
+
+ /*
+ * At this point we should always have at least one existing
+ * value, even if it is empty. Do not bother appending the new
+ * value if this continuation header is itself empty.
+ */
+ if (!values->nr) {
+ BUG("should have at least one existing header value");
+ } else if (buf.len) {
+ char *prev = xstrdup(values->v[values->nr - 1]);
+
+ /* Join two non-empty values with a single space. */
+ const char *const sp = *prev ? " " : "";
+
+ strvec_pop(values);
+ strvec_pushf(values, "%s%s%s", prev, sp, buf.buf);
+ free(prev);
+ }
+
+ goto exit;
+ }
+
+ /* Not a continuation of a previously matched auth header line. */
+ http_auth.header_is_last_match = 0;
+
+ /*
+ * If this is a HTTP status line and not a header field, this signals
+ * a different HTTP response. libcurl writes all the output of all
+ * response headers of all responses, including redirects.
+ * We only care about the last HTTP request response's headers so clear
+ * the existing array.
+ */
+ if (skip_iprefix_mem(ptr, size, "http/", &val, &val_len))
+ strvec_clear(values);
+
+exit:
+ strbuf_release(&buf);
+ return size;
+}
+
size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
{
return nmemb;
@@ -264,8 +378,12 @@ static int http_options(const char *var, const char *value, void *cb)
return git_config_string(&ssl_version, var, value);
if (!strcmp("http.sslcert", var))
return git_config_pathname(&ssl_cert, var, value);
+ if (!strcmp("http.sslcerttype", var))
+ return git_config_string(&ssl_cert_type, var, value);
if (!strcmp("http.sslkey", var))
return git_config_pathname(&ssl_key, var, value);
+ if (!strcmp("http.sslkeytype", var))
+ return git_config_string(&ssl_key_type, var, value);
if (!strcmp("http.sslcapath", var))
return git_config_pathname(&ssl_capath, var, value);
if (!strcmp("http.sslcainfo", var))
@@ -904,10 +1022,14 @@ static CURL *get_curl_handle(void)
if (ssl_cert)
curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
+ if (ssl_cert_type)
+ curl_easy_setopt(result, CURLOPT_SSLCERTTYPE, ssl_cert_type);
if (has_cert_password())
curl_easy_setopt(result, CURLOPT_KEYPASSWD, cert_auth.password);
if (ssl_key)
curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
+ if (ssl_key_type)
+ curl_easy_setopt(result, CURLOPT_SSLKEYTYPE, ssl_key_type);
if (ssl_capath)
curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath);
#ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
@@ -1142,7 +1264,9 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
curl_ssl_verify = 0;
set_from_env(&ssl_cert, "GIT_SSL_CERT");
+ set_from_env(&ssl_cert_type, "GIT_SSL_CERT_TYPE");
set_from_env(&ssl_key, "GIT_SSL_KEY");
+ set_from_env(&ssl_key_type, "GIT_SSL_KEY_TYPE");
set_from_env(&ssl_capath, "GIT_SSL_CAPATH");
set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO");
@@ -1895,6 +2019,8 @@ static int http_request(const char *url,
fwrite_buffer);
}
+ curl_easy_setopt(slot->curl, CURLOPT_HEADERFUNCTION, fwrite_wwwauth);
+
accept_language = http_get_accept_language_header();
if (accept_language)
diff --git a/http.h b/http.h
index 77c042706c..3a409bccd4 100644
--- a/http.h
+++ b/http.h
@@ -1,7 +1,9 @@
#ifndef HTTP_H
#define HTTP_H
-#include "cache.h"
+struct packed_git;
+
+#include "git-zlib.h"
#include <curl/curl.h>
#include <curl/easy.h>
diff --git a/ident.c b/ident.c
index 6de76f9421..8fad92d700 100644
--- a/ident.c
+++ b/ident.c
@@ -5,10 +5,13 @@
*
* Copyright (C) 2005 Linus Torvalds
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "ident.h"
#include "config.h"
#include "date.h"
+#include "gettext.h"
#include "mailmap.h"
+#include "strbuf.h"
static struct strbuf git_default_name = STRBUF_INIT;
static struct strbuf git_default_email = STRBUF_INIT;
diff --git a/ident.h b/ident.h
new file mode 100644
index 0000000000..96a64896a0
--- /dev/null
+++ b/ident.h
@@ -0,0 +1,67 @@
+#ifndef IDENT_H
+#define IDENT_H
+
+#include "string-list.h"
+
+struct ident_split {
+ const char *name_begin;
+ const char *name_end;
+ const char *mail_begin;
+ const char *mail_end;
+ const char *date_begin;
+ const char *date_end;
+ const char *tz_begin;
+ const char *tz_end;
+};
+
+#define IDENT_STRICT 1
+#define IDENT_NO_DATE 2
+#define IDENT_NO_NAME 4
+
+enum want_ident {
+ WANT_BLANK_IDENT,
+ WANT_AUTHOR_IDENT,
+ WANT_COMMITTER_IDENT
+};
+
+const char *ident_default_name(void);
+const char *ident_default_email(void);
+/*
+ * Prepare an ident to fall back on if the user didn't configure it.
+ */
+void prepare_fallback_ident(const char *name, const char *email);
+void reset_ident_date(void);
+/*
+ * Signals an success with 0, but time part of the result may be NULL
+ * if the input lacks timestamp and zone
+ */
+int split_ident_line(struct ident_split *, const char *, int);
+
+/*
+ * Given a commit or tag object buffer and the commit or tag headers, replaces
+ * the idents in the headers with their canonical versions using the mailmap mechanism.
+ */
+void apply_mailmap_to_header(struct strbuf *, const char **, struct string_list *);
+
+/*
+ * Compare split idents for equality or strict ordering. Note that we
+ * compare only the ident part of the line, ignoring any timestamp.
+ *
+ * Because there are two fields, we must choose one as the primary key; we
+ * currently arbitrarily pick the email.
+ */
+int ident_cmp(const struct ident_split *, const struct ident_split *);
+
+const char *git_author_info(int);
+const char *git_committer_info(int);
+const char *fmt_ident(const char *name, const char *email,
+ enum want_ident whose_ident,
+ const char *date_str, int);
+const char *fmt_name(enum want_ident);
+
+int committer_ident_sufficiently_given(void);
+int author_ident_sufficiently_given(void);
+
+int git_ident_config(const char *, const char *, void *);
+
+#endif
diff --git a/imap-send.c b/imap-send.c
index a50af56b82..d1f312a07c 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -21,35 +21,29 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "credential.h"
#include "exec-cmd.h"
+#include "gettext.h"
#include "run-command.h"
#include "parse-options.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "wrapper.h"
#if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG)
typedef void *SSL;
#endif
-#ifdef USE_CURL_FOR_IMAP_SEND
#include "http.h"
-#endif
-
-#if defined(USE_CURL_FOR_IMAP_SEND)
-/* Always default to curl if it's available. */
-#define USE_CURL_DEFAULT 1
-#else
-/* We don't have curl, so continue to use the historical implementation */
-#define USE_CURL_DEFAULT 0
-#endif
static int verbosity;
-static int use_curl = USE_CURL_DEFAULT;
+static int use_curl = 1;
static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] < <mbox>", NULL };
static struct option imap_send_options[] = {
OPT__VERBOSITY(&verbosity),
- OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
+ OPT_HIDDEN_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
OPT_END()
};
@@ -207,14 +201,7 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret)
}
}
-#ifdef NO_OPENSSL
-static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
-{
- fprintf(stderr, "SSL requested but SSL support not compiled in\n");
- return -1;
-}
-
-#else
+#ifndef NO_OPENSSL
static int host_matches(const char *host, const char *pattern)
{
@@ -263,7 +250,7 @@ static int verify_hostname(X509 *cert, const char *hostname)
cname, hostname);
}
-static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
+static int ssl_socket_connect(struct imap_socket *sock, int verify)
{
#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
const SSL_METHOD *meth;
@@ -289,8 +276,7 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
return -1;
}
- if (use_tls_only)
- SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
if (verify)
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
@@ -935,7 +921,7 @@ static void server_fill_credential(struct imap_server_conf *srvc, struct credent
return;
cred->protocol = xstrdup(srvc->use_ssl ? "imaps" : "imap");
- cred->host = xstrdup(srvc->host);
+ cred->host = xstrdup(srvc->tunnel ? "tunnel" : srvc->host);
cred->username = xstrdup_or_null(srvc->user);
cred->password = xstrdup_or_null(srvc->pass);
@@ -954,7 +940,8 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
struct imap_store *ctx;
struct imap *imap;
char *arg, *rsp;
- int s = -1, preauth;
+ int preauth;
+ struct child_process tunnel = CHILD_PROCESS_INIT;
CALLOC_ARRAY(ctx, 1);
@@ -963,107 +950,19 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
imap->in_progress_append = &imap->in_progress;
/* open connection to IMAP server */
+ imap_info("Starting tunnel '%s'... ", srvc->tunnel);
- if (srvc->tunnel) {
- struct child_process tunnel = CHILD_PROCESS_INIT;
-
- imap_info("Starting tunnel '%s'... ", srvc->tunnel);
-
- strvec_push(&tunnel.args, srvc->tunnel);
- tunnel.use_shell = 1;
- tunnel.in = -1;
- tunnel.out = -1;
- if (start_command(&tunnel))
- die("cannot start proxy %s", srvc->tunnel);
-
- imap->buf.sock.fd[0] = tunnel.out;
- imap->buf.sock.fd[1] = tunnel.in;
-
- imap_info("ok\n");
- } else {
-#ifndef NO_IPV6
- struct addrinfo hints, *ai0, *ai;
- int gai;
- char portstr[6];
-
- xsnprintf(portstr, sizeof(portstr), "%d", srvc->port);
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
-
- imap_info("Resolving %s... ", srvc->host);
- gai = getaddrinfo(srvc->host, portstr, &hints, &ai);
- if (gai) {
- fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai));
- goto bail;
- }
- imap_info("ok\n");
-
- for (ai0 = ai; ai; ai = ai->ai_next) {
- char addr[NI_MAXHOST];
-
- s = socket(ai->ai_family, ai->ai_socktype,
- ai->ai_protocol);
- if (s < 0)
- continue;
-
- getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
- sizeof(addr), NULL, 0, NI_NUMERICHOST);
- imap_info("Connecting to [%s]:%s... ", addr, portstr);
-
- if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
- close(s);
- s = -1;
- perror("connect");
- continue;
- }
-
- break;
- }
- freeaddrinfo(ai0);
-#else /* NO_IPV6 */
- struct hostent *he;
- struct sockaddr_in addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_port = htons(srvc->port);
- addr.sin_family = AF_INET;
-
- imap_info("Resolving %s... ", srvc->host);
- he = gethostbyname(srvc->host);
- if (!he) {
- perror("gethostbyname");
- goto bail;
- }
- imap_info("ok\n");
-
- addr.sin_addr.s_addr = *((int *) he->h_addr_list[0]);
-
- s = socket(PF_INET, SOCK_STREAM, 0);
-
- imap_info("Connecting to %s:%hu... ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
- if (connect(s, (struct sockaddr *)&addr, sizeof(addr))) {
- close(s);
- s = -1;
- perror("connect");
- }
-#endif
- if (s < 0) {
- fputs("Error: unable to connect to server.\n", stderr);
- goto bail;
- }
+ strvec_push(&tunnel.args, srvc->tunnel);
+ tunnel.use_shell = 1;
+ tunnel.in = -1;
+ tunnel.out = -1;
+ if (start_command(&tunnel))
+ die("cannot start proxy %s", srvc->tunnel);
- imap->buf.sock.fd[0] = s;
- imap->buf.sock.fd[1] = dup(s);
+ imap->buf.sock.fd[0] = tunnel.out;
+ imap->buf.sock.fd[1] = tunnel.in;
- if (srvc->use_ssl &&
- ssl_socket_connect(&imap->buf.sock, 0, srvc->ssl_verify)) {
- close(s);
- goto bail;
- }
- imap_info("ok\n");
- }
+ imap_info("ok\n");
/* read the greeting string */
if (buffer_gets(&imap->buf, &rsp)) {
@@ -1091,7 +990,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
if (!srvc->use_ssl && CAP(STARTTLS)) {
if (imap_exec(ctx, NULL, "STARTTLS") != RESP_OK)
goto bail;
- if (ssl_socket_connect(&imap->buf.sock, 1,
+ if (ssl_socket_connect(&imap->buf.sock,
srvc->ssl_verify))
goto bail;
/* capabilities may have changed, so get the new capabilities */
@@ -1109,7 +1008,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
if (!CAP(AUTH_CRAM_MD5)) {
fprintf(stderr, "You specified "
"CRAM-MD5 as authentication method, "
- "but %s doesn't support it.\n", srvc->host);
+ "but tunnel doesn't support it.\n");
goto bail;
}
/* CRAM-MD5 */
@@ -1121,13 +1020,13 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
goto bail;
}
} else {
- fprintf(stderr, "Unknown authentication method:%s\n", srvc->host);
+ fprintf(stderr, "Unknown authentication method:%s\n", srvc->auth_method);
goto bail;
}
} else {
if (CAP(NOLOGIN)) {
- fprintf(stderr, "Skipping account %s@%s, server forbids LOGIN\n",
- srvc->user, srvc->host);
+ fprintf(stderr, "Skipping account %s, server forbids LOGIN\n",
+ srvc->user);
goto bail;
}
if (!imap->buf.sock.ssl)
@@ -1396,7 +1295,6 @@ static int append_msgs_to_imap(struct imap_server_conf *server,
return 0;
}
-#ifdef USE_CURL_FOR_IMAP_SEND
static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
{
CURL *curl;
@@ -1515,7 +1413,6 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,
return res != CURLE_OK;
}
-#endif
int cmd_main(int argc, const char **argv)
{
@@ -1531,17 +1428,8 @@ int cmd_main(int argc, const char **argv)
if (argc)
usage_with_options(imap_send_usage, imap_send_options);
-#ifndef USE_CURL_FOR_IMAP_SEND
- if (use_curl) {
- warning("--curl not supported in this build");
- use_curl = 0;
- }
-#elif defined(NO_OPENSSL)
- if (!use_curl) {
- warning("--no-curl not supported in this build");
- use_curl = 1;
- }
-#endif
+ if (!use_curl)
+ die(_("the --no-curl option to imap-send has been deprecated"));
if (!server.port)
server.port = server.use_ssl ? 993 : 143;
@@ -1550,12 +1438,9 @@ int cmd_main(int argc, const char **argv)
fprintf(stderr, "no imap store specified\n");
return 1;
}
- if (!server.host) {
- if (!server.tunnel) {
- fprintf(stderr, "no imap host specified\n");
- return 1;
- }
- server.host = "tunnel";
+ if (!server.host && !server.tunnel) {
+ fprintf(stderr, "no imap host specified\n");
+ return 1;
}
/* read the messages */
@@ -1577,13 +1462,8 @@ int cmd_main(int argc, const char **argv)
/* write it to the imap server */
- if (server.tunnel)
- return append_msgs_to_imap(&server, &all_msgs, total);
-
-#ifdef USE_CURL_FOR_IMAP_SEND
- if (use_curl)
+ if (!server.tunnel)
return curl_append_msgs_to_imap(&server, &all_msgs, total);
-#endif
return append_msgs_to_imap(&server, &all_msgs, total);
}
diff --git a/json-writer.c b/json-writer.c
index f1cfd8fa8c..005c820aa4 100644
--- a/json-writer.c
+++ b/json-writer.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "json-writer.h"
void jw_init(struct json_writer *jw)
diff --git a/khash.h b/khash.h
index cb79bf8856..ff88163177 100644
--- a/khash.h
+++ b/khash.h
@@ -26,8 +26,7 @@
#ifndef __AC_KHASH_H
#define __AC_KHASH_H
-#include "cache.h"
-#include "hashmap.h"
+#include "hash.h"
#define AC_VERSION_KHASH_H "0.2.8"
@@ -62,7 +61,7 @@ static inline khint_t __ac_X31_hash_string(const char *s)
static const double __ac_HASH_UPPER = 0.77;
#define __KHASH_TYPE(name, khkey_t, khval_t) \
- typedef struct { \
+ typedef struct kh_##name { \
khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \
khkey_t *keys; \
diff --git a/kwset.c b/kwset.c
index 08aadf0311..4b14d4f86b 100644
--- a/kwset.c
+++ b/kwset.c
@@ -32,7 +32,7 @@
String Matching: An Aid to Bibliographic Search," CACM June 1975,
Vol. 18, No. 6, which describes the failure function used below. */
-#include "cache.h"
+#include "git-compat-util.h"
#include "kwset.h"
#include "compat/obstack.h"
diff --git a/levenshtein.c b/levenshtein.c
index d2632690d5..fd8026fe20 100644
--- a/levenshtein.c
+++ b/levenshtein.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "levenshtein.h"
/*
diff --git a/line-log.c b/line-log.c
index a7f3e7f6ce..2eff914bf3 100644
--- a/line-log.c
+++ b/line-log.c
@@ -1,12 +1,14 @@
#include "git-compat-util.h"
+#include "alloc.h"
#include "line-range.h"
-#include "cache.h"
+#include "hex.h"
#include "tag.h"
#include "blob.h"
#include "tree.h"
#include "diff.h"
#include "commit.h"
#include "decorate.h"
+#include "repository.h"
#include "revision.h"
#include "xdiff-interface.h"
#include "strbuf.h"
@@ -14,8 +16,10 @@
#include "graph.h"
#include "userdiff.h"
#include "line-log.h"
+#include "setup.h"
#include "strvec.h"
#include "bloom.h"
+#include "tree-walk.h"
static void range_set_grow(struct range_set *rs, size_t extra)
{
@@ -1281,7 +1285,8 @@ int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, struct commit
return changed;
}
-static enum rewrite_result line_log_rewrite_one(struct rev_info *rev, struct commit **pp)
+static enum rewrite_result line_log_rewrite_one(struct rev_info *rev UNUSED,
+ struct commit **pp)
{
for (;;) {
struct commit *p = *pp;
diff --git a/line-log.h b/line-log.h
index 82ae8d98a4..adff361b1b 100644
--- a/line-log.h
+++ b/line-log.h
@@ -5,6 +5,7 @@
struct rev_info;
struct commit;
+struct string_list;
/* A range [start,end]. Lines are numbered starting at 0, and the
* ranges include start but exclude end. */
diff --git a/linear-assignment.c b/linear-assignment.c
index ecffc09be6..5416cbcf40 100644
--- a/linear-assignment.c
+++ b/linear-assignment.c
@@ -3,7 +3,7 @@
* algorithm for dense and sparse linear assignment problems</i>. Computing,
* 38(4), 325-340.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "linear-assignment.h"
#define COST(column, row) cost[(column) + column_count * (row)]
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index ee01bcd2cc..2a3b7881af 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "commit.h"
#include "config.h"
+#include "gettext.h"
#include "revision.h"
#include "strvec.h"
#include "list-objects.h"
@@ -9,6 +11,7 @@
#include "promisor-remote.h"
#include "trace.h"
#include "url.h"
+#include "parse-options.h"
static int parse_combine_filter(
struct list_objects_filter_options *filter_options,
@@ -341,7 +344,7 @@ void partial_clone_register(
char *filter_name;
/* Check if it is already registered */
- if ((promisor_remote = promisor_remote_find(remote))) {
+ if ((promisor_remote = repo_promisor_remote_find(the_repository, remote))) {
if (promisor_remote->partial_clone_filter)
/*
* Remote is already registered and a filter is already
@@ -369,14 +372,15 @@ void partial_clone_register(
free(filter_name);
/* Make sure the config info are reset */
- promisor_remote_reinit();
+ repo_promisor_remote_reinit(the_repository);
}
void partial_clone_get_default_filter_spec(
struct list_objects_filter_options *filter_options,
const char *remote)
{
- struct promisor_remote *promisor = promisor_remote_find(remote);
+ struct promisor_remote *promisor = repo_promisor_remote_find(the_repository,
+ remote);
struct strbuf errbuf = STRBUF_INIT;
/*
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 1fe393f447..55fab8563d 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -1,9 +1,11 @@
#ifndef LIST_OBJECTS_FILTER_OPTIONS_H
#define LIST_OBJECTS_FILTER_OPTIONS_H
-#include "cache.h"
-#include "parse-options.h"
-#include "string-list.h"
+#include "gettext.h"
+#include "object.h"
+#include "strbuf.h"
+
+struct option;
/*
* The list of defined filters for list-objects.
diff --git a/list-objects-filter.c b/list-objects-filter.c
index 7ed21cb299..e075a66c99 100644
--- a/list-objects-filter.c
+++ b/list-objects-filter.c
@@ -1,5 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "dir.h"
+#include "gettext.h"
+#include "hex.h"
#include "tag.h"
#include "commit.h"
#include "tree.h"
@@ -12,7 +15,8 @@
#include "list-objects-filter-options.h"
#include "oidmap.h"
#include "oidset.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
/* Remember to update object flag allocation in object.h */
/*
diff --git a/list-objects.c b/list-objects.c
index 7528fe1db2..672a4cd529 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "tag.h"
#include "commit.h"
+#include "gettext.h"
+#include "hex.h"
#include "tree.h"
#include "blob.h"
#include "diff.h"
@@ -10,7 +12,7 @@
#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "trace.h"
struct traversal_context {
@@ -64,7 +66,7 @@ static void process_blob(struct traversal_context *ctx,
* of missing objects.
*/
if (ctx->revs->exclude_promisor_objects &&
- !has_object_file(&obj->oid) &&
+ !repo_has_object_file(the_repository, &obj->oid) &&
is_promisor_object(&obj->oid))
return;
@@ -227,7 +229,8 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
struct commit *parent = parents->item;
if (!(parent->object.flags & UNINTERESTING))
continue;
- mark_tree_uninteresting(revs->repo, get_commit_tree(parent));
+ mark_tree_uninteresting(revs->repo,
+ repo_get_commit_tree(the_repository, parent));
if (revs->edge_hint && !(parent->object.flags & SHOWN)) {
parent->object.flags |= SHOWN;
show_edge(parent);
@@ -244,7 +247,8 @@ static void add_edge_parents(struct commit *commit,
for (parents = commit->parents; parents; parents = parents->next) {
struct commit *parent = parents->item;
- struct tree *tree = get_commit_tree(parent);
+ struct tree *tree = repo_get_commit_tree(the_repository,
+ parent);
if (!tree)
continue;
@@ -275,7 +279,8 @@ void mark_edges_uninteresting(struct rev_info *revs,
for (list = revs->commits; list; list = list->next) {
struct commit *commit = list->item;
- struct tree *tree = get_commit_tree(commit);
+ struct tree *tree = repo_get_commit_tree(the_repository,
+ commit);
if (commit->object.flags & UNINTERESTING)
tree->object.flags |= UNINTERESTING;
@@ -291,7 +296,7 @@ void mark_edges_uninteresting(struct rev_info *revs,
struct commit *commit = list->item;
if (commit->object.flags & UNINTERESTING) {
mark_tree_uninteresting(revs->repo,
- get_commit_tree(commit));
+ repo_get_commit_tree(the_repository, commit));
if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
commit->object.flags |= SHOWN;
show_edge(commit);
@@ -309,7 +314,7 @@ void mark_edges_uninteresting(struct rev_info *revs,
if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING))
continue;
mark_tree_uninteresting(revs->repo,
- get_commit_tree(commit));
+ repo_get_commit_tree(the_repository, commit));
if (!(obj->flags & SHOWN)) {
obj->flags |= SHOWN;
show_edge(commit);
@@ -376,8 +381,9 @@ static void do_traverse(struct traversal_context *ctx)
*/
if (!ctx->revs->tree_objects)
; /* do not bother loading tree */
- else if (get_commit_tree(commit)) {
- struct tree *tree = get_commit_tree(commit);
+ else if (repo_get_commit_tree(the_repository, commit)) {
+ struct tree *tree = repo_get_commit_tree(the_repository,
+ commit);
tree->object.flags |= NOT_USER_GIVEN;
add_pending_tree(ctx->revs, tree);
} else if (commit->object.parsed) {
diff --git a/lockfile.c b/lockfile.c
index cc9a4b8428..1d5ed01682 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -2,7 +2,9 @@
* Copyright (c) 2005, Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "gettext.h"
#include "lockfile.h"
/*
diff --git a/log-tree.c b/log-tree.c
index 1dd5fcbf7b..f807e286c8 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "commit-reach.h"
#include "config.h"
#include "diff.h"
-#include "object-store.h"
+#include "environment.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "repository.h"
#include "tmp-objdir.h"
#include "commit.h"
@@ -12,6 +15,8 @@
#include "merge-ort.h"
#include "reflog-walk.h"
#include "refs.h"
+#include "replace-object.h"
+#include "revision.h"
#include "string-list.h"
#include "color.h"
#include "gpg-interface.h"
@@ -20,6 +25,9 @@
#include "help.h"
#include "range-diff.h"
#include "strmap.h"
+#include "tree.h"
+#include "wildmatch.h"
+#include "write-or-die.h"
static struct decoration name_decoration = { "object names" };
static int decoration_loaded;
@@ -196,7 +204,8 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
return 0;
}
-static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
+static int add_graft_decoration(const struct commit_graft *graft,
+ void *cb_data UNUSED)
{
struct commit *commit = lookup_commit(the_repository, &graft->oid);
if (!commit)
@@ -233,7 +242,8 @@ static void show_parents(struct commit *commit, int abbrev, FILE *file)
struct commit_list *p;
for (p = commit->parents; p ; p = p->next) {
struct commit *parent = p->item;
- fprintf(file, " %s", find_unique_abbrev(&parent->object.oid, abbrev));
+ fprintf(file, " %s",
+ repo_find_unique_abbrev(the_repository, &parent->object.oid, abbrev));
}
}
@@ -241,7 +251,8 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
{
struct commit_list *p = lookup_decoration(&opt->children, &commit->object);
for ( ; p; p = p->next) {
- fprintf(opt->diffopt.file, " %s", find_unique_abbrev(&p->item->object.oid, abbrev));
+ fprintf(opt->diffopt.file, " %s",
+ repo_find_unique_abbrev(the_repository, &p->item->object.oid, abbrev));
}
}
@@ -405,7 +416,8 @@ void fmt_output_commit(struct strbuf *filename,
struct pretty_print_context ctx = {0};
struct strbuf subject = STRBUF_INIT;
- format_commit_message(commit, "%f", &subject, &ctx);
+ repo_format_commit_message(the_repository, commit, "%f", &subject,
+ &ctx);
fmt_output_subject(filename, subject.buf, info);
strbuf_release(&subject);
}
@@ -440,7 +452,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
fprintf(opt->diffopt.file, "From %s Mon Sep 17 00:00:00 2001\n", name);
graph_show_oneline(opt->graph);
if (opt->message_id) {
- fprintf(opt->diffopt.file, "Message-Id: <%s>\n", opt->message_id);
+ fprintf(opt->diffopt.file, "Message-ID: <%s>\n", opt->message_id);
graph_show_oneline(opt->graph);
}
if (opt->ref_message_ids && opt->ref_message_ids->nr > 0) {
@@ -644,7 +656,8 @@ void show_log(struct rev_info *opt)
if (!opt->graph)
put_revision_mark(opt, commit);
- fputs(find_unique_abbrev(&commit->object.oid, abbrev_commit), opt->diffopt.file);
+ fputs(repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev_commit),
+ opt->diffopt.file);
if (opt->print_parents)
show_parents(commit, abbrev_commit, opt->diffopt.file);
if (opt->children.name)
@@ -706,8 +719,8 @@ void show_log(struct rev_info *opt)
if (!opt->graph)
put_revision_mark(opt, commit);
- fputs(find_unique_abbrev(&commit->object.oid,
- abbrev_commit),
+ fputs(repo_find_unique_abbrev(the_repository, &commit->object.oid,
+ abbrev_commit),
opt->diffopt.file);
if (opt->print_parents)
show_parents(commit, abbrev_commit, opt->diffopt.file);
@@ -715,7 +728,7 @@ void show_log(struct rev_info *opt)
show_children(opt, commit, abbrev_commit);
if (parent)
fprintf(opt->diffopt.file, " (from %s)",
- find_unique_abbrev(&parent->object.oid, abbrev_commit));
+ repo_find_unique_abbrev(the_repository, &parent->object.oid, abbrev_commit));
fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), opt->diffopt.file);
show_decorations(opt, commit);
if (opt->commit_format == CMIT_FMT_ONELINE) {
@@ -846,7 +859,7 @@ void show_log(struct rev_info *opt)
* Pass minimum required diff-options to range-diff; others
* can be added later if deemed desirable.
*/
- diff_setup(&opts);
+ repo_diff_setup(the_repository, &opts);
opts.file = opt->diffopt.file;
opts.use_color = opt->diffopt.use_color;
diff_setup_done(&opts);
@@ -982,15 +995,17 @@ static int do_remerge_diff(struct rev_info *opt,
o.msg_header_prefix = "remerge";
ctx.abbrev = DEFAULT_ABBREV;
- format_commit_message(parent1, "%h (%s)", &parent1_desc, &ctx);
- format_commit_message(parent2, "%h (%s)", &parent2_desc, &ctx);
+ repo_format_commit_message(the_repository, parent1, "%h (%s)",
+ &parent1_desc, &ctx);
+ repo_format_commit_message(the_repository, parent2, "%h (%s)",
+ &parent2_desc, &ctx);
o.branch1 = parent1_desc.buf;
o.branch2 = parent2_desc.buf;
/* Parse the relevant commits and get the merge bases */
parse_commit_or_die(parent1);
parse_commit_or_die(parent2);
- bases = get_merge_bases(parent1, parent2);
+ bases = repo_get_merge_bases(the_repository, parent1, parent2);
/* Re-merge the parents */
merge_incore_recursive(&o, bases, parent1, parent2, &res);
diff --git a/log-tree.h b/log-tree.h
index e7e4641cf8..bdb6432815 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -1,7 +1,7 @@
#ifndef LOG_TREE_H
#define LOG_TREE_H
-#include "revision.h"
+struct rev_info;
struct log_info {
struct commit *commit, *parent;
diff --git a/ls-refs.c b/ls-refs.c
index 697d4beb8d..c9a723ba89 100644
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -1,4 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "repository.h"
#include "refs.h"
#include "remote.h"
@@ -8,38 +12,32 @@
#include "config.h"
#include "string-list.h"
-static int config_read;
-static int advertise_unborn;
-static int allow_unborn;
-
-static void ensure_config_read(void)
+static enum {
+ UNBORN_IGNORE = 0,
+ UNBORN_ALLOW,
+ UNBORN_ADVERTISE /* implies ALLOW */
+} unborn_config(struct repository *r)
{
const char *str = NULL;
- if (config_read)
- return;
-
- if (repo_config_get_string_tmp(the_repository, "lsrefs.unborn", &str)) {
+ if (repo_config_get_string_tmp(r, "lsrefs.unborn", &str)) {
/*
* If there is no such config, advertise and allow it by
* default.
*/
- advertise_unborn = 1;
- allow_unborn = 1;
+ return UNBORN_ADVERTISE;
} else {
if (!strcmp(str, "advertise")) {
- advertise_unborn = 1;
- allow_unborn = 1;
+ return UNBORN_ADVERTISE;
} else if (!strcmp(str, "allow")) {
- allow_unborn = 1;
+ return UNBORN_ALLOW;
} else if (!strcmp(str, "ignore")) {
- /* do nothing */
+ return UNBORN_IGNORE;
} else {
die(_("invalid value for '%s': '%s'"),
"lsrefs.unborn", str);
}
}
- config_read = 1;
}
/*
@@ -74,7 +72,7 @@ struct ls_refs_data {
unsigned symrefs;
struct strvec prefixes;
struct strbuf buf;
- struct string_list hidden_refs;
+ struct strvec hidden_refs;
unsigned unborn : 1;
};
@@ -157,9 +155,8 @@ int ls_refs(struct repository *r, struct packet_reader *request)
memset(&data, 0, sizeof(data));
strvec_init(&data.prefixes);
strbuf_init(&data.buf, 0);
- string_list_init_dup(&data.hidden_refs);
+ strvec_init(&data.hidden_refs);
- ensure_config_read();
git_config(ls_refs_config, &data);
while (packet_reader_read(request) == PACKET_READ_NORMAL) {
@@ -175,7 +172,7 @@ int ls_refs(struct repository *r, struct packet_reader *request)
strvec_push(&data.prefixes, out);
}
else if (!strcmp("unborn", arg))
- data.unborn = allow_unborn;
+ data.unborn = !!unborn_config(r);
else
die(_("unexpected line: '%s'"), arg);
}
@@ -196,21 +193,18 @@ int ls_refs(struct repository *r, struct packet_reader *request)
strvec_push(&data.prefixes, "");
refs_for_each_fullref_in_prefixes(get_main_ref_store(r),
get_git_namespace(), data.prefixes.v,
- send_ref, &data);
+ data.hidden_refs.v, send_ref, &data);
packet_fflush(stdout);
strvec_clear(&data.prefixes);
strbuf_release(&data.buf);
- string_list_clear(&data.hidden_refs, 0);
+ strvec_clear(&data.hidden_refs);
return 0;
}
int ls_refs_advertise(struct repository *r, struct strbuf *value)
{
- if (value) {
- ensure_config_read();
- if (advertise_unborn)
- strbuf_addstr(value, "unborn");
- }
+ if (value && unborn_config(r) == UNBORN_ADVERTISE)
+ strbuf_addstr(value, "unborn");
return 1;
}
diff --git a/mailinfo.c b/mailinfo.c
index 833d28612f..2aeb20e5e6 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "gettext.h"
+#include "hex.h"
#include "utf8.h"
#include "strbuf.h"
#include "mailinfo.h"
@@ -597,7 +599,7 @@ static int check_header(struct mailinfo *mi,
ret = 1;
goto check_header_out;
}
- if (parse_header(line, "Message-Id", mi, &sb)) {
+ if (parse_header(line, "Message-ID", mi, &sb)) {
if (mi->add_message_id)
mi->message_id = strbuf_detach(&sb, NULL);
ret = 1;
@@ -829,7 +831,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)
if (patchbreak(line)) {
if (mi->message_id)
strbuf_addf(&mi->log_message,
- "Message-Id: %s\n", mi->message_id);
+ "Message-ID: %s\n", mi->message_id);
return 1;
}
diff --git a/mailmap.c b/mailmap.c
index da2589b082..3d6a5e9400 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -1,17 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
#include "string-list.h"
#include "mailmap.h"
-#include "object-store.h"
-
-#define DEBUG_MAILMAP 0
-#if DEBUG_MAILMAP
-#define debug_mm(...) fprintf(stderr, __VA_ARGS__)
-#define debug_str(X) ((X) ? (X) : "(none)")
-#else
-__attribute__((format (printf, 1, 2)))
-static inline void debug_mm(const char *format, ...) {}
-static inline const char *debug_str(const char *s) { return s; }
-#endif
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "setup.h"
const char *git_mailmap_file;
const char *git_mailmap_blob;
@@ -30,23 +23,17 @@ struct mailmap_entry {
struct string_list namemap;
};
-static void free_mailmap_info(void *p, const char *s)
+static void free_mailmap_info(void *p, const char *s UNUSED)
{
struct mailmap_info *mi = (struct mailmap_info *)p;
- debug_mm("mailmap: -- complex: '%s' -> '%s' <%s>\n",
- s, debug_str(mi->name), debug_str(mi->email));
free(mi->name);
free(mi->email);
free(mi);
}
-static void free_mailmap_entry(void *p, const char *s)
+static void free_mailmap_entry(void *p, const char *s UNUSED)
{
struct mailmap_entry *me = (struct mailmap_entry *)p;
- debug_mm("mailmap: removing entries for <%s>, with %"PRIuMAX" sub-entries\n",
- s, (uintmax_t)me->namemap.nr);
- debug_mm("mailmap: - simple: '%s' <%s>\n",
- debug_str(me->name), debug_str(me->email));
free(me->name);
free(me->email);
@@ -93,8 +80,6 @@ static void add_mapping(struct string_list *map,
}
if (!old_name) {
- debug_mm("mailmap: adding (simple) entry for '%s'\n", old_email);
-
/* Replace current name and new email for simple entry */
if (new_name) {
free(me->name);
@@ -106,15 +91,10 @@ static void add_mapping(struct string_list *map,
}
} else {
struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
- debug_mm("mailmap: adding (complex) entry for '%s'\n", old_email);
mi->name = xstrdup_or_null(new_name);
mi->email = xstrdup_or_null(new_email);
string_list_insert(&me->namemap, old_name)->util = mi;
}
-
- debug_mm("mailmap: '%s' <%s> -> '%s' <%s>\n",
- debug_str(old_name), old_email,
- debug_str(new_name), debug_str(new_email));
}
static char *parse_name_and_email(char *buffer, char **name,
@@ -213,10 +193,10 @@ static int read_mailmap_blob(struct string_list *map, const char *name)
if (!name)
return 0;
- if (get_oid(name, &oid) < 0)
+ if (repo_get_oid(the_repository, name, &oid) < 0)
return 0;
- buf = read_object_file(&oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &oid, &type, &size);
if (!buf)
return error("unable to read mailmap object at %s", name);
if (type != OBJ_BLOB)
@@ -250,11 +230,8 @@ int read_mailmap(struct string_list *map)
void clear_mailmap(struct string_list *map)
{
- debug_mm("mailmap: clearing %"PRIuMAX" entries...\n",
- (uintmax_t)map->nr);
map->strdup_strings = 1;
string_list_clear_func(map, free_mailmap_entry);
- debug_mm("mailmap: cleared\n");
}
/*
@@ -315,10 +292,6 @@ int map_user(struct string_list *map,
struct string_list_item *item;
struct mailmap_entry *me;
- debug_mm("map_user: map '%.*s' <%.*s>\n",
- (int)*namelen, debug_str(*name),
- (int)*emaillen, debug_str(*email));
-
item = lookup_prefix(map, *email, *emaillen);
if (item) {
me = (struct mailmap_entry *)item->util;
@@ -336,10 +309,8 @@ int map_user(struct string_list *map,
}
if (item) {
struct mailmap_info *mi = (struct mailmap_info *)item->util;
- if (mi->name == NULL && mi->email == NULL) {
- debug_mm("map_user: -- (no simple mapping)\n");
+ if (mi->name == NULL && mi->email == NULL)
return 0;
- }
if (mi->email) {
*email = mi->email;
*emaillen = strlen(*email);
@@ -348,11 +319,7 @@ int map_user(struct string_list *map,
*name = mi->name;
*namelen = strlen(*name);
}
- debug_mm("map_user: to '%.*s' <%.*s>\n",
- (int)*namelen, debug_str(*name),
- (int)*emaillen, debug_str(*email));
return 1;
}
- debug_mm("map_user: --\n");
return 0;
}
diff --git a/mailmap.h b/mailmap.h
index 7e99fccb46..0f8fd2c586 100644
--- a/mailmap.h
+++ b/mailmap.h
@@ -3,6 +3,9 @@
struct string_list;
+extern const char *git_mailmap_file;
+extern const char *git_mailmap_blob;
+
int read_mailmap(struct string_list *map);
void clear_mailmap(struct string_list *map);
diff --git a/match-trees.c b/match-trees.c
index 49398e599f..0885ac681c 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hex.h"
+#include "match-trees.h"
+#include "strbuf.h"
#include "tree.h"
#include "tree-walk.h"
-#include "object-store.h"
+#include "object-store-ll.h"
static int score_missing(unsigned mode)
{
@@ -55,7 +58,7 @@ static void *fill_tree_desc_strict(struct tree_desc *desc,
enum object_type type;
unsigned long size;
- buffer = read_object_file(hash, &type, &size);
+ buffer = repo_read_object_file(the_repository, hash, &type, &size);
if (!buffer)
die("unable to read tree (%s)", oid_to_hex(hash));
if (type != OBJ_TREE)
@@ -188,7 +191,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
if (*subpath)
subpath++;
- buf = read_object_file(oid1, &type, &sz);
+ buf = repo_read_object_file(the_repository, oid1, &type, &sz);
if (!buf)
die("cannot read tree %s", oid_to_hex(oid1));
init_tree_desc(&desc, buf, sz);
diff --git a/match-trees.h b/match-trees.h
new file mode 100644
index 0000000000..e3877acd58
--- /dev/null
+++ b/match-trees.h
@@ -0,0 +1,10 @@
+#ifndef MATCH_TREES_H
+#define MATCH_TREES_H
+
+struct object_id;
+struct repository;
+
+void shift_tree(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, int);
+void shift_tree_by(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, const char *);
+
+#endif /* MATCH_TREES_H */
diff --git a/mem-pool.c b/mem-pool.c
index 599d8e895f..c34846d176 100644
--- a/mem-pool.c
+++ b/mem-pool.c
@@ -2,7 +2,7 @@
* Memory Pool implementation logic.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "mem-pool.h"
#define BLOCK_GROWTH_SIZE (1024 * 1024 - sizeof(struct mp_block))
diff --git a/merge-blobs.c b/merge-blobs.c
index 8138090f81..9293cbf75c 100644
--- a/merge-blobs.c
+++ b/merge-blobs.c
@@ -1,10 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "run-command.h"
#include "xdiff-interface.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
#include "blob.h"
#include "merge-blobs.h"
-#include "object-store.h"
+#include "object-store-ll.h"
static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
{
@@ -12,7 +12,8 @@ static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
unsigned long size;
enum object_type type;
- buf = read_object_file(&obj->object.oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &obj->object.oid, &type,
+ &size);
if (!buf)
return -1;
if (type != OBJ_BLOB) {
@@ -78,7 +79,8 @@ void *merge_blobs(struct index_state *istate, const char *path,
return NULL;
if (!our)
our = their;
- return read_object_file(&our->object.oid, &type, size);
+ return repo_read_object_file(the_repository, &our->object.oid,
+ &type, size);
}
if (fill_mmfile_blob(&f1, our) < 0)
diff --git a/ll-merge.c b/merge-ll.c
index 130d26501c..740b8c6bfd 100644
--- a/ll-merge.c
+++ b/merge-ll.c
@@ -4,13 +4,16 @@
* Copyright (c) 2007 Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "convert.h"
#include "attr.h"
#include "xdiff-interface.h"
#include "run-command.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
#include "quote.h"
+#include "strbuf.h"
+#include "wrapper.h"
struct ll_merge_driver;
@@ -391,7 +394,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
normalize_file(theirs, path, istate);
}
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
ll_driver_name = check->items[0].value;
if (check->items[1].value) {
marker_size = atoi(check->items[1].value);
@@ -419,7 +422,7 @@ int ll_merge_marker_size(struct index_state *istate, const char *path)
if (!check)
check = attr_check_initl("conflict-marker-size", NULL);
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
if (check->items[0].value) {
marker_size = atoi(check->items[0].value);
if (marker_size <= 0)
diff --git a/ll-merge.h b/merge-ll.h
index e4a20e81a3..e4a20e81a3 100644
--- a/ll-merge.h
+++ b/merge-ll.h
diff --git a/merge-ort-wrappers.c b/merge-ort-wrappers.c
index 748924a69b..4acedf3c33 100644
--- a/merge-ort-wrappers.c
+++ b/merge-ort-wrappers.c
@@ -1,6 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hash.h"
#include "merge-ort.h"
#include "merge-ort-wrappers.h"
+#include "read-cache-ll.h"
+#include "tree.h"
#include "commit.h"
diff --git a/merge-ort.c b/merge-ort.c
index d1611ca400..8631c99700 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -14,7 +14,7 @@
* "cale", "peedy", or "ins" instead of "ort"?)
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "merge-ort.h"
#include "alloc.h"
@@ -26,14 +26,25 @@
#include "diff.h"
#include "diffcore.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "entry.h"
-#include "ll-merge.h"
-#include "object-store.h"
+#include "merge-ll.h"
+#include "match-trees.h"
+#include "mem-pool.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
+#include "path.h"
#include "promisor-remote.h"
+#include "read-cache-ll.h"
#include "revision.h"
+#include "sparse-index.h"
#include "strmap.h"
#include "submodule-config.h"
#include "submodule.h"
+#include "trace2.h"
#include "tree.h"
#include "unpack-trees.h"
#include "xdiff-interface.h"
@@ -3505,7 +3516,7 @@ static int read_oid_strbuf(struct merge_options *opt,
void *buf;
enum object_type type;
unsigned long size;
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf)
return err(opt, _("cannot read object %s"), oid_to_hex(oid));
if (type != OBJ_BLOB) {
@@ -4216,7 +4227,7 @@ static void prefetch_for_content_merges(struct merge_options *opt,
struct string_list_item *e;
struct oid_array to_fetch = OID_ARRAY_INIT;
- if (opt->repo != the_repository || !has_promisor_remote())
+ if (opt->repo != the_repository || !repo_has_promisor_remote(the_repository))
return;
for (e = &plist->items[plist->nr-1]; e >= plist->items; --e) {
@@ -4715,14 +4726,14 @@ void merge_switch_to_result(struct merge_options *opt,
void merge_finalize(struct merge_options *opt,
struct merge_result *result)
{
- struct merge_options_internal *opti = result->priv;
-
if (opt->renormalize)
git_attr_set_direction(GIT_ATTR_CHECKIN);
assert(opt->priv == NULL);
- clear_or_reinit_internal_opts(opti, 0);
- FREE_AND_NULL(opti);
+ if (result->priv) {
+ clear_or_reinit_internal_opts(result->priv, 0);
+ FREE_AND_NULL(result->priv);
+ }
}
/*** Function Grouping: helper functions for merge_incore_*() ***/
@@ -5017,7 +5028,7 @@ static void merge_ort_internal(struct merge_options *opt,
struct strbuf merge_base_abbrev = STRBUF_INIT;
if (!merge_bases) {
- merge_bases = get_merge_bases(h1, h2);
+ merge_bases = repo_get_merge_bases(the_repository, h1, h2);
/* See merge-ort.h:merge_incore_recursive() declaration NOTE */
merge_bases = reverse_commit_list(merge_bases);
}
diff --git a/merge-ort.h b/merge-ort.h
index a994c9a5fc..ce56ec1a78 100644
--- a/merge-ort.h
+++ b/merge-ort.h
@@ -2,7 +2,7 @@
#define MERGE_ORT_H
#include "merge-recursive.h"
-#include "hash.h"
+#include "hash-ll.h"
struct commit;
struct tree;
diff --git a/merge-recursive.c b/merge-recursive.c
index ae469f8cc8..43f6b2d036 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -3,14 +3,13 @@
* Fredrik Kuivinen.
* The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "merge-recursive.h"
#include "advice.h"
#include "alloc.h"
#include "attr.h"
#include "blob.h"
-#include "builtin.h"
#include "cache-tree.h"
#include "commit.h"
#include "commit-reach.h"
@@ -18,17 +17,28 @@
#include "diff.h"
#include "diffcore.h"
#include "dir.h"
-#include "ll-merge.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "merge-ll.h"
#include "lockfile.h"
-#include "object-store.h"
+#include "match-trees.h"
+#include "name-hash.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "repository.h"
#include "revision.h"
+#include "sparse-index.h"
#include "string-list.h"
#include "submodule-config.h"
#include "submodule.h"
+#include "symlinks.h"
#include "tag.h"
#include "tree-walk.h"
#include "unpack-trees.h"
+#include "wrapper.h"
#include "xdiff-interface.h"
struct merge_options_internal {
@@ -951,7 +961,8 @@ static int update_file_flags(struct merge_options *opt,
goto update_index;
}
- buf = read_object_file(&contents->oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &contents->oid,
+ &type, &size);
if (!buf) {
ret = err(opt, _("cannot read object %s '%s'"),
oid_to_hex(&contents->oid), path);
@@ -3021,7 +3032,7 @@ static int read_oid_strbuf(struct merge_options *opt,
void *buf;
enum object_type type;
unsigned long size;
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf)
return err(opt, _("cannot read object %s"), oid_to_hex(oid));
if (type != OBJ_BLOB) {
@@ -3592,7 +3603,7 @@ static int merge_recursive_internal(struct merge_options *opt,
}
if (!merge_bases) {
- merge_bases = get_merge_bases(h1, h2);
+ merge_bases = repo_get_merge_bases(the_repository, h1, h2);
merge_bases = reverse_commit_list(merge_bases);
}
@@ -3797,7 +3808,7 @@ static struct commit *get_ref(struct repository *repo,
return make_virtual_commit(repo, (struct tree*)object, name);
if (object->type != OBJ_COMMIT)
return NULL;
- if (parse_commit((struct commit *)object))
+ if (repo_parse_commit(repo, (struct commit *)object))
return NULL;
return (struct commit *)object;
}
diff --git a/merge.c b/merge.c
index 445b4f19aa..b60925459c 100644
--- a/merge.c
+++ b/merge.c
@@ -1,10 +1,16 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "diff.h"
#include "diffcore.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "lockfile.h"
+#include "merge.h"
#include "commit.h"
+#include "repository.h"
#include "run-command.h"
#include "resolve-undo.h"
+#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
#include "dir.h"
diff --git a/merge.h b/merge.h
new file mode 100644
index 0000000000..21ac7ef2f1
--- /dev/null
+++ b/merge.h
@@ -0,0 +1,17 @@
+#ifndef MERGE_H
+#define MERGE_H
+
+struct commit_list;
+struct object_id;
+struct repository;
+
+int try_merge_command(struct repository *r,
+ const char *strategy, size_t xopts_nr,
+ const char **xopts, struct commit_list *common,
+ const char *head_arg, struct commit_list *remotes);
+int checkout_fast_forward(struct repository *r,
+ const struct object_id *from,
+ const struct object_id *to,
+ int overwrite_ignore);
+
+#endif /* MERGE_H */
diff --git a/midx.c b/midx.c
index 7cfad04a24..db459e448b 100644
--- a/midx.c
+++ b/midx.c
@@ -1,10 +1,15 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
#include "csum-file.h"
#include "dir.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "hash-lookup.h"
#include "midx.h"
#include "progress.h"
@@ -1326,17 +1331,17 @@ static int write_midx_internal(const char *object_dir,
}
if (preferred_pack_name) {
- int found = 0;
+ ctx.preferred_pack_idx = -1;
+
for (i = 0; i < ctx.nr; i++) {
if (!cmp_idx_or_pack_name(preferred_pack_name,
ctx.info[i].pack_name)) {
ctx.preferred_pack_idx = i;
- found = 1;
break;
}
}
- if (!found)
+ if (ctx.preferred_pack_idx == -1)
warning(_("unknown preferred pack: '%s'"),
preferred_pack_name);
} else if (ctx.nr &&
@@ -1607,7 +1612,7 @@ struct clear_midx_data {
const char *ext;
};
-static void clear_midx_file_ext(const char *full_path, size_t full_path_len,
+static void clear_midx_file_ext(const char *full_path, size_t full_path_len UNUSED,
const char *file_name, void *_data)
{
struct clear_midx_data *data = _data;
diff --git a/name-hash.c b/name-hash.c
index cd009c7c8a..251f036eef 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -5,8 +5,14 @@
*
* Copyright (C) 2008 Linus Torvalds
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
+#include "name-hash.h"
+#include "object.h"
+#include "read-cache-ll.h"
#include "thread-utils.h"
+#include "trace.h"
#include "trace2.h"
#include "sparse-index.h"
diff --git a/name-hash.h b/name-hash.h
new file mode 100644
index 0000000000..b1b4b0fb33
--- /dev/null
+++ b/name-hash.h
@@ -0,0 +1,16 @@
+#ifndef NAME_HASH_H
+#define NAME_HASH_H
+
+struct cache_entry;
+struct index_state;
+
+int index_dir_exists(struct index_state *istate, const char *name, int namelen);
+void adjust_dirname_case(struct index_state *istate, char *name);
+struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
+
+int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);
+void add_name_hash(struct index_state *istate, struct cache_entry *ce);
+void remove_name_hash(struct index_state *istate, struct cache_entry *ce);
+void free_name_hash(struct index_state *istate);
+
+#endif /* NAME_HASH_H */
diff --git a/negotiator/default.c b/negotiator/default.c
index b7e79feaf0..9a5b696327 100644
--- a/negotiator/default.c
+++ b/negotiator/default.c
@@ -1,9 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "default.h"
#include "../commit.h"
#include "../fetch-negotiator.h"
#include "../prio-queue.h"
#include "../refs.h"
+#include "../repository.h"
#include "../tag.h"
/* Remember to update object flag allocation in object.h */
@@ -25,7 +26,7 @@ static void rev_list_push(struct negotiation_state *ns,
if (!(commit->object.flags & mark)) {
commit->object.flags |= mark;
- if (parse_commit(commit))
+ if (repo_parse_commit(the_repository, commit))
return;
prio_queue_put(&ns->rev_list, commit);
@@ -55,30 +56,49 @@ static int clear_marks(const char *refname, const struct object_id *oid,
static void mark_common(struct negotiation_state *ns, struct commit *commit,
int ancestors_only, int dont_parse)
{
- if (commit != NULL && !(commit->object.flags & COMMON)) {
- struct object *o = (struct object *)commit;
+ struct prio_queue queue = { NULL };
+
+ if (!commit || (commit->object.flags & COMMON))
+ return;
+
+ prio_queue_put(&queue, commit);
+ if (!ancestors_only) {
+ commit->object.flags |= COMMON;
- if (!ancestors_only)
- o->flags |= COMMON;
+ if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
+ ns->non_common_revs--;
+ }
+ while ((commit = prio_queue_get(&queue))) {
+ struct object *o = (struct object *)commit;
if (!(o->flags & SEEN))
rev_list_push(ns, commit, SEEN);
else {
struct commit_list *parents;
- if (!ancestors_only && !(o->flags & POPPED))
- ns->non_common_revs--;
if (!o->parsed && !dont_parse)
- if (parse_commit(commit))
- return;
+ if (repo_parse_commit(the_repository, commit))
+ continue;
for (parents = commit->parents;
parents;
- parents = parents->next)
- mark_common(ns, parents->item, 0,
- dont_parse);
+ parents = parents->next) {
+ struct commit *p = parents->item;
+
+ if (p->object.flags & COMMON)
+ continue;
+
+ p->object.flags |= COMMON;
+
+ if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
+ ns->non_common_revs--;
+
+ prio_queue_put(&queue, parents->item);
+ }
}
}
+
+ clear_prio_queue(&queue);
}
/*
@@ -96,7 +116,7 @@ static const struct object_id *get_rev(struct negotiation_state *ns)
return NULL;
commit = prio_queue_get(&ns->rev_list);
- parse_commit(commit);
+ repo_parse_commit(the_repository, commit);
parents = commit->parents;
commit->object.flags |= POPPED;
diff --git a/negotiator/noop.c b/negotiator/noop.c
index 60569b8350..7b72937686 100644
--- a/negotiator/noop.c
+++ b/negotiator/noop.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "noop.h"
#include "../commit.h"
#include "../fetch-negotiator.h"
diff --git a/negotiator/skipping.c b/negotiator/skipping.c
index 0f5ac48e87..5b91520430 100644
--- a/negotiator/skipping.c
+++ b/negotiator/skipping.c
@@ -1,9 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "skipping.h"
#include "../commit.h"
#include "../fetch-negotiator.h"
+#include "../hex.h"
#include "../prio-queue.h"
#include "../refs.h"
+#include "../repository.h"
#include "../tag.h"
/* Remember to update object flag allocation in object.h */
@@ -50,7 +52,7 @@ struct data {
int non_common_revs;
};
-static int compare(const void *a_, const void *b_, void *unused)
+static int compare(const void *a_, const void *b_, void *data UNUSED)
{
const struct entry *a = a_;
const struct entry *b = b_;
@@ -84,29 +86,37 @@ static int clear_marks(const char *refname, const struct object_id *oid,
}
/*
- * Mark this SEEN commit and all its SEEN ancestors as COMMON.
+ * Mark this SEEN commit and all its parsed SEEN ancestors as COMMON.
*/
static void mark_common(struct data *data, struct commit *seen_commit)
{
struct prio_queue queue = { NULL };
struct commit *c;
+ if (seen_commit->object.flags & COMMON)
+ return;
+
prio_queue_put(&queue, seen_commit);
+ seen_commit->object.flags |= COMMON;
while ((c = prio_queue_get(&queue))) {
struct commit_list *p;
- if (c->object.flags & COMMON)
- return;
- c->object.flags |= COMMON;
+
if (!(c->object.flags & POPPED))
data->non_common_revs--;
if (!c->object.parsed)
- return;
+ continue;
for (p = c->parents; p; p = p->next) {
- if (p->item->object.flags & SEEN)
- prio_queue_put(&queue, p->item);
+ if (!(p->item->object.flags & SEEN) ||
+ (p->item->object.flags & COMMON))
+ continue;
+
+ p->item->object.flags |= COMMON;
+ prio_queue_put(&queue, p->item);
}
}
+
+ clear_prio_queue(&queue);
}
/*
@@ -183,7 +193,7 @@ static const struct object_id *get_rev(struct data *data)
if (!(commit->object.flags & COMMON) && !entry->ttl)
to_send = commit;
- parse_commit(commit);
+ repo_parse_commit(the_repository, commit);
for (p = commit->parents; p; p = p->next)
parent_pushed |= push_parent(data, entry, p->item);
diff --git a/notes-cache.c b/notes-cache.c
index 9dfd251a81..0e1d5b1ac7 100644
--- a/notes-cache.c
+++ b/notes-cache.c
@@ -1,9 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "notes-cache.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "pretty.h"
#include "repository.h"
#include "commit.h"
#include "refs.h"
+#include "strbuf.h"
static int notes_cache_match_validity(struct repository *r,
const char *ref,
@@ -23,7 +25,8 @@ static int notes_cache_match_validity(struct repository *r,
return 0;
memset(&pretty_ctx, 0, sizeof(pretty_ctx));
- format_commit_message(commit, "%s", &msg, &pretty_ctx);
+ repo_format_commit_message(r, commit, "%s", &msg,
+ &pretty_ctx);
strbuf_trim(&msg);
ret = !strcmp(msg.buf, validity);
@@ -81,7 +84,7 @@ char *notes_cache_get(struct notes_cache *c, struct object_id *key_oid,
value_oid = get_note(&c->tree, key_oid);
if (!value_oid)
return NULL;
- value = read_object_file(value_oid, &type, &size);
+ value = repo_read_object_file(the_repository, value_oid, &type, &size);
*outsize = size;
return value;
diff --git a/notes-merge.c b/notes-merge.c
index b4cc594a79..071947894e 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -1,18 +1,26 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
#include "commit.h"
+#include "gettext.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "repository.h"
#include "diff.h"
#include "diffcore.h"
+#include "hex.h"
#include "xdiff-interface.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
#include "dir.h"
#include "notes.h"
#include "notes-merge.h"
#include "strbuf.h"
+#include "trace.h"
#include "notes-utils.h"
#include "commit-reach.h"
+#include "wrapper.h"
struct notes_merge_pair {
struct object_id obj, base, local, remote;
@@ -326,7 +334,7 @@ static void write_note_to_worktree(const struct object_id *obj,
{
enum object_type type;
unsigned long size;
- void *buf = read_object_file(note, &type, &size);
+ void *buf = repo_read_object_file(the_repository, note, &type, &size);
if (!buf)
die("cannot read note %s for object %s",
@@ -566,7 +574,7 @@ int notes_merge(struct notes_merge_options *o,
trace_printf("\tlocal commit: %.7s\n", oid_to_hex(&local_oid));
/* Dereference o->remote_ref into remote_oid */
- if (get_oid(o->remote_ref, &remote_oid)) {
+ if (repo_get_oid(the_repository, o->remote_ref, &remote_oid)) {
/*
* Failed to get remote_oid. If o->remote_ref looks like an
* unborn ref, perform the merge using an empty notes tree.
@@ -600,7 +608,7 @@ int notes_merge(struct notes_merge_options *o,
assert(local && remote);
/* Find merge bases */
- bases = get_merge_bases(local, remote);
+ bases = repo_get_merge_bases(the_repository, local, remote);
if (!bases) {
base_oid = null_oid();
base_tree_oid = the_hash_algo->empty_tree;
@@ -678,7 +686,8 @@ int notes_merge_commit(struct notes_merge_options *o,
DIR *dir;
struct dirent *e;
struct strbuf path = STRBUF_INIT;
- const char *buffer = get_commit_buffer(partial_commit, NULL);
+ const char *buffer = repo_get_commit_buffer(the_repository,
+ partial_commit, NULL);
const char *msg = strstr(buffer, "\n\n");
int baselen;
@@ -725,7 +734,7 @@ int notes_merge_commit(struct notes_merge_options *o,
create_notes_commit(o->repo, partial_tree, partial_commit->parents, msg,
strlen(msg), result_oid);
- unuse_commit_buffer(partial_commit, buffer);
+ repo_unuse_commit_buffer(the_repository, partial_commit, buffer);
if (o->verbosity >= 4)
printf("Finalized notes merge commit: %s\n",
oid_to_hex(result_oid));
diff --git a/notes-utils.c b/notes-utils.c
index d7d18e30f5..4a793eb347 100644
--- a/notes-utils.c
+++ b/notes-utils.c
@@ -1,9 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "commit.h"
+#include "environment.h"
+#include "gettext.h"
#include "refs.h"
#include "notes-utils.h"
#include "repository.h"
+#include "strbuf.h"
void create_notes_commit(struct repository *r,
struct notes_tree *t,
@@ -23,7 +26,7 @@ void create_notes_commit(struct repository *r,
struct object_id parent_oid;
if (!read_ref(t->ref, &parent_oid)) {
struct commit *parent = lookup_commit(r, &parent_oid);
- if (parse_commit(parent))
+ if (repo_parse_commit(r, parent))
die("Failed to find/parse commit %s", t->ref);
commit_list_insert(parent, &parents);
}
diff --git a/notes.c b/notes.c
index f2805d51bb..503dbc4be1 100644
--- a/notes.c
+++ b/notes.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "environment.h"
+#include "hex.h"
#include "notes.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "blob.h"
#include "tree.h"
#include "utf8.h"
@@ -752,7 +755,7 @@ static int write_each_non_note_until(const char *note_path,
return 0;
}
-static int write_each_note(const struct object_id *object_oid,
+static int write_each_note(const struct object_id *object_oid UNUSED,
const struct object_id *note_oid, char *note_path,
void *cb_data)
{
@@ -780,13 +783,14 @@ struct note_delete_list {
};
static int prune_notes_helper(const struct object_id *object_oid,
- const struct object_id *note_oid, char *note_path,
- void *cb_data)
+ const struct object_id *note_oid UNUSED,
+ char *note_path UNUSED,
+ void *cb_data)
{
struct note_delete_list **l = (struct note_delete_list **) cb_data;
struct note_delete_list *n;
- if (has_object_file(object_oid))
+ if (repo_has_object_file(the_repository, object_oid))
return 0; /* nothing to do for this note */
/* failed to find object => prune this note */
@@ -807,13 +811,15 @@ int combine_notes_concatenate(struct object_id *cur_oid,
/* read in both note blob objects */
if (!is_null_oid(new_oid))
- new_msg = read_object_file(new_oid, &new_type, &new_len);
+ new_msg = repo_read_object_file(the_repository, new_oid,
+ &new_type, &new_len);
if (!new_msg || !new_len || new_type != OBJ_BLOB) {
free(new_msg);
return 0;
}
if (!is_null_oid(cur_oid))
- cur_msg = read_object_file(cur_oid, &cur_type, &cur_len);
+ cur_msg = repo_read_object_file(the_repository, cur_oid,
+ &cur_type, &cur_len);
if (!cur_msg || !cur_len || cur_type != OBJ_BLOB) {
free(cur_msg);
free(new_msg);
@@ -848,8 +854,8 @@ int combine_notes_overwrite(struct object_id *cur_oid,
return 0;
}
-int combine_notes_ignore(struct object_id *cur_oid,
- const struct object_id *new_oid)
+int combine_notes_ignore(struct object_id *cur_oid UNUSED,
+ const struct object_id *new_oid UNUSED)
{
return 0;
}
@@ -869,7 +875,7 @@ static int string_list_add_note_lines(struct string_list *list,
return 0;
/* read_sha1_file NUL-terminates */
- data = read_object_file(oid, &t, &len);
+ data = repo_read_object_file(the_repository, oid, &t, &len);
if (t != OBJ_BLOB || !data || !len) {
free(data);
return t != OBJ_BLOB || !data;
@@ -944,7 +950,7 @@ void string_list_add_refs_by_glob(struct string_list *list, const char *glob)
for_each_glob_ref(string_list_add_one_ref, glob, list);
} else {
struct object_id oid;
- if (get_oid(glob, &oid))
+ if (repo_get_oid(the_repository, glob, &oid))
warning("notes ref %s is invalid", glob);
if (!unsorted_string_list_has_string(list, glob))
string_list_append(list, glob);
@@ -958,7 +964,7 @@ void string_list_add_refs_from_colon_sep(struct string_list *list,
char *globs_copy = xstrdup(globs);
int i;
- string_list_split_in_place(&split, globs_copy, ':', -1);
+ string_list_split_in_place(&split, globs_copy, ":", -1);
string_list_remove_empty_items(&split, 0);
for (i = 0; i < split.nr; i++)
@@ -1014,14 +1020,14 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
t->root = (struct int_node *) xcalloc(1, sizeof(struct int_node));
t->first_non_note = NULL;
t->prev_non_note = NULL;
- t->ref = xstrdup_or_null(notes_ref);
+ t->ref = xstrdup(notes_ref);
t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL;
t->combine_notes = combine_notes;
t->initialized = 1;
t->dirty = 0;
- if (flags & NOTES_INIT_EMPTY || !notes_ref ||
- get_oid_treeish(notes_ref, &object_oid))
+ if (flags & NOTES_INIT_EMPTY ||
+ repo_get_oid_treeish(the_repository, notes_ref, &object_oid))
return;
if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
die("Cannot use notes ref %s", notes_ref);
@@ -1264,7 +1270,7 @@ static void format_note(struct notes_tree *t, const struct object_id *object_oid
if (!oid)
return;
- if (!(msg = read_object_file(oid, &type, &msglen)) || type != OBJ_BLOB) {
+ if (!(msg = repo_read_object_file(the_repository, oid, &type, &msglen)) || type != OBJ_BLOB) {
free(msg);
return;
}
@@ -1348,7 +1354,7 @@ void expand_loose_notes_ref(struct strbuf *sb)
{
struct object_id object;
- if (get_oid(sb->buf, &object)) {
+ if (repo_get_oid(the_repository, sb->buf, &object)) {
/* fallback to expand_notes_ref */
expand_notes_ref(sb);
}
diff --git a/object-file.c b/object-file.c
index 939865c1ae..8d87720dd5 100644
--- a/object-file.c
+++ b/object-file.c
@@ -6,8 +6,14 @@
* This handles basic git object files - packing, unpacking,
* creation etc.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
+#include "convert.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "string-list.h"
#include "lockfile.h"
#include "delta.h"
@@ -30,10 +36,15 @@
#include "mergesort.h"
#include "quote.h"
#include "packfile.h"
+#include "object-file.h"
#include "object-store.h"
+#include "oidtree.h"
+#include "path.h"
#include "promisor-remote.h"
+#include "setup.h"
#include "submodule.h"
#include "fsck.h"
+#include "wrapper.h"
/* The maximum size for an object header. */
#define MAX_HEADER_LEN 32
@@ -267,7 +278,7 @@ int hash_algo_by_length(int len)
/*
* This is meant to hold a *small* number of objects that you would
- * want read_object_file() to be able to return, but yet you do not want
+ * want repo_read_object_file() to be able to return, but yet you do not want
* to write them into the object store (e.g. a browse-only
* application).
*/
@@ -944,6 +955,12 @@ void prepare_alt_odb(struct repository *r)
r->objects->loaded_alternates = 1;
}
+int has_alt_odb(struct repository *r)
+{
+ prepare_alt_odb(r);
+ return !!r->objects->odb->next;
+}
+
/* Returns 1 if we have successfully freshened the file, 0 otherwise. */
static int freshen_file(const char *fn)
{
@@ -1678,7 +1695,7 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
struct cached_object *co;
hash_object_file(the_hash_algo, buf, len, type, oid);
- if (has_object_file_with_flags(oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) ||
+ if (repo_has_object_file_with_flags(the_repository, oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) ||
find_cached_object(oid))
return 0;
ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
@@ -2644,7 +2661,8 @@ int for_each_loose_object(each_loose_object_fn cb, void *data,
return 0;
}
-static int append_loose_object(const struct object_id *oid, const char *path,
+static int append_loose_object(const struct object_id *oid,
+ const char *path UNUSED,
void *data)
{
oidtree_insert(data, oid);
diff --git a/object-file.h b/object-file.h
new file mode 100644
index 0000000000..d6414610f8
--- /dev/null
+++ b/object-file.h
@@ -0,0 +1,131 @@
+#ifndef OBJECT_FILE_H
+#define OBJECT_FILE_H
+
+#include "git-zlib.h"
+#include "object.h"
+
+struct index_state;
+
+/*
+ * Set this to 0 to prevent oid_object_info_extended() from fetching missing
+ * blobs. This has a difference only if extensions.partialClone is set.
+ *
+ * Its default value is 1.
+ */
+extern int fetch_if_missing;
+
+#define HASH_WRITE_OBJECT 1
+#define HASH_FORMAT_CHECK 2
+#define HASH_RENORMALIZE 4
+#define HASH_SILENT 8
+int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
+int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags);
+
+/*
+ * Create the directory containing the named path, using care to be
+ * somewhat safe against races. Return one of the scld_error values to
+ * indicate success/failure. On error, set errno to describe the
+ * problem.
+ *
+ * SCLD_VANISHED indicates that one of the ancestor directories of the
+ * path existed at one point during the function call and then
+ * suddenly vanished, probably because another process pruned the
+ * directory while we were working. To be robust against this kind of
+ * race, callers might want to try invoking the function again when it
+ * returns SCLD_VANISHED.
+ *
+ * safe_create_leading_directories() temporarily changes path while it
+ * is working but restores it before returning.
+ * safe_create_leading_directories_const() doesn't modify path, even
+ * temporarily. Both these variants adjust the permissions of the
+ * created directories to honor core.sharedRepository, so they are best
+ * suited for files inside the git dir. For working tree files, use
+ * safe_create_leading_directories_no_share() instead, as it ignores
+ * the core.sharedRepository setting.
+ */
+enum scld_error {
+ SCLD_OK = 0,
+ SCLD_FAILED = -1,
+ SCLD_PERMS = -2,
+ SCLD_EXISTS = -3,
+ SCLD_VANISHED = -4
+};
+enum scld_error safe_create_leading_directories(char *path);
+enum scld_error safe_create_leading_directories_const(const char *path);
+enum scld_error safe_create_leading_directories_no_share(char *path);
+
+int mkdir_in_gitdir(const char *path);
+
+int git_open_cloexec(const char *name, int flags);
+#define git_open(name) git_open_cloexec(name, O_RDONLY)
+
+/**
+ * unpack_loose_header() initializes the data stream needed to unpack
+ * a loose object header.
+ *
+ * Returns:
+ *
+ * - ULHR_OK on success
+ * - ULHR_BAD on error
+ * - ULHR_TOO_LONG if the header was too long
+ *
+ * It will only parse up to MAX_HEADER_LEN bytes unless an optional
+ * "hdrbuf" argument is non-NULL. This is intended for use with
+ * OBJECT_INFO_ALLOW_UNKNOWN_TYPE to extract the bad type for (error)
+ * reporting. The full header will be extracted to "hdrbuf" for use
+ * with parse_loose_header(), ULHR_TOO_LONG will still be returned
+ * from this function to indicate that the header was too long.
+ */
+enum unpack_loose_header_result {
+ ULHR_OK,
+ ULHR_BAD,
+ ULHR_TOO_LONG,
+};
+enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
+ unsigned char *map,
+ unsigned long mapsize,
+ void *buffer,
+ unsigned long bufsiz,
+ struct strbuf *hdrbuf);
+
+/**
+ * parse_loose_header() parses the starting "<type> <len>\0" of an
+ * object. If it doesn't follow that format -1 is returned. To check
+ * the validity of the <type> populate the "typep" in the "struct
+ * object_info". It will be OBJ_BAD if the object type is unknown. The
+ * parsed <len> can be retrieved via "oi->sizep", and from there
+ * passed to unpack_loose_rest().
+ */
+struct object_info;
+int parse_loose_header(const char *hdr, struct object_info *oi);
+
+/**
+ * With in-core object data in "buf", rehash it to make sure the
+ * object name actually matches "oid" to detect object corruption.
+ *
+ * A negative value indicates an error, usually that the OID is not
+ * what we expected, but it might also indicate another error.
+ */
+int check_object_signature(struct repository *r, const struct object_id *oid,
+ void *map, unsigned long size,
+ enum object_type type);
+
+/**
+ * A streaming version of check_object_signature().
+ * Try reading the object named with "oid" using
+ * the streaming interface and rehash it to do the same.
+ */
+int stream_object_signature(struct repository *r, const struct object_id *oid);
+
+int finalize_object_file(const char *tmpfile, const char *filename);
+
+/* Helper to check and "touch" a file */
+int check_and_freshen_file(const char *fn, int freshen);
+
+void *read_object_with_reference(struct repository *r,
+ const struct object_id *oid,
+ enum object_type required_type,
+ unsigned long *size,
+ struct object_id *oid_ret);
+
+#endif /* OBJECT_FILE_H */
diff --git a/object-name.c b/object-name.c
index 2dd1a0f56e..0bfa29dbbf 100644
--- a/object-name.c
+++ b/object-name.c
@@ -1,5 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "object-name.h"
+#include "advice.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "tag.h"
#include "commit.h"
#include "tree.h"
@@ -9,9 +14,13 @@
#include "remote.h"
#include "dir.h"
#include "oid-array.h"
+#include "oidtree.h"
#include "packfile.h"
-#include "object-store.h"
+#include "pretty.h"
+#include "object-store-ll.h"
+#include "read-cache-ll.h"
#include "repository.h"
+#include "setup.h"
#include "submodule.h"
#include "midx.h"
#include "commit-reach.h"
@@ -223,7 +232,7 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,
static int disambiguate_commit_only(struct repository *r,
const struct object_id *oid,
- void *cb_data_unused)
+ void *cb_data UNUSED)
{
int kind = oid_object_info(r, oid, NULL);
return kind == OBJ_COMMIT;
@@ -231,7 +240,7 @@ static int disambiguate_commit_only(struct repository *r,
static int disambiguate_committish_only(struct repository *r,
const struct object_id *oid,
- void *cb_data_unused)
+ void *cb_data UNUSED)
{
struct object *obj;
int kind;
@@ -251,7 +260,7 @@ static int disambiguate_committish_only(struct repository *r,
static int disambiguate_tree_only(struct repository *r,
const struct object_id *oid,
- void *cb_data_unused)
+ void *cb_data UNUSED)
{
int kind = oid_object_info(r, oid, NULL);
return kind == OBJ_TREE;
@@ -259,7 +268,7 @@ static int disambiguate_tree_only(struct repository *r,
static int disambiguate_treeish_only(struct repository *r,
const struct object_id *oid,
- void *cb_data_unused)
+ void *cb_data UNUSED)
{
struct object *obj;
int kind;
@@ -279,7 +288,7 @@ static int disambiguate_treeish_only(struct repository *r,
static int disambiguate_blob_only(struct repository *r,
const struct object_id *oid,
- void *cb_data_unused)
+ void *cb_data UNUSED)
{
int kind = oid_object_info(r, oid, NULL);
return kind == OBJ_BLOB;
@@ -394,8 +403,10 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)
if (commit) {
struct pretty_print_context pp = {0};
pp.date_mode.type = DATE_SHORT;
- format_commit_message(commit, "%ad", &date, &pp);
- format_commit_message(commit, "%s", &msg, &pp);
+ repo_format_commit_message(the_repository, commit,
+ "%ad", &date, &pp);
+ repo_format_commit_message(the_repository, commit,
+ "%s", &msg, &pp);
}
/*
@@ -473,7 +484,7 @@ static int collect_ambiguous(const struct object_id *oid, void *data)
return 0;
}
-static int repo_collect_ambiguous(struct repository *r,
+static int repo_collect_ambiguous(struct repository *r UNUSED,
const struct object_id *oid,
void *data)
{
@@ -665,7 +676,7 @@ static int extend_abbrev_len(const struct object_id *oid, void *cb_data)
return 0;
}
-static int repo_extend_abbrev_len(struct repository *r,
+static int repo_extend_abbrev_len(struct repository *r UNUSED,
const struct object_id *oid,
void *cb_data)
{
@@ -758,6 +769,21 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)
find_abbrev_len_for_pack(p, mad);
}
+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
+ const struct object_id *oid, int abbrev_len)
+{
+ int r;
+ strbuf_grow(sb, GIT_MAX_HEXSZ + 1);
+ r = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);
+ strbuf_setlen(sb, sb->len + r);
+}
+
+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
+ int abbrev_len)
+{
+ strbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);
+}
+
int repo_find_unique_abbrev_r(struct repository *r, char *hex,
const struct object_id *oid, int len)
{
@@ -898,6 +924,7 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
char *real_ref = NULL;
int refs_found = 0;
int at, reflog_len, nth_prior = 0;
+ int fatal = !(flags & GET_OID_QUIETLY);
if (len == r->hash_algo->hexsz && !get_oid_hex(str, oid)) {
if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
@@ -952,11 +979,11 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
if (!len && reflog_len)
/* allow "@{...}" to mean the current branch reflog */
- refs_found = repo_dwim_ref(r, "HEAD", 4, oid, &real_ref, 0);
+ refs_found = repo_dwim_ref(r, "HEAD", 4, oid, &real_ref, !fatal);
else if (reflog_len)
refs_found = repo_dwim_log(r, str, len, oid, &real_ref);
else
- refs_found = repo_dwim_ref(r, str, len, oid, &real_ref, 0);
+ refs_found = repo_dwim_ref(r, str, len, oid, &real_ref, !fatal);
if (!refs_found)
return -1;
@@ -1036,7 +1063,7 @@ static enum get_oid_result get_parent(struct repository *r,
if (ret)
return ret;
commit = lookup_commit_reference(r, &oid);
- if (parse_commit(commit))
+ if (repo_parse_commit(r, commit))
return MISSING_OBJECT;
if (!idx) {
oidcpy(result, &commit->object.oid);
@@ -1070,7 +1097,7 @@ static enum get_oid_result get_nth_ancestor(struct repository *r,
return MISSING_OBJECT;
while (generation--) {
- if (parse_commit(commit) || !commit->parents)
+ if (repo_parse_commit(r, commit) || !commit->parents)
return MISSING_OBJECT;
commit = commit->parents->item;
}
@@ -1361,10 +1388,10 @@ static int get_oid_oneline(struct repository *r,
commit = pop_most_recent_commit(&list, ONELINE_SEEN);
if (!parse_object(r, &commit->object.oid))
continue;
- buf = get_commit_buffer(commit, NULL);
+ buf = repo_get_commit_buffer(r, commit, NULL);
p = strstr(buf, "\n\n");
matches = negative ^ (p && !regexec(&regex, p + 2, 0, NULL, 0));
- unuse_commit_buffer(commit, buf);
+ repo_unuse_commit_buffer(r, commit, buf);
if (matches) {
oidcpy(oid, &commit->object.oid);
@@ -1666,7 +1693,8 @@ void strbuf_branchname(struct strbuf *sb, const char *name, unsigned allowed)
struct interpret_branch_name_options options = {
.allowed = allowed
};
- int used = interpret_branch_name(name, len, sb, &options);
+ int used = repo_interpret_branch_name(the_repository, name, len, sb,
+ &options);
if (used < 0)
used = 0;
@@ -1719,7 +1747,7 @@ int get_oidf(struct object_id *oid, const char *fmt, ...)
strbuf_vaddf(&sb, fmt, ap);
va_end(ap);
- ret = get_oid(sb.buf, oid);
+ ret = repo_get_oid(the_repository, sb.buf, oid);
strbuf_release(&sb);
return ret;
diff --git a/object-name.h b/object-name.h
new file mode 100644
index 0000000000..9ae5223071
--- /dev/null
+++ b/object-name.h
@@ -0,0 +1,130 @@
+#ifndef OBJECT_NAME_H
+#define OBJECT_NAME_H
+
+#include "object.h"
+#include "strbuf.h"
+
+struct object_id;
+struct repository;
+
+struct object_context {
+ unsigned short mode;
+ /*
+ * symlink_path is only used by get_tree_entry_follow_symlinks,
+ * and only for symlinks that point outside the repository.
+ */
+ struct strbuf symlink_path;
+ /*
+ * If GET_OID_RECORD_PATH is set, this will record path (if any)
+ * found when resolving the name. The caller is responsible for
+ * releasing the memory.
+ */
+ char *path;
+};
+
+/*
+ * Return an abbreviated sha1 unique within this repository's object database.
+ * The result will be at least `len` characters long, and will be NUL
+ * terminated.
+ *
+ * The non-`_r` version returns a static buffer which remains valid until 4
+ * more calls to repo_find_unique_abbrev are made.
+ *
+ * The `_r` variant writes to a buffer supplied by the caller, which must be at
+ * least `GIT_MAX_HEXSZ + 1` bytes. The return value is the number of bytes
+ * written (excluding the NUL terminator).
+ *
+ * Note that while this version avoids the static buffer, it is not fully
+ * reentrant, as it calls into other non-reentrant git code.
+ */
+const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);
+int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);
+
+/**
+ * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to
+ * the strbuf `sb`.
+ */
+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
+ const struct object_id *oid, int abbrev_len);
+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
+ int abbrev_len);
+
+int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);
+__attribute__((format (printf, 2, 3)))
+int get_oidf(struct object_id *oid, const char *fmt, ...);
+int repo_get_oid_commit(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_committish(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_tree(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_treeish(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_blob(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_mb(struct repository *r, const char *str, struct object_id *oid);
+void maybe_die_on_misspelt_object_name(struct repository *repo,
+ const char *name,
+ const char *prefix);
+enum get_oid_result get_oid_with_context(struct repository *repo, const char *str,
+ unsigned flags, struct object_id *oid,
+ struct object_context *oc);
+
+
+typedef int each_abbrev_fn(const struct object_id *oid, void *);
+int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *);
+
+int set_disambiguate_hint_config(const char *var, const char *value);
+
+/*
+ * This reads short-hand syntax that not only evaluates to a commit
+ * object name, but also can act as if the end user spelled the name
+ * of the branch from the command line.
+ *
+ * - "@{-N}" finds the name of the Nth previous branch we were on, and
+ * places the name of the branch in the given buf and returns the
+ * number of characters parsed if successful.
+ *
+ * - "<branch>@{upstream}" finds the name of the other ref that
+ * <branch> is configured to merge with (missing <branch> defaults
+ * to the current branch), and places the name of the branch in the
+ * given buf and returns the number of characters parsed if
+ * successful.
+ *
+ * If the input is not of the accepted format, it returns a negative
+ * number to signal an error.
+ *
+ * If the input was ok but there are not N branch switches in the
+ * reflog, it returns 0.
+ */
+#define INTERPRET_BRANCH_LOCAL (1<<0)
+#define INTERPRET_BRANCH_REMOTE (1<<1)
+#define INTERPRET_BRANCH_HEAD (1<<2)
+struct interpret_branch_name_options {
+ /*
+ * If "allowed" is non-zero, it is a treated as a bitfield of allowable
+ * expansions: local branches ("refs/heads/"), remote branches
+ * ("refs/remotes/"), or "HEAD". If no "allowed" bits are set, any expansion is
+ * allowed, even ones to refs outside of those namespaces.
+ */
+ unsigned allowed;
+
+ /*
+ * If ^{upstream} or ^{push} (or equivalent) is requested, and the
+ * branch in question does not have such a reference, return -1 instead
+ * of die()-ing.
+ */
+ unsigned nonfatal_dangling_mark : 1;
+};
+int repo_interpret_branch_name(struct repository *r,
+ const char *str, int len,
+ struct strbuf *buf,
+ const struct interpret_branch_name_options *options);
+
+struct object *repo_peel_to_type(struct repository *r,
+ const char *name, int namelen,
+ struct object *o, enum object_type);
+
+/* Convert to/from hex/sha1 representation */
+#define MINIMUM_ABBREV minimum_abbrev
+#define DEFAULT_ABBREV default_abbrev
+
+/* used when the code does not know or care what the default abbrev is */
+#define FALLBACK_DEFAULT_ABBREV 7
+
+#endif /* OBJECT_NAME_H */
diff --git a/object-store-ll.h b/object-store-ll.h
new file mode 100644
index 0000000000..e8f22cdb1b
--- /dev/null
+++ b/object-store-ll.h
@@ -0,0 +1,533 @@
+#ifndef OBJECT_STORE_LL_H
+#define OBJECT_STORE_LL_H
+
+#include "hashmap.h"
+#include "object.h"
+#include "list.h"
+#include "thread-utils.h"
+#include "oidset.h"
+
+struct oidmap;
+struct oidtree;
+struct strbuf;
+
+struct object_directory {
+ struct object_directory *next;
+
+ /*
+ * Used to store the results of readdir(3) calls when we are OK
+ * sacrificing accuracy due to races for speed. That includes
+ * object existence with OBJECT_INFO_QUICK, as well as
+ * our search for unique abbreviated hashes. Don't use it for tasks
+ * requiring greater accuracy!
+ *
+ * Be sure to call odb_load_loose_cache() before using.
+ */
+ uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
+ struct oidtree *loose_objects_cache;
+
+ /*
+ * This is a temporary object store created by the tmp_objdir
+ * facility. Disable ref updates since the objects in the store
+ * might be discarded on rollback.
+ */
+ int disable_ref_updates;
+
+ /*
+ * This object store is ephemeral, so there is no need to fsync.
+ */
+ int will_destroy;
+
+ /*
+ * Path to the alternative object store. If this is a relative path,
+ * it is relative to the current working directory.
+ */
+ char *path;
+};
+
+struct input_stream {
+ const void *(*read)(struct input_stream *, unsigned long *len);
+ void *data;
+ int is_finished;
+};
+
+void prepare_alt_odb(struct repository *r);
+int has_alt_odb(struct repository *r);
+char *compute_alternate_path(const char *path, struct strbuf *err);
+struct object_directory *find_odb(struct repository *r, const char *obj_dir);
+typedef int alt_odb_fn(struct object_directory *, void *);
+int foreach_alt_odb(alt_odb_fn, void*);
+typedef void alternate_ref_fn(const struct object_id *oid, void *);
+void for_each_alternate_ref(alternate_ref_fn, void *);
+
+/*
+ * Add the directory to the on-disk alternates file; the new entry will also
+ * take effect in the current process.
+ */
+void add_to_alternates_file(const char *dir);
+
+/*
+ * Add the directory to the in-memory list of alternates (along with any
+ * recursive alternates it points to), but do not modify the on-disk alternates
+ * file.
+ */
+void add_to_alternates_memory(const char *dir);
+
+/*
+ * Replace the current writable object directory with the specified temporary
+ * object directory; returns the former primary object directory.
+ */
+struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy);
+
+/*
+ * Restore a previous ODB replaced by set_temporary_main_odb.
+ */
+void restore_primary_odb(struct object_directory *restore_odb, const char *old_path);
+
+/*
+ * Populate and return the loose object cache array corresponding to the
+ * given object ID.
+ */
+struct oidtree *odb_loose_cache(struct object_directory *odb,
+ const struct object_id *oid);
+
+/* Empty the loose object cache for the specified object directory. */
+void odb_clear_loose_cache(struct object_directory *odb);
+
+/* Clear and free the specified object directory */
+void free_object_directory(struct object_directory *odb);
+
+struct packed_git {
+ struct hashmap_entry packmap_ent;
+ struct packed_git *next;
+ struct list_head mru;
+ struct pack_window *windows;
+ off_t pack_size;
+ const void *index_data;
+ size_t index_size;
+ uint32_t num_objects;
+ uint32_t crc_offset;
+ struct oidset bad_objects;
+ int index_version;
+ time_t mtime;
+ int pack_fd;
+ int index; /* for builtin/pack-objects.c */
+ unsigned pack_local:1,
+ pack_keep:1,
+ pack_keep_in_core:1,
+ freshened:1,
+ do_not_close:1,
+ pack_promisor:1,
+ multi_pack_index:1,
+ is_cruft:1;
+ unsigned char hash[GIT_MAX_RAWSZ];
+ struct revindex_entry *revindex;
+ const uint32_t *revindex_data;
+ const uint32_t *revindex_map;
+ size_t revindex_size;
+ /*
+ * mtimes_map points at the beginning of the memory mapped region of
+ * this pack's corresponding .mtimes file, and mtimes_size is the size
+ * of that .mtimes file
+ */
+ const uint32_t *mtimes_map;
+ size_t mtimes_size;
+ /* something like ".git/objects/pack/xxxxx.pack" */
+ char pack_name[FLEX_ARRAY]; /* more */
+};
+
+struct multi_pack_index;
+
+static inline int pack_map_entry_cmp(const void *cmp_data UNUSED,
+ const struct hashmap_entry *entry,
+ const struct hashmap_entry *entry2,
+ const void *keydata)
+{
+ const char *key = keydata;
+ const struct packed_git *pg1, *pg2;
+
+ pg1 = container_of(entry, const struct packed_git, packmap_ent);
+ pg2 = container_of(entry2, const struct packed_git, packmap_ent);
+
+ return strcmp(pg1->pack_name, key ? key : pg2->pack_name);
+}
+
+struct raw_object_store {
+ /*
+ * Set of all object directories; the main directory is first (and
+ * cannot be NULL after initialization). Subsequent directories are
+ * alternates.
+ */
+ struct object_directory *odb;
+ struct object_directory **odb_tail;
+ struct kh_odb_path_map *odb_by_path;
+
+ int loaded_alternates;
+
+ /*
+ * A list of alternate object directories loaded from the environment;
+ * this should not generally need to be accessed directly, but will
+ * populate the "odb" list when prepare_alt_odb() is run.
+ */
+ char *alternate_db;
+
+ /*
+ * Objects that should be substituted by other objects
+ * (see git-replace(1)).
+ */
+ struct oidmap *replace_map;
+ unsigned replace_map_initialized : 1;
+ pthread_mutex_t replace_mutex; /* protect object replace functions */
+
+ struct commit_graph *commit_graph;
+ unsigned commit_graph_attempted : 1; /* if loading has been attempted */
+
+ /*
+ * private data
+ *
+ * should only be accessed directly by packfile.c and midx.c
+ */
+ struct multi_pack_index *multi_pack_index;
+
+ /*
+ * private data
+ *
+ * should only be accessed directly by packfile.c
+ */
+
+ struct packed_git *packed_git;
+ /* A most-recently-used ordered version of the packed_git list. */
+ struct list_head packed_git_mru;
+
+ struct {
+ struct packed_git **packs;
+ unsigned flags;
+ } kept_pack_cache;
+
+ /*
+ * A map of packfiles to packed_git structs for tracking which
+ * packs have been loaded already.
+ */
+ struct hashmap pack_map;
+
+ /*
+ * A fast, rough count of the number of objects in the repository.
+ * These two fields are not meant for direct access. Use
+ * repo_approximate_object_count() instead.
+ */
+ unsigned long approximate_object_count;
+ unsigned approximate_object_count_valid : 1;
+
+ /*
+ * Whether packed_git has already been populated with this repository's
+ * packs.
+ */
+ unsigned packed_git_initialized : 1;
+};
+
+struct raw_object_store *raw_object_store_new(void);
+void raw_object_store_clear(struct raw_object_store *o);
+
+/*
+ * Put in `buf` the name of the file in the local object database that
+ * would be used to store a loose object with the specified oid.
+ */
+const char *loose_object_path(struct repository *r, struct strbuf *buf,
+ const struct object_id *oid);
+
+void *map_loose_object(struct repository *r, const struct object_id *oid,
+ unsigned long *size);
+
+void *repo_read_object_file(struct repository *r,
+ const struct object_id *oid,
+ enum object_type *type,
+ unsigned long *size);
+
+/* Read and unpack an object file into memory, write memory to an object file */
+int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);
+
+void hash_object_file(const struct git_hash_algo *algo, const void *buf,
+ unsigned long len, enum object_type type,
+ struct object_id *oid);
+
+int write_object_file_flags(const void *buf, unsigned long len,
+ enum object_type type, struct object_id *oid,
+ unsigned flags);
+static inline int write_object_file(const void *buf, unsigned long len,
+ enum object_type type, struct object_id *oid)
+{
+ return write_object_file_flags(buf, len, type, oid, 0);
+}
+
+int write_object_file_literally(const void *buf, unsigned long len,
+ const char *type, struct object_id *oid,
+ unsigned flags);
+int stream_loose_object(struct input_stream *in_stream, size_t len,
+ struct object_id *oid);
+
+/*
+ * Add an object file to the in-memory object store, without writing it
+ * to disk.
+ *
+ * Callers are responsible for calling write_object_file to record the
+ * object in persistent storage before writing any other new objects
+ * that reference it.
+ */
+int pretend_object_file(void *, unsigned long, enum object_type,
+ struct object_id *oid);
+
+int force_object_loose(const struct object_id *oid, time_t mtime);
+
+struct object_info {
+ /* Request */
+ enum object_type *typep;
+ unsigned long *sizep;
+ off_t *disk_sizep;
+ struct object_id *delta_base_oid;
+ struct strbuf *type_name;
+ void **contentp;
+
+ /* Response */
+ enum {
+ OI_CACHED,
+ OI_LOOSE,
+ OI_PACKED,
+ OI_DBCACHED
+ } whence;
+ union {
+ /*
+ * struct {
+ * ... Nothing to expose in this case
+ * } cached;
+ * struct {
+ * ... Nothing to expose in this case
+ * } loose;
+ */
+ struct {
+ struct packed_git *pack;
+ off_t offset;
+ unsigned int is_delta;
+ } packed;
+ } u;
+};
+
+/*
+ * Initializer for a "struct object_info" that wants no items. You may
+ * also memset() the memory to all-zeroes.
+ */
+#define OBJECT_INFO_INIT { 0 }
+
+/* Invoke lookup_replace_object() on the given hash */
+#define OBJECT_INFO_LOOKUP_REPLACE 1
+/* Allow reading from a loose object file of unknown/bogus type */
+#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
+/* Do not retry packed storage after checking packed and loose storage */
+#define OBJECT_INFO_QUICK 8
+/*
+ * Do not attempt to fetch the object if missing (even if fetch_is_missing is
+ * nonzero).
+ */
+#define OBJECT_INFO_SKIP_FETCH_OBJECT 16
+/*
+ * This is meant for bulk prefetching of missing blobs in a partial
+ * clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
+ */
+#define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
+
+/* Die if object corruption (not just an object being missing) was detected. */
+#define OBJECT_INFO_DIE_IF_CORRUPT 32
+
+int oid_object_info_extended(struct repository *r,
+ const struct object_id *,
+ struct object_info *, unsigned flags);
+
+/*
+ * Open the loose object at path, check its hash, and return the contents,
+ * use the "oi" argument to assert things about the object, or e.g. populate its
+ * type, and size. If the object is a blob, then "contents" may return NULL,
+ * to allow streaming of large blobs.
+ *
+ * Returns 0 on success, negative on error (details may be written to stderr).
+ */
+int read_loose_object(const char *path,
+ const struct object_id *expected_oid,
+ struct object_id *real_oid,
+ void **contents,
+ struct object_info *oi);
+
+/* Retry packed storage after checking packed and loose storage */
+#define HAS_OBJECT_RECHECK_PACKED 1
+
+/*
+ * Returns 1 if the object exists. This function will not lazily fetch objects
+ * in a partial clone.
+ */
+int has_object(struct repository *r, const struct object_id *oid,
+ unsigned flags);
+
+/*
+ * These macros and functions are deprecated. If checking existence for an
+ * object that is likely to be missing and/or whose absence is relatively
+ * inconsequential (or is consequential but the caller is prepared to handle
+ * it), use has_object(), which has better defaults (no lazy fetch in a partial
+ * clone and no rechecking of packed storage). In the unlikely event that a
+ * caller needs to assert existence of an object that it fully expects to
+ * exist, and wants to trigger a lazy fetch in a partial clone, use
+ * oid_object_info_extended() with a NULL struct object_info.
+ *
+ * These functions can be removed once all callers have migrated to
+ * has_object() and/or oid_object_info_extended().
+ */
+int repo_has_object_file(struct repository *r, const struct object_id *oid);
+int repo_has_object_file_with_flags(struct repository *r,
+ const struct object_id *oid, int flags);
+
+/*
+ * Return true iff an alternate object database has a loose object
+ * with the specified name. This function does not respect replace
+ * references.
+ */
+int has_loose_object_nonlocal(const struct object_id *);
+
+int has_loose_object(const struct object_id *);
+
+/**
+ * format_object_header() is a thin wrapper around s xsnprintf() that
+ * writes the initial "<type> <obj-len>" part of the loose object
+ * header. It returns the size that snprintf() returns + 1.
+ */
+int format_object_header(char *str, size_t size, enum object_type type,
+ size_t objsize);
+
+void assert_oid_type(const struct object_id *oid, enum object_type expect);
+
+/*
+ * Enabling the object read lock allows multiple threads to safely call the
+ * following functions in parallel: repo_read_object_file(),
+ * read_object_with_reference(), oid_object_info() and oid_object_info_extended().
+ *
+ * obj_read_lock() and obj_read_unlock() may also be used to protect other
+ * section which cannot execute in parallel with object reading. Since the used
+ * lock is a recursive mutex, these sections can even contain calls to object
+ * reading functions. However, beware that in these cases zlib inflation won't
+ * be performed in parallel, losing performance.
+ *
+ * TODO: oid_object_info_extended()'s call stack has a recursive behavior. If
+ * any of its callees end up calling it, this recursive call won't benefit from
+ * parallel inflation.
+ */
+void enable_obj_read_lock(void);
+void disable_obj_read_lock(void);
+
+extern int obj_read_use_lock;
+extern pthread_mutex_t obj_read_mutex;
+
+static inline void obj_read_lock(void)
+{
+ if(obj_read_use_lock)
+ pthread_mutex_lock(&obj_read_mutex);
+}
+
+static inline void obj_read_unlock(void)
+{
+ if(obj_read_use_lock)
+ pthread_mutex_unlock(&obj_read_mutex);
+}
+
+/*
+ * Iterate over the files in the loose-object parts of the object
+ * directory "path", triggering the following callbacks:
+ *
+ * - loose_object is called for each loose object we find.
+ *
+ * - loose_cruft is called for any files that do not appear to be
+ * loose objects. Note that we only look in the loose object
+ * directories "objects/[0-9a-f]{2}/", so we will not report
+ * "objects/foobar" as cruft.
+ *
+ * - loose_subdir is called for each top-level hashed subdirectory
+ * of the object directory (e.g., "$OBJDIR/f0"). It is called
+ * after the objects in the directory are processed.
+ *
+ * Any callback that is NULL will be ignored. Callbacks returning non-zero
+ * will end the iteration.
+ *
+ * In the "buf" variant, "path" is a strbuf which will also be used as a
+ * scratch buffer, but restored to its original contents before
+ * the function returns.
+ */
+typedef int each_loose_object_fn(const struct object_id *oid,
+ const char *path,
+ void *data);
+typedef int each_loose_cruft_fn(const char *basename,
+ const char *path,
+ void *data);
+typedef int each_loose_subdir_fn(unsigned int nr,
+ const char *path,
+ void *data);
+int for_each_file_in_obj_subdir(unsigned int subdir_nr,
+ struct strbuf *path,
+ each_loose_object_fn obj_cb,
+ each_loose_cruft_fn cruft_cb,
+ each_loose_subdir_fn subdir_cb,
+ void *data);
+int for_each_loose_file_in_objdir(const char *path,
+ each_loose_object_fn obj_cb,
+ each_loose_cruft_fn cruft_cb,
+ each_loose_subdir_fn subdir_cb,
+ void *data);
+int for_each_loose_file_in_objdir_buf(struct strbuf *path,
+ each_loose_object_fn obj_cb,
+ each_loose_cruft_fn cruft_cb,
+ each_loose_subdir_fn subdir_cb,
+ void *data);
+
+/* Flags for for_each_*_object() below. */
+enum for_each_object_flags {
+ /* Iterate only over local objects, not alternates. */
+ FOR_EACH_OBJECT_LOCAL_ONLY = (1<<0),
+
+ /* Only iterate over packs obtained from the promisor remote. */
+ FOR_EACH_OBJECT_PROMISOR_ONLY = (1<<1),
+
+ /*
+ * Visit objects within a pack in packfile order rather than .idx order
+ */
+ FOR_EACH_OBJECT_PACK_ORDER = (1<<2),
+
+ /* Only iterate over packs that are not marked as kept in-core. */
+ FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS = (1<<3),
+
+ /* Only iterate over packs that do not have .keep files. */
+ FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS = (1<<4),
+};
+
+/*
+ * Iterate over all accessible loose objects without respect to
+ * reachability. By default, this includes both local and alternate objects.
+ * The order in which objects are visited is unspecified.
+ *
+ * Any flags specific to packs are ignored.
+ */
+int for_each_loose_object(each_loose_object_fn, void *,
+ enum for_each_object_flags flags);
+
+/*
+ * Iterate over all accessible packed objects without respect to reachability.
+ * By default, this includes both local and alternate packs.
+ *
+ * Note that some objects may appear twice if they are found in multiple packs.
+ * Each pack is visited in an unspecified order. By default, objects within a
+ * pack are visited in pack-idx order (i.e., sorted by oid).
+ */
+typedef int each_packed_object_fn(const struct object_id *oid,
+ struct packed_git *pack,
+ uint32_t pos,
+ void *data);
+int for_each_object_in_pack(struct packed_git *p,
+ each_packed_object_fn, void *data,
+ enum for_each_object_flags flags);
+int for_each_packed_object(each_packed_object_fn, void *,
+ enum for_each_object_flags flags);
+
+#endif /* OBJECT_STORE_LL_H */
diff --git a/object-store.h b/object-store.h
index 1a713d89d7..1b3e3d7d01 100644
--- a/object-store.h
+++ b/object-store.h
@@ -1,543 +1,11 @@
#ifndef OBJECT_STORE_H
#define OBJECT_STORE_H
-#include "cache.h"
-#include "oidmap.h"
-#include "list.h"
-#include "oid-array.h"
-#include "strbuf.h"
-#include "thread-utils.h"
#include "khash.h"
#include "dir.h"
-#include "oidtree.h"
-#include "oidset.h"
-
-struct object_directory {
- struct object_directory *next;
-
- /*
- * Used to store the results of readdir(3) calls when we are OK
- * sacrificing accuracy due to races for speed. That includes
- * object existence with OBJECT_INFO_QUICK, as well as
- * our search for unique abbreviated hashes. Don't use it for tasks
- * requiring greater accuracy!
- *
- * Be sure to call odb_load_loose_cache() before using.
- */
- uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
- struct oidtree *loose_objects_cache;
-
- /*
- * This is a temporary object store created by the tmp_objdir
- * facility. Disable ref updates since the objects in the store
- * might be discarded on rollback.
- */
- int disable_ref_updates;
-
- /*
- * This object store is ephemeral, so there is no need to fsync.
- */
- int will_destroy;
-
- /*
- * Path to the alternative object store. If this is a relative path,
- * it is relative to the current working directory.
- */
- char *path;
-};
-
-struct input_stream {
- const void *(*read)(struct input_stream *, unsigned long *len);
- void *data;
- int is_finished;
-};
+#include "object-store-ll.h"
KHASH_INIT(odb_path_map, const char * /* key: odb_path */,
struct object_directory *, 1, fspathhash, fspatheq)
-void prepare_alt_odb(struct repository *r);
-char *compute_alternate_path(const char *path, struct strbuf *err);
-struct object_directory *find_odb(struct repository *r, const char *obj_dir);
-typedef int alt_odb_fn(struct object_directory *, void *);
-int foreach_alt_odb(alt_odb_fn, void*);
-typedef void alternate_ref_fn(const struct object_id *oid, void *);
-void for_each_alternate_ref(alternate_ref_fn, void *);
-
-/*
- * Add the directory to the on-disk alternates file; the new entry will also
- * take effect in the current process.
- */
-void add_to_alternates_file(const char *dir);
-
-/*
- * Add the directory to the in-memory list of alternates (along with any
- * recursive alternates it points to), but do not modify the on-disk alternates
- * file.
- */
-void add_to_alternates_memory(const char *dir);
-
-/*
- * Replace the current writable object directory with the specified temporary
- * object directory; returns the former primary object directory.
- */
-struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy);
-
-/*
- * Restore a previous ODB replaced by set_temporary_main_odb.
- */
-void restore_primary_odb(struct object_directory *restore_odb, const char *old_path);
-
-/*
- * Populate and return the loose object cache array corresponding to the
- * given object ID.
- */
-struct oidtree *odb_loose_cache(struct object_directory *odb,
- const struct object_id *oid);
-
-/* Empty the loose object cache for the specified object directory. */
-void odb_clear_loose_cache(struct object_directory *odb);
-
-/* Clear and free the specified object directory */
-void free_object_directory(struct object_directory *odb);
-
-struct packed_git {
- struct hashmap_entry packmap_ent;
- struct packed_git *next;
- struct list_head mru;
- struct pack_window *windows;
- off_t pack_size;
- const void *index_data;
- size_t index_size;
- uint32_t num_objects;
- uint32_t crc_offset;
- struct oidset bad_objects;
- int index_version;
- time_t mtime;
- int pack_fd;
- int index; /* for builtin/pack-objects.c */
- unsigned pack_local:1,
- pack_keep:1,
- pack_keep_in_core:1,
- freshened:1,
- do_not_close:1,
- pack_promisor:1,
- multi_pack_index:1,
- is_cruft:1;
- unsigned char hash[GIT_MAX_RAWSZ];
- struct revindex_entry *revindex;
- const uint32_t *revindex_data;
- const uint32_t *revindex_map;
- size_t revindex_size;
- /*
- * mtimes_map points at the beginning of the memory mapped region of
- * this pack's corresponding .mtimes file, and mtimes_size is the size
- * of that .mtimes file
- */
- const uint32_t *mtimes_map;
- size_t mtimes_size;
- /* something like ".git/objects/pack/xxxxx.pack" */
- char pack_name[FLEX_ARRAY]; /* more */
-};
-
-struct multi_pack_index;
-
-static inline int pack_map_entry_cmp(const void *cmp_data UNUSED,
- const struct hashmap_entry *entry,
- const struct hashmap_entry *entry2,
- const void *keydata)
-{
- const char *key = keydata;
- const struct packed_git *pg1, *pg2;
-
- pg1 = container_of(entry, const struct packed_git, packmap_ent);
- pg2 = container_of(entry2, const struct packed_git, packmap_ent);
-
- return strcmp(pg1->pack_name, key ? key : pg2->pack_name);
-}
-
-struct raw_object_store {
- /*
- * Set of all object directories; the main directory is first (and
- * cannot be NULL after initialization). Subsequent directories are
- * alternates.
- */
- struct object_directory *odb;
- struct object_directory **odb_tail;
- kh_odb_path_map_t *odb_by_path;
-
- int loaded_alternates;
-
- /*
- * A list of alternate object directories loaded from the environment;
- * this should not generally need to be accessed directly, but will
- * populate the "odb" list when prepare_alt_odb() is run.
- */
- char *alternate_db;
-
- /*
- * Objects that should be substituted by other objects
- * (see git-replace(1)).
- */
- struct oidmap *replace_map;
- unsigned replace_map_initialized : 1;
- pthread_mutex_t replace_mutex; /* protect object replace functions */
-
- struct commit_graph *commit_graph;
- unsigned commit_graph_attempted : 1; /* if loading has been attempted */
-
- /*
- * private data
- *
- * should only be accessed directly by packfile.c and midx.c
- */
- struct multi_pack_index *multi_pack_index;
-
- /*
- * private data
- *
- * should only be accessed directly by packfile.c
- */
-
- struct packed_git *packed_git;
- /* A most-recently-used ordered version of the packed_git list. */
- struct list_head packed_git_mru;
-
- struct {
- struct packed_git **packs;
- unsigned flags;
- } kept_pack_cache;
-
- /*
- * A map of packfiles to packed_git structs for tracking which
- * packs have been loaded already.
- */
- struct hashmap pack_map;
-
- /*
- * A fast, rough count of the number of objects in the repository.
- * These two fields are not meant for direct access. Use
- * approximate_object_count() instead.
- */
- unsigned long approximate_object_count;
- unsigned approximate_object_count_valid : 1;
-
- /*
- * Whether packed_git has already been populated with this repository's
- * packs.
- */
- unsigned packed_git_initialized : 1;
-};
-
-struct raw_object_store *raw_object_store_new(void);
-void raw_object_store_clear(struct raw_object_store *o);
-
-/*
- * Put in `buf` the name of the file in the local object database that
- * would be used to store a loose object with the specified oid.
- */
-const char *loose_object_path(struct repository *r, struct strbuf *buf,
- const struct object_id *oid);
-
-void *map_loose_object(struct repository *r, const struct object_id *oid,
- unsigned long *size);
-
-void *repo_read_object_file(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define read_object_file(oid, type, size) repo_read_object_file(the_repository, oid, type, size)
-#endif
-
-/* Read and unpack an object file into memory, write memory to an object file */
-int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);
-
-void hash_object_file(const struct git_hash_algo *algo, const void *buf,
- unsigned long len, enum object_type type,
- struct object_id *oid);
-
-int write_object_file_flags(const void *buf, unsigned long len,
- enum object_type type, struct object_id *oid,
- unsigned flags);
-static inline int write_object_file(const void *buf, unsigned long len,
- enum object_type type, struct object_id *oid)
-{
- return write_object_file_flags(buf, len, type, oid, 0);
-}
-
-int write_object_file_literally(const void *buf, unsigned long len,
- const char *type, struct object_id *oid,
- unsigned flags);
-int stream_loose_object(struct input_stream *in_stream, size_t len,
- struct object_id *oid);
-
-/*
- * Add an object file to the in-memory object store, without writing it
- * to disk.
- *
- * Callers are responsible for calling write_object_file to record the
- * object in persistent storage before writing any other new objects
- * that reference it.
- */
-int pretend_object_file(void *, unsigned long, enum object_type,
- struct object_id *oid);
-
-int force_object_loose(const struct object_id *oid, time_t mtime);
-
-/*
- * Open the loose object at path, check its hash, and return the contents,
- * use the "oi" argument to assert things about the object, or e.g. populate its
- * type, and size. If the object is a blob, then "contents" may return NULL,
- * to allow streaming of large blobs.
- *
- * Returns 0 on success, negative on error (details may be written to stderr).
- */
-int read_loose_object(const char *path,
- const struct object_id *expected_oid,
- struct object_id *real_oid,
- void **contents,
- struct object_info *oi);
-
-/* Retry packed storage after checking packed and loose storage */
-#define HAS_OBJECT_RECHECK_PACKED 1
-
-/*
- * Returns 1 if the object exists. This function will not lazily fetch objects
- * in a partial clone.
- */
-int has_object(struct repository *r, const struct object_id *oid,
- unsigned flags);
-
-/*
- * These macros and functions are deprecated. If checking existence for an
- * object that is likely to be missing and/or whose absence is relatively
- * inconsequential (or is consequential but the caller is prepared to handle
- * it), use has_object(), which has better defaults (no lazy fetch in a partial
- * clone and no rechecking of packed storage). In the unlikely event that a
- * caller needs to assert existence of an object that it fully expects to
- * exist, and wants to trigger a lazy fetch in a partial clone, use
- * oid_object_info_extended() with a NULL struct object_info.
- *
- * These functions can be removed once all callers have migrated to
- * has_object() and/or oid_object_info_extended().
- */
-int repo_has_object_file(struct repository *r, const struct object_id *oid);
-int repo_has_object_file_with_flags(struct repository *r,
- const struct object_id *oid, int flags);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define has_object_file(oid) repo_has_object_file(the_repository, oid)
-#define has_object_file_with_flags(oid, flags) repo_has_object_file_with_flags(the_repository, oid, flags)
-#endif
-
-/*
- * Return true iff an alternate object database has a loose object
- * with the specified name. This function does not respect replace
- * references.
- */
-int has_loose_object_nonlocal(const struct object_id *);
-
-int has_loose_object(const struct object_id *);
-
-/**
- * format_object_header() is a thin wrapper around s xsnprintf() that
- * writes the initial "<type> <obj-len>" part of the loose object
- * header. It returns the size that snprintf() returns + 1.
- */
-int format_object_header(char *str, size_t size, enum object_type type,
- size_t objsize);
-
-void assert_oid_type(const struct object_id *oid, enum object_type expect);
-
-/*
- * Enabling the object read lock allows multiple threads to safely call the
- * following functions in parallel: repo_read_object_file(), read_object_file(),
- * read_object_with_reference(), oid_object_info() and oid_object_info_extended().
- *
- * obj_read_lock() and obj_read_unlock() may also be used to protect other
- * section which cannot execute in parallel with object reading. Since the used
- * lock is a recursive mutex, these sections can even contain calls to object
- * reading functions. However, beware that in these cases zlib inflation won't
- * be performed in parallel, losing performance.
- *
- * TODO: oid_object_info_extended()'s call stack has a recursive behavior. If
- * any of its callees end up calling it, this recursive call won't benefit from
- * parallel inflation.
- */
-void enable_obj_read_lock(void);
-void disable_obj_read_lock(void);
-
-extern int obj_read_use_lock;
-extern pthread_mutex_t obj_read_mutex;
-
-static inline void obj_read_lock(void)
-{
- if(obj_read_use_lock)
- pthread_mutex_lock(&obj_read_mutex);
-}
-
-static inline void obj_read_unlock(void)
-{
- if(obj_read_use_lock)
- pthread_mutex_unlock(&obj_read_mutex);
-}
-
-struct object_info {
- /* Request */
- enum object_type *typep;
- unsigned long *sizep;
- off_t *disk_sizep;
- struct object_id *delta_base_oid;
- struct strbuf *type_name;
- void **contentp;
-
- /* Response */
- enum {
- OI_CACHED,
- OI_LOOSE,
- OI_PACKED,
- OI_DBCACHED
- } whence;
- union {
- /*
- * struct {
- * ... Nothing to expose in this case
- * } cached;
- * struct {
- * ... Nothing to expose in this case
- * } loose;
- */
- struct {
- struct packed_git *pack;
- off_t offset;
- unsigned int is_delta;
- } packed;
- } u;
-};
-
-/*
- * Initializer for a "struct object_info" that wants no items. You may
- * also memset() the memory to all-zeroes.
- */
-#define OBJECT_INFO_INIT { 0 }
-
-/* Invoke lookup_replace_object() on the given hash */
-#define OBJECT_INFO_LOOKUP_REPLACE 1
-/* Allow reading from a loose object file of unknown/bogus type */
-#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
-/* Do not retry packed storage after checking packed and loose storage */
-#define OBJECT_INFO_QUICK 8
-/*
- * Do not attempt to fetch the object if missing (even if fetch_is_missing is
- * nonzero).
- */
-#define OBJECT_INFO_SKIP_FETCH_OBJECT 16
-/*
- * This is meant for bulk prefetching of missing blobs in a partial
- * clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
- */
-#define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
-
-/* Die if object corruption (not just an object being missing) was detected. */
-#define OBJECT_INFO_DIE_IF_CORRUPT 32
-
-int oid_object_info_extended(struct repository *r,
- const struct object_id *,
- struct object_info *, unsigned flags);
-
-/*
- * Iterate over the files in the loose-object parts of the object
- * directory "path", triggering the following callbacks:
- *
- * - loose_object is called for each loose object we find.
- *
- * - loose_cruft is called for any files that do not appear to be
- * loose objects. Note that we only look in the loose object
- * directories "objects/[0-9a-f]{2}/", so we will not report
- * "objects/foobar" as cruft.
- *
- * - loose_subdir is called for each top-level hashed subdirectory
- * of the object directory (e.g., "$OBJDIR/f0"). It is called
- * after the objects in the directory are processed.
- *
- * Any callback that is NULL will be ignored. Callbacks returning non-zero
- * will end the iteration.
- *
- * In the "buf" variant, "path" is a strbuf which will also be used as a
- * scratch buffer, but restored to its original contents before
- * the function returns.
- */
-typedef int each_loose_object_fn(const struct object_id *oid,
- const char *path,
- void *data);
-typedef int each_loose_cruft_fn(const char *basename,
- const char *path,
- void *data);
-typedef int each_loose_subdir_fn(unsigned int nr,
- const char *path,
- void *data);
-int for_each_file_in_obj_subdir(unsigned int subdir_nr,
- struct strbuf *path,
- each_loose_object_fn obj_cb,
- each_loose_cruft_fn cruft_cb,
- each_loose_subdir_fn subdir_cb,
- void *data);
-int for_each_loose_file_in_objdir(const char *path,
- each_loose_object_fn obj_cb,
- each_loose_cruft_fn cruft_cb,
- each_loose_subdir_fn subdir_cb,
- void *data);
-int for_each_loose_file_in_objdir_buf(struct strbuf *path,
- each_loose_object_fn obj_cb,
- each_loose_cruft_fn cruft_cb,
- each_loose_subdir_fn subdir_cb,
- void *data);
-
-/* Flags for for_each_*_object() below. */
-enum for_each_object_flags {
- /* Iterate only over local objects, not alternates. */
- FOR_EACH_OBJECT_LOCAL_ONLY = (1<<0),
-
- /* Only iterate over packs obtained from the promisor remote. */
- FOR_EACH_OBJECT_PROMISOR_ONLY = (1<<1),
-
- /*
- * Visit objects within a pack in packfile order rather than .idx order
- */
- FOR_EACH_OBJECT_PACK_ORDER = (1<<2),
-
- /* Only iterate over packs that are not marked as kept in-core. */
- FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS = (1<<3),
-
- /* Only iterate over packs that do not have .keep files. */
- FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS = (1<<4),
-};
-
-/*
- * Iterate over all accessible loose objects without respect to
- * reachability. By default, this includes both local and alternate objects.
- * The order in which objects are visited is unspecified.
- *
- * Any flags specific to packs are ignored.
- */
-int for_each_loose_object(each_loose_object_fn, void *,
- enum for_each_object_flags flags);
-
-/*
- * Iterate over all accessible packed objects without respect to reachability.
- * By default, this includes both local and alternate packs.
- *
- * Note that some objects may appear twice if they are found in multiple packs.
- * Each pack is visited in an unspecified order. By default, objects within a
- * pack are visited in pack-idx order (i.e., sorted by oid).
- */
-typedef int each_packed_object_fn(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
- void *data);
-int for_each_object_in_pack(struct packed_git *p,
- each_packed_object_fn, void *data,
- enum for_each_object_flags flags);
-int for_each_packed_object(each_packed_object_fn, void *,
- enum for_each_object_flags flags);
-
#endif /* OBJECT_STORE_H */
diff --git a/object.c b/object.c
index 344087de4d..0edb22fa0f 100644
--- a/object.c
+++ b/object.c
@@ -1,8 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
#include "object.h"
#include "replace-object.h"
+#include "object-file.h"
#include "object-store.h"
#include "blob.h"
+#include "statinfo.h"
#include "tree.h"
#include "commit.h"
#include "tag.h"
@@ -177,6 +181,18 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)
}
}
+void *object_as_type_hint(struct object *obj, enum object_type type,
+ enum object_type hint)
+{
+ if (hint != OBJ_NONE && obj->type != OBJ_NONE && obj->type != type) {
+ error(_("object %s is a %s, not a %s"), oid_to_hex(&obj->oid),
+ type_name(type), type_name(obj->type));
+ obj->type = type;
+ return NULL;
+ }
+ return object_as_type(obj, type, 0);;
+}
+
struct object *lookup_unknown_object(struct repository *r, const struct object_id *oid)
{
struct object *obj = lookup_object(r, oid);
@@ -210,13 +226,13 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id
obj = NULL;
if (type == OBJ_BLOB) {
- struct blob *blob = lookup_blob(r, oid);
+ struct blob *blob = lookup_blob_type(r, oid, type);
if (blob) {
parse_blob_buffer(blob);
obj = &blob->object;
}
} else if (type == OBJ_TREE) {
- struct tree *tree = lookup_tree(r, oid);
+ struct tree *tree = lookup_tree_type(r, oid, type);
if (tree) {
obj = &tree->object;
if (!tree->buffer)
@@ -228,7 +244,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id
}
}
} else if (type == OBJ_COMMIT) {
- struct commit *commit = lookup_commit(r, oid);
+ struct commit *commit = lookup_commit_type(r, oid, type);
if (commit) {
if (parse_commit_buffer(r, commit, buffer, size, 1))
return NULL;
@@ -240,7 +256,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id
obj = &commit->object;
}
} else if (type == OBJ_TAG) {
- struct tag *tag = lookup_tag(r, oid);
+ struct tag *tag = lookup_tag_type(r, oid, type);
if (tag) {
if (parse_tag_buffer(r, tag, buffer, size))
return NULL;
diff --git a/object.h b/object.h
index 31ebe11458..17ca7f2c20 100644
--- a/object.h
+++ b/object.h
@@ -1,9 +1,10 @@
#ifndef OBJECT_H
#define OBJECT_H
-#include "cache.h"
+#include "hash-ll.h"
struct buffer_slab;
+struct repository;
struct parsed_object_pool {
struct object **obj_hash;
@@ -81,6 +82,70 @@ struct object_array {
*/
#define FLAG_BITS 28
+#define TYPE_BITS 3
+
+/*
+ * Values in this enum (except those outside the 3 bit range) are part
+ * of pack file format. See gitformat-pack(5) for more information.
+ */
+enum object_type {
+ OBJ_BAD = -1,
+ OBJ_NONE = 0,
+ OBJ_COMMIT = 1,
+ OBJ_TREE = 2,
+ OBJ_BLOB = 3,
+ OBJ_TAG = 4,
+ /* 5 for future expansion */
+ OBJ_OFS_DELTA = 6,
+ OBJ_REF_DELTA = 7,
+ OBJ_ANY,
+ OBJ_MAX
+};
+
+/* unknown mode (impossible combination S_IFIFO|S_IFCHR) */
+#define S_IFINVALID 0030000
+
+/*
+ * A "directory link" is a link to another git directory.
+ *
+ * The value 0160000 is not normally a valid mode, and
+ * also just happens to be S_IFDIR + S_IFLNK
+ */
+#define S_IFGITLINK 0160000
+#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
+
+#define S_ISSPARSEDIR(m) ((m) == S_IFDIR)
+
+static inline enum object_type object_type(unsigned int mode)
+{
+ return S_ISDIR(mode) ? OBJ_TREE :
+ S_ISGITLINK(mode) ? OBJ_COMMIT :
+ OBJ_BLOB;
+}
+
+#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
+static inline unsigned int create_ce_mode(unsigned int mode)
+{
+ if (S_ISLNK(mode))
+ return S_IFLNK;
+ if (S_ISSPARSEDIR(mode))
+ return S_IFDIR;
+ if (S_ISDIR(mode) || S_ISGITLINK(mode))
+ return S_IFGITLINK;
+ return S_IFREG | ce_permissions(mode);
+}
+
+static inline unsigned int canon_mode(unsigned int mode)
+{
+ if (S_ISREG(mode))
+ return S_IFREG | ce_permissions(mode);
+ if (S_ISLNK(mode))
+ return S_IFLNK;
+ if (S_ISDIR(mode))
+ return S_IFDIR;
+ return S_IFGITLINK;
+}
+
/*
* The object type is stored in 3 bits.
*/
@@ -122,6 +187,8 @@ struct object *lookup_object(struct repository *r, const struct object_id *oid);
void *create_object(struct repository *r, const struct object_id *oid, void *obj);
void *object_as_type(struct object *obj, enum object_type type, int quiet);
+void *object_as_type_hint(struct object *obj, enum object_type type,
+ enum object_type hint);
/*
* Returns the object, having parsed it to find out what it is.
diff --git a/oid-array.c b/oid-array.c
index 73ba76e9e9..e8228c777b 100644
--- a/oid-array.c
+++ b/oid-array.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "oid-array.h"
#include "hash-lookup.h"
diff --git a/oidmap.c b/oidmap.c
index 49965fe856..8b1bc4dec9 100644
--- a/oidmap.c
+++ b/oidmap.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hash.h"
#include "oidmap.h"
static int oidmap_neq(const void *hashmap_cmp_fn_data UNUSED,
diff --git a/oidmap.h b/oidmap.h
index c66a83ab1d..05c673eb7c 100644
--- a/oidmap.h
+++ b/oidmap.h
@@ -1,7 +1,7 @@
#ifndef OIDMAP_H
#define OIDMAP_H
-#include "cache.h"
+#include "hash-ll.h"
#include "hashmap.h"
/*
diff --git a/oidset.c b/oidset.c
index b36a2bae86..d1e5376316 100644
--- a/oidset.c
+++ b/oidset.c
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "oidset.h"
+#include "hex.h"
+#include "strbuf.h"
void oidset_init(struct oidset *set, size_t initial_size)
{
diff --git a/oidtree.c b/oidtree.c
index 0d39389bee..7d57b7b19e 100644
--- a/oidtree.c
+++ b/oidtree.c
@@ -2,6 +2,7 @@
* A wrapper around cbtree which stores oids
* May be used to replace oid-array for prefix (abbreviation) matches
*/
+#include "git-compat-util.h"
#include "oidtree.h"
#include "alloc.h"
#include "hash.h"
diff --git a/oidtree.h b/oidtree.h
index 77898f510a..55c83513fd 100644
--- a/oidtree.h
+++ b/oidtree.h
@@ -2,7 +2,7 @@
#define OIDTREE_H
#include "cbtree.h"
-#include "hash.h"
+#include "hash-ll.h"
#include "mem-pool.h"
struct oidtree {
diff --git a/oss-fuzz/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c
index 914026f5d8..2992079dd9 100644
--- a/oss-fuzz/fuzz-commit-graph.c
+++ b/oss-fuzz/fuzz-commit-graph.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
#include "commit-graph.h"
#include "repository.h"
diff --git a/oss-fuzz/fuzz-pack-headers.c b/oss-fuzz/fuzz-pack-headers.c
index 99da1d0fd3..150c0f5fa2 100644
--- a/oss-fuzz/fuzz-pack-headers.c
+++ b/oss-fuzz/fuzz-pack-headers.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
#include "packfile.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
diff --git a/oss-fuzz/fuzz-pack-idx.c b/oss-fuzz/fuzz-pack-idx.c
index 0c3d777aac..3e190214d1 100644
--- a/oss-fuzz/fuzz-pack-idx.c
+++ b/oss-fuzz/fuzz-pack-idx.c
@@ -1,4 +1,5 @@
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "object-store-ll.h"
#include "packfile.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index cfa67a510f..d86f4e739a 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -1,5 +1,9 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
#include "commit.h"
#include "tag.h"
#include "diff.h"
@@ -11,8 +15,12 @@
#include "pack-bitmap.h"
#include "hash-lookup.h"
#include "pack-objects.h"
+#include "path.h"
#include "commit-reach.h"
#include "prio-queue.h"
+#include "trace2.h"
+#include "tree.h"
+#include "tree-walk.h"
struct bitmapped_commit {
struct commit *commit;
@@ -425,7 +433,8 @@ static int fill_bitmap_commit(struct bb_commit *ent,
if (!found)
return -1;
bitmap_set(ent->bitmap, pos);
- prio_queue_put(tree_queue, get_commit_tree(c));
+ prio_queue_put(tree_queue,
+ repo_get_commit_tree(the_repository, c));
for (p = c->parents; p; p = p->next) {
pos = find_object_pos(&p->item->object.oid, &found);
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 6b5178a436..e452c7dff7 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -1,5 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "commit.h"
+#include "gettext.h"
+#include "hex.h"
#include "strbuf.h"
#include "tag.h"
#include "diff.h"
@@ -12,7 +15,9 @@
#include "pack-objects.h"
#include "packfile.h"
#include "repository.h"
-#include "object-store.h"
+#include "trace2.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "list-objects-filter-options.h"
#include "midx.h"
#include "config.h"
@@ -415,7 +420,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
goto cleanup;
}
- if (load_midx_revindex(bitmap_git->midx) < 0) {
+ if (load_midx_revindex(bitmap_git->midx)) {
warning(_("multi-pack bitmap is missing required reverse index"));
goto cleanup;
}
@@ -499,7 +504,7 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
return 0;
}
-static int load_reverse_index(struct bitmap_index *bitmap_git)
+static int load_reverse_index(struct repository *r, struct bitmap_index *bitmap_git)
{
if (bitmap_is_midx(bitmap_git)) {
uint32_t i;
@@ -513,23 +518,23 @@ static int load_reverse_index(struct bitmap_index *bitmap_git)
* since we will need to make use of them in pack-objects.
*/
for (i = 0; i < bitmap_git->midx->num_packs; i++) {
- ret = load_pack_revindex(bitmap_git->midx->packs[i]);
+ ret = load_pack_revindex(r, bitmap_git->midx->packs[i]);
if (ret)
return ret;
}
return 0;
}
- return load_pack_revindex(bitmap_git->pack);
+ return load_pack_revindex(r, bitmap_git->pack);
}
-static int load_bitmap(struct bitmap_index *bitmap_git)
+static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git)
{
assert(bitmap_git->map);
bitmap_git->bitmaps = kh_init_oid_map();
bitmap_git->ext_index.positions = kh_init_oid_pos();
- if (load_reverse_index(bitmap_git))
+ if (load_reverse_index(r, bitmap_git))
goto failed;
if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) ||
@@ -616,7 +621,7 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r)
{
struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
- if (!open_bitmap(r, bitmap_git) && !load_bitmap(bitmap_git))
+ if (!open_bitmap(r, bitmap_git) && !load_bitmap(r, bitmap_git))
return bitmap_git;
free_bitmap_index(bitmap_git);
@@ -625,9 +630,10 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r)
struct bitmap_index *prepare_midx_bitmap_git(struct multi_pack_index *midx)
{
+ struct repository *r = the_repository;
struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
- if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(bitmap_git))
+ if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(r, bitmap_git))
return bitmap_git;
free_bitmap_index(bitmap_git);
@@ -985,7 +991,8 @@ static void show_object(struct object *object, const char *name, void *data_)
bitmap_set(data->base, bitmap_pos);
}
-static void show_commit(struct commit *commit, void *data)
+static void show_commit(struct commit *commit UNUSED,
+ void *data UNUSED)
{
}
@@ -1622,7 +1629,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
* from disk. this is the point of no return; after this the rev_list
* becomes invalidated and we must perform the revwalk through bitmaps
*/
- if (load_bitmap(bitmap_git) < 0)
+ if (load_bitmap(revs->repo, bitmap_git) < 0)
goto cleanup;
object_array_clear(&revs->pending);
@@ -1772,6 +1779,7 @@ int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
uint32_t *entries,
struct bitmap **reuse_out)
{
+ struct repository *r = the_repository;
struct packed_git *pack;
struct bitmap *result = bitmap_git->result;
struct bitmap *reuse;
@@ -1782,7 +1790,7 @@ int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
assert(result);
- load_reverse_index(bitmap_git);
+ load_reverse_index(r, bitmap_git);
if (bitmap_is_midx(bitmap_git))
pack = bitmap_git->midx->packs[midx_preferred_pack(bitmap_git)];
@@ -1974,7 +1982,8 @@ static void test_bitmap_type(struct bitmap_test_data *tdata,
type_name(bitmap_type));
}
-static void test_show_object(struct object *object, const char *name,
+static void test_show_object(struct object *object,
+ const char *name UNUSED,
void *data)
{
struct bitmap_test_data *tdata = data;
@@ -2161,12 +2170,13 @@ int rebuild_bitmap(const uint32_t *reposition,
uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git,
struct packing_data *mapping)
{
+ struct repository *r = the_repository;
uint32_t i, num_objects;
uint32_t *reposition;
if (!bitmap_is_midx(bitmap_git))
- load_reverse_index(bitmap_git);
- else if (load_midx_revindex(bitmap_git->midx) < 0)
+ load_reverse_index(r, bitmap_git);
+ else if (load_midx_revindex(bitmap_git->midx))
BUG("rebuild_existing_bitmaps: missing required rev-cache "
"extension");
@@ -2348,7 +2358,11 @@ int bitmap_is_midx(struct bitmap_index *bitmap_git)
const struct string_list *bitmap_preferred_tips(struct repository *r)
{
- return repo_config_get_value_multi(r, "pack.preferbitmaptips");
+ const struct string_list *dest;
+
+ if (!repo_config_get_string_multi(r, "pack.preferbitmaptips", &dest))
+ return dest;
+ return NULL;
}
int bitmap_is_preferred_refname(struct repository *r, const char *refname)
@@ -2366,3 +2380,48 @@ int bitmap_is_preferred_refname(struct repository *r, const char *refname)
return 0;
}
+
+static int verify_bitmap_file(const char *name)
+{
+ struct stat st;
+ unsigned char *data;
+ int fd = git_open(name);
+ int res = 0;
+
+ /* It is OK to not have the file. */
+ if (fd < 0 || fstat(fd, &st)) {
+ if (fd >= 0)
+ close(fd);
+ return 0;
+ }
+
+ data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ close(fd);
+ if (!hashfile_checksum_valid(data, st.st_size))
+ res = error(_("bitmap file '%s' has invalid checksum"),
+ name);
+
+ munmap(data, st.st_size);
+ return res;
+}
+
+int verify_bitmap_files(struct repository *r)
+{
+ int res = 0;
+
+ for (struct multi_pack_index *m = get_multi_pack_index(r);
+ m; m = m->next) {
+ char *midx_bitmap_name = midx_bitmap_filename(m);
+ res |= verify_bitmap_file(midx_bitmap_name);
+ free(midx_bitmap_name);
+ }
+
+ for (struct packed_git *p = get_all_packs(r);
+ p; p = p->next) {
+ char *pack_bitmap_name = pack_bitmap_filename(p);
+ res |= verify_bitmap_file(pack_bitmap_name);
+ free(pack_bitmap_name);
+ }
+
+ return res;
+}
diff --git a/pack-bitmap.h b/pack-bitmap.h
index f0180b5276..84591f041b 100644
--- a/pack-bitmap.h
+++ b/pack-bitmap.h
@@ -111,4 +111,6 @@ int bitmap_is_midx(struct bitmap_index *bitmap_git);
const struct string_list *bitmap_preferred_tips(struct repository *r);
int bitmap_is_preferred_refname(struct repository *r, const char *refname);
+int verify_bitmap_files(struct repository *r);
+
#endif
diff --git a/pack-check.c b/pack-check.c
index bfb593ba72..977f619618 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -1,10 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "hex.h"
#include "repository.h"
#include "pack.h"
#include "pack-revindex.h"
#include "progress.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
struct idx_entry {
off_t offset;
diff --git a/pack-mtimes.c b/pack-mtimes.c
index 0f9785fc5e..cdf30b8d2b 100644
--- a/pack-mtimes.c
+++ b/pack-mtimes.c
@@ -1,7 +1,10 @@
#include "git-compat-util.h"
+#include "gettext.h"
#include "pack-mtimes.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "packfile.h"
+#include "strbuf.h"
static char *pack_mtimes_filename(struct packed_git *p)
{
diff --git a/pack-mtimes.h b/pack-mtimes.h
index cc957b3e85..107327cec0 100644
--- a/pack-mtimes.h
+++ b/pack-mtimes.h
@@ -1,8 +1,6 @@
#ifndef PACK_MTIMES_H
#define PACK_MTIMES_H
-#include "git-compat-util.h"
-
#define MTIMES_SIGNATURE 0x4d544d45 /* "MTME" */
#define MTIMES_VERSION 1
diff --git a/pack-objects.c b/pack-objects.c
index 272e8d4517..ccab09fe65 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "object.h"
#include "pack.h"
#include "pack-objects.h"
diff --git a/pack-objects.h b/pack-objects.h
index 579476687c..0d78db40cb 100644
--- a/pack-objects.h
+++ b/pack-objects.h
@@ -1,7 +1,7 @@
#ifndef PACK_OBJECTS_H
#define PACK_OBJECTS_H
-#include "object-store.h"
+#include "object-store-ll.h"
#include "thread-utils.h"
#include "pack.h"
diff --git a/pack-revindex.c b/pack-revindex.c
index 08dc160167..7fffcad912 100644
--- a/pack-revindex.c
+++ b/pack-revindex.c
@@ -1,9 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
#include "pack-revindex.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "packfile.h"
+#include "strbuf.h"
+#include "trace2.h"
#include "config.h"
#include "midx.h"
+#include "csum-file.h"
struct revindex_entry {
off_t offset;
@@ -204,10 +209,14 @@ static int load_revindex_from_disk(char *revindex_name,
size_t revindex_size;
struct revindex_header *hdr;
+ if (git_env_bool(GIT_TEST_REV_INDEX_DIE_ON_DISK, 0))
+ die("dying as requested by '%s'", GIT_TEST_REV_INDEX_DIE_ON_DISK);
+
fd = git_open(revindex_name);
if (fd < 0) {
- ret = -1;
+ /* "No file" means return 1. */
+ ret = 1;
goto cleanup;
}
if (fstat(fd, &st)) {
@@ -259,7 +268,7 @@ cleanup:
return ret;
}
-static int load_pack_revindex_from_disk(struct packed_git *p)
+int load_pack_revindex_from_disk(struct packed_git *p)
{
char *revindex_name;
int ret;
@@ -282,18 +291,58 @@ cleanup:
return ret;
}
-int load_pack_revindex(struct packed_git *p)
+int load_pack_revindex(struct repository *r, struct packed_git *p)
{
if (p->revindex || p->revindex_data)
return 0;
- if (!load_pack_revindex_from_disk(p))
+ prepare_repo_settings(r);
+
+ if (r->settings.pack_read_reverse_index &&
+ !load_pack_revindex_from_disk(p))
return 0;
else if (!create_pack_revindex_in_memory(p))
return 0;
return -1;
}
+/*
+ * verify_pack_revindex verifies that the on-disk rev-index for the given
+ * pack-file is the same that would be created if written from scratch.
+ *
+ * A negative number is returned on error.
+ */
+int verify_pack_revindex(struct packed_git *p)
+{
+ int res = 0;
+
+ /* Do not bother checking if not initialized. */
+ if (!p->revindex_map || !p->revindex_data)
+ return res;
+
+ if (!hashfile_checksum_valid((const unsigned char *)p->revindex_map, p->revindex_size)) {
+ error(_("invalid checksum"));
+ res = -1;
+ }
+
+ /* This may fail due to a broken .idx. */
+ if (create_pack_revindex_in_memory(p))
+ return res;
+
+ for (size_t i = 0; i < p->num_objects; i++) {
+ uint32_t nr = p->revindex[i].nr;
+ uint32_t rev_val = get_be32(p->revindex_data + i);
+
+ if (nr != rev_val) {
+ error(_("invalid rev-index position at %"PRIu64": %"PRIu32" != %"PRIu32""),
+ (uint64_t)i, nr, rev_val);
+ res = -1;
+ }
+ }
+
+ return res;
+}
+
int load_midx_revindex(struct multi_pack_index *m)
{
struct strbuf revindex_name = STRBUF_INIT;
@@ -355,7 +404,7 @@ int offset_to_pack_pos(struct packed_git *p, off_t ofs, uint32_t *pos)
{
unsigned lo, hi;
- if (load_pack_revindex(p) < 0)
+ if (load_pack_revindex(the_repository, p) < 0)
return -1;
lo = 0;
diff --git a/pack-revindex.h b/pack-revindex.h
index 4974e75eb4..6dd47efea1 100644
--- a/pack-revindex.h
+++ b/pack-revindex.h
@@ -34,11 +34,13 @@
#define RIDX_SIGNATURE 0x52494458 /* "RIDX" */
#define RIDX_VERSION 1
-#define GIT_TEST_WRITE_REV_INDEX "GIT_TEST_WRITE_REV_INDEX"
+#define GIT_TEST_NO_WRITE_REV_INDEX "GIT_TEST_NO_WRITE_REV_INDEX"
#define GIT_TEST_REV_INDEX_DIE_IN_MEMORY "GIT_TEST_REV_INDEX_DIE_IN_MEMORY"
+#define GIT_TEST_REV_INDEX_DIE_ON_DISK "GIT_TEST_REV_INDEX_DIE_ON_DISK"
struct packed_git;
struct multi_pack_index;
+struct repository;
/*
* load_pack_revindex populates the revindex's internal data-structures for the
@@ -47,7 +49,23 @@ struct multi_pack_index;
* If a '.rev' file is present it is mmap'd, and pointers are assigned into it
* (instead of using the in-memory variant).
*/
-int load_pack_revindex(struct packed_git *p);
+int load_pack_revindex(struct repository *r, struct packed_git *p);
+
+/*
+ * Specifically load a pack revindex from disk.
+ *
+ * Returns 0 on success, 1 on "no .rev file", and -1 when there is an
+ * error parsing the .rev file.
+ */
+int load_pack_revindex_from_disk(struct packed_git *p);
+
+/*
+ * verify_pack_revindex verifies that the on-disk rev-index for the given
+ * pack-file is the same that would be created if written from scratch.
+ *
+ * A negative number is returned on error.
+ */
+int verify_pack_revindex(struct packed_git *p);
/*
* load_midx_revindex loads the '.rev' file corresponding to the given
diff --git a/pack-write.c b/pack-write.c
index 3363729748..af48813a9b 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -1,4 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "pack.h"
#include "csum-file.h"
#include "remote.h"
@@ -6,6 +9,10 @@
#include "pack-mtimes.h"
#include "oidmap.h"
#include "pack-objects.h"
+#include "pack-revindex.h"
+#include "path.h"
+#include "strbuf.h"
+#include "wrapper.h"
void reset_pack_idx_option(struct pack_idx_option *opts)
{
@@ -309,13 +316,13 @@ static void write_mtimes_trailer(struct hashfile *f, const unsigned char *hash)
hashwrite(f, hash, the_hash_algo->rawsz);
}
-static const char *write_mtimes_file(struct packing_data *to_pack,
- struct pack_idx_entry **objects,
- uint32_t nr_objects,
- const unsigned char *hash)
+static char *write_mtimes_file(struct packing_data *to_pack,
+ struct pack_idx_entry **objects,
+ uint32_t nr_objects,
+ const unsigned char *hash)
{
struct strbuf tmp_file = STRBUF_INIT;
- const char *mtimes_name;
+ char *mtimes_name;
struct hashfile *f;
int fd;
@@ -541,7 +548,7 @@ void stage_tmp_packfiles(struct strbuf *name_buffer,
char **idx_tmp_name)
{
const char *rev_tmp_name = NULL;
- const char *mtimes_tmp_name = NULL;
+ char *mtimes_tmp_name = NULL;
if (adjust_shared_perm(pack_tmp_name))
die_errno("unable to make temporary pack file readable");
@@ -565,6 +572,9 @@ void stage_tmp_packfiles(struct strbuf *name_buffer,
rename_tmp_packfile(name_buffer, rev_tmp_name, "rev");
if (mtimes_tmp_name)
rename_tmp_packfile(name_buffer, mtimes_tmp_name, "mtimes");
+
+ free((char *)rev_tmp_name);
+ free(mtimes_tmp_name);
}
void write_promisor_file(const char *promisor_name, struct ref **sought, int nr_sought)
diff --git a/pack.h b/pack.h
index 01d385903a..3ab9e3f60c 100644
--- a/pack.h
+++ b/pack.h
@@ -4,6 +4,8 @@
#include "object.h"
#include "csum-file.h"
+struct packed_git;
+struct pack_window;
struct repository;
/*
diff --git a/packfile.c b/packfile.c
index 79e21ab18e..c60aeb05ec 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1,4 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "list.h"
#include "pack.h"
#include "repository.h"
@@ -11,12 +15,16 @@
#include "commit.h"
#include "object.h"
#include "tag.h"
+#include "trace.h"
#include "tree-walk.h"
#include "tree.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "midx.h"
#include "commit-graph.h"
+#include "pack-revindex.h"
#include "promisor-remote.h"
+#include "wrapper.h"
char *odb_pack_name(struct strbuf *buf,
const unsigned char *hash,
@@ -1008,6 +1016,16 @@ void reprepare_packed_git(struct repository *r)
struct object_directory *odb;
obj_read_lock();
+
+ /*
+ * Reprepare alt odbs, in case the alternates file was modified
+ * during the course of this process. This only _adds_ odbs to
+ * the linked list, so existing odbs will continue to exist for
+ * the lifetime of the process.
+ */
+ r->objects->loaded_alternates = 0;
+ prepare_alt_odb(r);
+
for (odb = r->objects->odb; odb; odb = odb->next)
odb_clear_loose_cache(odb);
@@ -2136,7 +2154,7 @@ int for_each_object_in_pack(struct packed_git *p,
int r = 0;
if (flags & FOR_EACH_OBJECT_PACK_ORDER) {
- if (load_pack_revindex(p))
+ if (load_pack_revindex(the_repository, p))
return -1;
}
@@ -2204,8 +2222,8 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,
}
static int add_promisor_object(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED,
void *set_)
{
struct oidset *set = set_;
@@ -2263,7 +2281,7 @@ int is_promisor_object(const struct object_id *oid)
static int promisor_objects_prepared;
if (!promisor_objects_prepared) {
- if (has_promisor_remote()) {
+ if (repo_has_promisor_remote(the_repository)) {
for_each_packed_object(add_promisor_object,
&promisor_objects,
FOR_EACH_OBJECT_PROMISOR_ONLY |
diff --git a/packfile.h b/packfile.h
index a3f6723857..c3692308b8 100644
--- a/packfile.h
+++ b/packfile.h
@@ -1,13 +1,27 @@
#ifndef PACKFILE_H
#define PACKFILE_H
-#include "cache.h"
+#include "object.h"
#include "oidset.h"
/* in object-store.h */
struct packed_git;
struct object_info;
+struct pack_window {
+ struct pack_window *next;
+ unsigned char *base;
+ off_t offset;
+ size_t len;
+ unsigned int last_used;
+ unsigned int inuse_cnt;
+};
+
+struct pack_entry {
+ off_t offset;
+ struct packed_git *p;
+};
+
/*
* Generate the filename to be used for a pack file with checksum "sha1" and
* extension "ext". The result is written into the strbuf "buf", overwriting
@@ -65,7 +79,6 @@ struct packed_git *get_all_packs(struct repository *r);
* for speed.
*/
unsigned long repo_approximate_object_count(struct repository *r);
-#define approximate_object_count() repo_approximate_object_count(the_repository)
struct packed_git *find_sha1_pack(const unsigned char *sha1,
struct packed_git *packs);
diff --git a/pager.c b/pager.c
index b66bbff278..63055d0873 100644
--- a/pager.c
+++ b/pager.c
@@ -1,9 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "editor.h"
+#include "pager.h"
#include "run-command.h"
#include "sigchain.h"
#include "alias.h"
+int pager_use_color = 1;
+
#ifndef DEFAULT_PAGER
#define DEFAULT_PAGER "less"
#endif
diff --git a/pager.h b/pager.h
new file mode 100644
index 0000000000..b77433026d
--- /dev/null
+++ b/pager.h
@@ -0,0 +1,17 @@
+#ifndef PAGER_H
+#define PAGER_H
+
+struct child_process;
+
+const char *git_pager(int stdout_is_tty);
+void setup_pager(void);
+int pager_in_use(void);
+int term_columns(void);
+void term_clear_line(void);
+int decimal_width(uintmax_t);
+int check_pager_config(const char *cmd);
+void prepare_pager_args(struct child_process *, const char *pager);
+
+extern int pager_use_color;
+
+#endif /* PAGER_H */
diff --git a/parallel-checkout.c b/parallel-checkout.c
index 4f6819f240..602fbf19d3 100644
--- a/parallel-checkout.c
+++ b/parallel-checkout.c
@@ -1,14 +1,21 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
#include "entry.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "parallel-checkout.h"
#include "pkt-line.h"
#include "progress.h"
+#include "read-cache-ll.h"
#include "run-command.h"
#include "sigchain.h"
#include "streaming.h"
+#include "symlinks.h"
#include "thread-utils.h"
#include "trace2.h"
+#include "wrapper.h"
struct pc_worker {
struct child_process cp;
diff --git a/parse-options-cb.c b/parse-options-cb.c
index d346dbe210..a24521dee0 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -1,9 +1,12 @@
#include "git-compat-util.h"
#include "parse-options.h"
#include "branch.h"
-#include "cache.h"
#include "commit.h"
#include "color.h"
+#include "date.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-name.h"
#include "string-list.h"
#include "strvec.h"
#include "oid-array.h"
@@ -91,7 +94,7 @@ int parse_opt_commits(const struct option *opt, const char *arg, int unset)
if (!arg)
return -1;
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
return error("malformed object name %s", arg);
commit = lookup_commit_reference(the_repository, &oid);
if (!commit)
@@ -110,7 +113,7 @@ int parse_opt_commit(const struct option *opt, const char *arg, int unset)
if (!arg)
return -1;
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
return error("malformed object name %s", arg);
commit = lookup_commit_reference(the_repository, &oid);
if (!commit)
@@ -129,7 +132,7 @@ int parse_opt_object_name(const struct option *opt, const char *arg, int unset)
}
if (!arg)
return -1;
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
return error(_("malformed object name '%s'"), arg);
oid_array_append(opt->value, &oid);
return 0;
@@ -146,7 +149,7 @@ int parse_opt_object_id(const struct option *opt, const char *arg, int unset)
}
if (!arg)
return -1;
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
return error(_("malformed object name '%s'"), arg);
*target = oid;
return 0;
@@ -208,24 +211,25 @@ int parse_opt_string_list(const struct option *opt, const char *arg, int unset)
return 0;
}
-int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
+int parse_opt_strvec(const struct option *opt, const char *arg, int unset)
{
+ struct strvec *v = opt->value;
+
+ if (unset) {
+ strvec_clear(v);
+ return 0;
+ }
+
+ if (!arg)
+ return -1;
+
+ strvec_push(v, arg);
return 0;
}
-/**
- * Report that the option is unknown, so that other code can handle
- * it. This can be used as a callback together with
- * OPTION_LOWLEVEL_CALLBACK to allow an option to be documented in the
- * "-h" output even if it's not being handled directly by
- * parse_options().
- */
-enum parse_opt_result parse_opt_unknown_cb(struct parse_opt_ctx_t *ctx,
- const struct option *opt,
- const char *arg, int unset)
+int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
{
- BUG_ON_OPT_ARG(arg);
- return PARSE_OPT_UNKNOWN;
+ return 0;
}
/**
diff --git a/parse-options.c b/parse-options.c
index fd4743293f..f8a155ee13 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -1,9 +1,11 @@
#include "git-compat-util.h"
#include "parse-options.h"
-#include "cache.h"
+#include "abspath.h"
#include "config.h"
#include "commit.h"
#include "color.h"
+#include "gettext.h"
+#include "strbuf.h"
#include "utf8.h"
static int disallow_abbreviated_options;
@@ -59,12 +61,12 @@ static enum parse_opt_result get_arg(struct parse_opt_ctx_t *p,
return 0;
}
-static void fix_filename(const char *prefix, const char **file)
+static void fix_filename(const char *prefix, char **file)
{
- if (!file || !*file || !prefix || is_absolute_path(*file)
- || !strcmp("-", *file))
- return;
- *file = prefix_filename(prefix, *file);
+ if (!file || !*file)
+ ; /* leave as NULL */
+ else
+ *file = prefix_filename_except_for_dash(prefix, *file);
}
static enum parse_opt_result opt_command_mode_error(
@@ -177,7 +179,7 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
err = get_arg(p, opt, flags, (const char **)opt->value);
if (!err)
- fix_filename(p->prefix, (const char **)opt->value);
+ fix_filename(p->prefix, (char **)opt->value);
return err;
case OPTION_CALLBACK:
diff --git a/parse-options.h b/parse-options.h
index 50d852f299..8e48efe524 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -1,6 +1,8 @@
#ifndef PARSE_OPTIONS_H
#define PARSE_OPTIONS_H
+#include "gettext.h"
+
/**
* Refer to Documentation/technical/api-parse-options.txt for the API doc.
*/
@@ -158,71 +160,211 @@ struct option {
parse_opt_subcommand_fn *subcommand_fn;
};
-#define OPT_BIT_F(s, l, v, h, b, f) { OPTION_BIT, (s), (l), (v), NULL, (h), \
- PARSE_OPT_NOARG|(f), NULL, (b) }
-#define OPT_COUNTUP_F(s, l, v, h, f) { OPTION_COUNTUP, (s), (l), (v), NULL, \
- (h), PARSE_OPT_NOARG|(f) }
-#define OPT_SET_INT_F(s, l, v, h, i, f) { OPTION_SET_INT, (s), (l), (v), NULL, \
- (h), PARSE_OPT_NOARG | (f), NULL, (i) }
+#define OPT_BIT_F(s, l, v, h, b, f) { \
+ .type = OPTION_BIT, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .help = (h), \
+ .flags = PARSE_OPT_NOARG|(f), \
+ .callback = NULL, \
+ .defval = (b), \
+}
+#define OPT_COUNTUP_F(s, l, v, h, f) { \
+ .type = OPTION_COUNTUP, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .help = (h), \
+ .flags = PARSE_OPT_NOARG|(f), \
+}
+#define OPT_SET_INT_F(s, l, v, h, i, f) { \
+ .type = OPTION_SET_INT, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .help = (h), \
+ .flags = PARSE_OPT_NOARG | (f), \
+ .defval = (i), \
+}
#define OPT_BOOL_F(s, l, v, h, f) OPT_SET_INT_F(s, l, v, h, 1, f)
-#define OPT_CALLBACK_F(s, l, v, a, h, f, cb) \
- { OPTION_CALLBACK, (s), (l), (v), (a), (h), (f), (cb) }
-#define OPT_STRING_F(s, l, v, a, h, f) { OPTION_STRING, (s), (l), (v), (a), (h), (f) }
-#define OPT_INTEGER_F(s, l, v, h, f) { OPTION_INTEGER, (s), (l), (v), N_("n"), (h), (f) }
+#define OPT_CALLBACK_F(s, l, v, a, h, f, cb) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = (a), \
+ .help = (h), \
+ .flags = (f), \
+ .callback = (cb), \
+}
+#define OPT_STRING_F(s, l, v, a, h, f) { \
+ .type = OPTION_STRING, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = (a), \
+ .help = (h), \
+ .flags = (f), \
+}
+#define OPT_INTEGER_F(s, l, v, h, f) { \
+ .type = OPTION_INTEGER, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = N_("n"), \
+ .help = (h), \
+ .flags = (f), \
+}
-#define OPT_END() { OPTION_END }
-#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
+#define OPT_END() { \
+ .type = OPTION_END, \
+}
+#define OPT_GROUP(h) { \
+ .type = OPTION_GROUP, \
+ .help = (h), \
+}
#define OPT_BIT(s, l, v, h, b) OPT_BIT_F(s, l, v, h, b, 0)
-#define OPT_BITOP(s, l, v, h, set, clear) { OPTION_BITOP, (s), (l), (v), NULL, (h), \
- PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, \
- (set), NULL, (clear) }
-#define OPT_NEGBIT(s, l, v, h, b) { OPTION_NEGBIT, (s), (l), (v), NULL, \
- (h), PARSE_OPT_NOARG, NULL, (b) }
+#define OPT_BITOP(s, l, v, h, set, clear) { \
+ .type = OPTION_BITOP, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .help = (h), \
+ .flags = PARSE_OPT_NOARG|PARSE_OPT_NONEG, \
+ .defval = (set), \
+ .extra = (clear), \
+}
+#define OPT_NEGBIT(s, l, v, h, b) { \
+ .type = OPTION_NEGBIT, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .help = (h), \
+ .flags = PARSE_OPT_NOARG, \
+ .defval = (b), \
+}
#define OPT_COUNTUP(s, l, v, h) OPT_COUNTUP_F(s, l, v, h, 0)
#define OPT_SET_INT(s, l, v, h, i) OPT_SET_INT_F(s, l, v, h, i, 0)
#define OPT_BOOL(s, l, v, h) OPT_BOOL_F(s, l, v, h, 0)
-#define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \
- (h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1}
-#define OPT_CMDMODE_F(s, l, v, h, i, f) { OPTION_SET_INT, (s), (l), (v), NULL, \
- (h), PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG | (f), NULL, (i) }
+#define OPT_HIDDEN_BOOL(s, l, v, h) { \
+ .type = OPTION_SET_INT, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .help = (h), \
+ .flags = PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, \
+ .defval = 1, \
+}
+#define OPT_CMDMODE_F(s, l, v, h, i, f) { \
+ .type = OPTION_SET_INT, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .help = (h), \
+ .flags = PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG | (f), \
+ .defval = (i), \
+}
#define OPT_CMDMODE(s, l, v, h, i) OPT_CMDMODE_F(s, l, v, h, i, 0)
#define OPT_INTEGER(s, l, v, h) OPT_INTEGER_F(s, l, v, h, 0)
-#define OPT_MAGNITUDE(s, l, v, h) { OPTION_MAGNITUDE, (s), (l), (v), \
- N_("n"), (h), PARSE_OPT_NONEG }
+#define OPT_MAGNITUDE(s, l, v, h) { \
+ .type = OPTION_MAGNITUDE, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = N_("n"), \
+ .help = (h), \
+ .flags = PARSE_OPT_NONEG, \
+}
#define OPT_STRING(s, l, v, a, h) OPT_STRING_F(s, l, v, a, h, 0)
-#define OPT_STRING_LIST(s, l, v, a, h) \
- { OPTION_CALLBACK, (s), (l), (v), (a), \
- (h), 0, &parse_opt_string_list }
-#define OPT_UYN(s, l, v, h) { OPTION_CALLBACK, (s), (l), (v), NULL, \
- (h), PARSE_OPT_NOARG, &parse_opt_tertiary }
-#define OPT_EXPIRY_DATE(s, l, v, h) \
- { OPTION_CALLBACK, (s), (l), (v), N_("expiry-date"),(h), 0, \
- parse_opt_expiry_date_cb }
-#define OPT_CALLBACK(s, l, v, a, h, f) OPT_CALLBACK_F(s, l, v, a, h, 0, f)
-#define OPT_NUMBER_CALLBACK(v, h, f) \
- { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
-#define OPT_FILENAME(s, l, v, h) { OPTION_FILENAME, (s), (l), (v), \
- N_("file"), (h) }
-#define OPT_COLOR_FLAG(s, l, v, h) \
- { OPTION_CALLBACK, (s), (l), (v), N_("when"), (h), PARSE_OPT_OPTARG, \
- parse_opt_color_flag_cb, (intptr_t)"always" }
-
-#define OPT_NOOP_NOARG(s, l) \
- { OPTION_CALLBACK, (s), (l), NULL, NULL, \
- N_("no-op (backward compatibility)"), \
- PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, parse_opt_noop_cb }
-
-#define OPT_ALIAS(s, l, source_long_name) \
- { OPTION_ALIAS, (s), (l), (source_long_name) }
+#define OPT_STRING_LIST(s, l, v, a, h) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = (a), \
+ .help = (h), \
+ .callback = &parse_opt_string_list, \
+}
+#define OPT_STRVEC(s, l, v, a, h) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = (a), \
+ .help = (h), \
+ .callback = &parse_opt_strvec, \
+}
+#define OPT_UYN(s, l, v, h) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .help = (h), \
+ .flags = PARSE_OPT_NOARG, \
+ .callback = &parse_opt_tertiary, \
+}
+#define OPT_EXPIRY_DATE(s, l, v, h) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = N_("expiry-date"), \
+ .help = (h), \
+ .callback = parse_opt_expiry_date_cb, \
+}
+#define OPT_CALLBACK(s, l, v, a, h, cb) OPT_CALLBACK_F(s, l, v, a, h, 0, cb)
+#define OPT_NUMBER_CALLBACK(v, h, cb) { \
+ .type = OPTION_NUMBER, \
+ .value = (v), \
+ .help = (h), \
+ .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, \
+ .callback = (cb), \
+}
+#define OPT_FILENAME(s, l, v, h) { \
+ .type = OPTION_FILENAME, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = N_("file"), \
+ .help = (h), \
+}
+#define OPT_COLOR_FLAG(s, l, v, h) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = N_("when"), \
+ .help = (h), \
+ .flags = PARSE_OPT_OPTARG, \
+ .callback = parse_opt_color_flag_cb, \
+ .defval = (intptr_t)"always", \
+}
+
+#define OPT_NOOP_NOARG(s, l) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .help = N_("no-op (backward compatibility)"), \
+ .flags = PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, \
+ .callback = parse_opt_noop_cb, \
+}
+
+#define OPT_ALIAS(s, l, source_long_name) { \
+ .type = OPTION_ALIAS, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (source_long_name), \
+}
#define OPT_SUBCOMMAND_F(l, v, fn, f) { \
.type = OPTION_SUBCOMMAND, \
.long_name = (l), \
.value = (v), \
.flags = (f), \
- .subcommand_fn = (fn) }
+ .subcommand_fn = (fn), \
+}
#define OPT_SUBCOMMAND(l, v, fn) OPT_SUBCOMMAND_F((l), (v), (fn), 0)
/*
@@ -347,10 +489,8 @@ int parse_opt_commits(const struct option *, const char *, int);
int parse_opt_commit(const struct option *, const char *, int);
int parse_opt_tertiary(const struct option *, const char *, int);
int parse_opt_string_list(const struct option *, const char *, int);
+int parse_opt_strvec(const struct option *, const char *, int);
int parse_opt_noop_cb(const struct option *, const char *, int);
-enum parse_opt_result parse_opt_unknown_cb(struct parse_opt_ctx_t *ctx,
- const struct option *,
- const char *, int);
int parse_opt_passthru(const struct option *, const char *, int);
int parse_opt_passthru_argv(const struct option *, const char *, int);
/* value is enum branch_track* */
@@ -358,34 +498,80 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
#define OPT__VERBOSE(var, h) OPT_COUNTUP('v', "verbose", (var), (h))
#define OPT__QUIET(var, h) OPT_COUNTUP('q', "quiet", (var), (h))
-#define OPT__VERBOSITY(var) \
- { OPTION_CALLBACK, 'v', "verbose", (var), NULL, N_("be more verbose"), \
- PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
- { OPTION_CALLBACK, 'q', "quiet", (var), NULL, N_("be more quiet"), \
- PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
+#define OPT__VERBOSITY(var) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = 'v', \
+ .long_name = "verbose", \
+ .value = (var), \
+ .help = N_("be more verbose"), \
+ .flags = PARSE_OPT_NOARG, \
+ .callback = &parse_opt_verbosity_cb, \
+}, { \
+ .type = OPTION_CALLBACK, \
+ .short_name = 'q', \
+ .long_name = "quiet", \
+ .value = (var), \
+ .help = N_("be more quiet"), \
+ .flags = PARSE_OPT_NOARG, \
+ .callback = &parse_opt_verbosity_cb, \
+}
#define OPT__DRY_RUN(var, h) OPT_BOOL('n', "dry-run", (var), (h))
#define OPT__FORCE(var, h, f) OPT_COUNTUP_F('f', "force", (var), (h), (f))
-#define OPT__ABBREV(var) \
- { OPTION_CALLBACK, 0, "abbrev", (var), N_("n"), \
- N_("use <n> digits to display object names"), \
- PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+#define OPT__ABBREV(var) { \
+ .type = OPTION_CALLBACK, \
+ .long_name = "abbrev", \
+ .value = (var), \
+ .argh = N_("n"), \
+ .help = N_("use <n> digits to display object names"), \
+ .flags = PARSE_OPT_OPTARG, \
+ .callback = &parse_opt_abbrev_cb, \
+}
#define OPT__SUPER_PREFIX(var) \
OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
#define OPT__COLOR(var, h) \
OPT_COLOR_FLAG(0, "color", (var), (h))
-#define OPT_COLUMN(s, l, v, h) \
- { OPTION_CALLBACK, (s), (l), (v), N_("style"), (h), PARSE_OPT_OPTARG, parseopt_column_callback }
-#define OPT_PASSTHRU(s, l, v, a, h, f) \
- { OPTION_CALLBACK, (s), (l), (v), (a), (h), (f), parse_opt_passthru }
-#define OPT_PASSTHRU_ARGV(s, l, v, a, h, f) \
- { OPTION_CALLBACK, (s), (l), (v), (a), (h), (f), parse_opt_passthru_argv }
-#define _OPT_CONTAINS_OR_WITH(name, variable, help, flag) \
- { OPTION_CALLBACK, 0, name, (variable), N_("commit"), (help), \
- PARSE_OPT_LASTARG_DEFAULT | flag, \
- parse_opt_commits, (intptr_t) "HEAD" \
- }
+#define OPT_COLUMN(s, l, v, h) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = N_("style"), \
+ .help = (h), \
+ .flags = PARSE_OPT_OPTARG, \
+ .callback = parseopt_column_callback, \
+}
+#define OPT_PASSTHRU(s, l, v, a, h, f) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = (a), \
+ .help = (h), \
+ .flags = (f), \
+ .callback = parse_opt_passthru, \
+}
+#define OPT_PASSTHRU_ARGV(s, l, v, a, h, f) { \
+ .type = OPTION_CALLBACK, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = (a), \
+ .help = (h), \
+ .flags = (f), \
+ .callback = parse_opt_passthru_argv, \
+}
+#define _OPT_CONTAINS_OR_WITH(l, v, h, f) { \
+ .type = OPTION_CALLBACK, \
+ .long_name = (l), \
+ .value = (v), \
+ .argh = N_("commit"), \
+ .help = (h), \
+ .flags = PARSE_OPT_LASTARG_DEFAULT | (f), \
+ .callback = parse_opt_commits, \
+ .defval = (intptr_t) "HEAD", \
+}
#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("contains", v, h, PARSE_OPT_NONEG)
#define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("no-contains", v, h, PARSE_OPT_NONEG)
#define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
diff --git a/patch-ids.c b/patch-ids.c
index 3153446626..c3e1a0dd21 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -1,7 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "diff.h"
#include "commit.h"
+#include "hash.h"
#include "hash-lookup.h"
+#include "hex.h"
#include "patch-ids.h"
static int patch_id_defined(struct commit *commit)
diff --git a/path.c b/path.c
index 492e17ad12..044a50bad0 100644
--- a/path.c
+++ b/path.c
@@ -1,18 +1,24 @@
/*
* Utilities for paths and pathnames
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "strbuf.h"
#include "string-list.h"
#include "dir.h"
#include "worktree.h"
+#include "setup.h"
#include "submodule-config.h"
#include "path.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "lockfile.h"
#include "exec-cmd.h"
+#include "wrapper.h"
static int get_st_mode_bits(const char *path, int *mode)
{
@@ -347,7 +353,8 @@ static void init_common_trie(void)
* Helper function for update_common_dir: returns 1 if the dir
* prefix is common.
*/
-static int check_common(const char *unmatched, void *value, void *baton)
+static int check_common(const char *unmatched, void *value,
+ void *baton UNUSED)
{
struct common_dir *dir = value;
@@ -1206,6 +1213,26 @@ int normalize_path_copy(char *dst, const char *src)
return normalize_path_copy_len(dst, src, NULL);
}
+int strbuf_normalize_path(struct strbuf *src)
+{
+ struct strbuf dst = STRBUF_INIT;
+
+ strbuf_grow(&dst, src->len);
+ if (normalize_path_copy(dst.buf, src->buf) < 0) {
+ strbuf_release(&dst);
+ return -1;
+ }
+
+ /*
+ * normalize_path does not tell us the new length, so we have to
+ * compute it by looking for the new NUL it placed
+ */
+ strbuf_setlen(&dst, strlen(dst.buf));
+ strbuf_swap(src, &dst);
+ strbuf_release(&dst);
+ return 0;
+}
+
/*
* path = Canonical absolute path
* prefixes = string_list containing normalized, absolute paths without
diff --git a/path.h b/path.h
index 0a59c85a62..639372edd9 100644
--- a/path.h
+++ b/path.h
@@ -3,6 +3,7 @@
struct repository;
struct strbuf;
+struct string_list;
/*
* The result to all functions which return statically allocated memory may be
@@ -179,7 +180,71 @@ const char *git_path_auto_merge(struct repository *r);
const char *git_path_fetch_head(struct repository *r);
const char *git_path_shallow(struct repository *r);
-
int ends_with_path_components(const char *path, const char *components);
+int validate_headref(const char *ref);
+
+int adjust_shared_perm(const char *path);
+
+char *interpolate_path(const char *path, int real_home);
+const char *enter_repo(const char *path, int strict);
+const char *remove_leading_path(const char *in, const char *prefix);
+const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
+int normalize_path_copy(char *dst, const char *src);
+/**
+ * Normalize in-place the path contained in the strbuf. If an error occurs,
+ * the contents of "sb" are left untouched, and -1 is returned.
+ */
+int strbuf_normalize_path(struct strbuf *src);
+int longest_ancestor_length(const char *path, struct string_list *prefixes);
+char *strip_path_suffix(const char *path, const char *suffix);
+int daemon_avoid_alias(const char *path);
+
+/*
+ * These functions match their is_hfs_dotgit() counterparts; see utf8.h for
+ * details.
+ */
+int is_ntfs_dotgit(const char *name);
+int is_ntfs_dotgitmodules(const char *name);
+int is_ntfs_dotgitignore(const char *name);
+int is_ntfs_dotgitattributes(const char *name);
+int is_ntfs_dotmailmap(const char *name);
+
+/*
+ * Returns true iff "str" could be confused as a command-line option when
+ * passed to a sub-program like "ssh". Note that this has nothing to do with
+ * shell-quoting, which should be handled separately; we're assuming here that
+ * the string makes it verbatim to the sub-program.
+ */
+int looks_like_command_line_option(const char *str);
+
+/**
+ * Return a newly allocated string with the evaluation of
+ * "$XDG_CONFIG_HOME/$subdir/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
+ * "$HOME/.config/$subdir/$filename". Return NULL upon error.
+ */
+char *xdg_config_home_for(const char *subdir, const char *filename);
+
+/**
+ * Return a newly allocated string with the evaluation of
+ * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
+ * "$HOME/.config/git/$filename". Return NULL upon error.
+ */
+char *xdg_config_home(const char *filename);
+
+/**
+ * Return a newly allocated string with the evaluation of
+ * "$XDG_CACHE_HOME/git/$filename" if $XDG_CACHE_HOME is non-empty, otherwise
+ * "$HOME/.cache/git/$filename". Return NULL upon error.
+ */
+char *xdg_cache_home(const char *filename);
+
+/*
+ * Create a directory and (if share is nonzero) adjust its permissions
+ * according to the shared_repository setting. Only use this for
+ * directories under $GIT_DIR. Don't use it for working tree
+ * directories.
+ */
+void safe_create_dir(const char *dir, int share);
#endif /* PATH_H */
diff --git a/pathspec.c b/pathspec.c
index ab70fcbe61..4991455281 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -1,10 +1,18 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
#include "pathspec.h"
#include "attr.h"
+#include "read-cache.h"
+#include "repository.h"
+#include "setup.h"
#include "strvec.h"
+#include "symlinks.h"
#include "quote.h"
+#include "wildmatch.h"
/*
* Finds which of the given pathspecs match items in the index.
@@ -730,7 +738,7 @@ int match_pathspec_attrs(struct index_state *istate,
if (name[namelen])
name = to_free = xmemdupz(name, namelen);
- git_check_attr(istate, NULL, name, item->attr_check);
+ git_check_attr(istate, name, item->attr_check);
free(to_free);
diff --git a/pathspec.h b/pathspec.h
index 41f6adfbb4..a5b38e0907 100644
--- a/pathspec.h
+++ b/pathspec.h
@@ -171,6 +171,11 @@ int match_pathspec_attrs(struct index_state *istate,
const char *name, int namelen,
const struct pathspec_item *item);
+int match_pathspec(struct index_state *istate,
+ const struct pathspec *pathspec,
+ const char *name, int namelen,
+ int prefix, char *seen, int is_dir);
+
/*
* Determine whether a pathspec will match only entire index entries (non-sparse
* files and/or entire sparse directories). If the pathspec has the potential to
diff --git a/pkt-line.c b/pkt-line.c
index ce4e73b683..62b4208b66 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -1,6 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "copy.h"
#include "pkt-line.h"
+#include "gettext.h"
+#include "hex.h"
#include "run-command.h"
+#include "trace.h"
+#include "wrapper.h"
+#include "write-or-die.h"
char packet_buffer[LARGE_PACKET_MAX];
static const char *packet_trace_prefix = "git";
diff --git a/pkt-line.h b/pkt-line.h
index 79c538b99e..7c23a4bfaf 100644
--- a/pkt-line.h
+++ b/pkt-line.h
@@ -1,7 +1,6 @@
#ifndef PKTLINE_H
#define PKTLINE_H
-#include "git-compat-util.h"
#include "strbuf.h"
#include "sideband.h"
@@ -247,4 +246,6 @@ void packet_writer_error(struct packet_writer *writer, const char *fmt, ...);
void packet_writer_delim(struct packet_writer *writer);
void packet_writer_flush(struct packet_writer *writer);
+void packet_trace_identity(const char *prog);
+
#endif
diff --git a/preload-index.c b/preload-index.c
index 100f7a374d..e44530c80c 100644
--- a/preload-index.c
+++ b/preload-index.c
@@ -1,14 +1,20 @@
/*
* Copyright (C) 2008 Linus Torvalds
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "pathspec.h"
#include "dir.h"
+#include "environment.h"
#include "fsmonitor.h"
+#include "gettext.h"
#include "config.h"
+#include "preload-index.h"
#include "progress.h"
+#include "read-cache.h"
#include "thread-utils.h"
#include "repository.h"
+#include "symlinks.h"
+#include "trace2.h"
/*
* Mostly randomly chosen maximum thread counts: we
diff --git a/preload-index.h b/preload-index.h
new file mode 100644
index 0000000000..251b1ed88e
--- /dev/null
+++ b/preload-index.h
@@ -0,0 +1,15 @@
+#ifndef PRELOAD_INDEX_H
+#define PRELOAD_INDEX_H
+
+struct index_state;
+struct pathspec;
+struct repository;
+
+void preload_index(struct index_state *index,
+ const struct pathspec *pathspec,
+ unsigned int refresh_flags);
+int repo_read_index_preload(struct repository *,
+ const struct pathspec *pathspec,
+ unsigned refresh_flags);
+
+#endif /* PRELOAD_INDEX_H */
diff --git a/pretty.c b/pretty.c
index 1e1e21878c..d4bc4b0286 100644
--- a/pretty.c
+++ b/pretty.c
@@ -1,8 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
#include "commit.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "utf8.h"
#include "diff.h"
+#include "pager.h"
#include "revision.h"
#include "string-list.h"
#include "mailmap.h"
@@ -13,6 +19,7 @@
#include "gpg-interface.h"
#include "trailer.h"
#include "run-command.h"
+#include "object-name.h"
/*
* The limit for formatting directives, which enable the caller to append
@@ -719,7 +726,7 @@ const char *repo_logmsg_reencode(struct repository *r,
* Otherwise, we still want to munge the encoding header in the
* result, which will be done by modifying the buffer. If we
* are using a fresh copy, we can reuse it. But if we are using
- * the cached copy from get_commit_buffer, we need to duplicate it
+ * the cached copy from repo_get_commit_buffer, we need to duplicate it
* to avoid munging the cached copy.
*/
if (msg == get_cached_commit_buffer(r, commit, NULL))
@@ -1857,7 +1864,8 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
return consumed + 1;
}
-static size_t userformat_want_item(struct strbuf *sb, const char *placeholder,
+static size_t userformat_want_item(struct strbuf *sb UNUSED,
+ const char *placeholder,
void *context)
{
struct userformat_want *w = context;
@@ -2199,12 +2207,14 @@ void pretty_print_commit(struct pretty_print_context *pp,
int need_8bit_cte = pp->need_8bit_cte;
if (pp->fmt == CMIT_FMT_USERFORMAT) {
- format_commit_message(commit, user_format, sb, pp);
+ repo_format_commit_message(the_repository, commit,
+ user_format, sb, pp);
return;
}
encoding = get_log_output_encoding();
- msg = reencoded = logmsg_reencode(commit, NULL, encoding);
+ msg = reencoded = repo_logmsg_reencode(the_repository, commit, NULL,
+ encoding);
if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
indent = 0;
@@ -2261,7 +2271,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body)
strbuf_addch(sb, '\n');
- unuse_commit_buffer(commit, reencoded);
+ repo_unuse_commit_buffer(the_repository, commit, reencoded);
}
void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
diff --git a/pretty.h b/pretty.h
index f34e24c53a..421209e9ec 100644
--- a/pretty.h
+++ b/pretty.h
@@ -1,11 +1,11 @@
#ifndef PRETTY_H
#define PRETTY_H
-#include "cache.h"
#include "date.h"
#include "string-list.h"
struct commit;
+struct repository;
struct strbuf;
struct process_trailer_options;
@@ -120,10 +120,6 @@ void repo_format_commit_message(struct repository *r,
const struct commit *commit,
const char *format, struct strbuf *sb,
const struct pretty_print_context *context);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define format_commit_message(c, f, s, con) \
- repo_format_commit_message(the_repository, c, f, s, con)
-#endif
/*
* Parse given arguments from "arg", check it for correctness and
@@ -153,6 +149,8 @@ int commit_format_is_empty(enum cmit_fmt);
/* Make subject of commit message suitable for filename */
void format_sanitized_subject(struct strbuf *sb, const char *msg, size_t len);
+int has_non_ascii(const char *text);
+
/*
* Set values of fields in "struct process_trailer_options"
* according to trailers arguments.
diff --git a/prio-queue.c b/prio-queue.c
index d31b48e725..dc2476be53 100644
--- a/prio-queue.c
+++ b/prio-queue.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "prio-queue.h"
static inline int compare(struct prio_queue *queue, int i, int j)
diff --git a/progress.c b/progress.c
index 0cdd875d37..f695798aca 100644
--- a/progress.c
+++ b/progress.c
@@ -9,11 +9,13 @@
*/
#define GIT_TEST_PROGRESS_ONLY
-#include "cache.h"
-#include "gettext.h"
+#include "git-compat-util.h"
+#include "pager.h"
#include "progress.h"
+#include "repository.h"
#include "strbuf.h"
#include "trace.h"
+#include "trace2.h"
#include "utf8.h"
#include "config.h"
@@ -59,7 +61,7 @@ void progress_test_force_update(void)
}
-static void progress_interval(int signum)
+static void progress_interval(int signum UNUSED)
{
progress_update = 1;
}
diff --git a/promisor-remote.c b/promisor-remote.c
index faa7612941..db88d2064d 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -1,7 +1,10 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
#include "promisor-remote.h"
#include "config.h"
+#include "trace2.h"
#include "transport.h"
#include "strvec.h"
#include "packfile.h"
diff --git a/promisor-remote.h b/promisor-remote.h
index df36eb08ef..2cb9eda9ea 100644
--- a/promisor-remote.h
+++ b/promisor-remote.h
@@ -18,24 +18,9 @@ struct promisor_remote {
};
void repo_promisor_remote_reinit(struct repository *r);
-static inline void promisor_remote_reinit(void)
-{
- repo_promisor_remote_reinit(the_repository);
-}
-
void promisor_remote_clear(struct promisor_remote_config *config);
-
struct promisor_remote *repo_promisor_remote_find(struct repository *r, const char *remote_name);
-static inline struct promisor_remote *promisor_remote_find(const char *remote_name)
-{
- return repo_promisor_remote_find(the_repository, remote_name);
-}
-
int repo_has_promisor_remote(struct repository *r);
-static inline int has_promisor_remote(void)
-{
- return repo_has_promisor_remote(the_repository);
-}
/*
* Fetches all requested objects from all promisor remotes, trying them one at
diff --git a/prompt.c b/prompt.c
index 50df17279d..3baa33f63d 100644
--- a/prompt.c
+++ b/prompt.c
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "environment.h"
#include "run-command.h"
#include "strbuf.h"
#include "prompt.h"
diff --git a/protocol-caps.c b/protocol-caps.c
index bbde91810a..808a68c974 100644
--- a/protocol-caps.c
+++ b/protocol-caps.c
@@ -1,11 +1,13 @@
#include "git-compat-util.h"
#include "protocol-caps.h"
#include "gettext.h"
+#include "hex.h"
#include "pkt-line.h"
#include "strvec.h"
-#include "hash.h"
+#include "hash-ll.h"
+#include "hex.h"
#include "object.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "string-list.h"
#include "strbuf.h"
@@ -77,7 +79,7 @@ static void send_info(struct repository *r, struct packet_writer *writer,
int cap_object_info(struct repository *r, struct packet_reader *request)
{
- struct requested_info info;
+ struct requested_info info = { 0 };
struct packet_writer writer;
struct string_list oid_str_list = STRING_LIST_INIT_DUP;
diff --git a/protocol.c b/protocol.c
index c53f7df5be..079ba75acf 100644
--- a/protocol.c
+++ b/protocol.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "environment.h"
#include "protocol.h"
+#include "trace2.h"
static enum protocol_version parse_protocol_version(const char *value)
{
diff --git a/protocol.h b/protocol.h
index cef1a4a01c..de66bf80f8 100644
--- a/protocol.h
+++ b/protocol.h
@@ -1,6 +1,27 @@
#ifndef PROTOCOL_H
#define PROTOCOL_H
+/*
+ * Intensive research over the course of many years has shown that
+ * port 9418 is totally unused by anything else. Or
+ *
+ * Your search - "port 9418" - did not match any documents.
+ *
+ * as www.google.com puts it.
+ *
+ * This port has been properly assigned for git use by IANA:
+ * git (Assigned-9418) [I06-050728-0001].
+ *
+ * git 9418/tcp git pack transfer service
+ * git 9418/udp git pack transfer service
+ *
+ * with Linus Torvalds <torvalds@osdl.org> as the point of
+ * contact. September 2005.
+ *
+ * See http://www.iana.org/assignments/port-numbers
+ */
+#define DEFAULT_GIT_PORT 9418
+
enum protocol_version {
protocol_unknown_version = -1,
protocol_v0 = 0,
diff --git a/prune-packed.c b/prune-packed.c
index 261520b472..e54daf740a 100644
--- a/prune-packed.c
+++ b/prune-packed.c
@@ -1,4 +1,7 @@
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-store-ll.h"
#include "packfile.h"
#include "progress.h"
#include "prune-packed.h"
diff --git a/quote.c b/quote.c
index 26719d21d1..43c739671e 100644
--- a/quote.c
+++ b/quote.c
@@ -1,5 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "path.h"
#include "quote.h"
+#include "strbuf.h"
#include "strvec.h"
int quote_path_fully = 1;
diff --git a/quote.h b/quote.h
index 87ff458b06..0300c29104 100644
--- a/quote.h
+++ b/quote.h
@@ -3,6 +3,8 @@
struct strbuf;
+extern int quote_path_fully;
+
/* Help to copy the thing properly quoted for the shell safety.
* any single quote is replaced with '\'', any exclamation point
* is replaced with '\!', and the whole thing is enclosed in a
diff --git a/range-diff.c b/range-diff.c
index 4bd65ab749..2e86063491 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -1,5 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
#include "range-diff.h"
+#include "object-name.h"
#include "string-list.h"
#include "run-command.h"
#include "strvec.h"
@@ -8,7 +11,9 @@
#include "linear-assignment.h"
#include "diffcore.h"
#include "commit.h"
+#include "pager.h"
#include "pretty.h"
+#include "repository.h"
#include "userdiff.h"
#include "apply.h"
#include "revision.h"
@@ -94,7 +99,7 @@ static int read_patches(const char *range, struct string_list *list,
strbuf_reset(&buf);
}
CALLOC_ARRAY(util, 1);
- if (get_oid(p, &util->oid)) {
+ if (repo_get_oid(the_repository, p, &util->oid)) {
error(_("could not parse commit '%s'"), p);
FREE_AND_NULL(util);
string_list_clear(list, 1);
@@ -390,7 +395,7 @@ static void output_pair_header(struct diff_options *diffopt,
if (!dashes->len)
strbuf_addchars(dashes, '-',
- strlen(find_unique_abbrev(oid, abbrev)));
+ strlen(repo_find_unique_abbrev(the_repository, oid, abbrev)));
if (!b_util) {
color = color_old;
@@ -412,7 +417,7 @@ static void output_pair_header(struct diff_options *diffopt,
strbuf_addf(buf, "%*s: %s ", patch_no_width, "-", dashes->buf);
else
strbuf_addf(buf, "%*d: %s ", patch_no_width, a_util->i + 1,
- find_unique_abbrev(&a_util->oid, abbrev));
+ repo_find_unique_abbrev(the_repository, &a_util->oid, abbrev));
if (status == '!')
strbuf_addf(buf, "%s%s", color_reset, color);
@@ -424,7 +429,7 @@ static void output_pair_header(struct diff_options *diffopt,
strbuf_addf(buf, " %*s: %s", patch_no_width, "-", dashes->buf);
else
strbuf_addf(buf, " %*d: %s", patch_no_width, b_util->i + 1,
- find_unique_abbrev(&b_util->oid, abbrev));
+ repo_find_unique_abbrev(the_repository, &b_util->oid, abbrev));
commit = lookup_commit_reference(the_repository, oid);
if (commit) {
@@ -485,7 +490,7 @@ static void output(struct string_list *a, struct string_list *b,
if (range_diff_opts->diffopt)
memcpy(&opts, range_diff_opts->diffopt, sizeof(opts));
else
- diff_setup(&opts);
+ repo_diff_setup(the_repository, &opts);
opts.no_free = 1;
if (!opts.output_format)
@@ -588,7 +593,7 @@ int is_range_diff_range(const char *arg)
int i, positive = 0, negative = 0;
struct rev_info revs;
- init_revisions(&revs, NULL);
+ repo_init_revisions(the_repository, &revs, NULL);
if (setup_revisions(3, argv, &revs, NULL) == 1) {
for (i = 0; i < revs.pending.nr; i++)
if (revs.pending.objects[i].item->flags & UNINTERESTING)
diff --git a/reachable.c b/reachable.c
index aba63ebeb3..0136c4b78b 100644
--- a/reachable.c
+++ b/reachable.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
#include "tag.h"
#include "commit.h"
@@ -11,9 +13,11 @@
#include "list-objects.h"
#include "packfile.h"
#include "worktree.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "pack-bitmap.h"
#include "pack-mtimes.h"
+#include "config.h"
+#include "run-command.h"
struct connectivity_progress {
struct progress *progress;
@@ -48,7 +52,9 @@ static int add_one_ref(const char *path, const struct object_id *oid,
* The traversal will have already marked us as SEEN, so we
* only need to handle any progress reporting here.
*/
-static void mark_object(struct object *obj, const char *name, void *data)
+static void mark_object(struct object *obj UNUSED,
+ const char *name UNUSED,
+ void *data)
{
update_progress(data);
}
@@ -63,8 +69,77 @@ struct recent_data {
timestamp_t timestamp;
report_recent_object_fn *cb;
int ignore_in_core_kept_packs;
+
+ struct oidset extra_recent_oids;
+ int extra_recent_oids_loaded;
};
+static int run_one_gc_recent_objects_hook(struct oidset *set,
+ const char *args)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ struct strbuf buf = STRBUF_INIT;
+ FILE *out;
+ int ret = 0;
+
+ cmd.use_shell = 1;
+ cmd.out = -1;
+
+ strvec_push(&cmd.args, args);
+
+ if (start_command(&cmd))
+ return -1;
+
+ out = xfdopen(cmd.out, "r");
+ while (strbuf_getline(&buf, out) != EOF) {
+ struct object_id oid;
+ const char *rest;
+
+ if (parse_oid_hex(buf.buf, &oid, &rest) || *rest) {
+ ret = error(_("invalid extra cruft tip: '%s'"), buf.buf);
+ break;
+ }
+
+ oidset_insert(set, &oid);
+ }
+
+ fclose(out);
+ ret |= finish_command(&cmd);
+
+ strbuf_release(&buf);
+ return ret;
+}
+
+static void load_gc_recent_objects(struct recent_data *data)
+{
+ const struct string_list *programs;
+ int ret = 0;
+ size_t i;
+
+ data->extra_recent_oids_loaded = 1;
+
+ if (git_config_get_string_multi("gc.recentobjectshook", &programs))
+ return;
+
+ for (i = 0; i < programs->nr; i++) {
+ ret = run_one_gc_recent_objects_hook(&data->extra_recent_oids,
+ programs->items[i].string);
+ if (ret)
+ die(_("unable to enumerate additional cruft tips"));
+ }
+}
+
+static int obj_is_recent(const struct object_id *oid, timestamp_t mtime,
+ struct recent_data *data)
+{
+ if (mtime > data->timestamp)
+ return 1;
+
+ if (!data->extra_recent_oids_loaded)
+ load_gc_recent_objects(data);
+ return oidset_contains(&data->extra_recent_oids, oid);
+}
+
static void add_recent_object(const struct object_id *oid,
struct packed_git *pack,
off_t offset,
@@ -74,7 +149,7 @@ static void add_recent_object(const struct object_id *oid,
struct object *obj;
enum object_type type;
- if (mtime <= data->timestamp)
+ if (!obj_is_recent(oid, mtime, data))
return;
/*
@@ -152,7 +227,8 @@ static int add_recent_loose(const struct object_id *oid,
}
static int add_recent_packed(const struct object_id *oid,
- struct packed_git *p, uint32_t pos,
+ struct packed_git *p,
+ uint32_t pos,
void *data)
{
struct object *obj;
@@ -188,24 +264,32 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
data.cb = cb;
data.ignore_in_core_kept_packs = ignore_in_core_kept_packs;
+ oidset_init(&data.extra_recent_oids, 0);
+ data.extra_recent_oids_loaded = 0;
+
r = for_each_loose_object(add_recent_loose, &data,
FOR_EACH_OBJECT_LOCAL_ONLY);
if (r)
- return r;
+ goto done;
flags = FOR_EACH_OBJECT_LOCAL_ONLY | FOR_EACH_OBJECT_PACK_ORDER;
if (ignore_in_core_kept_packs)
flags |= FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS;
- return for_each_packed_object(add_recent_packed, &data, flags);
+ r = for_each_packed_object(add_recent_packed, &data, flags);
+
+done:
+ oidset_clear(&data.extra_recent_oids);
+
+ return r;
}
static int mark_object_seen(const struct object_id *oid,
enum object_type type,
- int exclude,
- uint32_t name_hash,
- struct packed_git *found_pack,
- off_t found_offset)
+ int exclude UNUSED,
+ uint32_t name_hash UNUSED,
+ struct packed_git *found_pack UNUSED,
+ off_t found_offset UNUSED)
{
struct object *obj = lookup_object_by_type(the_repository, oid, type);
if (!obj)
diff --git a/read-cache-ll.h b/read-cache-ll.h
new file mode 100644
index 0000000000..9a1a7edc5a
--- /dev/null
+++ b/read-cache-ll.h
@@ -0,0 +1,481 @@
+#ifndef READ_CACHE_LL_H
+#define READ_CACHE_LL_H
+
+#include "hash-ll.h"
+#include "hashmap.h"
+#include "statinfo.h"
+
+/*
+ * Basic data structures for the directory cache
+ */
+
+#define CACHE_SIGNATURE 0x44495243 /* "DIRC" */
+struct cache_header {
+ uint32_t hdr_signature;
+ uint32_t hdr_version;
+ uint32_t hdr_entries;
+};
+
+#define INDEX_FORMAT_LB 2
+#define INDEX_FORMAT_UB 4
+
+struct cache_entry {
+ struct hashmap_entry ent;
+ struct stat_data ce_stat_data;
+ unsigned int ce_mode;
+ unsigned int ce_flags;
+ unsigned int mem_pool_allocated;
+ unsigned int ce_namelen;
+ unsigned int index; /* for link extension */
+ struct object_id oid;
+ char name[FLEX_ARRAY]; /* more */
+};
+
+#define CE_STAGEMASK (0x3000)
+#define CE_EXTENDED (0x4000)
+#define CE_VALID (0x8000)
+#define CE_STAGESHIFT 12
+
+/*
+ * Range 0xFFFF0FFF in ce_flags is divided into
+ * two parts: in-memory flags and on-disk ones.
+ * Flags in CE_EXTENDED_FLAGS will get saved on-disk
+ * if you want to save a new flag, add it in
+ * CE_EXTENDED_FLAGS
+ *
+ * In-memory only flags
+ */
+#define CE_UPDATE (1 << 16)
+#define CE_REMOVE (1 << 17)
+#define CE_UPTODATE (1 << 18)
+#define CE_ADDED (1 << 19)
+
+#define CE_HASHED (1 << 20)
+#define CE_FSMONITOR_VALID (1 << 21)
+#define CE_WT_REMOVE (1 << 22) /* remove in work directory */
+#define CE_CONFLICTED (1 << 23)
+
+#define CE_UNPACKED (1 << 24)
+#define CE_NEW_SKIP_WORKTREE (1 << 25)
+
+/* used to temporarily mark paths matched by pathspecs */
+#define CE_MATCHED (1 << 26)
+
+#define CE_UPDATE_IN_BASE (1 << 27)
+#define CE_STRIP_NAME (1 << 28)
+
+/*
+ * Extended on-disk flags
+ */
+#define CE_INTENT_TO_ADD (1 << 29)
+#define CE_SKIP_WORKTREE (1 << 30)
+/* CE_EXTENDED2 is for future extension */
+#define CE_EXTENDED2 (1U << 31)
+
+#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
+
+/*
+ * Safeguard to avoid saving wrong flags:
+ * - CE_EXTENDED2 won't get saved until its semantic is known
+ * - Bits in 0x0000FFFF have been saved in ce_flags already
+ * - Bits in 0x003F0000 are currently in-memory flags
+ */
+#if CE_EXTENDED_FLAGS & 0x803FFFFF
+#error "CE_EXTENDED_FLAGS out of range"
+#endif
+
+/* Forward structure decls */
+struct pathspec;
+struct tree;
+
+/*
+ * Copy the sha1 and stat state of a cache entry from one to
+ * another. But we never change the name, or the hash state!
+ */
+static inline void copy_cache_entry(struct cache_entry *dst,
+ const struct cache_entry *src)
+{
+ unsigned int state = dst->ce_flags & CE_HASHED;
+ int mem_pool_allocated = dst->mem_pool_allocated;
+
+ /* Don't copy hash chain and name */
+ memcpy(&dst->ce_stat_data, &src->ce_stat_data,
+ offsetof(struct cache_entry, name) -
+ offsetof(struct cache_entry, ce_stat_data));
+
+ /* Restore the hash state */
+ dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
+
+ /* Restore the mem_pool_allocated flag */
+ dst->mem_pool_allocated = mem_pool_allocated;
+}
+
+static inline unsigned create_ce_flags(unsigned stage)
+{
+ return (stage << CE_STAGESHIFT);
+}
+
+#define ce_namelen(ce) ((ce)->ce_namelen)
+#define ce_size(ce) cache_entry_size(ce_namelen(ce))
+#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
+#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
+#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
+#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
+#define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD)
+
+#define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1)
+
+#define SOMETHING_CHANGED (1 << 0) /* unclassified changes go here */
+#define CE_ENTRY_CHANGED (1 << 1)
+#define CE_ENTRY_REMOVED (1 << 2)
+#define CE_ENTRY_ADDED (1 << 3)
+#define RESOLVE_UNDO_CHANGED (1 << 4)
+#define CACHE_TREE_CHANGED (1 << 5)
+#define SPLIT_INDEX_ORDERED (1 << 6)
+#define UNTRACKED_CHANGED (1 << 7)
+#define FSMONITOR_CHANGED (1 << 8)
+
+struct split_index;
+struct untracked_cache;
+struct progress;
+struct pattern_list;
+
+enum sparse_index_mode {
+ /*
+ * There are no sparse directories in the index at all.
+ *
+ * Repositories that don't use cone-mode sparse-checkout will
+ * always have their indexes in this mode.
+ */
+ INDEX_EXPANDED = 0,
+
+ /*
+ * The index has already been collapsed to sparse directories
+ * whereever possible.
+ */
+ INDEX_COLLAPSED,
+
+ /*
+ * The sparse directories that exist are outside the
+ * sparse-checkout boundary, but it is possible that some file
+ * entries could collapse to sparse directory entries.
+ */
+ INDEX_PARTIALLY_SPARSE,
+};
+
+struct index_state {
+ struct cache_entry **cache;
+ unsigned int version;
+ unsigned int cache_nr, cache_alloc, cache_changed;
+ struct string_list *resolve_undo;
+ struct cache_tree *cache_tree;
+ struct split_index *split_index;
+ struct cache_time timestamp;
+ unsigned name_hash_initialized : 1,
+ initialized : 1,
+ drop_cache_tree : 1,
+ updated_workdir : 1,
+ updated_skipworktree : 1,
+ fsmonitor_has_run_once : 1;
+ enum sparse_index_mode sparse_index;
+ struct hashmap name_hash;
+ struct hashmap dir_hash;
+ struct object_id oid;
+ struct untracked_cache *untracked;
+ char *fsmonitor_last_update;
+ struct ewah_bitmap *fsmonitor_dirty;
+ struct mem_pool *ce_mem_pool;
+ struct progress *progress;
+ struct repository *repo;
+ struct pattern_list *sparse_checkout_patterns;
+};
+
+/**
+ * A "struct index_state istate" must be initialized with
+ * INDEX_STATE_INIT or the corresponding index_state_init().
+ *
+ * If the variable won't be used again, use release_index() to free()
+ * its resources. If it needs to be used again use discard_index(),
+ * which does the same thing, but will use use index_state_init() at
+ * the end. The discard_index() will use its own "istate->repo" as the
+ * "r" argument to index_state_init() in that case.
+ */
+#define INDEX_STATE_INIT(r) { \
+ .repo = (r), \
+}
+void index_state_init(struct index_state *istate, struct repository *r);
+void release_index(struct index_state *istate);
+
+/* Cache entry creation and cleanup */
+
+/*
+ * Create cache_entry intended for use in the specified index. Caller
+ * is responsible for discarding the cache_entry with
+ * `discard_cache_entry`.
+ */
+struct cache_entry *make_cache_entry(struct index_state *istate,
+ unsigned int mode,
+ const struct object_id *oid,
+ const char *path,
+ int stage,
+ unsigned int refresh_options);
+
+struct cache_entry *make_empty_cache_entry(struct index_state *istate,
+ size_t name_len);
+
+/*
+ * Create a cache_entry that is not intended to be added to an index. If
+ * `ce_mem_pool` is not NULL, the entry is allocated within the given memory
+ * pool. Caller is responsible for discarding "loose" entries with
+ * `discard_cache_entry()` and the memory pool with
+ * `mem_pool_discard(ce_mem_pool, should_validate_cache_entries())`.
+ */
+struct cache_entry *make_transient_cache_entry(unsigned int mode,
+ const struct object_id *oid,
+ const char *path,
+ int stage,
+ struct mem_pool *ce_mem_pool);
+
+struct cache_entry *make_empty_transient_cache_entry(size_t len,
+ struct mem_pool *ce_mem_pool);
+
+/*
+ * Discard cache entry.
+ */
+void discard_cache_entry(struct cache_entry *ce);
+
+/*
+ * Check configuration if we should perform extra validation on cache
+ * entries.
+ */
+int should_validate_cache_entries(void);
+
+/*
+ * Duplicate a cache_entry. Allocate memory for the new entry from a
+ * memory_pool. Takes into account cache_entry fields that are meant
+ * for managing the underlying memory allocation of the cache_entry.
+ */
+struct cache_entry *dup_cache_entry(const struct cache_entry *ce, struct index_state *istate);
+
+/*
+ * Validate the cache entries in the index. This is an internal
+ * consistency check that the cache_entry structs are allocated from
+ * the expected memory pool.
+ */
+void validate_cache_entries(const struct index_state *istate);
+
+/*
+ * Bulk prefetch all missing cache entries that are not GITLINKs and that match
+ * the given predicate. This function should only be called if
+ * repo_has_promisor_remote() returns true.
+ */
+typedef int (*must_prefetch_predicate)(const struct cache_entry *);
+void prefetch_cache_entries(const struct index_state *istate,
+ must_prefetch_predicate must_prefetch);
+
+/* Initialize and use the cache information */
+struct lock_file;
+int do_read_index(struct index_state *istate, const char *path,
+ int must_exist); /* for testting only! */
+int read_index_from(struct index_state *, const char *path,
+ const char *gitdir);
+int is_index_unborn(struct index_state *);
+
+/* For use with `write_locked_index()`. */
+#define COMMIT_LOCK (1 << 0)
+#define SKIP_IF_UNCHANGED (1 << 1)
+
+/*
+ * Write the index while holding an already-taken lock. Close the lock,
+ * and if `COMMIT_LOCK` is given, commit it.
+ *
+ * Unless a split index is in use, write the index into the lockfile.
+ *
+ * With a split index, write the shared index to a temporary file,
+ * adjust its permissions and rename it into place, then write the
+ * split index to the lockfile. If the temporary file for the shared
+ * index cannot be created, fall back to the behavior described in
+ * the previous paragraph.
+ *
+ * With `COMMIT_LOCK`, the lock is always committed or rolled back.
+ * Without it, the lock is closed, but neither committed nor rolled
+ * back.
+ *
+ * If `SKIP_IF_UNCHANGED` is given and the index is unchanged, nothing
+ * is written (and the lock is rolled back if `COMMIT_LOCK` is given).
+ */
+int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
+
+void discard_index(struct index_state *);
+void move_index_extensions(struct index_state *dst, struct index_state *src);
+int unmerged_index(const struct index_state *);
+
+/**
+ * Returns 1 if istate differs from tree, 0 otherwise. If tree is NULL,
+ * compares istate to HEAD. If tree is NULL and on an unborn branch,
+ * returns 1 if there are entries in istate, 0 otherwise. If an strbuf is
+ * provided, the space-separated list of files that differ will be appended
+ * to it.
+ */
+int repo_index_has_changes(struct repository *repo,
+ struct tree *tree,
+ struct strbuf *sb);
+
+int verify_path(const char *path, unsigned mode);
+int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
+
+/*
+ * Searches for an entry defined by name and namelen in the given index.
+ * If the return value is positive (including 0) it is the position of an
+ * exact match. If the return value is negative, the negated value minus 1
+ * is the position where the entry would be inserted.
+ * Example: The current index consists of these files and its stages:
+ *
+ * b#0, d#0, f#1, f#3
+ *
+ * index_name_pos(&index, "a", 1) -> -1
+ * index_name_pos(&index, "b", 1) -> 0
+ * index_name_pos(&index, "c", 1) -> -2
+ * index_name_pos(&index, "d", 1) -> 1
+ * index_name_pos(&index, "e", 1) -> -3
+ * index_name_pos(&index, "f", 1) -> -3
+ * index_name_pos(&index, "g", 1) -> -5
+ */
+int index_name_pos(struct index_state *, const char *name, int namelen);
+
+/*
+ * Like index_name_pos, returns the position of an entry of the given name in
+ * the index if one exists, otherwise returns a negative value where the negated
+ * value minus 1 is the position where the index entry would be inserted. Unlike
+ * index_name_pos, however, a sparse index is not expanded to find an entry
+ * inside a sparse directory.
+ */
+int index_name_pos_sparse(struct index_state *, const char *name, int namelen);
+
+/*
+ * Determines whether an entry with the given name exists within the
+ * given index. The return value is 1 if an exact match is found, otherwise
+ * it is 0. Note that, unlike index_name_pos, this function does not expand
+ * the index if it is sparse. If an item exists within the full index but it
+ * is contained within a sparse directory (and not in the sparse index), 0 is
+ * returned.
+ */
+int index_entry_exists(struct index_state *, const char *name, int namelen);
+
+/*
+ * Some functions return the negative complement of an insert position when a
+ * precise match was not found but a position was found where the entry would
+ * need to be inserted. This helper protects that logic from any integer
+ * underflow.
+ */
+static inline int index_pos_to_insert_pos(uintmax_t pos)
+{
+ if (pos > INT_MAX)
+ die("overflow: -1 - %"PRIuMAX, pos);
+ return -1 - (int)pos;
+}
+
+#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
+#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
+#define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */
+#define ADD_CACHE_JUST_APPEND 8 /* Append only */
+#define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */
+#define ADD_CACHE_KEEP_CACHE_TREE 32 /* Do not invalidate cache-tree */
+#define ADD_CACHE_RENORMALIZE 64 /* Pass along HASH_RENORMALIZE */
+int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
+void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
+
+/* Remove entry, return true if there are more entries to go. */
+int remove_index_entry_at(struct index_state *, int pos);
+
+void remove_marked_cache_entries(struct index_state *istate, int invalidate);
+int remove_file_from_index(struct index_state *, const char *path);
+#define ADD_CACHE_VERBOSE 1
+#define ADD_CACHE_PRETEND 2
+#define ADD_CACHE_IGNORE_ERRORS 4
+#define ADD_CACHE_IGNORE_REMOVAL 8
+#define ADD_CACHE_INTENT 16
+/*
+ * These two are used to add the contents of the file at path
+ * to the index, marking the working tree up-to-date by storing
+ * the cached stat info in the resulting cache entry. A caller
+ * that has already run lstat(2) on the path can call
+ * add_to_index(), and all others can call add_file_to_index();
+ * the latter will do necessary lstat(2) internally before
+ * calling the former.
+ */
+int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
+int add_file_to_index(struct index_state *, const char *path, int flags);
+
+int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
+int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
+void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
+int index_name_is_other(struct index_state *, const char *, int);
+void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
+
+/* do stat comparison even if CE_VALID is true */
+#define CE_MATCH_IGNORE_VALID 01
+/* do not check the contents but report dirty on racily-clean entries */
+#define CE_MATCH_RACY_IS_DIRTY 02
+/* do stat comparison even if CE_SKIP_WORKTREE is true */
+#define CE_MATCH_IGNORE_SKIP_WORKTREE 04
+/* ignore non-existent files during stat update */
+#define CE_MATCH_IGNORE_MISSING 0x08
+/* enable stat refresh */
+#define CE_MATCH_REFRESH 0x10
+/* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */
+#define CE_MATCH_IGNORE_FSMONITOR 0X20
+int is_racy_timestamp(const struct index_state *istate,
+ const struct cache_entry *ce);
+int has_racy_timestamp(struct index_state *istate);
+int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
+int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
+
+int match_stat_data_racy(const struct index_state *istate,
+ const struct stat_data *sd, struct stat *st);
+
+void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, struct stat *st);
+
+#define REFRESH_REALLY (1 << 0) /* ignore_valid */
+#define REFRESH_UNMERGED (1 << 1) /* allow unmerged */
+#define REFRESH_QUIET (1 << 2) /* be quiet about it */
+#define REFRESH_IGNORE_MISSING (1 << 3) /* ignore non-existent */
+#define REFRESH_IGNORE_SUBMODULES (1 << 4) /* ignore submodules */
+#define REFRESH_IN_PORCELAIN (1 << 5) /* user friendly output, not "needs update" */
+#define REFRESH_PROGRESS (1 << 6) /* show progress bar if stderr is tty */
+#define REFRESH_IGNORE_SKIP_WORKTREE (1 << 7) /* ignore skip_worktree entries */
+int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
+/*
+ * Refresh the index and write it to disk.
+ *
+ * 'refresh_flags' is passed directly to 'refresh_index()', while
+ * 'COMMIT_LOCK | write_flags' is passed to 'write_locked_index()', so
+ * the lockfile is always either committed or rolled back.
+ *
+ * If 'gentle' is passed, errors locking the index are ignored.
+ *
+ * Return 1 if refreshing the index returns an error, -1 if writing
+ * the index to disk fails, 0 on success.
+ *
+ * Note that if refreshing the index returns an error, we still write
+ * out the index (unless locking fails).
+ */
+int repo_refresh_and_write_index(struct repository*, unsigned int refresh_flags, unsigned int write_flags, int gentle, const struct pathspec *, char *seen, const char *header_msg);
+
+struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int);
+
+void set_alternate_index_output(const char *);
+
+extern int verify_index_checksum;
+extern int verify_ce_order;
+
+int cmp_cache_name_compare(const void *a_, const void *b_);
+
+int add_files_to_cache(struct repository *repo, const char *prefix,
+ const struct pathspec *pathspec, int include_sparse,
+ int flags);
+
+void overlay_tree_on_index(struct index_state *istate,
+ const char *tree_name, const char *prefix);
+
+#endif /* READ_CACHE_LL_H */
diff --git a/read-cache.c b/read-cache.c
index 35e5657877..b9a995e5a1 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -3,24 +3,41 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "bulk-checkin.h"
#include "config.h"
+#include "date.h"
#include "diff.h"
#include "diffcore.h"
+#include "hex.h"
#include "tempfile.h"
#include "lockfile.h"
#include "cache-tree.h"
#include "refs.h"
#include "dir.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
#include "tree.h"
#include "commit.h"
#include "blob.h"
+#include "environment.h"
+#include "gettext.h"
+#include "mem-pool.h"
+#include "name-hash.h"
+#include "object-name.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
#include "resolve-undo.h"
+#include "revision.h"
#include "run-command.h"
#include "strbuf.h"
+#include "trace2.h"
#include "varint.h"
#include "split-index.h"
+#include "symlinks.h"
#include "utf8.h"
#include "fsmonitor.h"
#include "thread-utils.h"
@@ -29,6 +46,7 @@
#include "csum-file.h"
#include "promisor-remote.h"
#include "hook.h"
+#include "wrapper.h"
/* Mask for the name length in ce_flags in the on-disk index */
@@ -163,61 +181,6 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
add_index_entry(istate, new_entry, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
}
-void fill_stat_data(struct stat_data *sd, struct stat *st)
-{
- sd->sd_ctime.sec = (unsigned int)st->st_ctime;
- sd->sd_mtime.sec = (unsigned int)st->st_mtime;
- sd->sd_ctime.nsec = ST_CTIME_NSEC(*st);
- sd->sd_mtime.nsec = ST_MTIME_NSEC(*st);
- sd->sd_dev = st->st_dev;
- sd->sd_ino = st->st_ino;
- sd->sd_uid = st->st_uid;
- sd->sd_gid = st->st_gid;
- sd->sd_size = st->st_size;
-}
-
-int match_stat_data(const struct stat_data *sd, struct stat *st)
-{
- int changed = 0;
-
- if (sd->sd_mtime.sec != (unsigned int)st->st_mtime)
- changed |= MTIME_CHANGED;
- if (trust_ctime && check_stat &&
- sd->sd_ctime.sec != (unsigned int)st->st_ctime)
- changed |= CTIME_CHANGED;
-
-#ifdef USE_NSEC
- if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
- changed |= MTIME_CHANGED;
- if (trust_ctime && check_stat &&
- sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
-#endif
-
- if (check_stat) {
- if (sd->sd_uid != (unsigned int) st->st_uid ||
- sd->sd_gid != (unsigned int) st->st_gid)
- changed |= OWNER_CHANGED;
- if (sd->sd_ino != (unsigned int) st->st_ino)
- changed |= INODE_CHANGED;
- }
-
-#ifdef USE_STDEV
- /*
- * st_dev breaks on network filesystems where different
- * clients will have different views of what "device"
- * the filesystem is on
- */
- if (check_stat && sd->sd_dev != (unsigned int) st->st_dev)
- changed |= INODE_CHANGED;
-#endif
-
- if (sd->sd_size != (unsigned int) st->st_size)
- changed |= DATA_CHANGED;
-
- return changed;
-}
-
/*
* This only updates the "non-critical" parts of the directory
* cache, ie the parts that aren't tracked by GIT, and only used
@@ -263,7 +226,7 @@ static int ce_compare_link(const struct cache_entry *ce, size_t expected_size)
if (strbuf_readlink(&sb, ce->name, expected_size))
return -1;
- buffer = read_object_file(&ce->oid, &type, &size);
+ buffer = repo_read_object_file(the_repository, &ce->oid, &type, &size);
if (buffer) {
if (size == sb.len)
match = memcmp(buffer, sb.buf, size);
@@ -488,87 +451,30 @@ int ie_modified(struct index_state *istate,
return 0;
}
-int base_name_compare(const char *name1, size_t len1, int mode1,
- const char *name2, size_t len2, int mode2)
+static int cache_name_stage_compare(const char *name1, int len1, int stage1,
+ const char *name2, int len2, int stage2)
{
- unsigned char c1, c2;
- size_t len = len1 < len2 ? len1 : len2;
int cmp;
- cmp = memcmp(name1, name2, len);
- if (cmp)
- return cmp;
- c1 = name1[len];
- c2 = name2[len];
- if (!c1 && S_ISDIR(mode1))
- c1 = '/';
- if (!c2 && S_ISDIR(mode2))
- c2 = '/';
- return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
-}
-
-/*
- * df_name_compare() is identical to base_name_compare(), except it
- * compares conflicting directory/file entries as equal. Note that
- * while a directory name compares as equal to a regular file, they
- * then individually compare _differently_ to a filename that has
- * a dot after the basename (because '\0' < '.' < '/').
- *
- * This is used by routines that want to traverse the git namespace
- * but then handle conflicting entries together when possible.
- */
-int df_name_compare(const char *name1, size_t len1, int mode1,
- const char *name2, size_t len2, int mode2)
-{
- unsigned char c1, c2;
- size_t len = len1 < len2 ? len1 : len2;
- int cmp;
-
- cmp = memcmp(name1, name2, len);
+ cmp = name_compare(name1, len1, name2, len2);
if (cmp)
return cmp;
- /* Directories and files compare equal (same length, same name) */
- if (len1 == len2)
- return 0;
- c1 = name1[len];
- if (!c1 && S_ISDIR(mode1))
- c1 = '/';
- c2 = name2[len];
- if (!c2 && S_ISDIR(mode2))
- c2 = '/';
- if (c1 == '/' && !c2)
- return 0;
- if (c2 == '/' && !c1)
- return 0;
- return c1 - c2;
-}
-int name_compare(const char *name1, size_t len1, const char *name2, size_t len2)
-{
- size_t min_len = (len1 < len2) ? len1 : len2;
- int cmp = memcmp(name1, name2, min_len);
- if (cmp)
- return cmp;
- if (len1 < len2)
+ if (stage1 < stage2)
return -1;
- if (len1 > len2)
+ if (stage1 > stage2)
return 1;
return 0;
}
-int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
+int cmp_cache_name_compare(const void *a_, const void *b_)
{
- int cmp;
-
- cmp = name_compare(name1, len1, name2, len2);
- if (cmp)
- return cmp;
+ const struct cache_entry *ce1, *ce2;
- if (stage1 < stage2)
- return -1;
- if (stage1 > stage2)
- return 1;
- return 0;
+ ce1 = *((const struct cache_entry **)a_);
+ ce2 = *((const struct cache_entry **)b_);
+ return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
+ ce2->name, ce2->ce_namelen, ce_stage(ce2));
}
static int index_name_stage_pos(struct index_state *istate,
@@ -2628,7 +2534,7 @@ int repo_index_has_changes(struct repository *repo,
if (tree)
cmp = tree->object.oid;
- if (tree || !get_oid_tree("HEAD", &cmp)) {
+ if (tree || !repo_get_oid_tree(repo, "HEAD", &cmp)) {
struct diff_options opt;
repo_diff_setup(repo, &opt);
@@ -2901,6 +2807,16 @@ static int record_ieot(void)
return !git_config_get_index_threads(&val) && val != 1;
}
+enum write_extensions {
+ WRITE_NO_EXTENSION = 0,
+ WRITE_SPLIT_INDEX_EXTENSION = 1<<0,
+ WRITE_CACHE_TREE_EXTENSION = 1<<1,
+ WRITE_RESOLVE_UNDO_EXTENSION = 1<<2,
+ WRITE_UNTRACKED_CACHE_EXTENSION = 1<<3,
+ WRITE_FSMONITOR_EXTENSION = 1<<4,
+};
+#define WRITE_ALL_EXTENSIONS ((enum write_extensions)-1)
+
/*
* On success, `tempfile` is closed. If it is the temporary file
* of a `struct lock_file`, we will therefore effectively perform
@@ -2909,7 +2825,7 @@ static int record_ieot(void)
* rely on it.
*/
static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
- int strip_extensions, unsigned flags)
+ enum write_extensions write_extensions, unsigned flags)
{
uint64_t start = getnanotime();
struct hashfile *f;
@@ -2947,7 +2863,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
}
if (!istate->version)
- istate->version = get_index_format_default(the_repository);
+ istate->version = get_index_format_default(r);
/* demote version 3 to version 2 when the latter suffices */
if (istate->version == 3 || istate->version == 2)
@@ -3082,8 +2998,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
return -1;
}
- if (!strip_extensions && istate->split_index &&
- !is_null_oid(&istate->split_index->base_oid)) {
+ if (write_extensions & WRITE_SPLIT_INDEX_EXTENSION &&
+ istate->split_index) {
struct strbuf sb = STRBUF_INIT;
if (istate->sparse_index)
@@ -3097,7 +3013,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
if (err)
return -1;
}
- if (!strip_extensions && !drop_cache_tree && istate->cache_tree) {
+ if (write_extensions & WRITE_CACHE_TREE_EXTENSION &&
+ !drop_cache_tree && istate->cache_tree) {
struct strbuf sb = STRBUF_INIT;
cache_tree_write(&sb, istate->cache_tree);
@@ -3107,7 +3024,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
if (err)
return -1;
}
- if (!strip_extensions && istate->resolve_undo) {
+ if (write_extensions & WRITE_RESOLVE_UNDO_EXTENSION &&
+ istate->resolve_undo) {
struct strbuf sb = STRBUF_INIT;
resolve_undo_write(&sb, istate->resolve_undo);
@@ -3118,7 +3036,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
if (err)
return -1;
}
- if (!strip_extensions && istate->untracked) {
+ if (write_extensions & WRITE_UNTRACKED_CACHE_EXTENSION &&
+ istate->untracked) {
struct strbuf sb = STRBUF_INIT;
write_untracked_extension(&sb, istate->untracked);
@@ -3129,7 +3048,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
if (err)
return -1;
}
- if (!strip_extensions && istate->fsmonitor_last_update) {
+ if (write_extensions & WRITE_FSMONITOR_EXTENSION &&
+ istate->fsmonitor_last_update) {
struct strbuf sb = STRBUF_INIT;
write_fsmonitor_extension(&sb, istate);
@@ -3203,8 +3123,10 @@ static int commit_locked_index(struct lock_file *lk)
return commit_lock_file(lk);
}
-static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
- unsigned flags)
+static int do_write_locked_index(struct index_state *istate,
+ struct lock_file *lock,
+ unsigned flags,
+ enum write_extensions write_extensions)
{
int ret;
int was_full = istate->sparse_index == INDEX_EXPANDED;
@@ -3222,7 +3144,7 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
*/
trace2_region_enter_printf("index", "do_write_index", the_repository,
"%s", get_lock_file_path(lock));
- ret = do_write_index(istate, lock->tempfile, 0, flags);
+ ret = do_write_index(istate, lock->tempfile, write_extensions, flags);
trace2_region_leave_printf("index", "do_write_index", the_repository,
"%s", get_lock_file_path(lock));
@@ -3251,7 +3173,7 @@ static int write_split_index(struct index_state *istate,
{
int ret;
prepare_to_write_split_index(istate);
- ret = do_write_locked_index(istate, lock, flags);
+ ret = do_write_locked_index(istate, lock, flags, WRITE_ALL_EXTENSIONS);
finish_writing_split_index(istate);
return ret;
}
@@ -3326,7 +3248,7 @@ static int write_shared_index(struct index_state *istate,
trace2_region_enter_printf("index", "shared/do_write_index",
the_repository, "%s", get_tempfile_path(*temp));
- ret = do_write_index(si->base, *temp, 1, flags);
+ ret = do_write_index(si->base, *temp, WRITE_NO_EXTENSION, flags);
trace2_region_leave_printf("index", "shared/do_write_index",
the_repository, "%s", get_tempfile_path(*temp));
@@ -3403,9 +3325,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
if ((!si && !test_split_index_env) ||
alternate_index_output ||
(istate->cache_changed & ~EXTMASK)) {
- if (si)
- oidclr(&si->base_oid);
- ret = do_write_locked_index(istate, lock, flags);
+ ret = do_write_locked_index(istate, lock, flags,
+ ~WRITE_SPLIT_INDEX_EXTENSION);
goto out;
}
@@ -3431,8 +3352,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
/* Same initial permissions as the main .git/index file */
temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666);
if (!temp) {
- oidclr(&si->base_oid);
- ret = do_write_locked_index(istate, lock, flags);
+ ret = do_write_locked_index(istate, lock, flags,
+ ~WRITE_SPLIT_INDEX_EXTENSION);
goto out;
}
ret = write_shared_index(istate, &temp, flags);
@@ -3553,7 +3474,8 @@ void *read_blob_data_from_index(struct index_state *istate,
}
if (pos < 0)
return NULL;
- data = read_object_file(&istate->cache[pos]->oid, &type, &sz);
+ data = repo_read_object_file(the_repository, &istate->cache[pos]->oid,
+ &type, &sz);
if (!data || type != OBJ_BLOB) {
free(data);
return NULL;
@@ -3563,35 +3485,6 @@ void *read_blob_data_from_index(struct index_state *istate,
return data;
}
-void stat_validity_clear(struct stat_validity *sv)
-{
- FREE_AND_NULL(sv->sd);
-}
-
-int stat_validity_check(struct stat_validity *sv, const char *path)
-{
- struct stat st;
-
- if (stat(path, &st) < 0)
- return sv->sd == NULL;
- if (!sv->sd)
- return 0;
- return S_ISREG(st.st_mode) && !match_stat_data(sv->sd, &st);
-}
-
-void stat_validity_update(struct stat_validity *sv, int fd)
-{
- struct stat st;
-
- if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode))
- stat_validity_clear(sv);
- else {
- if (!sv->sd)
- CALLOC_ARRAY(sv->sd, 1);
- fill_stat_data(sv->sd, &st);
- }
-}
-
void move_index_extensions(struct index_state *dst, struct index_state *src)
{
dst->untracked = src->untracked;
@@ -3835,3 +3728,240 @@ void prefetch_cache_entries(const struct index_state *istate,
to_fetch.oid, to_fetch.nr);
oid_array_clear(&to_fetch);
}
+
+static int read_one_entry_opt(struct index_state *istate,
+ const struct object_id *oid,
+ struct strbuf *base,
+ const char *pathname,
+ unsigned mode, int opt)
+{
+ int len;
+ struct cache_entry *ce;
+
+ if (S_ISDIR(mode))
+ return READ_TREE_RECURSIVE;
+
+ len = strlen(pathname);
+ ce = make_empty_cache_entry(istate, base->len + len);
+
+ ce->ce_mode = create_ce_mode(mode);
+ ce->ce_flags = create_ce_flags(1);
+ ce->ce_namelen = base->len + len;
+ memcpy(ce->name, base->buf, base->len);
+ memcpy(ce->name + base->len, pathname, len+1);
+ oidcpy(&ce->oid, oid);
+ return add_index_entry(istate, ce, opt);
+}
+
+static int read_one_entry(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode,
+ void *context)
+{
+ struct index_state *istate = context;
+ return read_one_entry_opt(istate, oid, base, pathname,
+ mode,
+ ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
+}
+
+/*
+ * This is used when the caller knows there is no existing entries at
+ * the stage that will conflict with the entry being added.
+ */
+static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode,
+ void *context)
+{
+ struct index_state *istate = context;
+ return read_one_entry_opt(istate, oid, base, pathname,
+ mode, ADD_CACHE_JUST_APPEND);
+}
+
+/*
+ * Read the tree specified with --with-tree option
+ * (typically, HEAD) into stage #1 and then
+ * squash them down to stage #0. This is used for
+ * --error-unmatch to list and check the path patterns
+ * that were given from the command line. We are not
+ * going to write this index out.
+ */
+void overlay_tree_on_index(struct index_state *istate,
+ const char *tree_name, const char *prefix)
+{
+ struct tree *tree;
+ struct object_id oid;
+ struct pathspec pathspec;
+ struct cache_entry *last_stage0 = NULL;
+ int i;
+ read_tree_fn_t fn = NULL;
+ int err;
+
+ if (repo_get_oid(the_repository, tree_name, &oid))
+ die("tree-ish %s not found.", tree_name);
+ tree = parse_tree_indirect(&oid);
+ if (!tree)
+ die("bad tree-ish %s", tree_name);
+
+ /* Hoist the unmerged entries up to stage #3 to make room */
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(istate);
+ for (i = 0; i < istate->cache_nr; i++) {
+ struct cache_entry *ce = istate->cache[i];
+ if (!ce_stage(ce))
+ continue;
+ ce->ce_flags |= CE_STAGEMASK;
+ }
+
+ if (prefix) {
+ static const char *(matchbuf[1]);
+ matchbuf[0] = NULL;
+ parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC,
+ PATHSPEC_PREFER_CWD, prefix, matchbuf);
+ } else
+ memset(&pathspec, 0, sizeof(pathspec));
+
+ /*
+ * See if we have cache entry at the stage. If so,
+ * do it the original slow way, otherwise, append and then
+ * sort at the end.
+ */
+ for (i = 0; !fn && i < istate->cache_nr; i++) {
+ const struct cache_entry *ce = istate->cache[i];
+ if (ce_stage(ce) == 1)
+ fn = read_one_entry;
+ }
+
+ if (!fn)
+ fn = read_one_entry_quick;
+ err = read_tree(the_repository, tree, &pathspec, fn, istate);
+ clear_pathspec(&pathspec);
+ if (err)
+ die("unable to read tree entries %s", tree_name);
+
+ /*
+ * Sort the cache entry -- we need to nuke the cache tree, though.
+ */
+ if (fn == read_one_entry_quick) {
+ cache_tree_free(&istate->cache_tree);
+ QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
+ }
+
+ for (i = 0; i < istate->cache_nr; i++) {
+ struct cache_entry *ce = istate->cache[i];
+ switch (ce_stage(ce)) {
+ case 0:
+ last_stage0 = ce;
+ /* fallthru */
+ default:
+ continue;
+ case 1:
+ /*
+ * If there is stage #0 entry for this, we do not
+ * need to show it. We use CE_UPDATE bit to mark
+ * such an entry.
+ */
+ if (last_stage0 &&
+ !strcmp(last_stage0->name, ce->name))
+ ce->ce_flags |= CE_UPDATE;
+ }
+ }
+}
+
+struct update_callback_data {
+ struct index_state *index;
+ int include_sparse;
+ int flags;
+ int add_errors;
+};
+
+static int fix_unmerged_status(struct diff_filepair *p,
+ struct update_callback_data *data)
+{
+ if (p->status != DIFF_STATUS_UNMERGED)
+ return p->status;
+ if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
+ /*
+ * This is not an explicit add request, and the
+ * path is missing from the working tree (deleted)
+ */
+ return DIFF_STATUS_DELETED;
+ else
+ /*
+ * Either an explicit add request, or path exists
+ * in the working tree. An attempt to explicitly
+ * add a path that does not exist in the working tree
+ * will be caught as an error by the caller immediately.
+ */
+ return DIFF_STATUS_MODIFIED;
+}
+
+static void update_callback(struct diff_queue_struct *q,
+ struct diff_options *opt UNUSED, void *cbdata)
+{
+ int i;
+ struct update_callback_data *data = cbdata;
+
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ const char *path = p->one->path;
+
+ if (!data->include_sparse &&
+ !path_in_sparse_checkout(path, data->index))
+ continue;
+
+ switch (fix_unmerged_status(p, data)) {
+ default:
+ die(_("unexpected diff status %c"), p->status);
+ case DIFF_STATUS_MODIFIED:
+ case DIFF_STATUS_TYPE_CHANGED:
+ if (add_file_to_index(data->index, path, data->flags)) {
+ if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
+ die(_("updating files failed"));
+ data->add_errors++;
+ }
+ break;
+ case DIFF_STATUS_DELETED:
+ if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
+ break;
+ if (!(data->flags & ADD_CACHE_PRETEND))
+ remove_file_from_index(data->index, path);
+ if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
+ printf(_("remove '%s'\n"), path);
+ break;
+ }
+ }
+}
+
+int add_files_to_cache(struct repository *repo, const char *prefix,
+ const struct pathspec *pathspec, int include_sparse,
+ int flags)
+{
+ struct update_callback_data data;
+ struct rev_info rev;
+
+ memset(&data, 0, sizeof(data));
+ data.index = repo->index;
+ data.include_sparse = include_sparse;
+ data.flags = flags;
+
+ repo_init_revisions(repo, &rev, prefix);
+ setup_revisions(0, NULL, &rev, NULL);
+ if (pathspec)
+ copy_pathspec(&rev.prune_data, pathspec);
+ rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+ rev.diffopt.format_callback = update_callback;
+ 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);
+ end_odb_transaction();
+
+ release_revisions(&rev);
+ return !!data.add_errors;
+}
diff --git a/read-cache.h b/read-cache.h
new file mode 100644
index 0000000000..043da1f1aa
--- /dev/null
+++ b/read-cache.h
@@ -0,0 +1,45 @@
+#ifndef READ_CACHE_H
+#define READ_CACHE_H
+
+#include "read-cache-ll.h"
+#include "object.h"
+#include "pathspec.h"
+
+static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce,
+ unsigned int mode)
+{
+ extern int trust_executable_bit, has_symlinks;
+ if (!has_symlinks && S_ISREG(mode) &&
+ ce && S_ISLNK(ce->ce_mode))
+ return ce->ce_mode;
+ if (!trust_executable_bit && S_ISREG(mode)) {
+ if (ce && S_ISREG(ce->ce_mode))
+ return ce->ce_mode;
+ return create_ce_mode(0666);
+ }
+ return create_ce_mode(mode);
+}
+
+static inline int ce_to_dtype(const struct cache_entry *ce)
+{
+ unsigned ce_mode = ntohl(ce->ce_mode);
+ if (S_ISREG(ce_mode))
+ return DT_REG;
+ else if (S_ISDIR(ce_mode) || S_ISGITLINK(ce_mode))
+ return DT_DIR;
+ else if (S_ISLNK(ce_mode))
+ return DT_LNK;
+ else
+ return DT_UNKNOWN;
+}
+
+static inline int ce_path_match(struct index_state *istate,
+ const struct cache_entry *ce,
+ const struct pathspec *pathspec,
+ char *seen)
+{
+ return match_pathspec(istate, pathspec, ce->name, ce_namelen(ce), 0, seen,
+ S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode));
+}
+
+#endif /* READ_CACHE_H */
diff --git a/rebase-interactive.c b/rebase-interactive.c
index 7407c59319..f286404d4b 100644
--- a/rebase-interactive.c
+++ b/rebase-interactive.c
@@ -1,11 +1,17 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "commit.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
#include "sequencer.h"
#include "rebase-interactive.h"
+#include "repository.h"
#include "strbuf.h"
#include "commit-slab.h"
#include "config.h"
#include "dir.h"
+#include "object-name.h"
+#include "wrapper.h"
static const char edit_todo_list_advice[] =
N_("You can fix this with 'git rebase --edit-todo' "
@@ -66,13 +72,14 @@ void append_todo_help(int command_count,
if (!edit_todo) {
strbuf_addch(buf, '\n');
- strbuf_commented_addf(buf, Q_("Rebase %s onto %s (%d command)",
- "Rebase %s onto %s (%d commands)",
- command_count),
+ strbuf_commented_addf(buf, comment_line_char,
+ Q_("Rebase %s onto %s (%d command)",
+ "Rebase %s onto %s (%d commands)",
+ command_count),
shortrevisions, shortonto, command_count);
}
- strbuf_add_commented_lines(buf, msg, strlen(msg));
+ strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);
if (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)
msg = _("\nDo not remove any line. Use 'drop' "
@@ -81,7 +88,7 @@ void append_todo_help(int command_count,
msg = _("\nIf you remove a line here "
"THAT COMMIT WILL BE LOST.\n");
- strbuf_add_commented_lines(buf, msg, strlen(msg));
+ strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);
if (edit_todo)
msg = _("\nYou are editing the todo file "
@@ -92,7 +99,7 @@ void append_todo_help(int command_count,
msg = _("\nHowever, if you remove everything, "
"the rebase will be aborted.\n\n");
- strbuf_add_commented_lines(buf, msg, strlen(msg));
+ strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);
}
int edit_todo_list(struct repository *r, struct todo_list *todo_list,
@@ -124,7 +131,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,
if (launch_sequence_editor(todo_file, &new_todo->buf, NULL))
return -2;
- strbuf_stripspace(&new_todo->buf, 1);
+ strbuf_stripspace(&new_todo->buf, comment_line_char);
if (initial && new_todo->buf.len == 0)
return -3;
@@ -187,7 +194,7 @@ int todo_list_check(struct todo_list *old_todo, struct todo_list *new_todo)
struct commit *commit = item->commit;
if (commit && !*commit_seen_at(&commit_seen, commit)) {
strbuf_addf(&missing, " - %s %.*s\n",
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
item->arg_len,
todo_item_get_arg(old_todo, item));
*commit_seen_at(&commit_seen, commit) = 1;
diff --git a/rebase.c b/rebase.c
index 6775cddb28..17a570f1ff 100644
--- a/rebase.c
+++ b/rebase.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
#include "rebase.h"
#include "config.h"
#include "gettext.h"
diff --git a/ref-filter.c b/ref-filter.c
index f8203c6b05..771fa6c133 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1,9 +1,15 @@
-#include "builtin.h"
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "environment.h"
+#include "gettext.h"
+#include "gpg-interface.h"
+#include "hex.h"
#include "parse-options.h"
#include "refs.h"
#include "wildmatch.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
#include "repository.h"
#include "commit.h"
#include "remote.h"
@@ -13,8 +19,8 @@
#include "ref-filter.h"
#include "revision.h"
#include "utf8.h"
-#include "git-compat-util.h"
#include "version.h"
+#include "versioncmp.h"
#include "trailer.h"
#include "wt-status.h"
#include "commit-slab.h"
@@ -158,6 +164,7 @@ enum atom_type {
ATOM_THEN,
ATOM_ELSE,
ATOM_REST,
+ ATOM_AHEADBEHIND,
};
/*
@@ -282,7 +289,8 @@ static int refname_atom_parser_internal(struct refname_atom *atom, const char *a
return 0;
}
-static int remote_ref_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int remote_ref_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
struct string_list params = STRING_LIST_INIT_DUP;
@@ -329,7 +337,8 @@ static int remote_ref_atom_parser(struct ref_format *format, struct used_atom *a
return 0;
}
-static int objecttype_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int objecttype_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
@@ -341,7 +350,8 @@ static int objecttype_atom_parser(struct ref_format *format, struct used_atom *a
return 0;
}
-static int objectsize_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int objectsize_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg) {
@@ -361,7 +371,8 @@ static int objectsize_atom_parser(struct ref_format *format, struct used_atom *a
return 0;
}
-static int deltabase_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int deltabase_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
@@ -373,7 +384,8 @@ static int deltabase_atom_parser(struct ref_format *format, struct used_atom *at
return 0;
}
-static int body_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int body_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
@@ -382,7 +394,8 @@ static int body_atom_parser(struct ref_format *format, struct used_atom *atom,
return 0;
}
-static int subject_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int subject_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -394,7 +407,8 @@ static int subject_atom_parser(struct ref_format *format, struct used_atom *atom
return 0;
}
-static int trailers_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int trailers_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
atom->u.contents.trailer_opts.no_divider = 1;
@@ -448,8 +462,9 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
return 0;
}
-static int raw_atom_parser(struct ref_format *format, struct used_atom *atom,
- const char *arg, struct strbuf *err)
+static int raw_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
+ const char *arg, struct strbuf *err)
{
if (!arg)
atom->u.raw_data.option = RAW_BARE;
@@ -460,7 +475,8 @@ static int raw_atom_parser(struct ref_format *format, struct used_atom *atom,
return 0;
}
-static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int oid_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -479,7 +495,8 @@ static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
return 0;
}
-static int person_email_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int person_email_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -493,7 +510,8 @@ static int person_email_atom_parser(struct ref_format *format, struct used_atom
return 0;
}
-static int refname_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int refname_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
return refname_atom_parser_internal(&atom->u.refname, arg, atom->name, err);
@@ -510,7 +528,8 @@ static align_type parse_align_position(const char *s)
return -1;
}
-static int align_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int align_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
struct align *align = &atom->u.align;
@@ -562,7 +581,8 @@ static int align_atom_parser(struct ref_format *format, struct used_atom *atom,
return 0;
}
-static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int if_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg) {
@@ -577,16 +597,33 @@ static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
return 0;
}
-static int rest_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int rest_atom_parser(struct ref_format *format,
+ struct used_atom *atom UNUSED,
const char *arg, struct strbuf *err)
{
if (arg)
return err_no_arg(err, "rest");
- format->use_rest = 1;
return 0;
}
-static int head_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int ahead_behind_atom_parser(struct ref_format *format, struct used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+ struct string_list_item *item;
+
+ if (!arg)
+ return strbuf_addf_ret(err, -1, _("expected format: %%(ahead-behind:<committish>)"));
+
+ item = string_list_append(&format->bases, arg);
+ item->util = lookup_commit_reference_by_name(arg);
+ if (!item->util)
+ die("failed to find '%s'", arg);
+
+ return 0;
+}
+
+static int head_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
@@ -645,6 +682,7 @@ static struct {
[ATOM_THEN] = { "then", SOURCE_NONE },
[ATOM_ELSE] = { "else", SOURCE_NONE },
[ATOM_REST] = { "rest", SOURCE_NONE, FIELD_STR, rest_atom_parser },
+ [ATOM_AHEADBEHIND] = { "ahead-behind", SOURCE_OTHER, FIELD_STR, ahead_behind_atom_parser },
/*
* Please update $__git_ref_fieldlist in git-completion.bash
* when you add new atoms
@@ -791,7 +829,7 @@ static void quote_formatting(struct strbuf *s, const char *str, ssize_t len, int
}
static int append_atom(struct atom_value *v, struct ref_formatting_state *state,
- struct strbuf *unused_err)
+ struct strbuf *err UNUSED)
{
/*
* Quote formatting is only done when the stack has a single
@@ -841,7 +879,7 @@ static void end_align_handler(struct ref_formatting_stack **stack)
}
static int align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
- struct strbuf *unused_err)
+ struct strbuf *err UNUSED)
{
struct ref_formatting_stack *new_stack;
@@ -888,7 +926,7 @@ static void if_then_else_handler(struct ref_formatting_stack **stack)
}
static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
- struct strbuf *unused_err)
+ struct strbuf *err UNUSED)
{
struct ref_formatting_stack *new_stack;
struct if_then_else *if_then_else = xcalloc(1,
@@ -915,7 +953,8 @@ static int is_empty(struct strbuf *buf)
return cur == end;
}
-static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
+static int then_atom_handler(struct atom_value *atomv UNUSED,
+ struct ref_formatting_state *state,
struct strbuf *err)
{
struct ref_formatting_stack *cur = state->stack;
@@ -952,7 +991,8 @@ static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
return 0;
}
-static int else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
+static int else_atom_handler(struct atom_value *atomv UNUSED,
+ struct ref_formatting_state *state,
struct strbuf *err)
{
struct ref_formatting_stack *prev = state->stack;
@@ -973,7 +1013,8 @@ static int else_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
return 0;
}
-static int end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
+static int end_atom_handler(struct atom_value *atomv UNUSED,
+ struct ref_formatting_state *state,
struct strbuf *err)
{
struct ref_formatting_stack *current = state->stack;
@@ -1075,9 +1116,11 @@ static const char *do_grab_oid(const char *field, const struct object_id *oid,
case O_FULL:
return oid_to_hex(oid);
case O_LENGTH:
- return find_unique_abbrev(oid, atom->u.oid.length);
+ return repo_find_unique_abbrev(the_repository, oid,
+ atom->u.oid.length);
case O_SHORT:
- return find_unique_abbrev(oid, DEFAULT_ABBREV);
+ return repo_find_unique_abbrev(the_repository, oid,
+ DEFAULT_ABBREV);
default:
BUG("unknown %%(%s) option", field);
}
@@ -1822,7 +1865,7 @@ static void lazy_init_worktree_map(void)
populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
}
-static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+static char *get_worktree_path(const struct ref_array_item *ref)
{
struct hashmap_entry entry, *e;
struct ref_to_worktree_entry *lookup_result;
@@ -1848,6 +1891,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
struct object *obj;
int i;
struct object_info empty = OBJECT_INFO_INIT;
+ int ahead_behind_atoms = 0;
CALLOC_ARRAY(ref->value, used_atom_cnt);
@@ -1881,7 +1925,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
refname = get_refname(atom, ref);
else if (atom_type == ATOM_WORKTREEPATH) {
if (ref->kind == FILTER_REFS_BRANCHES)
- v->s = get_worktree_path(atom, ref);
+ v->s = get_worktree_path(ref);
else
v->s = xstrdup("");
continue;
@@ -1978,6 +2022,16 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
else
v->s = xstrdup("");
continue;
+ } else if (atom_type == ATOM_AHEADBEHIND) {
+ if (ref->counts) {
+ const struct ahead_behind_count *count;
+ count = ref->counts[ahead_behind_atoms++];
+ v->s = xstrfmt("%d %d", count->ahead, count->behind);
+ } else {
+ /* Not a commit. */
+ v->s = xstrdup("");
+ }
+ continue;
} else
continue;
@@ -2050,12 +2104,12 @@ static int get_ref_atom_value(struct ref_array_item *ref, int atom,
* matches a pattern "refs/heads/mas") or a wildcard (e.g. the same ref
* matches "refs/heads/mas*", too).
*/
-static int match_pattern(const struct ref_filter *filter, const char *refname)
+static int match_pattern(const char **patterns, const char *refname,
+ const int ignore_case)
{
- const char **patterns = filter->name_patterns;
unsigned flags = 0;
- if (filter->ignore_case)
+ if (ignore_case)
flags |= WM_CASEFOLD;
/*
@@ -2080,9 +2134,10 @@ static int match_pattern(const struct ref_filter *filter, const char *refname)
* matches a pattern "refs/heads/" but not "refs/heads/m") or a
* wildcard (e.g. the same ref matches "refs/heads/m*", too).
*/
-static int match_name_as_path(const struct ref_filter *filter, const char *refname)
+static int match_name_as_path(const struct ref_filter *filter,
+ const char **pattern,
+ const char *refname)
{
- const char **pattern = filter->name_patterns;
int namelen = strlen(refname);
unsigned flags = WM_PATHNAME;
@@ -2111,8 +2166,18 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
if (!*filter->name_patterns)
return 1; /* No pattern always matches */
if (filter->match_as_path)
- return match_name_as_path(filter, refname);
- return match_pattern(filter, refname);
+ return match_name_as_path(filter, filter->name_patterns, refname);
+ return match_pattern(filter->name_patterns, refname,
+ filter->ignore_case);
+}
+
+static int filter_exclude_match(struct ref_filter *filter, const char *refname)
+{
+ if (!filter->exclude.nr)
+ return 0;
+ if (filter->match_as_path)
+ return match_name_as_path(filter, filter->exclude.v, refname);
+ return match_pattern(filter->exclude.v, refname, filter->ignore_case);
}
/*
@@ -2144,11 +2209,13 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
if (!filter->name_patterns[0]) {
/* no patterns; we have to look at everything */
- return for_each_fullref_in("", cb, cb_data);
+ return refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "", filter->exclude.v, cb, cb_data);
}
return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository),
NULL, filter->name_patterns,
+ filter->exclude.v,
cb, cb_data);
}
@@ -2282,6 +2349,9 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
if (!filter_pattern_match(filter, refname))
return 0;
+ if (filter_exclude_match(filter, refname))
+ return 0;
+
if (filter->points_at.nr && !match_points_at(&filter->points_at, oid, refname))
return 0;
@@ -2328,6 +2398,7 @@ static void free_array_item(struct ref_array_item *item)
free((char *)item->value[i].s);
free(item->value);
}
+ free(item->counts);
free(item);
}
@@ -2356,41 +2427,32 @@ void ref_array_clear(struct ref_array *array)
free_worktrees(ref_to_worktree_map.worktrees);
ref_to_worktree_map.worktrees = NULL;
}
+
+ FREE_AND_NULL(array->counts);
}
#define EXCLUDE_REACHED 0
#define INCLUDE_REACHED 1
static void reach_filter(struct ref_array *array,
- struct commit_list *check_reachable,
+ struct commit_list **check_reachable,
int include_reached)
{
- struct rev_info revs;
int i, old_nr;
struct commit **to_clear;
- struct commit_list *cr;
- if (!check_reachable)
+ if (!*check_reachable)
return;
CALLOC_ARRAY(to_clear, array->nr);
-
- repo_init_revisions(the_repository, &revs, NULL);
-
for (i = 0; i < array->nr; i++) {
struct ref_array_item *item = array->items[i];
- add_pending_object(&revs, &item->commit->object, item->refname);
to_clear[i] = item->commit;
}
- for (cr = check_reachable; cr; cr = cr->next) {
- struct commit *merge_commit = cr->item;
- merge_commit->object.flags |= UNINTERESTING;
- add_pending_object(&revs, &merge_commit->object, "");
- }
-
- revs.limited = 1;
- if (prepare_revision_walk(&revs))
- die(_("revision walk setup failed"));
+ tips_reachable_from_bases(the_repository,
+ *check_reachable,
+ to_clear, array->nr,
+ UNINTERESTING);
old_nr = array->nr;
array->nr = 0;
@@ -2409,15 +2471,55 @@ static void reach_filter(struct ref_array *array,
clear_commit_marks_many(old_nr, to_clear, ALL_REV_FLAGS);
- while (check_reachable) {
- struct commit *merge_commit = pop_commit(&check_reachable);
+ while (*check_reachable) {
+ struct commit *merge_commit = pop_commit(check_reachable);
clear_commit_marks(merge_commit, ALL_REV_FLAGS);
}
- release_revisions(&revs);
free(to_clear);
}
+void filter_ahead_behind(struct repository *r,
+ struct ref_format *format,
+ struct ref_array *array)
+{
+ struct commit **commits;
+ size_t commits_nr = format->bases.nr + array->nr;
+
+ if (!format->bases.nr || !array->nr)
+ return;
+
+ ALLOC_ARRAY(commits, commits_nr);
+ for (size_t i = 0; i < format->bases.nr; i++)
+ commits[i] = format->bases.items[i].util;
+
+ ALLOC_ARRAY(array->counts, st_mult(format->bases.nr, array->nr));
+
+ commits_nr = format->bases.nr;
+ array->counts_nr = 0;
+ for (size_t i = 0; i < array->nr; i++) {
+ const char *name = array->items[i]->refname;
+ commits[commits_nr] = lookup_commit_reference_by_name(name);
+
+ if (!commits[commits_nr])
+ continue;
+
+ CALLOC_ARRAY(array->items[i]->counts, format->bases.nr);
+ for (size_t j = 0; j < format->bases.nr; j++) {
+ struct ahead_behind_count *count;
+ count = &array->counts[array->counts_nr++];
+ count->tip_index = commits_nr;
+ count->base_index = j;
+
+ array->items[i]->counts[j] = count;
+ }
+ commits_nr++;
+ }
+
+ ahead_behind(r, commits, commits_nr, array->counts, array->counts_nr);
+ free(commits);
+}
+
/*
* API for filtering a set of refs. Based on the type of refs the user
* has requested, we iterate through those refs and apply filters
@@ -2467,8 +2569,8 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
clear_contains_cache(&ref_cbdata.no_contains_cache);
/* Filters that need revision walking */
- reach_filter(array, filter->reachable_from, INCLUDE_REACHED);
- reach_filter(array, filter->unreachable_from, EXCLUDE_REACHED);
+ reach_filter(array, &filter->reachable_from, INCLUDE_REACHED);
+ reach_filter(array, &filter->unreachable_from, EXCLUDE_REACHED);
save_commit_buffer = save_commit_buffer_orig;
return ret;
@@ -2765,7 +2867,7 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
BUG_ON_OPT_NEG(unset);
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
die(_("malformed object name %s"), arg);
merge_commit = lookup_commit_reference_gently(the_repository, &oid, 0);
@@ -2780,3 +2882,20 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
return 0;
}
+
+void ref_filter_init(struct ref_filter *filter)
+{
+ struct ref_filter blank = REF_FILTER_INIT;
+ memcpy(filter, &blank, sizeof(blank));
+}
+
+void ref_filter_clear(struct ref_filter *filter)
+{
+ strvec_clear(&filter->exclude);
+ oid_array_clear(&filter->points_at);
+ free_commit_list(filter->with_commit);
+ free_commit_list(filter->no_commit);
+ free_commit_list(filter->reachable_from);
+ free_commit_list(filter->unreachable_from);
+ ref_filter_init(filter);
+}
diff --git a/ref-filter.h b/ref-filter.h
index aa0eea4ecf..1524bc463a 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -1,10 +1,12 @@
#ifndef REF_FILTER_H
#define REF_FILTER_H
+#include "gettext.h"
#include "oid-array.h"
#include "refs.h"
#include "commit.h"
-#include "parse-options.h"
+#include "string-list.h"
+#include "strvec.h"
/* Quoting styles */
#define QUOTE_NONE 0
@@ -24,6 +26,8 @@
struct atom_value;
struct ref_sorting;
+struct ahead_behind_count;
+struct option;
enum ref_sorting_order {
REF_SORTING_REVERSE = 1<<0,
@@ -40,6 +44,8 @@ struct ref_array_item {
const char *symref;
struct commit *commit;
struct atom_value *value;
+ struct ahead_behind_count **counts;
+
char refname[FLEX_ARRAY];
};
@@ -47,10 +53,14 @@ struct ref_array {
int nr, alloc;
struct ref_array_item **items;
struct rev_info *revs;
+
+ struct ahead_behind_count *counts;
+ size_t counts_nr;
};
struct ref_filter {
const char **name_patterns;
+ struct strvec exclude;
struct oid_array points_at;
struct commit_list *with_commit;
struct commit_list *no_commit;
@@ -75,14 +85,23 @@ struct ref_format {
const char *format;
const char *rest;
int quote_style;
- int use_rest;
int use_color;
/* Internal state to ref-filter */
int need_color_reset_at_eol;
+
+ /* List of bases for ahead-behind counts. */
+ struct string_list bases;
};
-#define REF_FORMAT_INIT { .use_color = -1 }
+#define REF_FILTER_INIT { \
+ .points_at = OID_ARRAY_INIT, \
+ .exclude = STRVEC_INIT, \
+}
+#define REF_FORMAT_INIT { \
+ .use_color = -1, \
+ .bases = STRING_LIST_INIT_DUP, \
+}
/* Macros for checking --merged and --no-merged options */
#define _OPT_MERGED_NO_MERGED(option, filter, h) \
@@ -96,6 +115,9 @@ struct ref_format {
#define OPT_REF_SORT(var) \
OPT_STRING_LIST(0, "sort", (var), \
N_("key"), N_("field name to sort on"))
+#define OPT_REF_FILTER_EXCLUDE(var) \
+ OPT_STRVEC(0, "exclude", &(var)->exclude, \
+ N_("pattern"), N_("exclude refs which match pattern"))
/*
* API for filtering a set of refs. Based on the type of refs the user
@@ -143,4 +165,18 @@ struct ref_array_item *ref_array_push(struct ref_array *array,
const char *refname,
const struct object_id *oid);
+/*
+ * If the provided format includes ahead-behind atoms, then compute the
+ * ahead-behind values for the array of filtered references. Must be
+ * called after filter_refs() but before outputting the formatted refs.
+ *
+ * If this is not called, then any ahead-behind atoms will be blank.
+ */
+void filter_ahead_behind(struct repository *r,
+ struct ref_format *format,
+ struct ref_array *array);
+
+void ref_filter_init(struct ref_filter *filter);
+void ref_filter_clear(struct ref_filter *filter);
+
#endif /* REF_FILTER_H */
diff --git a/reflog-walk.c b/reflog-walk.c
index 8a4d8fa3bd..d337e64431 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -1,7 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "commit.h"
#include "refs.h"
#include "diff.h"
+#include "repository.h"
#include "revision.h"
#include "string-list.h"
#include "reflog-walk.h"
diff --git a/reflog-walk.h b/reflog-walk.h
index 8076f10d9f..4d93a26957 100644
--- a/reflog-walk.h
+++ b/reflog-walk.h
@@ -1,8 +1,6 @@
#ifndef REFLOG_WALK_H
#define REFLOG_WALK_H
-#include "cache.h"
-
struct commit;
struct reflog_walk_info;
struct date_mode;
diff --git a/reflog.c b/reflog.c
index 04630f56ec..9ad50e7d93 100644
--- a/reflog.c
+++ b/reflog.c
@@ -1,8 +1,11 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "object-store-ll.h"
#include "reflog.h"
#include "refs.h"
#include "revision.h"
+#include "tree.h"
+#include "tree-walk.h"
#include "worktree.h"
/* Remember to update object flag allocation in object.h */
@@ -28,7 +31,8 @@ static int tree_is_complete(const struct object_id *oid)
if (!tree->buffer) {
enum object_type type;
unsigned long size;
- void *data = read_object_file(oid, &type, &size);
+ void *data = repo_read_object_file(the_repository, oid, &type,
+ &size);
if (!data) {
tree->object.flags |= INCOMPLETE;
return 0;
@@ -39,7 +43,7 @@ static int tree_is_complete(const struct object_id *oid)
init_tree_desc(&desc, tree->buffer, tree->size);
complete = 1;
while (tree_entry(&desc, &entry)) {
- if (!has_object_file(&entry.oid) ||
+ if (!repo_has_object_file(the_repository, &entry.oid) ||
(S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
tree->object.flags |= INCOMPLETE;
complete = 0;
@@ -186,7 +190,7 @@ static void mark_reachable(struct expire_reflog_policy_cb *cb)
struct commit *commit = pop_commit(&pending);
if (commit->object.flags & REACHABLE)
continue;
- if (parse_commit(commit))
+ if (repo_parse_commit(the_repository, commit))
continue;
commit->object.flags |= REACHABLE;
if (commit->date < expire_limit) {
diff --git a/refs.c b/refs.c
index aeae31c972..baed76af04 100644
--- a/refs.c
+++ b/refs.c
@@ -2,25 +2,35 @@
* The backend-independent part of the reference module.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
#include "hashmap.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "iterator.h"
#include "refs.h"
#include "refs/refs-internal.h"
#include "run-command.h"
#include "hook.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "object.h"
+#include "path.h"
#include "tag.h"
#include "submodule.h"
#include "worktree.h"
#include "strvec.h"
#include "repository.h"
+#include "setup.h"
#include "sigchain.h"
#include "date.h"
#include "commit.h"
+#include "wildmatch.h"
+#include "wrapper.h"
/*
* List of all available backends
@@ -367,8 +377,8 @@ char *resolve_refdup(const char *refname, int resolve_flags,
oid, flags);
}
-/* The argument to filter_refs */
-struct ref_filter {
+/* The argument to for_each_filter_refs */
+struct for_each_ref_filter {
const char *pattern;
const char *prefix;
each_ref_fn *fn;
@@ -401,10 +411,11 @@ int ref_exists(const char *refname)
return refs_ref_exists(get_main_ref_store(the_repository), refname);
}
-static int filter_refs(const char *refname, const struct object_id *oid,
- int flags, void *data)
+static int for_each_filter_refs(const char *refname,
+ const struct object_id *oid,
+ int flags, void *data)
{
- struct ref_filter *filter = (struct ref_filter *)data;
+ struct for_each_ref_filter *filter = data;
if (wildmatch(filter->pattern, refname, 0))
return 0;
@@ -561,7 +572,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
const char *prefix, void *cb_data)
{
struct strbuf real_pattern = STRBUF_INIT;
- struct ref_filter filter;
+ struct for_each_ref_filter filter;
int ret;
if (!prefix && !starts_with(pattern, "refs/"))
@@ -581,7 +592,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
filter.prefix = prefix;
filter.fn = fn;
filter.cb_data = cb_data;
- ret = for_each_ref(filter_refs, &filter);
+ ret = for_each_ref(for_each_filter_refs, &filter);
strbuf_release(&real_pattern);
return ret;
@@ -1418,7 +1429,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
}
int parse_hide_refs_config(const char *var, const char *value, const char *section,
- struct string_list *hide_refs)
+ struct strvec *hide_refs)
{
const char *key;
if (!strcmp("transfer.hiderefs", var) ||
@@ -1429,22 +1440,23 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti
if (!value)
return config_error_nonbool(var);
- ref = xstrdup(value);
+
+ /* drop const to remove trailing '/' characters */
+ ref = (char *)strvec_push(hide_refs, value);
len = strlen(ref);
while (len && ref[len - 1] == '/')
ref[--len] = '\0';
- string_list_append_nodup(hide_refs, ref);
}
return 0;
}
int ref_is_hidden(const char *refname, const char *refname_full,
- const struct string_list *hide_refs)
+ const struct strvec *hide_refs)
{
int i;
for (i = hide_refs->nr - 1; i >= 0; i--) {
- const char *match = hide_refs->items[i].string;
+ const char *match = hide_refs->v[i];
const char *subject;
int neg = 0;
const char *p;
@@ -1517,7 +1529,9 @@ int head_ref(each_ref_fn fn, void *cb_data)
struct ref_iterator *refs_ref_iterator_begin(
struct ref_store *refs,
- const char *prefix, int trim,
+ const char *prefix,
+ const char **exclude_patterns,
+ int trim,
enum do_for_each_ref_flags flags)
{
struct ref_iterator *iter;
@@ -1533,8 +1547,7 @@ struct ref_iterator *refs_ref_iterator_begin(
}
}
- iter = refs->be->iterator_begin(refs, prefix, flags);
-
+ iter = refs->be->iterator_begin(refs, prefix, exclude_patterns, flags);
/*
* `iterator_begin()` already takes care of prefix, but we
* might need to do some trimming:
@@ -1568,7 +1581,7 @@ static int do_for_each_repo_ref(struct repository *r, const char *prefix,
if (!refs)
return 0;
- iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
+ iter = refs_ref_iterator_begin(refs, prefix, NULL, trim, flags);
return do_for_each_repo_ref_iterator(r, iter, fn, cb_data);
}
@@ -1590,6 +1603,7 @@ static int do_for_each_ref_helper(struct repository *r,
}
static int do_for_each_ref(struct ref_store *refs, const char *prefix,
+ const char **exclude_patterns,
each_ref_fn fn, int trim,
enum do_for_each_ref_flags flags, void *cb_data)
{
@@ -1599,7 +1613,8 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,
if (!refs)
return 0;
- iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
+ iter = refs_ref_iterator_begin(refs, prefix, exclude_patterns, trim,
+ flags);
return do_for_each_repo_ref_iterator(the_repository, iter,
do_for_each_ref_helper, &hp);
@@ -1607,7 +1622,7 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,
int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(refs, "", fn, 0, 0, cb_data);
+ return do_for_each_ref(refs, "", NULL, fn, 0, 0, cb_data);
}
int for_each_ref(each_ref_fn fn, void *cb_data)
@@ -1618,7 +1633,7 @@ int for_each_ref(each_ref_fn fn, void *cb_data)
int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,
each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(refs, prefix, fn, strlen(prefix), 0, cb_data);
+ return do_for_each_ref(refs, prefix, NULL, fn, strlen(prefix), 0, cb_data);
}
int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
@@ -1629,13 +1644,14 @@ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data)
{
return do_for_each_ref(get_main_ref_store(the_repository),
- prefix, fn, 0, 0, cb_data);
+ prefix, NULL, fn, 0, 0, cb_data);
}
int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
+ const char **exclude_patterns,
each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(refs, prefix, fn, 0, 0, cb_data);
+ return do_for_each_ref(refs, prefix, exclude_patterns, fn, 0, 0, cb_data);
}
int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
@@ -1646,20 +1662,21 @@ int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_dat
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
-int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
+int for_each_namespaced_ref(const char **exclude_patterns,
+ each_ref_fn fn, void *cb_data)
{
struct strbuf buf = STRBUF_INIT;
int ret;
strbuf_addf(&buf, "%srefs/", get_git_namespace());
ret = do_for_each_ref(get_main_ref_store(the_repository),
- buf.buf, fn, 0, 0, cb_data);
+ buf.buf, exclude_patterns, fn, 0, 0, cb_data);
strbuf_release(&buf);
return ret;
}
int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(refs, "", fn, 0,
+ return do_for_each_ref(refs, "", NULL, fn, 0,
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
@@ -1729,6 +1746,7 @@ static void find_longest_prefixes(struct string_list *out,
int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
const char *namespace,
const char **patterns,
+ const char **exclude_patterns,
each_ref_fn fn, void *cb_data)
{
struct string_list prefixes = STRING_LIST_INIT_DUP;
@@ -1744,7 +1762,8 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
for_each_string_list_item(prefix, &prefixes) {
strbuf_addstr(&buf, prefix->string);
- ret = refs_for_each_fullref_in(ref_store, buf.buf, fn, cb_data);
+ ret = refs_for_each_fullref_in(ref_store, buf.buf,
+ exclude_patterns, fn, cb_data);
if (ret)
break;
strbuf_setlen(&buf, namespace_len);
@@ -1821,7 +1840,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
return NULL;
/*
- * dwim_ref() uses REF_ISBROKEN to distinguish between
+ * repo_dwim_ref() uses REF_ISBROKEN to distinguish between
* missing refs and refs that were present but invalid,
* to complain about the latter to stderr.
*
@@ -2399,7 +2418,7 @@ int refs_verify_refname_available(struct ref_store *refs,
strbuf_addstr(&dirname, refname + dirname.len);
strbuf_addch(&dirname, '/');
- iter = refs_ref_iterator_begin(refs, dirname.buf, 0,
+ iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
DO_FOR_EACH_INCLUDE_BROKEN);
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
if (skip &&
diff --git a/refs.h b/refs.h
index 935cdd1ece..f23626beca 100644
--- a/refs.h
+++ b/refs.h
@@ -1,7 +1,6 @@
#ifndef REFS_H
#define REFS_H
-#include "cache.h"
#include "commit.h"
struct object_id;
@@ -159,12 +158,6 @@ int expand_ref(struct repository *r, const char *str, int len, struct object_id
int repo_dwim_ref(struct repository *r, const char *str, int len,
struct object_id *oid, char **ref, int nonfatal_dangling_mark);
int repo_dwim_log(struct repository *r, const char *str, int len, struct object_id *oid, char **ref);
-static inline int dwim_ref(const char *str, int len, struct object_id *oid,
- char **ref, int nonfatal_dangling_mark)
-{
- return repo_dwim_ref(the_repository, str, len, oid, ref,
- nonfatal_dangling_mark);
-}
int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
/*
@@ -345,6 +338,7 @@ int for_each_ref(each_ref_fn fn, void *cb_data);
int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
+ const char **exclude_patterns,
each_ref_fn fn, void *cb_data);
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data);
@@ -352,10 +346,15 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data);
* iterate all refs in "patterns" by partitioning patterns into disjoint sets
* and iterating the longest-common prefix of each set.
*
+ * references matching any pattern in "exclude_patterns" are omitted from the
+ * result set on a best-effort basis.
+ *
* callers should be prepared to ignore references that they did not ask for.
*/
int refs_for_each_fullref_in_prefixes(struct ref_store *refs,
- const char *namespace, const char **patterns,
+ const char *namespace,
+ const char **patterns,
+ const char **exclude_patterns,
each_ref_fn fn, void *cb_data);
/**
@@ -373,7 +372,8 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
const char *prefix, void *cb_data);
int head_ref_namespaced(each_ref_fn fn, void *cb_data);
-int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);
+int for_each_namespaced_ref(const char **exclude_patterns,
+ each_ref_fn fn, void *cb_data);
/* can be used to learn about broken ref and symref */
int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data);
@@ -811,7 +811,7 @@ int update_ref(const char *msg, const char *refname,
unsigned int flags, enum action_on_err onerr);
int parse_hide_refs_config(const char *var, const char *value, const char *,
- struct string_list *);
+ struct strvec *);
/*
* Check whether a ref is hidden. If no namespace is set, both the first and
@@ -821,7 +821,7 @@ int parse_hide_refs_config(const char *var, const char *value, const char *,
* the ref is outside that namespace, the first parameter is NULL. The second
* parameter always points to the full ref name.
*/
-int ref_is_hidden(const char *, const char *, const struct string_list *);
+int ref_is_hidden(const char *, const char *, const struct strvec *);
/* Is this a per-worktree ref living in the refs/ namespace? */
int is_per_worktree_ref(const char *refname);
diff --git a/refs/debug.c b/refs/debug.c
index eed8bc94b0..328f894177 100644
--- a/refs/debug.c
+++ b/refs/debug.c
@@ -1,5 +1,7 @@
-
+#include "git-compat-util.h"
+#include "hex.h"
#include "refs-internal.h"
+#include "string-list.h"
#include "trace.h"
static struct trace_key trace_refs = TRACE_KEY_INIT(REFS);
@@ -227,11 +229,12 @@ static struct ref_iterator_vtable debug_ref_iterator_vtable = {
static struct ref_iterator *
debug_ref_iterator_begin(struct ref_store *ref_store, const char *prefix,
- unsigned int flags)
+ const char **exclude_patterns, unsigned int flags)
{
struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
struct ref_iterator *res =
- drefs->refs->be->iterator_begin(drefs->refs, prefix, flags);
+ drefs->refs->be->iterator_begin(drefs->refs, prefix,
+ exclude_patterns, flags);
struct debug_ref_iterator *diter = xcalloc(1, sizeof(*diter));
base_ref_iterator_init(&diter->base, &debug_ref_iterator_vtable, 1);
diter->iter = res;
diff --git a/refs/files-backend.c b/refs/files-backend.c
index b89954355d..f0b4ac81ba 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1,16 +1,27 @@
-#include "../cache.h"
+#include "../git-compat-util.h"
#include "../config.h"
+#include "../copy.h"
+#include "../environment.h"
+#include "../gettext.h"
+#include "../hash.h"
+#include "../hex.h"
#include "../refs.h"
#include "refs-internal.h"
#include "ref-cache.h"
#include "packed-backend.h"
+#include "../ident.h"
#include "../iterator.h"
#include "../dir-iterator.h"
#include "../lockfile.h"
#include "../object.h"
+#include "../object-file.h"
+#include "../path.h"
#include "../dir.h"
#include "../chdir-notify.h"
-#include "worktree.h"
+#include "../setup.h"
+#include "../worktree.h"
+#include "../wrapper.h"
+#include "../write-or-die.h"
/*
* This backend uses the following flags in `ref_update::flags` for
@@ -819,7 +830,8 @@ static struct ref_iterator_vtable files_ref_iterator_vtable = {
static struct ref_iterator *files_ref_iterator_begin(
struct ref_store *ref_store,
- const char *prefix, unsigned int flags)
+ const char *prefix, const char **exclude_patterns,
+ unsigned int flags)
{
struct files_ref_store *refs;
struct ref_iterator *loose_iter, *packed_iter, *overlay_iter;
@@ -864,7 +876,7 @@ static struct ref_iterator *files_ref_iterator_begin(
* the packed and loose references.
*/
packed_iter = refs_ref_iterator_begin(
- refs->packed_ref_store, prefix, 0,
+ refs->packed_ref_store, prefix, exclude_patterns, 0,
DO_FOR_EACH_INCLUDE_BROKEN);
overlay_iter = overlay_ref_iterator_begin(loose_iter, packed_iter);
diff --git a/refs/iterator.c b/refs/iterator.c
index c9fd0bcaf9..6b680f610e 100644
--- a/refs/iterator.c
+++ b/refs/iterator.c
@@ -3,7 +3,7 @@
* documentation about the design and use of reference iterators.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "refs.h"
#include "refs/refs-internal.h"
#include "iterator.h"
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 6f5a0709fb..af841840ea 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1,11 +1,19 @@
-#include "../cache.h"
+#include "../git-compat-util.h"
+#include "../alloc.h"
#include "../config.h"
+#include "../gettext.h"
+#include "../hash.h"
+#include "../hex.h"
#include "../refs.h"
#include "refs-internal.h"
#include "packed-backend.h"
#include "../iterator.h"
#include "../lockfile.h"
#include "../chdir-notify.h"
+#include "../statinfo.h"
+#include "../wrapper.h"
+#include "../write-or-die.h"
+#include "../trace2.h"
enum mmap_strategy {
/*
@@ -297,7 +305,8 @@ static int cmp_packed_ref_records(const void *v1, const void *v2)
* Compare a snapshot record at `rec` to the specified NUL-terminated
* refname.
*/
-static int cmp_record_to_refname(const char *rec, const char *refname)
+static int cmp_record_to_refname(const char *rec, const char *refname,
+ int start)
{
const char *r1 = rec + the_hash_algo->hexsz + 1;
const char *r2 = refname;
@@ -306,7 +315,7 @@ static int cmp_record_to_refname(const char *rec, const char *refname)
if (*r1 == '\n')
return *r2 ? -1 : 0;
if (!*r2)
- return 1;
+ return start ? 1 : -1;
if (*r1 != *r2)
return (unsigned char)*r1 < (unsigned char)*r2 ? -1 : +1;
r1++;
@@ -521,22 +530,9 @@ static int load_contents(struct snapshot *snapshot)
return 1;
}
-/*
- * Find the place in `snapshot->buf` where the start of the record for
- * `refname` starts. If `mustexist` is true and the reference doesn't
- * exist, then return NULL. If `mustexist` is false and the reference
- * doesn't exist, then return the point where that reference would be
- * inserted, or `snapshot->eof` (which might be NULL) if it would be
- * inserted at the end of the file. In the latter mode, `refname`
- * doesn't have to be a proper reference name; for example, one could
- * search for "refs/replace/" to find the start of any replace
- * references.
- *
- * The record is sought using a binary search, so `snapshot->buf` must
- * be sorted.
- */
-static const char *find_reference_location(struct snapshot *snapshot,
- const char *refname, int mustexist)
+static const char *find_reference_location_1(struct snapshot *snapshot,
+ const char *refname, int mustexist,
+ int start)
{
/*
* This is not *quite* a garden-variety binary search, because
@@ -566,7 +562,7 @@ static const char *find_reference_location(struct snapshot *snapshot,
mid = lo + (hi - lo) / 2;
rec = find_start_of_record(lo, mid);
- cmp = cmp_record_to_refname(rec, refname);
+ cmp = cmp_record_to_refname(rec, refname, start);
if (cmp < 0) {
lo = find_end_of_record(mid, hi);
} else if (cmp > 0) {
@@ -583,6 +579,41 @@ static const char *find_reference_location(struct snapshot *snapshot,
}
/*
+ * Find the place in `snapshot->buf` where the start of the record for
+ * `refname` starts. If `mustexist` is true and the reference doesn't
+ * exist, then return NULL. If `mustexist` is false and the reference
+ * doesn't exist, then return the point where that reference would be
+ * inserted, or `snapshot->eof` (which might be NULL) if it would be
+ * inserted at the end of the file. In the latter mode, `refname`
+ * doesn't have to be a proper reference name; for example, one could
+ * search for "refs/replace/" to find the start of any replace
+ * references.
+ *
+ * The record is sought using a binary search, so `snapshot->buf` must
+ * be sorted.
+ */
+static const char *find_reference_location(struct snapshot *snapshot,
+ const char *refname, int mustexist)
+{
+ return find_reference_location_1(snapshot, refname, mustexist, 1);
+}
+
+/*
+ * Find the place in `snapshot->buf` after the end of the record for
+ * `refname`. In other words, find the location of first thing *after*
+ * `refname`.
+ *
+ * Other semantics are identical to the ones in
+ * `find_reference_location()`.
+ */
+static const char *find_reference_location_end(struct snapshot *snapshot,
+ const char *refname,
+ int mustexist)
+{
+ return find_reference_location_1(snapshot, refname, mustexist, 0);
+}
+
+/*
* Create a newly-allocated `snapshot` of the `packed-refs` file in
* its current state and return it. The return value will already have
* its reference count incremented.
@@ -646,7 +677,7 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
snapshot->buf,
snapshot->eof - snapshot->buf);
- string_list_split_in_place(&traits, p, ' ', -1);
+ string_list_split_in_place(&traits, p, " ", -1);
if (unsorted_string_list_has_string(&traits, "fully-peeled"))
snapshot->peeled = PEELED_FULLY;
@@ -773,6 +804,13 @@ struct packed_ref_iterator {
/* The end of the part of the buffer that will be iterated over: */
const char *eof;
+ struct jump_list_entry {
+ const char *start;
+ const char *end;
+ } *jump;
+ size_t jump_nr, jump_alloc;
+ size_t jump_pos;
+
/* Scratch space for current values: */
struct object_id oid, peeled;
struct strbuf refname_buf;
@@ -790,14 +828,35 @@ struct packed_ref_iterator {
*/
static int next_record(struct packed_ref_iterator *iter)
{
- const char *p = iter->pos, *eol;
+ const char *p, *eol;
strbuf_reset(&iter->refname_buf);
+ /*
+ * If iter->pos is contained within a skipped region, jump past
+ * it.
+ *
+ * Note that each skipped region is considered at most once,
+ * since they are ordered based on their starting position.
+ */
+ while (iter->jump_pos < iter->jump_nr) {
+ struct jump_list_entry *curr = &iter->jump[iter->jump_pos];
+ if (iter->pos < curr->start)
+ break; /* not to the next jump yet */
+
+ iter->jump_pos++;
+ if (iter->pos < curr->end) {
+ iter->pos = curr->end;
+ trace2_counter_add(TRACE2_COUNTER_ID_PACKED_REFS_JUMPS, 1);
+ break;
+ }
+ }
+
if (iter->pos == iter->eof)
return ITER_DONE;
iter->base.flags = REF_ISPACKED;
+ p = iter->pos;
if (iter->eof - p < the_hash_algo->hexsz + 2 ||
parse_oid_hex(p, &iter->oid, &p) ||
@@ -905,6 +964,7 @@ static int packed_ref_iterator_abort(struct ref_iterator *ref_iterator)
int ok = ITER_DONE;
strbuf_release(&iter->refname_buf);
+ free(iter->jump);
release_snapshot(iter->snapshot);
base_ref_iterator_free(ref_iterator);
return ok;
@@ -916,9 +976,135 @@ static struct ref_iterator_vtable packed_ref_iterator_vtable = {
.abort = packed_ref_iterator_abort
};
+static int jump_list_entry_cmp(const void *va, const void *vb)
+{
+ const struct jump_list_entry *a = va;
+ const struct jump_list_entry *b = vb;
+
+ if (a->start < b->start)
+ return -1;
+ if (a->start > b->start)
+ return 1;
+ return 0;
+}
+
+static int has_glob_special(const char *str)
+{
+ const char *p;
+ for (p = str; *p; p++) {
+ if (is_glob_special(*p))
+ return 1;
+ }
+ return 0;
+}
+
+static const char *ptr_max(const char *x, const char *y)
+{
+ if (x > y)
+ return x;
+ return y;
+}
+
+static void populate_excluded_jump_list(struct packed_ref_iterator *iter,
+ struct snapshot *snapshot,
+ const char **excluded_patterns)
+{
+ size_t i, j;
+ const char **pattern;
+ struct jump_list_entry *last_disjoint;
+
+ if (!excluded_patterns)
+ return;
+
+ for (pattern = excluded_patterns; *pattern; pattern++) {
+ /*
+ * We also can't feed any excludes from hidden refs
+ * config sections, since later rules may override
+ * previous ones. For example, with rules "refs/foo" and
+ * "!refs/foo/bar", we should show "refs/foo/bar" (and
+ * everything underneath it), but the earlier exclusion
+ * would cause us to skip all of "refs/foo". We likewise
+ * don't implement the namespace stripping required for
+ * '^' rules.
+ *
+ * Both are possible to do, but complicated, so avoid
+ * populating the jump list at all if we see either of
+ * these patterns.
+ */
+ if (**pattern == '!' || **pattern == '^')
+ return;
+ }
+
+ for (pattern = excluded_patterns; *pattern; pattern++) {
+ struct jump_list_entry *e;
+
+ /*
+ * We can't feed any excludes with globs in them to the
+ * refs machinery. It only understands prefix matching.
+ * We likewise can't even feed the string leading up to
+ * the first meta-character, as something like "foo[a]"
+ * should not exclude "foobar" (but the prefix "foo"
+ * would match that and mark it for exclusion).
+ */
+ if (has_glob_special(*pattern))
+ continue;
+
+ ALLOC_GROW(iter->jump, iter->jump_nr + 1, iter->jump_alloc);
+
+ e = &iter->jump[iter->jump_nr++];
+ e->start = find_reference_location(snapshot, *pattern, 0);
+ e->end = find_reference_location_end(snapshot, *pattern, 0);
+ }
+
+ if (!iter->jump_nr) {
+ /*
+ * Every entry in exclude_patterns has a meta-character,
+ * nothing to do here.
+ */
+ return;
+ }
+
+ QSORT(iter->jump, iter->jump_nr, jump_list_entry_cmp);
+
+ /*
+ * As an optimization, merge adjacent entries in the jump list
+ * to jump forwards as far as possible when entering a skipped
+ * region.
+ *
+ * For example, if we have two skipped regions:
+ *
+ * [[A, B], [B, C]]
+ *
+ * we want to combine that into a single entry jumping from A to
+ * C.
+ */
+ last_disjoint = iter->jump;
+
+ for (i = 1, j = 1; i < iter->jump_nr; i++) {
+ struct jump_list_entry *ours = &iter->jump[i];
+
+ if (ours->start == ours->end) {
+ /* ignore empty regions (no matching entries) */
+ continue;
+ } else if (ours->start <= last_disjoint->end) {
+ /* overlapping regions extend the previous one */
+ last_disjoint->end = ptr_max(last_disjoint->end, ours->end);
+ } else {
+ /* otherwise, insert a new region */
+ iter->jump[j++] = *ours;
+ last_disjoint = ours;
+
+ }
+ }
+
+ iter->jump_nr = j;
+ iter->jump_pos = 0;
+}
+
static struct ref_iterator *packed_ref_iterator_begin(
struct ref_store *ref_store,
- const char *prefix, unsigned int flags)
+ const char *prefix, const char **exclude_patterns,
+ unsigned int flags)
{
struct packed_ref_store *refs;
struct snapshot *snapshot;
@@ -950,6 +1136,9 @@ static struct ref_iterator *packed_ref_iterator_begin(
ref_iterator = &iter->base;
base_ref_iterator_init(ref_iterator, &packed_ref_iterator_vtable, 1);
+ if (exclude_patterns)
+ populate_excluded_jump_list(iter, snapshot, exclude_patterns);
+
iter->snapshot = snapshot;
acquire_snapshot(snapshot);
@@ -1143,7 +1332,7 @@ static int write_with_updates(struct packed_ref_store *refs,
* list of refs is exhausted, set iter to NULL. When the list
* of updates is exhausted, leave i set to updates->nr.
*/
- iter = packed_ref_iterator_begin(&refs->base, "",
+ iter = packed_ref_iterator_begin(&refs->base, "", NULL,
DO_FOR_EACH_INCLUDE_BROKEN);
if ((ok = ref_iterator_advance(iter)) != ITER_OK)
iter = NULL;
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index 32afd8a40b..2294c4564f 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -1,5 +1,8 @@
-#include "../cache.h"
+#include "../git-compat-util.h"
+#include "../alloc.h"
+#include "../hash.h"
#include "../refs.h"
+#include "../repository.h"
#include "refs-internal.h"
#include "ref-cache.h"
#include "../iterator.h"
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index 850d9d3744..95c76e27c8 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -1,10 +1,11 @@
#ifndef REFS_REF_CACHE_H
#define REFS_REF_CACHE_H
-#include "cache.h"
+#include "hash-ll.h"
struct ref_dir;
struct ref_store;
+struct repository;
/*
* If this ref_cache is filled lazily, this function is used to load
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 69f93b0e2a..28a11b9d61 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -1,7 +1,6 @@
#ifndef REFS_REFS_INTERNAL_H
#define REFS_REFS_INTERNAL_H
-#include "cache.h"
#include "refs.h"
#include "iterator.h"
@@ -368,8 +367,8 @@ int is_empty_ref_iterator(struct ref_iterator *ref_iterator);
*/
struct ref_iterator *refs_ref_iterator_begin(
struct ref_store *refs,
- const char *prefix, int trim,
- enum do_for_each_ref_flags flags);
+ const char *prefix, const char **exclude_patterns,
+ int trim, enum do_for_each_ref_flags flags);
/*
* A callback function used to instruct merge_ref_iterator how to
@@ -571,7 +570,8 @@ typedef int copy_ref_fn(struct ref_store *ref_store,
*/
typedef struct ref_iterator *ref_iterator_begin_fn(
struct ref_store *ref_store,
- const char *prefix, unsigned int flags);
+ const char *prefix, const char **exclude_patterns,
+ unsigned int flags);
/* reflog functions */
diff --git a/refspec.c b/refspec.c
index 63e3112104..57f6c2aaf9 100644
--- a/refspec.c
+++ b/refspec.c
@@ -1,7 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "strvec.h"
#include "refs.h"
#include "refspec.h"
+#include "strbuf.h"
static struct refspec_item s_tag_refspec = {
.force = 0,
diff --git a/reftable/dump.c b/reftable/dump.c
index 155953d1b8..ce936b4e18 100644
--- a/reftable/dump.c
+++ b/reftable/dump.c
@@ -7,7 +7,7 @@ https://developers.google.com/open-source/licenses/bsd
*/
#include "git-compat-util.h"
-#include "hash.h"
+#include "hash-ll.h"
#include "reftable-blocksource.h"
#include "reftable-error.h"
diff --git a/reftable/error.c b/reftable/error.c
index 93941f2145..0d1766735e 100644
--- a/reftable/error.c
+++ b/reftable/error.c
@@ -6,6 +6,7 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#include "system.h"
#include "reftable-error.h"
#include <stdio.h>
diff --git a/reftable/publicbasics.c b/reftable/publicbasics.c
index 0ad7d5c0ff..bcb82530d6 100644
--- a/reftable/publicbasics.c
+++ b/reftable/publicbasics.c
@@ -6,10 +6,10 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#include "system.h"
#include "reftable-malloc.h"
#include "basics.h"
-#include "system.h"
static void *(*reftable_malloc_ptr)(size_t sz);
static void *(*reftable_realloc_ptr)(void *, size_t);
diff --git a/reftable/system.h b/reftable/system.h
index 18f9207dfe..6b74a81514 100644
--- a/reftable/system.h
+++ b/reftable/system.h
@@ -13,7 +13,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "git-compat-util.h"
#include "strbuf.h"
-#include "hash.h" /* hash ID, sizes.*/
+#include "hash-ll.h" /* hash ID, sizes.*/
#include "dir.h" /* remove_dir_recursively, for tests.*/
int hash_size(uint32_t id);
diff --git a/reftable/tree.c b/reftable/tree.c
index b8899e060a..a5bf880985 100644
--- a/reftable/tree.c
+++ b/reftable/tree.c
@@ -6,10 +6,10 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#include "system.h"
#include "tree.h"
#include "basics.h"
-#include "system.h"
struct tree_node *tree_search(void *key, struct tree_node **rootp,
int (*compare)(const void *, const void *),
diff --git a/reftable/tree_test.c b/reftable/tree_test.c
index cbff125588..ac3a045ad4 100644
--- a/reftable/tree_test.c
+++ b/reftable/tree_test.c
@@ -6,6 +6,7 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#include "system.h"
#include "tree.h"
#include "basics.h"
diff --git a/remote-curl.c b/remote-curl.c
index a76b6405eb..acf7b2bb40 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -1,5 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "remote.h"
#include "connect.h"
#include "strbuf.h"
@@ -14,9 +18,12 @@
#include "credential.h"
#include "oid-array.h"
#include "send-pack.h"
+#include "setup.h"
#include "protocol.h"
#include "quote.h"
+#include "trace2.h"
#include "transport.h"
+#include "write-or-die.h"
static struct remote *remote;
/* always ends with a trailing slash */
@@ -472,10 +479,11 @@ static struct discovery *discover_refs(const char *service, int for_push)
/*
* NEEDSWORK: If we are trying to use protocol v2 and we are planning
- * to perform a push, then fallback to v0 since the client doesn't know
- * how to push yet using v2.
+ * to perform any operation that doesn't involve upload-pack (i.e., a
+ * fetch, ls-remote, etc), then fallback to v0 since we don't know how
+ * to do anything else (like push or remote archive) via v2.
*/
- if (version == protocol_v2 && !strcmp("git-receive-pack", service))
+ if (version == protocol_v2 && strcmp("git-upload-pack", service))
version = protocol_v0;
/* Add the extra Git-Protocol header */
diff --git a/remote.c b/remote.c
index 60869beebe..6538b6037d 100644
--- a/remote.c
+++ b/remote.c
@@ -1,20 +1,29 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "remote.h"
#include "urlmatch.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
#include "dir.h"
#include "tag.h"
+#include "setup.h"
#include "string-list.h"
#include "strvec.h"
#include "commit-reach.h"
#include "advice.h"
#include "connect.h"
+#include "parse-options.h"
enum map_direction { FROM_SRC, FROM_DST };
@@ -1163,7 +1172,7 @@ static int try_explicit_object_name(const char *name,
return 0;
}
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
return -1;
if (match) {
@@ -1251,7 +1260,7 @@ static void show_push_unqualified_ref_name_error(const char *dst_value,
if (!advice_enabled(ADVICE_PUSH_UNQUALIFIED_REF_NAME))
return;
- if (get_oid(matched_src_name, &oid))
+ if (repo_get_oid(the_repository, matched_src_name, &oid))
BUG("'%s' is not a valid object, "
"match_explicit_lhs() should catch this!",
matched_src_name);
@@ -1759,7 +1768,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) {
if (starts_with(ref->name, "refs/tags/"))
reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
- else if (!has_object_file(&ref->old_oid))
+ else if (!repo_has_object_file(the_repository, &ref->old_oid))
reject_reason = REF_STATUS_REJECT_FETCH_FIRST;
else if (!lookup_commit_reference_gently(the_repository, &ref->old_oid, 1) ||
!lookup_commit_reference_gently(the_repository, &ref->new_oid, 1))
@@ -1808,8 +1817,9 @@ static void set_merge(struct remote_state *remote_state, struct branch *ret)
if (!remote_find_tracking(remote, ret->merge[i]) ||
strcmp(ret->remote_name, "."))
continue;
- if (dwim_ref(ret->merge_name[i], strlen(ret->merge_name[i]),
- &oid, &ref, 0) == 1)
+ if (repo_dwim_ref(the_repository, ret->merge_name[i],
+ strlen(ret->merge_name[i]), &oid, &ref,
+ 0) == 1)
ret->merge[i]->dst = ref;
else
ret->merge[i]->dst = xstrdup(ret->merge_name[i]);
@@ -2505,7 +2515,7 @@ static int parse_push_cas_option(struct push_cas_option *cas, const char *arg, i
entry->use_tracking = 1;
else if (!colon[1])
oidclr(&entry->expect);
- else if (get_oid(colon + 1, &entry->expect))
+ else if (repo_get_oid(the_repository, colon + 1, &entry->expect))
return error(_("cannot parse expected object name '%s'"),
colon + 1);
return 0;
@@ -2662,7 +2672,7 @@ static int is_reachable_in_reflog(const char *local, const struct ref *remote)
if (MERGE_BASES_BATCH_SIZE < size)
size = MERGE_BASES_BATCH_SIZE;
- if ((ret = in_merge_bases_many(commit, size, chunk)))
+ if ((ret = repo_in_merge_bases_many(the_repository, commit, size, chunk)))
break;
}
diff --git a/remote.h b/remote.h
index 1ebbe42792..929c7c676d 100644
--- a/remote.h
+++ b/remote.h
@@ -1,11 +1,11 @@
#ifndef REMOTE_H
#define REMOTE_H
-#include "cache.h"
-#include "parse-options.h"
+#include "hash-ll.h"
#include "hashmap.h"
#include "refspec.h"
+struct option;
struct transport_ls_refs_options;
/**
diff --git a/replace-object.c b/replace-object.c
index 320be2522d..ca4017635d 100644
--- a/replace-object.c
+++ b/replace-object.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
#include "oidmap.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "replace-object.h"
#include "refs.h"
#include "repository.h"
diff --git a/replace-object.h b/replace-object.h
index 3fbc32eb7b..a964db1670 100644
--- a/replace-object.h
+++ b/replace-object.h
@@ -3,7 +3,15 @@
#include "oidmap.h"
#include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+
+/*
+ * Do replace refs need to be checked this run? This variable is
+ * initialized to true unless --no-replace-object is used or
+ * $GIT_NO_REPLACE_OBJECTS is set, but is set to false by some
+ * commands that do not want replace references to be active.
+ */
+extern int read_replace_refs;
struct replace_object {
struct oidmap_entry original;
diff --git a/repo-settings.c b/repo-settings.c
index 3dbd3f0e2e..d220c5dd9f 100644
--- a/repo-settings.c
+++ b/repo-settings.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "repository.h"
#include "midx.h"
@@ -41,10 +41,8 @@ void prepare_repo_settings(struct repository *r)
repo_cfg_bool(r, "feature.experimental", &experimental, 0);
/* Defaults modified by feature.* */
- if (experimental) {
+ if (experimental)
r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING;
- r->settings.gc_cruft_packs = 1;
- }
if (manyfiles) {
r->settings.index_version = 4;
r->settings.index_skip_hash = 1;
@@ -63,6 +61,7 @@ void prepare_repo_settings(struct repository *r)
repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1);
repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
repo_cfg_bool(r, "index.skiphash", &r->settings.index_skip_hash, r->settings.index_skip_hash);
+ repo_cfg_bool(r, "pack.readreverseindex", &r->settings.pack_read_reverse_index, 1);
/*
* The GIT_TEST_MULTI_PACK_INDEX variable is special in that
diff --git a/repository.c b/repository.c
index 937fa974b3..8c77b7ed23 100644
--- a/repository.c
+++ b/repository.c
@@ -3,15 +3,20 @@
* declaration matches the definition in this file.
*/
#define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "config.h"
#include "object.h"
#include "lockfile.h"
+#include "path.h"
+#include "read-cache-ll.h"
#include "remote.h"
+#include "setup.h"
#include "submodule-config.h"
#include "sparse-index.h"
+#include "trace2.h"
#include "promisor-remote.h"
/* The main repository */
diff --git a/repository.h b/repository.h
index e8c67ffe16..510aa6d9a2 100644
--- a/repository.h
+++ b/repository.h
@@ -1,9 +1,6 @@
#ifndef REPOSITORY_H
#define REPOSITORY_H
-#include "git-compat-util.h"
-#include "path.h"
-
struct config_set;
struct fsmonitor_settings;
struct git_hash_algo;
@@ -34,10 +31,10 @@ struct repo_settings {
int commit_graph_generation_version;
int commit_graph_read_changed_paths;
int gc_write_commit_graph;
- int gc_cruft_packs;
int fetch_write_commit_graph;
int command_requires_full_index;
int sparse_index;
+ int pack_read_reverse_index;
struct fsmonitor_settings *fsmonitor; /* lazily loaded */
@@ -170,6 +167,9 @@ struct repository {
};
extern struct repository *the_repository;
+#ifdef USE_THE_INDEX_VARIABLE
+extern struct index_state the_index;
+#endif
/*
* Define a custom repository layout. Any field can be NULL, which
@@ -221,9 +221,6 @@ int repo_hold_locked_index(struct repository *repo,
struct lock_file *lf,
int flags);
-int repo_read_index_preload(struct repository *,
- const struct pathspec *pathspec,
- unsigned refresh_flags);
int repo_read_index_unmerged(struct repository *);
/*
* Opportunistically update the index but do not complain if we can't.
diff --git a/rerere.c b/rerere.c
index 876ab435da..e2b8597f88 100644
--- a/rerere.c
+++ b/rerere.c
@@ -1,17 +1,26 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
#include "config.h"
+#include "copy.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "string-list.h"
+#include "read-cache-ll.h"
#include "rerere.h"
#include "xdiff-interface.h"
#include "dir.h"
#include "resolve-undo.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
#include "attr.h"
+#include "path.h"
#include "pathspec.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "hash-lookup.h"
#include "strmap.h"
+#include "wrapper.h"
#define RESOLVED 0
#define PUNTED 1
@@ -965,8 +974,9 @@ static int handle_cache(struct index_state *istate,
break;
i = ce_stage(ce) - 1;
if (!mmfile[i].ptr) {
- mmfile[i].ptr = read_object_file(&ce->oid, &type,
- &size);
+ mmfile[i].ptr = repo_read_object_file(the_repository,
+ &ce->oid, &type,
+ &size);
mmfile[i].size = size;
}
}
diff --git a/rerere.h b/rerere.h
index c32d79c3bd..5d6cb63879 100644
--- a/rerere.h
+++ b/rerere.h
@@ -1,6 +1,7 @@
#ifndef RERERE_H
#define RERERE_H
+#include "gettext.h"
#include "string-list.h"
struct pathspec;
@@ -24,9 +25,6 @@ struct rerere_id {
};
int setup_rerere(struct repository *,struct string_list *, int);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define rerere(flags) repo_rerere(the_repository, flags)
-#endif
int repo_rerere(struct repository *, int);
/*
* Given the conflict ID and the name of a "file" used for replaying
diff --git a/reset.c b/reset.c
index 5ded23611f..48da0adf85 100644
--- a/reset.c
+++ b/reset.c
@@ -1,6 +1,9 @@
#include "git-compat-util.h"
#include "cache-tree.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
+#include "object-name.h"
#include "refs.h"
#include "reset.h"
#include "run-command.h"
@@ -38,7 +41,7 @@ static int update_refs(const struct reset_head_opts *opts,
prefix_len = msg.len;
if (update_orig_head) {
- if (!get_oid("ORIG_HEAD", &oid_old_orig))
+ if (!repo_get_oid(the_repository, "ORIG_HEAD", &oid_old_orig))
old_orig = &oid_old_orig;
if (head) {
if (!reflog_orig_head) {
@@ -106,7 +109,7 @@ int reset_head(struct repository *r, const struct reset_head_opts *opts)
goto leave_reset_head;
}
- if (!get_oid("HEAD", &head_oid)) {
+ if (!repo_get_oid(r, "HEAD", &head_oid)) {
head = &head_oid;
} else if (!oid || !reset_hard) {
ret = error(_("could not determine HEAD revision"));
diff --git a/reset.h b/reset.h
index a28f81829d..10708d8ddc 100644
--- a/reset.h
+++ b/reset.h
@@ -1,7 +1,7 @@
#ifndef RESET_H
#define RESET_H
-#include "hash.h"
+#include "hash-ll.h"
#include "repository.h"
#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
diff --git a/resolve-undo.c b/resolve-undo.c
index e81096e2d4..7817f5d6db 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -1,6 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "dir.h"
+#include "hash.h"
+#include "read-cache.h"
#include "resolve-undo.h"
+#include "sparse-index.h"
#include "string-list.h"
/* The only error case is to run out of memory in string-list */
diff --git a/resolve-undo.h b/resolve-undo.h
index 2b3f0f901e..c5deafc92f 100644
--- a/resolve-undo.h
+++ b/resolve-undo.h
@@ -1,7 +1,12 @@
#ifndef RESOLVE_UNDO_H
#define RESOLVE_UNDO_H
-#include "cache.h"
+struct cache_entry;
+struct index_state;
+struct pathspec;
+struct string_list;
+
+#include "hash-ll.h"
struct resolve_undo_info {
unsigned int mode[3];
diff --git a/revision.c b/revision.c
index 21f5f572c2..c53e9f84ae 100644
--- a/revision.c
+++ b/revision.c
@@ -1,6 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
-#include "object-store.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "tag.h"
#include "blob.h"
#include "tree.h"
@@ -25,7 +31,11 @@
#include "bisect.h"
#include "packfile.h"
#include "worktree.h"
+#include "read-cache.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "strvec.h"
+#include "trace2.h"
#include "commit-reach.h"
#include "commit-graph.h"
#include "prio-queue.h"
@@ -35,6 +45,8 @@
#include "json-writer.h"
#include "list-objects-filter-options.h"
#include "resolve-undo.h"
+#include "parse-options.h"
+#include "wildmatch.h"
volatile show_early_output_fn_t show_early_output;
@@ -324,7 +336,8 @@ static void add_pending_object_with_path(struct rev_info *revs,
if (revs->reflog_info && obj->type == OBJ_COMMIT) {
struct strbuf buf = STRBUF_INIT;
size_t namelen = strlen(name);
- int len = interpret_branch_name(name, namelen, &buf, &options);
+ int len = repo_interpret_branch_name(the_repository, name,
+ namelen, &buf, &options);
if (0 < len && len < namelen && buf.len)
strbuf_addstr(&buf, name + len);
@@ -354,7 +367,7 @@ void add_head_to_pending(struct rev_info *revs)
{
struct object_id oid;
struct object *obj;
- if (get_oid("HEAD", &oid))
+ if (repo_get_oid(the_repository, "HEAD", &oid))
return;
obj = parse_object(revs->repo, &oid);
if (!obj)
@@ -777,8 +790,8 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs,
static int rev_compare_tree(struct rev_info *revs,
struct commit *parent, struct commit *commit, int nth_parent)
{
- struct tree *t1 = get_commit_tree(parent);
- struct tree *t2 = get_commit_tree(commit);
+ struct tree *t1 = repo_get_commit_tree(the_repository, parent);
+ struct tree *t2 = repo_get_commit_tree(the_repository, commit);
int bloom_ret = 1;
if (!t1)
@@ -824,7 +837,7 @@ static int rev_compare_tree(struct rev_info *revs,
static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
{
- struct tree *t1 = get_commit_tree(commit);
+ struct tree *t1 = repo_get_commit_tree(the_repository, commit);
if (!t1)
return 0;
@@ -962,7 +975,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
if (!revs->prune)
return;
- if (!get_commit_tree(commit))
+ if (!repo_get_commit_tree(the_repository, commit))
return;
if (!commit->parents) {
@@ -1548,7 +1561,7 @@ void init_ref_exclusions(struct ref_exclusions *exclusions)
void clear_ref_exclusions(struct ref_exclusions *exclusions)
{
string_list_clear(&exclusions->excluded_refs, 0);
- string_list_clear(&exclusions->hidden_refs, 0);
+ strvec_clear(&exclusions->hidden_refs);
exclusions->hidden_refs_configured = 0;
}
@@ -1574,7 +1587,8 @@ void exclude_hidden_refs(struct ref_exclusions *exclusions, const char *section)
{
struct exclude_hidden_refs_cb cb;
- if (strcmp(section, "receive") && strcmp(section, "uploadpack"))
+ if (strcmp(section, "fetch") && strcmp(section, "receive") &&
+ strcmp(section, "uploadpack"))
die(_("unsupported section for hidden refs: %s"), section);
if (exclusions->hidden_refs_configured)
@@ -1867,7 +1881,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
flags ^= UNINTERESTING | BOTTOM;
arg++;
}
- if (get_oid_committish(arg, &oid))
+ if (repo_get_oid_committish(the_repository, arg, &oid))
return 0;
while (1) {
it = get_reference(revs, arg, &oid, 0);
@@ -1948,15 +1962,15 @@ static void prepare_show_merge(struct rev_info *revs)
int i, prune_num = 1; /* counting terminating NULL */
struct index_state *istate = revs->repo->index;
- if (get_oid("HEAD", &oid))
+ if (repo_get_oid(the_repository, "HEAD", &oid))
die("--merge without HEAD?");
head = lookup_commit_or_die(&oid, "HEAD");
- if (get_oid("MERGE_HEAD", &oid))
+ if (repo_get_oid(the_repository, "MERGE_HEAD", &oid))
die("--merge without MERGE_HEAD?");
other = lookup_commit_or_die(&oid, "MERGE_HEAD");
add_pending_object(revs, &head->object, "HEAD");
add_pending_object(revs, &other->object, "MERGE_HEAD");
- bases = get_merge_bases(head, other);
+ bases = repo_get_merge_bases(the_repository, head, other);
add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
free_commit_list(bases);
@@ -2051,7 +2065,7 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
if (!a || !b)
return dotdot_missing(arg, dotdot, revs, symmetric);
- exclude = get_merge_bases(a, b);
+ exclude = repo_get_merge_bases(the_repository, a, b);
add_rev_cmdline_list(revs, exclude, REV_CMD_MERGE_BASE,
flags_exclude);
add_pending_commit_list(revs, exclude, flags_exclude);
@@ -2659,7 +2673,7 @@ static int for_each_bisect_ref(struct ref_store *refs, each_ref_fn fn,
struct strbuf bisect_refs = STRBUF_INIT;
int status;
strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
- status = refs_for_each_fullref_in(refs, bisect_refs.buf, fn, cb_data);
+ status = refs_for_each_fullref_in(refs, bisect_refs.buf, NULL, fn, cb_data);
strbuf_release(&bisect_refs);
return status;
}
@@ -3440,8 +3454,8 @@ void reset_revision_walk(void)
}
static int mark_uninteresting(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED,
void *cb)
{
struct rev_info *revs = cb;
@@ -3877,7 +3891,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
* in it.
*/
encoding = get_log_output_encoding();
- message = logmsg_reencode(commit, NULL, encoding);
+ message = repo_logmsg_reencode(the_repository, commit, NULL, encoding);
/* Copy the commit to temporary if we are using "fake" headers */
if (buf.len)
@@ -3913,7 +3927,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
retval = grep_buffer(&opt->grep_filter,
(char *)message, strlen(message));
strbuf_release(&buf);
- unuse_commit_buffer(commit, message);
+ repo_unuse_commit_buffer(the_repository, commit, message);
return retval;
}
@@ -4159,7 +4173,7 @@ static struct commit *get_revision_1(struct rev_info *revs)
* Return true for entries that have not yet been shown. (This is an
* object_array_each_func_t.)
*/
-static int entry_unshown(struct object_array_entry *entry, void *cb_data_unused)
+static int entry_unshown(struct object_array_entry *entry, void *cb_data UNUSED)
{
return !(entry->item->flags & SHOWN);
}
diff --git a/revision.h b/revision.h
index 30febad09a..94f035fa22 100644
--- a/revision.h
+++ b/revision.h
@@ -2,13 +2,15 @@
#define REVISION_H
#include "commit.h"
-#include "parse-options.h"
#include "grep.h"
#include "notes.h"
#include "pretty.h"
#include "diff.h"
#include "commit-slab-decl.h"
+#include "decorate.h"
+#include "ident.h"
#include "list-objects-filter-options.h"
+#include "strvec.h"
/**
* The revision walking API offers functions to build a list of revisions
@@ -61,6 +63,8 @@ struct string_list;
struct saved_parents;
struct bloom_key;
struct bloom_filter_settings;
+struct option;
+struct parse_opt_ctx_t;
define_shared_commit_slab(revision_sources, char *);
struct rev_cmdline_info {
@@ -92,7 +96,7 @@ struct ref_exclusions {
* Hidden refs is a list of patterns that is to be hidden via
* `ref_is_hidden()`.
*/
- struct string_list hidden_refs;
+ struct strvec hidden_refs;
/*
* Indicates whether hidden refs have been configured. This is to
@@ -107,7 +111,7 @@ struct ref_exclusions {
*/
#define REF_EXCLUSIONS_INIT { \
.excluded_refs = STRING_LIST_INIT_DUP, \
- .hidden_refs = STRING_LIST_INIT_DUP, \
+ .hidden_refs = STRVEC_INIT, \
}
struct oidset;
@@ -415,9 +419,6 @@ struct rev_info {
void repo_init_revisions(struct repository *r,
struct rev_info *revs,
const char *prefix);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define init_revisions(revs, prefix) repo_init_revisions(the_repository, revs, prefix)
-#endif
/**
* Parse revision information, filling in the `rev_info` structure, and
diff --git a/run-command.c b/run-command.c
index 6bd16acb06..3e8b268ca2 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1,16 +1,22 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "run-command.h"
+#include "environment.h"
#include "exec-cmd.h"
+#include "gettext.h"
#include "sigchain.h"
#include "strvec.h"
+#include "symlinks.h"
#include "thread-utils.h"
#include "strbuf.h"
#include "string-list.h"
+#include "trace.h"
+#include "trace2.h"
#include "quote.h"
#include "config.h"
#include "packfile.h"
#include "hook.h"
#include "compat/nonblock.h"
+#include "alloc.h"
void child_process_init(struct child_process *child)
{
@@ -341,19 +347,19 @@ static void child_close_pair(int fd[2])
child_close(fd[1]);
}
-static void child_error_fn(const char *err, va_list params)
+static void child_error_fn(const char *err UNUSED, va_list params UNUSED)
{
const char msg[] = "error() should not be called in child\n";
xwrite(2, msg, sizeof(msg) - 1);
}
-static void child_warn_fn(const char *err, va_list params)
+static void child_warn_fn(const char *err UNUSED, va_list params UNUSED)
{
const char msg[] = "warn() should not be called in child\n";
xwrite(2, msg, sizeof(msg) - 1);
}
-static void NORETURN child_die_fn(const char *err, va_list params)
+static void NORETURN child_die_fn(const char *err UNUSED, va_list params UNUSED)
{
const char msg[] = "die() should not be called in child\n";
xwrite(2, msg, sizeof(msg) - 1);
@@ -1526,6 +1532,11 @@ static void pp_init(struct parallel_processes *pp,
if (!opts->get_next_task)
BUG("you need to specify a get_next_task function");
+ if (opts->ungroup) {
+ if (opts->on_stderr_output)
+ BUG("on_stderr_output and ungroup are incompatible with each other");
+ }
+
CALLOC_ARRAY(pp->children, n);
if (!opts->ungroup)
CALLOC_ARRAY(pp->pfd, n);
@@ -1650,14 +1661,19 @@ static void pp_buffer_stderr(struct parallel_processes *pp,
for (size_t i = 0; i < opts->processes; i++) {
if (pp->children[i].state == GIT_CP_WORKING &&
pp->pfd[i].revents & (POLLIN | POLLHUP)) {
- int n = strbuf_read_once(&pp->children[i].err,
- pp->children[i].process.err, 0);
+ ssize_t n = strbuf_read_once(&pp->children[i].err,
+ pp->children[i].process.err, 0);
if (n == 0) {
close(pp->children[i].process.err);
pp->children[i].state = GIT_CP_WAIT_CLEANUP;
- } else if (n < 0)
+ } else if (n < 0) {
if (errno != EAGAIN)
die_errno("read");
+ } else if (opts->on_stderr_output) {
+ opts->on_stderr_output(&pp->children[i].err,
+ pp->children[i].err.len - n,
+ opts->data, pp->children[i].data);
+ }
}
}
}
diff --git a/run-command.h b/run-command.h
index 072db56a4d..fc3e6a2287 100644
--- a/run-command.h
+++ b/run-command.h
@@ -409,6 +409,25 @@ typedef int (*start_failure_fn)(struct strbuf *out,
void *pp_task_cb);
/**
+ * This callback is called whenever output from a child process is buffered
+ *
+ * See run_processes_parallel() below for a discussion of the "struct
+ * strbuf *out" parameter.
+ *
+ * The offset refers to the number of bytes originally in "out" before
+ * the output from the child process was buffered. Therefore, the buffer
+ * range, "out + buf" to the end of "out", would contain the buffer of
+ * the child process output.
+ *
+ * pp_cb is the callback cookie as passed into run_processes_parallel,
+ * pp_task_cb is the callback cookie as passed into get_next_task_fn.
+ *
+ * This function is incompatible with "ungroup"
+ */
+typedef void (*on_stderr_output_fn)(struct strbuf *out, size_t offset,
+ void *pp_cb, void *pp_task_cb);
+
+/**
* This callback is called on every child process that finished processing.
*
* See run_processes_parallel() below for a discussion of the "struct
@@ -462,6 +481,12 @@ struct run_process_parallel_opts
start_failure_fn start_failure;
/**
+ * on_stderr_output: See on_stderr_output_fn() above. Unless you need
+ * to capture output from child processes, leave this as NULL.
+ */
+ on_stderr_output_fn on_stderr_output;
+
+ /**
* task_finished: See task_finished_fn() above. This can be
* NULL to omit any special handling.
*/
@@ -503,7 +528,7 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts);
* exception of GIT_CONFIG_PARAMETERS and GIT_CONFIG_COUNT (which cause the
* corresponding environment variables to be unset in the subprocess) and adds
* an environment variable pointing to new_git_dir. See local_repo_env in
- * cache.h for more information.
+ * environment.h for more information.
*/
void prepare_other_repo_env(struct strvec *env, const char *new_git_dir);
@@ -564,4 +589,6 @@ enum start_bg_result start_bg_command(struct child_process *cmd,
void *cb_data,
unsigned int timeout_sec);
+int sane_execvp(const char *file, char *const argv[]);
+
#endif
diff --git a/scalar.c b/scalar.c
index ca19b95ce4..1326e1f608 100644
--- a/scalar.c
+++ b/scalar.c
@@ -2,7 +2,8 @@
* The Scalar command-line interface.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "gettext.h"
#include "parse-options.h"
#include "config.h"
@@ -14,6 +15,8 @@
#include "dir.h"
#include "packfile.h"
#include "help.h"
+#include "setup.h"
+#include "trace2.h"
static void setup_enlistment_directory(int argc, const char **argv,
const char * const *usagestr,
@@ -563,7 +566,7 @@ static int cmd_diagnose(int argc, const char **argv)
return res;
}
-static int cmd_list(int argc, const char **argv)
+static int cmd_list(int argc, const char **argv UNUSED)
{
if (argc != 1)
die(_("`scalar list` does not take arguments"));
diff --git a/send-pack.c b/send-pack.c
index f2e19838c9..9510bef856 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -1,8 +1,11 @@
-#include "builtin.h"
+#include "git-compat-util.h"
#include "config.h"
#include "commit.h"
+#include "date.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "pkt-line.h"
#include "sideband.h"
#include "run-command.h"
@@ -12,10 +15,13 @@
#include "quote.h"
#include "transport.h"
#include "version.h"
+#include "wrapper.h"
#include "oid-array.h"
#include "gpg-interface.h"
-#include "cache.h"
#include "shallow.h"
+#include "parse-options.h"
+#include "trace2.h"
+#include "write-or-die.h"
int option_parse_push_signed(const struct option *opt,
const char *arg, int unset)
@@ -42,9 +48,9 @@ int option_parse_push_signed(const struct option *opt,
static void feed_object(const struct object_id *oid, FILE *fh, int negative)
{
if (negative &&
- !has_object_file_with_flags(oid,
- OBJECT_INFO_SKIP_FETCH_OBJECT |
- OBJECT_INFO_QUICK))
+ !repo_has_object_file_with_flags(the_repository, oid,
+ OBJECT_INFO_SKIP_FETCH_OBJECT |
+ OBJECT_INFO_QUICK))
return;
if (negative)
@@ -534,7 +540,7 @@ int send_pack(struct send_pack_args *args,
die(_("the receiving end does not support this repository's hash algorithm"));
if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {
- int len;
+ size_t len;
push_cert_nonce = server_feature_value("push-cert", &len);
if (push_cert_nonce) {
reject_invalid_nonce(push_cert_nonce, len);
diff --git a/sequencer.c b/sequencer.c
index 1c96a75b1e..83d53a7bf6 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1,9 +1,19 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "advice.h"
+#include "alloc.h"
#include "config.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "dir.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "object.h"
+#include "pager.h"
#include "commit.h"
#include "sequencer.h"
#include "tag.h"
@@ -13,11 +23,14 @@
#include "utf8.h"
#include "cache-tree.h"
#include "diff.h"
+#include "path.h"
#include "revision.h"
#include "rerere.h"
+#include "merge.h"
#include "merge-ort.h"
#include "merge-ort-wrappers.h"
#include "refs.h"
+#include "sparse-index.h"
#include "strvec.h"
#include "quote.h"
#include "trailer.h"
@@ -36,6 +49,7 @@
#include "rebase-interactive.h"
#include "reset.h"
#include "branch.h"
+#include "wrapper.h"
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
@@ -127,6 +141,11 @@ static GIT_PATH_FUNC(rebase_path_amend, "rebase-merge/amend")
*/
static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
/*
+ * When we stop for the user to resolve conflicts this file contains
+ * the patch of the commit that is being picked.
+ */
+static GIT_PATH_FUNC(rebase_path_patch, "rebase-merge/patch")
+/*
* For the post-rewrite hook, we make a list of rewritten commits and
* their new sha1s. The rewritten-pending list keeps the sha1s of
* commits that have been processed, but not committed yet,
@@ -263,10 +282,6 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
if (opts->action == REPLAY_REVERT && !strcmp(k, "revert.reference"))
opts->commit_use_reference = git_config_bool(k, v);
- status = git_gpg_config(k, v, NULL);
- if (status)
- return status;
-
return git_diff_basic_config(k, v, NULL);
}
@@ -357,9 +372,7 @@ void replay_opts_release(struct replay_opts *opts)
free(opts->reflog_action);
free(opts->default_strategy);
free(opts->strategy);
- for (size_t i = 0; i < opts->xopts_nr; i++)
- free(opts->xopts[i]);
- free(opts->xopts);
+ strvec_clear (&opts->xopts);
strbuf_release(&opts->current_fixups);
if (opts->revs)
release_revisions(opts->revs);
@@ -419,7 +432,8 @@ struct commit_message {
static const char *short_commit_name(struct commit *commit)
{
- return find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV);
+ return repo_find_unique_abbrev(the_repository, &commit->object.oid,
+ DEFAULT_ABBREV);
}
static int get_message(struct commit *commit, struct commit_message *out)
@@ -427,7 +441,8 @@ static int get_message(struct commit *commit, struct commit_message *out)
const char *abbrev, *subject;
int subject_len;
- out->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());
+ out->message = repo_logmsg_reencode(the_repository, commit, NULL,
+ get_commit_output_encoding());
abbrev = short_commit_name(commit);
subject_len = find_commit_subject(out->message, &subject);
@@ -444,7 +459,7 @@ static void free_message(struct commit *commit, struct commit_message *msg)
free(msg->parent_label);
free(msg->label);
free(msg->subject);
- unuse_commit_buffer(commit, msg->message);
+ repo_unuse_commit_buffer(the_repository, commit, msg->message);
}
static void print_advice(struct repository *r, int show_hint,
@@ -561,7 +576,7 @@ static void update_abort_safety_file(void)
if (!file_exists(git_path_seq_dir()))
return;
- if (!get_oid("HEAD", &head))
+ if (!repo_get_oid(the_repository, "HEAD", &head))
write_file(git_path_abort_safety_file(), "%s", oid_to_hex(&head));
else
write_file(git_path_abort_safety_file(), "%s", "");
@@ -653,11 +668,12 @@ void append_conflicts_hint(struct index_state *istate,
}
strbuf_addch(msgbuf, '\n');
- strbuf_commented_addf(msgbuf, "Conflicts:\n");
+ strbuf_commented_addf(msgbuf, comment_line_char, "Conflicts:\n");
for (i = 0; i < istate->cache_nr;) {
const struct cache_entry *ce = istate->cache[i++];
if (ce_stage(ce)) {
- strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
+ strbuf_commented_addf(msgbuf, comment_line_char,
+ "\t%s\n", ce->name);
while (i < istate->cache_nr &&
!strcmp(ce->name, istate->cache[i]->name))
i++;
@@ -692,11 +708,11 @@ static int do_recursive_merge(struct repository *r,
o.show_rename_progress = 1;
head_tree = parse_tree_indirect(head);
- next_tree = next ? get_commit_tree(next) : empty_tree(r);
- base_tree = base ? get_commit_tree(base) : empty_tree(r);
+ next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r);
+ base_tree = base ? repo_get_commit_tree(r, base) : empty_tree(r);
- for (i = 0; i < opts->xopts_nr; i++)
- parse_merge_opt(&o, opts->xopts[i]);
+ for (i = 0; i < opts->xopts.nr; i++)
+ parse_merge_opt(&o, opts->xopts.v[i]);
if (!opts->strategy || !strcmp(opts->strategy, "ort")) {
memset(&result, 0, sizeof(result));
@@ -766,12 +782,12 @@ static int is_index_unchanged(struct repository *r)
/*
* If head_commit is NULL, check_commit, called from
* lookup_commit, would have indicated that head_commit is not
- * a commit object already. parse_commit() will return failure
+ * a commit object already. repo_parse_commit() will return failure
* without further complaints in such a case. Otherwise, if
- * the commit is invalid, parse_commit() will complain. So
+ * the commit is invalid, repo_parse_commit() will complain. So
* there is nothing for us to say here. Just return failure.
*/
- if (parse_commit(head_commit))
+ if (repo_parse_commit(r, head_commit))
return -1;
if (!(cache_tree_oid = get_cache_tree_oid(istate)))
@@ -1048,7 +1064,7 @@ static int run_git_commit(const char *defmsg,
if (is_rebase_i(opts) &&
((opts->committer_date_is_author_date && !opts->ignore_date) ||
- !(!defmsg && (flags & AMEND_MSG))) &&
+ !(flags & AMEND_MSG)) &&
read_env_script(&cmd.env)) {
const char *gpg_opt = gpg_sign_opt_quoted(opts);
@@ -1136,7 +1152,8 @@ void cleanup_message(struct strbuf *msgbuf,
cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
- strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+ strbuf_stripspace(msgbuf,
+ cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
}
/*
@@ -1167,7 +1184,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,
if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
return 0;
- strbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+ strbuf_stripspace(&tmpl,
+ cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
if (!skip_prefix(sb->buf, tmpl.buf, &start))
start = sb->buf;
strbuf_release(&tmpl);
@@ -1336,13 +1354,15 @@ void print_commit_summary(struct repository *r,
commit = lookup_commit(r, oid);
if (!commit)
die(_("couldn't look up newly created commit"));
- if (parse_commit(commit))
+ if (repo_parse_commit(r, commit))
die(_("could not parse newly created commit"));
strbuf_addstr(&format, "format:%h] %s");
- format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
- format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
+ repo_format_commit_message(r, commit, "%an <%ae>", &author_ident,
+ &pctx);
+ repo_format_commit_message(r, commit, "%cn <%ce>", &committer_ident,
+ &pctx);
if (strbuf_cmp(&author_ident, &committer_ident)) {
strbuf_addstr(&format, "\n Author: ");
strbuf_addbuf_percentquote(&format, &author_ident);
@@ -1350,7 +1370,7 @@ void print_commit_summary(struct repository *r,
if (flags & SUMMARY_SHOW_AUTHOR_DATE) {
struct strbuf date = STRBUF_INIT;
- format_commit_message(commit, "%ad", &date, &pctx);
+ repo_format_commit_message(r, commit, "%ad", &date, &pctx);
strbuf_addstr(&format, "\n Date: ");
strbuf_addbuf_percentquote(&format, &date);
strbuf_release(&date);
@@ -1380,7 +1400,7 @@ void print_commit_summary(struct repository *r,
rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
diff_setup_done(&rev.diffopt);
- refs = get_main_ref_store(the_repository);
+ refs = get_main_ref_store(r);
head = refs_resolve_ref_unsafe(refs, "HEAD", 0, NULL, NULL);
if (!head)
die(_("unable to resolve HEAD after creating commit"));
@@ -1406,7 +1426,7 @@ static int parse_head(struct repository *r, struct commit **head)
struct commit *current_head;
struct object_id oid;
- if (get_oid("HEAD", &oid)) {
+ if (repo_get_oid(r, "HEAD", &oid)) {
current_head = NULL;
} else {
current_head = lookup_commit_reference(r, &oid);
@@ -1416,7 +1436,7 @@ static int parse_head(struct repository *r, struct commit **head)
warning(_("HEAD %s is not a commit!"),
oid_to_hex(&oid));
}
- if (parse_commit(current_head))
+ if (repo_parse_commit(r, current_head))
return error(_("could not parse HEAD commit"));
}
*head = current_head;
@@ -1459,8 +1479,8 @@ static int try_to_commit(struct repository *r,
if (flags & AMEND_MSG) {
const char *exclude_gpgsig[] = { "gpgsig", "gpgsig-sha256", NULL };
const char *out_enc = get_commit_output_encoding();
- const char *message = logmsg_reencode(current_head, NULL,
- out_enc);
+ const char *message = repo_logmsg_reencode(r, current_head,
+ NULL, out_enc);
if (!msg) {
const char *orig_message = NULL;
@@ -1471,7 +1491,8 @@ static int try_to_commit(struct repository *r,
hook_commit = "HEAD";
}
author = amend_author = get_author(message);
- unuse_commit_buffer(current_head, message);
+ repo_unuse_commit_buffer(r, current_head,
+ message);
if (!author) {
res = error(_("unable to parse commit author"));
goto out;
@@ -1536,7 +1557,8 @@ static int try_to_commit(struct repository *r,
cleanup = opts->default_msg_cleanup;
if (cleanup != COMMIT_MSG_CLEANUP_NONE)
- strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
+ strbuf_stripspace(msg,
+ cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {
res = 1; /* run 'git commit' to display error message */
goto out;
@@ -1668,12 +1690,12 @@ static int is_original_commit_empty(struct commit *commit)
{
const struct object_id *ptree_oid;
- if (parse_commit(commit))
+ if (repo_parse_commit(the_repository, commit))
return error(_("could not parse commit %s"),
oid_to_hex(&commit->object.oid));
if (commit->parents) {
struct commit *parent = commit->parents->item;
- if (parse_commit(parent))
+ if (repo_parse_commit(the_repository, parent))
return error(_("could not parse parent commit %s"),
oid_to_hex(&parent->object.oid));
ptree_oid = get_commit_tree_oid(parent);
@@ -1830,7 +1852,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)
s += count;
len -= count;
}
- strbuf_add_commented_lines(buf, s, len);
+ strbuf_add_commented_lines(buf, s, len, comment_line_char);
}
/* Does the current fixup chain contain a squash command? */
@@ -1929,7 +1951,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,
strbuf_addf(buf, _(nth_commit_msg_fmt),
++opts->current_fixup_count + 1);
strbuf_addstr(buf, "\n\n");
- strbuf_add_commented_lines(buf, body, commented_len);
+ strbuf_add_commented_lines(buf, body, commented_len, comment_line_char);
/* buf->buf may be reallocated so store an offset into the buffer */
fixup_off = buf->len;
strbuf_addstr(buf, body + commented_len);
@@ -1997,17 +2019,18 @@ static int update_squash_messages(struct repository *r,
struct commit *head_commit;
const char *head_message, *body;
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(r, "HEAD", &head))
return error(_("need a HEAD to fixup"));
if (!(head_commit = lookup_commit_reference(r, &head)))
return error(_("could not read HEAD"));
- if (!(head_message = logmsg_reencode(head_commit, NULL, encoding)))
+ if (!(head_message = repo_logmsg_reencode(r, head_commit, NULL,
+ encoding)))
return error(_("could not read HEAD's commit message"));
find_commit_subject(head_message, &body);
if (command == TODO_FIXUP && !flag && write_message(body, strlen(body),
rebase_path_fixup_msg(), 0) < 0) {
- unuse_commit_buffer(head_commit, head_message);
+ repo_unuse_commit_buffer(r, head_commit, head_message);
return error(_("cannot write '%s'"), rebase_path_fixup_msg());
}
strbuf_addf(&buf, "%c ", comment_line_char);
@@ -2018,14 +2041,15 @@ static int update_squash_messages(struct repository *r,
_(first_commit_msg_str));
strbuf_addstr(&buf, "\n\n");
if (is_fixup_flag(command, flag))
- strbuf_add_commented_lines(&buf, body, strlen(body));
+ strbuf_add_commented_lines(&buf, body, strlen(body),
+ comment_line_char);
else
strbuf_addstr(&buf, body);
- unuse_commit_buffer(head_commit, head_message);
+ repo_unuse_commit_buffer(r, head_commit, head_message);
}
- if (!(message = logmsg_reencode(commit, NULL, encoding)))
+ if (!(message = repo_logmsg_reencode(r, commit, NULL, encoding)))
return error(_("could not read commit message of %s"),
oid_to_hex(&commit->object.oid));
find_commit_subject(message, &body);
@@ -2037,10 +2061,11 @@ static int update_squash_messages(struct repository *r,
strbuf_addf(&buf, _(skip_nth_commit_msg_fmt),
++opts->current_fixup_count + 1);
strbuf_addstr(&buf, "\n\n");
- strbuf_add_commented_lines(&buf, body, strlen(body));
+ strbuf_add_commented_lines(&buf, body, strlen(body),
+ comment_line_char);
} else
return error(_("unknown command: %d"), command);
- unuse_commit_buffer(commit, message);
+ repo_unuse_commit_buffer(r, commit, message);
if (!res)
res = write_message(buf.buf, buf.len, rebase_path_squash_msg(),
@@ -2067,7 +2092,7 @@ static void flush_rewritten_pending(void)
FILE *out;
if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), (GIT_MAX_HEXSZ + 1) * 2) > 0 &&
- !get_oid("HEAD", &newoid) &&
+ !repo_get_oid(the_repository, "HEAD", &newoid) &&
(out = fopen_or_warn(rebase_path_rewritten_list(), "a"))) {
char *bol = buf.buf, *eol;
@@ -2119,7 +2144,8 @@ static void refer_to_commit(struct replay_opts *opts,
.abbrev = DEFAULT_ABBREV,
.date_mode.type = DATE_SHORT,
};
- format_commit_message(commit, "%h (%s, %ad)", msgbuf, &ctx);
+ repo_format_commit_message(the_repository, commit,
+ "%h (%s, %ad)", msgbuf, &ctx);
} else {
strbuf_addstr(msgbuf, oid_to_hex(&commit->object.oid));
}
@@ -2152,7 +2178,7 @@ static int do_pick_commit(struct repository *r,
if (write_index_as_tree(&head, r->index, r->index_file, 0, NULL))
return error(_("your index file is unmerged."));
} else {
- unborn = get_oid("HEAD", &head);
+ unborn = repo_get_oid(r, "HEAD", &head);
/* Do we want to generate a root commit? */
if (is_pick_or_similar(command) && opts->have_squash_onto &&
oideq(&head, &opts->squash_onto)) {
@@ -2204,8 +2230,6 @@ static int do_pick_commit(struct repository *r,
if (opts->allow_ff && !is_fixup(command) &&
((parent && oideq(&parent->object.oid, &head)) ||
(!parent && unborn))) {
- if (is_rebase_i(opts))
- write_author_script(msg.message);
res = fast_forward_to(r, &commit->object.oid, &head, unborn,
opts);
if (res || command != TODO_REWORD)
@@ -2214,7 +2238,7 @@ static int do_pick_commit(struct repository *r,
msg_file = NULL;
goto fast_forward_edit;
}
- if (parent && parse_commit(parent) < 0)
+ if (parent && repo_parse_commit(r, parent) < 0)
/* TRANSLATORS: The first %s will be a "todo" command like
"revert" or "pick", the second %s a SHA1. */
return error(_("%s: cannot parse parent commit %s"),
@@ -2312,9 +2336,10 @@ static int do_pick_commit(struct repository *r,
command == TODO_REVERT) {
res = do_recursive_merge(r, base, next, base_label, next_label,
&head, &msgbuf, opts);
- if (res < 0)
+ if (res < 0) {
+ unlink(rebase_path_author_script());
goto leave;
-
+ }
res |= write_message(msgbuf.buf, msgbuf.len,
git_path_merge_msg(r), 0);
} else {
@@ -2327,7 +2352,7 @@ static int do_pick_commit(struct repository *r,
commit_list_insert(base, &common);
commit_list_insert(next, &remotes);
res |= try_merge_command(r, opts->strategy,
- opts->xopts_nr, (const char **)opts->xopts,
+ opts->xopts.nr, opts->xopts.v,
common, oid_to_hex(&head), remotes);
free_commit_list(common);
free_commit_list(remotes);
@@ -2606,7 +2631,7 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
saved = *end_of_object_name;
*end_of_object_name = '\0';
- status = get_oid(bol, &commit_oid);
+ status = repo_get_oid(r, bol, &commit_oid);
if (status < 0)
error(_("could not parse '%s'"), bol); /* return later */
*end_of_object_name = saved;
@@ -2900,8 +2925,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
else if (!strcmp(key, "options.gpg-sign"))
git_config_string_dup(&opts->gpg_sign, key, value);
else if (!strcmp(key, "options.strategy-option")) {
- ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
- opts->xopts[opts->xopts_nr++] = xstrdup(value);
+ strvec_push(&opts->xopts, value);
} else if (!strcmp(key, "options.allow-rerere-auto"))
opts->allow_rerere_auto =
git_config_bool_or_int(key, value, &error_flag) ?
@@ -2918,22 +2942,27 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
return 0;
}
-void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)
+static void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)
{
int i;
+ int count;
+ const char **argv;
char *strategy_opts_string = raw_opts;
if (*strategy_opts_string == ' ')
strategy_opts_string++;
- opts->xopts_nr = split_cmdline(strategy_opts_string,
- (const char ***)&opts->xopts);
- for (i = 0; i < opts->xopts_nr; i++) {
- const char *arg = opts->xopts[i];
+ count = split_cmdline(strategy_opts_string, &argv);
+ if (count < 0)
+ BUG("could not split '%s': %s", strategy_opts_string,
+ split_cmdline_strerror(count));
+ for (i = 0; i < count; i++) {
+ const char *arg = argv[i];
skip_prefix(arg, "--", &arg);
- opts->xopts[i] = xstrdup(arg);
+ strvec_push(&opts->xopts, arg);
}
+ free(argv);
}
static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
@@ -2941,7 +2970,6 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
strbuf_reset(buf);
if (!read_oneliner(buf, rebase_path_strategy(), 0))
return;
- free(opts->strategy);
opts->strategy = strbuf_detach(buf, NULL);
if (!read_oneliner(buf, rebase_path_strategy_opts(), 0))
return;
@@ -3022,7 +3050,7 @@ static int read_populate_opts(struct replay_opts *opts)
}
if (read_oneliner(&buf, rebase_path_squash_onto(), 0)) {
- if (get_oid_committish(buf.buf, &opts->squash_onto) < 0) {
+ if (repo_get_oid_committish(the_repository, buf.buf, &opts->squash_onto) < 0) {
ret = error(_("unusable squash-onto"));
goto done_rebase_i;
}
@@ -3050,12 +3078,13 @@ done_rebase_i:
static void write_strategy_opts(struct replay_opts *opts)
{
- int i;
struct strbuf buf = STRBUF_INIT;
- for (i = 0; i < opts->xopts_nr; ++i)
- strbuf_addf(&buf, " --%s", opts->xopts[i]);
-
+ /*
+ * Quote strategy options so that they can be read correctly
+ * by split_cmdline().
+ */
+ quote_cmdline(&buf, opts->xopts.v);
write_file(rebase_path_strategy_opts(), "%s\n", buf.buf);
strbuf_release(&buf);
}
@@ -3078,7 +3107,7 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
write_file(rebase_path_verbose(), "%s", "");
if (opts->strategy)
write_file(rebase_path_strategy(), "%s\n", opts->strategy);
- if (opts->xopts_nr > 0)
+ if (opts->xopts.nr > 0)
write_strategy_opts(opts);
if (opts->allow_rerere_auto == RERERE_AUTOUPDATE)
@@ -3122,7 +3151,9 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
while ((commit = get_revision(opts->revs))) {
struct todo_item *item = append_new_todo(todo_list);
- const char *commit_buffer = logmsg_reencode(commit, NULL, encoding);
+ const char *commit_buffer = repo_logmsg_reencode(the_repository,
+ commit, NULL,
+ encoding);
const char *subject;
int subject_len;
@@ -3134,7 +3165,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
subject_len = find_commit_subject(commit_buffer, &subject);
strbuf_addf(&todo_list->buf, "%s %s %.*s\n", command_string,
short_commit_name(commit), subject_len, subject);
- unuse_commit_buffer(commit, commit_buffer);
+ repo_unuse_commit_buffer(the_repository, commit,
+ commit_buffer);
}
if (!todo_list->nr)
@@ -3184,25 +3216,7 @@ static int create_seq_dir(struct repository *r)
static int save_head(const char *head)
{
- struct lock_file head_lock = LOCK_INIT;
- struct strbuf buf = STRBUF_INIT;
- int fd;
- ssize_t written;
-
- fd = hold_lock_file_for_update(&head_lock, git_path_head_file(), 0);
- if (fd < 0)
- return error_errno(_("could not lock HEAD"));
- strbuf_addf(&buf, "%s\n", head);
- written = write_in_full(fd, buf.buf, buf.len);
- strbuf_release(&buf);
- if (written < 0) {
- error_errno(_("could not write to '%s'"), git_path_head_file());
- rollback_lock_file(&head_lock);
- return -1;
- }
- if (commit_lock_file(&head_lock) < 0)
- return error(_("failed to finalize '%s'"), git_path_head_file());
- return 0;
+ return write_message(head, strlen(head), git_path_head_file(), 1);
}
static int rollback_is_safe(void)
@@ -3223,7 +3237,7 @@ static int rollback_is_safe(void)
else
die_errno(_("could not read '%s'"), git_path_abort_safety_file());
- if (get_oid("HEAD", &actual_head))
+ if (repo_get_oid(the_repository, "HEAD", &actual_head))
oidclr(&actual_head);
return oideq(&actual_head, &expected_head);
@@ -3379,7 +3393,8 @@ give_advice:
return -1;
}
-static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts,
+ int reschedule)
{
struct lock_file todo_lock = LOCK_INIT;
const char *todo_path = get_todo_path(opts);
@@ -3389,7 +3404,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
* rebase -i writes "git-rebase-todo" without the currently executing
* command, appending it to "done" instead.
*/
- if (is_rebase_i(opts))
+ if (is_rebase_i(opts) && !reschedule)
next++;
fd = hold_lock_file_for_update(&todo_lock, todo_path, 0);
@@ -3402,7 +3417,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
if (commit_lock_file(&todo_lock) < 0)
return error(_("failed to finalize '%s'"), todo_path);
- if (is_rebase_i(opts) && next > 0) {
+ if (is_rebase_i(opts) && !reschedule && next > 0) {
const char *done = rebase_path_done();
int fd = open(done, O_CREAT | O_WRONLY | O_APPEND, 0666);
int ret = 0;
@@ -3462,13 +3477,10 @@ static int save_opts(struct replay_opts *opts)
if (opts->gpg_sign)
res |= git_config_set_in_file_gently(opts_file,
"options.gpg-sign", opts->gpg_sign);
- if (opts->xopts) {
- int i;
- for (i = 0; i < opts->xopts_nr; i++)
- res |= git_config_set_multivar_in_file_gently(opts_file,
- "options.strategy-option",
- opts->xopts[i], "^$", 0);
- }
+ for (size_t i = 0; i < opts->xopts.nr; i++)
+ res |= git_config_set_multivar_in_file_gently(opts_file,
+ "options.strategy-option",
+ opts->xopts.v[i], "^$", 0);
if (opts->allow_rerere_auto)
res |= git_config_set_in_file_gently(opts_file,
"options.allow-rerere-auto",
@@ -3497,7 +3509,6 @@ static int make_patch(struct repository *r,
return -1;
res |= write_rebase_head(&commit->object.oid);
- strbuf_addf(&buf, "%s/patch", get_dir(opts));
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
repo_init_revisions(r, &log_tree_opt, NULL);
log_tree_opt.abbrev = 0;
@@ -3505,7 +3516,7 @@ static int make_patch(struct repository *r,
log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
log_tree_opt.disable_stdin = 1;
log_tree_opt.no_commit_id = 1;
- log_tree_opt.diffopt.file = fopen(buf.buf, "w");
+ log_tree_opt.diffopt.file = fopen(rebase_path_patch(), "w");
log_tree_opt.diffopt.use_color = GIT_COLOR_NEVER;
if (!log_tree_opt.diffopt.file)
res |= error_errno(_("could not open '%s'"), buf.buf);
@@ -3518,10 +3529,13 @@ static int make_patch(struct repository *r,
strbuf_addf(&buf, "%s/message", get_dir(opts));
if (!file_exists(buf.buf)) {
const char *encoding = get_commit_output_encoding();
- const char *commit_buffer = logmsg_reencode(commit, NULL, encoding);
+ const char *commit_buffer = repo_logmsg_reencode(r,
+ commit, NULL,
+ encoding);
find_commit_subject(commit_buffer, &subject);
res |= write_message(subject, strlen(subject), buf.buf, 1);
- unuse_commit_buffer(commit, commit_buffer);
+ repo_unuse_commit_buffer(r, commit,
+ commit_buffer);
}
strbuf_release(&buf);
release_revisions(&log_tree_opt);
@@ -3534,7 +3548,7 @@ static int intend_to_amend(void)
struct object_id head;
char *p;
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(the_repository, "HEAD", &head))
return error(_("cannot read HEAD"));
p = oid_to_hex(&head);
@@ -3625,14 +3639,14 @@ static int do_exec(struct repository *r, const char *command_line)
" git rebase --continue\n"
"\n"),
command_line,
- dirty ? N_("and made changes to the index and/or the "
- "working tree\n") : "");
+ dirty ? _("and made changes to the index and/or the "
+ "working tree.\n") : "");
if (status == 127)
/* command not found */
status = 1;
} else if (dirty) {
warning(_("execution succeeded: %s\nbut "
- "left changes to the index and/or the working tree\n"
+ "left changes to the index and/or the working tree.\n"
"Commit or stash your changes, and then run\n"
"\n"
" git rebase --continue\n"
@@ -3673,7 +3687,6 @@ static int safe_append(const char *filename, const char *fmt, ...)
}
if (commit_lock_file(&lock) < 0) {
strbuf_release(&buf);
- rollback_lock_file(&lock);
return error(_("failed to finalize '%s'"), filename);
}
@@ -3700,7 +3713,7 @@ static int do_label(struct repository *r, const char *name, int len)
if (!transaction) {
error("%s", err.buf);
ret = -1;
- } else if (get_oid("HEAD", &head_oid)) {
+ } else if (repo_get_oid(r, "HEAD", &head_oid)) {
error(_("could not read HEAD"));
ret = -1;
} else if (ref_transaction_update(transaction, ref_name.buf, &head_oid,
@@ -3878,7 +3891,7 @@ static int do_merge(struct repository *r,
struct commit *head_commit, *merge_commit, *i;
struct commit_list *bases, *j;
struct commit_list *to_merge = NULL, **tail = &to_merge;
- const char *strategy = !opts->xopts_nr &&
+ const char *strategy = !opts->xopts.nr &&
(!opts->strategy ||
!strcmp(opts->strategy, "recursive") ||
!strcmp(opts->strategy, "ort")) ?
@@ -3988,7 +4001,8 @@ static int do_merge(struct repository *r,
if (commit) {
const char *encoding = get_commit_output_encoding();
- const char *message = logmsg_reencode(commit, NULL, encoding);
+ const char *message = repo_logmsg_reencode(r, commit, NULL,
+ encoding);
const char *body;
int len;
@@ -4001,7 +4015,7 @@ static int do_merge(struct repository *r,
find_commit_subject(message, &body);
len = strlen(body);
ret = write_message(body, len, git_path_merge_msg(r), 0);
- unuse_commit_buffer(commit, message);
+ repo_unuse_commit_buffer(r, commit, message);
if (ret) {
error_errno(_("could not write '%s'"),
git_path_merge_msg(r));
@@ -4061,9 +4075,9 @@ static int do_merge(struct repository *r,
strvec_push(&cmd.args, "octopus");
else {
strvec_push(&cmd.args, strategy);
- for (k = 0; k < opts->xopts_nr; k++)
+ for (k = 0; k < opts->xopts.nr; k++)
strvec_pushf(&cmd.args,
- "-X%s", opts->xopts[k]);
+ "-X%s", opts->xopts.v[k]);
}
if (!(flags & TODO_EDIT_MERGE_MSG))
strvec_push(&cmd.args, "--no-edit");
@@ -4101,7 +4115,7 @@ static int do_merge(struct repository *r,
}
merge_commit = to_merge->item;
- bases = get_merge_bases(head_commit, merge_commit);
+ bases = repo_get_merge_bases(r, head_commit, merge_commit);
if (bases && oideq(&merge_commit->object.oid,
&bases->item->object.oid)) {
ret = 0;
@@ -4141,6 +4155,8 @@ static int do_merge(struct repository *r,
if (ret < 0) {
error(_("could not even attempt to merge '%.*s'"),
merge_arg_len, arg);
+ unlink(rebase_path_author_script());
+ unlink(git_path_merge_msg(r));
goto leave_merge;
}
/*
@@ -4456,7 +4472,7 @@ void create_autostash(struct repository *r, const char *path)
if (capture_command(&stash, &buf, GIT_MAX_HEXSZ))
die(_("Cannot autostash"));
strbuf_trim_trailing_newline(&buf);
- if (get_oid(buf.buf, &oid))
+ if (repo_get_oid(r, buf.buf, &oid))
die(_("Unexpected stash response: '%s'"),
buf.buf);
strbuf_reset(&buf);
@@ -4581,9 +4597,9 @@ static int stopped_at_head(struct repository *r)
struct commit *commit;
struct commit_message message;
- if (get_oid("HEAD", &head) ||
+ if (repo_get_oid(r, "HEAD", &head) ||
!(commit = lookup_commit(r, &head)) ||
- parse_commit(commit) || get_message(commit, &message))
+ repo_parse_commit(r, commit) || get_message(commit, &message))
fprintf(stderr, _("Stopped at HEAD\n"));
else {
fprintf(stderr, _("Stopped at %s\n"), message.label);
@@ -4628,6 +4644,68 @@ N_("Could not execute the todo command\n"
" git rebase --edit-todo\n"
" git rebase --continue\n");
+static int pick_one_commit(struct repository *r,
+ struct todo_list *todo_list,
+ struct replay_opts *opts,
+ int *check_todo, int* reschedule)
+{
+ int res;
+ struct todo_item *item = todo_list->items + todo_list->current;
+ const char *arg = todo_item_get_arg(todo_list, item);
+ if (is_rebase_i(opts))
+ opts->reflog_message = reflog_message(
+ opts, command_to_string(item->command), NULL);
+
+ res = do_pick_commit(r, item, opts, is_final_fixup(todo_list),
+ check_todo);
+ if (is_rebase_i(opts) && res < 0) {
+ /* Reschedule */
+ *reschedule = 1;
+ return -1;
+ }
+ if (item->command == TODO_EDIT) {
+ struct commit *commit = item->commit;
+ if (!res) {
+ if (!opts->verbose)
+ term_clear_line();
+ fprintf(stderr, _("Stopped at %s... %.*s\n"),
+ short_commit_name(commit), item->arg_len, arg);
+ }
+ return error_with_patch(r, commit,
+ arg, item->arg_len, opts, res, !res);
+ }
+ if (is_rebase_i(opts) && !res)
+ record_in_rewritten(&item->commit->object.oid,
+ peek_command(todo_list, 1));
+ if (res && is_fixup(item->command)) {
+ if (res == 1)
+ intend_to_amend();
+ return error_failed_squash(r, item->commit, opts,
+ item->arg_len, arg);
+ } else if (res && is_rebase_i(opts) && item->commit) {
+ int to_amend = 0;
+ struct object_id oid;
+
+ /*
+ * If we are rewording and have either
+ * fast-forwarded already, or are about to
+ * create a new root commit, we want to amend,
+ * otherwise we do not.
+ */
+ if (item->command == TODO_REWORD &&
+ !repo_get_oid(r, "HEAD", &oid) &&
+ (oideq(&item->commit->object.oid, &oid) ||
+ (opts->have_squash_onto &&
+ oideq(&opts->squash_onto, &oid))))
+ to_amend = 1;
+
+ return res | error_with_patch(r, item->commit,
+ arg, item->arg_len, opts,
+ res, to_amend);
+ }
+ return res;
+}
+
static int pick_commits(struct repository *r,
struct todo_list *todo_list,
struct replay_opts *opts)
@@ -4643,12 +4721,17 @@ static int pick_commits(struct repository *r,
if (read_and_refresh_cache(r, opts))
return -1;
+ unlink(rebase_path_message());
+ unlink(rebase_path_stopped_sha());
+ unlink(rebase_path_amend());
+ unlink(rebase_path_patch());
+
while (todo_list->current < todo_list->nr) {
struct todo_item *item = todo_list->items + todo_list->current;
const char *arg = todo_item_get_arg(todo_list, item);
int check_todo = 0;
- if (save_todo(todo_list, opts))
+ if (save_todo(todo_list, opts, reschedule))
return -1;
if (is_rebase_i(opts)) {
if (item->command != TODO_COMMENT) {
@@ -4666,10 +4749,7 @@ static int pick_commits(struct repository *r,
todo_list->total_nr,
opts->verbose ? "\n" : "\r");
}
- unlink(rebase_path_message());
unlink(rebase_path_author_script());
- unlink(rebase_path_stopped_sha());
- unlink(rebase_path_amend());
unlink(git_path_merge_head(r));
unlink(git_path_auto_merge(r));
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
@@ -4681,66 +4761,10 @@ static int pick_commits(struct repository *r,
}
}
if (item->command <= TODO_SQUASH) {
- if (is_rebase_i(opts))
- opts->reflog_message = reflog_message(opts,
- command_to_string(item->command), NULL);
-
- res = do_pick_commit(r, item, opts,
- is_final_fixup(todo_list),
- &check_todo);
- if (is_rebase_i(opts) && res < 0) {
- /* Reschedule */
- advise(_(rescheduled_advice),
- get_item_line_length(todo_list,
- todo_list->current),
- get_item_line(todo_list,
- todo_list->current));
- todo_list->current--;
- if (save_todo(todo_list, opts))
- return -1;
- }
- if (item->command == TODO_EDIT) {
- struct commit *commit = item->commit;
- if (!res) {
- if (!opts->verbose)
- term_clear_line();
- fprintf(stderr,
- _("Stopped at %s... %.*s\n"),
- short_commit_name(commit),
- item->arg_len, arg);
- }
- return error_with_patch(r, commit,
- arg, item->arg_len, opts, res, !res);
- }
- if (is_rebase_i(opts) && !res)
- record_in_rewritten(&item->commit->object.oid,
- peek_command(todo_list, 1));
- if (res && is_fixup(item->command)) {
- if (res == 1)
- intend_to_amend();
- return error_failed_squash(r, item->commit, opts,
- item->arg_len, arg);
- } else if (res && is_rebase_i(opts) && item->commit) {
- int to_amend = 0;
- struct object_id oid;
-
- /*
- * If we are rewording and have either
- * fast-forwarded already, or are about to
- * create a new root commit, we want to amend,
- * otherwise we do not.
- */
- if (item->command == TODO_REWORD &&
- !get_oid("HEAD", &oid) &&
- (oideq(&item->commit->object.oid, &oid) ||
- (opts->have_squash_onto &&
- oideq(&opts->squash_onto, &oid))))
- to_amend = 1;
-
- return res | error_with_patch(r, item->commit,
- arg, item->arg_len, opts,
- res, to_amend);
- }
+ res = pick_one_commit(r, todo_list, opts, &check_todo,
+ &reschedule);
+ if (!res && item->command == TODO_EDIT)
+ return 0;
} else if (item->command == TODO_EXEC) {
char *end_of_arg = (char *)(arg + item->arg_len);
int saved = *end_of_arg;
@@ -4788,14 +4812,10 @@ static int pick_commits(struct repository *r,
get_item_line_length(todo_list,
todo_list->current),
get_item_line(todo_list, todo_list->current));
- todo_list->current--;
- if (save_todo(todo_list, opts))
+ if (save_todo(todo_list, opts, reschedule))
return -1;
if (item->commit)
- return error_with_patch(r,
- item->commit,
- arg, item->arg_len,
- opts, res, 0);
+ write_rebase_head(&item->commit->object.oid);
} else if (is_rebase_i(opts) && check_todo && !res &&
reread_todo_if_changed(r, todo_list, opts)) {
return -1;
@@ -4820,7 +4840,7 @@ static int pick_commits(struct repository *r,
struct object_id head, orig;
int res;
- if (get_oid("HEAD", &head)) {
+ if (repo_get_oid(r, "HEAD", &head)) {
res = error(_("cannot read HEAD"));
cleanup_head_ref:
strbuf_release(&head_ref);
@@ -4867,8 +4887,8 @@ cleanup_head_ref:
log_tree_opt.disable_stdin = 1;
if (read_oneliner(&buf, rebase_path_orig_head(), 0) &&
- !get_oid(buf.buf, &orig) &&
- !get_oid("HEAD", &head)) {
+ !repo_get_oid(r, buf.buf, &orig) &&
+ !repo_get_oid(r, "HEAD", &head)) {
diff_tree_oid(&orig, &head, "",
&log_tree_opt.diffopt);
log_tree_diff_flush(&log_tree_opt);
@@ -4960,7 +4980,7 @@ static int commit_staged_changes(struct repository *r,
struct strbuf rev = STRBUF_INIT;
struct object_id head, to_amend;
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(r, "HEAD", &head))
return error(_("cannot amend non-existing commit"));
if (!read_oneliner(&rev, rebase_path_amend(), 0))
return error(_("invalid file: '%s'"), rebase_path_amend());
@@ -5040,13 +5060,14 @@ static int commit_staged_changes(struct repository *r,
const char *encoding = get_commit_output_encoding();
if (parse_head(r, &commit) ||
- !(p = logmsg_reencode(commit, NULL, encoding)) ||
+ !(p = repo_logmsg_reencode(r, commit, NULL, encoding)) ||
write_message(p, strlen(p), path, 0)) {
- unuse_commit_buffer(commit, p);
+ repo_unuse_commit_buffer(r, commit, p);
return error(_("could not write file: "
"'%s'"), path);
}
- unuse_commit_buffer(commit, p);
+ repo_unuse_commit_buffer(r,
+ commit, p);
}
}
@@ -5185,7 +5206,7 @@ int sequencer_pick_revisions(struct repository *r,
if (!strlen(name))
continue;
- if (!get_oid(name, &oid)) {
+ if (!repo_get_oid(r, name, &oid)) {
if (!lookup_commit_reference_gently(r, &oid, 1)) {
enum object_type type = oid_object_info(r,
&oid,
@@ -5228,7 +5249,7 @@ int sequencer_pick_revisions(struct repository *r,
if (walk_revs_populate_todo(&todo_list, opts) ||
create_seq_dir(r) < 0)
return -1;
- if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
+ if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
return error(_("can't revert as initial commit"));
if (save_head(oid_to_hex(&oid)))
return -1;
@@ -5344,7 +5365,7 @@ static const char *label_oid(struct object_id *oid, const char *label,
* For "uninteresting" commits, i.e. commits that are not to be
* rebased, and which can therefore not be labeled, we use a unique
* abbreviation of the commit name. This is slightly more complicated
- * than calling find_unique_abbrev() because we also need to make
+ * than calling repo_find_unique_abbrev() because we also need to make
* sure that the abbreviation does not conflict with any other
* label.
*
@@ -5360,7 +5381,8 @@ static const char *label_oid(struct object_id *oid, const char *label,
strbuf_grow(&state->buf, GIT_MAX_HEXSZ);
label = p = state->buf.buf;
- find_unique_abbrev_r(p, oid, default_abbrev);
+ repo_find_unique_abbrev_r(the_repository, p, oid,
+ default_abbrev);
/*
* We may need to extend the abbreviated hash so that there is
@@ -5922,7 +5944,7 @@ static int skip_unnecessary_picks(struct repository *r,
continue;
if (item->command != TODO_PICK)
break;
- if (parse_commit(item->commit)) {
+ if (repo_parse_commit(r, item->commit)) {
return error(_("could not parse commit '%s'"),
oid_to_hex(&item->commit->object.oid));
}
@@ -6093,7 +6115,8 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
struct object_id oid = onto->object.oid;
int res;
- find_unique_abbrev_r(shortonto, &oid, DEFAULT_ABBREV);
+ repo_find_unique_abbrev_r(r, shortonto, &oid,
+ DEFAULT_ABBREV);
if (buf->len == 0) {
struct todo_item *item = append_new_todo(todo_list);
@@ -6254,12 +6277,15 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
return error(_("the script was already rearranged."));
}
- parse_commit(item->commit);
- commit_buffer = logmsg_reencode(item->commit, NULL, "UTF-8");
+ repo_parse_commit(the_repository, item->commit);
+ commit_buffer = repo_logmsg_reencode(the_repository,
+ item->commit, NULL,
+ "UTF-8");
find_commit_subject(commit_buffer, &subject);
format_subject(&buf, subject, " ");
subject = subjects[i] = strbuf_detach(&buf, &subject_len);
- unuse_commit_buffer(item->commit, commit_buffer);
+ repo_unuse_commit_buffer(the_repository, item->commit,
+ commit_buffer);
if (skip_fixupish(subject, &p)) {
struct commit *commit2;
@@ -6369,8 +6395,8 @@ int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
if (file_exists(git_path_seq_dir()))
*whence = FROM_CHERRY_PICK_MULTI;
if (file_exists(rebase_path()) &&
- !get_oid("REBASE_HEAD", &rebase_head) &&
- !get_oid("CHERRY_PICK_HEAD", &cherry_pick_head) &&
+ !repo_get_oid(r, "REBASE_HEAD", &rebase_head) &&
+ !repo_get_oid(r, "CHERRY_PICK_HEAD", &cherry_pick_head) &&
oideq(&rebase_head, &cherry_pick_head))
*whence = FROM_REBASE_PICK;
else
diff --git a/sequencer.h b/sequencer.h
index 3bcdfa1b58..913a0f652d 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -1,11 +1,12 @@
#ifndef SEQUENCER_H
#define SEQUENCER_H
-#include "cache.h"
#include "strbuf.h"
+#include "strvec.h"
#include "wt-status.h"
struct commit;
+struct index_state;
struct repository;
const char *git_path_commit_editmsg(void);
@@ -60,8 +61,7 @@ struct replay_opts {
/* Merge strategy */
char *default_strategy; /* from config options */
char *strategy;
- char **xopts;
- size_t xopts_nr, xopts_alloc;
+ struct strvec xopts;
/* Reflog */
char *reflog_action;
@@ -80,7 +80,12 @@ struct replay_opts {
/* Private use */
const char *reflog_message;
};
-#define REPLAY_OPTS_INIT { .edit = -1, .action = -1, .current_fixups = STRBUF_INIT }
+#define REPLAY_OPTS_INIT { \
+ .edit = -1, \
+ .action = -1, \
+ .current_fixups = STRBUF_INIT, \
+ .xopts = STRVEC_INIT, \
+}
/*
* Note that ordering matters in this enum. Not only must it match the mapping
@@ -247,7 +252,6 @@ int read_oneliner(struct strbuf *buf,
const char *path, unsigned flags);
int read_author_script(const char *path, char **name, char **email, char **date,
int allow_missing);
-void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);
int write_basic_state(struct replay_opts *opts, const char *head_name,
struct commit *onto, const struct object_id *orig_head);
void sequencer_post_commit_cleanup(struct repository *r, int verbose);
diff --git a/serve.c b/serve.c
index cbf4a143cf..a1d71134d4 100644
--- a/serve.c
+++ b/serve.c
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "repository.h"
#include "config.h"
+#include "hash-ll.h"
#include "pkt-line.h"
#include "version.h"
#include "ls-refs.h"
@@ -8,17 +9,18 @@
#include "serve.h"
#include "upload-pack.h"
#include "bundle-uri.h"
+#include "trace2.h"
static int advertise_sid = -1;
static int client_hash_algo = GIT_HASH_SHA1;
-static int always_advertise(struct repository *r,
- struct strbuf *value)
+static int always_advertise(struct repository *r UNUSED,
+ struct strbuf *value UNUSED)
{
return 1;
}
-static int agent_advertise(struct repository *r,
+static int agent_advertise(struct repository *r UNUSED,
struct strbuf *value)
{
if (value)
@@ -34,7 +36,7 @@ static int object_format_advertise(struct repository *r,
return 1;
}
-static void object_format_receive(struct repository *r,
+static void object_format_receive(struct repository *r UNUSED,
const char *algo_name)
{
if (!algo_name)
@@ -48,7 +50,7 @@ static void object_format_receive(struct repository *r,
static int session_id_advertise(struct repository *r, struct strbuf *value)
{
if (advertise_sid == -1 &&
- git_config_get_bool("transfer.advertisesid", &advertise_sid))
+ repo_config_get_bool(r, "transfer.advertisesid", &advertise_sid))
advertise_sid = 0;
if (!advertise_sid)
return 0;
@@ -57,7 +59,7 @@ static int session_id_advertise(struct repository *r, struct strbuf *value)
return 1;
}
-static void session_id_receive(struct repository *r,
+static void session_id_receive(struct repository *r UNUSED,
const char *client_sid)
{
if (!client_sid)
diff --git a/server-info.c b/server-info.c
index 0ec6c0c165..382e481a2b 100644
--- a/server-info.c
+++ b/server-info.c
@@ -1,13 +1,20 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "dir.h"
+#include "environment.h"
+#include "hex.h"
#include "repository.h"
#include "refs.h"
#include "object.h"
#include "commit.h"
#include "tag.h"
#include "packfile.h"
-#include "object-store.h"
+#include "path.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "server-info.h"
#include "strbuf.h"
+#include "wrapper.h"
struct update_info_ctx {
FILE *cur_fp;
diff --git a/server-info.h b/server-info.h
new file mode 100644
index 0000000000..13bbde2c55
--- /dev/null
+++ b/server-info.h
@@ -0,0 +1,7 @@
+#ifndef SERVER_INFO_H
+#define SERVER_INFO_H
+
+/* Dumb servers support */
+int update_server_info(int);
+
+#endif /* SERVER_INFO_H */
diff --git a/setup.c b/setup.c
index cefd5f63c4..3c383c972c 100644
--- a/setup.c
+++ b/setup.c
@@ -1,11 +1,23 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "copy.h"
+#include "environment.h"
+#include "exec-cmd.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "refs.h"
#include "repository.h"
#include "config.h"
#include "dir.h"
+#include "setup.h"
#include "string-list.h"
#include "chdir-notify.h"
+#include "path.h"
#include "promisor-remote.h"
#include "quote.h"
+#include "trace2.h"
+#include "worktree.h"
+#include "wrapper.h"
static int inside_git_dir = -1;
static int inside_work_tree = -1;
@@ -1345,6 +1357,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
}
if (is_git_directory(dir->buf)) {
+ trace2_data_string("setup", NULL, "implicit-bare-repository", dir->buf);
if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT)
return GIT_DIR_DISALLOWED_BARE;
if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
@@ -1699,3 +1712,495 @@ int daemonize(void)
return 0;
#endif
}
+
+#ifndef DEFAULT_GIT_TEMPLATE_DIR
+#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
+#endif
+
+#ifdef NO_TRUSTABLE_FILEMODE
+#define TEST_FILEMODE 0
+#else
+#define TEST_FILEMODE 1
+#endif
+
+#define GIT_DEFAULT_HASH_ENVIRONMENT "GIT_DEFAULT_HASH"
+
+static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
+ DIR *dir)
+{
+ size_t path_baselen = path->len;
+ size_t template_baselen = template_path->len;
+ struct dirent *de;
+
+ /* Note: if ".git/hooks" file exists in the repository being
+ * re-initialized, /etc/core-git/templates/hooks/update would
+ * cause "git init" to fail here. I think this is sane but
+ * it means that the set of templates we ship by default, along
+ * with the way the namespace under .git/ is organized, should
+ * be really carefully chosen.
+ */
+ safe_create_dir(path->buf, 1);
+ while ((de = readdir(dir)) != NULL) {
+ struct stat st_git, st_template;
+ int exists = 0;
+
+ strbuf_setlen(path, path_baselen);
+ strbuf_setlen(template_path, template_baselen);
+
+ if (de->d_name[0] == '.')
+ continue;
+ strbuf_addstr(path, de->d_name);
+ strbuf_addstr(template_path, de->d_name);
+ if (lstat(path->buf, &st_git)) {
+ if (errno != ENOENT)
+ die_errno(_("cannot stat '%s'"), path->buf);
+ }
+ else
+ exists = 1;
+
+ if (lstat(template_path->buf, &st_template))
+ die_errno(_("cannot stat template '%s'"), template_path->buf);
+
+ if (S_ISDIR(st_template.st_mode)) {
+ DIR *subdir = opendir(template_path->buf);
+ if (!subdir)
+ die_errno(_("cannot opendir '%s'"), template_path->buf);
+ strbuf_addch(path, '/');
+ strbuf_addch(template_path, '/');
+ copy_templates_1(path, template_path, subdir);
+ closedir(subdir);
+ }
+ else if (exists)
+ continue;
+ else if (S_ISLNK(st_template.st_mode)) {
+ struct strbuf lnk = STRBUF_INIT;
+ if (strbuf_readlink(&lnk, template_path->buf,
+ st_template.st_size) < 0)
+ die_errno(_("cannot readlink '%s'"), template_path->buf);
+ if (symlink(lnk.buf, path->buf))
+ die_errno(_("cannot symlink '%s' '%s'"),
+ lnk.buf, path->buf);
+ strbuf_release(&lnk);
+ }
+ else if (S_ISREG(st_template.st_mode)) {
+ if (copy_file(path->buf, template_path->buf, st_template.st_mode))
+ die_errno(_("cannot copy '%s' to '%s'"),
+ template_path->buf, path->buf);
+ }
+ else
+ error(_("ignoring template %s"), template_path->buf);
+ }
+}
+
+static void copy_templates(const char *template_dir, const char *init_template_dir)
+{
+ struct strbuf path = STRBUF_INIT;
+ struct strbuf template_path = STRBUF_INIT;
+ size_t template_len;
+ struct repository_format template_format = REPOSITORY_FORMAT_INIT;
+ struct strbuf err = STRBUF_INIT;
+ DIR *dir;
+ char *to_free = NULL;
+
+ if (!template_dir)
+ template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
+ if (!template_dir)
+ template_dir = init_template_dir;
+ if (!template_dir)
+ template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
+ if (!template_dir[0]) {
+ free(to_free);
+ return;
+ }
+
+ strbuf_addstr(&template_path, template_dir);
+ strbuf_complete(&template_path, '/');
+ template_len = template_path.len;
+
+ dir = opendir(template_path.buf);
+ if (!dir) {
+ warning(_("templates not found in %s"), template_dir);
+ goto free_return;
+ }
+
+ /* Make sure that template is from the correct vintage */
+ strbuf_addstr(&template_path, "config");
+ read_repository_format(&template_format, template_path.buf);
+ strbuf_setlen(&template_path, template_len);
+
+ /*
+ * No mention of version at all is OK, but anything else should be
+ * verified.
+ */
+ if (template_format.version >= 0 &&
+ verify_repository_format(&template_format, &err) < 0) {
+ warning(_("not copying templates from '%s': %s"),
+ template_dir, err.buf);
+ strbuf_release(&err);
+ goto close_free_return;
+ }
+
+ strbuf_addstr(&path, get_git_common_dir());
+ strbuf_complete(&path, '/');
+ copy_templates_1(&path, &template_path, dir);
+close_free_return:
+ closedir(dir);
+free_return:
+ free(to_free);
+ strbuf_release(&path);
+ strbuf_release(&template_path);
+ clear_repository_format(&template_format);
+}
+
+/*
+ * If the git_dir is not directly inside the working tree, then git will not
+ * find it by default, and we need to set the worktree explicitly.
+ */
+static int needs_work_tree_config(const char *git_dir, const char *work_tree)
+{
+ if (!strcmp(work_tree, "/") && !strcmp(git_dir, "/.git"))
+ return 0;
+ if (skip_prefix(git_dir, work_tree, &git_dir) &&
+ !strcmp(git_dir, "/.git"))
+ return 0;
+ return 1;
+}
+
+void initialize_repository_version(int hash_algo, int reinit)
+{
+ char repo_version_string[10];
+ int repo_version = GIT_REPO_VERSION;
+
+ if (hash_algo != GIT_HASH_SHA1)
+ repo_version = GIT_REPO_VERSION_READ;
+
+ /* This forces creation of new config file */
+ xsnprintf(repo_version_string, sizeof(repo_version_string),
+ "%d", repo_version);
+ git_config_set("core.repositoryformatversion", repo_version_string);
+
+ if (hash_algo != GIT_HASH_SHA1)
+ git_config_set("extensions.objectformat",
+ hash_algos[hash_algo].name);
+ else if (reinit)
+ git_config_set_gently("extensions.objectformat", NULL);
+}
+
+static int create_default_files(const char *template_path,
+ const char *original_git_dir,
+ const char *initial_branch,
+ const struct repository_format *fmt,
+ int prev_bare_repository,
+ int init_shared_repository,
+ int quiet)
+{
+ struct stat st1;
+ struct strbuf buf = STRBUF_INIT;
+ char *path;
+ char junk[2];
+ int reinit;
+ int filemode;
+ struct strbuf err = STRBUF_INIT;
+ const char *init_template_dir = NULL;
+ const char *work_tree = get_git_work_tree();
+
+ /*
+ * First copy the templates -- we might have the default
+ * config file there, in which case we would want to read
+ * from it after installing.
+ *
+ * Before reading that config, we also need to clear out any cached
+ * values (since we've just potentially changed what's available on
+ * disk).
+ */
+ git_config_get_pathname("init.templatedir", &init_template_dir);
+ copy_templates(template_path, init_template_dir);
+ free((char *)init_template_dir);
+ git_config_clear();
+ reset_shared_repository();
+ git_config(git_default_config, NULL);
+
+ /*
+ * We must make sure command-line options continue to override any
+ * values we might have just re-read from the config.
+ */
+ if (init_shared_repository != -1)
+ set_shared_repository(init_shared_repository);
+ /*
+ * TODO: heed core.bare from config file in templates if no
+ * command-line override given
+ */
+ is_bare_repository_cfg = prev_bare_repository || !work_tree;
+ /* TODO (continued):
+ *
+ * Unfortunately, the line above is equivalent to
+ * is_bare_repository_cfg = !work_tree;
+ * which ignores the config entirely even if no `--[no-]bare`
+ * command line option was present.
+ *
+ * To see why, note that before this function, there was this call:
+ * prev_bare_repository = is_bare_repository()
+ * expanding the right hand side:
+ * = is_bare_repository_cfg && !get_git_work_tree()
+ * = is_bare_repository_cfg && !work_tree
+ * note that the last simplification above is valid because nothing
+ * calls repo_init() or set_git_work_tree() between any of the
+ * relevant calls in the code, and thus the !get_git_work_tree()
+ * calls will return the same result each time. So, what we are
+ * interested in computing is the right hand side of the line of
+ * code just above this comment:
+ * prev_bare_repository || !work_tree
+ * = is_bare_repository_cfg && !work_tree || !work_tree
+ * = !work_tree
+ * because "A && !B || !B == !B" for all boolean values of A & B.
+ */
+
+ /*
+ * We would have created the above under user's umask -- under
+ * shared-repository settings, we would need to fix them up.
+ */
+ if (get_shared_repository()) {
+ adjust_shared_perm(get_git_dir());
+ }
+
+ /*
+ * We need to create a "refs" dir in any case so that older
+ * versions of git can tell that this is a repository.
+ */
+ safe_create_dir(git_path("refs"), 1);
+ adjust_shared_perm(git_path("refs"));
+
+ if (refs_init_db(&err))
+ die("failed to set up refs db: %s", err.buf);
+
+ /*
+ * Point the HEAD symref to the initial branch with if HEAD does
+ * not yet exist.
+ */
+ path = git_path_buf(&buf, "HEAD");
+ reinit = (!access(path, R_OK)
+ || readlink(path, junk, sizeof(junk)-1) != -1);
+ if (!reinit) {
+ char *ref;
+
+ if (!initial_branch)
+ initial_branch = git_default_branch_name(quiet);
+
+ ref = xstrfmt("refs/heads/%s", initial_branch);
+ if (check_refname_format(ref, 0) < 0)
+ die(_("invalid initial branch name: '%s'"),
+ initial_branch);
+
+ if (create_symref("HEAD", ref, NULL) < 0)
+ exit(1);
+ free(ref);
+ }
+
+ initialize_repository_version(fmt->hash_algo, 0);
+
+ /* Check filemode trustability */
+ path = git_path_buf(&buf, "config");
+ filemode = TEST_FILEMODE;
+ if (TEST_FILEMODE && !lstat(path, &st1)) {
+ struct stat st2;
+ filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
+ !lstat(path, &st2) &&
+ st1.st_mode != st2.st_mode &&
+ !chmod(path, st1.st_mode));
+ if (filemode && !reinit && (st1.st_mode & S_IXUSR))
+ filemode = 0;
+ }
+ git_config_set("core.filemode", filemode ? "true" : "false");
+
+ if (is_bare_repository())
+ git_config_set("core.bare", "true");
+ else {
+ git_config_set("core.bare", "false");
+ /* allow template config file to override the default */
+ if (log_all_ref_updates == LOG_REFS_UNSET)
+ git_config_set("core.logallrefupdates", "true");
+ if (needs_work_tree_config(original_git_dir, work_tree))
+ git_config_set("core.worktree", work_tree);
+ }
+
+ if (!reinit) {
+ /* Check if symlink is supported in the work tree */
+ path = git_path_buf(&buf, "tXXXXXX");
+ if (!close(xmkstemp(path)) &&
+ !unlink(path) &&
+ !symlink("testing", path) &&
+ !lstat(path, &st1) &&
+ S_ISLNK(st1.st_mode))
+ unlink(path); /* good */
+ else
+ git_config_set("core.symlinks", "false");
+
+ /* Check if the filesystem is case-insensitive */
+ path = git_path_buf(&buf, "CoNfIg");
+ if (!access(path, F_OK))
+ git_config_set("core.ignorecase", "true");
+ probe_utf8_pathname_composition();
+ }
+
+ strbuf_release(&buf);
+ return reinit;
+}
+
+static void create_object_directory(void)
+{
+ struct strbuf path = STRBUF_INIT;
+ size_t baselen;
+
+ strbuf_addstr(&path, get_object_directory());
+ baselen = path.len;
+
+ safe_create_dir(path.buf, 1);
+
+ strbuf_setlen(&path, baselen);
+ strbuf_addstr(&path, "/pack");
+ safe_create_dir(path.buf, 1);
+
+ strbuf_setlen(&path, baselen);
+ strbuf_addstr(&path, "/info");
+ safe_create_dir(path.buf, 1);
+
+ strbuf_release(&path);
+}
+
+static void separate_git_dir(const char *git_dir, const char *git_link)
+{
+ struct stat st;
+
+ if (!stat(git_link, &st)) {
+ const char *src;
+
+ if (S_ISREG(st.st_mode))
+ src = read_gitfile(git_link);
+ else if (S_ISDIR(st.st_mode))
+ src = git_link;
+ else
+ die(_("unable to handle file type %d"), (int)st.st_mode);
+
+ if (rename(src, git_dir))
+ die_errno(_("unable to move %s to %s"), src, git_dir);
+ repair_worktrees(NULL, NULL);
+ }
+
+ write_file(git_link, "gitdir: %s", git_dir);
+}
+
+static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
+{
+ const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
+ /*
+ * If we already have an initialized repo, don't allow the user to
+ * specify a different algorithm, as that could cause corruption.
+ * Otherwise, if the user has specified one on the command line, use it.
+ */
+ if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
+ die(_("attempt to reinitialize repository with different hash"));
+ else if (hash != GIT_HASH_UNKNOWN)
+ repo_fmt->hash_algo = hash;
+ else if (env) {
+ int env_algo = hash_algo_by_name(env);
+ if (env_algo == GIT_HASH_UNKNOWN)
+ die(_("unknown hash algorithm '%s'"), env);
+ repo_fmt->hash_algo = env_algo;
+ }
+}
+
+int init_db(const char *git_dir, const char *real_git_dir,
+ const char *template_dir, int hash, const char *initial_branch,
+ int init_shared_repository, unsigned int flags)
+{
+ int reinit;
+ int exist_ok = flags & INIT_DB_EXIST_OK;
+ char *original_git_dir = real_pathdup(git_dir, 1);
+ struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
+ int prev_bare_repository;
+
+ if (real_git_dir) {
+ struct stat st;
+
+ if (!exist_ok && !stat(git_dir, &st))
+ die(_("%s already exists"), git_dir);
+
+ if (!exist_ok && !stat(real_git_dir, &st))
+ die(_("%s already exists"), real_git_dir);
+
+ set_git_dir(real_git_dir, 1);
+ git_dir = get_git_dir();
+ separate_git_dir(git_dir, original_git_dir);
+ }
+ else {
+ set_git_dir(git_dir, 1);
+ git_dir = get_git_dir();
+ }
+ startup_info->have_repository = 1;
+
+ /* Ensure `core.hidedotfiles` is processed */
+ git_config(platform_core_config, NULL);
+
+ safe_create_dir(git_dir, 0);
+
+ prev_bare_repository = is_bare_repository();
+
+ /* Check to see if the repository version is right.
+ * Note that a newly created repository does not have
+ * config file, so this will not fail. What we are catching
+ * is an attempt to reinitialize new repository with an old tool.
+ */
+ check_repository_format(&repo_fmt);
+
+ validate_hash_algorithm(&repo_fmt, hash);
+
+ reinit = create_default_files(template_dir, original_git_dir,
+ initial_branch, &repo_fmt,
+ prev_bare_repository,
+ init_shared_repository,
+ flags & INIT_DB_QUIET);
+ if (reinit && initial_branch)
+ warning(_("re-init: ignored --initial-branch=%s"),
+ initial_branch);
+
+ create_object_directory();
+
+ if (get_shared_repository()) {
+ char buf[10];
+ /* We do not spell "group" and such, so that
+ * the configuration can be read by older version
+ * of git. Note, we use octal numbers for new share modes,
+ * and compatibility values for PERM_GROUP and
+ * PERM_EVERYBODY.
+ */
+ if (get_shared_repository() < 0)
+ /* force to the mode value */
+ xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
+ else if (get_shared_repository() == PERM_GROUP)
+ xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
+ else if (get_shared_repository() == PERM_EVERYBODY)
+ xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
+ else
+ BUG("invalid value for shared_repository");
+ git_config_set("core.sharedrepository", buf);
+ git_config_set("receive.denyNonFastforwards", "true");
+ }
+
+ if (!(flags & INIT_DB_QUIET)) {
+ int len = strlen(git_dir);
+
+ if (reinit)
+ printf(get_shared_repository()
+ ? _("Reinitialized existing shared Git repository in %s%s\n")
+ : _("Reinitialized existing Git repository in %s%s\n"),
+ git_dir, len && git_dir[len-1] != '/' ? "/" : "");
+ else
+ printf(get_shared_repository()
+ ? _("Initialized empty shared Git repository in %s%s\n")
+ : _("Initialized empty Git repository in %s%s\n"),
+ git_dir, len && git_dir[len-1] != '/' ? "/" : "");
+ }
+
+ free(original_git_dir);
+ return 0;
+}
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000000..58fd2605dd
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,177 @@
+#ifndef SETUP_H
+#define SETUP_H
+
+#include "string-list.h"
+
+int is_inside_git_dir(void);
+int is_inside_work_tree(void);
+int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
+int get_common_dir(struct strbuf *sb, const char *gitdir);
+
+/*
+ * Return true if the given path is a git directory; note that this _just_
+ * looks at the directory itself. If you want to know whether "foo/.git"
+ * is a repository, you must feed that path, not just "foo".
+ */
+int is_git_directory(const char *path);
+
+/*
+ * Return 1 if the given path is the root of a git repository or
+ * submodule, else 0. Will not return 1 for bare repositories with the
+ * exception of creating a bare repository in "foo/.git" and calling
+ * is_git_repository("foo").
+ *
+ * If we run into read errors, we err on the side of saying "yes, it is",
+ * as we usually consider sub-repos precious, and would prefer to err on the
+ * side of not disrupting or deleting them.
+ */
+int is_nonbare_repository_dir(struct strbuf *path);
+
+#define READ_GITFILE_ERR_STAT_FAILED 1
+#define READ_GITFILE_ERR_NOT_A_FILE 2
+#define READ_GITFILE_ERR_OPEN_FAILED 3
+#define READ_GITFILE_ERR_READ_FAILED 4
+#define READ_GITFILE_ERR_INVALID_FORMAT 5
+#define READ_GITFILE_ERR_NO_PATH 6
+#define READ_GITFILE_ERR_NOT_A_REPO 7
+#define READ_GITFILE_ERR_TOO_LARGE 8
+void read_gitfile_error_die(int error_code, const char *path, const char *dir);
+const char *read_gitfile_gently(const char *path, int *return_error_code);
+#define read_gitfile(path) read_gitfile_gently((path), NULL)
+const char *resolve_gitdir_gently(const char *suspect, int *return_error_code);
+#define resolve_gitdir(path) resolve_gitdir_gently((path), NULL)
+
+void setup_work_tree(void);
+/*
+ * Find the commondir and gitdir of the repository that contains the current
+ * working directory, without changing the working directory or other global
+ * state. The result is appended to commondir and gitdir. If the discovered
+ * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
+ * both have the same result appended to the buffer. The return value is
+ * either 0 upon success and non-zero if no repository was found.
+ */
+int discover_git_directory(struct strbuf *commondir,
+ struct strbuf *gitdir);
+const char *setup_git_directory_gently(int *);
+const char *setup_git_directory(void);
+char *prefix_path(const char *prefix, int len, const char *path);
+char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
+
+int check_filename(const char *prefix, const char *name);
+void verify_filename(const char *prefix,
+ const char *name,
+ int diagnose_misspelt_rev);
+void verify_non_filename(const char *prefix, const char *name);
+int path_inside_repo(const char *prefix, const char *path);
+
+void sanitize_stdfds(void);
+int daemonize(void);
+
+/*
+ * GIT_REPO_VERSION is the version we write by default. The
+ * _READ variant is the highest number we know how to
+ * handle.
+ */
+#define GIT_REPO_VERSION 0
+#define GIT_REPO_VERSION_READ 1
+
+/*
+ * You _have_ to initialize a `struct repository_format` using
+ * `= REPOSITORY_FORMAT_INIT` before calling `read_repository_format()`.
+ */
+struct repository_format {
+ int version;
+ int precious_objects;
+ char *partial_clone; /* value of extensions.partialclone */
+ int worktree_config;
+ int is_bare;
+ int hash_algo;
+ int sparse_index;
+ char *work_tree;
+ struct string_list unknown_extensions;
+ struct string_list v1_only_extensions;
+};
+
+/*
+ * Always use this to initialize a `struct repository_format`
+ * to a well-defined, default state before calling
+ * `read_repository()`.
+ */
+#define REPOSITORY_FORMAT_INIT \
+{ \
+ .version = -1, \
+ .is_bare = -1, \
+ .hash_algo = GIT_HASH_SHA1, \
+ .unknown_extensions = STRING_LIST_INIT_DUP, \
+ .v1_only_extensions = STRING_LIST_INIT_DUP, \
+}
+
+/*
+ * Read the repository format characteristics from the config file "path" into
+ * "format" struct. Returns the numeric version. On error, or if no version is
+ * found in the configuration, -1 is returned, format->version is set to -1,
+ * and all other fields in the struct are set to the default configuration
+ * (REPOSITORY_FORMAT_INIT). Always initialize the struct using
+ * REPOSITORY_FORMAT_INIT before calling this function.
+ */
+int read_repository_format(struct repository_format *format, const char *path);
+
+/*
+ * Free the memory held onto by `format`, but not the struct itself.
+ * (No need to use this after `read_repository_format()` fails.)
+ */
+void clear_repository_format(struct repository_format *format);
+
+/*
+ * Verify that the repository described by repository_format is something we
+ * can read. If it is, return 0. Otherwise, return -1, and "err" will describe
+ * any errors encountered.
+ */
+int verify_repository_format(const struct repository_format *format,
+ struct strbuf *err);
+
+/*
+ * Check the repository format version in the path found in get_git_dir(),
+ * and die if it is a version we don't understand. Generally one would
+ * set_git_dir() before calling this, and use it only for "are we in a valid
+ * repo?".
+ *
+ * If successful and fmt is not NULL, fill fmt with data.
+ */
+void check_repository_format(struct repository_format *fmt);
+
+#define INIT_DB_QUIET 0x0001
+#define INIT_DB_EXIST_OK 0x0002
+
+int init_db(const char *git_dir, const char *real_git_dir,
+ const char *template_dir, int hash_algo,
+ const char *initial_branch, int init_shared_repository,
+ unsigned int flags);
+void initialize_repository_version(int hash_algo, int reinit);
+
+/*
+ * NOTE NOTE NOTE!!
+ *
+ * PERM_UMASK, OLD_PERM_GROUP and OLD_PERM_EVERYBODY enumerations must
+ * not be changed. Old repositories have core.sharedrepository written in
+ * numeric format, and therefore these values are preserved for compatibility
+ * reasons.
+ */
+enum sharedrepo {
+ PERM_UMASK = 0,
+ OLD_PERM_GROUP = 1,
+ OLD_PERM_EVERYBODY = 2,
+ PERM_GROUP = 0660,
+ PERM_EVERYBODY = 0664
+};
+int git_config_perm(const char *var, const char *value);
+
+struct startup_info {
+ int have_repository;
+ const char *prefix;
+ const char *original_cwd;
+};
+extern struct startup_info *startup_info;
+extern const char *tmp_original_cwd;
+
+#endif /* SETUP_H */
diff --git a/sha1dc_git.c b/sha1dc_git.c
index 5c300e812e..9b675a046e 100644
--- a/sha1dc_git.c
+++ b/sha1dc_git.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "sha1dc_git.h"
+#include "hex.h"
#ifdef DC_SHA1_EXTERNAL
/*
diff --git a/shallow.c b/shallow.c
index 17f9bcdb5f..f3ef94d4c9 100644
--- a/shallow.c
+++ b/shallow.c
@@ -1,20 +1,26 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "hex.h"
#include "repository.h"
#include "tempfile.h"
#include "lockfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "commit.h"
#include "tag.h"
#include "pkt-line.h"
#include "remote.h"
#include "refs.h"
#include "oid-array.h"
+#include "path.h"
#include "diff.h"
#include "revision.h"
#include "commit-slab.h"
#include "list-objects.h"
#include "commit-reach.h"
#include "shallow.h"
+#include "statinfo.h"
+#include "trace.h"
+#include "wrapper.h"
void set_alternate_shallow_file(struct repository *r, const char *path, int override)
{
@@ -30,7 +36,7 @@ int register_shallow(struct repository *r, const struct object_id *oid)
{
struct commit_graft *graft =
xmalloc(sizeof(struct commit_graft));
- struct commit *commit = lookup_commit(the_repository, oid);
+ struct commit *commit = lookup_commit(r, oid);
oidcpy(&graft->oid, oid);
graft->nr_parent = -1;
@@ -247,7 +253,7 @@ struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av,
struct commit *c = p->item;
struct commit_list *parent;
- if (parse_commit(c))
+ if (repo_parse_commit(the_repository, c))
die("unable to parse commit %s",
oid_to_hex(&c->object.oid));
@@ -301,7 +307,7 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
if (graft->nr_parent != -1)
return 0;
if (data->flags & QUICK) {
- if (!has_object_file(&graft->oid))
+ if (!repo_has_object_file(the_repository, &graft->oid))
return 0;
} else if (data->flags & SEEN_ONLY) {
struct commit *c = lookup_commit(the_repository, &graft->oid);
@@ -466,7 +472,7 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
ALLOC_ARRAY(info->ours, sa->nr);
ALLOC_ARRAY(info->theirs, sa->nr);
for (i = 0; i < sa->nr; i++) {
- if (has_object_file(sa->oid + i)) {
+ if (repo_has_object_file(the_repository, sa->oid + i)) {
struct commit_graft *graft;
graft = lookup_commit_graft(the_repository,
&sa->oid[i]);
@@ -494,7 +500,7 @@ void remove_nonexistent_theirs_shallow(struct shallow_info *info)
for (i = dst = 0; i < info->nr_theirs; i++) {
if (i != dst)
info->theirs[dst] = info->theirs[i];
- if (has_object_file(oid + info->theirs[i]))
+ if (repo_has_object_file(the_repository, oid + info->theirs[i]))
dst++;
}
info->nr_theirs = dst;
@@ -583,7 +589,7 @@ static void paint_down(struct paint_info *info, const struct object_id *oid,
if (c->object.flags & BOTTOM)
continue;
- if (parse_commit(c))
+ if (repo_parse_commit(the_repository, c))
die("unable to parse commit %s",
oid_to_hex(&c->object.oid));
@@ -791,7 +797,7 @@ static void post_assign_shallow(struct shallow_info *info,
for (j = 0; j < bitmap_nr; j++)
if (bitmap[0][j] &&
/* Step 7, reachability test at commit level */
- !in_merge_bases_many(c, ca.nr, ca.commits)) {
+ !repo_in_merge_bases_many(the_repository, c, ca.nr, ca.commits)) {
update_refstatus(ref_status, info->ref->nr, *bitmap);
dst++;
break;
@@ -819,9 +825,10 @@ int delayed_reachability_test(struct shallow_info *si, int c)
si->nr_commits = ca.nr;
}
- si->reachable[c] = in_merge_bases_many(commit,
- si->nr_commits,
- si->commits);
+ si->reachable[c] = repo_in_merge_bases_many(the_repository,
+ commit,
+ si->nr_commits,
+ si->commits);
si->need_reachability_test[c] = 0;
}
return si->reachable[c];
diff --git a/shallow.h b/shallow.h
index aba6ff5829..e9ca7e4bc8 100644
--- a/shallow.h
+++ b/shallow.h
@@ -6,6 +6,8 @@
#include "repository.h"
#include "strbuf.h"
+struct oid_array;
+
void set_alternate_shallow_file(struct repository *r, const char *path, int override);
int register_shallow(struct repository *r, const struct object_id *oid);
int unregister_shallow(const struct object_id *oid);
diff --git a/shell.c b/shell.c
index af0d7c734f..5c67e7bd97 100644
--- a/shell.c
+++ b/shell.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "quote.h"
#include "exec-cmd.h"
#include "strbuf.h"
diff --git a/sideband.c b/sideband.c
index 85bddfdcd4..6cbfd391c4 100644
--- a/sideband.c
+++ b/sideband.c
@@ -1,9 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "color.h"
#include "config.h"
+#include "editor.h"
+#include "gettext.h"
#include "sideband.h"
#include "help.h"
#include "pkt-line.h"
+#include "write-or-die.h"
struct keyword_entry {
/*
diff --git a/sigchain.c b/sigchain.c
index 022677b6ab..ee778c0580 100644
--- a/sigchain.c
+++ b/sigchain.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "sigchain.h"
#define SIGCHAIN_MAX_SIGNALS 32
diff --git a/sparse-index.c b/sparse-index.c
index 147a13386a..90d0462256 100644
--- a/sparse-index.c
+++ b/sparse-index.c
@@ -1,4 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "environment.h"
+#include "gettext.h"
+#include "name-hash.h"
+#include "read-cache-ll.h"
#include "repository.h"
#include "sparse-index.h"
#include "tree.h"
@@ -7,7 +12,7 @@
#include "cache-tree.h"
#include "config.h"
#include "dir.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
struct modify_index_context {
struct index_state *write;
diff --git a/sparse-index.h b/sparse-index.h
index 59a92d819e..a16f3e67d7 100644
--- a/sparse-index.h
+++ b/sparse-index.h
@@ -37,4 +37,6 @@ struct pattern_list;
*/
void expand_index(struct index_state *istate, struct pattern_list *pl);
+void ensure_full_index(struct index_state *istate);
+
#endif
diff --git a/split-index.c b/split-index.c
index 5d0f04763e..0ee3865a55 100644
--- a/split-index.c
+++ b/split-index.c
@@ -1,5 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "gettext.h"
+#include "hash.h"
+#include "mem-pool.h"
+#include "read-cache-ll.h"
#include "split-index.h"
+#include "strbuf.h"
#include "ewah/ewok.h"
struct split_index *init_split_index(struct index_state *istate)
diff --git a/split-index.h b/split-index.h
index 7a435ca2c9..15a29cd08c 100644
--- a/split-index.h
+++ b/split-index.h
@@ -1,7 +1,7 @@
#ifndef SPLIT_INDEX_H
#define SPLIT_INDEX_H
-#include "cache.h"
+#include "hash-ll.h"
struct index_state;
struct strbuf;
diff --git a/statinfo.c b/statinfo.c
new file mode 100644
index 0000000000..17bb8966c3
--- /dev/null
+++ b/statinfo.c
@@ -0,0 +1,87 @@
+#include "git-compat-util.h"
+#include "environment.h"
+#include "statinfo.h"
+
+void fill_stat_data(struct stat_data *sd, struct stat *st)
+{
+ sd->sd_ctime.sec = (unsigned int)st->st_ctime;
+ sd->sd_mtime.sec = (unsigned int)st->st_mtime;
+ sd->sd_ctime.nsec = ST_CTIME_NSEC(*st);
+ sd->sd_mtime.nsec = ST_MTIME_NSEC(*st);
+ sd->sd_dev = st->st_dev;
+ sd->sd_ino = st->st_ino;
+ sd->sd_uid = st->st_uid;
+ sd->sd_gid = st->st_gid;
+ sd->sd_size = st->st_size;
+}
+
+int match_stat_data(const struct stat_data *sd, struct stat *st)
+{
+ int changed = 0;
+
+ if (sd->sd_mtime.sec != (unsigned int)st->st_mtime)
+ changed |= MTIME_CHANGED;
+ if (trust_ctime && check_stat &&
+ sd->sd_ctime.sec != (unsigned int)st->st_ctime)
+ changed |= CTIME_CHANGED;
+
+#ifdef USE_NSEC
+ if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
+ if (trust_ctime && check_stat &&
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+#endif
+
+ if (check_stat) {
+ if (sd->sd_uid != (unsigned int) st->st_uid ||
+ sd->sd_gid != (unsigned int) st->st_gid)
+ changed |= OWNER_CHANGED;
+ if (sd->sd_ino != (unsigned int) st->st_ino)
+ changed |= INODE_CHANGED;
+ }
+
+#ifdef USE_STDEV
+ /*
+ * st_dev breaks on network filesystems where different
+ * clients will have different views of what "device"
+ * the filesystem is on
+ */
+ if (check_stat && sd->sd_dev != (unsigned int) st->st_dev)
+ changed |= INODE_CHANGED;
+#endif
+
+ if (sd->sd_size != (unsigned int) st->st_size)
+ changed |= DATA_CHANGED;
+
+ return changed;
+}
+
+void stat_validity_clear(struct stat_validity *sv)
+{
+ FREE_AND_NULL(sv->sd);
+}
+
+int stat_validity_check(struct stat_validity *sv, const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st) < 0)
+ return sv->sd == NULL;
+ if (!sv->sd)
+ return 0;
+ return S_ISREG(st.st_mode) && !match_stat_data(sv->sd, &st);
+}
+
+void stat_validity_update(struct stat_validity *sv, int fd)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode))
+ stat_validity_clear(sv);
+ else {
+ if (!sv->sd)
+ CALLOC_ARRAY(sv->sd, 1);
+ fill_stat_data(sv->sd, &st);
+ }
+}
diff --git a/statinfo.h b/statinfo.h
new file mode 100644
index 0000000000..bb9b61bc47
--- /dev/null
+++ b/statinfo.h
@@ -0,0 +1,75 @@
+#ifndef STATINFO_H
+#define STATINFO_H
+
+struct index_state;
+
+/*
+ * The "cache_time" is just the low 32 bits of the
+ * time. It doesn't matter if it overflows - we only
+ * check it for equality in the 32 bits we save.
+ */
+struct cache_time {
+ uint32_t sec;
+ uint32_t nsec;
+};
+
+struct stat_data {
+ struct cache_time sd_ctime;
+ struct cache_time sd_mtime;
+ unsigned int sd_dev;
+ unsigned int sd_ino;
+ unsigned int sd_uid;
+ unsigned int sd_gid;
+ unsigned int sd_size;
+};
+
+/*
+ * A struct to encapsulate the concept of whether a file has changed
+ * since we last checked it. This uses criteria similar to those used
+ * for the index.
+ */
+struct stat_validity {
+ struct stat_data *sd;
+};
+
+#define MTIME_CHANGED 0x0001
+#define CTIME_CHANGED 0x0002
+#define OWNER_CHANGED 0x0004
+#define MODE_CHANGED 0x0008
+#define INODE_CHANGED 0x0010
+#define DATA_CHANGED 0x0020
+#define TYPE_CHANGED 0x0040
+
+/*
+ * Record to sd the data from st that we use to check whether a file
+ * might have changed.
+ */
+void fill_stat_data(struct stat_data *sd, struct stat *st);
+
+/*
+ * Return 0 if st is consistent with a file not having been changed
+ * since sd was filled. If there are differences, return a
+ * combination of MTIME_CHANGED, CTIME_CHANGED, OWNER_CHANGED,
+ * INODE_CHANGED, and DATA_CHANGED.
+ */
+int match_stat_data(const struct stat_data *sd, struct stat *st);
+
+void stat_validity_clear(struct stat_validity *sv);
+
+/*
+ * Returns 1 if the path is a regular file (or a symlink to a regular
+ * file) and matches the saved stat_validity, 0 otherwise. A missing
+ * or inaccessible file is considered a match if the struct was just
+ * initialized, or if the previous update found an inaccessible file.
+ */
+int stat_validity_check(struct stat_validity *sv, const char *path);
+
+/*
+ * Update the stat_validity from a file opened at descriptor fd. If
+ * the file is missing, inaccessible, or not a regular file, then
+ * future calls to stat_validity_check will match iff one of those
+ * conditions continues to be true.
+ */
+void stat_validity_update(struct stat_validity *sv, int fd);
+
+#endif
diff --git a/strbuf.c b/strbuf.c
index c383f41a3c..37fd5247b3 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -1,8 +1,13 @@
-#include "cache.h"
-#include "refs.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "gettext.h"
+#include "hex.h"
+#include "path.h"
+#include "strbuf.h"
#include "string-list.h"
#include "utf8.h"
#include "date.h"
+#include "wrapper.h"
int starts_with(const char *str, const char *prefix)
{
@@ -357,7 +362,8 @@ static void add_lines(struct strbuf *out,
strbuf_complete_line(out);
}
-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)
+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,
+ size_t size, char comment_line_char)
{
static char prefix1[3];
static char prefix2[2];
@@ -369,7 +375,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size
add_lines(out, prefix1, prefix2, buf, size);
}
-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)
+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,
+ const char *fmt, ...)
{
va_list params;
struct strbuf buf = STRBUF_INIT;
@@ -379,7 +386,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)
strbuf_vaddf(&buf, fmt, params);
va_end(params);
- strbuf_add_commented_lines(sb, buf.buf, buf.len);
+ strbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);
if (incomplete_line)
sb->buf[--sb->len] = '\0';
@@ -803,25 +810,6 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
}
}
-int is_rfc3986_reserved_or_unreserved(char ch)
-{
- if (is_rfc3986_unreserved(ch))
- return 1;
- switch (ch) {
- case '!': case '*': case '\'': case '(': case ')': case ';':
- case ':': case '@': case '&': case '=': case '+': case '$':
- case ',': case '/': case '?': case '#': case '[': case ']':
- return 1;
- }
- return 0;
-}
-
-int is_rfc3986_unreserved(char ch)
-{
- return isalnum(ch) ||
- ch == '-' || ch == '_' || ch == '.' || ch == '~';
-}
-
static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
char_predicate allow_unencoded_fn)
{
@@ -892,42 +880,6 @@ void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)
strbuf_humanise(buf, bytes, 1);
}
-void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
-{
- if (!*path)
- die("The empty string is not a valid path");
- if (!is_absolute_path(path)) {
- struct stat cwd_stat, pwd_stat;
- size_t orig_len = sb->len;
- char *cwd = xgetcwd();
- char *pwd = getenv("PWD");
- if (pwd && strcmp(pwd, cwd) &&
- !stat(cwd, &cwd_stat) &&
- (cwd_stat.st_dev || cwd_stat.st_ino) &&
- !stat(pwd, &pwd_stat) &&
- pwd_stat.st_dev == cwd_stat.st_dev &&
- pwd_stat.st_ino == cwd_stat.st_ino)
- strbuf_addstr(sb, pwd);
- else
- strbuf_addstr(sb, cwd);
- if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))
- strbuf_addch(sb, '/');
- free(cwd);
- }
- strbuf_addstr(sb, path);
-}
-
-void strbuf_add_real_path(struct strbuf *sb, const char *path)
-{
- if (sb->len) {
- struct strbuf resolved = STRBUF_INIT;
- strbuf_realpath(&resolved, path, 1);
- strbuf_addbuf(sb, &resolved);
- strbuf_release(&resolved);
- } else
- strbuf_realpath(sb, path, 1);
-}
-
int printf_ln(const char *fmt, ...)
{
int ret;
@@ -1072,21 +1024,6 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
strbuf_setlen(sb, sb->len + len);
}
-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
- const struct object_id *oid, int abbrev_len)
-{
- int r;
- strbuf_grow(sb, GIT_MAX_HEXSZ + 1);
- r = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);
- strbuf_setlen(sb, sb->len + r);
-}
-
-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
- int abbrev_len)
-{
- strbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);
-}
-
/*
* Returns the length of a line, without trailing spaces.
*
@@ -1116,10 +1053,10 @@ static size_t cleanup(char *line, size_t len)
*
* If last line does not have a newline at the end, one is added.
*
- * Enable skip_comments to skip every line starting with comment
- * character.
+ * Pass a non-NUL comment_line_char to skip every line starting
+ * with it.
*/
-void strbuf_stripspace(struct strbuf *sb, int skip_comments)
+void strbuf_stripspace(struct strbuf *sb, char comment_line_char)
{
size_t empties = 0;
size_t i, j, len, newlen;
@@ -1132,7 +1069,8 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)
eol = memchr(sb->buf + i, '\n', sb->len - i);
len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
- if (skip_comments && len && sb->buf[i] == comment_line_char) {
+ if (comment_line_char && len &&
+ sb->buf[i] == comment_line_char) {
newlen = 0;
continue;
}
@@ -1153,54 +1091,6 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)
strbuf_setlen(sb, j);
}
-int strbuf_normalize_path(struct strbuf *src)
-{
- struct strbuf dst = STRBUF_INIT;
-
- strbuf_grow(&dst, src->len);
- if (normalize_path_copy(dst.buf, src->buf) < 0) {
- strbuf_release(&dst);
- return -1;
- }
-
- /*
- * normalize_path does not tell us the new length, so we have to
- * compute it by looking for the new NUL it placed
- */
- strbuf_setlen(&dst, strlen(dst.buf));
- strbuf_swap(src, &dst);
- strbuf_release(&dst);
- return 0;
-}
-
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
- const char *const *env)
-{
- char *path2 = NULL;
- int fd, res = 0;
-
- if (!is_absolute_path(path))
- path = path2 = xstrdup(git_path("%s", path));
-
- fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0)
- res = error_errno(_("could not open '%s' for writing"), path);
- else if (write_in_full(fd, buffer->buf, buffer->len) < 0) {
- res = error_errno(_("could not write to '%s'"), path);
- close(fd);
- } else if (close(fd) < 0)
- res = error_errno(_("could not close '%s'"), path);
- else {
- strbuf_reset(buffer);
- if (launch_editor(path, buffer, env) < 0)
- res = error_errno(_("could not edit '%s'"), path);
- unlink(path);
- }
-
- free(path2);
- return res;
-}
-
void strbuf_strip_file_from_path(struct strbuf *sb)
{
char *path_sep = find_last_dir_sep(sb->buf);
diff --git a/strbuf.h b/strbuf.h
index f6dbb9681e..8903195416 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -1,6 +1,14 @@
#ifndef STRBUF_H
#define STRBUF_H
+/*
+ * NOTE FOR STRBUF DEVELOPERS
+ *
+ * strbuf is a low-level primitive; as such it should interact only
+ * with other low-level primitives. Do not introduce new functions
+ * which interact with higher-level APIs.
+ */
+
struct string_list;
/**
@@ -72,10 +80,6 @@ struct strbuf {
extern char strbuf_slopbuf[];
#define STRBUF_INIT { .buf = strbuf_slopbuf }
-/*
- * Predeclare this here, since cache.h includes this file before it defines the
- * struct.
- */
struct object_id;
/**
@@ -283,7 +287,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
* by a comment character and a blank.
*/
void strbuf_add_commented_lines(struct strbuf *out,
- const char *buf, size_t size);
+ const char *buf, size_t size,
+ char comment_line_char);
/**
@@ -412,8 +417,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
* Add a formatted string prepended by a comment character and a
* blank to the buffer.
*/
-__attribute__((format (printf, 2, 3)))
-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);
+__attribute__((format (printf, 3, 4)))
+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);
__attribute__((format (printf,2,0)))
void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
@@ -528,28 +533,6 @@ int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);
int strbuf_getcwd(struct strbuf *sb);
/**
- * Add a path to a buffer, converting a relative path to an
- * absolute one in the process. Symbolic links are not
- * resolved.
- */
-void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
-
-/**
- * Canonize `path` (make it absolute, resolve symlinks, remove extra
- * slashes) and append it to `sb`. Die with an informative error
- * message if there is a problem.
- *
- * The directory part of `path` (i.e., everything up to the last
- * dir_sep) must denote a valid, existing directory, but the last
- * component need not exist.
- *
- * Callers that don't mind links should use the more lightweight
- * strbuf_add_absolute_path() instead.
- */
-void strbuf_add_real_path(struct strbuf *sb, const char *path);
-
-
-/**
* Normalize in-place the path contained in the strbuf. See
* normalize_path_copy() for details. If an error occurs, the contents of "sb"
* are left untouched, and -1 is returned.
@@ -557,10 +540,11 @@ void strbuf_add_real_path(struct strbuf *sb, const char *path);
int strbuf_normalize_path(struct strbuf *sb);
/**
- * Strip whitespace from a buffer. The second parameter controls if
- * comments are considered contents to be removed or not.
+ * Strip whitespace from a buffer. If comment_line_char is non-NUL,
+ * then lines beginning with that character are considered comments,
+ * thus removed.
*/
-void strbuf_stripspace(struct strbuf *buf, int skip_comments);
+void strbuf_stripspace(struct strbuf *buf, char comment_line_char);
static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
{
@@ -630,40 +614,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,
*/
void strbuf_list_free(struct strbuf **list);
-/**
- * Add the abbreviation, as generated by find_unique_abbrev, of `sha1` to
- * the strbuf `sb`.
- */
-struct repository;
-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
- const struct object_id *oid, int abbrev_len);
-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
- int abbrev_len);
-
-/**
- * Launch the user preferred editor to edit a file and fill the buffer
- * with the file's contents upon the user completing their editing. The
- * third argument can be used to set the environment which the editor is
- * run in. If the buffer is NULL the editor is launched as usual but the
- * file's contents are not read into the buffer upon completion.
- */
-int launch_editor(const char *path, struct strbuf *buffer,
- const char *const *env);
-
-int launch_sequence_editor(const char *path, struct strbuf *buffer,
- const char *const *env);
-
-/*
- * In contrast to `launch_editor()`, this function writes out the contents
- * of the specified file first, then clears the `buffer`, then launches
- * the editor and reads back in the file contents into the `buffer`.
- * Finally, it deletes the temporary file.
- *
- * If `path` is relative, it refers to a file in the `.git` directory.
- */
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
- const char *const *env);
-
/*
* Remove the filename from the provided path string. If the path
* contains a trailing separator, then the path is considered a directory
@@ -706,14 +656,14 @@ static inline void strbuf_complete_line(struct strbuf *sb)
/*
* Copy "name" to "sb", expanding any special @-marks as handled by
- * interpret_branch_name(). The result is a non-qualified branch name
+ * repo_interpret_branch_name(). The result is a non-qualified branch name
* (so "foo" or "origin/master" instead of "refs/heads/foo" or
* "refs/remotes/origin/master").
*
* Note that the resulting name may not be a syntactically valid refname.
*
* If "allowed" is non-zero, restrict the set of allowed expansions. See
- * interpret_branch_name() for details.
+ * repo_interpret_branch_name() for details.
*/
void strbuf_branchname(struct strbuf *sb, const char *name,
unsigned allowed);
@@ -728,9 +678,6 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
typedef int (*char_predicate)(char ch);
-int is_rfc3986_unreserved(char ch);
-int is_rfc3986_reserved_or_unreserved(char ch);
-
void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,
char_predicate allow_unencoded_fn);
diff --git a/streaming.c b/streaming.c
index 27841dc1d9..49791ab958 100644
--- a/streaming.c
+++ b/streaming.c
@@ -1,12 +1,16 @@
/*
* Copyright (c) 2011, Google Inc.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "convert.h"
+#include "environment.h"
#include "streaming.h"
#include "repository.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "replace-object.h"
#include "packfile.h"
+#include "wrapper.h"
typedef int (*open_istream_fn)(struct git_istream *,
struct repository *,
diff --git a/streaming.h b/streaming.h
index 5e4e6acfd0..bd27f59e57 100644
--- a/streaming.h
+++ b/streaming.h
@@ -3,10 +3,12 @@
*/
#ifndef STREAMING_H
#define STREAMING_H 1
-#include "cache.h"
+
+#include "object.h"
/* opaque */
struct git_istream;
+struct stream_filter;
struct git_istream *open_istream(struct repository *, const struct object_id *,
enum object_type *, unsigned long *,
diff --git a/string-list.c b/string-list.c
index 42bacaec55..0f8ac117fd 100644
--- a/string-list.c
+++ b/string-list.c
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "string-list.h"
+#include "alloc.h"
void string_list_init_nodup(struct string_list *list)
{
@@ -202,6 +203,15 @@ void string_list_clear_func(struct string_list *list, string_list_clear_func_t c
list->nr = list->alloc = 0;
}
+void string_list_setlen(struct string_list *list, size_t nr)
+{
+ if (list->strdup_strings)
+ BUG("cannot setlen a string_list which owns its entries");
+ if (nr > list->nr)
+ BUG("cannot grow a string_list with setlen");
+ list->nr = nr;
+}
+
struct string_list_item *string_list_append_nodup(struct string_list *list,
char *string)
{
@@ -300,7 +310,7 @@ int string_list_split(struct string_list *list, const char *string,
}
int string_list_split_in_place(struct string_list *list, char *string,
- int delim, int maxsplit)
+ const char *delim, int maxsplit)
{
int count = 0;
char *p = string, *end;
@@ -314,7 +324,7 @@ int string_list_split_in_place(struct string_list *list, char *string,
string_list_append(list, p);
return count;
}
- end = strchr(p, delim);
+ end = strpbrk(p, delim);
if (end) {
*end = '\0';
string_list_append(list, p);
diff --git a/string-list.h b/string-list.h
index c7b0d5d000..122b318641 100644
--- a/string-list.h
+++ b/string-list.h
@@ -134,6 +134,16 @@ typedef void (*string_list_clear_func_t)(void *p, const char *str);
/** Call a custom clear function on each util pointer */
void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc);
+/*
+ * Set the length of a string_list to `nr`, provided that (a) `list`
+ * does not own its own storage, and (b) that `nr` is no larger than
+ * `list->nr`.
+ *
+ * Useful when "shrinking" `list` to write over existing entries that
+ * are no longer used without reallocating.
+ */
+void string_list_setlen(struct string_list *list, size_t nr);
+
/**
* Apply `func` to each item. If `func` returns nonzero, the
* iteration aborts and the return value is propagated.
@@ -270,5 +280,5 @@ int string_list_split(struct string_list *list, const char *string,
* list->strdup_strings must *not* be set.
*/
int string_list_split_in_place(struct string_list *list, char *string,
- int delim, int maxsplit);
+ const char *delim, int maxsplit);
#endif /* STRING_LIST_H */
diff --git a/strvec.c b/strvec.c
index 61a76ce6cb..17d54b6c3b 100644
--- a/strvec.c
+++ b/strvec.c
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "strvec.h"
+#include "alloc.h"
+#include "hex.h"
#include "strbuf.h"
const char *empty_strvec[] = { NULL };
diff --git a/sub-process.c b/sub-process.c
index 6d4232294d..1daf5a9752 100644
--- a/sub-process.c
+++ b/sub-process.c
@@ -1,6 +1,7 @@
/*
* Generic implementation of background process infrastructure.
*/
+#include "git-compat-util.h"
#include "sub-process.h"
#include "sigchain.h"
#include "pkt-line.h"
diff --git a/sub-process.h b/sub-process.h
index e85f21fa1a..6a61638a8a 100644
--- a/sub-process.h
+++ b/sub-process.h
@@ -1,7 +1,6 @@
#ifndef SUBPROCESS_H
#define SUBPROCESS_H
-#include "git-compat-util.h"
#include "hashmap.h"
#include "run-command.h"
diff --git a/submodule-config.c b/submodule-config.c
index 4dc61b3a78..1efd547169 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -1,12 +1,19 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "path.h"
#include "repository.h"
#include "config.h"
#include "submodule-config.h"
#include "submodule.h"
#include "strbuf.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "parse-options.h"
+#include "thread-utils.h"
#include "tree-walk.h"
/*
@@ -535,7 +542,7 @@ static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
}
strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
- if (get_oid(rev->buf, gitmodules_oid) >= 0)
+ if (repo_get_oid(the_repository, rev->buf, gitmodules_oid) >= 0)
ret = 1;
return ret;
@@ -588,7 +595,8 @@ static const struct submodule *config_from(struct submodule_cache *cache,
if (submodule)
goto out;
- config = read_object_file(&oid, &type, &config_size);
+ config = repo_read_object_file(the_repository, &oid, &type,
+ &config_size);
if (!config || type != OBJ_BLOB)
goto out;
diff --git a/submodule-config.h b/submodule-config.h
index 28a8ca6bf4..c2045875bb 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -1,7 +1,6 @@
#ifndef SUBMODULE_CONFIG_CACHE_H
#define SUBMODULE_CONFIG_CACHE_H
-#include "cache.h"
#include "config.h"
#include "hashmap.h"
#include "submodule.h"
diff --git a/submodule.c b/submodule.c
index 3a0dfc417c..a42b3bc70f 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1,5 +1,6 @@
-
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
#include "repository.h"
#include "config.h"
#include "submodule-config.h"
@@ -7,6 +8,9 @@
#include "dir.h"
#include "diff.h"
#include "commit.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "revision.h"
#include "run-command.h"
#include "diffcore.h"
@@ -16,18 +20,28 @@
#include "strvec.h"
#include "blob.h"
#include "thread-utils.h"
+#include "path.h"
#include "quote.h"
#include "remote.h"
#include "worktree.h"
#include "parse-options.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "commit-reach.h"
+#include "read-cache-ll.h"
+#include "setup.h"
#include "shallow.h"
+#include "trace2.h"
static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
static int initialized_fetch_ref_tips;
static struct oid_array ref_tips_before_fetch;
static struct oid_array ref_tips_after_fetch;
+#define STATUS_PORCELAIN_START_ERROR \
+ N_("could not run 'git status --porcelain=2' in submodule %s")
+#define STATUS_PORCELAIN_FAIL_ERROR \
+ N_("'git status --porcelain=2' failed in submodule %s")
/*
* Check if the .gitmodules file is unmerged. Parsing of the .gitmodules file
@@ -65,7 +79,7 @@ int is_writing_gitmodules_ok(void)
{
struct object_id oid;
return file_exists(GITMODULES_FILE) ||
- (get_oid(GITMODULES_INDEX, &oid) < 0 && get_oid(GITMODULES_HEAD, &oid) < 0);
+ (repo_get_oid(the_repository, GITMODULES_INDEX, &oid) < 0 && repo_get_oid(the_repository, GITMODULES_HEAD, &oid) < 0);
}
/*
@@ -274,8 +288,7 @@ int is_tree_submodule_active(struct repository *repo,
free(key);
/* submodule.active is set */
- sl = repo_config_get_value_multi(repo, "submodule.active");
- if (sl) {
+ if (!repo_config_get_string_multi(repo, "submodule.active", &sl)) {
struct pathspec ps;
struct strvec args = STRVEC_INIT;
const struct string_list_item *item;
@@ -1369,6 +1382,13 @@ int submodule_touches_in_range(struct repository *r,
return ret;
}
+struct submodule_parallel_status {
+ size_t index_count;
+ int result;
+
+ struct string_list *submodule_names;
+};
+
struct submodule_parallel_fetch {
/*
* The index of the last index entry processed by
@@ -1451,6 +1471,12 @@ struct fetch_task {
struct oid_array *commits; /* Ensure these commits are fetched */
};
+struct status_task {
+ const char *path;
+ struct strbuf out;
+ int ignore_untracked;
+};
+
/**
* When a submodule is not defined in .gitmodules, we cannot access it
* via the regular submodule-config. Create a fake submodule, which we can
@@ -1625,7 +1651,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
if (!task->repo) {
strbuf_addf(err, _("Could not access submodule '%s' at commit %s\n"),
cs_data->path,
- find_unique_abbrev(cs_data->super_oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, cs_data->super_oid, DEFAULT_ABBREV));
fetch_task_release(task);
free(task);
@@ -1636,8 +1662,8 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
strbuf_addf(err,
_("Fetching submodule %s%s at commit %s\n"),
spf->prefix, task->sub->path,
- find_unique_abbrev(cs_data->super_oid,
- DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, cs_data->super_oid,
+ DEFAULT_ABBREV));
spf->changed_count++;
/*
@@ -1739,7 +1765,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
return 0;
}
-static int fetch_start_failure(struct strbuf *err,
+static int fetch_start_failure(struct strbuf *err UNUSED,
void *cb, void *task_cb)
{
struct submodule_parallel_fetch *spf = cb;
@@ -1760,7 +1786,7 @@ static int commit_missing_in_sub(const struct object_id *oid, void *data)
return type != OBJ_COMMIT;
}
-static int fetch_finish(int retvalue, struct strbuf *err,
+static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
void *cb, void *task_cb)
{
struct submodule_parallel_fetch *spf = cb;
@@ -1870,14 +1896,10 @@ out:
return spf.result;
}
-unsigned is_submodule_modified(const char *path, int ignore_untracked)
+static int verify_submodule_git_directory(const char *path)
{
- struct child_process cp = CHILD_PROCESS_INIT;
- struct strbuf buf = STRBUF_INIT;
- FILE *fp;
- unsigned dirty_submodule = 0;
const char *git_dir;
- int ignore_cp_exit_code = 0;
+ struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%s/.git", path);
git_dir = read_gitfile(buf.buf);
@@ -1890,65 +1912,212 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
/* The submodule is not checked out, so it is not modified */
return 0;
}
- strbuf_reset(&buf);
+ strbuf_release(&buf);
+ return 1;
+}
- strvec_pushl(&cp.args, "status", "--porcelain=2", NULL);
+static void prepare_status_porcelain(struct child_process *cp,
+ const char *path, int ignore_untracked)
+{
+ strvec_pushl(&cp->args, "status", "--porcelain=2", NULL);
if (ignore_untracked)
- strvec_push(&cp.args, "-uno");
+ strvec_push(&cp->args, "-uno");
+
+ prepare_submodule_repo_env(&cp->env);
+ cp->git_cmd = 1;
+ cp->no_stdin = 1;
+ cp->out = -1;
+ cp->dir = path;
+}
+
+static int parse_status_porcelain(char *str, size_t len,
+ unsigned *dirty_submodule,
+ int ignore_untracked)
+{
+ /* regular untracked files */
+ if (str[0] == '?')
+ *dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
+
+ if (str[0] == 'u' ||
+ str[0] == '1' ||
+ str[0] == '2') {
+ /* T = line type, XY = status, SSSS = submodule state */
+ if (len < strlen("T XY SSSS"))
+ BUG("invalid status --porcelain=2 line %s",
+ str);
+
+ if (str[5] == 'S' && str[8] == 'U')
+ /* nested untracked file */
+ *dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
+
+ if (str[0] == 'u' ||
+ str[0] == '2' ||
+ memcmp(str + 5, "S..U", 4))
+ /* other change */
+ *dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
+ }
- prepare_submodule_repo_env(&cp.env);
- cp.git_cmd = 1;
- cp.no_stdin = 1;
- cp.out = -1;
- cp.dir = path;
+ if ((*dirty_submodule & DIRTY_SUBMODULE_MODIFIED) &&
+ ((*dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) ||
+ ignore_untracked)) {
+ /*
+ * We're not interested in any further information from
+ * the child any more, neither output nor its exit code.
+ */
+ return 1;
+ }
+ return 0;
+}
+
+unsigned is_submodule_modified(const char *path, int ignore_untracked)
+{
+ struct child_process cp = CHILD_PROCESS_INIT;
+ struct strbuf buf = STRBUF_INIT;
+ FILE *fp;
+ unsigned dirty_submodule = 0;
+ int ignore_cp_exit_code = 0;
+
+ if (!verify_submodule_git_directory(path))
+ return 0;
+
+ prepare_status_porcelain(&cp, path, ignore_untracked);
if (start_command(&cp))
- die(_("Could not run 'git status --porcelain=2' in submodule %s"), path);
+ die(_(STATUS_PORCELAIN_START_ERROR), path);
fp = xfdopen(cp.out, "r");
while (strbuf_getwholeline(&buf, fp, '\n') != EOF) {
- /* regular untracked files */
- if (buf.buf[0] == '?')
- dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
-
- if (buf.buf[0] == 'u' ||
- buf.buf[0] == '1' ||
- buf.buf[0] == '2') {
- /* T = line type, XY = status, SSSS = submodule state */
- if (buf.len < strlen("T XY SSSS"))
- BUG("invalid status --porcelain=2 line %s",
- buf.buf);
-
- if (buf.buf[5] == 'S' && buf.buf[8] == 'U')
- /* nested untracked file */
- dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
-
- if (buf.buf[0] == 'u' ||
- buf.buf[0] == '2' ||
- memcmp(buf.buf + 5, "S..U", 4))
- /* other change */
- dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
- }
+ char *str = buf.buf;
+ const size_t len = buf.len;
- if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) &&
- ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) ||
- ignore_untracked)) {
- /*
- * We're not interested in any further information from
- * the child any more, neither output nor its exit code.
- */
- ignore_cp_exit_code = 1;
+ ignore_cp_exit_code = parse_status_porcelain(str, len, &dirty_submodule,
+ ignore_untracked);
+ if (ignore_cp_exit_code)
break;
- }
}
fclose(fp);
if (finish_command(&cp) && !ignore_cp_exit_code)
- die(_("'git status --porcelain=2' failed in submodule %s"), path);
+ die(_(STATUS_PORCELAIN_FAIL_ERROR), path);
strbuf_release(&buf);
return dirty_submodule;
}
+static struct status_task *
+get_status_task_from_index(struct submodule_parallel_status *sps,
+ struct strbuf *err)
+{
+ for (; sps->index_count < sps->submodule_names->nr; sps->index_count++) {
+ struct submodule_status_util *util = sps->submodule_names->items[sps->index_count].util;
+ struct status_task *task;
+
+ if (!verify_submodule_git_directory(util->path))
+ continue;
+
+ task = xmalloc(sizeof(*task));
+ task->path = util->path;
+ task->ignore_untracked = util->ignore_untracked;
+ strbuf_init(&task->out, 0);
+ sps->index_count++;
+ return task;
+ }
+ return NULL;
+}
+
+static int get_next_submodule_status(struct child_process *cp,
+ struct strbuf *err, void *data,
+ void **task_cb)
+{
+ struct submodule_parallel_status *sps = data;
+ struct status_task *task = get_status_task_from_index(sps, err);
+
+ if (!task)
+ return 0;
+
+ child_process_init(cp);
+ prepare_submodule_repo_env_in_gitdir(&cp->env);
+ prepare_status_porcelain(cp, task->path, task->ignore_untracked);
+ *task_cb = task;
+ return 1;
+}
+
+static int status_start_failure(struct strbuf *err,
+ void *cb, void *task_cb)
+{
+ struct submodule_parallel_status *sps = cb;
+ struct status_task *task = task_cb;
+
+ sps->result = 1;
+ strbuf_addf(err, _(STATUS_PORCELAIN_START_ERROR), task->path);
+ return 0;
+}
+
+static void status_on_stderr_output(struct strbuf *out,
+ size_t offset,
+ void *cb, void *task_cb)
+{
+ struct status_task *task = task_cb;
+
+ strbuf_add(&task->out, out->buf + offset, out->len - offset);
+ strbuf_setlen(out, offset);
+}
+
+static int status_finish(int retvalue, struct strbuf *err,
+ void *cb, void *task_cb)
+{
+ struct submodule_parallel_status *sps = cb;
+ struct status_task *task = task_cb;
+ struct string_list_item *it =
+ string_list_lookup(sps->submodule_names, task->path);
+ struct submodule_status_util *util = it->util;
+ struct string_list list = STRING_LIST_INIT_DUP;
+ struct string_list_item *item;
+
+ if (retvalue) {
+ sps->result = 1;
+ strbuf_addf(err, _(STATUS_PORCELAIN_FAIL_ERROR), task->path);
+ }
+
+ string_list_split(&list, task->out.buf, '\n', -1);
+ for_each_string_list_item(item, &list) {
+ if (parse_status_porcelain(item->string,
+ strlen(item->string),
+ &util->dirty_submodule,
+ util->ignore_untracked))
+ break;
+ }
+ string_list_clear(&list, 0);
+ strbuf_release(&task->out);
+ free(task);
+
+ return 0;
+}
+
+int get_submodules_status(struct string_list *submodules,
+ int max_parallel_jobs)
+{
+ struct submodule_parallel_status sps = {
+ .submodule_names = submodules,
+ };
+ const struct run_process_parallel_opts opts = {
+ .tr2_category = "submodule",
+ .tr2_label = "parallel/status",
+
+ .processes = max_parallel_jobs,
+
+ .get_next_task = get_next_submodule_status,
+ .start_failure = status_start_failure,
+ .on_stderr_output = status_on_stderr_output,
+ .task_finished = status_finish,
+ .data = &sps,
+ };
+
+ string_list_sort(sps.submodule_names);
+ run_processes_parallel(&opts);
+
+ return sps.result;
+}
+
int submodule_uses_gitfile(const char *path)
{
struct child_process cp = CHILD_PROCESS_INIT;
diff --git a/submodule.h b/submodule.h
index c55a25ca37..3b6abca05c 100644
--- a/submodule.h
+++ b/submodule.h
@@ -41,6 +41,13 @@ struct submodule_update_strategy {
.type = SM_UPDATE_UNSPECIFIED, \
}
+struct submodule_status_util {
+ int changed, ignore_untracked;
+ unsigned dirty_submodule, newmode;
+ struct cache_entry *ce;
+ const char *path;
+};
+
int is_gitmodules_unmerged(struct index_state *istate);
int is_writing_gitmodules_ok(void);
int is_staging_gitmodules_ok(struct index_state *istate);
@@ -94,6 +101,8 @@ int fetch_submodules(struct repository *r,
int command_line_option,
int default_option,
int quiet, int max_parallel_jobs);
+int get_submodules_status(struct string_list *submodules,
+ int max_parallel_jobs);
unsigned is_submodule_modified(const char *path, int ignore_untracked);
int submodule_uses_gitfile(const char *path);
diff --git a/symlinks.c b/symlinks.c
index c667baa949..b29e340c2d 100644
--- a/symlinks.c
+++ b/symlinks.c
@@ -1,4 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "setup.h"
+#include "symlinks.h"
static int threaded_check_leading_path(struct cache_def *cache, const char *name,
int len, int warn_on_lstat_err);
diff --git a/symlinks.h b/symlinks.h
new file mode 100644
index 0000000000..7ae3d5b856
--- /dev/null
+++ b/symlinks.h
@@ -0,0 +1,28 @@
+#ifndef SYMLINKS_H
+#define SYMLINKS_H
+
+#include "strbuf.h"
+
+struct cache_def {
+ struct strbuf path;
+ int flags;
+ int track_flags;
+ int prefix_len_stat_func;
+};
+#define CACHE_DEF_INIT { \
+ .path = STRBUF_INIT, \
+}
+static inline void cache_def_clear(struct cache_def *cache)
+{
+ strbuf_release(&cache->path);
+}
+
+int has_symlink_leading_path(const char *name, int len);
+int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
+int check_leading_path(const char *name, int len, int warn_on_lstat_err);
+int has_dirs_only_path(const char *name, int len, int prefix_len);
+void invalidate_lstat_cache(void);
+void schedule_dir_for_removal(const char *name, int len);
+void remove_scheduled_dirs(void);
+
+#endif /* SYMLINKS_H */
diff --git a/t/Makefile b/t/Makefile
index 2c2b252240..3e00cdd801 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -44,8 +44,8 @@ CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl
# `test-chainlint` (which is a dependency of `test-lint`, `test` and `prove`)
# checks all tests in all scripts via a single invocation, so tell individual
-# scripts not to "chainlint" themselves
-CHAINLINTSUPPRESS = GIT_TEST_CHAIN_LINT=0 && export GIT_TEST_CHAIN_LINT &&
+# scripts not to run the external "chainlint.pl" script themselves
+CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT &&
all: $(DEFAULT_TEST_TARGET)
@@ -140,9 +140,7 @@ aggregate-results-and-cleanup: $(T)
$(MAKE) clean
aggregate-results:
- for f in '$(TEST_RESULTS_DIRECTORY_SQ)'/t*-*.counts; do \
- echo "$$f"; \
- done | '$(SHELL_PATH_SQ)' ./aggregate-results.sh
+ @'$(SHELL_PATH_SQ)' ./aggregate-results.sh '$(TEST_RESULTS_DIRECTORY_SQ)'
valgrind:
$(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind"
diff --git a/t/README b/t/README
index 29576c3748..bdfac4cceb 100644
--- a/t/README
+++ b/t/README
@@ -475,7 +475,7 @@ GIT_TEST_DEFAULT_HASH=<hash-algo> specifies which hash algorithm to
use in the test scripts. Recognized values for <hash-algo> are "sha1"
and "sha256".
-GIT_TEST_WRITE_REV_INDEX=<boolean>, when true enables the
+GIT_TEST_NO_WRITE_REV_INDEX=<boolean>, when true disables the
'pack.writeReverseIndex' setting.
GIT_TEST_SPARSE_INDEX=<boolean>, when true enables index writes to use the
diff --git a/t/aggregate-results.sh b/t/aggregate-results.sh
index 7f2b83bdc8..6e3bcc4aec 100755
--- a/t/aggregate-results.sh
+++ b/t/aggregate-results.sh
@@ -8,7 +8,7 @@ broken=0
total=0
missing_prereq=
-while read file
+for file in "$1"/t*-*.counts
do
while read type value
do
diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh
index f1b9a6ce4d..2ef70235b1 100644
--- a/t/annotate-tests.sh
+++ b/t/annotate-tests.sh
@@ -72,6 +72,23 @@ test_expect_success 'blame 1 author' '
check_count A 2
'
+test_expect_success 'blame working copy' '
+ test_when_finished "git restore file" &&
+ echo "1A quick brown fox jumps over the" >file &&
+ echo "another lazy dog" >>file &&
+ check_count A 1 "Not Committed Yet" 1
+'
+
+test_expect_success 'blame with --contents' '
+ check_count --contents=file A 2
+'
+
+test_expect_success 'blame with --contents changed' '
+ echo "1A quick brown fox jumps over the" >contents &&
+ echo "another lazy dog" >>contents &&
+ check_count --contents=contents A 1 "External file (--contents)" 1
+'
+
test_expect_success 'blame in a bare repo without starting commit' '
git clone --bare . bare.git &&
(
@@ -98,6 +115,10 @@ test_expect_success 'blame 2 authors' '
check_count A 2 B 2
'
+test_expect_success 'blame with --contents and revision' '
+ check_count -h testTag --contents=file A 2 "External file (--contents)" 2
+'
+
test_expect_success 'setup B1 lines (branch1)' '
git checkout -b branch1 main &&
echo "3A slow green fox jumps into the" >>file &&
diff --git a/t/chainlint.pl b/t/chainlint.pl
index e966412999..556ee91a15 100755
--- a/t/chainlint.pl
+++ b/t/chainlint.pl
@@ -80,7 +80,8 @@ sub scan_heredoc_tag {
return "<<$indented" unless $token;
my $tag = $token->[0];
$tag =~ s/['"\\]//g;
- push(@{$self->{heretags}}, $indented ? "\t$tag" : "$tag");
+ $$token[0] = $indented ? "\t$tag" : "$tag";
+ push(@{$self->{heretags}}, $token);
return "<<$indented$tag";
}
@@ -169,10 +170,18 @@ sub swallow_heredocs {
my $tags = $self->{heretags};
while (my $tag = shift @$tags) {
my $start = pos($$b);
- my $indent = $tag =~ s/^\t// ? '\\s*' : '';
- $$b =~ /(?:\G|\n)$indent\Q$tag\E(?:\n|\z)/gc;
+ my $indent = $$tag[0] =~ s/^\t// ? '\\s*' : '';
+ $$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc;
+ if (pos($$b) > $start) {
+ my $body = substr($$b, $start, pos($$b) - $start);
+ $self->{lineno} += () = $body =~ /\n/sg;
+ next;
+ }
+ push(@{$self->{parser}->{problems}}, ['UNCLOSED-HEREDOC', $tag]);
+ $$b =~ /(?:\G|\n).*\z/gc; # consume rest of input
my $body = substr($$b, $start, pos($$b) - $start);
$self->{lineno} += () = $body =~ /\n/sg;
+ last;
}
}
diff --git a/t/chainlint/unclosed-here-doc-indent.expect b/t/chainlint/unclosed-here-doc-indent.expect
new file mode 100644
index 0000000000..7c30a1a024
--- /dev/null
+++ b/t/chainlint/unclosed-here-doc-indent.expect
@@ -0,0 +1,4 @@
+command_which_is_run &&
+cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! &&
+we forget to end the here-doc
+command_which_is_gobbled
diff --git a/t/chainlint/unclosed-here-doc-indent.test b/t/chainlint/unclosed-here-doc-indent.test
new file mode 100644
index 0000000000..5c841a9dfd
--- /dev/null
+++ b/t/chainlint/unclosed-here-doc-indent.test
@@ -0,0 +1,4 @@
+command_which_is_run &&
+cat >expect <<-\EOF &&
+we forget to end the here-doc
+command_which_is_gobbled
diff --git a/t/chainlint/unclosed-here-doc.expect b/t/chainlint/unclosed-here-doc.expect
new file mode 100644
index 0000000000..d65e50f78d
--- /dev/null
+++ b/t/chainlint/unclosed-here-doc.expect
@@ -0,0 +1,7 @@
+command_which_is_run &&
+cat >expect <<\EOF ?!UNCLOSED-HEREDOC?! &&
+ we try to end the here-doc below,
+ but the indentation throws us off
+ since the operator is not "<<-".
+ EOF
+command_which_is_gobbled
diff --git a/t/chainlint/unclosed-here-doc.test b/t/chainlint/unclosed-here-doc.test
new file mode 100644
index 0000000000..69d3786c34
--- /dev/null
+++ b/t/chainlint/unclosed-here-doc.test
@@ -0,0 +1,7 @@
+command_which_is_run &&
+cat >expect <<\EOF &&
+ we try to end the here-doc below,
+ but the indentation throws us off
+ since the operator is not "<<-".
+ EOF
+command_which_is_gobbled
diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c
index cb881139f7..8a3fd0009a 100644
--- a/t/helper/test-advise.c
+++ b/t/helper/test-advise.c
@@ -1,7 +1,7 @@
#include "test-tool.h"
-#include "cache.h"
#include "advice.h"
#include "config.h"
+#include "setup.h"
int cmd__advise_if_enabled(int argc, const char **argv)
{
diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c
index ff35f5999b..af43ee1cb5 100644
--- a/t/helper/test-bitmap.c
+++ b/t/helper/test-bitmap.c
@@ -1,6 +1,7 @@
#include "test-tool.h"
-#include "cache.h"
+#include "git-compat-util.h"
#include "pack-bitmap.h"
+#include "setup.h"
static int bitmap_list_commits(void)
{
diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c
index 6c900ca668..aabe31d724 100644
--- a/t/helper/test-bloom.c
+++ b/t/helper/test-bloom.c
@@ -1,7 +1,9 @@
-#include "git-compat-util.h"
-#include "bloom.h"
#include "test-tool.h"
+#include "bloom.h"
+#include "hex.h"
#include "commit.h"
+#include "repository.h"
+#include "setup.h"
static struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c
index b18e760310..475058592d 100644
--- a/t/helper/test-bundle-uri.c
+++ b/t/helper/test-bundle-uri.c
@@ -1,6 +1,7 @@
#include "test-tool.h"
#include "parse-options.h"
#include "bundle-uri.h"
+#include "gettext.h"
#include "strbuf.h"
#include "string-list.h"
#include "transport.h"
diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c
index 9159a17301..e7236392c8 100644
--- a/t/helper/test-cache-tree.c
+++ b/t/helper/test-cache-tree.c
@@ -1,9 +1,13 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hex.h"
#include "tree.h"
#include "cache-tree.h"
#include "parse-options.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
static char const * const test_cache_tree_usage[] = {
N_("test-tool cache-tree <options> (control|prime|update)"),
diff --git a/t/helper/test-chmtime.c b/t/helper/test-chmtime.c
index dc28890a18..0e5538833a 100644
--- a/t/helper/test-chmtime.c
+++ b/t/helper/test-chmtime.c
@@ -94,7 +94,7 @@ int cmd__chmtime(int argc, const char **argv)
if (timespec_arg(argv[i], &set_time, &set_eq)) {
++i;
} else {
- if (get == 0) {
+ if (get == 0 && verbose == 0) {
fprintf(stderr, "Not a base-10 integer: %s\n", argv[i] + 1);
goto usage;
}
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index 4ba9eb6560..ad78fc1768 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -1,6 +1,6 @@
#include "test-tool.h"
-#include "cache.h"
#include "config.h"
+#include "setup.h"
#include "string-list.h"
/*
@@ -14,6 +14,8 @@
* get_value_multi -> prints all values for the entered key in increasing order
* of priority
*
+ * get -> print return value for the entered key
+ *
* get_int -> print integer value for the entered key or die
*
* get_bool -> print bool value for the entered key or die
@@ -30,6 +32,9 @@
* iterate -> iterate over all values using git_config(), and print some
* data for each
*
+ * git_config_int -> iterate over all values using git_config() and print the
+ * integer value for the entered key or die
+ *
* Examples:
*
* To print the value with highest priority for key "foo.bAr Baz.rock":
@@ -54,6 +59,17 @@ static int iterate_cb(const char *var, const char *value, void *data UNUSED)
return 0;
}
+static int parse_int_cb(const char *var, const char *value, void *data)
+{
+ const char *key_to_match = data;
+
+ if (!strcmp(key_to_match, var)) {
+ int parsed = git_config_int(value, value);
+ printf("%d\n", parsed);
+ }
+ return 0;
+}
+
static int early_config_cb(const char *var, const char *value, void *vdata)
{
const char *key = vdata;
@@ -95,8 +111,7 @@ int cmd__config(int argc, const char **argv)
goto exit1;
}
} else if (argc == 3 && !strcmp(argv[1], "get_value_multi")) {
- strptr = git_config_get_value_multi(argv[2]);
- if (strptr) {
+ if (!git_config_get_value_multi(argv[2], &strptr)) {
for (i = 0; i < strptr->nr; i++) {
v = strptr->items[i].string;
if (!v)
@@ -109,6 +124,26 @@ int cmd__config(int argc, const char **argv)
printf("Value not found for \"%s\"\n", argv[2]);
goto exit1;
}
+ } else if (argc == 3 && !strcmp(argv[1], "get")) {
+ int ret;
+
+ if (!(ret = git_config_get(argv[2])))
+ goto exit0;
+ else if (ret == 1)
+ printf("Value not found for \"%s\"\n", argv[2]);
+ else if (ret == -CONFIG_INVALID_KEY)
+ printf("Key \"%s\" is invalid\n", argv[2]);
+ else if (ret == -CONFIG_NO_SECTION_OR_NAME)
+ printf("Key \"%s\" has no section\n", argv[2]);
+ else
+ /*
+ * A normal caller should just check "ret <
+ * 0", but for our own tests let's BUG() if
+ * our whitelist of git_config_parse_key()
+ * return values isn't exhaustive.
+ */
+ BUG("Key \"%s\" has unknown return %d", argv[2], ret);
+ goto exit1;
} else if (argc == 3 && !strcmp(argv[1], "get_int")) {
if (!git_config_get_int(argv[2], &val)) {
printf("%d\n", val);
@@ -159,8 +194,7 @@ int cmd__config(int argc, const char **argv)
goto exit2;
}
}
- strptr = git_configset_get_value_multi(&cs, argv[2]);
- if (strptr) {
+ if (!git_configset_get_value_multi(&cs, argv[2], &strptr)) {
for (i = 0; i < strptr->nr; i++) {
v = strptr->items[i].string;
if (!v)
@@ -176,6 +210,9 @@ int cmd__config(int argc, const char **argv)
} else if (!strcmp(argv[1], "iterate")) {
git_config(iterate_cb, NULL);
goto exit0;
+ } else if (argc == 3 && !strcmp(argv[1], "git_config_int")) {
+ git_config(parse_int_cb, (void *) argv[2]);
+ goto exit0;
}
die("%s: Please check the syntax and the function name", argv[0]);
diff --git a/t/helper/test-crontab.c b/t/helper/test-crontab.c
index e6c1b1e22b..597027a96e 100644
--- a/t/helper/test-crontab.c
+++ b/t/helper/test-crontab.c
@@ -1,5 +1,4 @@
#include "test-tool.h"
-#include "cache.h"
/*
* Usage: test-tool crontab <file> -l|<input>
diff --git a/t/helper/test-ctype.c b/t/helper/test-ctype.c
index b21bd672d9..e5659df40b 100644
--- a/t/helper/test-ctype.c
+++ b/t/helper/test-ctype.c
@@ -1,5 +1,4 @@
#include "test-tool.h"
-#include "cache.h"
static int rc;
@@ -28,6 +27,8 @@ static int is_in(const char *s, int ch)
if (is_in(s, i) != t(i)) \
report_error(#t, i); \
} \
+ if (t(EOF)) \
+ report_error(#t, EOF); \
}
#define DIGIT "0123456789"
@@ -48,7 +49,7 @@ static int is_in(const char *s, int ch)
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
"\x7f"
-int cmd__ctype(int argc, const char **argv)
+int cmd__ctype(int argc UNUSED, const char **argv UNUSED)
{
TEST_CLASS(isdigit, DIGIT);
TEST_CLASS(isspace, " \n\r\t");
diff --git a/t/helper/test-date.c b/t/helper/test-date.c
index 45951b1df8..0683d46574 100644
--- a/t/helper/test-date.c
+++ b/t/helper/test-date.c
@@ -1,6 +1,6 @@
#include "test-tool.h"
-#include "cache.h"
#include "date.h"
+#include "trace.h"
static const char *usage_msg = "\n"
" test-tool date relative [time_t]...\n"
@@ -81,7 +81,7 @@ static void parse_approxidate(const char **argv)
{
for (; *argv; argv++) {
timestamp_t t;
- t = approxidate_relative(*argv);
+ t = approxidate(*argv);
printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601)));
}
}
@@ -90,7 +90,7 @@ static void parse_approx_timestamp(const char **argv)
{
for (; *argv; argv++) {
timestamp_t t;
- t = approxidate_relative(*argv);
+ t = approxidate(*argv);
printf("%s -> %"PRItime"\n", *argv, t);
}
}
@@ -104,7 +104,7 @@ static void getnanos(const char **argv)
printf("%lf\n", seconds);
}
-int cmd__date(int argc, const char **argv)
+int cmd__date(int argc UNUSED, const char **argv)
{
const char *x;
diff --git a/t/helper/test-delta.c b/t/helper/test-delta.c
index b15481ea59..e7d134ec25 100644
--- a/t/helper/test-delta.c
+++ b/t/helper/test-delta.c
@@ -11,7 +11,7 @@
#include "test-tool.h"
#include "git-compat-util.h"
#include "delta.h"
-#include "cache.h"
+#include "wrapper.h"
static const char usage_str[] =
"test-tool delta (-d|-p) <from_file> <data_file> <out_file>";
diff --git a/t/helper/test-drop-caches.c b/t/helper/test-drop-caches.c
index e37396dd9c..73e551cfc2 100644
--- a/t/helper/test-drop-caches.c
+++ b/t/helper/test-drop-caches.c
@@ -155,7 +155,7 @@ static int cmd_dropcaches(void)
#endif
-int cmd__drop_caches(int argc, const char **argv)
+int cmd__drop_caches(int argc UNUSED, const char **argv UNUSED)
{
cmd_sync();
return cmd_dropcaches();
diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c
index 454f17b1a0..c38f546e4f 100644
--- a/t/helper/test-dump-cache-tree.c
+++ b/t/helper/test-dump-cache-tree.c
@@ -1,9 +1,12 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
-#include "cache.h"
+#include "hash.h"
+#include "hex.h"
#include "tree.h"
#include "cache-tree.h"
-
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
static void dump_one(struct cache_tree *it, const char *pfx, const char *x)
{
@@ -56,7 +59,7 @@ static int dump_cache_tree(struct cache_tree *it,
return errs;
}
-int cmd__dump_cache_tree(int ac, const char **av)
+int cmd__dump_cache_tree(int ac UNUSED, const char **av UNUSED)
{
struct index_state istate;
struct cache_tree *another = cache_tree();
diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c
index 975f0ac890..4f215fea02 100644
--- a/t/helper/test-dump-fsmonitor.c
+++ b/t/helper/test-dump-fsmonitor.c
@@ -1,7 +1,9 @@
#include "test-tool.h"
-#include "cache.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
-int cmd__dump_fsmonitor(int ac, const char **av)
+int cmd__dump_fsmonitor(int ac UNUSED, const char **av UNUSED)
{
struct index_state *istate = the_repository->index;
int i;
diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c
index 0ea97b8407..5cf0b26dca 100644
--- a/t/helper/test-dump-split-index.c
+++ b/t/helper/test-dump-split-index.c
@@ -1,6 +1,9 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
#include "split-index.h"
#include "ewah/ewok.h"
@@ -9,7 +12,7 @@ static void show_bit(size_t pos, void *data)
printf(" %d", (int)pos);
}
-int cmd__dump_split_index(int ac, const char **av)
+int cmd__dump_split_index(int ac UNUSED, const char **av)
{
struct split_index *si;
int i;
diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
index 6d53683f13..b4af9712fe 100644
--- a/t/helper/test-dump-untracked-cache.c
+++ b/t/helper/test-dump-untracked-cache.c
@@ -1,7 +1,10 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
-#include "cache.h"
#include "dir.h"
+#include "hex.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
static int compare_untracked(const void *a_, const void *b_)
{
@@ -40,7 +43,7 @@ static void dump(struct untracked_cache_dir *ucd, struct strbuf *base)
strbuf_setlen(base, len);
}
-int cmd__dump_untracked_cache(int ac, const char **av)
+int cmd__dump_untracked_cache(int ac UNUSED, const char **av UNUSED)
{
struct untracked_cache *uc;
struct strbuf base = STRBUF_INIT;
diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c
index b9d1200eb9..2ed910adaa 100644
--- a/t/helper/test-example-decorate.c
+++ b/t/helper/test-example-decorate.c
@@ -1,9 +1,10 @@
#include "test-tool.h"
-#include "cache.h"
+#include "git-compat-util.h"
#include "object.h"
#include "decorate.h"
+#include "repository.h"
-int cmd__example_decorate(int argc, const char **argv)
+int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED)
{
struct decoration n;
struct object_id one_oid = { {1} };
diff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c
index efc82dd80c..cac20a72b3 100644
--- a/t/helper/test-fast-rebase.c
+++ b/t/helper/test-fast-rebase.c
@@ -12,20 +12,27 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
-
#include "cache-tree.h"
#include "commit.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "lockfile.h"
#include "merge-ort.h"
+#include "object-name.h"
+#include "read-cache-ll.h"
#include "refs.h"
#include "revision.h"
#include "sequencer.h"
+#include "setup.h"
#include "strvec.h"
#include "tree.h"
static const char *short_commit_name(struct commit *commit)
{
- return find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV);
+ return repo_find_unique_abbrev(the_repository, &commit->object.oid,
+ DEFAULT_ABBREV);
}
static struct commit *peel_committish(const char *name)
@@ -33,10 +40,11 @@ static struct commit *peel_committish(const char *name)
struct object *obj;
struct object_id oid;
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
return NULL;
obj = parse_object(the_repository, &oid);
- return (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
+ return (struct commit *)repo_peel_to_type(the_repository, name, 0, obj,
+ OBJ_COMMIT);
}
static char *get_author(const char *message)
@@ -63,7 +71,8 @@ static struct commit *create_commit(struct tree *tree,
struct commit_extra_header *extra;
struct strbuf msg = STRBUF_INIT;
const char *out_enc = get_commit_output_encoding();
- const char *message = logmsg_reencode(based_on, NULL, out_enc);
+ const char *message = repo_logmsg_reencode(the_repository, based_on,
+ NULL, out_enc);
const char *orig_message = NULL;
const char *exclude_gpgsig[] = { "gpgsig", NULL };
@@ -119,7 +128,7 @@ int cmd__fast_rebase(int argc, const char **argv)
strbuf_addf(&branch_name, "refs/heads/%s", argv[4]);
/* Sanity check */
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(the_repository, "HEAD", &head))
die(_("Cannot read HEAD"));
assert(oideq(&onto->object.oid, &head));
@@ -154,7 +163,7 @@ int cmd__fast_rebase(int argc, const char **argv)
memset(&result, 0, sizeof(result));
merge_opt.show_rename_progress = 1;
merge_opt.branch1 = "HEAD";
- head_tree = get_commit_tree(onto);
+ head_tree = repo_get_commit_tree(the_repository, onto);
result.tree = head_tree;
last_commit = onto;
while ((commit = get_revision(&revs))) {
@@ -165,8 +174,8 @@ int cmd__fast_rebase(int argc, const char **argv)
assert(commit->parents && !commit->parents->next);
base = commit->parents->item;
- next_tree = get_commit_tree(commit);
- base_tree = get_commit_tree(base);
+ next_tree = repo_get_commit_tree(the_repository, commit);
+ base_tree = repo_get_commit_tree(the_repository, base);
merge_opt.branch2 = short_commit_name(commit);
merge_opt.ancestor = xstrfmt("parent of %s", merge_opt.branch2);
diff --git a/t/helper/test-fsmonitor-client.c b/t/helper/test-fsmonitor-client.c
index 54a4856c48..58d1dc5fc8 100644
--- a/t/helper/test-fsmonitor-client.c
+++ b/t/helper/test-fsmonitor-client.c
@@ -4,14 +4,17 @@
*/
#include "test-tool.h"
-#include "cache.h"
#include "parse-options.h"
#include "fsmonitor-ipc.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
#include "thread-utils.h"
#include "trace2.h"
+#include "wrapper.h"
#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
-int cmd__fsmonitor_client(int argc, const char **argv)
+int cmd__fsmonitor_client(int argc UNUSED, const char **argv UNUSED)
{
die("fsmonitor--daemon not available on this platform");
}
diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c
index f40d9ad0c2..b235da594f 100644
--- a/t/helper/test-hash-speed.c
+++ b/t/helper/test-hash-speed.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hash-ll.h"
#define NUM_SECONDS 3
diff --git a/t/helper/test-hash.c b/t/helper/test-hash.c
index 5860dab0ff..45d829c908 100644
--- a/t/helper/test-hash.c
+++ b/t/helper/test-hash.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
int cmd_hash_impl(int ac, const char **av, int algo)
{
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index 36ff07bd4b..0eb0b3d49c 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -2,6 +2,7 @@
#include "git-compat-util.h"
#include "hashmap.h"
#include "strbuf.h"
+#include "string-list.h"
struct test_entry
{
@@ -150,6 +151,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
*/
int cmd__hashmap(int argc, const char **argv)
{
+ struct string_list parts = STRING_LIST_INIT_NODUP;
struct strbuf line = STRBUF_INIT;
int icase;
struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
@@ -159,21 +161,26 @@ int cmd__hashmap(int argc, const char **argv)
/* process commands from stdin */
while (strbuf_getline(&line, stdin) != EOF) {
- char *cmd, *p1 = NULL, *p2 = NULL;
+ char *cmd, *p1, *p2;
unsigned int hash = 0;
struct test_entry *entry;
/* break line into command and up to two parameters */
- cmd = strtok(line.buf, DELIM);
+ string_list_setlen(&parts, 0);
+ string_list_split_in_place(&parts, line.buf, DELIM, 2);
+ string_list_remove_empty_items(&parts, 0);
+
/* ignore empty lines */
- if (!cmd || *cmd == '#')
+ if (!parts.nr)
+ continue;
+ if (!*parts.items[0].string || *parts.items[0].string == '#')
continue;
- p1 = strtok(NULL, DELIM);
- if (p1) {
+ cmd = parts.items[0].string;
+ p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
+ p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
+ if (p1)
hash = icase ? strihash(p1) : strhash(p1);
- p2 = strtok(NULL, DELIM);
- }
if (!strcmp("add", cmd) && p1 && p2) {
@@ -260,6 +267,7 @@ int cmd__hashmap(int argc, const char **argv)
}
}
+ string_list_clear(&parts, 0);
strbuf_release(&line);
hashmap_clear_and_free(&map, struct test_entry, ent);
return 0;
diff --git a/t/helper/test-hexdump.c b/t/helper/test-hexdump.c
index 811e89c1bc..05f55eca21 100644
--- a/t/helper/test-hexdump.c
+++ b/t/helper/test-hexdump.c
@@ -4,7 +4,7 @@
/*
* Read stdin and print a hexdump to stdout.
*/
-int cmd__hexdump(int argc, const char **argv)
+int cmd__hexdump(int argc UNUSED, const char **argv UNUSED)
{
char buf[1024];
ssize_t i, len;
diff --git a/t/helper/test-index-version.c b/t/helper/test-index-version.c
index fcd10968cc..f3c2dbe0a2 100644
--- a/t/helper/test-index-version.c
+++ b/t/helper/test-index-version.c
@@ -1,7 +1,7 @@
#include "test-tool.h"
-#include "cache.h"
+#include "read-cache-ll.h"
-int cmd__index_version(int argc, const char **argv)
+int cmd__index_version(int argc UNUSED, const char **argv UNUSED)
{
struct cache_header hdr;
int version;
diff --git a/t/helper/test-json-writer.c b/t/helper/test-json-writer.c
index 8c3edacc00..afe393f597 100644
--- a/t/helper/test-json-writer.c
+++ b/t/helper/test-json-writer.c
@@ -1,6 +1,6 @@
#include "test-tool.h"
-#include "cache.h"
#include "json-writer.h"
+#include "string-list.h"
static const char *expect_obj1 = "{\"a\":\"abc\",\"b\":42,\"c\":true}";
static const char *expect_obj2 = "{\"a\":-1,\"b\":2147483647,\"c\":0}";
@@ -395,35 +395,41 @@ static int unit_tests(void)
return 0;
}
-static void get_s(int line_nr, char **s_in)
+struct line {
+ struct string_list *parts;
+ size_t consumed_nr;
+ int nr;
+};
+
+static void get_s(struct line *line, char **s_in)
{
- *s_in = strtok(NULL, " ");
- if (!*s_in)
- die("line[%d]: expected: <s>", line_nr);
+ if (line->consumed_nr > line->parts->nr)
+ die("line[%d]: expected: <s>", line->nr);
+ *s_in = line->parts->items[line->consumed_nr++].string;
}
-static void get_i(int line_nr, intmax_t *s_in)
+static void get_i(struct line *line, intmax_t *s_in)
{
char *s;
char *endptr;
- get_s(line_nr, &s);
+ get_s(line, &s);
*s_in = strtol(s, &endptr, 10);
if (*endptr || errno == ERANGE)
- die("line[%d]: invalid integer value", line_nr);
+ die("line[%d]: invalid integer value", line->nr);
}
-static void get_d(int line_nr, double *s_in)
+static void get_d(struct line *line, double *s_in)
{
char *s;
char *endptr;
- get_s(line_nr, &s);
+ get_s(line, &s);
*s_in = strtod(s, &endptr);
if (*endptr || errno == ERANGE)
- die("line[%d]: invalid float value", line_nr);
+ die("line[%d]: invalid float value", line->nr);
}
static int pretty;
@@ -454,6 +460,7 @@ static char *get_trimmed_line(char *buf, int buf_size)
static int scripted(void)
{
+ struct string_list parts = STRING_LIST_INIT_NODUP;
struct json_writer jw = JSON_WRITER_INIT;
char buf[MAX_LINE_LENGTH];
char *line;
@@ -471,66 +478,77 @@ static int scripted(void)
die("expected first line to be 'object' or 'array'");
while ((line = get_trimmed_line(buf, MAX_LINE_LENGTH)) != NULL) {
+ struct line state = { 0 };
char *verb;
char *key;
char *s_value;
intmax_t i_value;
double d_value;
- line_nr++;
+ state.parts = &parts;
+ state.nr = ++line_nr;
+
+ /* break line into command and zero or more tokens */
+ string_list_setlen(&parts, 0);
+ string_list_split_in_place(&parts, line, " ", -1);
+ string_list_remove_empty_items(&parts, 0);
+
+ /* ignore empty lines */
+ if (!parts.nr || !*parts.items[0].string)
+ continue;
- verb = strtok(line, " ");
+ verb = parts.items[state.consumed_nr++].string;
if (!strcmp(verb, "end")) {
jw_end(&jw);
}
else if (!strcmp(verb, "object-string")) {
- get_s(line_nr, &key);
- get_s(line_nr, &s_value);
+ get_s(&state, &key);
+ get_s(&state, &s_value);
jw_object_string(&jw, key, s_value);
}
else if (!strcmp(verb, "object-int")) {
- get_s(line_nr, &key);
- get_i(line_nr, &i_value);
+ get_s(&state, &key);
+ get_i(&state, &i_value);
jw_object_intmax(&jw, key, i_value);
}
else if (!strcmp(verb, "object-double")) {
- get_s(line_nr, &key);
- get_i(line_nr, &i_value);
- get_d(line_nr, &d_value);
+ get_s(&state, &key);
+ get_i(&state, &i_value);
+ get_d(&state, &d_value);
jw_object_double(&jw, key, i_value, d_value);
}
else if (!strcmp(verb, "object-true")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_true(&jw, key);
}
else if (!strcmp(verb, "object-false")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_false(&jw, key);
}
else if (!strcmp(verb, "object-null")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_null(&jw, key);
}
else if (!strcmp(verb, "object-object")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_inline_begin_object(&jw, key);
}
else if (!strcmp(verb, "object-array")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_inline_begin_array(&jw, key);
}
else if (!strcmp(verb, "array-string")) {
- get_s(line_nr, &s_value);
+ get_s(&state, &s_value);
jw_array_string(&jw, s_value);
}
else if (!strcmp(verb, "array-int")) {
- get_i(line_nr, &i_value);
+ get_i(&state, &i_value);
jw_array_intmax(&jw, i_value);
}
else if (!strcmp(verb, "array-double")) {
- get_i(line_nr, &i_value);
- get_d(line_nr, &d_value);
+ get_i(&state, &i_value);
+ get_d(&state, &d_value);
jw_array_double(&jw, i_value, d_value);
}
else if (!strcmp(verb, "array-true"))
@@ -553,6 +571,7 @@ static int scripted(void)
printf("%s\n", jw.json.buf);
jw_release(&jw);
+ string_list_clear(&parts, 0);
return 0;
}
diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c
index ab86c14c8b..187a115d57 100644
--- a/t/helper/test-lazy-init-name-hash.c
+++ b/t/helper/test-lazy-init-name-hash.c
@@ -1,7 +1,12 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
-#include "cache.h"
+#include "environment.h"
+#include "name-hash.h"
#include "parse-options.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
+#include "trace.h"
static int single;
static int multi;
diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c
index 4079fdee06..d0db5ff26f 100644
--- a/t/helper/test-match-trees.c
+++ b/t/helper/test-match-trees.c
@@ -1,17 +1,21 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
+#include "match-trees.h"
+#include "object-name.h"
+#include "repository.h"
+#include "setup.h"
#include "tree.h"
-int cmd__match_trees(int ac, const char **av)
+int cmd__match_trees(int ac UNUSED, const char **av)
{
struct object_id hash1, hash2, shifted;
struct tree *one, *two;
setup_git_directory();
- if (get_oid(av[1], &hash1))
+ if (repo_get_oid(the_repository, av[1], &hash1))
die("cannot parse %s as an object name", av[1]);
- if (get_oid(av[2], &hash2))
+ if (repo_get_oid(the_repository, av[2], &hash2))
die("cannot parse %s as an object name", av[2]);
one = parse_tree_indirect(&hash1);
if (!one)
diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c
index 335e5bb3a9..42ccc87051 100644
--- a/t/helper/test-mergesort.c
+++ b/t/helper/test-mergesort.c
@@ -1,6 +1,7 @@
#include "test-tool.h"
-#include "cache.h"
+#include "mem-pool.h"
#include "mergesort.h"
+#include "strbuf.h"
static uint32_t minstd_rand(uint32_t *state)
{
diff --git a/t/helper/test-oid-array.c b/t/helper/test-oid-array.c
index d1324d086a..eef68833b7 100644
--- a/t/helper/test-oid-array.c
+++ b/t/helper/test-oid-array.c
@@ -1,6 +1,8 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
#include "oid-array.h"
+#include "setup.h"
+#include "strbuf.h"
static int print_oid(const struct object_id *oid, void *data)
{
@@ -8,7 +10,7 @@ static int print_oid(const struct object_id *oid, void *data)
return 0;
}
-int cmd__oid_array(int argc, const char **argv)
+int cmd__oid_array(int argc UNUSED, const char **argv UNUSED)
{
struct oid_array array = OID_ARRAY_INIT;
struct strbuf line = STRBUF_INIT;
diff --git a/t/helper/test-oidmap.c b/t/helper/test-oidmap.c
index 0acf99931e..bd30244a54 100644
--- a/t/helper/test-oidmap.c
+++ b/t/helper/test-oidmap.c
@@ -1,7 +1,11 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
+#include "object-name.h"
#include "oidmap.h"
+#include "repository.h"
+#include "setup.h"
#include "strbuf.h"
+#include "string-list.h"
/* key is an oid and value is a name (could be a refname for example) */
struct test_entry {
@@ -21,8 +25,9 @@ struct test_entry {
* iterate -> oidkey1 namevalue1\noidkey2 namevalue2\n...
*
*/
-int cmd__oidmap(int argc, const char **argv)
+int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
{
+ struct string_list parts = STRING_LIST_INIT_NODUP;
struct strbuf line = STRBUF_INIT;
struct oidmap map = OIDMAP_INIT;
@@ -33,23 +38,28 @@ int cmd__oidmap(int argc, const char **argv)
/* process commands from stdin */
while (strbuf_getline(&line, stdin) != EOF) {
- char *cmd, *p1 = NULL, *p2 = NULL;
+ char *cmd, *p1, *p2;
struct test_entry *entry;
struct object_id oid;
/* break line into command and up to two parameters */
- cmd = strtok(line.buf, DELIM);
+ string_list_setlen(&parts, 0);
+ string_list_split_in_place(&parts, line.buf, DELIM, 2);
+ string_list_remove_empty_items(&parts, 0);
+
/* ignore empty lines */
- if (!cmd || *cmd == '#')
+ if (!parts.nr)
+ continue;
+ if (!*parts.items[0].string || *parts.items[0].string == '#')
continue;
- p1 = strtok(NULL, DELIM);
- if (p1)
- p2 = strtok(NULL, DELIM);
+ cmd = parts.items[0].string;
+ p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
+ p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
if (!strcmp("put", cmd) && p1 && p2) {
- if (get_oid(p1, &oid)) {
+ if (repo_get_oid(the_repository, p1, &oid)) {
printf("Unknown oid: %s\n", p1);
continue;
}
@@ -67,7 +77,7 @@ int cmd__oidmap(int argc, const char **argv)
} else if (!strcmp("get", cmd) && p1) {
- if (get_oid(p1, &oid)) {
+ if (repo_get_oid(the_repository, p1, &oid)) {
printf("Unknown oid: %s\n", p1);
continue;
}
@@ -80,7 +90,7 @@ int cmd__oidmap(int argc, const char **argv)
} else if (!strcmp("remove", cmd) && p1) {
- if (get_oid(p1, &oid)) {
+ if (repo_get_oid(the_repository, p1, &oid)) {
printf("Unknown oid: %s\n", p1);
continue;
}
@@ -106,6 +116,7 @@ int cmd__oidmap(int argc, const char **argv)
}
}
+ string_list_clear(&parts, 0);
strbuf_release(&line);
oidmap_free(&map, 1);
return 0;
diff --git a/t/helper/test-oidtree.c b/t/helper/test-oidtree.c
index d48a409f4e..c7a1d4c642 100644
--- a/t/helper/test-oidtree.c
+++ b/t/helper/test-oidtree.c
@@ -1,14 +1,16 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
#include "oidtree.h"
+#include "setup.h"
+#include "strbuf.h"
-static enum cb_next print_oid(const struct object_id *oid, void *data)
+static enum cb_next print_oid(const struct object_id *oid, void *data UNUSED)
{
puts(oid_to_hex(oid));
return CB_CONTINUE;
}
-int cmd__oidtree(int argc, const char **argv)
+int cmd__oidtree(int argc UNUSED, const char **argv UNUSED)
{
struct oidtree ot;
struct strbuf line = STRBUF_INIT;
diff --git a/t/helper/test-online-cpus.c b/t/helper/test-online-cpus.c
index 8cb0d53840..47dc211711 100644
--- a/t/helper/test-online-cpus.c
+++ b/t/helper/test-online-cpus.c
@@ -2,7 +2,7 @@
#include "git-compat-util.h"
#include "thread-utils.h"
-int cmd__online_cpus(int argc, const char **argv)
+int cmd__online_cpus(int argc UNUSED, const char **argv UNUSED)
{
printf("%d\n", online_cpus());
return 0;
diff --git a/t/helper/test-pack-mtimes.c b/t/helper/test-pack-mtimes.c
index f7b79daf4c..67a964ef90 100644
--- a/t/helper/test-pack-mtimes.c
+++ b/t/helper/test-pack-mtimes.c
@@ -1,9 +1,10 @@
-#include "git-compat-util.h"
#include "test-tool.h"
+#include "hex.h"
#include "strbuf.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "packfile.h"
#include "pack-mtimes.h"
+#include "setup.h"
static void dump_mtimes(struct packed_git *p)
{
diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c
index 506835521a..00fa281a9c 100644
--- a/t/helper/test-parse-options.c
+++ b/t/helper/test-parse-options.c
@@ -1,6 +1,6 @@
#include "test-tool.h"
-#include "cache.h"
#include "parse-options.h"
+#include "strbuf.h"
#include "string-list.h"
#include "trace2.h"
@@ -263,14 +263,14 @@ int cmd__parse_options_flags(int argc, const char **argv)
return parse_options_flags__cmd(argc, argv, test_flags);
}
-static int subcmd_one(int argc, const char **argv, const char *prefix)
+static int subcmd_one(int argc, const char **argv, const char *prefix UNUSED)
{
printf("fn: subcmd_one\n");
print_args(argc, argv);
return 0;
}
-static int subcmd_two(int argc, const char **argv, const char *prefix)
+static int subcmd_two(int argc, const char **argv, const char *prefix UNUSED)
{
printf("fn: subcmd_two\n");
print_args(argc, argv);
diff --git a/t/helper/test-parse-pathspec-file.c b/t/helper/test-parse-pathspec-file.c
index b3e08cef4b..89ecefd1cd 100644
--- a/t/helper/test-parse-pathspec-file.c
+++ b/t/helper/test-parse-pathspec-file.c
@@ -1,12 +1,11 @@
#include "test-tool.h"
#include "parse-options.h"
#include "pathspec.h"
-#include "gettext.h"
int cmd__parse_pathspec_file(int argc, const char **argv)
{
struct pathspec pathspec;
- const char *pathspec_from_file = NULL;
+ char *pathspec_from_file = NULL;
int pathspec_file_nul = 0, i;
static const char *const usage[] = {
@@ -29,5 +28,6 @@ int cmd__parse_pathspec_file(int argc, const char **argv)
printf("%s\n", pathspec.items[i].original);
clear_pathspec(&pathspec);
+ free(pathspec_from_file);
return 0;
}
diff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c
index 3f102cfddd..910a128614 100644
--- a/t/helper/test-partial-clone.c
+++ b/t/helper/test-partial-clone.c
@@ -1,7 +1,8 @@
-#include "cache.h"
#include "test-tool.h"
+#include "hex.h"
#include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "setup.h"
/*
* Prints the size of the object corresponding to the given hash in a specific
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index f69709d674..70396fa384 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -1,6 +1,11 @@
#include "test-tool.h"
-#include "cache.h"
+#include "abspath.h"
+#include "environment.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "setup.h"
#include "string-list.h"
+#include "trace.h"
#include "utf8.h"
/*
diff --git a/t/helper/test-pcre2-config.c b/t/helper/test-pcre2-config.c
index 5258fdddba..5d0b2a2e10 100644
--- a/t/helper/test-pcre2-config.c
+++ b/t/helper/test-pcre2-config.c
@@ -1,5 +1,4 @@
#include "test-tool.h"
-#include "cache.h"
#include "grep.h"
int cmd__pcre2_config(int argc, const char **argv)
diff --git a/t/helper/test-pkt-line.c b/t/helper/test-pkt-line.c
index c5e052e537..f4d134a145 100644
--- a/t/helper/test-pkt-line.c
+++ b/t/helper/test-pkt-line.c
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "test-tool.h"
#include "pkt-line.h"
+#include "write-or-die.h"
static void pack_line(const char *line)
{
diff --git a/t/helper/test-prio-queue.c b/t/helper/test-prio-queue.c
index 133b5e6f4a..f0bf255f5f 100644
--- a/t/helper/test-prio-queue.c
+++ b/t/helper/test-prio-queue.c
@@ -1,8 +1,7 @@
#include "test-tool.h"
-#include "cache.h"
#include "prio-queue.h"
-static int intcmp(const void *va, const void *vb, void *data)
+static int intcmp(const void *va, const void *vb, void *data UNUSED)
{
const int *a = va, *b = vb;
return *a - *b;
@@ -17,7 +16,7 @@ static void show(int *v)
free(v);
}
-int cmd__prio_queue(int argc, const char **argv)
+int cmd__prio_queue(int argc UNUSED, const char **argv)
{
struct prio_queue pq = { intcmp };
diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c
index a4b305f494..f30022d222 100644
--- a/t/helper/test-proc-receive.c
+++ b/t/helper/test-proc-receive.c
@@ -1,9 +1,10 @@
-#include "cache.h"
+#include "test-tool.h"
#include "connect.h"
+#include "hex.h"
#include "parse-options.h"
#include "pkt-line.h"
+#include "setup.h"
#include "sigchain.h"
-#include "test-tool.h"
static const char *proc_receive_usage[] = {
"test-tool proc-receive [<options>]",
diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c
index 6cc9735b60..66acb6a06c 100644
--- a/t/helper/test-progress.c
+++ b/t/helper/test-progress.c
@@ -19,7 +19,6 @@
*/
#define GIT_TEST_PROGRESS_ONLY
#include "test-tool.h"
-#include "gettext.h"
#include "parse-options.h"
#include "progress.h"
#include "strbuf.h"
diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c
index 2f65c7f6a5..ef58f10c2d 100644
--- a/t/helper/test-reach.c
+++ b/t/helper/test-reach.c
@@ -1,10 +1,14 @@
#include "test-tool.h"
-#include "cache.h"
+#include "alloc.h"
#include "commit.h"
#include "commit-reach.h"
#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
#include "parse-options.h"
#include "ref-filter.h"
+#include "setup.h"
#include "string-list.h"
#include "tag.h"
@@ -57,7 +61,7 @@ int cmd__reach(int ac, const char **av)
if (buf.len < 3)
continue;
- if (get_oid_committish(buf.buf + 2, &oid))
+ if (repo_get_oid_committish(the_repository, buf.buf + 2, &oid))
die("failed to resolve %s", buf.buf + 2);
orig = parse_object(r, &oid);
@@ -106,13 +110,17 @@ int cmd__reach(int ac, const char **av)
if (!strcmp(av[1], "ref_newer"))
printf("%s(A,B):%d\n", av[1], ref_newer(&oid_A, &oid_B));
else if (!strcmp(av[1], "in_merge_bases"))
- printf("%s(A,B):%d\n", av[1], in_merge_bases(A, B));
+ printf("%s(A,B):%d\n", av[1],
+ repo_in_merge_bases(the_repository, A, B));
else if (!strcmp(av[1], "in_merge_bases_many"))
- printf("%s(A,X):%d\n", av[1], in_merge_bases_many(A, X_nr, X_array));
+ printf("%s(A,X):%d\n", av[1],
+ repo_in_merge_bases_many(the_repository, A, X_nr, X_array));
else if (!strcmp(av[1], "is_descendant_of"))
printf("%s(A,X):%d\n", av[1], repo_is_descendant_of(r, A, X));
else if (!strcmp(av[1], "get_merge_bases_many")) {
- struct commit_list *list = get_merge_bases_many(A, X_nr, X_array);
+ struct commit_list *list = repo_get_merge_bases_many(the_repository,
+ A, X_nr,
+ X_array);
printf("%s(A,X):\n", av[1]);
print_sorted_commit_ids(list);
} else if (!strcmp(av[1], "reduce_heads")) {
@@ -131,7 +139,7 @@ int cmd__reach(int ac, const char **av)
printf("%s(X,_,_,0,0):%d\n", av[1], can_all_from_reach_with_flag(&X_obj, 2, 4, 0, 0));
} else if (!strcmp(av[1], "commit_contains")) {
- struct ref_filter filter;
+ struct ref_filter filter = REF_FILTER_INIT;
struct contains_cache cache;
init_contains_cache(&cache);
diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c
index 23e9e27109..56c2d25f35 100644
--- a/t/helper/test-read-cache.c
+++ b/t/helper/test-read-cache.c
@@ -1,7 +1,10 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
-#include "cache.h"
#include "config.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
+#include "wrapper.h"
int cmd__read_cache(int argc, const char **argv)
{
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
index 98b73bb8f2..8c7a83f578 100644
--- a/t/helper/test-read-graph.c
+++ b/t/helper/test-read-graph.c
@@ -1,11 +1,11 @@
#include "test-tool.h"
-#include "cache.h"
#include "commit-graph.h"
#include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "bloom.h"
+#include "setup.h"
-int cmd__read_graph(int argc, const char **argv)
+int cmd__read_graph(int argc UNUSED, const char **argv UNUSED)
{
struct commit_graph *graph = NULL;
struct object_directory *odb;
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
index 27072ba94d..e9a444ddba 100644
--- a/t/helper/test-read-midx.c
+++ b/t/helper/test-read-midx.c
@@ -1,9 +1,11 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
#include "midx.h"
#include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "pack-bitmap.h"
+#include "packfile.h"
+#include "setup.h"
static int read_midx_file(const char *object_dir, int show_objects)
{
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index ae8a5648da..948517cf1d 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -1,9 +1,12 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
#include "refs.h"
+#include "setup.h"
#include "worktree.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "repository.h"
+#include "strbuf.h"
struct flag_definition {
const char *name;
@@ -174,6 +177,15 @@ static int cmd_for_each_ref(struct ref_store *refs, const char **argv)
return refs_for_each_ref_in(refs, prefix, each_ref, NULL);
}
+static int cmd_for_each_ref__exclude(struct ref_store *refs, const char **argv)
+{
+ const char *prefix = notnull(*argv++, "prefix");
+ const char **exclude_patterns = argv;
+
+ return refs_for_each_fullref_in(refs, prefix, exclude_patterns, each_ref,
+ NULL);
+}
+
static int cmd_resolve_ref(struct ref_store *refs, const char **argv)
{
struct object_id oid = *null_oid();
@@ -200,7 +212,8 @@ static int cmd_verify_ref(struct ref_store *refs, const char **argv)
return ret;
}
-static int cmd_for_each_reflog(struct ref_store *refs, const char **argv)
+static int cmd_for_each_reflog(struct ref_store *refs,
+ const char **argv UNUSED)
{
return refs_for_each_reflog(refs, each_ref, NULL);
}
@@ -305,6 +318,7 @@ static struct command commands[] = {
{ "delete-refs", cmd_delete_refs },
{ "rename-ref", cmd_rename_ref },
{ "for-each-ref", cmd_for_each_ref },
+ { "for-each-ref--exclude", cmd_for_each_ref__exclude },
{ "resolve-ref", cmd_resolve_ref },
{ "verify-ref", cmd_verify_ref },
{ "for-each-reflog", cmd_for_each_reflog },
@@ -322,7 +336,7 @@ static struct command commands[] = {
{ NULL, NULL }
};
-int cmd__ref_store(int argc, const char **argv)
+int cmd__ref_store(int argc UNUSED, const char **argv)
{
struct ref_store *refs;
const char *func;
diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c
index 1f0a28cbb6..00237ef0d9 100644
--- a/t/helper/test-reftable.c
+++ b/t/helper/test-reftable.c
@@ -1,3 +1,4 @@
+#include "reftable/system.h"
#include "reftable/reftable-tests.h"
#include "test-tool.h"
diff --git a/t/helper/test-repository.c b/t/helper/test-repository.c
index 56f0e3c1be..4cd8a952e5 100644
--- a/t/helper/test-repository.c
+++ b/t/helper/test-repository.c
@@ -1,11 +1,13 @@
#include "test-tool.h"
-#include "cache.h"
#include "commit-graph.h"
#include "commit.h"
#include "config.h"
-#include "object-store.h"
+#include "environment.h"
+#include "hex.h"
+#include "object-store-ll.h"
#include "object.h"
#include "repository.h"
+#include "setup.h"
#include "tree.h"
static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
diff --git a/t/helper/test-revision-walking.c b/t/helper/test-revision-walking.c
index 4a45d5bac2..f346951bc2 100644
--- a/t/helper/test-revision-walking.c
+++ b/t/helper/test-revision-walking.c
@@ -9,17 +9,19 @@
*/
#include "test-tool.h"
-#include "cache.h"
#include "commit.h"
#include "diff.h"
+#include "repository.h"
#include "revision.h"
+#include "setup.h"
static void print_commit(struct commit *commit)
{
struct strbuf sb = STRBUF_INIT;
struct pretty_print_context ctx = {0};
ctx.date_mode.type = DATE_NORMAL;
- format_commit_message(commit, " %m %s", &sb, &ctx);
+ repo_format_commit_message(the_repository, commit, " %m %s", &sb,
+ &ctx);
printf("%s\n", sb.buf);
strbuf_release(&sb);
}
diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c
index 3ecb830f4a..86ca155bda 100644
--- a/t/helper/test-run-command.c
+++ b/t/helper/test-run-command.c
@@ -9,8 +9,6 @@
*/
#include "test-tool.h"
-#include "git-compat-util.h"
-#include "cache.h"
#include "run-command.h"
#include "strvec.h"
#include "strbuf.h"
@@ -18,13 +16,12 @@
#include "string-list.h"
#include "thread-utils.h"
#include "wildmatch.h"
-#include "gettext.h"
static int number_callbacks;
static int parallel_next(struct child_process *cp,
struct strbuf *err,
void *cb,
- void **task_cb)
+ void **task_cb UNUSED)
{
struct child_process *d = cb;
if (number_callbacks >= 4)
@@ -40,10 +37,10 @@ static int parallel_next(struct child_process *cp,
return 1;
}
-static int no_job(struct child_process *cp,
+static int no_job(struct child_process *cp UNUSED,
struct strbuf *err,
- void *cb,
- void **task_cb)
+ void *cb UNUSED,
+ void **task_cb UNUSED)
{
if (err)
strbuf_addstr(err, "no further jobs available\n");
@@ -52,10 +49,24 @@ static int no_job(struct child_process *cp,
return 0;
}
-static int task_finished(int result,
+static void on_stderr_output(struct strbuf *out,
+ size_t offset,
+ void *pp_cb UNUSED,
+ void *pp_task_cb UNUSED)
+{
+ struct string_list list = STRING_LIST_INIT_DUP;
+ struct string_list_item *item;
+
+ string_list_split(&list, out->buf + offset, '\n', -1);
+ for_each_string_list_item(item, &list)
+ fprintf(stderr, "on_stderr_output: %s\n", item->string);
+ string_list_clear(&list, 0);
+}
+
+static int task_finished(int result UNUSED,
struct strbuf *err,
- void *pp_cb,
- void *pp_task_cb)
+ void *pp_cb UNUSED,
+ void *pp_task_cb UNUSED)
{
if (err)
strbuf_addstr(err, "asking for a quick stop\n");
@@ -439,6 +450,12 @@ int cmd__run_command(int argc, const char **argv)
opts.ungroup = 1;
}
+ if (!strcmp(argv[1], "--on-stderr-output")) {
+ argv += 1;
+ argc -= 1;
+ opts.on_stderr_output = on_stderr_output;
+ }
+
jobs = atoi(argv[2]);
strvec_clear(&proc.args);
strvec_pushv(&proc.args, (const char **)argv + 3);
diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c
index a26107ed70..0a816a96e2 100644
--- a/t/helper/test-scrap-cache-tree.c
+++ b/t/helper/test-scrap-cache-tree.c
@@ -1,11 +1,13 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
-#include "cache.h"
#include "lockfile.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
#include "tree.h"
#include "cache-tree.h"
-int cmd__scrap_cache_tree(int ac, const char **av)
+int cmd__scrap_cache_tree(int ac UNUSED, const char **av UNUSED)
{
struct lock_file index_lock = LOCK_INIT;
diff --git a/t/helper/test-serve-v2.c b/t/helper/test-serve-v2.c
index 824e5c0a95..054cbcf5d8 100644
--- a/t/helper/test-serve-v2.c
+++ b/t/helper/test-serve-v2.c
@@ -1,7 +1,8 @@
#include "test-tool.h"
-#include "cache.h"
+#include "gettext.h"
#include "parse-options.h"
#include "serve.h"
+#include "setup.h"
static char const * const serve_usage[] = {
N_("test-tool serve-v2 [<options>]"),
diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c
index 71fe5c6145..dcb7f6c003 100644
--- a/t/helper/test-sha1.c
+++ b/t/helper/test-sha1.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hash-ll.h"
int cmd__sha1(int ac, const char **av)
{
diff --git a/t/helper/test-sha256.c b/t/helper/test-sha256.c
index 0ac6a99d5f..08cf149001 100644
--- a/t/helper/test-sha256.c
+++ b/t/helper/test-sha256.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "cache.h"
+#include "hash-ll.h"
int cmd__sha256(int ac, const char **av)
{
diff --git a/t/helper/test-sigchain.c b/t/helper/test-sigchain.c
index d013bccdda..2d5ecf7383 100644
--- a/t/helper/test-sigchain.c
+++ b/t/helper/test-sigchain.c
@@ -1,5 +1,4 @@
#include "test-tool.h"
-#include "cache.h"
#include "sigchain.h"
#define X(f) \
@@ -14,7 +13,7 @@ X(two)
X(three)
#undef X
-int cmd__sigchain(int argc, const char **argv)
+int cmd__sigchain(int argc UNUSED, const char **argv UNUSED)
{
sigchain_push(SIGTERM, one);
sigchain_push(SIGTERM, two);
diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c
index 28365ff85b..3d1436da59 100644
--- a/t/helper/test-simple-ipc.c
+++ b/t/helper/test-simple-ipc.c
@@ -3,13 +3,14 @@
*/
#include "test-tool.h"
-#include "cache.h"
+#include "gettext.h"
#include "strbuf.h"
#include "simple-ipc.h"
#include "parse-options.h"
#include "thread-utils.h"
#include "strvec.h"
#include "run-command.h"
+#include "trace2.h"
#ifndef SUPPORTS_SIMPLE_IPC
int cmd__simple_ipc(int argc, const char **argv)
diff --git a/t/helper/test-strcmp-offset.c b/t/helper/test-strcmp-offset.c
index 44e4a6d143..d8473cf2fc 100644
--- a/t/helper/test-strcmp-offset.c
+++ b/t/helper/test-strcmp-offset.c
@@ -1,7 +1,7 @@
#include "test-tool.h"
-#include "cache.h"
+#include "read-cache-ll.h"
-int cmd__strcmp_offset(int argc, const char **argv)
+int cmd__strcmp_offset(int argc UNUSED, const char **argv)
{
int result;
size_t offset;
diff --git a/t/helper/test-string-list.c b/t/helper/test-string-list.c
index 2123dda85b..e2aad611d1 100644
--- a/t/helper/test-string-list.c
+++ b/t/helper/test-string-list.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "cache.h"
+#include "strbuf.h"
#include "string-list.h"
/*
@@ -62,7 +62,7 @@ int cmd__string_list(int argc, const char **argv)
struct string_list list = STRING_LIST_INIT_NODUP;
int i;
char *s = xstrdup(argv[2]);
- int delim = *argv[3];
+ const char *delim = argv[3];
int maxsplit = atoi(argv[4]);
i = string_list_split_in_place(&list, s, delim, maxsplit);
@@ -111,7 +111,7 @@ int cmd__string_list(int argc, const char **argv)
*/
if (sb.len && sb.buf[sb.len - 1] == '\n')
strbuf_setlen(&sb, sb.len - 1);
- string_list_split_in_place(&list, sb.buf, '\n', -1);
+ string_list_split_in_place(&list, sb.buf, "\n", -1);
string_list_sort(&list);
diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c
index 22a41c4092..9df2f03ac8 100644
--- a/t/helper/test-submodule-config.c
+++ b/t/helper/test-submodule-config.c
@@ -1,10 +1,13 @@
#include "test-tool.h"
-#include "cache.h"
#include "config.h"
+#include "hash.h"
+#include "object-name.h"
+#include "repository.h"
+#include "setup.h"
#include "submodule-config.h"
#include "submodule.h"
-static void die_usage(int argc, const char **argv, const char *msg)
+static void die_usage(int argc UNUSED, const char **argv, const char *msg)
{
fprintf(stderr, "%s\n", msg);
fprintf(stderr, "Usage: %s [<commit> <submodulepath>] ...\n", argv[0]);
@@ -42,7 +45,7 @@ int cmd__submodule_config(int argc, const char **argv)
if (commit[0] == '\0')
oidclr(&commit_oid);
- else if (get_oid(commit, &commit_oid) < 0)
+ else if (repo_get_oid(the_repository, commit, &commit_oid) < 0)
die_usage(argc, argv, "Commit not found.");
if (lookup_name) {
diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c
index dc1c14bde3..ecd40ded99 100644
--- a/t/helper/test-submodule-nested-repo-config.c
+++ b/t/helper/test-submodule-nested-repo-config.c
@@ -1,4 +1,6 @@
#include "test-tool.h"
+#include "repository.h"
+#include "setup.h"
#include "submodule-config.h"
static void die_usage(const char **argv, const char *msg)
diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c
index e060cc6226..356e0a26c5 100644
--- a/t/helper/test-submodule.c
+++ b/t/helper/test-submodule.c
@@ -1,8 +1,9 @@
#include "test-tool.h"
#include "test-tool-utils.h"
-#include "cache.h"
#include "parse-options.h"
#include "remote.h"
+#include "repository.h"
+#include "setup.h"
#include "submodule-config.h"
#include "submodule.h"
@@ -174,7 +175,7 @@ static int cmd__submodule_config_unset(int argc, const char **argv)
usage_with_options(usage, options);
}
-static int cmd__submodule_config_writeable(int argc, const char **argv)
+static int cmd__submodule_config_writeable(int argc, const char **argv UNUSED)
{
struct option options[] = {
OPT_END()
diff --git a/t/helper/test-subprocess.c b/t/helper/test-subprocess.c
index ff22f2fa2c..c344f1694d 100644
--- a/t/helper/test-subprocess.c
+++ b/t/helper/test-subprocess.c
@@ -1,6 +1,6 @@
#include "test-tool.h"
-#include "cache.h"
#include "run-command.h"
+#include "setup.h"
int cmd__subprocess(int argc, const char **argv)
{
diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c
index f374c21ec3..20c7495f38 100644
--- a/t/helper/test-trace2.c
+++ b/t/helper/test-trace2.c
@@ -1,9 +1,10 @@
#include "test-tool.h"
-#include "cache.h"
#include "strvec.h"
#include "run-command.h"
#include "exec-cmd.h"
#include "config.h"
+#include "repository.h"
+#include "trace2.h"
typedef int(fn_unit_test)(int argc, const char **argv);
@@ -208,7 +209,7 @@ static int ut_007BUG(int argc, const char **argv)
BUG("the bug message");
}
-static int ut_008bug(int argc, const char **argv)
+static int ut_008bug(int argc UNUSED, const char **argv UNUSED)
{
bug("a bug message");
bug("another bug message");
@@ -216,7 +217,7 @@ static int ut_008bug(int argc, const char **argv)
return 0;
}
-static int ut_009bug_BUG(int argc, const char **argv)
+static int ut_009bug_BUG(int argc UNUSED, const char **argv UNUSED)
{
bug("a bug message");
bug("another bug message");
@@ -224,7 +225,7 @@ static int ut_009bug_BUG(int argc, const char **argv)
return 0;
}
-static int ut_010bug_BUG(int argc, const char **argv)
+static int ut_010bug_BUG(int argc UNUSED, const char **argv UNUSED)
{
bug("a %s message", "bug");
BUG("a %s message", "BUG");
diff --git a/t/helper/test-userdiff.c b/t/helper/test-userdiff.c
index a2b56b9cae..680124a676 100644
--- a/t/helper/test-userdiff.c
+++ b/t/helper/test-userdiff.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "cache.h"
+#include "setup.h"
#include "userdiff.h"
#include "config.h"
diff --git a/t/helper/test-wildmatch.c b/t/helper/test-wildmatch.c
index 2c103d1824..b4ff5f986a 100644
--- a/t/helper/test-wildmatch.c
+++ b/t/helper/test-wildmatch.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "cache.h"
+#include "wildmatch.h"
int cmd__wildmatch(int argc, const char **argv)
{
diff --git a/t/helper/test-write-cache.c b/t/helper/test-write-cache.c
index 7d45cd61e8..f084034d38 100644
--- a/t/helper/test-write-cache.c
+++ b/t/helper/test-write-cache.c
@@ -1,7 +1,9 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
-#include "cache.h"
#include "lockfile.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
int cmd__write_cache(int argc, const char **argv)
{
diff --git a/t/helper/test-xml-encode.c b/t/helper/test-xml-encode.c
index a648bbd961..b2f330d1a4 100644
--- a/t/helper/test-xml-encode.c
+++ b/t/helper/test-xml-encode.c
@@ -6,7 +6,7 @@ static const char *utf8_replace_character = "&#xfffd;";
* Encodes (possibly incorrect) UTF-8 on <stdin> to <stdout>, to be embedded
* in an XML file.
*/
-int cmd__xml_encode(int argc, const char **argv)
+int cmd__xml_encode(int argc UNUSED, const char **argv UNUSED)
{
unsigned char buf[1024], tmp[4], *tmp2 = NULL;
ssize_t cur = 0, len = 1, remaining = 0;
diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 5ea8bc9f1d..4ad498adbc 100644
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -43,6 +43,8 @@ helper_test_clean() {
reject $1 https example.com store-user
reject $1 https example.com user1
reject $1 https example.com user2
+ reject $1 https example.com user3
+ reject $1 https example.com user4
reject $1 http path.tld user
reject $1 https timeout.tld user
reject $1 https sso.tld
@@ -270,6 +272,35 @@ helper_test() {
password=
EOF
'
+
+ : ${GIT_TEST_LONG_CRED_BUFFER:=1024}
+ # 23 bytes accounts for "wwwauth[]=basic realm=" plus NUL
+ LONG_VALUE_LEN=$((GIT_TEST_LONG_CRED_BUFFER - 23))
+ LONG_VALUE=$(perl -e 'print "a" x shift' $LONG_VALUE_LEN)
+
+ test_expect_success "helper ($HELPER) not confused by long header" '
+ check approve $HELPER <<-\EOF &&
+ protocol=https
+ host=victim.example.com
+ username=user
+ password=to-be-stolen
+ EOF
+
+ check fill $HELPER <<-EOF
+ protocol=https
+ host=badguy.example.com
+ wwwauth[]=basic realm=${LONG_VALUE}host=victim.example.com
+ --
+ protocol=https
+ host=badguy.example.com
+ username=askpass-username
+ password=askpass-password
+ wwwauth[]=basic realm=${LONG_VALUE}host=victim.example.com
+ --
+ askpass: Username for '\''https://badguy.example.com'\'':
+ askpass: Password for '\''https://askpass-username@badguy.example.com'\'':
+ EOF
+ '
}
helper_test_timeout() {
@@ -298,6 +329,64 @@ helper_test_timeout() {
'
}
+helper_test_password_expiry_utc() {
+ HELPER=$1
+
+ test_expect_success "helper ($HELPER) stores password_expiry_utc" '
+ check approve $HELPER <<-\EOF
+ protocol=https
+ host=example.com
+ username=user3
+ password=pass
+ password_expiry_utc=9999999999
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) gets password_expiry_utc" '
+ check fill $HELPER <<-\EOF
+ protocol=https
+ host=example.com
+ username=user3
+ --
+ protocol=https
+ host=example.com
+ username=user3
+ password=pass
+ password_expiry_utc=9999999999
+ --
+ EOF
+ '
+}
+
+helper_test_oauth_refresh_token() {
+ HELPER=$1
+
+ test_expect_success "helper ($HELPER) stores oauth_refresh_token" '
+ check approve $HELPER <<-\EOF
+ protocol=https
+ host=example.com
+ username=user4
+ password=pass
+ oauth_refresh_token=xyzzy
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) gets oauth_refresh_token" '
+ check fill $HELPER <<-\EOF
+ protocol=https
+ host=example.com
+ username=user4
+ --
+ protocol=https
+ host=example.com
+ username=user4
+ password=pass
+ oauth_refresh_token=xyzzy
+ --
+ EOF
+ '
+}
+
write_script askpass <<\EOF
echo >&2 askpass: $*
what=$(echo $1 | cut -d" " -f1 | tr A-Z a-z | tr -cd a-z)
diff --git a/t/lib-diff-alternative.sh b/t/lib-diff-alternative.sh
index a8f5d3274a..c4dc2d46dc 100644
--- a/t/lib-diff-alternative.sh
+++ b/t/lib-diff-alternative.sh
@@ -112,15 +112,36 @@ EOF
STRATEGY=$1
- test_expect_success "$STRATEGY diff from attributes" '
+ test_expect_success "setup attributes files for tests with $STRATEGY" '
+ git checkout -b master &&
echo "file* diff=driver" >.gitattributes &&
- git config diff.driver.algorithm "$STRATEGY" &&
- test_must_fail git diff --no-index file1 file2 > output &&
- cat expect &&
- cat output &&
+ git add file1 file2 .gitattributes &&
+ git commit -m "adding files" &&
+ git checkout -b branchA &&
+ echo "file* diff=driverA" >.gitattributes &&
+ git add .gitattributes &&
+ git commit -m "adding driverA as diff driver" &&
+ git checkout master &&
+ git clone --bare --no-local . bare.git
+ '
+
+ test_expect_success "$STRATEGY diff from attributes" '
+ test_must_fail git -c diff.driver.algorithm=$STRATEGY diff --no-index file1 file2 > output &&
test_cmp expect output
'
+ test_expect_success "diff from attributes with bare repo with source" '
+ git -C bare.git --attr-source=branchA -c diff.driver.algorithm=myers \
+ -c diff.driverA.algorithm=$STRATEGY \
+ diff HEAD:file1 HEAD:file2 >output &&
+ test_cmp expect output
+ '
+
+ test_expect_success "diff from attributes with bare repo with invalid source" '
+ test_must_fail git -C bare.git --attr-source=invalid-branch diff \
+ HEAD:file1 HEAD:file2
+ '
+
test_expect_success "$STRATEGY diff from attributes has valid diffstat" '
echo "file* diff=driver" >.gitattributes &&
git config diff.driver.algorithm "$STRATEGY" &&
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 09cf5ed012..6805229dcb 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -142,6 +142,7 @@ prepare_httpd() {
install_script error-smart-http.sh
install_script error.sh
install_script apply-one-time-perl.sh
+ install_script nph-custom-auth.sh
ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
@@ -227,8 +228,12 @@ test_http_push_nonff () {
git commit -a -m path2 --amend &&
test_must_fail git push -v origin >output 2>&1 &&
- (cd "$REMOTE_REPO" &&
- test $HEAD = $(git rev-parse --verify HEAD))
+ (
+ cd "$REMOTE_REPO" &&
+ echo "$HEAD" >expect &&
+ git rev-parse --verify HEAD >actual &&
+ test_cmp expect actual
+ )
'
test_expect_success 'non-fast-forward push show ref status' '
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 31f82fa093..9e6892970d 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -101,6 +101,8 @@ PassEnv LC_ALL
Alias /dumb/ www/
Alias /auth/dumb/ www/auth/dumb/
+SetEnv PERL_PATH ${PERL_PATH}
+
<LocationMatch /smart/>
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
SetEnv GIT_HTTP_EXPORT_ALL
@@ -141,6 +143,11 @@ Alias /auth/dumb/ www/auth/dumb/
SetEnv GIT_HTTP_EXPORT_ALL
SetEnv GIT_PROTOCOL
</LocationMatch>
+<LocationMatch /custom_auth/>
+ SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
+ SetEnv GIT_HTTP_EXPORT_ALL
+ CGIPassAuth on
+</LocationMatch>
ScriptAlias /smart/incomplete_length/git-upload-pack incomplete-length-upload-pack-v2-http.sh/
ScriptAlias /smart/incomplete_body/git-upload-pack incomplete-body-upload-pack-v2-http.sh/
ScriptAlias /smart/no_report/git-receive-pack error-no-report.sh/
@@ -150,6 +157,7 @@ ScriptAlias /broken_smart/ broken-smart-http.sh/
ScriptAlias /error_smart/ error-smart-http.sh/
ScriptAlias /error/ error.sh/
ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1
+ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
<Directory ${GIT_EXEC_PATH}>
Options FollowSymlinks
</Directory>
diff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh
index 09a0abdff7..d7f9fed6ae 100644
--- a/t/lib-httpd/apply-one-time-perl.sh
+++ b/t/lib-httpd/apply-one-time-perl.sh
@@ -13,7 +13,7 @@ then
export LC_ALL
"$GIT_EXEC_PATH/git-http-backend" >out
- perl -pe "$(cat one-time-perl)" out >out_modified
+ "$PERL_PATH" -pe "$(cat one-time-perl)" out >out_modified
if cmp -s out out_modified
then
diff --git a/t/lib-httpd/nph-custom-auth.sh b/t/lib-httpd/nph-custom-auth.sh
new file mode 100644
index 0000000000..f5345e775e
--- /dev/null
+++ b/t/lib-httpd/nph-custom-auth.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+VALID_CREDS_FILE=custom-auth.valid
+CHALLENGE_FILE=custom-auth.challenge
+
+#
+# If $VALID_CREDS_FILE exists in $HTTPD_ROOT_PATH, consider each line as a valid
+# credential for the current request. Each line in the file is considered a
+# valid HTTP Authorization header value. For example:
+#
+# Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+#
+# If $CHALLENGE_FILE exists in $HTTPD_ROOT_PATH, output the contents as headers
+# in a 401 response if no valid authentication credentials were included in the
+# request. For example:
+#
+# WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+# WWW-Authenticate: Basic realm="example.com"
+#
+
+if test -n "$HTTP_AUTHORIZATION" && \
+ grep -Fqsx "${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE"
+then
+ # Note that although git-http-backend returns a status line, it
+ # does so using a CGI 'Status' header. Because this script is an
+ # No Parsed Headers (NPH) script, we must return a real HTTP
+ # status line.
+ # This is only a test script, so we don't bother to check for
+ # the actual status from git-http-backend and always return 200.
+ echo 'HTTP/1.1 200 OK'
+ exec "$GIT_EXEC_PATH"/git-http-backend
+fi
+
+echo 'HTTP/1.1 401 Authorization Required'
+if test -f "$CHALLENGE_FILE"
+then
+ cat "$CHALLENGE_FILE"
+fi
+echo
diff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh
index cfd76bf987..89ca1f7805 100644
--- a/t/lib-patch-mode.sh
+++ b/t/lib-patch-mode.sh
@@ -29,8 +29,12 @@ set_and_save_state () {
# verify_state <path> <expected-worktree-content> <expected-index-content>
verify_state () {
- test "$(cat "$1")" = "$2" &&
- test "$(git show :"$1")" = "$3"
+ echo "$2" >expect &&
+ test_cmp expect "$1" &&
+
+ echo "$3" >expect &&
+ git show :"$1" >actual &&
+ test_cmp expect actual
}
# verify_saved_state <path>
@@ -46,5 +50,6 @@ save_head () {
}
verify_saved_head () {
- test "$(cat _head)" = "$(git rev-parse HEAD)"
+ git rev-parse HEAD >actual &&
+ test_cmp _head actual
}
diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 2d31fcfda1..9acb0d5d19 100644
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -168,20 +168,16 @@ replace_gitfile_with_git_dir () {
# Note that this only supports submodules at the root level of the
# superproject, with the default name, i.e. same as its path.
test_git_directory_is_unchanged () {
- (
- cd ".git/modules/$1" &&
- # does core.worktree point at the right place?
- test "$(git config core.worktree)" = "../../../$1" &&
- # remove it temporarily before comparing, as
- # "$1/.git/config" lacks it...
- git config --unset core.worktree
- ) &&
+ # does core.worktree point at the right place?
+ echo "../../../$1" >expect &&
+ git -C ".git/modules/$1" config core.worktree >actual &&
+ test_cmp expect actual &&
+ # remove it temporarily before comparing, as
+ # "$1/.git/config" lacks it...
+ git -C ".git/modules/$1" config --unset core.worktree &&
diff -r ".git/modules/$1" "$1/.git" &&
- (
- # ... and then restore.
- cd ".git/modules/$1" &&
- git config core.worktree "../../../$1"
- )
+ # ... and then restore.
+ git -C ".git/modules/$1" config core.worktree "../../../$1"
}
test_git_directory_exists () {
@@ -189,7 +185,9 @@ test_git_directory_exists () {
if test -f sub1/.git
then
# does core.worktree point at the right place?
- test "$(git -C .git/modules/$1 config core.worktree)" = "../../../$1"
+ echo "../../../$1" >expect &&
+ git -C ".git/modules/$1" config core.worktree >actual &&
+ test_cmp expect actual
fi
}
@@ -804,7 +802,7 @@ test_submodule_recursing_with_args_common () {
git branch -t no_submodule origin/no_submodule &&
$command no_submodule &&
test_superproject_content origin/no_submodule &&
- ! test_path_is_dir sub1 &&
+ test_path_is_missing sub1 &&
test_must_fail git config -f .git/modules/sub1/config core.worktree &&
test_must_fail git config -f .git/modules/sub1/modules/sub2/config core.worktree
)
diff --git a/t/perf/p1500-graph-walks.sh b/t/perf/p1500-graph-walks.sh
new file mode 100755
index 0000000000..e14e7620cc
--- /dev/null
+++ b/t/perf/p1500-graph-walks.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='Commit walk performance tests'
+. ./perf-lib.sh
+
+test_perf_large_repo
+
+test_expect_success 'setup' '
+ git for-each-ref --format="%(refname)" "refs/heads/*" "refs/tags/*" >allrefs &&
+ sort -r allrefs | head -n 50 >refs &&
+ for ref in $(cat refs)
+ do
+ git branch -f ref-$ref $ref &&
+ echo ref-$ref ||
+ return 1
+ done >branches &&
+ for ref in $(cat refs)
+ do
+ git tag -f tag-$ref $ref &&
+ echo tag-$ref ||
+ return 1
+ done >tags &&
+ git commit-graph write --reachable
+'
+
+test_perf 'ahead-behind counts: git for-each-ref' '
+ git for-each-ref --format="%(ahead-behind:HEAD)" --stdin <refs
+'
+
+test_perf 'ahead-behind counts: git branch' '
+ xargs git branch -l --format="%(ahead-behind:HEAD)" <branches
+'
+
+test_perf 'ahead-behind counts: git tag' '
+ xargs git tag -l --format="%(ahead-behind:HEAD)" <tags
+'
+
+test_perf 'contains: git for-each-ref --merged' '
+ git for-each-ref --merged=HEAD --stdin <refs
+'
+
+test_perf 'contains: git branch --merged' '
+ xargs git branch --merged=HEAD <branches
+'
+
+test_perf 'contains: git tag --merged' '
+ xargs git tag --merged=HEAD <tags
+'
+
+test_done
diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh
index 3242cfe91a..901cc493ef 100755
--- a/t/perf/p2000-sparse-operations.sh
+++ b/t/perf/p2000-sparse-operations.sh
@@ -43,6 +43,7 @@ test_expect_success 'setup repo and indexes' '
done &&
git sparse-checkout init --cone &&
+ git tag -a v1.0 -m "Final" &&
git sparse-checkout set $SPARSE_CONE &&
git checkout -b wide $OLD_COMMIT &&
@@ -124,6 +125,11 @@ test_perf_on_all git read-tree -mu HEAD
test_perf_on_all git checkout-index -f --all
test_perf_on_all git update-index --add --remove $SPARSE_CONE/a
test_perf_on_all "git rm -f $SPARSE_CONE/a && git checkout HEAD -- $SPARSE_CONE/a"
-test_perf_on_all git grep --cached --sparse bogus -- "f2/f1/f1/*"
+test_perf_on_all git grep --cached bogus -- "f2/f1/f1/*"
+test_perf_on_all git write-tree
+test_perf_on_all git describe --dirty
+test_perf_on_all 'echo >>new && git describe --dirty'
+test_perf_on_all git diff-files
+test_perf_on_all git diff-files -- $SPARSE_CONE/a
test_done
diff --git a/t/perf/p5312-pack-bitmaps-revs.sh b/t/perf/p5312-pack-bitmaps-revs.sh
index 0684b690af..ceec60656b 100755
--- a/t/perf/p5312-pack-bitmaps-revs.sh
+++ b/t/perf/p5312-pack-bitmaps-revs.sh
@@ -12,8 +12,7 @@ test_lookup_pack_bitmap () {
test_perf_large_repo
test_expect_success 'setup bitmap config' '
- git config pack.writebitmaps true &&
- git config pack.writeReverseIndex true
+ git config pack.writebitmaps true
'
# we need to create the tag up front such that it is covered by the repack and
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index d479303efa..30a6edca1d 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -598,9 +598,14 @@ test_expect_success 'invalid default branch name' '
test_expect_success 'branch -m with the initial branch' '
git init rename-initial &&
git -C rename-initial branch -m renamed &&
- test renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&
+ echo renamed >expect &&
+ git -C rename-initial symbolic-ref --short HEAD >actual &&
+ test_cmp expect actual &&
+
git -C rename-initial branch -m renamed again &&
- test again = $(git -C rename-initial symbolic-ref --short HEAD)
+ echo again >expect &&
+ git -C rename-initial symbolic-ref --short HEAD >actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh
index 26eaca095a..e013d38f48 100755
--- a/t/t0002-gitfile.sh
+++ b/t/t0002-gitfile.sh
@@ -33,7 +33,9 @@ test_expect_success 'bad setup: invalid .git file path' '
test_expect_success 'final setup + check rev-parse --git-dir' '
echo "gitdir: $REAL" >.git &&
- test "$REAL" = "$(git rev-parse --git-dir)"
+ echo "$REAL" >expect &&
+ git rev-parse --git-dir >actual &&
+ test_cmp expect actual
'
test_expect_success 'check hash-object' '
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index 89b306cb11..26e082f05b 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -30,8 +30,17 @@ attr_check_quote () {
attr_check_source () {
path="$1" expect="$2" source="$3" git_opts="$4" &&
- git $git_opts check-attr --source $source test -- "$path" >actual 2>err &&
echo "$path: test: $expect" >expect &&
+
+ git $git_opts check-attr --source $source test -- "$path" >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err &&
+
+ git $git_opts --attr-source="$source" check-attr test -- "$path" >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
+
+ GIT_ATTR_SOURCE="$source" git $git_opts check-attr test -- "$path" >actual 2>err &&
test_cmp expect actual &&
test_must_be_empty err
}
diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index 35cc8c3b39..81946e87cc 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -125,7 +125,7 @@ test_expect_success 'update with autocrlf=input' '
munge_cr append dir/two &&
git update-index -- one dir/two &&
differs=$(git diff-index --cached HEAD) &&
- verbose test -z "$differs"
+ test -z "$differs"
'
@@ -138,7 +138,7 @@ test_expect_success 'update with autocrlf=true' '
munge_cr append dir/two &&
git update-index -- one dir/two &&
differs=$(git diff-index --cached HEAD) &&
- verbose test -z "$differs"
+ test -z "$differs"
'
@@ -153,7 +153,7 @@ test_expect_success 'checkout with autocrlf=true' '
test "$one" = $(git hash-object --stdin <one) &&
test "$two" = $(git hash-object --stdin <dir/two) &&
differs=$(git diff-index --cached HEAD) &&
- verbose test -z "$differs"
+ test -z "$differs"
'
test_expect_success 'checkout with autocrlf=input' '
@@ -167,7 +167,7 @@ test_expect_success 'checkout with autocrlf=input' '
test "$one" = $(git hash-object --stdin <one) &&
test "$two" = $(git hash-object --stdin <dir/two) &&
differs=$(git diff-index --cached HEAD) &&
- verbose test -z "$differs"
+ test -z "$differs"
'
test_expect_success 'apply patch (autocrlf=input)' '
@@ -177,7 +177,7 @@ test_expect_success 'apply patch (autocrlf=input)' '
git read-tree --reset -u HEAD &&
git apply patch.file &&
- verbose test "$patched" = "$(git hash-object --stdin <one)"
+ test "$patched" = "$(git hash-object --stdin <one)"
'
test_expect_success 'apply patch --cached (autocrlf=input)' '
@@ -187,7 +187,7 @@ test_expect_success 'apply patch --cached (autocrlf=input)' '
git read-tree --reset -u HEAD &&
git apply --cached patch.file &&
- verbose test "$patched" = $(git rev-parse :one)
+ test "$patched" = $(git rev-parse :one)
'
test_expect_success 'apply patch --index (autocrlf=input)' '
@@ -197,8 +197,8 @@ test_expect_success 'apply patch --index (autocrlf=input)' '
git read-tree --reset -u HEAD &&
git apply --index patch.file &&
- verbose test "$patched" = $(git rev-parse :one) &&
- verbose test "$patched" = $(git hash-object --stdin <one)
+ test "$patched" = $(git rev-parse :one) &&
+ test "$patched" = $(git hash-object --stdin <one)
'
test_expect_success 'apply patch (autocrlf=true)' '
@@ -208,7 +208,7 @@ test_expect_success 'apply patch (autocrlf=true)' '
git read-tree --reset -u HEAD &&
git apply patch.file &&
- verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
+ test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
'
test_expect_success 'apply patch --cached (autocrlf=true)' '
@@ -218,7 +218,7 @@ test_expect_success 'apply patch --cached (autocrlf=true)' '
git read-tree --reset -u HEAD &&
git apply --cached patch.file &&
- verbose test "$patched" = $(git rev-parse :one)
+ test "$patched" = $(git rev-parse :one)
'
test_expect_success 'apply patch --index (autocrlf=true)' '
@@ -228,8 +228,8 @@ test_expect_success 'apply patch --index (autocrlf=true)' '
git read-tree --reset -u HEAD &&
git apply --index patch.file &&
- verbose test "$patched" = $(git rev-parse :one) &&
- verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
+ test "$patched" = $(git rev-parse :one) &&
+ test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
'
test_expect_success '.gitattributes says two is binary' '
@@ -240,7 +240,7 @@ test_expect_success '.gitattributes says two is binary' '
git read-tree --reset -u HEAD &&
! has_cr dir/two &&
- verbose has_cr one &&
+ has_cr one &&
! has_cr three
'
@@ -259,8 +259,8 @@ test_expect_success '.gitattributes says two and three are text' '
echo "t* crlf" >.gitattributes &&
git read-tree --reset -u HEAD &&
- verbose has_cr dir/two &&
- verbose has_cr three
+ has_cr dir/two &&
+ has_cr three
'
test_expect_success 'in-tree .gitattributes (1)' '
@@ -273,7 +273,7 @@ test_expect_success 'in-tree .gitattributes (1)' '
git read-tree --reset -u HEAD &&
! has_cr one &&
- verbose has_cr three
+ has_cr three
'
test_expect_success 'in-tree .gitattributes (2)' '
@@ -283,7 +283,7 @@ test_expect_success 'in-tree .gitattributes (2)' '
git checkout-index -f -q -u -a &&
! has_cr one &&
- verbose has_cr three
+ has_cr three
'
test_expect_success 'in-tree .gitattributes (3)' '
@@ -294,7 +294,7 @@ test_expect_success 'in-tree .gitattributes (3)' '
git checkout-index -u one dir/two three &&
! has_cr one &&
- verbose has_cr three
+ has_cr three
'
test_expect_success 'in-tree .gitattributes (4)' '
@@ -305,7 +305,7 @@ test_expect_success 'in-tree .gitattributes (4)' '
git checkout-index -u .gitattributes &&
! has_cr one &&
- verbose has_cr three
+ has_cr three
'
test_expect_success 'checkout with existing .gitattributes' '
diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index a94ac1eae3..2f57c8669c 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -70,7 +70,8 @@ create_NNO_MIX_files () {
cp CRLF ${pfx}_CRLF.txt &&
cp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&
cp LF_mix_CR ${pfx}_LF_mix_CR.txt &&
- cp CRLF_nul ${pfx}_CRLF_nul.txt
+ cp CRLF_nul ${pfx}_CRLF_nul.txt ||
+ return 1
done
done
done
@@ -101,7 +102,8 @@ commit_check_warn () {
do
fname=${pfx}_$f.txt &&
cp $f $fname &&
- git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
+ git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" ||
+ return 1
done &&
git commit -m "core.autocrlf $crlf" &&
check_warning "$lfname" ${pfx}_LF.err &&
@@ -121,15 +123,19 @@ commit_chk_wrnNNO () {
lfmixcr=$1 ; shift
crlfnul=$1 ; shift
pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}
- #Commit files on top of existing file
- create_gitattributes "$attr" $aeol &&
- for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
- do
- fname=${pfx}_$f.txt &&
- cp $f $fname &&
- printf Z >>"$fname" &&
- git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
- done
+
+ test_expect_success 'setup commit NNO files' '
+ #Commit files on top of existing file
+ create_gitattributes "$attr" $aeol &&
+ for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
+ do
+ fname=${pfx}_$f.txt &&
+ cp $f $fname &&
+ printf Z >>"$fname" &&
+ git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" ||
+ return 1
+ done
+ '
test_expect_success "commit NNO files crlf=$crlf attr=$attr LF" '
check_warning "$lfwarn" ${pfx}_LF.err
@@ -163,15 +169,19 @@ commit_MIX_chkwrn () {
lfmixcr=$1 ; shift
crlfnul=$1 ; shift
pfx=MIX_attr_${attr}_aeol_${aeol}_${crlf}
- #Commit file with CLRF_mix_LF on top of existing file
- create_gitattributes "$attr" $aeol &&
- for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
- do
- fname=${pfx}_$f.txt &&
- cp CRLF_mix_LF $fname &&
- printf Z >>"$fname" &&
- git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
- done
+
+ test_expect_success 'setup commit file with mixed EOL' '
+ #Commit file with CLRF_mix_LF on top of existing file
+ create_gitattributes "$attr" $aeol &&
+ for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
+ do
+ fname=${pfx}_$f.txt &&
+ cp CRLF_mix_LF $fname &&
+ printf Z >>"$fname" &&
+ git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" ||
+ return 1
+ done
+ '
test_expect_success "commit file with mixed EOL onto LF crlf=$crlf attr=$attr" '
check_warning "$lfwarn" ${pfx}_LF.err
@@ -289,17 +299,17 @@ checkout_files () {
lfmixcrlf=$1 ; shift
lfmixcr=$1 ; shift
crlfnul=$1 ; shift
- create_gitattributes "$attr" $ident $aeol &&
- git config core.autocrlf $crlf &&
+ test_expect_success "setup config for checkout attr=$attr ident=$ident aeol=$aeol core.autocrlf=$crlf" '
+ create_gitattributes "$attr" $ident $aeol &&
+ git config core.autocrlf $crlf
+ '
pfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&
for f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul
do
- rm crlf_false_attr__$f.txt &&
- if test -z "$ceol"; then
- git checkout -- crlf_false_attr__$f.txt
- else
- git -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt
- fi
+ test_expect_success "setup $f checkout ${ceol:+ with -c core.eol=$ceol}" '
+ rm -f crlf_false_attr__$f.txt &&
+ git ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt
+ '
done
test_expect_success "ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol" '
diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh
index 11c15a48aa..038b8b788d 100755
--- a/t/t0035-safe-bare-repository.sh
+++ b/t/t0035-safe-bare-repository.sh
@@ -7,13 +7,26 @@ TEST_PASSES_SANITIZE_LEAK=true
pwd="$(pwd)"
-expect_accepted () {
- git "$@" rev-parse --git-dir
+expect_accepted_implicit () {
+ test_when_finished 'rm "$pwd/trace.perf"' &&
+ GIT_TRACE2_PERF="$pwd/trace.perf" git "$@" rev-parse --git-dir &&
+ # Note: we're intentionally only checking that the bare repo has a
+ # directory *prefix* of $pwd
+ grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
+}
+
+expect_accepted_explicit () {
+ test_when_finished 'rm "$pwd/trace.perf"' &&
+ GIT_DIR="$1" GIT_TRACE2_PERF="$pwd/trace.perf" git rev-parse --git-dir &&
+ ! grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
}
expect_rejected () {
- test_must_fail git "$@" rev-parse --git-dir 2>err &&
- grep -F "cannot use bare repository" err
+ test_when_finished 'rm "$pwd/trace.perf"' &&
+ test_env GIT_TRACE2_PERF="$pwd/trace.perf" \
+ test_must_fail git "$@" rev-parse --git-dir 2>err &&
+ grep -F "cannot use bare repository" err &&
+ grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
}
test_expect_success 'setup bare repo in worktree' '
@@ -22,12 +35,13 @@ test_expect_success 'setup bare repo in worktree' '
'
test_expect_success 'safe.bareRepository unset' '
- expect_accepted -C outer-repo/bare-repo
+ test_unconfig --global safe.bareRepository &&
+ expect_accepted_implicit -C outer-repo/bare-repo
'
test_expect_success 'safe.bareRepository=all' '
test_config_global safe.bareRepository all &&
- expect_accepted -C outer-repo/bare-repo
+ expect_accepted_implicit -C outer-repo/bare-repo
'
test_expect_success 'safe.bareRepository=explicit' '
@@ -47,7 +61,7 @@ test_expect_success 'safe.bareRepository in the repository' '
test_expect_success 'safe.bareRepository on the command line' '
test_config_global safe.bareRepository explicit &&
- expect_accepted -C outer-repo/bare-repo \
+ expect_accepted_implicit -C outer-repo/bare-repo \
-c safe.bareRepository=all
'
@@ -60,4 +74,8 @@ test_expect_success 'safe.bareRepository in included file' '
expect_rejected -C outer-repo/bare-repo
'
+test_expect_success 'no trace when GIT_DIR is explicitly provided' '
+ expect_accepted_explicit "$pwd/outer-repo/bare-repo"
+'
+
test_done
diff --git a/t/t0041-usage.sh b/t/t0041-usage.sh
index c4fc34eb18..9ea974b0c6 100755
--- a/t/t0041-usage.sh
+++ b/t/t0041-usage.sh
@@ -5,6 +5,7 @@ test_description='Test commands behavior when given invalid argument value'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup ' '
diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh
index 6bada37022..c3eb1158ef 100755
--- a/t/t0055-beyond-symlinks.sh
+++ b/t/t0055-beyond-symlinks.sh
@@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup '
test_expect_success SYMLINKS 'update-index --add beyond symlinks' '
test_must_fail git update-index --add c/d &&
- ! ( git ls-files | grep c/d )
+ cat >expect <<-\EOF &&
+ a
+ b/d
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
'
test_expect_success SYMLINKS 'add beyond symlinks' '
test_must_fail git add c/d &&
- ! ( git ls-files | grep c/d )
+ cat >expect <<-\EOF &&
+ a
+ b/d
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 68e29c904a..0afa3d0d31 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -10,20 +10,27 @@ TEST_PASSES_SANITIZE_LEAK=true
norm_path() {
expected=$(test-tool path-utils print_path "$2")
- test_expect_success $3 "normalize path: $1 => $2" \
- "test \"\$(test-tool path-utils normalize_path_copy '$1')\" = '$expected'"
+ test_expect_success $3 "normalize path: $1 => $2" "
+ echo '$expected' >expect &&
+ test-tool path-utils normalize_path_copy '$1' >actual &&
+ test_cmp expect actual
+ "
}
relative_path() {
expected=$(test-tool path-utils print_path "$3")
- test_expect_success $4 "relative path: $1 $2 => $3" \
- "test \"\$(test-tool path-utils relative_path '$1' '$2')\" = '$expected'"
+ test_expect_success $4 "relative path: $1 $2 => $3" "
+ echo '$expected' >expect &&
+ test-tool path-utils relative_path '$1' '$2' >actual &&
+ test_cmp expect actual
+ "
}
test_submodule_relative_url() {
test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
- actual=\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&
- test \"\$actual\" = '$4'
+ echo '$4' >expect &&
+ test-tool submodule resolve-relative-url '$1' '$2' '$3' >actual &&
+ test_cmp expect actual
"
}
@@ -64,9 +71,11 @@ ancestor() {
expected=$(($expected-$rootslash+$rootoff))
;;
esac
- test_expect_success $4 "longest ancestor: $1 $2 => $expected" \
- "actual=\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&
- test \"\$actual\" = '$expected'"
+ test_expect_success $4 "longest ancestor: $1 $2 => $expected" "
+ echo '$expected' >expect &&
+ test-tool path-utils longest_ancestor_length '$1' '$2' >actual &&
+ test_cmp expect actual
+ "
}
# Some absolute path tests should be skipped on Windows due to path mangling
@@ -166,8 +175,10 @@ ancestor D:/Users/me C:/ -1 MINGW
ancestor //server/share/my-directory //server/share/ 14 MINGW
test_expect_success 'strip_path_suffix' '
- test c:/msysgit = $(test-tool path-utils strip_path_suffix \
- c:/msysgit/libexec//git-core libexec/git-core)
+ echo c:/msysgit >expect &&
+ test-tool path-utils strip_path_suffix \
+ c:/msysgit/libexec//git-core libexec/git-core >actual &&
+ test_cmp expect actual
'
test_expect_success 'absolute path rejects the empty string' '
@@ -188,35 +199,61 @@ test_expect_success 'real path rejects the empty string' '
'
test_expect_success POSIX 'real path works on absolute paths 1' '
+ echo / >expect &&
+ test-tool path-utils real_path "/" >actual &&
+ test_cmp expect actual &&
+
nopath="hopefully-absent-path" &&
- test "/" = "$(test-tool path-utils real_path "/")" &&
- test "/$nopath" = "$(test-tool path-utils real_path "/$nopath")"
+ echo "/$nopath" >expect &&
+ test-tool path-utils real_path "/$nopath" >actual &&
+ test_cmp expect actual
'
test_expect_success 'real path works on absolute paths 2' '
- nopath="hopefully-absent-path" &&
# Find an existing top-level directory for the remaining tests:
d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
- test "$d" = "$(test-tool path-utils real_path "$d")" &&
- test "$d/$nopath" = "$(test-tool path-utils real_path "$d/$nopath")"
+ echo "$d" >expect &&
+ test-tool path-utils real_path "$d" >actual &&
+ test_cmp expect actual &&
+
+ nopath="hopefully-absent-path" &&
+ echo "$d/$nopath" >expect &&
+ test-tool path-utils real_path "$d/$nopath" >actual &&
+ test_cmp expect actual
'
test_expect_success POSIX 'real path removes extra leading slashes' '
+ echo "/" >expect &&
+ test-tool path-utils real_path "///" >actual &&
+ test_cmp expect actual &&
+
nopath="hopefully-absent-path" &&
- test "/" = "$(test-tool path-utils real_path "///")" &&
- test "/$nopath" = "$(test-tool path-utils real_path "///$nopath")" &&
+ echo "/$nopath" >expect &&
+ test-tool path-utils real_path "///$nopath" >actual &&
+ test_cmp expect actual &&
+
# Find an existing top-level directory for the remaining tests:
d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
- test "$d" = "$(test-tool path-utils real_path "//$d")" &&
- test "$d/$nopath" = "$(test-tool path-utils real_path "//$d/$nopath")"
+ echo "$d" >expect &&
+ test-tool path-utils real_path "//$d" >actual &&
+ test_cmp expect actual &&
+
+ echo "$d/$nopath" >expect &&
+ test-tool path-utils real_path "//$d/$nopath" >actual &&
+ test_cmp expect actual
'
test_expect_success 'real path removes other extra slashes' '
- nopath="hopefully-absent-path" &&
# Find an existing top-level directory for the remaining tests:
d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
- test "$d" = "$(test-tool path-utils real_path "$d///")" &&
- test "$d/$nopath" = "$(test-tool path-utils real_path "$d///$nopath")"
+ echo "$d" >expect &&
+ test-tool path-utils real_path "$d///" >actual &&
+ test_cmp expect actual &&
+
+ nopath="hopefully-absent-path" &&
+ echo "$d/$nopath" >expect &&
+ test-tool path-utils real_path "$d///$nopath" >actual &&
+ test_cmp expect actual
'
test_expect_success SYMLINKS 'real path works on symlinks' '
@@ -227,19 +264,29 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
mkdir third &&
dir="$(cd .git && pwd -P)" &&
dir2=third/../second/other/.git &&
- test "$dir" = "$(test-tool path-utils real_path $dir2)" &&
+ echo "$dir" >expect &&
+ test-tool path-utils real_path $dir2 >actual &&
+ test_cmp expect actual &&
file="$dir"/index &&
- test "$file" = "$(test-tool path-utils real_path $dir2/index)" &&
+ echo "$file" >expect &&
+ test-tool path-utils real_path $dir2/index >actual &&
+ test_cmp expect actual &&
basename=blub &&
- test "$dir/$basename" = "$(cd .git && test-tool path-utils real_path "$basename")" &&
+ echo "$dir/$basename" >expect &&
+ test-tool -C .git path-utils real_path "$basename" >actual &&
+ test_cmp expect actual &&
ln -s ../first/file .git/syml &&
sym="$(cd first && pwd -P)"/file &&
- test "$sym" = "$(test-tool path-utils real_path "$dir2/syml")"
+ echo "$sym" >expect &&
+ test-tool path-utils real_path "$dir2/syml" >actual &&
+ test_cmp expect actual
'
test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '
ln -s target symlink &&
- test "$(test-tool path-utils prefix_path prefix "$(pwd)/symlink")" = "symlink"
+ echo "symlink" >expect &&
+ test-tool path-utils prefix_path prefix "$(pwd)/symlink" >actual &&
+ test_cmp expect actual
'
test_expect_success 'prefix_path works with only absolute path to work tree' '
@@ -255,7 +302,10 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin
test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having same beginning as work tree' '
git init repo &&
ln -s repo repolink &&
- test "a" = "$(cd repo && test-tool path-utils prefix_path prefix "$(pwd)/../repolink/a")"
+ echo "a" >expect &&
+ repo_path="$(cd repo && pwd)" &&
+ test-tool -C repo path-utils prefix_path prefix "$repo_path/../repolink/a" >actual &&
+ test_cmp expect actual
'
relative_path /foo/a/b/c/ /foo/a/b/ c/
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index e2411f6a9b..883d871dfb 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -135,6 +135,15 @@ test_expect_success 'run_command runs in parallel with more jobs available than
test_cmp expect actual
'
+test_expect_success 'run_command runs in parallel with more jobs available than tasks --on-stderr-output' '
+ test-tool run-command --on-stderr-output run-command-parallel 5 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>err &&
+ test_must_be_empty out &&
+ test 4 = $(grep -c "on_stderr_output: Hello" err) &&
+ test 4 = $(grep -c "on_stderr_output: World" err) &&
+ sed "/on_stderr_output/d" err >err1 &&
+ test_cmp expect err1
+'
+
test_expect_success 'run_command runs ungrouped in parallel with more jobs available than tasks' '
test-tool run-command --ungroup run-command-parallel 5 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>err &&
test_line_count = 8 out &&
@@ -147,6 +156,15 @@ test_expect_success 'run_command runs in parallel with as many jobs as tasks' '
test_cmp expect actual
'
+test_expect_success 'run_command runs in parallel with as many jobs as tasks --on-stderr-output' '
+ test-tool run-command --on-stderr-output run-command-parallel 4 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>err &&
+ test_must_be_empty out &&
+ test 4 = $(grep -c "on_stderr_output: Hello" err) &&
+ test 4 = $(grep -c "on_stderr_output: World" err) &&
+ sed "/on_stderr_output/d" err >err1 &&
+ test_cmp expect err1
+'
+
test_expect_success 'run_command runs ungrouped in parallel with as many jobs as tasks' '
test-tool run-command --ungroup run-command-parallel 4 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>err &&
test_line_count = 8 out &&
@@ -159,6 +177,15 @@ test_expect_success 'run_command runs in parallel with more tasks than jobs avai
test_cmp expect actual
'
+test_expect_success 'run_command runs in parallel with more tasks than jobs available --on-stderr-output' '
+ test-tool run-command --on-stderr-output run-command-parallel 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>err &&
+ test_must_be_empty out &&
+ test 4 = $(grep -c "on_stderr_output: Hello" err) &&
+ test 4 = $(grep -c "on_stderr_output: World" err) &&
+ sed "/on_stderr_output/d" err >err1 &&
+ test_cmp expect err1
+'
+
test_expect_success 'run_command runs ungrouped in parallel with more tasks than jobs available' '
test-tool run-command --ungroup run-command-parallel 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>err &&
test_line_count = 8 out &&
@@ -180,6 +207,12 @@ test_expect_success 'run_command is asked to abort gracefully' '
test_cmp expect actual
'
+test_expect_success 'run_command is asked to abort gracefully --on-stderr-output' '
+ test-tool run-command --on-stderr-output run-command-abort 3 false >out 2>err &&
+ test_must_be_empty out &&
+ test_cmp expect err
+'
+
test_expect_success 'run_command is asked to abort gracefully (ungroup)' '
test-tool run-command --ungroup run-command-abort 3 false >out 2>err &&
test_must_be_empty out &&
@@ -196,6 +229,12 @@ test_expect_success 'run_command outputs ' '
test_cmp expect actual
'
+test_expect_success 'run_command outputs --on-stderr-output' '
+ test-tool run-command --on-stderr-output run-command-no-jobs 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>err &&
+ test_must_be_empty out &&
+ test_cmp expect err
+'
+
test_expect_success 'run_command outputs (ungroup) ' '
test-tool run-command --ungroup run-command-no-jobs 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>err &&
test_must_be_empty out &&
diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh
index 46d4839194..1fee6d9010 100755
--- a/t/t0063-string-list.sh
+++ b/t/t0063-string-list.sh
@@ -18,6 +18,14 @@ test_split () {
"
}
+test_split_in_place() {
+ cat >expected &&
+ test_expect_success "split (in place) $1 at $2, max $3" "
+ test-tool string-list split_in_place '$1' '$2' '$3' >actual &&
+ test_cmp expected actual
+ "
+}
+
test_split "foo:bar:baz" ":" "-1" <<EOF
3
[0]: "foo"
@@ -61,6 +69,49 @@ test_split ":" ":" "-1" <<EOF
[1]: ""
EOF
+test_split_in_place "foo:;:bar:;:baz:;:" ":;" "-1" <<EOF
+10
+[0]: "foo"
+[1]: ""
+[2]: ""
+[3]: "bar"
+[4]: ""
+[5]: ""
+[6]: "baz"
+[7]: ""
+[8]: ""
+[9]: ""
+EOF
+
+test_split_in_place "foo:;:bar:;:baz" ":;" "0" <<EOF
+1
+[0]: "foo:;:bar:;:baz"
+EOF
+
+test_split_in_place "foo:;:bar:;:baz" ":;" "1" <<EOF
+2
+[0]: "foo"
+[1]: ";:bar:;:baz"
+EOF
+
+test_split_in_place "foo:;:bar:;:baz" ":;" "2" <<EOF
+3
+[0]: "foo"
+[1]: ""
+[2]: ":bar:;:baz"
+EOF
+
+test_split_in_place "foo:;:bar:;:" ":;" "-1" <<EOF
+7
+[0]: "foo"
+[1]: ""
+[2]: ""
+[3]: "bar"
+[4]: ""
+[5]: ""
+[6]: ""
+EOF
+
test_expect_success "test filter_string_list" '
test "x-" = "x$(test-tool string-list filter - y)" &&
test "x-" = "x$(test-tool string-list filter no y)" &&
diff --git a/t/t0068-for-each-repo.sh b/t/t0068-for-each-repo.sh
index 3648d439a8..4b90b74d5d 100755
--- a/t/t0068-for-each-repo.sh
+++ b/t/t0068-for-each-repo.sh
@@ -40,4 +40,23 @@ test_expect_success 'do nothing on empty config' '
git for-each-repo --config=bogus.config -- help --no-such-option
'
+test_expect_success 'error on bad config keys' '
+ test_expect_code 129 git for-each-repo --config=a &&
+ test_expect_code 129 git for-each-repo --config=a.b. &&
+ test_expect_code 129 git for-each-repo --config="'\''.b"
+'
+
+test_expect_success 'error on NULL value for config keys' '
+ cat >>.git/config <<-\EOF &&
+ [empty]
+ key
+ EOF
+ cat >expect <<-\EOF &&
+ error: missing value for '\''empty.key'\''
+ EOF
+ test_expect_code 129 git for-each-repo --config=empty.key 2>actual.raw &&
+ grep ^error actual.raw >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t0100-previous.sh b/t/t0100-previous.sh
index a16cc3d298..70a3223f21 100755
--- a/t/t0100-previous.sh
+++ b/t/t0100-previous.sh
@@ -12,7 +12,9 @@ test_expect_success 'branch -d @{-1}' '
test_commit A &&
git checkout -b junk &&
git checkout - &&
- test "$(git symbolic-ref HEAD)" = refs/heads/main &&
+ echo refs/heads/main >expect &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
git branch -d @{-1} &&
test_must_fail git rev-parse --verify refs/heads/junk
'
@@ -21,7 +23,9 @@ test_expect_success 'branch -d @{-12} when there is not enough switches yet' '
git reflog expire --expire=now &&
git checkout -b junk2 &&
git checkout - &&
- test "$(git symbolic-ref HEAD)" = refs/heads/main &&
+ echo refs/heads/main >expect &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
test_must_fail git branch -d @{-12} &&
git rev-parse --verify refs/heads/main
'
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index c66d91e82d..a4f5bba507 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -214,6 +214,24 @@ test_expect_success 'credential_approve stores password expiry' '
EOF
'
+test_expect_success 'credential_approve stores oauth refresh token' '
+ check approve useless <<-\EOF
+ protocol=http
+ host=example.com
+ username=foo
+ password=bar
+ oauth_refresh_token=xyzzy
+ --
+ --
+ useless: store
+ useless: protocol=http
+ useless: host=example.com
+ useless: username=foo
+ useless: password=bar
+ useless: oauth_refresh_token=xyzzy
+ EOF
+'
+
test_expect_success 'do not bother storing password-less credential' '
check approve useless <<-\EOF
protocol=http
@@ -808,7 +826,7 @@ test_expect_success 'credential config with partial URLs' '
git -c credential.$partial.helper=yep \
-c credential.with%0anewline.username=uh-oh \
- credential fill <stdin >stdout 2>stderr &&
+ credential fill <stdin 2>stderr &&
test_i18ngrep "skipping credential lookup for key" stderr
'
diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh
index 698b7159f0..8300faadea 100755
--- a/t/t0301-credential-cache.sh
+++ b/t/t0301-credential-cache.sh
@@ -29,6 +29,8 @@ test_atexit 'git credential-cache exit'
# test that the daemon works with no special setup
helper_test cache
+helper_test_password_expiry_utc cache
+helper_test_oauth_refresh_token cache
test_expect_success 'socket defaults to ~/.cache/git/credential/socket' '
test_when_finished "
diff --git a/t/t0303-credential-external.sh b/t/t0303-credential-external.sh
index f028fd1418..095574bfc6 100755
--- a/t/t0303-credential-external.sh
+++ b/t/t0303-credential-external.sh
@@ -45,6 +45,8 @@ test -z "$GIT_TEST_CREDENTIAL_HELPER_SETUP" ||
helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER"
helper_test "$GIT_TEST_CREDENTIAL_HELPER"
+helper_test_password_expiry_utc "$GIT_TEST_CREDENTIAL_HELPER"
+helper_test_oauth_refresh_token "$GIT_TEST_CREDENTIAL_HELPER"
if test -z "$GIT_TEST_CREDENTIAL_HELPER_TIMEOUT"; then
say "# skipping timeout tests (GIT_TEST_CREDENTIAL_HELPER_TIMEOUT not set)"
diff --git a/t/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh
index 12e30d77d0..26be4a2b5a 100755
--- a/t/t1005-read-tree-reset.sh
+++ b/t/t1005-read-tree-reset.sh
@@ -41,7 +41,8 @@ test_expect_success 'reset should remove remnants from a failed merge' '
git ls-files -s &&
read_tree_u_must_succeed --reset -u HEAD &&
git ls-files -s >actual &&
- ! test -f old
+ ! test -f old &&
+ test_cmp expect actual
'
test_expect_success 'two-way reset should remove remnants too' '
@@ -56,7 +57,8 @@ test_expect_success 'two-way reset should remove remnants too' '
git ls-files -s &&
read_tree_u_must_succeed --reset -u HEAD HEAD &&
git ls-files -s >actual &&
- ! test -f old
+ ! test -f old &&
+ test_cmp expect actual
'
test_expect_success 'Porcelain reset should remove remnants too' '
@@ -71,7 +73,8 @@ test_expect_success 'Porcelain reset should remove remnants too' '
git ls-files -s &&
git reset --hard &&
git ls-files -s >actual &&
- ! test -f old
+ ! test -f old &&
+ test_cmp expect actual
'
test_expect_success 'Porcelain checkout -f should remove remnants too' '
@@ -86,7 +89,8 @@ test_expect_success 'Porcelain checkout -f should remove remnants too' '
git ls-files -s &&
git checkout -f &&
git ls-files -s >actual &&
- ! test -f old
+ ! test -f old &&
+ test_cmp expect actual
'
test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' '
@@ -101,7 +105,8 @@ test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' '
git ls-files -s &&
git checkout -f HEAD &&
git ls-files -s >actual &&
- ! test -f old
+ ! test -f old &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 2d875b17d8..8eac74b59c 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -603,7 +603,8 @@ do
fatal: Not a valid object name $(test_oid deadbeef_short)
EOF
test_must_fail git cat-file $arg1 $arg2 $(test_oid deadbeef_short) >out 2>err.actual &&
- test_must_be_empty out
+ test_must_be_empty out &&
+ test_cmp expect.err err.actual
'
test_expect_success "cat-file $arg1 $arg2 error on missing full OID" '
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index 3c08194526..22875ba598 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -60,11 +60,11 @@ test_expect_success 'allow missing object with --missing' '
'
test_expect_success 'mktree refuses to read ls-tree -r output (1)' '
- test_must_fail git mktree <all >actual
+ test_must_fail git mktree <all
'
test_expect_success 'mktree refuses to read ls-tree -r output (2)' '
- test_must_fail git mktree <all.withsub >actual
+ test_must_fail git mktree <all.withsub
'
test_done
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index 627267be15..9ceb17f911 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -555,7 +555,7 @@ test_expect_success 'cone mode: set with core.ignoreCase=true' '
check_files repo a folder1
'
-test_expect_success 'interaction with submodules' '
+test_expect_success 'setup submodules' '
git clone repo super &&
(
cd super &&
@@ -566,11 +566,22 @@ test_expect_success 'interaction with submodules' '
git commit -m "add submodule" &&
git sparse-checkout init --cone &&
git sparse-checkout set folder1
- ) &&
+ )
+'
+
+test_expect_success 'interaction with submodules' '
check_files super a folder1 modules &&
check_files super/modules/child a deep folder1 folder2
'
+test_expect_success 'check-rules interaction with submodules' '
+ git -C super ls-tree --name-only -r HEAD >all-files &&
+ git -C super sparse-checkout check-rules >check-rules-matches <all-files &&
+
+ test_i18ngrep ! "modules/" check-rules-matches &&
+ test_i18ngrep "folder1/" check-rules-matches
+'
+
test_expect_success 'different sparse-checkouts with worktrees' '
git -C repo sparse-checkout set --cone deep folder1 &&
git -C repo worktree add --detach ../worktree &&
@@ -882,4 +893,156 @@ test_expect_success 'by default, non-cone mode will warn on individual files' '
grep "pass a leading slash before paths.*if you want a single file" warning
'
+test_expect_success 'setup bare repo' '
+ git clone --bare "file://$(pwd)/repo" bare
+'
+test_expect_success 'list fails outside work tree' '
+ test_must_fail git -C bare sparse-checkout list 2>err &&
+ test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'add fails outside work tree' '
+ test_must_fail git -C bare sparse-checkout add deeper 2>err &&
+ test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'set fails outside work tree' '
+ test_must_fail git -C bare sparse-checkout set deeper 2>err &&
+ test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'init fails outside work tree' '
+ test_must_fail git -C bare sparse-checkout init 2>err &&
+ test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'reapply fails outside work tree' '
+ test_must_fail git -C bare sparse-checkout reapply 2>err &&
+ test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'disable fails outside work tree' '
+ test_must_fail git -C bare sparse-checkout disable 2>err &&
+ test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'setup clean' '
+ git -C repo clean -fdx
+'
+
+test_expect_success 'check-rules cone mode' '
+ cat >rules <<-\EOF &&
+ folder1
+ deep/deeper1/deepest
+ EOF
+
+ git -C bare ls-tree -r --name-only HEAD >all-files &&
+ git -C bare sparse-checkout check-rules --cone \
+ --rules-file ../rules >check-rules-file <all-files &&
+
+ git -C repo sparse-checkout set --cone --stdin <rules&&
+ git -C repo ls-files -t >out &&
+ sed -n "/^S /!s/^. //p" out >ls-files &&
+
+ git -C repo sparse-checkout check-rules >check-rules-default <all-files &&
+
+ test_i18ngrep "deep/deeper1/deepest/a" check-rules-file &&
+ test_i18ngrep ! "deep/deeper2" check-rules-file &&
+
+ test_cmp check-rules-file ls-files &&
+ test_cmp check-rules-file check-rules-default
+'
+
+test_expect_success 'check-rules non-cone mode' '
+ cat >rules <<-\EOF &&
+ deep/deeper1/deepest/a
+ EOF
+
+ git -C bare ls-tree -r --name-only HEAD >all-files &&
+ git -C bare sparse-checkout check-rules --no-cone --rules-file ../rules\
+ >check-rules-file <all-files &&
+
+ cat rules | git -C repo sparse-checkout set --no-cone --stdin &&
+ git -C repo ls-files -t >out &&
+ sed -n "/^S /!s/^. //p" out >ls-files &&
+
+ git -C repo sparse-checkout check-rules >check-rules-default <all-files &&
+
+ cat >expect <<-\EOF &&
+ deep/deeper1/deepest/a
+ EOF
+
+ test_cmp expect check-rules-file &&
+ test_cmp check-rules-file ls-files &&
+ test_cmp check-rules-file check-rules-default
+'
+
+test_expect_success 'check-rules cone mode is default' '
+ cat >rules <<-\EOF &&
+ folder1
+ EOF
+
+ cat >all-files <<-\EOF &&
+ toplevel
+ folder2/file
+ folder1/file
+ EOF
+
+ cat >expect <<-\EOF &&
+ toplevel
+ folder1/file
+ EOF
+
+ git -C repo sparse-checkout set --no-cone &&
+ git -C repo sparse-checkout check-rules \
+ --rules-file ../rules >actual <all-files &&
+
+ git -C bare sparse-checkout check-rules \
+ --rules-file ../rules >actual-bare <all-files &&
+
+ test_cmp expect actual &&
+ test_cmp expect actual-bare
+'
+
+test_expect_success 'check-rules quoting' '
+ cat >rules <<-EOF &&
+ "folder\" a"
+ EOF
+ cat >files <<-EOF &&
+ "folder\" a/file"
+ "folder\" b/file"
+ EOF
+ cat >expect <<-EOF &&
+ "folder\" a/file"
+ EOF
+ git sparse-checkout check-rules --cone \
+ --rules-file rules >actual <files &&
+
+ test_cmp expect actual
+'
+
+test_expect_success 'check-rules null termination' '
+ cat >rules <<-EOF &&
+ "folder\" a"
+ EOF
+
+ lf_to_nul >files <<-EOF &&
+ folder" a/a
+ folder" a/b
+ folder" b/fileQ
+ EOF
+
+ cat >expect <<-EOF &&
+ folder" a/aQfolder" a/bQ
+ EOF
+
+ git sparse-checkout check-rules --cone -z \
+ --rules-file rules >actual.nul <files &&
+ nul_to_q <actual.nul >actual &&
+ echo >>actual &&
+
+ test_cmp expect actual
+'
+
+
test_done
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index 801919009e..a63d0cc222 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -1377,7 +1377,7 @@ test_expect_success 'index.sparse disabled inline uses full index' '
! test_region index ensure_full_index trace2.txt
'
-ensure_not_expanded () {
+run_sparse_index_trace2 () {
rm -f trace2.txt &&
if test -z "$WITHOUT_UNTRACKED_TXT"
then
@@ -1397,7 +1397,16 @@ ensure_not_expanded () {
git -C sparse-index "$@" \
>sparse-index-out \
2>sparse-index-error || return 1
- fi &&
+ fi
+}
+
+ensure_expanded () {
+ run_sparse_index_trace2 "$@" &&
+ test_region index ensure_full_index trace2.txt
+}
+
+ensure_not_expanded () {
+ run_sparse_index_trace2 "$@" &&
test_region ! index ensure_full_index trace2.txt
}
@@ -1514,6 +1523,31 @@ test_expect_success 'sparse-index is not expanded: stash' '
ensure_not_expanded stash pop
'
+test_expect_success 'describe tested on all' '
+ init_repos &&
+
+ # Add tag to be read by describe
+
+ run_on_all git tag -a v1.0 -m "Version 1" &&
+ test_all_match git describe --dirty &&
+ run_on_all rm g &&
+ test_all_match git describe --dirty
+'
+
+
+test_expect_success 'sparse-index is not expanded: describe' '
+ init_repos &&
+
+ # Add tag to be read by describe
+
+ git -C sparse-index tag -a v1.0 -m "Version 1" &&
+
+ ensure_not_expanded describe --dirty &&
+ echo "test" >>sparse-index/g &&
+ ensure_not_expanded describe --dirty &&
+ ensure_not_expanded describe
+'
+
test_expect_success 'sparse index is not expanded: diff' '
init_repos &&
@@ -2055,4 +2089,95 @@ test_expect_success 'grep sparse directory within submodules' '
test_cmp actual expect
'
+test_expect_success 'write-tree' '
+ init_repos &&
+
+ test_all_match git write-tree &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>"$1"
+ EOF
+
+ # make a change inside the sparse cone
+ run_on_all ../edit-contents deep/a &&
+ test_all_match git update-index deep/a &&
+ test_all_match git write-tree &&
+ test_all_match git status --porcelain=v2 &&
+
+ # make a change outside the sparse cone
+ run_on_all mkdir -p folder1 &&
+ run_on_all cp a folder1/a &&
+ run_on_all ../edit-contents folder1/a &&
+ test_all_match git update-index folder1/a &&
+ test_all_match git write-tree &&
+ test_all_match git status --porcelain=v2 &&
+
+ # check that SKIP_WORKTREE files are not materialized
+ test_path_is_missing sparse-checkout/folder2/a &&
+ test_path_is_missing sparse-index/folder2/a
+'
+
+test_expect_success 'sparse-index is not expanded: write-tree' '
+ init_repos &&
+
+ ensure_not_expanded write-tree &&
+
+ echo "test1" >>sparse-index/a &&
+ git -C sparse-index update-index a &&
+ ensure_not_expanded write-tree
+'
+
+test_expect_success 'diff-files with pathspec inside sparse definition' '
+ init_repos &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>"$1"
+ EOF
+
+ run_on_all ../edit-contents deep/a &&
+
+ test_all_match git diff-files &&
+
+ test_all_match git diff-files -- deep/a &&
+
+ # test wildcard
+ test_all_match git diff-files -- "deep/*"
+'
+
+test_expect_success 'diff-files with pathspec outside sparse definition' '
+ init_repos &&
+
+ test_sparse_match git diff-files -- folder2/a &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>"$1"
+ EOF
+
+ # The directory "folder1" is outside the cone of interest
+ # and will not exist in the sparse checkout repositories.
+ # Create it as needed, add file "folder1/a" there with
+ # contents that is different from the staged version.
+ run_on_all mkdir -p folder1 &&
+ run_on_all cp a folder1/a &&
+
+ run_on_all ../edit-contents folder1/a &&
+ test_all_match git diff-files &&
+ test_all_match git diff-files -- folder1/a &&
+ test_all_match git diff-files -- "folder*/a"
+'
+
+test_expect_success 'sparse index is not expanded: diff-files' '
+ init_repos &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>"$1"
+ EOF
+
+ run_on_all ../edit-contents deep/a &&
+
+ ensure_not_expanded diff-files &&
+ ensure_not_expanded diff-files -- deep/a &&
+ ensure_not_expanded diff-files -- "deep/*"
+'
+
test_done
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 2575279ab8..86bfbc2b36 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -98,6 +98,23 @@ test_expect_success 'subsections are not canonicalized by git-config' '
test_cmp_config two section.SubSection.key
'
+test_missing_key () {
+ local key="$1" &&
+ local title="$2" &&
+ test_expect_success "value for $title is not printed" '
+ test_must_fail git config "$key" >out 2>err &&
+ test_must_be_empty out &&
+ test_must_be_empty err
+ '
+}
+
+test_missing_key 'missingsection.missingkey' 'missing section and missing key'
+test_missing_key 'missingsection.penguin' 'missing section and existing key'
+test_missing_key 'section.missingkey' 'existing section and missing key'
+test_missing_key 'section.MissingSubSection.missingkey' 'missing subsection and missing key'
+test_missing_key 'section.SubSection.missingkey' 'existing subsection and missing key'
+test_missing_key 'section.MissingSubSection.key' 'missing subsection and existing key'
+
cat > .git/config <<\EOF
[alpha]
bar = foo
@@ -617,6 +634,36 @@ test_expect_success 'renaming to bogus section is rejected' '
test_must_fail git config --rename-section branch.zwei "bogus name"
'
+test_expect_success 'renaming a section with a long line' '
+ {
+ printf "[b]\\n" &&
+ printf " c = d %1024s [a] e = f\\n" " " &&
+ printf "[a] g = h\\n"
+ } >y &&
+ git config -f y --rename-section a xyz &&
+ test_must_fail git config -f y b.e
+'
+
+test_expect_success 'renaming an embedded section with a long line' '
+ {
+ printf "[b]\\n" &&
+ printf " c = d %1024s [a] [foo] e = f\\n" " " &&
+ printf "[a] g = h\\n"
+ } >y &&
+ git config -f y --rename-section a xyz &&
+ test_must_fail git config -f y foo.e
+'
+
+test_expect_success 'renaming a section with an overly-long line' '
+ {
+ printf "[b]\\n" &&
+ printf " c = d %525000s e" " " &&
+ printf "[a] g = h\\n"
+ } >y &&
+ test_must_fail git config -f y --rename-section a xyz 2>err &&
+ grep "refusing to work with overly long line in .y. on line 2" err
+'
+
cat >> .git/config << EOF
[branch "zwei"] a = 1 [branch "vier"]
EOF
@@ -1458,35 +1505,29 @@ test_expect_success 'git config ignores pairs without count' '
test_must_be_empty error
'
-test_expect_success 'git config ignores pairs with zero count' '
- test_must_fail env \
- GIT_CONFIG_COUNT=0 \
- GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
- git config pair.one
-'
-
test_expect_success 'git config ignores pairs exceeding count' '
GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="value" \
- git config --get-regexp "pair.*" >actual &&
+ git config --get-regexp "pair.*" >actual 2>error &&
cat >expect <<-EOF &&
pair.one value
EOF
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_be_empty error
'
test_expect_success 'git config ignores pairs with zero count' '
test_must_fail env \
GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
- git config pair.one >error &&
+ git config pair.one 2>error &&
test_must_be_empty error
'
test_expect_success 'git config ignores pairs with empty count' '
test_must_fail env \
GIT_CONFIG_COUNT= GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
- git config pair.one >error &&
+ git config pair.one 2>error &&
test_must_be_empty error
'
@@ -1571,11 +1612,11 @@ test_expect_success 'git config --edit respects core.editor' '
# malformed configuration files
test_expect_success 'barf on syntax error' '
cat >.git/config <<-\EOF &&
- # broken section line
+ # broken key=value
[section]
key garbage
EOF
- test_must_fail git config --get section.key >actual 2>error &&
+ test_must_fail git config --get section.key 2>error &&
test_i18ngrep " line 3 " error
'
@@ -1585,17 +1626,17 @@ test_expect_success 'barf on incomplete section header' '
[section
key = value
EOF
- test_must_fail git config --get section.key >actual 2>error &&
+ test_must_fail git config --get section.key 2>error &&
test_i18ngrep " line 2 " error
'
test_expect_success 'barf on incomplete string' '
cat >.git/config <<-\EOF &&
- # broken section line
+ # broken value string
[section]
key = "value string
EOF
- test_must_fail git config --get section.key >actual 2>error &&
+ test_must_fail git config --get section.key 2>error &&
test_i18ngrep " line 3 " error
'
diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index 1b6437ec07..e5a0d65caa 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -52,6 +52,28 @@ test_expect_success 'shared=all' '
test 2 = $(git config core.sharedrepository)
'
+test_expect_failure 'template can set core.bare' '
+ test_when_finished "rm -rf subdir" &&
+ test_when_finished "rm -rf templates" &&
+ test_config core.bare true &&
+ umask 0022 &&
+ mkdir -p templates/ &&
+ cp .git/config templates/config &&
+ git init --template=templates subdir &&
+ test_path_exists subdir/HEAD
+'
+
+test_expect_success 'template can set core.bare but overridden by command line' '
+ test_when_finished "rm -rf subdir" &&
+ test_when_finished "rm -rf templates" &&
+ test_config core.bare true &&
+ umask 0022 &&
+ mkdir -p templates/ &&
+ cp .git/config templates/config &&
+ git init --no-bare --template=templates subdir &&
+ test_path_exists subdir/.git/HEAD
+'
+
test_expect_success POSIXPERM 'update-server-info honors core.sharedRepository' '
: > a1 &&
git add a1 &&
@@ -89,7 +111,7 @@ do
rm -f .git/info/refs &&
git update-server-info &&
actual="$(test_modebits .git/info/refs)" &&
- verbose test "x$actual" = "x-$y"
+ test "x$actual" = "x-$y"
'
@@ -99,7 +121,7 @@ do
rm -f .git/info/refs &&
git update-server-info &&
actual="$(test_modebits .git/info/refs)" &&
- verbose test "x$actual" = "x-$x"
+ test "x$actual" = "x-$x"
'
diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh
index 70389fa2eb..179474fa65 100755
--- a/t/t1302-repo-version.sh
+++ b/t/t1302-repo-version.sh
@@ -37,7 +37,7 @@ test_expect_success 'gitdir selection on normal repos' '
test_expect_success 'gitdir selection on unsupported repo' '
# Make sure it would stop at test2, not trash
- test_expect_code 1 git -C test2 config core.repositoryformatversion >actual
+ test_expect_code 1 git -C test2 config core.repositoryformatversion
'
test_expect_success 'gitdir not required mode' '
diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
index b38e158d3b..777648722c 100755
--- a/t/t1308-config-set.sh
+++ b/t/t1308-config-set.sh
@@ -58,6 +58,8 @@ test_expect_success 'setup default config' '
skin = false
nose = 1
horns
+ [value]
+ less
EOF
'
@@ -116,10 +118,53 @@ test_expect_success 'find value with the highest priority' '
check_config get_value case.baz "hask"
'
+test_expect_success 'return value for an existing key' '
+ test-tool config get lamb.chop >out 2>err &&
+ test_must_be_empty out &&
+ test_must_be_empty err
+'
+
+test_expect_success 'return value for value-less key' '
+ test-tool config get value.less >out 2>err &&
+ test_must_be_empty out &&
+ test_must_be_empty err
+'
+
+test_expect_success 'return value for a missing key' '
+ cat >expect <<-\EOF &&
+ Value not found for "missing.key"
+ EOF
+ test_expect_code 1 test-tool config get missing.key >actual 2>err &&
+ test_cmp actual expect &&
+ test_must_be_empty err
+'
+
+test_expect_success 'return value for a bad key: CONFIG_INVALID_KEY' '
+ cat >expect <<-\EOF &&
+ Key "fails.iskeychar.-" is invalid
+ EOF
+ test_expect_code 1 test-tool config get fails.iskeychar.- >actual 2>err &&
+ test_cmp actual expect &&
+ test_must_be_empty out
+'
+
+test_expect_success 'return value for a bad key: CONFIG_NO_SECTION_OR_NAME' '
+ cat >expect <<-\EOF &&
+ Key "keynosection" has no section
+ EOF
+ test_expect_code 1 test-tool config get keynosection >actual 2>err &&
+ test_cmp actual expect &&
+ test_must_be_empty out
+'
+
test_expect_success 'find integer value for a key' '
check_config get_int lamb.chop 65
'
+test_expect_success 'parse integer value during iteration' '
+ check_config git_config_int lamb.chop 65
+'
+
test_expect_success 'find string value for a key' '
check_config get_string case.baz hask &&
check_config expect_code 1 get_string case.ba "Value not found for \"case.ba\""
@@ -134,6 +179,11 @@ test_expect_success 'find integer if value is non parse-able' '
check_config expect_code 128 get_int lamb.head
'
+test_expect_success 'non parse-able integer value during iteration' '
+ check_config expect_code 128 git_config_int lamb.head 2>result &&
+ grep "fatal: bad numeric config value .* in file \.git/config" result
+'
+
test_expect_success 'find bool value for the entered key' '
check_config get_bool goat.head 1 &&
check_config get_bool goat.skin 0 &&
@@ -146,6 +196,71 @@ test_expect_success 'find multiple values' '
check_config get_value_multi case.baz sam bat hask
'
+test_NULL_in_multi () {
+ local op="$1" &&
+ local file="$2" &&
+
+ test_expect_success "$op: NULL value in config${file:+ in $file}" '
+ config="$file" &&
+ if test -z "$config"
+ then
+ config=.git/config &&
+ test_when_finished "mv $config.old $config" &&
+ mv "$config" "$config".old
+ fi &&
+
+ # Value-less in the middle of a list
+ cat >"$config" <<-\EOF &&
+ [a]key=x
+ [a]key
+ [a]key=y
+ EOF
+ case "$op" in
+ *_multi)
+ cat >expect <<-\EOF
+ x
+ (NULL)
+ y
+ EOF
+ ;;
+ *)
+ cat >expect <<-\EOF
+ y
+ EOF
+ ;;
+ esac &&
+ test-tool config "$op" a.key $file >actual &&
+ test_cmp expect actual &&
+
+ # Value-less at the end of a least
+ cat >"$config" <<-\EOF &&
+ [a]key=x
+ [a]key=y
+ [a]key
+ EOF
+ case "$op" in
+ *_multi)
+ cat >expect <<-\EOF
+ x
+ y
+ (NULL)
+ EOF
+ ;;
+ *)
+ cat >expect <<-\EOF
+ (NULL)
+ EOF
+ ;;
+ esac &&
+ test-tool config "$op" a.key $file >actual &&
+ test_cmp expect actual
+ '
+}
+
+test_NULL_in_multi "get_value_multi"
+test_NULL_in_multi "configset_get_value" "my.config"
+test_NULL_in_multi "configset_get_value_multi" "my.config"
+
test_expect_success 'find value from a configset' '
cat >config2 <<-\EOF &&
[case]
@@ -207,7 +322,7 @@ test_expect_success 'proper error on error in default config files' '
cp .git/config .git/config.old &&
test_when_finished "mv .git/config.old .git/config" &&
echo "[" >>.git/config &&
- echo "fatal: bad config line 34 in file .git/config" >expect &&
+ echo "fatal: bad config line 36 in file .git/config" >expect &&
test_expect_code 128 test-tool config get_value foo.bar 2>actual &&
test_cmp expect actual
'
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index cf58cf025c..4d66cd7f4a 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -1568,6 +1568,7 @@ test_expect_success 'transaction can create and delete' '
EOF
git update-ref --stdin <stdin >actual &&
printf "%s: ok\n" start commit start commit >expect &&
+ test_cmp expect actual &&
test_must_fail git show-ref --verify refs/heads/create-and-delete
'
@@ -1595,6 +1596,8 @@ test_expect_success 'transaction cannot restart ongoing transaction' '
commit
EOF
test_must_fail git update-ref --stdin <stdin >actual &&
+ printf "%s: ok\n" start >expect &&
+ test_cmp expect actual &&
test_must_fail git show-ref --verify refs/heads/restart
'
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index be23be30c7..c7745e1bf6 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -33,7 +33,8 @@ test_expect_success 'symbolic-ref refuses non-ref for HEAD' '
reset_to_sane
test_expect_success 'symbolic-ref refuses bare sha1' '
- test_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)
+ rev=$(git rev-parse HEAD) &&
+ test_must_fail git symbolic-ref HEAD "$rev"
'
reset_to_sane
diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh
index b5606d93b5..937ae0d733 100755
--- a/t/t1404-update-ref-errors.sh
+++ b/t/t1404-update-ref-errors.sh
@@ -551,7 +551,6 @@ test_expect_success REFFILES 'no bogus intermediate values during delete' '
git update-ref $prefix/foo $C &&
git pack-refs --all &&
git update-ref $prefix/foo $D &&
- git for-each-ref $prefix >unchanged &&
# Now try to update the reference, but hold the `packed-refs` lock
# for a while to see what happens while the process is blocked:
: >.git/packed-refs.lock &&
diff --git a/t/t1419-exclude-refs.sh b/t/t1419-exclude-refs.sh
new file mode 100755
index 0000000000..0e91e2f399
--- /dev/null
+++ b/t/t1419-exclude-refs.sh
@@ -0,0 +1,131 @@
+#!/bin/sh
+
+test_description='test exclude_patterns functionality in main ref store'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+for_each_ref__exclude () {
+ GIT_TRACE2_PERF=1 test-tool ref-store main \
+ for-each-ref--exclude "$@" >actual.raw
+ cut -d ' ' -f 2 actual.raw
+}
+
+for_each_ref () {
+ git for-each-ref --format='%(refname)' "$@"
+}
+
+assert_jumps () {
+ local nr="$1"
+ local trace="$2"
+
+ grep -q "name:jumps_made value:$nr" $trace
+}
+
+assert_no_jumps () {
+ ! assert_jumps ".*" "$1"
+}
+
+test_expect_success 'setup' '
+ test_commit --no-tag base &&
+ base="$(git rev-parse HEAD)" &&
+
+ for name in foo bar baz quux
+ do
+ for i in 1 2 3
+ do
+ echo "create refs/heads/$name/$i $base" || return 1
+ done || return 1
+ done >in &&
+ echo "delete refs/heads/main" >>in &&
+
+ git update-ref --stdin <in &&
+ git pack-refs --all
+'
+
+test_expect_success 'excluded region in middle' '
+ for_each_ref__exclude refs/heads refs/heads/foo >actual 2>perf &&
+ for_each_ref refs/heads/bar refs/heads/baz refs/heads/quux >expect &&
+
+ test_cmp expect actual &&
+ assert_jumps 1 perf
+'
+
+test_expect_success 'excluded region at beginning' '
+ for_each_ref__exclude refs/heads refs/heads/bar >actual 2>perf &&
+ for_each_ref refs/heads/baz refs/heads/foo refs/heads/quux >expect &&
+
+ test_cmp expect actual &&
+ assert_jumps 1 perf
+'
+
+test_expect_success 'excluded region at end' '
+ for_each_ref__exclude refs/heads refs/heads/quux >actual 2>perf &&
+ for_each_ref refs/heads/foo refs/heads/bar refs/heads/baz >expect &&
+
+ test_cmp expect actual &&
+ assert_jumps 1 perf
+'
+
+test_expect_success 'disjoint excluded regions' '
+ for_each_ref__exclude refs/heads refs/heads/bar refs/heads/quux >actual 2>perf &&
+ for_each_ref refs/heads/baz refs/heads/foo >expect &&
+
+ test_cmp expect actual &&
+ assert_jumps 2 perf
+'
+
+test_expect_success 'adjacent, non-overlapping excluded regions' '
+ for_each_ref__exclude refs/heads refs/heads/bar refs/heads/baz >actual 2>perf &&
+ for_each_ref refs/heads/foo refs/heads/quux >expect &&
+
+ test_cmp expect actual &&
+ assert_jumps 1 perf
+'
+
+test_expect_success 'overlapping excluded regions' '
+ for_each_ref__exclude refs/heads refs/heads/ba refs/heads/baz >actual 2>perf &&
+ for_each_ref refs/heads/foo refs/heads/quux >expect &&
+
+ test_cmp expect actual &&
+ assert_jumps 1 perf
+'
+
+test_expect_success 'several overlapping excluded regions' '
+ for_each_ref__exclude refs/heads \
+ refs/heads/bar refs/heads/baz refs/heads/foo >actual 2>perf &&
+ for_each_ref refs/heads/quux >expect &&
+
+ test_cmp expect actual &&
+ assert_jumps 1 perf
+'
+
+test_expect_success 'non-matching excluded section' '
+ for_each_ref__exclude refs/heads refs/heads/does/not/exist >actual 2>perf &&
+ for_each_ref >expect &&
+
+ test_cmp expect actual &&
+ assert_no_jumps
+'
+
+test_expect_success 'meta-characters are discarded' '
+ for_each_ref__exclude refs/heads "refs/heads/ba*" >actual 2>perf &&
+ for_each_ref >expect &&
+
+ test_cmp expect actual &&
+ assert_no_jumps
+'
+
+test_expect_success 'complex hidden ref rules are discarded' '
+ for_each_ref__exclude refs/heads refs/heads/foo "!refs/heads/foo/1" \
+ >actual 2>perf &&
+ for_each_ref >expect &&
+
+ test_cmp expect actual &&
+ assert_no_jumps
+'
+
+test_done
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index fdb886dfe4..8c442adb1a 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -989,10 +989,7 @@ test_expect_success 'fsck error and recovery on invalid object type' '
garbage_blob=$(git hash-object --stdin -w -t garbage --literally </dev/null) &&
- cat >err.expect <<-\EOF &&
- fatal: invalid object type
- EOF
- test_must_fail git fsck >out 2>err &&
+ test_must_fail git fsck 2>err &&
grep -e "^error" -e "^fatal" err >errors &&
test_line_count = 1 errors &&
grep "$garbage_blob: object is of unknown type '"'"'garbage'"'"':" err
@@ -1023,4 +1020,34 @@ test_expect_success 'fsck error on gitattributes with excessive size' '
test_cmp expected actual
'
+test_expect_success 'fsck detects problems in worktree index' '
+ test_when_finished "git worktree remove -f wt" &&
+ git worktree add wt &&
+
+ echo "this will be removed to break the worktree index" >wt/file &&
+ git -C wt add file &&
+ blob=$(git -C wt rev-parse :file) &&
+ remove_object $blob &&
+
+ test_must_fail git fsck --name-objects >actual 2>&1 &&
+ cat >expect <<-EOF &&
+ missing blob $blob (.git/worktrees/wt/index:file)
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'fsck reports problems in main index without filename' '
+ test_when_finished "rm -f .git/index && git read-tree HEAD" &&
+ echo "this object will be removed to break the main index" >file &&
+ git add file &&
+ blob=$(git rev-parse :file) &&
+ remove_object $blob &&
+
+ test_must_fail git fsck --name-objects >actual 2>&1 &&
+ cat >expect <<-EOF &&
+ missing blob $blob (:file)
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index de1d48f3ba..dd811b7fb4 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -302,14 +302,14 @@ test_expect_success 'test --parseopt help output: "wrapped" options normal "or:"
|EOF
END_EXPECT
- test_must_fail git rev-parse --parseopt -- -h >out <spec >actual &&
+ test_must_fail git rev-parse --parseopt -- -h <spec >actual &&
test_cmp expect actual
'
test_expect_success 'test --parseopt invalid opt-spec' '
test_write_lines x -- "=, x" >spec &&
echo "fatal: missing opt-spec before option flags" >expect &&
- test_must_fail git rev-parse --parseopt -- >out <spec 2>err &&
+ test_must_fail git rev-parse --parseopt -- <spec 2>err &&
test_cmp expect err
'
@@ -339,7 +339,7 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l
|EOF
END_EXPECT
- test_must_fail git rev-parse --parseopt -- -h >out <spec >actual &&
+ test_must_fail git rev-parse --parseopt -- -h <spec >actual &&
test_cmp expect actual
'
diff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh
index 0fafcf9dde..c1679e31d8 100755
--- a/t/t1504-ceiling-dirs.sh
+++ b/t/t1504-ceiling-dirs.sh
@@ -6,8 +6,12 @@ TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_prefix() {
- test_expect_success "$1" \
- "test '$2' = \"\$(git rev-parse --show-prefix)\""
+ local expect="$2" &&
+ test_expect_success "$1: git rev-parse --show-prefix is '$2'" '
+ echo "$expect" >expect &&
+ git rev-parse --show-prefix >actual &&
+ test_cmp expect actual
+ '
}
test_fail() {
diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh
index c34714ffe3..cb9ef7e329 100755
--- a/t/t1507-rev-parse-upstream.sh
+++ b/t/t1507-rev-parse-upstream.sh
@@ -97,7 +97,8 @@ test_expect_success 'my-side@{u} resolves to correct commit' '
commit_subject my-side >actual &&
test_cmp expect actual &&
echo 5 >expect &&
- commit_subject my-side@{u} >actual
+ commit_subject my-side@{u} >actual &&
+ test_cmp expect actual
'
test_expect_success 'not-tracking@{u} fails' '
@@ -183,6 +184,11 @@ test_expect_success '@{u} error message when no upstream' '
test_cmp expect actual
'
+test_expect_success '@{u} silent error when no upstream' '
+ test_must_fail git rev-parse --verify --quiet @{u} 2>actual &&
+ test_must_be_empty actual
+'
+
test_expect_success 'branch@{u} error message with misspelt branch' '
cat >expect <<-EOF &&
fatal: no such branch: ${SQ}no-such-branch${SQ}
@@ -258,7 +264,8 @@ test_expect_success '@{reflog}-parsing does not look beyond colon' '
git add @{yesterday} &&
git commit -m "funny reflog file" &&
git hash-object @{yesterday} >expect &&
- git rev-parse HEAD:@{yesterday} >actual
+ git rev-parse HEAD:@{yesterday} >actual &&
+ test_cmp expect actual
'
test_expect_success '@{upstream}-parsing does not look beyond colon' '
@@ -266,7 +273,8 @@ test_expect_success '@{upstream}-parsing does not look beyond colon' '
git add @{upstream} &&
git commit -m "funny upstream file" &&
git hash-object @{upstream} >expect &&
- git rev-parse HEAD:@{upstream} >actual
+ git rev-parse HEAD:@{upstream} >actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh
index 112682a45a..67d18cfa10 100755
--- a/t/t2005-checkout-index-symlinks.sh
+++ b/t/t2005-checkout-index-symlinks.sh
@@ -22,8 +22,10 @@ test_expect_success \
git checkout-index symlink &&
test -f symlink'
-test_expect_success \
-'the file must be the blob we added during the setup' '
-test "$(git hash-object -t blob symlink)" = $l'
+test_expect_success 'the file must be the blob we added during the setup' '
+ echo "$l" >expect &&
+ git hash-object -t blob symlink >actual &&
+ test_cmp expect actual
+'
test_done
diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh
index 2c8c926b4d..9540588664 100755
--- a/t/t2019-checkout-ambiguous-ref.sh
+++ b/t/t2019-checkout-ambiguous-ref.sh
@@ -16,7 +16,7 @@ test_expect_success 'setup ambiguous refs' '
'
test_expect_success 'checkout ambiguous ref succeeds' '
- git checkout ambiguity >stdout 2>stderr
+ git checkout ambiguity 2>stderr
'
test_expect_success 'checkout produces ambiguity warning' '
@@ -37,7 +37,7 @@ test_expect_success 'checkout reports switch to branch' '
'
test_expect_success 'checkout vague ref succeeds' '
- git checkout vagueness >stdout 2>stderr &&
+ git checkout vagueness 2>stderr &&
test_set_prereq VAGUENESS_SUCCESS
'
diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh
index 713c3fa603..ecfacf0f7f 100755
--- a/t/t2021-checkout-overwrite.sh
+++ b/t/t2021-checkout-overwrite.sh
@@ -50,10 +50,13 @@ test_expect_success 'checkout commit with dir must not remove untracked a/b' '
test_expect_success SYMLINKS 'the symlink remained' '
- test_when_finished "rm a/b" &&
test -h a/b
'
+test_expect_success 'cleanup after previous symlink tests' '
+ rm a/b
+'
+
test_expect_success SYMLINKS 'checkout -f must not follow symlinks when removing entries' '
git checkout -f start &&
mkdir dir &&
@@ -66,4 +69,15 @@ test_expect_success SYMLINKS 'checkout -f must not follow symlinks when removing
test_path_is_file untracked/f
'
+test_expect_success 'checkout --overwrite-ignore should succeed if only ignored files in the way' '
+ git checkout -b df_conflict &&
+ test_commit contents some_dir &&
+ git checkout start &&
+ mkdir some_dir &&
+ echo autogenerated information >some_dir/ignore &&
+ echo ignore >.git/info/exclude &&
+ git checkout --overwrite-ignore df_conflict &&
+ test_path_is_file some_dir
+'
+
test_done
diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh
index 4a1c901456..74049a9812 100755
--- a/t/t2024-checkout-dwim.sh
+++ b/t/t2024-checkout-dwim.sh
@@ -305,10 +305,13 @@ test_expect_success 'loosely defined local base branch is reported correctly' '
test_config branch.strict.merge refs/heads/main &&
test_config branch.loose.merge main &&
- git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect &&
+ git checkout strict >expect.raw 2>&1 &&
+ sed -e "s/strict/BRANCHNAME/g" <expect.raw >expect &&
status_uno_is_clean &&
- git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual &&
+ git checkout loose >actual.raw 2>&1 &&
+ sed -e "s/loose/BRANCHNAME/g" <actual.raw >actual &&
status_uno_is_clean &&
+ grep BRANCHNAME actual &&
test_cmp expect actual
'
diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
index 5a7caf958c..e247a4735b 100755
--- a/t/t2060-switch.sh
+++ b/t/t2060-switch.sh
@@ -146,4 +146,33 @@ test_expect_success 'tracking info copied with autoSetupMerge=inherit' '
test_cmp_config "" --default "" branch.main2.merge
'
+test_expect_success 'switch back when temporarily detached and checked out elsewhere ' '
+ test_when_finished "
+ git worktree remove wt1 ||:
+ git worktree remove wt2 ||:
+ git checkout - ||:
+ git branch -D shared ||:
+ " &&
+ git checkout -b shared &&
+ test_commit shared-first &&
+ HASH1=$(git rev-parse --verify HEAD) &&
+ test_commit shared-second &&
+ test_commit shared-third &&
+ HASH2=$(git rev-parse --verify HEAD) &&
+ git worktree add wt1 -f shared &&
+ git -C wt1 bisect start &&
+ git -C wt1 bisect good $HASH1 &&
+ git -C wt1 bisect bad $HASH2 &&
+ git worktree add wt2 -f shared &&
+ git -C wt2 bisect start &&
+ git -C wt2 bisect good $HASH1 &&
+ git -C wt2 bisect bad $HASH2 &&
+ # we test in both worktrees to ensure that works
+ # as expected with "first" and "next" worktrees
+ test_must_fail git -C wt1 switch shared &&
+ git -C wt1 switch --ignore-other-worktrees shared &&
+ test_must_fail git -C wt2 switch shared &&
+ git -C wt2 switch --ignore-other-worktrees shared
+'
+
test_done
diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh
index 7c43ddf1d9..c5d19dd973 100755
--- a/t/t2070-restore.sh
+++ b/t/t2070-restore.sh
@@ -137,4 +137,20 @@ test_expect_success 'restore --staged invalidates cache tree for deletions' '
test_must_fail git rev-parse HEAD:new1
'
+test_expect_success 'restore with merge options rejects --staged' '
+ for opts in \
+ "--staged --ours" \
+ "--staged --theirs" \
+ "--staged --merge" \
+ "--staged --conflict=diff3" \
+ "--staged --worktree --ours" \
+ "--staged --worktree --theirs" \
+ "--staged --worktree --merge" \
+ "--staged --worktree --conflict=zdiff3"
+ do
+ test_must_fail git restore $opts . 2>err &&
+ grep "cannot be used with --staged" err || return
+ done
+'
+
test_done
diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh
index 07e6de84e6..89b285fa3a 100755
--- a/t/t2107-update-index-basic.sh
+++ b/t/t2107-update-index-basic.sh
@@ -83,7 +83,7 @@ test_expect_success '.lock files cleaned up' '
cd repo &&
git config core.worktree ../../worktree &&
# --refresh triggers late setup_work_tree,
- # active_cache_changed is zero, rollback_lock_file fails
+ # the_index.cache_changed is zero, rollback_lock_file fails
git update-index --refresh --verbose >out &&
test_must_be_empty out &&
! test -f .git/index.lock
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index d587e0b20d..1c914879a4 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -118,14 +118,17 @@ test_expect_success '"add" worktree creating new branch' '
)
'
-test_expect_success 'die the same branch is already checked out' '
+test_expect_success 'die if the same branch is already checked out' '
(
cd here &&
- test_must_fail git checkout newmain
+ test_must_fail git checkout newmain &&
+ test_must_fail git checkout -B newmain &&
+ test_must_fail git switch newmain &&
+ test_must_fail git switch -C newmain
)
'
-test_expect_success SYMLINKS 'die the same branch is already checked out (symlink)' '
+test_expect_success SYMLINKS 'die if the same branch is already checked out (symlink)' '
head=$(git -C there rev-parse --git-path HEAD) &&
ref=$(git -C there symbolic-ref HEAD) &&
rm "$head" &&
@@ -133,17 +136,34 @@ test_expect_success SYMLINKS 'die the same branch is already checked out (symlin
test_must_fail git -C here checkout newmain
'
-test_expect_success 'not die the same branch is already checked out' '
+test_expect_success 'allow creating multiple worktrees for same branch with force' '
+ git worktree add --force anothernewmain newmain
+'
+
+test_expect_success 'allow checkout/reset from the conflicted branch' '
(
cd here &&
- git worktree add --force anothernewmain newmain
+ git checkout -b conflictedmain newmain &&
+ git checkout -B conflictedmain newmain &&
+ git switch -C conflictedmain newmain
)
'
-test_expect_success 'not die on re-checking out current branch' '
+test_expect_success 'and not die on re-checking out current branch even if conflicted' '
(
cd there &&
- git checkout newmain
+ git checkout newmain &&
+ git switch newmain
+ )
+'
+
+test_expect_success 'unless using force without --ignore-other-worktrees' '
+ (
+ cd there &&
+ test_must_fail git checkout -B newmain &&
+ test_must_fail git switch -C newmain &&
+ git checkout --ignore-other-worktrees -B newmain &&
+ git switch --ignore-other-worktrees -C newmain
)
'
@@ -298,17 +318,24 @@ test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
test_must_fail git -C mish/mash symbolic-ref HEAD
'
-test_expect_success '"add" -b/-B mutually exclusive' '
- test_must_fail git worktree add -b poodle -B poodle bamboo main
-'
-
-test_expect_success '"add" -b/--detach mutually exclusive' '
- test_must_fail git worktree add -b poodle --detach bamboo main
-'
+# Helper function to test mutually exclusive options.
+#
+# Note: Quoted arguments containing spaces are not supported.
+test_wt_add_excl () {
+ local opts="$*" &&
+ test_expect_success "'worktree add' with '$opts' has mutually exclusive options" '
+ test_must_fail git worktree add $opts 2>actual &&
+ grep -E "fatal:( options)? .* cannot be used together" actual
+ '
+}
-test_expect_success '"add" -B/--detach mutually exclusive' '
- test_must_fail git worktree add -B poodle --detach bamboo main
-'
+test_wt_add_excl -b poodle -B poodle bamboo main
+test_wt_add_excl -b poodle --detach bamboo main
+test_wt_add_excl -B poodle --detach bamboo main
+test_wt_add_excl --orphan --detach bamboo
+test_wt_add_excl --orphan --no-checkout bamboo
+test_wt_add_excl --orphan bamboo main
+test_wt_add_excl --orphan -b bamboo wtdir/ main
test_expect_success '"add -B" fails if the branch is checked out' '
git rev-parse newmain >before &&
@@ -326,10 +353,111 @@ test_expect_success 'add -B' '
'
test_expect_success 'add --quiet' '
+ test_when_finished "git worktree remove -f -f another-worktree" &&
git worktree add --quiet another-worktree main 2>actual &&
test_must_be_empty actual
'
+test_expect_success 'add --quiet -b' '
+ test_when_finished "git branch -D quietnewbranch" &&
+ test_when_finished "git worktree remove -f -f another-worktree" &&
+ git worktree add --quiet -b quietnewbranch another-worktree 2>actual &&
+ test_must_be_empty actual
+'
+
+test_expect_success '"add --orphan"' '
+ test_when_finished "git worktree remove -f -f orphandir" &&
+ git worktree add --orphan -b neworphan orphandir &&
+ echo refs/heads/neworphan >expected &&
+ git -C orphandir symbolic-ref HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '"add --orphan (no -b)"' '
+ test_when_finished "git worktree remove -f -f neworphan" &&
+ git worktree add --orphan neworphan &&
+ echo refs/heads/neworphan >expected &&
+ git -C neworphan symbolic-ref HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '"add --orphan --quiet"' '
+ test_when_finished "git worktree remove -f -f orphandir" &&
+ git worktree add --quiet --orphan -b neworphan orphandir 2>log.actual &&
+ test_must_be_empty log.actual &&
+ echo refs/heads/neworphan >expected &&
+ git -C orphandir symbolic-ref HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '"add --orphan" fails if the branch already exists' '
+ test_when_finished "git branch -D existingbranch" &&
+ git worktree add -b existingbranch orphandir main &&
+ git worktree remove orphandir &&
+ test_must_fail git worktree add --orphan -b existingbranch orphandir
+'
+
+test_expect_success '"add --orphan" with empty repository' '
+ test_when_finished "rm -rf empty_repo" &&
+ echo refs/heads/newbranch >expected &&
+ GIT_DIR="empty_repo" git init --bare &&
+ git -C empty_repo worktree add --orphan -b newbranch worktreedir &&
+ git -C empty_repo/worktreedir symbolic-ref HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '"add" worktree with orphan branch and lock' '
+ git worktree add --lock --orphan -b orphanbr orphan-with-lock &&
+ test_when_finished "git worktree unlock orphan-with-lock || :" &&
+ test -f .git/worktrees/orphan-with-lock/locked
+'
+
+test_expect_success '"add" worktree with orphan branch, lock, and reason' '
+ lock_reason="why not" &&
+ git worktree add --detach --lock --reason "$lock_reason" orphan-with-lock-reason main &&
+ test_when_finished "git worktree unlock orphan-with-lock-reason || :" &&
+ test -f .git/worktrees/orphan-with-lock-reason/locked &&
+ echo "$lock_reason" >expect &&
+ test_cmp expect .git/worktrees/orphan-with-lock-reason/locked
+'
+
+# Note: Quoted arguments containing spaces are not supported.
+test_wt_add_orphan_hint () {
+ local context="$1" &&
+ local use_branch=$2 &&
+ shift 2 &&
+ local opts="$*" &&
+ test_expect_success "'worktree add' show orphan hint in bad/orphan HEAD w/ $context" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (cd repo && test_commit commit) &&
+ git -C repo switch --orphan noref &&
+ test_must_fail git -C repo worktree add $opts foobar/ 2>actual &&
+ ! grep "error: unknown switch" actual &&
+ grep "hint: If you meant to create a worktree containing a new orphan branch" actual &&
+ if [ $use_branch -eq 1 ]
+ then
+ grep -E "^hint:\s+git worktree add --orphan -b \S+ \S+\s*$" actual
+ else
+ grep -E "^hint:\s+git worktree add --orphan \S+\s*$" actual
+ fi
+
+ '
+}
+
+test_wt_add_orphan_hint 'no opts' 0
+test_wt_add_orphan_hint '-b' 1 -b foobar_branch
+test_wt_add_orphan_hint '-B' 1 -B foobar_branch
+
+test_expect_success "'worktree add' doesn't show orphan hint in bad/orphan HEAD w/ --quiet" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (cd repo && test_commit commit) &&
+ test_must_fail git -C repo worktree add --quiet foobar_branch foobar/ 2>actual &&
+ ! grep "error: unknown switch" actual &&
+ ! grep "hint: If you meant to create a worktree containing a new orphan branch" actual
+'
+
test_expect_success 'local clone from linked checkout' '
git clone --local here here-clone &&
( cd here-clone && git fsck )
@@ -446,6 +574,14 @@ setup_remote_repo () {
)
}
+test_expect_success '"add" <path> <remote/branch> w/ no HEAD' '
+ test_when_finished rm -rf repo_upstream repo_local foo &&
+ setup_remote_repo repo_upstream repo_local &&
+ git -C repo_local config --bool core.bare true &&
+ git -C repo_local branch -D main &&
+ git -C repo_local worktree add ./foo repo_upstream/foo
+'
+
test_expect_success '--no-track avoids setting up tracking' '
test_when_finished rm -rf repo_upstream repo_local foo &&
setup_remote_repo repo_upstream repo_local &&
@@ -528,6 +664,35 @@ test_expect_success 'git worktree add --guess-remote sets up tracking' '
test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
)
'
+test_expect_success 'git worktree add --guess-remote sets up tracking (quiet)' '
+ test_when_finished rm -rf repo_a repo_b foo &&
+ setup_remote_repo repo_a repo_b &&
+ (
+ cd repo_b &&
+ git worktree add --quiet --guess-remote ../foo 2>actual &&
+ test_must_be_empty actual
+ ) &&
+ (
+ cd foo &&
+ test_branch_upstream foo repo_a foo &&
+ test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+ )
+'
+
+test_expect_success 'git worktree --no-guess-remote (quiet)' '
+ test_when_finished rm -rf repo_a repo_b foo &&
+ setup_remote_repo repo_a repo_b &&
+ (
+ cd repo_b &&
+ git worktree add --quiet --no-guess-remote ../foo
+ ) &&
+ (
+ cd foo &&
+ test_must_fail git config "branch.foo.remote" &&
+ test_must_fail git config "branch.foo.merge" &&
+ test_cmp_rev ! refs/remotes/repo_a/foo refs/heads/foo
+ )
+'
test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' '
test_when_finished rm -rf repo_a repo_b foo &&
@@ -560,6 +725,348 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' '
)
'
+test_dwim_orphan () {
+ local info_text="No possible source branch, inferring '--orphan'" &&
+ local fetch_error_text="fatal: No local or remote refs exist despite at least one remote" &&
+ local orphan_hint="hint: If you meant to create a worktree containing a new orphan branch" &&
+ local invalid_ref_regex="^fatal: invalid reference:\s\+.*" &&
+ local bad_combo_regex="^fatal: '[a-z-]\+' and '[a-z-]\+' cannot be used together" &&
+
+ local git_ns="repo" &&
+ local dashc_args="-C $git_ns" &&
+ local use_cd=0 &&
+
+ local bad_head=0 &&
+ local empty_repo=1 &&
+ local local_ref=0 &&
+ local use_quiet=0 &&
+ local remote=0 &&
+ local remote_ref=0 &&
+ local use_detach=0 &&
+ local use_new_branch=0 &&
+
+ local outcome="$1" &&
+ local outcome_text &&
+ local success &&
+ shift &&
+ local args="" &&
+ local context="" &&
+ case "$outcome" in
+ "infer")
+ success=1 &&
+ outcome_text='"add" DWIM infer --orphan'
+ ;;
+ "no_infer")
+ success=1 &&
+ outcome_text='"add" DWIM doesnt infer --orphan'
+ ;;
+ "fetch_error")
+ success=0 &&
+ outcome_text='"add" error need fetch'
+ ;;
+ "fatal_orphan_bad_combo")
+ success=0 &&
+ outcome_text='"add" error inferred "--orphan" gives illegal opts combo'
+ ;;
+ "warn_bad_head")
+ success=0 &&
+ outcome_text='"add" error, warn on bad HEAD, hint use orphan'
+ ;;
+ *)
+ echo "test_dwim_orphan(): invalid outcome: '$outcome'" >&2 &&
+ return 1
+ ;;
+ esac &&
+ while [ $# -gt 0 ]
+ do
+ case "$1" in
+ # How and from where to create the worktree
+ "-C_repo")
+ use_cd=0 &&
+ git_ns="repo" &&
+ dashc_args="-C $git_ns" &&
+ context="$context, 'git -C repo'"
+ ;;
+ "-C_wt")
+ use_cd=0 &&
+ git_ns="wt" &&
+ dashc_args="-C $git_ns" &&
+ context="$context, 'git -C wt'"
+ ;;
+ "cd_repo")
+ use_cd=1 &&
+ git_ns="repo" &&
+ dashc_args="" &&
+ context="$context, 'cd repo && git'"
+ ;;
+ "cd_wt")
+ use_cd=1 &&
+ git_ns="wt" &&
+ dashc_args="" &&
+ context="$context, 'cd wt && git'"
+ ;;
+
+ # Bypass the "pull first" warning
+ "force")
+ args="$args --force" &&
+ context="$context, --force"
+ ;;
+
+ # Try to use remote refs when DWIM
+ "guess_remote")
+ args="$args --guess-remote" &&
+ context="$context, --guess-remote"
+ ;;
+ "no_guess_remote")
+ args="$args --no-guess-remote" &&
+ context="$context, --no-guess-remote"
+ ;;
+
+ # Whether there is at least one local branch present
+ "local_ref")
+ empty_repo=0 &&
+ local_ref=1 &&
+ context="$context, >=1 local branches"
+ ;;
+ "no_local_ref")
+ empty_repo=0 &&
+ context="$context, 0 local branches"
+ ;;
+
+ # Whether the HEAD points at a valid ref (skip this opt when no refs)
+ "good_head")
+ # requires: local_ref
+ context="$context, valid HEAD"
+ ;;
+ "bad_head")
+ bad_head=1 &&
+ context="$context, invalid (or orphan) HEAD"
+ ;;
+
+ # Whether the code path is tested with the base add command, -b, or --detach
+ "no_-b")
+ use_new_branch=0 &&
+ context="$context, no --branch"
+ ;;
+ "-b")
+ use_new_branch=1 &&
+ context="$context, --branch"
+ ;;
+ "detach")
+ use_detach=1 &&
+ context="$context, --detach"
+ ;;
+
+ # Whether to check that all output is suppressed (except errors)
+ # or that the output is as expected
+ "quiet")
+ use_quiet=1 &&
+ args="$args --quiet" &&
+ context="$context, --quiet"
+ ;;
+ "no_quiet")
+ use_quiet=0 &&
+ context="$context, no --quiet (expect output)"
+ ;;
+
+ # Whether there is at least one remote attached to the repo
+ "remote")
+ empty_repo=0 &&
+ remote=1 &&
+ context="$context, >=1 remotes"
+ ;;
+ "no_remote")
+ empty_repo=0 &&
+ remote=0 &&
+ context="$context, 0 remotes"
+ ;;
+
+ # Whether there is at least one valid remote ref
+ "remote_ref")
+ # requires: remote
+ empty_repo=0 &&
+ remote_ref=1 &&
+ context="$context, >=1 fetched remote branches"
+ ;;
+ "no_remote_ref")
+ empty_repo=0 &&
+ remote_ref=0 &&
+ context="$context, 0 fetched remote branches"
+ ;;
+
+ # Options or flags that become illegal when --orphan is inferred
+ "no_checkout")
+ args="$args --no-checkout" &&
+ context="$context, --no-checkout"
+ ;;
+ "track")
+ args="$args --track" &&
+ context="$context, --track"
+ ;;
+
+ # All other options are illegal
+ *)
+ echo "test_dwim_orphan(): invalid arg: '$1'" >&2 &&
+ return 1
+ ;;
+ esac &&
+ shift
+ done &&
+ context="${context#', '}" &&
+ if [ $use_new_branch -eq 1 ]
+ then
+ args="$args -b foo"
+ elif [ $use_detach -eq 1 ]
+ then
+ args="$args --detach"
+ else
+ context="DWIM (no --branch), $context"
+ fi &&
+ if [ $empty_repo -eq 1 ]
+ then
+ context="empty repo, $context"
+ fi &&
+ args="$args ../foo" &&
+ context="${context%', '}" &&
+ test_expect_success "$outcome_text w/ $context" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ if [ $local_ref -eq 1 ] && [ "$git_ns" = "repo" ]
+ then
+ (cd repo && test_commit commit) &&
+ if [ $bad_head -eq 1 ]
+ then
+ git -C repo symbolic-ref HEAD refs/heads/badbranch
+ fi
+ elif [ $local_ref -eq 1 ] && [ "$git_ns" = "wt" ]
+ then
+ test_when_finished "git -C repo worktree remove -f ../wt" &&
+ git -C repo worktree add --orphan -b main ../wt &&
+ (cd wt && test_commit commit) &&
+ if [ $bad_head -eq 1 ]
+ then
+ git -C wt symbolic-ref HEAD refs/heads/badbranch
+ fi
+ elif [ $local_ref -eq 0 ] && [ "$git_ns" = "wt" ]
+ then
+ test_when_finished "git -C repo worktree remove -f ../wt" &&
+ git -C repo worktree add --orphan -b orphanbranch ../wt
+ fi &&
+
+ if [ $remote -eq 1 ]
+ then
+ test_when_finished "rm -rf upstream" &&
+ git init upstream &&
+ (cd upstream && test_commit commit) &&
+ git -C upstream switch -c foo &&
+ git -C repo remote add upstream ../upstream
+ fi &&
+
+ if [ $remote_ref -eq 1 ]
+ then
+ git -C repo fetch
+ fi &&
+ if [ $success -eq 1 ]
+ then
+ test_when_finished git -C repo worktree remove ../foo
+ fi &&
+ (
+ if [ $use_cd -eq 1 ]
+ then
+ cd $git_ns
+ fi &&
+ if [ "$outcome" = "infer" ]
+ then
+ git $dashc_args worktree add $args 2>actual &&
+ if [ $use_quiet -eq 1 ]
+ then
+ test_must_be_empty actual
+ else
+ grep "$info_text" actual
+ fi
+ elif [ "$outcome" = "no_infer" ]
+ then
+ git $dashc_args worktree add $args 2>actual &&
+ if [ $use_quiet -eq 1 ]
+ then
+ test_must_be_empty actual
+ else
+ ! grep "$info_text" actual
+ fi
+ elif [ "$outcome" = "fetch_error" ]
+ then
+ test_must_fail git $dashc_args worktree add $args 2>actual &&
+ grep "$fetch_error_text" actual
+ elif [ "$outcome" = "fatal_orphan_bad_combo" ]
+ then
+ test_must_fail git $dashc_args worktree add $args 2>actual &&
+ if [ $use_quiet -eq 1 ]
+ then
+ ! grep "$info_text" actual
+ else
+ grep "$info_text" actual
+ fi &&
+ grep "$bad_combo_regex" actual
+ elif [ "$outcome" = "warn_bad_head" ]
+ then
+ test_must_fail git $dashc_args worktree add $args 2>actual &&
+ if [ $use_quiet -eq 1 ]
+ then
+ grep "$invalid_ref_regex" actual &&
+ ! grep "$orphan_hint" actual
+ else
+ headpath=$(git $dashc_args rev-parse --sq --path-format=absolute --git-path HEAD) &&
+ headcontents=$(cat "$headpath") &&
+ grep "HEAD points to an invalid (or orphaned) reference" actual &&
+ grep "HEAD path:\s*.$headpath." actual &&
+ grep "HEAD contents:\s*.$headcontents." actual &&
+ grep "$orphan_hint" actual &&
+ ! grep "$info_text" actual
+ fi &&
+ grep "$invalid_ref_regex" actual
+ else
+ # Unreachable
+ false
+ fi
+ ) &&
+ if [ $success -ne 1 ]
+ then
+ test_path_is_missing foo
+ fi
+ '
+}
+
+for quiet_mode in "no_quiet" "quiet"
+do
+ for changedir_type in "cd_repo" "cd_wt" "-C_repo" "-C_wt"
+ do
+ dwim_test_args="$quiet_mode $changedir_type"
+ test_dwim_orphan 'infer' $dwim_test_args no_-b
+ test_dwim_orphan 'no_infer' $dwim_test_args no_-b local_ref good_head
+ test_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref no_remote no_remote_ref no_guess_remote
+ test_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref remote no_remote_ref no_guess_remote
+ test_dwim_orphan 'fetch_error' $dwim_test_args no_-b no_local_ref remote no_remote_ref guess_remote
+ test_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref remote no_remote_ref guess_remote force
+ test_dwim_orphan 'no_infer' $dwim_test_args no_-b no_local_ref remote remote_ref guess_remote
+
+ test_dwim_orphan 'infer' $dwim_test_args -b
+ test_dwim_orphan 'no_infer' $dwim_test_args -b local_ref good_head
+ test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref no_remote no_remote_ref no_guess_remote
+ test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref no_guess_remote
+ test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref guess_remote
+ test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote remote_ref guess_remote
+
+ test_dwim_orphan 'warn_bad_head' $dwim_test_args no_-b local_ref bad_head
+ test_dwim_orphan 'warn_bad_head' $dwim_test_args -b local_ref bad_head
+ test_dwim_orphan 'warn_bad_head' $dwim_test_args detach local_ref bad_head
+ done
+
+ test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode no_-b no_checkout
+ test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode no_-b track
+ test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode -b no_checkout
+ test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode -b track
+done
+
post_checkout_hook () {
test_when_finished "rm -rf .git/hooks" &&
mkdir .git/hooks &&
diff --git a/t/t3013-ls-files-format.sh b/t/t3013-ls-files-format.sh
index efb7450bf1..6e6ea0b6f3 100755
--- a/t/t3013-ls-files-format.sh
+++ b/t/t3013-ls-files-format.sh
@@ -38,6 +38,41 @@ test_expect_success 'git ls-files --format objectname v.s. -s' '
test_cmp expect actual
'
+test_expect_success 'git ls-files --format objecttype' '
+ git ls-files --format="%(objectname)" o1.txt o4.txt o6.txt >objectname &&
+ git cat-file --batch-check="%(objecttype)" >expect <objectname &&
+ git ls-files --format="%(objecttype)" o1.txt o4.txt o6.txt >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format objectsize' '
+ cat>expect <<-\EOF &&
+26
+29
+27
+26
+-
+26
+ EOF
+ git ls-files --format="%(objectsize)" >actual &&
+
+ test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format objectsize:padded' '
+ cat>expect <<-\EOF &&
+ 26
+ 29
+ 27
+ 26
+ -
+ 26
+ EOF
+ git ls-files --format="%(objectsize:padded)" >actual &&
+
+ test_cmp expect actual
+'
+
test_expect_success 'git ls-files --format v.s. --eol' '
git ls-files --eol >tmp &&
sed -e "s/ / /g" -e "s/ */ /g" tmp >expect 2>err &&
@@ -54,6 +89,22 @@ test_expect_success 'git ls-files --format path v.s. -s' '
test_cmp expect actual
'
+test_expect_success 'git ls-files --format with relative path' '
+ cat >expect <<-\EOF &&
+ ../o1.txt
+ ../o2.txt
+ ../o3.txt
+ ../o4.txt
+ ../o5.txt
+ ../o6.txt
+ EOF
+ mkdir sub &&
+ cd sub &&
+ git ls-files --format="%(path)" ":/" >../actual &&
+ cd .. &&
+ test_cmp expect actual
+'
+
test_expect_success 'git ls-files --format with -m' '
echo change >o1.txt &&
cat >expect <<-\EOF &&
diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index c4a72ae446..5a06732ca7 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -40,7 +40,7 @@ test_expect_success 'setup' '
git commit -a -m "remove them all" &&
# The bug also requires some entry before our directory so that
- # prune_path will modify the_index.cache
+ # prune_index will modify the_repository->index.cache
mkdir a_directory_that_sorts_before_sub &&
>a_directory_that_sorts_before_sub/file &&
@@ -56,7 +56,7 @@ test_expect_success 'usage' '
'
test_expect_success 'git ls-files --with-tree should succeed from subdir' '
- # We have to run from a sub-directory to trigger prune_path
+ # We have to run from a sub-directory to trigger prune_index
# Then we finally get to run our --with-tree test
(
cd sub &&
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 5d871fde96..4dd42df38c 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -431,4 +431,15 @@ match 1 1 1 1 'a' '[B-a]'
match 0 1 0 1 'z' '[Z-y]'
match 1 1 1 1 'Z' '[Z-y]'
+test_expect_success 'matching does not exhibit exponential behavior' '
+ {
+ test-tool wildmatch wildmatch \
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab \
+ "*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a" &
+ pid=$!
+ } &&
+ sleep 2 &&
+ ! kill $!
+'
+
test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 5a169b68d6..98b6c8ac34 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -239,15 +239,34 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
git worktree prune
'
+test_expect_success 'git branch -M fails if updating any linked working tree fails' '
+ git worktree add -b baz bazdir1 &&
+ git worktree add -f bazdir2 baz &&
+ touch .git/worktrees/bazdir1/HEAD.lock &&
+ test_must_fail git branch -M baz bam &&
+ test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam &&
+ git branch -M bam baz &&
+ rm .git/worktrees/bazdir1/HEAD.lock &&
+ touch .git/worktrees/bazdir2/HEAD.lock &&
+ test_must_fail git branch -M baz bam &&
+ test $(git -C bazdir1 rev-parse --abbrev-ref HEAD) = bam &&
+ rm -rf bazdir1 bazdir2 &&
+ git worktree prune
+'
+
test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '
git checkout -b baz &&
git worktree add -f bazdir baz &&
(
cd bazdir &&
git branch -M baz bam &&
- test $(git rev-parse --abbrev-ref HEAD) = bam
+ echo bam >expect &&
+ git rev-parse --abbrev-ref HEAD >actual &&
+ test_cmp expect actual
) &&
- test $(git rev-parse --abbrev-ref HEAD) = bam &&
+ echo bam >expect &&
+ git rev-parse --abbrev-ref HEAD >actual &&
+ test_cmp expect actual &&
rm -r bazdir &&
git worktree prune
'
@@ -279,6 +298,20 @@ test_expect_success 'git branch -M and -C fail on detached HEAD' '
test_cmp expect err
'
+test_expect_success 'git branch -m should work with orphan branches' '
+ test_when_finished git checkout - &&
+ test_when_finished git worktree remove -f wt &&
+ git worktree add wt --detach &&
+ # rename orphan in another worktreee
+ git -C wt checkout --orphan orphan-foo-wt &&
+ git branch -m orphan-foo-wt orphan-bar-wt &&
+ test orphan-bar-wt=$(git -C orphan-worktree branch --show-current) &&
+ # rename orphan in the current worktree
+ git checkout --orphan orphan-foo &&
+ git branch -m orphan-foo orphan-bar &&
+ test orphan-bar=$(git branch --show-current)
+'
+
test_expect_success 'git branch -d on orphan HEAD (merged)' '
test_when_finished git checkout main &&
git checkout --orphan orphan &&
diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh
index ea7cfd1951..be20ebe1d5 100755
--- a/t/t3202-show-branch.sh
+++ b/t/t3202-show-branch.sh
@@ -221,4 +221,22 @@ test_expect_success 'fatal descriptions on non-existent branch' '
test_cmp expect actual
'
+test_expect_success 'error descriptions on orphan branch' '
+ test_when_finished git worktree remove -f wt &&
+ git worktree add wt --detach &&
+ git -C wt checkout --orphan orphan-branch &&
+ test_branch_op_in_wt() {
+ test_orphan_error() {
+ test_must_fail git $* 2>actual &&
+ test_i18ngrep "No commit on branch .orphan-branch. yet.$" actual
+ } &&
+ test_orphan_error -C wt branch $1 $2 && # implicit branch
+ test_orphan_error -C wt branch $1 orphan-branch $2 && # explicit branch
+ test_orphan_error branch $1 orphan-branch $2 # different worktree
+ } &&
+ test_branch_op_in_wt --edit-description &&
+ test_branch_op_in_wt --set-upstream-to=ne &&
+ test_branch_op_in_wt -c new-branch
+'
+
test_done
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index d34d77f893..93f8295339 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -337,10 +337,48 @@ test_expect_success 'git branch --format option' '
test_cmp expect actual
'
+test_expect_success 'git branch --format with ahead-behind' '
+ cat >expect <<-\EOF &&
+ (HEAD detached from fromtag) 0 0
+ refs/heads/ambiguous 0 0
+ refs/heads/branch-one 1 0
+ refs/heads/branch-two 0 0
+ refs/heads/main 1 0
+ refs/heads/ref-to-branch 1 0
+ refs/heads/ref-to-remote 1 0
+ EOF
+ git branch --format="%(refname) %(ahead-behind:HEAD)" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'git branch with --format=%(rest) must fail' '
test_must_fail git branch --format="%(rest)" >actual
'
+test_expect_success 'git branch --format --omit-empty' '
+ cat >expect <<-\EOF &&
+ Refname is (HEAD detached from fromtag)
+ Refname is refs/heads/ambiguous
+ Refname is refs/heads/branch-one
+ Refname is refs/heads/branch-two
+
+ Refname is refs/heads/ref-to-branch
+ Refname is refs/heads/ref-to-remote
+ EOF
+ git branch --format="%(if:notequals=refs/heads/main)%(refname)%(then)Refname is %(refname)%(end)" >actual &&
+ test_cmp expect actual &&
+ cat >expect <<-\EOF &&
+ Refname is (HEAD detached from fromtag)
+ Refname is refs/heads/ambiguous
+ Refname is refs/heads/branch-one
+ Refname is refs/heads/branch-two
+ Refname is refs/heads/ref-to-branch
+ Refname is refs/heads/ref-to-remote
+ EOF
+ git branch --omit-empty --format="%(if:notequals=refs/heads/main)%(refname)%(then)Refname is %(refname)%(end)" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'worktree colors correct' '
cat >expect <<-EOF &&
* <GREEN>(HEAD detached from fromtag)<RESET>
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index 3288aaec7d..dbadcf1375 100755
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
@@ -362,6 +362,7 @@ test_expect_success 'do not create empty note with -m ""' '
'
test_expect_success 'create note with combination of -m and -F' '
+ test_when_finished git notes remove HEAD &&
cat >expect-combine_m_and_F <<-EOF &&
foo
@@ -380,6 +381,25 @@ test_expect_success 'create note with combination of -m and -F' '
test_cmp expect-combine_m_and_F actual
'
+test_expect_success 'create note with combination of -m and -F and --separator' '
+ cat >expect-combine_m_and_F <<-\EOF &&
+ foo
+ -------
+ xyzzy
+ -------
+ bar
+ -------
+ zyxxy
+ -------
+ baz
+ EOF
+ echo "xyzzy" >note_a &&
+ echo "zyxxy" >note_b &&
+ git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" --separator "-------" &&
+ git notes show >actual &&
+ test_cmp expect-combine_m_and_F actual
+'
+
test_expect_success 'remove note with "git notes remove"' '
git notes remove HEAD^ &&
git notes remove &&
@@ -521,6 +541,85 @@ test_expect_success 'listing non-existing notes fails' '
test_must_be_empty actual
'
+test_expect_success 'append: specify an empty separator' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect <<-\EOF &&
+ notes-1
+
+ notes-2
+ EOF
+
+ git notes add -m "notes-1" &&
+ git notes append --separator="" -m "notes-2" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append: specify separator with line break' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect <<-\EOF &&
+ notes-1
+ -------
+ notes-2
+ EOF
+
+ git notes add -m "notes-1" &&
+ git notes append --separator="-------$LF" -m "notes-2" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append: specify separator without line break' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect <<-\EOF &&
+ notes-1
+ -------
+ notes-2
+ EOF
+
+ git notes add -m "notes-1" &&
+ git notes append --separator="-------" -m "notes-2" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append: specify separator with multiple messages' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect <<-\EOF &&
+ notes-1
+ -------
+ notes-2
+ -------
+ notes-3
+ EOF
+
+ git notes add -m "notes-1" &&
+ git notes append --separator="-------" -m "notes-2" -m "notes-3" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note with combination of -m and -F and --separator' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect-combine_m_and_F <<-\EOF &&
+ m-notes-1
+ -------
+ f-notes-1
+ -------
+ m-notes-2
+ -------
+ f-notes-2
+ -------
+ m-notes-3
+ EOF
+
+ echo "f-notes-1" >note_a &&
+ echo "f-notes-2" >note_b &&
+ git notes append -m "m-notes-1" -F note_a -m "m-notes-2" -F note_b -m "m-notes-3" --separator "-------" &&
+ git notes show >actual &&
+ test_cmp expect-combine_m_and_F actual
+'
+
test_expect_success 'append to existing note with "git notes append"' '
cat >expect <<-EOF &&
Initial set of notes
@@ -818,6 +917,33 @@ test_expect_success 'create note from blob with "git notes add -C" reuses blob i
test_cmp blob actual
'
+test_expect_success 'create note from blob with "-C", also specify "-m", "-F" and "--separator"' '
+ # 8th will be reuseed in following tests, so rollback when the test is done
+ test_when_finished "git notes remove && git notes add -C $(cat blob)" &&
+ commit=$(git rev-parse HEAD) &&
+ cat >expect <<-EOF &&
+ commit $commit
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:20:13 2005 -0700
+
+ ${indent}8th
+
+ Notes:
+ ${indent}This is a blob object
+ ${indent}-------
+ ${indent}This is created by -m
+ ${indent}-------
+ ${indent}This is created by -F
+ EOF
+
+ git notes remove &&
+ echo "This is a blob object" | git hash-object -w --stdin >blob &&
+ echo "This is created by -F" >note_a &&
+ git notes add -C $(cat blob) -m "This is created by -m" -F note_a --separator="-------" &&
+ git log -1 >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'create note from other note with "git notes add -c"' '
test_commit 9th &&
commit=$(git rev-parse HEAD) &&
diff --git a/t/t3309-notes-merge-auto-resolve.sh b/t/t3309-notes-merge-auto-resolve.sh
index 141d3e4ca4..9bd5dbf341 100755
--- a/t/t3309-notes-merge-auto-resolve.sh
+++ b/t/t3309-notes-merge-auto-resolve.sh
@@ -360,7 +360,12 @@ test_expect_success 'merge z into y with invalid strategy => Fail/No changes' '
test_expect_success 'merge z into y with invalid configuration option => Fail/No changes' '
git config core.notesRef refs/notes/y &&
- test_must_fail git -c notes.mergeStrategy="foo" notes merge z &&
+ cat >expect <<-\EOF &&
+ error: unknown notes merge strategy foo
+ fatal: unable to parse '\''notes.mergeStrategy'\'' from command-line config
+ EOF
+ test_must_fail git -c notes.mergeStrategy="foo" notes merge z 2>actual &&
+ test_cmp expect actual &&
# Verify no changes (y)
verify_notes y y
'
diff --git a/t/t3321-notes-stripspace.sh b/t/t3321-notes-stripspace.sh
new file mode 100755
index 0000000000..028d825e8f
--- /dev/null
+++ b/t/t3321-notes-stripspace.sh
@@ -0,0 +1,577 @@
+#!/bin/sh
+#
+# Copyright (c) 2023 Teng Long
+#
+
+test_description='Test commit notes with stripspace behavior'
+
+. ./test-lib.sh
+
+MULTI_LF="$LF$LF$LF"
+write_script fake_editor <<\EOF
+echo "$MSG" >"$1"
+echo "$MSG" >&2
+EOF
+GIT_EDITOR=./fake_editor
+export GIT_EDITOR
+
+test_expect_success 'setup the commit' '
+ test_commit 1st
+'
+
+test_expect_success 'add note by editor' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-m", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "${LF}first-line${MULTI_LF}second-line${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --stripspace -m "${LF}first-line${MULTI_LF}second-line${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-m" and "--no-stripspace" ' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}first-line${MULTI_LF}second-line
+ EOF
+
+ git notes add --no-stripspace \
+ -m "${LF}first-line${MULTI_LF}second-line${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying multiple "-m", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "${LF}" \
+ -m "first-line" \
+ -m "${MULTI_LF}" \
+ -m "second-line" \
+ -m "${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --stripspace -m "${LF}" \
+ -m "first-line" \
+ -m "${MULTI_LF}" \
+ -m "second-line" \
+ -m "${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add notes by specifying multiple "-m" and "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line${LF}
+ EOF
+
+ git notes add --no-stripspace \
+ -m "${LF}" \
+ -m "first-line" \
+ -m "${MULTI_LF}" \
+ -m "second-line" \
+ -m "${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-F", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ cat >note-file <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ git notes add -F note-file &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --stripspace -F note-file &&
+ git notes show >actual
+'
+
+test_expect_success 'add note by specifying single "-F" and "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ cat >note-file <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ git notes add --no-stripspace -F note-file &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying multiple "-F", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ file-1-first-line
+
+ file-1-second-line
+
+ file-2-first-line
+
+ file-2-second-line
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --stripspace -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying multiple "-F" with "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add --no-stripspace -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by editor' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "first-line" &&
+ MSG="${MULTI_LF}second-line${LF}" git notes append &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying single "-m"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "${LF}first-line" &&
+ git notes append -m "${MULTI_LF}second-line${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying multiple "-m"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "${LF}first-line" &&
+ git notes append -m "${MULTI_LF}" \
+ -m "second-line" \
+ -m "${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-F"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ cat >note-file <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ git notes add -F note-file &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add notes by specifying multiple "-F"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ file-1-first-line
+
+ file-1-second-line
+
+ file-2-first-line
+
+ file-2-second-line
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying single "-F"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ initial-line
+
+ first-line
+
+ second-line
+ EOF
+
+ cat >note-file <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ git notes add -m "initial-line" &&
+ git notes append -F note-file &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append notes by specifying multiple "-F"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ initial-line
+
+ file-1-first-line
+
+ file-1-second-line
+
+ file-2-first-line
+
+ file-2-second-line
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add -m "initial-line" &&
+ git notes append -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying multiple "-F" with "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ initial-line
+ ${LF}${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add -m "initial-line" &&
+ git notes append --no-stripspace -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add notes with empty messages' '
+ rev=$(git rev-parse HEAD) &&
+ git notes add -m "${LF}" \
+ -m "${MULTI_LF}" \
+ -m "${LF}" >actual 2>&1 &&
+ test_i18ngrep "Removing note for object" actual
+'
+
+test_expect_success 'add note by specifying "-C", "--no-stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ cat expect | git hash-object -w --stdin >blob &&
+ git notes add -C $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --no-stripspace -C $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'reuse note by specifying "-C" and "--stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >data <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ cat data | git hash-object -w --stdin >blob &&
+ git notes add --stripspace -C $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'reuse with "-C" and add note with "-m", "-m" will stripspace all together' '
+ test_when_finished "git notes remove" &&
+ cat >data <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+
+ third-line
+ EOF
+
+ cat data | git hash-object -w --stdin >blob &&
+ git notes add -C $(cat blob) -m "third-line" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note with "-m" and reuse note with "-C", "-C" will not stripspace all together' '
+ test_when_finished "git notes remove" &&
+ cat >data <<-EOF &&
+
+ second-line
+ EOF
+
+ cat >expect <<-EOF &&
+ first-line
+ ${LF}
+ second-line
+ EOF
+
+ cat data | git hash-object -w --stdin >blob &&
+ git notes add -m "first-line" -C $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying "-c", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ echo "initial-line" | git hash-object -w --stdin >blob &&
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add -c $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --stripspace -c $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying "-c" with "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}first-line${MULTI_LF}second-line${LF}
+ EOF
+
+ echo "initial-line" | git hash-object -w --stdin >blob &&
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --no-stripspace -c $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'edit note by specifying "-c", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes edit &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes edit --stripspace &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'edit note by specifying "-c" with "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}first-line${MULTI_LF}second-line${LF}
+ EOF
+
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --no-stripspace &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index d5a8ee39fc..3ce918fdb8 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -388,6 +388,20 @@ test_expect_success 'switch to branch checked out here' '
git rebase main main
'
+test_expect_success 'switch to branch checked out elsewhere fails' '
+ test_when_finished "
+ git worktree remove wt1 &&
+ git worktree remove wt2 &&
+ git branch -d shared
+ " &&
+ git worktree add wt1 -b shared &&
+ git worktree add wt2 -f shared &&
+ # we test in both worktrees to ensure that works
+ # as expected with "first" and "next" worktrees
+ test_must_fail git -C wt1 rebase shared shared &&
+ test_must_fail git -C wt2 rebase shared shared
+'
+
test_expect_success 'switch to branch not checked out' '
git checkout main &&
git branch other &&
diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh
index 7e46f4ca85..e9e03ca4b5 100755
--- a/t/t3402-rebase-merge.sh
+++ b/t/t3402-rebase-merge.sh
@@ -8,6 +8,7 @@ test_description='git rebase --merge test'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
T="A quick brown fox
@@ -131,27 +132,6 @@ test_expect_success 'picking rebase' '
esac
'
-test_expect_success 'rebase -s funny -Xopt' '
- test_when_finished "rm -fr test-bin funny.was.run" &&
- mkdir test-bin &&
- cat >test-bin/git-merge-funny <<-EOF &&
- #!$SHELL_PATH
- case "\$1" in --opt) ;; *) exit 2 ;; esac
- shift &&
- >funny.was.run &&
- exec git merge-recursive "\$@"
- EOF
- chmod +x test-bin/git-merge-funny &&
- git reset --hard &&
- git checkout -b test-funny main^ &&
- test_commit funny &&
- (
- PATH=./test-bin:$PATH &&
- git rebase -s funny -Xopt main
- ) &&
- test -f funny.was.run
-'
-
test_expect_success 'rebase --skip works with two conflicts in a row' '
git checkout second-side &&
tr "[A-Z]" "[a-z]" <newfile >tmp &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index ff0afad63e..653c19bc9c 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1276,20 +1276,37 @@ test_expect_success 'todo count' '
'
test_expect_success 'rebase -i commits that overwrite untracked files (pick)' '
- git checkout --force branch2 &&
+ git checkout --force A &&
git clean -f &&
+ cat >todo <<-EOF &&
+ exec >file2
+ pick $(git rev-parse B) B
+ pick $(git rev-parse C) C
+ pick $(git rev-parse D) D
+ exec cat .git/rebase-merge/done >actual
+ EOF
(
- set_fake_editor &&
- FAKE_LINES="edit 1 2" git rebase -i A
- ) &&
- test_cmp_rev HEAD F &&
- test_path_is_missing file6 &&
- >file6 &&
- test_must_fail git rebase --continue &&
- test_cmp_rev HEAD F &&
- rm file6 &&
+ set_replace_editor todo &&
+ test_must_fail git rebase -i A
+ ) &&
+ test_cmp_rev HEAD B &&
+ head -n3 todo >expect &&
+ test_cmp expect .git/rebase-merge/done &&
+ rm file2 &&
+ test_path_is_missing .git/rebase-merge/author-script &&
+ test_path_is_missing .git/rebase-merge/patch &&
+ test_path_is_missing .git/MERGE_MSG &&
+ test_path_is_missing .git/rebase-merge/message &&
+ test_path_is_missing .git/rebase-merge/stopped-sha &&
+ echo changed >file1 &&
+ git add file1 &&
+ test_must_fail git rebase --continue 2>err &&
+ grep "error: you have staged changes in your working tree" err &&
+ git reset --hard HEAD &&
git rebase --continue &&
- test_cmp_rev HEAD I
+ test_cmp_rev HEAD D &&
+ tail -n3 todo >>expect &&
+ test_cmp expect actual
'
test_expect_success 'rebase -i commits that overwrite untracked files (squash)' '
@@ -1306,6 +1323,11 @@ test_expect_success 'rebase -i commits that overwrite untracked files (squash)'
test_must_fail git rebase --continue &&
test_cmp_rev HEAD F &&
rm file6 &&
+ test_path_is_missing .git/rebase-merge/author-script &&
+ test_path_is_missing .git/rebase-merge/patch &&
+ test_path_is_missing .git/MERGE_MSG &&
+ test_path_is_missing .git/rebase-merge/message &&
+ test_path_is_missing .git/rebase-merge/stopped-sha &&
git rebase --continue &&
test $(git cat-file commit HEAD | sed -ne \$p) = I &&
git reset --hard original-branch2
@@ -1324,6 +1346,11 @@ test_expect_success 'rebase -i commits that overwrite untracked files (no ff)' '
test_must_fail git rebase --continue &&
test $(git cat-file commit HEAD | sed -ne \$p) = F &&
rm file6 &&
+ test_path_is_missing .git/rebase-merge/author-script &&
+ test_path_is_missing .git/rebase-merge/patch &&
+ test_path_is_missing .git/MERGE_MSG &&
+ test_path_is_missing .git/rebase-merge/message &&
+ test_path_is_missing .git/rebase-merge/stopped-sha &&
git rebase --continue &&
test $(git cat-file commit HEAD | sed -ne \$p) = I
'
diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh
index 130e2f9b55..2d0789e554 100755
--- a/t/t3418-rebase-continue.sh
+++ b/t/t3418-rebase-continue.sh
@@ -62,61 +62,39 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '
rm -fr .git/rebase-* &&
git reset --hard commit-new-file-F2-on-topic-branch &&
test_commit "commit-new-file-F3-on-topic-branch" F3 32 &&
- test_when_finished "rm -fr test-bin funny.was.run" &&
+ test_when_finished "rm -fr test-bin" &&
mkdir test-bin &&
- cat >test-bin/git-merge-funny <<-EOF &&
- #!$SHELL_PATH
- case "\$1" in --opt) ;; *) exit 2 ;; esac
- shift &&
- >funny.was.run &&
- exec git merge-recursive "\$@"
+
+ write_script test-bin/git-merge-funny <<-\EOF &&
+ printf "[%s]\n" $# "$1" "$2" "$3" "$5" >actual
+ shift 3 &&
+ exec git merge-recursive "$@"
EOF
- chmod +x test-bin/git-merge-funny &&
- (
- PATH=./test-bin:$PATH &&
- test_must_fail git rebase -s funny -Xopt main topic
- ) &&
- test -f funny.was.run &&
- rm funny.was.run &&
- echo "Resolved" >F2 &&
- git add F2 &&
- (
- PATH=./test-bin:$PATH &&
- git rebase --continue
- ) &&
- test -f funny.was.run
-'
-test_expect_success 'rebase -i --continue handles merge strategy and options' '
- rm -fr .git/rebase-* &&
- git reset --hard commit-new-file-F2-on-topic-branch &&
- test_commit "commit-new-file-F3-on-topic-branch-for-dash-i" F3 32 &&
- test_when_finished "rm -fr test-bin funny.was.run funny.args" &&
- mkdir test-bin &&
- cat >test-bin/git-merge-funny <<-EOF &&
- #!$SHELL_PATH
- echo "\$@" >>funny.args
- case "\$1" in --opt) ;; *) exit 2 ;; esac
- case "\$2" in --foo) ;; *) exit 2 ;; esac
- case "\$4" in --) ;; *) exit 2 ;; esac
- shift 2 &&
- >funny.was.run &&
- exec git merge-recursive "\$@"
+ cat >expect <<-\EOF &&
+ [7]
+ [--option=arg with space]
+ [--op"tion\]
+ [--new
+ line ]
+ [--]
EOF
- chmod +x test-bin/git-merge-funny &&
+
+ rm -f actual &&
(
PATH=./test-bin:$PATH &&
- test_must_fail git rebase -i -s funny -Xopt -Xfoo main topic
+ test_must_fail git rebase -s funny -X"option=arg with space" \
+ -Xop\"tion\\ -X"new${LF}line " main topic
) &&
- test -f funny.was.run &&
- rm funny.was.run &&
+ test_cmp expect actual &&
+ rm actual &&
echo "Resolved" >F2 &&
git add F2 &&
(
PATH=./test-bin:$PATH &&
git rebase --continue
) &&
- test -f funny.was.run
+ test_cmp expect actual
'
test_expect_success 'rebase -r passes merge strategy options correctly' '
diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh
index 4711b37a28..2eba00bdf5 100755
--- a/t/t3422-rebase-incompatible-options.sh
+++ b/t/t3422-rebase-incompatible-options.sh
@@ -85,6 +85,11 @@ test_rebase_am_only () {
test_must_fail git rebase $opt --reapply-cherry-picks A
"
+ test_expect_success "$opt incompatible with --rebase-merges" "
+ git checkout B^0 &&
+ test_must_fail git rebase $opt --rebase-merges A
+ "
+
test_expect_success "$opt incompatible with --update-refs" "
git checkout B^0 &&
test_must_fail git rebase $opt --update-refs A
@@ -101,6 +106,12 @@ test_rebase_am_only () {
grep -e --no-autosquash err
"
+ test_expect_success "$opt incompatible with rebase.rebaseMerges" "
+ git checkout B^0 &&
+ test_must_fail git -c rebase.rebaseMerges=true rebase $opt A 2>err &&
+ grep -e --no-rebase-merges err
+ "
+
test_expect_success "$opt incompatible with rebase.updateRefs" "
git checkout B^0 &&
test_must_fail git -c rebase.updateRefs=true rebase $opt A 2>err &&
@@ -113,6 +124,12 @@ test_rebase_am_only () {
git -c rebase.autosquash=true rebase --no-autosquash $opt A
"
+ test_expect_success "$opt okay with overridden rebase.rebaseMerges" "
+ test_when_finished \"git reset --hard B^0\" &&
+ git checkout B^0 &&
+ git -c rebase.rebaseMerges=true rebase --no-rebase-merges $opt A
+ "
+
test_expect_success "$opt okay with overridden rebase.updateRefs" "
test_when_finished \"git reset --hard B^0\" &&
git checkout B^0 &&
diff --git a/t/t3427-rebase-subtree.sh b/t/t3427-rebase-subtree.sh
index 48b76f8232..1b3e97c875 100755
--- a/t/t3427-rebase-subtree.sh
+++ b/t/t3427-rebase-subtree.sh
@@ -74,9 +74,9 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --onto commit' '
test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --onto files-main main &&
: first pick results in no changes &&
git rebase --skip &&
- verbose test "$(commit_message HEAD~2)" = "topic_4" &&
- verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
- verbose test "$(commit_message HEAD)" = "Empty commit"
+ test "$(commit_message HEAD~2)" = "topic_4" &&
+ test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
+ test "$(commit_message HEAD)" = "Empty commit"
'
test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit' '
@@ -85,9 +85,9 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit'
test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --rebase-merges --onto files-main --root &&
: first pick results in no changes &&
git rebase --skip &&
- verbose test "$(commit_message HEAD~2)" = "topic_4" &&
- verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
- verbose test "$(commit_message HEAD)" = "Empty commit"
+ test "$(commit_message HEAD~2)" = "topic_4" &&
+ test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
+ test "$(commit_message HEAD)" = "Empty commit"
'
test_done
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index fa2a06c19f..86f4e0e4d6 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -128,14 +128,24 @@ test_expect_success 'generate correct todo list' '
'
test_expect_success '`reset` refuses to overwrite untracked files' '
- git checkout -b refuse-to-reset &&
+ git checkout B &&
test_commit dont-overwrite-untracked &&
- git checkout @{-1} &&
- : >dont-overwrite-untracked.t &&
- echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch &&
+ cat >script-from-scratch <<-EOF &&
+ exec >dont-overwrite-untracked.t
+ pick $(git rev-parse B) B
+ reset refs/tags/dont-overwrite-untracked
+ pick $(git rev-parse C) C
+ exec cat .git/rebase-merge/done >actual
+ EOF
test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
- test_must_fail git rebase -ir HEAD &&
- git rebase --abort
+ test_must_fail git rebase -ir A &&
+ test_cmp_rev HEAD B &&
+ head -n3 script-from-scratch >expect &&
+ test_cmp expect .git/rebase-merge/done &&
+ rm dont-overwrite-untracked.t &&
+ git rebase --continue &&
+ tail -n3 script-from-scratch >>expect &&
+ test_cmp expect actual
'
test_expect_success '`reset` rejects trees' '
@@ -167,14 +177,21 @@ test_expect_success 'failed `merge -C` writes patch (may be rescheduled, too)' '
test_must_fail git rebase -ir HEAD &&
grep "^merge -C .* G$" .git/rebase-merge/done &&
grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
- test_path_is_file .git/rebase-merge/patch &&
+ test_path_is_missing .git/rebase-merge/patch &&
+ test_path_is_missing .git/rebase-merge/author-script &&
+ test_path_is_missing .git/MERGE_MSG &&
+ test_path_is_missing .git/rebase-merge/message &&
+ test_path_is_missing .git/rebase-merge/stopped-sha &&
: fail because of merge conflict &&
- rm G.t .git/rebase-merge/patch &&
git reset --hard conflicting-G &&
test_must_fail git rebase --continue &&
! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
- test_path_is_file .git/rebase-merge/patch
+ test_path_is_file .git/rebase-merge/patch &&
+ test_path_is_file .git/rebase-merge/author-script &&
+ test_path_is_file .git/MERGE_MSG &&
+ test_path_is_file .git/rebase-merge/message &&
+ test_path_is_file .git/rebase-merge/stopped-sha
'
test_expect_success 'failed `merge <branch>` does not crash' '
@@ -250,6 +267,16 @@ test_expect_success 'with a branch tip that was cherry-picked already' '
EOF
'
+test_expect_success '--no-rebase-merges countermands --rebase-merges' '
+ git checkout -b no-rebase-merges E &&
+ git rebase --rebase-merges --no-rebase-merges C &&
+ test_cmp_graph C.. <<-\EOF
+ * B
+ * D
+ o C
+ EOF
+'
+
test_expect_success 'do not rebase cousins unless asked for' '
git checkout -b cousins main &&
before="$(git rev-parse --verify HEAD)" &&
@@ -268,6 +295,40 @@ test_expect_success 'do not rebase cousins unless asked for' '
EOF
'
+test_expect_success 'rebase.rebaseMerges=rebase-cousins is equivalent to --rebase-merges=rebase-cousins' '
+ test_config rebase.rebaseMerges rebase-cousins &&
+ git checkout -b config-rebase-cousins main &&
+ git rebase HEAD^ &&
+ test_cmp_graph HEAD^.. <<-\EOF
+ * Merge the topic branch '\''onebranch'\''
+ |\
+ | * D
+ | * G
+ |/
+ o H
+ EOF
+'
+
+test_expect_success '--no-rebase-merges overrides rebase.rebaseMerges=no-rebase-cousins' '
+ test_config rebase.rebaseMerges no-rebase-cousins &&
+ git checkout -b override-config-no-rebase-cousins E &&
+ git rebase --no-rebase-merges C &&
+ test_cmp_graph C.. <<-\EOF
+ * B
+ * D
+ o C
+ EOF
+'
+
+test_expect_success '--rebase-merges overrides rebase.rebaseMerges=rebase-cousins' '
+ test_config rebase.rebaseMerges rebase-cousins &&
+ git checkout -b override-config-rebase-cousins E &&
+ before="$(git rev-parse --verify HEAD)" &&
+ test_tick &&
+ git rebase --rebase-merges C &&
+ test_cmp_rev HEAD $before
+'
+
test_expect_success 'refs/rewritten/* is worktree-local' '
git worktree add wt &&
cat >wt/script-from-scratch <<-\EOF &&
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 2f3e3e2416..e2ef619323 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -1,14 +1,6 @@
#!/bin/sh
-test_description='test cherry-pick and revert with renames
-
- --
- + rename2: renames oops to opos
- + rename1: renames oops to spoo
- + added: adds extra line to oops
- ++ initial: has lines in oops
-
-'
+test_description='miscellaneous basic tests for cherry-pick and revert'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
@@ -63,6 +55,14 @@ test_expect_success 'revert --nonsense' '
test_i18ngrep "[Uu]sage:" msg
'
+# the following two test cherry-pick and revert with renames
+#
+# --
+# + rename2: renames oops to opos
+# + rename1: renames oops to spoo
+# + added: adds extra line to oops
+# ++ initial: has lines in oops
+
test_expect_success 'cherry-pick after renaming branch' '
git checkout rename2 &&
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 51afbd7b24..82dd768944 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' '
test_expect_success '.gitignore is honored' '
git add . &&
- ! (git ls-files | grep "\\.ig")
+ git ls-files >files &&
+ sed -n "/\\.ig/p" <files >actual &&
+ test_must_be_empty actual
'
test_expect_success 'error out when attempting to add ignored ones without -f' '
test_must_fail git add a.?? &&
- ! (git ls-files | grep "\\.ig")
+ git ls-files >files &&
+ sed -n "/\\.ig/p" <files >actual &&
+ test_must_be_empty actual
'
test_expect_success 'error out when attempting to add ignored ones without -f' '
test_must_fail git add d.?? &&
- ! (git ls-files | grep "\\.ig")
+ git ls-files >files &&
+ sed -n "/\\.ig/p" <files >actual &&
+ test_must_be_empty actual
'
test_expect_success 'error out when attempting to add ignored ones but add others' '
touch a.if &&
test_must_fail git add a.?? &&
- ! (git ls-files | grep "\\.ig") &&
- (git ls-files | grep a.if)
+ git ls-files >files &&
+ sed -n "/\\.ig/p" <files >actual &&
+ test_must_be_empty actual &&
+ grep a.if files
'
test_expect_success 'add ignored ones with -f' '
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index 3a99837d9b..3982b6b49d 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -7,12 +7,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
-if test_have_prereq !PERL
-then
- skip_all='skipping add -i (scripted) tests, perl not available'
- test_done
-fi
-
diff_cmp () {
for x
do
@@ -311,9 +305,11 @@ test_expect_success FILEMODE 'stage mode and hunk' '
echo content >>file &&
chmod +x file &&
printf "y\\ny\\n" | git add -p &&
- git diff --cached file | grep "new mode" &&
- git diff --cached file | grep "+content" &&
- test -z "$(git diff file)"
+ git diff --cached file >out &&
+ grep "new mode" out &&
+ grep "+content" out &&
+ git diff file >out &&
+ test_must_be_empty out
'
# end of tests disabled when filemode is not usable
@@ -1075,4 +1071,25 @@ test_expect_success 'show help from add--helper' '
test_cmp expect actual
'
+test_expect_success 'reset -p with unmerged files' '
+ test_when_finished "git checkout --force main" &&
+ test_commit one conflict &&
+ git checkout -B side HEAD^ &&
+ test_commit two conflict &&
+ test_must_fail git merge one &&
+
+ # this is a noop with only an unmerged entry
+ git reset -p &&
+
+ # add files that sort before and after unmerged entry
+ echo a >a &&
+ echo z >z &&
+ git add a z &&
+
+ # confirm that we can reset those files
+ printf "%s\n" y y | git reset -p &&
+ git diff-index --cached --diff-filter=u HEAD >staged &&
+ test_must_be_empty staged
+'
+
test_done
diff --git a/t/t4000-diff-format.sh b/t/t4000-diff-format.sh
index bfcaae390f..8d50331b8c 100755
--- a/t/t4000-diff-format.sh
+++ b/t/t4000-diff-format.sh
@@ -5,6 +5,9 @@
test_description='Test built-in diff output engine.
+We happen to know that all diff plumbing and diff Porcelain share the
+same command line parser, so testing one should be sufficient; pick
+diff-files as a representative.
'
TEST_PASSES_SANITIZE_LEAK=true
@@ -16,9 +19,11 @@ Line 2
line 3'
cat path0 >path1
chmod +x path1
+mkdir path2
+>path2/path3
test_expect_success 'update-index --add two files with and without +x.' '
- git update-index --add path0 path1
+ git update-index --add path0 path1 path2/path3
'
mv path0 path0-
@@ -91,4 +96,31 @@ test_expect_success 'git diff-files --patch --no-patch does not show the patch'
test_must_be_empty err
'
+
+# Smudge path2/path3 so that dirstat has something to show
+date >path2/path3
+
+for format in stat raw numstat shortstat summary \
+ dirstat cumulative dirstat-by-file \
+ patch-with-raw patch-with-stat compact-summary
+do
+ test_expect_success "--no-patch in 'git diff-files --no-patch --$format' is a no-op" '
+ git diff-files --no-patch "--$format" >actual &&
+ git diff-files "--$format" >expect &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "--no-patch clears all previous ones" '
+ git diff-files --$format -s -p >actual &&
+ git diff-files -p >expect &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "--no-patch in 'git diff --no-patch --$format' is a no-op" '
+ git diff --no-patch "--$format" >actual &&
+ git diff "--$format" >expect &&
+ test_cmp expect actual
+ '
+done
+
test_done
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index dfcf3a0aaa..3a687c1617 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -334,6 +334,7 @@ log --first-parent --diff-merges=off -p master
log -p --first-parent master
log -p --diff-merges=first-parent master
log --diff-merges=first-parent master
+log --diff-merges=first-parent --diff-merges=hide master
log -m -p --first-parent master
log -m -p master
log --cc -m -p master
@@ -460,7 +461,18 @@ EOF
test_expect_success 'log -m matches pure log' '
git log master >result &&
process_diffs result >expected &&
- git log -m >result &&
+ git log -m master >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'log --diff-merges=on matches -m only with --diff-merges=hide' '
+ git log -m master >result &&
+ process_diffs result >expected &&
+ git log --diff-merges=on master >result &&
+ process_diffs result >actual &&
+ ! test_cmp expected actual &&
+ git log --diff-merges=on --diff-merges=hide master >result &&
process_diffs result >actual &&
test_cmp expected actual
'
@@ -473,6 +485,14 @@ test_expect_success 'log --diff-merges=on matches --diff-merges=separate' '
test_cmp expected actual
'
+test_expect_success 'log --diff-merges=<V1>,<V2>' '
+ git log --diff-merges=1,hide master >result &&
+ process_diffs result >expected &&
+ git log --diff-merges=1 --diff-merges=hide master >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'deny wrong log.diffMerges config' '
test_config log.diffMerges wrong-value &&
test_expect_code 128 git log
@@ -496,6 +516,55 @@ test_expect_success 'git config log.diffMerges first-parent vs -m' '
test_cmp expected actual
'
+test_expect_success 'git config log.diffMerges hide: has effect' '
+ git log --diff-merges=on master >result &&
+ process_diffs result >no-hide &&
+ test_config log.diffMerges hide &&
+ git log --diff-merges=on master >result &&
+ process_diffs result >hide &&
+ ! test_cmp no-hide hide
+'
+
+test_expect_success 'git config log.diffMerges no-hide: is the default' '
+ git log --diff-merges=on master >result &&
+ process_diffs result >default &&
+ test_config log.diffMerges no-hide &&
+ git log --diff-merges=on master >result &&
+ process_diffs result >no-hide &&
+ test_cmp default no-hide
+'
+
+# As "-m" is synonym for "--diff-merges=hide --diff-merges=on", the
+# "log.diffMerges=hide" configuration should have no effect on "-m"
+test_expect_success 'git config log.diffMerges hide: has no effect on -m' '
+ git log -m master >result &&
+ process_diffs result >expected &&
+ test_config log.diffMerges hide &&
+ git log -m master >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
+# As "--cc" implies "-p", the "log.diffMerges=hide" configuration
+# should have no effect on "--cc"
+test_expect_success 'git config log.diffMerges hide: has no effect on --cc' '
+ git log --cc master >result &&
+ process_diffs result >expected &&
+ test_config log.diffMerges hide &&
+ git log --cc master >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'git config log.diffMerges-m-imply-p has proper effect' '
+ git log -m -p master >result &&
+ process_diffs result >expected &&
+ test_config log.diffMerges-m-imply-p true &&
+ git log -m master >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
# -m in "git diff-index" means "match missing", that differs
# from its meaning in "git diff". Let's check it in diff-index.
# The line in the output for removed file should disappear when
@@ -616,4 +685,46 @@ test_expect_success 'diff -I<regex>: detect malformed regex' '
test_i18ngrep "invalid regex given to -I: " error
'
+# check_prefix <patch> <src> <dst>
+# check only lines with paths to avoid dependency on exact oid/contents
+check_prefix () {
+ grep -E '^(diff|---|\+\+\+) ' "$1" >actual.paths &&
+ cat >expect <<-EOF &&
+ diff --git $2 $3
+ --- $2
+ +++ $3
+ EOF
+ test_cmp expect actual.paths
+}
+
+test_expect_success 'diff-files does not respect diff.noprefix' '
+ git -c diff.noprefix diff-files -p >actual &&
+ check_prefix actual a/file0 b/file0
+'
+
+test_expect_success 'diff-files respects --no-prefix' '
+ git diff-files -p --no-prefix >actual &&
+ check_prefix actual file0 file0
+'
+
+test_expect_success 'diff respects diff.noprefix' '
+ git -c diff.noprefix diff >actual &&
+ check_prefix actual file0 file0
+'
+
+test_expect_success 'diff --default-prefix overrides diff.noprefix' '
+ git -c diff.noprefix diff --default-prefix >actual &&
+ check_prefix actual a/file0 b/file0
+'
+
+test_expect_success 'diff respects diff.mnemonicprefix' '
+ git -c diff.mnemonicprefix diff >actual &&
+ check_prefix actual i/file0 w/file0
+'
+
+test_expect_success 'diff --default-prefix overrides diff.mnemonicprefix' '
+ git -c diff.mnemonicprefix diff --default-prefix >actual &&
+ check_prefix actual a/file0 b/file0
+'
+
test_done
diff --git a/t/t4013/diff.log_--diff-merges=first-parent_--diff-merges=hide_master b/t/t4013/diff.log_--diff-merges=first-parent_--diff-merges=hide_master
new file mode 100644
index 0000000000..596caec642
--- /dev/null
+++ b/t/t4013/diff.log_--diff-merges=first-parent_--diff-merges=hide_master
@@ -0,0 +1,34 @@
+$ git log --diff-merges=first-parent --diff-merges=hide master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+ This is the second commit.
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index f3313b8c58..3cf2b7a7fb 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -59,6 +59,10 @@ test_expect_success setup '
test_tick &&
git commit -m "patchid 3" &&
+ git checkout -b empty main &&
+ test_tick &&
+ git commit --allow-empty -m "empty commit" &&
+
git checkout main
'
@@ -128,6 +132,12 @@ test_expect_success 'replay did not screw up the log message' '
grep "^Side .* with .* backslash-n" actual
'
+test_expect_success 'format-patch empty commit' '
+ git format-patch --stdout main..empty >empty &&
+ grep "^From " empty >from &&
+ test_line_count = 1 from
+'
+
test_expect_success 'extra headers' '
git config format.headers "To: R E Cipient <rcipient@example.com>
" &&
@@ -445,13 +455,13 @@ test_expect_success 'no threading' '
cat >expect.thread <<EOF
---
-Message-Id: <0>
+Message-ID: <0>
---
-Message-Id: <1>
+Message-ID: <1>
In-Reply-To: <0>
References: <0>
---
-Message-Id: <2>
+Message-ID: <2>
In-Reply-To: <0>
References: <0>
EOF
@@ -460,17 +470,22 @@ test_expect_success 'thread' '
check_threading expect.thread --thread main
'
+test_expect_success '--thread overrides format.thread=deep' '
+ test_config format.thread deep &&
+ check_threading expect.thread --thread main
+'
+
cat >expect.in-reply-to <<EOF
---
-Message-Id: <0>
+Message-ID: <0>
In-Reply-To: <1>
References: <1>
---
-Message-Id: <2>
+Message-ID: <2>
In-Reply-To: <1>
References: <1>
---
-Message-Id: <3>
+Message-ID: <3>
In-Reply-To: <1>
References: <1>
EOF
@@ -482,17 +497,17 @@ test_expect_success 'thread in-reply-to' '
cat >expect.cover-letter <<EOF
---
-Message-Id: <0>
+Message-ID: <0>
---
-Message-Id: <1>
+Message-ID: <1>
In-Reply-To: <0>
References: <0>
---
-Message-Id: <2>
+Message-ID: <2>
In-Reply-To: <0>
References: <0>
---
-Message-Id: <3>
+Message-ID: <3>
In-Reply-To: <0>
References: <0>
EOF
@@ -503,21 +518,21 @@ test_expect_success 'thread cover-letter' '
cat >expect.cl-irt <<EOF
---
-Message-Id: <0>
+Message-ID: <0>
In-Reply-To: <1>
References: <1>
---
-Message-Id: <2>
+Message-ID: <2>
In-Reply-To: <0>
References: <1>
<0>
---
-Message-Id: <3>
+Message-ID: <3>
In-Reply-To: <0>
References: <1>
<0>
---
-Message-Id: <4>
+Message-ID: <4>
In-Reply-To: <0>
References: <1>
<0>
@@ -535,13 +550,13 @@ test_expect_success 'thread explicit shallow' '
cat >expect.deep <<EOF
---
-Message-Id: <0>
+Message-ID: <0>
---
-Message-Id: <1>
+Message-ID: <1>
In-Reply-To: <0>
References: <0>
---
-Message-Id: <2>
+Message-ID: <2>
In-Reply-To: <1>
References: <0>
<1>
@@ -553,16 +568,16 @@ test_expect_success 'thread deep' '
cat >expect.deep-irt <<EOF
---
-Message-Id: <0>
+Message-ID: <0>
In-Reply-To: <1>
References: <1>
---
-Message-Id: <2>
+Message-ID: <2>
In-Reply-To: <0>
References: <1>
<0>
---
-Message-Id: <3>
+Message-ID: <3>
In-Reply-To: <2>
References: <1>
<0>
@@ -576,18 +591,18 @@ test_expect_success 'thread deep in-reply-to' '
cat >expect.deep-cl <<EOF
---
-Message-Id: <0>
+Message-ID: <0>
---
-Message-Id: <1>
+Message-ID: <1>
In-Reply-To: <0>
References: <0>
---
-Message-Id: <2>
+Message-ID: <2>
In-Reply-To: <1>
References: <0>
<1>
---
-Message-Id: <3>
+Message-ID: <3>
In-Reply-To: <2>
References: <0>
<1>
@@ -600,22 +615,22 @@ test_expect_success 'thread deep cover-letter' '
cat >expect.deep-cl-irt <<EOF
---
-Message-Id: <0>
+Message-ID: <0>
In-Reply-To: <1>
References: <1>
---
-Message-Id: <2>
+Message-ID: <2>
In-Reply-To: <0>
References: <1>
<0>
---
-Message-Id: <3>
+Message-ID: <3>
In-Reply-To: <2>
References: <1>
<0>
<2>
---
-Message-Id: <4>
+Message-ID: <4>
In-Reply-To: <3>
References: <1>
<0>
@@ -2386,4 +2401,20 @@ test_expect_success 'interdiff: solo-patch' '
test_cmp expect actual
'
+test_expect_success 'format-patch does not respect diff.noprefix' '
+ git -c diff.noprefix format-patch -1 --stdout >actual &&
+ grep "^--- a/blorp" actual
+'
+
+test_expect_success 'format-patch respects format.noprefix' '
+ git -c format.noprefix format-patch -1 --stdout >actual &&
+ grep "^--- blorp" actual
+'
+
+test_expect_success 'format-patch --default-prefix overrides format.noprefix' '
+ git -c format.noprefix \
+ format-patch -1 --default-prefix --stdout >actual &&
+ grep "^--- a/blorp" actual
+'
+
test_done
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 42a2b9a13b..c8d555771d 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -63,6 +63,25 @@ do
test_i18ngrep ! fatal msg &&
test_i18ngrep ! error msg
'
+
+ test_expect_success "builtin $p pattern compiles on bare repo with --attr-source" '
+ test_when_finished "rm -rf bare.git" &&
+ git checkout -B master &&
+ git add . &&
+ echo "*.java diff=notexist" >.gitattributes &&
+ git add .gitattributes &&
+ git commit -am "changing gitattributes" &&
+ git checkout -B branchA &&
+ echo "*.java diff=$p" >.gitattributes &&
+ git add .gitattributes &&
+ git commit -am "changing gitattributes" &&
+ git clone --bare --no-local . bare.git &&
+ git -C bare.git symbolic-ref HEAD refs/heads/master &&
+ test_expect_code 1 git -C bare.git --attr-source=branchA \
+ diff --exit-code HEAD:A.java HEAD:B.java 2>msg &&
+ test_i18ngrep ! fatal msg &&
+ test_i18ngrep ! error msg
+ '
done
test_expect_success 'last regexp must not be negated' '
diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh
index 1c89050a97..6fed993ea0 100755
--- a/t/t4022-diff-rewrite.sh
+++ b/t/t4022-diff-rewrite.sh
@@ -24,7 +24,7 @@ test_expect_success setup '
test_expect_success 'detect rewrite' '
actual=$(git diff-files -B --summary test) &&
- verbose expr "$actual" : " rewrite test ([0-9]*%)$"
+ expr "$actual" : " rewrite test ([0-9]*%)$"
'
diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh
index 40164ae07d..1c747cc325 100755
--- a/t/t4027-diff-submodule.sh
+++ b/t/t4027-diff-submodule.sh
@@ -34,6 +34,25 @@ test_expect_success setup '
subtip=$3 subprev=$2
'
+test_expect_success 'diff in superproject with submodules respects parallel settings' '
+ test_when_finished "rm -f trace.out" &&
+ (
+ GIT_TRACE=$(pwd)/trace.out git diff &&
+ grep "1 tasks" trace.out &&
+ >trace.out &&
+
+ git config submodule.diffJobs 8 &&
+ GIT_TRACE=$(pwd)/trace.out git diff &&
+ grep "8 tasks" trace.out &&
+ >trace.out &&
+
+ GIT_TRACE=$(pwd)/trace.out git -c submodule.diffJobs=0 diff &&
+ grep "preparing to run up to [0-9]* tasks" trace.out &&
+ ! grep "up to 0 tasks" trace.out &&
+ >trace.out
+ )
+'
+
test_expect_success 'git diff --raw HEAD' '
hexsz=$(test_oid hexsz) &&
git diff --raw --abbrev=$hexsz HEAD >actual &&
@@ -70,6 +89,18 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree)' '
test_cmp expect.body actual.body
'
+test_expect_success 'git diff HEAD with dirty submodule (work tree, parallel)' '
+ (
+ cd sub &&
+ git reset --hard &&
+ echo >>world
+ ) &&
+ git -c submodule.diffJobs=8 diff HEAD >actual &&
+ sed -e "1,/^@@/d" actual >actual.body &&
+ expect_from_to >expect.body $subtip $subprev-dirty &&
+ test_cmp expect.body actual.body
+'
+
test_expect_success 'git diff HEAD with dirty submodule (index)' '
(
cd sub &&
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index 15764ee9ac..74586f3813 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -69,6 +69,10 @@ test_language_driver () {
echo "* diff='"$lang"'" >.gitattributes &&
word_diff --color-words
'
+ test_expect_success "diff driver '$lang' in Islandic" '
+ LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \
+ word_diff --color-words
+ '
}
test_expect_success setup '
diff --git a/t/t4047-diff-dirstat.sh b/t/t4047-diff-dirstat.sh
index 7fec2cb9cd..70224c3da1 100755
--- a/t/t4047-diff-dirstat.sh
+++ b/t/t4047-diff-dirstat.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='diff --dirstat tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# set up two commits where the second commit has these files
diff --git a/t/t4062-diff-pickaxe.sh b/t/t4062-diff-pickaxe.sh
index 9aaa068ed9..a90b46b678 100755
--- a/t/t4062-diff-pickaxe.sh
+++ b/t/t4062-diff-pickaxe.sh
@@ -24,7 +24,7 @@ test_expect_success '-G matches' '
test_expect_success '-S --pickaxe-regex' '
git diff --name-only -S0 --pickaxe-regex HEAD^ >out &&
- verbose test 4096-zeroes.txt = "$(cat out)"
+ test 4096-zeroes.txt = "$(cat out)"
'
test_done
diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh
index f60f5cbd65..7af3a08862 100755
--- a/t/t4067-diff-partial-clone.sh
+++ b/t/t4067-diff-partial-clone.sh
@@ -151,7 +151,7 @@ test_expect_success 'diff does not fetch anything if inexact rename detection is
# Ensure no fetches.
GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --raw -M HEAD^ HEAD &&
- ! test_path_exists trace
+ test_path_is_missing trace
'
test_expect_success 'diff --break-rewrites fetches only if necessary, and batches blobs if it does' '
@@ -171,7 +171,7 @@ test_expect_success 'diff --break-rewrites fetches only if necessary, and batche
# Ensure no fetches.
GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --raw -M HEAD^ HEAD &&
- ! test_path_exists trace &&
+ test_path_is_missing trace &&
# But with --break-rewrites, ensure that there is exactly 1 negotiation
# by checking that there is only 1 "done" line sent. ("done" marks the
diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
index 65ac7df2d7..a22a90d552 100755
--- a/t/t4115-apply-symlink.sh
+++ b/t/t4115-apply-symlink.sh
@@ -74,7 +74,7 @@ test_expect_success SYMLINKS 'symlink escape when creating new files' '
error: affected file ${SQ}renamed-symlink/create-me${SQ} is beyond a symbolic link
EOF
test_cmp expected_stderr stderr &&
- ! test_path_exists .git/create-me
+ test_path_is_missing .git/create-me
'
test_expect_success SYMLINKS 'symlink escape when modifying file' '
@@ -126,4 +126,19 @@ test_expect_success SYMLINKS 'symlink escape when deleting file' '
test_path_is_file .git/delete-me
'
+test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' '
+ test_when_finished "git reset --hard && git clean -dfx" &&
+
+ test_commit file &&
+ echo modified >file.t &&
+ git diff -- file.t >patch &&
+ echo modified-again >file.t &&
+
+ ln -s foo file.t.rej &&
+ test_must_fail git apply patch --reject 2>err &&
+ test_i18ngrep "Rejected hunk" err &&
+ test_path_is_missing foo &&
+ test_path_is_file file.t.rej
+'
+
test_done
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 78cf1c880e..2935fe1b2d 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -103,7 +103,7 @@ test_expect_success setup '
git format-patch --stdout first >patch1 &&
{
- echo "Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" &&
+ echo "Message-ID: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" &&
echo "X-Fake-Field: Line One" &&
echo "X-Fake-Field: Line Two" &&
echo "X-Fake-Field: Line Three" &&
@@ -942,7 +942,7 @@ test_expect_success 'am --message-id really adds the message id' '
git am --message-id patch1.eml &&
test_path_is_missing .git/rebase-apply &&
git cat-file commit HEAD | tail -n1 >actual &&
- grep Message-Id patch1.eml >expected &&
+ grep Message-ID patch1.eml >expected &&
test_cmp expected actual
'
@@ -954,7 +954,7 @@ test_expect_success 'am.messageid really adds the message id' '
git am patch1.eml &&
test_path_is_missing .git/rebase-apply &&
git cat-file commit HEAD | tail -n1 >actual &&
- grep Message-Id patch1.eml >expected &&
+ grep Message-ID patch1.eml >expected &&
test_cmp expected actual
'
@@ -965,7 +965,7 @@ test_expect_success 'am --message-id -s signs off after the message id' '
git am -s --message-id patch1.eml &&
test_path_is_missing .git/rebase-apply &&
git cat-file commit HEAD | tail -n2 | head -n1 >actual &&
- grep Message-Id patch1.eml >expected &&
+ grep Message-ID patch1.eml >expected &&
test_cmp expected actual
'
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 2ce2b41174..ae73aef922 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -835,6 +835,21 @@ test_expect_success 'log.decorate configuration' '
'
+test_expect_success 'parse log.excludeDecoration with no value' '
+ cp .git/config .git/config.orig &&
+ test_when_finished mv .git/config.orig .git/config &&
+
+ cat >>.git/config <<-\EOF &&
+ [log]
+ excludeDecoration
+ EOF
+ cat >expect <<-\EOF &&
+ error: missing value for '\''log.excludeDecoration'\''
+ EOF
+ git log --decorate=short 2>actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'decorate-refs with glob' '
cat >expect.decorate <<-\EOF &&
Merge-tag-reach
diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh
index e89e1f54b6..85e90acb09 100755
--- a/t/t4212-log-corrupt.sh
+++ b/t/t4212-log-corrupt.sh
@@ -8,8 +8,9 @@ TEST_PASSES_SANITIZE_LEAK=true
test_expect_success 'setup' '
test_commit foo &&
- git cat-file commit HEAD |
- sed "/^author /s/>/>-<>/" >broken_email.commit &&
+ git cat-file commit HEAD >ok.commit &&
+ sed "s/>/>-<>/" <ok.commit >broken_email.commit &&
+
git hash-object --literally -w -t commit broken_email.commit >broken_email.hash &&
git update-ref refs/heads/broken_email $(cat broken_email.hash)
'
@@ -43,6 +44,11 @@ test_expect_success 'git log --format with broken author email' '
test_must_be_empty actual.err
'
+test_expect_success '--until handles broken email' '
+ git rev-list --until=1980-01-01 broken_email >actual &&
+ test_must_be_empty actual
+'
+
munge_author_date () {
git cat-file commit "$1" >commit.orig &&
sed "s/^\(author .*>\) [0-9]*/\1 $2/" <commit.orig >commit.munge &&
@@ -86,4 +92,45 @@ test_expect_success 'absurdly far-in-future date' '
git log -1 --format=%ad $commit
'
+test_expect_success 'create commits with whitespace committer dates' '
+ # It is important that this subject line is numeric, since we want to
+ # be sure we are not confused by skipping whitespace and accidentally
+ # parsing the subject as a timestamp.
+ #
+ # Do not use munge_author_date here. Besides not hitting the committer
+ # line, it leaves the timezone intact, and we want nothing but
+ # whitespace.
+ #
+ # We will make two munged commits here. The first, ws_commit, will
+ # be purely spaces. The second contains a vertical tab, which is
+ # considered a space by strtoumax(), but not by our isspace().
+ test_commit 1234567890 &&
+ git cat-file commit HEAD >commit.orig &&
+ sed "s/>.*/> /" <commit.orig >commit.munge &&
+ ws_commit=$(git hash-object --literally -w -t commit commit.munge) &&
+ sed "s/>.*/> $(printf "\013")/" <commit.orig >commit.munge &&
+ vt_commit=$(git hash-object --literally -w -t commit commit.munge)
+'
+
+test_expect_success '--until treats whitespace date as sentinel' '
+ echo $ws_commit >expect &&
+ git rev-list --until=1980-01-01 $ws_commit >actual &&
+ test_cmp expect actual &&
+
+ echo $vt_commit >expect &&
+ git rev-list --until=1980-01-01 $vt_commit >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'pretty-printer handles whitespace date' '
+ # as with the %ad test above, we will show these as the empty string,
+ # not the 1970 epoch date. This is intentional; see 7d9a281941 (t4212:
+ # test bogus timestamps with git-log, 2014-02-24) for more discussion.
+ echo : >expect &&
+ git log -1 --format="%at:%ct" $ws_commit >actual &&
+ test_cmp expect actual &&
+ git log -1 --format="%at:%ct" $vt_commit >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4258/mbox b/t/t4258/mbox
index c62819f3d2..1ae528ba78 100644
--- a/t/t4258/mbox
+++ b/t/t4258/mbox
@@ -2,7 +2,7 @@ From: A U Thor <mail@example.com>
To: list@example.org
Subject: [PATCH v2] sample
Date: Mon, 3 Aug 2020 22:40:55 +0700
-Message-Id: <msg-id@example.com>
+Message-ID: <msg-id@example.com>
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh
index c52c8a21fa..57c4f26e46 100755
--- a/t/t4300-merge-tree.sh
+++ b/t/t4300-merge-tree.sh
@@ -334,4 +334,22 @@ test_expect_success 'turn tree to file' '
test_cmp expect actual
'
+test_expect_success 'merge-tree respects core.useReplaceRefs=false' '
+ test_commit merge-to &&
+ test_commit valid base &&
+ git reset --hard HEAD^ &&
+ test_commit malicious base &&
+
+ test_when_finished "git replace -d $(git rev-parse valid^0)" &&
+ git replace valid^0 malicious^0 &&
+
+ tree=$(git -c core.useReplaceRefs=true merge-tree --write-tree merge-to valid) &&
+ merged=$(git cat-file -p $tree:base) &&
+ test malicious = $merged &&
+
+ tree=$(git -c core.useReplaceRefs=false merge-tree --write-tree merge-to valid) &&
+ merged=$(git cat-file -p $tree:base) &&
+ test valid = $merged
+'
+
test_done
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 918a2fc7c6..4b4c3315d8 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -185,6 +185,7 @@ test_expect_success 'git archive' '
'
check_tar b
+check_mtime b a/a 1117231200
test_expect_success 'git archive --mtime' '
git archive --mtime=2002-02-02T02:02:02-0200 HEAD >with_mtime.tar
@@ -257,14 +258,6 @@ test_expect_success 'git archive --remote with configured remote' '
test_cmp_bin b.tar b5-nick.tar
'
-test_expect_success 'validate file modification time' '
- mkdir extract &&
- "$TAR" xf b.tar -C extract a/a &&
- test-tool chmtime --get extract/a/a >b.mtime &&
- echo "1117231200" >expected.mtime &&
- test_cmp expected.mtime b.mtime
-'
-
test_expect_success 'git get-tar-commit-id' '
git get-tar-commit-id <b.tar >actual &&
git rev-parse HEAD >expect &&
@@ -433,6 +426,19 @@ test_expect_success 'catch non-matching pathspec' '
test_must_fail git archive -v HEAD -- "*.abc" >/dev/null
'
+test_expect_success 'reject paths outside the current directory' '
+ test_must_fail git -C a/bin archive HEAD .. >/dev/null 2>err &&
+ grep "outside the current directory" err
+'
+
+test_expect_success 'allow pathspecs that resolve to the current directory' '
+ git -C a/bin archive -v HEAD ../bin >/dev/null 2>actual &&
+ cat >expect <<-\EOF &&
+ sh
+ EOF
+ test_cmp expect actual
+'
+
# Pull the size and date of each entry in a tarfile using the system tar.
#
# We'll pull out only the year from the date; that avoids any question of
diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh
index 04d300eeda..0ff47a239d 100755
--- a/t/t5001-archive-attr.sh
+++ b/t/t5001-archive-attr.sh
@@ -33,6 +33,13 @@ test_expect_success 'setup' '
echo ignored-by-tree.d export-ignore >>.gitattributes &&
git add ignored-by-tree ignored-by-tree.d .gitattributes &&
+ mkdir subdir &&
+ >subdir/included &&
+ >subdir/ignored-by-subtree &&
+ >subdir/ignored-by-tree &&
+ echo ignored-by-subtree export-ignore >subdir/.gitattributes &&
+ git add subdir &&
+
echo ignored by worktree >ignored-by-worktree &&
echo ignored-by-worktree export-ignore >.gitattributes &&
git add ignored-by-worktree &&
@@ -93,6 +100,15 @@ test_expect_exists archive-pathspec-wildcard/ignored-by-worktree
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d/file
+test_expect_success 'git -C subdir archive' '
+ git -C subdir archive HEAD >archive-subdir.tar &&
+ extract_tar_to_dir archive-subdir
+'
+
+test_expect_exists archive-subdir/included
+test_expect_missing archive-subdir/ignored-by-subtree
+test_expect_missing archive-subdir/ignored-by-tree
+
test_expect_success 'git archive with worktree attributes' '
git archive --worktree-attributes HEAD >worktree.tar &&
(mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar
diff --git a/t/t5100/msg0002 b/t/t5100/msg0002
index e2546ec733..1089382425 100644
--- a/t/t5100/msg0002
+++ b/t/t5100/msg0002
@@ -3,7 +3,7 @@ message:
From: Nit Picker <nit.picker@example.net>
Subject: foo is too old
-Message-Id: <nitpicker.12121212@example.net>
+Message-ID: <nitpicker.12121212@example.net>
Hopefully this would fix the problem stated there.
diff --git a/t/t5100/msg0003 b/t/t5100/msg0003
index 1ac68101b1..3402b534a6 100644
--- a/t/t5100/msg0003
+++ b/t/t5100/msg0003
@@ -3,7 +3,7 @@ message:
From: Nit Picker <nit.picker@example.net>
Subject: foo is too old
-Message-Id: <nitpicker.12121212@example.net>
+Message-ID: <nitpicker.12121212@example.net>
Hopefully this would fix the problem stated there.
diff --git a/t/t5100/msg0012--message-id b/t/t5100/msg0012--message-id
index 376e26e9ae..44482958ce 100644
--- a/t/t5100/msg0012--message-id
+++ b/t/t5100/msg0012--message-id
@@ -5,4 +5,4 @@ docutils заменён на python-docutils
python-docutils. В то время как сам rest2web не нужен.
Signed-off-by: Dmitriy Blinov <bda@mnsspb.ru>
-Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
+Message-ID: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
diff --git a/t/t5100/quoted-cr.mbox b/t/t5100/quoted-cr.mbox
index 909021bb7a..a529d4de08 100644
--- a/t/t5100/quoted-cr.mbox
+++ b/t/t5100/quoted-cr.mbox
@@ -3,7 +3,7 @@ From: A U Thor <mail@example.com>
To: list@example.org
Subject: [PATCH v2] sample
Date: Mon, 3 Aug 2020 22:40:55 +0700
-Message-Id: <msg-id@example.com>
+Message-ID: <msg-id@example.com>
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
@@ -27,7 +27,7 @@ From: A U Thor <mail@example.com>
To: list@example.org
Subject: [PATCH v2] sample
Date: Mon, 3 Aug 2020 22:40:55 +0700
-Message-Id: <msg-id2@example.com>
+Message-ID: <msg-id2@example.com>
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox
index 6d4d0e4474..4a54ee5171 100644
--- a/t/t5100/sample.mbox
+++ b/t/t5100/sample.mbox
@@ -35,7 +35,7 @@ message:
From: Nit Picker <nit.picker@example.net>
Subject: foo is too old
-Message-Id: <nitpicker.12121212@example.net>
+Message-ID: <nitpicker.12121212@example.net>
Hopefully this would fix the problem stated there.
@@ -78,7 +78,7 @@ message:
From: Nit Picker <nit.picker@example.net>
Subject: foo is too old
-Message-Id: <nitpicker.12121212@example.net>
+Message-ID: <nitpicker.12121212@example.net>
Hopefully this would fix the problem stated there.
@@ -508,7 +508,7 @@ From bda@mnsspb.ru Wed Nov 12 17:54:41 2008
From: Dmitriy Blinov <bda@mnsspb.ru>
To: navy-patches@dinar.mns.mnsspb.ru
Date: Wed, 12 Nov 2008 17:54:41 +0300
-Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
+Message-ID: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
X-Mailer: git-send-email 1.5.6.5
MIME-Version: 1.0
Content-Type: text/plain;
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index f8a0f309e2..d2ce236d61 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -589,141 +589,6 @@ test_expect_success 'prefetch objects' '
test_line_count = 1 donelines
'
-test_expect_success 'setup for --stdin-packs tests' '
- git init stdin-packs &&
- (
- cd stdin-packs &&
-
- test_commit A &&
- test_commit B &&
- test_commit C &&
-
- for id in A B C
- do
- git pack-objects .git/objects/pack/pack-$id \
- --incremental --revs <<-EOF || exit 1
- refs/tags/$id
- EOF
- done &&
-
- ls -la .git/objects/pack
- )
-'
-
-test_expect_success '--stdin-packs with excluded packs' '
- (
- cd stdin-packs &&
-
- PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
- PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
- PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
-
- git pack-objects test --stdin-packs <<-EOF &&
- $PACK_A
- ^$PACK_B
- $PACK_C
- EOF
-
- (
- git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
- git show-index <$(ls .git/objects/pack/pack-C-*.idx)
- ) >expect.raw &&
- git show-index <$(ls test-*.idx) >actual.raw &&
-
- cut -d" " -f2 <expect.raw | sort >expect &&
- cut -d" " -f2 <actual.raw | sort >actual &&
- test_cmp expect actual
- )
-'
-
-test_expect_success '--stdin-packs is incompatible with --filter' '
- (
- cd stdin-packs &&
- test_must_fail git pack-objects --stdin-packs --stdout \
- --filter=blob:none </dev/null 2>err &&
- test_i18ngrep "cannot use --filter with --stdin-packs" err
- )
-'
-
-test_expect_success '--stdin-packs is incompatible with --revs' '
- (
- cd stdin-packs &&
- test_must_fail git pack-objects --stdin-packs --revs out \
- </dev/null 2>err &&
- test_i18ngrep "cannot use internal rev list with --stdin-packs" err
- )
-'
-
-test_expect_success '--stdin-packs with loose objects' '
- (
- cd stdin-packs &&
-
- PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
- PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
- PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
-
- test_commit D && # loose
-
- git pack-objects test2 --stdin-packs --unpacked <<-EOF &&
- $PACK_A
- ^$PACK_B
- $PACK_C
- EOF
-
- (
- git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
- git show-index <$(ls .git/objects/pack/pack-C-*.idx) &&
- git rev-list --objects --no-object-names \
- refs/tags/C..refs/tags/D
-
- ) >expect.raw &&
- ls -la . &&
- git show-index <$(ls test2-*.idx) >actual.raw &&
-
- cut -d" " -f2 <expect.raw | sort >expect &&
- cut -d" " -f2 <actual.raw | sort >actual &&
- test_cmp expect actual
- )
-'
-
-test_expect_success '--stdin-packs with broken links' '
- (
- cd stdin-packs &&
-
- # make an unreachable object with a bogus parent
- git cat-file -p HEAD >commit &&
- sed "s/$(git rev-parse HEAD^)/$(test_oid zero)/" <commit |
- git hash-object -w -t commit --stdin >in &&
-
- git pack-objects .git/objects/pack/pack-D <in &&
-
- PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
- PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
- PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
- PACK_D="$(basename .git/objects/pack/pack-D-*.pack)" &&
-
- git pack-objects test3 --stdin-packs --unpacked <<-EOF &&
- $PACK_A
- ^$PACK_B
- $PACK_C
- $PACK_D
- EOF
-
- (
- git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
- git show-index <$(ls .git/objects/pack/pack-C-*.idx) &&
- git show-index <$(ls .git/objects/pack/pack-D-*.idx) &&
- git rev-list --objects --no-object-names \
- refs/tags/C..refs/tags/D
- ) >expect.raw &&
- git show-index <$(ls test3-*.idx) >actual.raw &&
-
- cut -d" " -f2 <expect.raw | sort >expect &&
- cut -d" " -f2 <actual.raw | sort >actual &&
- test_cmp expect actual
- )
-'
-
test_expect_success 'negative window clamps to 0' '
git pack-objects --progress --window=-1 neg-window <obj-list 2>stderr &&
check_deltas stderr = 0
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
index d65a5f94b4..b4df545e5a 100755
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -16,7 +16,7 @@ add_blob() {
before=$(git count-objects | sed "s/ .*//") &&
BLOB=$(echo aleph_0 | git hash-object -w --stdin) &&
BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") &&
- verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
+ test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE &&
test-tool chmtime =+0 $BLOB_FILE
}
@@ -51,34 +51,42 @@ test_expect_success 'prune stale packs' '
test_expect_success 'prune --expire' '
add_blob &&
git prune --expire=1.hour.ago &&
- verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
+ test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE &&
test-tool chmtime =-86500 $BLOB_FILE &&
git prune --expire 1.day &&
- verbose test $before = $(git count-objects | sed "s/ .*//") &&
+ test $before = $(git count-objects | sed "s/ .*//") &&
test_path_is_missing $BLOB_FILE
'
test_expect_success 'gc: implicit prune --expire' '
add_blob &&
test-tool chmtime =-$((2*$week-30)) $BLOB_FILE &&
- git gc &&
- verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
+ git gc --no-cruft &&
+ test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE &&
test-tool chmtime =-$((2*$week+1)) $BLOB_FILE &&
- git gc &&
- verbose test $before = $(git count-objects | sed "s/ .*//") &&
+ git gc --no-cruft &&
+ test $before = $(git count-objects | sed "s/ .*//") &&
test_path_is_missing $BLOB_FILE
'
test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' '
- git config gc.pruneExpire invalid &&
- test_must_fail git gc
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ >repo/.git/config &&
+ git -C repo config gc.pruneExpire invalid &&
+ cat >expect <<-\EOF &&
+ error: Invalid gc.pruneexpire: '\''invalid'\''
+ fatal: bad config variable '\''gc.pruneexpire'\'' in file '\''.git/config'\'' at line 2
+ EOF
+ test_must_fail git -C repo gc 2>actual &&
+ test_cmp expect actual
'
test_expect_success 'gc: start with ok gc.pruneExpire' '
git config gc.pruneExpire 2.days.ago &&
- git gc
+ git gc --no-cruft
'
test_expect_success 'prune: prune nonsense parameters' '
@@ -129,44 +137,44 @@ test_expect_success 'gc --no-prune' '
add_blob &&
test-tool chmtime =-$((5001*$day)) $BLOB_FILE &&
git config gc.pruneExpire 2.days.ago &&
- git gc --no-prune &&
- verbose test 1 = $(git count-objects | sed "s/ .*//") &&
+ git gc --no-prune --no-cruft &&
+ test 1 = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE
'
test_expect_success 'gc respects gc.pruneExpire' '
git config gc.pruneExpire 5002.days.ago &&
- git gc &&
+ git gc --no-cruft &&
test_path_is_file $BLOB_FILE &&
git config gc.pruneExpire 5000.days.ago &&
- git gc &&
+ git gc --no-cruft &&
test_path_is_missing $BLOB_FILE
'
test_expect_success 'gc --prune=<date>' '
add_blob &&
test-tool chmtime =-$((5001*$day)) $BLOB_FILE &&
- git gc --prune=5002.days.ago &&
+ git gc --prune=5002.days.ago --no-cruft &&
test_path_is_file $BLOB_FILE &&
- git gc --prune=5000.days.ago &&
+ git gc --prune=5000.days.ago --no-cruft &&
test_path_is_missing $BLOB_FILE
'
test_expect_success 'gc --prune=never' '
add_blob &&
- git gc --prune=never &&
+ git gc --prune=never --no-cruft &&
test_path_is_file $BLOB_FILE &&
- git gc --prune=now &&
+ git gc --prune=now --no-cruft &&
test_path_is_missing $BLOB_FILE
'
test_expect_success 'gc respects gc.pruneExpire=never' '
git config gc.pruneExpire never &&
add_blob &&
- git gc &&
+ git gc --no-cruft &&
test_path_is_file $BLOB_FILE &&
git config gc.pruneExpire now &&
- git gc &&
+ git gc --no-cruft &&
test_path_is_missing $BLOB_FILE
'
@@ -184,10 +192,10 @@ test_expect_success 'gc: prune old objects after local clone' '
git clone --no-hardlinks . aclone &&
(
cd aclone &&
- verbose test 1 = $(git count-objects | sed "s/ .*//") &&
+ test 1 = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE &&
- git gc --prune &&
- verbose test 0 = $(git count-objects | sed "s/ .*//") &&
+ git gc --prune --no-cruft &&
+ test 0 = $(git count-objects | sed "s/ .*//") &&
test_path_is_missing $BLOB_FILE
)
'
@@ -229,7 +237,7 @@ test_expect_success 'clean pack garbage with gc' '
>.git/objects/pack/fake2.keep &&
>.git/objects/pack/fake2.idx &&
>.git/objects/pack/fake3.keep &&
- git gc &&
+ git gc --no-cruft &&
git count-objects -v 2>stderr &&
grep "^warning:" stderr | sort >actual &&
cat >expected <<\EOF &&
@@ -342,4 +350,18 @@ test_expect_success 'old reachable-from-recent retained with bitmaps' '
test_must_fail git cat-file -e $to_drop
'
+test_expect_success 'gc.recentObjectsHook' '
+ add_blob &&
+ test-tool chmtime =-86500 $BLOB_FILE &&
+
+ write_script precious-objects <<-EOF &&
+ echo $BLOB
+ EOF
+ test_config gc.recentObjectsHook ./precious-objects &&
+
+ git prune --expire=now &&
+
+ git cat-file -p $BLOB
+'
+
test_done
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 7d8dee41b0..526a5a506e 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -404,6 +404,26 @@ test_bitmap_cases () {
)
'
+ test_expect_success 'pack.preferBitmapTips' '
+ git init repo &&
+ test_when_finished "rm -rf repo" &&
+ (
+ cd repo &&
+ git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
+ test_commit_bulk --message="%s" 103 &&
+
+ cat >>.git/config <<-\EOF &&
+ [pack]
+ preferBitmapTips
+ EOF
+ cat >expect <<-\EOF &&
+ error: missing value for '\''pack.preferbitmaptips'\''
+ EOF
+ git repack -adb 2>actual &&
+ test_cmp expect actual
+ )
+ '
+
test_expect_success 'complains about multiple pack bitmaps' '
rm -fr repo &&
git init repo &&
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index 049c5fc8ea..b6e1211578 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -630,7 +630,7 @@ test_expect_success 'detect incorrect generation number' '
test_expect_success 'detect incorrect generation number' '
corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\01" \
- "non-zero generation number"
+ "commit-graph generation for commit"
'
test_expect_success 'detect incorrect commit date' '
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 499d5d4c78..0883c7c6bd 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -183,6 +183,18 @@ test_expect_success 'write midx with --stdin-packs' '
compare_results_with_midx "mixed mode (one pack + extra)"
+test_expect_success 'write with no objects and preferred pack' '
+ test_when_finished "rm -rf empty" &&
+ git init empty &&
+ test_must_fail git -C empty multi-pack-index write \
+ --stdin-packs --preferred-pack=does-not-exist </dev/null 2>err &&
+ cat >expect <<-EOF &&
+ warning: unknown preferred pack: ${SQ}does-not-exist${SQ}
+ error: no pack files to index.
+ EOF
+ test_cmp expect err
+'
+
test_expect_success 'write progress off for redirected stderr' '
git multi-pack-index --object-dir=$objdir write 2>err &&
test_line_count = 0 err
diff --git a/t/t5325-reverse-index.sh b/t/t5325-reverse-index.sh
index d042d26f2b..431a603ca0 100755
--- a/t/t5325-reverse-index.sh
+++ b/t/t5325-reverse-index.sh
@@ -1,17 +1,20 @@
#!/bin/sh
test_description='on-disk reverse index'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# The below tests want control over the 'pack.writeReverseIndex' setting
# themselves to assert various combinations of it with other options.
-sane_unset GIT_TEST_WRITE_REV_INDEX
+sane_unset GIT_TEST_NO_WRITE_REV_INDEX
packdir=.git/objects/pack
test_expect_success 'setup' '
test_commit base &&
+ test_config pack.writeReverseIndex false &&
pack=$(git pack-objects --all $packdir/pack) &&
rev=$packdir/pack-$pack.rev &&
@@ -94,6 +97,17 @@ test_expect_success 'reverse index is not generated when available on disk' '
--batch-check="%(objectsize:disk)" <tip
'
+test_expect_success 'reverse index is ignored when pack.readReverseIndex is false' '
+ test_index_pack true &&
+ test_path_is_file $rev &&
+
+ test_config pack.readReverseIndex false &&
+
+ git rev-parse HEAD >tip &&
+ GIT_TEST_REV_INDEX_DIE_ON_DISK=1 git cat-file \
+ --batch-check="%(objectsize:disk)" <tip
+'
+
test_expect_success 'revindex in-memory vs on-disk' '
git init repo &&
test_when_finished "rm -fr repo" &&
@@ -117,4 +131,78 @@ test_expect_success 'revindex in-memory vs on-disk' '
test_cmp on-disk in-core
)
'
+
+test_expect_success 'fsck succeeds on good rev-index' '
+ test_when_finished rm -fr repo &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit commit &&
+ git -c pack.writeReverseIndex=true repack -ad &&
+ git fsck 2>err &&
+ test_must_be_empty err
+ )
+'
+
+test_expect_success 'set up rev-index corruption tests' '
+ git init corrupt &&
+ (
+ cd corrupt &&
+
+ test_commit commit &&
+ git -c pack.writeReverseIndex=true repack -ad &&
+
+ revfile=$(ls .git/objects/pack/pack-*.rev) &&
+ chmod a+w $revfile &&
+ cp $revfile $revfile.bak
+ )
+'
+
+corrupt_rev_and_verify () {
+ (
+ pos="$1" &&
+ value="$2" &&
+ error="$3" &&
+
+ cd corrupt &&
+ revfile=$(ls .git/objects/pack/pack-*.rev) &&
+
+ # Reset to original rev-file.
+ cp $revfile.bak $revfile &&
+
+ printf "$value" | dd of=$revfile bs=1 seek="$pos" conv=notrunc &&
+ test_must_fail git fsck 2>err &&
+ grep "$error" err
+ )
+}
+
+test_expect_success 'fsck catches invalid checksum' '
+ revfile=$(ls corrupt/.git/objects/pack/pack-*.rev) &&
+ orig_size=$(wc -c <$revfile) &&
+ hashpos=$((orig_size - 10)) &&
+ corrupt_rev_and_verify $hashpos bogus \
+ "invalid checksum"
+'
+
+test_expect_success 'fsck catches invalid row position' '
+ corrupt_rev_and_verify 14 "\07" \
+ "invalid rev-index position"
+'
+
+test_expect_success 'fsck catches invalid header: magic number' '
+ corrupt_rev_and_verify 1 "\07" \
+ "reverse-index file .* has unknown signature"
+'
+
+test_expect_success 'fsck catches invalid header: version' '
+ corrupt_rev_and_verify 7 "\02" \
+ "reverse-index file .* has unsupported version"
+'
+
+test_expect_success 'fsck catches invalid header: hash function' '
+ corrupt_rev_and_verify 11 "\03" \
+ "reverse-index file .* has unsupported hash id"
+'
+
test_done
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 0882cbb6e4..f771c442d4 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -434,4 +434,48 @@ test_expect_success 'tagged commits are selected for bitmapping' '
)
'
+corrupt_file () {
+ chmod a+w "$1" &&
+ printf "bogus" | dd of="$1" bs=1 seek="12" conv=notrunc
+}
+
+test_expect_success 'git fsck correctly identifies good and bad bitmaps' '
+ git init valid &&
+ test_when_finished rm -rf valid &&
+
+ test_commit_bulk 20 &&
+ git repack -adbf &&
+
+ # Move pack-bitmap aside so it is not deleted
+ # in next repack.
+ packbitmap=$(ls .git/objects/pack/pack-*.bitmap) &&
+ mv "$packbitmap" "$packbitmap.bak" &&
+
+ test_commit_bulk 10 &&
+ git repack -b --write-midx &&
+ midxbitmap=$(ls .git/objects/pack/multi-pack-index-*.bitmap) &&
+
+ # Copy MIDX bitmap to backup. Copy pack bitmap from backup.
+ cp "$midxbitmap" "$midxbitmap.bak" &&
+ cp "$packbitmap.bak" "$packbitmap" &&
+
+ # fsck works at first
+ git fsck 2>err &&
+ test_must_be_empty err &&
+
+ corrupt_file "$packbitmap" &&
+ test_must_fail git fsck 2>err &&
+ grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err &&
+
+ cp "$packbitmap.bak" "$packbitmap" &&
+ corrupt_file "$midxbitmap" &&
+ test_must_fail git fsck 2>err &&
+ grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err &&
+
+ corrupt_file "$packbitmap" &&
+ test_must_fail git fsck 2>err &&
+ grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err &&
+ grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err
+'
+
test_done
diff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh
index 093f0c067a..57e4d9c699 100755
--- a/t/t5328-commit-graph-64bit-time.sh
+++ b/t/t5328-commit-graph-64bit-time.sh
@@ -63,4 +63,13 @@ test_expect_success 'set up and verify repo with generation data overflow chunk'
graph_git_behavior 'overflow 2' repo left right
+test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
+ git init repo-uint32-max &&
+ cd repo-uint32-max &&
+ test_commit --date "@4294967297 +0000" 1 &&
+ git commit-graph write --reachable &&
+ graph_read_expect 1 "generation_data" &&
+ git commit-graph verify
+'
+
test_done
diff --git a/t/t5329-pack-objects-cruft.sh b/t/t5329-pack-objects-cruft.sh
index 303f7a5d84..3ae61ca995 100755
--- a/t/t5329-pack-objects-cruft.sh
+++ b/t/t5329-pack-objects-cruft.sh
@@ -739,4 +739,175 @@ test_expect_success 'cruft objects are freshend via loose' '
)
'
+test_expect_success 'gc.recentObjectsHook' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ # Create a handful of objects.
+ #
+ # - one reachable commit, "base", designated for the reachable
+ # pack
+ # - one unreachable commit, "cruft.discard", which is marked
+ # for deletion
+ # - one unreachable commit, "cruft.old", which would be marked
+ # for deletion, but is rescued as an extra cruft tip
+ # - one unreachable commit, "cruft.new", which is not marked
+ # for deletion
+ test_commit base &&
+ git branch -M main &&
+
+ git checkout --orphan discard &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.discard &&
+
+ git checkout --orphan old &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.old &&
+ cruft_old="$(git rev-parse HEAD)" &&
+
+ git checkout --orphan new &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.new &&
+ cruft_new="$(git rev-parse HEAD)" &&
+
+ git checkout main &&
+ git branch -D discard old new &&
+ git reflog expire --all --expire=all &&
+
+ # mark cruft.old with an mtime that is many minutes
+ # older than the expiration period, and mark cruft.new
+ # with an mtime that is in the future (and thus not
+ # eligible for pruning).
+ test-tool chmtime -2000 "$objdir/$(test_oid_to_path $cruft_old)" &&
+ test-tool chmtime +1000 "$objdir/$(test_oid_to_path $cruft_new)" &&
+
+ # Write the list of cruft objects we expect to
+ # accumulate, which is comprised of everything reachable
+ # from cruft.old and cruft.new, but not cruft.discard.
+ git rev-list --objects --no-object-names \
+ $cruft_old $cruft_new >cruft.raw &&
+ sort cruft.raw >cruft.expect &&
+
+ # Write the script to list extra tips, which are limited
+ # to cruft.old, in this case.
+ write_script extra-tips <<-EOF &&
+ echo $cruft_old
+ EOF
+ git config gc.recentObjectsHook ./extra-tips &&
+
+ git repack --cruft --cruft-expiration=now -d &&
+
+ mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+ git show-index <${mtimes%.mtimes}.idx >cruft &&
+ cut -d" " -f2 cruft | sort >cruft.actual &&
+ test_cmp cruft.expect cruft.actual &&
+
+ # Ensure that the "old" objects are removed after
+ # dropping the gc.recentObjectsHook hook.
+ git config --unset gc.recentObjectsHook &&
+ git repack --cruft --cruft-expiration=now -d &&
+
+ mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+ git show-index <${mtimes%.mtimes}.idx >cruft &&
+ cut -d" " -f2 cruft | sort >cruft.actual &&
+
+ git rev-list --objects --no-object-names $cruft_new >cruft.raw &&
+ cp cruft.expect cruft.old &&
+ sort cruft.raw >cruft.expect &&
+ test_cmp cruft.expect cruft.actual &&
+
+ # ensure objects which are no longer in the cruft pack were
+ # removed from the repository
+ for object in $(comm -13 cruft.expect cruft.old)
+ do
+ test_must_fail git cat-file -t $object || return 1
+ done
+ )
+'
+
+test_expect_success 'multi-valued gc.recentObjectsHook' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit base &&
+ git branch -M main &&
+
+ git checkout --orphan cruft.a &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.a &&
+ cruft_a="$(git rev-parse HEAD)" &&
+
+ git checkout --orphan cruft.b &&
+ git rm -fr . &&
+ test_commit --no-tag cruft.b &&
+ cruft_b="$(git rev-parse HEAD)" &&
+
+ git checkout main &&
+ git branch -D cruft.a cruft.b &&
+ git reflog expire --all --expire=all &&
+
+ echo "echo $cruft_a" | write_script extra-tips.a &&
+ echo "echo $cruft_b" | write_script extra-tips.b &&
+ echo "false" | write_script extra-tips.c &&
+
+ git rev-list --objects --no-object-names $cruft_a $cruft_b \
+ >cruft.raw &&
+ sort cruft.raw >cruft.expect &&
+
+ # ensure that each extra cruft tip is saved by its
+ # respective hook
+ git config --add gc.recentObjectsHook ./extra-tips.a &&
+ git config --add gc.recentObjectsHook ./extra-tips.b &&
+ git repack --cruft --cruft-expiration=now -d &&
+
+ mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+ git show-index <${mtimes%.mtimes}.idx >cruft &&
+ cut -d" " -f2 cruft | sort >cruft.actual &&
+ test_cmp cruft.expect cruft.actual &&
+
+ # ensure that a dirty exit halts cruft pack generation
+ git config --add gc.recentObjectsHook ./extra-tips.c &&
+ test_must_fail git repack --cruft --cruft-expiration=now -d 2>err &&
+ grep "unable to enumerate additional cruft tips" err &&
+
+ # and that the existing cruft pack is left alone
+ test_path_is_file "$mtimes"
+ )
+'
+
+test_expect_success 'additional cruft blobs via gc.recentObjectsHook' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit base &&
+
+ blob=$(echo "unreachable" | git hash-object -w --stdin) &&
+
+ # mark the unreachable blob we wrote above as having
+ # aged out of the retention period
+ test-tool chmtime -2000 "$objdir/$(test_oid_to_path $blob)" &&
+
+ # Write the script to list extra tips, which is just the
+ # extra blob as above.
+ write_script extra-tips <<-EOF &&
+ echo $blob
+ EOF
+ git config gc.recentObjectsHook ./extra-tips &&
+
+ git repack --cruft --cruft-expiration=now -d &&
+
+ mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+ git show-index <${mtimes%.mtimes}.idx >cruft &&
+ cut -d" " -f2 cruft >actual &&
+ echo $blob >expect &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t5331-pack-objects-stdin.sh b/t/t5331-pack-objects-stdin.sh
new file mode 100755
index 0000000000..acab31667a
--- /dev/null
+++ b/t/t5331-pack-objects-stdin.sh
@@ -0,0 +1,240 @@
+#!/bin/sh
+
+test_description='pack-objects --stdin'
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+packed_objects () {
+ git show-index <"$1" >tmp-object-list &&
+ cut -d' ' -f2 tmp-object-list | sort &&
+ rm tmp-object-list
+ }
+
+test_expect_success 'setup for --stdin-packs tests' '
+ git init stdin-packs &&
+ (
+ cd stdin-packs &&
+
+ test_commit A &&
+ test_commit B &&
+ test_commit C &&
+
+ for id in A B C
+ do
+ git pack-objects .git/objects/pack/pack-$id \
+ --incremental --revs <<-EOF || exit 1
+ refs/tags/$id
+ EOF
+ done &&
+
+ ls -la .git/objects/pack
+ )
+'
+
+test_expect_success '--stdin-packs with excluded packs' '
+ (
+ cd stdin-packs &&
+
+ PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
+ PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
+ PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
+
+ git pack-objects test --stdin-packs <<-EOF &&
+ $PACK_A
+ ^$PACK_B
+ $PACK_C
+ EOF
+
+ (
+ git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
+ git show-index <$(ls .git/objects/pack/pack-C-*.idx)
+ ) >expect.raw &&
+ git show-index <$(ls test-*.idx) >actual.raw &&
+
+ cut -d" " -f2 <expect.raw | sort >expect &&
+ cut -d" " -f2 <actual.raw | sort >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success '--stdin-packs is incompatible with --filter' '
+ (
+ cd stdin-packs &&
+ test_must_fail git pack-objects --stdin-packs --stdout \
+ --filter=blob:none </dev/null 2>err &&
+ test_i18ngrep "cannot use --filter with --stdin-packs" err
+ )
+'
+
+test_expect_success '--stdin-packs is incompatible with --revs' '
+ (
+ cd stdin-packs &&
+ test_must_fail git pack-objects --stdin-packs --revs out \
+ </dev/null 2>err &&
+ test_i18ngrep "cannot use internal rev list with --stdin-packs" err
+ )
+'
+
+test_expect_success '--stdin-packs with loose objects' '
+ (
+ cd stdin-packs &&
+
+ PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
+ PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
+ PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
+
+ test_commit D && # loose
+
+ git pack-objects test2 --stdin-packs --unpacked <<-EOF &&
+ $PACK_A
+ ^$PACK_B
+ $PACK_C
+ EOF
+
+ (
+ git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
+ git show-index <$(ls .git/objects/pack/pack-C-*.idx) &&
+ git rev-list --objects --no-object-names \
+ refs/tags/C..refs/tags/D
+
+ ) >expect.raw &&
+ ls -la . &&
+ git show-index <$(ls test2-*.idx) >actual.raw &&
+
+ cut -d" " -f2 <expect.raw | sort >expect &&
+ cut -d" " -f2 <actual.raw | sort >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success '--stdin-packs with broken links' '
+ (
+ cd stdin-packs &&
+
+ # make an unreachable object with a bogus parent
+ git cat-file -p HEAD >commit &&
+ sed "s/$(git rev-parse HEAD^)/$(test_oid zero)/" <commit |
+ git hash-object -w -t commit --stdin >in &&
+
+ git pack-objects .git/objects/pack/pack-D <in &&
+
+ PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
+ PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
+ PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
+ PACK_D="$(basename .git/objects/pack/pack-D-*.pack)" &&
+
+ git pack-objects test3 --stdin-packs --unpacked <<-EOF &&
+ $PACK_A
+ ^$PACK_B
+ $PACK_C
+ $PACK_D
+ EOF
+
+ (
+ git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
+ git show-index <$(ls .git/objects/pack/pack-C-*.idx) &&
+ git show-index <$(ls .git/objects/pack/pack-D-*.idx) &&
+ git rev-list --objects --no-object-names \
+ refs/tags/C..refs/tags/D
+ ) >expect.raw &&
+ git show-index <$(ls test3-*.idx) >actual.raw &&
+
+ cut -d" " -f2 <expect.raw | sort >expect &&
+ cut -d" " -f2 <actual.raw | sort >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'pack-objects --stdin with duplicate packfile' '
+ test_when_finished "rm -fr repo" &&
+
+ git init repo &&
+ (
+ cd repo &&
+ test_commit "commit" &&
+ git repack -ad &&
+
+ {
+ basename .git/objects/pack/pack-*.pack &&
+ basename .git/objects/pack/pack-*.pack
+ } >packfiles &&
+
+ git pack-objects --stdin-packs generated-pack <packfiles &&
+ packed_objects .git/objects/pack/pack-*.idx >expect &&
+ packed_objects generated-pack-*.idx >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'pack-objects --stdin with same packfile excluded and included' '
+ test_when_finished "rm -fr repo" &&
+
+ git init repo &&
+ (
+ cd repo &&
+ test_commit "commit" &&
+ git repack -ad &&
+
+ {
+ basename .git/objects/pack/pack-*.pack &&
+ printf "^%s\n" "$(basename .git/objects/pack/pack-*.pack)"
+ } >packfiles &&
+
+ git pack-objects --stdin-packs generated-pack <packfiles &&
+ packed_objects generated-pack-*.idx >packed-objects &&
+ test_must_be_empty packed-objects
+ )
+'
+
+test_expect_success 'pack-objects --stdin with packfiles from alternate object database' '
+ test_when_finished "rm -fr shared member" &&
+
+ # Set up a shared repository with a single packfile.
+ git init shared &&
+ test_commit -C shared "shared-objects" &&
+ git -C shared repack -ad &&
+ basename shared/.git/objects/pack/pack-*.pack >packfile &&
+
+ # Set up a repository that is connected to the shared repository. This
+ # repository has no objects on its own, but we still expect to be able
+ # to pack objects from its alternate.
+ git clone --shared shared member &&
+ git -C member pack-objects --stdin-packs generated-pack <packfile &&
+ test_cmp shared/.git/objects/pack/pack-*.pack member/generated-pack-*.pack
+'
+
+test_expect_success 'pack-objects --stdin with packfiles from main and alternate object database' '
+ test_when_finished "rm -fr shared member" &&
+
+ # Set up a shared repository with a single packfile.
+ git init shared &&
+ test_commit -C shared "shared-commit" &&
+ git -C shared repack -ad &&
+
+ # Set up a repository that is connected to the shared repository. This
+ # repository has a second packfile so that we can verify that it is
+ # possible to write packs that include packfiles from different object
+ # databases.
+ git clone --shared shared member &&
+ test_commit -C member "local-commit" &&
+ git -C member repack -dl &&
+
+ {
+ basename shared/.git/objects/pack/pack-*.pack &&
+ basename member/.git/objects/pack/pack-*.pack
+ } >packfiles &&
+
+ {
+ packed_objects shared/.git/objects/pack/pack-*.idx &&
+ packed_objects member/.git/objects/pack/pack-*.idx
+ } | sort >expected-objects &&
+
+ git -C member pack-objects --stdin-packs generated-pack <packfiles &&
+ packed_objects member/generated-pack-*.idx >actual-objects &&
+ test_cmp expected-objects actual-objects
+'
+
+test_done
diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index 5f3ff051ca..c490a5137f 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -173,6 +173,17 @@ test_fail_interactive_rebase () {
)
}
+test_expect_success 'git rebase with failed pick' '
+ test_fail_interactive_rebase "exec_>bar pick 1" --onto C A E &&
+ rm bar &&
+ git rebase --continue &&
+ echo rebase >expected.args &&
+ cat >expected.data <<-EOF &&
+ $(git rev-parse E) $(git rev-parse HEAD)
+ EOF
+ verify_hook_input
+'
+
test_expect_success 'git rebase -i (unchanged)' '
git reset --hard D &&
clear_hook_input &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 34a1261520..4f289063ce 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -1118,58 +1118,14 @@ test_expect_success 'fetching with auto-gc does not lock up' '
)
'
-test_expect_success 'fetch aligned output' '
- git clone . full-output &&
- test_commit looooooooooooong-tag &&
- (
- cd full-output &&
- git -c fetch.output=full fetch origin >actual 2>&1 &&
- grep -e "->" actual | cut -c 22- >../actual
- ) &&
- cat >expect <<-\EOF &&
- main -> origin/main
- looooooooooooong-tag -> looooooooooooong-tag
- EOF
- test_cmp expect actual
-'
-
-test_expect_success 'fetch compact output' '
- git clone . compact &&
- test_commit extraaa &&
- (
- cd compact &&
- git -c fetch.output=compact fetch origin >actual 2>&1 &&
- grep -e "->" actual | cut -c 22- >../actual
- ) &&
- cat >expect <<-\EOF &&
- main -> origin/*
- extraaa -> *
- EOF
- test_cmp expect actual
-'
-
-test_expect_success '--no-show-forced-updates' '
- mkdir forced-updates &&
- (
- cd forced-updates &&
- git init &&
- test_commit 1 &&
- test_commit 2
- ) &&
- git clone forced-updates forced-update-clone &&
- git clone forced-updates no-forced-update-clone &&
- git -C forced-updates reset --hard HEAD~1 &&
- (
- cd forced-update-clone &&
- git fetch --show-forced-updates origin 2>output &&
- test_i18ngrep "(forced update)" output
- ) &&
- (
- cd no-forced-update-clone &&
- git fetch --no-show-forced-updates origin 2>output &&
- test_i18ngrep ! "(forced update)" output
- )
-'
+for section in fetch transfer
+do
+ test_expect_success "$section.hideRefs affects connectivity check" '
+ GIT_TRACE="$PWD"/trace git -c $section.hideRefs=refs -c \
+ $section.hideRefs="!refs/tags/" fetch &&
+ grep "git rev-list .*--exclude-hidden=fetch" trace
+ '
+done
setup_negotiation_tip () {
SERVER="$1"
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 20d063fb9a..151c76eb09 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -15,6 +15,19 @@ generate_references () {
done
}
+test_expect_success 'set up fake upload-pack' '
+ # This can be used to simulate an upload-pack that just shows the
+ # contents of the "input" file (prepared with the test-tool pkt-line
+ # helper), and does not do any negotiation (since ls-remote does not
+ # need it).
+ write_script cat-input <<-\EOF
+ # send our initial advertisement/response
+ cat input
+ # soak up the flush packet from the client
+ cat
+ EOF
+'
+
test_expect_success 'dies when no remote found' '
test_must_fail git ls-remote
'
@@ -231,22 +244,25 @@ test_expect_success 'protocol v2 supports hiderefs' '
test_expect_success 'ls-remote --symref' '
git fetch origin &&
- echo "ref: refs/heads/main HEAD" >expect &&
+ echo "ref: refs/heads/main HEAD" >expect.v2 &&
generate_references \
HEAD \
- refs/heads/main >>expect &&
+ refs/heads/main >>expect.v2 &&
+ echo "ref: refs/remotes/origin/main refs/remotes/origin/HEAD" >>expect.v2 &&
oid=$(git rev-parse HEAD) &&
- echo "$oid refs/remotes/origin/HEAD" >>expect &&
+ echo "$oid refs/remotes/origin/HEAD" >>expect.v2 &&
generate_references \
refs/remotes/origin/main \
refs/tags/mark \
refs/tags/mark1.1 \
refs/tags/mark1.10 \
- refs/tags/mark1.2 >>expect &&
- # Protocol v2 supports sending symrefs for refs other than HEAD, so use
- # protocol v0 here.
- GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref >actual &&
- test_cmp expect actual
+ refs/tags/mark1.2 >>expect.v2 &&
+ # v0 does not show non-HEAD symrefs
+ grep -v "ref: refs/remotes" <expect.v2 >expect.v0 &&
+ git -c protocol.version=0 ls-remote --symref >actual.v0 &&
+ test_cmp expect.v0 actual.v0 &&
+ git -c protocol.version=2 ls-remote --symref >actual.v2 &&
+ test_cmp expect.v2 actual.v2
'
test_expect_success 'ls-remote with filtered symref (refname)' '
@@ -255,76 +271,41 @@ test_expect_success 'ls-remote with filtered symref (refname)' '
ref: refs/heads/main HEAD
$rev HEAD
EOF
- # Protocol v2 supports sending symrefs for refs other than HEAD, so use
- # protocol v0 here.
- GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref . HEAD >actual &&
+ git ls-remote --symref . HEAD >actual &&
test_cmp expect actual
'
-test_expect_failure 'ls-remote with filtered symref (--heads)' '
+test_expect_success 'ls-remote with filtered symref (--heads)' '
git symbolic-ref refs/heads/foo refs/tags/mark &&
- cat >expect <<-EOF &&
+ cat >expect.v2 <<-EOF &&
ref: refs/tags/mark refs/heads/foo
$rev refs/heads/foo
$rev refs/heads/main
EOF
- # Protocol v2 supports sending symrefs for refs other than HEAD, so use
- # protocol v0 here.
- GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref --heads . >actual &&
- test_cmp expect actual
+ grep -v "^ref: refs/tags/" <expect.v2 >expect.v0 &&
+ git -c protocol.version=0 ls-remote --symref --heads . >actual.v0 &&
+ test_cmp expect.v0 actual.v0 &&
+ git -c protocol.version=2 ls-remote --symref --heads . >actual.v2 &&
+ test_cmp expect.v2 actual.v2
'
-test_expect_success 'ls-remote --symref omits filtered-out matches' '
- cat >expect <<-EOF &&
- $rev refs/heads/foo
- $rev refs/heads/main
+test_expect_success 'indicate no refs in v0 standards-compliant empty remote' '
+ # Git does not produce an output like this, but it does match the
+ # standard and is produced by other implementations like JGit. So
+ # hard-code the case we care about.
+ #
+ # The actual capabilities do not matter; there are none that would
+ # change how ls-remote behaves.
+ oid=0000000000000000000000000000000000000000 &&
+ test-tool pkt-line pack >input.q <<-EOF &&
+ $oid capabilities^{}Qcaps-go-here
+ 0000
EOF
- # Protocol v2 supports sending symrefs for refs other than HEAD, so use
- # protocol v0 here.
- GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref --heads . >actual &&
- test_cmp expect actual &&
- GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref . "refs/heads/*" >actual &&
- test_cmp expect actual
-'
-
-test_lazy_prereq GIT_DAEMON '
- test_bool_env GIT_TEST_GIT_DAEMON true
-'
+ q_to_nul <input.q >input &&
-# This test spawns a daemon, so run it only if the user would be OK with
-# testing with git-daemon.
-test_expect_success PIPE,JGIT,GIT_DAEMON 'indicate no refs in standards-compliant empty remote' '
- test_set_port JGIT_DAEMON_PORT &&
- JGIT_DAEMON_PID= &&
- git init --bare empty.git &&
- >empty.git/git-daemon-export-ok &&
- mkfifo jgit_daemon_output &&
- {
- jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output &
- JGIT_DAEMON_PID=$!
- } &&
- test_when_finished kill "$JGIT_DAEMON_PID" &&
- {
- read line &&
- case $line in
- Exporting*)
- ;;
- *)
- echo "Expected: Exporting" &&
- false;;
- esac &&
- read line &&
- case $line in
- "Listening on"*)
- ;;
- *)
- echo "Expected: Listening on" &&
- false;;
- esac
- } <jgit_daemon_output &&
# --exit-code asks the command to exit with 2 when no
# matching refs are found.
- test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
+ test_expect_code 2 git ls-remote --exit-code --upload-pack=./cat-input .
'
test_expect_success 'ls-remote works outside repository' '
@@ -345,8 +326,8 @@ test_expect_success 'ls-remote --sort fails gracefully outside repository' '
test_expect_success 'ls-remote patterns work with all protocol versions' '
git for-each-ref --format="%(objectname) %(refname)" \
refs/heads/main refs/remotes/origin/main >expect &&
- git -c protocol.version=1 ls-remote . main >actual.v1 &&
- test_cmp expect actual.v1 &&
+ git -c protocol.version=0 ls-remote . main >actual.v0 &&
+ test_cmp expect actual.v0 &&
git -c protocol.version=2 ls-remote . main >actual.v2 &&
test_cmp expect actual.v2
'
@@ -354,10 +335,49 @@ test_expect_success 'ls-remote patterns work with all protocol versions' '
test_expect_success 'ls-remote prefixes work with all protocol versions' '
git for-each-ref --format="%(objectname) %(refname)" \
refs/heads/ refs/tags/ >expect &&
- git -c protocol.version=1 ls-remote --heads --tags . >actual.v1 &&
- test_cmp expect actual.v1 &&
+ git -c protocol.version=0 ls-remote --heads --tags . >actual.v0 &&
+ test_cmp expect actual.v0 &&
git -c protocol.version=2 ls-remote --heads --tags . >actual.v2 &&
test_cmp expect actual.v2
'
+test_expect_success 'v0 clients can handle multiple symrefs' '
+ # Modern versions of Git will not return multiple symref capabilities
+ # for v0, so we have to hard-code the response. Note that we will
+ # always use both v0 and object-format=sha1 here, as the hard-coded
+ # response reflects a server that only supports those.
+ oid=1234567890123456789012345678901234567890 &&
+ symrefs="symref=refs/remotes/origin/HEAD:refs/remotes/origin/main" &&
+ symrefs="$symrefs symref=HEAD:refs/heads/main" &&
+
+ # Likewise we want to make sure our parser is not fooled by the string
+ # "symref" appearing as part of an earlier cap. But there is no way to
+ # do that via upload-pack, as arbitrary strings can appear only in a
+ # "symref" value itself (where we skip past the values as a whole)
+ # and "agent" (which always appears after "symref", so putting our
+ # parser in a confused state is less interesting).
+ caps="some other caps including a-fake-symref-cap" &&
+
+ test-tool pkt-line pack >input.q <<-EOF &&
+ $oid HEADQ$caps $symrefs
+ $oid refs/heads/main
+ $oid refs/remotes/origin/HEAD
+ $oid refs/remotes/origin/main
+ 0000
+ EOF
+ q_to_nul <input.q >input &&
+
+ cat >expect <<-EOF &&
+ ref: refs/heads/main HEAD
+ $oid HEAD
+ $oid refs/heads/main
+ ref: refs/remotes/origin/main refs/remotes/origin/HEAD
+ $oid refs/remotes/origin/HEAD
+ $oid refs/remotes/origin/main
+ EOF
+
+ git ls-remote --symref --upload-pack=./cat-input . >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh
index 54f422ced3..98f034aa77 100755
--- a/t/t5514-fetch-multiple.sh
+++ b/t/t5514-fetch-multiple.sh
@@ -58,6 +58,13 @@ test_expect_success 'git fetch --all' '
test_cmp expect output)
'
+test_expect_success 'git fetch --all --no-write-fetch-head' '
+ (cd test &&
+ rm -f .git/FETCH_HEAD &&
+ git fetch --all --no-write-fetch-head &&
+ test_path_is_missing .git/FETCH_HEAD)
+'
+
test_expect_success 'git fetch --all should continue if a remote has errors' '
(git clone one test2 &&
cd test2 &&
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 98a27a2948..19ebefa5ac 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -401,6 +401,11 @@ test_expect_success 'push with ambiguity' '
'
+test_expect_success 'push with onelevel ref' '
+ mk_test testrepo heads/main &&
+ test_must_fail git push testrepo HEAD:refs/onelevel
+'
+
test_expect_success 'push with colon-less refspec (1)' '
mk_test testrepo heads/frotz tags/frotz &&
@@ -898,6 +903,13 @@ test_expect_success 'push --delete refuses empty string' '
test_must_fail git push testrepo --delete ""
'
+test_expect_success 'push --delete onelevel refspecs' '
+ mk_test testrepo heads/main &&
+ git -C testrepo update-ref refs/onelevel refs/heads/main &&
+ git push testrepo --delete refs/onelevel &&
+ test_must_fail git -C testrepo rev-parse --verify refs/onelevel
+'
+
test_expect_success 'warn on push to HEAD of non-bare repository' '
mk_test testrepo heads/main &&
(
diff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh
index 394bc60cb8..cc5496e28f 100755
--- a/t/t5522-pull-symlink.sh
+++ b/t/t5522-pull-symlink.sh
@@ -79,7 +79,9 @@ test_expect_success SYMLINKS 'pushing from symlinked subdir' '
git commit -m push ./file &&
git push
) &&
- test push = $(git show HEAD:subdir/file)
+ echo push >expect &&
+ git show HEAD:subdir/file >actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh
index c9acc07635..1b8d609879 100755
--- a/t/t5523-push-upstream.sh
+++ b/t/t5523-push-upstream.sh
@@ -61,12 +61,20 @@ test_expect_success 'push -u :topic_2' '
check_config topic_2 upstream refs/heads/other2
'
-test_expect_success 'push -u --all' '
+test_expect_success 'push -u --all(the same behavior with--branches)' '
git branch all1 &&
git branch all2 &&
git push -u --all &&
check_config all1 upstream refs/heads/all1 &&
- check_config all2 upstream refs/heads/all2
+ check_config all2 upstream refs/heads/all2 &&
+ git config --get-regexp branch.all* > expect &&
+ git config --remove-section branch.all1 &&
+ git config --remove-section branch.all2 &&
+ git push -u --branches &&
+ check_config all1 upstream refs/heads/all1 &&
+ check_config all2 upstream refs/heads/all2 &&
+ git config --get-regexp branch.all* > actual &&
+ test_cmp expect actual
'
test_expect_success 'push -u HEAD' '
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index b9546ef8e5..26e933f93a 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -167,6 +167,19 @@ test_expect_success "fetch --recurse-submodules recurses into submodules" '
verify_fetch_result actual.err
'
+test_expect_success "fetch --recurse-submodules honors --no-write-fetch-head" '
+ (
+ cd downstream &&
+ git submodule foreach --recursive \
+ sh -c "cd \"\$(git rev-parse --git-dir)\" && rm -f FETCH_HEAD" &&
+
+ git fetch --recurse-submodules --no-write-fetch-head &&
+
+ git submodule foreach --recursive \
+ sh -c "cd \"\$(git rev-parse --git-dir)\" && ! test -f FETCH_HEAD"
+ )
+'
+
test_expect_success "submodule.recurse option triggers recursive fetch" '
add_submodule_commits &&
(
@@ -1167,4 +1180,17 @@ test_expect_success 'fetch --all with --recurse-submodules with multiple' '
test_line_count = 2 fetch-subs
'
+test_expect_success "fetch --all with --no-recurse-submodules only fetches superproject" '
+ test_when_finished "rm -rf src_clone" &&
+
+ git clone --recurse-submodules src src_clone &&
+ (
+ cd src_clone &&
+ git remote add secondary ../src &&
+ git config submodule.recurse true &&
+ git fetch --all --no-recurse-submodules 2>../fetch-log
+ ) &&
+ ! grep "Fetching submodule" fetch-log
+'
+
test_done
diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh
index 70431122a4..04b47ad84a 100755
--- a/t/t5543-atomic-push.sh
+++ b/t/t5543-atomic-push.sh
@@ -117,7 +117,10 @@ test_expect_success 'atomic push fails if one branch fails' '
test_commit five &&
git checkout main &&
test_commit six &&
- test_must_fail git push --atomic --all up
+ test_must_fail git push --atomic --all up >output-all 2>&1 &&
+ # --all and --branches have the same behavior when be combined with --atomic
+ test_must_fail git push --atomic --branches up >output-branches 2>&1 &&
+ test_cmp output-all output-branches
) &&
test_refs main HEAD@{7} &&
test_refs second HEAD@{4}
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 0908534f25..21b7767cbd 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -611,6 +611,33 @@ test_expect_success 'client falls back from v2 to v0 to match server' '
grep symref=HEAD:refs/heads/ trace
'
+test_expect_success 'create empty http-accessible SHA-256 repository' '
+ mkdir "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" &&
+ (cd "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" &&
+ git --bare init --object-format=sha256
+ )
+'
+
+test_expect_success 'clone empty SHA-256 repository with protocol v2' '
+ rm -fr sha256 &&
+ echo sha256 >expected &&
+ git -c protocol.version=2 clone "$HTTPD_URL/smart/sha256.git" &&
+ git -C sha256 rev-parse --show-object-format >actual &&
+ test_cmp actual expected &&
+ git ls-remote "$HTTPD_URL/smart/sha256.git" >actual &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'clone empty SHA-256 repository with protocol v0' '
+ rm -fr sha256 &&
+ echo sha256 >expected &&
+ GIT_TRACE=1 GIT_TRACE_PACKET=1 git -c protocol.version=0 clone "$HTTPD_URL/smart/sha256.git" &&
+ git -C sha256 rev-parse --show-object-format >actual &&
+ test_cmp actual expected &&
+ git ls-remote "$HTTPD_URL/smart/sha256.git" >actual &&
+ test_must_be_empty actual
+'
+
test_expect_success 'passing hostname resolution information works' '
BOGUS_HOST=gitbogusexamplehost.invalid &&
BOGUS_HTTPD_URL=$HTTPD_PROTO://$BOGUS_HOST:$LIB_HTTPD_PORT &&
diff --git a/t/t5552-skipping-fetch-negotiator.sh b/t/t5552-skipping-fetch-negotiator.sh
index 165427d57e..b55a9f65e6 100755
--- a/t/t5552-skipping-fetch-negotiator.sh
+++ b/t/t5552-skipping-fetch-negotiator.sh
@@ -3,6 +3,22 @@
test_description='test skipping fetch negotiator'
. ./test-lib.sh
+test_expect_success 'fetch.negotiationalgorithm config' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ cat >repo/.git/config <<-\EOF &&
+ [fetch]
+ negotiationAlgorithm
+ EOF
+ cat >expect <<-\EOF &&
+ error: missing value for '\''fetch.negotiationalgorithm'\''
+ fatal: bad config variable '\''fetch.negotiationalgorithm'\'' in file '\''.git/config'\'' at line 2
+ EOF
+ test_expect_code 128 git -C repo fetch >out 2>actual &&
+ test_must_be_empty out &&
+ test_cmp expect actual
+'
+
have_sent () {
while test "$#" -ne 0
do
diff --git a/t/t5558-clone-bundle-uri.sh b/t/t5558-clone-bundle-uri.sh
index afd56926c5..996a08e90c 100755
--- a/t/t5558-clone-bundle-uri.sh
+++ b/t/t5558-clone-bundle-uri.sh
@@ -1018,6 +1018,40 @@ test_expect_success 'creationToken heuristic with failed downloads (fetch)' '
test_cmp expect refs
'
+test_expect_success 'bundles are downloaded once during fetch --all' '
+ test_when_finished rm -rf download-* trace*.txt fetch-mult &&
+
+ cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ heuristic = creationToken
+
+ [bundle "bundle-1"]
+ uri = bundle-1.bundle
+ creationToken = 1
+
+ [bundle "bundle-2"]
+ uri = bundle-2.bundle
+ creationToken = 2
+
+ [bundle "bundle-3"]
+ uri = bundle-3.bundle
+ creationToken = 3
+ EOF
+
+ git clone --single-branch --branch=left \
+ --bundle-uri="$HTTPD_URL/bundle-list" \
+ "$HTTPD_URL/smart/fetch.git" fetch-mult &&
+ git -C fetch-mult remote add dup1 "$HTTPD_URL/smart/fetch.git" &&
+ git -C fetch-mult remote add dup2 "$HTTPD_URL/smart/fetch.git" &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace-mult.txt" \
+ git -C fetch-mult fetch --all &&
+ grep "\"child_start\".*\"git-remote-https\",\"$HTTPD_URL/bundle-list\"" \
+ trace-mult.txt >bundle-fetches &&
+ test_line_count = 1 bundle-fetches
+'
# Do not add tests here unless they use the HTTP server, as they will
# not run unless the HTTP dependencies exist.
diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh
new file mode 100755
index 0000000000..f45a43b4b5
--- /dev/null
+++ b/t/t5563-simple-http-auth.sh
@@ -0,0 +1,323 @@
+#!/bin/sh
+
+test_description='test http auth header and credential helper interop'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+
+start_httpd
+
+test_expect_success 'setup_credential_helper' '
+ mkdir "$TRASH_DIRECTORY/bin" &&
+ PATH=$PATH:"$TRASH_DIRECTORY/bin" &&
+ export PATH &&
+
+ CREDENTIAL_HELPER="$TRASH_DIRECTORY/bin/git-credential-test-helper" &&
+ write_script "$CREDENTIAL_HELPER" <<-\EOF
+ cmd=$1
+ teefile=$cmd-query.cred
+ catfile=$cmd-reply.cred
+ sed -n -e "/^$/q" -e "p" >>$teefile
+ if test "$cmd" = "get"
+ then
+ cat $catfile
+ fi
+ EOF
+'
+
+set_credential_reply () {
+ cat >"$TRASH_DIRECTORY/$1-reply.cred"
+}
+
+expect_credential_query () {
+ cat >"$TRASH_DIRECTORY/$1-expect.cred" &&
+ test_cmp "$TRASH_DIRECTORY/$1-expect.cred" \
+ "$TRASH_DIRECTORY/$1-query.cred"
+}
+
+per_test_cleanup () {
+ rm -f *.cred &&
+ rm -f "$HTTPD_ROOT_PATH"/custom-auth.valid \
+ "$HTTPD_ROOT_PATH"/custom-auth.challenge
+}
+
+test_expect_success 'setup repository' '
+ test_commit foo &&
+ git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+ git push --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git"
+'
+
+test_expect_success 'access using basic auth' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ username=alice
+ password=secret-passwd
+ EOF
+
+ # Basic base64(alice:secret-passwd)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ WWW-Authenticate: Basic realm="example.com"
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=Basic realm="example.com"
+ EOF
+
+ expect_credential_query store <<-EOF
+ protocol=http
+ host=$HTTPD_DEST
+ username=alice
+ password=secret-passwd
+ EOF
+'
+
+test_expect_success 'access using basic auth invalid credentials' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ username=baduser
+ password=wrong-passwd
+ EOF
+
+ # Basic base64(alice:secret-passwd)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ WWW-Authenticate: Basic realm="example.com"
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ test_must_fail git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=Basic realm="example.com"
+ EOF
+
+ expect_credential_query erase <<-EOF
+ protocol=http
+ host=$HTTPD_DEST
+ username=baduser
+ password=wrong-passwd
+ wwwauth[]=Basic realm="example.com"
+ EOF
+'
+
+test_expect_success 'access using basic auth with extra challenges' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ username=alice
+ password=secret-passwd
+ EOF
+
+ # Basic base64(alice:secret-passwd)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ WWW-Authenticate: FooBar param1="value1" param2="value2"
+ WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+ WWW-Authenticate: Basic realm="example.com"
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=FooBar param1="value1" param2="value2"
+ wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0
+ wwwauth[]=Basic realm="example.com"
+ EOF
+
+ expect_credential_query store <<-EOF
+ protocol=http
+ host=$HTTPD_DEST
+ username=alice
+ password=secret-passwd
+ EOF
+'
+
+test_expect_success 'access using basic auth mixed-case wwwauth header name' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ username=alice
+ password=secret-passwd
+ EOF
+
+ # Basic base64(alice:secret-passwd)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ www-authenticate: foobar param1="value1" param2="value2"
+ WWW-AUTHENTICATE: BEARER authorize_uri="id.example.com" p=1 q=0
+ WwW-aUtHeNtIcAtE: baSiC realm="example.com"
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=foobar param1="value1" param2="value2"
+ wwwauth[]=BEARER authorize_uri="id.example.com" p=1 q=0
+ wwwauth[]=baSiC realm="example.com"
+ EOF
+
+ expect_credential_query store <<-EOF
+ protocol=http
+ host=$HTTPD_DEST
+ username=alice
+ password=secret-passwd
+ EOF
+'
+
+test_expect_success 'access using basic auth with wwwauth header continuations' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ username=alice
+ password=secret-passwd
+ EOF
+
+ # Basic base64(alice:secret-passwd)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ # Note that leading and trailing whitespace is important to correctly
+ # simulate a continuation/folded header.
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ WWW-Authenticate: FooBar param1="value1"
+ param2="value2"
+ WWW-Authenticate: Bearer authorize_uri="id.example.com"
+ p=1
+ q=0
+ WWW-Authenticate: Basic realm="example.com"
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=FooBar param1="value1" param2="value2"
+ wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0
+ wwwauth[]=Basic realm="example.com"
+ EOF
+
+ expect_credential_query store <<-EOF
+ protocol=http
+ host=$HTTPD_DEST
+ username=alice
+ password=secret-passwd
+ EOF
+'
+
+test_expect_success 'access using basic auth with wwwauth header empty continuations' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ username=alice
+ password=secret-passwd
+ EOF
+
+ # Basic base64(alice:secret-passwd)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" &&
+
+ # Note that leading and trailing whitespace is important to correctly
+ # simulate a continuation/folded header.
+ printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" &&
+ printf " \r\n" >>"$CHALLENGE" &&
+ printf " param2=\"value2\"\r\n" >>"$CHALLENGE" &&
+ printf "WWW-Authenticate: Bearer authorize_uri=\"id.example.com\"\r\n" >>"$CHALLENGE" &&
+ printf " p=1\r\n" >>"$CHALLENGE" &&
+ printf " \r\n" >>"$CHALLENGE" &&
+ printf " q=0\r\n" >>"$CHALLENGE" &&
+ printf "WWW-Authenticate: Basic realm=\"example.com\"\r\n" >>"$CHALLENGE" &&
+
+ test_config_global credential.helper test-helper &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=FooBar param1="value1" param2="value2"
+ wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0
+ wwwauth[]=Basic realm="example.com"
+ EOF
+
+ expect_credential_query store <<-EOF
+ protocol=http
+ host=$HTTPD_DEST
+ username=alice
+ password=secret-passwd
+ EOF
+'
+
+test_expect_success 'access using basic auth with wwwauth header mixed line-endings' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ username=alice
+ password=secret-passwd
+ EOF
+
+ # Basic base64(alice:secret-passwd)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" &&
+
+ # Note that leading and trailing whitespace is important to correctly
+ # simulate a continuation/folded header.
+ printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" &&
+ printf " \r\n" >>"$CHALLENGE" &&
+ printf "\tparam2=\"value2\"\r\n" >>"$CHALLENGE" &&
+ printf "WWW-Authenticate: Basic realm=\"example.com\"" >>"$CHALLENGE" &&
+
+ test_config_global credential.helper test-helper &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=FooBar param1="value1" param2="value2"
+ wwwauth[]=Basic realm="example.com"
+ EOF
+
+ expect_credential_query store <<-EOF
+ protocol=http
+ host=$HTTPD_DEST
+ username=alice
+ password=secret-passwd
+ EOF
+'
+
+test_done
diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh
index 09097eff3f..4e917bf87d 100755
--- a/t/t5572-pull-submodule.sh
+++ b/t/t5572-pull-submodule.sh
@@ -121,7 +121,7 @@ test_expect_success "fetch.recurseSubmodules option triggers recursive fetch (bu
sub_oid=$(git -C child rev-parse HEAD) &&
git -C super/sub cat-file -e $sub_oid &&
# Check that the submodule worktree did not update
- ! test_path_is_file super/sub/merge_strategy_5.t
+ test_path_is_missing super/sub/merge_strategy_5.t
'
test_expect_success "fetch.recurseSubmodules takes precedence over submodule.recurse" '
@@ -134,7 +134,7 @@ test_expect_success "fetch.recurseSubmodules takes precedence over submodule.rec
sub_oid=$(git -C child rev-parse HEAD) &&
git -C super/sub cat-file -e $sub_oid &&
# Check that the submodule worktree did not update
- ! test_path_is_file super/sub/merge_strategy_6.t
+ test_path_is_missing super/sub/merge_strategy_6.t
'
test_expect_success 'pull --rebase --recurse-submodules (remote superproject submodule changes, local submodule changes)' '
diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh
new file mode 100755
index 0000000000..90e6dcb9a7
--- /dev/null
+++ b/t/t5574-fetch-output.sh
@@ -0,0 +1,293 @@
+#!/bin/sh
+
+test_description='git fetch output format'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'fetch with invalid output format configuration' '
+ test_when_finished "rm -rf clone" &&
+ git clone . clone &&
+
+ test_must_fail git -C clone -c fetch.output fetch origin 2>actual.err &&
+ cat >expect <<-EOF &&
+ error: missing value for ${SQ}fetch.output${SQ}
+ fatal: unable to parse ${SQ}fetch.output${SQ} from command-line config
+ EOF
+ test_cmp expect actual.err &&
+
+ test_must_fail git -C clone -c fetch.output= fetch origin 2>actual.err &&
+ cat >expect <<-EOF &&
+ fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}${SQ}
+ EOF
+ test_cmp expect actual.err &&
+
+ test_must_fail git -C clone -c fetch.output=garbage fetch origin 2>actual.err &&
+ cat >expect <<-EOF &&
+ fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}garbage${SQ}
+ EOF
+ test_cmp expect actual.err
+'
+
+test_expect_success 'fetch aligned output' '
+ git clone . full-output &&
+ test_commit looooooooooooong-tag &&
+ (
+ cd full-output &&
+ git -c fetch.output=full fetch origin >actual 2>&1 &&
+ grep -e "->" actual | cut -c 22- >../actual
+ ) &&
+ cat >expect <<-\EOF &&
+ main -> origin/main
+ looooooooooooong-tag -> looooooooooooong-tag
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch compact output' '
+ git clone . compact &&
+ test_commit extraaa &&
+ (
+ cd compact &&
+ git -c fetch.output=compact fetch origin >actual 2>&1 &&
+ grep -e "->" actual | cut -c 22- >../actual
+ ) &&
+ cat >expect <<-\EOF &&
+ main -> origin/*
+ extraaa -> *
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch porcelain output' '
+ test_when_finished "rm -rf porcelain" &&
+
+ # Set up a bunch of references that we can use to demonstrate different
+ # kinds of flag symbols in the output format.
+ MAIN_OLD=$(git rev-parse HEAD) &&
+ git branch "fast-forward" &&
+ git branch "deleted-branch" &&
+ git checkout -b force-updated &&
+ test_commit --no-tag force-update-old &&
+ FORCE_UPDATED_OLD=$(git rev-parse HEAD) &&
+ git checkout main &&
+
+ # Clone and pre-seed the repositories. We fetch references into two
+ # namespaces so that we can test that rejected and force-updated
+ # references are reported properly.
+ refspecs="refs/heads/*:refs/unforced/* +refs/heads/*:refs/forced/*" &&
+ git clone . porcelain &&
+ git -C porcelain fetch origin $refspecs &&
+
+ # Now that we have set up the client repositories we can change our
+ # local references.
+ git branch new-branch &&
+ git branch -d deleted-branch &&
+ git checkout fast-forward &&
+ test_commit --no-tag fast-forward-new &&
+ FAST_FORWARD_NEW=$(git rev-parse HEAD) &&
+ git checkout force-updated &&
+ git reset --hard HEAD~ &&
+ test_commit --no-tag force-update-new &&
+ FORCE_UPDATED_NEW=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ - $MAIN_OLD $ZERO_OID refs/forced/deleted-branch
+ - $MAIN_OLD $ZERO_OID refs/unforced/deleted-branch
+ $MAIN_OLD $FAST_FORWARD_NEW refs/unforced/fast-forward
+ ! $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/unforced/force-updated
+ * $ZERO_OID $MAIN_OLD refs/unforced/new-branch
+ $MAIN_OLD $FAST_FORWARD_NEW refs/forced/fast-forward
+ + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/forced/force-updated
+ * $ZERO_OID $MAIN_OLD refs/forced/new-branch
+ $MAIN_OLD $FAST_FORWARD_NEW refs/remotes/origin/fast-forward
+ + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/remotes/origin/force-updated
+ * $ZERO_OID $MAIN_OLD refs/remotes/origin/new-branch
+ EOF
+
+ # Execute a dry-run fetch first. We do this to assert that the dry-run
+ # and non-dry-run fetches produces the same output. Execution of the
+ # fetch is expected to fail as we have a rejected reference update.
+ test_must_fail git -C porcelain fetch \
+ --porcelain --dry-run --prune origin $refspecs >actual &&
+ test_cmp expect actual &&
+
+ # And now we perform a non-dry-run fetch.
+ test_must_fail git -C porcelain fetch \
+ --porcelain --prune origin $refspecs >actual 2>stderr &&
+ test_cmp expect actual &&
+ test_must_be_empty stderr
+'
+
+test_expect_success 'fetch porcelain with multiple remotes' '
+ test_when_finished "rm -rf porcelain" &&
+
+ git switch --create multiple-remotes &&
+ git clone . porcelain &&
+ git -C porcelain remote add second-remote "$PWD" &&
+ git -C porcelain fetch second-remote &&
+
+ test_commit --no-tag multi-commit &&
+ old_commit=$(git rev-parse HEAD~) &&
+ new_commit=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ $old_commit $new_commit refs/remotes/origin/multiple-remotes
+ $old_commit $new_commit refs/remotes/second-remote/multiple-remotes
+ EOF
+
+ git -C porcelain fetch --porcelain --all >actual 2>stderr &&
+ test_cmp expect actual &&
+ test_must_be_empty stderr
+'
+
+test_expect_success 'fetch porcelain refuses to work with submodules' '
+ test_when_finished "rm -rf porcelain" &&
+
+ cat >expect <<-EOF &&
+ fatal: options ${SQ}--porcelain${SQ} and ${SQ}--recurse-submodules${SQ} cannot be used together
+ EOF
+
+ git init porcelain &&
+ test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=yes 2>stderr &&
+ test_cmp expect stderr &&
+
+ test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=on-demand 2>stderr &&
+ test_cmp expect stderr
+'
+
+test_expect_success 'fetch porcelain overrides fetch.output config' '
+ test_when_finished "rm -rf porcelain" &&
+
+ git switch --create config-override &&
+ git clone . porcelain &&
+ test_commit new-commit &&
+ old_commit=$(git rev-parse HEAD~) &&
+ new_commit=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ $old_commit $new_commit refs/remotes/origin/config-override
+ * $ZERO_OID $new_commit refs/tags/new-commit
+ EOF
+
+ git -C porcelain -c fetch.output=compact fetch --porcelain >stdout 2>stderr &&
+ test_must_be_empty stderr &&
+ test_cmp expect stdout
+'
+
+test_expect_success 'fetch --no-porcelain overrides previous --porcelain' '
+ test_when_finished "rm -rf no-porcelain" &&
+
+ git switch --create no-porcelain &&
+ git clone . no-porcelain &&
+ test_commit --no-tag no-porcelain &&
+ old_commit=$(git rev-parse --short HEAD~) &&
+ new_commit=$(git rev-parse --short HEAD) &&
+
+ cat >expect <<-EOF &&
+ From $(test-tool path-utils real_path .)/.
+ $old_commit..$new_commit no-porcelain -> origin/no-porcelain
+ EOF
+
+ git -C no-porcelain fetch --porcelain --no-porcelain >stdout 2>stderr &&
+ test_cmp expect stderr &&
+ test_must_be_empty stdout
+'
+
+test_expect_success 'fetch output with HEAD' '
+ test_when_finished "rm -rf head" &&
+ git clone . head &&
+
+ git -C head fetch --dry-run origin HEAD >actual.out 2>actual.err &&
+ cat >expect <<-EOF &&
+ From $(test-tool path-utils real_path .)/.
+ * branch HEAD -> FETCH_HEAD
+ EOF
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err &&
+
+ git -C head fetch origin HEAD >actual.out 2>actual.err &&
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err &&
+
+ git -C head fetch --dry-run origin HEAD:foo >actual.out 2>actual.err &&
+ cat >expect <<-EOF &&
+ From $(test-tool path-utils real_path .)/.
+ * [new ref] HEAD -> foo
+ EOF
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err &&
+
+ git -C head fetch origin HEAD:foo >actual.out 2>actual.err &&
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err
+'
+
+test_expect_success 'fetch porcelain output with HEAD' '
+ test_when_finished "rm -rf head" &&
+ git clone . head &&
+ COMMIT_ID=$(git rev-parse HEAD) &&
+
+ git -C head fetch --porcelain --dry-run origin HEAD >actual &&
+ cat >expect <<-EOF &&
+ * $ZERO_OID $COMMIT_ID FETCH_HEAD
+ EOF
+ test_cmp expect actual &&
+
+ git -C head fetch --porcelain origin HEAD >actual &&
+ test_cmp expect actual &&
+
+ git -C head fetch --porcelain --dry-run origin HEAD:foo >actual &&
+ cat >expect <<-EOF &&
+ * $ZERO_OID $COMMIT_ID refs/heads/foo
+ EOF
+ test_cmp expect actual &&
+
+ git -C head fetch --porcelain origin HEAD:foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch output with object ID' '
+ test_when_finished "rm -rf object-id" &&
+ git clone . object-id &&
+ commit=$(git rev-parse HEAD) &&
+
+ git -C object-id fetch --dry-run origin $commit:object-id >actual.out 2>actual.err &&
+ cat >expect <<-EOF &&
+ From $(test-tool path-utils real_path .)/.
+ * [new ref] $commit -> object-id
+ EOF
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err &&
+
+ git -C object-id fetch origin $commit:object-id >actual.out 2>actual.err &&
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err
+'
+
+test_expect_success '--no-show-forced-updates' '
+ mkdir forced-updates &&
+ (
+ cd forced-updates &&
+ git init &&
+ test_commit 1 &&
+ test_commit 2
+ ) &&
+ git clone forced-updates forced-update-clone &&
+ git clone forced-updates no-forced-update-clone &&
+ git -C forced-updates reset --hard HEAD~1 &&
+ (
+ cd forced-update-clone &&
+ git fetch --show-forced-updates origin 2>output &&
+ test_i18ngrep "(forced update)" output
+ ) &&
+ (
+ cd no-forced-update-clone &&
+ git fetch --no-show-forced-updates origin 2>output &&
+ test_i18ngrep ! "(forced update)" output
+ )
+'
+
+test_done
diff --git a/t/t5583-push-branches.sh b/t/t5583-push-branches.sh
new file mode 100755
index 0000000000..e7e1b6dab6
--- /dev/null
+++ b/t/t5583-push-branches.sh
@@ -0,0 +1,115 @@
+#!/bin/sh
+
+test_description='check the consisitency of behavior of --all and --branches'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+delete_refs() {
+ dir=$1
+ shift
+ rm -rf deletes
+ for arg in $*
+ do
+ echo "delete ${arg}" >>deletes
+ done
+ git -C $dir update-ref --stdin < deletes
+}
+
+test_expect_success 'setup bare remote' '
+ git init --bare remote-1 &&
+ git -C remote-1 config gc.auto 0 &&
+ test_commit one &&
+ git push remote-1 HEAD
+'
+
+test_expect_success 'setup different types of references' '
+ cat >refs <<-EOF &&
+ update refs/heads/branch-1 HEAD
+ update refs/heads/branch-2 HEAD
+ EOF
+
+ git tag -a -m "annotated" annotated-1 HEAD &&
+ git tag -a -m "annotated" annotated-2 HEAD &&
+ git update-ref --stdin < refs
+'
+
+test_expect_success '--all and --branches have the same behavior' '
+ test_when_finished "delete_refs remote-1 \
+ refs/heads/branch-1 \
+ refs/heads/branch-2" &&
+ git push remote-1 --all &&
+ commit=$(git rev-parse HEAD) &&
+ cat >expect <<-EOF &&
+ $commit refs/heads/branch-1
+ $commit refs/heads/branch-2
+ $commit refs/heads/main
+ EOF
+
+ git -C remote-1 show-ref --heads >actual.all &&
+ delete_refs remote-1 refs/heads/branch-1 refs/heads/branch-2 &&
+ git push remote-1 --branches &&
+ git -C remote-1 show-ref --heads >actual.branches &&
+ test_cmp actual.all actual.branches &&
+ test_cmp expect actual.all
+'
+
+test_expect_success '--all or --branches can not be combined with refspecs' '
+ test_must_fail git push remote-1 --all main >actual.all 2>&1 &&
+ test_must_fail git push remote-1 --branches main >actual.branches 2>&1 &&
+ test_cmp actual.all actual.branches &&
+ grep "be combined with refspecs" actual.all
+'
+
+test_expect_success '--all or --branches can not be combined with --mirror' '
+ test_must_fail git push remote-1 --all --mirror >actual.all 2>&1 &&
+ test_must_fail git push remote-1 --branches --mirror >actual.branches 2>&1 &&
+ test_cmp actual.all actual.branches &&
+ grep "cannot be used together" actual.all
+'
+
+test_expect_success '--all or --branches can not be combined with --tags' '
+ test_must_fail git push remote-1 --all --tags >actual.all 2>&1 &&
+ test_must_fail git push remote-1 --branches --tags >actual.branches 2>&1 &&
+ test_cmp actual.all actual.branches &&
+ grep "cannot be used together" actual.all
+'
+
+
+test_expect_success '--all or --branches can not be combined with --delete' '
+ test_must_fail git push remote-1 --all --delete >actual.all 2>&1 &&
+ test_must_fail git push remote-1 --branches --delete >actual.branches 2>&1 &&
+ test_cmp actual.all actual.branches &&
+ grep "cannot be used together" actual.all
+'
+
+test_expect_success '--all or --branches combines with --follow-tags have same behavior' '
+ test_when_finished "delete_refs remote-1 \
+ refs/heads/branch-1 \
+ refs/heads/branch-2 \
+ refs/tags/annotated-1 \
+ refs/tags/annotated-2" &&
+ git push remote-1 --all --follow-tags &&
+ git -C remote-1 show-ref > actual.all &&
+ cat >expect <<-EOF &&
+ $commit refs/heads/branch-1
+ $commit refs/heads/branch-2
+ $commit refs/heads/main
+ $(git rev-parse annotated-1) refs/tags/annotated-1
+ $(git rev-parse annotated-2) refs/tags/annotated-2
+ EOF
+
+ delete_refs remote-1 \
+ refs/heads/branch-1 \
+ refs/heads/branch-2 \
+ refs/tags/annotated-1 \
+ refs/tags/annotated-2 &&
+ git push remote-1 --branches --follow-tags &&
+ git -C remote-1 show-ref >actual.branches &&
+ test_cmp actual.all actual.branches &&
+ test_cmp expect actual.all
+'
+
+test_done
diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh
index 83e3c97861..9845fc04d5 100755
--- a/t/t5604-clone-reference.sh
+++ b/t/t5604-clone-reference.sh
@@ -358,7 +358,7 @@ test_expect_success SYMLINKS 'clone repo with symlinked objects directory' '
test_must_fail git clone --local malicious clone 2>err &&
test_path_is_missing clone &&
- grep "failed to start iterator over" err
+ grep "is a symlink, refusing to clone with --local" err
'
test_done
diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh
index 38b850c10e..1d7b1abda1 100755
--- a/t/t5605-clone-local.sh
+++ b/t/t5605-clone-local.sh
@@ -15,8 +15,12 @@ test_expect_success 'preparing origin repository' '
: >file && git add . && git commit -m1 &&
git clone --bare . a.git &&
git clone --bare . x &&
- test "$(cd a.git && git config --bool core.bare)" = true &&
- test "$(cd x && git config --bool core.bare)" = true &&
+ echo true >expect &&
+ git -C a.git config --bool core.bare >actual &&
+ test_cmp expect actual &&
+ echo true >expect &&
+ git -C x config --bool core.bare >actual &&
+ test_cmp expect actual &&
git bundle create b1.bundle --all &&
git bundle create b2.bundle main &&
mkdir dir &&
@@ -29,7 +33,9 @@ test_expect_success 'preparing origin repository' '
test_expect_success 'local clone without .git suffix' '
git clone -l -s a b &&
(cd b &&
- test "$(git config --bool core.bare)" = false &&
+ echo false >expect &&
+ git config --bool core.bare >actual &&
+ test_cmp expect actual &&
git fetch)
'
diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh
index 27f9f77638..5890319b97 100755
--- a/t/t5606-clone-options.sh
+++ b/t/t5606-clone-options.sh
@@ -120,6 +120,16 @@ test_expect_success 'prefers -c config over --template config' '
'
+test_expect_failure 'prefers --template config even for core.bare' '
+
+ template="$TRASH_DIRECTORY/template-with-bare-config" &&
+ mkdir "$template" &&
+ git config --file "$template/config" core.bare true &&
+ git clone "--template=$template" parent clone-bare-config &&
+ test "$(git -C clone-bare-config config --local core.bare)" = "true" &&
+ test_path_is_file clone-bare-config/HEAD
+'
+
test_expect_success 'prefers config "clone.defaultRemoteName" over default' '
test_config_global clone.defaultRemoteName from_config &&
diff --git a/t/t5700-protocol-v1.sh b/t/t5700-protocol-v1.sh
index 6c8d4c6cf1..a73b4d4ff6 100755
--- a/t/t5700-protocol-v1.sh
+++ b/t/t5700-protocol-v1.sh
@@ -244,15 +244,28 @@ test_expect_success 'push with ssh:// using protocol v1' '
grep "push< version 1" log
'
+test_expect_success 'clone propagates object-format from empty repo' '
+ test_when_finished "rm -fr src256 dst256" &&
+
+ echo sha256 >expect &&
+ git init --object-format=sha256 src256 &&
+ git clone --no-local src256 dst256 &&
+ git -C dst256 rev-parse --show-object-format >actual &&
+
+ test_cmp expect actual
+'
+
# Test protocol v1 with 'http://' transport
#
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
-test_expect_success 'create repo to be served by http:// transport' '
+test_expect_success 'create repos to be served by http:// transport' '
git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" config http.receivepack true &&
- test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one
+ test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one &&
+ git init --object-format=sha256 "$HTTPD_DOCUMENT_ROOT_PATH/sha256" &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/sha256" config http.receivepack true
'
test_expect_success 'clone with http:// using protocol v1' '
@@ -269,6 +282,20 @@ test_expect_success 'clone with http:// using protocol v1' '
grep "git< version 1" log
'
+test_expect_success 'clone with http:// using protocol v1 with empty SHA-256 repo' '
+ GIT_TRACE_PACKET=1 GIT_TRACE_CURL=1 git -c protocol.version=1 \
+ clone "$HTTPD_URL/smart/sha256" sha256 2>log &&
+
+ echo sha256 >expect &&
+ git -C sha256 rev-parse --show-object-format >actual &&
+ test_cmp expect actual &&
+
+ # Client requested to use protocol v1
+ grep "Git-Protocol: version=1" log &&
+ # Server responded using protocol v1
+ grep "git< version 1" log
+'
+
test_expect_success 'fetch with http:// using protocol v1' '
test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" two &&
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index e4db7513f4..6af5c2062f 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -269,6 +269,17 @@ test_expect_success 'clone propagates unborn HEAD from non-empty repo' '
grep "warning: remote HEAD refers to nonexistent ref" stderr
'
+test_expect_success 'clone propagates object-format from empty repo' '
+ test_when_finished "rm -fr src256 dst256" &&
+
+ echo sha256 >expect &&
+ git init --object-format=sha256 src256 &&
+ git clone src256 dst256 &&
+ git -C dst256 rev-parse --show-object-format >actual &&
+
+ test_cmp expect actual
+'
+
test_expect_success 'bare clone propagates unborn HEAD from non-empty repo' '
test_when_finished "rm -rf file_unborn_parent file_unborn_child.git" &&
@@ -728,6 +739,33 @@ test_expect_success 'file:// --negotiate-only with protocol v0' '
test_i18ngrep "negotiate-only requires protocol v2" err
'
+test_expect_success 'push with custom path does not request v2' '
+ rm -f env.trace &&
+ git -C client push \
+ --receive-pack="env >../env.trace; git-receive-pack" \
+ origin HEAD:refs/heads/custom-push-test &&
+ test_path_is_file env.trace &&
+ ! grep ^GIT_PROTOCOL env.trace
+'
+
+test_expect_success 'fetch with custom path does request v2' '
+ rm -f env.trace &&
+ git -C client fetch \
+ --upload-pack="env >../env.trace; git-upload-pack" \
+ origin HEAD &&
+ grep ^GIT_PROTOCOL=version=2 env.trace
+'
+
+test_expect_success 'archive with custom path does not request v2' '
+ rm -f env.trace &&
+ git -C client archive \
+ --exec="env >../env.trace; git-upload-archive" \
+ --remote=origin \
+ HEAD >/dev/null &&
+ test_path_is_file env.trace &&
+ ! grep ^GIT_PROTOCOL env.trace
+'
+
# Test protocol v2 with 'http://' transport
#
. "$TEST_DIRECTORY"/lib-httpd.sh
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 41d0ca00b1..573eb97a0f 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -493,7 +493,7 @@ test_expect_success 'empty email' '
test_tick &&
C=$(GIT_AUTHOR_EMAIL= git commit-tree HEAD^{tree} </dev/null) &&
A=$(git show --pretty=format:%an,%ae,%ad%n -s $C) &&
- verbose test "$A" = "$GIT_AUTHOR_NAME,,Thu Apr 7 15:14:13 2005 -0700"
+ test "$A" = "$GIT_AUTHOR_NAME,,Thu Apr 7 15:14:13 2005 -0700"
'
test_expect_success 'del LF before empty (1)' '
diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh
index aabf590dda..67d523d405 100755
--- a/t/t6018-rev-list-glob.sh
+++ b/t/t6018-rev-list-glob.sh
@@ -187,7 +187,7 @@ test_expect_success 'rev-parse --exclude=ref with --remotes=glob' '
compare rev-parse "--exclude=upstream/x --remotes=upstream/*" "upstream/one upstream/two"
'
-for section in receive uploadpack
+for section in fetch receive uploadpack
do
test_expect_success "rev-parse --exclude-hidden=$section with --all" '
compare "-c transfer.hideRefs=refs/remotes/ rev-parse" "--branches --tags" "--exclude-hidden=$section --all"
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index 7d40994991..dface8bcfe 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -10,6 +10,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-bundle.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
for cmd in create verify list-heads unbundle
do
@@ -606,4 +607,42 @@ test_expect_success 'verify catches unreachable, broken prerequisites' '
)
'
+test_expect_success 'bundle progress includes write phase' '
+ GIT_PROGRESS_DELAY=0 \
+ git bundle create --progress out.bundle --all 2>err &&
+ grep 'Writing' err
+'
+
+test_expect_success TTY 'create --quiet disables all bundle progress' '
+ test_terminal env GIT_PROGRESS_DELAY=0 \
+ git bundle create --quiet out.bundle --all 2>err &&
+ test_must_be_empty err
+'
+
+test_expect_success 'read bundle over stdin' '
+ git bundle create some.bundle HEAD &&
+
+ git bundle verify - <some.bundle 2>err &&
+ grep "<stdin> is okay" err &&
+
+ git bundle list-heads some.bundle >expect &&
+ git bundle list-heads - <some.bundle >actual &&
+ test_cmp expect actual &&
+
+ git bundle unbundle some.bundle >expect &&
+ git bundle unbundle - <some.bundle >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'send a bundle to standard output' '
+ git bundle create - --all HEAD >bundle-one &&
+ mkdir -p down &&
+ git -C down bundle create - --all HEAD >bundle-two &&
+ git bundle verify bundle-one &&
+ git bundle verify bundle-two &&
+ git ls-remote bundle-one >expect &&
+ git ls-remote bundle-two >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6021-rev-list-exclude-hidden.sh b/t/t6021-rev-list-exclude-hidden.sh
index 11c50b7c0d..1a9d37e638 100755
--- a/t/t6021-rev-list-exclude-hidden.sh
+++ b/t/t6021-rev-list-exclude-hidden.sh
@@ -22,7 +22,7 @@ test_expect_success 'invalid section' '
test_cmp expected err
'
-for section in receive uploadpack
+for section in fetch receive uploadpack
do
test_expect_success "$section: passed multiple times" '
echo "fatal: --exclude-hidden= passed more than once" >expected &&
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 3ba4fdf615..fb01bd6abc 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -122,6 +122,29 @@ test_expect_success 'bisect start without -- takes unknown arg as pathspec' '
grep bar ".git/BISECT_NAMES"
'
+test_expect_success 'bisect reset: back in a branch checked out also elsewhere' '
+ echo "shared" > branch.expect &&
+ test_bisect_reset() {
+ git -C $1 bisect start &&
+ git -C $1 bisect good $HASH1 &&
+ git -C $1 bisect bad $HASH3 &&
+ git -C $1 bisect reset &&
+ git -C $1 branch --show-current > branch.output &&
+ cmp branch.expect branch.output
+ } &&
+ test_when_finished "
+ git worktree remove wt1 &&
+ git worktree remove wt2 &&
+ git branch -d shared
+ " &&
+ git worktree add wt1 -b shared &&
+ git worktree add wt2 -f shared &&
+ # we test in both worktrees to ensure that works
+ # as expected with "first" and "next" worktrees
+ test_bisect_reset wt1 &&
+ test_bisect_reset wt2
+'
+
test_expect_success 'bisect reset: back in the main branch' '
git bisect reset &&
echo "* main" > branch.expect &&
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 9350b5fd2c..98e36e7369 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -130,4 +130,150 @@ test_expect_success 'traverse unexpected non-blob tag (seen)' '
test_i18ngrep "not a blob" output
'
+test_expect_success !SANITIZE_LEAK 'setup unexpected non-tag tag' '
+ test_when_finished "git tag -d tag-commit tag-tag" &&
+
+ git tag -a -m"my tagged commit" tag-commit $commit &&
+ tag_commit=$(git rev-parse tag-commit) &&
+ git tag -a -m"my tagged tag" tag-tag tag-commit &&
+ tag_tag=$(git rev-parse tag-tag) &&
+
+ git cat-file tag tag-tag >good-tag-tag &&
+ git cat-file tag tag-commit >good-commit-tag &&
+
+ sed -e "s/$tag_commit/$commit/" <good-tag-tag >broken-tag-tag-commit &&
+ sed -e "s/$tag_commit/$tree/" <good-tag-tag >broken-tag-tag-tree &&
+ sed -e "s/$tag_commit/$blob/" <good-tag-tag >broken-tag-tag-blob &&
+
+ sed -e "s/$commit/$tag_commit/" <good-commit-tag >broken-commit-tag-tag &&
+ sed -e "s/$commit/$tree/" <good-commit-tag >broken-commit-tag-tree &&
+ sed -e "s/$commit/$blob/" <good-commit-tag >broken-commit-tag-blob &&
+
+ tag_tag_commit=$(git hash-object -w -t tag broken-tag-tag-commit) &&
+ tag_tag_tree=$(git hash-object -w -t tag broken-tag-tag-tree) &&
+ tag_tag_blob=$(git hash-object -w -t tag broken-tag-tag-blob) &&
+
+ git update-ref refs/tags/tag_tag_commit $tag_tag_commit &&
+ git update-ref refs/tags/tag_tag_tree $tag_tag_tree &&
+ git update-ref refs/tags/tag_tag_blob $tag_tag_blob &&
+
+ commit_tag_tag=$(git hash-object -w -t tag broken-commit-tag-tag) &&
+ commit_tag_tree=$(git hash-object -w -t tag broken-commit-tag-tree) &&
+ commit_tag_blob=$(git hash-object -w -t tag broken-commit-tag-blob) &&
+
+ git update-ref refs/tags/commit_tag_tag $commit_tag_tag &&
+ git update-ref refs/tags/commit_tag_tree $commit_tag_tree &&
+ git update-ref refs/tags/commit_tag_blob $commit_tag_blob
+'
+
+test_expect_success !SANITIZE_LEAK 'traverse unexpected incorrectly typed tag (to commit & tag)' '
+ test_must_fail git rev-list --objects $tag_tag_commit 2>err &&
+ cat >expect <<-EOF &&
+ error: object $commit is a commit, not a tag
+ fatal: bad object $commit
+ EOF
+ test_cmp expect err &&
+
+ test_must_fail git rev-list --objects $commit_tag_tag 2>err &&
+ cat >expect <<-EOF &&
+ error: object $tag_commit is a tag, not a commit
+ fatal: bad object $tag_commit
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success !SANITIZE_LEAK 'traverse unexpected incorrectly typed tag (to tree)' '
+ test_must_fail git rev-list --objects $tag_tag_tree 2>err &&
+ cat >expect <<-EOF &&
+ error: object $tree is a tree, not a tag
+ fatal: bad object $tree
+ EOF
+ test_cmp expect err &&
+
+ test_must_fail git rev-list --objects $commit_tag_tree 2>err &&
+ cat >expect <<-EOF &&
+ error: object $tree is a tree, not a commit
+ fatal: bad object $tree
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success !SANITIZE_LEAK 'traverse unexpected incorrectly typed tag (to blob)' '
+ test_must_fail git rev-list --objects $tag_tag_blob 2>err &&
+ cat >expect <<-EOF &&
+ error: object $blob is a blob, not a tag
+ fatal: bad object $blob
+ EOF
+ test_cmp expect err &&
+
+ test_must_fail git rev-list --objects $commit_tag_blob 2>err &&
+ cat >expect <<-EOF &&
+ error: object $blob is a blob, not a commit
+ fatal: bad object $blob
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success !SANITIZE_LEAK 'traverse unexpected non-tag tag (tree seen to blob)' '
+ test_must_fail git rev-list --objects $tree $commit_tag_blob 2>err &&
+ cat >expect <<-EOF &&
+ error: object $blob is a blob, not a commit
+ fatal: bad object $blob
+ EOF
+ test_cmp expect err &&
+
+ test_must_fail git rev-list --objects $tree $tag_tag_blob 2>err &&
+ cat >expect <<-EOF &&
+ error: object $blob is a blob, not a tag
+ fatal: bad object $blob
+ EOF
+ test_cmp expect err
+'
+
+
+test_expect_success !SANITIZE_LEAK 'traverse unexpected objects with for-each-ref' '
+ cat >expect <<-EOF &&
+ error: bad tag pointer to $tree in $tag_tag_tree
+ fatal: parse_object_buffer failed on $tag_tag_tree for refs/tags/tag_tag_tree
+ EOF
+ test_must_fail git for-each-ref --format="%(*objectname)" 2>actual &&
+ test_cmp expect actual
+'
+
+>fsck-object-isa
+test_expect_success 'setup: unexpected objects with fsck' '
+ test_must_fail git fsck 2>err &&
+ sed -n -e "/^error: object .* is a .*, not a .*$/ {
+ s/^error: object \([0-9a-f]*\) is a \([a-z]*\), not a [a-z]*$/\\1 \\2/;
+ p;
+ }" <err >fsck-object-isa
+'
+
+while read oid type
+do
+ test_expect_success "fsck knows unexpected object $oid is $type" '
+ git cat-file -t $oid >expect &&
+ echo $type >actual &&
+ test_cmp expect actual
+ '
+done <fsck-object-isa
+
+test_expect_success !SANITIZE_LEAK 'traverse unexpected non-tag tag (blob seen to blob)' '
+ test_must_fail git rev-list --objects $blob $commit_tag_blob 2>err &&
+ cat >expected <<-EOF &&
+ error: object $blob is a blob, not a commit
+ error: bad tag pointer to $blob in $commit_tag_blob
+ fatal: bad object $commit_tag_blob
+ EOF
+ test_cmp expected err &&
+
+ test_must_fail git rev-list --objects $blob $tag_tag_blob 2>err &&
+ cat >expected <<-EOF &&
+ error: object $blob is a blob, not a tag
+ error: bad tag pointer to $blob in $tag_tag_blob
+ fatal: bad object $tag_tag_blob
+ EOF
+ test_cmp expected err
+'
+
test_done
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index c466fd989f..7e8d578522 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -448,6 +448,41 @@ test_expect_success 'exercise glob patterns with prefixes' '
'
cat >expected <<\EOF
+refs/tags/bar
+refs/tags/baz
+refs/tags/testtag
+EOF
+
+test_expect_success 'exercise patterns with prefix exclusions' '
+ for tag in foo/one foo/two foo/three bar baz
+ do
+ git tag "$tag" || return 1
+ done &&
+ test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
+ git for-each-ref --format="%(refname)" \
+ refs/tags/ --exclude=refs/tags/foo >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+refs/tags/bar
+refs/tags/baz
+refs/tags/foo/one
+refs/tags/testtag
+EOF
+
+test_expect_success 'exercise patterns with pattern exclusions' '
+ for tag in foo/one foo/two foo/three bar baz
+ do
+ git tag "$tag" || return 1
+ done &&
+ test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
+ git for-each-ref --format="%(refname)" \
+ refs/tags/ --exclude="refs/tags/foo/t*" >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
'refs/heads/main'
'refs/remotes/origin/main'
'refs/tags/testtag'
@@ -1374,6 +1409,14 @@ test_expect_success 'for-each-ref --ignore-case ignores case' '
test_cmp expect actual
'
+test_expect_success 'for-each-ref --omit-empty works' '
+ git for-each-ref --format="%(refname)" >actual &&
+ test_line_count -gt 1 actual &&
+ git for-each-ref --format="%(if:equals=refs/heads/main)%(refname)%(then)%(refname)%(end)" --omit-empty >actual &&
+ echo refs/heads/main >expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' '
# name refs numerically to avoid case-insensitive filesystem conflicts
nr=0 &&
@@ -1464,4 +1507,54 @@ sig_crlf="$(printf "%s" "$sig" | append_cr; echo dummy)"
sig_crlf=${sig_crlf%dummy}
test_atom refs/tags/fake-sig-crlf contents:signature "$sig_crlf"
+test_expect_success 'git for-each-ref --stdin: empty' '
+ >in &&
+ git for-each-ref --format="%(refname)" --stdin <in >actual &&
+ git for-each-ref --format="%(refname)" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git for-each-ref --stdin: fails if extra args' '
+ >in &&
+ test_must_fail git for-each-ref --format="%(refname)" \
+ --stdin refs/heads/extra <in 2>err &&
+ grep "unknown arguments supplied with --stdin" err
+'
+
+test_expect_success 'git for-each-ref --stdin: matches' '
+ cat >in <<-EOF &&
+ refs/tags/multi*
+ refs/heads/amb*
+ EOF
+
+ cat >expect <<-EOF &&
+ refs/heads/ambiguous
+ refs/tags/multi-ref1-100000-user1
+ refs/tags/multi-ref1-100000-user2
+ refs/tags/multi-ref1-200000-user1
+ refs/tags/multi-ref1-200000-user2
+ refs/tags/multi-ref2-100000-user1
+ refs/tags/multi-ref2-100000-user2
+ refs/tags/multi-ref2-200000-user1
+ refs/tags/multi-ref2-200000-user2
+ refs/tags/multiline
+ EOF
+
+ git for-each-ref --format="%(refname)" --stdin <in >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git for-each-ref with non-existing refs' '
+ cat >in <<-EOF &&
+ refs/heads/this-ref-does-not-exist
+ refs/tags/bogus
+ EOF
+
+ git for-each-ref --format="%(refname)" --stdin <in >actual &&
+ test_must_be_empty actual &&
+
+ xargs git for-each-ref --format="%(refname)" <in >actual &&
+ test_must_be_empty actual
+'
+
test_done
diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh
index bfda1f46ad..2667dd13fe 100755
--- a/t/t6301-for-each-ref-errors.sh
+++ b/t/t6301-for-each-ref-errors.sh
@@ -54,4 +54,18 @@ test_expect_success 'Missing objects are reported correctly' '
test_must_be_empty brief-err
'
+test_expect_success 'ahead-behind requires an argument' '
+ test_must_fail git for-each-ref \
+ --format="%(ahead-behind)" 2>err &&
+ echo "fatal: expected format: %(ahead-behind:<committish>)" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'missing ahead-behind base' '
+ test_must_fail git for-each-ref \
+ --format="%(ahead-behind:refs/heads/missing)" 2>err &&
+ echo "fatal: failed to find '\''refs/heads/missing'\''" >expect &&
+ test_cmp expect err
+'
+
test_done
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index d9acb63951..69509d0c11 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -210,90 +210,95 @@ prepare_cruft_history () {
git reset HEAD^^
}
-assert_cruft_packs () {
- find .git/objects/pack -name "*.mtimes" >mtimes &&
- sed -e 's/\.mtimes$/\.pack/g' mtimes >packs &&
-
- test_file_not_empty packs &&
- while read pack
- do
- test_path_is_file "$pack" || return 1
- done <packs
-}
-
assert_no_cruft_packs () {
find .git/objects/pack -name "*.mtimes" >mtimes &&
test_must_be_empty mtimes
}
-test_expect_success 'gc --cruft generates a cruft pack' '
- test_when_finished "rm -fr crufts" &&
- git init crufts &&
+for argv in \
+ "gc" \
+ "-c gc.cruftPacks=true gc" \
+ "-c gc.cruftPacks=false gc --cruft"
+do
+ test_expect_success "git $argv generates a cruft pack" '
+ test_when_finished "rm -fr repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ prepare_cruft_history &&
+ git $argv &&
+
+ find .git/objects/pack -name "*.mtimes" >mtimes &&
+ sed -e 's/\.mtimes$/\.pack/g' mtimes >packs &&
+
+ test_file_not_empty packs &&
+ while read pack
+ do
+ test_path_is_file "$pack" || return 1
+ done <packs
+ )
+ '
+done
+
+for argv in \
+ "gc --no-cruft" \
+ "-c gc.cruftPacks=false gc" \
+ "-c gc.cruftPacks=true gc --no-cruft"
+do
+ test_expect_success "git $argv does not generate a cruft pack" '
+ test_when_finished "rm -fr repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ prepare_cruft_history &&
+ git $argv &&
+
+ assert_no_cruft_packs
+ )
+ '
+done
+
+test_expect_success '--keep-largest-pack ignores cruft packs' '
+ test_when_finished "rm -fr repo" &&
+ git init repo &&
(
- cd crufts &&
+ cd repo &&
+ # Generate a pack for reachable objects (of which there
+ # are 3), and one for unreachable objects (of which
+ # there are 6).
prepare_cruft_history &&
git gc --cruft &&
- assert_cruft_packs
- )
-'
-
-test_expect_success 'gc.cruftPacks=true generates a cruft pack' '
- test_when_finished "rm -fr crufts" &&
- git init crufts &&
- (
- cd crufts &&
-
- prepare_cruft_history &&
- git -c gc.cruftPacks=true gc &&
- assert_cruft_packs
- )
-'
-
-test_expect_success 'feature.experimental=true generates a cruft pack' '
- git init crufts &&
- test_when_finished "rm -fr crufts" &&
- (
- cd crufts &&
- prepare_cruft_history &&
- git -c feature.experimental=true gc &&
- assert_cruft_packs
- )
-'
+ mtimes="$(find .git/objects/pack -type f -name "pack-*.mtimes")" &&
+ sz="$(test_file_size "${mtimes%.mtimes}.pack")" &&
-test_expect_success 'feature.experimental=false allows explicit cruft packs' '
- git init crufts &&
- test_when_finished "rm -fr crufts" &&
- (
- cd crufts &&
+ # Ensure that the cruft pack gets removed (due to
+ # `--prune=now`) despite it being the largest pack.
+ git -c gc.bigPackThreshold=$sz gc --cruft --prune=now &&
- prepare_cruft_history &&
- git -c gc.cruftPacks=true -c feature.experimental=false gc &&
- assert_cruft_packs
+ assert_no_cruft_packs
)
'
-test_expect_success 'feature.experimental=true can be overridden' '
- git init crufts &&
- test_when_finished "rm -fr crufts" &&
+test_expect_success 'gc.bigPackThreshold ignores cruft packs' '
+ test_when_finished "rm -fr repo" &&
+ git init repo &&
(
- cd crufts &&
+ cd repo &&
+ # Generate a pack for reachable objects (of which there
+ # are 3), and one for unreachable objects (of which
+ # there are 6).
prepare_cruft_history &&
- git -c feature.expiremental=true -c gc.cruftPacks=false gc &&
- assert_no_cruft_packs
- )
-'
+ git gc --cruft &&
-test_expect_success 'feature.experimental=false avoids cruft packs by default' '
- git init crufts &&
- test_when_finished "rm -fr crufts" &&
- (
- cd crufts &&
+ # Ensure that the cruft pack gets removed (due to
+ # `--prune=now`) despite it being the largest pack.
+ git gc --cruft --prune=now --keep-largest-pack &&
- prepare_cruft_history &&
- git -c feature.experimental=false gc &&
assert_no_cruft_packs
)
'
diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh
index 3968b47ed5..4521508b83 100755
--- a/t/t6501-freshen-objects.sh
+++ b/t/t6501-freshen-objects.sh
@@ -101,7 +101,7 @@ do
'
test_expect_success "simultaneous gc ($title)" '
- git gc --prune=12.hours.ago
+ git gc --no-cruft --prune=12.hours.ago
'
test_expect_success "finish writing out commit ($title)" '
@@ -131,7 +131,7 @@ do
'
test_expect_success "simultaneous gc ($title)" '
- git gc --prune=12.hours.ago
+ git gc --no-cruft --prune=12.hours.ago
'
# tree should have been refreshed by write-tree
@@ -151,8 +151,8 @@ test_expect_success 'do not complain about existing broken links (commit)' '
some message
EOF
commit=$(git hash-object -t commit -w broken-commit) &&
- git gc -q 2>stderr &&
- verbose git cat-file -e $commit &&
+ git gc --no-cruft -q 2>stderr &&
+ git cat-file -e $commit &&
test_must_be_empty stderr
'
@@ -161,7 +161,7 @@ test_expect_success 'do not complain about existing broken links (tree)' '
100644 blob $(test_oid 003) foo
EOF
tree=$(git mktree --missing <broken-tree) &&
- git gc -q 2>stderr &&
+ git gc --no-cruft -q 2>stderr &&
git cat-file -e $tree &&
test_must_be_empty stderr
'
@@ -176,7 +176,7 @@ test_expect_success 'do not complain about existing broken links (tag)' '
this is a broken tag
EOF
tag=$(git hash-object -t tag -w broken-tag) &&
- git gc -q 2>stderr &&
+ git gc --no-cruft -q 2>stderr &&
git cat-file -e $tag &&
test_must_be_empty stderr
'
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
index 338a9c46a2..b330945f49 100755
--- a/t/t6600-test-reach.sh
+++ b/t/t6600-test-reach.sh
@@ -443,4 +443,173 @@ test_expect_success 'get_reachable_subset:none' '
test_all_modes get_reachable_subset
'
+test_expect_success 'for-each-ref ahead-behind:linear' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-1-3
+ refs/heads/commit-1-5
+ refs/heads/commit-1-8
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1 0 8
+ refs/heads/commit-1-3 0 6
+ refs/heads/commit-1-5 0 4
+ refs/heads/commit-1-8 0 1
+ EOF
+ run_all_modes git for-each-ref \
+ --format="%(refname) %(ahead-behind:commit-1-9)" --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:all' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-2-4
+ refs/heads/commit-4-2
+ refs/heads/commit-4-4
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1 0 24
+ refs/heads/commit-2-4 0 17
+ refs/heads/commit-4-2 0 17
+ refs/heads/commit-4-4 0 9
+ EOF
+ run_all_modes git for-each-ref \
+ --format="%(refname) %(ahead-behind:commit-5-5)" --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:some' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-5-3
+ refs/heads/commit-4-8
+ refs/heads/commit-9-9
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1 0 53
+ refs/heads/commit-4-8 8 30
+ refs/heads/commit-5-3 0 39
+ refs/heads/commit-9-9 27 0
+ EOF
+ run_all_modes git for-each-ref \
+ --format="%(refname) %(ahead-behind:commit-9-6)" --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:some, multibase' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-5-3
+ refs/heads/commit-7-8
+ refs/heads/commit-4-8
+ refs/heads/commit-9-9
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1 0 53 0 53
+ refs/heads/commit-4-8 8 30 0 22
+ refs/heads/commit-5-3 0 39 0 39
+ refs/heads/commit-7-8 14 12 8 6
+ refs/heads/commit-9-9 27 0 27 0
+ EOF
+ run_all_modes git for-each-ref \
+ --format="%(refname) %(ahead-behind:commit-9-6) %(ahead-behind:commit-6-9)" \
+ --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:none' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-7-5
+ refs/heads/commit-4-8
+ refs/heads/commit-9-9
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-4-8 16 16
+ refs/heads/commit-7-5 7 4
+ refs/heads/commit-9-9 49 0
+ EOF
+ run_all_modes git for-each-ref \
+ --format="%(refname) %(ahead-behind:commit-8-4)" --stdin
+'
+
+test_expect_success 'for-each-ref merged:linear' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-1-3
+ refs/heads/commit-1-5
+ refs/heads/commit-1-8
+ refs/heads/commit-2-1
+ refs/heads/commit-5-1
+ refs/heads/commit-9-1
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-1-3
+ refs/heads/commit-1-5
+ refs/heads/commit-1-8
+ EOF
+ run_all_modes git for-each-ref --merged=commit-1-9 \
+ --format="%(refname)" --stdin
+'
+
+test_expect_success 'for-each-ref merged:all' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-2-4
+ refs/heads/commit-4-2
+ refs/heads/commit-4-4
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-2-4
+ refs/heads/commit-4-2
+ refs/heads/commit-4-4
+ EOF
+ run_all_modes git for-each-ref --merged=commit-5-5 \
+ --format="%(refname)" --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:some' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-5-3
+ refs/heads/commit-4-8
+ refs/heads/commit-9-9
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-5-3
+ EOF
+ run_all_modes git for-each-ref --merged=commit-9-6 \
+ --format="%(refname)" --stdin
+'
+
+test_expect_success 'for-each-ref merged:some, multibase' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-5-3
+ refs/heads/commit-7-8
+ refs/heads/commit-4-8
+ refs/heads/commit-9-9
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-4-8
+ refs/heads/commit-5-3
+ EOF
+ run_all_modes git for-each-ref \
+ --merged=commit-5-8 \
+ --merged=commit-8-5 \
+ --format="%(refname)" \
+ --stdin
+'
+
+test_expect_success 'for-each-ref merged:none' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-7-5
+ refs/heads/commit-4-8
+ refs/heads/commit-9-9
+ EOF
+ >expect &&
+ run_all_modes git for-each-ref --merged=commit-8-4 \
+ --format="%(refname)" --stdin
+'
+
test_done
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index d72cef8826..898a920532 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -4,6 +4,10 @@ test_description='git mv in subdirs'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff-data.sh
+index_at_path () {
+ git ls-files --format='%(objectmode) %(objectname) %(stage)' "$@"
+}
+
test_expect_success 'mv -f refreshes updated index entry' '
echo test >bar &&
git add bar &&
@@ -187,7 +191,8 @@ test_expect_success "Michael Cassar's test case" '
git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf &&
T=$(git write-tree) &&
- git ls-tree -r $T | verbose grep partA/outline.txt
+ git ls-tree -r $T >out &&
+ grep partA/outline.txt out
'
rm -fr papers partA path?
@@ -260,12 +265,12 @@ test_expect_success 'git mv should not change sha1 of moved cache entry' '
git init &&
echo 1 >dirty &&
git add dirty &&
- entry="$(git ls-files --stage dirty | cut -f 1)" &&
+ entry="$(index_at_path dirty)" &&
git mv dirty dirty2 &&
- test "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" &&
+ test "$entry" = "$(index_at_path dirty2)" &&
echo 2 >dirty2 &&
git mv dirty2 dirty &&
- test "$entry" = "$(git ls-files --stage dirty | cut -f 1)"
+ test "$entry" = "$(index_at_path dirty)"
'
rm -f dirty dirty2
@@ -342,7 +347,7 @@ test_expect_success 'git mv cannot move a submodule in a file' '
'
test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
git rm .gitmodules &&
(
cd sub &&
@@ -353,7 +358,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and no .gitm
mkdir mod &&
git mv sub mod/sub &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
@@ -363,7 +368,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu
rm -rf mod &&
git reset --hard &&
git submodule update &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
(
cd sub &&
rm -f .git &&
@@ -373,7 +378,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu
mkdir mod &&
git mv sub mod/sub &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
echo mod/sub >expected &&
git config -f .gitmodules submodule.sub.path >actual &&
@@ -386,11 +391,11 @@ test_expect_success 'git mv moves a submodule with gitfile' '
rm -rf mod &&
git reset --hard &&
git submodule update &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
mkdir mod &&
git -C mod mv ../sub/ . &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
echo mod/sub >expected &&
git config -f .gitmodules submodule.sub.path >actual &&
@@ -404,12 +409,12 @@ test_expect_success 'mv does not complain when no .gitmodules file is found' '
git reset --hard &&
git submodule update &&
git rm .gitmodules &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
mkdir mod &&
git mv sub mod/sub 2>actual.err &&
test_must_be_empty actual.err &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
@@ -420,7 +425,7 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta
git reset --hard &&
git submodule update &&
git config -f .gitmodules foo.bar true &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
mkdir mod &&
test_must_fail git mv sub mod/sub 2>actual.err &&
test_file_not_empty actual.err &&
@@ -430,7 +435,7 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta
git mv sub mod/sub 2>actual.err &&
test_must_be_empty actual.err &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
@@ -442,13 +447,13 @@ test_expect_success 'mv issues a warning when section is not found in .gitmodule
git submodule update &&
git config -f .gitmodules --remove-section submodule.sub &&
git add .gitmodules &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
mkdir mod &&
git mv sub mod/sub 2>actual.err &&
test_cmp expect.err actual.err &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 9aa1660651..e689db4292 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -792,6 +792,34 @@ test_expect_success 'annotations for blobs are empty' '
test_cmp expect actual
'
+# Run this before doing any signing, so the test has the same results
+# regardless of the GPG prereq.
+test_expect_success 'git tag --format with ahead-behind' '
+ test_when_finished git reset --hard tag-one-line &&
+ git commit --allow-empty -m "left" &&
+ git tag -a -m left tag-left &&
+ git reset --hard HEAD~1 &&
+ git commit --allow-empty -m "right" &&
+ git tag -a -m left tag-right &&
+
+ # Use " !" at the end to demonstrate whitespace
+ # around empty ahead-behind token for tag-blob.
+ cat >expect <<-EOF &&
+ refs/tags/tag-blob !
+ refs/tags/tag-left 1 1 !
+ refs/tags/tag-lines 0 1 !
+ refs/tags/tag-one-line 0 1 !
+ refs/tags/tag-right 0 0 !
+ refs/tags/tag-zero-lines 0 1 !
+ EOF
+ git tag -l --format="%(refname) %(ahead-behind:HEAD) !" >actual 2>err &&
+ grep "refs/tags/tag" actual >actual.focus &&
+ test_cmp expect actual.focus &&
+
+ # Error reported for tags that point to non-commits.
+ grep "error: object [0-9a-f]* is a blob, not a commit" err
+'
+
# trying to verify annotated non-signed tags:
test_expect_success GPG \
@@ -1843,6 +1871,23 @@ test_expect_success 'invalid sort parameter in configuratoin' '
test_must_fail git tag -l "foo*"
'
+test_expect_success 'version sort handles empty value for versionsort.{prereleaseSuffix,suffix}' '
+ cp .git/config .git/config.orig &&
+ test_when_finished mv .git/config.orig .git/config &&
+
+ cat >>.git/config <<-\EOF &&
+ [versionsort]
+ prereleaseSuffix
+ suffix
+ EOF
+ cat >expect <<-\EOF &&
+ error: missing value for '\''versionsort.suffix'\''
+ error: missing value for '\''versionsort.prereleasesuffix'\''
+ EOF
+ git tag -l --sort=version:refname 2>actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'version sort with prerelease reordering' '
test_config versionsort.prereleaseSuffix -rc &&
git tag foo1.6-rc1 &&
@@ -2001,6 +2046,22 @@ test_expect_success '--format should list tags as per format given' '
test_cmp expect actual
'
+test_expect_success '--format --omit-empty works' '
+ cat >expect <<-\EOF &&
+ refname : refs/tags/v1.0
+
+ refname : refs/tags/v1.1.3
+ EOF
+ git tag -l --format="%(if:notequals=refs/tags/v1.0.1)%(refname)%(then)refname : %(refname)%(end)" "v1*" >actual &&
+ test_cmp expect actual &&
+ cat >expect <<-\EOF &&
+ refname : refs/tags/v1.0
+ refname : refs/tags/v1.1.3
+ EOF
+ git tag -l --omit-empty --format="%(if:notequals=refs/tags/v1.0.1)%(refname)%(then)refname : %(refname)%(end)" "v1*" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'git tag -l with --format="%(rest)" must fail' '
test_must_fail git tag -l --format="%(rest)" "v1*"
'
@@ -2127,4 +2188,23 @@ test_expect_success 'Does --[no-]contains stop at commits? Yes!' '
test_cmp expected actual
'
+test_expect_success 'If tag is created then tag message file is unlinked' '
+ test_when_finished "git tag -d foo" &&
+ write_script fakeeditor <<-\EOF &&
+ echo Message >.git/TAG_EDITMSG
+ EOF
+ GIT_EDITOR=./fakeeditor git tag -a foo &&
+ test_path_is_missing .git/TAG_EDITMSG
+'
+
+test_expect_success 'If tag cannot be created then tag message file is not unlinked' '
+ test_when_finished "git tag -d foo/bar && rm .git/TAG_EDITMSG" &&
+ write_script fakeeditor <<-\EOF &&
+ echo Message >.git/TAG_EDITMSG
+ EOF
+ git tag foo/bar &&
+ test_must_fail env GIT_EDITOR=./fakeeditor git tag -a foo &&
+ test_path_exists .git/TAG_EDITMSG
+'
+
test_done
diff --git a/t/t7031-verify-tag-signed-ssh.sh b/t/t7031-verify-tag-signed-ssh.sh
index 36eb86a4b1..20913b3713 100755
--- a/t/t7031-verify-tag-signed-ssh.sh
+++ b/t/t7031-verify-tag-signed-ssh.sh
@@ -200,4 +200,14 @@ test_expect_success GPGSSH 'verifying a forged tag with --format should fail sil
test_must_be_empty actual-forged
'
+test_expect_success GPGSSH 'rev-list --format=%G' '
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+ git rev-list -1 --format="%G? %H" sixth-signed >actual &&
+ cat >expect <<-EOF &&
+ commit $(git rev-parse sixth-signed^0)
+ G $(git rev-parse sixth-signed^0)
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index c975eb54d2..0ef7b78457 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -120,7 +120,7 @@ test_expect_success 'git clean with relative prefix' '
grep part3 |
sed -n -e "s|^Would remove ||p"
) &&
- verbose test "$would_clean" = ../src/part3.c
+ test "$would_clean" = ../src/part3.c
'
test_expect_success 'git clean with absolute path' '
@@ -133,7 +133,7 @@ test_expect_success 'git clean with absolute path' '
grep part3 |
sed -n -e "s|^Would remove ||p"
) &&
- verbose test "$would_clean" = ../src/part3.c
+ test "$would_clean" = ../src/part3.c
'
test_expect_success 'git clean with out of work tree relative path' '
diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh
index b19792b326..2b3c363078 100755
--- a/t/t7402-submodule-rebase.sh
+++ b/t/t7402-submodule-rebase.sh
@@ -56,12 +56,15 @@ chmod a+x fake-editor.sh
test_expect_success 'interactive rebase with a dirty submodule' '
- test submodule = $(git diff --name-only) &&
+ echo submodule >expect &&
+ git diff --name-only >actual &&
+ test_cmp expect actual &&
HEAD=$(git rev-parse HEAD) &&
GIT_EDITOR="\"$(pwd)/fake-editor.sh\"" EDITOR_TEXT="pick $HEAD" \
git rebase -i HEAD^ &&
- test submodule = $(git diff --name-only)
-
+ echo submodule >expect &&
+ git diff --name-only >actual &&
+ test_cmp expect actual
'
test_expect_success 'rebase with dirty file and submodule fails' '
@@ -83,11 +86,19 @@ test_expect_success 'stash with a dirty submodule' '
CURRENT=$(cd submodule && git rev-parse HEAD) &&
git stash &&
test new != $(cat file) &&
- test submodule = $(git diff --name-only) &&
- test $CURRENT = $(cd submodule && git rev-parse HEAD) &&
+ echo submodule >expect &&
+ git diff --name-only >actual &&
+ test_cmp expect actual &&
+
+ echo "$CURRENT" >expect &&
+ git -C submodule rev-parse HEAD >actual &&
+ test_cmp expect actual &&
+
git stash apply &&
test new = $(cat file) &&
- test $CURRENT = $(cd submodule && git rev-parse HEAD)
+ echo "$CURRENT" >expect &&
+ git -C submodule rev-parse HEAD >actual &&
+ test_cmp expect actual
'
diff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh
index 7cdc263764..887d181b72 100755
--- a/t/t7413-submodule-is-active.sh
+++ b/t/t7413-submodule-is-active.sh
@@ -51,6 +51,22 @@ test_expect_success 'is-active works with submodule.<name>.active config' '
test-tool -C super submodule is-active sub1
'
+test_expect_success 'is-active handles submodule.active config missing a value' '
+ cp super/.git/config super/.git/config.orig &&
+ test_when_finished mv super/.git/config.orig super/.git/config &&
+
+ cat >>super/.git/config <<-\EOF &&
+ [submodule]
+ active
+ EOF
+
+ cat >expect <<-\EOF &&
+ error: missing value for '\''submodule.active'\''
+ EOF
+ test-tool -C super submodule is-active sub1 2>actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'is-active works with basic submodule.active config' '
test_when_finished "git -C super config submodule.sub1.URL ../sub" &&
test_when_finished "git -C super config --unset-all submodule.active" &&
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index 07ca46fb0d..d1255228d5 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -102,7 +102,9 @@ test_expect_success 'setup: commit-msg hook that always fails' '
'
commit_msg_is () {
- test "$(git log --pretty=format:%s%b -1)" = "$1"
+ printf "%s" "$1" >expect &&
+ git log --pretty=format:%s%b -1 >actual &&
+ test_cmp expect actual
}
test_expect_success 'with failing hook' '
diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
index d050091345..7da64e4c4c 100755
--- a/t/t7506-status-submodule.sh
+++ b/t/t7506-status-submodule.sh
@@ -412,4 +412,29 @@ test_expect_success 'status with added file in nested submodule (short)' '
EOF
'
+test_expect_success 'status in superproject with submodules respects parallel settings' '
+ test_when_finished "rm -f trace.out" &&
+ (
+ GIT_TRACE=$(pwd)/trace.out git status &&
+ grep "1 tasks" trace.out &&
+ >trace.out &&
+
+ git config submodule.diffJobs 8 &&
+ GIT_TRACE=$(pwd)/trace.out git status &&
+ grep "8 tasks" trace.out &&
+ >trace.out &&
+
+ GIT_TRACE=$(pwd)/trace.out git -c submodule.diffJobs=0 status &&
+ grep "preparing to run up to [0-9]* tasks" trace.out &&
+ ! grep "up to 0 tasks" trace.out &&
+ >trace.out
+ )
+'
+
+test_expect_success 'status in superproject with submodules (parallel)' '
+ git -C super status --porcelain >output &&
+ git -C super -c submodule.diffJobs=8 status --porcelain >output_parallel &&
+ diff output output_parallel
+'
+
test_done
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index 48f86cb367..ccbc416402 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -221,84 +221,91 @@ test_expect_success GPG 'amending already signed commit' '
test_expect_success GPG 'show good signature with custom format' '
cat >expect <<-\EOF &&
G
+ ultimate
13B6F51ECDDE430D
C O Mitter <committer@example.com>
73D758744BE721698EC54E8713B6F51ECDDE430D
73D758744BE721698EC54E8713B6F51ECDDE430D
EOF
- git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show bad signature with custom format' '
cat >expect <<-\EOF &&
B
+ undefined
13B6F51ECDDE430D
C O Mitter <committer@example.com>
EOF
- git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show untrusted signature with custom format' '
cat >expect <<-\EOF &&
U
+ undefined
65A0EEA02E30CAD7
Eris Discordia <discord@example.net>
F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
D4BE22311AD3131E5EDA29A461092E85B7227189
EOF
- git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show untrusted signature with undefined trust level' '
cat >expect <<-\EOF &&
+ U
undefined
65A0EEA02E30CAD7
Eris Discordia <discord@example.net>
F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
D4BE22311AD3131E5EDA29A461092E85B7227189
EOF
- git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show untrusted signature with ultimate trust level' '
cat >expect <<-\EOF &&
+ G
ultimate
13B6F51ECDDE430D
C O Mitter <committer@example.com>
73D758744BE721698EC54E8713B6F51ECDDE430D
73D758744BE721698EC54E8713B6F51ECDDE430D
EOF
- git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show unknown signature with custom format' '
cat >expect <<-\EOF &&
E
+ undefined
65A0EEA02E30CAD7
EOF
- GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
+ GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show lack of signature with custom format' '
cat >expect <<-\EOF &&
N
+ undefined
EOF
- git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual &&
test_cmp expect actual
'
diff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh
index f2ce14e907..2d38a16480 100755
--- a/t/t7516-commit-races.sh
+++ b/t/t7516-commit-races.sh
@@ -10,7 +10,8 @@ test_expect_success 'race to create orphan commit' '
test_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&
git show -s --pretty=format:%s >subject &&
grep hare subject &&
- test -z "$(git show -s --pretty=format:%P)"
+ git show -s --pretty=format:%P >out &&
+ test_must_be_empty out
'
test_expect_success 'race to create non-orphan commit' '
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
index 4c0327b2bb..0c241d6c14 100755
--- a/t/t7527-builtin-fsmonitor.sh
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -995,4 +995,41 @@ test_expect_success !UNICODE_COMPOSITION_SENSITIVE 'Unicode nfc/nfd' '
grep -E "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace
'
+test_expect_success 'split-index and FSMonitor work well together' '
+ git init split-index &&
+ test_when_finished "git -C \"$PWD/split-index\" \
+ fsmonitor--daemon stop" &&
+ (
+ cd split-index &&
+ git config core.splitIndex true &&
+ # force split-index in most cases
+ git config splitIndex.maxPercentChange 99 &&
+ git config core.fsmonitor true &&
+
+ # Create the following commit topology:
+ #
+ # * merge three
+ # |\
+ # | * three
+ # * | merge two
+ # |\|
+ # | * two
+ # * | one
+ # |/
+ # * 5a5efd7 initial
+
+ test_commit initial &&
+ test_commit two &&
+ test_commit three &&
+ git reset --hard initial &&
+ test_commit one &&
+ test_tick &&
+ git merge two &&
+ test_tick &&
+ git merge three &&
+
+ git rebase --force-rebase -r one
+ )
+'
+
test_done
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
index 7b957022f1..22b3a85b3e 100755
--- a/t/t7610-mergetool.sh
+++ b/t/t7610-mergetool.sh
@@ -860,4 +860,42 @@ test_expect_success 'mergetool hideResolved' '
git commit -m "test resolved with mergetool"
'
+test_expect_success 'mergetool with guiDefault' '
+ test_config merge.guitool myguitool &&
+ test_config mergetool.myguitool.cmd "(printf \"gui \" && cat \"\$REMOTE\") >\"\$MERGED\"" &&
+ test_config mergetool.myguitool.trustExitCode true &&
+ test_when_finished "git reset --hard" &&
+ git checkout -b test$test_count branch1 &&
+ git submodule update -N &&
+ test_must_fail git merge main &&
+
+ test_config mergetool.guiDefault auto &&
+ DISPLAY=SOMETHING && export DISPLAY &&
+ yes "" | git mergetool both &&
+ yes "" | git mergetool file1 file1 &&
+
+ DISPLAY= && export DISPLAY &&
+ yes "" | git mergetool file2 "spaced name" &&
+
+ test_config mergetool.guiDefault true &&
+ yes "" | git mergetool subdir/file3 &&
+
+ yes "d" | git mergetool file11 &&
+ yes "d" | git mergetool file12 &&
+ yes "l" | git mergetool submod &&
+
+ echo "gui main updated" >expect &&
+ test_cmp expect file1 &&
+
+ echo "main new" >expect &&
+ test_cmp expect file2 &&
+
+ echo "gui main new sub" >expect &&
+ test_cmp expect subdir/file3 &&
+
+ echo "branch1 submodule" >expect &&
+ test_cmp expect submod/bar &&
+ git commit -m "branch1 resolved with mergetool"
+'
+
test_done
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 4aabe98139..faa739eeb9 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -106,6 +106,23 @@ test_expect_success SYMLINKS '--local keeps packs when alternate is objectdir '
test_cmp expect actual
'
+test_expect_success '--local disables writing bitmaps when connected to alternate ODB' '
+ test_when_finished "rm -rf shared member" &&
+
+ git init shared &&
+ git clone --shared shared member &&
+ (
+ cd member &&
+ test_commit "object" &&
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adl --write-bitmap-index 2>err &&
+ cat >expect <<-EOF &&
+ warning: disabling bitmap writing, as some objects are not being packed
+ EOF
+ test_cmp expect err &&
+ test_path_is_missing .git/objects/pack-*.bitmap
+ )
+'
+
test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' '
mkdir alt_objects/pack &&
mv .git/objects/pack/* alt_objects/pack &&
diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh
index ebb267855f..ba428c18a8 100755
--- a/t/t7701-repack-unpack-unreachable.sh
+++ b/t/t7701-repack-unpack-unreachable.sh
@@ -113,6 +113,37 @@ test_expect_success 'do not bother loosening old objects' '
test_must_fail git cat-file -p $obj2
'
+test_expect_success 'gc.recentObjectsHook' '
+ obj1=$(echo one | git hash-object -w --stdin) &&
+ obj2=$(echo two | git hash-object -w --stdin) &&
+ obj3=$(echo three | git hash-object -w --stdin) &&
+ pack1=$(echo $obj1 | git pack-objects .git/objects/pack/pack) &&
+ pack2=$(echo $obj2 | git pack-objects .git/objects/pack/pack) &&
+ pack3=$(echo $obj3 | git pack-objects .git/objects/pack/pack) &&
+ git prune-packed &&
+
+ git cat-file -p $obj1 &&
+ git cat-file -p $obj2 &&
+ git cat-file -p $obj3 &&
+
+ git tag -a -m tag obj2-tag $obj2 &&
+ obj2_tag="$(git rev-parse obj2-tag)" &&
+
+ write_script precious-objects <<-EOF &&
+ echo $obj2_tag
+ EOF
+ git config gc.recentObjectsHook ./precious-objects &&
+
+ test-tool chmtime =-86400 .git/objects/pack/pack-$pack2.pack &&
+ test-tool chmtime =-86400 .git/objects/pack/pack-$pack3.pack &&
+ git repack -A -d --unpack-unreachable=1.hour.ago &&
+
+ git cat-file -p $obj1 &&
+ git cat-file -p $obj2 &&
+ git cat-file -p $obj2_tag &&
+ test_must_fail git cat-file -p $obj3
+'
+
test_expect_success 'keep packed objects found only in index' '
echo my-unique-content >file &&
git add file &&
diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh
index 8821fbd2dd..00f28fb558 100755
--- a/t/t7703-repack-geometric.sh
+++ b/t/t7703-repack-geometric.sh
@@ -10,6 +10,12 @@ objdir=.git/objects
packdir=$objdir/pack
midx=$objdir/pack/multi-pack-index
+packed_objects () {
+ git show-index <"$1" >tmp-object-list &&
+ cut -d' ' -f2 tmp-object-list | sort &&
+ rm tmp-object-list
+ }
+
test_expect_success '--geometric with no packs' '
git init geometric &&
test_when_finished "rm -fr geometric" &&
@@ -281,4 +287,162 @@ test_expect_success '--geometric with pack.packSizeLimit' '
)
'
+test_expect_success '--geometric --write-midx with packfiles in main and alternate ODB' '
+ test_when_finished "rm -fr shared member" &&
+
+ # Create a shared repository that will serve as the alternate object
+ # database for the member linked to it. It has got some objects on its
+ # own that are packed into a single packfile.
+ git init shared &&
+ test_commit -C shared common-object &&
+ git -C shared repack -ad &&
+
+ # We create member so that its alternates file points to the shared
+ # repository. We then create a commit in it so that git-repack(1) has
+ # something to repack.
+ # of the shared object database.
+ git clone --shared shared member &&
+ test_commit -C member unique-object &&
+ git -C member repack --geometric=2 --write-midx 2>err &&
+ test_must_be_empty err &&
+
+ # We should see that a new packfile was generated.
+ find shared/.git/objects/pack -type f -name "*.pack" >packs &&
+ test_line_count = 1 packs &&
+
+ # We should also see a multi-pack-index. This multi-pack-index should
+ # never refer to any packfiles in the alternate object database.
+ test_path_is_file member/.git/objects/pack/multi-pack-index &&
+ test-tool read-midx member/.git/objects >packs.midx &&
+ grep "^pack-.*\.idx$" packs.midx | sort >actual &&
+ basename member/.git/objects/pack/pack-*.idx >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--geometric --with-midx with no local objects' '
+ test_when_finished "rm -fr shared member" &&
+
+ # Create a repository with a single packfile that acts as alternate
+ # object database.
+ git init shared &&
+ test_commit -C shared "shared-objects" &&
+ git -C shared repack -ad &&
+
+ # Create a second repository linked to the first one and perform a
+ # geometric repack on it.
+ git clone --shared shared member &&
+ git -C member repack --geometric 2 --write-midx 2>err &&
+ test_must_be_empty err &&
+
+ # Assert that we wrote neither a new packfile nor a multi-pack-index.
+ # We should not have a packfile because the single packfile in the
+ # alternate object database does not invalidate the geometric sequence.
+ # And we should not have a multi-pack-index because these only index
+ # local packfiles, and there are none.
+ test_dir_is_empty member/$packdir
+'
+
+test_expect_success '--geometric with same pack in main and alternate ODB' '
+ test_when_finished "rm -fr shared member" &&
+
+ # Create a repository with a single packfile that acts as alternate
+ # object database.
+ git init shared &&
+ test_commit -C shared "shared-objects" &&
+ git -C shared repack -ad &&
+
+ # We create the member repository as an exact copy so that it has the
+ # same packfile.
+ cp -r shared member &&
+ test-tool path-utils real_path shared/.git/objects >member/.git/objects/info/alternates &&
+ find shared/.git/objects -type f >expected-files &&
+
+ # Verify that we can repack objects as expected without observing any
+ # error. Having the same packfile in both ODBs used to cause an error
+ # in git-pack-objects(1).
+ git -C member repack --geometric 2 2>err &&
+ test_must_be_empty err &&
+ # Nothing should have changed.
+ find shared/.git/objects -type f >actual-files &&
+ test_cmp expected-files actual-files
+'
+
+test_expect_success '--geometric -l with non-intact geometric sequence across ODBs' '
+ test_when_finished "rm -fr shared member" &&
+
+ git init shared &&
+ test_commit_bulk -C shared --start=1 1 &&
+
+ git clone --shared shared member &&
+ test_commit_bulk -C member --start=2 1 &&
+
+ # Verify that our assumptions actually hold: both generated packfiles
+ # should have three objects and should be non-equal.
+ packed_objects shared/.git/objects/pack/pack-*.idx >shared-objects &&
+ packed_objects member/.git/objects/pack/pack-*.idx >member-objects &&
+ test_line_count = 3 shared-objects &&
+ test_line_count = 3 member-objects &&
+ ! test_cmp shared-objects member-objects &&
+
+ # Perform the geometric repack. With `-l`, we should only see the local
+ # packfile and thus arrive at the conclusion that the geometric
+ # sequence is intact. We thus expect no changes.
+ #
+ # Note that we are tweaking mtimes of the packfiles so that we can
+ # verify they did not change. This is done in order to detect the case
+ # where we do repack objects, but the resulting packfile is the same.
+ test-tool chmtime --verbose =0 member/.git/objects/pack/* >expected-member-packs &&
+ git -C member repack --geometric=2 -l -d &&
+ test-tool chmtime --verbose member/.git/objects/pack/* >actual-member-packs &&
+ test_cmp expected-member-packs actual-member-packs &&
+
+ {
+ packed_objects shared/.git/objects/pack/pack-*.idx &&
+ packed_objects member/.git/objects/pack/pack-*.idx
+ } | sort >expected-objects &&
+
+ # On the other hand, when doing a non-local geometric repack we should
+ # see both packfiles and thus repack them. We expect that the shared
+ # object database was not changed.
+ test-tool chmtime --verbose =0 shared/.git/objects/pack/* >expected-shared-packs &&
+ git -C member repack --geometric=2 -d &&
+ test-tool chmtime --verbose shared/.git/objects/pack/* >actual-shared-packs &&
+ test_cmp expected-shared-packs actual-shared-packs &&
+
+ # Furthermore, we expect that the member repository now has a single
+ # packfile that contains the combined shared and non-shared objects.
+ ls member/.git/objects/pack/pack-*.idx >actual &&
+ test_line_count = 1 actual &&
+ packed_objects member/.git/objects/pack/pack-*.idx >actual-objects &&
+ test_line_count = 6 actual-objects &&
+ test_cmp expected-objects actual-objects
+'
+
+test_expect_success '--geometric -l disables writing bitmaps with non-local packfiles' '
+ test_when_finished "rm -fr shared member" &&
+
+ git init shared &&
+ test_commit_bulk -C shared --start=1 1 &&
+
+ git clone --shared shared member &&
+ test_commit_bulk -C member --start=2 1 &&
+
+ # When performing a geometric repack with `-l` while connected to an
+ # alternate object database that has a packfile we do not have full
+ # coverage of objects. As a result, we expect that writing the bitmap
+ # will be disabled.
+ git -C member repack -l --geometric=2 --write-midx --write-bitmap-index 2>err &&
+ cat >expect <<-EOF &&
+ warning: disabling bitmap writing, as some objects are not being packed
+ EOF
+ test_cmp expect err &&
+ test_path_is_missing member/.git/objects/pack/multi-pack-index-*.bitmap &&
+
+ # On the other hand, when we repack without `-l`, we should see that
+ # the bitmap gets created.
+ git -C member repack --geometric=2 --write-midx --write-bitmap-index 2>err &&
+ test_must_be_empty err &&
+ test_path_is_file member/.git/objects/pack/multi-pack-index-*.bitmap
+'
+
test_done
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 24297e26ca..59d3847bf8 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -155,6 +155,58 @@ test_expect_success 'difftool honors --gui' '
test_cmp expect actual
'
+test_expect_success 'difftool with guiDefault auto selects gui tool when there is DISPLAY' '
+ difftool_test_setup &&
+ test_config merge.tool bogus-tool &&
+ test_config diff.tool bogus-tool &&
+ test_config diff.guitool test-tool &&
+ test_config difftool.guiDefault auto &&
+ DISPLAY=SOMETHING && export DISPLAY &&
+
+ echo branch >expect &&
+ git difftool --no-prompt branch >actual &&
+ test_cmp expect actual
+'
+test_expect_success 'difftool with guiDefault auto selects regular tool when no DISPLAY' '
+ difftool_test_setup &&
+ test_config diff.guitool bogus-tool &&
+ test_config diff.tool test-tool &&
+ test_config difftool.guiDefault Auto &&
+ DISPLAY= && export DISPLAY &&
+
+ echo branch >expect &&
+ git difftool --no-prompt branch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'difftool with guiDefault true selects gui tool' '
+ difftool_test_setup &&
+ test_config diff.tool bogus-tool &&
+ test_config diff.guitool test-tool &&
+ test_config difftool.guiDefault true &&
+
+ DISPLAY= && export DISPLAY &&
+ echo branch >expect &&
+ git difftool --no-prompt branch >actual &&
+ test_cmp expect actual &&
+
+ DISPLAY=Something && export DISPLAY &&
+ echo branch >expect &&
+ git difftool --no-prompt branch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'difftool --no-gui trumps config guiDefault' '
+ difftool_test_setup &&
+ test_config diff.guitool bogus-tool &&
+ test_config diff.tool test-tool &&
+ test_config difftool.guiDefault true &&
+
+ echo branch >expect &&
+ git difftool --no-prompt --no-gui branch >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'difftool --gui last setting wins' '
difftool_test_setup &&
: >expect &&
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 8eded6ab27..39d6d713ec 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -1001,7 +1001,9 @@ test_expect_success 'log --committer does not search in timestamp' '
test_expect_success 'grep with CE_VALID file' '
git update-index --assume-unchanged t/t &&
rm t/t &&
- test "$(git grep test)" = "t/t:test" &&
+ echo "t/t:test" >expect &&
+ git grep test >actual &&
+ test_cmp expect actual &&
git update-index --no-assume-unchanged t/t &&
git checkout t/t
'
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 823331e44a..487e326b3f 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -524,6 +524,44 @@ test_expect_success 'register and unregister' '
git maintenance unregister --config-file ./other --force
'
+test_expect_success 'register with no value for maintenance.repo' '
+ cp .git/config .git/config.orig &&
+ test_when_finished mv .git/config.orig .git/config &&
+
+ cat >>.git/config <<-\EOF &&
+ [maintenance]
+ repo
+ EOF
+ cat >expect <<-\EOF &&
+ error: missing value for '\''maintenance.repo'\''
+ EOF
+ git maintenance register 2>actual &&
+ test_cmp expect actual &&
+ git config maintenance.repo
+'
+
+test_expect_success 'unregister with no value for maintenance.repo' '
+ cp .git/config .git/config.orig &&
+ test_when_finished mv .git/config.orig .git/config &&
+
+ cat >>.git/config <<-\EOF &&
+ [maintenance]
+ repo
+ EOF
+ cat >expect <<-\EOF &&
+ error: missing value for '\''maintenance.repo'\''
+ EOF
+ test_expect_code 128 git maintenance unregister 2>actual.raw &&
+ grep ^error actual.raw >actual &&
+ test_cmp expect actual &&
+ git config maintenance.repo &&
+
+ git maintenance unregister --force 2>actual.raw &&
+ grep ^error actual.raw >actual &&
+ test_cmp expect actual &&
+ git config maintenance.repo
+'
+
test_expect_success !MINGW 'register and unregister with regex metacharacters' '
META="a+b*c" &&
git init "$META" &&
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 323952a572..48bf0af2ee 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -12,7 +12,7 @@ PREREQ="PERL"
replace_variable_fields () {
sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \
- -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
+ -e "s/^\(Message-ID:\).*/\1 MESSAGE-ID-STRING/" \
-e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/"
}
@@ -47,7 +47,7 @@ clean_fake_sendmail () {
test_expect_success $PREREQ 'Extract patches' '
patches=$(git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1) &&
- threaded_patches=$(git format-patch -o threaded -s --in-reply-to="format" HEAD^1)
+ threaded_patches=$(git format-patch -o threaded --thread=shallow -s --in-reply-to="format" HEAD^1)
'
# Test no confirm early to ensure remaining tests will not hang
@@ -225,7 +225,7 @@ Cc: cc@example.com,
two@example.com
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
In-Reply-To: <unique-message-id@example.com>
References: <unique-message-id@example.com>
@@ -374,13 +374,16 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email'
)
'
-test_expect_success $PREREQ 'setup tocmd and cccmd scripts' '
+test_expect_success $PREREQ 'setup cmd scripts' '
write_script tocmd-sed <<-\EOF &&
sed -n -e "s/^tocmd--//p" "$1"
EOF
- write_script cccmd-sed <<-\EOF
+ write_script cccmd-sed <<-\EOF &&
sed -n -e "s/^cccmd--//p" "$1"
EOF
+ write_script headercmd-sed <<-\EOF
+ sed -n -e "s/^headercmd--//p" "$1"
+ EOF
'
test_expect_success $PREREQ 'tocmd works' '
@@ -410,6 +413,70 @@ test_expect_success $PREREQ 'cccmd works' '
grep "^ cccmd@example.com" msgtxt1
'
+test_expect_success $PREREQ 'headercmd works' '
+ clean_fake_sendmail &&
+ cp $patches headercmd.patch &&
+ echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --header-cmd=./headercmd-sed \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ headercmd.patch \
+ &&
+ grep "^X-Debbugs-CC: dummy@example.com" msgtxt1
+'
+
+test_expect_success $PREREQ '--no-header-cmd works' '
+ clean_fake_sendmail &&
+ cp $patches headercmd.patch &&
+ echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --header-cmd=./headercmd-sed \
+ --no-header-cmd \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ headercmd.patch \
+ &&
+ ! grep "^X-Debbugs-CC: dummy@example.com" msgtxt1
+'
+
+test_expect_success $PREREQ 'multiline fields are correctly unfolded' '
+ clean_fake_sendmail &&
+ cp $patches headercmd.patch &&
+ write_script headercmd-multiline <<-\EOF &&
+ echo "X-Debbugs-CC: someone@example.com
+FoldedField: This is a tale
+ best told using
+ multiple lines."
+ EOF
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --header-cmd=./headercmd-multiline \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ headercmd.patch &&
+ grep "^FoldedField: This is a tale best told using multiple lines.$" msgtxt1
+'
+
+# Blank lines in the middle of the output of a command are invalid.
+test_expect_success $PREREQ 'malform output reported on blank lines in command output' '
+ clean_fake_sendmail &&
+ cp $patches headercmd.patch &&
+ write_script headercmd-malformed-output <<-\EOF &&
+ echo "X-Debbugs-CC: someone@example.com
+
+SomeOtherField: someone-else@example.com"
+ EOF
+ ! git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --header-cmd=./headercmd-malformed-output \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ headercmd.patch
+'
+
test_expect_success $PREREQ 'reject long lines' '
z8=zzzzzzzz &&
z64=$z8$z8$z8$z8$z8$z8$z8$z8 &&
@@ -540,7 +607,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@@ -559,12 +626,50 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
'
+test_expect_success $PREREQ "--validate hook supports header argument" '
+ write_script my-hooks/sendemail-validate <<-\EOF &&
+ if test "$#" -ge 2
+ then
+ grep "X-test-header: v1.0" "$2"
+ else
+ echo "No header arg passed"
+ exit 1
+ fi
+ EOF
+ test_config core.hooksPath "my-hooks" &&
+ rm -fr outdir &&
+ git format-patch \
+ --add-header="X-test-header: v1.0" \
+ -n HEAD^1 -o outdir &&
+ git send-email \
+ --dry-run \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --validate \
+ outdir/000?-*.patch
+'
+
+test_expect_success $PREREQ 'clear message-id before parsing a new message' '
+ clean_fake_sendmail &&
+ echo true | write_script my-hooks/sendemail-validate &&
+ test_config core.hooksPath my-hooks &&
+ GIT_SEND_EMAIL_NOTTY=1 \
+ git send-email --validate --to=recipient@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches $threaded_patches &&
+ id0=$(grep "^Message-ID: " $threaded_patches) &&
+ id1=$(grep "^Message-ID: " msgtxt1) &&
+ id2=$(grep "^Message-ID: " msgtxt2) &&
+ test "z$id0" = "z$id2" &&
+ test "z$id1" != "z$id2"
+'
+
for enc in 7bit 8bit quoted-printable base64
do
test_expect_success $PREREQ "--transfer-encoding=$enc produces correct header" '
@@ -617,7 +722,7 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' '
sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual &&
test_cmp expect actual &&
# Second and subsequent messages are replies to the first one
- sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect &&
+ sed -n -e "s/^Message-ID: *\(.*\)/\1/p" msgtxt1 >expect &&
sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual &&
test_cmp expect actual &&
sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual &&
@@ -637,10 +742,10 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
2>errors &&
sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual &&
test_cmp expect actual &&
- sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect &&
+ sed -n -e "s/^Message-ID: *\(.*\)/\1/p" msgtxt1 >expect &&
sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual &&
test_cmp expect actual &&
- sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt2 >expect &&
+ sed -n -e "s/^Message-ID: *\(.*\)/\1/p" msgtxt2 >expect &&
sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual &&
test_cmp expect actual
'
@@ -713,7 +818,7 @@ Cc: cc@example.com,
two@example.com
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
@@ -759,7 +864,7 @@ Cc: A <author@example.com>,
two@example.com
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
@@ -796,7 +901,7 @@ Cc: A <author@example.com>,
C O Mitter <committer@example.com>
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
@@ -824,7 +929,7 @@ From: Example <from@example.com>
To: to@example.com
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
@@ -860,7 +965,7 @@ Cc: A <author@example.com>,
cc-cmd@example.com
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
@@ -893,7 +998,7 @@ Cc: A <author@example.com>,
two@example.com
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
@@ -926,7 +1031,7 @@ Cc: A <author@example.com>,
two@example.com
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
@@ -963,7 +1068,7 @@ Cc: A <author@example.com>,
C O Mitter <committer@example.com>
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
@@ -993,7 +1098,7 @@ Cc: A <author@example.com>,
C O Mitter <committer@example.com>
Subject: [PATCH 1/1] Second.
Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
X-Mailer: X-MAILER-STRING
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
@@ -1478,7 +1583,7 @@ test_expect_success $PREREQ 'To headers from files reset each patch' '
test_expect_success $PREREQ 'setup expect' '
cat >email-using-8bit <<\EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
-Message-Id: <bogus-message-id@example.com>
+Message-ID: <bogus-message-id@example.com>
From: author@example.com
Date: Sat, 12 Jun 2010 15:53:58 +0200
Subject: subject goes here
@@ -1564,7 +1669,7 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
test_expect_success $PREREQ 'setup expect' '
cat >email-using-8bit <<-\EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
- Message-Id: <bogus-message-id@example.com>
+ Message-ID: <bogus-message-id@example.com>
From: author@example.com
Date: Sat, 12 Jun 2010 15:53:58 +0200
Subject: Dieser Betreff enthält auch einen Umlaut!
@@ -1593,7 +1698,7 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
test_expect_success $PREREQ 'setup expect' '
cat >email-using-8bit <<-\EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
- Message-Id: <bogus-message-id@example.com>
+ Message-ID: <bogus-message-id@example.com>
From: A U Thor <author@example.com>
Date: Sat, 12 Jun 2010 15:53:58 +0200
Content-Type: text/plain; charset=UTF-8
@@ -1674,7 +1779,7 @@ test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' '
test_expect_success $PREREQ 'setup expect' '
cat >email-using-qp <<-\EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
- Message-Id: <bogus-message-id@example.com>
+ Message-ID: <bogus-message-id@example.com>
From: A U Thor <author@example.com>
Date: Sat, 12 Jun 2010 15:53:58 +0200
MIME-Version: 1.0
@@ -1700,7 +1805,7 @@ test_expect_success $PREREQ 'convert from quoted-printable to base64' '
test_expect_success $PREREQ 'setup expect' "
tr -d '\\015' | tr '%' '\\015' >email-using-crlf <<EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
-Message-Id: <bogus-message-id@example.com>
+Message-ID: <bogus-message-id@example.com>
From: A U Thor <author@example.com>
Date: Sat, 12 Jun 2010 15:53:58 +0200
Content-Type: text/plain; charset=UTF-8
@@ -2326,6 +2431,37 @@ test_expect_success $PREREQ 'invoke hook' '
)
'
+expected_file_counter_output () {
+ total=$1
+ count=0
+ while test $count -ne $total
+ do
+ count=$((count + 1)) &&
+ echo "$count/$total" || return
+ done
+}
+
+test_expect_success $PREREQ '--validate hook allows counting of messages' '
+ test_when_finished "rm -rf my-hooks.log" &&
+ test_config core.hooksPath "my-hooks" &&
+ mkdir -p my-hooks &&
+
+ write_script my-hooks/sendemail-validate <<-\EOF &&
+ num=$GIT_SENDEMAIL_FILE_COUNTER &&
+ tot=$GIT_SENDEMAIL_FILE_TOTAL &&
+ echo "$num/$tot" >>my-hooks.log || exit 1
+ EOF
+
+ >my-hooks.log &&
+ expected_file_counter_output 4 >expect &&
+ git send-email \
+ --from="Example <from@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --validate -3 --cover-letter --force &&
+ test_cmp expect my-hooks.log
+'
+
test_expect_success $PREREQ 'test that send-email works outside a repo' '
nongit git send-email \
--from="Example <nobody@example.com>" \
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index aa55b41b9a..ac237a1f90 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -388,9 +388,7 @@ test_expect_success 'B: accept branch name "TEMP_TAG"' '
INPUT_END
- test_when_finished "rm -f .git/TEMP_TAG
- git gc
- git prune" &&
+ test_when_finished "rm -f .git/TEMP_TAG && git gc --prune=now" &&
git fast-import <input &&
test $(test-tool ref-store main resolve-ref TEMP_TAG 0 | cut -f1 -d " " ) != "$ZERO_OID" &&
test $(git rev-parse main) = $(git rev-parse TEMP_TAG^)
@@ -406,8 +404,7 @@ test_expect_success 'B: accept empty committer' '
INPUT_END
test_when_finished "git update-ref -d refs/heads/empty-committer-1
- git gc
- git prune" &&
+ git gc --prune=now" &&
git fast-import <input &&
out=$(git fsck) &&
echo "$out" &&
@@ -452,8 +449,7 @@ test_expect_success 'B: accept and fixup committer with no name' '
INPUT_END
test_when_finished "git update-ref -d refs/heads/empty-committer-2
- git gc
- git prune" &&
+ git gc --prune=now" &&
git fast-import <input &&
out=$(git fsck) &&
echo "$out" &&
@@ -1778,8 +1774,7 @@ test_expect_success 'P: verbatim SHA gitlinks' '
INPUT_END
git branch -D sub &&
- git gc &&
- git prune &&
+ git gc --prune=now &&
git fast-import <input &&
test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1)
'
diff --git a/t/t9304-fast-import-marks.sh b/t/t9304-fast-import-marks.sh
index a98ef032d9..410a871c52 100755
--- a/t/t9304-fast-import-marks.sh
+++ b/t/t9304-fast-import-marks.sh
@@ -49,4 +49,33 @@ test_expect_success 'import with submodule mapping' '
test_cmp expect actual
'
+test_expect_success 'paths adjusted for relative subdir' '
+ git init deep-dst &&
+ mkdir deep-dst/subdir &&
+ >deep-dst/subdir/empty-marks &&
+ git -C deep-dst/subdir fast-import \
+ --rewrite-submodules-from=sub:../../from \
+ --rewrite-submodules-to=sub:../../to \
+ --import-marks=empty-marks \
+ --export-marks=exported-marks \
+ --export-pack-edges=exported-edges \
+ <dump &&
+ # we do not bother checking resulting repo; we just care that nothing
+ # complained about failing to open files for reading, and that files
+ # for writing were created in the expected spot
+ test_path_is_file deep-dst/subdir/exported-marks &&
+ test_path_is_file deep-dst/subdir/exported-edges
+'
+
+test_expect_success 'relative marks are not affected by subdir' '
+ git init deep-relative &&
+ mkdir deep-relative/subdir &&
+ git -C deep-relative/subdir fast-import \
+ --relative-marks \
+ --export-marks=exported-marks \
+ <dump &&
+ test_path_is_missing deep-relative/subdir/exported-marks &&
+ test_path_is_file deep-relative/.git/info/fast-import/exported-marks
+'
+
test_done
diff --git a/t/t9351-fast-export-anonymize.sh b/t/t9351-fast-export-anonymize.sh
index 77047e250d..156a647484 100755
--- a/t/t9351-fast-export-anonymize.sh
+++ b/t/t9351-fast-export-anonymize.sh
@@ -25,6 +25,7 @@ test_expect_success 'setup simple repo' '
test_expect_success 'export anonymized stream' '
git fast-export --anonymize --all \
--anonymize-map=retain-me \
+ --anonymize-map=xyzzy:should-not-appear \
--anonymize-map=xyzzy:custom-name \
--anonymize-map=other \
>stream
@@ -41,6 +42,7 @@ test_expect_success 'stream omits path names' '
test_expect_success 'stream contains user-specified names' '
grep retain-me stream &&
+ ! grep should-not-appear stream &&
grep custom-name stream
'
diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh
index dc88d0e064..a4b3cb9492 100755
--- a/t/t9800-git-p4-basic.sh
+++ b/t/t9800-git-p4-basic.sh
@@ -330,7 +330,7 @@ test_expect_success 'initial import time from top change time' '
test_when_finished cleanup_git &&
(
cd "$git" &&
- gittime=$(git show -s --raw --pretty=format:%at HEAD) &&
+ gittime=$(git show -s --pretty=format:%at HEAD) &&
echo $p4time $gittime &&
test $p4time = $gittime
)
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index d6c0478d98..09af98a7dc 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -405,40 +405,40 @@ test_expect_success '__gitdir - remote as argument' '
test_expect_success '__git_dequote - plain unquoted word' '
__git_dequote unquoted-word &&
- verbose test unquoted-word = "$dequoted_word"
+ test unquoted-word = "$dequoted_word"
'
# input: b\a\c\k\'\\\"s\l\a\s\h\es
# expected: back'\"slashes
test_expect_success '__git_dequote - backslash escaped' '
__git_dequote "b\a\c\k\\'\''\\\\\\\"s\l\a\s\h\es" &&
- verbose test "back'\''\\\"slashes" = "$dequoted_word"
+ test "back'\''\\\"slashes" = "$dequoted_word"
'
# input: sin'gle\' '"quo'ted
# expected: single\ "quoted
test_expect_success '__git_dequote - single quoted' '
__git_dequote "'"sin'gle\\\\' '\\\"quo'ted"'" &&
- verbose test '\''single\ "quoted'\'' = "$dequoted_word"
+ test '\''single\ "quoted'\'' = "$dequoted_word"
'
# input: dou"ble\\" "\"\quot"ed
# expected: double\ "\quoted
test_expect_success '__git_dequote - double quoted' '
__git_dequote '\''dou"ble\\" "\"\quot"ed'\'' &&
- verbose test '\''double\ "\quoted'\'' = "$dequoted_word"
+ test '\''double\ "\quoted'\'' = "$dequoted_word"
'
# input: 'open single quote
test_expect_success '__git_dequote - open single quote' '
__git_dequote "'\''open single quote" &&
- verbose test "open single quote" = "$dequoted_word"
+ test "open single quote" = "$dequoted_word"
'
# input: "open double quote
test_expect_success '__git_dequote - open double quote' '
__git_dequote "\"open double quote" &&
- verbose test "open double quote" = "$dequoted_word"
+ test "open double quote" = "$dequoted_word"
'
@@ -616,7 +616,7 @@ test_expect_success '__git_is_configured_remote' '
test_when_finished "git remote remove remote_2" &&
git remote add remote_2 git://remote_2 &&
(
- verbose __git_is_configured_remote remote_2 &&
+ __git_is_configured_remote remote_2 &&
test_must_fail __git_is_configured_remote non-existent
)
'
@@ -2527,6 +2527,8 @@ test_expect_success 'git config - variable name' '
log.date Z
log.decorate Z
log.diffMerges Z
+ log.diffMergesHide Z
+ log.diffMerges-m-imply-p Z
EOF
'
@@ -2555,6 +2557,8 @@ test_expect_success 'git -c - variable name' '
log.date=Z
log.decorate=Z
log.diffMerges=Z
+ log.diffMergesHide=Z
+ log.diffMerges-m-imply-p=Z
EOF
'
@@ -2577,6 +2581,8 @@ test_expect_success 'git clone --config= - variable name' '
log.date=Z
log.decorate=Z
log.diffMerges=Z
+ log.diffMergesHide=Z
+ log.diffMerges-m-imply-p=Z
EOF
'
@@ -2596,30 +2602,30 @@ test_expect_success 'options with value' '
test_expect_success 'sourcing the completion script clears cached commands' '
(
__git_compute_all_commands &&
- verbose test -n "$__git_all_commands" &&
+ test -n "$__git_all_commands" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- verbose test -z "$__git_all_commands"
+ test -z "$__git_all_commands"
)
'
test_expect_success 'sourcing the completion script clears cached merge strategies' '
(
__git_compute_merge_strategies &&
- verbose test -n "$__git_merge_strategies" &&
+ test -n "$__git_merge_strategies" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- verbose test -z "$__git_merge_strategies"
+ test -z "$__git_merge_strategies"
)
'
test_expect_success 'sourcing the completion script clears cached --options' '
(
__gitcomp_builtin checkout &&
- verbose test -n "$__gitcomp_builtin_checkout" &&
+ test -n "$__gitcomp_builtin_checkout" &&
__gitcomp_builtin notes_edit &&
- verbose test -n "$__gitcomp_builtin_notes_edit" &&
+ test -n "$__gitcomp_builtin_notes_edit" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- verbose test -z "$__gitcomp_builtin_checkout" &&
- verbose test -z "$__gitcomp_builtin_notes_edit"
+ test -z "$__gitcomp_builtin_checkout" &&
+ test -z "$__gitcomp_builtin_notes_edit"
)
'
diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh
index d459fae655..d667dda654 100755
--- a/t/t9903-bash-prompt.sh
+++ b/t/t9903-bash-prompt.sh
@@ -13,10 +13,10 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh"
actual="$TRASH_DIRECTORY/actual"
-c_red='\\[\\e[31m\\]'
-c_green='\\[\\e[32m\\]'
-c_lblue='\\[\\e[1;34m\\]'
-c_clear='\\[\\e[0m\\]'
+c_red='\001\e[31m\002'
+c_green='\001\e[32m\002'
+c_lblue='\001\e[1;34m\002'
+c_clear='\001\e[0m\002'
test_expect_success 'setup for prompt tests' '
git init otherrepo &&
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 999d46fafe..6e19ebc922 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1227,15 +1227,6 @@ test_i18ngrep () {
return 1
}
-# Call any command "$@" but be more verbose about its
-# failure. This is handy for commands like "test" which do
-# not output anything when they fail.
-verbose () {
- "$@" && return 0
- echo >&4 "command failed: $(git rev-parse --sq-quote "$@")"
- return 1
-}
-
# Check if the file expected to be empty is indeed empty, and barfs
# otherwise.
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 62136caee5..3315919eaf 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -157,6 +157,8 @@ parse_option () {
local opt="$1"
case "$opt" in
+ -c|--c|--co|--cou|--coun|--count|--counts)
+ record_counts=t ;;
-d|--d|--de|--deb|--debu|--debug)
debug=t ;;
-i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
@@ -1041,10 +1043,7 @@ want_trace () {
# (and we want to make sure we run any cleanup like
# "set +x").
test_eval_inner_ () {
- # Do not add anything extra (including LF) after '$*'
- eval "
- want_trace && trace_level_=$(($trace_level_+1)) && set -x
- $*"
+ eval "$*"
}
test_eval_ () {
@@ -1069,7 +1068,10 @@ test_eval_ () {
# be _inside_ the block to avoid polluting the "set -x" output
#
- test_eval_inner_ "$@" </dev/null >&3 2>&4
+ # Do not add anything extra (including LF) after '$*'
+ test_eval_inner_ </dev/null >&3 2>&4 "
+ want_trace && trace_level_=$(($trace_level_+1)) && set -x
+ $*"
{
test_eval_ret_=$?
if want_trace
@@ -1086,22 +1088,22 @@ test_eval_ () {
return $test_eval_ret_
}
+fail_117 () {
+ return 117
+}
+
test_run_ () {
test_cleanup=:
expecting_failure=$2
if test "${GIT_TEST_CHAIN_LINT:-1}" != 0; then
- # turn off tracing for this test-eval, as it simply creates
- # confusing noise in the "-x" output
- trace_tmp=$trace
- trace=
# 117 is magic because it is unlikely to match the exit
# code of other programs
- if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
+ test_eval_inner_ "fail_117 && $1" </dev/null >&3 2>&4
+ if test $? != 117
then
- BUG "broken &&-chain or run-away HERE-DOC: $1"
+ BUG "broken &&-chain: $1"
fi
- trace=$trace_tmp
fi
setup_malloc_check
@@ -1276,7 +1278,7 @@ test_done () {
finalize_test_output
- if test -z "$HARNESS_ACTIVE"
+ if test -z "$HARNESS_ACTIVE" || test -n "$record_counts"
then
mkdir -p "$TEST_RESULTS_DIR"
@@ -1593,7 +1595,8 @@ then
BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_SANITIZE_LEAK_LOG=true"
fi
-if test "${GIT_TEST_CHAIN_LINT:-1}" != 0
+if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 &&
+ test "${GIT_TEST_EXT_CHAIN_LINT:-1}" != 0
then
"$PERL_PATH" "$TEST_DIRECTORY/chainlint.pl" "$0" ||
BUG "lint error (see '?!...!? annotations above)"
diff --git a/tag.c b/tag.c
index dfbcd7fcc2..c356d58890 100644
--- a/tag.c
+++ b/tag.c
@@ -1,12 +1,17 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
#include "tag.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "commit.h"
#include "tree.h"
#include "blob.h"
#include "alloc.h"
#include "gpg-interface.h"
+#include "hex.h"
#include "packfile.h"
+#include "wrapper.h"
const char *tag_type = "tag";
@@ -51,15 +56,15 @@ int gpg_verify_tag(const struct object_id *oid, const char *name_to_report,
return error("%s: cannot verify a non-tag object of type %s.",
name_to_report ?
name_to_report :
- find_unique_abbrev(oid, DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV),
type_name(type));
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf)
return error("%s: unable to read file.",
name_to_report ?
name_to_report :
- find_unique_abbrev(oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
ret = run_gpg_verify(buf, size, flags);
@@ -100,12 +105,18 @@ struct object *deref_tag_noverify(struct object *o)
return o;
}
-struct tag *lookup_tag(struct repository *r, const struct object_id *oid)
+struct tag *lookup_tag_type(struct repository *r, const struct object_id *oid,
+ enum object_type type)
{
struct object *obj = lookup_object(r, oid);
if (!obj)
return create_object(r, oid, alloc_tag_node(r));
- return object_as_type(obj, OBJ_TAG, 0);
+ return object_as_type_hint(obj, OBJ_TAG, type);
+}
+
+struct tag *lookup_tag(struct repository *r, const struct object_id *oid)
+{
+ return lookup_tag_type(r, oid, OBJ_NONE);
}
static timestamp_t parse_tag_date(const char *buf, const char *tail)
@@ -135,6 +146,7 @@ void release_tag_memory(struct tag *t)
int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size)
{
+ struct object *obj;
struct object_id oid;
char type[20];
const char *bufptr = data;
@@ -169,7 +181,10 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
type[nl - bufptr] = '\0';
bufptr = nl + 1;
- if (!strcmp(type, blob_type)) {
+ obj = lookup_object(r, &oid);
+ if (obj) {
+ item->tagged = obj;
+ } else if (!strcmp(type, blob_type)) {
item->tagged = (struct object *)lookup_blob(r, &oid);
} else if (!strcmp(type, tree_type)) {
item->tagged = (struct object *)lookup_tree(r, &oid);
@@ -182,10 +197,14 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
type, oid_to_hex(&item->object.oid));
}
- if (!item->tagged)
+ if (!item->tagged || strcmp(type_name(item->tagged->type), type)) {
+ if (item->tagged && item->tagged->parsed)
+ error(_("object %s is a %s, not a %s"), oid_to_hex(&oid),
+ type_name(item->tagged->type), type);
return error("bad tag pointer to %s in %s",
oid_to_hex(&oid),
oid_to_hex(&item->object.oid));
+ }
if (bufptr + 4 < tail && starts_with(bufptr, "tag "))
; /* good */
@@ -216,7 +235,8 @@ int parse_tag(struct tag *item)
if (item->object.parsed)
return 0;
- data = read_object_file(&item->object.oid, &type, &size);
+ data = repo_read_object_file(the_repository, &item->object.oid, &type,
+ &size);
if (!data)
return error("Could not read %s",
oid_to_hex(&item->object.oid));
diff --git a/tag.h b/tag.h
index 3ce8e72192..42bd3e6401 100644
--- a/tag.h
+++ b/tag.h
@@ -12,6 +12,8 @@ struct tag {
timestamp_t date;
};
struct tag *lookup_tag(struct repository *r, const struct object_id *oid);
+struct tag *lookup_tag_type(struct repository *r, const struct object_id *oid,
+ enum object_type type);
int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size);
int parse_tag(struct tag *item);
void release_tag_memory(struct tag *t);
diff --git a/tempfile.c b/tempfile.c
index e27048f970..6c88a63b42 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -42,9 +42,12 @@
* file created by its parent.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "path.h"
#include "tempfile.h"
#include "sigchain.h"
+#include "wrapper.h"
static VOLATILE_LIST_HEAD(tempfile_list);
diff --git a/templates/hooks--sendemail-validate.sample b/templates/hooks--sendemail-validate.sample
new file mode 100755
index 0000000000..640bcf874d
--- /dev/null
+++ b/templates/hooks--sendemail-validate.sample
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# An example hook script to validate a patch (and/or patch series) before
+# sending it via email.
+#
+# The hook should exit with non-zero status after issuing an appropriate
+# message if it wants to prevent the email(s) from being sent.
+#
+# To enable this hook, rename this file to "sendemail-validate".
+#
+# By default, it will only check that the patch(es) can be applied on top of
+# the default upstream branch without conflicts in a secondary worktree. After
+# validation (successful or not) of the last patch of a series, the worktree
+# will be deleted.
+#
+# The following config variables can be set to change the default remote and
+# remote ref that are used to apply the patches against:
+#
+# sendemail.validateRemote (default: origin)
+# sendemail.validateRemoteRef (default: HEAD)
+#
+# Replace the TODO placeholders with appropriate checks according to your
+# needs.
+
+validate_cover_letter () {
+ file="$1"
+ # TODO: Replace with appropriate checks (e.g. spell checking).
+ true
+}
+
+validate_patch () {
+ file="$1"
+ # Ensure that the patch applies without conflicts.
+ git am -3 "$file" || return
+ # TODO: Replace with appropriate checks for this patch
+ # (e.g. checkpatch.pl).
+ true
+}
+
+validate_series () {
+ # TODO: Replace with appropriate checks for the whole series
+ # (e.g. quick build, coding style checks, etc.).
+ true
+}
+
+# main -------------------------------------------------------------------------
+
+if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
+then
+ remote=$(git config --default origin --get sendemail.validateRemote) &&
+ ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
+ worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
+ git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
+ git config --replace-all sendemail.validateWorktree "$worktree"
+else
+ worktree=$(git config --get sendemail.validateWorktree)
+fi || {
+ echo "sendemail-validate: error: failed to prepare worktree" >&2
+ exit 1
+}
+
+unset GIT_DIR GIT_WORK_TREE
+cd "$worktree" &&
+
+if grep -q "^diff --git " "$1"
+then
+ validate_patch "$1"
+else
+ validate_cover_letter "$1"
+fi &&
+
+if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
+then
+ git config --unset-all sendemail.validateWorktree &&
+ trap 'git worktree remove -ff "$worktree"' EXIT &&
+ validate_series
+fi
diff --git a/thread-utils.c b/thread-utils.c
index 5329845691..1f89ffab4c 100644
--- a/thread-utils.c
+++ b/thread-utils.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "thread-utils.h"
#if defined(hpux) || defined(__hpux) || defined(_hpux)
diff --git a/tmp-objdir.c b/tmp-objdir.c
index 2a2012eb6d..5f9074ad1c 100644
--- a/tmp-objdir.c
+++ b/tmp-objdir.c
@@ -1,13 +1,17 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "tmp-objdir.h"
+#include "abspath.h"
#include "chdir-notify.h"
#include "dir.h"
+#include "environment.h"
+#include "object-file.h"
+#include "path.h"
#include "sigchain.h"
#include "string-list.h"
#include "strbuf.h"
#include "strvec.h"
#include "quote.h"
-#include "object-store.h"
+#include "object-store-ll.h"
struct tmp_objdir {
struct strbuf path;
diff --git a/trace.c b/trace.c
index efa4e2d8e0..592c141d78 100644
--- a/trace.c
+++ b/trace.c
@@ -21,8 +21,13 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "environment.h"
#include "quote.h"
+#include "setup.h"
+#include "trace.h"
+#include "wrapper.h"
struct trace_key trace_default_key = { "GIT_TRACE", 0, 0, 0 };
struct trace_key trace_perf_key = TRACE_KEY_INIT(PERFORMANCE);
diff --git a/trace.h b/trace.h
index b6e35b9470..d304d55aa1 100644
--- a/trace.h
+++ b/trace.h
@@ -1,7 +1,6 @@
#ifndef TRACE_H
#define TRACE_H
-#include "git-compat-util.h"
#include "strbuf.h"
/**
diff --git a/trace2.c b/trace2.c
index 279bddf53b..0efc4e7b95 100644
--- a/trace2.c
+++ b/trace2.c
@@ -1,11 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "json-writer.h"
#include "quote.h"
+#include "repository.h"
#include "run-command.h"
#include "sigchain.h"
#include "thread-utils.h"
#include "version.h"
+#include "trace.h"
+#include "trace2.h"
#include "trace2/tr2_cfg.h"
#include "trace2/tr2_cmd_name.h"
#include "trace2/tr2_ctr.h"
diff --git a/trace2.h b/trace2.h
index 4ced30c0db..9452e291f5 100644
--- a/trace2.h
+++ b/trace2.h
@@ -551,6 +551,8 @@ enum trace2_counter_id {
TRACE2_COUNTER_ID_TEST1 = 0, /* emits summary event only */
TRACE2_COUNTER_ID_TEST2, /* emits summary and thread events */
+ TRACE2_COUNTER_ID_PACKED_REFS_JUMPS, /* counts number of jumps */
+
/* Add additional counter definitions before here. */
TRACE2_NUMBER_OF_COUNTERS
};
diff --git a/trace2/tr2_cfg.c b/trace2/tr2_cfg.c
index ec9ac1a6ef..db817a80c5 100644
--- a/trace2/tr2_cfg.c
+++ b/trace2/tr2_cfg.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "strbuf.h"
+#include "trace2.h"
#include "trace2/tr2_cfg.h"
#include "trace2/tr2_sysenv.h"
+#include "wildmatch.h"
static struct strbuf **tr2_cfg_patterns;
static int tr2_cfg_count_patterns;
diff --git a/trace2/tr2_cmd_name.c b/trace2/tr2_cmd_name.c
index dd313204f5..b7b5a869b7 100644
--- a/trace2/tr2_cmd_name.c
+++ b/trace2/tr2_cmd_name.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "strbuf.h"
#include "trace2/tr2_cmd_name.h"
#define TR2_ENVVAR_PARENT_NAME "GIT_TRACE2_PARENT_NAME"
diff --git a/trace2/tr2_ctr.c b/trace2/tr2_ctr.c
index 483ca7c308..50570d0165 100644
--- a/trace2/tr2_ctr.c
+++ b/trace2/tr2_ctr.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "thread-utils.h"
#include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h"
@@ -27,6 +27,11 @@ static struct tr2_counter_metadata tr2_counter_metadata[TRACE2_NUMBER_OF_COUNTER
.name = "test2",
.want_per_thread_events = 1,
},
+ [TRACE2_COUNTER_ID_PACKED_REFS_JUMPS] = {
+ .category = "packed-refs",
+ .name = "jumps_made",
+ .want_per_thread_events = 0,
+ },
/* Add additional metadata before here. */
};
diff --git a/trace2/tr2_dst.c b/trace2/tr2_dst.c
index 8a21dd2972..5be892cd5c 100644
--- a/trace2/tr2_dst.c
+++ b/trace2/tr2_dst.c
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "sigchain.h"
+#include "strbuf.h"
#include "trace2/tr2_dst.h"
#include "trace2/tr2_sid.h"
#include "trace2/tr2_sysenv.h"
diff --git a/trace2/tr2_sid.c b/trace2/tr2_sid.c
index dc6e75ef13..09c4ef0d17 100644
--- a/trace2/tr2_sid.c
+++ b/trace2/tr2_sid.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hex.h"
+#include "strbuf.h"
#include "trace2/tr2_tbuf.h"
#include "trace2/tr2_sid.h"
diff --git a/trace2/tr2_sysenv.c b/trace2/tr2_sysenv.c
index a380dcf910..069786cb92 100644
--- a/trace2/tr2_sysenv.c
+++ b/trace2/tr2_sysenv.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "dir.h"
#include "tr2_sysenv.h"
diff --git a/trace2/tr2_tbuf.c b/trace2/tr2_tbuf.c
index 2498482d9a..c3b3822ed7 100644
--- a/trace2/tr2_tbuf.c
+++ b/trace2/tr2_tbuf.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "tr2_tbuf.h"
void tr2_tbuf_local_time(struct tr2_tbuf *tb)
diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c
index 16f6332755..2af53e5d4d 100644
--- a/trace2/tr2_tgt_event.c
+++ b/trace2/tr2_tgt_event.c
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "json-writer.h"
+#include "repository.h"
#include "run-command.h"
#include "version.h"
#include "trace2/tr2_dst.h"
diff --git a/trace2/tr2_tgt_normal.c b/trace2/tr2_tgt_normal.c
index fbbef68dfc..1ebfb464d5 100644
--- a/trace2/tr2_tgt_normal.c
+++ b/trace2/tr2_tgt_normal.c
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "repository.h"
#include "run-command.h"
#include "quote.h"
#include "version.h"
diff --git a/trace2/tr2_tgt_perf.c b/trace2/tr2_tgt_perf.c
index adae803263..328e483a05 100644
--- a/trace2/tr2_tgt_perf.c
+++ b/trace2/tr2_tgt_perf.c
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "repository.h"
#include "run-command.h"
#include "quote.h"
#include "version.h"
diff --git a/trace2/tr2_tls.c b/trace2/tr2_tls.c
index 04900bb4c3..9f46ae12f5 100644
--- a/trace2/tr2_tls.c
+++ b/trace2/tr2_tls.c
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "thread-utils.h"
+#include "trace.h"
#include "trace2/tr2_tls.h"
/*
diff --git a/trace2/tr2_tmr.c b/trace2/tr2_tmr.c
index 786762dfd2..31d0e4d1bd 100644
--- a/trace2/tr2_tmr.c
+++ b/trace2/tr2_tmr.c
@@ -1,8 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "thread-utils.h"
#include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h"
#include "trace2/tr2_tmr.h"
+#include "trace.h"
#define MY_MAX(a, b) ((a) > (b) ? (a) : (b))
#define MY_MIN(a, b) ((a) < (b) ? (a) : (b))
diff --git a/trailer.c b/trailer.c
index 0fd5b142a3..a2c3ed6f28 100644
--- a/trailer.c
+++ b/trailer.c
@@ -1,5 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
#include "string-list.h"
#include "run-command.h"
#include "commit.h"
diff --git a/transport-helper.c b/transport-helper.c
index 3ea7c2bb5a..5c0bc6a896 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -1,9 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "transport.h"
#include "quote.h"
#include "run-command.h"
#include "commit.h"
#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "repository.h"
#include "revision.h"
#include "remote.h"
#include "string-list.h"
@@ -14,6 +19,7 @@
#include "refspec.h"
#include "transport-internal.h"
#include "protocol.h"
+#include "wrapper.h"
static int debug;
@@ -1081,7 +1087,7 @@ static int push_refs_with_export(struct transport *transport,
struct object_id oid;
private = apply_refspecs(&data->rs, ref->name);
- if (private && !get_oid(private, &oid)) {
+ if (private && !repo_get_oid(the_repository, private, &oid)) {
strbuf_addf(&buf, "^%s", private);
string_list_append_nodup(&revlist_args,
strbuf_detach(&buf, NULL));
diff --git a/transport.c b/transport.c
index 77a61a9d7b..4dc187a388 100644
--- a/transport.c
+++ b/transport.c
@@ -1,5 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
+#include "alloc.h"
#include "config.h"
+#include "environment.h"
+#include "hex.h"
#include "transport.h"
#include "hook.h"
#include "pkt-line.h"
@@ -10,6 +14,7 @@
#include "walker.h"
#include "bundle.h"
#include "dir.h"
+#include "gettext.h"
#include "refs.h"
#include "refspec.h"
#include "branch.h"
@@ -18,11 +23,14 @@
#include "string-list.h"
#include "oid-array.h"
#include "sigchain.h"
+#include "trace2.h"
#include "transport-internal.h"
#include "protocol.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "color.h"
#include "bundle-uri.h"
+#include "wrapper.h"
static int transport_use_color = -1;
static char transport_colors[][COLOR_MAXLEN] = {
@@ -167,7 +175,8 @@ static struct ref *get_refs_from_bundle(struct transport *transport,
}
static int fetch_refs_from_bundle(struct transport *transport,
- int nr_heads, struct ref **to_fetch)
+ int nr_heads UNUSED,
+ struct ref **to_fetch UNUSED)
{
struct bundle_transport_data *data = transport->data;
struct strvec extra_index_pack_args = STRVEC_INIT;
@@ -276,8 +285,12 @@ static int connect_setup(struct transport *transport, int for_push)
}
data->conn = git_connect(data->fd, transport->url,
- for_push ? data->options.receivepack :
- data->options.uploadpack,
+ for_push ?
+ "git-receive-pack" :
+ "git-upload-pack",
+ for_push ?
+ data->options.receivepack :
+ data->options.uploadpack,
flags);
return 0;
@@ -307,7 +320,7 @@ static struct ref *handshake(struct transport *transport, int for_push,
struct git_transport_data *data = transport->data;
struct ref *refs = NULL;
struct packet_reader reader;
- int sid_len;
+ size_t sid_len;
const char *server_sid;
connect_setup(transport, for_push);
@@ -776,7 +789,8 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count,
static int measure_abbrev(const struct object_id *oid, int sofar)
{
char hex[GIT_MAX_HEXSZ + 1];
- int w = find_unique_abbrev_r(hex, oid, DEFAULT_ABBREV);
+ int w = repo_find_unique_abbrev_r(the_repository, hex, oid,
+ DEFAULT_ABBREV);
return (w < sofar) ? sofar : w;
}
@@ -911,7 +925,7 @@ static int connect_git(struct transport *transport, const char *name,
{
struct git_transport_data *data = transport->data;
data->conn = git_connect(data->fd, transport->url,
- executable, 0);
+ name, executable, 0);
fd[0] = data->fd[0];
fd[1] = data->fd[1];
return 0;
diff --git a/transport.h b/transport.h
index 85150f504f..6393cd9823 100644
--- a/transport.h
+++ b/transport.h
@@ -1,7 +1,6 @@
#ifndef TRANSPORT_H
#define TRANSPORT_H
-#include "cache.h"
#include "run-command.h"
#include "remote.h"
#include "list-objects-filter-options.h"
diff --git a/tree-diff.c b/tree-diff.c
index 69031d7cba..966946848a 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -1,10 +1,25 @@
/*
* Helper functions for tree diff generation
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "diff.h"
#include "diffcore.h"
+#include "hash.h"
#include "tree.h"
+#include "tree-walk.h"
+
+/*
+ * Some mode bits are also used internally for computations.
+ *
+ * They *must* not overlap with any valid modes, and they *must* not be emitted
+ * to outside world - i.e. appear on disk or network. In other words, it's just
+ * temporary fields, which we internally use, but they have to stay in-house.
+ *
+ * ( such approach is valid, as standard S_IF* fits into 16 bits, and in Git
+ * codebase mode is `unsigned int` which is assumed to be at least 32 bits )
+ */
+
+#define S_DIFFTREE_IFXMIN_NEQ 0x80000000
/*
* internal mode marker, saying a tree entry != entry of tp[imin]
diff --git a/tree-walk.c b/tree-walk.c
index 74f4d710e8..42ed86ef58 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -1,7 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "tree-walk.h"
+#include "alloc.h"
#include "dir.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "trace2.h"
#include "tree.h"
#include "pathspec.h"
#include "json-writer.h"
diff --git a/tree-walk.h b/tree-walk.h
index 6305d53150..01a9d8eb44 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -1,7 +1,10 @@
#ifndef TREE_WALK_H
#define TREE_WALK_H
-#include "cache.h"
+#include "hash-ll.h"
+
+struct index_state;
+struct repository;
#define MAX_TRAVERSE_TREES 8
diff --git a/tree.c b/tree.c
index 410e3b477e..5710c38746 100644
--- a/tree.c
+++ b/tree.c
@@ -1,7 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "cache-tree.h"
+#include "hex.h"
#include "tree.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "blob.h"
#include "commit.h"
#include "tag.h"
@@ -58,7 +60,7 @@ int read_tree_at(struct repository *r,
oid_to_hex(&entry.oid),
base->buf, entry.path);
- if (parse_commit(commit))
+ if (repo_parse_commit(r, commit))
die("Invalid commit %s in submodule path %s%s",
oid_to_hex(&entry.oid),
base->buf, entry.path);
@@ -92,22 +94,87 @@ int read_tree(struct repository *r,
return ret;
}
-int cmp_cache_name_compare(const void *a_, const void *b_)
+int base_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2)
{
- const struct cache_entry *ce1, *ce2;
+ unsigned char c1, c2;
+ size_t len = len1 < len2 ? len1 : len2;
+ int cmp;
+
+ cmp = memcmp(name1, name2, len);
+ if (cmp)
+ return cmp;
+ c1 = name1[len];
+ c2 = name2[len];
+ if (!c1 && S_ISDIR(mode1))
+ c1 = '/';
+ if (!c2 && S_ISDIR(mode2))
+ c2 = '/';
+ return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
+}
- ce1 = *((const struct cache_entry **)a_);
- ce2 = *((const struct cache_entry **)b_);
- return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
- ce2->name, ce2->ce_namelen, ce_stage(ce2));
+/*
+ * df_name_compare() is identical to base_name_compare(), except it
+ * compares conflicting directory/file entries as equal. Note that
+ * while a directory name compares as equal to a regular file, they
+ * then individually compare _differently_ to a filename that has
+ * a dot after the basename (because '\0' < '.' < '/').
+ *
+ * This is used by routines that want to traverse the git namespace
+ * but then handle conflicting entries together when possible.
+ */
+int df_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2)
+{
+ unsigned char c1, c2;
+ size_t len = len1 < len2 ? len1 : len2;
+ int cmp;
+
+ cmp = memcmp(name1, name2, len);
+ if (cmp)
+ return cmp;
+ /* Directories and files compare equal (same length, same name) */
+ if (len1 == len2)
+ return 0;
+ c1 = name1[len];
+ if (!c1 && S_ISDIR(mode1))
+ c1 = '/';
+ c2 = name2[len];
+ if (!c2 && S_ISDIR(mode2))
+ c2 = '/';
+ if (c1 == '/' && !c2)
+ return 0;
+ if (c2 == '/' && !c1)
+ return 0;
+ return c1 - c2;
}
-struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
+int name_compare(const char *name1, size_t len1, const char *name2, size_t len2)
+{
+ size_t min_len = (len1 < len2) ? len1 : len2;
+ int cmp = memcmp(name1, name2, min_len);
+ if (cmp)
+ return cmp;
+ if (len1 < len2)
+ return -1;
+ if (len1 > len2)
+ return 1;
+ return 0;
+}
+
+struct tree *lookup_tree_type(struct repository *r,
+ const struct object_id *oid,
+ enum object_type type)
{
struct object *obj = lookup_object(r, oid);
if (!obj)
return create_object(r, oid, alloc_tree_node(r));
- return object_as_type(obj, OBJ_TREE, 0);
+ return object_as_type_hint(obj, OBJ_TREE, type);
+}
+
+struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
+{
+ return lookup_tree_type(r, oid, OBJ_NONE);
}
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
@@ -129,7 +196,8 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)
if (item->object.parsed)
return 0;
- buffer = read_object_file(&item->object.oid, &type, &size);
+ buffer = repo_read_object_file(the_repository, &item->object.oid,
+ &type, &size);
if (!buffer)
return quiet_on_missing ? -1 :
error("Could not read %s",
diff --git a/tree.h b/tree.h
index 6efff003e2..0e7f40071c 100644
--- a/tree.h
+++ b/tree.h
@@ -3,6 +3,7 @@
#include "object.h"
+struct pathspec;
struct repository;
struct strbuf;
@@ -15,6 +16,8 @@ struct tree {
extern const char *tree_type;
struct tree *lookup_tree(struct repository *r, const struct object_id *oid);
+struct tree *lookup_tree_type(struct repository *r, const struct object_id *oid,
+ enum object_type type);
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
@@ -28,7 +31,15 @@ void free_tree_buffer(struct tree *tree);
/* Parses and returns the tree in the given ent, chasing tags and commits. */
struct tree *parse_tree_indirect(const struct object_id *oid);
-int cmp_cache_name_compare(const void *a_, const void *b_);
+/*
+ * Functions for comparing pathnames
+ */
+int base_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2);
+int df_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2);
+int name_compare(const char *name1, size_t len1,
+ const char *name2, size_t len2);
#define READ_TREE_RECURSIVE 1
typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
diff --git a/unicode-width.h b/unicode-width.h
index 97c851b27d..e15fb0455b 100644
--- a/unicode-width.h
+++ b/unicode-width.h
@@ -94,7 +94,7 @@ static const struct interval zero_width[] = {
{ 0x0E47, 0x0E4E },
{ 0x0EB1, 0x0EB1 },
{ 0x0EB4, 0x0EBC },
-{ 0x0EC8, 0x0ECD },
+{ 0x0EC8, 0x0ECE },
{ 0x0F18, 0x0F19 },
{ 0x0F35, 0x0F35 },
{ 0x0F37, 0x0F37 },
@@ -228,6 +228,7 @@ static const struct interval zero_width[] = {
{ 0x10AE5, 0x10AE6 },
{ 0x10D24, 0x10D27 },
{ 0x10EAB, 0x10EAC },
+{ 0x10EFD, 0x10EFF },
{ 0x10F46, 0x10F50 },
{ 0x10F82, 0x10F85 },
{ 0x11001, 0x11001 },
@@ -252,6 +253,7 @@ static const struct interval zero_width[] = {
{ 0x11234, 0x11234 },
{ 0x11236, 0x11237 },
{ 0x1123E, 0x1123E },
+{ 0x11241, 0x11241 },
{ 0x112DF, 0x112DF },
{ 0x112E3, 0x112EA },
{ 0x11300, 0x11301 },
@@ -313,7 +315,12 @@ static const struct interval zero_width[] = {
{ 0x11D95, 0x11D95 },
{ 0x11D97, 0x11D97 },
{ 0x11EF3, 0x11EF4 },
-{ 0x13430, 0x13438 },
+{ 0x11F00, 0x11F01 },
+{ 0x11F36, 0x11F3A },
+{ 0x11F40, 0x11F40 },
+{ 0x11F42, 0x11F42 },
+{ 0x13430, 0x13440 },
+{ 0x13447, 0x13455 },
{ 0x16AF0, 0x16AF4 },
{ 0x16B30, 0x16B36 },
{ 0x16F4F, 0x16F4F },
@@ -339,9 +346,11 @@ static const struct interval zero_width[] = {
{ 0x1E01B, 0x1E021 },
{ 0x1E023, 0x1E024 },
{ 0x1E026, 0x1E02A },
+{ 0x1E08F, 0x1E08F },
{ 0x1E130, 0x1E136 },
{ 0x1E2AE, 0x1E2AE },
{ 0x1E2EC, 0x1E2EF },
+{ 0x1E4EC, 0x1E4EF },
{ 0x1E8D0, 0x1E8D6 },
{ 0x1E944, 0x1E94A },
{ 0xE0001, 0xE0001 },
@@ -417,7 +426,9 @@ static const struct interval double_width[] = {
{ 0x1AFF5, 0x1AFFB },
{ 0x1AFFD, 0x1AFFE },
{ 0x1B000, 0x1B122 },
+{ 0x1B132, 0x1B132 },
{ 0x1B150, 0x1B152 },
+{ 0x1B155, 0x1B155 },
{ 0x1B164, 0x1B167 },
{ 0x1B170, 0x1B2FB },
{ 0x1F004, 0x1F004 },
@@ -451,7 +462,7 @@ static const struct interval double_width[] = {
{ 0x1F6CC, 0x1F6CC },
{ 0x1F6D0, 0x1F6D2 },
{ 0x1F6D5, 0x1F6D7 },
-{ 0x1F6DD, 0x1F6DF },
+{ 0x1F6DC, 0x1F6DF },
{ 0x1F6EB, 0x1F6EC },
{ 0x1F6F4, 0x1F6FC },
{ 0x1F7E0, 0x1F7EB },
@@ -459,15 +470,13 @@ static const struct interval double_width[] = {
{ 0x1F90C, 0x1F93A },
{ 0x1F93C, 0x1F945 },
{ 0x1F947, 0x1F9FF },
-{ 0x1FA70, 0x1FA74 },
-{ 0x1FA78, 0x1FA7C },
-{ 0x1FA80, 0x1FA86 },
-{ 0x1FA90, 0x1FAAC },
-{ 0x1FAB0, 0x1FABA },
-{ 0x1FAC0, 0x1FAC5 },
-{ 0x1FAD0, 0x1FAD9 },
-{ 0x1FAE0, 0x1FAE7 },
-{ 0x1FAF0, 0x1FAF6 },
+{ 0x1FA70, 0x1FA7C },
+{ 0x1FA80, 0x1FA88 },
+{ 0x1FA90, 0x1FABD },
+{ 0x1FABF, 0x1FAC5 },
+{ 0x1FACE, 0x1FADB },
+{ 0x1FAE0, 0x1FAE8 },
+{ 0x1FAF0, 0x1FAF8 },
{ 0x20000, 0x2FFFD },
{ 0x30000, 0x3FFFD }
};
diff --git a/unix-socket.c b/unix-socket.c
index e0be1badb5..79800d8063 100644
--- a/unix-socket.c
+++ b/unix-socket.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "strbuf.h"
#include "unix-socket.h"
#define DEFAULT_UNIX_STREAM_LISTEN_BACKLOG (5)
diff --git a/unix-stream-server.c b/unix-stream-server.c
index efa2a207ab..22ac2373e0 100644
--- a/unix-stream-server.c
+++ b/unix-stream-server.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "lockfile.h"
#include "unix-socket.h"
#include "unix-stream-server.h"
diff --git a/unpack-trees.c b/unpack-trees.c
index 3d05e45a27..87517364dc 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1,8 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
#include "strvec.h"
#include "repository.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "name-hash.h"
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
@@ -10,15 +15,19 @@
#include "progress.h"
#include "refs.h"
#include "attr.h"
+#include "read-cache.h"
#include "split-index.h"
#include "sparse-index.h"
#include "submodule.h"
#include "submodule-config.h"
+#include "symlinks.h"
+#include "trace2.h"
#include "fsmonitor.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "promisor-remote.h"
#include "entry.h"
#include "parallel-checkout.h"
+#include "setup.h"
/*
* Error messages expected by scripts out of plumbing commands such as
@@ -66,8 +75,8 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
};
#define ERRORMSG(o,type) \
- ( ((o) && (o)->msgs[(type)]) \
- ? ((o)->msgs[(type)]) \
+ ( ((o) && (o)->internal.msgs[(type)]) \
+ ? ((o)->internal.msgs[(type)]) \
: (unpack_plumbing_errors[(type)]) )
static const char *super_prefixed(const char *path, const char *super_prefix)
@@ -108,10 +117,10 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
const char *cmd)
{
int i;
- const char **msgs = opts->msgs;
+ const char **msgs = opts->internal.msgs;
const char *msg;
- strvec_init(&opts->msgs_to_free);
+ strvec_init(&opts->internal.msgs_to_free);
if (!strcmp(cmd, "checkout"))
msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
@@ -129,7 +138,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
"Please commit your changes or stash them before you %s.")
: _("Your local changes to the following files would be overwritten by %s:\n%%s");
msgs[ERROR_WOULD_OVERWRITE] = msgs[ERROR_NOT_UPTODATE_FILE] =
- strvec_pushf(&opts->msgs_to_free, msg, cmd, cmd);
+ strvec_pushf(&opts->internal.msgs_to_free, msg, cmd, cmd);
msgs[ERROR_NOT_UPTODATE_DIR] =
_("Updating the following directories would lose untracked files in them:\n%s");
@@ -153,7 +162,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
"Please move or remove them before you %s.")
: _("The following untracked working tree files would be removed by %s:\n%%s");
msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] =
- strvec_pushf(&opts->msgs_to_free, msg, cmd, cmd);
+ strvec_pushf(&opts->internal.msgs_to_free, msg, cmd, cmd);
if (!strcmp(cmd, "checkout"))
msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
@@ -171,7 +180,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
"Please move or remove them before you %s.")
: _("The following untracked working tree files would be overwritten by %s:\n%%s");
msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] =
- strvec_pushf(&opts->msgs_to_free, msg, cmd, cmd);
+ strvec_pushf(&opts->internal.msgs_to_free, msg, cmd, cmd);
/*
* Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
@@ -189,16 +198,16 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
msgs[WARNING_SPARSE_ORPHANED_NOT_OVERWRITTEN] =
_("The following paths were already present and thus not updated despite sparse patterns:\n%s");
- opts->show_all_errors = 1;
+ opts->internal.show_all_errors = 1;
/* rejected paths may not have a static buffer */
- for (i = 0; i < ARRAY_SIZE(opts->unpack_rejects); i++)
- opts->unpack_rejects[i].strdup_strings = 1;
+ for (i = 0; i < ARRAY_SIZE(opts->internal.unpack_rejects); i++)
+ opts->internal.unpack_rejects[i].strdup_strings = 1;
}
void clear_unpack_trees_porcelain(struct unpack_trees_options *opts)
{
- strvec_clear(&opts->msgs_to_free);
- memset(opts->msgs, 0, sizeof(opts->msgs));
+ strvec_clear(&opts->internal.msgs_to_free);
+ memset(opts->internal.msgs, 0, sizeof(opts->internal.msgs));
}
static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
@@ -210,7 +219,7 @@ static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
set |= CE_WT_REMOVE;
ce->ce_flags = (ce->ce_flags & ~clear) | set;
- return add_index_entry(&o->result, ce,
+ return add_index_entry(&o->internal.result, ce,
ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
@@ -218,7 +227,7 @@ static void add_entry(struct unpack_trees_options *o,
const struct cache_entry *ce,
unsigned int set, unsigned int clear)
{
- do_add_entry(o, dup_cache_entry(ce, &o->result), set, clear);
+ do_add_entry(o, dup_cache_entry(ce, &o->internal.result), set, clear);
}
/*
@@ -233,7 +242,7 @@ static int add_rejected_path(struct unpack_trees_options *o,
if (o->quiet)
return -1;
- if (!o->show_all_errors)
+ if (!o->internal.show_all_errors)
return error(ERRORMSG(o, e), super_prefixed(path,
o->super_prefix));
@@ -241,7 +250,7 @@ static int add_rejected_path(struct unpack_trees_options *o,
* Otherwise, insert in a list for future display by
* display_(error|warning)_msgs()
*/
- string_list_append(&o->unpack_rejects[e], path);
+ string_list_append(&o->internal.unpack_rejects[e], path);
return -1;
}
@@ -253,7 +262,7 @@ static void display_error_msgs(struct unpack_trees_options *o)
int e;
unsigned error_displayed = 0;
for (e = 0; e < NB_UNPACK_TREES_ERROR_TYPES; e++) {
- struct string_list *rejects = &o->unpack_rejects[e];
+ struct string_list *rejects = &o->internal.unpack_rejects[e];
if (rejects->nr > 0) {
int i;
@@ -281,7 +290,7 @@ static void display_warning_msgs(struct unpack_trees_options *o)
unsigned warning_displayed = 0;
for (e = NB_UNPACK_TREES_ERROR_TYPES + 1;
e < NB_UNPACK_TREES_WARNING_TYPES; e++) {
- struct string_list *rejects = &o->unpack_rejects[e];
+ struct string_list *rejects = &o->internal.unpack_rejects[e];
if (rejects->nr > 0) {
int i;
@@ -458,7 +467,7 @@ static int check_updates(struct unpack_trees_options *o,
if (should_update_submodules())
load_gitmodules_file(index, &state);
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
/*
* Prefetch the objects that are to be checked out in the loop
* below.
@@ -600,13 +609,14 @@ static void mark_ce_used(struct cache_entry *ce, struct unpack_trees_options *o)
{
ce->ce_flags |= CE_UNPACKED;
- if (o->cache_bottom < o->src_index->cache_nr &&
- o->src_index->cache[o->cache_bottom] == ce) {
- int bottom = o->cache_bottom;
+ if (o->internal.cache_bottom < o->src_index->cache_nr &&
+ o->src_index->cache[o->internal.cache_bottom] == ce) {
+ int bottom = o->internal.cache_bottom;
+
while (bottom < o->src_index->cache_nr &&
o->src_index->cache[bottom]->ce_flags & CE_UNPACKED)
bottom++;
- o->cache_bottom = bottom;
+ o->internal.cache_bottom = bottom;
}
}
@@ -652,7 +662,7 @@ static void mark_ce_used_same_name(struct cache_entry *ce,
static struct cache_entry *next_cache_entry(struct unpack_trees_options *o)
{
const struct index_state *index = o->src_index;
- int pos = o->cache_bottom;
+ int pos = o->internal.cache_bottom;
while (pos < index->cache_nr) {
struct cache_entry *ce = index->cache[pos];
@@ -711,7 +721,7 @@ static void restore_cache_bottom(struct traverse_info *info, int bottom)
if (o->diff_index_cached)
return;
- o->cache_bottom = bottom;
+ o->internal.cache_bottom = bottom;
}
static int switch_cache_bottom(struct traverse_info *info)
@@ -721,13 +731,13 @@ static int switch_cache_bottom(struct traverse_info *info)
if (o->diff_index_cached)
return 0;
- ret = o->cache_bottom;
+ ret = o->internal.cache_bottom;
pos = find_cache_pos(info->prev, info->name, info->namelen);
if (pos < -1)
- o->cache_bottom = -2 - pos;
+ o->internal.cache_bottom = -2 - pos;
else if (pos < 0)
- o->cache_bottom = o->src_index->cache_nr;
+ o->internal.cache_bottom = o->src_index->cache_nr;
return ret;
}
@@ -838,7 +848,7 @@ static int traverse_by_cache_tree(int pos, int nr_entries, int nr_names,
mark_ce_used(src[0], o);
}
free(tree_ce);
- if (o->debug_unpack)
+ if (o->internal.debug_unpack)
printf("Unpacked %d entries from %s to %s using cache-tree\n",
nr_entries,
o->src_index->cache[pos]->name,
@@ -873,9 +883,9 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
* save and restore cache_bottom anyway to not miss
* unprocessed entries before 'pos'.
*/
- bottom = o->cache_bottom;
+ bottom = o->internal.cache_bottom;
ret = traverse_by_cache_tree(pos, nr_entries, n, info);
- o->cache_bottom = bottom;
+ o->internal.cache_bottom = bottom;
return ret;
}
@@ -1212,8 +1222,8 @@ static int unpack_single_entry(int n, unsigned long mask,
* cache entry from the index aware logic.
*/
src[i + o->merge] = create_ce_entry(info, names + i, stage,
- &o->result, o->merge,
- bit & dirmask);
+ &o->internal.result,
+ o->merge, bit & dirmask);
}
if (o->merge) {
@@ -1237,7 +1247,7 @@ static int unpack_single_entry(int n, unsigned long mask,
static int unpack_failed(struct unpack_trees_options *o, const char *message)
{
- discard_index(&o->result);
+ discard_index(&o->internal.result);
if (!o->quiet && !o->exiting_early) {
if (message)
return error("%s", message);
@@ -1260,7 +1270,7 @@ static int find_cache_pos(struct traverse_info *info,
struct index_state *index = o->src_index;
int pfxlen = info->pathlen;
- for (pos = o->cache_bottom; pos < index->cache_nr; pos++) {
+ for (pos = o->internal.cache_bottom; pos < index->cache_nr; pos++) {
const struct cache_entry *ce = index->cache[pos];
const char *ce_name, *ce_slash;
int cmp, ce_len;
@@ -1271,8 +1281,8 @@ static int find_cache_pos(struct traverse_info *info,
* we can never match it; don't check it
* again.
*/
- if (pos == o->cache_bottom)
- ++o->cache_bottom;
+ if (pos == o->internal.cache_bottom)
+ ++o->internal.cache_bottom;
continue;
}
if (!ce_in_traverse_path(ce, info)) {
@@ -1450,7 +1460,7 @@ static int unpack_sparse_callback(int n, unsigned long mask, unsigned long dirma
*/
if (!is_null_oid(&names[0].oid)) {
src[0] = create_ce_entry(info, &names[0], 0,
- &o->result, 1,
+ &o->internal.result, 1,
dirmask & (1ul << 0));
src[0]->ce_flags |= (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
}
@@ -1487,7 +1497,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
while (!p->mode)
p++;
- if (o->debug_unpack)
+ if (o->internal.debug_unpack)
debug_unpack_callback(n, mask, dirmask, names, info);
/* Are we supposed to look at the index too? */
@@ -1560,7 +1570,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
* in 'mark_ce_used()'
*/
if (!src[0] || !S_ISSPARSEDIR(src[0]->ce_mode))
- o->cache_bottom += matches;
+ o->internal.cache_bottom += matches;
return mask;
}
}
@@ -1809,7 +1819,7 @@ static void populate_from_existing_patterns(struct unpack_trees_options *o,
if (get_sparse_checkout_patterns(pl) < 0)
o->skip_sparse_checkout = 1;
else
- o->pl = pl;
+ o->internal.pl = pl;
}
static void update_sparsity_for_prefix(const char *prefix,
@@ -1871,8 +1881,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (len > MAX_UNPACK_TREES)
die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES);
- if (o->dir)
- BUG("o->dir is for internal use only");
+ if (o->internal.dir)
+ BUG("o->internal.dir is for internal use only");
+ if (o->internal.pl)
+ BUG("o->internal.pl is for internal use only");
+ if (o->df_conflict_entry)
+ BUG("o->df_conflict_entry is an output only field");
trace_performance_enter();
trace2_region_enter("unpack_trees", "unpack_trees", the_repository);
@@ -1889,9 +1903,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
BUG("UNPACK_RESET_OVERWRITE_UNTRACKED incompatible with preserved ignored files");
if (!o->preserve_ignored) {
- o->dir = &dir;
- o->dir->flags |= DIR_SHOW_IGNORED;
- setup_standard_excludes(o->dir);
+ o->internal.dir = &dir;
+ o->internal.dir->flags |= DIR_SHOW_IGNORED;
+ setup_standard_excludes(o->internal.dir);
}
if (o->prefix)
@@ -1899,49 +1913,52 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (!core_apply_sparse_checkout || !o->update)
o->skip_sparse_checkout = 1;
- if (!o->skip_sparse_checkout && !o->pl) {
+ if (!o->skip_sparse_checkout) {
memset(&pl, 0, sizeof(pl));
free_pattern_list = 1;
populate_from_existing_patterns(o, &pl);
}
- index_state_init(&o->result, o->src_index->repo);
- o->result.initialized = 1;
- o->result.timestamp.sec = o->src_index->timestamp.sec;
- o->result.timestamp.nsec = o->src_index->timestamp.nsec;
- o->result.version = o->src_index->version;
+ index_state_init(&o->internal.result, o->src_index->repo);
+ o->internal.result.initialized = 1;
+ o->internal.result.timestamp.sec = o->src_index->timestamp.sec;
+ o->internal.result.timestamp.nsec = o->src_index->timestamp.nsec;
+ o->internal.result.version = o->src_index->version;
if (!o->src_index->split_index) {
- o->result.split_index = NULL;
+ o->internal.result.split_index = NULL;
} else if (o->src_index == o->dst_index) {
/*
* o->dst_index (and thus o->src_index) will be discarded
- * and overwritten with o->result at the end of this function,
- * so just use src_index's split_index to avoid having to
- * create a new one.
+ * and overwritten with o->internal.result at the end of
+ * this function, so just use src_index's split_index to
+ * avoid having to create a new one.
*/
- o->result.split_index = o->src_index->split_index;
- o->result.split_index->refcount++;
+ o->internal.result.split_index = o->src_index->split_index;
+ if (o->src_index->cache_changed & SPLIT_INDEX_ORDERED)
+ o->internal.result.cache_changed |= SPLIT_INDEX_ORDERED;
+ o->internal.result.split_index->refcount++;
} else {
- o->result.split_index = init_split_index(&o->result);
+ o->internal.result.split_index =
+ init_split_index(&o->internal.result);
}
- oidcpy(&o->result.oid, &o->src_index->oid);
- o->merge_size = len;
+ oidcpy(&o->internal.result.oid, &o->src_index->oid);
+ o->internal.merge_size = len;
mark_all_ce_unused(o->src_index);
- o->result.fsmonitor_last_update =
+ o->internal.result.fsmonitor_last_update =
xstrdup_or_null(o->src_index->fsmonitor_last_update);
- o->result.fsmonitor_has_run_once = o->src_index->fsmonitor_has_run_once;
+ o->internal.result.fsmonitor_has_run_once = o->src_index->fsmonitor_has_run_once;
if (!o->src_index->initialized &&
!repo->settings.command_requires_full_index &&
- is_sparse_index_allowed(&o->result, 0))
- o->result.sparse_index = 1;
+ is_sparse_index_allowed(&o->internal.result, 0))
+ o->internal.result.sparse_index = 1;
/*
* Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
*/
if (!o->skip_sparse_checkout)
- mark_new_skip_worktree(o->pl, o->src_index, 0,
+ mark_new_skip_worktree(o->internal.pl, o->src_index, 0,
CE_NEW_SKIP_WORKTREE, o->verbose_update);
if (!dfc)
@@ -1955,7 +1972,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
setup_traverse_info(&info, prefix);
info.fn = unpack_callback;
info.data = o;
- info.show_all_errors = o->show_all_errors;
+ info.show_all_errors = o->internal.show_all_errors;
info.pathspec = o->pathspec;
if (o->prefix) {
@@ -1996,7 +2013,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
}
mark_all_ce_unused(o->src_index);
- if (o->trivial_merges_only && o->nontrivial_merge) {
+ if (o->trivial_merges_only && o->internal.nontrivial_merge) {
ret = unpack_failed(o, "Merge requires file-level merging");
goto done;
}
@@ -2007,13 +2024,13 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
* If they will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE
* so apply_sparse_checkout() won't attempt to remove it from worktree
*/
- mark_new_skip_worktree(o->pl, &o->result,
+ mark_new_skip_worktree(o->internal.pl, &o->internal.result,
CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE,
o->verbose_update);
ret = 0;
- for (i = 0; i < o->result.cache_nr; i++) {
- struct cache_entry *ce = o->result.cache[i];
+ for (i = 0; i < o->internal.result.cache_nr; i++) {
+ struct cache_entry *ce = o->internal.result.cache[i];
/*
* Entries marked with CE_ADDED in merged_entry() do not have
@@ -2027,7 +2044,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
verify_absent(ce, WARNING_SPARSE_ORPHANED_NOT_OVERWRITTEN, o))
ret = 1;
- if (apply_sparse_checkout(&o->result, ce, o))
+ if (apply_sparse_checkout(&o->internal.result, ce, o))
ret = 1;
}
if (ret == 1) {
@@ -2035,46 +2052,47 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
* Inability to sparsify or de-sparsify individual
* paths is not an error, but just a warning.
*/
- if (o->show_all_errors)
+ if (o->internal.show_all_errors)
display_warning_msgs(o);
ret = 0;
}
}
- ret = check_updates(o, &o->result) ? (-2) : 0;
+ ret = check_updates(o, &o->internal.result) ? (-2) : 0;
if (o->dst_index) {
- move_index_extensions(&o->result, o->src_index);
+ move_index_extensions(&o->internal.result, o->src_index);
if (!ret) {
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
- cache_tree_verify(the_repository, &o->result);
+ cache_tree_verify(the_repository,
+ &o->internal.result);
if (!o->skip_cache_tree_update &&
- !cache_tree_fully_valid(o->result.cache_tree))
- cache_tree_update(&o->result,
+ !cache_tree_fully_valid(o->internal.result.cache_tree))
+ cache_tree_update(&o->internal.result,
WRITE_TREE_SILENT |
WRITE_TREE_REPAIR);
}
- o->result.updated_workdir = 1;
+ o->internal.result.updated_workdir = 1;
discard_index(o->dst_index);
- *o->dst_index = o->result;
+ *o->dst_index = o->internal.result;
} else {
- discard_index(&o->result);
+ discard_index(&o->internal.result);
}
o->src_index = NULL;
done:
if (free_pattern_list)
clear_pattern_list(&pl);
- if (o->dir) {
- dir_clear(o->dir);
- o->dir = NULL;
+ if (o->internal.dir) {
+ dir_clear(o->internal.dir);
+ o->internal.dir = NULL;
}
trace2_region_leave("unpack_trees", "unpack_trees", the_repository);
trace_performance_leave("unpack_trees");
return ret;
return_failed:
- if (o->show_all_errors)
+ if (o->internal.show_all_errors)
display_error_msgs(o);
mark_all_ce_unused(o->src_index);
ret = unpack_failed(o, NULL);
@@ -2089,16 +2107,17 @@ return_failed:
*
* CE_NEW_SKIP_WORKTREE is used internally.
*/
-enum update_sparsity_result update_sparsity(struct unpack_trees_options *o)
+enum update_sparsity_result update_sparsity(struct unpack_trees_options *o,
+ struct pattern_list *pl)
{
enum update_sparsity_result ret = UPDATE_SPARSITY_SUCCESS;
- struct pattern_list pl;
int i;
unsigned old_show_all_errors;
int free_pattern_list = 0;
- old_show_all_errors = o->show_all_errors;
- o->show_all_errors = 1;
+ old_show_all_errors = o->internal.show_all_errors;
+ o->internal.show_all_errors = 1;
+ index_state_init(&o->internal.result, o->src_index->repo);
/* Sanity checks */
if (!o->update || o->index_only || o->skip_sparse_checkout)
@@ -2109,20 +2128,19 @@ enum update_sparsity_result update_sparsity(struct unpack_trees_options *o)
trace_performance_enter();
/* If we weren't given patterns, use the recorded ones */
- if (!o->pl) {
- memset(&pl, 0, sizeof(pl));
+ if (!pl) {
free_pattern_list = 1;
- populate_from_existing_patterns(o, &pl);
- if (o->skip_sparse_checkout)
- goto skip_sparse_checkout;
+ pl = xcalloc(1, sizeof(*pl));
+ populate_from_existing_patterns(o, pl);
}
+ o->internal.pl = pl;
/* Expand sparse directories as needed */
- expand_index(o->src_index, o->pl);
+ expand_index(o->src_index, o->internal.pl);
/* Set NEW_SKIP_WORKTREE on existing entries. */
mark_all_ce_unused(o->src_index);
- mark_new_skip_worktree(o->pl, o->src_index, 0,
+ mark_new_skip_worktree(o->internal.pl, o->src_index, 0,
CE_NEW_SKIP_WORKTREE, o->verbose_update);
/* Then loop over entries and update/remove as needed */
@@ -2142,14 +2160,16 @@ enum update_sparsity_result update_sparsity(struct unpack_trees_options *o)
ret = UPDATE_SPARSITY_WARNINGS;
}
-skip_sparse_checkout:
if (check_updates(o, o->src_index))
ret = UPDATE_SPARSITY_WORKTREE_UPDATE_FAILURES;
display_warning_msgs(o);
- o->show_all_errors = old_show_all_errors;
- if (free_pattern_list)
- clear_pattern_list(&pl);
+ o->internal.show_all_errors = old_show_all_errors;
+ if (free_pattern_list) {
+ clear_pattern_list(pl);
+ free(pl);
+ o->internal.pl = NULL;
+ }
trace_performance_leave("update_sparsity");
return ret;
}
@@ -2244,15 +2264,15 @@ static int verify_uptodate_sparse(const struct cache_entry *ce,
}
/*
- * TODO: We should actually invalidate o->result, not src_index [1].
+ * TODO: We should actually invalidate o->internal.result, not src_index [1].
* But since cache tree and untracked cache both are not copied to
- * o->result until unpacking is complete, we invalidate them on
+ * o->internal.result until unpacking is complete, we invalidate them on
* src_index instead with the assumption that they will be copied to
* dst_index at the end.
*
* [1] src_index->cache_tree is also used in unpack_callback() so if
- * we invalidate o->result, we need to update it to use
- * o->result.cache_tree as well.
+ * we invalidate o->internal.result, we need to update it to use
+ * o->internal.result.cache_tree as well.
*/
static void invalidate_ce_path(const struct cache_entry *ce,
struct unpack_trees_options *o)
@@ -2336,8 +2356,8 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,
pathbuf = xstrfmt("%.*s/", namelen, ce->name);
memset(&d, 0, sizeof(d));
- if (o->dir)
- d.exclude_per_dir = o->dir->exclude_per_dir;
+ if (o->internal.dir)
+ setup_standard_excludes(&d);
i = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);
dir_clear(&d);
free(pathbuf);
@@ -2391,8 +2411,8 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
if (ignore_case && icase_exists(o, name, len, st))
return 0;
- if (o->dir &&
- is_excluded(o->dir, o->src_index, name, &dtype))
+ if (o->internal.dir &&
+ is_excluded(o->internal.dir, o->src_index, name, &dtype))
/*
* ce->name is explicitly excluded, so it is Ok to
* overwrite it.
@@ -2420,7 +2440,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
* delete this path, which is in a subdirectory that
* is being replaced with a blob.
*/
- result = index_file_exists(&o->result, name, len, 0);
+ result = index_file_exists(&o->internal.result, name, len, 0);
if (result) {
if (result->ce_flags & CE_REMOVE)
return 0;
@@ -2521,7 +2541,7 @@ static int merged_entry(const struct cache_entry *ce,
struct unpack_trees_options *o)
{
int update = CE_UPDATE;
- struct cache_entry *merge = dup_cache_entry(ce, &o->result);
+ struct cache_entry *merge = dup_cache_entry(ce, &o->internal.result);
if (!old) {
/*
@@ -2616,7 +2636,7 @@ static int merged_sparse_dir(const struct cache_entry * const *src, int n,
setup_traverse_info(&info, src[0]->name);
info.fn = unpack_sparse_callback;
info.data = o;
- info.show_all_errors = o->show_all_errors;
+ info.show_all_errors = o->internal.show_all_errors;
info.pathspec = o->pathspec;
/* Get the tree descriptors of the sparse directory in each of the merging trees */
@@ -2834,7 +2854,7 @@ int threeway_merge(const struct cache_entry * const *stages,
return -1;
}
- o->nontrivial_merge = 1;
+ o->internal.nontrivial_merge = 1;
/* #2, #3, #4, #6, #7, #9, #10, #11. */
count = 0;
@@ -2875,9 +2895,9 @@ int twoway_merge(const struct cache_entry * const *src,
const struct cache_entry *oldtree = src[1];
const struct cache_entry *newtree = src[2];
- if (o->merge_size != 2)
+ if (o->internal.merge_size != 2)
return error("Cannot do a twoway merge of %d trees",
- o->merge_size);
+ o->internal.merge_size);
if (oldtree == o->df_conflict_entry)
oldtree = NULL;
@@ -2957,9 +2977,9 @@ int bind_merge(const struct cache_entry * const *src,
const struct cache_entry *old = src[0];
const struct cache_entry *a = src[1];
- if (o->merge_size != 1)
+ if (o->internal.merge_size != 1)
return error("Cannot do a bind merge of %d trees",
- o->merge_size);
+ o->internal.merge_size);
if (a && old)
return o->quiet ? -1 :
error(ERRORMSG(o, ERROR_BIND_OVERLAP),
@@ -2983,9 +3003,9 @@ int oneway_merge(const struct cache_entry * const *src,
const struct cache_entry *old = src[0];
const struct cache_entry *a = src[1];
- if (o->merge_size != 1)
+ if (o->internal.merge_size != 1)
return error("Cannot do a oneway merge of %d trees",
- o->merge_size);
+ o->internal.merge_size);
if (!a || a == o->df_conflict_entry)
return deleted_entry(old, old, o);
@@ -3020,8 +3040,8 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,
const struct cache_entry *worktree = src[1];
const struct cache_entry *untracked = src[2];
- if (o->merge_size != 2)
- BUG("invalid merge_size: %d", o->merge_size);
+ if (o->internal.merge_size != 2)
+ BUG("invalid merge_size: %d", o->internal.merge_size);
if (worktree && untracked)
return error(_("worktree and untracked commit have duplicate entries: %s"),
diff --git a/unpack-trees.h b/unpack-trees.h
index 3a7b3e5f00..9b827c307f 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -1,7 +1,8 @@
#ifndef UNPACK_TREES_H
#define UNPACK_TREES_H
-#include "cache.h"
+#include "convert.h"
+#include "read-cache-ll.h"
#include "strvec.h"
#include "string-list.h"
#include "tree-walk.h"
@@ -59,47 +60,54 @@ struct unpack_trees_options {
preserve_ignored,
clone,
index_only,
- nontrivial_merge,
trivial_merges_only,
verbose_update,
aggressive,
skip_unmerged,
initial_checkout,
diff_index_cached,
- debug_unpack,
skip_sparse_checkout,
quiet,
exiting_early,
- show_all_errors,
dry_run,
skip_cache_tree_update;
enum unpack_trees_reset_type reset;
const char *prefix;
const char *super_prefix;
- int cache_bottom;
struct pathspec *pathspec;
merge_fn_t fn;
- const char *msgs[NB_UNPACK_TREES_WARNING_TYPES];
- struct strvec msgs_to_free;
- /*
- * Store error messages in an array, each case
- * corresponding to a error message type
- */
- struct string_list unpack_rejects[NB_UNPACK_TREES_WARNING_TYPES];
int head_idx;
- int merge_size;
- struct cache_entry *df_conflict_entry;
+ struct cache_entry *df_conflict_entry; /* output only */
void *unpack_data;
struct index_state *dst_index;
struct index_state *src_index;
- struct index_state result;
- struct pattern_list *pl; /* for internal use */
- struct dir_struct *dir; /* for internal use only */
struct checkout_metadata meta;
+
+ struct unpack_trees_options_internal {
+ unsigned int nontrivial_merge,
+ show_all_errors,
+ debug_unpack; /* used by read-tree debugging */
+
+ int merge_size; /* used by read-tree debugging */
+ int cache_bottom;
+ const char *msgs[NB_UNPACK_TREES_WARNING_TYPES];
+ struct strvec msgs_to_free;
+
+ /*
+ * Store error messages in an array, each case
+ * corresponding to a error message type
+ */
+ struct string_list unpack_rejects[NB_UNPACK_TREES_WARNING_TYPES];
+
+ struct index_state result;
+
+ struct pattern_list *pl;
+ struct dir_struct *dir;
+ } internal;
};
int unpack_trees(unsigned n, struct tree_desc *t,
@@ -112,7 +120,8 @@ enum update_sparsity_result {
UPDATE_SPARSITY_WORKTREE_UPDATE_FAILURES = -2
};
-enum update_sparsity_result update_sparsity(struct unpack_trees_options *options);
+enum update_sparsity_result update_sparsity(struct unpack_trees_options *options,
+ struct pattern_list *pl);
int verify_uptodate(const struct cache_entry *ce,
struct unpack_trees_options *o);
diff --git a/upload-pack.c b/upload-pack.c
index 551f22ffa5..3a176a7209 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -1,10 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
#include "pkt-line.h"
#include "sideband.h"
#include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
#include "tag.h"
#include "object.h"
#include "commit.h"
@@ -19,6 +23,7 @@
#include "version.h"
#include "string-list.h"
#include "strvec.h"
+#include "trace2.h"
#include "prio-queue.h"
#include "protocol.h"
#include "quote.h"
@@ -27,6 +32,8 @@
#include "commit-graph.h"
#include "commit-reach.h"
#include "shallow.h"
+#include "wrapper.h"
+#include "write-or-die.h"
/* Remember to update object flag allocation in object.h */
#define THEY_HAVE (1u << 11)
@@ -62,7 +69,7 @@ struct upload_pack_data {
struct object_array have_obj;
struct oid_array haves; /* v2 only */
struct string_list wanted_refs; /* v2 only */
- struct string_list hidden_refs;
+ struct strvec hidden_refs;
struct object_array shallows;
struct string_list deepen_not;
@@ -113,13 +120,14 @@ struct upload_pack_data {
unsigned allow_ref_in_want : 1; /* v2 only */
unsigned allow_sideband_all : 1; /* v2 only */
unsigned advertise_sid : 1;
+ unsigned sent_capabilities : 1;
};
static void upload_pack_data_init(struct upload_pack_data *data)
{
struct string_list symref = STRING_LIST_INIT_DUP;
struct string_list wanted_refs = STRING_LIST_INIT_DUP;
- struct string_list hidden_refs = STRING_LIST_INIT_DUP;
+ struct strvec hidden_refs = STRVEC_INIT;
struct object_array want_obj = OBJECT_ARRAY_INIT;
struct object_array have_obj = OBJECT_ARRAY_INIT;
struct oid_array haves = OID_ARRAY_INIT;
@@ -154,7 +162,7 @@ static void upload_pack_data_clear(struct upload_pack_data *data)
{
string_list_clear(&data->symref, 1);
string_list_clear(&data->wanted_refs, 1);
- string_list_clear(&data->hidden_refs, 0);
+ strvec_clear(&data->hidden_refs);
object_array_clear(&data->want_obj);
object_array_clear(&data->have_obj);
oid_array_clear(&data->haves);
@@ -499,8 +507,8 @@ static int got_oid(struct upload_pack_data *data,
{
if (get_oid_hex(hex, oid))
die("git upload-pack: expected SHA1 object, got '%s'", hex);
- if (!has_object_file_with_flags(oid,
- OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
+ if (!repo_has_object_file_with_flags(the_repository, oid,
+ OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
return -1;
return do_got_oid(data, oid);
}
@@ -594,11 +602,32 @@ static int get_common_commits(struct upload_pack_data *data,
}
}
+static int allow_hidden_refs(enum allow_uor allow_uor)
+{
+ return allow_uor & (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1);
+}
+
+static void for_each_namespaced_ref_1(each_ref_fn fn,
+ struct upload_pack_data *data)
+{
+ /*
+ * If `data->allow_uor` allows fetching hidden refs, we need to
+ * mark all references (including hidden ones), to check in
+ * `is_our_ref()` below.
+ *
+ * Otherwise, we only care about whether each reference's object
+ * has the OUR_REF bit set or not, so do not need to visit
+ * hidden references.
+ */
+ if (allow_hidden_refs(data->allow_uor))
+ for_each_namespaced_ref(NULL, fn, data);
+ else
+ for_each_namespaced_ref(data->hidden_refs.v, fn, data);
+}
+
static int is_our_ref(struct object *o, enum allow_uor allow_uor)
{
- int allow_hidden_ref = (allow_uor &
- (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1));
- return o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);
+ return o->flags & ((allow_hidden_refs(allow_uor) ? HIDDEN_REF : 0) | OUR_REF);
}
/*
@@ -847,7 +876,7 @@ static void deepen(struct upload_pack_data *data, int depth)
* marked with OUR_REF.
*/
head_ref_namespaced(check_ref, data);
- for_each_namespaced_ref(check_ref, data);
+ for_each_namespaced_ref_1(check_ref, data);
get_reachable_list(data, &reachable_shallows);
result = get_shallow_commits(&reachable_shallows,
@@ -1063,7 +1092,7 @@ static void receive_needs(struct upload_pack_data *data,
const char *features;
struct object_id oid_buf;
const char *arg;
- int feature_len;
+ size_t feature_len;
reset_timeout(data->timeout);
if (packet_reader_read(reader) != PACKET_READ_NORMAL)
@@ -1162,7 +1191,7 @@ static void receive_needs(struct upload_pack_data *data,
/* return non-zero if the ref is hidden, otherwise 0 */
static int mark_our_ref(const char *refname, const char *refname_full,
- const struct object_id *oid, const struct string_list *hidden_refs)
+ const struct object_id *oid, const struct strvec *hidden_refs)
{
struct object *o = lookup_unknown_object(the_repository, oid);
@@ -1199,18 +1228,17 @@ static void format_session_id(struct strbuf *buf, struct upload_pack_data *d) {
strbuf_addf(buf, " session-id=%s", trace2_session_id());
}
-static int send_ref(const char *refname, const struct object_id *oid,
- int flag UNUSED, void *cb_data)
+static void write_v0_ref(struct upload_pack_data *data,
+ const char *refname, const char *refname_nons,
+ const struct object_id *oid)
{
static const char *capabilities = "multi_ack thin-pack side-band"
" side-band-64k ofs-delta shallow deepen-since deepen-not"
" deepen-relative no-progress include-tag multi_ack_detailed";
- const char *refname_nons = strip_namespace(refname);
struct object_id peeled;
- struct upload_pack_data *data = cb_data;
if (mark_our_ref(refname_nons, refname, oid, &data->hidden_refs))
- return 0;
+ return;
if (capabilities) {
struct strbuf symref_info = STRBUF_INIT;
@@ -1233,12 +1261,20 @@ static int send_ref(const char *refname, const struct object_id *oid,
git_user_agent_sanitized());
strbuf_release(&symref_info);
strbuf_release(&session_id);
+ data->sent_capabilities = 1;
} else {
packet_fwrite_fmt(stdout, "%s %s\n", oid_to_hex(oid), refname_nons);
}
capabilities = NULL;
if (!peel_iterated_oid(oid, &peeled))
packet_fwrite_fmt(stdout, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
+ return;
+}
+
+static int send_ref(const char *refname, const struct object_id *oid,
+ int flag UNUSED, void *cb_data)
+{
+ write_v0_ref(cb_data, refname, strip_namespace(refname), oid);
return 0;
}
@@ -1371,7 +1407,11 @@ void upload_pack(const int advertise_refs, const int stateless_rpc,
if (advertise_refs)
data.no_done = 1;
head_ref_namespaced(send_ref, &data);
- for_each_namespaced_ref(send_ref, &data);
+ for_each_namespaced_ref_1(send_ref, &data);
+ if (!data.sent_capabilities) {
+ const char *refname = "capabilities^{}";
+ write_v0_ref(&data, refname, refname, null_oid());
+ }
/*
* fflush stdout before calling advertise_shallow_grafts because send_ref
* uses stdio.
@@ -1381,7 +1421,7 @@ void upload_pack(const int advertise_refs, const int stateless_rpc,
packet_flush(1);
} else {
head_ref_namespaced(check_ref, &data);
- for_each_namespaced_ref(check_ref, &data);
+ for_each_namespaced_ref_1(check_ref, &data);
}
if (!advertise_refs) {
@@ -1446,7 +1486,7 @@ static int parse_want(struct packet_writer *writer, const char *line,
static int parse_want_ref(struct packet_writer *writer, const char *line,
struct string_list *wanted_refs,
- struct string_list *hidden_refs,
+ struct strvec *hidden_refs,
struct object_array *want_obj)
{
const char *refname_nons;
@@ -1600,8 +1640,8 @@ static int process_haves(struct upload_pack_data *data, struct oid_array *common
for (i = 0; i < data->haves.nr; i++) {
const struct object_id *oid = &data->haves.oid[i];
- if (!has_object_file_with_flags(oid,
- OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
+ if (!repo_has_object_file_with_flags(the_repository, oid,
+ OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
continue;
oid_array_append(common, oid);
@@ -1699,7 +1739,7 @@ enum fetch_state {
FETCH_DONE,
};
-int upload_pack_v2(struct repository *r, struct packet_reader *request)
+int upload_pack_v2(struct repository *r UNUSED, struct packet_reader *request)
{
enum fetch_state state = FETCH_PROCESS_ARGS;
struct upload_pack_data data;
@@ -1775,26 +1815,26 @@ int upload_pack_advertise(struct repository *r,
strbuf_addstr(value, "shallow wait-for-done");
- if (!repo_config_get_bool(the_repository,
+ if (!repo_config_get_bool(r,
"uploadpack.allowfilter",
&allow_filter_value) &&
allow_filter_value)
strbuf_addstr(value, " filter");
- if (!repo_config_get_bool(the_repository,
+ if (!repo_config_get_bool(r,
"uploadpack.allowrefinwant",
&allow_ref_in_want) &&
allow_ref_in_want)
strbuf_addstr(value, " ref-in-want");
if (git_env_bool("GIT_TEST_SIDEBAND_ALL", 0) ||
- (!repo_config_get_bool(the_repository,
+ (!repo_config_get_bool(r,
"uploadpack.allowsidebandall",
&allow_sideband_all_value) &&
allow_sideband_all_value))
strbuf_addstr(value, " sideband-all");
- if (!repo_config_get_string(the_repository,
+ if (!repo_config_get_string(r,
"uploadpack.blobpackfileuri",
&str) &&
str) {
diff --git a/url.c b/url.c
index e04bd60b6b..2e1a9f6fee 100644
--- a/url.c
+++ b/url.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hex.h"
+#include "strbuf.h"
#include "url.h"
int is_urlschemechar(int first_flag, int ch)
diff --git a/urlmatch.c b/urlmatch.c
index 620a648efc..eba0bdd77f 100644
--- a/urlmatch.c
+++ b/urlmatch.c
@@ -1,4 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
+#include "strbuf.h"
#include "urlmatch.h"
#define URL_ALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
diff --git a/usage.c b/usage.c
index 5a7c6c346c..46d99f8bd4 100644
--- a/usage.c
+++ b/usage.c
@@ -4,7 +4,9 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include "git-compat-util.h"
-#include "cache.h"
+#include "gettext.h"
+#include "trace2.h"
+#include "wrapper.h"
static void vreportf(const char *prefix, const char *err, va_list params)
{
diff --git a/userdiff.c b/userdiff.c
index 58a3d59ef8..664c7c1402 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -1,7 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
#include "config.h"
#include "userdiff.h"
#include "attr.h"
+#include "strbuf.h"
static struct userdiff_driver *drivers;
static int ndrivers;
@@ -15,6 +17,7 @@ static int drivers_alloc;
.cflags = REG_EXTENDED, \
}, \
.word_regex = wrx "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+", \
+ .word_regex_multi_byte = wrx "|[^[:space:]]", \
}
#define IPATTERN(lang, rx, wrx) { \
.name = lang, \
@@ -24,6 +27,7 @@ static int drivers_alloc;
.cflags = REG_EXTENDED | REG_ICASE, \
}, \
.word_regex = wrx "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+", \
+ .word_regex_multi_byte = wrx "|[^[:space:]]", \
}
/*
@@ -292,7 +296,7 @@ PATTERNS("scheme",
/* All other words should be delimited by spaces or parentheses */
"|([^][)(}{[ \t])+"),
PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
- "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"),
+ "\\\\[a-zA-Z@]+|\\\\.|([a-zA-Z0-9]|[^\x01-\x7f])+"),
{ "default", NULL, NULL, -1, { NULL, 0 } },
};
#undef PATTERNS
@@ -328,6 +332,25 @@ static int userdiff_find_by_namelen_cb(struct userdiff_driver *driver,
return 0;
}
+static int regexec_supports_multi_byte_chars(void)
+{
+ static const char not_space[] = "[^[:space:]]";
+ static const char utf8_multi_byte_char[] = "\xc2\xa3";
+ regex_t re;
+ regmatch_t match;
+ static int result = -1;
+
+ if (result != -1)
+ return result;
+ if (regcomp(&re, not_space, REG_EXTENDED))
+ BUG("invalid regular expression: %s", not_space);
+ result = !regexec(&re, utf8_multi_byte_char, 1, &match, 0) &&
+ match.rm_so == 0 &&
+ match.rm_eo == strlen(utf8_multi_byte_char);
+ regfree(&re);
+ return result;
+}
+
static struct userdiff_driver *userdiff_find_by_namelen(const char *name, size_t len)
{
struct find_by_namelen_data udcbdata = {
@@ -403,7 +426,13 @@ int userdiff_config(const char *k, const char *v)
struct userdiff_driver *userdiff_find_by_name(const char *name)
{
int len = strlen(name);
- return userdiff_find_by_namelen(name, len);
+ struct userdiff_driver *driver = userdiff_find_by_namelen(name, len);
+ if (driver && driver->word_regex_multi_byte) {
+ if (regexec_supports_multi_byte_chars())
+ driver->word_regex = driver->word_regex_multi_byte;
+ driver->word_regex_multi_byte = NULL;
+ }
+ return driver;
}
struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
@@ -415,7 +444,7 @@ struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
check = attr_check_initl("diff", NULL);
if (!path)
return NULL;
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
if (ATTR_TRUE(check->items[0].value))
return &driver_true;
diff --git a/userdiff.h b/userdiff.h
index 24419db697..d726804c3e 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -18,6 +18,7 @@ struct userdiff_driver {
int binary;
struct userdiff_funcname funcname;
const char *word_regex;
+ const char *word_regex_multi_byte;
const char *textconv;
struct notes_cache *textconv_cache;
int textconv_want_cache;
diff --git a/versioncmp.c b/versioncmp.c
index 069ee94a4d..74cc7c43f0 100644
--- a/versioncmp.c
+++ b/versioncmp.c
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "string-list.h"
+#include "versioncmp.h"
/*
* versioncmp(): copied from string/strverscmp.c in glibc commit
@@ -160,15 +161,21 @@ int versioncmp(const char *s1, const char *s2)
}
if (!initialized) {
- const struct string_list *deprecated_prereleases;
+ const char *const newk = "versionsort.suffix";
+ const char *const oldk = "versionsort.prereleasesuffix";
+ const struct string_list *newl;
+ const struct string_list *oldl;
+ int new = git_config_get_string_multi(newk, &newl);
+ int old = git_config_get_string_multi(oldk, &oldl);
+
+ if (!new && !old)
+ warning("ignoring %s because %s is set", oldk, newk);
+ if (!new)
+ prereleases = newl;
+ else if (!old)
+ prereleases = oldl;
+
initialized = 1;
- prereleases = git_config_get_value_multi("versionsort.suffix");
- deprecated_prereleases = git_config_get_value_multi("versionsort.prereleasesuffix");
- if (prereleases) {
- if (deprecated_prereleases)
- warning("ignoring versionsort.prereleasesuffix because versionsort.suffix is set");
- } else
- prereleases = deprecated_prereleases;
}
if (prereleases && swap_prereleases(s1, s2, (const char *) p1 - s1 - 1,
&diff))
diff --git a/versioncmp.h b/versioncmp.h
new file mode 100644
index 0000000000..879b510e82
--- /dev/null
+++ b/versioncmp.h
@@ -0,0 +1,6 @@
+#ifndef VERSIONCMP_H
+#define VERSIONCMP_H
+
+int versioncmp(const char *s1, const char *s2);
+
+#endif /* VERSIONCMP_H */
diff --git a/walker.c b/walker.c
index 99d0e0eae0..65002a7220 100644
--- a/walker.c
+++ b/walker.c
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
#include "walker.h"
#include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "commit.h"
+#include "strbuf.h"
#include "tree.h"
#include "tree-walk.h"
#include "tag.h"
@@ -79,7 +82,7 @@ static int process_commit(struct walker *walker, struct commit *commit)
{
struct commit_list *parents;
- if (parse_commit(commit))
+ if (repo_parse_commit(the_repository, commit))
return -1;
while (complete && complete->item->date >= commit->date) {
@@ -93,7 +96,7 @@ static int process_commit(struct walker *walker, struct commit *commit)
walker_say(walker, "walk %s\n", oid_to_hex(&commit->object.oid));
- if (process(walker, &get_commit_tree(commit)->object))
+ if (process(walker, &repo_get_commit_tree(the_repository, commit)->object))
return -1;
for (parents = commit->parents; parents; parents = parents->next) {
@@ -145,7 +148,7 @@ static int process(struct walker *walker, struct object *obj)
return 0;
obj->flags |= SEEN;
- if (has_object_file(&obj->oid)) {
+ if (repo_has_object_file(the_repository, &obj->oid)) {
/* We already have it, so we should scan it now. */
obj->flags |= TO_SCAN;
}
diff --git a/wildmatch.c b/wildmatch.c
index 7e5a7ea1ea..8ea29141bd 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -9,11 +9,15 @@
** work differently than '*', and to fix the character-class code.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "wildmatch.h"
typedef unsigned char uchar;
+/* Internal return values */
+#define WM_ABORT_ALL -1
+#define WM_ABORT_TO_STARSTAR -2
+
/* What character marks an inverted character class? */
#define NEGATE_CLASS '!'
#define NEGATE_CLASS2 '^'
@@ -83,12 +87,12 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
continue;
case '*':
if (*++p == '*') {
- const uchar *prev_p = p - 2;
+ const uchar *prev_p = p;
while (*++p == '*') {}
if (!(flags & WM_PATHNAME))
/* without WM_PATHNAME, '*' == '**' */
match_slash = 1;
- else if ((prev_p < pattern || *prev_p == '/') &&
+ else if ((prev_p - pattern < 2 || *(prev_p - 2) == '/') &&
(*p == '\0' || *p == '/' ||
(p[0] == '\\' && p[1] == '/'))) {
/*
@@ -114,7 +118,7 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
* only if there are no more slash characters. */
if (!match_slash) {
if (strchr((char *)text, '/'))
- return WM_NOMATCH;
+ return WM_ABORT_TO_STARSTAR;
}
return WM_MATCH;
} else if (!match_slash && *p == '/') {
@@ -125,7 +129,7 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
*/
const char *slash = strchr((char*)text, '/');
if (!slash)
- return WM_NOMATCH;
+ return WM_ABORT_ALL;
text = (const uchar*)slash;
/* the slash is consumed by the top-level for loop */
break;
@@ -153,8 +157,12 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
break;
text++;
}
- if (t_ch != p_ch)
- return WM_NOMATCH;
+ if (t_ch != p_ch) {
+ if (match_slash)
+ return WM_ABORT_ALL;
+ else
+ return WM_ABORT_TO_STARSTAR;
+ }
}
if ((matched = dowild(p, text, flags)) != WM_NOMATCH) {
if (!match_slash || matched != WM_ABORT_TO_STARSTAR)
@@ -274,5 +282,6 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
/* Match the "pattern" against the "text" string. */
int wildmatch(const char *pattern, const char *text, unsigned int flags)
{
- return dowild((const uchar*)pattern, (const uchar*)text, flags);
+ int res = dowild((const uchar*)pattern, (const uchar*)text, flags);
+ return res == WM_MATCH ? WM_MATCH : WM_NOMATCH;
}
diff --git a/wildmatch.h b/wildmatch.h
index 5993696298..0c890cb56b 100644
--- a/wildmatch.h
+++ b/wildmatch.h
@@ -6,8 +6,6 @@
#define WM_NOMATCH 1
#define WM_MATCH 0
-#define WM_ABORT_ALL -1
-#define WM_ABORT_TO_STARSTAR -2
int wildmatch(const char *pattern, const char *text, unsigned int flags);
#endif
diff --git a/worktree.c b/worktree.c
index aa43c64119..f9aa371ca7 100644
--- a/worktree.c
+++ b/worktree.c
@@ -1,11 +1,18 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "alloc.h"
+#include "environment.h"
+#include "gettext.h"
+#include "path.h"
#include "repository.h"
#include "refs.h"
+#include "setup.h"
#include "strbuf.h"
#include "worktree.h"
#include "dir.h"
#include "wt-status.h"
#include "config.h"
+#include "wrapper.h"
void free_worktrees(struct worktree **worktrees)
{
@@ -403,44 +410,43 @@ int is_worktree_being_bisected(const struct worktree *wt,
* bisect). New commands that do similar things should update this
* function as well.
*/
-const struct worktree *find_shared_symref(struct worktree **worktrees,
- const char *symref,
- const char *target)
+int is_shared_symref(const struct worktree *wt, const char *symref,
+ const char *target)
{
- const struct worktree *existing = NULL;
- int i = 0;
+ const char *symref_target;
+ struct ref_store *refs;
+ int flags;
- for (i = 0; worktrees[i]; i++) {
- struct worktree *wt = worktrees[i];
- const char *symref_target;
- struct ref_store *refs;
- int flags;
+ if (wt->is_bare)
+ return 0;
- if (wt->is_bare)
- continue;
+ if (wt->is_detached && !strcmp(symref, "HEAD")) {
+ if (is_worktree_being_rebased(wt, target))
+ return 1;
+ if (is_worktree_being_bisected(wt, target))
+ return 1;
+ }
- if (wt->is_detached && !strcmp(symref, "HEAD")) {
- if (is_worktree_being_rebased(wt, target)) {
- existing = wt;
- break;
- }
- if (is_worktree_being_bisected(wt, target)) {
- existing = wt;
- break;
- }
- }
+ refs = get_worktree_ref_store(wt);
+ symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
+ NULL, &flags);
+ if ((flags & REF_ISSYMREF) &&
+ symref_target && !strcmp(symref_target, target))
+ return 1;
- refs = get_worktree_ref_store(wt);
- symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
- NULL, &flags);
- if ((flags & REF_ISSYMREF) &&
- symref_target && !strcmp(symref_target, target)) {
- existing = wt;
- break;
- }
- }
+ return 0;
+}
- return existing;
+const struct worktree *find_shared_symref(struct worktree **worktrees,
+ const char *symref,
+ const char *target)
+{
+
+ for (int i = 0; worktrees[i]; i++)
+ if (is_shared_symref(worktrees[i], symref, target))
+ return worktrees[i];
+
+ return NULL;
}
int submodule_uses_worktrees(const char *path)
diff --git a/worktree.h b/worktree.h
index 9dcea6fc8c..ce45b66de9 100644
--- a/worktree.h
+++ b/worktree.h
@@ -1,7 +1,6 @@
#ifndef WORKTREE_H
#define WORKTREE_H
-#include "cache.h"
#include "refs.h"
struct strbuf;
@@ -150,6 +149,12 @@ const struct worktree *find_shared_symref(struct worktree **worktrees,
const char *target);
/*
+ * Returns true if a symref points to a ref in a worktree.
+ */
+int is_shared_symref(const struct worktree *wt,
+ const char *symref, const char *target);
+
+/*
* Similar to head_ref() for all HEADs _except_ one from the current
* worktree, which is covered by head_ref().
*/
diff --git a/wrapper.c b/wrapper.c
index 299d6489a6..67f5f5dbe1 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -1,8 +1,15 @@
/*
* Various trivial helper wrappers around standard functions
*/
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "config.h"
+#include "gettext.h"
+#include "object.h"
+#include "repository.h"
+#include "strbuf.h"
+#include "trace2.h"
+#include "wrapper.h"
static intmax_t count_fsync_writeout_only;
static intmax_t count_fsync_hardware_flush;
diff --git a/wrapper.h b/wrapper.h
new file mode 100644
index 0000000000..f0c7d0616d
--- /dev/null
+++ b/wrapper.h
@@ -0,0 +1,36 @@
+#ifndef WRAPPER_H
+#define WRAPPER_H
+
+/* set default permissions by passing mode arguments to open(2) */
+int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
+int git_mkstemp_mode(char *pattern, int mode);
+
+ssize_t read_in_full(int fd, void *buf, size_t count);
+ssize_t write_in_full(int fd, const void *buf, size_t count);
+ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
+
+static inline ssize_t write_str_in_full(int fd, const char *str)
+{
+ return write_in_full(fd, str, strlen(str));
+}
+
+/**
+ * Open (and truncate) the file at path, write the contents of buf to it,
+ * and close it. Dies if any errors are encountered.
+ */
+void write_file_buf(const char *path, const char *buf, size_t len);
+
+/**
+ * Like write_file_buf(), but format the contents into a buffer first.
+ * Additionally, write_file() will append a newline if one is not already
+ * present, making it convenient to write text files:
+ *
+ * write_file(path, "counter: %d", ctr);
+ */
+__attribute__((format (printf, 2, 3)))
+void write_file(const char *path, const char *fmt, ...);
+
+/* Return 1 if the file is empty or does not exists, 0 otherwise. */
+int is_empty_or_missing_file(const char *filename);
+
+#endif /* WRAPPER_H */
diff --git a/write-or-die.c b/write-or-die.c
index aaa0318e82..cc9e0787a1 100644
--- a/write-or-die.c
+++ b/write-or-die.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "run-command.h"
+#include "wrapper.h"
+#include "write-or-die.h"
/*
* Some cases use stdio, but want to flush after the write
diff --git a/write-or-die.h b/write-or-die.h
new file mode 100644
index 0000000000..65a5c42a47
--- /dev/null
+++ b/write-or-die.h
@@ -0,0 +1,78 @@
+#ifndef WRITE_OR_DIE_H
+#define WRITE_OR_DIE_H
+
+void maybe_flush_or_die(FILE *, const char *);
+__attribute__((format (printf, 2, 3)))
+void fprintf_or_die(FILE *, const char *fmt, ...);
+void fwrite_or_die(FILE *f, const void *buf, size_t count);
+void fflush_or_die(FILE *f);
+void write_or_die(int fd, const void *buf, size_t count);
+
+/*
+ * These values are used to help identify parts of a repository to fsync.
+ * FSYNC_COMPONENT_NONE identifies data that will not be a persistent part of the
+ * repository and so shouldn't be fsynced.
+ */
+enum fsync_component {
+ FSYNC_COMPONENT_NONE,
+ FSYNC_COMPONENT_LOOSE_OBJECT = 1 << 0,
+ FSYNC_COMPONENT_PACK = 1 << 1,
+ FSYNC_COMPONENT_PACK_METADATA = 1 << 2,
+ FSYNC_COMPONENT_COMMIT_GRAPH = 1 << 3,
+ FSYNC_COMPONENT_INDEX = 1 << 4,
+ FSYNC_COMPONENT_REFERENCE = 1 << 5,
+};
+
+#define FSYNC_COMPONENTS_OBJECTS (FSYNC_COMPONENT_LOOSE_OBJECT | \
+ FSYNC_COMPONENT_PACK)
+
+#define FSYNC_COMPONENTS_DERIVED_METADATA (FSYNC_COMPONENT_PACK_METADATA | \
+ FSYNC_COMPONENT_COMMIT_GRAPH)
+
+#define FSYNC_COMPONENTS_DEFAULT ((FSYNC_COMPONENTS_OBJECTS | \
+ FSYNC_COMPONENTS_DERIVED_METADATA) & \
+ ~FSYNC_COMPONENT_LOOSE_OBJECT)
+
+#define FSYNC_COMPONENTS_COMMITTED (FSYNC_COMPONENTS_OBJECTS | \
+ FSYNC_COMPONENT_REFERENCE)
+
+#define FSYNC_COMPONENTS_ADDED (FSYNC_COMPONENTS_COMMITTED | \
+ FSYNC_COMPONENT_INDEX)
+
+#define FSYNC_COMPONENTS_ALL (FSYNC_COMPONENT_LOOSE_OBJECT | \
+ FSYNC_COMPONENT_PACK | \
+ FSYNC_COMPONENT_PACK_METADATA | \
+ FSYNC_COMPONENT_COMMIT_GRAPH | \
+ FSYNC_COMPONENT_INDEX | \
+ FSYNC_COMPONENT_REFERENCE)
+
+#ifndef FSYNC_COMPONENTS_PLATFORM_DEFAULT
+#define FSYNC_COMPONENTS_PLATFORM_DEFAULT FSYNC_COMPONENTS_DEFAULT
+#endif
+
+/* IO helper functions */
+void fsync_or_die(int fd, const char *);
+int fsync_component(enum fsync_component component, int fd);
+void fsync_component_or_die(enum fsync_component component, int fd, const char *msg);
+
+/*
+ * A bitmask indicating which components of the repo should be fsynced.
+ */
+extern enum fsync_component fsync_components;
+extern int fsync_object_files;
+extern int use_fsync;
+
+enum fsync_method {
+ FSYNC_METHOD_FSYNC,
+ FSYNC_METHOD_WRITEOUT_ONLY,
+ FSYNC_METHOD_BATCH,
+};
+
+extern enum fsync_method fsync_method;
+
+static inline int batch_fsync_enabled(enum fsync_component component)
+{
+ return (fsync_components & component) && (fsync_method == FSYNC_METHOD_BATCH);
+}
+
+#endif /* WRITE_OR_DIE_H */
diff --git a/ws.c b/ws.c
index da3d0e28cb..9456e2fdbe 100644
--- a/ws.c
+++ b/ws.c
@@ -3,8 +3,12 @@
*
* Copyright (c) 2007 Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "attr.h"
+#include "strbuf.h"
+#include "ws.h"
+
+unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
static struct whitespace_rule {
const char *rule_name;
@@ -79,7 +83,7 @@ unsigned whitespace_rule(struct index_state *istate, const char *pathname)
if (!attr_whitespace_rule)
attr_whitespace_rule = attr_check_initl("whitespace", NULL);
- git_check_attr(istate, NULL, pathname, attr_whitespace_rule);
+ git_check_attr(istate, pathname, attr_whitespace_rule);
value = attr_whitespace_rule->items[0].value;
if (ATTR_TRUE(value)) {
/* true (whitespace) */
diff --git a/ws.h b/ws.h
new file mode 100644
index 0000000000..5ba676c559
--- /dev/null
+++ b/ws.h
@@ -0,0 +1,33 @@
+#ifndef WS_H
+#define WS_H
+
+struct index_state;
+struct strbuf;
+
+/*
+ * whitespace rules.
+ * used by both diff and apply
+ * last two digits are tab width
+ */
+#define WS_BLANK_AT_EOL 0100
+#define WS_SPACE_BEFORE_TAB 0200
+#define WS_INDENT_WITH_NON_TAB 0400
+#define WS_CR_AT_EOL 01000
+#define WS_BLANK_AT_EOF 02000
+#define WS_TAB_IN_INDENT 04000
+#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
+#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
+#define WS_TAB_WIDTH_MASK 077
+/* All WS_* -- when extended, adapt diff.c emit_symbol */
+#define WS_RULE_MASK 07777
+extern unsigned whitespace_rule_cfg;
+unsigned whitespace_rule(struct index_state *, const char *);
+unsigned parse_whitespace_rule(const char *);
+unsigned ws_check(const char *line, int len, unsigned ws_rule);
+void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
+char *whitespace_error_string(unsigned ws);
+void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
+int ws_blank_line(const char *line, int len);
+#define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK)
+
+#endif /* WS_H */
diff --git a/wt-status.c b/wt-status.c
index 3162241a57..ea4e49c42b 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1,9 +1,16 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
#include "wt-status.h"
#include "object.h"
#include "dir.h"
#include "commit.h"
#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "object-name.h"
+#include "path.h"
#include "revision.h"
#include "diffcore.h"
#include "quote.h"
@@ -13,7 +20,12 @@
#include "refs.h"
#include "submodule.h"
#include "column.h"
+#include "read-cache.h"
+#include "setup.h"
#include "strbuf.h"
+#include "trace.h"
+#include "trace2.h"
+#include "tree.h"
#include "utf8.h"
#include "worktree.h"
#include "lockfile.h"
@@ -1015,7 +1027,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom
if (s->display_comment_prefix) {
size_t len;
summary_content = strbuf_detach(&summary, &len);
- strbuf_add_commented_lines(&summary, summary_content, len);
+ strbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);
free(summary_content);
}
@@ -1090,8 +1102,8 @@ void wt_status_append_cut_line(struct strbuf *buf)
{
const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
- strbuf_commented_addf(buf, "%s", cut_line);
- strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+ strbuf_commented_addf(buf, comment_line_char, "%s", cut_line);
+ strbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);
}
void wt_status_add_cut_line(FILE *fp)
@@ -1337,7 +1349,7 @@ static void abbrev_oid_in_line(struct strbuf *line)
* it after abbreviation.
*/
strbuf_trim(split[1]);
- if (!get_oid(split[1]->buf, &oid)) {
+ if (!repo_get_oid(the_repository, split[1]->buf, &oid)) {
strbuf_reset(split[1]);
strbuf_add_unique_abbrev(split[1], &oid,
DEFAULT_ABBREV);
@@ -1503,8 +1515,8 @@ static void show_cherry_pick_in_progress(struct wt_status *s,
else
status_printf_ln(s, color,
_("You are currently cherry-picking commit %s."),
- find_unique_abbrev(&s->state.cherry_pick_head_oid,
- DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &s->state.cherry_pick_head_oid,
+ DEFAULT_ABBREV));
if (s->hints) {
if (has_unmerged(s))
@@ -1533,8 +1545,8 @@ static void show_revert_in_progress(struct wt_status *s,
else
status_printf_ln(s, color,
_("You are currently reverting commit %s."),
- find_unique_abbrev(&s->state.revert_head_oid,
- DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &s->state.revert_head_oid,
+ DEFAULT_ABBREV));
if (s->hints) {
if (has_unmerged(s))
status_printf_ln(s, color,
@@ -1664,7 +1676,8 @@ static void wt_status_get_detached_from(struct repository *r,
return;
}
- if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref, 1) == 1 &&
+ if (repo_dwim_ref(r, cb.buf.buf, cb.buf.len, &oid, &ref,
+ 1) == 1 &&
/* oid is a commit? match without further lookup */
(oideq(&cb.noid, &oid) ||
/* perhaps oid is a tag, try to dereference to a commit */
@@ -1676,9 +1689,9 @@ static void wt_status_get_detached_from(struct repository *r,
state->detached_from = xstrdup(from);
} else
state->detached_from =
- xstrdup(find_unique_abbrev(&cb.noid, DEFAULT_ABBREV));
+ xstrdup(repo_find_unique_abbrev(r, &cb.noid, DEFAULT_ABBREV));
oidcpy(&state->detached_oid, &cb.noid);
- state->detached_at = !get_oid("HEAD", &oid) &&
+ state->detached_at = !repo_get_oid(r, "HEAD", &oid) &&
oideq(&oid, &state->detached_oid);
free(ref);
@@ -1769,13 +1782,13 @@ void wt_status_get_state(struct repository *r,
} else if (wt_status_check_rebase(NULL, state)) {
; /* all set */
} else if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
- !get_oid("CHERRY_PICK_HEAD", &oid)) {
+ !repo_get_oid(r, "CHERRY_PICK_HEAD", &oid)) {
state->cherry_pick_in_progress = 1;
oidcpy(&state->cherry_pick_head_oid, &oid);
}
wt_status_check_bisect(NULL, state);
if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") &&
- !get_oid("REVERT_HEAD", &oid)) {
+ !repo_get_oid(r, "REVERT_HEAD", &oid)) {
state->revert_in_progress = 1;
oidcpy(&state->revert_head_oid, &oid);
}
diff --git a/xdiff-interface.c b/xdiff-interface.c
index e87950de32..abc7275a52 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
-#include "object-store.h"
+#include "hex.h"
+#include "object-store-ll.h"
+#include "strbuf.h"
#include "xdiff-interface.h"
#include "xdiff/xtypes.h"
#include "xdiff/xdiffi.h"
@@ -183,7 +185,7 @@ void read_mmblob(mmfile_t *ptr, const struct object_id *oid)
return;
}
- ptr->ptr = read_object_file(oid, &type, &size);
+ ptr->ptr = repo_read_object_file(the_repository, oid, &type, &size);
if (!ptr->ptr || type != OBJ_BLOB)
die("unable to read blob object %s", oid_to_hex(oid));
ptr->size = size;
diff --git a/xdiff-interface.h b/xdiff-interface.h
index 4301a7eef2..733c364d26 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -1,7 +1,7 @@
#ifndef XDIFF_INTERFACE_H
#define XDIFF_INTERFACE_H
-#include "cache.h"
+#include "hash-ll.h"
#include "xdiff/xdiff.h"
/*