summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap11
-rw-r--r--Documentation/RelNotes/2.19.0.txt247
-rw-r--r--Documentation/SubmittingPatches4
-rw-r--r--Documentation/config.txt94
-rw-r--r--Documentation/diff-options.txt36
-rw-r--r--Documentation/fetch-options.txt16
-rw-r--r--Documentation/git-bisect-lk2009.txt2
-rw-r--r--Documentation/git-branch.txt3
-rw-r--r--Documentation/git-checkout.txt9
-rw-r--r--Documentation/git-commit-graph.txt14
-rw-r--r--Documentation/git-for-each-ref.txt2
-rw-r--r--Documentation/git-fsck.txt3
-rw-r--r--Documentation/git-gc.txt4
-rw-r--r--Documentation/git-grep.txt16
-rw-r--r--Documentation/git-imap-send.txt4
-rw-r--r--Documentation/git-interpret-trailers.txt9
-rw-r--r--Documentation/git-merge.txt16
-rw-r--r--Documentation/git-notes.txt2
-rw-r--r--Documentation/git-rebase.txt144
-rw-r--r--Documentation/git-send-email.txt17
-rw-r--r--Documentation/git-status.txt2
-rw-r--r--Documentation/git-svn.txt2
-rw-r--r--Documentation/git-tag.txt2
-rw-r--r--Documentation/git-worktree.txt9
-rw-r--r--Documentation/giteveryday.txt2
-rw-r--r--Documentation/gitignore.txt2
-rw-r--r--Documentation/gitsubmodules.txt2
-rw-r--r--Documentation/glossary-content.txt2
-rw-r--r--Documentation/revisions.txt3
-rw-r--r--Documentation/technical/api-directory-listing.txt2
-rw-r--r--Documentation/technical/api-gitattributes.txt2
-rw-r--r--Documentation/technical/commit-graph-format.txt10
-rw-r--r--Documentation/technical/commit-graph.txt22
-rw-r--r--Documentation/technical/directory-rename-detection.txt115
-rw-r--r--Documentation/technical/pack-protocol.txt7
-rw-r--r--Documentation/technical/protocol-v2.txt31
-rw-r--r--Makefile18
-rw-r--r--advice.c2
-rw-r--r--advice.h1
-rw-r--r--apply.c27
-rw-r--r--archive-tar.c1
-rw-r--r--archive-zip.c1
-rw-r--r--archive.c3
-rw-r--r--bisect.c2
-rw-r--r--blame.c27
-rw-r--r--blob.c10
-rw-r--r--blob.h2
-rw-r--r--branch.c16
-rw-r--r--builtin/am.c16
-rw-r--r--builtin/blame.c12
-rw-r--r--builtin/branch.c29
-rw-r--r--builtin/cat-file.c1
-rw-r--r--builtin/checkout.c56
-rw-r--r--builtin/clone.c30
-rw-r--r--builtin/commit-graph.c101
-rw-r--r--builtin/commit-tree.c5
-rw-r--r--builtin/commit.c38
-rw-r--r--builtin/config.c27
-rw-r--r--builtin/describe.c14
-rw-r--r--builtin/diff-tree.c9
-rw-r--r--builtin/diff.c7
-rw-r--r--builtin/difftool.c7
-rw-r--r--builtin/fast-export.c15
-rw-r--r--builtin/fetch.c224
-rw-r--r--builtin/fmt-merge-msg.c27
-rw-r--r--builtin/fsck.c44
-rw-r--r--builtin/gc.c7
-rw-r--r--builtin/grep.c10
-rw-r--r--builtin/hash-object.c1
-rw-r--r--builtin/index-pack.c7
-rw-r--r--builtin/log.c12
-rw-r--r--builtin/ls-tree.c1
-rw-r--r--builtin/merge-base.c7
-rw-r--r--builtin/merge-recursive.c4
-rw-r--r--builtin/merge-tree.c4
-rw-r--r--builtin/merge.c80
-rw-r--r--builtin/mktag.c1
-rw-r--r--builtin/mktree.c1
-rw-r--r--builtin/name-rev.c13
-rw-r--r--builtin/notes.c4
-rw-r--r--builtin/pack-objects.c17
-rw-r--r--builtin/prune.c7
-rw-r--r--builtin/pull.c19
-rw-r--r--builtin/receive-pack.c26
-rw-r--r--builtin/reflog.c16
-rw-r--r--builtin/remote.c1
-rw-r--r--builtin/replace.c12
-rw-r--r--builtin/reset.c8
-rw-r--r--builtin/rev-list.c16
-rw-r--r--builtin/rev-parse.c9
-rw-r--r--builtin/show-branch.c5
-rw-r--r--builtin/show-ref.c1
-rw-r--r--builtin/submodule--helper.c34
-rw-r--r--builtin/tag.c3
-rw-r--r--builtin/unpack-file.c1
-rw-r--r--builtin/unpack-objects.c10
-rw-r--r--builtin/update-index.c40
-rw-r--r--builtin/upload-pack.c2
-rw-r--r--builtin/verify-commit.c5
-rw-r--r--builtin/worktree.c4
-rw-r--r--bulk-checkin.c1
-rw-r--r--bundle.c11
-rw-r--r--cache-tree.c4
-rw-r--r--cache.h210
-rw-r--r--checkout.c37
-rw-r--r--checkout.h4
-rwxr-xr-xci/run-static-analysis.sh21
-rw-r--r--combine-diff.c1
-rw-r--r--commit-graph.c359
-rw-r--r--commit-graph.h22
-rw-r--r--commit-slab-impl.h3
-rw-r--r--commit.c173
-rw-r--r--commit.h29
-rw-r--r--compat/vcbuild/README4
-rw-r--r--config.c60
-rw-r--r--config.h23
-rw-r--r--config.mak.dev5
-rw-r--r--connect.h2
-rw-r--r--connected.c6
-rw-r--r--connected.h7
-rw-r--r--contrib/coccinelle/commit.cocci2
-rw-r--r--contrib/git-jump/README12
-rwxr-xr-xcontrib/git-jump/git-jump2
-rw-r--r--convert.c3
-rw-r--r--diff-lib.c3
-rw-r--r--diff.c271
-rw-r--r--diff.h9
-rw-r--r--diffcore-rename.c1
-rw-r--r--dir.c3
-rw-r--r--entry.c1
-rw-r--r--environment.c13
-rw-r--r--ewah/bitmap.c32
-rw-r--r--ewah/ewah_bitmap.c249
-rw-r--r--ewah/ewah_io.c91
-rw-r--r--ewah/ewah_rlw.c8
-rw-r--r--ewah/ewok.h33
-rw-r--r--ewah/ewok_rlw.h1
-rw-r--r--fast-import.c8
-rw-r--r--fetch-negotiator.c14
-rw-r--r--fetch-negotiator.h58
-rw-r--r--fetch-object.c2
-rw-r--r--fetch-pack.c419
-rw-r--r--fetch-pack.h22
-rw-r--r--fsck.c34
-rwxr-xr-xgit-filter-branch.sh1
-rwxr-xr-xgit-p4.py348
-rw-r--r--git-rebase--merge.sh4
-rw-r--r--git-rebase--preserve-merges.sh4
-rwxr-xr-xgit-rebase.sh45
-rwxr-xr-xgit-send-email.perl49
-rwxr-xr-xgit-submodule.sh5
-rw-r--r--git.c7
-rw-r--r--gpg-interface.c110
-rw-r--r--gpg-interface.h2
-rw-r--r--grep.c218
-rw-r--r--grep.h3
-rw-r--r--hex.c6
-rw-r--r--http-backend.c4
-rw-r--r--http-push.c16
-rw-r--r--json-writer.c414
-rw-r--r--json-writer.h105
-rw-r--r--line-log.c6
-rw-r--r--line-range.c2
-rw-r--r--list-objects-filter.c1
-rw-r--r--list-objects.c11
-rw-r--r--log-tree.c18
-rw-r--r--mailmap.c1
-rw-r--r--match-trees.c1
-rw-r--r--mem-pool.c114
-rw-r--r--mem-pool.h23
-rw-r--r--merge-blobs.c1
-rw-r--r--merge-recursive.c222
-rw-r--r--merge.c31
-rw-r--r--negotiator/default.c176
-rw-r--r--negotiator/default.h8
-rw-r--r--negotiator/skipping.c250
-rw-r--r--negotiator/skipping.h8
-rw-r--r--notes-cache.c4
-rw-r--r--notes-merge.c6
-rw-r--r--notes-utils.c4
-rw-r--r--notes.c1
-rw-r--r--object-store.h123
-rw-r--r--object.c70
-rw-r--r--object.h27
-rw-r--r--pack-bitmap-write.c11
-rw-r--r--pack-bitmap.c344
-rw-r--r--pack-bitmap.h20
-rw-r--r--packfile.c2
-rw-r--r--packfile.h5
-rw-r--r--parse-options-cb.c2
-rw-r--r--path.c18
-rw-r--r--path.h42
-rw-r--r--pretty.c8
-rw-r--r--reachable.c8
-rw-r--r--read-cache.c305
-rw-r--r--ref-filter.c26
-rw-r--r--reflog-walk.c3
-rw-r--r--refs.c15
-rw-r--r--refs/files-backend.c35
-rw-r--r--refs/refs-internal.h9
-rw-r--r--remote-testsvn.c1
-rw-r--r--remote.c21
-rw-r--r--remote.h1
-rw-r--r--replace-object.c2
-rw-r--r--replace-object.h2
-rw-r--r--repository.h5
-rw-r--r--rerere.c8
-rw-r--r--resolve-undo.c4
-rw-r--r--revision.c31
-rw-r--r--revision.h3
-rw-r--r--send-pack.c7
-rw-r--r--sequencer.c284
-rw-r--r--server-info.c4
-rw-r--r--sha1-file.c12
-rw-r--r--sha1-name.c46
-rw-r--r--shallow.c104
-rw-r--r--split-index.c58
-rw-r--r--strbuf.c2
-rw-r--r--string-list.c18
-rw-r--r--submodule-config.c78
-rw-r--r--submodule-config.h12
-rw-r--r--submodule.c20
-rw-r--r--submodule.h2
-rw-r--r--t/.gitignore1
-rw-r--r--t/Makefile25
-rw-r--r--t/annotate-tests.sh4
-rw-r--r--t/chainlint.sed346
-rw-r--r--t/chainlint/arithmetic-expansion.expect9
-rw-r--r--t/chainlint/arithmetic-expansion.test11
-rw-r--r--t/chainlint/bash-array.expect10
-rw-r--r--t/chainlint/bash-array.test12
-rw-r--r--t/chainlint/blank-line.expect4
-rw-r--r--t/chainlint/blank-line.test10
-rw-r--r--t/chainlint/block.expect12
-rw-r--r--t/chainlint/block.test15
-rw-r--r--t/chainlint/broken-chain.expect6
-rw-r--r--t/chainlint/broken-chain.test8
-rw-r--r--t/chainlint/case.expect19
-rw-r--r--t/chainlint/case.test23
-rw-r--r--t/chainlint/close-nested-and-parent-together.expect4
-rw-r--r--t/chainlint/close-nested-and-parent-together.test3
-rw-r--r--t/chainlint/close-subshell.expect25
-rw-r--r--t/chainlint/close-subshell.test27
-rw-r--r--t/chainlint/command-substitution.expect9
-rw-r--r--t/chainlint/command-substitution.test11
-rw-r--r--t/chainlint/comment.expect4
-rw-r--r--t/chainlint/comment.test11
-rw-r--r--t/chainlint/complex-if-in-cuddled-loop.expect10
-rw-r--r--t/chainlint/complex-if-in-cuddled-loop.test11
-rw-r--r--t/chainlint/cuddled-if-then-else.expect7
-rw-r--r--t/chainlint/cuddled-if-then-else.test7
-rw-r--r--t/chainlint/cuddled-loop.expect5
-rw-r--r--t/chainlint/cuddled-loop.test7
-rw-r--r--t/chainlint/cuddled.expect21
-rw-r--r--t/chainlint/cuddled.test23
-rw-r--r--t/chainlint/exit-loop.expect24
-rw-r--r--t/chainlint/exit-loop.test27
-rw-r--r--t/chainlint/exit-subshell.expect5
-rw-r--r--t/chainlint/exit-subshell.test6
-rw-r--r--t/chainlint/for-loop.expect11
-rw-r--r--t/chainlint/for-loop.test19
-rw-r--r--t/chainlint/here-doc.expect3
-rw-r--r--t/chainlint/here-doc.test16
-rw-r--r--t/chainlint/if-in-loop.expect12
-rw-r--r--t/chainlint/if-in-loop.test15
-rw-r--r--t/chainlint/if-then-else.expect19
-rw-r--r--t/chainlint/if-then-else.test28
-rw-r--r--t/chainlint/incomplete-line.expect4
-rw-r--r--t/chainlint/incomplete-line.test12
-rw-r--r--t/chainlint/inline-comment.expect9
-rw-r--r--t/chainlint/inline-comment.test12
-rw-r--r--t/chainlint/loop-in-if.expect12
-rw-r--r--t/chainlint/loop-in-if.test15
-rw-r--r--t/chainlint/multi-line-nested-command-substitution.expect9
-rw-r--r--t/chainlint/multi-line-nested-command-substitution.test9
-rw-r--r--t/chainlint/multi-line-string.expect9
-rw-r--r--t/chainlint/multi-line-string.test15
-rw-r--r--t/chainlint/negated-one-liner.expect5
-rw-r--r--t/chainlint/negated-one-liner.test7
-rw-r--r--t/chainlint/nested-cuddled-subshell.expect19
-rw-r--r--t/chainlint/nested-cuddled-subshell.test31
-rw-r--r--t/chainlint/nested-here-doc.expect5
-rw-r--r--t/chainlint/nested-here-doc.test23
-rw-r--r--t/chainlint/nested-subshell-comment.expect11
-rw-r--r--t/chainlint/nested-subshell-comment.test13
-rw-r--r--t/chainlint/nested-subshell.expect12
-rw-r--r--t/chainlint/nested-subshell.test14
-rw-r--r--t/chainlint/one-liner.expect9
-rw-r--r--t/chainlint/one-liner.test12
-rw-r--r--t/chainlint/p4-filespec.expect4
-rw-r--r--t/chainlint/p4-filespec.test5
-rw-r--r--t/chainlint/pipe.expect8
-rw-r--r--t/chainlint/pipe.test12
-rw-r--r--t/chainlint/semicolon.expect20
-rw-r--r--t/chainlint/semicolon.test25
-rw-r--r--t/chainlint/subshell-here-doc.expect5
-rw-r--r--t/chainlint/subshell-here-doc.test23
-rw-r--r--t/chainlint/subshell-one-liner.expect14
-rw-r--r--t/chainlint/subshell-one-liner.test24
-rw-r--r--t/chainlint/while-loop.expect11
-rw-r--r--t/chainlint/while-loop.test19
-rwxr-xr-xt/check-non-portable-shell.pl31
-rw-r--r--t/helper/test-drop-caches.c4
-rw-r--r--t/helper/test-json-writer.c565
-rw-r--r--t/helper/test-pkt-line.c33
-rw-r--r--t/helper/test-repository.c82
-rw-r--r--t/helper/test-tool.c2
-rw-r--r--t/helper/test-tool.h2
-rwxr-xr-xt/lib-gpg.sh28
-rw-r--r--t/lib-gpg/gpgsm-gen-key.in8
-rw-r--r--t/lib-gpg/gpgsm_cert.p12bin0 -> 2652 bytes
-rw-r--r--t/lib-httpd.sh22
-rw-r--r--t/lib-httpd/apache.conf8
-rw-r--r--t/lib-httpd/apply-one-time-sed.sh22
-rwxr-xr-xt/lib-submodule-update.sh13
-rwxr-xr-xt/t0000-basic.sh2
-rwxr-xr-xt/t0001-init.sh4
-rwxr-xr-xt/t0003-attributes.sh24
-rwxr-xr-xt/t0019-json-writer.sh331
-rw-r--r--t/t0019/parse_json.perl52
-rwxr-xr-xt/t0021-conversion.sh4
-rwxr-xr-xt/t0090-cache-tree.sh2
-rwxr-xr-xt/t1004-read-tree-m-u-wf.sh8
-rwxr-xr-xt/t1005-read-tree-reset.sh10
-rwxr-xr-xt/t1008-read-tree-overlay.sh2
-rwxr-xr-xt/t1020-subdirectory.sh2
-rwxr-xr-xt/t1050-large.sh6
-rwxr-xr-xt/t1300-config.sh2
-rwxr-xr-xt/t1410-reflog.sh4
-rwxr-xr-xt/t1411-reflog-show.sh6
-rwxr-xr-xt/t1507-rev-parse-upstream.sh6
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh6
-rwxr-xr-xt/t1700-split-index.sh2
-rwxr-xr-xt/t2016-checkout-patch.sh24
-rwxr-xr-xt/t2024-checkout-dwim.sh59
-rwxr-xr-xt/t2025-worktree-add.sh21
-rwxr-xr-xt/t2103-update-index-ignore-missing.sh2
-rwxr-xr-xt/t2202-add-addremove.sh14
-rwxr-xr-xt/t3000-ls-files-others.sh2
-rwxr-xr-xt/t3006-ls-files-long.sh2
-rwxr-xr-xt/t3008-ls-files-lazy-init-name-hash.sh8
-rwxr-xr-xt/t3030-merge-recursive.sh340
-rwxr-xr-xt/t3035-merge-sparse.sh59
-rwxr-xr-xt/t3050-subprojects-fetch.sh8
-rwxr-xr-xt/t3102-ls-tree-wildcards.sh2
-rwxr-xr-xt/t3200-branch.sh34
-rwxr-xr-xt/t3210-pack-refs.sh4
-rwxr-xr-xt/t3301-notes.sh8
-rwxr-xr-xt/t3400-rebase.sh8
-rwxr-xr-xt/t3401-rebase-and-am-rename.sh105
-rwxr-xr-xt/t3402-rebase-merge.sh4
-rwxr-xr-xt/t3404-rebase-interactive.sh59
-rwxr-xr-xt/t3405-rebase-malformed.sh11
-rwxr-xr-xt/t3418-rebase-continue.sh36
-rwxr-xr-xt/t3422-rebase-incompatible-options.sh88
-rwxr-xr-xt/t3423-rebase-reword.sh48
-rwxr-xr-xt/t3430-rebase-merges.sh34
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh7
-rwxr-xr-xt/t3700-add.sh8
-rwxr-xr-xt/t3701-add-interactive.sh16
-rwxr-xr-xt/t3904-stash-patch.sh8
-rwxr-xr-xt/t4001-diff-rename.sh2
-rwxr-xr-xt/t4010-diff-pathspec.sh4
-rwxr-xr-xt/t4012-diff-binary.sh6
-rwxr-xr-xt/t4014-format-patch.sh6
-rwxr-xr-xt/t4015-diff-whitespace.sh243
-rw-r--r--t/t4018/php-abstract-class4
-rw-r--r--t/t4018/php-class4
-rw-r--r--t/t4018/php-final-class4
-rw-r--r--t/t4018/php-function4
-rw-r--r--t/t4018/php-interface4
-rw-r--r--t/t4018/php-method7
-rw-r--r--t/t4018/php-trait7
-rwxr-xr-xt/t4024-diff-optimize-common.sh16
-rwxr-xr-xt/t4025-hunk-header.sh8
-rwxr-xr-xt/t4041-diff-submodule-option.sh4
-rwxr-xr-xt/t4060-diff-submodule-option-diff-format.sh2
-rwxr-xr-xt/t4121-apply-diffs.sh2
-rwxr-xr-xt/t4202-log.sh37
-rwxr-xr-xt/t4208-log-magic-pathspec.sh26
-rwxr-xr-xt/t4211-line-log.sh5
-rwxr-xr-xt/t5300-pack-object.sh2
-rwxr-xr-xt/t5302-pack-index.sh2
-rwxr-xr-xt/t5317-pack-objects-filter-objects.sh16
-rwxr-xr-xt/t5318-commit-graph.sh240
-rwxr-xr-xt/t5400-send-pack.sh4
-rwxr-xr-xt/t5401-update-hooks.sh4
-rwxr-xr-xt/t5405-send-pack-rewind.sh3
-rwxr-xr-xt/t5406-remote-rejects.sh5
-rwxr-xr-xt/t5407-post-rewrite-hook.sh2
-rwxr-xr-xt/t5500-fetch-pack.sh54
-rwxr-xr-xt/t5505-remote.sh10
-rwxr-xr-xt/t5510-fetch.sh80
-rwxr-xr-xt/t5512-ls-remote.sh4
-rwxr-xr-xt/t5516-fetch-push.sh10
-rwxr-xr-xt/t5517-push-mirror.sh10
-rwxr-xr-xt/t5520-pull.sh12
-rwxr-xr-xt/t5526-fetch-submodules.sh2
-rwxr-xr-xt/t5531-deep-submodule-push.sh2
-rwxr-xr-xt/t5534-push-signed.sh63
-rwxr-xr-xt/t5537-fetch-shallow.sh43
-rwxr-xr-xt/t5541-http-push-smart.sh28
-rwxr-xr-xt/t5543-atomic-push.sh2
-rwxr-xr-xt/t5551-http-fetch-smart.sh8
-rwxr-xr-xt/t5552-skipping-fetch-negotiator.sh179
-rwxr-xr-xt/t5561-http-backend.sh8
-rwxr-xr-xt/t5601-clone.sh2
-rwxr-xr-xt/t5605-clone-local.sh2
-rwxr-xr-xt/t5608-clone-2gb.sh2
-rwxr-xr-xt/t5616-partial-clone.sh108
-rwxr-xr-xt/t5702-protocol-v2.sh7
-rwxr-xr-xt/t5703-upload-pack-ref-in-want.sh377
-rwxr-xr-xt/t5801-remote-helpers.sh2
-rwxr-xr-xt/t6010-merge-base.sh2
-rwxr-xr-xt/t6029-merge-subtree.sh16
-rwxr-xr-xt/t6036-recursive-corner-cases.sh713
-rwxr-xr-xt/t6042-merge-rename-corner-cases.sh253
-rwxr-xr-xt/t6043-merge-rename-directories.sh2
-rwxr-xr-xt/t6044-merge-unrelated-index-changes.sh67
-rwxr-xr-xt/t6046-merge-skip-unneeded-updates.sh4
-rwxr-xr-xt/t6050-replace.sh6
-rwxr-xr-xt/t6300-for-each-ref.sh11
-rwxr-xr-xt/t7001-mv.sh2
-rwxr-xr-xt/t7003-filter-branch.sh15
-rwxr-xr-xt/t7004-tag.sh13
-rwxr-xr-xt/t7030-verify-tag.sh34
-rwxr-xr-xt/t7105-reset-patch.sh12
-rwxr-xr-xt/t7201-co.sh41
-rwxr-xr-xt/t7301-clean-interactive.sh41
-rwxr-xr-xt/t7400-submodule-basic.sh18
-rwxr-xr-xt/t7405-submodule-merge.sh173
-rwxr-xr-xt/t7406-submodule-update.sh17
-rwxr-xr-xt/t7408-submodule-reference.sh2
-rwxr-xr-xt/t7415-submodule-names.sh15
-rwxr-xr-xt/t7501-commit.sh56
-rwxr-xr-xt/t7504-commit-msg-hook.sh4
-rwxr-xr-xt/t7506-status-submodule.sh10
-rwxr-xr-xt/t7510-signed-commit.sh7
-rwxr-xr-xt/t7610-mergetool.sh8
-rwxr-xr-xt/t7611-merge-abort.sh118
-rwxr-xr-xt/t7810-grep.sh117
-rwxr-xr-xt/t8003-blame-corner-cases.sh12
-rwxr-xr-xt/t9001-send-email.sh67
-rwxr-xr-xt/t9100-git-svn-basic.sh2
-rwxr-xr-xt/t9101-git-svn-props.sh2
-rwxr-xr-xt/t9119-git-svn-info.sh120
-rwxr-xr-xt/t9122-git-svn-author.sh6
-rwxr-xr-xt/t9129-git-svn-i18n-commitencoding.sh2
-rwxr-xr-xt/t9130-git-svn-authors-file.sh4
-rwxr-xr-xt/t9134-git-svn-ignore-paths.sh6
-rwxr-xr-xt/t9137-git-svn-dcommit-clobber-series.sh2
-rwxr-xr-xt/t9138-git-svn-authors-prog.sh6
-rwxr-xr-xt/t9146-git-svn-empty-dirs.sh20
-rwxr-xr-xt/t9147-git-svn-include-paths.sh6
-rwxr-xr-xt/t9152-svn-empty-dirs-after-gc.sh2
-rwxr-xr-xt/t9164-git-svn-dcommit-concurrent.sh2
-rwxr-xr-xt/t9165-git-svn-fetch-merge-branch-of-branch.sh2
-rwxr-xr-xt/t9200-git-cvsexportcommit.sh6
-rwxr-xr-xt/t9300-fast-import.sh5
-rwxr-xr-xt/t9302-fast-import-unpack-limit.sh2
-rwxr-xr-xt/t9400-git-cvsserver-server.sh8
-rwxr-xr-xt/t9600-cvsimport.sh2
-rwxr-xr-xt/t9806-git-p4-options.sh2
-rwxr-xr-xt/t9810-git-p4-rcs.sh2
-rwxr-xr-xt/t9811-git-p4-label-import.sh2
-rwxr-xr-xt/t9814-git-p4-rename.sh18
-rwxr-xr-xt/t9815-git-p4-submit-fail.sh2
-rwxr-xr-xt/t9830-git-p4-symlink-dir.sh2
-rwxr-xr-xt/t9831-git-p4-triggers.sh2
-rwxr-xr-xt/t9833-errors.sh4
-rwxr-xr-xt/t9902-completion.sh4
-rwxr-xr-xt/t9903-bash-prompt.sh2
-rw-r--r--t/test-lib.sh3
-rw-r--r--tag.c40
-rw-r--r--tag.h7
-rw-r--r--transport-helper.c9
-rw-r--r--transport-internal.h9
-rw-r--r--transport.c36
-rw-r--r--transport.h24
-rw-r--r--tree-walk.c4
-rw-r--r--tree.c24
-rw-r--r--tree.h2
-rw-r--r--unicode-width.h41
-rw-r--r--unpack-trees.c43
-rw-r--r--upload-pack.c98
-rw-r--r--userdiff.c2
-rw-r--r--utf8.c8
-rw-r--r--walker.c13
-rw-r--r--wt-status.c20
-rw-r--r--xdiff-interface.c1
-rw-r--r--xdiff/xdiff.h8
-rw-r--r--xdiff/xdiffi.c17
492 files changed, 12598 insertions, 3562 deletions
diff --git a/.mailmap b/.mailmap
index df7cf63..f165222 100644
--- a/.mailmap
+++ b/.mailmap
@@ -35,11 +35,13 @@ Chris Wright <chrisw@sous-sol.org> <chrisw@osdl.org>
Cord Seele <cowose@gmail.com> <cowose@googlemail.com>
Christian Couder <chriscool@tuxfamily.org> <christian.couder@gmail.com>
Christian Stimming <stimming@tuhh.de> <chs@ckiste.goetheallee>
+Christopher Díaz Riveros <chrisadr@gentoo.org> Christopher Diaz Riveros
Csaba Henk <csaba@gluster.com> <csaba@lowlife.hu>
Dan Johnson <computerdruid@gmail.com>
Dana L. How <danahow@gmail.com> <how@deathvalley.cswitch.com>
Dana L. How <danahow@gmail.com> Dana How
Daniel Barkalow <barkalow@iabervon.org>
+Daniel Knittl-Frank <knittl89@googlemail.com> knittl
Daniel Trstenjak <daniel.trstenjak@gmail.com> <daniel.trstenjak@online.de>
Daniel Trstenjak <daniel.trstenjak@gmail.com> <trsten@science-computing.de>
David Brown <git@davidb.org> <davidb@quicinc.com>
@@ -57,6 +59,7 @@ Eric S. Raymond <esr@thyrsus.com>
Eric Wong <e@80x24.org> <normalperson@yhbt.net>
Erik Faye-Lund <kusmabite@gmail.com> <kusmabite@googlemail.com>
Eyvind Bernhardsen <eyvind.bernhardsen@gmail.com> <eyvind-git@orakel.ntnu.no>
+Fangyi Zhou <fangyi.zhou@yuriko.moe> Zhou Fangyi
Florian Achleitner <florian.achleitner.2.6.31@gmail.com> <florian.achleitner2.6.31@gmail.com>
Franck Bui-Huu <vagabon.xyz@gmail.com> <fbuihuu@gmail.com>
Frank Lichtenheld <frank@lichtenheld.de> <djpig@debian.org>
@@ -86,6 +89,8 @@ Jason McMullan <mcmullan@netapp.com>
Jason Riedy <ejr@eecs.berkeley.edu> <ejr@EECS.Berkeley.EDU>
Jason Riedy <ejr@eecs.berkeley.edu> <ejr@cs.berkeley.edu>
Jay Soffian <jaysoffian@gmail.com> <jaysoffian+git@gmail.com>
+Jean-Noël Avila <jn.avila@free.fr> Jean-Noel Avila
+Jean-Noël Avila <jn.avila@free.fr> Jean-Noël AVILA
Jeff King <peff@peff.net> <peff@github.com>
Jeff Muizelaar <jmuizelaar@mozilla.com> <jeff@infidigm.net>
Jens Axboe <axboe@kernel.dk> <axboe@suse.de>
@@ -149,6 +154,7 @@ Matt Draisey <matt@draisey.ca> <mattdraisey@sympatico.ca>
Matt Kraai <kraai@ftbfs.org> <matt.kraai@amo.abbott.com>
Matt McCutchen <matt@mattmccutchen.net> <hashproduct@gmail.com>
Matthias Kestenholz <matthias@spinlock.ch> <mk@spinlock.ch>
+Matthias Rüster <matthias.ruester@gmail.com> Matthias Ruester
Matthias Urlichs <matthias@urlichs.de> <smurf@kiste.(none)>
Matthias Urlichs <matthias@urlichs.de> <smurf@smurf.noris.de>
Michael Coleman <tutufan@gmail.com>
@@ -213,6 +219,8 @@ Sean Estabrooks <seanlkml@sympatico.ca>
Sebastian Schuberth <sschuberth@gmail.com> <sschuberth@visageimaging.com>
Seth Falcon <seth@userprimary.net> <sfalcon@fhcrc.org>
Shawn O. Pearce <spearce@spearce.org>
+Wei Shuyu <wsy@dogben.com> Shuyu Wei
+Sidhant Sharma <tigerkid001@gmail.com> Sidhant Sharma [:tk]
Simon Hausmann <hausmann@kde.org> <simon@lst.de>
Simon Hausmann <hausmann@kde.org> <shausman@trolltech.com>
Stefan Beller <stefanbeller@gmail.com> <stefanbeller@googlemail.com>
@@ -253,7 +261,8 @@ Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <ukleinek@informatik.uni-frei
Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <uzeisberger@io.fsforth.de>
Uwe Kleine-König <u.kleine-koenig@pengutronix.de> <zeisberg@informatik.uni-freiburg.de>
Ville Skyttä <ville.skytta@iki.fi> <scop@xemacs.org>
-Vitaly "_Vi" Shukela <public_vi@tut.by>
+Vitaly "_Vi" Shukela <vi0oss@gmail.com> <public_vi@tut.by>
+Vitaly "_Vi" Shukela <vi0oss@gmail.com> Vitaly _Vi Shukela
W. Trevor King <wking@tremily.us> <wking@drexel.edu>
William Pursell <bill.pursell@gmail.com>
YONETANI Tomokazu <y0n3t4n1@gmail.com> <qhwt+git@les.ath.cx>
diff --git a/Documentation/RelNotes/2.19.0.txt b/Documentation/RelNotes/2.19.0.txt
index 2b45b6f..8a03613 100644
--- a/Documentation/RelNotes/2.19.0.txt
+++ b/Documentation/RelNotes/2.19.0.txt
@@ -15,6 +15,41 @@ UI, Workflows & Features
otherwise working-tree-only application of a patch will add new
paths to the index marked with the "intent-to-add" bit.
+ * "git grep" learned the "--column" option that gives not just the
+ line number but the column number of the hit.
+
+ * The "-l" option in "git branch -l" is an unfortunate short-hand for
+ "--create-reflog", but many users, both old and new, somehow expect
+ it to be something else, perhaps "--list". This step warns when "-l"
+ is used as a short-hand for "--create-reflog" and warns about the
+ future repurposing of the it when it is used.
+
+ * The userdiff pattern for .php has been updated.
+
+ * The content-transfer-encoding of the message "git send-email" sends
+ out by default was 8bit, which can cause trouble when there is an
+ overlong line to bust RFC 5322/2822 limit. A new option 'auto' to
+ automatically switch to quoted-printable when there is such a line
+ in the payload has been introduced and is made the default.
+
+ * "git checkout" and "git worktree add" learned to honor
+ checkout.defaultRemote when auto-vivifying a local branch out of a
+ remote tracking branch in a repository with multiple remotes that
+ have tracking branches that share the same names.
+ (merge 8d7b558bae ab/checkout-default-remote later to maint).
+
+ * "git grep" learned the "--only-matching" option.
+
+ * "git rebase --rebase-merges" mode now handles octopus merges as
+ well.
+
+ * Add a server-side knob to skip commits in exponential/fibbonacci
+ stride in an attempt to cover wider swath of history with a smaller
+ number of iterations, potentially accepting a larger packfile
+ transfer, instead of going back one commit a time during common
+ ancestor discovery during the "git fetch" transaction.
+ (merge 42cc7485a2 jt/fetch-negotiator-skipping later to maint).
+
Performance, Internal Implementation, Development Support etc.
@@ -51,6 +86,77 @@ Performance, Internal Implementation, Development Support etc.
* Build and test procedure for netrc credential helper (in contrib/)
has been updated.
+ * The conversion to pass "the_repository" and then "a_repository"
+ throughout the object access API continues.
+
+ * Remove unused function definitions and declarations from ewah
+ bitmap subsystem.
+
+ * Code preparation to make "git p4" closer to be usable with Python 3.
+
+ * Tighten the API to make it harder to misuse in-tree .gitmodules
+ file, even though it shares the same syntax with configuration
+ files, to read random configuration items from it.
+
+ * "git fast-import" has been updated to avoid attempting to create
+ delta against a zero-byte-long string, which is pointless.
+
+ * The codebase has been updated to compile cleanly with -pedantic
+ option.
+ (merge 2b647a05d7 bb/pedantic later to maint).
+
+ * The character display width table has been updated to match the
+ latest Unicode standard.
+ (merge 570951eea2 bb/unicode-11-width later to maint).
+
+ * test-lint now looks for broken use of "VAR=VAL shell_func" in test
+ scripts.
+
+ * Conversion from uchar[40] to struct object_id continues.
+
+ * Recent "security fix" to pay attention to contents of ".gitmodules"
+ while accepting "git push" was a bit overly strict than necessary,
+ which has been adjusted.
+
+ * "git fsck" learns to make sure the optional commit-graph file is in
+ a sane state.
+
+ * "git diff --color-moved" feature has further been tweaked.
+
+ * Code restructuring and a small fix to transport protocol v2 during
+ fetching.
+
+ * Parsing of -L[<N>][,[<M>]] parameters "git blame" and "git log"
+ take has been tweaked.
+
+ * lookup_commit_reference() and friends have been updated to find
+ in-core object for a specific in-core repository instance.
+
+ * Various glitches in the heuristics of merge-recursive strategy have
+ been documented in new tests.
+
+ * "git fetch" learned a new option "--negotiation-tip" to limit the
+ set of commits it tells the other end as "have", to reduce wasted
+ bandwidth and cycles, which would be helpful when the receiving
+ repository has a lot of refs that have little to do with the
+ history at the remote it is fetching from.
+
+ * For a large tree, the index needs to hold many cache entries
+ allocated on heap. These cache entries are now allocated out of a
+ dedicated memory pool to amortize malloc(3) overhead.
+
+ * Tests to cover various conflicting cases have been added for
+ merge-recursive.
+
+ * Tests to cover conflict cases that involve submodules have been
+ added for merge-recursive.
+
+ * Look for broken "&&" chains that are hidden in subshell, many of
+ which have been found and corrected.
+
+ * The singleton commit-graph in-core instance is made per in-core
+ repository instance.
+
Fixes since v2.18
-----------------
@@ -96,6 +202,145 @@ Fixes since v2.18
to the submodule was changed in the range of commits in the
superproject, sometimes showing "(null)". This has been corrected.
- * Code cleanup.
+ * "git submodule" did not correctly adjust core.worktree setting that
+ indicates whether/where a submodule repository has its associated
+ working tree across various state transitions, which has been
+ corrected.
+ (merge 984cd77ddb sb/submodule-core-worktree later to maint).
+
+ * Bugfix for "rebase -i" corner case regression.
+ (merge a9279c6785 pw/rebase-i-keep-reword-after-conflict later to maint).
+
+ * Recently added "--base" option to "git format-patch" command did
+ not correctly generate prereq patch ids.
+ (merge 15b76c1fb3 xy/format-patch-prereq-patch-id-fix later to maint).
+
+ * POSIX portability fix in Makefile to fix a glitch introduced a few
+ releases ago.
+ (merge 6600054e9b dj/runtime-prefix later to maint).
+
+ * "git filter-branch" when used with the "--state-branch" option
+ still attempted to rewrite the commits whose filtered result is
+ known from the previous attempt (which is recorded on the state
+ branch); the command has been corrected not to waste cycles doing
+ so.
+ (merge 709cfe848a mb/filter-branch-optim later to maint).
+
+ * Clarify that setting core.ignoreCase to deviate from reality would
+ not turn a case-incapable filesystem into a case-capable one.
+ (merge 48294b512a ms/core-icase-doc later to maint).
+
+ * "fsck.skipList" did not prevent a blob object listed there from
+ being inspected for is contents (e.g. we recently started to
+ inspect the contents of ".gitmodules" for certain malicious
+ patterns), which has been corrected.
+ (merge fb16287719 rj/submodule-fsck-skip later to maint).
+
+ * "git checkout --recurse-submodules another-branch" did not report
+ in which submodule it failed to update the working tree, which
+ resulted in an unhelpful error message.
+ (merge ba95d4e4bd sb/submodule-move-head-error-msg later to maint).
+
+ * "git rebase" behaved slightly differently depending on which one of
+ the three backends gets used; this has been documented and an
+ effort to make them more uniform has begun.
+ (merge b00bf1c9a8 en/rebase-consistency later to maint).
+
+ * The "--ignore-case" option of "git for-each-ref" (and its friends)
+ did not work correctly, which has been fixed.
+ (merge e674eb2528 jk/for-each-ref-icase later to maint).
+
+ * "git fetch" failed to correctly validate the set of objects it
+ received when making a shallow history deeper, which has been
+ corrected.
+ (merge cf1e7c0770 jt/connectivity-check-after-unshallow later to maint).
+
+ * Partial clone support of "git clone" has been updated to correctly
+ validate the objects it receives from the other side. The server
+ side has been corrected to send objects that are directly
+ requested, even if they may match the filtering criteria (e.g. when
+ doing a "lazy blob" partial clone).
+ (merge a7e67c11b8 jt/partial-clone-fsck-connectivity later to maint).
+
+ * Handling of an empty range by "git cherry-pick" was inconsistent
+ depending on how the range ended up to be empty, which has been
+ corrected.
+ (merge c5e358d073 jk/empty-pick-fix later to maint).
+
+ * "git reset --merge" (hence "git merge ---abort") and "git reset --hard"
+ had trouble working correctly in a sparsely checked out working
+ tree after a conflict, which has been corrected.
+ (merge b33fdfc34c mk/merge-in-sparse-checkout later to maint).
+
+ * Correct a broken use of "VAR=VAL shell_func" in a test.
+ (merge 650161a277 jc/t3404-one-shot-export-fix later to maint).
+
+ * "git rev-parse ':/substring'" did not consider the history leading
+ only to HEAD when looking for a commit with the given substring,
+ when the HEAD is detached. This has been fixed.
+ (merge 6b3351e799 wc/find-commit-with-pattern-on-detached-head later to maint).
+
+ * Build doc update for Windows.
+ (merge ede8d89bb1 nd/command-list later to maint).
+
+ * core.commentchar is now honored when preparing the list of commits
+ to replay in "rebase -i".
+
+ * "git pull --rebase" on a corrupt HEAD caused a segfault. In
+ general we substitute an empty tree object when running the in-core
+ equivalent of the diff-index command, and the codepath has been
+ corrected to do so as well to fix this issue.
+ (merge 3506dc9445 jk/has-uncommitted-changes-fix later to maint).
+
+ * httpd tests saw occasional breakage due to the way its access log
+ gets inspected by the tests, which has been updated to make them
+ less flaky.
+ (merge e8b3b2e275 sg/httpd-test-unflake later to maint).
+
+ * Tests to cover more D/F conflict cases have been added for
+ merge-recursive.
+
+ * "git gc --auto" opens file descriptors for the packfiles before
+ spawning "git repack/prune", which would upset Windows that does
+ not want a process to work on a file that is open by another
+ process. The issue has been worked around.
+ (merge 12e73a3ce4 kg/gc-auto-windows-workaround later to maint).
+
+ * The recursive merge strategy did not properly ensure there was no
+ change between HEAD and the index before performing its operation,
+ which has been corrected.
+ (merge 55f39cf755 en/dirty-merge-fixes later to maint).
+
+ * "git rebase" started exporting GIT_DIR environment variable and
+ exposing it to hook scripts when part of it got rewritten in C.
+ Instead of matching the old scripted Porcelains' behaviour,
+ compensate by also exporting GIT_WORK_TREE environment as well to
+ lessen the damage. This can harm existing hooks that want to
+ operate on different repository, but the current behaviour is
+ already broken for them anyway.
+ (merge ab5e67d751 bc/sequencer-export-work-tree-as-well later to maint).
+
+ * "git send-email" when using in a batched mode that limits the
+ number of messages sent in a single SMTP session lost the contents
+ of the variable used to choose between tls/ssl, unable to send the
+ second and later batches, which has been fixed.
+ (merge 636f3d7ac5 jm/send-email-tls-auth-on-batch later to maint).
+
+ * The lazy clone support had a few places where missing but promised
+ objects were not correctly tolerated, which have been fixed.
+
+ * Code cleanup, docfix, build fix, etc.
(merge aee9be2ebe sg/update-ref-stdin-cleanup later to maint).
(merge 037714252f jc/clean-after-sanity-tests later to maint).
+ (merge 5b26c3c941 en/merge-recursive-cleanup later to maint).
+ (merge 0dcbc0392e bw/config-refer-to-gitsubmodules-doc later to maint).
+ (merge bb4d000e87 bw/protocol-v2 later to maint).
+ (merge 928f0ab4ba vs/typofixes later to maint).
+ (merge d7f590be84 en/rebase-i-microfixes later to maint).
+ (merge 81d395cc85 js/rebase-recreate-merge later to maint).
+ (merge 51d1863168 tz/exclude-doc-smallfixes later to maint).
+ (merge a9aa3c0927 ds/commit-graph later to maint).
+ (merge 5cf8e06474 js/enhanced-version-info later to maint).
+ (merge 6aaded5509 tb/config-default later to maint).
+ (merge 022d2ac1f3 sb/blame-color later to maint).
+ (merge 5a06a20e0c bp/test-drop-caches-for-windows later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 2488544..b44fd51 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -298,7 +298,7 @@ smaller project it is a good discipline to follow it.
The sign-off is a simple line at the end of the explanation for
the patch, which certifies that you wrote it or otherwise have
-the right to pass it on as a open-source patch. The rules are
+the right to pass it on as an open-source patch. The rules are
pretty simple: if you can certify the below D-C-O:
[[dco]]
@@ -403,7 +403,7 @@ don't demand). +git log -p {litdd} _$area_you_are_modifying_+ would
help you find out who they are.
. You get comments and suggestions for improvements. You may
- even get them in a "on top of your change" patch form.
+ even get them in an "on top of your change" patch form.
. Polish, refine, and re-send to the list and the people who
spend their time to improve your patch. Go back to step (2).
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1cc18a8..fd8d27e 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -344,6 +344,16 @@ advice.*::
Advice shown when you used linkgit:git-checkout[1] to
move to the detach HEAD state, to instruct how to create
a local branch after the fact.
+ checkoutAmbiguousRemoteBranchName::
+ Advice shown when the argument to
+ linkgit:git-checkout[1] ambiguously resolves to a
+ remote tracking branch on more than one remote in
+ situations where an unambiguous argument would have
+ otherwise caused a remote-tracking branch to be
+ checked out. See the `checkout.defaultRemote`
+ configuration variable for how to set a given remote
+ to used by default in some situations where this
+ advice would be printed.
amWorkDir::
Advice that shows the location of the patch file when
linkgit:git-am[1] fails to apply it.
@@ -354,7 +364,7 @@ advice.*::
Advice on what to do when you've accidentally added one
git repo inside of another.
ignoredHook::
- Advice shown if an hook is ignored because the hook is not
+ Advice shown if a hook is ignored because the hook is not
set as executable.
waitingForEditor::
Print a message to the terminal whenever Git is waiting for
@@ -390,16 +400,19 @@ core.hideDotFiles::
default mode is 'dotGitOnly'.
core.ignoreCase::
- If true, this option enables various workarounds to enable
+ Internal variable which enables various workarounds to enable
Git to work better on filesystems that are not case sensitive,
- like FAT. For example, if a directory listing finds
- "makefile" when Git expects "Makefile", Git will assume
+ like APFS, HFS+, FAT, NTFS, etc. For example, if a directory listing
+ finds "makefile" when Git expects "Makefile", Git will assume
it is really the same file, and continue to remember it as
"Makefile".
+
The default is false, except linkgit:git-clone[1] or linkgit:git-init[1]
will probe and set core.ignoreCase true if appropriate when the repository
is created.
++
+Git relies on the proper configuration of this variable for your operating
+and file system. Modifying this value may result in unexpected behavior.
core.precomposeUnicode::
This option is only used by Mac OS implementation of Git.
@@ -904,9 +917,17 @@ core.notesRef::
This setting defaults to "refs/notes/commits", and it can be overridden by
the `GIT_NOTES_REF` environment variable. See linkgit:git-notes[1].
-core.commitGraph::
- Enable git commit graph feature. Allows reading from the
- commit-graph file.
+gc.commitGraph::
+ If true, then gc will rewrite the commit-graph file when
+ linkgit:git-gc[1] is run. When using linkgit:git-gc[1]
+ '--auto' the commit-graph will be updated if housekeeping is
+ required. Default is false. See linkgit:git-commit-graph[1]
+ for details.
+
+core.useReplaceRefs::
+ If set to `false`, behave as if the `--no-replace-objects`
+ option was given on the command line. See linkgit:git[1] and
+ linkgit:git-replace[1] for more information.
core.sparseCheckout::
Enable "sparse checkout" feature. See section "Sparse checkout" in
@@ -1098,6 +1119,22 @@ browser.<tool>.path::
browse HTML help (see `-w` option in linkgit:git-help[1]) or a
working repository in gitweb (see linkgit:git-instaweb[1]).
+checkout.defaultRemote::
+ When you run 'git checkout <something>' and only have one
+ remote, it may implicitly fall back on checking out and
+ tracking e.g. 'origin/<something>'. This stops working as soon
+ as you have more than one remote with a '<something>'
+ reference. This setting allows for setting the name of a
+ preferred remote that should always win when it comes to
+ disambiguation. The typical use-case is to set this to
+ `origin`.
++
+Currently this is used by linkgit:git-checkout[1] when 'git checkout
+<something>' will checkout the '<something>' branch on another remote,
+and by linkgit:git-worktree[1] when 'git worktree add' refers to a
+remote branch. This setting might be used for other checkout-like
+commands or functionality in the future.
+
clean.requireForce::
A boolean to make git-clean do nothing unless given -f,
-i or -n. Defaults to true.
@@ -1146,6 +1183,11 @@ diff.colorMoved::
true the default color mode will be used. When set to false,
moved lines are not colored.
+diff.colorMovedWS::
+ When moved lines are colored using e.g. the `diff.colorMoved` setting,
+ this option controls the `<mode>` how spaces are treated
+ for details of valid modes see '--color-moved-ws' in linkgit:git-diff[1].
+
color.diff.<slot>::
Use customized color for diff colorization. `<slot>` specifies
which part of the patch to use the specified color, and is one
@@ -1182,8 +1224,10 @@ color.grep.<slot>::
filename prefix (when not using `-h`)
`function`;;
function name lines (when using `-p`)
-`linenumber`;;
+`lineNumber`;;
line number prefix (when using `-n`)
+`column`;;
+ column number prefix (when using `--column`)
`match`;;
matching text (same as setting `matchContext` and `matchSelected`)
`matchContext`;;
@@ -1492,6 +1536,15 @@ fetch.output::
`full` and `compact`. Default value is `full`. See section
OUTPUT in linkgit:git-fetch[1] for detail.
+fetch.negotiationAlgorithm::
+ Control how information about the commits in the local repository is
+ sent when negotiating the contents of the packfile to be sent by the
+ server. Set to "skipping" to use an algorithm that skips commits in an
+ effort to converge faster, but may result in a larger-than-necessary
+ packfile; any other value instructs Git to use the default algorithm
+ that never skips commits (unless the server has acknowledged it or one
+ of its descendants).
+
format.attach::
Enable multipart/mixed attachments as the default for
'format-patch'. The value can also be a double quoted string
@@ -1798,6 +1851,9 @@ gitweb.snapshot::
grep.lineNumber::
If set to true, enable `-n` option by default.
+grep.column::
+ If set to true, enable the `--column` option by default.
+
grep.patternType::
Set the default matching behavior. Using a value of 'basic', 'extended',
'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`,
@@ -1828,6 +1884,16 @@ gpg.program::
signed, and the program is expected to send the result to its
standard output.
+gpg.format::
+ Specifies which key format to use when signing with `--gpg-sign`.
+ Default is "openpgp" and another possible value is "x509".
+
+gpg.<format>.program::
+ Use this to customize the program used for the signing format you
+ chose. (see `gpg.program` and `gpg.format`) `gpg.program` can still
+ be used as a legacy synonym for `gpg.openpgp.program`. The default
+ value for `gpg.x509.program` is "gpgsm".
+
gui.commitMsgWidth::
Defines how wide the commit message window is in the
linkgit:git-gui[1]. "75" is the default.
@@ -3328,12 +3394,13 @@ submodule.<name>.ignore::
submodule.<name>.active::
Boolean value indicating if the submodule is of interest to git
commands. This config option takes precedence over the
- submodule.active config option.
+ submodule.active config option. See linkgit:gitsubmodules[7] for
+ details.
submodule.active::
A repeated field which contains a pathspec used to match against a
submodule's path to determine if the submodule is of interest to git
- commands.
+ commands. See linkgit:gitsubmodules[7] for details.
submodule.recurse::
Specifies if commands recurse into submodules by default. This
@@ -3480,6 +3547,13 @@ Note that this configuration variable is ignored if it is seen in the
repository-level config (this is a safety measure against fetching from
untrusted repositories).
+uploadpack.allowRefInWant::
+ If this option is set, `upload-pack` will support the `ref-in-want`
+ feature of the protocol version 2 `fetch` command. This feature
+ is intended for the benefit of load-balanced servers which may
+ not have the same view of what OIDs their refs point to due to
+ replication delay.
+
url.<base>.insteadOf::
Any URL that starts with this value will be rewritten to
start, instead, with <base>. In cases where some site serves a
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 4106490..0378cd5 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -276,16 +276,46 @@ plain::
that are added somewhere else in the diff. This mode picks up any
moved line, but it is not very useful in a review to determine
if a block of code was moved without permutation.
-zebra::
+blocks::
Blocks of moved text of at least 20 alphanumeric characters
are detected greedily. The detected blocks are
- painted using either the 'color.diff.{old,new}Moved' color or
+ painted using either the 'color.diff.{old,new}Moved' color.
+ Adjacent blocks cannot be told apart.
+zebra::
+ Blocks of moved text are detected as in 'blocks' mode. The blocks
+ are painted using either the 'color.diff.{old,new}Moved' color or
'color.diff.{old,new}MovedAlternative'. The change between
the two colors indicates that a new block was detected.
-dimmed_zebra::
+dimmed-zebra::
Similar to 'zebra', but additional dimming of uninteresting parts
of moved code is performed. The bordering lines of two adjacent
blocks are considered interesting, the rest is uninteresting.
+ `dimmed_zebra` is a deprecated synonym.
+--
+
+--color-moved-ws=<modes>::
+ This configures how white spaces are ignored when performing the
+ move detection for `--color-moved`.
+ifdef::git-diff[]
+ It can be set by the `diff.colorMovedWS` configuration setting.
+endif::git-diff[]
+ These modes can be given as a comma separated list:
++
+--
+ignore-space-at-eol::
+ Ignore changes in whitespace at EOL.
+ignore-space-change::
+ Ignore changes in amount of whitespace. This ignores whitespace
+ at line end, and considers all other sequences of one or
+ more whitespace characters to be equivalent.
+ignore-all-space::
+ Ignore whitespace when comparing lines. This ignores differences
+ even if one line has whitespace where the other line has none.
+allow-indentation-change::
+ Initially ignore any white spaces in the move detection, then
+ group the moved code blocks only into a block if the change in
+ whitespace is the same per line. This is incompatible with the
+ other modes.
--
--word-diff[=<mode>]::
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 97d3217..2d09f87 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -42,6 +42,22 @@ the current repository has the same history as the source repository.
.git/shallow. This option updates .git/shallow and accept such
refs.
+--negotiation-tip=<commit|glob>::
+ By default, Git will report, to the server, commits reachable
+ from all local refs to find common commits in an attempt to
+ reduce the size of the to-be-received packfile. If specified,
+ Git will only report commits reachable from the given tips.
+ This is useful to speed up fetches when the user knows which
+ local ref is likely to have commits in common with the
+ upstream ref being fetched.
++
+This option may be specified more than once; if so, Git will report
+commits reachable from any of the given commits.
++
+The argument to this option may be a glob on ref names, a ref, or the (possibly
+abbreviated) SHA-1 of a commit. Specifying a glob is equivalent to specifying
+this option multiple times, one for each matching ref name.
+
ifndef::git-pull[]
--dry-run::
Show what would be done, without making any changes.
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt
index 78479b0..0f9ef2f 100644
--- a/Documentation/git-bisect-lk2009.txt
+++ b/Documentation/git-bisect-lk2009.txt
@@ -1103,7 +1103,7 @@ _____________
Combining test suites, git bisect and other systems together
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We have seen that test suites an git bisect are very powerful when
+We have seen that test suites and git bisect are very powerful when
used together. It can be even more powerful if you can combine them
with other systems.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 02eccbb..1072ca0 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -91,7 +91,6 @@ OPTIONS
-D::
Shortcut for `--delete --force`.
--l::
--create-reflog::
Create the branch's reflog. This activates recording of
all changes made to the branch ref, enabling use of date
@@ -101,6 +100,8 @@ OPTIONS
The negated form `--no-create-reflog` only overrides an earlier
`--create-reflog`, but currently does not negate the setting of
`core.logAllRefUpdates`.
++
+The `-l` option is a deprecated synonym for `--create-reflog`.
-f::
--force::
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index ca5fc9c..9db0292 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -38,6 +38,15 @@ equivalent to
$ git checkout -b <branch> --track <remote>/<branch>
------------
+
+If the branch exists in multiple remotes and one of them is named by
+the `checkout.defaultRemote` configuration variable, we'll use that
+one for the purposes of disambiguation, even if the `<branch>` isn't
+unique across all remotes. Set it to
+e.g. `checkout.defaultRemote=origin` to always checkout remote
+branches from there if `<branch>` is ambiguous but exists on the
+'origin' remote. See also `checkout.defaultRemote` in
+linkgit:git-config[1].
++
You could omit <branch>, in which case the command degenerates to
"check out the current branch", which is a glorified no-op with
rather expensive side-effects to show only the tracking information,
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index 4c97b55..dececb7 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -10,6 +10,7 @@ SYNOPSIS
--------
[verse]
'git commit-graph read' [--object-dir <dir>]
+'git commit-graph verify' [--object-dir <dir>]
'git commit-graph write' <options> [--object-dir <dir>]
@@ -37,12 +38,16 @@ Write a commit graph file based on the commits found in packfiles.
+
With the `--stdin-packs` option, generate the new commit graph by
walking objects only in the specified pack-indexes. (Cannot be combined
-with --stdin-commits.)
+with `--stdin-commits` or `--reachable`.)
+
With the `--stdin-commits` option, generate the new commit graph by
walking commits starting at the commits specified in stdin as a list
of OIDs in hex, one OID per line. (Cannot be combined with
---stdin-packs.)
+`--stdin-packs` or `--reachable`.)
++
+With the `--reachable` option, generate the new commit graph by walking
+commits starting at all refs. (Cannot be combined with `--stdin-commits`
+or `--stdin-packs`.)
+
With the `--append` option, include all commits that are present in the
existing commit-graph file.
@@ -52,6 +57,11 @@ existing commit-graph file.
Read a graph file given by the commit-graph file and output basic
details about the graph file. Used for debugging purposes.
+'verify'::
+
+Read the commit-graph file and verify its contents against the object
+database. Used to check for corrupted data.
+
EXAMPLES
--------
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 085d177..901faef 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -57,7 +57,7 @@ OPTIONS
`xx`; for example `%00` interpolates to `\0` (NUL),
`%09` to `\t` (TAB) and `%0a` to `\n` (LF).
---color[=<when>]:
+--color[=<when>]::
Respect any colors specified in the `--format` option. The
`<when>` field must be one of `always`, `never`, or `auto` (if
`<when>` is absent, behave as if `always` was given).
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt
index b9f060e..ab9a93f 100644
--- a/Documentation/git-fsck.txt
+++ b/Documentation/git-fsck.txt
@@ -110,6 +110,9 @@ Any corrupt objects you will have to find in backups or other archives
(i.e., you can just remove them and do an 'rsync' with some other site in
the hopes that somebody else has the object you have corrupted).
+If core.commitGraph is true, the commit-graph file will also be inspected
+using 'git commit-graph verify'. See linkgit:git-commit-graph[1].
+
Extracted Diagnostics
---------------------
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 24b2dd4..f5bc98c 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -136,6 +136,10 @@ The optional configuration variable `gc.packRefs` determines if
it within all non-bare repos or it can be set to a boolean value.
This defaults to true.
+The optional configuration variable `gc.commitGraph` determines if
+'git gc' should run 'git commit-graph write'. This can be set to a
+boolean value. This defaults to false.
+
The optional configuration variable `gc.aggressiveWindow` controls how
much time is spent optimizing the delta compression of the objects in
the repository when the --aggressive option is specified. The larger
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 312409a..a3049af 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -13,11 +13,11 @@ SYNOPSIS
[-v | --invert-match] [-h|-H] [--full-name]
[-E | --extended-regexp] [-G | --basic-regexp]
[-P | --perl-regexp]
- [-F | --fixed-strings] [-n | --line-number]
+ [-F | --fixed-strings] [-n | --line-number] [--column]
[-l | --files-with-matches] [-L | --files-without-match]
[(-O | --open-files-in-pager) [<pager>]]
[-z | --null]
- [-c | --count] [--all-match] [-q | --quiet]
+ [ -o | --only-matching ] [-c | --count] [--all-match] [-q | --quiet]
[--max-depth <depth>]
[--color[=<when>] | --no-color]
[--break] [--heading] [-p | --show-function]
@@ -44,6 +44,9 @@ CONFIGURATION
grep.lineNumber::
If set to true, enable `-n` option by default.
+grep.column::
+ If set to true, enable the `--column` option by default.
+
grep.patternType::
Set the default matching behavior. Using a value of 'basic', 'extended',
'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`,
@@ -169,6 +172,10 @@ providing this option will cause it to die.
--line-number::
Prefix the line number to matching lines.
+--column::
+ Prefix the 1-indexed byte-offset of the first match from the start of the
+ matching line.
+
-l::
--files-with-matches::
--name-only::
@@ -194,6 +201,11 @@ providing this option will cause it to die.
Output \0 instead of the character that normally follows a
file name.
+-o::
+--only-matching::
+ Print only the matched (non-empty) parts of a matching line, with each such
+ part on a separate output line.
+
-c::
--count::
Instead of showing every matched line, show the number of
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index 032613c..7b15744 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -68,8 +68,8 @@ imap.tunnel::
to the server. Required when imap.host is not set.
imap.host::
- A URL identifying the server. Use a `imap://` prefix for non-secure
- connections and a `imaps://` prefix for secure connections.
+ A URL identifying the server. Use an `imap://` prefix for non-secure
+ connections and an `imaps://` prefix for secure connections.
Ignored when imap.tunnel is set, but required otherwise.
imap.user::
diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt
index 9111c47..b8fafb1 100644
--- a/Documentation/git-interpret-trailers.txt
+++ b/Documentation/git-interpret-trailers.txt
@@ -88,7 +88,8 @@ OPTIONS
Specify where all new trailers will be added. A setting
provided with '--where' overrides all configuration variables
and applies to all '--trailer' options until the next occurrence of
- '--where' or '--no-where'.
+ '--where' or '--no-where'. Possible values are `after`, `before`,
+ `end` or `start`.
--if-exists <action>::
--no-if-exists::
@@ -96,7 +97,8 @@ OPTIONS
least one trailer with the same <token> in the message. 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'.
+ '--if-exists' or '--no-if-exists'. Possible actions are `addIfDifferent`,
+ `addIfDifferentNeighbor`, `add`, `replace` and `doNothing`.
--if-missing <action>::
--no-if-missing::
@@ -104,7 +106,8 @@ OPTIONS
trailer with the same <token> in the message. 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'.
+ '--if-missing' or '--no-if-missing'. Possible actions are `doNothing`
+ or `add`.
--only-trailers::
Output only the trailers, not any other parts of the input.
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 6a5c00e..eb36837 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -12,7 +12,7 @@ SYNOPSIS
'git merge' [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
[-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
[--[no-]allow-unrelated-histories]
- [--[no-]rerere-autoupdate] [-m <msg>] [<commit>...]
+ [--[no-]rerere-autoupdate] [-m <msg>] [-F <file>] [<commit>...]
'git merge' --abort
'git merge' --continue
@@ -75,6 +75,14 @@ The 'git fmt-merge-msg' command can be
used to give a good default for automated 'git merge'
invocations. The automated message can include the branch description.
+-F <file>::
+--file=<file>::
+ Read the commit message to be used for the merge commit (in
+ case one is created).
++
+If `--log` is specified, a shortlog of the commits being merged
+will be appended to the specified message.
+
--[no-]rerere-autoupdate::
Allow the rerere mechanism to update the index with the
result of auto-conflict resolution if possible.
@@ -122,9 +130,9 @@ merge' may need to update.
To avoid recording unrelated changes in the merge commit,
'git pull' and 'git merge' will also abort if there are any changes
-registered in the index relative to the `HEAD` commit. (One
-exception is when the changed index entries are in the state that
-would result from the merge already.)
+registered in the index relative to the `HEAD` commit. (Special
+narrow exceptions to this rule may exist depending on which merge
+strategy is in use, but generally, the index must match HEAD.)
If all named commits are already ancestors of `HEAD`, 'git merge'
will exit early with the message "Already up to date."
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index e8dec1b..df2b64d 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -199,7 +199,7 @@ OPTIONS
.git/NOTES_MERGE_REF symref is updated to the resulting commit.
--abort::
- Abort/reset a in-progress 'git notes merge', i.e. a notes merge
+ Abort/reset an in-progress 'git notes merge', i.e. a notes merge
with conflicts. This simply removes all files related to the
notes merge.
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 0e20a66..1fbc6eb 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -243,11 +243,15 @@ leave out at most one of A and B, in which case it defaults to HEAD.
--keep-empty::
Keep the commits that do not change anything from its
parents in the result.
++
+See also INCOMPATIBLE OPTIONS below.
--allow-empty-message::
By default, rebasing commits with an empty message will fail.
This option overrides that behavior, allowing commits with empty
messages to be rebased.
++
+See also INCOMPATIBLE OPTIONS below.
--skip::
Restart the rebasing process by skipping the current patch.
@@ -271,6 +275,8 @@ branch on top of the <upstream> branch. Because of this, when a merge
conflict happens, the side reported as 'ours' is the so-far rebased
series, starting with <upstream>, and 'theirs' is the working branch. In
other words, the sides are swapped.
++
+See also INCOMPATIBLE OPTIONS below.
-s <strategy>::
--strategy=<strategy>::
@@ -280,8 +286,10 @@ other words, the sides are swapped.
+
Because 'git rebase' replays each commit from the working branch
on top of the <upstream> branch using the given strategy, using
-the 'ours' strategy simply discards all patches from the <branch>,
+the 'ours' strategy simply empties all patches from the <branch>,
which makes little sense.
++
+See also INCOMPATIBLE OPTIONS below.
-X <strategy-option>::
--strategy-option=<strategy-option>::
@@ -289,6 +297,8 @@ which makes little sense.
This implies `--merge` and, if no strategy has been
specified, `-s recursive`. Note the reversal of 'ours' and
'theirs' as noted above for the `-m` option.
++
+See also INCOMPATIBLE OPTIONS below.
-S[<keyid>]::
--gpg-sign[=<keyid>]::
@@ -324,17 +334,21 @@ which makes little sense.
and after each change. When fewer lines of surrounding
context exist they all must match. By default no context is
ever ignored.
++
+See also INCOMPATIBLE OPTIONS below.
--f::
+--no-ff::
--force-rebase::
- Force a rebase even if the current branch is up to date and
- the command without `--force` would return without doing anything.
+-f::
+ Individually replay all rebased commits instead of fast-forwarding
+ over the unchanged ones. This ensures that the entire history of
+ the rebased branch is composed of new commits.
+
-You may find this (or --no-ff with an interactive rebase) helpful after
-reverting a topic branch merge, as this option recreates the topic branch with
-fresh commits so it can be remerged successfully without needing to "revert
-the reversion" (see the
-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).
+You may find this helpful after reverting a topic branch merge, as this option
+recreates the topic branch with fresh commits so it can be remerged
+successfully without needing to "revert the reversion" (see the
+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for
+details).
--fork-point::
--no-fork-point::
@@ -355,19 +369,22 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.
--whitespace=<option>::
These flag are passed to the 'git apply' program
(see linkgit:git-apply[1]) that applies the patch.
- Incompatible with the --interactive option.
++
+See also INCOMPATIBLE OPTIONS below.
--committer-date-is-author-date::
--ignore-date::
These flags are passed to 'git am' to easily change the dates
of the rebased commits (see linkgit:git-am[1]).
- Incompatible with the --interactive option.
++
+See also INCOMPATIBLE OPTIONS below.
--signoff::
Add a Signed-off-by: trailer to all the rebased commits. Note
that if `--interactive` is given then only commits marked to be
- picked, edited or reworded will have the trailer added. Incompatible
- with the `--preserve-merges` option.
+ picked, edited or reworded will have the trailer added.
++
+See also INCOMPATIBLE OPTIONS below.
-i::
--interactive::
@@ -378,6 +395,8 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.
The commit list format can be changed by setting the configuration option
rebase.instructionFormat. A customized instruction format will automatically
have the long commit hash prepended to the format.
++
+See also INCOMPATIBLE OPTIONS below.
-r::
--rebase-merges[=(rebase-cousins|no-rebase-cousins)]::
@@ -404,7 +423,7 @@ It is currently only possible to recreate the merge commits using the
`recursive` merge strategy; Different merge strategies can be used only via
explicit `exec git merge -s <strategy> [...]` commands.
+
-See also REBASING MERGES below.
+See also REBASING MERGES and INCOMPATIBLE OPTIONS below.
-p::
--preserve-merges::
@@ -415,6 +434,8 @@ See also REBASING MERGES below.
This uses the `--interactive` machinery internally, but combining it
with the `--interactive` option explicitly is generally not a good
idea unless you know what you are doing (see BUGS below).
++
+See also INCOMPATIBLE OPTIONS below.
-x <cmd>::
--exec <cmd>::
@@ -437,6 +458,8 @@ squash/fixup series.
+
This uses the `--interactive` machinery internally, but it can be run
without an explicit `--interactive`.
++
+See also INCOMPATIBLE OPTIONS below.
--root::
Rebase all commits reachable from <branch>, instead of
@@ -447,6 +470,8 @@ without an explicit `--interactive`.
When used together with both --onto and --preserve-merges,
'all' root commits will be rewritten to have <newbase> as parent
instead.
++
+See also INCOMPATIBLE OPTIONS below.
--autosquash::
--no-autosquash::
@@ -461,11 +486,11 @@ without an explicit `--interactive`.
too. The recommended way to create fixup/squash commits is by using
the `--fixup`/`--squash` options of linkgit:git-commit[1].
+
-This option is only valid when the `--interactive` option is used.
-+
If the `--autosquash` option is enabled by default using the
configuration variable `rebase.autoSquash`, this option can be
used to override and disable this setting.
++
+See also INCOMPATIBLE OPTIONS below.
--autostash::
--no-autostash::
@@ -475,17 +500,73 @@ used to override and disable this setting.
with care: the final stash application after a successful
rebase might result in non-trivial conflicts.
---no-ff::
- With --interactive, cherry-pick all rebased commits instead of
- fast-forwarding over the unchanged ones. This ensures that the
- entire history of the rebased branch is composed of new commits.
-+
-Without --interactive, this is a synonym for --force-rebase.
-+
-You may find this helpful after reverting a topic branch merge, as this option
-recreates the topic branch with fresh commits so it can be remerged
-successfully without needing to "revert the reversion" (see the
-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).
+INCOMPATIBLE OPTIONS
+--------------------
+
+git-rebase has many flags that are incompatible with each other,
+predominantly due to the fact that it has three different underlying
+implementations:
+
+ * one based on linkgit:git-am[1] (the default)
+ * one based on git-merge-recursive (merge backend)
+ * one based on linkgit:git-cherry-pick[1] (interactive backend)
+
+Flags only understood by the am backend:
+
+ * --committer-date-is-author-date
+ * --ignore-date
+ * --whitespace
+ * --ignore-whitespace
+ * -C
+
+Flags understood by both merge and interactive backends:
+
+ * --merge
+ * --strategy
+ * --strategy-option
+ * --allow-empty-message
+
+Flags only understood by the interactive backend:
+
+ * --[no-]autosquash
+ * --rebase-merges
+ * --preserve-merges
+ * --interactive
+ * --exec
+ * --keep-empty
+ * --autosquash
+ * --edit-todo
+ * --root when used in combination with --onto
+
+Other incompatible flag pairs:
+
+ * --preserve-merges and --interactive
+ * --preserve-merges and --signoff
+ * --preserve-merges and --rebase-merges
+ * --rebase-merges and --strategy
+ * --rebase-merges and --strategy-option
+
+BEHAVIORAL DIFFERENCES
+-----------------------
+
+ * empty commits:
+
+ am-based rebase will drop any "empty" commits, whether the
+ commit started empty (had no changes relative to its parent to
+ start with) or ended empty (all changes were already applied
+ upstream in other commits).
+
+ merge-based rebase does the same.
+
+ interactive-based rebase will by default drop commits that
+ started empty and halt if it hits a commit that ended up empty.
+ The `--keep-empty` option exists for interactive rebases to allow
+ it to keep commits that started empty.
+
+ * directory rename detection:
+
+ merge-based and interactive-based rebases work fine with
+ directory rename detection. am-based rebases sometimes do not.
include::merge-strategies.txt[]
@@ -804,7 +885,7 @@ The ripple effect of a "hard case" recovery is especially bad:
case" recovery too!
REBASING MERGES
------------------
+---------------
The interactive rebase command was originally designed to handle
individual patch series. As such, it makes sense to exclude merge
@@ -879,8 +960,8 @@ rescheduled immediately, with a helpful message how to edit the todo list
(this typically happens when a `reset` command was inserted into the todo
list manually and contains a typo).
-The `merge` command will merge the specified revision into whatever is
-HEAD at that time. With `-C <original-commit>`, the commit message of
+The `merge` command will merge the specified revision(s) into whatever
+is HEAD at that time. With `-C <original-commit>`, the commit message of
the specified merge commit will be used. When the `-C` is changed to
a lower-case `-c`, the message will be opened in an editor after a
successful merge so that the user can edit the message.
@@ -889,7 +970,8 @@ If a `merge` command fails for any reason other than merge conflicts (i.e.
when the merge operation did not even start), it is rescheduled immediately.
At this time, the `merge` command will *always* use the `recursive`
-merge strategy, with no way to choose a different one. To work around
+merge strategy for regular merges, and `octopus` for octopus merges,
+strategy, with no way to choose a different one. To work around
this, an `exec` command can be used to call `git merge` explicitly,
using the fact that the labels are worktree-local refs (the ref
`refs/rewritten/onto` would correspond to the label `onto`, for example).
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 4f3efde..465a4ec 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -137,15 +137,17 @@ Note that no attempts whatsoever are made to validate the encoding.
Specify encoding of compose message. Default is the value of the
'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed.
---transfer-encoding=(7bit|8bit|quoted-printable|base64)::
+--transfer-encoding=(7bit|8bit|quoted-printable|base64|auto)::
Specify the transfer encoding to be used to send the message over SMTP.
7bit will fail upon encountering a non-ASCII message. quoted-printable
can be useful when the repository contains files that contain carriage
returns, but makes the raw patch email file (as saved from a MUA) much
harder to inspect manually. base64 is even more fool proof, but also
- even more opaque. Default is the value of the `sendemail.transferEncoding`
- configuration value; if that is unspecified, git will use 8bit and not
- add a Content-Transfer-Encoding header.
+ even more opaque. auto will use 8bit when possible, and quoted-printable
+ otherwise.
++
+Default is the value of the `sendemail.transferEncoding` configuration
+value; if that is unspecified, default to `auto`.
--xmailer::
--no-xmailer::
@@ -398,8 +400,11 @@ have been specified, in which case default to 'compose'.
+
--
* Invoke the sendemail-validate hook if present (see linkgit:githooks[5]).
- * Warn of patches that contain lines longer than 998 characters; this
- is due to SMTP limits as described by http://www.ietf.org/rfc/rfc2821.txt.
+ * Warn of patches that contain lines longer than
+ 998 characters unless a suitable transfer encoding
+ ('auto', 'base64', or 'quoted-printable') is used;
+ this is due to SMTP limits as described by
+ http://www.ietf.org/rfc/rfc5322.txt.
--
+
Default is the value of `sendemail.validate`; if this is not set,
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index c4467ff..d9f422d 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -106,7 +106,7 @@ It is optional: it defaults to 'traditional'.
The possible options are:
+
- 'traditional' - Shows ignored files and directories, unless
- --untracked-files=all is specifed, in which case
+ --untracked-files=all is specified, in which case
individual files in ignored directories are
displayed.
- 'no' - Show no ignored files.
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 7ea24fc..b990295 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -452,7 +452,7 @@ Any other arguments are passed directly to 'git log'
'commit-diff'::
Commits the diff of two tree-ish arguments from the
- command-line. This command does not rely on being inside an `git svn
+ command-line. This command does not rely on being inside a `git svn
init`-ed repository. This command takes three arguments, (a) the
original tree to diff against, (b) the new tree result, (c) the
URL of the target Subversion repository. The final argument
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 87c4288..92f9c12 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -115,7 +115,7 @@ options for details.
variable if it exists, or lexicographic order otherwise. See
linkgit:git-config[1].
---color[=<when>]:
+--color[=<when>]::
Respect any colors specified in the `--format` option. The
`<when>` field must be one of `always`, `never`, or `auto` (if
`<when>` is absent, behave as if `always` was given).
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index afc6576..9c26be4 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -60,6 +60,15 @@ with a matching name, treat as equivalent to:
$ git worktree add --track -b <branch> <path> <remote>/<branch>
------------
+
+If the branch exists in multiple remotes and one of them is named by
+the `checkout.defaultRemote` configuration variable, we'll use that
+one for the purposes of disambiguation, even if the `<branch>` isn't
+unique across all remotes. Set it to
+e.g. `checkout.defaultRemote=origin` to always checkout remote
+branches from there if `<branch>` is ambiguous but exists on the
+'origin' remote. See also `checkout.defaultRemote` in
+linkgit:git-config[1].
++
If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
then, as a convenience, the new worktree is associated with a branch
(call it `<branch>`) named after `$(basename <path>)`. If `<branch>`
diff --git a/Documentation/giteveryday.txt b/Documentation/giteveryday.txt
index 10c8ff9..9f2528f 100644
--- a/Documentation/giteveryday.txt
+++ b/Documentation/giteveryday.txt
@@ -244,7 +244,7 @@ commands in addition to the ones needed by participants.
This section can also be used by those who respond to `git
request-pull` or pull-request on GitHub (www.github.com) to
-integrate the work of others into their history. An sub-area
+integrate the work of others into their history. A sub-area
lieutenant for a repository will act both as a participant and
as an integrator.
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index ff5d7f9..d107daa 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -7,7 +7,7 @@ gitignore - Specifies intentionally untracked files to ignore
SYNOPSIS
--------
-$HOME/.config/git/ignore, $GIT_DIR/info/exclude, .gitignore
+$XDG_CONFIG_HOME/git/ignore, $GIT_DIR/info/exclude, .gitignore
DESCRIPTION
-----------
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt
index 3b9faab..504c5f1 100644
--- a/Documentation/gitsubmodules.txt
+++ b/Documentation/gitsubmodules.txt
@@ -194,7 +194,7 @@ In the above config only the submodule 'bar' and 'baz' are active,
Note that (c) is a historical artefact and will be ignored if the
(a) and (b) specify that the submodule is not active. In other words,
-if we have an `submodule.<name>.active` set to `false` or if the
+if we have a `submodule.<name>.active` set to `false` or if the
submodule's path is excluded in the pathspec in `submodule.active`, the
url doesn't matter whether it is present or not. This is illustrated in
the example that follows.
diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt
index 6c2d23d..0d2aa48 100644
--- a/Documentation/glossary-content.txt
+++ b/Documentation/glossary-content.txt
@@ -334,7 +334,7 @@ The optional colon that terminates the "magic signature" can be
omitted if the pattern begins with a character that does not belong to
"magic signature" symbol set and is not a colon.
+
-In the long form, the leading colon `:` is followed by a open
+In the long form, the leading colon `:` is followed by an open
parenthesis `(`, a comma-separated list of zero or more "magic words",
and a close parentheses `)`, and the remainder is the pattern to match
against the path.
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 7d1bd44..72daa20 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -184,7 +184,8 @@ existing tag object.
A colon, followed by a slash, followed by a text, names
a commit whose commit message matches the specified regular expression.
This name returns the youngest matching commit which is
- reachable from any ref. The regular expression can match any part of the
+ reachable from any ref, including HEAD.
+ The regular expression can match any part of the
commit message. To match messages starting with a string, one can use
e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what
is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a
diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt
index 4f44ca2..5abb8e8 100644
--- a/Documentation/technical/api-directory-listing.txt
+++ b/Documentation/technical/api-directory-listing.txt
@@ -54,7 +54,7 @@ The notable options are:
this case, the contents are returned as individual entries.
+
If this is set, files and directories that explicitly match an ignore
-pattern are reported. Implicity ignored directories (directories that
+pattern are reported. Implicitly ignored directories (directories that
do not match an ignore pattern, but whose contents are all ignored)
are not reported, instead all of the contents are reported.
diff --git a/Documentation/technical/api-gitattributes.txt b/Documentation/technical/api-gitattributes.txt
index e7cbb7c..45f0df6 100644
--- a/Documentation/technical/api-gitattributes.txt
+++ b/Documentation/technical/api-gitattributes.txt
@@ -146,7 +146,7 @@ To get the values of all attributes associated with a file:
* Iterate over the `attr_check.items[]` array to examine
the attribute names and values. The name of the attribute
- described by a `attr_check.items[]` object can be retrieved via
+ described by an `attr_check.items[]` object can be retrieved via
`git_attr_name(check->items[i].attr)`. (Please note that no items
will be returned for unset attributes, so `ATTR_UNSET()` will return
false for all returned `attr_check.items[]` objects.)
diff --git a/Documentation/technical/commit-graph-format.txt b/Documentation/technical/commit-graph-format.txt
index ad6af81..cc0474b 100644
--- a/Documentation/technical/commit-graph-format.txt
+++ b/Documentation/technical/commit-graph-format.txt
@@ -18,9 +18,9 @@ metadata, including:
the graph file.
These positional references are stored as unsigned 32-bit integers
-corresponding to the array position withing the list of commit OIDs. We
-use the most-significant bit for special purposes, so we can store at most
-(1 << 31) - 1 (around 2 billion) commits.
+corresponding to the array position within the list of commit OIDs. Due
+to some special constants we use to track parents, we can store at most
+(1 << 30) + (1 << 29) + (1 << 28) - 1 (around 1.8 billion) commits.
== Commit graph files have the following format:
@@ -70,10 +70,10 @@ CHUNK DATA:
OID Lookup (ID: {'O', 'I', 'D', 'L'}) (N * H bytes)
The OIDs for all commits in the graph, sorted in ascending order.
- Commit Data (ID: {'C', 'G', 'E', 'T' }) (N * (H + 16) bytes)
+ Commit Data (ID: {'C', 'D', 'A', 'T' }) (N * (H + 16) bytes)
* The first H bytes are for the OID of the root tree.
* The next 8 bytes are for the positions of the first two parents
- of the ith commit. Stores value 0xffffffff if no parent in that
+ of the ith commit. Stores value 0x7000000 if no parent in that
position. If there are more than two parents, the second value
has its most-significant bit on and the other bits store an array
position into the Large Edge List chunk.
diff --git a/Documentation/technical/commit-graph.txt b/Documentation/technical/commit-graph.txt
index e1a883e..c664acb 100644
--- a/Documentation/technical/commit-graph.txt
+++ b/Documentation/technical/commit-graph.txt
@@ -118,9 +118,6 @@ Future Work
- The commit graph feature currently does not honor commit grafts. This can
be remedied by duplicating or refactoring the current graft logic.
-- The 'commit-graph' subcommand does not have a "verify" mode that is
- necessary for integration with fsck.
-
- After computing and storing generation numbers, we must make graph
walks aware of generation numbers to gain the performance benefits they
enable. This will mostly be accomplished by swapping a commit-date-ordered
@@ -130,25 +127,6 @@ Future Work
- 'log --topo-order'
- 'tag --merged'
-- Currently, parse_commit_gently() requires filling in the root tree
- object for a commit. This passes through lookup_tree() and consequently
- lookup_object(). Also, it calls lookup_commit() when loading the parents.
- These method calls check the ODB for object existence, even if the
- consumer does not need the content. For example, we do not need the
- tree contents when computing merge bases. Now that commit parsing is
- removed from the computation time, these lookup operations are the
- slowest operations keeping graph walks from being fast. Consider
- loading these objects without verifying their existence in the ODB and
- only loading them fully when consumers need them. Consider a method
- such as "ensure_tree_loaded(commit)" that fully loads a tree before
- using commit->tree.
-
-- The current design uses the 'commit-graph' subcommand to generate the graph.
- When this feature stabilizes enough to recommend to most users, we should
- add automatic graph writes to common operations that create many commits.
- For example, one could compute a graph on 'clone', 'fetch', or 'repack'
- commands.
-
- A server could provide a commit graph file as part of the network protocol
to avoid extra calculations by clients. This feature is only of benefit if
the user is willing to trust the file, because verifying the file is correct
diff --git a/Documentation/technical/directory-rename-detection.txt b/Documentation/technical/directory-rename-detection.txt
new file mode 100644
index 0000000..1c0086e
--- /dev/null
+++ b/Documentation/technical/directory-rename-detection.txt
@@ -0,0 +1,115 @@
+Directory rename detection
+==========================
+
+Rename detection logic in diffcore-rename that checks for renames of
+individual files is aggregated and analyzed in merge-recursive for cases
+where combinations of renames indicate that a full directory has been
+renamed.
+
+Scope of abilities
+------------------
+
+It is perhaps easiest to start with an example:
+
+ * When all of x/a, x/b and x/c have moved to z/a, z/b and z/c, it is
+ likely that x/d added in the meantime would also want to move to z/d by
+ taking the hint that the entire directory 'x' moved to 'z'.
+
+More interesting possibilities exist, though, such as:
+
+ * one side of history renames x -> z, and the other renames some file to
+ x/e, causing the need for the merge to do a transitive rename.
+
+ * one side of history renames x -> z, but also renames all files within
+ x. For example, x/a -> z/alpha, x/b -> z/bravo, etc.
+
+ * both 'x' and 'y' being merged into a single directory 'z', with a
+ directory rename being detected for both x->z and y->z.
+
+ * not all files in a directory being renamed to the same location;
+ i.e. perhaps most the files in 'x' are now found under 'z', but a few
+ are found under 'w'.
+
+ * a directory being renamed, which also contained a subdirectory that was
+ renamed to some entirely different location. (And perhaps the inner
+ directory itself contained inner directories that were renamed to yet
+ other locations).
+
+ * combinations of the above; see t/t6043-merge-rename-directories.sh for
+ various interesting cases.
+
+Limitations -- applicability of directory renames
+-------------------------------------------------
+
+In order to prevent edge and corner cases resulting in either conflicts
+that cannot be represented in the index or which might be too complex for
+users to try to understand and resolve, a couple basic rules limit when
+directory rename detection applies:
+
+ 1) If a given directory still exists on both sides of a merge, we do
+ not consider it to have been renamed.
+
+ 2) If a subset of to-be-renamed files have a file or directory in the
+ way (or would be in the way of each other), "turn off" the directory
+ rename for those specific sub-paths and report the conflict to the
+ user.
+
+ 3) If the other side of history did a directory rename to a path that
+ your side of history renamed away, then ignore that particular
+ rename from the other side of history for any implicit directory
+ renames (but warn the user).
+
+Limitations -- detailed rules and testcases
+-------------------------------------------
+
+t/t6043-merge-rename-directories.sh contains extensive tests and commentary
+which generate and explore the rules listed above. It also lists a few
+additional rules:
+
+ a) If renames split a directory into two or more others, the directory
+ with the most renames, "wins".
+
+ b) Avoid directory-rename-detection for a path, if that path is the
+ source of a rename on either side of a merge.
+
+ c) Only apply implicit directory renames to directories if the other side
+ of history is the one doing the renaming.
+
+Limitations -- support in different commands
+--------------------------------------------
+
+Directory rename detection is supported by 'merge' and 'cherry-pick'.
+Other git commands which users might be surprised to see limited or no
+directory rename detection support in:
+
+ * diff
+
+ Folks have requested in the past that `git diff` detect directory
+ renames and somehow simplify its output. It is not clear whether this
+ would be desirable or how the output should be simplified, so this was
+ simply not implemented. Further, to implement this, directory rename
+ detection logic would need to move from merge-recursive to
+ diffcore-rename.
+
+ * am
+
+ git-am tries to avoid a full three way merge, instead calling
+ git-apply. That prevents us from detecting renames at all, which may
+ defeat the directory rename detection. There is a fallback, though; if
+ the initial git-apply fails and the user has specified the -3 option,
+ git-am will fall back to a three way merge. However, git-am lacks the
+ necessary information to do a "real" three way merge. Instead, it has
+ to use build_fake_ancestor() to get a merge base that is missing files
+ whose rename may have been important to detect for directory rename
+ detection to function.
+
+ * rebase
+
+ Since am-based rebases work by first generating a bunch of patches
+ (which no longer record what the original commits were and thus don't
+ have the necessary info from which we can find a real merge-base), and
+ then calling git-am, this implies that am-based rebases will not always
+ successfully detect directory renames either (see the 'am' section
+ above). merged-based rebases (rebase -m) and cherry-pick-based rebases
+ (rebase -i) are not affected by this shortcoming, and fully support
+ directory rename detection.
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index 7fee6b7..6ac774d 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -50,7 +50,8 @@ Each Extra Parameter takes the form of `<key>=<value>` or `<key>`.
Servers that receive any such Extra Parameters MUST ignore all
unrecognized keys. Currently, the only Extra Parameter recognized is
-"version=1".
+"version" with a value of '1' or '2'. See protocol-v2.txt for more
+information on protocol version 2.
Git Transport
-------------
@@ -284,7 +285,9 @@ information is sent back to the client in the next step.
The client can optionally request that pack-objects omit various
objects from the packfile using one of several filtering techniques.
These are intended for use with partial clone and partial fetch
-operations. See `rev-list` for possible "filter-spec" values.
+operations. An object that does not meet a filter-spec value is
+omitted unless explicitly requested in a 'want' line. See `rev-list`
+for possible filter-spec values.
Once all the 'want's and 'shallow's (and optional 'deepen') are
transferred, clients MUST send a flush-pkt, to tell the server side
diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
index 49bda76..09e4e02 100644
--- a/Documentation/technical/protocol-v2.txt
+++ b/Documentation/technical/protocol-v2.txt
@@ -64,9 +64,8 @@ When using the http:// or https:// transport a client makes a "smart"
info/refs request as described in `http-protocol.txt` and requests that
v2 be used by supplying "version=2" in the `Git-Protocol` header.
- C: Git-Protocol: version=2
- C:
C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0
+ C: Git-Protocol: version=2
A v2 server would reply:
@@ -299,12 +298,21 @@ included in the client's request:
for use with partial clone and partial fetch operations. See
`rev-list` for possible "filter-spec" values.
+If the 'ref-in-want' feature is advertised, the following argument can
+be included in the client's request as well as the potential addition of
+the 'wanted-refs' section in the server's response as explained below.
+
+ want-ref <ref>
+ Indicates to the server that the client wants to retrieve a
+ particular ref, where <ref> is the full name of a ref on the
+ server.
+
The response of `fetch` is broken into a number of sections separated by
delimiter packets (0001), with each section beginning with its section
header.
output = *section
- section = (acknowledgments | shallow-info | packfile)
+ section = (acknowledgments | shallow-info | wanted-refs | packfile)
(flush-pkt | delim-pkt)
acknowledgments = PKT-LINE("acknowledgments" LF)
@@ -319,6 +327,10 @@ header.
shallow = "shallow" SP obj-id
unshallow = "unshallow" SP obj-id
+ wanted-refs = PKT-LINE("wanted-refs" LF)
+ *PKT-LINE(wanted-ref LF)
+ wanted-ref = obj-id SP refname
+
packfile = PKT-LINE("packfile" LF)
*PKT-LINE(%x01-03 *%x00-ff)
@@ -379,6 +391,19 @@ header.
* This section is only included if a packfile section is also
included in the response.
+ wanted-refs section
+ * This section is only included if the client has requested a
+ ref using a 'want-ref' line and if a packfile section is also
+ included in the response.
+
+ * Always begins with the section header "wanted-refs".
+
+ * The server will send a ref listing ("<oid> <refname>") for
+ each reference requested using 'want-ref' lines.
+
+ * The server MUST NOT send any refs which were not requested
+ using 'want-ref' lines.
+
packfile section
* This section is only included if the client has sent 'want'
lines in its request and either requested that no more
diff --git a/Makefile b/Makefile
index 0cb6590..8251c39 100644
--- a/Makefile
+++ b/Makefile
@@ -484,6 +484,11 @@ all::
# The DEVELOPER mode enables -Wextra with a few exceptions. By
# setting this flag the exceptions are removed, and all of
# -Wextra is used.
+#
+# pedantic:
+#
+# Enable -pedantic compilation. This also disables
+# USE_PARENS_AROUND_GETTEXT_N to produce only relevant warnings.
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -709,6 +714,7 @@ TEST_BUILTINS_OBJS += test-example-decorate.o
TEST_BUILTINS_OBJS += test-genrandom.o
TEST_BUILTINS_OBJS += test-hashmap.o
TEST_BUILTINS_OBJS += test-index-version.o
+TEST_BUILTINS_OBJS += test-json-writer.o
TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
TEST_BUILTINS_OBJS += test-match-trees.o
TEST_BUILTINS_OBJS += test-mergesort.o
@@ -719,6 +725,7 @@ TEST_BUILTINS_OBJS += test-prio-queue.o
TEST_BUILTINS_OBJS += test-read-cache.o
TEST_BUILTINS_OBJS += test-ref-store.o
TEST_BUILTINS_OBJS += test-regex.o
+TEST_BUILTINS_OBJS += test-repository.o
TEST_BUILTINS_OBJS += test-revision-walking.o
TEST_BUILTINS_OBJS += test-run-command.o
TEST_BUILTINS_OBJS += test-scrap-cache-tree.o
@@ -859,6 +866,7 @@ LIB_OBJS += ewah/ewah_bitmap.o
LIB_OBJS += ewah/ewah_io.o
LIB_OBJS += ewah/ewah_rlw.o
LIB_OBJS += exec-cmd.o
+LIB_OBJS += fetch-negotiator.o
LIB_OBJS += fetch-object.o
LIB_OBJS += fetch-pack.o
LIB_OBJS += fsck.o
@@ -871,6 +879,7 @@ LIB_OBJS += hashmap.o
LIB_OBJS += help.o
LIB_OBJS += hex.o
LIB_OBJS += ident.o
+LIB_OBJS += json-writer.o
LIB_OBJS += kwset.o
LIB_OBJS += levenshtein.o
LIB_OBJS += line-log.o
@@ -891,6 +900,8 @@ LIB_OBJS += merge-blobs.o
LIB_OBJS += merge-recursive.o
LIB_OBJS += mergesort.o
LIB_OBJS += name-hash.o
+LIB_OBJS += negotiator/default.o
+LIB_OBJS += negotiator/skipping.o
LIB_OBJS += notes.o
LIB_OBJS += notes-cache.o
LIB_OBJS += notes-merge.o
@@ -2021,8 +2032,9 @@ version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT
version.sp version.s version.o: EXTRA_CPPFLAGS = \
'-DGIT_VERSION="$(GIT_VERSION)"' \
'-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)' \
- '-DGIT_BUILT_FROM_COMMIT="$(shell GIT_CEILING_DIRECTORIES=\"$(CURDIR)/..\" \
- git rev-parse -q --verify HEAD || :)"'
+ '-DGIT_BUILT_FROM_COMMIT="$(shell \
+ GIT_CEILING_DIRECTORIES="$(CURDIR)/.." \
+ git rev-parse -q --verify HEAD 2>/dev/null)"'
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && \
@@ -2110,7 +2122,7 @@ $(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1{' \
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
- -e ' rGIT-PERL-HEADER' \
+ -e ' r GIT-PERL-HEADER' \
-e ' G' \
-e '}' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
diff --git a/advice.c b/advice.c
index 52aa85b..3561cd6 100644
--- a/advice.c
+++ b/advice.c
@@ -23,6 +23,7 @@ int advice_add_embedded_repo = 1;
int advice_ignored_hook = 1;
int advice_waiting_for_editor = 1;
int advice_graft_file_deprecated = 1;
+int advice_checkout_ambiguous_remote_branch_name = 1;
static int advice_use_color = -1;
static char advice_colors[][COLOR_MAXLEN] = {
@@ -75,6 +76,7 @@ static struct {
{ "ignoredHook", &advice_ignored_hook },
{ "waitingForEditor", &advice_waiting_for_editor },
{ "graftFileDeprecated", &advice_graft_file_deprecated },
+ { "checkoutAmbiguousRemoteBranchName", &advice_checkout_ambiguous_remote_branch_name },
/* make this an alias for backward compatibility */
{ "pushNonFastForward", &advice_push_update_rejected }
diff --git a/advice.h b/advice.h
index 7e93778..ab24df0 100644
--- a/advice.h
+++ b/advice.h
@@ -23,6 +23,7 @@ extern int advice_add_embedded_repo;
extern int advice_ignored_hook;
extern int advice_waiting_for_editor;
extern int advice_graft_file_deprecated;
+extern int advice_checkout_ambiguous_remote_branch_name;
int git_default_advice_config(const char *var, const char *value);
__attribute__((format (printf, 1, 2)))
diff --git a/apply.c b/apply.c
index 959c457..2594927 100644
--- a/apply.c
+++ b/apply.c
@@ -9,6 +9,7 @@
#include "cache.h"
#include "config.h"
+#include "object-store.h"
#include "blob.h"
#include "delta.h"
#include "diff.h"
@@ -4055,7 +4056,7 @@ static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)
return get_oid_hex(p->old_sha1_prefix, oid);
}
-/* Build an index that contains the just the files needed for a 3way merge */
+/* Build an index that contains just the files needed for a 3way merge */
static int build_fake_ancestor(struct apply_state *state, struct patch *list)
{
struct patch *patch;
@@ -4092,12 +4093,12 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
return error(_("sha1 information is lacking or useless "
"(%s)."), name);
- ce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0);
+ ce = make_cache_entry(&result, patch->old_mode, &oid, name, 0, 0);
if (!ce)
return error(_("make_cache_entry failed for path '%s'"),
name);
if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {
- free(ce);
+ discard_cache_entry(ce);
return error(_("could not add %s to temporary index"),
name);
}
@@ -4265,9 +4266,8 @@ static int add_index_file(struct apply_state *state,
struct stat st;
struct cache_entry *ce;
int namelen = strlen(path);
- unsigned ce_size = cache_entry_size(namelen);
- ce = xcalloc(1, ce_size);
+ ce = make_empty_cache_entry(&the_index, namelen);
memcpy(ce->name, path, namelen);
ce->ce_mode = create_ce_mode(mode);
ce->ce_flags = create_ce_flags(0);
@@ -4280,13 +4280,13 @@ static int add_index_file(struct apply_state *state,
if (!skip_prefix(buf, "Subproject commit ", &s) ||
get_oid_hex(s, &ce->oid)) {
- free(ce);
- return error(_("corrupt patch for submodule %s"), path);
+ discard_cache_entry(ce);
+ return error(_("corrupt patch for submodule %s"), path);
}
} else {
if (!state->cached) {
if (lstat(path, &st) < 0) {
- free(ce);
+ discard_cache_entry(ce);
return error_errno(_("unable to stat newly "
"created file '%s'"),
path);
@@ -4294,13 +4294,13 @@ static int add_index_file(struct apply_state *state,
fill_stat_cache_info(ce, &st);
}
if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
- free(ce);
+ discard_cache_entry(ce);
return error(_("unable to create backing store "
"for newly created file %s"), path);
}
}
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
- free(ce);
+ discard_cache_entry(ce);
return error(_("unable to add cache entry for %s"), path);
}
@@ -4424,27 +4424,26 @@ static int add_conflicted_stages_file(struct apply_state *state,
struct patch *patch)
{
int stage, namelen;
- unsigned ce_size, mode;
+ unsigned mode;
struct cache_entry *ce;
if (!state->update_index)
return 0;
namelen = strlen(patch->new_name);
- ce_size = cache_entry_size(namelen);
mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
remove_file_from_cache(patch->new_name);
for (stage = 1; stage < 4; stage++) {
if (is_null_oid(&patch->threeway_stage[stage - 1]))
continue;
- ce = xcalloc(1, ce_size);
+ ce = make_empty_cache_entry(&the_index, namelen);
memcpy(ce->name, patch->new_name, namelen);
ce->ce_mode = create_ce_mode(mode);
ce->ce_flags = create_ce_flags(stage);
ce->ce_namelen = namelen;
oidcpy(&ce->oid, &patch->threeway_stage[stage - 1]);
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
- free(ce);
+ discard_cache_entry(ce);
return error(_("unable to add cache entry for %s"),
patch->new_name);
}
diff --git a/archive-tar.c b/archive-tar.c
index 68e72d9..0bc50f6 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -5,6 +5,7 @@
#include "config.h"
#include "tar.h"
#include "archive.h"
+#include "object-store.h"
#include "streaming.h"
#include "run-command.h"
diff --git a/archive-zip.c b/archive-zip.c
index 7ad46d8..024267f 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -6,6 +6,7 @@
#include "archive.h"
#include "streaming.h"
#include "utf8.h"
+#include "object-store.h"
#include "userdiff.h"
#include "xdiff-interface.h"
diff --git a/archive.c b/archive.c
index 4fe7bec..78b0a39 100644
--- a/archive.c
+++ b/archive.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "config.h"
#include "refs.h"
+#include "object-store.h"
#include "commit.h"
#include "tree-walk.h"
#include "attr.h"
@@ -379,7 +380,7 @@ static void parse_treeish_arg(const char **argv,
if (get_oid(name, &oid))
die("Not a valid object name");
- commit = lookup_commit_reference_gently(&oid, 1);
+ commit = lookup_commit_reference_gently(the_repository, &oid, 1);
if (commit) {
commit_sha1 = commit->object.oid.hash;
archive_time = commit->date;
diff --git a/bisect.c b/bisect.c
index 6de1abd..e1275ba 100644
--- a/bisect.c
+++ b/bisect.c
@@ -724,7 +724,7 @@ static int bisect_checkout(const struct object_id *bisect_rev, int no_checkout)
static struct commit *get_commit_reference(const struct object_id *oid)
{
- struct commit *r = lookup_commit_reference(oid);
+ struct commit *r = lookup_commit_reference(the_repository, oid);
if (!r)
die(_("Not a valid commit name %s"), oid_to_hex(oid));
return r;
diff --git a/blame.c b/blame.c
index a5c9bd7..58a7036 100644
--- a/blame.c
+++ b/blame.c
@@ -1,5 +1,6 @@
#include "cache.h"
#include "refs.h"
+#include "object-store.h"
#include "cache-tree.h"
#include "mergesort.h"
#include "diff.h"
@@ -118,7 +119,7 @@ static struct commit_list **append_parent(struct commit_list **tail, const struc
{
struct commit *parent;
- parent = lookup_commit_reference(oid);
+ parent = lookup_commit_reference(the_repository, oid);
if (!parent)
die("no such commit %s", oid_to_hex(oid));
return &commit_list_insert(parent, tail)->next;
@@ -129,17 +130,19 @@ static void append_merge_parents(struct commit_list **tail)
int merge_head;
struct strbuf line = STRBUF_INIT;
- merge_head = open(git_path_merge_head(), O_RDONLY);
+ merge_head = open(git_path_merge_head(the_repository), O_RDONLY);
if (merge_head < 0) {
if (errno == ENOENT)
return;
- die("cannot open '%s' for reading", git_path_merge_head());
+ die("cannot open '%s' for reading",
+ git_path_merge_head(the_repository));
}
while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
struct object_id oid;
if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid))
- die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
+ die("unknown line in '%s': %s",
+ git_path_merge_head(the_repository), line.buf);
tail = append_parent(tail, &oid);
}
close(merge_head);
@@ -155,7 +158,7 @@ static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb)
{
size_t len;
void *buf = strbuf_detach(sb, &len);
- set_commit_buffer(c, buf, len);
+ set_commit_buffer(the_repository, c, buf, len);
}
/*
@@ -173,7 +176,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
struct strbuf buf = STRBUF_INIT;
const char *ident;
time_t now;
- int size, len;
+ int len;
struct cache_entry *ce;
unsigned mode;
struct strbuf msg = STRBUF_INIT;
@@ -271,8 +274,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
/* Let's not bother reading from HEAD tree */
mode = S_IFREG | 0644;
}
- size = cache_entry_size(len);
- ce = xcalloc(1, size);
+ ce = make_empty_cache_entry(&the_index, len);
oidcpy(&ce->oid, &origin->blob_oid);
memcpy(ce->name, path, len);
ce->ce_flags = create_ce_flags(0);
@@ -1671,7 +1673,7 @@ static struct commit *find_single_final(struct rev_info *revs,
struct object *obj = revs->pending.objects[i].item;
if (obj->flags & UNINTERESTING)
continue;
- obj = deref_tag(obj, NULL, 0);
+ obj = deref_tag(the_repository, obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (found)
@@ -1702,14 +1704,15 @@ static struct commit *dwim_reverse_initial(struct rev_info *revs,
/* Is that sole rev a committish? */
obj = revs->pending.objects[0].item;
- obj = deref_tag(obj, NULL, 0);
+ obj = deref_tag(the_repository, obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
return NULL;
/* Do we have HEAD? */
if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
return NULL;
- head_commit = lookup_commit_reference_gently(&head_oid, 1);
+ head_commit = lookup_commit_reference_gently(the_repository,
+ &head_oid, 1);
if (!head_commit)
return NULL;
@@ -1737,7 +1740,7 @@ static struct commit *find_single_initial(struct rev_info *revs,
struct object *obj = revs->pending.objects[i].item;
if (!(obj->flags & UNINTERESTING))
continue;
- obj = deref_tag(obj, NULL, 0);
+ obj = deref_tag(the_repository, obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (found)
diff --git a/blob.c b/blob.c
index 458dafa..342bdbb 100644
--- a/blob.c
+++ b/blob.c
@@ -5,13 +5,13 @@
const char *blob_type = "blob";
-struct blob *lookup_blob(const struct object_id *oid)
+struct blob *lookup_blob(struct repository *r, const struct object_id *oid)
{
- struct object *obj = lookup_object(oid->hash);
+ struct object *obj = lookup_object(r, oid->hash);
if (!obj)
- return create_object(the_repository, oid->hash,
- alloc_blob_node(the_repository));
- return object_as_type(obj, OBJ_BLOB, 0);
+ return create_object(r, oid->hash,
+ alloc_blob_node(r));
+ return object_as_type(r, obj, OBJ_BLOB, 0);
}
int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)
diff --git a/blob.h b/blob.h
index 4460616..1664872 100644
--- a/blob.h
+++ b/blob.h
@@ -9,7 +9,7 @@ struct blob {
struct object object;
};
-struct blob *lookup_blob(const struct object_id *oid);
+struct blob *lookup_blob(struct repository *r, const struct object_id *oid);
int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);
diff --git a/branch.c b/branch.c
index f967c98..ecd710d 100644
--- a/branch.c
+++ b/branch.c
@@ -302,7 +302,7 @@ void create_branch(const char *name, const char *start_name,
break;
}
- if ((commit = lookup_commit_reference(&oid)) == NULL)
+ if ((commit = lookup_commit_reference(the_repository, &oid)) == NULL)
die(_("Not a valid branch point: '%s'."), start_name);
oidcpy(&oid, &commit->object.oid);
@@ -340,13 +340,13 @@ void create_branch(const char *name, const char *start_name,
void remove_branch_state(void)
{
- unlink(git_path_cherry_pick_head());
- unlink(git_path_revert_head());
- unlink(git_path_merge_head());
- unlink(git_path_merge_rr());
- unlink(git_path_merge_msg());
- unlink(git_path_merge_mode());
- unlink(git_path_squash_msg());
+ unlink(git_path_cherry_pick_head(the_repository));
+ unlink(git_path_revert_head(the_repository));
+ unlink(git_path_merge_head(the_repository));
+ unlink(git_path_merge_rr(the_repository));
+ unlink(git_path_merge_msg(the_repository));
+ unlink(git_path_merge_mode(the_repository));
+ unlink(git_path_squash_msg(the_repository));
}
void die_if_checked_out(const char *branch, int ignore_current_worktree)
diff --git a/builtin/am.c b/builtin/am.c
index 6273ea5..2c19e69 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -32,6 +32,7 @@
#include "apply.h"
#include "string-list.h"
#include "packfile.h"
+#include "repository.h"
/**
* Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -1400,9 +1401,10 @@ static void write_index_patch(const struct am_state *state)
FILE *fp;
if (!get_oid_tree("HEAD", &head))
- tree = lookup_tree(&head);
+ tree = lookup_tree(the_repository, &head);
else
- tree = lookup_tree(the_hash_algo->empty_tree);
+ tree = lookup_tree(the_repository,
+ the_repository->hash_algo->empty_tree);
fp = xfopen(am_path(state, "patch"), "w");
init_revisions(&rev_info, NULL);
@@ -1631,7 +1633,8 @@ static void do_commit(const struct am_state *state)
if (!get_oid_commit("HEAD", &parent)) {
old_oid = &parent;
- commit_list_insert(lookup_commit(&parent), &parents);
+ commit_list_insert(lookup_commit(the_repository, &parent),
+ &parents);
} else {
old_oid = NULL;
say(state, stderr, _("applying to an empty history"));
@@ -1763,7 +1766,7 @@ static void am_run(struct am_state *state, int resume)
refresh_and_write_cache();
- if (index_has_changes(&sb)) {
+ if (index_has_changes(&the_index, NULL, &sb)) {
write_state_bool(state, "dirtyindex", 1);
die(_("Dirty index: cannot apply patches (dirty: %s)"), sb.buf);
}
@@ -1820,7 +1823,8 @@ static void am_run(struct am_state *state, int resume)
* Applying the patch to an earlier tree and merging
* the result may have produced the same tree as ours.
*/
- if (!apply_status && !index_has_changes(NULL)) {
+ if (!apply_status &&
+ !index_has_changes(&the_index, NULL, NULL)) {
say(state, stdout, _("No changes -- Patch already applied."));
goto next;
}
@@ -1874,7 +1878,7 @@ static void am_resolve(struct am_state *state)
say(state, stdout, _("Applying: %.*s"), linelen(state->msg), state->msg);
- if (!index_has_changes(NULL)) {
+ if (!index_has_changes(&the_index, NULL, NULL)) {
printf_ln(_("No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
"already introduced the same changes; you might want to skip this patch."));
diff --git a/builtin/blame.c b/builtin/blame.c
index b77ba6a..97f6eca 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -9,6 +9,7 @@
#include "config.h"
#include "color.h"
#include "builtin.h"
+#include "repository.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
@@ -23,6 +24,7 @@
#include "line-log.h"
#include "dir.h"
#include "progress.h"
+#include "object-store.h"
#include "blame.h"
#include "string-list.h"
@@ -576,7 +578,7 @@ static int read_ancestry(const char *graft_file)
/* The format is just "Commit Parent1 Parent2 ...\n" */
struct commit_graft *graft = read_graft_line(&buf);
if (graft)
- register_commit_graft(graft, 0);
+ register_commit_graft(the_repository, graft, 0);
}
fclose(fp);
strbuf_release(&buf);
@@ -1000,13 +1002,13 @@ parse_done:
nth_line_cb, &sb, lno, anchor,
&bottom, &top, sb.path))
usage(blame_usage);
- if (lno < top || ((lno || bottom) && lno < bottom))
+ if ((!lno && (top || bottom)) || lno < bottom)
die(Q_("file %s has only %lu line",
"file %s has only %lu lines",
lno), path, lno);
if (bottom < 1)
bottom = 1;
- if (top < 1)
+ if (top < 1 || lno < top)
top = lno;
bottom--;
range_set_append_unsafe(&ranges, bottom, top);
@@ -1069,7 +1071,9 @@ parse_done:
find_alignment(&sb, &output_option);
if (!*repeated_meta_color &&
(output_option & OUTPUT_COLOR_LINE))
- strcpy(repeated_meta_color, GIT_COLOR_CYAN);
+ xsnprintf(repeated_meta_color,
+ sizeof(repeated_meta_color),
+ "%s", GIT_COLOR_CYAN);
}
if (output_option & OUTPUT_ANNOTATE_COMPAT)
output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
diff --git a/builtin/branch.c b/builtin/branch.c
index 1876ca9..4fc55c3 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -37,6 +37,7 @@ static const char * const builtin_branch_usage[] = {
static const char *head;
static struct object_id head_oid;
+static int used_deprecated_reflog_option;
static int branch_use_color = -1;
static char branch_colors[][COLOR_MAXLEN] = {
@@ -121,7 +122,8 @@ static int branch_merged(int kind, const char *name,
(reference_name = reference_name_to_free =
resolve_refdup(upstream, RESOLVE_REF_READING,
&oid, NULL)) != NULL)
- reference_rev = lookup_commit_reference(&oid);
+ reference_rev = lookup_commit_reference(the_repository,
+ &oid);
}
if (!reference_rev)
reference_rev = head_rev;
@@ -154,7 +156,7 @@ static int check_branch_commit(const char *branchname, const char *refname,
const struct object_id *oid, struct commit *head_rev,
int kinds, int force)
{
- struct commit *rev = lookup_commit_reference(oid);
+ struct commit *rev = lookup_commit_reference(the_repository, oid);
if (!rev) {
error(_("Couldn't look up commit object for '%s'"), refname);
return -1;
@@ -208,7 +210,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
}
if (!force) {
- head_rev = lookup_commit_reference(&head_oid);
+ head_rev = lookup_commit_reference(the_repository, &head_oid);
if (!head_rev)
die(_("Couldn't look up commit object for HEAD"));
}
@@ -568,6 +570,14 @@ static int edit_branch_description(const char *branch_name)
return 0;
}
+static int deprecated_reflog_option_cb(const struct option *opt,
+ const char *arg, int unset)
+{
+ used_deprecated_reflog_option = 1;
+ *(int *)opt->value = !unset;
+ return 0;
+}
+
int cmd_branch(int argc, const char **argv, const char *prefix)
{
int delete = 0, rename = 0, copy = 0, force = 0, list = 0;
@@ -610,7 +620,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
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(0, "list", &list, N_("list branch names")),
- OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
+ OPT_BOOL(0, "create-reflog", &reflog, N_("create the branch's reflog")),
+ {
+ OPTION_CALLBACK, 'l', NULL, &reflog, NULL,
+ N_("deprecated synonym for --create-reflog"),
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN,
+ deprecated_reflog_option_cb
+ },
OPT_BOOL(0, "edit-description", &edit_description,
N_("edit the description for the branch")),
OPT__FORCE(&force, N_("force creation, move/rename, deletion"), PARSE_OPT_NOCOMPLETE),
@@ -683,6 +699,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (list)
setup_auto_pager("branch", 1);
+ if (used_deprecated_reflog_option && !list) {
+ warning("the '-l' alias for '--create-reflog' is deprecated;");
+ warning("it will be removed in a future version of Git");
+ }
+
if (delete) {
if (!argc)
die(_("branch name required"));
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 665b581..4a44b24 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -13,6 +13,7 @@
#include "tree-walk.h"
#include "sha1-array.h"
#include "packfile.h"
+#include "object-store.h"
struct batch_options {
int enabled;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 6268686..cb6bb76 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -4,6 +4,7 @@
#include "lockfile.h"
#include "parse-options.h"
#include "refs.h"
+#include "object-store.h"
#include "commit.h"
#include "tree.h"
#include "tree-walk.h"
@@ -22,6 +23,7 @@
#include "resolve-undo.h"
#include "submodule-config.h"
#include "submodule.h"
+#include "advice.h"
static const char * const checkout_usage[] = {
N_("git checkout [<options>] <branch>"),
@@ -77,7 +79,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
return READ_TREE_RECURSIVE;
len = base->len + strlen(pathname);
- ce = xcalloc(1, cache_entry_size(len));
+ ce = make_empty_cache_entry(&the_index, len);
oidcpy(&ce->oid, oid);
memcpy(ce->name, base->buf, base->len);
memcpy(ce->name + base->len, pathname, len - base->len);
@@ -96,7 +98,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
if (ce->ce_mode == old->ce_mode &&
!oidcmp(&ce->oid, &old->oid)) {
old->ce_flags |= CE_UPDATE;
- free(ce);
+ discard_cache_entry(ce);
return 0;
}
}
@@ -230,11 +232,11 @@ static int checkout_merged(int pos, const struct checkout *state)
if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
die(_("Unable to add merge result for '%s'"), path);
free(result_buf.ptr);
- ce = make_cache_entry(mode, oid.hash, path, 2, 0);
+ ce = make_transient_cache_entry(mode, &oid, path, 2);
if (!ce)
die(_("make_cache_entry failed for path '%s'"), path);
status = checkout_entry(ce, state, NULL);
- free(ce);
+ discard_cache_entry(ce);
return status;
}
@@ -378,7 +380,7 @@ static int checkout_paths(const struct checkout_opts *opts,
die(_("unable to write new index file"));
read_ref_full("HEAD", 0, &rev, NULL);
- head = lookup_commit_reference_gently(&rev, 1);
+ head = lookup_commit_reference_gently(the_repository, &rev, 1);
errs |= post_checkout_hook(head, head, 0);
return errs;
@@ -829,7 +831,7 @@ static int switch_branches(const struct checkout_opts *opts,
memset(&old_branch_info, 0, sizeof(old_branch_info));
old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
if (old_branch_info.path)
- old_branch_info.commit = lookup_commit_reference_gently(&rev, 1);
+ old_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);
if (!(flag & REF_ISSYMREF))
old_branch_info.path = NULL;
@@ -878,7 +880,8 @@ static int parse_branchname_arg(int argc, const char **argv,
int dwim_new_local_branch_ok,
struct branch_info *new_branch_info,
struct checkout_opts *opts,
- struct object_id *rev)
+ struct object_id *rev,
+ int *dwim_remotes_matched)
{
struct tree **source_tree = &opts->source_tree;
const char **new_branch = &opts->new_branch;
@@ -910,8 +913,10 @@ static int parse_branchname_arg(int argc, const char **argv,
* (b) If <something> is _not_ a commit, either "--" is present
* or <something> is not a path, no -t or -b was given, and
* and there is a tracking branch whose name is <something>
- * in one and only one remote, then this is a short-hand to
- * fork local <something> from that remote-tracking branch.
+ * in one and only one remote (or if the branch exists on the
+ * remote named in checkout.defaultRemote), then this is a
+ * short-hand to fork local <something> from that
+ * remote-tracking branch.
*
* (c) Otherwise, if "--" is present, treat it like case (1).
*
@@ -972,7 +977,8 @@ static int parse_branchname_arg(int argc, const char **argv,
recover_with_dwim = 0;
if (recover_with_dwim) {
- const char *remote = unique_tracking_name(arg, rev);
+ const char *remote = unique_tracking_name(arg, rev,
+ dwim_remotes_matched);
if (remote) {
*new_branch = arg;
arg = remote;
@@ -1003,7 +1009,7 @@ static int parse_branchname_arg(int argc, const char **argv,
else
new_branch_info->path = NULL; /* not an existing branch */
- new_branch_info->commit = lookup_commit_reference_gently(rev, 1);
+ new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
if (!new_branch_info->commit) {
/* not a commit */
*source_tree = parse_tree_indirect(rev);
@@ -1109,6 +1115,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
struct branch_info new_branch_info;
char *conflict_style = NULL;
int dwim_new_local_branch = 1;
+ int dwim_remotes_matched = 0;
struct option options[] = {
OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -1221,7 +1228,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.track == BRANCH_TRACK_UNSPECIFIED &&
!opts.new_branch;
int n = parse_branchname_arg(argc, argv, dwim_ok,
- &new_branch_info, &opts, &rev);
+ &new_branch_info, &opts, &rev,
+ &dwim_remotes_matched);
argv += n;
argc -= n;
}
@@ -1263,8 +1271,26 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
}
UNLEAK(opts);
- if (opts.patch_mode || opts.pathspec.nr)
- return checkout_paths(&opts, new_branch_info.name);
- else
+ if (opts.patch_mode || opts.pathspec.nr) {
+ int ret = checkout_paths(&opts, new_branch_info.name);
+ if (ret && dwim_remotes_matched > 1 &&
+ advice_checkout_ambiguous_remote_branch_name)
+ advise(_("'%s' matched more than one remote tracking branch.\n"
+ "We found %d remotes with a reference that matched. So we fell back\n"
+ "on trying to resolve the argument as a path, but failed there too!\n"
+ "\n"
+ "If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
+ "you can do so by fully qualifying the name with the --track option:\n"
+ "\n"
+ " git checkout --track origin/<name>\n"
+ "\n"
+ "If you'd like to always have checkouts of an ambiguous <name> prefer\n"
+ "one remote, e.g. the 'origin' remote, consider setting\n"
+ "checkout.defaultRemote=origin in your config."),
+ argv[0],
+ dwim_remotes_matched);
+ return ret;
+ } else {
return checkout_branch(&opts, &new_branch_info);
+ }
}
diff --git a/builtin/clone.c b/builtin/clone.c
index 74a804f..26fb0da 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -15,6 +15,7 @@
#include "fetch-pack.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
@@ -695,7 +696,8 @@ static void update_head(const struct ref *our, const struct ref *remote,
install_branch_config(0, head, option_origin, our->name);
}
} else if (our) {
- struct commit *c = lookup_commit_reference(&our->old_oid);
+ struct commit *c = lookup_commit_reference(the_repository,
+ &our->old_oid);
/* --branch specifies a non-branch (i.e. tags), detach HEAD */
update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
UPDATE_REFS_DIE_ON_ERR);
@@ -895,7 +897,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int err = 0, complete_refs_before_fetch = 1;
int submodule_progress;
- struct refspec_item refspec;
+ struct refspec rs = REFSPEC_INIT_FETCH;
+ struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
fetch_if_missing = 0;
@@ -1077,7 +1080,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();
- refspec_item_init_or_die(&refspec, value.buf, REFSPEC_FETCH);
+ refspec_append(&rs, value.buf);
strbuf_reset(&value);
@@ -1134,10 +1137,18 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (transport->smart_options && !deepen && !filter_options.choice)
transport->smart_options->check_self_contained_and_connected = 1;
- refs = transport_get_remote_refs(transport, NULL);
+
+ argv_array_push(&ref_prefixes, "HEAD");
+ refspec_ref_prefixes(&rs, &ref_prefixes);
+ if (option_branch)
+ expand_ref_prefix(&ref_prefixes, option_branch);
+ if (!option_no_tags)
+ argv_array_push(&ref_prefixes, "refs/tags/");
+
+ refs = transport_get_remote_refs(transport, &ref_prefixes);
if (refs) {
- mapped_refs = wanted_peer_refs(refs, &refspec);
+ mapped_refs = wanted_peer_refs(refs, &rs.items[0]);
/*
* transport_get_remote_refs() may return refs with null sha-1
* in mapped_refs (see struct transport->get_refs_list
@@ -1155,7 +1166,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (!is_local && !complete_refs_before_fetch)
- transport_fetch_refs(transport, mapped_refs);
+ transport_fetch_refs(transport, mapped_refs, NULL);
remote_head = find_ref_by_name(refs, "HEAD");
remote_head_points_at =
@@ -1197,11 +1208,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (is_local)
clone_local(path, git_dir);
else if (refs && complete_refs_before_fetch)
- transport_fetch_refs(transport, mapped_refs);
+ transport_fetch_refs(transport, mapped_refs, NULL);
update_remote_refs(refs, mapped_refs, remote_head_points_at,
branch_top.buf, reflog_msg.buf, transport,
- !is_local && !filter_options.choice);
+ !is_local);
update_head(our_head_points_at, remote_head, reflog_msg.buf);
@@ -1231,6 +1242,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_release(&value);
junk_mode = JUNK_LEAVE_ALL;
- refspec_item_clear(&refspec);
+ refspec_clear(&rs);
+ argv_array_clear(&ref_prefixes);
return err;
}
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 37420ae..0bf0c48 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -3,12 +3,19 @@
#include "dir.h"
#include "lockfile.h"
#include "parse-options.h"
+#include "repository.h"
#include "commit-graph.h"
static char const * const builtin_commit_graph_usage[] = {
N_("git commit-graph [--object-dir <objdir>]"),
N_("git commit-graph read [--object-dir <objdir>]"),
- N_("git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--stdin-commits]"),
+ N_("git commit-graph verify [--object-dir <objdir>]"),
+ N_("git commit-graph write [--object-dir <objdir>] [--append] [--reachable|--stdin-packs|--stdin-commits]"),
+ NULL
+};
+
+static const char * const builtin_commit_graph_verify_usage[] = {
+ N_("git commit-graph verify [--object-dir <objdir>]"),
NULL
};
@@ -18,17 +25,48 @@ static const char * const builtin_commit_graph_read_usage[] = {
};
static const char * const builtin_commit_graph_write_usage[] = {
- N_("git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--stdin-commits]"),
+ N_("git commit-graph write [--object-dir <objdir>] [--append] [--reachable|--stdin-packs|--stdin-commits]"),
NULL
};
static struct opts_commit_graph {
const char *obj_dir;
+ int reachable;
int stdin_packs;
int stdin_commits;
int append;
} opts;
+
+static int graph_verify(int argc, const char **argv)
+{
+ struct commit_graph *graph = NULL;
+ char *graph_name;
+
+ static struct option builtin_commit_graph_verify_options[] = {
+ OPT_STRING(0, "object-dir", &opts.obj_dir,
+ N_("dir"),
+ N_("The object directory to store the graph")),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, NULL,
+ builtin_commit_graph_verify_options,
+ builtin_commit_graph_verify_usage, 0);
+
+ if (!opts.obj_dir)
+ opts.obj_dir = get_object_directory();
+
+ graph_name = get_commit_graph_filename(opts.obj_dir);
+ graph = load_commit_graph_one(graph_name);
+ FREE_AND_NULL(graph_name);
+
+ if (!graph)
+ return 0;
+
+ return verify_commit_graph(the_repository, graph);
+}
+
static int graph_read(int argc, const char **argv)
{
struct commit_graph *graph = NULL;
@@ -51,8 +89,11 @@ static int graph_read(int argc, const char **argv)
graph_name = get_commit_graph_filename(opts.obj_dir);
graph = load_commit_graph_one(graph_name);
- if (!graph)
+ if (!graph) {
+ UNLEAK(graph_name);
die("graph file %s does not exist", graph_name);
+ }
+
FREE_AND_NULL(graph_name);
printf("header: %08x %d %d %d %d\n",
@@ -74,23 +115,23 @@ static int graph_read(int argc, const char **argv)
printf(" large_edges");
printf("\n");
+ free_commit_graph(graph);
+
return 0;
}
static int graph_write(int argc, const char **argv)
{
- const char **pack_indexes = NULL;
- int packs_nr = 0;
- const char **commit_hex = NULL;
- int commits_nr = 0;
- const char **lines = NULL;
- int lines_nr = 0;
- int lines_alloc = 0;
+ struct string_list *pack_indexes = NULL;
+ struct string_list *commit_hex = NULL;
+ struct string_list lines;
static struct option builtin_commit_graph_write_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
N_("dir"),
N_("The object directory to store the graph")),
+ OPT_BOOL(0, "reachable", &opts.reachable,
+ N_("start walk at all refs")),
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
N_("scan pack-indexes listed by stdin for commits")),
OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
@@ -104,39 +145,35 @@ static int graph_write(int argc, const char **argv)
builtin_commit_graph_write_options,
builtin_commit_graph_write_usage, 0);
- if (opts.stdin_packs && opts.stdin_commits)
- die(_("cannot use both --stdin-commits and --stdin-packs"));
+ if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
+ die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
if (!opts.obj_dir)
opts.obj_dir = get_object_directory();
+ if (opts.reachable) {
+ write_commit_graph_reachable(opts.obj_dir, opts.append);
+ return 0;
+ }
+
+ string_list_init(&lines, 0);
if (opts.stdin_packs || opts.stdin_commits) {
struct strbuf buf = STRBUF_INIT;
- lines_nr = 0;
- lines_alloc = 128;
- ALLOC_ARRAY(lines, lines_alloc);
-
- while (strbuf_getline(&buf, stdin) != EOF) {
- ALLOC_GROW(lines, lines_nr + 1, lines_alloc);
- lines[lines_nr++] = strbuf_detach(&buf, NULL);
- }
-
- if (opts.stdin_packs) {
- pack_indexes = lines;
- packs_nr = lines_nr;
- }
- if (opts.stdin_commits) {
- commit_hex = lines;
- commits_nr = lines_nr;
- }
+
+ while (strbuf_getline(&buf, stdin) != EOF)
+ string_list_append(&lines, strbuf_detach(&buf, NULL));
+
+ if (opts.stdin_packs)
+ pack_indexes = &lines;
+ if (opts.stdin_commits)
+ commit_hex = &lines;
}
write_commit_graph(opts.obj_dir,
pack_indexes,
- packs_nr,
commit_hex,
- commits_nr,
opts.append);
+ string_list_clear(&lines, 0);
return 0;
}
@@ -162,6 +199,8 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
if (argc > 0) {
if (!strcmp(argv[0], "read"))
return graph_read(argc, argv);
+ if (!strcmp(argv[0], "verify"))
+ return graph_verify(argc, argv);
if (!strcmp(argv[0], "write"))
return graph_write(argc, argv);
}
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index ecf4219..9ec36a8 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -5,6 +5,8 @@
*/
#include "cache.h"
#include "config.h"
+#include "object-store.h"
+#include "repository.h"
#include "commit.h"
#include "tree.h"
#include "builtin.h"
@@ -59,7 +61,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
if (get_oid_commit(argv[i], &oid))
die("Not a valid object name %s", argv[i]);
assert_oid_type(&oid, OBJ_COMMIT);
- new_parent(lookup_commit(&oid), &parents);
+ new_parent(lookup_commit(the_repository, &oid),
+ &parents);
continue;
}
diff --git a/builtin/commit.c b/builtin/commit.c
index d3276a1..213fca2 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -168,9 +168,9 @@ static int opt_parse_rename_score(const struct option *opt, const char *arg, int
static void determine_whence(struct wt_status *s)
{
- if (file_exists(git_path_merge_head()))
+ if (file_exists(git_path_merge_head(the_repository)))
whence = FROM_MERGE;
- else if (file_exists(git_path_cherry_pick_head())) {
+ else if (file_exists(git_path_cherry_pick_head(the_repository))) {
whence = FROM_CHERRY_PICK;
if (file_exists(git_path_seq_dir()))
sequencer_in_use = 1;
@@ -718,21 +718,21 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (have_option_m)
strbuf_addbuf(&sb, &message);
hook_arg1 = "message";
- } else if (!stat(git_path_merge_msg(), &statbuf)) {
+ } else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
/*
* prepend SQUASH_MSG here if it exists and a
* "merge --squash" was originally performed
*/
- if (!stat(git_path_squash_msg(), &statbuf)) {
- if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
+ if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
+ if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
die_errno(_("could not read SQUASH_MSG"));
hook_arg1 = "squash";
} else
hook_arg1 = "merge";
- if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
+ if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
die_errno(_("could not read MERGE_MSG"));
- } else if (!stat(git_path_squash_msg(), &statbuf)) {
- if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
+ } else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
+ if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
die_errno(_("could not read SQUASH_MSG"));
hook_arg1 = "squash";
} else if (template_file) {
@@ -813,8 +813,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
" %s\n"
"and try again.\n"),
whence == FROM_MERGE ?
- git_path_merge_head() :
- git_path_cherry_pick_head());
+ git_path_merge_head(the_repository) :
+ git_path_cherry_pick_head(the_repository));
}
fprintf(s->fp, "\n");
@@ -1564,7 +1564,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!reflog_msg)
reflog_msg = "commit (merge)";
pptr = commit_list_append(current_head, pptr);
- fp = xfopen(git_path_merge_head(), "r");
+ fp = xfopen(git_path_merge_head(the_repository), "r");
while (strbuf_getline_lf(&m, fp) != EOF) {
struct commit *parent;
@@ -1575,8 +1575,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
fclose(fp);
strbuf_release(&m);
- if (!stat(git_path_merge_mode(), &statbuf)) {
- if (strbuf_read_file(&sb, git_path_merge_mode(), 0) < 0)
+ if (!stat(git_path_merge_mode(the_repository), &statbuf)) {
+ if (strbuf_read_file(&sb, git_path_merge_mode(the_repository), 0) < 0)
die_errno(_("could not read MERGE_MODE"));
if (!strcmp(sb.buf, "no-ff"))
allow_fast_forward = 0;
@@ -1639,12 +1639,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
die("%s", err.buf);
}
- unlink(git_path_cherry_pick_head());
- unlink(git_path_revert_head());
- unlink(git_path_merge_head());
- unlink(git_path_merge_msg());
- unlink(git_path_merge_mode());
- unlink(git_path_squash_msg());
+ unlink(git_path_cherry_pick_head(the_repository));
+ unlink(git_path_revert_head(the_repository));
+ unlink(git_path_merge_head(the_repository));
+ unlink(git_path_merge_msg(the_repository));
+ unlink(git_path_merge_mode(the_repository));
+ unlink(git_path_squash_msg(the_repository));
if (commit_index_files())
die(_("repository has been updated, but unable to write\n"
diff --git a/builtin/config.c b/builtin/config.c
index 5761a2c..97b58c4 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -67,7 +67,7 @@ static int show_origin;
{ OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \
PARSE_OPT_NONEG, option_parse_type, (i) }
-static struct option builtin_config_options[];
+static NORETURN void usage_builtin_config(void);
static int option_parse_type(const struct option *opt, const char *arg,
int unset)
@@ -111,8 +111,7 @@ static int option_parse_type(const struct option *opt, const char *arg,
* --type=int'.
*/
error(_("only one type at a time"));
- usage_with_options(builtin_config_usage,
- builtin_config_options);
+ usage_builtin_config();
}
*to_type = new_type;
@@ -157,6 +156,11 @@ static struct option builtin_config_options[] = {
OPT_END(),
};
+static NORETURN void usage_builtin_config(void)
+{
+ usage_with_options(builtin_config_usage, builtin_config_options);
+}
+
static void check_argc(int argc, int min, int max) {
if (argc >= min && argc <= max)
return;
@@ -165,7 +169,7 @@ static void check_argc(int argc, int min, int max) {
else
error(_("wrong number of arguments, should be from %d to %d"),
min, max);
- usage_with_options(builtin_config_usage, builtin_config_options);
+ usage_builtin_config();
}
static void show_config_origin(struct strbuf *buf)
@@ -600,7 +604,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (use_global_config + use_system_config + use_local_config +
!!given_config_source.file + !!given_config_source.blob > 1) {
error(_("only one config file at a time"));
- usage_with_options(builtin_config_usage, builtin_config_options);
+ usage_builtin_config();
}
if (use_local_config && nongit)
@@ -664,12 +668,12 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) {
error(_("--get-color and variable type are incoherent"));
- usage_with_options(builtin_config_usage, builtin_config_options);
+ usage_builtin_config();
}
if (HAS_MULTI_BITS(actions)) {
error(_("only one action at a time"));
- usage_with_options(builtin_config_usage, builtin_config_options);
+ usage_builtin_config();
}
if (actions == 0)
switch (argc) {
@@ -677,25 +681,24 @@ int cmd_config(int argc, const char **argv, const char *prefix)
case 2: actions = ACTION_SET; break;
case 3: actions = ACTION_SET_ALL; break;
default:
- usage_with_options(builtin_config_usage, builtin_config_options);
+ usage_builtin_config();
}
if (omit_values &&
!(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
error(_("--name-only is only applicable to --list or --get-regexp"));
- usage_with_options(builtin_config_usage, builtin_config_options);
+ usage_builtin_config();
}
if (show_origin && !(actions &
(ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) {
error(_("--show-origin is only applicable to --get, --get-all, "
"--get-regexp, and --list"));
- usage_with_options(builtin_config_usage, builtin_config_options);
+ usage_builtin_config();
}
if (default_value && !(actions & ACTION_GET)) {
error(_("--default is only applicable to --get"));
- usage_with_options(builtin_config_usage,
- builtin_config_options);
+ usage_builtin_config();
}
if (actions & PAGING_ACTIONS)
diff --git a/builtin/describe.c b/builtin/describe.c
index bec2513..41606c8 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -13,6 +13,7 @@
#include "hashmap.h"
#include "argv-array.h"
#include "run-command.h"
+#include "object-store.h"
#include "revision.h"
#include "list-objects.h"
#include "commit-slab.h"
@@ -92,13 +93,13 @@ static int replace_name(struct commit_name *e,
struct tag *t;
if (!e->tag) {
- t = lookup_tag(&e->oid);
+ t = lookup_tag(the_repository, &e->oid);
if (!t || parse_tag(t))
return 1;
e->tag = t;
}
- t = lookup_tag(oid);
+ t = lookup_tag(the_repository, oid);
if (!t || parse_tag(t))
return 0;
*tag = t;
@@ -266,7 +267,7 @@ static unsigned long finish_depth_computation(
static void append_name(struct commit_name *n, struct strbuf *dst)
{
if (n->prio == 2 && !n->tag) {
- n->tag = lookup_tag(&n->oid);
+ n->tag = lookup_tag(the_repository, &n->oid);
if (!n->tag || parse_tag(n->tag))
die(_("annotated tag %s not available"), n->path);
}
@@ -302,7 +303,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
unsigned long seen_commits = 0;
unsigned int unannotated_cnt = 0;
- cmit = lookup_commit_reference(oid);
+ cmit = lookup_commit_reference(the_repository, oid);
n = find_commit_name(&cmit->object.oid);
if (n && (tags || all || n->prio == 2)) {
@@ -330,7 +331,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
init_commit_names(&commit_names);
n = hashmap_iter_first(&names, &iter);
for (; n; n = hashmap_iter_next(&iter)) {
- c = lookup_commit_reference_gently(&n->peeled, 1);
+ c = lookup_commit_reference_gently(the_repository,
+ &n->peeled, 1);
if (c)
*commit_names_at(&commit_names, c) = n;
}
@@ -508,7 +510,7 @@ static void describe(const char *arg, int last_one)
if (get_oid(arg, &oid))
die(_("Not a valid object name %s"), arg);
- cmit = lookup_commit_reference_gently(&oid, 1);
+ cmit = lookup_commit_reference_gently(the_repository, &oid, 1);
if (cmit)
describe_commit(&oid, &sb);
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 4736151..91ba670 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -5,12 +5,13 @@
#include "log-tree.h"
#include "builtin.h"
#include "submodule.h"
+#include "repository.h"
static struct rev_info log_tree_opt;
static int diff_tree_commit_oid(const struct object_id *oid)
{
- struct commit *commit = lookup_commit_reference(oid);
+ struct commit *commit = lookup_commit_reference(the_repository, oid);
if (!commit)
return -1;
return log_tree_commit(&log_tree_opt, commit);
@@ -24,7 +25,7 @@ static int stdin_diff_commit(struct commit *commit, const char *p)
/* Graft the fake parents locally to the commit */
while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) {
- struct commit *parent = lookup_commit(&oid);
+ struct commit *parent = lookup_commit(the_repository, &oid);
if (!pptr) {
/* Free the real parent list */
free_commit_list(commit->parents);
@@ -45,7 +46,7 @@ static int stdin_diff_trees(struct tree *tree1, const char *p)
struct tree *tree2;
if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p)
return error("Need exactly two trees, separated by a space");
- tree2 = lookup_tree(&oid);
+ tree2 = lookup_tree(the_repository, &oid);
if (!tree2 || parse_tree(tree2))
return -1;
printf("%s %s\n", oid_to_hex(&tree1->object.oid),
@@ -68,7 +69,7 @@ static int diff_tree_stdin(char *line)
line[len-1] = 0;
if (parse_oid_hex(line, &oid, &p))
return -1;
- obj = parse_object(&oid);
+ obj = parse_object(the_repository, &oid);
if (!obj)
return -1;
if (obj->type == OBJ_COMMIT)
diff --git a/builtin/diff.c b/builtin/diff.c
index b709b6e..361a3c3 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -386,7 +386,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
add_head_to_pending(&rev);
if (!rev.pending.nr) {
struct tree *tree;
- tree = lookup_tree(the_hash_algo->empty_tree);
+ tree = lookup_tree(the_repository,
+ the_repository->hash_algo->empty_tree);
add_pending_object(&rev, &tree->object, "HEAD");
}
break;
@@ -400,8 +401,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
const char *name = entry->name;
int flags = (obj->flags & UNINTERESTING);
if (!obj->parsed)
- obj = parse_object(&obj->oid);
- obj = deref_tag(obj, NULL, 0);
+ obj = parse_object(the_repository, &obj->oid);
+ obj = deref_tag(the_repository, obj, NULL, 0);
if (!obj)
die(_("invalid object '%s' given."), name);
if (obj->type == OBJ_COMMIT)
diff --git a/builtin/difftool.c b/builtin/difftool.c
index bc97d4a..3018e61 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -20,6 +20,7 @@
#include "argv-array.h"
#include "strbuf.h"
#include "lockfile.h"
+#include "object-store.h"
#include "dir.h"
static char *diff_gui_tool;
@@ -321,10 +322,10 @@ static int checkout_path(unsigned mode, struct object_id *oid,
struct cache_entry *ce;
int ret;
- ce = make_cache_entry(mode, oid->hash, path, 0, 0);
+ ce = make_transient_cache_entry(mode, oid, path, 0);
ret = checkout_entry(ce, state, NULL);
- free(ce);
+ discard_cache_entry(ce);
return ret;
}
@@ -488,7 +489,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
* index.
*/
struct cache_entry *ce2 =
- make_cache_entry(rmode, roid.hash,
+ make_cache_entry(&wtindex, rmode, &roid,
dst_path, 0, 0);
add_index_entry(&wtindex, ce2,
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 83c4825..9bd8a14 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -8,6 +8,7 @@
#include "config.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "commit.h"
#include "object.h"
#include "tag.h"
@@ -229,13 +230,13 @@ static void export_blob(const struct object_id *oid)
if (is_null_oid(oid))
return;
- object = lookup_object(oid->hash);
+ object = lookup_object(the_repository, oid->hash);
if (object && object->flags & SHOWN)
return;
if (anonymize) {
buf = anonymize_blob(&size);
- object = (struct object *)lookup_blob(oid);
+ object = (struct object *)lookup_blob(the_repository, oid);
eaten = 0;
} else {
buf = read_object_file(oid, &type, &size);
@@ -243,7 +244,8 @@ static void export_blob(const struct object_id *oid)
die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(oid, buf, size, type_name(type)) < 0)
die("sha1 mismatch in blob %s", oid_to_hex(oid));
- object = parse_object_buffer(oid, type, size, buf, &eaten);
+ object = parse_object_buffer(the_repository, oid, type,
+ size, buf, &eaten);
}
if (!object)
@@ -401,7 +403,8 @@ static void show_filemodify(struct diff_queue_struct *q,
anonymize_sha1(&spec->oid) :
spec->oid.hash));
else {
- struct object *object = lookup_object(spec->oid.hash);
+ struct object *object = lookup_object(the_repository,
+ spec->oid.hash);
printf("M %06o :%d ", spec->mode,
get_object_mark(object));
}
@@ -800,7 +803,7 @@ static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
/* handle nested tags */
while (tag && tag->object.type == OBJ_TAG) {
- parse_object(&tag->object.oid);
+ parse_object(the_repository, &tag->object.oid);
string_list_append(&extra_refs, full_name)->util = tag;
tag = (struct tag *)tag->tagged;
}
@@ -960,7 +963,7 @@ static void import_marks(char *input_file)
/* only commits */
continue;
- commit = lookup_commit(&oid);
+ commit = lookup_commit(the_repository, &oid);
if (!commit)
die("not a commit? can't happen: %s", oid_to_hex(&oid));
diff --git a/builtin/fetch.c b/builtin/fetch.c
index ea5b966..34d2bd1 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -6,6 +6,7 @@
#include "repository.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "commit.h"
#include "builtin.h"
#include "string-list.h"
@@ -63,6 +64,7 @@ static int shown_url = 0;
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options;
static struct string_list server_options = STRING_LIST_INIT_DUP;
+static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
@@ -93,19 +95,6 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
return git_default_config(k, v, cb);
}
-static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
-{
- if (!strcmp(var, "submodule.fetchjobs")) {
- max_children = parse_submodule_fetchjobs(var, value);
- return 0;
- } else if (!strcmp(var, "fetch.recursesubmodules")) {
- recurse_submodules = parse_fetch_recurse_submodules_arg(var, value);
- return 0;
- }
-
- return 0;
-}
-
static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
{
/*
@@ -174,6 +163,8 @@ static struct option builtin_fetch_options[] = {
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_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_END()
};
@@ -254,9 +245,9 @@ static int will_fetch(struct ref **head, const unsigned char *sha1)
return 0;
}
-static void find_non_local_tags(struct transport *transport,
- struct ref **head,
- struct ref ***tail)
+static void find_non_local_tags(const struct ref *refs,
+ struct ref **head,
+ struct ref ***tail)
{
struct string_list existing_refs = STRING_LIST_INIT_DUP;
struct string_list remote_refs = STRING_LIST_INIT_NODUP;
@@ -264,7 +255,7 @@ static void find_non_local_tags(struct transport *transport,
struct string_list_item *item = NULL;
for_each_ref(add_existing, &existing_refs);
- for (ref = transport_get_remote_refs(transport, NULL); ref; ref = ref->next) {
+ for (ref = refs; ref; ref = ref->next) {
if (!starts_with(ref->name, "refs/tags/"))
continue;
@@ -338,7 +329,8 @@ static void find_non_local_tags(struct transport *transport,
string_list_clear(&remote_refs, 0);
}
-static struct ref *get_ref_map(struct transport *transport,
+static struct ref *get_ref_map(struct remote *remote,
+ const struct ref *remote_refs,
struct refspec *rs,
int tags, int *autotags)
{
@@ -346,26 +338,11 @@ static struct ref *get_ref_map(struct transport *transport,
struct ref *rm;
struct ref *ref_map = NULL;
struct ref **tail = &ref_map;
- struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
/* opportunistically-updated references: */
struct ref *orefs = NULL, **oref_tail = &orefs;
- const struct ref *remote_refs;
-
- if (rs->nr)
- refspec_ref_prefixes(rs, &ref_prefixes);
- else if (transport->remote && transport->remote->fetch.nr)
- refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
-
- if (ref_prefixes.argc &&
- (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
- argv_array_push(&ref_prefixes, "refs/tags/");
- }
-
- remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
-
- argv_array_clear(&ref_prefixes);
+ struct string_list existing_refs = STRING_LIST_INIT_DUP;
if (rs->nr) {
struct refspec *fetch_refspec;
@@ -402,7 +379,7 @@ static struct ref *get_ref_map(struct transport *transport,
if (refmap.nr)
fetch_refspec = &refmap;
else
- fetch_refspec = &transport->remote->fetch;
+ fetch_refspec = &remote->fetch;
for (i = 0; i < fetch_refspec->nr; i++)
get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
@@ -410,7 +387,6 @@ static struct ref *get_ref_map(struct transport *transport,
die("--refmap option is only meaningful with command-line refspec(s).");
} else {
/* Use the defaults */
- struct remote *remote = transport->remote;
struct branch *branch = branch_get(NULL);
int has_merge = branch_has_merge_config(branch);
if (remote &&
@@ -449,7 +425,7 @@ static struct ref *get_ref_map(struct transport *transport,
/* also fetch all tags */
get_fetch_map(remote_refs, tag_refspec, &tail, 0);
else if (tags == TAGS_DEFAULT && *autotags)
- find_non_local_tags(transport, &ref_map, &tail);
+ find_non_local_tags(remote_refs, &ref_map, &tail);
/* Now append any refs to be updated opportunistically: */
*tail = orefs;
@@ -458,7 +434,23 @@ static struct ref *get_ref_map(struct transport *transport,
tail = &rm->next;
}
- return ref_remove_duplicates(ref_map);
+ ref_map = ref_remove_duplicates(ref_map);
+
+ for_each_ref(add_existing, &existing_refs);
+ for (rm = ref_map; rm; rm = rm->next) {
+ if (rm->peer_ref) {
+ struct string_list_item *peer_item =
+ string_list_lookup(&existing_refs,
+ rm->peer_ref->name);
+ if (peer_item) {
+ struct object_id *old_oid = peer_item->util;
+ oidcpy(&rm->peer_ref->old_oid, old_oid);
+ }
+ }
+ }
+ string_list_clear(&existing_refs, 1);
+
+ return ref_map;
}
#define STORE_REF_ERROR_OTHER 1
@@ -683,8 +675,10 @@ static int update_local_ref(struct ref *ref,
return r;
}
- current = lookup_commit_reference_gently(&ref->old_oid, 1);
- updated = lookup_commit_reference_gently(&ref->new_oid, 1);
+ current = lookup_commit_reference_gently(the_repository,
+ &ref->old_oid, 1);
+ updated = lookup_commit_reference_gently(the_repository,
+ &ref->new_oid, 1);
if (!current || !updated) {
const char *msg;
const char *what;
@@ -768,7 +762,7 @@ static int iterate_ref_map(void *cb_data, struct object_id *oid)
}
static int store_updated_refs(const char *raw_url, const char *remote_name,
- struct ref *ref_map)
+ int connectivity_checked, struct ref *ref_map)
{
FILE *fp;
struct commit *commit;
@@ -777,7 +771,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
const char *what, *kind;
struct ref *rm;
char *url;
- const char *filename = dry_run ? "/dev/null" : git_path_fetch_head();
+ const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(the_repository);
int want_status;
int summary_width = transport_summary_width(ref_map);
@@ -790,10 +784,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
else
url = xstrdup("foreign");
- rm = ref_map;
- if (check_connected(iterate_ref_map, &rm, NULL)) {
- rc = error(_("%s did not send all necessary objects\n"), url);
- goto abort;
+ if (!connectivity_checked) {
+ rm = ref_map;
+ if (check_connected(iterate_ref_map, &rm, NULL)) {
+ rc = error(_("%s did not send all necessary objects\n"), url);
+ goto abort;
+ }
}
prepare_format_display(ref_map);
@@ -817,7 +813,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
continue;
}
- commit = lookup_commit_reference_gently(&rm->old_oid,
+ commit = lookup_commit_reference_gently(the_repository,
+ &rm->old_oid,
1);
if (!commit)
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
@@ -945,15 +942,32 @@ static int quickfetch(struct ref *ref_map)
return check_connected(iterate_ref_map, &rm, &opt);
}
-static int fetch_refs(struct transport *transport, struct ref *ref_map)
+static int fetch_refs(struct transport *transport, struct ref *ref_map,
+ struct ref **updated_remote_refs)
{
int ret = quickfetch(ref_map);
if (ret)
- ret = transport_fetch_refs(transport, ref_map);
+ ret = transport_fetch_refs(transport, ref_map,
+ updated_remote_refs);
if (!ret)
- ret |= store_updated_refs(transport->url,
- transport->remote->name,
- ref_map);
+ /*
+ * Keep the new pack's ".keep" file around to allow the caller
+ * time to update refs to reference the new objects.
+ */
+ return 0;
+ transport_unlock_pack(transport);
+ return ret;
+}
+
+/* Update local refs based on the ref values fetched from a remote */
+static int consume_refs(struct transport *transport, struct ref *ref_map)
+{
+ int connectivity_checked = transport->smart_options
+ ? transport->smart_options->connectivity_checked : 0;
+ int ret = store_updated_refs(transport->url,
+ transport->remote->name,
+ connectivity_checked,
+ ref_map);
transport_unlock_pack(transport);
return ret;
}
@@ -1029,7 +1043,7 @@ static void check_not_current_branch(struct ref *ref_map)
static int truncate_fetch_head(void)
{
- const char *filename = git_path_fetch_head();
+ const char *filename = git_path_fetch_head(the_repository);
FILE *fp = fopen_for_writing(filename);
if (!fp)
@@ -1049,6 +1063,40 @@ static void set_option(struct transport *transport, const char *name, const char
name, transport->url);
}
+
+static int add_oid(const char *refname, const struct object_id *oid, int flags,
+ void *cb_data)
+{
+ struct oid_array *oids = cb_data;
+
+ oid_array_append(oids, oid);
+ return 0;
+}
+
+static void add_negotiation_tips(struct git_transport_options *smart_options)
+{
+ struct oid_array *oids = xcalloc(1, sizeof(*oids));
+ int i;
+
+ for (i = 0; i < negotiation_tip.nr; i++) {
+ const char *s = negotiation_tip.items[i].string;
+ int old_nr;
+ if (!has_glob_specials(s)) {
+ struct object_id oid;
+ if (get_oid(s, &oid))
+ die("%s is not a valid object", s);
+ oid_array_append(oids, &oid);
+ continue;
+ }
+ old_nr = oids->nr;
+ for_each_glob_ref(add_oid, s, oids);
+ if (old_nr == oids->nr)
+ warning("Ignoring --negotiation-tip=%s because it does not match any refs",
+ s);
+ }
+ smart_options->negotiation_tips = oids;
+}
+
static struct transport *prepare_transport(struct remote *remote, int deepen)
{
struct transport *transport;
@@ -1075,6 +1123,12 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
filter_options.filter_spec);
set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
}
+ if (negotiation_tip.nr) {
+ if (transport->smart_options)
+ add_negotiation_tips(transport->smart_options);
+ else
+ warning("Ignoring --negotiation-tip because the protocol does not support it.");
+ }
return transport;
}
@@ -1099,7 +1153,8 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
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);
- fetch_refs(transport, ref_map);
+ if (!fetch_refs(transport, ref_map, NULL))
+ consume_refs(transport, ref_map);
if (gsecondary) {
transport_disconnect(gsecondary);
@@ -1110,13 +1165,12 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
static int do_fetch(struct transport *transport,
struct refspec *rs)
{
- struct string_list existing_refs = STRING_LIST_INIT_DUP;
struct ref *ref_map;
- struct ref *rm;
int autotags = (transport->remote->fetch_tags == 1);
int retcode = 0;
-
- for_each_ref(add_existing, &existing_refs);
+ const struct ref *remote_refs;
+ struct ref *updated_remote_refs = NULL;
+ struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
if (tags == TAGS_DEFAULT) {
if (transport->remote->fetch_tags == 2)
@@ -1132,22 +1186,24 @@ static int do_fetch(struct transport *transport,
goto cleanup;
}
- ref_map = get_ref_map(transport, rs, tags, &autotags);
- if (!update_head_ok)
- check_not_current_branch(ref_map);
+ if (rs->nr)
+ refspec_ref_prefixes(rs, &ref_prefixes);
+ else if (transport->remote && transport->remote->fetch.nr)
+ refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
- for (rm = ref_map; rm; rm = rm->next) {
- if (rm->peer_ref) {
- struct string_list_item *peer_item =
- string_list_lookup(&existing_refs,
- rm->peer_ref->name);
- if (peer_item) {
- struct object_id *old_oid = peer_item->util;
- oidcpy(&rm->peer_ref->old_oid, old_oid);
- }
- }
+ if (ref_prefixes.argc &&
+ (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
+ argv_array_push(&ref_prefixes, "refs/tags/");
}
+ remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
+ argv_array_clear(&ref_prefixes);
+
+ ref_map = get_ref_map(transport->remote, remote_refs, rs,
+ tags, &autotags);
+ if (!update_head_ok)
+ check_not_current_branch(ref_map);
+
if (tags == TAGS_DEFAULT && autotags)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
if (prune) {
@@ -1164,7 +1220,24 @@ static int do_fetch(struct transport *transport,
transport->url);
}
}
- if (fetch_refs(transport, ref_map)) {
+
+ if (fetch_refs(transport, ref_map, &updated_remote_refs)) {
+ free_refs(ref_map);
+ retcode = 1;
+ goto cleanup;
+ }
+ if (updated_remote_refs) {
+ /*
+ * Regenerate ref_map using the updated remote refs. This is
+ * to account for additional information which may be provided
+ * by the transport (e.g. shallow info).
+ */
+ free_refs(ref_map);
+ ref_map = get_ref_map(transport->remote, updated_remote_refs, rs,
+ tags, &autotags);
+ free_refs(updated_remote_refs);
+ }
+ if (consume_refs(transport, ref_map)) {
free_refs(ref_map);
retcode = 1;
goto cleanup;
@@ -1176,14 +1249,13 @@ static int do_fetch(struct transport *transport,
if (tags == TAGS_DEFAULT && autotags) {
struct ref **tail = &ref_map;
ref_map = NULL;
- find_non_local_tags(transport, &ref_map, &tail);
+ find_non_local_tags(remote_refs, &ref_map, &tail);
if (ref_map)
backfill_tags(transport, ref_map);
free_refs(ref_map);
}
cleanup:
- string_list_clear(&existing_refs, 1);
return retcode;
}
@@ -1433,7 +1505,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc; i++)
strbuf_addf(&default_rla, " %s", argv[i]);
- config_from_gitmodules(gitmodules_fetch_config, NULL);
+ fetch_config_from_gitmodules(&max_children, &recurse_submodules);
git_config(git_fetch_config, NULL);
argc = parse_options(argc, argv, prefix,
@@ -1449,7 +1521,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (unshallow) {
if (depth)
die(_("--depth and --unshallow cannot be used together"));
- else if (!is_repository_shallow())
+ else if (!is_repository_shallow(the_repository))
die(_("--unshallow on a complete repository does not make sense"));
else
depth = xstrfmt("%d", INFINITE_DEPTH);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index a08f239..f35ff16 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -2,6 +2,7 @@
#include "cache.h"
#include "config.h"
#include "refs.h"
+#include "object-store.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
@@ -10,6 +11,7 @@
#include "branch.h"
#include "fmt-merge-msg.h"
#include "gpg-interface.h"
+#include "repository.h"
static const char * const fmt_merge_msg_usage[] = {
N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
@@ -108,14 +110,15 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
struct string_list_item *item;
int pulling_head = 0;
struct object_id oid;
+ const unsigned hexsz = the_hash_algo->hexsz;
- if (len < GIT_SHA1_HEXSZ + 3 || line[GIT_SHA1_HEXSZ] != '\t')
+ if (len < hexsz + 3 || line[hexsz] != '\t')
return 1;
- if (starts_with(line + GIT_SHA1_HEXSZ + 1, "not-for-merge"))
+ if (starts_with(line + hexsz + 1, "not-for-merge"))
return 0;
- if (line[GIT_SHA1_HEXSZ + 1] != '\t')
+ if (line[hexsz + 1] != '\t')
return 2;
i = get_oid_hex(line, &oid);
@@ -130,7 +133,7 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
if (line[len - 1] == '\n')
line[len - 1] = 0;
- line += GIT_SHA1_HEXSZ + 2;
+ line += hexsz + 2;
/*
* At this point, line points at the beginning of comment e.g.
@@ -342,7 +345,9 @@ static void shortlog(const char *name,
const struct object_id *oid = &origin_data->oid;
int limit = opts->shortlog_len;
- branch = deref_tag(parse_object(oid), oid_to_hex(oid), GIT_SHA1_HEXSZ);
+ branch = deref_tag(the_repository, parse_object(the_repository, oid),
+ oid_to_hex(oid),
+ the_hash_algo->hexsz);
if (!branch || branch->type != OBJ_COMMIT)
return;
@@ -545,6 +550,7 @@ static void find_merge_parents(struct merge_parents *result,
int len;
char *p = in->buf + pos;
char *newline = strchr(p, '\n');
+ const char *q;
struct object_id oid;
struct commit *parent;
struct object *obj;
@@ -552,24 +558,23 @@ static void find_merge_parents(struct merge_parents *result,
len = newline ? newline - p : strlen(p);
pos += len + !!newline;
- if (len < GIT_SHA1_HEXSZ + 3 ||
- get_oid_hex(p, &oid) ||
- p[GIT_SHA1_HEXSZ] != '\t' ||
- p[GIT_SHA1_HEXSZ + 1] != '\t')
+ if (parse_oid_hex(p, &oid, &q) ||
+ q[0] != '\t' ||
+ q[1] != '\t')
continue; /* skip not-for-merge */
/*
* Do not use get_merge_parent() here; we do not have
* "name" here and we do not want to contaminate its
* util field yet.
*/
- obj = parse_object(&oid);
+ obj = parse_object(the_repository, &oid);
parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
if (!parent)
continue;
commit_list_insert(parent, &parents);
add_merge_parent(result, &obj->oid, &parent->object.oid);
}
- head_commit = lookup_commit(head);
+ head_commit = lookup_commit(the_repository, head);
if (head_commit)
commit_list_insert(head_commit, &parents);
reduce_heads_replace(&parents);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 3ad4f16..250f5af 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -18,6 +18,7 @@
#include "decorate.h"
#include "packfile.h"
#include "object-store.h"
+#include "run-command.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
@@ -47,6 +48,7 @@ static int name_objects;
#define ERROR_REACHABLE 02
#define ERROR_PACK 04
#define ERROR_REFS 010
+#define ERROR_COMMIT_GRAPH 020
static const char *describe_object(struct object *obj)
{
@@ -70,7 +72,7 @@ static const char *printable_type(struct object *obj)
enum object_type type = oid_object_info(the_repository,
&obj->oid, NULL);
if (type > 0)
- object_as_type(obj, type, 0);
+ object_as_type(the_repository, obj, type, 0);
}
ret = type_name(obj->type);
@@ -392,7 +394,8 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
* verify_packfile(), data_valid variable for details.
*/
struct object *obj;
- obj = parse_object_buffer(oid, type, size, buffer, eaten);
+ obj = parse_object_buffer(the_repository, oid, type, size, buffer,
+ eaten);
if (!obj) {
errors_found |= ERROR_OBJECT;
return error("%s: object corrupt or missing", oid_to_hex(oid));
@@ -410,7 +413,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
struct object *obj;
if (!is_null_oid(oid)) {
- obj = lookup_object(oid->hash);
+ obj = lookup_object(the_repository, oid->hash);
if (obj && (obj->flags & HAS_OBJ)) {
if (timestamp && name_objects)
add_decoration(fsck_walk_options.object_names,
@@ -452,7 +455,7 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
{
struct object *obj;
- obj = parse_object(oid);
+ obj = parse_object(the_repository, oid);
if (!obj) {
if (is_promisor_object(oid)) {
/*
@@ -525,7 +528,9 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data)
if (!contents && type != OBJ_BLOB)
BUG("read_loose_object streamed a non-blob");
- obj = parse_object_buffer(oid, type, size, contents, &eaten);
+ obj = parse_object_buffer(the_repository, oid, type, size,
+ contents, &eaten);
+
if (!obj) {
errors_found |= ERROR_OBJECT;
error("%s: object could not be parsed: %s",
@@ -614,7 +619,7 @@ static int fsck_cache_tree(struct cache_tree *it)
fprintf(stderr, "Checking cache tree\n");
if (0 <= it->entry_count) {
- struct object *obj = parse_object(&it->oid);
+ struct object *obj = parse_object(the_repository, &it->oid);
if (!obj) {
error("%s: invalid sha1 pointer in cache-tree",
oid_to_hex(&it->oid));
@@ -689,7 +694,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
fetch_if_missing = 0;
errors_found = 0;
- check_replace_refs = 0;
+ read_replace_refs = 0;
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
@@ -763,7 +768,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
const char *arg = argv[i];
struct object_id oid;
if (!get_oid(arg, &oid)) {
- struct object *obj = lookup_object(oid.hash);
+ struct object *obj = lookup_object(the_repository,
+ oid.hash);
if (!obj || !(obj->flags & HAS_OBJ)) {
if (is_promisor_object(&oid))
@@ -806,7 +812,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
mode = active_cache[i]->ce_mode;
if (S_ISGITLINK(mode))
continue;
- blob = lookup_blob(&active_cache[i]->oid);
+ blob = lookup_blob(the_repository,
+ &active_cache[i]->oid);
if (!blob)
continue;
obj = &blob->object;
@@ -822,5 +829,24 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
check_connectivity();
+
+ if (!git_config_get_bool("core.commitgraph", &i) && i) {
+ struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
+ const char *verify_argv[] = { "commit-graph", "verify", NULL, NULL, NULL };
+
+ commit_graph_verify.argv = verify_argv;
+ commit_graph_verify.git_cmd = 1;
+ if (run_command(&commit_graph_verify))
+ errors_found |= ERROR_COMMIT_GRAPH;
+
+ prepare_alt_odb(the_repository);
+ for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) {
+ verify_argv[2] = "--object-dir";
+ verify_argv[3] = alt->path;
+ if (run_command(&commit_graph_verify))
+ errors_found |= ERROR_COMMIT_GRAPH;
+ }
+ }
+
return errors_found;
}
diff --git a/builtin/gc.c b/builtin/gc.c
index ccfb1ce..5706944 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -20,6 +20,7 @@
#include "sigchain.h"
#include "argv-array.h"
#include "commit.h"
+#include "commit-graph.h"
#include "packfile.h"
#include "object-store.h"
#include "pack.h"
@@ -40,6 +41,7 @@ static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
static int gc_auto_pack_limit = 50;
+static int gc_write_commit_graph;
static int detach_auto = 1;
static timestamp_t gc_log_expire_time;
static const char *gc_log_expire = "1.day.ago";
@@ -129,6 +131,7 @@ static void gc_config(void)
git_config_get_int("gc.aggressivedepth", &aggressive_depth);
git_config_get_int("gc.auto", &gc_auto_threshold);
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
+ git_config_get_bool("gc.writecommitgraph", &gc_write_commit_graph);
git_config_get_bool("gc.autodetach", &detach_auto);
git_config_get_expiry("gc.pruneexpire", &prune_expire);
git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
@@ -612,6 +615,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
return -1;
if (!repository_format_precious_objects) {
+ close_all_packs(the_repository->objects);
if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
return error(FAILED_RUN, repack.argv[0]);
@@ -641,6 +645,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (pack_garbage.nr > 0)
clean_pack_garbage();
+ if (gc_write_commit_graph)
+ write_commit_graph_reachable(get_object_directory(), 0);
+
if (auto_gc && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "
"run 'git prune' to remove them."));
diff --git a/builtin/grep.c b/builtin/grep.c
index 58f941e..ee5a1bd 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -647,7 +647,8 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
for (i = 0; i < nr; i++) {
struct object *real_obj;
- real_obj = deref_tag(list->objects[i].item, NULL, 0);
+ real_obj = deref_tag(the_repository, list->objects[i].item,
+ NULL, 0);
/* load the gitmodules file for this rev */
if (recurse_submodules) {
@@ -828,6 +829,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
GREP_PATTERN_TYPE_PCRE),
OPT_GROUP(""),
OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")),
+ OPT_BOOL(0, "column", &opt.columnnum, N_("show column number of first match")),
OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1),
OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1),
OPT_NEGBIT(0, "full-name", &opt.relative,
@@ -842,6 +844,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_BOOL_F('z', "null", &opt.null_following_name,
N_("print NUL after filenames"),
PARSE_OPT_NOCOMPLETE),
+ OPT_BOOL('o', "only-matching", &opt.only_matching,
+ N_("show only matching parts of a line")),
OPT_BOOL('c', "count", &opt.count,
N_("show the number of matches instead of matching lines")),
OPT__COLOR(&opt.color, N_("highlight matches")),
@@ -961,6 +965,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!opt.pattern_list)
die(_("no pattern given"));
+ /* --only-matching has no effect with --invert. */
+ if (opt.invert)
+ opt.only_matching = 0;
+
/*
* We have to find "--" in a separate pass, because its presence
* influences how we will parse arguments that come before it.
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index a9a3a19..9ada4f4 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -6,6 +6,7 @@
*/
#include "builtin.h"
#include "config.h"
+#include "object-store.h"
#include "blob.h"
#include "quote.h"
#include "parse-options.h"
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 74fe297..9582ead 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -832,7 +832,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
if (strict || do_fsck_object) {
read_lock();
if (type == OBJ_BLOB) {
- struct blob *blob = lookup_blob(oid);
+ struct blob *blob = lookup_blob(the_repository, oid);
if (blob)
blob->object.flags |= FLAG_CHECKED;
else
@@ -851,7 +851,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
* we do not need to free the memory here, as the
* buf is deleted by the caller.
*/
- obj = parse_object_buffer(oid, type, size, buf,
+ obj = parse_object_buffer(the_repository, oid, type,
+ size, buf,
&eaten);
if (!obj)
die(_("invalid %s"), type_name(type));
@@ -1679,7 +1680,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(index_pack_usage);
- check_replace_refs = 0;
+ read_replace_refs = 0;
fsck_options.walk = mark_link;
reset_pack_idx_option(&opts);
diff --git a/builtin/log.c b/builtin/log.c
index 99d4c69..e094560 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -7,6 +7,7 @@
#include "cache.h"
#include "config.h"
#include "refs.h"
+#include "object-store.h"
#include "color.h"
#include "commit.h"
#include "diff.h"
@@ -29,6 +30,7 @@
#include "gpg-interface.h"
#include "progress.h"
#include "commit-slab.h"
+#include "repository.h"
#define MAIL_DEFAULT_WRAP 72
@@ -618,7 +620,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
rev.shown_one = 1;
if (ret)
break;
- o = parse_object(&t->tagged->oid);
+ o = parse_object(the_repository, &t->tagged->oid);
if (!o)
ret = error(_("Could not read object %s"),
oid_to_hex(&t->tagged->oid));
@@ -905,8 +907,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
o2 = rev->pending.objects[1].item;
flags1 = o1->flags;
flags2 = o2->flags;
- c1 = lookup_commit_reference(&o1->oid);
- c2 = lookup_commit_reference(&o2->oid);
+ c1 = lookup_commit_reference(the_repository, &o1->oid);
+ c2 = lookup_commit_reference(the_repository, &o2->oid);
if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
die(_("Not a range."));
@@ -1755,6 +1757,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (base_commit || base_auto) {
struct commit *base = get_base_commit(base_commit, list, nr);
reset_revision_walk();
+ clear_object_flags(UNINTERESTING);
prepare_bases(&bases, base, list, nr);
}
@@ -1862,7 +1865,8 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
{
struct object_id oid;
if (get_oid(arg, &oid) == 0) {
- struct commit *commit = lookup_commit_reference(&oid);
+ struct commit *commit = lookup_commit_reference(the_repository,
+ &oid);
if (commit) {
commit->object.flags |= flags;
add_pending_object(revs, &commit->object, arg);
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 409da4e..fe3b952 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -5,6 +5,7 @@
*/
#include "cache.h"
#include "config.h"
+#include "object-store.h"
#include "blob.h"
#include "tree.h"
#include "commit.h"
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 3b76001..08d91b1 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -6,6 +6,7 @@
#include "diff.h"
#include "revision.h"
#include "parse-options.h"
+#include "repository.h"
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
@@ -42,7 +43,7 @@ static struct commit *get_commit_reference(const char *arg)
if (get_oid(arg, &revkey))
die("Not a valid object name %s", arg);
- r = lookup_commit_reference(&revkey);
+ r = lookup_commit_reference(the_repository, &revkey);
if (!r)
die("Not a valid commit name %s", arg);
@@ -123,7 +124,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
if (is_null_oid(oid))
return;
- commit = lookup_commit(oid);
+ commit = lookup_commit(the_repository, oid);
if (!commit ||
(commit->object.flags & TMP_MARK) ||
parse_commit(commit))
@@ -171,7 +172,7 @@ static int handle_fork_point(int argc, const char **argv)
if (get_oid(commitname, &oid))
die("Not a valid object name: '%s'", commitname);
- derived = lookup_commit_reference(&oid);
+ derived = lookup_commit_reference(the_repository, &oid);
memset(&revs, 0, sizeof(revs));
revs.initial = 1;
for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 0dd9021..9b2f707 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -9,10 +9,10 @@ static const char builtin_merge_recursive_usage[] =
static const char *better_branch_name(const char *branch)
{
- static char githead_env[8 + GIT_SHA1_HEXSZ + 1];
+ static char githead_env[8 + GIT_MAX_HEXSZ + 1];
char *name;
- if (strlen(branch) != GIT_SHA1_HEXSZ)
+ if (strlen(branch) != the_hash_algo->hexsz)
return branch;
xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch);
name = getenv(githead_env);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index bf01e05..f8023ba 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -1,6 +1,8 @@
#include "builtin.h"
#include "tree-walk.h"
#include "xdiff-interface.h"
+#include "object-store.h"
+#include "repository.h"
#include "blob.h"
#include "exec-cmd.h"
#include "merge-blobs.h"
@@ -169,7 +171,7 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const stru
res->stage = stage;
res->path = path;
res->mode = mode;
- res->blob = lookup_blob(oid);
+ res->blob = lookup_blob(the_repository, oid);
return res;
}
diff --git a/builtin/merge.c b/builtin/merge.c
index f553f89..8f4a506 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -111,6 +111,35 @@ static int option_parse_message(const struct option *opt,
return 0;
}
+static int option_read_message(struct parse_opt_ctx_t *ctx,
+ const struct option *opt, int unset)
+{
+ struct strbuf *buf = opt->value;
+ const char *arg;
+
+ if (unset)
+ BUG("-F cannot be negated");
+
+ if (ctx->opt) {
+ arg = ctx->opt;
+ ctx->opt = NULL;
+ } else if (ctx->argc > 1) {
+ ctx->argc--;
+ arg = *++ctx->argv;
+ } else
+ return opterror(opt, "requires a value", 0);
+
+ if (buf->len)
+ strbuf_addch(buf, '\n');
+ if (ctx->prefix && !is_absolute_path(arg))
+ arg = prefix_filename(ctx->prefix, arg);
+ if (strbuf_read_file(buf, arg, 0) < 0)
+ return error(_("could not read file '%s'"), arg);
+ have_message = 1;
+
+ return 0;
+}
+
static struct strategy *get_strategy(const char *name)
{
int i;
@@ -228,6 +257,9 @@ static struct option builtin_merge_options[] = {
OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
+ { OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
+ N_("read message from file"), PARSE_OPT_NONEG,
+ (parse_opt_cb *) option_read_message },
OPT__VERBOSITY(&verbosity),
OPT_BOOL(0, "abort", &abort_current_merge,
N_("abort the current in-progress merge")),
@@ -247,9 +279,9 @@ static struct option builtin_merge_options[] = {
/* Cleans up metadata that is uninteresting after a succeeded merge. */
static void drop_save(void)
{
- unlink(git_path_merge_head());
- unlink(git_path_merge_msg());
- unlink(git_path_merge_mode());
+ unlink(git_path_merge_head(the_repository));
+ unlink(git_path_merge_msg(the_repository));
+ unlink(git_path_merge_mode(the_repository));
}
static int save_state(struct object_id *stash)
@@ -382,7 +414,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
oid_to_hex(&commit->object.oid));
pretty_print_commit(&ctx, commit, &out);
}
- write_file_buf(git_path_squash_msg(), out.buf, out.len);
+ write_file_buf(git_path_squash_msg(the_repository), out.buf, out.len);
strbuf_release(&out);
}
@@ -741,7 +773,7 @@ static void add_strategies(const char *string, unsigned attr)
static void read_merge_msg(struct strbuf *msg)
{
- const char *filename = git_path_merge_msg();
+ const char *filename = git_path_merge_msg(the_repository);
strbuf_reset(msg);
if (strbuf_read_file(msg, filename, 0) < 0)
die_errno(_("Could not read from '%s'"), filename);
@@ -778,18 +810,18 @@ static void prepare_to_commit(struct commit_list *remoteheads)
if (signoff)
append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
write_merge_heads(remoteheads);
- write_file_buf(git_path_merge_msg(), msg.buf, msg.len);
+ write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
- git_path_merge_msg(), "merge", NULL))
+ git_path_merge_msg(the_repository), "merge", NULL))
abort_commit(remoteheads, NULL);
if (0 < option_edit) {
- if (launch_editor(git_path_merge_msg(), NULL, NULL))
+ if (launch_editor(git_path_merge_msg(the_repository), NULL, NULL))
abort_commit(remoteheads, NULL);
}
if (verify_msg && run_commit_hook(0 < option_edit, get_index_file(),
"commit-msg",
- git_path_merge_msg(), NULL))
+ git_path_merge_msg(the_repository), NULL))
abort_commit(remoteheads, NULL);
read_merge_msg(&msg);
@@ -859,7 +891,7 @@ static int suggest_conflicts(void)
FILE *fp;
struct strbuf msgbuf = STRBUF_INIT;
- filename = git_path_merge_msg();
+ filename = git_path_merge_msg(the_repository);
fp = xfopen(filename, "a");
append_conflicts_hint(&msgbuf);
@@ -942,12 +974,12 @@ static void write_merge_heads(struct commit_list *remoteheads)
}
strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
}
- write_file_buf(git_path_merge_head(), buf.buf, buf.len);
+ write_file_buf(git_path_merge_head(the_repository), buf.buf, buf.len);
strbuf_reset(&buf);
if (fast_forward == FF_NO)
strbuf_addstr(&buf, "no-ff");
- write_file_buf(git_path_merge_mode(), buf.buf, buf.len);
+ write_file_buf(git_path_merge_mode(the_repository), buf.buf, buf.len);
strbuf_release(&buf);
}
@@ -955,7 +987,8 @@ static void write_merge_state(struct commit_list *remoteheads)
{
write_merge_heads(remoteheads);
strbuf_addch(&merge_msg, '\n');
- write_file_buf(git_path_merge_msg(), merge_msg.buf, merge_msg.len);
+ write_file_buf(git_path_merge_msg(the_repository), merge_msg.buf,
+ merge_msg.len);
}
static int default_edit_option(void)
@@ -1034,11 +1067,12 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
const char *filename;
int fd, pos, npos;
struct strbuf fetch_head_file = STRBUF_INIT;
+ const unsigned hexsz = the_hash_algo->hexsz;
if (!merge_names)
merge_names = &fetch_head_file;
- filename = git_path_fetch_head();
+ filename = git_path_fetch_head(the_repository);
fd = open(filename, O_RDONLY);
if (fd < 0)
die_errno(_("could not open '%s' for reading"), filename);
@@ -1059,16 +1093,16 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
else
npos = merge_names->len;
- if (npos - pos < GIT_SHA1_HEXSZ + 2 ||
+ if (npos - pos < hexsz + 2 ||
get_oid_hex(merge_names->buf + pos, &oid))
commit = NULL; /* bad */
- else if (memcmp(merge_names->buf + pos + GIT_SHA1_HEXSZ, "\t\t", 2))
+ else if (memcmp(merge_names->buf + pos + hexsz, "\t\t", 2))
continue; /* not-for-merge */
else {
- char saved = merge_names->buf[pos + GIT_SHA1_HEXSZ];
- merge_names->buf[pos + GIT_SHA1_HEXSZ] = '\0';
+ char saved = merge_names->buf[pos + hexsz];
+ merge_names->buf[pos + hexsz] = '\0';
commit = get_merge_parent(merge_names->buf + pos);
- merge_names->buf[pos + GIT_SHA1_HEXSZ] = saved;
+ merge_names->buf[pos + hexsz] = saved;
}
if (!commit) {
if (ptr)
@@ -1213,7 +1247,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
usage_msg_opt(_("--abort expects no arguments"),
builtin_merge_usage, builtin_merge_options);
- if (!file_exists(git_path_merge_head()))
+ if (!file_exists(git_path_merge_head(the_repository)))
die(_("There is no merge to abort (MERGE_HEAD missing)."));
/* Invoke 'git reset --merge' */
@@ -1229,7 +1263,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
usage_msg_opt(_("--continue expects no arguments"),
builtin_merge_usage, builtin_merge_options);
- if (!file_exists(git_path_merge_head()))
+ if (!file_exists(git_path_merge_head(the_repository)))
die(_("There is no merge in progress (MERGE_HEAD missing)."));
/* Invoke 'git commit' */
@@ -1240,7 +1274,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (read_cache_unmerged())
die_resolve_conflict("merge");
- if (file_exists(git_path_merge_head())) {
+ if (file_exists(git_path_merge_head(the_repository))) {
/*
* There is no unmerged entry, don't advise 'git
* add/rm <file>', just 'git commit'.
@@ -1251,7 +1285,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
die(_("You have not concluded your merge (MERGE_HEAD exists)."));
}
- if (file_exists(git_path_cherry_pick_head())) {
+ if (file_exists(git_path_cherry_pick_head(the_repository))) {
if (advice_resolve_conflict)
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge."));
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 82a6e86..6fb7dc8 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "tag.h"
#include "replace-object.h"
+#include "object-store.h"
/*
* A signature file has a very simple fixed format: four lines
diff --git a/builtin/mktree.c b/builtin/mktree.c
index bb76b46..2dc4ad6 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -7,6 +7,7 @@
#include "quote.h"
#include "tree.h"
#include "parse-options.h"
+#include "object-store.h"
static struct treeent {
unsigned mode;
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 0eb4403..f1cb45c 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "cache.h"
+#include "repository.h"
#include "config.h"
#include "commit.h"
#include "tag.h"
@@ -203,7 +204,7 @@ static int tipcmp(const void *a_, const void *b_)
static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data)
{
- struct object *o = parse_object(oid);
+ struct object *o = parse_object(the_repository, oid);
struct name_ref_data *data = cb_data;
int can_abbreviate_output = data->tags_only && data->name_only;
int deref = 0;
@@ -261,7 +262,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
struct tag *t = (struct tag *) o;
if (!t->tagged)
break; /* broken repository */
- o = parse_object(&t->tagged->oid);
+ o = parse_object(the_repository, &t->tagged->oid);
deref = 1;
taggerdate = t->date;
}
@@ -378,7 +379,8 @@ static void name_rev_line(char *p, struct name_ref_data *data)
*(p+1) = 0;
if (!get_oid(p - (GIT_SHA1_HEXSZ - 1), &oid)) {
struct object *o =
- lookup_object(oid.hash);
+ lookup_object(the_repository,
+ oid.hash);
if (o)
name = get_rev_name(o, &buf);
}
@@ -451,9 +453,10 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
}
commit = NULL;
- object = parse_object(&oid);
+ object = parse_object(the_repository, &oid);
if (object) {
- struct object *peeled = deref_tag(object, *argv, 0);
+ struct object *peeled = deref_tag(the_repository,
+ object, *argv, 0);
if (peeled && peeled->type == OBJ_COMMIT)
commit = (struct commit *)peeled;
}
diff --git a/builtin/notes.c b/builtin/notes.c
index 6981e2d..c05cd00 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -11,6 +11,8 @@
#include "config.h"
#include "builtin.h"
#include "notes.h"
+#include "object-store.h"
+#include "repository.h"
#include "blob.h"
#include "pretty.h"
#include "refs.h"
@@ -710,7 +712,7 @@ static int merge_commit(struct notes_merge_options *o)
if (get_oid("NOTES_MERGE_PARTIAL", &oid))
die(_("failed to read ref NOTES_MERGE_PARTIAL"));
- else if (!(partial = lookup_commit_reference(&oid)))
+ else if (!(partial = lookup_commit_reference(the_repository, &oid)))
die(_("could not find commit from NOTES_MERGE_PARTIAL."));
else if (parse_commit(partial))
die(_("could not parse commit from NOTES_MERGE_PARTIAL."));
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 37d63f6..3848f37 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2480,7 +2480,7 @@ static void add_tag_chain(const struct object_id *oid)
if (packlist_find(&to_pack, oid->hash, NULL))
return;
- tag = lookup_tag(oid);
+ tag = lookup_tag(the_repository, oid);
while (1) {
if (!tag || parse_tag(tag) || !tag->tagged)
die(_("unable to pack objects reachable from tag %s"),
@@ -2935,11 +2935,13 @@ static int pack_options_allow_reuse(void)
static int get_object_list_from_bitmap(struct rev_info *revs)
{
- if (prepare_bitmap_walk(revs) < 0)
+ struct bitmap_index *bitmap_git;
+ if (!(bitmap_git = prepare_bitmap_walk(revs)))
return -1;
if (pack_options_allow_reuse() &&
!reuse_partial_packfile_from_bitmap(
+ bitmap_git,
&reuse_packfile,
&reuse_packfile_objects,
&reuse_packfile_offset)) {
@@ -2948,7 +2950,8 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
display_progress(progress_state, nr_result);
}
- traverse_bitmap_commit_list(&add_object_entry_from_bitmap);
+ traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap);
+ free_bitmap_index(bitmap_git);
return 0;
}
@@ -2975,7 +2978,7 @@ static void get_object_list(int ac, const char **av)
setup_revisions(ac, av, &revs, NULL);
/* make sure shallows are read */
- is_repository_shallow();
+ is_repository_shallow(the_repository);
while (fgets(line, sizeof(line), stdin) != NULL) {
int len = strlen(line);
@@ -2993,7 +2996,7 @@ static void get_object_list(int ac, const char **av)
struct object_id oid;
if (get_oid_hex(line + 10, &oid))
die("not an SHA-1 '%s'", line + 10);
- register_shallow(&oid);
+ register_shallow(the_repository, &oid);
use_bitmap_index = 0;
continue;
}
@@ -3191,7 +3194,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (DFS_NUM_STATES > (1 << OE_DFS_STATE_BITS))
BUG("too many dfs states, increase OE_DFS_STATE_BITS");
- check_replace_refs = 0;
+ read_replace_refs = 0;
reset_pack_idx_option(&pack_idx_opts);
git_config(git_pack_config, NULL);
@@ -3305,7 +3308,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
use_bitmap_index = use_bitmap_index_default;
/* "hard" reasons not to use bitmaps; these just won't work at all */
- if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow())
+ if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow(the_repository))
use_bitmap_index = 0;
if (pack_to_stdout || !rev_list_all)
diff --git a/builtin/prune.c b/builtin/prune.c
index 518ffbe..4916a4d 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -6,6 +6,7 @@
#include "reachable.h"
#include "parse-options.h"
#include "progress.h"
+#include "object-store.h"
static const char * const prune_usage[] = {
N_("git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"),
@@ -39,7 +40,7 @@ static int prune_object(const struct object_id *oid, const char *fullpath,
* Do we know about this object?
* It must have been reachable
*/
- if (lookup_object(oid->hash))
+ if (lookup_object(the_repository, oid->hash))
return 0;
if (lstat(fullpath, &st)) {
@@ -117,7 +118,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
expire = TIME_MAX;
save_commit_buffer = 0;
- check_replace_refs = 0;
+ read_replace_refs = 0;
ref_paranoia = 1;
init_revisions(&revs, prefix);
@@ -159,7 +160,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
remove_temporary_files(s);
free(s);
- if (is_repository_shallow())
+ if (is_repository_shallow(the_repository))
prune_shallow(show_only);
return 0;
diff --git a/builtin/pull.c b/builtin/pull.c
index fe002a7..4e78935 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -356,7 +356,7 @@ static int git_pull_config(const char *var, const char *value, void *cb)
*/
static void get_merge_heads(struct oid_array *merge_heads)
{
- const char *filename = git_path_fetch_head();
+ const char *filename = git_path_fetch_head(the_repository);
FILE *fp;
struct strbuf sb = STRBUF_INIT;
struct object_id oid;
@@ -765,10 +765,13 @@ static int get_octopus_merge_base(struct object_id *merge_base,
{
struct commit_list *revs = NULL, *result;
- commit_list_insert(lookup_commit_reference(curr_head), &revs);
- commit_list_insert(lookup_commit_reference(merge_head), &revs);
+ commit_list_insert(lookup_commit_reference(the_repository, curr_head),
+ &revs);
+ commit_list_insert(lookup_commit_reference(the_repository, merge_head),
+ &revs);
if (!is_null_oid(fork_point))
- commit_list_insert(lookup_commit_reference(fork_point), &revs);
+ commit_list_insert(lookup_commit_reference(the_repository, fork_point),
+ &revs);
result = get_octopus_merge_bases(revs);
free_commit_list(revs);
@@ -864,7 +867,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (read_cache_unmerged())
die_resolve_conflict("pull");
- if (file_exists(git_path_merge_head()))
+ if (file_exists(git_path_merge_head(the_repository)))
die_conclude_merge();
if (get_oid("HEAD", &orig_head))
@@ -944,9 +947,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
struct commit_list *list = NULL;
struct commit *merge_head, *head;
- head = lookup_commit_reference(&orig_head);
+ head = lookup_commit_reference(the_repository,
+ &orig_head);
commit_list_insert(head, &list);
- merge_head = lookup_commit_reference(&merge_heads.oid[0]);
+ merge_head = lookup_commit_reference(the_repository,
+ &merge_heads.oid[0]);
if (is_descendant_of(merge_head, list)) {
/* we can fast-forward this without invoking rebase */
opt_ff = "--ff-only";
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 68d36e0..c17ce94 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -25,6 +25,7 @@
#include "tmp-objdir.h"
#include "oidset.h"
#include "packfile.h"
+#include "object-store.h"
#include "protocol.h"
static const char * const receive_pack_usage[] = {
@@ -629,8 +630,6 @@ static void prepare_push_cert_sha1(struct child_process *proc)
return;
if (!already_done) {
- struct strbuf gpg_output = STRBUF_INIT;
- struct strbuf gpg_status = STRBUF_INIT;
int bogs /* beginning_of_gpg_sig */;
already_done = 1;
@@ -639,22 +638,11 @@ static void prepare_push_cert_sha1(struct child_process *proc)
oidclr(&push_cert_oid);
memset(&sigcheck, '\0', sizeof(sigcheck));
- sigcheck.result = 'N';
bogs = parse_signature(push_cert.buf, push_cert.len);
- if (verify_signed_buffer(push_cert.buf, bogs,
- push_cert.buf + bogs, push_cert.len - bogs,
- &gpg_output, &gpg_status) < 0) {
- ; /* error running gpg */
- } else {
- sigcheck.payload = push_cert.buf;
- sigcheck.gpg_output = gpg_output.buf;
- sigcheck.gpg_status = gpg_status.buf;
- parse_gpg_output(&sigcheck);
- }
+ check_signature(push_cert.buf, bogs, push_cert.buf + bogs,
+ push_cert.len - bogs, &sigcheck);
- strbuf_release(&gpg_output);
- strbuf_release(&gpg_status);
nonce_status = check_nonce(push_cert.buf, bogs);
}
if (!is_null_oid(&push_cert_oid)) {
@@ -905,7 +893,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
* not lose these new roots..
*/
for (i = 0; i < extra.nr; i++)
- register_shallow(&extra.oid[i]);
+ register_shallow(the_repository, &extra.oid[i]);
si->shallow_ref[cmd->index] = 0;
oid_array_clear(&extra);
@@ -1107,8 +1095,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
struct object *old_object, *new_object;
struct commit *old_commit, *new_commit;
- old_object = parse_object(old_oid);
- new_object = parse_object(new_oid);
+ old_object = parse_object(the_repository, old_oid);
+ new_object = parse_object(the_repository, new_oid);
if (!old_object || !new_object ||
old_object->type != OBJ_COMMIT ||
@@ -1131,7 +1119,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (is_null_oid(new_oid)) {
struct strbuf err = STRBUF_INIT;
- if (!parse_object(old_oid)) {
+ if (!parse_object(the_repository, old_oid)) {
old_oid = NULL;
if (ref_exists(name)) {
rp_warning("Allowing deletion of corrupt ref.");
diff --git a/builtin/reflog.c b/builtin/reflog.c
index a48984d..3acef5a 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -1,6 +1,8 @@
#include "builtin.h"
#include "config.h"
#include "lockfile.h"
+#include "object-store.h"
+#include "repository.h"
#include "commit.h"
#include "refs.h"
#include "dir.h"
@@ -64,7 +66,7 @@ static int tree_is_complete(const struct object_id *oid)
int complete;
struct tree *tree;
- tree = lookup_tree(oid);
+ tree = lookup_tree(the_repository, oid);
if (!tree)
return 0;
if (tree->object.flags & SEEN)
@@ -128,7 +130,7 @@ static int commit_is_complete(struct commit *commit)
struct commit_list *parent;
c = (struct commit *)object_array_pop(&study);
- if (!c->object.parsed && !parse_object(&c->object.oid))
+ if (!c->object.parsed && !parse_object(the_repository, &c->object.oid))
c->object.flags |= INCOMPLETE;
if (c->object.flags & INCOMPLETE) {
@@ -194,7 +196,7 @@ static int keep_entry(struct commit **it, struct object_id *oid)
if (is_null_oid(oid))
return 1;
- commit = lookup_commit_reference_gently(oid, 1);
+ commit = lookup_commit_reference_gently(the_repository, oid, 1);
if (!commit)
return 0;
@@ -263,7 +265,8 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit
if (is_null_oid(oid))
return 0;
- commit = lookup_commit_reference_gently(oid, 1);
+ commit = lookup_commit_reference_gently(the_repository, oid,
+ 1);
/* Not a commit -- keep it */
if (!commit)
@@ -320,7 +323,7 @@ static int push_tip_to_list(const char *refname, const struct object_id *oid,
struct commit *tip_commit;
if (flags & REF_ISSYMREF)
return 0;
- tip_commit = lookup_commit_reference_gently(oid, 1);
+ tip_commit = lookup_commit_reference_gently(the_repository, oid, 1);
if (!tip_commit)
return 0;
commit_list_insert(tip_commit, list);
@@ -337,7 +340,8 @@ static void reflog_expiry_prepare(const char *refname,
cb->tip_commit = NULL;
cb->unreachable_expire_kind = UE_HEAD;
} else {
- cb->tip_commit = lookup_commit_reference_gently(oid, 1);
+ cb->tip_commit = lookup_commit_reference_gently(the_repository,
+ oid, 1);
if (!cb->tip_commit)
cb->unreachable_expire_kind = UE_ALWAYS;
else
diff --git a/builtin/remote.c b/builtin/remote.c
index 1a82d85..c74ee88 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "argv-array.h"
static const char * const builtin_remote_usage[] = {
diff --git a/builtin/replace.c b/builtin/replace.c
index e879ace..4f05791 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -371,7 +371,7 @@ static int replace_parents(struct strbuf *buf, int argc, const char **argv)
return error(_("not a valid object name: '%s'"),
argv[i]);
}
- if (!lookup_commit_reference(&oid)) {
+ if (!lookup_commit_reference(the_repository, &oid)) {
strbuf_release(&new_parents);
return error(_("could not parse %s"), argv[i]);
}
@@ -402,10 +402,10 @@ static int check_one_mergetag(struct commit *commit,
int i;
hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &tag_oid);
- tag = lookup_tag(&tag_oid);
+ tag = lookup_tag(the_repository, &tag_oid);
if (!tag)
return error(_("bad mergetag in commit '%s'"), ref);
- if (parse_tag_buffer(tag, extra->value, extra->len))
+ if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
return error(_("malformed mergetag in commit '%s'"), ref);
/* iterate over new parents */
@@ -443,7 +443,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
if (get_oid(old_ref, &old_oid) < 0)
return error(_("not a valid object name: '%s'"), old_ref);
- commit = lookup_commit_reference(&old_oid);
+ commit = lookup_commit_reference(the_repository, &old_oid);
if (!commit)
return error(_("could not parse %s"), old_ref);
@@ -487,7 +487,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
static int convert_graft_file(int force)
{
- const char *graft_file = get_graft_file();
+ const char *graft_file = get_graft_file(the_repository);
FILE *fp = fopen_or_warn(graft_file, "r");
struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
struct argv_array args = ARGV_ARRAY_INIT;
@@ -544,7 +544,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
OPT_END()
};
- check_replace_refs = 0;
+ read_replace_refs = 0;
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
diff --git a/builtin/reset.c b/builtin/reset.c
index a862c70..11cd0dc 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -39,7 +39,7 @@ static const char *reset_type_names[] = {
static inline int is_merge(void)
{
- return !access(git_path_merge_head(), F_OK);
+ return !access(git_path_merge_head(the_repository), F_OK);
}
static int reset_index(const struct object_id *oid, int reset_type, int quiet)
@@ -134,7 +134,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
continue;
}
- ce = make_cache_entry(one->mode, one->oid.hash, one->path,
+ ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
0, 0);
if (!ce)
die(_("make_cache_entry failed for path '%s'"),
@@ -319,7 +319,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
struct commit *commit;
if (get_oid_committish(rev, &oid))
die(_("Failed to resolve '%s' as a valid revision."), rev);
- commit = lookup_commit_reference(&oid);
+ commit = lookup_commit_reference(the_repository, &oid);
if (!commit)
die(_("Could not parse object '%s'."), rev);
oidcpy(&oid, &commit->object.oid);
@@ -396,7 +396,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
update_ref_status = reset_refs(rev, &oid);
if (reset_type == HARD && !update_ref_status && !quiet)
- print_new_head_line(lookup_commit_reference(&oid));
+ print_new_head_line(lookup_commit_reference(the_repository, &oid));
}
if (!pathspec.nr)
remove_branch_state();
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index fadd3ec..5b07f3f 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -6,6 +6,7 @@
#include "list-objects.h"
#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
+#include "object-store.h"
#include "pack.h"
#include "pack-bitmap.h"
#include "builtin.h"
@@ -16,6 +17,7 @@
#include "reflog-walk.h"
#include "oidset.h"
#include "packfile.h"
+#include "object-store.h"
static const char rev_list_usage[] =
"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@@ -238,7 +240,7 @@ static int finish_object(struct object *obj, const char *name, void *cb_data)
return 1;
}
if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
- parse_object(&obj->oid);
+ parse_object(the_repository, &obj->oid);
return 0;
}
@@ -514,17 +516,21 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (revs.count && !revs.left_right && !revs.cherry_mark) {
uint32_t commit_count;
int max_count = revs.max_count;
- if (!prepare_bitmap_walk(&revs)) {
- count_bitmap_commit_list(&commit_count, NULL, NULL, NULL);
+ struct bitmap_index *bitmap_git;
+ if ((bitmap_git = prepare_bitmap_walk(&revs))) {
+ count_bitmap_commit_list(bitmap_git, &commit_count, NULL, NULL, NULL);
if (max_count >= 0 && max_count < commit_count)
commit_count = max_count;
printf("%d\n", commit_count);
+ free_bitmap_index(bitmap_git);
return 0;
}
} else if (revs.max_count < 0 &&
revs.tag_objects && revs.tree_objects && revs.blob_objects) {
- if (!prepare_bitmap_walk(&revs)) {
- traverse_bitmap_commit_list(&show_object_fast);
+ struct bitmap_index *bitmap_git;
+ if ((bitmap_git = prepare_bitmap_walk(&revs))) {
+ traverse_bitmap_commit_list(bitmap_git, &show_object_fast);
+ free_bitmap_index(bitmap_git);
return 0;
}
}
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 4f49e96..0f09bbb 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -280,8 +280,8 @@ static int try_difference(const char *arg)
if (symmetric) {
struct commit_list *exclude;
struct commit *a, *b;
- a = lookup_commit_reference(&start_oid);
- b = lookup_commit_reference(&end_oid);
+ a = lookup_commit_reference(the_repository, &start_oid);
+ b = lookup_commit_reference(the_repository, &end_oid);
if (!a || !b) {
*dotdot = '.';
return 0;
@@ -333,7 +333,7 @@ static int try_parent_shorthands(const char *arg)
*dotdot = 0;
if (get_oid_committish(arg, &oid) ||
- !(commit = lookup_commit_reference(&oid))) {
+ !(commit = lookup_commit_reference(the_repository, &oid))) {
*dotdot = '^';
return 0;
}
@@ -883,7 +883,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--is-shallow-repository")) {
- printf("%s\n", is_repository_shallow() ? "true"
+ printf("%s\n",
+ is_repository_shallow(the_repository) ? "true"
: "false");
continue;
}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index f2e985c..4b9d3c0 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -378,7 +378,8 @@ static void sort_ref_range(int bottom, int top)
static int append_ref(const char *refname, const struct object_id *oid,
int allow_dups)
{
- struct commit *commit = lookup_commit_reference_gently(oid, 1);
+ struct commit *commit = lookup_commit_reference_gently(the_repository,
+ oid, 1);
int i;
if (!commit)
@@ -830,7 +831,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
MAX_REVS), MAX_REVS);
if (get_oid(ref_name[num_rev], &revkey))
die(_("'%s' is not a valid ref."), ref_name[num_rev]);
- commit = lookup_commit_reference(&revkey);
+ commit = lookup_commit_reference(the_repository, &revkey);
if (!commit)
die(_("cannot find commit %s (%s)"),
ref_name[num_rev], oid_to_hex(&revkey));
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index f2eb1a7..2f13f13 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "cache.h"
#include "refs.h"
+#include "object-store.h"
#include "object.h"
#include "tag.h"
#include "string-list.h"
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 20ae919..a3c4564 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1124,6 +1124,8 @@ static void deinit_submodule(const char *path, const char *prefix,
if (!(flags & OPT_QUIET))
printf(format, displaypath);
+ submodule_unset_core_worktree(sub);
+
strbuf_release(&sb_rm);
}
@@ -1706,8 +1708,8 @@ static int update_clone_task_finished(int result,
return 0;
}
-static int gitmodules_update_clone_config(const char *var, const char *value,
- void *cb)
+static int git_update_clone_config(const char *var, const char *value,
+ void *cb)
{
int *max_jobs = cb;
if (!strcmp(var, "submodule.fetchjobs"))
@@ -1757,8 +1759,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
};
suc.prefix = prefix;
- config_from_gitmodules(gitmodules_update_clone_config, &max_jobs);
- git_config(gitmodules_update_clone_config, &max_jobs);
+ update_clone_config_from_gitmodules(&max_jobs);
+ git_config(git_update_clone_config, &max_jobs);
argc = parse_options(argc, argv, prefix, module_update_clone_options,
git_submodule_helper_usage, 0);
@@ -2004,6 +2006,29 @@ static int check_name(int argc, const char **argv, const char *prefix)
return 0;
}
+static int connect_gitdir_workingtree(int argc, const char **argv, const char *prefix)
+{
+ struct strbuf sb = STRBUF_INIT;
+ const char *name, *path;
+ char *sm_gitdir;
+
+ if (argc != 3)
+ BUG("submodule--helper connect-gitdir-workingtree <name> <path>");
+
+ name = argv[1];
+ path = argv[2];
+
+ strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name);
+ sm_gitdir = absolute_pathdup(sb.buf);
+
+ connect_work_tree_and_git_dir(path, sm_gitdir, 0);
+
+ strbuf_release(&sb);
+ free(sm_gitdir);
+
+ return 0;
+}
+
#define SUPPORT_SUPER_PREFIX (1<<0)
struct cmd_struct {
@@ -2017,6 +2042,7 @@ static struct cmd_struct commands[] = {
{"name", module_name, 0},
{"clone", module_clone, 0},
{"update-clone", update_clone, 0},
+ {"connect-gitdir-workingtree", connect_gitdir_workingtree, 0},
{"relative-path", resolve_relative_path, 0},
{"resolve-relative-url", resolve_relative_url, 0},
{"resolve-relative-url-test", resolve_relative_url_test, 0},
diff --git a/builtin/tag.c b/builtin/tag.c
index 5d0dd11..9a19ffb 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -10,6 +10,7 @@
#include "config.h"
#include "builtin.h"
#include "refs.h"
+#include "object-store.h"
#include "tag.h"
#include "run-command.h"
#include "parse-options.h"
@@ -312,7 +313,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
}
free(buf);
- if ((c = lookup_commit_reference(oid)) != NULL)
+ if ((c = lookup_commit_reference(the_repository, oid)) != NULL)
strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
break;
case OBJ_TREE:
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 300eb59..5865222 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "object-store.h"
static char *create_temp_file(struct object_id *oid)
{
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 6e81ca8..30d9413 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "cache.h"
#include "config.h"
+#include "object-store.h"
#include "object.h"
#include "delta.h"
#include "pack.h"
@@ -253,7 +254,7 @@ static void write_object(unsigned nr, enum object_type type,
added_object(nr, type, buf, size);
free(buf);
- blob = lookup_blob(&obj_list[nr].oid);
+ blob = lookup_blob(the_repository, &obj_list[nr].oid);
if (blob)
blob->object.flags |= FLAG_WRITTEN;
else
@@ -264,7 +265,8 @@ static void write_object(unsigned nr, enum object_type type,
int eaten;
hash_object_file(buf, size, type_name(type), &obj_list[nr].oid);
added_object(nr, type, buf, size);
- obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf,
+ obj = parse_object_buffer(the_repository, &obj_list[nr].oid,
+ type, size, buf,
&eaten);
if (!obj)
die("invalid %s", type_name(type));
@@ -330,7 +332,7 @@ static int resolve_against_held(unsigned nr, const struct object_id *base,
{
struct object *obj;
struct obj_buffer *obj_buffer;
- obj = lookup_object(base->hash);
+ obj = lookup_object(the_repository, base->hash);
if (!obj)
return 0;
obj_buffer = lookup_object_buffer(obj);
@@ -512,7 +514,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
int i;
struct object_id oid;
- check_replace_refs = 0;
+ read_replace_refs = 0;
git_config(git_default_config, NULL);
diff --git a/builtin/update-index.c b/builtin/update-index.c
index a8709a2..f5c0b6a 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -268,15 +268,14 @@ static int process_lstat_error(const char *path, int err)
static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st)
{
- int option, size;
+ int option;
struct cache_entry *ce;
/* Was the old index entry already up-to-date? */
if (old && !ce_stage(old) && !ce_match_stat(old, st, 0))
return 0;
- size = cache_entry_size(len);
- ce = xcalloc(1, size);
+ ce = make_empty_cache_entry(&the_index, len);
memcpy(ce->name, path, len);
ce->ce_flags = create_ce_flags(0);
ce->ce_namelen = len;
@@ -285,13 +284,13 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
if (index_path(&ce->oid, path, st,
info_only ? 0 : HASH_WRITE_OBJECT)) {
- free(ce);
+ discard_cache_entry(ce);
return -1;
}
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
if (add_cache_entry(ce, option)) {
- free(ce);
+ discard_cache_entry(ce);
return error("%s: cannot add to the index - missing --add option?", path);
}
return 0;
@@ -402,15 +401,14 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
const char *path, int stage)
{
- int size, len, option;
+ int len, option;
struct cache_entry *ce;
if (!verify_path(path, mode))
return error("Invalid path '%s'", path);
len = strlen(path);
- size = cache_entry_size(len);
- ce = xcalloc(1, size);
+ ce = make_empty_cache_entry(&the_index, len);
oidcpy(&ce->oid, oid);
memcpy(ce->name, path, len);
@@ -492,6 +490,7 @@ static void update_one(const char *path)
static void read_index_info(int nul_term_line)
{
+ const int hexsz = the_hash_algo->hexsz;
struct strbuf buf = STRBUF_INIT;
struct strbuf uq = STRBUF_INIT;
strbuf_getline_fn getline_fn;
@@ -529,7 +528,7 @@ static void read_index_info(int nul_term_line)
mode = ul;
tab = strchr(ptr, '\t');
- if (!tab || tab - ptr < GIT_SHA1_HEXSZ + 1)
+ if (!tab || tab - ptr < hexsz + 1)
goto bad_line;
if (tab[-2] == ' ' && '0' <= tab[-1] && tab[-1] <= '3') {
@@ -542,8 +541,8 @@ static void read_index_info(int nul_term_line)
ptr = tab + 1; /* point at the head of path */
}
- if (get_oid_hex(tab - GIT_SHA1_HEXSZ, &oid) ||
- tab[-(GIT_SHA1_HEXSZ + 1)] != ' ')
+ if (get_oid_hex(tab - hexsz, &oid) ||
+ tab[-(hexsz + 1)] != ' ')
goto bad_line;
path_name = ptr;
@@ -571,7 +570,7 @@ static void read_index_info(int nul_term_line)
* ptr[-1] points at tab,
* ptr[-41] is at the beginning of sha1
*/
- ptr[-(GIT_SHA1_HEXSZ + 2)] = ptr[-1] = 0;
+ ptr[-(hexsz + 2)] = ptr[-1] = 0;
if (add_cacheinfo(mode, &oid, path_name, stage))
die("git update-index: unable to update %s",
path_name);
@@ -599,7 +598,6 @@ static struct cache_entry *read_one_ent(const char *which,
{
unsigned mode;
struct object_id oid;
- int size;
struct cache_entry *ce;
if (get_tree_entry(ent, path, &oid, &mode)) {
@@ -612,8 +610,7 @@ static struct cache_entry *read_one_ent(const char *which,
error("%s: not a blob in %s branch.", path, which);
return NULL;
}
- size = cache_entry_size(namelen);
- ce = xcalloc(1, size);
+ ce = make_empty_cache_entry(&the_index, namelen);
oidcpy(&ce->oid, &oid);
memcpy(ce->name, path, namelen);
@@ -690,8 +687,8 @@ static int unresolve_one(const char *path)
error("%s: cannot add their version to the index.", path);
ret = -1;
free_return:
- free(ce_2);
- free(ce_3);
+ discard_cache_entry(ce_2);
+ discard_cache_entry(ce_3);
return ret;
}
@@ -758,7 +755,7 @@ static int do_reupdate(int ac, const char **av,
ce->name, ce_namelen(ce), 0);
if (old && ce->ce_mode == old->ce_mode &&
!oidcmp(&ce->oid, &old->oid)) {
- free(old);
+ discard_cache_entry(old);
continue; /* unchanged */
}
/* Be careful. The working tree may not have the
@@ -769,7 +766,7 @@ static int do_reupdate(int ac, const char **av,
path = xstrdup(ce->name);
update_one(path);
free(path);
- free(old);
+ discard_cache_entry(old);
if (save_nr != active_nr)
goto redo;
}
@@ -826,6 +823,7 @@ static int parse_new_style_cacheinfo(const char *arg,
{
unsigned long ul;
char *endp;
+ const char *p;
if (!arg)
return -1;
@@ -836,9 +834,9 @@ static int parse_new_style_cacheinfo(const char *arg,
return -1; /* not a new-style cacheinfo */
*mode = ul;
endp++;
- if (get_oid_hex(endp, oid) || endp[GIT_SHA1_HEXSZ] != ',')
+ if (parse_oid_hex(endp, oid, &p) || *p != ',')
return -1;
- *path = endp + GIT_SHA1_HEXSZ + 1;
+ *path = p + 1;
return 0;
}
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index decde5a..42dc4da 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -31,7 +31,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
};
packet_trace_identity("upload-pack");
- check_replace_refs = 0;
+ read_replace_refs = 0;
argc = parse_options(argc, argv, NULL, options, upload_pack_usage, 0);
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index dcdaada..7772c07 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -8,6 +8,8 @@
#include "cache.h"
#include "config.h"
#include "builtin.h"
+#include "object-store.h"
+#include "repository.h"
#include "commit.h"
#include "run-command.h"
#include <signal.h>
@@ -26,7 +28,8 @@ static int run_gpg_verify(const struct object_id *oid, const char *buf, unsigned
memset(&signature_check, 0, sizeof(signature_check));
- ret = check_commit_signature(lookup_commit(oid), &signature_check);
+ ret = check_commit_signature(lookup_commit(the_repository, oid),
+ &signature_check);
print_signature_buffer(&signature_check, flags);
signature_check_clear(&signature_check);
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 5c7d2bb..a763dbd 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -412,7 +412,7 @@ static const char *dwim_branch(const char *path, const char **new_branch)
if (guess_remote) {
struct object_id oid;
const char *remote =
- unique_tracking_name(*new_branch, &oid);
+ unique_tracking_name(*new_branch, &oid, NULL);
return remote;
}
return NULL;
@@ -484,7 +484,7 @@ static int add(int ac, const char **av, const char *prefix)
commit = lookup_commit_reference_by_name(branch);
if (!commit) {
- remote = unique_tracking_name(branch, &oid);
+ remote = unique_tracking_name(branch, &oid, NULL);
if (remote) {
new_branch = branch;
branch = remote;
diff --git a/bulk-checkin.c b/bulk-checkin.c
index b7e131c..9f3b644 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -8,6 +8,7 @@
#include "pack.h"
#include "strbuf.h"
#include "packfile.h"
+#include "object-store.h"
static struct bulk_checkin_state {
unsigned plugged:1;
diff --git a/bundle.c b/bundle.c
index 160bbfd..24cbe40 100644
--- a/bundle.c
+++ b/bundle.c
@@ -1,6 +1,8 @@
#include "cache.h"
#include "lockfile.h"
#include "bundle.h"
+#include "object-store.h"
+#include "repository.h"
#include "object.h"
#include "commit.h"
#include "diff.h"
@@ -141,7 +143,7 @@ int verify_bundle(struct bundle_header *header, int verbose)
init_revisions(&revs, NULL);
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
- struct object *o = parse_object(&e->oid);
+ struct object *o = parse_object(the_repository, &e->oid);
if (o) {
o->flags |= PREREQ_MARK;
add_pending_object(&revs, o, e->name);
@@ -166,7 +168,7 @@ int verify_bundle(struct bundle_header *header, int verbose)
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
- struct object *o = parse_object(&e->oid);
+ struct object *o = parse_object(the_repository, &e->oid);
assert(o); /* otherwise we'd have returned early */
if (o->flags & SHOWN)
continue;
@@ -178,7 +180,7 @@ int verify_bundle(struct bundle_header *header, int verbose)
/* Clean up objects used, as they will be reused. */
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
- commit = lookup_commit_reference_gently(&e->oid, 1);
+ commit = lookup_commit_reference_gently(the_repository, &e->oid, 1);
if (commit)
clear_commit_marks(commit, ALL_REV_FLAGS);
}
@@ -373,7 +375,8 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
* in terms of a tag (e.g. v2.0 from the range
* "v1.0..v2.0")?
*/
- struct commit *one = lookup_commit_reference(&oid);
+ struct commit *one = lookup_commit_reference(the_repository,
+ &oid);
struct object *obj;
if (e->item == &(one->object)) {
diff --git a/cache-tree.c b/cache-tree.c
index 2566382..181d591 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -3,6 +3,7 @@
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
+#include "object-store.h"
#ifndef DEBUG
#define DEBUG 0
@@ -670,7 +671,8 @@ static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
cnt++;
else {
struct cache_tree_sub *sub;
- struct tree *subtree = lookup_tree(entry.oid);
+ struct tree *subtree = lookup_tree(the_repository,
+ entry.oid);
if (!subtree->object.parsed)
parse_tree(subtree);
sub = cache_tree_sub(it, entry.path);
diff --git a/cache.h b/cache.h
index d49092d..8cf62b5 100644
--- a/cache.h
+++ b/cache.h
@@ -15,6 +15,7 @@
#include "path.h"
#include "sha1-array.h"
#include "repository.h"
+#include "mem-pool.h"
#include <zlib.h>
typedef struct git_zstream {
@@ -156,6 +157,7 @@ struct cache_entry {
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;
@@ -218,6 +220,7 @@ struct cache_entry {
/* Forward structure decls */
struct pathspec;
struct child_process;
+struct tree;
/*
* Copy the sha1 and stat state of a cache entry from one to
@@ -227,6 +230,7 @@ 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,
@@ -235,6 +239,9 @@ static inline void copy_cache_entry(struct cache_entry *dst,
/* 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)
@@ -328,6 +335,7 @@ struct index_state {
struct untracked_cache *untracked;
uint64_t fsmonitor_last_update;
struct ewah_bitmap *fsmonitor_dirty;
+ struct mem_pool *ce_mem_pool;
};
extern struct index_state the_index;
@@ -339,6 +347,60 @@ extern void remove_name_hash(struct index_state *istate, struct cache_entry *ce)
extern 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.
+ * Caller is responsible for discarding the cache_entry
+ * with `discard_cache_entry`.
+ */
+struct cache_entry *make_transient_cache_entry(unsigned int mode,
+ const struct object_id *oid,
+ const char *path,
+ int stage);
+
+struct cache_entry *make_empty_transient_cache_entry(size_t name_len);
+
+/*
+ * 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);
+
#ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
#define active_cache (the_index.cache)
#define active_nr (the_index.cache_nr)
@@ -484,7 +546,7 @@ extern const char *get_git_dir(void);
extern const char *get_git_common_dir(void);
extern char *get_object_directory(void);
extern char *get_index_file(void);
-extern char *get_graft_file(void);
+extern char *get_graft_file(struct repository *r);
extern void set_git_dir(const char *path);
extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
extern int get_common_dir(struct strbuf *sb, const char *gitdir);
@@ -635,12 +697,15 @@ extern void move_index_extensions(struct index_state *dst, struct index_state *s
extern int unmerged_index(const struct index_state *);
/**
- * Returns 1 if the index differs from HEAD, 0 otherwise. When on an unborn
- * branch, returns 1 if there are entries in the index, 0 otherwise. If an
- * strbuf is provided, the space-separated list of files that differ will be
- * appended to it.
+ * 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.
*/
-extern int index_has_changes(struct strbuf *sb);
+extern int index_has_changes(const struct index_state *istate,
+ struct tree *tree,
+ struct strbuf *sb);
extern int verify_path(const char *path, unsigned mode);
extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
@@ -698,7 +763,6 @@ extern int remove_file_from_index(struct index_state *, const char *path);
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
extern int add_file_to_index(struct index_state *, const char *path, int flags);
-extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
@@ -751,7 +815,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
#define REFRESH_IGNORE_SUBMODULES 0x0010 /* ignore submodules */
#define REFRESH_IN_PORCELAIN 0x0020 /* user friendly output, not "needs update" */
extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
-extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);
+extern struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int);
/*
* Opportunistically update the index but do not complain if we can't.
@@ -804,16 +868,13 @@ 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. As an
- * optimization it is also set to false if replace references have
- * been sought but there were none.
+ * commands that do not want replace references to be active.
*/
-extern int check_replace_refs;
+extern int read_replace_refs;
extern char *git_replace_ref_base;
extern int fsync_object_files;
extern int core_preload_index;
-extern int core_commit_graph;
extern int core_apply_sparse_checkout;
extern int precomposed_unicode;
extern int protect_hfs;
@@ -972,7 +1033,7 @@ extern const struct object_id null_oid;
static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
{
- return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
+ return memcmp(sha1, sha2, the_hash_algo->rawsz);
}
static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
@@ -992,7 +1053,7 @@ static inline int is_null_oid(const struct object_id *oid)
static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
{
- memcpy(sha_dst, sha_src, GIT_SHA1_RAWSZ);
+ memcpy(sha_dst, sha_src, the_hash_algo->rawsz);
}
static inline void oidcpy(struct object_id *dst, const struct object_id *src)
@@ -1009,7 +1070,7 @@ static inline struct object_id *oiddup(const struct object_id *src)
static inline void hashclr(unsigned char *hash)
{
- memset(hash, 0, GIT_SHA1_RAWSZ);
+ memset(hash, 0, the_hash_algo->rawsz);
}
static inline void oidclr(struct object_id *oid)
@@ -1192,32 +1253,6 @@ extern char *xdg_config_home(const char *filename);
*/
extern char *xdg_cache_home(const char *filename);
-extern void *read_object_file_extended(const struct object_id *oid,
- enum object_type *type,
- unsigned long *size, int lookup_replace);
-static inline void *read_object_file(const struct object_id *oid, enum object_type *type, unsigned long *size)
-{
- return read_object_file_extended(oid, type, size, 1);
-}
-
-/* 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 *);
-
-extern int hash_object_file(const void *buf, unsigned long len,
- const char *type, struct object_id *oid);
-
-extern int write_object_file(const void *buf, unsigned long len,
- const char *type, struct object_id *oid);
-
-extern int hash_object_file_literally(const void *buf, unsigned long len,
- const char *type, struct object_id *oid,
- unsigned flags);
-
-extern int pretend_object_file(void *, unsigned long, enum object_type,
- struct object_id *oid);
-
-extern int force_object_loose(const struct object_id *oid, time_t mtime);
-
extern int git_open_cloexec(const char *name, int flags);
#define git_open(name) git_open_cloexec(name, O_RDONLY)
extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
@@ -1227,43 +1262,6 @@ extern int check_object_signature(const struct object_id *oid, void *buf, unsign
extern int finalize_object_file(const char *tmpfile, const char *filename);
-/*
- * Open the loose object at path, check its hash, and return the contents,
- * 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,
- enum object_type *type,
- unsigned long *size,
- void **contents);
-
-/*
- * Convenience for sha1_object_info_extended() with a NULL struct
- * object_info. OBJECT_INFO_SKIP_CACHED is automatically set; pass
- * nonzero flags to also set other flags.
- */
-extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags);
-static inline int has_sha1_file(const unsigned char *sha1)
-{
- return has_sha1_file_with_flags(sha1, 0);
-}
-
-/* Same as the above, except for struct object_id. */
-extern int has_object_file(const struct object_id *oid);
-extern int has_object_file_with_flags(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.
- */
-extern int has_loose_object_nonlocal(const struct object_id *oid);
-
-extern void assert_oid_type(const struct object_id *oid, enum object_type expect);
-
/* Helper to check and "touch" a file */
extern int check_and_freshen_file(const char *fn, int freshen);
@@ -1631,60 +1629,6 @@ int for_each_loose_file_in_objdir_buf(struct strbuf *path,
#define FOR_EACH_OBJECT_LOCAL_ONLY 0x1
extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags);
-struct object_info {
- /* Request */
- enum object_type *typep;
- unsigned long *sizep;
- off_t *disk_sizep;
- unsigned char *delta_base_sha1;
- 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 {NULL}
-
-/* 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 check cached storage */
-#define OBJECT_INFO_SKIP_CACHED 4
-/* Do not retry packed storage after checking packed and loose storage */
-#define OBJECT_INFO_QUICK 8
-/* Do not check loose object */
-#define OBJECT_INFO_IGNORE_LOOSE 16
-
-int oid_object_info_extended(struct repository *r,
- const struct object_id *,
- struct object_info *, unsigned flags);
-
/*
* Set this to 0 to prevent sha1_object_info_extended() from fetching missing
* blobs. This has a difference only if extensions.partialClone is set.
diff --git a/checkout.c b/checkout.c
index bdefc88..c72e9f9 100644
--- a/checkout.c
+++ b/checkout.c
@@ -2,14 +2,20 @@
#include "remote.h"
#include "refspec.h"
#include "checkout.h"
+#include "config.h"
struct tracking_name_data {
/* const */ char *src_ref;
char *dst_ref;
struct object_id *dst_oid;
- int unique;
+ int num_matches;
+ const char *default_remote;
+ char *default_dst_ref;
+ struct object_id *default_dst_oid;
};
+#define TRACKING_NAME_DATA_INIT { NULL, NULL, NULL, 0, NULL, NULL, NULL }
+
static int check_tracking_name(struct remote *remote, void *cb_data)
{
struct tracking_name_data *cb = cb_data;
@@ -21,24 +27,45 @@ static int check_tracking_name(struct remote *remote, void *cb_data)
free(query.dst);
return 0;
}
+ cb->num_matches++;
+ if (cb->default_remote && !strcmp(remote->name, cb->default_remote)) {
+ struct object_id *dst = xmalloc(sizeof(*cb->default_dst_oid));
+ cb->default_dst_ref = xstrdup(query.dst);
+ oidcpy(dst, cb->dst_oid);
+ cb->default_dst_oid = dst;
+ }
if (cb->dst_ref) {
free(query.dst);
- cb->unique = 0;
return 0;
}
cb->dst_ref = query.dst;
return 0;
}
-const char *unique_tracking_name(const char *name, struct object_id *oid)
+const char *unique_tracking_name(const char *name, struct object_id *oid,
+ int *dwim_remotes_matched)
{
- struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
+ struct tracking_name_data cb_data = TRACKING_NAME_DATA_INIT;
+ const char *default_remote = NULL;
+ if (!git_config_get_string_const("checkout.defaultremote", &default_remote))
+ cb_data.default_remote = default_remote;
cb_data.src_ref = xstrfmt("refs/heads/%s", name);
cb_data.dst_oid = oid;
for_each_remote(check_tracking_name, &cb_data);
+ if (dwim_remotes_matched)
+ *dwim_remotes_matched = cb_data.num_matches;
free(cb_data.src_ref);
- if (cb_data.unique)
+ free((char *)default_remote);
+ if (cb_data.num_matches == 1) {
+ free(cb_data.default_dst_ref);
+ free(cb_data.default_dst_oid);
return cb_data.dst_ref;
+ }
free(cb_data.dst_ref);
+ if (cb_data.default_dst_ref) {
+ oidcpy(oid, cb_data.default_dst_oid);
+ free(cb_data.default_dst_oid);
+ return cb_data.default_dst_ref;
+ }
return NULL;
}
diff --git a/checkout.h b/checkout.h
index 9980711..6b20733 100644
--- a/checkout.h
+++ b/checkout.h
@@ -8,6 +8,8 @@
* tracking branch. Return the name of the remote if such a branch
* exists, NULL otherwise.
*/
-extern const char *unique_tracking_name(const char *name, struct object_id *oid);
+extern const char *unique_tracking_name(const char *name,
+ struct object_id *oid,
+ int *dwim_remotes_matched);
#endif /* CHECKOUT_H */
diff --git a/ci/run-static-analysis.sh b/ci/run-static-analysis.sh
index fe4ee4e..5688f26 100755
--- a/ci/run-static-analysis.sh
+++ b/ci/run-static-analysis.sh
@@ -5,6 +5,25 @@
. ${0%/*}/lib-travisci.sh
-make coccicheck
+make --jobs=2 coccicheck
+
+set +x
+
+fail=
+for cocci_patch in contrib/coccinelle/*.patch
+do
+ if test -s "$cocci_patch"
+ then
+ echo "$(tput setaf 1)Coccinelle suggests the following changes in '$cocci_patch':$(tput sgr0)"
+ cat "$cocci_patch"
+ fail=UnfortunatelyYes
+ fi
+done
+
+if test -n "$fail"
+then
+ echo "$(tput setaf 1)error: Coccinelle suggested some changes$(tput sgr0)"
+ exit 1
+fi
save_good_tree
diff --git a/combine-diff.c b/combine-diff.c
index 2ef4959..de7695e 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "object-store.h"
#include "commit.h"
#include "blob.h"
#include "diff.h"
diff --git a/commit-graph.c b/commit-graph.c
index c8d5219..0034740 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -7,10 +7,12 @@
#include "packfile.h"
#include "commit.h"
#include "object.h"
+#include "refs.h"
#include "revision.h"
#include "sha1-lookup.h"
#include "commit-graph.h"
#include "object-store.h"
+#include "alloc.h"
#define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
#define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
@@ -35,10 +37,11 @@
#define GRAPH_LAST_EDGE 0x80000000
+#define GRAPH_HEADER_SIZE 8
#define GRAPH_FANOUT_SIZE (4 * 256)
#define GRAPH_CHUNKLOOKUP_WIDTH 12
-#define GRAPH_MIN_SIZE (5 * GRAPH_CHUNKLOOKUP_WIDTH + GRAPH_FANOUT_SIZE + \
- GRAPH_OID_LEN + 8)
+#define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * GRAPH_CHUNKLOOKUP_WIDTH \
+ + GRAPH_FANOUT_SIZE + GRAPH_OID_LEN)
char *get_commit_graph_filename(const char *obj_dir)
{
@@ -180,53 +183,60 @@ cleanup_fail:
exit(1);
}
-/* global storage */
-static struct commit_graph *commit_graph = NULL;
-
-static void prepare_commit_graph_one(const char *obj_dir)
+static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
{
char *graph_name;
- if (commit_graph)
+ if (r->objects->commit_graph)
return;
graph_name = get_commit_graph_filename(obj_dir);
- commit_graph = load_commit_graph_one(graph_name);
+ r->objects->commit_graph =
+ load_commit_graph_one(graph_name);
FREE_AND_NULL(graph_name);
}
-static int prepare_commit_graph_run_once = 0;
-static void prepare_commit_graph(void)
+/*
+ * Return 1 if commit_graph is non-NULL, and 0 otherwise.
+ *
+ * On the first invocation, this function attemps to load the commit
+ * graph if the_repository is configured to have one.
+ */
+static int prepare_commit_graph(struct repository *r)
{
struct alternate_object_database *alt;
char *obj_dir;
+ int config_value;
+
+ if (r->objects->commit_graph_attempted)
+ return !!r->objects->commit_graph;
+ r->objects->commit_graph_attempted = 1;
+
+ if (repo_config_get_bool(r, "core.commitgraph", &config_value) ||
+ !config_value)
+ /*
+ * This repository is not configured to use commit graphs, so
+ * do not load one. (But report commit_graph_attempted anyway
+ * so that commit graph loading is not attempted again for this
+ * repository.)
+ */
+ return 0;
- if (prepare_commit_graph_run_once)
- return;
- prepare_commit_graph_run_once = 1;
-
- obj_dir = get_object_directory();
- prepare_commit_graph_one(obj_dir);
- prepare_alt_odb(the_repository);
- for (alt = the_repository->objects->alt_odb_list;
- !commit_graph && alt;
+ obj_dir = r->objects->objectdir;
+ prepare_commit_graph_one(r, obj_dir);
+ prepare_alt_odb(r);
+ for (alt = r->objects->alt_odb_list;
+ !r->objects->commit_graph && alt;
alt = alt->next)
- prepare_commit_graph_one(alt->path);
+ prepare_commit_graph_one(r, alt->path);
+ return !!r->objects->commit_graph;
}
static void close_commit_graph(void)
{
- if (!commit_graph)
- return;
-
- if (commit_graph->graph_fd >= 0) {
- munmap((void *)commit_graph->data, commit_graph->data_len);
- commit_graph->data = NULL;
- close(commit_graph->graph_fd);
- }
-
- FREE_AND_NULL(commit_graph);
+ free_commit_graph(the_repository->objects->commit_graph);
+ the_repository->objects->commit_graph = NULL;
}
static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
@@ -241,8 +251,12 @@ static struct commit_list **insert_parent_or_die(struct commit_graph *g,
{
struct commit *c;
struct object_id oid;
+
+ if (pos >= g->num_commits)
+ die("invalid parent position %"PRIu64, pos);
+
hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * pos);
- c = lookup_commit(&oid);
+ c = lookup_commit(the_repository, &oid);
if (!c)
die(_("could not find commit %s"), oid_to_hex(&oid));
c->graph_pos = pos;
@@ -313,28 +327,33 @@ static int find_commit_in_graph(struct commit *item, struct commit_graph *g, uin
}
}
-int parse_commit_in_graph(struct commit *item)
+static int parse_commit_in_graph_one(struct commit_graph *g, struct commit *item)
{
uint32_t pos;
- if (!core_commit_graph)
- return 0;
if (item->object.parsed)
return 1;
- prepare_commit_graph();
- if (commit_graph && find_commit_in_graph(item, commit_graph, &pos))
- return fill_commit_in_graph(item, commit_graph, pos);
+
+ if (find_commit_in_graph(item, g, &pos))
+ return fill_commit_in_graph(item, g, pos);
+
return 0;
}
-void load_commit_graph_info(struct commit *item)
+int parse_commit_in_graph(struct repository *r, struct commit *item)
+{
+ if (!prepare_commit_graph(r))
+ return 0;
+ return parse_commit_in_graph_one(r->objects->commit_graph, item);
+}
+
+void load_commit_graph_info(struct repository *r, struct commit *item)
{
uint32_t pos;
- if (!core_commit_graph)
+ if (!prepare_commit_graph(r))
return;
- prepare_commit_graph();
- if (commit_graph && find_commit_in_graph(item, commit_graph, &pos))
- fill_commit_graph_info(item, commit_graph, pos);
+ if (find_commit_in_graph(item, r->objects->commit_graph, &pos))
+ fill_commit_graph_info(item, r->objects->commit_graph, pos);
}
static struct tree *load_tree_for_commit(struct commit_graph *g, struct commit *c)
@@ -344,19 +363,25 @@ static struct tree *load_tree_for_commit(struct commit_graph *g, struct commit *
GRAPH_DATA_WIDTH * (c->graph_pos);
hashcpy(oid.hash, commit_data);
- c->maybe_tree = lookup_tree(&oid);
+ c->maybe_tree = lookup_tree(the_repository, &oid);
return c->maybe_tree;
}
-struct tree *get_commit_tree_in_graph(const struct commit *c)
+static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g,
+ const struct commit *c)
{
if (c->maybe_tree)
return c->maybe_tree;
if (c->graph_pos == COMMIT_NOT_FROM_GRAPH)
- BUG("get_commit_tree_in_graph called from non-commit-graph commit");
+ BUG("get_commit_tree_in_graph_one called from non-commit-graph commit");
- return load_tree_for_commit(commit_graph, (struct commit *)c);
+ return load_tree_for_commit(g, (struct commit *)c);
+}
+
+struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)
+{
+ return get_commit_tree_in_graph_one(r->objects->commit_graph, c);
}
static void write_graph_chunk_fanout(struct hashfile *f,
@@ -568,7 +593,7 @@ static void close_reachable(struct packed_oid_list *oids)
struct commit *commit;
for (i = 0; i < oids->nr; i++) {
- commit = lookup_commit(&oids->list[i]);
+ commit = lookup_commit(the_repository, &oids->list[i]);
if (commit)
commit->object.flags |= UNINTERESTING;
}
@@ -579,14 +604,14 @@ static void close_reachable(struct packed_oid_list *oids)
* closure.
*/
for (i = 0; i < oids->nr; i++) {
- commit = lookup_commit(&oids->list[i]);
+ commit = lookup_commit(the_repository, &oids->list[i]);
if (commit && !parse_commit(commit))
add_missing_parents(oids, commit);
}
for (i = 0; i < oids->nr; i++) {
- commit = lookup_commit(&oids->list[i]);
+ commit = lookup_commit(the_repository, &oids->list[i]);
if (commit)
commit->object.flags &= ~UNINTERESTING;
@@ -632,11 +657,28 @@ static void compute_generation_numbers(struct packed_commit_list* commits)
}
}
+static int add_ref_to_list(const char *refname,
+ const struct object_id *oid,
+ int flags, void *cb_data)
+{
+ struct string_list *list = (struct string_list *)cb_data;
+
+ string_list_append(list, oid_to_hex(oid));
+ return 0;
+}
+
+void write_commit_graph_reachable(const char *obj_dir, int append)
+{
+ struct string_list list;
+
+ string_list_init(&list, 1);
+ for_each_ref(add_ref_to_list, &list);
+ write_commit_graph(obj_dir, NULL, &list, append);
+}
+
void write_commit_graph(const char *obj_dir,
- const char **pack_indexes,
- int nr_packs,
- const char **commit_hex,
- int nr_commits,
+ struct string_list *pack_indexes,
+ struct string_list *commit_hex,
int append)
{
struct packed_oid_list oids;
@@ -655,16 +697,18 @@ void write_commit_graph(const char *obj_dir,
oids.alloc = approximate_object_count() / 4;
if (append) {
- prepare_commit_graph_one(obj_dir);
- if (commit_graph)
- oids.alloc += commit_graph->num_commits;
+ prepare_commit_graph_one(the_repository, obj_dir);
+ if (the_repository->objects->commit_graph)
+ oids.alloc += the_repository->objects->commit_graph->num_commits;
}
if (oids.alloc < 1024)
oids.alloc = 1024;
ALLOC_ARRAY(oids.list, oids.alloc);
- if (append && commit_graph) {
+ if (append && the_repository->objects->commit_graph) {
+ struct commit_graph *commit_graph =
+ the_repository->objects->commit_graph;
for (i = 0; i < commit_graph->num_commits; i++) {
const unsigned char *hash = commit_graph->chunk_oid_lookup +
commit_graph->hash_len * i;
@@ -677,10 +721,10 @@ void write_commit_graph(const char *obj_dir,
int dirlen;
strbuf_addf(&packname, "%s/pack/", obj_dir);
dirlen = packname.len;
- for (i = 0; i < nr_packs; i++) {
+ for (i = 0; i < pack_indexes->nr; i++) {
struct packed_git *p;
strbuf_setlen(&packname, dirlen);
- strbuf_addstr(&packname, pack_indexes[i]);
+ strbuf_addstr(&packname, pack_indexes->items[i].string);
p = add_packed_git(packname.buf, packname.len, 1);
if (!p)
die(_("error adding pack %s"), packname.buf);
@@ -693,15 +737,16 @@ void write_commit_graph(const char *obj_dir,
}
if (commit_hex) {
- for (i = 0; i < nr_commits; i++) {
+ for (i = 0; i < commit_hex->nr; i++) {
const char *end;
struct object_id oid;
struct commit *result;
- if (commit_hex[i] && parse_oid_hex(commit_hex[i], &oid, &end))
+ if (commit_hex->items[i].string &&
+ parse_oid_hex(commit_hex->items[i].string, &oid, &end))
continue;
- result = lookup_commit_reference_gently(&oid, 1);
+ result = lookup_commit_reference_gently(the_repository, &oid, 1);
if (result) {
ALLOC_GROW(oids.list, oids.nr + 1, oids.alloc);
@@ -737,7 +782,7 @@ void write_commit_graph(const char *obj_dir,
if (i > 0 && !oidcmp(&oids.list[i-1], &oids.list[i]))
continue;
- commits.list[commits.nr] = lookup_commit(&oids.list[i]);
+ commits.list[commits.nr] = lookup_commit(the_repository, &oids.list[i]);
parse_commit(commits.list[commits.nr]);
for (parent = commits.list[commits.nr]->parents;
@@ -808,3 +853,191 @@ void write_commit_graph(const char *obj_dir,
oids.alloc = 0;
oids.nr = 0;
}
+
+#define VERIFY_COMMIT_GRAPH_ERROR_HASH 2
+static int verify_commit_graph_error;
+
+static void graph_report(const char *fmt, ...)
+{
+ va_list ap;
+
+ verify_commit_graph_error = 1;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+#define GENERATION_ZERO_EXISTS 1
+#define GENERATION_NUMBER_EXISTS 2
+
+int verify_commit_graph(struct repository *r, struct commit_graph *g)
+{
+ uint32_t i, cur_fanout_pos = 0;
+ struct object_id prev_oid, cur_oid, checksum;
+ int generation_zero = 0;
+ struct hashfile *f;
+ int devnull;
+
+ if (!g) {
+ graph_report("no commit-graph file loaded");
+ return 1;
+ }
+
+ verify_commit_graph_error = 0;
+
+ if (!g->chunk_oid_fanout)
+ graph_report("commit-graph is missing the OID Fanout chunk");
+ if (!g->chunk_oid_lookup)
+ graph_report("commit-graph is missing the OID Lookup chunk");
+ if (!g->chunk_commit_data)
+ graph_report("commit-graph is missing the Commit Data chunk");
+
+ if (verify_commit_graph_error)
+ return verify_commit_graph_error;
+
+ devnull = open("/dev/null", O_WRONLY);
+ f = hashfd(devnull, NULL);
+ hashwrite(f, g->data, g->data_len - g->hash_len);
+ finalize_hashfile(f, checksum.hash, CSUM_CLOSE);
+ if (hashcmp(checksum.hash, g->data + g->data_len - g->hash_len)) {
+ graph_report(_("the commit-graph file has incorrect checksum and is likely corrupt"));
+ verify_commit_graph_error = VERIFY_COMMIT_GRAPH_ERROR_HASH;
+ }
+
+ for (i = 0; i < g->num_commits; i++) {
+ struct commit *graph_commit;
+
+ hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
+
+ if (i && oidcmp(&prev_oid, &cur_oid) >= 0)
+ graph_report("commit-graph has incorrect OID order: %s then %s",
+ oid_to_hex(&prev_oid),
+ oid_to_hex(&cur_oid));
+
+ oidcpy(&prev_oid, &cur_oid);
+
+ while (cur_oid.hash[0] > cur_fanout_pos) {
+ uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
+
+ if (i != fanout_value)
+ graph_report("commit-graph has incorrect fanout value: fanout[%d] = %u != %u",
+ cur_fanout_pos, fanout_value, i);
+ cur_fanout_pos++;
+ }
+
+ graph_commit = lookup_commit(r, &cur_oid);
+ if (!parse_commit_in_graph_one(g, graph_commit))
+ graph_report("failed to parse %s from commit-graph",
+ oid_to_hex(&cur_oid));
+ }
+
+ while (cur_fanout_pos < 256) {
+ uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
+
+ if (g->num_commits != fanout_value)
+ graph_report("commit-graph has incorrect fanout value: fanout[%d] = %u != %u",
+ cur_fanout_pos, fanout_value, i);
+
+ cur_fanout_pos++;
+ }
+
+ if (verify_commit_graph_error & ~VERIFY_COMMIT_GRAPH_ERROR_HASH)
+ return verify_commit_graph_error;
+
+ for (i = 0; i < g->num_commits; i++) {
+ struct commit *graph_commit, *odb_commit;
+ struct commit_list *graph_parents, *odb_parents;
+ uint32_t max_generation = 0;
+
+ hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
+
+ graph_commit = lookup_commit(r, &cur_oid);
+ odb_commit = (struct commit *)create_object(r, cur_oid.hash, alloc_commit_node(r));
+ if (parse_commit_internal(odb_commit, 0, 0)) {
+ graph_report("failed to parse %s from object database",
+ oid_to_hex(&cur_oid));
+ continue;
+ }
+
+ if (oidcmp(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,
+ get_commit_tree_oid(odb_commit)))
+ graph_report("root tree OID for commit %s in commit-graph is %s != %s",
+ oid_to_hex(&cur_oid),
+ oid_to_hex(get_commit_tree_oid(graph_commit)),
+ oid_to_hex(get_commit_tree_oid(odb_commit)));
+
+ graph_parents = graph_commit->parents;
+ odb_parents = odb_commit->parents;
+
+ while (graph_parents) {
+ if (odb_parents == NULL) {
+ graph_report("commit-graph parent list for commit %s is too long",
+ oid_to_hex(&cur_oid));
+ break;
+ }
+
+ if (oidcmp(&graph_parents->item->object.oid, &odb_parents->item->object.oid))
+ graph_report("commit-graph parent for %s is %s != %s",
+ oid_to_hex(&cur_oid),
+ oid_to_hex(&graph_parents->item->object.oid),
+ oid_to_hex(&odb_parents->item->object.oid));
+
+ if (graph_parents->item->generation > max_generation)
+ max_generation = graph_parents->item->generation;
+
+ graph_parents = graph_parents->next;
+ odb_parents = odb_parents->next;
+ }
+
+ if (odb_parents != NULL)
+ graph_report("commit-graph parent list for commit %s terminates early",
+ oid_to_hex(&cur_oid));
+
+ if (!graph_commit->generation) {
+ if (generation_zero == GENERATION_NUMBER_EXISTS)
+ graph_report("commit-graph has generation number zero for commit %s, but non-zero elsewhere",
+ oid_to_hex(&cur_oid));
+ generation_zero = GENERATION_ZERO_EXISTS;
+ } else if (generation_zero == GENERATION_ZERO_EXISTS)
+ graph_report("commit-graph has non-zero generation number for commit %s, but zero elsewhere",
+ oid_to_hex(&cur_oid));
+
+ if (generation_zero == GENERATION_ZERO_EXISTS)
+ continue;
+
+ /*
+ * If one of our parents has generation GENERATION_NUMBER_MAX, then
+ * our generation is also GENERATION_NUMBER_MAX. Decrement to avoid
+ * extra logic in the following condition.
+ */
+ if (max_generation == GENERATION_NUMBER_MAX)
+ max_generation--;
+
+ if (graph_commit->generation != max_generation + 1)
+ graph_report("commit-graph generation for commit %s is %u != %u",
+ oid_to_hex(&cur_oid),
+ graph_commit->generation,
+ max_generation + 1);
+
+ if (graph_commit->date != odb_commit->date)
+ graph_report("commit date for commit %s in commit-graph is %"PRItime" != %"PRItime,
+ oid_to_hex(&cur_oid),
+ graph_commit->date,
+ odb_commit->date);
+ }
+
+ return verify_commit_graph_error;
+}
+
+void free_commit_graph(struct commit_graph *g)
+{
+ if (!g)
+ return;
+ if (g->graph_fd >= 0) {
+ munmap((void *)g->data, g->data_len);
+ g->data = NULL;
+ close(g->graph_fd);
+ }
+ free(g);
+}
diff --git a/commit-graph.h b/commit-graph.h
index 96cccb1..76e0989 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -2,6 +2,10 @@
#define COMMIT_GRAPH_H
#include "git-compat-util.h"
+#include "repository.h"
+#include "string-list.h"
+
+struct commit;
char *get_commit_graph_filename(const char *obj_dir);
@@ -15,7 +19,7 @@ char *get_commit_graph_filename(const char *obj_dir);
*
* See parse_commit_buffer() for the fallback after this call.
*/
-int parse_commit_in_graph(struct commit *item);
+int parse_commit_in_graph(struct repository *r, struct commit *item);
/*
* It is possible that we loaded commit contents from the commit buffer,
@@ -23,9 +27,10 @@ int parse_commit_in_graph(struct commit *item);
* checked and filled. Fill the graph_pos and generation members of
* the given commit.
*/
-void load_commit_graph_info(struct commit *item);
+void load_commit_graph_info(struct repository *r, struct commit *item);
-struct tree *get_commit_tree_in_graph(const struct commit *c);
+struct tree *get_commit_tree_in_graph(struct repository *r,
+ const struct commit *c);
struct commit_graph {
int graph_fd;
@@ -46,11 +51,14 @@ struct commit_graph {
struct commit_graph *load_commit_graph_one(const char *graph_file);
+void write_commit_graph_reachable(const char *obj_dir, int append);
void write_commit_graph(const char *obj_dir,
- const char **pack_indexes,
- int nr_packs,
- const char **commit_hex,
- int nr_commits,
+ struct string_list *pack_indexes,
+ struct string_list *commit_hex,
int append);
+int verify_commit_graph(struct repository *r, struct commit_graph *g);
+
+void free_commit_graph(struct commit_graph *);
+
#endif
diff --git a/commit-slab-impl.h b/commit-slab-impl.h
index 87a9cad..ac1e6d4 100644
--- a/commit-slab-impl.h
+++ b/commit-slab-impl.h
@@ -11,8 +11,6 @@
#define implement_commit_slab(slabname, elemtype, scope) \
\
-static int stat_ ##slabname## realloc; \
- \
scope void init_ ##slabname## _with_stride(struct slabname *s, \
unsigned stride) \
{ \
@@ -54,7 +52,6 @@ scope elemtype *slabname## _at_peek(struct slabname *s, \
if (!add_if_missing) \
return NULL; \
REALLOC_ARRAY(s->slab, nth_slab + 1); \
- stat_ ##slabname## realloc++; \
for (i = s->slab_count; i <= nth_slab; i++) \
s->slab[i] = NULL; \
s->slab_count = nth_slab + 1; \
diff --git a/commit.c b/commit.c
index 0c3b75a..30d1af2 100644
--- a/commit.c
+++ b/commit.c
@@ -2,6 +2,8 @@
#include "tag.h"
#include "commit.h"
#include "commit-graph.h"
+#include "repository.h"
+#include "object-store.h"
#include "pkt-line.h"
#include "utf8.h"
#include "diff.h"
@@ -22,24 +24,26 @@ int save_commit_buffer = 1;
const char *commit_type = "commit";
-struct commit *lookup_commit_reference_gently(const struct object_id *oid,
- int quiet)
+struct commit *lookup_commit_reference_gently(struct repository *r,
+ const struct object_id *oid, int quiet)
{
- struct object *obj = deref_tag(parse_object(oid), NULL, 0);
+ struct object *obj = deref_tag(r,
+ parse_object(r, oid),
+ NULL, 0);
if (!obj)
return NULL;
- return object_as_type(obj, OBJ_COMMIT, quiet);
+ return object_as_type(r, obj, OBJ_COMMIT, quiet);
}
-struct commit *lookup_commit_reference(const struct object_id *oid)
+struct commit *lookup_commit_reference(struct repository *r, const struct object_id *oid)
{
- return lookup_commit_reference_gently(oid, 0);
+ return lookup_commit_reference_gently(r, oid, 0);
}
struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name)
{
- struct commit *c = lookup_commit_reference(oid);
+ struct commit *c = lookup_commit_reference(the_repository, oid);
if (!c)
die(_("could not parse %s"), ref_name);
if (oidcmp(oid, &c->object.oid)) {
@@ -49,13 +53,13 @@ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref
return c;
}
-struct commit *lookup_commit(const struct object_id *oid)
+struct commit *lookup_commit(struct repository *r, const struct object_id *oid)
{
- struct object *obj = lookup_object(oid->hash);
+ struct object *obj = lookup_object(r, oid->hash);
if (!obj)
- return create_object(the_repository, oid->hash,
- alloc_commit_node(the_repository));
- return object_as_type(obj, OBJ_COMMIT, 0);
+ return create_object(r, oid->hash,
+ alloc_commit_node(r));
+ return object_as_type(r, obj, OBJ_COMMIT, 0);
}
struct commit *lookup_commit_reference_by_name(const char *name)
@@ -65,7 +69,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
if (get_oid_committish(name, &oid))
return NULL;
- commit = lookup_commit_reference(&oid);
+ commit = lookup_commit_reference(the_repository, &oid);
if (parse_commit(commit))
return NULL;
return commit;
@@ -98,41 +102,44 @@ static timestamp_t parse_commit_date(const char *buf, const char *tail)
return parse_timestamp(dateptr, NULL, 10);
}
-static struct commit_graft **commit_graft;
-static int commit_graft_alloc, commit_graft_nr;
-
static const unsigned char *commit_graft_sha1_access(size_t index, void *table)
{
struct commit_graft **commit_graft_table = table;
return commit_graft_table[index]->oid.hash;
}
-static int commit_graft_pos(const unsigned char *sha1)
+static int commit_graft_pos(struct repository *r, const unsigned char *sha1)
{
- return sha1_pos(sha1, commit_graft, commit_graft_nr,
+ return sha1_pos(sha1, r->parsed_objects->grafts,
+ r->parsed_objects->grafts_nr,
commit_graft_sha1_access);
}
-int register_commit_graft(struct commit_graft *graft, int ignore_dups)
+int register_commit_graft(struct repository *r, struct commit_graft *graft,
+ int ignore_dups)
{
- int pos = commit_graft_pos(graft->oid.hash);
+ int pos = commit_graft_pos(r, graft->oid.hash);
if (0 <= pos) {
if (ignore_dups)
free(graft);
else {
- free(commit_graft[pos]);
- commit_graft[pos] = graft;
+ free(r->parsed_objects->grafts[pos]);
+ r->parsed_objects->grafts[pos] = graft;
}
return 1;
}
pos = -pos - 1;
- ALLOC_GROW(commit_graft, commit_graft_nr + 1, commit_graft_alloc);
- commit_graft_nr++;
- if (pos < commit_graft_nr)
- MOVE_ARRAY(commit_graft + pos + 1, commit_graft + pos,
- commit_graft_nr - pos - 1);
- commit_graft[pos] = graft;
+ ALLOC_GROW(r->parsed_objects->grafts,
+ r->parsed_objects->grafts_nr + 1,
+ r->parsed_objects->grafts_alloc);
+ r->parsed_objects->grafts_nr++;
+ if (pos < r->parsed_objects->grafts_nr)
+ memmove(r->parsed_objects->grafts + pos + 1,
+ r->parsed_objects->grafts + pos,
+ (r->parsed_objects->grafts_nr - pos - 1) *
+ sizeof(*r->parsed_objects->grafts));
+ r->parsed_objects->grafts[pos] = graft;
return 0;
}
@@ -174,7 +181,7 @@ bad_graft_data:
return NULL;
}
-static int read_graft_file(const char *graft_file)
+static int read_graft_file(struct repository *r, const char *graft_file)
{
FILE *fp = fopen_or_warn(graft_file, "r");
struct strbuf buf = STRBUF_INIT;
@@ -194,7 +201,7 @@ static int read_graft_file(const char *graft_file)
struct commit_graft *graft = read_graft_line(&buf);
if (!graft)
continue;
- if (register_commit_graft(graft, 1))
+ if (register_commit_graft(r, graft, 1))
error("duplicate graft data: %s", buf.buf);
}
fclose(fp);
@@ -202,50 +209,50 @@ static int read_graft_file(const char *graft_file)
return 0;
}
-static void prepare_commit_graft(void)
+static void prepare_commit_graft(struct repository *r)
{
- static int commit_graft_prepared;
char *graft_file;
- if (commit_graft_prepared)
+ if (r->parsed_objects->commit_graft_prepared)
return;
if (!startup_info->have_repository)
return;
- graft_file = get_graft_file();
- read_graft_file(graft_file);
+ graft_file = get_graft_file(r);
+ read_graft_file(r, graft_file);
/* make sure shallows are read */
- is_repository_shallow();
- commit_graft_prepared = 1;
+ is_repository_shallow(r);
+ r->parsed_objects->commit_graft_prepared = 1;
}
-struct commit_graft *lookup_commit_graft(const struct object_id *oid)
+struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid)
{
int pos;
- prepare_commit_graft();
- pos = commit_graft_pos(oid->hash);
+ prepare_commit_graft(r);
+ pos = commit_graft_pos(r, oid->hash);
if (pos < 0)
return NULL;
- return commit_graft[pos];
+ return r->parsed_objects->grafts[pos];
}
int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
{
int i, ret;
- for (i = ret = 0; i < commit_graft_nr && !ret; i++)
- ret = fn(commit_graft[i], cb_data);
+ for (i = ret = 0; i < the_repository->parsed_objects->grafts_nr && !ret; i++)
+ ret = fn(the_repository->parsed_objects->grafts[i], cb_data);
return ret;
}
int unregister_shallow(const struct object_id *oid)
{
- int pos = commit_graft_pos(oid->hash);
+ int pos = commit_graft_pos(the_repository, oid->hash);
if (pos < 0)
return -1;
- if (pos + 1 < commit_graft_nr)
- MOVE_ARRAY(commit_graft + pos, commit_graft + pos + 1,
- commit_graft_nr - pos - 1);
- commit_graft_nr--;
+ if (pos + 1 < the_repository->parsed_objects->grafts_nr)
+ MOVE_ARRAY(the_repository->parsed_objects->grafts + pos,
+ the_repository->parsed_objects->grafts + pos + 1,
+ the_repository->parsed_objects->grafts_nr - pos - 1);
+ the_repository->parsed_objects->grafts_nr--;
return 0;
}
@@ -254,18 +261,32 @@ struct commit_buffer {
unsigned long size;
};
define_commit_slab(buffer_slab, struct commit_buffer);
-static struct buffer_slab buffer_slab = COMMIT_SLAB_INIT(1, buffer_slab);
-void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size)
+struct buffer_slab *allocate_commit_buffer_slab(void)
+{
+ struct buffer_slab *bs = xmalloc(sizeof(*bs));
+ init_buffer_slab(bs);
+ return bs;
+}
+
+void free_commit_buffer_slab(struct buffer_slab *bs)
+{
+ clear_buffer_slab(bs);
+ free(bs);
+}
+
+void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, unsigned long size)
{
- struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ struct commit_buffer *v = buffer_slab_at(
+ r->parsed_objects->buffer_slab, commit);
v->buffer = buffer;
v->size = size;
}
-const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep)
+const void *get_cached_commit_buffer(struct repository *r, const struct commit *commit, unsigned long *sizep)
{
- struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
+ struct commit_buffer *v = buffer_slab_peek(
+ r->parsed_objects->buffer_slab, commit);
if (!v) {
if (sizep)
*sizep = 0;
@@ -278,7 +299,7 @@ const void *get_cached_commit_buffer(const struct commit *commit, unsigned long
const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
{
- const void *ret = get_cached_commit_buffer(commit, sizep);
+ const void *ret = get_cached_commit_buffer(the_repository, commit, sizep);
if (!ret) {
enum object_type type;
unsigned long size;
@@ -297,14 +318,16 @@ const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
void unuse_commit_buffer(const struct commit *commit, const void *buffer)
{
- struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
+ struct commit_buffer *v = buffer_slab_peek(
+ the_repository->parsed_objects->buffer_slab, commit);
if (!(v && v->buffer == buffer))
free((void *)buffer);
}
void free_commit_buffer(struct commit *commit)
{
- struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
+ struct commit_buffer *v = buffer_slab_peek(
+ the_repository->parsed_objects->buffer_slab, commit);
if (v) {
FREE_AND_NULL(v->buffer);
v->size = 0;
@@ -319,7 +342,7 @@ struct tree *get_commit_tree(const struct commit *commit)
if (commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
BUG("commit has NULL tree, but was not loaded from commit-graph");
- return get_commit_tree_in_graph(commit);
+ return get_commit_tree_in_graph(the_repository, commit);
}
struct object_id *get_commit_tree_oid(const struct commit *commit)
@@ -340,7 +363,8 @@ void release_commit_memory(struct commit *c)
const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
{
- struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
+ struct commit_buffer *v = buffer_slab_peek(
+ the_repository->parsed_objects->buffer_slab, commit);
void *ret;
if (!v) {
@@ -357,15 +381,15 @@ const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
return ret;
}
-int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size, int check_graph)
+int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph)
{
const char *tail = buffer;
const char *bufptr = buffer;
struct object_id parent;
struct commit_list **pptr;
struct commit_graft *graft;
- const int tree_entry_len = GIT_SHA1_HEXSZ + 5;
- const int parent_entry_len = GIT_SHA1_HEXSZ + 7;
+ const int tree_entry_len = the_hash_algo->hexsz + 5;
+ const int parent_entry_len = the_hash_algo->hexsz + 7;
if (item->object.parsed)
return 0;
@@ -377,11 +401,11 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
if (get_oid_hex(bufptr + 5, &parent) < 0)
return error("bad tree pointer in commit %s",
oid_to_hex(&item->object.oid));
- item->maybe_tree = lookup_tree(&parent);
+ item->maybe_tree = lookup_tree(r, &parent);
bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
pptr = &item->parents;
- graft = lookup_commit_graft(&item->object.oid);
+ graft = lookup_commit_graft(r, &item->object.oid);
while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
struct commit *new_parent;
@@ -396,7 +420,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
*/
if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
continue;
- new_parent = lookup_commit(&parent);
+ new_parent = lookup_commit(r, &parent);
if (new_parent)
pptr = &commit_list_insert(new_parent, pptr)->next;
}
@@ -404,7 +428,8 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
int i;
struct commit *new_parent;
for (i = 0; i < graft->nr_parent; i++) {
- new_parent = lookup_commit(&graft->parent[i]);
+ new_parent = lookup_commit(r,
+ &graft->parent[i]);
if (!new_parent)
continue;
pptr = &commit_list_insert(new_parent, pptr)->next;
@@ -413,12 +438,12 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
item->date = parse_commit_date(bufptr, tail);
if (check_graph)
- load_commit_graph_info(item);
+ load_commit_graph_info(the_repository, item);
return 0;
}
-int parse_commit_gently(struct commit *item, int quiet_on_missing)
+int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph)
{
enum object_type type;
void *buffer;
@@ -429,7 +454,7 @@ int parse_commit_gently(struct commit *item, int quiet_on_missing)
return -1;
if (item->object.parsed)
return 0;
- if (parse_commit_in_graph(item))
+ if (use_commit_graph && parse_commit_in_graph(the_repository, item))
return 0;
buffer = read_object_file(&item->object.oid, &type, &size);
if (!buffer)
@@ -441,15 +466,21 @@ int parse_commit_gently(struct commit *item, int quiet_on_missing)
return error("Object %s not a commit",
oid_to_hex(&item->object.oid));
}
- ret = parse_commit_buffer(item, buffer, size, 0);
+
+ ret = parse_commit_buffer(the_repository, item, buffer, size, 0);
if (save_commit_buffer && !ret) {
- set_commit_buffer(item, buffer, size);
+ set_commit_buffer(the_repository, item, buffer, size);
return 0;
}
free(buffer);
return ret;
}
+int parse_commit_gently(struct commit *item, int quiet_on_missing)
+{
+ return parse_commit_internal(item, quiet_on_missing, 1);
+}
+
void parse_commit_or_die(struct commit *item)
{
if (parse_commit(item))
@@ -1687,7 +1718,7 @@ struct commit *get_merge_parent(const char *name)
struct object_id oid;
if (get_oid(name, &oid))
return NULL;
- obj = parse_object(&oid);
+ obj = parse_object(the_repository, &oid);
commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
if (commit && !merge_remote_util(commit))
set_merge_remote_desc(commit, name, obj);
diff --git a/commit.h b/commit.h
index 3ad07c2..da0db36 100644
--- a/commit.h
+++ b/commit.h
@@ -63,9 +63,11 @@ enum decoration_type {
void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);
const struct name_decoration *get_name_decoration(const struct object *obj);
-struct commit *lookup_commit(const struct object_id *oid);
-struct commit *lookup_commit_reference(const struct object_id *oid);
-struct commit *lookup_commit_reference_gently(const struct object_id *oid,
+struct commit *lookup_commit(struct repository *r, const struct object_id *oid);
+struct commit *lookup_commit_reference(struct repository *r,
+ const struct object_id *oid);
+struct commit *lookup_commit_reference_gently(struct repository *r,
+ const struct object_id *oid,
int quiet);
struct commit *lookup_commit_reference_by_name(const char *name);
@@ -76,7 +78,8 @@ struct commit *lookup_commit_reference_by_name(const char *name);
*/
struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name);
-int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size, int check_graph);
+int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph);
+int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph);
int parse_commit_gently(struct commit *item, int quiet_on_missing);
static inline int parse_commit(struct commit *item)
{
@@ -84,17 +87,21 @@ static inline int parse_commit(struct commit *item)
}
void parse_commit_or_die(struct commit *item);
+struct buffer_slab;
+struct buffer_slab *allocate_commit_buffer_slab(void);
+void free_commit_buffer_slab(struct buffer_slab *bs);
+
/*
* Associate an object buffer with the commit. The ownership of the
* memory is handed over to the commit, and must be free()-able.
*/
-void set_commit_buffer(struct commit *, void *buffer, unsigned long size);
+void set_commit_buffer(struct repository *r, struct commit *, void *buffer, unsigned long size);
/*
* Get any cached object buffer associated with the commit. Returns NULL
* if none. The resulting memory should not be freed.
*/
-const void *get_cached_commit_buffer(const struct commit *, unsigned long *size);
+const void *get_cached_commit_buffer(struct repository *, const struct commit *, unsigned long *size);
/*
* Get the commit's object contents, either from cache or by reading the object
@@ -194,8 +201,8 @@ struct commit_graft {
typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
struct commit_graft *read_graft_line(struct strbuf *line);
-int register_commit_graft(struct commit_graft *, int);
-struct commit_graft *lookup_commit_graft(const struct object_id *oid);
+int register_commit_graft(struct repository *r, struct commit_graft *, int);
+struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2);
extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos);
@@ -209,15 +216,15 @@ extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n,
struct oid_array;
struct ref;
-extern int register_shallow(const struct object_id *oid);
+extern int register_shallow(struct repository *r, const struct object_id *oid);
extern int unregister_shallow(const struct object_id *oid);
extern int for_each_commit_graft(each_commit_graft_fn, void *);
-extern int is_repository_shallow(void);
+extern int is_repository_shallow(struct repository *r);
extern struct commit_list *get_shallow_commits(struct object_array *heads,
int depth, int shallow_flag, int not_shallow_flag);
extern struct commit_list *get_shallow_commits_by_rev_list(
int ac, const char **av, int shallow_flag, int not_shallow_flag);
-extern void set_alternate_shallow_file(const char *path, int override);
+extern void set_alternate_shallow_file(struct repository *r, const char *path, int override);
extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
const struct oid_array *extra);
extern void setup_alternate_shallow(struct lock_file *shallow_lock,
diff --git a/compat/vcbuild/README b/compat/vcbuild/README
index df8a657..60fd873 100644
--- a/compat/vcbuild/README
+++ b/compat/vcbuild/README
@@ -30,8 +30,8 @@ The Steps of Build Git with VS2008
the git operations.
3. Inside Git's directory run the command:
- make common-cmds.h
- to generate the common-cmds.h file needed to compile git.
+ make command-list.h
+ to generate the command-list.h file needed to compile git.
4. Then either build Git with the GNU Make Makefile in the Git projects
root
diff --git a/config.c b/config.c
index 736b9f2..10522f3 100644
--- a/config.c
+++ b/config.c
@@ -14,6 +14,7 @@
#include "quote.h"
#include "hashmap.h"
#include "string-list.h"
+#include "object-store.h"
#include "utf8.h"
#include "dir.h"
#include "color.h"
@@ -31,7 +32,7 @@ struct config_source {
enum config_origin_type origin_type;
const char *name;
const char *path;
- int die_on_error;
+ enum config_error_action default_error_action;
int linenr;
int eof;
struct strbuf value;
@@ -809,10 +810,21 @@ static int git_parse_source(config_fn_t fn, void *data,
cf->linenr, cf->name);
}
- if (cf->die_on_error)
+ switch (opts && opts->error_action ?
+ opts->error_action :
+ cf->default_error_action) {
+ case CONFIG_ERROR_DIE:
die("%s", error_msg);
- else
+ break;
+ case CONFIG_ERROR_ERROR:
error_return = error("%s", error_msg);
+ break;
+ case CONFIG_ERROR_SILENT:
+ error_return = -1;
+ break;
+ case CONFIG_ERROR_UNSET:
+ BUG("config error action unset");
+ }
free(error_msg);
return error_return;
@@ -1308,11 +1320,6 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}
- if (!strcmp(var, "core.commitgraph")) {
- core_commit_graph = git_config_bool(var, value);
- return 0;
- }
-
if (!strcmp(var, "core.sparsecheckout")) {
core_apply_sparse_checkout = git_config_bool(var, value);
return 0;
@@ -1346,6 +1353,11 @@ static int git_default_core_config(const char *var, const char *value)
var, value);
}
+ if (!strcmp(var, "core.usereplacerefs")) {
+ read_replace_refs = git_config_bool(var, value);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
@@ -1520,7 +1532,7 @@ static int do_config_from_file(config_fn_t fn,
top.origin_type = origin_type;
top.name = name;
top.path = path;
- top.die_on_error = 1;
+ top.default_error_action = CONFIG_ERROR_DIE;
top.do_fgetc = config_file_fgetc;
top.do_ungetc = config_file_ungetc;
top.do_ftell = config_file_ftell;
@@ -1558,8 +1570,10 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
return git_config_from_file_with_options(fn, filename, data, NULL);
}
-int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_type,
- const char *name, const char *buf, size_t len, void *data)
+int git_config_from_mem(config_fn_t fn,
+ const enum config_origin_type origin_type,
+ const char *name, const char *buf, size_t len,
+ void *data, const struct config_options *opts)
{
struct config_source top;
@@ -1569,12 +1583,12 @@ int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_typ
top.origin_type = origin_type;
top.name = name;
top.path = NULL;
- top.die_on_error = 0;
+ top.default_error_action = CONFIG_ERROR_ERROR;
top.do_fgetc = config_buf_fgetc;
top.do_ungetc = config_buf_ungetc;
top.do_ftell = config_buf_ftell;
- return do_config_from(&top, fn, data, NULL);
+ return do_config_from(&top, fn, data, opts);
}
int git_config_from_blob_oid(config_fn_t fn,
@@ -1595,7 +1609,8 @@ int git_config_from_blob_oid(config_fn_t fn,
return error(_("reference '%s' does not point to a blob"), name);
}
- ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size, data);
+ ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size,
+ data, NULL);
free(buf);
return ret;
@@ -2172,23 +2187,6 @@ int git_config_get_pathname(const char *key, const char **dest)
return repo_config_get_pathname(the_repository, key, dest);
}
-/*
- * Note: This function exists solely to maintain backward compatibility with
- * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should
- * NOT be used anywhere else.
- *
- * Runs the provided config function on the '.gitmodules' file found in the
- * working directory.
- */
-void config_from_gitmodules(config_fn_t fn, void *data)
-{
- if (the_repository->worktree) {
- char *file = repo_worktree_path(the_repository, GITMODULES_FILE);
- git_config_from_file(fn, file, data);
- free(file);
- }
-}
-
int git_config_get_expiry(const char *key, const char **output)
{
int ret = git_config_get_string_const(key, output);
diff --git a/config.h b/config.h
index 626d465..bb2f506 100644
--- a/config.h
+++ b/config.h
@@ -54,6 +54,12 @@ struct config_options {
const char *git_dir;
config_parser_event_fn_t event_fn;
void *event_fn_data;
+ enum config_error_action {
+ CONFIG_ERROR_UNSET = 0, /* use source-specific default */
+ CONFIG_ERROR_DIE, /* die() on error */
+ CONFIG_ERROR_ERROR, /* error() on error, return -1 */
+ CONFIG_ERROR_SILENT, /* return -1 */
+ } error_action;
};
typedef int (*config_fn_t)(const char *, const char *, void *);
@@ -62,8 +68,11 @@ extern int git_config_from_file(config_fn_t fn, const char *, void *);
extern int git_config_from_file_with_options(config_fn_t fn, const char *,
void *,
const struct config_options *);
-extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
- const char *name, const char *buf, size_t len, void *data);
+extern int git_config_from_mem(config_fn_t fn,
+ const enum config_origin_type,
+ const char *name,
+ const char *buf, size_t len,
+ void *data, const struct config_options *opts);
extern int git_config_from_blob_oid(config_fn_t fn, const char *name,
const struct object_id *oid, void *data);
extern void git_config_push_parameter(const char *text);
@@ -215,16 +224,6 @@ extern int repo_config_get_maybe_bool(struct repository *repo,
extern int repo_config_get_pathname(struct repository *repo,
const char *key, const char **dest);
-/*
- * Note: This function exists solely to maintain backward compatibility with
- * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should
- * NOT be used anywhere else.
- *
- * Runs the provided config function on the '.gitmodules' file found in the
- * working directory.
- */
-extern void config_from_gitmodules(config_fn_t fn, void *data);
-
extern int git_config_get_value(const char *key, const char **value);
extern const struct string_list *git_config_get_value_multi(const char *key);
extern void git_config_clear(void);
diff --git a/config.mak.dev b/config.mak.dev
index 2d244ca..9a99814 100644
--- a/config.mak.dev
+++ b/config.mak.dev
@@ -1,6 +1,11 @@
ifeq ($(filter no-error,$(DEVOPTS)),)
CFLAGS += -Werror
endif
+ifneq ($(filter pedantic,$(DEVOPTS)),)
+CFLAGS += -pedantic
+# don't warn for each N_ use
+CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=0
+endif
CFLAGS += -Wdeclaration-after-statement
CFLAGS += -Wno-format-zero-length
CFLAGS += -Wold-style-definition
diff --git a/connect.h b/connect.h
index 0e69c67..32aff60 100644
--- a/connect.h
+++ b/connect.h
@@ -1,6 +1,8 @@
#ifndef CONNECT_H
#define CONNECT_H
+#include "protocol.h"
+
#define CONNECT_VERBOSE (1u << 0)
#define CONNECT_DIAG_URL (1u << 1)
#define CONNECT_IPV4 (1u << 2)
diff --git a/connected.c b/connected.c
index 91feb78..1bba888 100644
--- a/connected.c
+++ b/connected.c
@@ -58,8 +58,10 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
argv_array_push(&rev_list.args, "--stdin");
if (repository_format_partial_clone)
argv_array_push(&rev_list.args, "--exclude-promisor-objects");
- argv_array_push(&rev_list.args, "--not");
- argv_array_push(&rev_list.args, "--all");
+ if (!opt->is_deepening_fetch) {
+ argv_array_push(&rev_list.args, "--not");
+ argv_array_push(&rev_list.args, "--all");
+ }
argv_array_push(&rev_list.args, "--quiet");
if (opt->progress)
argv_array_pushf(&rev_list.args, "--progress=%s",
diff --git a/connected.h b/connected.h
index a53f03a..322dc76 100644
--- a/connected.h
+++ b/connected.h
@@ -38,6 +38,13 @@ struct check_connected_options {
* Insert these variables into the environment of the child process.
*/
const char **env;
+
+ /*
+ * If non-zero, check the ancestry chain completely, not stopping at
+ * any existing ref. This is necessary when deepening existing refs
+ * during a fetch.
+ */
+ unsigned is_deepening_fetch : 1;
};
#define CHECK_CONNECTED_INIT { 0 }
diff --git a/contrib/coccinelle/commit.cocci b/contrib/coccinelle/commit.cocci
index a7e9215..aec3345 100644
--- a/contrib/coccinelle/commit.cocci
+++ b/contrib/coccinelle/commit.cocci
@@ -12,7 +12,7 @@ expression c;
// These excluded functions must access c->maybe_tree direcly.
@@
-identifier f !~ "^(get_commit_tree|get_commit_tree_in_graph|load_tree_for_commit)$";
+identifier f !~ "^(get_commit_tree|get_commit_tree_in_graph_one|load_tree_for_commit)$";
expression c;
@@
f(...) {...
diff --git a/contrib/git-jump/README b/contrib/git-jump/README
index 4484bda..2f618a7 100644
--- a/contrib/git-jump/README
+++ b/contrib/git-jump/README
@@ -25,6 +25,13 @@ git-jump will feed this to the editor:
foo.c:2: printf("hello word!\n");
-----------------------------------
+Or, when running 'git jump grep', column numbers will also be emitted,
+e.g. `git jump grep "hello"` would return:
+
+-----------------------------------
+foo.c:2:9: printf("hello word!\n");
+-----------------------------------
+
Obviously this trivial case isn't that interesting; you could just open
`foo.c` yourself. But when you have many changes scattered across a
project, you can use the editor's support to "jump" from point to point.
@@ -35,7 +42,8 @@ Git-jump can generate four types of interesting lists:
2. The beginning of any merge conflict markers.
- 3. Any grep matches.
+ 3. Any grep matches, including the column of the first match on a
+ line.
4. Any whitespace errors detected by `git diff --check`.
@@ -82,7 +90,7 @@ which does something similar to `git jump grep`. However, it is limited
to positioning the cursor to the correct line in only the first file,
leaving you to locate subsequent hits in that file or other files using
the editor or pager. By contrast, git-jump provides the editor with a
-complete list of files and line numbers for each match.
+complete list of files, lines, and a column number for each match.
Limitations
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index 80ab059..931b0fe 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -52,7 +52,7 @@ mode_merge() {
# editor shows them to us in the status bar.
mode_grep() {
cmd=$(git config jump.grepCmd)
- test -n "$cmd" || cmd="git grep -n"
+ test -n "$cmd" || cmd="git grep -n --column"
$cmd "$@" |
perl -pe '
s/[ \t]+/ /g;
diff --git a/convert.c b/convert.c
index e53911d..3ee4bc2 100644
--- a/convert.c
+++ b/convert.c
@@ -1,6 +1,7 @@
#define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "config.h"
+#include "object-store.h"
#include "attr.h"
#include "run-command.h"
#include "quote.h"
@@ -334,7 +335,7 @@ static void trace_encoding(const char *context, const char *path,
strbuf_addf(&trace, "%s (%s, considered %s):\n", context, path, encoding);
for (i = 0; i < len && buf; ++i) {
strbuf_addf(
- &trace,"| \e[2m%2i:\e[0m %2x \e[2m%c\e[0m%c",
+ &trace, "| \033[2m%2i:\033[0m %2x \033[2m%c\033[0m%c",
i,
(unsigned char) buf[i],
(buf[i] > 32 && buf[i] < 127 ? buf[i] : ' '),
diff --git a/diff-lib.c b/diff-lib.c
index a9f38eb..732f684 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -520,6 +520,9 @@ int run_diff_index(struct rev_info *revs, int cached)
struct object_array_entry *ent;
uint64_t start = getnanotime();
+ if (revs->pending.nr != 1)
+ BUG("run_diff_index must be passed exactly one tree");
+
ent = revs->pending.objects;
if (diff_cache(revs, &ent->item->oid, ent->name, cached))
exit(128);
diff --git a/diff.c b/diff.c
index b70eb79..f830afa 100644
--- a/diff.c
+++ b/diff.c
@@ -13,6 +13,7 @@
#include "attr.h"
#include "run-command.h"
#include "utf8.h"
+#include "object-store.h"
#include "userdiff.h"
#include "submodule-config.h"
#include "submodule.h"
@@ -36,6 +37,7 @@ static int diff_rename_limit_default = 400;
static int diff_suppress_blank_empty;
static int diff_use_color_default = -1;
static int diff_color_moved_default;
+static int diff_color_moved_ws_default;
static int diff_context_default = 3;
static int diff_interhunk_context_default;
static const char *diff_word_regex_cfg;
@@ -263,14 +265,54 @@ static int parse_color_moved(const char *arg)
return COLOR_MOVED_NO;
else if (!strcmp(arg, "plain"))
return COLOR_MOVED_PLAIN;
+ else if (!strcmp(arg, "blocks"))
+ return COLOR_MOVED_BLOCKS;
else if (!strcmp(arg, "zebra"))
return COLOR_MOVED_ZEBRA;
else if (!strcmp(arg, "default"))
return COLOR_MOVED_DEFAULT;
+ else if (!strcmp(arg, "dimmed-zebra"))
+ return COLOR_MOVED_ZEBRA_DIM;
else if (!strcmp(arg, "dimmed_zebra"))
return COLOR_MOVED_ZEBRA_DIM;
else
- return error(_("color moved setting must be one of 'no', 'default', 'zebra', 'dimmed_zebra', 'plain'"));
+ return error(_("color moved setting must be one of 'no', 'default', 'blocks', 'zebra', 'dimmed-zebra', 'plain'"));
+}
+
+static int parse_color_moved_ws(const char *arg)
+{
+ int ret = 0;
+ struct string_list l = STRING_LIST_INIT_DUP;
+ struct string_list_item *i;
+
+ string_list_split(&l, arg, ',', -1);
+
+ for_each_string_list_item(i, &l) {
+ struct strbuf sb = STRBUF_INIT;
+ strbuf_addstr(&sb, i->string);
+ strbuf_trim(&sb);
+
+ if (!strcmp(sb.buf, "ignore-space-change"))
+ ret |= XDF_IGNORE_WHITESPACE_CHANGE;
+ else if (!strcmp(sb.buf, "ignore-space-at-eol"))
+ ret |= XDF_IGNORE_WHITESPACE_AT_EOL;
+ else if (!strcmp(sb.buf, "ignore-all-space"))
+ ret |= XDF_IGNORE_WHITESPACE;
+ else if (!strcmp(sb.buf, "allow-indentation-change"))
+ ret |= COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE;
+ else
+ error(_("ignoring unknown color-moved-ws mode '%s'"), sb.buf);
+
+ strbuf_release(&sb);
+ }
+
+ if ((ret & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) &&
+ (ret & XDF_WHITESPACE_FLAGS))
+ die(_("color-moved-ws: allow-indentation-change cannot be combined with other white space modes"));
+
+ string_list_clear(&l, 0);
+
+ return ret;
}
int git_diff_ui_config(const char *var, const char *value, void *cb)
@@ -286,6 +328,13 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
diff_color_moved_default = cm;
return 0;
}
+ if (!strcmp(var, "diff.colormovedws")) {
+ int cm = parse_color_moved_ws(value);
+ if (cm < 0)
+ return -1;
+ diff_color_moved_ws_default = cm;
+ return 0;
+ }
if (!strcmp(var, "diff.context")) {
diff_context_default = git_config_int(var, value);
if (diff_context_default < 0)
@@ -697,16 +746,116 @@ struct moved_entry {
struct hashmap_entry ent;
const struct emitted_diff_symbol *es;
struct moved_entry *next_line;
+ struct ws_delta *wsd;
};
-static int moved_entry_cmp(const struct diff_options *diffopt,
- const struct moved_entry *a,
- const struct moved_entry *b,
+/**
+ * The struct ws_delta holds white space differences between moved lines, i.e.
+ * between '+' and '-' lines that have been detected to be a move.
+ * The string contains the difference in leading white spaces, before the
+ * rest of the line is compared using the white space config for move
+ * coloring. The current_longer indicates if the first string in the
+ * comparision is longer than the second.
+ */
+struct ws_delta {
+ char *string;
+ unsigned int current_longer : 1;
+};
+#define WS_DELTA_INIT { NULL, 0 }
+
+static int compute_ws_delta(const struct emitted_diff_symbol *a,
+ const struct emitted_diff_symbol *b,
+ struct ws_delta *out)
+{
+ const struct emitted_diff_symbol *longer = a->len > b->len ? a : b;
+ const struct emitted_diff_symbol *shorter = a->len > b->len ? b : a;
+ int d = longer->len - shorter->len;
+
+ out->string = xmemdupz(longer->line, d);
+ out->current_longer = (a == longer);
+
+ return !strncmp(longer->line + d, shorter->line, shorter->len);
+}
+
+static int cmp_in_block_with_wsd(const struct diff_options *o,
+ const struct moved_entry *cur,
+ const struct moved_entry *match,
+ struct moved_entry *pmb,
+ int n)
+{
+ struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];
+ int al = cur->es->len, cl = l->len;
+ const char *a = cur->es->line,
+ *b = match->es->line,
+ *c = l->line;
+
+ int wslen;
+
+ /*
+ * We need to check if 'cur' is equal to 'match'.
+ * As those are from the same (+/-) side, we do not need to adjust for
+ * indent changes. However these were found using fuzzy matching
+ * so we do have to check if they are equal.
+ */
+ if (strcmp(a, b))
+ return 1;
+
+ if (!pmb->wsd)
+ /*
+ * No white space delta was carried forward? This can happen
+ * when we exit early in this function and do not carry
+ * forward ws.
+ */
+ return 1;
+
+ /*
+ * The indent changes of the block are known and carried forward in
+ * pmb->wsd; however we need to check if the indent changes of the
+ * current line are still the same as before.
+ *
+ * To do so we need to compare 'l' to 'cur', adjusting the
+ * one of them for the white spaces, depending which was longer.
+ */
+
+ wslen = strlen(pmb->wsd->string);
+ if (pmb->wsd->current_longer) {
+ c += wslen;
+ cl -= wslen;
+ } else {
+ a += wslen;
+ al -= wslen;
+ }
+
+ if (strcmp(a, c))
+ return 1;
+
+ return 0;
+}
+
+static int moved_entry_cmp(const void *hashmap_cmp_fn_data,
+ const void *entry,
+ const void *entry_or_key,
const void *keydata)
{
+ const struct diff_options *diffopt = hashmap_cmp_fn_data;
+ const struct moved_entry *a = entry;
+ const struct moved_entry *b = entry_or_key;
+ unsigned flags = diffopt->color_moved_ws_handling
+ & XDF_WHITESPACE_FLAGS;
+
+ if (diffopt->color_moved_ws_handling &
+ COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
+ /*
+ * As there is not specific white space config given,
+ * we'd need to check for a new block, so ignore all
+ * white space. The setup of the white space
+ * configuration for the next block is done else where
+ */
+ flags |= XDF_IGNORE_WHITESPACE;
+
return !xdiff_compare_lines(a->es->line, a->es->len,
b->es->line, b->es->len,
- diffopt->xdl_opts);
+ flags);
}
static struct moved_entry *prepare_entry(struct diff_options *o,
@@ -714,10 +863,12 @@ static struct moved_entry *prepare_entry(struct diff_options *o,
{
struct moved_entry *ret = xmalloc(sizeof(*ret));
struct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];
+ unsigned flags = o->color_moved_ws_handling & XDF_WHITESPACE_FLAGS;
- ret->ent.hash = xdiff_hash_string(l->line, l->len, o->xdl_opts);
+ ret->ent.hash = xdiff_hash_string(l->line, l->len, flags);
ret->es = l;
ret->next_line = NULL;
+ ret->wsd = NULL;
return ret;
}
@@ -754,6 +905,56 @@ static void add_lines_to_move_detection(struct diff_options *o,
}
}
+static void pmb_advance_or_null(struct diff_options *o,
+ struct moved_entry *match,
+ struct hashmap *hm,
+ struct moved_entry **pmb,
+ int pmb_nr)
+{
+ int i;
+ for (i = 0; i < pmb_nr; i++) {
+ struct moved_entry *prev = pmb[i];
+ struct moved_entry *cur = (prev && prev->next_line) ?
+ prev->next_line : NULL;
+ if (cur && !hm->cmpfn(o, cur, match, NULL)) {
+ pmb[i] = cur;
+ } else {
+ pmb[i] = NULL;
+ }
+ }
+}
+
+static void pmb_advance_or_null_multi_match(struct diff_options *o,
+ struct moved_entry *match,
+ struct hashmap *hm,
+ struct moved_entry **pmb,
+ int pmb_nr, int n)
+{
+ int i;
+ char *got_match = xcalloc(1, pmb_nr);
+
+ for (; match; match = hashmap_get_next(hm, match)) {
+ for (i = 0; i < pmb_nr; i++) {
+ struct moved_entry *prev = pmb[i];
+ struct moved_entry *cur = (prev && prev->next_line) ?
+ prev->next_line : NULL;
+ if (!cur)
+ continue;
+ if (!cmp_in_block_with_wsd(o, cur, match, pmb[i], n))
+ got_match[i] |= 1;
+ }
+ }
+
+ for (i = 0; i < pmb_nr; i++) {
+ if (got_match[i]) {
+ /* Carry the white space delta forward */
+ pmb[i]->next_line->wsd = pmb[i]->wsd;
+ pmb[i] = pmb[i]->next_line;
+ } else
+ pmb[i] = NULL;
+ }
+}
+
static int shrink_potential_moved_blocks(struct moved_entry **pmb,
int pmb_nr)
{
@@ -771,6 +972,10 @@ static int shrink_potential_moved_blocks(struct moved_entry **pmb,
if (lp < pmb_nr && rp > -1 && lp < rp) {
pmb[lp] = pmb[rp];
+ if (pmb[rp]->wsd) {
+ free(pmb[rp]->wsd->string);
+ FREE_AND_NULL(pmb[rp]->wsd);
+ }
pmb[rp] = NULL;
rp--;
lp++;
@@ -828,19 +1033,18 @@ static void mark_color_as_moved(struct diff_options *o,
struct moved_entry *key;
struct moved_entry *match = NULL;
struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];
- int i;
switch (l->s) {
case DIFF_SYMBOL_PLUS:
hm = del_lines;
key = prepare_entry(o, n);
- match = hashmap_get(hm, key, o);
+ match = hashmap_get(hm, key, NULL);
free(key);
break;
case DIFF_SYMBOL_MINUS:
hm = add_lines;
key = prepare_entry(o, n);
- match = hashmap_get(hm, key, o);
+ match = hashmap_get(hm, key, NULL);
free(key);
break;
default:
@@ -859,17 +1063,11 @@ static void mark_color_as_moved(struct diff_options *o,
if (o->color_moved == COLOR_MOVED_PLAIN)
continue;
- /* Check any potential block runs, advance each or nullify */
- for (i = 0; i < pmb_nr; i++) {
- struct moved_entry *p = pmb[i];
- struct moved_entry *pnext = (p && p->next_line) ?
- p->next_line : NULL;
- if (pnext && !hm->cmpfn(o, pnext, match, NULL)) {
- pmb[i] = p->next_line;
- } else {
- pmb[i] = NULL;
- }
- }
+ if (o->color_moved_ws_handling &
+ COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
+ pmb_advance_or_null_multi_match(o, match, hm, pmb, pmb_nr, n);
+ else
+ pmb_advance_or_null(o, match, hm, pmb, pmb_nr);
pmb_nr = shrink_potential_moved_blocks(pmb, pmb_nr);
@@ -880,7 +1078,17 @@ static void mark_color_as_moved(struct diff_options *o,
*/
for (; match; match = hashmap_get_next(hm, match)) {
ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);
- pmb[pmb_nr++] = match;
+ if (o->color_moved_ws_handling &
+ COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {
+ struct ws_delta *wsd = xmalloc(sizeof(*match->wsd));
+ if (compute_ws_delta(l, match->es, wsd)) {
+ match->wsd = wsd;
+ pmb[pmb_nr++] = match;
+ } else
+ free(wsd);
+ } else {
+ pmb[pmb_nr++] = match;
+ }
}
flipped_block = (flipped_block + 1) % 2;
@@ -891,7 +1099,7 @@ static void mark_color_as_moved(struct diff_options *o,
block_length++;
- if (flipped_block)
+ if (flipped_block && o->color_moved != COLOR_MOVED_BLOCKS)
l->flags |= DIFF_SYMBOL_MOVED_LINE_ALT;
}
adjust_last_block(o, n, block_length);
@@ -3832,7 +4040,7 @@ static const char *diff_abbrev_oid(const struct object_id *oid, int abbrev)
char *hex = oid_to_hex(oid);
if (abbrev < 0)
abbrev = FALLBACK_DEFAULT_ABBREV;
- if (abbrev > GIT_SHA1_HEXSZ)
+ if (abbrev > the_hash_algo->hexsz)
BUG("oid abbreviation out of range: %d", abbrev);
if (abbrev)
hex[abbrev] = '\0';
@@ -4124,6 +4332,7 @@ void diff_setup(struct diff_options *options)
}
options->color_moved = diff_color_moved_default;
+ options->color_moved_ws_handling = diff_color_moved_ws_default;
}
void diff_setup_done(struct diff_options *options)
@@ -4703,6 +4912,8 @@ int diff_opt_parse(struct diff_options *options,
if (cm < 0)
die("bad --color-moved argument: %s", arg);
options->color_moved = cm;
+ } else if (skip_prefix(arg, "--color-moved-ws=", &arg)) {
+ options->color_moved_ws_handling = parse_color_moved_ws(arg);
} else if (skip_to_optional_arg_default(arg, "--color-words", &options->word_regex, NULL)) {
options->use_color = 1;
options->word_diff = DIFF_WORDS_COLOR;
@@ -4947,7 +5158,7 @@ const char *diff_aligned_abbrev(const struct object_id *oid, int len)
const char *abbrev;
/* Do we want all 40 hex characters? */
- if (len == GIT_SHA1_HEXSZ)
+ if (len == the_hash_algo->hexsz)
return oid_to_hex(oid);
/* An abbreviated value is fine, possibly followed by an ellipsis. */
@@ -4977,7 +5188,7 @@ const char *diff_aligned_abbrev(const struct object_id *oid, int len)
* the automatic sizing is supposed to give abblen that ensures
* uniqueness across all objects (statistically speaking).
*/
- if (abblen < GIT_SHA1_HEXSZ - 3) {
+ if (abblen < the_hash_algo->hexsz - 3) {
static char hex[GIT_MAX_HEXSZ + 1];
if (len < abblen && abblen <= len + 2)
xsnprintf(hex, sizeof(hex), "%s%.*s", abbrev, len+3-abblen, "..");
@@ -5533,10 +5744,12 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
if (o->color_moved) {
struct hashmap add_lines, del_lines;
- hashmap_init(&del_lines,
- (hashmap_cmp_fn)moved_entry_cmp, o, 0);
- hashmap_init(&add_lines,
- (hashmap_cmp_fn)moved_entry_cmp, o, 0);
+ if (o->color_moved_ws_handling &
+ COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
+ o->color_moved_ws_handling |= XDF_IGNORE_WHITESPACE;
+
+ hashmap_init(&del_lines, moved_entry_cmp, o, 0);
+ hashmap_init(&add_lines, moved_entry_cmp, o, 0);
add_lines_to_move_detection(o, &add_lines, &del_lines);
mark_color_as_moved(o, &add_lines, &del_lines);
diff --git a/diff.h b/diff.h
index dedac47..a14895b 100644
--- a/diff.h
+++ b/diff.h
@@ -208,11 +208,16 @@ struct diff_options {
enum {
COLOR_MOVED_NO = 0,
COLOR_MOVED_PLAIN = 1,
- COLOR_MOVED_ZEBRA = 2,
- COLOR_MOVED_ZEBRA_DIM = 3,
+ COLOR_MOVED_BLOCKS = 2,
+ COLOR_MOVED_ZEBRA = 3,
+ COLOR_MOVED_ZEBRA_DIM = 4,
} color_moved;
#define COLOR_MOVED_DEFAULT COLOR_MOVED_ZEBRA
#define COLOR_MOVED_MIN_ALNUM_COUNT 20
+
+ /* XDF_WHITESPACE_FLAGS regarding block detection are set at 2, 3, 4 */
+ #define COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE (1<<5)
+ int color_moved_ws_handling;
};
void diff_emit_submodule_del(struct diff_options *o, const char *line);
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 0b7e498..d775183 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -4,6 +4,7 @@
#include "cache.h"
#include "diff.h"
#include "diffcore.h"
+#include "object-store.h"
#include "hashmap.h"
#include "progress.h"
diff --git a/dir.c b/dir.c
index 7c6e7a0..32f5f72 100644
--- a/dir.c
+++ b/dir.c
@@ -11,6 +11,7 @@
#include "cache.h"
#include "config.h"
#include "dir.h"
+#include "object-store.h"
#include "attr.h"
#include "refs.h"
#include "wildmatch.h"
@@ -2497,7 +2498,7 @@ void setup_standard_excludes(struct dir_struct *dir)
{
dir->exclude_per_dir = ".gitignore";
- /* core.excludefile defaulting to $XDG_HOME/git/ignore */
+ /* core.excludesfile defaulting to $XDG_CONFIG_HOME/git/ignore */
if (!excludes_file)
excludes_file = xdg_config_home("ignore");
if (excludes_file && !access_or_warn(excludes_file, R_OK, 0))
diff --git a/entry.c b/entry.c
index 2101201..b5d1d3c 100644
--- a/entry.c
+++ b/entry.c
@@ -1,5 +1,6 @@
#include "cache.h"
#include "blob.h"
+#include "object-store.h"
#include "dir.h"
#include "streaming.h"
#include "submodule.h"
diff --git a/environment.c b/environment.c
index d129c4a..68523b6b 100644
--- a/environment.c
+++ b/environment.c
@@ -51,7 +51,7 @@ const char *editor_program;
const char *askpass_program;
const char *excludes_file;
enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
-int check_replace_refs = 1; /* NEEDSWORK: rename to read_replace_refs */
+int read_replace_refs = 1;
char *git_replace_ref_base;
enum eol core_eol = EOL_UNSET;
int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
@@ -66,7 +66,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
char *notes_ref_name;
int grafts_replace_parents = 1;
-int core_commit_graph;
int core_apply_sparse_checkout;
int merge_log_config = -1;
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
@@ -183,7 +182,7 @@ void setup_git_env(const char *git_dir)
argv_array_clear(&to_free);
if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
- check_replace_refs = 0;
+ read_replace_refs = 0;
replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
free(git_replace_ref_base);
git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
@@ -192,7 +191,7 @@ void setup_git_env(const char *git_dir)
git_namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
if (shallow_file)
- set_alternate_shallow_file(shallow_file, 0);
+ set_alternate_shallow_file(the_repository, shallow_file, 0);
}
int is_bare_repository(void)
@@ -319,11 +318,11 @@ char *get_index_file(void)
return the_repository->index_file;
}
-char *get_graft_file(void)
+char *get_graft_file(struct repository *r)
{
- if (!the_repository->graft_file)
+ if (!r->graft_file)
BUG("git environment hasn't been setup");
- return the_repository->graft_file;
+ return r->graft_file;
}
static void set_git_dir_1(const char *path)
diff --git a/ewah/bitmap.c b/ewah/bitmap.c
index 756bdd0..52f1178 100644
--- a/ewah/bitmap.c
+++ b/ewah/bitmap.c
@@ -45,14 +45,6 @@ void bitmap_set(struct bitmap *self, size_t pos)
self->words[block] |= EWAH_MASK(pos);
}
-void bitmap_clear(struct bitmap *self, size_t pos)
-{
- size_t block = EWAH_BLOCK(pos);
-
- if (block < self->word_alloc)
- self->words[block] &= ~EWAH_MASK(pos);
-}
-
int bitmap_get(struct bitmap *self, size_t pos)
{
size_t block = EWAH_BLOCK(pos);
@@ -137,30 +129,6 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)
self->words[i++] |= word;
}
-void bitmap_each_bit(struct bitmap *self, ewah_callback callback, void *data)
-{
- size_t pos = 0, i;
-
- for (i = 0; i < self->word_alloc; ++i) {
- eword_t word = self->words[i];
- uint32_t offset;
-
- if (word == (eword_t)~0) {
- for (offset = 0; offset < BITS_IN_EWORD; ++offset)
- callback(pos++, data);
- } else {
- for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
- if ((word >> offset) == 0)
- break;
-
- offset += ewah_bit_ctz64(word >> offset);
- callback(pos + offset, data);
- }
- pos += BITS_IN_EWORD;
- }
- }
-}
-
size_t bitmap_popcount(struct bitmap *self)
{
size_t i, count = 0;
diff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c
index b9fdda1..d59b1af 100644
--- a/ewah/ewah_bitmap.c
+++ b/ewah/ewah_bitmap.c
@@ -276,6 +276,18 @@ void ewah_each_bit(struct ewah_bitmap *self, void (*callback)(size_t, void*), vo
}
}
+/**
+ * Clear all the bits in the bitmap. Does not free or resize
+ * memory.
+ */
+static void ewah_clear(struct ewah_bitmap *self)
+{
+ self->buffer_size = 1;
+ self->buffer[0] = 0;
+ self->bit_size = 0;
+ self->rlw = self->buffer;
+}
+
struct ewah_bitmap *ewah_new(void)
{
struct ewah_bitmap *self;
@@ -288,14 +300,6 @@ struct ewah_bitmap *ewah_new(void)
return self;
}
-void ewah_clear(struct ewah_bitmap *self)
-{
- self->buffer_size = 1;
- self->buffer[0] = 0;
- self->bit_size = 0;
- self->rlw = self->buffer;
-}
-
void ewah_free(struct ewah_bitmap *self)
{
if (!self)
@@ -376,25 +380,6 @@ void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent)
read_new_rlw(it);
}
-void ewah_not(struct ewah_bitmap *self)
-{
- size_t pointer = 0;
-
- while (pointer < self->buffer_size) {
- eword_t *word = &self->buffer[pointer];
- size_t literals, k;
-
- rlw_xor_run_bit(word);
- ++pointer;
-
- literals = rlw_get_literal_words(word);
- for (k = 0; k < literals; ++k) {
- self->buffer[pointer] = ~self->buffer[pointer];
- ++pointer;
- }
- }
-}
-
void ewah_xor(
struct ewah_bitmap *ewah_i,
struct ewah_bitmap *ewah_j,
@@ -459,216 +444,6 @@ void ewah_xor(
out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
}
-void ewah_and(
- struct ewah_bitmap *ewah_i,
- struct ewah_bitmap *ewah_j,
- struct ewah_bitmap *out)
-{
- struct rlw_iterator rlw_i;
- struct rlw_iterator rlw_j;
- size_t literals;
-
- rlwit_init(&rlw_i, ewah_i);
- rlwit_init(&rlw_j, ewah_j);
-
- while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
- while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
- struct rlw_iterator *prey, *predator;
-
- if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
- prey = &rlw_i;
- predator = &rlw_j;
- } else {
- prey = &rlw_j;
- predator = &rlw_i;
- }
-
- if (predator->rlw.running_bit == 0) {
- ewah_add_empty_words(out, 0,
- predator->rlw.running_len);
- rlwit_discard_first_words(prey,
- predator->rlw.running_len);
- rlwit_discard_first_words(predator,
- predator->rlw.running_len);
- } else {
- size_t index = rlwit_discharge(prey, out,
- predator->rlw.running_len, 0);
- ewah_add_empty_words(out, 0,
- predator->rlw.running_len - index);
- rlwit_discard_first_words(predator,
- predator->rlw.running_len);
- }
- }
-
- literals = min_size(
- rlw_i.rlw.literal_words,
- rlw_j.rlw.literal_words);
-
- if (literals) {
- size_t k;
-
- for (k = 0; k < literals; ++k) {
- ewah_add(out,
- rlw_i.buffer[rlw_i.literal_word_start + k] &
- rlw_j.buffer[rlw_j.literal_word_start + k]
- );
- }
-
- rlwit_discard_first_words(&rlw_i, literals);
- rlwit_discard_first_words(&rlw_j, literals);
- }
- }
-
- if (rlwit_word_size(&rlw_i) > 0)
- rlwit_discharge_empty(&rlw_i, out);
- else
- rlwit_discharge_empty(&rlw_j, out);
-
- out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
-}
-
-void ewah_and_not(
- struct ewah_bitmap *ewah_i,
- struct ewah_bitmap *ewah_j,
- struct ewah_bitmap *out)
-{
- struct rlw_iterator rlw_i;
- struct rlw_iterator rlw_j;
- size_t literals;
-
- rlwit_init(&rlw_i, ewah_i);
- rlwit_init(&rlw_j, ewah_j);
-
- while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
- while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
- struct rlw_iterator *prey, *predator;
-
- if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
- prey = &rlw_i;
- predator = &rlw_j;
- } else {
- prey = &rlw_j;
- predator = &rlw_i;
- }
-
- if ((predator->rlw.running_bit && prey == &rlw_i) ||
- (!predator->rlw.running_bit && prey != &rlw_i)) {
- ewah_add_empty_words(out, 0,
- predator->rlw.running_len);
- rlwit_discard_first_words(prey,
- predator->rlw.running_len);
- rlwit_discard_first_words(predator,
- predator->rlw.running_len);
- } else {
- size_t index;
- int negate_words;
-
- negate_words = (&rlw_i != prey);
- index = rlwit_discharge(prey, out,
- predator->rlw.running_len, negate_words);
- ewah_add_empty_words(out, negate_words,
- predator->rlw.running_len - index);
- rlwit_discard_first_words(predator,
- predator->rlw.running_len);
- }
- }
-
- literals = min_size(
- rlw_i.rlw.literal_words,
- rlw_j.rlw.literal_words);
-
- if (literals) {
- size_t k;
-
- for (k = 0; k < literals; ++k) {
- ewah_add(out,
- rlw_i.buffer[rlw_i.literal_word_start + k] &
- ~(rlw_j.buffer[rlw_j.literal_word_start + k])
- );
- }
-
- rlwit_discard_first_words(&rlw_i, literals);
- rlwit_discard_first_words(&rlw_j, literals);
- }
- }
-
- if (rlwit_word_size(&rlw_i) > 0)
- rlwit_discharge(&rlw_i, out, ~0, 0);
- else
- rlwit_discharge_empty(&rlw_j, out);
-
- out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
-}
-
-void ewah_or(
- struct ewah_bitmap *ewah_i,
- struct ewah_bitmap *ewah_j,
- struct ewah_bitmap *out)
-{
- struct rlw_iterator rlw_i;
- struct rlw_iterator rlw_j;
- size_t literals;
-
- rlwit_init(&rlw_i, ewah_i);
- rlwit_init(&rlw_j, ewah_j);
-
- while (rlwit_word_size(&rlw_i) > 0 && rlwit_word_size(&rlw_j) > 0) {
- while (rlw_i.rlw.running_len > 0 || rlw_j.rlw.running_len > 0) {
- struct rlw_iterator *prey, *predator;
-
- if (rlw_i.rlw.running_len < rlw_j.rlw.running_len) {
- prey = &rlw_i;
- predator = &rlw_j;
- } else {
- prey = &rlw_j;
- predator = &rlw_i;
- }
-
- if (predator->rlw.running_bit) {
- ewah_add_empty_words(out, 0,
- predator->rlw.running_len);
- rlwit_discard_first_words(prey,
- predator->rlw.running_len);
- rlwit_discard_first_words(predator,
- predator->rlw.running_len);
- } else {
- size_t index = rlwit_discharge(prey, out,
- predator->rlw.running_len, 0);
- ewah_add_empty_words(out, 0,
- predator->rlw.running_len - index);
- rlwit_discard_first_words(predator,
- predator->rlw.running_len);
- }
- }
-
- literals = min_size(
- rlw_i.rlw.literal_words,
- rlw_j.rlw.literal_words);
-
- if (literals) {
- size_t k;
-
- for (k = 0; k < literals; ++k) {
- ewah_add(out,
- rlw_i.buffer[rlw_i.literal_word_start + k] |
- rlw_j.buffer[rlw_j.literal_word_start + k]
- );
- }
-
- rlwit_discard_first_words(&rlw_i, literals);
- rlwit_discard_first_words(&rlw_j, literals);
- }
- }
-
- if (rlwit_word_size(&rlw_i) > 0)
- rlwit_discharge(&rlw_i, out, ~0, 0);
- else
- rlwit_discharge(&rlw_j, out, ~0, 0);
-
- out->bit_size = max_size(ewah_i->bit_size, ewah_j->bit_size);
-}
-
-
#define BITMAP_POOL_MAX 16
static struct ewah_bitmap *bitmap_pool[BITMAP_POOL_MAX];
static size_t bitmap_pool_size;
diff --git a/ewah/ewah_io.c b/ewah/ewah_io.c
index 33c08c4..9035ee6 100644
--- a/ewah/ewah_io.c
+++ b/ewah/ewah_io.c
@@ -20,32 +20,6 @@
#include "ewok.h"
#include "strbuf.h"
-int ewah_serialize_native(struct ewah_bitmap *self, int fd)
-{
- uint32_t write32;
- size_t to_write = self->buffer_size * 8;
-
- /* 32 bit -- bit size for the map */
- write32 = (uint32_t)self->bit_size;
- if (write(fd, &write32, 4) != 4)
- return -1;
-
- /** 32 bit -- number of compressed 64-bit words */
- write32 = (uint32_t)self->buffer_size;
- if (write(fd, &write32, 4) != 4)
- return -1;
-
- if (write(fd, self->buffer, to_write) != to_write)
- return -1;
-
- /** 32 bit -- position for the RLW */
- write32 = self->rlw - self->buffer;
- if (write(fd, &write32, 4) != 4)
- return -1;
-
- return (3 * 4) + to_write;
-}
-
int ewah_serialize_to(struct ewah_bitmap *self,
int (*write_fun)(void *, const void *, size_t),
void *data)
@@ -100,16 +74,6 @@ int ewah_serialize_to(struct ewah_bitmap *self,
return (3 * 4) + (self->buffer_size * 8);
}
-static int write_helper(void *fd, const void *buf, size_t len)
-{
- return write((intptr_t)fd, buf, len);
-}
-
-int ewah_serialize(struct ewah_bitmap *self, int fd)
-{
- return ewah_serialize_to(self, write_helper, (void *)(intptr_t)fd);
-}
-
static int write_strbuf(void *user_data, const void *data, size_t len)
{
struct strbuf *sb = user_data;
@@ -168,58 +132,3 @@ ssize_t ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len)
return ptr - (const uint8_t *)map;
}
-
-int ewah_deserialize(struct ewah_bitmap *self, int fd)
-{
- size_t i;
- eword_t dump[2048];
- const size_t words_per_dump = sizeof(dump) / sizeof(eword_t);
- uint32_t bitsize, word_count, rlw_pos;
-
- eword_t *buffer = NULL;
- size_t words_left;
-
- ewah_clear(self);
-
- /* 32 bit -- bit size for the map */
- if (read(fd, &bitsize, 4) != 4)
- return -1;
-
- self->bit_size = (size_t)ntohl(bitsize);
-
- /** 32 bit -- number of compressed 64-bit words */
- if (read(fd, &word_count, 4) != 4)
- return -1;
-
- self->buffer_size = self->alloc_size = (size_t)ntohl(word_count);
- REALLOC_ARRAY(self->buffer, self->alloc_size);
-
- /** 64 bit x N -- compressed words */
- buffer = self->buffer;
- words_left = self->buffer_size;
-
- while (words_left >= words_per_dump) {
- if (read(fd, dump, sizeof(dump)) != sizeof(dump))
- return -1;
-
- for (i = 0; i < words_per_dump; ++i, ++buffer)
- *buffer = ntohll(dump[i]);
-
- words_left -= words_per_dump;
- }
-
- if (words_left) {
- if (read(fd, dump, words_left * 8) != words_left * 8)
- return -1;
-
- for (i = 0; i < words_left; ++i, ++buffer)
- *buffer = ntohll(dump[i]);
- }
-
- /** 32 bit -- position for the RLW */
- if (read(fd, &rlw_pos, 4) != 4)
- return -1;
-
- self->rlw = self->buffer + ntohl(rlw_pos);
- return 0;
-}
diff --git a/ewah/ewah_rlw.c b/ewah/ewah_rlw.c
index b9643b7..5093d43 100644
--- a/ewah/ewah_rlw.c
+++ b/ewah/ewah_rlw.c
@@ -104,11 +104,3 @@ size_t rlwit_discharge(
return index;
}
-
-void rlwit_discharge_empty(struct rlw_iterator *it, struct ewah_bitmap *out)
-{
- while (rlwit_word_size(it) > 0) {
- ewah_add_empty_words(out, 0, rlwit_word_size(it));
- rlwit_discard_first_words(it, rlwit_word_size(it));
- }
-}
diff --git a/ewah/ewok.h b/ewah/ewok.h
index 357fd93..84b2a29 100644
--- a/ewah/ewok.h
+++ b/ewah/ewok.h
@@ -73,12 +73,6 @@ void ewah_pool_free(struct ewah_bitmap *self);
struct ewah_bitmap *ewah_new(void);
/**
- * Clear all the bits in the bitmap. Does not free or resize
- * memory.
- */
-void ewah_clear(struct ewah_bitmap *self);
-
-/**
* Free all the memory of the bitmap
*/
void ewah_free(struct ewah_bitmap *self);
@@ -86,23 +80,13 @@ void ewah_free(struct ewah_bitmap *self);
int ewah_serialize_to(struct ewah_bitmap *self,
int (*write_fun)(void *out, const void *buf, size_t len),
void *out);
-int ewah_serialize(struct ewah_bitmap *self, int fd);
-int ewah_serialize_native(struct ewah_bitmap *self, int fd);
int ewah_serialize_strbuf(struct ewah_bitmap *self, struct strbuf *);
-int ewah_deserialize(struct ewah_bitmap *self, int fd);
ssize_t ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len);
uint32_t ewah_checksum(struct ewah_bitmap *self);
/**
- * Logical not (bitwise negation) in-place on the bitmap
- *
- * This operation is linear time based on the size of the bitmap.
- */
-void ewah_not(struct ewah_bitmap *self);
-
-/**
* Call the given callback with the position of every single bit
* that has been set on the bitmap.
*
@@ -164,26 +148,11 @@ void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent);
*/
int ewah_iterator_next(eword_t *next, struct ewah_iterator *it);
-void ewah_or(
- struct ewah_bitmap *ewah_i,
- struct ewah_bitmap *ewah_j,
- struct ewah_bitmap *out);
-
-void ewah_and_not(
- struct ewah_bitmap *ewah_i,
- struct ewah_bitmap *ewah_j,
- struct ewah_bitmap *out);
-
void ewah_xor(
struct ewah_bitmap *ewah_i,
struct ewah_bitmap *ewah_j,
struct ewah_bitmap *out);
-void ewah_and(
- struct ewah_bitmap *ewah_i,
- struct ewah_bitmap *ewah_j,
- struct ewah_bitmap *out);
-
/**
* Direct word access
*/
@@ -204,7 +173,6 @@ struct bitmap {
struct bitmap *bitmap_new(void);
void bitmap_set(struct bitmap *self, size_t pos);
-void bitmap_clear(struct bitmap *self, size_t pos);
int bitmap_get(struct bitmap *self, size_t pos);
void bitmap_reset(struct bitmap *self);
void bitmap_free(struct bitmap *self);
@@ -218,7 +186,6 @@ void bitmap_and_not(struct bitmap *self, struct bitmap *other);
void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other);
void bitmap_or(struct bitmap *self, const struct bitmap *other);
-void bitmap_each_bit(struct bitmap *self, ewah_callback callback, void *data);
size_t bitmap_popcount(struct bitmap *self);
#endif
diff --git a/ewah/ewok_rlw.h b/ewah/ewok_rlw.h
index bb3c6ff..7cdfdd0 100644
--- a/ewah/ewok_rlw.h
+++ b/ewah/ewok_rlw.h
@@ -98,7 +98,6 @@ void rlwit_init(struct rlw_iterator *it, struct ewah_bitmap *bitmap);
void rlwit_discard_first_words(struct rlw_iterator *it, size_t x);
size_t rlwit_discharge(
struct rlw_iterator *it, struct ewah_bitmap *out, size_t max, int negate);
-void rlwit_discharge_empty(struct rlw_iterator *it, struct ewah_bitmap *out);
static inline size_t rlwit_word_size(struct rlw_iterator *it)
{
diff --git a/fast-import.c b/fast-import.c
index 4d55910..89bb0c9 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1076,7 +1076,7 @@ static int store_object(
return 1;
}
- if (last && last->data.buf && last->depth < max_depth
+ if (last && last->data.len && last->data.buf && last->depth < max_depth
&& dat->len > the_hash_algo->rawsz) {
delta_count_attempts_by_type[type]++;
@@ -1724,8 +1724,10 @@ static int update_branch(struct branch *b)
if (!force_update && !is_null_oid(&old_oid)) {
struct commit *old_cmit, *new_cmit;
- old_cmit = lookup_commit_reference_gently(&old_oid, 0);
- new_cmit = lookup_commit_reference_gently(&b->oid, 0);
+ old_cmit = lookup_commit_reference_gently(the_repository,
+ &old_oid, 0);
+ new_cmit = lookup_commit_reference_gently(the_repository,
+ &b->oid, 0);
if (!old_cmit || !new_cmit)
return error("Branch %s is missing commits.", b->name);
diff --git a/fetch-negotiator.c b/fetch-negotiator.c
new file mode 100644
index 0000000..5d28304
--- /dev/null
+++ b/fetch-negotiator.c
@@ -0,0 +1,14 @@
+#include "git-compat-util.h"
+#include "fetch-negotiator.h"
+#include "negotiator/default.h"
+#include "negotiator/skipping.h"
+
+void fetch_negotiator_init(struct fetch_negotiator *negotiator,
+ const char *algorithm)
+{
+ if (algorithm && !strcmp(algorithm, "skipping")) {
+ skipping_negotiator_init(negotiator);
+ return;
+ }
+ default_negotiator_init(negotiator);
+}
diff --git a/fetch-negotiator.h b/fetch-negotiator.h
new file mode 100644
index 0000000..ddb44a2
--- /dev/null
+++ b/fetch-negotiator.h
@@ -0,0 +1,58 @@
+#ifndef FETCH_NEGOTIATOR
+#define FETCH_NEGOTIATOR
+
+struct commit;
+
+/*
+ * An object that supplies the information needed to negotiate the contents of
+ * the to-be-sent packfile during a fetch.
+ *
+ * To set up the negotiator, call fetch_negotiator_init(), then known_common()
+ * (0 or more times), then add_tip() (0 or more times).
+ *
+ * Then, when "have" lines are required, call next(). Call ack() to report what
+ * the server tells us.
+ *
+ * Once negotiation is done, call release(). The negotiator then cannot be used
+ * (unless reinitialized with fetch_negotiator_init()).
+ */
+struct fetch_negotiator {
+ /*
+ * Before negotiation starts, indicate that the server is known to have
+ * this commit.
+ */
+ void (*known_common)(struct fetch_negotiator *, struct commit *);
+
+ /*
+ * Once this function is invoked, known_common() cannot be invoked any
+ * more.
+ *
+ * Indicate that this commit and all its ancestors are to be checked
+ * for commonality with the server.
+ */
+ void (*add_tip)(struct fetch_negotiator *, struct commit *);
+
+ /*
+ * Once this function is invoked, known_common() and add_tip() cannot
+ * be invoked any more.
+ *
+ * Return the next commit that the client should send as a "have" line.
+ */
+ const struct object_id *(*next)(struct fetch_negotiator *);
+
+ /*
+ * Inform the negotiator that the server has the given commit. This
+ * method must only be called on commits returned by next().
+ */
+ int (*ack)(struct fetch_negotiator *, struct commit *);
+
+ void (*release)(struct fetch_negotiator *);
+
+ /* internal use */
+ void *data;
+};
+
+void fetch_negotiator_init(struct fetch_negotiator *negotiator,
+ const char *algorithm);
+
+#endif
diff --git a/fetch-object.c b/fetch-object.c
index 853624f..48fe63d 100644
--- a/fetch-object.c
+++ b/fetch-object.c
@@ -19,7 +19,7 @@ static void fetch_refs(const char *remote_name, struct ref *ref)
transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
transport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, "1");
- transport_fetch_refs(transport, ref);
+ transport_fetch_refs(transport, ref, NULL);
fetch_if_missing = original_fetch_if_missing;
}
diff --git a/fetch-pack.c b/fetch-pack.c
index cc7a42f..1ab0b2d 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -15,10 +15,12 @@
#include "connect.h"
#include "transport.h"
#include "version.h"
-#include "prio-queue.h"
#include "sha1-array.h"
#include "oidset.h"
#include "packfile.h"
+#include "object-store.h"
+#include "connected.h"
+#include "fetch-negotiator.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@@ -33,16 +35,11 @@ static int agent_supported;
static int server_supports_filtering;
static struct lock_file shallow_lock;
static const char *alternate_shallow_file;
+static char *negotiation_algorithm;
/* Remember to update object flag allocation in object.h */
#define COMPLETE (1U << 0)
-#define COMMON (1U << 1)
-#define COMMON_REF (1U << 2)
-#define SEEN (1U << 3)
-#define POPPED (1U << 4)
-#define ALTERNATE (1U << 5)
-
-static int marked;
+#define ALTERNATE (1U << 1)
/*
* After sending this many "have"s if we do not get any new ACK , we
@@ -50,8 +47,7 @@ static int marked;
*/
#define MAX_IN_VAIN 256
-static struct prio_queue rev_list = { compare_commits_by_commit_date };
-static int non_common_revs, multi_ack, use_sideband;
+static int multi_ack, use_sideband;
/* Allow specifying sha1 if it is a ref tip. */
#define ALLOW_TIP_SHA1 01
/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
@@ -83,7 +79,7 @@ static void cache_one_alternate(const char *refname,
void *vcache)
{
struct alternate_object_cache *cache = vcache;
- struct object *obj = parse_object(oid);
+ struct object *obj = parse_object(the_repository, oid);
if (!obj || (obj->flags & ALTERNATE))
return;
@@ -93,7 +89,9 @@ static void cache_one_alternate(const char *refname,
cache->items[cache->nr++] = obj;
}
-static void for_each_cached_alternate(void (*cb)(struct object *))
+static void for_each_cached_alternate(struct fetch_negotiator *negotiator,
+ void (*cb)(struct fetch_negotiator *,
+ struct object *))
{
static int initialized;
static struct alternate_object_cache cache;
@@ -105,30 +103,19 @@ static void for_each_cached_alternate(void (*cb)(struct object *))
}
for (i = 0; i < cache.nr; i++)
- cb(cache.items[i]);
-}
-
-static void rev_list_push(struct commit *commit, int mark)
-{
- if (!(commit->object.flags & mark)) {
- commit->object.flags |= mark;
-
- if (parse_commit(commit))
- return;
-
- prio_queue_put(&rev_list, commit);
-
- if (!(commit->object.flags & COMMON))
- non_common_revs++;
- }
+ cb(negotiator, cache.items[i]);
}
-static int rev_list_insert_ref(const char *refname, const struct object_id *oid)
+static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
+ const char *refname,
+ const struct object_id *oid)
{
- struct object *o = deref_tag(parse_object(oid), refname, 0);
+ struct object *o = deref_tag(the_repository,
+ parse_object(the_repository, oid),
+ refname, 0);
if (o && o->type == OBJ_COMMIT)
- rev_list_push((struct commit *)o, SEEN);
+ negotiator->add_tip(negotiator, (struct commit *)o);
return 0;
}
@@ -136,98 +123,7 @@ static int rev_list_insert_ref(const char *refname, const struct object_id *oid)
static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid,
int flag, void *cb_data)
{
- return rev_list_insert_ref(refname, oid);
-}
-
-static int clear_marks(const char *refname, const struct object_id *oid,
- int flag, void *cb_data)
-{
- struct object *o = deref_tag(parse_object(oid), refname, 0);
-
- if (o && o->type == OBJ_COMMIT)
- clear_commit_marks((struct commit *)o,
- COMMON | COMMON_REF | SEEN | POPPED);
- return 0;
-}
-
-/*
- This function marks a rev and its ancestors as common.
- In some cases, it is desirable to mark only the ancestors (for example
- when only the server does not yet know that they are common).
-*/
-
-static void mark_common(struct commit *commit,
- int ancestors_only, int dont_parse)
-{
- if (commit != NULL && !(commit->object.flags & COMMON)) {
- struct object *o = (struct object *)commit;
-
- if (!ancestors_only)
- o->flags |= COMMON;
-
- if (!(o->flags & SEEN))
- rev_list_push(commit, SEEN);
- else {
- struct commit_list *parents;
-
- if (!ancestors_only && !(o->flags & POPPED))
- non_common_revs--;
- if (!o->parsed && !dont_parse)
- if (parse_commit(commit))
- return;
-
- for (parents = commit->parents;
- parents;
- parents = parents->next)
- mark_common(parents->item, 0, dont_parse);
- }
- }
-}
-
-/*
- Get the next rev to send, ignoring the common.
-*/
-
-static const struct object_id *get_rev(void)
-{
- struct commit *commit = NULL;
-
- while (commit == NULL) {
- unsigned int mark;
- struct commit_list *parents;
-
- if (rev_list.nr == 0 || non_common_revs == 0)
- return NULL;
-
- commit = prio_queue_get(&rev_list);
- parse_commit(commit);
- parents = commit->parents;
-
- commit->object.flags |= POPPED;
- if (!(commit->object.flags & COMMON))
- non_common_revs--;
-
- if (commit->object.flags & COMMON) {
- /* do not send "have", and ignore ancestors */
- commit = NULL;
- mark = COMMON | SEEN;
- } else if (commit->object.flags & COMMON_REF)
- /* send "have", and ignore ancestors */
- mark = COMMON | SEEN;
- else
- /* send "have", also for its ancestors */
- mark = SEEN;
-
- while (parents) {
- if (!(parents->item->object.flags & SEEN))
- rev_list_push(parents->item, mark);
- if (mark & COMMON)
- mark_common(parents->item, 1, 0);
- parents = parents->next;
- }
- }
-
- return &commit->object.oid;
+ return rev_list_insert_ref(cb_data, refname, oid);
}
enum ack_type {
@@ -296,9 +192,10 @@ static void send_request(struct fetch_pack_args *args,
write_or_die(fd, buf->buf, buf->len);
}
-static void insert_one_alternate_object(struct object *obj)
+static void insert_one_alternate_object(struct fetch_negotiator *negotiator,
+ struct object *obj)
{
- rev_list_insert_ref(NULL, &obj->oid);
+ rev_list_insert_ref(negotiator, NULL, &obj->oid);
}
#define INITIAL_FLUSH 16
@@ -321,7 +218,24 @@ static int next_flush(int stateless_rpc, int count)
return count;
}
-static int find_common(struct fetch_pack_args *args,
+static void mark_tips(struct fetch_negotiator *negotiator,
+ const struct oid_array *negotiation_tips)
+{
+ int i;
+
+ if (!negotiation_tips) {
+ for_each_ref(rev_list_insert_ref_oid, negotiator);
+ return;
+ }
+
+ for (i = 0; i < negotiation_tips->nr; i++)
+ rev_list_insert_ref(negotiator, NULL,
+ &negotiation_tips->oid[i]);
+ return;
+}
+
+static int find_common(struct fetch_negotiator *negotiator,
+ struct fetch_pack_args *args,
int fd[2], struct object_id *result_oid,
struct ref *refs)
{
@@ -336,12 +250,9 @@ static int find_common(struct fetch_pack_args *args,
if (args->stateless_rpc && multi_ack == 1)
die(_("--stateless-rpc requires multi_ack_detailed"));
- if (marked)
- for_each_ref(clear_marks, NULL);
- marked = 1;
- for_each_ref(rev_list_insert_ref_oid, NULL);
- for_each_cached_alternate(insert_one_alternate_object);
+ mark_tips(negotiator, args->negotiation_tips);
+ for_each_cached_alternate(negotiator, insert_one_alternate_object);
fetching = 0;
for ( ; refs ; refs = refs->next) {
@@ -359,7 +270,7 @@ static int find_common(struct fetch_pack_args *args,
* interested in the case we *know* the object is
* reachable and we have already scanned it.
*/
- if (((o = lookup_object(remote->hash)) != NULL) &&
+ if (((o = lookup_object(the_repository, remote->hash)) != NULL) &&
(o->flags & COMPLETE)) {
continue;
}
@@ -396,7 +307,7 @@ static int find_common(struct fetch_pack_args *args,
return 1;
}
- if (is_repository_shallow())
+ if (is_repository_shallow(the_repository))
write_shallow_commits(&req_buf, 1, NULL);
if (args->depth > 0)
packet_buf_write(&req_buf, "deepen %d", args->depth);
@@ -427,16 +338,16 @@ static int find_common(struct fetch_pack_args *args,
if (skip_prefix(line, "shallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid shallow line: %s"), line);
- register_shallow(&oid);
+ register_shallow(the_repository, &oid);
continue;
}
if (skip_prefix(line, "unshallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid unshallow line: %s"), line);
- if (!lookup_object(oid.hash))
+ if (!lookup_object(the_repository, oid.hash))
die(_("object not found: %s"), line);
/* make sure that it is parsed as shallow */
- if (!parse_object(&oid))
+ if (!parse_object(the_repository, &oid))
die(_("error in object: %s"), line);
if (unregister_shallow(&oid))
die(_("no shallow found: %s"), line);
@@ -459,7 +370,7 @@ static int find_common(struct fetch_pack_args *args,
retval = -1;
if (args->no_dependents)
goto done;
- while ((oid = get_rev())) {
+ while ((oid = negotiator->next(negotiator))) {
packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
print_verbose(args, "have %s", oid_to_hex(oid));
in_vain++;
@@ -495,12 +406,16 @@ static int find_common(struct fetch_pack_args *args,
case ACK_ready:
case ACK_continue: {
struct commit *commit =
- lookup_commit(result_oid);
+ lookup_commit(the_repository,
+ result_oid);
+ int was_common;
+
if (!commit)
die(_("invalid commit %s"), oid_to_hex(result_oid));
+ was_common = negotiator->ack(negotiator, commit);
if (args->stateless_rpc
&& ack == ACK_common
- && !(commit->object.flags & COMMON)) {
+ && !was_common) {
/* We need to replay the have for this object
* on the next RPC request so the peer knows
* it is in common with us.
@@ -517,13 +432,10 @@ static int find_common(struct fetch_pack_args *args,
} else if (!args->stateless_rpc
|| ack != ACK_common)
in_vain = 0;
- mark_common(commit, 0, 1);
retval = 0;
got_continue = 1;
- if (ack == ACK_ready) {
- clear_prio_queue(&rev_list);
+ if (ack == ACK_ready)
got_ready = 1;
- }
break;
}
}
@@ -533,6 +445,8 @@ static int find_common(struct fetch_pack_args *args,
print_verbose(args, _("giving up"));
break; /* give up */
}
+ if (got_ready)
+ break;
}
}
done:
@@ -569,14 +483,14 @@ static struct commit_list *complete;
static int mark_complete(const struct object_id *oid)
{
- struct object *o = parse_object(oid);
+ struct object *o = parse_object(the_repository, oid);
while (o && o->type == OBJ_TAG) {
struct tag *t = (struct tag *) o;
if (!t->tagged)
break; /* broken repository */
o->flags |= COMPLETE;
- o = parse_object(&t->tagged->oid);
+ o = parse_object(the_repository, &t->tagged->oid);
}
if (o && o->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *)o;
@@ -707,7 +621,8 @@ static void filter_refs(struct fetch_pack_args *args,
*refs = newlist;
}
-static void mark_alternate_complete(struct object *obj)
+static void mark_alternate_complete(struct fetch_negotiator *unused,
+ struct object *obj)
{
mark_complete(&obj->oid);
}
@@ -734,12 +649,21 @@ static int add_loose_objects_to_set(const struct object_id *oid,
return 0;
}
-static int everything_local(struct fetch_pack_args *args,
- struct ref **refs,
- struct ref **sought, int nr_sought)
+/*
+ * Mark recent commits available locally and reachable from a local ref as
+ * COMPLETE. If args->no_dependents is false, also mark COMPLETE remote refs as
+ * COMMON_REF (otherwise, we are not planning to participate in negotiation, and
+ * thus do not need COMMON_REF marks).
+ *
+ * The cutoff time for recency is determined by this heuristic: it is the
+ * earliest commit time of the objects in refs that are commits and that we know
+ * the commit time of.
+ */
+static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
+ struct fetch_pack_args *args,
+ struct ref **refs)
{
struct ref *ref;
- int retval;
int old_save_commit_buffer = save_commit_buffer;
timestamp_t cutoff = 0;
struct oidset loose_oid_set = OIDSET_INIT;
@@ -767,7 +691,7 @@ static int everything_local(struct fetch_pack_args *args,
if (!has_object_file_with_flags(&ref->old_oid, flags))
continue;
- o = parse_object(&ref->old_oid);
+ o = parse_object(the_repository, &ref->old_oid);
if (!o)
continue;
@@ -787,7 +711,7 @@ static int everything_local(struct fetch_pack_args *args,
if (!args->no_dependents) {
if (!args->deepen) {
for_each_ref(mark_complete_oid, NULL);
- for_each_cached_alternate(mark_alternate_complete);
+ for_each_cached_alternate(NULL, mark_alternate_complete);
commit_list_sort_by_date(&complete);
if (cutoff)
mark_recent_complete_commits(args, cutoff);
@@ -798,27 +722,37 @@ static int everything_local(struct fetch_pack_args *args,
* Don't mark them common yet; the server has to be told so first.
*/
for (ref = *refs; ref; ref = ref->next) {
- struct object *o = deref_tag(lookup_object(ref->old_oid.hash),
+ struct object *o = deref_tag(the_repository,
+ lookup_object(the_repository,
+ ref->old_oid.hash),
NULL, 0);
if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
continue;
- if (!(o->flags & SEEN)) {
- rev_list_push((struct commit *)o, COMMON_REF | SEEN);
-
- mark_common((struct commit *)o, 1, 1);
- }
+ negotiator->known_common(negotiator,
+ (struct commit *)o);
}
}
- filter_refs(args, refs, sought, nr_sought);
+ save_commit_buffer = old_save_commit_buffer;
+}
+
+/*
+ * Returns 1 if every object pointed to by the given remote refs is available
+ * locally and reachable from a local ref, and 0 otherwise.
+ */
+static int everything_local(struct fetch_pack_args *args,
+ struct ref **refs)
+{
+ struct ref *ref;
+ int retval;
for (retval = 1, ref = *refs; ref ; ref = ref->next) {
const struct object_id *remote = &ref->old_oid;
struct object *o;
- o = lookup_object(remote->hash);
+ o = lookup_object(the_repository, remote->hash);
if (!o || !(o->flags & COMPLETE)) {
retval = 0;
print_verbose(args, "want %s (%s)", oid_to_hex(remote),
@@ -829,8 +763,6 @@ static int everything_local(struct fetch_pack_args *args,
ref->name);
}
- save_commit_buffer = old_save_commit_buffer;
-
return retval;
}
@@ -981,11 +913,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
struct object_id oid;
const char *agent_feature;
int agent_len;
+ struct fetch_negotiator negotiator;
+ fetch_negotiator_init(&negotiator, negotiation_algorithm);
sort_ref_list(&ref, ref_compare_name);
QSORT(sought, nr_sought, cmp_ref_by_name);
- if ((args->depth > 0 || is_repository_shallow()) && !server_supports("shallow"))
+ if ((args->depth > 0 || is_repository_shallow(the_repository)) && !server_supports("shallow"))
die(_("Server does not support shallow clients"));
if (args->depth > 0 || args->deepen_since || args->deepen_not)
args->deepen = 1;
@@ -1053,11 +987,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (!server_supports("deepen-relative") && args->deepen_relative)
die(_("Server does not support --deepen"));
- if (everything_local(args, &ref, sought, nr_sought)) {
+ mark_complete_and_common_ref(&negotiator, args, &ref);
+ filter_refs(args, &ref, sought, nr_sought);
+ if (everything_local(args, &ref)) {
packet_flush(fd[1]);
goto all_done;
}
- if (find_common(args, fd, &oid, ref) < 0)
+ if (find_common(&negotiator, args, fd, &oid, ref) < 0)
if (!args->keep_pack)
/* When cloning, it is not unusual to have
* no common commit.
@@ -1077,13 +1013,14 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
die(_("git fetch-pack: fetch failed."));
all_done:
+ negotiator.release(&negotiator);
return ref;
}
static void add_shallow_requests(struct strbuf *req_buf,
const struct fetch_pack_args *args)
{
- if (is_repository_shallow())
+ if (is_repository_shallow(the_repository))
write_shallow_commits(req_buf, 1, NULL);
if (args->depth > 0)
packet_buf_write(req_buf, "deepen %d", args->depth);
@@ -1102,9 +1039,10 @@ static void add_shallow_requests(struct strbuf *req_buf,
static void add_wants(const struct ref *wants, struct strbuf *req_buf)
{
+ int use_ref_in_want = server_supports_feature("fetch", "ref-in-want", 0);
+
for ( ; wants ; wants = wants->next) {
const struct object_id *remote = &wants->old_oid;
- const char *remote_hex;
struct object *o;
/*
@@ -1117,13 +1055,15 @@ static void add_wants(const struct ref *wants, struct strbuf *req_buf)
* interested in the case we *know* the object is
* reachable and we have already scanned it.
*/
- if (((o = lookup_object(remote->hash)) != NULL) &&
+ if (((o = lookup_object(the_repository, remote->hash)) != NULL) &&
(o->flags & COMPLETE)) {
continue;
}
- remote_hex = oid_to_hex(remote);
- packet_buf_write(req_buf, "want %s\n", remote_hex);
+ if (!use_ref_in_want || wants->exact_oid)
+ packet_buf_write(req_buf, "want %s\n", oid_to_hex(remote));
+ else
+ packet_buf_write(req_buf, "want-ref %s\n", wants->name);
}
}
@@ -1138,13 +1078,15 @@ static void add_common(struct strbuf *req_buf, struct oidset *common)
}
}
-static int add_haves(struct strbuf *req_buf, int *haves_to_send, int *in_vain)
+static int add_haves(struct fetch_negotiator *negotiator,
+ struct strbuf *req_buf,
+ int *haves_to_send, int *in_vain)
{
int ret = 0;
int haves_added = 0;
const struct object_id *oid;
- while ((oid = get_rev())) {
+ while ((oid = negotiator->next(negotiator))) {
packet_buf_write(req_buf, "have %s\n", oid_to_hex(oid));
if (++haves_added >= *haves_to_send)
break;
@@ -1163,7 +1105,8 @@ static int add_haves(struct strbuf *req_buf, int *haves_to_send, int *in_vain)
return ret;
}
-static int send_fetch_request(int fd_out, const struct fetch_pack_args *args,
+static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
+ const struct fetch_pack_args *args,
const struct ref *wants, struct oidset *common,
int *haves_to_send, int *in_vain)
{
@@ -1195,7 +1138,7 @@ static int send_fetch_request(int fd_out, const struct fetch_pack_args *args,
/* Add shallow-info and deepen request */
if (server_supports_feature("fetch", "shallow", 0))
add_shallow_requests(&req_buf, args);
- else if (is_repository_shallow() || args->deepen)
+ else if (is_repository_shallow(the_repository) || args->deepen)
die(_("Server does not support shallow requests"));
/* Add filter */
@@ -1219,7 +1162,7 @@ static int send_fetch_request(int fd_out, const struct fetch_pack_args *args,
add_common(&req_buf, common);
/* Add initial haves */
- ret = add_haves(&req_buf, haves_to_send, in_vain);
+ ret = add_haves(negotiator, &req_buf, haves_to_send, in_vain);
}
/* Send request */
@@ -1242,13 +1185,13 @@ static int process_section_header(struct packet_reader *reader,
int ret;
if (packet_reader_peek(reader) != PACKET_READ_NORMAL)
- die("error reading section header '%s'", section);
+ die(_("error reading section header '%s'"), section);
ret = !strcmp(reader->line, section);
if (!peek) {
if (!ret)
- die("expected '%s', received '%s'",
+ die(_("expected '%s', received '%s'"),
section, reader->line);
packet_reader_read(reader);
}
@@ -1256,7 +1199,9 @@ static int process_section_header(struct packet_reader *reader,
return ret;
}
-static int process_acks(struct packet_reader *reader, struct oidset *common)
+static int process_acks(struct fetch_negotiator *negotiator,
+ struct packet_reader *reader,
+ struct oidset *common)
{
/* received */
int received_ready = 0;
@@ -1274,24 +1219,23 @@ static int process_acks(struct packet_reader *reader, struct oidset *common)
if (!get_oid_hex(arg, &oid)) {
struct commit *commit;
oidset_insert(common, &oid);
- commit = lookup_commit(&oid);
- mark_common(commit, 0, 1);
+ commit = lookup_commit(the_repository, &oid);
+ negotiator->ack(negotiator, commit);
}
continue;
}
if (!strcmp(reader->line, "ready")) {
- clear_prio_queue(&rev_list);
received_ready = 1;
continue;
}
- die("unexpected acknowledgment line: '%s'", reader->line);
+ die(_("unexpected acknowledgment line: '%s'"), reader->line);
}
if (reader->status != PACKET_READ_FLUSH &&
reader->status != PACKET_READ_DELIM)
- die("error processing acks: %d", reader->status);
+ die(_("error processing acks: %d"), reader->status);
/* return 0 if no common, 1 if there are common, or 2 if ready */
return received_ready ? 2 : (received_ack ? 1 : 0);
@@ -1308,16 +1252,16 @@ static void receive_shallow_info(struct fetch_pack_args *args,
if (skip_prefix(reader->line, "shallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid shallow line: %s"), reader->line);
- register_shallow(&oid);
+ register_shallow(the_repository, &oid);
continue;
}
if (skip_prefix(reader->line, "unshallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid unshallow line: %s"), reader->line);
- if (!lookup_object(oid.hash))
+ if (!lookup_object(the_repository, oid.hash))
die(_("object not found: %s"), reader->line);
/* make sure that it is parsed as shallow */
- if (!parse_object(&oid))
+ if (!parse_object(the_repository, &oid))
die(_("error in object: %s"), reader->line);
if (unregister_shallow(&oid))
die(_("no shallow found: %s"), reader->line);
@@ -1328,12 +1272,38 @@ static void receive_shallow_info(struct fetch_pack_args *args,
if (reader->status != PACKET_READ_FLUSH &&
reader->status != PACKET_READ_DELIM)
- die("error processing shallow info: %d", reader->status);
+ die(_("error processing shallow info: %d"), reader->status);
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL);
args->deepen = 1;
}
+static void receive_wanted_refs(struct packet_reader *reader, struct ref *refs)
+{
+ process_section_header(reader, "wanted-refs", 0);
+ while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
+ struct object_id oid;
+ const char *end;
+ struct ref *r = NULL;
+
+ if (parse_oid_hex(reader->line, &oid, &end) || *end++ != ' ')
+ die(_("expected wanted-ref, got '%s'"), reader->line);
+
+ for (r = refs; r; r = r->next) {
+ if (!strcmp(end, r->name)) {
+ oidcpy(&r->old_oid, &oid);
+ break;
+ }
+ }
+
+ if (!r)
+ die(_("unexpected wanted-ref: '%s'"), reader->line);
+ }
+
+ if (reader->status != PACKET_READ_DELIM)
+ die(_("error processing wanted refs: %d"), reader->status);
+}
+
enum fetch_state {
FETCH_CHECK_LOCAL = 0,
FETCH_SEND_REQUEST,
@@ -1354,6 +1324,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct packet_reader reader;
int in_vain = 0;
int haves_to_send = INITIAL_FLUSH;
+ struct fetch_negotiator negotiator;
+ fetch_negotiator_init(&negotiator, negotiation_algorithm);
packet_reader_init(&reader, fd[0], NULL, 0,
PACKET_READ_CHOMP_NEWLINE);
@@ -1369,21 +1341,21 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
if (args->depth > 0 || args->deepen_since || args->deepen_not)
args->deepen = 1;
- if (marked)
- for_each_ref(clear_marks, NULL);
- marked = 1;
-
- for_each_ref(rev_list_insert_ref_oid, NULL);
- for_each_cached_alternate(insert_one_alternate_object);
-
/* Filter 'ref' by 'sought' and those that aren't local */
- if (everything_local(args, &ref, sought, nr_sought))
+ mark_complete_and_common_ref(&negotiator, args, &ref);
+ filter_refs(args, &ref, sought, nr_sought);
+ if (everything_local(args, &ref))
state = FETCH_DONE;
else
state = FETCH_SEND_REQUEST;
+
+ mark_tips(&negotiator, args->negotiation_tips);
+ for_each_cached_alternate(&negotiator,
+ insert_one_alternate_object);
break;
case FETCH_SEND_REQUEST:
- if (send_fetch_request(fd[1], args, ref, &common,
+ if (send_fetch_request(&negotiator, fd[1], args, ref,
+ &common,
&haves_to_send, &in_vain))
state = FETCH_GET_PACK;
else
@@ -1391,7 +1363,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
break;
case FETCH_PROCESS_ACKS:
/* Process ACKs/NAKs */
- switch (process_acks(&reader, &common)) {
+ switch (process_acks(&negotiator, &reader, &common)) {
case 2:
state = FETCH_GET_PACK;
break;
@@ -1408,6 +1380,9 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
if (process_section_header(&reader, "shallow-info", 1))
receive_shallow_info(args, &reader);
+ if (process_section_header(&reader, "wanted-refs", 1))
+ receive_wanted_refs(&reader, ref);
+
/* get the pack */
process_section_header(&reader, "packfile", 0);
if (get_pack(args, fd, pack_lockfile))
@@ -1420,6 +1395,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
}
}
+ negotiator.release(&negotiator);
oidset_clear(&common);
return ref;
}
@@ -1431,6 +1407,8 @@ static void fetch_pack_config(void)
git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
+ git_config_get_string("fetch.negotiationalgorithm",
+ &negotiation_algorithm);
git_config(git_default_config, NULL);
}
@@ -1470,16 +1448,17 @@ static int remove_duplicates_in_refs(struct ref **ref, int nr)
}
static void update_shallow(struct fetch_pack_args *args,
- struct ref **sought, int nr_sought,
+ struct ref *refs,
struct shallow_info *si)
{
struct oid_array ref = OID_ARRAY_INIT;
int *status;
int i;
+ struct ref *r;
if (args->deepen && alternate_shallow_file) {
if (*alternate_shallow_file == '\0') { /* --unshallow */
- unlink_or_warn(git_path_shallow());
+ unlink_or_warn(git_path_shallow(the_repository));
rollback_lock_file(&shallow_lock);
} else
commit_lock_file(&shallow_lock);
@@ -1517,8 +1496,8 @@ static void update_shallow(struct fetch_pack_args *args,
remove_nonexistent_theirs_shallow(si);
if (!si->nr_ours && !si->nr_theirs)
return;
- for (i = 0; i < nr_sought; i++)
- oid_array_append(&ref, &sought[i]->old_oid);
+ for (r = refs; r; r = r->next)
+ oid_array_append(&ref, &r->old_oid);
si->ref = &ref;
if (args->update_shallow) {
@@ -1552,17 +1531,29 @@ static void update_shallow(struct fetch_pack_args *args,
* remote is also shallow, check what ref is safe to update
* without updating .git/shallow
*/
- status = xcalloc(nr_sought, sizeof(*status));
+ status = xcalloc(ref.nr, sizeof(*status));
assign_shallow_commits_to_refs(si, NULL, status);
if (si->nr_ours || si->nr_theirs) {
- for (i = 0; i < nr_sought; i++)
+ for (r = refs, i = 0; r; r = r->next, i++)
if (status[i])
- sought[i]->status = REF_STATUS_REJECT_SHALLOW;
+ r->status = REF_STATUS_REJECT_SHALLOW;
}
free(status);
oid_array_clear(&ref);
}
+static int iterate_ref_map(void *cb_data, struct object_id *oid)
+{
+ struct ref **rm = cb_data;
+ struct ref *ref = *rm;
+
+ if (!ref)
+ return -1; /* end of the list */
+ *rm = ref->next;
+ oidcpy(oid, &ref->old_oid);
+ return 0;
+}
+
struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
const struct ref *ref,
@@ -1591,7 +1582,25 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
&si, pack_lockfile);
reprepare_packed_git(the_repository);
- update_shallow(args, sought, nr_sought, &si);
+
+ if (!args->cloning && args->deepen) {
+ struct check_connected_options opt = CHECK_CONNECTED_INIT;
+ struct ref *iterator = ref_cpy;
+ opt.shallow_file = alternate_shallow_file;
+ if (args->deepen)
+ opt.is_deepening_fetch = 1;
+ if (check_connected(iterate_ref_map, &iterator, &opt)) {
+ error(_("remote did not send all necessary objects"));
+ free_refs(ref_cpy);
+ ref_cpy = NULL;
+ rollback_lock_file(&shallow_lock);
+ goto cleanup;
+ }
+ args->connectivity_checked = 1;
+ }
+
+ update_shallow(args, ref_cpy, &si);
+cleanup:
clear_shallow_info(&si);
return ref_cpy;
}
diff --git a/fetch-pack.h b/fetch-pack.h
index bb45a36..5b6e868 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -16,6 +16,13 @@ struct fetch_pack_args {
const struct string_list *deepen_not;
struct list_objects_filter_options filter_options;
const struct string_list *server_options;
+
+ /*
+ * If not NULL, during packfile negotiation, fetch-pack will send "have"
+ * lines only with these tips and their ancestors.
+ */
+ const struct oid_array *negotiation_tips;
+
unsigned deepen_relative:1;
unsigned quiet:1;
unsigned keep_pack:1;
@@ -41,6 +48,21 @@ struct fetch_pack_args {
* regardless of which object flags it uses (if any).
*/
unsigned no_dependents:1;
+
+ /*
+ * Because fetch_pack() overwrites the shallow file upon a
+ * successful deepening non-clone fetch, if this struct
+ * specifies such a fetch, fetch_pack() needs to perform a
+ * connectivity check before deciding if a fetch is successful
+ * (and overwriting the shallow file). fetch_pack() sets this
+ * field to 1 if such a connectivity check was performed.
+ *
+ * This is different from check_self_contained_and_connected
+ * in that the former allows existing objects in the
+ * repository to satisfy connectivity needs, whereas the
+ * latter doesn't.
+ */
+ unsigned connectivity_checked:1;
};
/*
diff --git a/fsck.c b/fsck.c
index 0b8b20b..a0cee0b 100644
--- a/fsck.c
+++ b/fsck.c
@@ -1,4 +1,6 @@
#include "cache.h"
+#include "object-store.h"
+#include "repository.h"
#include "object.h"
#include "blob.h"
#include "tree.h"
@@ -62,7 +64,7 @@ static struct oidset gitmodules_done = OIDSET_INIT;
FUNC(ZERO_PADDED_DATE, ERROR) \
FUNC(GITMODULES_MISSING, ERROR) \
FUNC(GITMODULES_BLOB, ERROR) \
- FUNC(GITMODULES_PARSE, ERROR) \
+ FUNC(GITMODULES_LARGE, ERROR) \
FUNC(GITMODULES_NAME, ERROR) \
FUNC(GITMODULES_SYMLINK, ERROR) \
/* warnings */ \
@@ -76,6 +78,7 @@ static struct oidset gitmodules_done = OIDSET_INIT;
FUNC(ZERO_PADDED_FILEMODE, WARN) \
FUNC(NUL_IN_COMMIT, WARN) \
/* infos (reported as warnings, but ignored by default) */ \
+ FUNC(GITMODULES_PARSE, INFO) \
FUNC(BAD_TAG_NAME, INFO) \
FUNC(MISSING_TAGGER_ENTRY, INFO)
@@ -315,6 +318,13 @@ static void append_msg_id(struct strbuf *sb, const char *msg_id)
strbuf_addstr(sb, ": ");
}
+static int object_on_skiplist(struct fsck_options *opts, struct object *obj)
+{
+ if (opts && opts->skiplist && obj)
+ return oid_array_lookup(opts->skiplist, &obj->oid) >= 0;
+ return 0;
+}
+
__attribute__((format (printf, 4, 5)))
static int report(struct fsck_options *options, struct object *object,
enum fsck_msg_id id, const char *fmt, ...)
@@ -326,8 +336,7 @@ static int report(struct fsck_options *options, struct object *object,
if (msg_type == FSCK_IGNORE)
return 0;
- if (options->skiplist && object &&
- oid_array_lookup(options->skiplist, &object->oid) >= 0)
+ if (object_on_skiplist(options, object))
return 0;
if (msg_type == FSCK_FATAL)
@@ -405,14 +414,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
continue;
if (S_ISDIR(entry.mode)) {
- obj = (struct object *)lookup_tree(entry.oid);
+ obj = (struct object *)lookup_tree(the_repository, entry.oid);
if (name && obj)
put_object_name(options, obj, "%s%s/", name,
entry.path);
result = options->walk(obj, OBJ_TREE, data, options);
}
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
- obj = (struct object *)lookup_blob(entry.oid);
+ obj = (struct object *)lookup_blob(the_repository, entry.oid);
if (name && obj)
put_object_name(options, obj, "%s%s", name,
entry.path);
@@ -510,7 +519,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
return -1;
if (obj->type == OBJ_NONE)
- parse_object(&obj->oid);
+ parse_object(the_repository, &obj->oid);
switch (obj->type) {
case OBJ_BLOB:
@@ -795,7 +804,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
buffer = p + 1;
parent_line_count++;
}
- graft = lookup_commit_graft(&commit->object.oid);
+ graft = lookup_commit_graft(the_repository, &commit->object.oid);
parent_count = commit_list_count(commit->parents);
if (graft) {
if (graft->nr_parent == -1 && !parent_count)
@@ -992,11 +1001,15 @@ static int fsck_blob(struct blob *blob, const char *buf,
unsigned long size, struct fsck_options *options)
{
struct fsck_gitmodules_data data;
+ struct config_options config_opts = { 0 };
if (!oidset_contains(&gitmodules_found, &blob->object.oid))
return 0;
oidset_insert(&gitmodules_done, &blob->object.oid);
+ if (object_on_skiplist(options, &blob->object))
+ return 0;
+
if (!buf) {
/*
* A missing buffer here is a sign that the caller found the
@@ -1004,15 +1017,16 @@ static int fsck_blob(struct blob *blob, const char *buf,
* that an error.
*/
return report(options, &blob->object,
- FSCK_MSG_GITMODULES_PARSE,
+ FSCK_MSG_GITMODULES_LARGE,
".gitmodules too large to parse");
}
data.obj = &blob->object;
data.options = options;
data.ret = 0;
+ config_opts.error_action = CONFIG_ERROR_SILENT;
if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
- ".gitmodules", buf, size, &data))
+ ".gitmodules", buf, size, &data, &config_opts))
data.ret |= report(options, &blob->object,
FSCK_MSG_GITMODULES_PARSE,
"could not parse gitmodules blob");
@@ -1068,7 +1082,7 @@ int fsck_finish(struct fsck_options *options)
if (oidset_contains(&gitmodules_done, oid))
continue;
- blob = lookup_blob(oid);
+ blob = lookup_blob(the_repository, oid);
if (!blob) {
struct object *obj = lookup_unknown_object(oid->hash);
ret |= report(options, obj,
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index ccceaf1..5c5afa2 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -372,6 +372,7 @@ while read commit parents; do
git_filter_branch__commit_count=$(($git_filter_branch__commit_count+1))
report_progress
+ test -f "$workdir"/../map/$commit && continue
case "$filter_subdir" in
"")
diff --git a/git-p4.py b/git-p4.py
index 0354d4d..b449db1 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -27,6 +27,22 @@ import zlib
import ctypes
import errno
+# support basestring in python3
+try:
+ unicode = unicode
+except NameError:
+ # 'unicode' is undefined, must be Python 3
+ str = str
+ unicode = str
+ bytes = bytes
+ basestring = (str,bytes)
+else:
+ # 'unicode' exists, must be Python 2
+ str = str
+ unicode = unicode
+ bytes = str
+ basestring = basestring
+
try:
from subprocess import CalledProcessError
except ImportError:
@@ -767,7 +783,7 @@ def gitDeleteRef(ref):
_gitConfig = {}
def gitConfig(key, typeSpecifier=None):
- if not _gitConfig.has_key(key):
+ if key not in _gitConfig:
cmd = [ "git", "config" ]
if typeSpecifier:
cmd += [ typeSpecifier ]
@@ -781,12 +797,12 @@ def gitConfigBool(key):
variable is set to true, and False if set to false or not present
in the config."""
- if not _gitConfig.has_key(key):
+ if key not in _gitConfig:
_gitConfig[key] = gitConfig(key, '--bool') == "true"
return _gitConfig[key]
def gitConfigInt(key):
- if not _gitConfig.has_key(key):
+ if key not in _gitConfig:
cmd = [ "git", "config", "--int", key ]
s = read_pipe(cmd, ignore_error=True)
v = s.strip()
@@ -797,7 +813,7 @@ def gitConfigInt(key):
return _gitConfig[key]
def gitConfigList(key):
- if not _gitConfig.has_key(key):
+ if key not in _gitConfig:
s = read_pipe(["git", "config", "--get-all", key], ignore_error=True)
_gitConfig[key] = s.strip().splitlines()
if _gitConfig[key] == ['']:
@@ -855,7 +871,7 @@ def findUpstreamBranchPoint(head = "HEAD"):
tip = branches[branch]
log = extractLogMessageFromGitCommit(tip)
settings = extractSettingsGitLog(log)
- if settings.has_key("depot-paths"):
+ if "depot-paths" in settings:
paths = ",".join(settings["depot-paths"])
branchByDepotPath[paths] = "remotes/p4/" + branch
@@ -865,9 +881,9 @@ def findUpstreamBranchPoint(head = "HEAD"):
commit = head + "~%s" % parent
log = extractLogMessageFromGitCommit(commit)
settings = extractSettingsGitLog(log)
- if settings.has_key("depot-paths"):
+ if "depot-paths" in settings:
paths = ",".join(settings["depot-paths"])
- if branchByDepotPath.has_key(paths):
+ if paths in branchByDepotPath:
return [branchByDepotPath[paths], settings]
parent = parent + 1
@@ -876,7 +892,7 @@ def findUpstreamBranchPoint(head = "HEAD"):
def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent=True):
if not silent:
- print ("Creating/updating branch(es) in %s based on origin branch(es)"
+ print("Creating/updating branch(es) in %s based on origin branch(es)"
% localRefPrefix)
originPrefix = "origin/p4/"
@@ -891,29 +907,29 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent
originHead = line
original = extractSettingsGitLog(extractLogMessageFromGitCommit(originHead))
- if (not original.has_key('depot-paths')
- or not original.has_key('change')):
+ if ('depot-paths' not in original
+ or 'change' not in original):
continue
update = False
if not gitBranchExists(remoteHead):
if verbose:
- print "creating %s" % remoteHead
+ print("creating %s" % remoteHead)
update = True
else:
settings = extractSettingsGitLog(extractLogMessageFromGitCommit(remoteHead))
- if settings.has_key('change') > 0:
+ if 'change' in settings:
if settings['depot-paths'] == original['depot-paths']:
originP4Change = int(original['change'])
p4Change = int(settings['change'])
if originP4Change > p4Change:
- print ("%s (%s) is newer than %s (%s). "
+ print("%s (%s) is newer than %s (%s). "
"Updating p4 branch from origin."
% (originHead, originP4Change,
remoteHead, p4Change))
update = True
else:
- print ("Ignoring: %s was imported from %s while "
+ print("Ignoring: %s was imported from %s while "
"%s was imported from %s"
% (originHead, ','.join(original['depot-paths']),
remoteHead, ','.join(settings['depot-paths'])))
@@ -1002,7 +1018,7 @@ def p4ChangesForPaths(depotPaths, changeRange, requestedBlockSize):
# Insert changes in chronological order
for entry in reversed(result):
- if not entry.has_key('change'):
+ if 'change' not in entry:
continue
changes.add(int(entry['change']))
@@ -1312,7 +1328,7 @@ class P4UserMap:
results = p4CmdList("user -o")
for r in results:
- if r.has_key('User'):
+ if 'User' in r:
self.myP4UserId = r['User']
return r['User']
die("Could not find your p4 user id")
@@ -1336,7 +1352,7 @@ class P4UserMap:
self.emails = {}
for output in p4CmdList("users"):
- if not output.has_key("User"):
+ if "User" not in output:
continue
self.users[output["User"]] = output["FullName"] + " <" + output["Email"] + ">"
self.emails[output["Email"]] = output["User"]
@@ -1381,9 +1397,9 @@ class P4Debug(Command):
def run(self, args):
j = 0
for output in p4CmdList(args):
- print 'Element: %d' % j
+ print('Element: %d' % j)
j += 1
- print output
+ print(output)
return True
class P4RollBack(Command):
@@ -1424,14 +1440,14 @@ class P4RollBack(Command):
if len(p4Cmd("changes -m 1 " + ' '.join (['%s...@%s' % (p, maxChange)
for p in depotPaths]))) == 0:
- print "Branch %s did not exist at change %s, deleting." % (ref, maxChange)
+ print("Branch %s did not exist at change %s, deleting." % (ref, maxChange))
system("git update-ref -d %s `git rev-parse %s`" % (ref, ref))
continue
while change and int(change) > maxChange:
changed = True
if self.verbose:
- print "%s is at %s ; rewinding towards %s" % (ref, change, maxChange)
+ print("%s is at %s ; rewinding towards %s" % (ref, change, maxChange))
system("git update-ref %s \"%s^\"" % (ref, ref))
log = extractLogMessageFromGitCommit(ref)
settings = extractSettingsGitLog(log)
@@ -1441,7 +1457,7 @@ class P4RollBack(Command):
change = settings['change']
if changed:
- print "%s rewound to %s" % (ref, change)
+ print("%s rewound to %s" % (ref, change))
return True
@@ -1577,10 +1593,10 @@ class P4Submit(Command, P4UserMap):
except:
# cleanup our temporary file
os.unlink(outFileName)
- print "Failed to strip RCS keywords in %s" % file
+ print("Failed to strip RCS keywords in %s" % file)
raise
- print "Patched up RCS keywords in %s" % file
+ print("Patched up RCS keywords in %s" % file)
def p4UserForCommit(self,id):
# Return the tuple (perforce user,git email) for a given git commit id
@@ -1588,7 +1604,7 @@ class P4Submit(Command, P4UserMap):
gitEmail = read_pipe(["git", "log", "--max-count=1",
"--format=%ae", id])
gitEmail = gitEmail.strip()
- if not self.emails.has_key(gitEmail):
+ if gitEmail not in self.emails:
return (None,gitEmail)
else:
return (self.emails[gitEmail],gitEmail)
@@ -1600,7 +1616,7 @@ class P4Submit(Command, P4UserMap):
if not user:
msg = "Cannot find p4 user for email %s in commit %s." % (email, id)
if gitConfigBool("git-p4.allowMissingP4Users"):
- print "%s" % msg
+ print("%s" % msg)
else:
die("Error: %s\nSet git-p4.allowMissingP4Users to true to allow this." % msg)
@@ -1612,14 +1628,14 @@ class P4Submit(Command, P4UserMap):
results = p4CmdList("client -o") # find the current client
client = None
for r in results:
- if r.has_key('Client'):
+ if 'Client' in r:
client = r['Client']
break
if not client:
die("could not get client spec")
results = p4CmdList(["changes", "-c", client, "-m", "1"])
for r in results:
- if r.has_key('change'):
+ if 'change' in r:
return r['change']
die("Could not get changelist number for last submit - cannot patch up user details")
@@ -1637,10 +1653,10 @@ class P4Submit(Command, P4UserMap):
result = p4CmdList("change -f -i", stdin=input)
for r in result:
- if r.has_key('code'):
+ if 'code' in r:
if r['code'] == 'error':
die("Could not modify user field of changelist %s to %s:%s" % (changelist, newUser, r['data']))
- if r.has_key('data'):
+ if 'data' in r:
print("Updated user field for changelist %s to %s" % (changelist, newUser))
return
die("Could not modify user field of changelist %s to %s" % (changelist, newUser))
@@ -1650,7 +1666,7 @@ class P4Submit(Command, P4UserMap):
# which are required to modify changelists.
results = p4CmdList(["protects", self.depotPath])
for r in results:
- if r.has_key('perm'):
+ if 'perm' in r:
if r['perm'] == 'admin':
return 1
if r['perm'] == 'super':
@@ -1690,7 +1706,7 @@ class P4Submit(Command, P4UserMap):
if changelist:
args.append(str(changelist))
for entry in p4CmdList(args):
- if not entry.has_key('code'):
+ if 'code' not in entry:
continue
if entry['code'] == 'stat':
change_entry = entry
@@ -1699,7 +1715,7 @@ class P4Submit(Command, P4UserMap):
die('Failed to decode output of p4 change -o')
for key, value in change_entry.iteritems():
if key.startswith('File'):
- if settings.has_key('depot-paths'):
+ if 'depot-paths' in settings:
if not [p for p in settings['depot-paths']
if p4PathStartsWith(value, p)]:
continue
@@ -1710,7 +1726,7 @@ class P4Submit(Command, P4UserMap):
continue
# Output in the order expected by prepareLogMessage
for key in ['Change', 'Client', 'User', 'Status', 'Description', 'Jobs']:
- if not change_entry.has_key(key):
+ if key not in change_entry:
continue
template += '\n'
template += key + ':'
@@ -1738,7 +1754,7 @@ class P4Submit(Command, P4UserMap):
mtime = os.stat(template_file).st_mtime
# invoke the editor
- if os.environ.has_key("P4EDITOR") and (os.environ.get("P4EDITOR") != ""):
+ if "P4EDITOR" in os.environ and (os.environ.get("P4EDITOR") != ""):
editor = os.environ.get("P4EDITOR")
else:
editor = read_pipe("git var GIT_EDITOR").strip()
@@ -1762,7 +1778,7 @@ class P4Submit(Command, P4UserMap):
def get_diff_description(self, editedFiles, filesToAdd, symlinks):
# diff
- if os.environ.has_key("P4DIFF"):
+ if "P4DIFF" in os.environ:
del(os.environ["P4DIFF"])
diff = ""
for editedFile in editedFiles:
@@ -1792,8 +1808,8 @@ class P4Submit(Command, P4UserMap):
def applyCommit(self, id):
"""Apply one commit, return True if it succeeded."""
- print "Applying", read_pipe(["git", "show", "-s",
- "--format=format:%h %s", id])
+ print("Applying", read_pipe(["git", "show", "-s",
+ "--format=format:%h %s", id]))
(p4User, gitEmail) = self.p4UserForCommit(id)
@@ -1825,7 +1841,7 @@ class P4Submit(Command, P4UserMap):
filesToDelete.remove(path)
dst_mode = int(diff['dst_mode'], 8)
- if dst_mode == 0120000:
+ if dst_mode == 0o120000:
symlinks.add(path)
elif modifier == "D":
@@ -1883,7 +1899,7 @@ class P4Submit(Command, P4UserMap):
if os.system(tryPatchCmd) != 0:
fixed_rcs_keywords = False
patch_succeeded = False
- print "Unfortunately applying the change failed!"
+ print("Unfortunately applying the change failed!")
# Patch failed, maybe it's just RCS keyword woes. Look through
# the patch to see if that's possible.
@@ -1901,13 +1917,13 @@ class P4Submit(Command, P4UserMap):
for line in read_pipe_lines(["git", "diff", "%s^..%s" % (id, id), file]):
if regexp.search(line):
if verbose:
- print "got keyword match on %s in %s in %s" % (pattern, line, file)
+ print("got keyword match on %s in %s in %s" % (pattern, line, file))
kwfiles[file] = pattern
break
for file in kwfiles:
if verbose:
- print "zapping %s with %s" % (line,pattern)
+ print("zapping %s with %s" % (line,pattern))
# File is being deleted, so not open in p4. Must
# disable the read-only bit on windows.
if self.isWindows and file not in editedFiles:
@@ -1916,7 +1932,7 @@ class P4Submit(Command, P4UserMap):
fixed_rcs_keywords = True
if fixed_rcs_keywords:
- print "Retrying the patch with RCS keywords cleaned up"
+ print("Retrying the patch with RCS keywords cleaned up")
if os.system(tryPatchCmd) == 0:
patch_succeeded = True
@@ -1984,34 +2000,34 @@ class P4Submit(Command, P4UserMap):
# Leave the p4 tree prepared, and the submit template around
# and let the user decide what to do next
#
- print
- print "P4 workspace prepared for submission."
- print "To submit or revert, go to client workspace"
- print " " + self.clientPath
- print
- print "To submit, use \"p4 submit\" to write a new description,"
- print "or \"p4 submit -i <%s\" to use the one prepared by" \
- " \"git p4\"." % fileName
- print "You can delete the file \"%s\" when finished." % fileName
+ print()
+ print("P4 workspace prepared for submission.")
+ print("To submit or revert, go to client workspace")
+ print(" " + self.clientPath)
+ print()
+ print("To submit, use \"p4 submit\" to write a new description,")
+ print("or \"p4 submit -i <%s\" to use the one prepared by" \
+ " \"git p4\"." % fileName)
+ print("You can delete the file \"%s\" when finished." % fileName)
if self.preserveUser and p4User and not self.p4UserIsMe(p4User):
- print "To preserve change ownership by user %s, you must\n" \
+ print("To preserve change ownership by user %s, you must\n" \
"do \"p4 change -f <change>\" after submitting and\n" \
- "edit the User field."
+ "edit the User field.")
if pureRenameCopy:
- print "After submitting, renamed files must be re-synced."
- print "Invoke \"p4 sync -f\" on each of these files:"
+ print("After submitting, renamed files must be re-synced.")
+ print("Invoke \"p4 sync -f\" on each of these files:")
for f in pureRenameCopy:
- print " " + f
+ print(" " + f)
- print
- print "To revert the changes, use \"p4 revert ...\", and delete"
- print "the submit template file \"%s\"" % fileName
+ print()
+ print("To revert the changes, use \"p4 revert ...\", and delete")
+ print("the submit template file \"%s\"" % fileName)
if filesToAdd:
- print "Since the commit adds new files, they must be deleted:"
+ print("Since the commit adds new files, they must be deleted:")
for f in filesToAdd:
- print " " + f
- print
+ print(" " + f)
+ print()
return True
#
@@ -2078,17 +2094,17 @@ class P4Submit(Command, P4UserMap):
if not m.match(name):
if verbose:
- print "tag %s does not match regexp %s" % (name, validLabelRegexp)
+ print("tag %s does not match regexp %s" % (name, validLabelRegexp))
continue
# Get the p4 commit this corresponds to
logMessage = extractLogMessageFromGitCommit(name)
values = extractSettingsGitLog(logMessage)
- if not values.has_key('change'):
+ if 'change' not in values:
# a tag pointing to something not sent to p4; ignore
if verbose:
- print "git tag %s does not give a p4 commit" % name
+ print("git tag %s does not give a p4 commit" % name)
continue
else:
changelist = values['change']
@@ -2123,10 +2139,10 @@ class P4Submit(Command, P4UserMap):
labelTemplate += "\t%s\n" % depot_side
if self.dry_run:
- print "Would create p4 label %s for tag" % name
+ print("Would create p4 label %s for tag" % name)
elif self.prepare_p4_only:
- print "Not creating p4 label %s for tag due to option" \
- " --prepare-p4-only" % name
+ print("Not creating p4 label %s for tag due to option" \
+ " --prepare-p4-only" % name)
else:
p4_write_pipe(["label", "-i"], labelTemplate)
@@ -2135,7 +2151,7 @@ class P4Submit(Command, P4UserMap):
["%s@%s" % (depot_side, changelist) for depot_side in clientSpec.mappings])
if verbose:
- print "created p4 label for tag %s" % name
+ print("created p4 label for tag %s" % name)
def run(self, args):
if len(args) == 0:
@@ -2179,10 +2195,10 @@ class P4Submit(Command, P4UserMap):
self.conflict_behavior = val
if self.verbose:
- print "Origin branch is " + self.origin
+ print("Origin branch is " + self.origin)
if len(self.depotPath) == 0:
- print "Internal error: cannot locate perforce depot path from existing branches"
+ print("Internal error: cannot locate perforce depot path from existing branches")
sys.exit(128)
self.useClientSpec = False
@@ -2203,7 +2219,7 @@ class P4Submit(Command, P4UserMap):
if self.clientPath == "":
die("Error: Cannot locate perforce checkout of %s in client view" % self.depotPath)
- print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath)
+ print("Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath))
self.oldWorkingDirectory = os.getcwd()
# ensure the clientPath exists
@@ -2214,9 +2230,9 @@ class P4Submit(Command, P4UserMap):
chdir(self.clientPath, is_client_path=True)
if self.dry_run:
- print "Would synchronize p4 checkout in %s" % self.clientPath
+ print("Would synchronize p4 checkout in %s" % self.clientPath)
else:
- print "Synchronizing p4 checkout..."
+ print("Synchronizing p4 checkout...")
if new_client_dir:
# old one was destroyed, and maybe nobody told p4
p4_sync("...", "-f")
@@ -2292,13 +2308,13 @@ class P4Submit(Command, P4UserMap):
# continue to try the rest of the patches, or quit.
#
if self.dry_run:
- print "Would apply"
+ print("Would apply")
applied = []
last = len(commits) - 1
for i, commit in enumerate(commits):
if self.dry_run:
- print " ", read_pipe(["git", "show", "-s",
- "--format=format:%h %s", commit])
+ print(" ", read_pipe(["git", "show", "-s",
+ "--format=format:%h %s", commit]))
ok = True
else:
ok = self.applyCommit(commit)
@@ -2306,15 +2322,15 @@ class P4Submit(Command, P4UserMap):
applied.append(commit)
else:
if self.prepare_p4_only and i < last:
- print "Processing only the first commit due to option" \
- " --prepare-p4-only"
+ print("Processing only the first commit due to option" \
+ " --prepare-p4-only")
break
if i < last:
quit = False
while True:
# prompt for what to do, or use the option/variable
if self.conflict_behavior == "ask":
- print "What do you want to do?"
+ print("What do you want to do?")
response = raw_input("[s]kip this commit but apply"
" the rest, or [q]uit? ")
if not response:
@@ -2328,10 +2344,10 @@ class P4Submit(Command, P4UserMap):
self.conflict_behavior)
if response[0] == "s":
- print "Skipping this commit, but applying the rest"
+ print("Skipping this commit, but applying the rest")
break
if response[0] == "q":
- print "Quitting"
+ print("Quitting")
quit = True
break
if quit:
@@ -2344,7 +2360,7 @@ class P4Submit(Command, P4UserMap):
elif self.prepare_p4_only:
pass
elif len(commits) == len(applied):
- print ("All commits {0}!".format(shelved_applied))
+ print("All commits {0}!".format(shelved_applied))
sync = P4Sync()
if self.branch:
@@ -2360,17 +2376,17 @@ class P4Submit(Command, P4UserMap):
else:
if len(applied) == 0:
- print ("No commits {0}.".format(shelved_applied))
+ print("No commits {0}.".format(shelved_applied))
else:
- print ("{0} only the commits marked with '*':".format(shelved_applied.capitalize()))
+ print("{0} only the commits marked with '*':".format(shelved_applied.capitalize()))
for c in commits:
if c in applied:
star = "*"
else:
star = " "
- print star, read_pipe(["git", "show", "-s",
- "--format=format:%h %s", c])
- print "You will have to do 'git p4 sync' and rebase."
+ print(star, read_pipe(["git", "show", "-s",
+ "--format=format:%h %s", c]))
+ print("You will have to do 'git p4 sync' and rebase.")
if gitConfigBool("git-p4.exportLabels"):
self.exportLabels = True
@@ -2580,7 +2596,7 @@ class P4Sync(Command, P4UserMap):
self.gitStream.write("progress checkpoint\n\n")
out = self.gitOutput.readline()
if self.verbose:
- print "checkpoint finished: " + out
+ print("checkpoint finished: " + out)
def cmp_shelved(self, path, filerev, revision):
""" Determine if a path at revision #filerev is the same as the file
@@ -2600,7 +2616,7 @@ class P4Sync(Command, P4UserMap):
for path in self.cloneExclude]
files = []
fnum = 0
- while commit.has_key("depotFile%s" % fnum):
+ while "depotFile%s" % fnum in commit:
path = commit["depotFile%s" % fnum]
if [p for p in self.cloneExclude
@@ -2638,7 +2654,7 @@ class P4Sync(Command, P4UserMap):
def extractJobsFromCommit(self, commit):
jobs = []
jnum = 0
- while commit.has_key("job%s" % jnum):
+ while "job%s" % jnum in commit:
job = commit["job%s" % jnum]
jobs.append(job)
jnum = jnum + 1
@@ -2686,7 +2702,7 @@ class P4Sync(Command, P4UserMap):
branches = {}
fnum = 0
- while commit.has_key("depotFile%s" % fnum):
+ while "depotFile%s" % fnum in commit:
path = commit["depotFile%s" % fnum]
found = [p for p in self.depotPaths
if p4PathStartsWith(path, p)]
@@ -2735,7 +2751,7 @@ class P4Sync(Command, P4UserMap):
encoding = gitConfig('git-p4.pathEncoding')
path = path.decode(encoding, 'replace').encode('utf8', 'replace')
if self.verbose:
- print 'Path with non-ASCII characters detected. Used %s to encode: %s ' % (encoding, path)
+ print('Path with non-ASCII characters detected. Used %s to encode: %s ' % (encoding, path))
return path
# output one file from the P4 stream
@@ -2764,7 +2780,7 @@ class P4Sync(Command, P4UserMap):
# to nothing. This causes p4 errors when checking out such
# a change, and errors here too. Work around it by ignoring
# the bad symlink; hopefully a future change fixes it.
- print "\nIgnoring empty symlink in %s" % file['depotFile']
+ print("\nIgnoring empty symlink in %s" % file['depotFile'])
return
elif data[-1] == '\n':
contents = [data[:-1]]
@@ -2804,7 +2820,7 @@ class P4Sync(Command, P4UserMap):
# Ideally, someday, this script can learn how to generate
# appledouble files directly and import those to git, but
# non-mac machines can never find a use for apple filetype.
- print "\nIgnoring apple filetype file %s" % file['depotFile']
+ print("\nIgnoring apple filetype file %s" % file['depotFile'])
return
# Note that we do not try to de-mangle keywords on utf16 files,
@@ -2866,7 +2882,7 @@ class P4Sync(Command, P4UserMap):
else:
die("Error from p4 print: %s" % err)
- if marshalled.has_key('depotFile') and self.stream_have_file_info:
+ if 'depotFile' in marshalled and self.stream_have_file_info:
# start of a new file - output the old one first
self.streamOneP4File(self.stream_file, self.stream_contents)
self.stream_file = {}
@@ -2938,7 +2954,7 @@ class P4Sync(Command, P4UserMap):
cb=streamP4FilesCbSelf)
# do the last chunk
- if self.stream_file.has_key('depotFile'):
+ if 'depotFile' in self.stream_file:
self.streamOneP4File(self.stream_file, self.stream_contents)
def make_email(self, userid):
@@ -2953,11 +2969,11 @@ class P4Sync(Command, P4UserMap):
"""
if verbose:
- print "writing tag %s for commit %s" % (labelName, commit)
+ print("writing tag %s for commit %s" % (labelName, commit))
gitStream.write("tag %s\n" % labelName)
gitStream.write("from %s\n" % commit)
- if labelDetails.has_key('Owner'):
+ if 'Owner' in labelDetails:
owner = labelDetails["Owner"]
else:
owner = None
@@ -2972,8 +2988,8 @@ class P4Sync(Command, P4UserMap):
gitStream.write("tagger %s\n" % tagger)
- print "labelDetails=",labelDetails
- if labelDetails.has_key('Description'):
+ print("labelDetails=",labelDetails)
+ if 'Description' in labelDetails:
description = labelDetails['Description']
else:
description = 'Label from git p4'
@@ -3044,7 +3060,7 @@ class P4Sync(Command, P4UserMap):
if len(parent) > 0:
if self.verbose:
- print "parent %s" % parent
+ print("parent %s" % parent)
self.gitStream.write("from %s\n" % parent)
self.streamP4Files(files)
@@ -3052,12 +3068,12 @@ class P4Sync(Command, P4UserMap):
change = int(details["change"])
- if self.labels.has_key(change):
+ if change in self.labels:
label = self.labels[change]
labelDetails = label[0]
labelRevisions = label[1]
if self.verbose:
- print "Change %s is labelled %s" % (change, labelDetails)
+ print("Change %s is labelled %s" % (change, labelDetails))
files = p4CmdList(["files"] + ["%s...@%s" % (p, change)
for p in self.branchPrefixes])
@@ -3075,12 +3091,12 @@ class P4Sync(Command, P4UserMap):
else:
if not self.silent:
- print ("Tag %s does not match with change %s: files do not match."
+ print("Tag %s does not match with change %s: files do not match."
% (labelDetails["label"], change))
else:
if not self.silent:
- print ("Tag %s does not match with change %s: file count is different."
+ print("Tag %s does not match with change %s: file count is different."
% (labelDetails["label"], change))
# Build a dictionary of changelists and labels, for "detect-labels" option.
@@ -3089,14 +3105,14 @@ class P4Sync(Command, P4UserMap):
l = p4CmdList(["labels"] + ["%s..." % p for p in self.depotPaths])
if len(l) > 0 and not self.silent:
- print "Finding files belonging to labels in %s" % `self.depotPaths`
+ print("Finding files belonging to labels in %s" % self.depotPaths)
for output in l:
label = output["label"]
revisions = {}
newestChange = 0
if self.verbose:
- print "Querying files for label %s" % label
+ print("Querying files for label %s" % label)
for file in p4CmdList(["files"] +
["%s...@%s" % (p, label)
for p in self.depotPaths]):
@@ -3108,7 +3124,7 @@ class P4Sync(Command, P4UserMap):
self.labels[newestChange] = [output, revisions]
if self.verbose:
- print "Label changes: %s" % self.labels.keys()
+ print("Label changes: %s" % self.labels.keys())
# Import p4 labels as git tags. A direct mapping does not
# exist, so assume that if all the files are at the same revision
@@ -3116,7 +3132,7 @@ class P4Sync(Command, P4UserMap):
# just ignore.
def importP4Labels(self, stream, p4Labels):
if verbose:
- print "import p4 labels: " + ' '.join(p4Labels)
+ print("import p4 labels: " + ' '.join(p4Labels))
ignoredP4Labels = gitConfigList("git-p4.ignoredP4Labels")
validLabelRegexp = gitConfig("git-p4.labelImportRegexp")
@@ -3129,7 +3145,7 @@ class P4Sync(Command, P4UserMap):
if not m.match(name):
if verbose:
- print "label %s does not match regexp %s" % (name,validLabelRegexp)
+ print("label %s does not match regexp %s" % (name,validLabelRegexp))
continue
if name in ignoredP4Labels:
@@ -3141,7 +3157,7 @@ class P4Sync(Command, P4UserMap):
change = p4Cmd(["changes", "-m", "1"] + ["%s...@%s" % (p, name)
for p in self.depotPaths])
- if change.has_key('change'):
+ if 'change' in change:
# find the corresponding git commit; take the oldest commit
changelist = int(change['change'])
if changelist in self.committedChanges:
@@ -3151,7 +3167,7 @@ class P4Sync(Command, P4UserMap):
gitCommit = read_pipe(["git", "rev-list", "--max-count=1",
"--reverse", ":/\[git-p4:.*change = %d\]" % changelist], ignore_error=True)
if len(gitCommit) == 0:
- print "importing label %s: could not find git commit for changelist %d" % (name, changelist)
+ print("importing label %s: could not find git commit for changelist %d" % (name, changelist))
else:
commitFound = True
gitCommit = gitCommit.strip()
@@ -3161,16 +3177,16 @@ class P4Sync(Command, P4UserMap):
try:
tmwhen = time.strptime(labelDetails['Update'], "%Y/%m/%d %H:%M:%S")
except ValueError:
- print "Could not convert label time %s" % labelDetails['Update']
+ print("Could not convert label time %s" % labelDetails['Update'])
tmwhen = 1
when = int(time.mktime(tmwhen))
self.streamTag(stream, name, labelDetails, gitCommit, when)
if verbose:
- print "p4 label %s mapped to git commit %s" % (name, gitCommit)
+ print("p4 label %s mapped to git commit %s" % (name, gitCommit))
else:
if verbose:
- print "Label %s has no changelists - possibly deleted?" % name
+ print("Label %s has no changelists - possibly deleted?" % name)
if not commitFound:
# We can't import this label; don't try again as it will get very
@@ -3200,7 +3216,7 @@ class P4Sync(Command, P4UserMap):
for info in p4CmdList(command):
details = p4Cmd(["branch", "-o", info["branch"]])
viewIdx = 0
- while details.has_key("View%s" % viewIdx):
+ while "View%s" % viewIdx in details:
paths = details["View%s" % viewIdx].split(" ")
viewIdx = viewIdx + 1
# require standard //depot/foo/... //depot/bar/... mapping
@@ -3215,8 +3231,8 @@ class P4Sync(Command, P4UserMap):
if destination in self.knownBranches:
if not self.silent:
- print "p4 branch %s defines a mapping from %s to %s" % (info["branch"], source, destination)
- print "but there exists another mapping from %s to %s already!" % (self.knownBranches[destination], destination)
+ print("p4 branch %s defines a mapping from %s to %s" % (info["branch"], source, destination))
+ print("but there exists another mapping from %s to %s already!" % (self.knownBranches[destination], destination))
continue
self.knownBranches[destination] = source
@@ -3266,7 +3282,7 @@ class P4Sync(Command, P4UserMap):
d["options"] = ' '.join(sorted(option_keys.keys()))
def readOptions(self, d):
- self.keepRepoPath = (d.has_key('options')
+ self.keepRepoPath = ('options' in d
and ('keepRepoPath' in d['options']))
def gitRefForBranch(self, branch):
@@ -3280,28 +3296,28 @@ class P4Sync(Command, P4UserMap):
def gitCommitByP4Change(self, ref, change):
if self.verbose:
- print "looking in ref " + ref + " for change %s using bisect..." % change
+ print("looking in ref " + ref + " for change %s using bisect..." % change)
earliestCommit = ""
latestCommit = parseRevision(ref)
while True:
if self.verbose:
- print "trying: earliest %s latest %s" % (earliestCommit, latestCommit)
+ print("trying: earliest %s latest %s" % (earliestCommit, latestCommit))
next = read_pipe("git rev-list --bisect %s %s" % (latestCommit, earliestCommit)).strip()
if len(next) == 0:
if self.verbose:
- print "argh"
+ print("argh")
return ""
log = extractLogMessageFromGitCommit(next)
settings = extractSettingsGitLog(log)
currentChange = int(settings['change'])
if self.verbose:
- print "current change %s" % currentChange
+ print("current change %s" % currentChange)
if currentChange == change:
if self.verbose:
- print "found %s" % next
+ print("found %s" % next)
return next
if currentChange < change:
@@ -3347,7 +3363,7 @@ class P4Sync(Command, P4UserMap):
if len(read_pipe(["git", "diff-tree", blob, target])) == 0:
parentFound = True
if self.verbose:
- print "Found parent of %s in commit %s" % (branch, blob)
+ print("Found parent of %s in commit %s" % (branch, blob))
break
if parentFound:
return blob
@@ -3378,7 +3394,7 @@ class P4Sync(Command, P4UserMap):
filesForCommit = branches[branch]
if self.verbose:
- print "branch is %s" % branch
+ print("branch is %s" % branch)
self.updatedBranches.add(branch)
@@ -3399,13 +3415,13 @@ class P4Sync(Command, P4UserMap):
print("\n Resuming with change %s" % change);
if self.verbose:
- print "parent determined through known branches: %s" % parent
+ print("parent determined through known branches: %s" % parent)
branch = self.gitRefForBranch(branch)
parent = self.gitRefForBranch(parent)
if self.verbose:
- print "looking for initial parent for %s; current parent is %s" % (branch, parent)
+ print("looking for initial parent for %s; current parent is %s" % (branch, parent))
if len(parent) == 0 and branch in self.initialParents:
parent = self.initialParents[branch]
@@ -3415,7 +3431,7 @@ class P4Sync(Command, P4UserMap):
if len(parent) > 0:
tempBranch = "%s/%d" % (self.tempBranchLocation, change)
if self.verbose:
- print "Creating temporary branch: " + tempBranch
+ print("Creating temporary branch: " + tempBranch)
self.commit(description, filesForCommit, tempBranch)
self.tempBranches.append(tempBranch)
self.checkpoint()
@@ -3424,7 +3440,7 @@ class P4Sync(Command, P4UserMap):
self.commit(description, filesForCommit, branch, blob)
else:
if self.verbose:
- print "Parent of %s not found. Committing into head of %s" % (branch, parent)
+ print("Parent of %s not found. Committing into head of %s" % (branch, parent))
self.commit(description, filesForCommit, branch, parent)
else:
files = self.extractFilesFromCommit(description, shelved, change, origin_revision)
@@ -3433,7 +3449,7 @@ class P4Sync(Command, P4UserMap):
# only needed once, to connect to the previous commit
self.initialParent = ""
except IOError:
- print self.gitError.read()
+ print(self.gitError.read())
sys.exit(1)
def sync_origin_only(self):
@@ -3441,11 +3457,11 @@ class P4Sync(Command, P4UserMap):
self.hasOrigin = originP4BranchesExist()
if self.hasOrigin:
if not self.silent:
- print 'Syncing with origin first, using "git fetch origin"'
+ print('Syncing with origin first, using "git fetch origin"')
system("git fetch origin")
def importHeadRevision(self, revision):
- print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch)
+ print("Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch))
details = {}
details["user"] = "git perforce import user"
@@ -3497,8 +3513,8 @@ class P4Sync(Command, P4UserMap):
try:
self.commit(details, self.extractFilesFromCommit(details), self.branch)
except IOError:
- print "IO error with git fast-import. Is your git version recent enough?"
- print self.gitError.read()
+ print("IO error with git fast-import. Is your git version recent enough?")
+ print(self.gitError.read())
def openStreams(self):
self.importProcess = subprocess.Popen(["git", "fast-import"],
@@ -3560,14 +3576,14 @@ class P4Sync(Command, P4UserMap):
if len(self.p4BranchesInGit) > 1:
if not self.silent:
- print "Importing from/into multiple branches"
+ print("Importing from/into multiple branches")
self.detectBranches = True
for branch in branches.keys():
self.initialParents[self.refPrefix + branch] = \
branches[branch]
if self.verbose:
- print "branches: %s" % self.p4BranchesInGit
+ print("branches: %s" % self.p4BranchesInGit)
p4Change = 0
for branch in self.p4BranchesInGit:
@@ -3576,8 +3592,8 @@ class P4Sync(Command, P4UserMap):
settings = extractSettingsGitLog(logMsg)
self.readOptions(settings)
- if (settings.has_key('depot-paths')
- and settings.has_key ('change')):
+ if ('depot-paths' in settings
+ and 'change' in settings):
change = int(settings['change']) + 1
p4Change = max(p4Change, change)
@@ -3590,7 +3606,7 @@ class P4Sync(Command, P4UserMap):
prev_list = prev.split("/")
cur_list = cur.split("/")
for i in range(0, min(len(cur_list), len(prev_list))):
- if cur_list[i] <> prev_list[i]:
+ if cur_list[i] != prev_list[i]:
i = i - 1
break
@@ -3602,7 +3618,7 @@ class P4Sync(Command, P4UserMap):
self.depotPaths = sorted(self.previousDepotPaths)
self.changeRange = "@%s,#head" % p4Change
if not self.silent and not self.detectBranches:
- print "Performing incremental import into %s git branch" % self.branch
+ print("Performing incremental import into %s git branch" % self.branch)
# accept multiple ref name abbreviations:
# refs/foo/bar/branch -> use it exactly
@@ -3619,10 +3635,10 @@ class P4Sync(Command, P4UserMap):
if len(args) == 0 and self.depotPaths:
if not self.silent:
- print "Depot paths: %s" % ' '.join(self.depotPaths)
+ print("Depot paths: %s" % ' '.join(self.depotPaths))
else:
if self.depotPaths and self.depotPaths != args:
- print ("previous import used depot path %s and now %s was specified. "
+ print("previous import used depot path %s and now %s was specified. "
"This doesn't work!" % (' '.join (self.depotPaths),
' '.join (args)))
sys.exit(1)
@@ -3689,8 +3705,8 @@ class P4Sync(Command, P4UserMap):
else:
self.getBranchMapping()
if self.verbose:
- print "p4-git branches: %s" % self.p4BranchesInGit
- print "initial parents: %s" % self.initialParents
+ print("p4-git branches: %s" % self.p4BranchesInGit)
+ print("initial parents: %s" % self.initialParents)
for b in self.p4BranchesInGit:
if b != "master":
@@ -3734,8 +3750,8 @@ class P4Sync(Command, P4UserMap):
self.branch)
if self.verbose:
- print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
- self.changeRange)
+ print("Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
+ self.changeRange))
changes = p4ChangesForPaths(self.depotPaths, self.changeRange, self.changes_block_size)
if len(self.maxChanges) > 0:
@@ -3743,10 +3759,10 @@ class P4Sync(Command, P4UserMap):
if len(changes) == 0:
if not self.silent:
- print "No changes to import!"
+ print("No changes to import!")
else:
if not self.silent and not self.detectBranches:
- print "Import destination: %s" % self.branch
+ print("Import destination: %s" % self.branch)
self.updatedBranches = set()
@@ -3761,7 +3777,7 @@ class P4Sync(Command, P4UserMap):
self.importChanges(changes)
if not self.silent:
- print ""
+ print("")
if len(self.updatedBranches) > 0:
sys.stdout.write("Updated branches: ")
for b in self.updatedBranches:
@@ -3825,7 +3841,7 @@ class P4Rebase(Command):
# the branchpoint may be p4/foo~3, so strip off the parent
upstream = re.sub("~[0-9]+$", "", upstream)
- print "Rebasing the current branch onto %s" % upstream
+ print("Rebasing the current branch onto %s" % upstream)
oldHead = read_pipe("git rev-parse HEAD").strip()
system("git rebase %s" % upstream)
system("git diff-tree --stat --summary -M %s HEAD --" % oldHead)
@@ -3879,7 +3895,7 @@ class P4Clone(P4Sync):
if not self.cloneDestination:
self.cloneDestination = self.defaultDestination(args)
- print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination)
+ print("Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination))
if not os.path.exists(self.cloneDestination):
os.makedirs(self.cloneDestination)
@@ -3901,8 +3917,8 @@ class P4Clone(P4Sync):
if not self.cloneBare:
system([ "git", "checkout", "-f" ])
else:
- print 'Not checking out any branch, use ' \
- '"git checkout -q -b master <branch>"'
+ print('Not checking out any branch, use ' \
+ '"git checkout -q -b master <branch>"')
# auto-set this variable if invoked with --use-client-spec
if self.useClientSpec_from_options:
@@ -3950,7 +3966,7 @@ class P4Unshelve(Command):
for parent in (range(65535)):
log = extractLogMessageFromGitCommit("{0}^{1}".format(starting_point, parent))
settings = extractSettingsGitLog(log)
- if settings.has_key('change'):
+ if 'change' in settings:
return settings
sys.exit("could not find git-p4 commits in {0}".format(self.origin))
@@ -4018,7 +4034,7 @@ class P4Branches(Command):
log = extractLogMessageFromGitCommit("refs/remotes/%s" % branch)
settings = extractSettingsGitLog(log)
- print "%s <= %s (%s)" % (branch, ",".join(settings["depot-paths"]), settings["change"])
+ print("%s <= %s (%s)" % (branch, ",".join(settings["depot-paths"]), settings["change"]))
return True
class HelpFormatter(optparse.IndentedHelpFormatter):
@@ -4032,12 +4048,12 @@ class HelpFormatter(optparse.IndentedHelpFormatter):
return ""
def printUsage(commands):
- print "usage: %s <command> [options]" % sys.argv[0]
- print ""
- print "valid commands: %s" % ", ".join(commands)
- print ""
- print "Try %s <command> --help for command specific help." % sys.argv[0]
- print ""
+ print("usage: %s <command> [options]" % sys.argv[0])
+ print("")
+ print("valid commands: %s" % ", ".join(commands))
+ print("")
+ print("Try %s <command> --help for command specific help." % sys.argv[0])
+ print("")
commands = {
"debug" : P4Debug,
@@ -4062,8 +4078,8 @@ def main():
klass = commands[cmdName]
cmd = klass()
except KeyError:
- print "unknown command %s" % cmdName
- print ""
+ print("unknown command %s" % cmdName)
+ print("")
printUsage(commands.keys())
sys.exit(2)
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index cf4c042..aa2f2f0 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -71,7 +71,7 @@ call_merge () {
test -z "$strategy" && strategy=recursive
# If cmt doesn't have a parent, don't include it as a base
base=$(git rev-parse --verify --quiet $cmt^)
- eval 'git-merge-$strategy' $strategy_opts $base ' -- "$hd" "$cmt"'
+ eval 'git merge-$strategy' $strategy_opts $base ' -- "$hd" "$cmt"'
rv=$?
case "$rv" in
0)
@@ -88,7 +88,7 @@ call_merge () {
;;
*)
die "Unknown exit code ($rv) from command:" \
- "git-merge-$strategy $cmt^ -- HEAD $cmt"
+ "git merge-$strategy $cmt^ -- HEAD $cmt"
;;
esac
}
diff --git a/git-rebase--preserve-merges.sh b/git-rebase--preserve-merges.sh
index c51c782..c214c5e 100644
--- a/git-rebase--preserve-merges.sh
+++ b/git-rebase--preserve-merges.sh
@@ -891,9 +891,9 @@ $comment_char $(eval_ngettext \
EOF
append_todo_help
gettext "
- However, if you remove everything, the rebase will be aborted.
+However, if you remove everything, the rebase will be aborted.
- " | git stripspace --comment-lines >>"$todo"
+" | git stripspace --comment-lines >>"$todo"
if test -z "$keep_empty"
then
diff --git a/git-rebase.sh b/git-rebase.sh
index 19bdebb..7973447 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -20,23 +20,23 @@ onto=! rebase onto given branch instead of upstream
r,rebase-merges? try to rebase merges instead of skipping them
p,preserve-merges! try to recreate merges instead of ignoring them
s,strategy=! use the given merge strategy
+X,strategy-option=! pass the argument through to the merge strategy
no-ff! cherry-pick all commits, even if unchanged
+f,force-rebase! cherry-pick all commits, even if unchanged
m,merge! use merging strategies to rebase
i,interactive! let the user edit the list of commits to rebase
x,exec=! add exec lines after each commit of the editable list
k,keep-empty preserve empty commits during rebase
allow-empty-message allow rebasing commits with empty messages
-f,force-rebase! force rebase even if branch is up to date
-X,strategy-option=! pass the argument through to the merge strategy
stat! display a diffstat of what changed upstream
n,no-stat! do not show diffstat of what changed upstream
verify allow pre-rebase hook to run
rerere-autoupdate allow rerere to update index with resolved conflicts
root! rebase all reachable commits up to the root(s)
autosquash move commits that begin with squash!/fixup! under -i
+signoff add a Signed-off-by: line to each commit
committer-date-is-author-date! passed to 'git am'
ignore-date! passed to 'git am'
-signoff passed to 'git am'
whitespace=! passed to 'git apply'
ignore-whitespace! passed to 'git apply'
C=! passed to 'git apply'
@@ -95,7 +95,7 @@ rebase_cousins=
preserve_merges=
autosquash=
keep_empty=
-allow_empty_message=
+allow_empty_message=--allow-empty-message
signoff=
test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
case "$(git config --bool commit.gpgsign)" in
@@ -328,7 +328,7 @@ do
do_merge=t
;;
--strategy-option=*)
- strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}")"
+ strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
do_merge=t
test -z "$strategy" && strategy=recursive
;;
@@ -521,6 +521,24 @@ then
git_format_patch_opt="$git_format_patch_opt --progress"
fi
+if test -n "$git_am_opt"; then
+ incompatible_opts=$(echo " $git_am_opt " | \
+ sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
+ if test -n "$interactive_rebase"
+ then
+ if test -n "$incompatible_opts"
+ then
+ die "$(gettext "error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)")"
+ fi
+ fi
+ if test -n "$do_merge"; then
+ if test -n "$incompatible_opts"
+ then
+ die "$(gettext "error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)")"
+ fi
+ fi
+fi
+
if test -n "$signoff"
then
test -n "$preserve_merges" &&
@@ -529,6 +547,23 @@ then
force_rebase=t
fi
+if test -n "$preserve_merges"
+then
+ # Note: incompatibility with --signoff handled in signoff block above
+ # Note: incompatibility with --interactive is just a strong warning;
+ # git-rebase.txt caveats with "unless you know what you are doing"
+ test -n "$rebase_merges" &&
+ die "$(gettext "error: cannot combine '--preserve_merges' with '--rebase-merges'")"
+fi
+
+if test -n "$rebase_merges"
+then
+ test -n "$strategy_opts" &&
+ die "$(gettext "error: cannot combine '--rebase_merges' with '--strategy-option'")"
+ test -n "$strategy" &&
+ die "$(gettext "error: cannot combine '--rebase_merges' with '--strategy'")"
+fi
+
if test -z "$rebase_root"
then
case "$#" in
diff --git a/git-send-email.perl b/git-send-email.perl
index 8ec70e5..2be5dac 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -231,7 +231,7 @@ my ($validate, $confirm);
my (@suppress_cc);
my ($auto_8bit_encoding);
my ($compose_encoding);
-my ($target_xfer_encoding);
+my $target_xfer_encoding = 'auto';
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
@@ -645,7 +645,7 @@ if (@rev_list_opts) {
if ($validate) {
foreach my $f (@files) {
unless (-p $f) {
- my $error = validate_patch($f);
+ my $error = validate_patch($f, $target_xfer_encoding);
$error and die sprintf(__("fatal: %s: %s\nwarning: no patches were sent\n"),
$f, $error);
}
@@ -1479,7 +1479,7 @@ EOF
SSL => 1);
}
}
- else {
+ elsif (!$smtp) {
$smtp_server_port ||= 25;
$smtp ||= Net::SMTP->new($smtp_server,
Hello => $smtp_domain,
@@ -1501,7 +1501,6 @@ EOF
$smtp->starttls(ssl_verify_params())
or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr());
}
- $smtp_encryption = '';
# Send EHLO again to receive fresh
# supported commands
$smtp->hello($smtp_domain);
@@ -1737,18 +1736,11 @@ sub process_file {
}
}
}
- if (defined $target_xfer_encoding) {
- $xfer_encoding = '8bit' if not defined $xfer_encoding;
- $message = apply_transfer_encoding(
- $message, $xfer_encoding, $target_xfer_encoding);
- $xfer_encoding = $target_xfer_encoding;
- }
- if (defined $xfer_encoding) {
- push @xh, "Content-Transfer-Encoding: $xfer_encoding";
- }
- if (defined $xfer_encoding or $has_content_type) {
- unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
- }
+ $xfer_encoding = '8bit' if not defined $xfer_encoding;
+ ($message, $xfer_encoding) = apply_transfer_encoding(
+ $message, $xfer_encoding, $target_xfer_encoding);
+ push @xh, "Content-Transfer-Encoding: $xfer_encoding";
+ unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
$needs_confirm = (
$confirm eq "always" or
@@ -1852,13 +1844,16 @@ sub apply_transfer_encoding {
$message = MIME::Base64::decode($message)
if ($from eq 'base64');
+ $to = ($message =~ /.{999,}/) ? 'quoted-printable' : '8bit'
+ if $to eq 'auto';
+
die __("cannot send message as 7bit")
if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
- return $message
+ return ($message, $to)
if ($to eq '7bit' or $to eq '8bit');
- return MIME::QuotedPrint::encode($message, "\n", 0)
+ return (MIME::QuotedPrint::encode($message, "\n", 0), $to)
if ($to eq 'quoted-printable');
- return MIME::Base64::encode($message, "\n")
+ return (MIME::Base64::encode($message, "\n"), $to)
if ($to eq 'base64');
die __("invalid transfer encoding");
}
@@ -1877,7 +1872,7 @@ sub unique_email_list {
}
sub validate_patch {
- my $fn = shift;
+ my ($fn, $xfer_encoding) = @_;
if ($repo) {
my $validate_hook = catfile(catdir($repo->repo_path(), 'hooks'),
@@ -1897,11 +1892,15 @@ sub validate_patch {
return $hook_error if $hook_error;
}
- open(my $fh, '<', $fn)
- or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
- while (my $line = <$fh>) {
- if (length($line) > 998) {
- return sprintf(__("%s: patch contains a line longer than 998 characters"), $.);
+ # Any long lines will be automatically fixed if we use a suitable transfer
+ # encoding.
+ unless ($xfer_encoding =~ /^(?:auto|quoted-printable|base64)$/) {
+ open(my $fh, '<', $fn)
+ or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
+ while (my $line = <$fh>) {
+ if (length($line) > 998) {
+ return sprintf(__("%s: patch contains a line longer than 998 characters"), $.);
+ }
}
}
return;
diff --git a/git-submodule.sh b/git-submodule.sh
index 5f9d9f6..8b5ad59 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -577,6 +577,11 @@ cmd_update()
die "$(eval_gettext "Unable to find current \${remote_name}/\${branch} revision in submodule path '\$sm_path'")"
fi
+ if ! $(git config -f "$(git rev-parse --git-common-dir)/modules/$name/config" core.worktree) 2>/dev/null
+ then
+ git submodule--helper connect-gitdir-workingtree "$name" "$sm_path"
+ fi
+
if test "$subsha1" != "$sha1" || test -n "$force"
then
subforce=$force
diff --git a/git.c b/git.c
index 9dbe6ff..cc0fad9 100644
--- a/git.c
+++ b/git.c
@@ -164,7 +164,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--no-replace-objects")) {
- check_replace_refs = 0;
+ read_replace_refs = 0;
setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
if (envchanged)
*envchanged = 1;
@@ -267,7 +267,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
} else if (!strcmp(cmd, "--shallow-file")) {
(*argv)++;
(*argc)--;
- set_alternate_shallow_file((*argv)[0], 1);
+ set_alternate_shallow_file(the_repository, (*argv)[0], 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "-C")) {
@@ -414,7 +414,10 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
trace_argv_printf(argv, "trace: built-in: git");
+ validate_cache_entries(&the_index);
status = p->fn(argc, argv, prefix);
+ validate_cache_entries(&the_index);
+
if (status)
return status;
diff --git a/gpg-interface.c b/gpg-interface.c
index 0647bd6..bb8ea66 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -7,10 +7,64 @@
#include "tempfile.h"
static char *configured_signing_key;
-static const char *gpg_program = "gpg";
+struct gpg_format {
+ const char *name;
+ const char *program;
+ const char **verify_args;
+ const char **sigs;
+};
+
+static const char *openpgp_verify_args[] = {
+ "--keyid-format=long",
+ NULL
+};
+static const char *openpgp_sigs[] = {
+ "-----BEGIN PGP SIGNATURE-----",
+ "-----BEGIN PGP MESSAGE-----",
+ NULL
+};
+
+static const char *x509_verify_args[] = {
+ NULL
+};
+static const char *x509_sigs[] = {
+ "-----BEGIN SIGNED MESSAGE-----",
+ NULL
+};
-#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
-#define PGP_MESSAGE "-----BEGIN PGP MESSAGE-----"
+static struct gpg_format gpg_format[] = {
+ { .name = "openpgp", .program = "gpg",
+ .verify_args = openpgp_verify_args,
+ .sigs = openpgp_sigs
+ },
+ { .name = "x509", .program = "gpgsm",
+ .verify_args = x509_verify_args,
+ .sigs = x509_sigs
+ },
+};
+
+static struct gpg_format *use_format = &gpg_format[0];
+
+static struct gpg_format *get_format_by_name(const char *str)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
+ if (!strcmp(gpg_format[i].name, str))
+ return gpg_format + i;
+ return NULL;
+}
+
+static struct gpg_format *get_format_by_sig(const char *sig)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
+ for (j = 0; gpg_format[i].sigs[j]; j++)
+ if (starts_with(sig, gpg_format[i].sigs[j]))
+ return gpg_format + i;
+ return NULL;
+}
void signature_check_clear(struct signature_check *sigc)
{
@@ -35,7 +89,7 @@ static struct {
{ 'R', "\n[GNUPG:] REVKEYSIG "},
};
-void parse_gpg_output(struct signature_check *sigc)
+static void parse_gpg_output(struct signature_check *sigc)
{
const char *buf = sigc->gpg_status;
int i;
@@ -53,10 +107,11 @@ void parse_gpg_output(struct signature_check *sigc)
sigc->result = sigcheck_gpg_status[i].result;
/* The trust messages are not followed by key/signer information */
if (sigc->result != 'U') {
- sigc->key = xmemdupz(found, 16);
+ next = strchrnul(found, ' ');
+ sigc->key = xmemdupz(found, next - found);
/* The ERRSIG message is not followed by signer information */
- if (sigc-> result != 'E') {
- found += 17;
+ if (*next && sigc-> result != 'E') {
+ found = next + 1;
next = strchrnul(found, '\n');
sigc->signer = xmemdupz(found, next - found);
}
@@ -101,12 +156,6 @@ void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
fputs(output, stderr);
}
-static int is_gpg_start(const char *line)
-{
- return starts_with(line, PGP_SIGNATURE) ||
- starts_with(line, PGP_MESSAGE);
-}
-
size_t parse_signature(const char *buf, size_t size)
{
size_t len = 0;
@@ -114,7 +163,7 @@ size_t parse_signature(const char *buf, size_t size)
while (len < size) {
const char *eol;
- if (is_gpg_start(buf + len))
+ if (get_format_by_sig(buf + len))
match = len;
eol = memchr(buf + len, '\n', size - len);
@@ -131,6 +180,9 @@ void set_signing_key(const char *key)
int git_gpg_config(const char *var, const char *value, void *cb)
{
+ struct gpg_format *fmt = NULL;
+ char *fmtname = NULL;
+
if (!strcmp(var, "user.signingkey")) {
if (!value)
return config_error_nonbool(var);
@@ -138,13 +190,28 @@ int git_gpg_config(const char *var, const char *value, void *cb)
return 0;
}
- if (!strcmp(var, "gpg.program")) {
+ if (!strcmp(var, "gpg.format")) {
if (!value)
return config_error_nonbool(var);
- gpg_program = xstrdup(value);
+ fmt = get_format_by_name(value);
+ if (!fmt)
+ return error("unsupported value for %s: %s",
+ var, value);
+ use_format = fmt;
return 0;
}
+ if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program"))
+ fmtname = "openpgp";
+
+ if (!strcmp(var, "gpg.x509.program"))
+ fmtname = "x509";
+
+ if (fmtname) {
+ fmt = get_format_by_name(fmtname);
+ return git_config_string(&fmt->program, var, value);
+ }
+
return 0;
}
@@ -163,7 +230,7 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *sig
struct strbuf gpg_status = STRBUF_INIT;
argv_array_pushl(&gpg.args,
- gpg_program,
+ use_format->program,
"--status-fd=2",
"-bsau", signing_key,
NULL);
@@ -201,6 +268,7 @@ int verify_signed_buffer(const char *payload, size_t payload_size,
struct strbuf *gpg_output, struct strbuf *gpg_status)
{
struct child_process gpg = CHILD_PROCESS_INIT;
+ struct gpg_format *fmt;
struct tempfile *temp;
int ret;
struct strbuf buf = STRBUF_INIT;
@@ -216,10 +284,14 @@ int verify_signed_buffer(const char *payload, size_t payload_size,
return -1;
}
+ fmt = get_format_by_sig(signature);
+ if (!fmt)
+ BUG("bad signature '%s'", signature);
+
+ argv_array_push(&gpg.args, fmt->program);
+ argv_array_pushv(&gpg.args, fmt->verify_args);
argv_array_pushl(&gpg.args,
- gpg_program,
"--status-fd=1",
- "--keyid-format=long",
"--verify", temp->filename.buf, "-",
NULL);
diff --git a/gpg-interface.h b/gpg-interface.h
index a5e6517..5ecff4a 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -33,8 +33,6 @@ void signature_check_clear(struct signature_check *sigc);
*/
size_t parse_signature(const char *buf, size_t size);
-void parse_gpg_output(struct signature_check *);
-
/*
* Create a detached signature for the contents of "buffer" and append
* it after "signature"; "buffer" and "signature" can be the same
diff --git a/grep.c b/grep.c
index 7c1b8e2..2b26cee 100644
--- a/grep.c
+++ b/grep.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "config.h"
#include "grep.h"
+#include "object-store.h"
#include "userdiff.h"
#include "xdiff-interface.h"
#include "diff.h"
@@ -19,6 +20,7 @@ static const char *color_grep_slots[] = {
[GREP_COLOR_FILENAME] = "filename",
[GREP_COLOR_FUNCTION] = "function",
[GREP_COLOR_LINENO] = "lineNumber",
+ [GREP_COLOR_COLUMNNO] = "column",
[GREP_COLOR_MATCH_CONTEXT] = "matchContext",
[GREP_COLOR_MATCH_SELECTED] = "matchSelected",
[GREP_COLOR_SELECTED] = "selected",
@@ -58,10 +60,12 @@ void init_grep_defaults(void)
color_set(opt->colors[GREP_COLOR_FILENAME], "");
color_set(opt->colors[GREP_COLOR_FUNCTION], "");
color_set(opt->colors[GREP_COLOR_LINENO], "");
+ color_set(opt->colors[GREP_COLOR_COLUMNNO], "");
color_set(opt->colors[GREP_COLOR_MATCH_CONTEXT], GIT_COLOR_BOLD_RED);
color_set(opt->colors[GREP_COLOR_MATCH_SELECTED], GIT_COLOR_BOLD_RED);
color_set(opt->colors[GREP_COLOR_SELECTED], "");
color_set(opt->colors[GREP_COLOR_SEP], GIT_COLOR_CYAN);
+ opt->only_matching = 0;
opt->color = -1;
opt->output = std_output;
}
@@ -109,6 +113,10 @@ int grep_config(const char *var, const char *value, void *cb)
opt->linenum = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "grep.column")) {
+ opt->columnnum = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp(var, "grep.fullname")) {
opt->relative = !git_config_bool(var, value);
@@ -152,10 +160,12 @@ void grep_init(struct grep_opt *opt, const char *prefix)
opt->pattern_tail = &opt->pattern_list;
opt->header_tail = &opt->header_list;
+ opt->only_matching = def->only_matching;
opt->color = def->color;
opt->extended_regexp_option = def->extended_regexp_option;
opt->pattern_type_option = def->pattern_type_option;
opt->linenum = def->linenum;
+ opt->columnnum = def->columnnum;
opt->max_depth = def->max_depth;
opt->pathname = def->pathname;
opt->relative = def->relative;
@@ -1243,11 +1253,11 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
return hit;
}
-static int match_expr_eval(struct grep_expr *x, char *bol, char *eol,
- enum grep_context ctx, int collect_hits)
+static int match_expr_eval(struct grep_opt *opt, struct grep_expr *x, char *bol,
+ char *eol, enum grep_context ctx, ssize_t *col,
+ ssize_t *icol, int collect_hits)
{
int h = 0;
- regmatch_t match;
if (!x)
die("Not a valid grep expression");
@@ -1256,25 +1266,52 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol,
h = 1;
break;
case GREP_NODE_ATOM:
- h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0);
+ {
+ regmatch_t tmp;
+ h = match_one_pattern(x->u.atom, bol, eol, ctx,
+ &tmp, 0);
+ if (h && (*col < 0 || tmp.rm_so < *col))
+ *col = tmp.rm_so;
+ }
break;
case GREP_NODE_NOT:
- h = !match_expr_eval(x->u.unary, bol, eol, ctx, 0);
+ /*
+ * Upon visiting a GREP_NODE_NOT, col and icol become swapped.
+ */
+ h = !match_expr_eval(opt, x->u.unary, bol, eol, ctx, icol, col,
+ 0);
break;
case GREP_NODE_AND:
- if (!match_expr_eval(x->u.binary.left, bol, eol, ctx, 0))
- return 0;
- h = match_expr_eval(x->u.binary.right, bol, eol, ctx, 0);
+ h = match_expr_eval(opt, x->u.binary.left, bol, eol, ctx, col,
+ icol, 0);
+ if (h || opt->columnnum) {
+ /*
+ * Don't short-circuit AND when given --column, since a
+ * NOT earlier in the tree may turn this into an OR. In
+ * this case, see the below comment.
+ */
+ h &= match_expr_eval(opt, x->u.binary.right, bol, eol,
+ ctx, col, icol, 0);
+ }
break;
case GREP_NODE_OR:
- if (!collect_hits)
- return (match_expr_eval(x->u.binary.left,
- bol, eol, ctx, 0) ||
- match_expr_eval(x->u.binary.right,
- bol, eol, ctx, 0));
- h = match_expr_eval(x->u.binary.left, bol, eol, ctx, 0);
- x->u.binary.left->hit |= h;
- h |= match_expr_eval(x->u.binary.right, bol, eol, ctx, 1);
+ if (!(collect_hits || opt->columnnum)) {
+ /*
+ * Don't short-circuit OR when given --column (or
+ * collecting hits) to ensure we don't skip a later
+ * child that would produce an earlier match.
+ */
+ return (match_expr_eval(opt, x->u.binary.left, bol, eol,
+ ctx, col, icol, 0) ||
+ match_expr_eval(opt, x->u.binary.right, bol,
+ eol, ctx, col, icol, 0));
+ }
+ h = match_expr_eval(opt, x->u.binary.left, bol, eol, ctx, col,
+ icol, 0);
+ if (collect_hits)
+ x->u.binary.left->hit |= h;
+ h |= match_expr_eval(opt, x->u.binary.right, bol, eol, ctx, col,
+ icol, collect_hits);
break;
default:
die("Unexpected node type (internal error) %d", x->node);
@@ -1285,27 +1322,43 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol,
}
static int match_expr(struct grep_opt *opt, char *bol, char *eol,
- enum grep_context ctx, int collect_hits)
+ enum grep_context ctx, ssize_t *col,
+ ssize_t *icol, int collect_hits)
{
struct grep_expr *x = opt->pattern_expression;
- return match_expr_eval(x, bol, eol, ctx, collect_hits);
+ return match_expr_eval(opt, x, bol, eol, ctx, col, icol, collect_hits);
}
static int match_line(struct grep_opt *opt, char *bol, char *eol,
+ ssize_t *col, ssize_t *icol,
enum grep_context ctx, int collect_hits)
{
struct grep_pat *p;
- regmatch_t match;
+ int hit = 0;
if (opt->extended)
- return match_expr(opt, bol, eol, ctx, collect_hits);
+ return match_expr(opt, bol, eol, ctx, col, icol,
+ collect_hits);
/* we do not call with collect_hits without being extended */
for (p = opt->pattern_list; p; p = p->next) {
- if (match_one_pattern(p, bol, eol, ctx, &match, 0))
- return 1;
+ regmatch_t tmp;
+ if (match_one_pattern(p, bol, eol, ctx, &tmp, 0)) {
+ hit |= 1;
+ if (!opt->columnnum) {
+ /*
+ * Without --column, any single match on a line
+ * is enough to know that it needs to be
+ * printed. With --column, scan _all_ patterns
+ * to find the earliest.
+ */
+ break;
+ }
+ if (*col < 0 || tmp.rm_so < *col)
+ *col = tmp.rm_so;
+ }
}
- return 0;
+ return hit;
}
static int match_next_pattern(struct grep_pat *p, char *bol, char *eol,
@@ -1353,11 +1406,44 @@ static int next_match(struct grep_opt *opt, char *bol, char *eol,
return hit;
}
+static void show_line_header(struct grep_opt *opt, const char *name,
+ unsigned lno, ssize_t cno, char sign)
+{
+ if (opt->heading && opt->last_shown == 0) {
+ output_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);
+ opt->output(opt, "\n", 1);
+ }
+ opt->last_shown = lno;
+
+ if (!opt->heading && opt->pathname) {
+ output_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);
+ output_sep(opt, sign);
+ }
+ if (opt->linenum) {
+ char buf[32];
+ xsnprintf(buf, sizeof(buf), "%d", lno);
+ output_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_LINENO]);
+ output_sep(opt, sign);
+ }
+ /*
+ * Treat 'cno' as the 1-indexed offset from the start of a non-context
+ * line to its first match. Otherwise, 'cno' is 0 indicating that we are
+ * being called with a context line.
+ */
+ if (opt->columnnum && cno) {
+ char buf[32];
+ xsnprintf(buf, sizeof(buf), "%"PRIuMAX, (uintmax_t)cno);
+ output_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_COLUMNNO]);
+ output_sep(opt, sign);
+ }
+}
+
static void show_line(struct grep_opt *opt, char *bol, char *eol,
- const char *name, unsigned lno, char sign)
+ const char *name, unsigned lno, ssize_t cno, char sign)
{
int rest = eol - bol;
- const char *match_color, *line_color = NULL;
+ const char *match_color = NULL;
+ const char *line_color = NULL;
if (opt->file_break && opt->last_shown == 0) {
if (opt->show_hunk_mark)
@@ -1373,54 +1459,55 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
opt->output(opt, "\n", 1);
}
}
- if (opt->heading && opt->last_shown == 0) {
- output_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);
- opt->output(opt, "\n", 1);
- }
- opt->last_shown = lno;
-
- if (!opt->heading && opt->pathname) {
- output_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);
- output_sep(opt, sign);
- }
- if (opt->linenum) {
- char buf[32];
- xsnprintf(buf, sizeof(buf), "%d", lno);
- output_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_LINENO]);
- output_sep(opt, sign);
+ if (!opt->only_matching) {
+ /*
+ * In case the line we're being called with contains more than
+ * one match, leave printing each header to the loop below.
+ */
+ show_line_header(opt, name, lno, cno, sign);
}
- if (opt->color) {
+ if (opt->color || opt->only_matching) {
regmatch_t match;
enum grep_context ctx = GREP_CONTEXT_BODY;
int ch = *eol;
int eflags = 0;
- if (sign == ':')
- match_color = opt->colors[GREP_COLOR_MATCH_SELECTED];
- else
- match_color = opt->colors[GREP_COLOR_MATCH_CONTEXT];
- if (sign == ':')
- line_color = opt->colors[GREP_COLOR_SELECTED];
- else if (sign == '-')
- line_color = opt->colors[GREP_COLOR_CONTEXT];
- else if (sign == '=')
- line_color = opt->colors[GREP_COLOR_FUNCTION];
+ if (opt->color) {
+ if (sign == ':')
+ match_color = opt->colors[GREP_COLOR_MATCH_SELECTED];
+ else
+ match_color = opt->colors[GREP_COLOR_MATCH_CONTEXT];
+ if (sign == ':')
+ line_color = opt->colors[GREP_COLOR_SELECTED];
+ else if (sign == '-')
+ line_color = opt->colors[GREP_COLOR_CONTEXT];
+ else if (sign == '=')
+ line_color = opt->colors[GREP_COLOR_FUNCTION];
+ }
*eol = '\0';
while (next_match(opt, bol, eol, ctx, &match, eflags)) {
if (match.rm_so == match.rm_eo)
break;
- output_color(opt, bol, match.rm_so, line_color);
+ if (opt->only_matching)
+ show_line_header(opt, name, lno, cno, sign);
+ else
+ output_color(opt, bol, match.rm_so, line_color);
output_color(opt, bol + match.rm_so,
match.rm_eo - match.rm_so, match_color);
+ if (opt->only_matching)
+ opt->output(opt, "\n", 1);
bol += match.rm_eo;
+ cno += match.rm_eo;
rest -= match.rm_eo;
eflags = REG_NOTBOL;
}
*eol = ch;
}
- output_color(opt, bol, rest, line_color);
- opt->output(opt, "\n", 1);
+ if (!opt->only_matching) {
+ output_color(opt, bol, rest, line_color);
+ opt->output(opt, "\n", 1);
+ }
}
#ifndef NO_PTHREADS
@@ -1494,7 +1581,7 @@ static void show_funcname_line(struct grep_opt *opt, struct grep_source *gs,
break;
if (match_funcname(opt, gs, bol, eol)) {
- show_line(opt, bol, eol, gs->name, lno, '=');
+ show_line(opt, bol, eol, gs->name, lno, 0, '=');
break;
}
}
@@ -1559,7 +1646,7 @@ static void show_pre_context(struct grep_opt *opt, struct grep_source *gs,
while (*eol != '\n')
eol++;
- show_line(opt, bol, eol, gs->name, cur, sign);
+ show_line(opt, bol, eol, gs->name, cur, 0, sign);
bol = eol + 1;
cur++;
}
@@ -1758,6 +1845,8 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
while (left) {
char *eol, ch;
int hit;
+ ssize_t cno;
+ ssize_t col = -1, icol = -1;
/*
* look_ahead() skips quickly to the line that possibly
@@ -1781,7 +1870,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
if ((ctx == GREP_CONTEXT_HEAD) && (eol == bol))
ctx = GREP_CONTEXT_BODY;
- hit = match_line(opt, bol, eol, ctx, collect_hits);
+ hit = match_line(opt, bol, eol, &col, &icol, ctx, collect_hits);
*eol = ch;
if (collect_hits)
@@ -1822,7 +1911,18 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
show_pre_context(opt, gs, bol, eol, lno);
else if (opt->funcname)
show_funcname_line(opt, gs, bol, lno);
- show_line(opt, bol, eol, gs->name, lno, ':');
+ cno = opt->invert ? icol : col;
+ if (cno < 0) {
+ /*
+ * A negative cno indicates that there was no
+ * match on the line. We are thus inverted and
+ * being asked to show all lines that _don't_
+ * match a given expression. Therefore, set cno
+ * to 0 to suggest the whole line matches.
+ */
+ cno = 0;
+ }
+ show_line(opt, bol, eol, gs->name, lno, cno + 1, ':');
last_hit = lno;
if (opt->funcbody)
show_function = 1;
@@ -1851,7 +1951,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
/* If the last hit is within the post context,
* we need to show this line.
*/
- show_line(opt, bol, eol, gs->name, lno, '-');
+ show_line(opt, bol, eol, gs->name, lno, col + 1, '-');
}
next_line:
diff --git a/grep.h b/grep.h
index ed25be2..0ba62a1 100644
--- a/grep.h
+++ b/grep.h
@@ -67,6 +67,7 @@ enum grep_color {
GREP_COLOR_FILENAME,
GREP_COLOR_FUNCTION,
GREP_COLOR_LINENO,
+ GREP_COLOR_COLUMNNO,
GREP_COLOR_MATCH_CONTEXT,
GREP_COLOR_MATCH_SELECTED,
GREP_COLOR_SELECTED,
@@ -139,6 +140,7 @@ struct grep_opt {
int prefix_length;
regex_t regexp;
int linenum;
+ int columnnum;
int invert;
int ignore_case;
int status_only;
@@ -161,6 +163,7 @@ struct grep_opt {
int relative;
int pathname;
int null_following_name;
+ int only_matching;
int color;
int max_depth;
int funcname;
diff --git a/hex.c b/hex.c
index 8df2d63..10af1a2 100644
--- a/hex.c
+++ b/hex.c
@@ -50,7 +50,7 @@ int hex_to_bytes(unsigned char *binary, const char *hex, size_t len)
int get_sha1_hex(const char *hex, unsigned char *sha1)
{
int i;
- for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
+ for (i = 0; i < the_hash_algo->rawsz; i++) {
int val = hex2chr(hex);
if (val < 0)
return -1;
@@ -69,7 +69,7 @@ int parse_oid_hex(const char *hex, struct object_id *oid, const char **end)
{
int ret = get_oid_hex(hex, oid);
if (!ret)
- *end = hex + GIT_SHA1_HEXSZ;
+ *end = hex + the_hash_algo->hexsz;
return ret;
}
@@ -79,7 +79,7 @@ char *sha1_to_hex_r(char *buffer, const unsigned char *sha1)
char *buf = buffer;
int i;
- for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
+ for (i = 0; i < the_hash_algo->rawsz; i++) {
unsigned int val = *sha1++;
*buf++ = hex[val >> 4];
*buf++ = hex[val & 0xf];
diff --git a/http-backend.c b/http-backend.c
index adaef16..bd0442a 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -436,13 +436,13 @@ static int show_text_ref(const char *name, const struct object_id *oid,
{
const char *name_nons = strip_namespace(name);
struct strbuf *buf = cb_data;
- struct object *o = parse_object(oid);
+ struct object *o = parse_object(the_repository, oid);
if (!o)
return 0;
strbuf_addf(buf, "%s\t%s\n", oid_to_hex(oid), name_nons);
if (o->type == OBJ_TAG) {
- o = deref_tag(o, name, 0);
+ o = deref_tag(the_repository, o, name, 0);
if (!o)
return 0;
strbuf_addf(buf, "%s\t%s^{}\n", oid_to_hex(&o->oid),
diff --git a/http-push.c b/http-push.c
index 7e38522..5eaf551 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "repository.h"
#include "commit.h"
#include "tag.h"
#include "blob.h"
@@ -14,6 +15,7 @@
#include "packfile.h"
#include "object-store.h"
+
#ifdef EXPAT_NEEDS_XMLPARSE_H
#include <xmlparse.h>
#else
@@ -720,9 +722,9 @@ static void one_remote_object(const struct object_id *oid)
{
struct object *obj;
- obj = lookup_object(oid->hash);
+ obj = lookup_object(the_repository, oid->hash);
if (!obj)
- obj = parse_object(oid);
+ obj = parse_object(the_repository, oid);
/* Ignore remote objects that don't exist locally */
if (!obj)
@@ -1309,10 +1311,12 @@ static struct object_list **process_tree(struct tree *tree,
while (tree_entry(&desc, &entry))
switch (object_type(entry.mode)) {
case OBJ_TREE:
- p = process_tree(lookup_tree(entry.oid), p);
+ p = process_tree(lookup_tree(the_repository, entry.oid),
+ p);
break;
case OBJ_BLOB:
- p = process_blob(lookup_blob(entry.oid), p);
+ p = process_blob(lookup_blob(the_repository, entry.oid),
+ p);
break;
default:
/* Subproject commit - not in this repository */
@@ -1459,7 +1463,7 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls)
return;
}
- o = parse_object(&ref->old_oid);
+ o = parse_object(the_repository, &ref->old_oid);
if (!o) {
fprintf(stderr,
"Unable to parse object %s for remote ref %s\n",
@@ -1473,7 +1477,7 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls)
oid_to_hex(&ref->old_oid), ls->dentry_name);
if (o->type == OBJ_TAG) {
- o = deref_tag(o, ls->dentry_name, 0);
+ o = deref_tag(the_repository, o, ls->dentry_name, 0);
if (o)
strbuf_addf(buf, "%s\t%s^{}\n",
oid_to_hex(&o->oid), ls->dentry_name);
diff --git a/json-writer.c b/json-writer.c
new file mode 100644
index 0000000..aadb9db
--- /dev/null
+++ b/json-writer.c
@@ -0,0 +1,414 @@
+#include "cache.h"
+#include "json-writer.h"
+
+void jw_init(struct json_writer *jw)
+{
+ strbuf_init(&jw->json, 0);
+ strbuf_init(&jw->open_stack, 0);
+ jw->need_comma = 0;
+ jw->pretty = 0;
+}
+
+void jw_release(struct json_writer *jw)
+{
+ strbuf_release(&jw->json);
+ strbuf_release(&jw->open_stack);
+}
+
+/*
+ * Append JSON-quoted version of the given string to 'out'.
+ */
+static void append_quoted_string(struct strbuf *out, const char *in)
+{
+ unsigned char c;
+
+ strbuf_addch(out, '"');
+ while ((c = *in++) != '\0') {
+ if (c == '"')
+ strbuf_addstr(out, "\\\"");
+ else if (c == '\\')
+ strbuf_addstr(out, "\\\\");
+ else if (c == '\n')
+ strbuf_addstr(out, "\\n");
+ else if (c == '\r')
+ strbuf_addstr(out, "\\r");
+ else if (c == '\t')
+ strbuf_addstr(out, "\\t");
+ else if (c == '\f')
+ strbuf_addstr(out, "\\f");
+ else if (c == '\b')
+ strbuf_addstr(out, "\\b");
+ else if (c < 0x20)
+ strbuf_addf(out, "\\u%04x", c);
+ else
+ strbuf_addch(out, c);
+ }
+ strbuf_addch(out, '"');
+}
+
+static void indent_pretty(struct json_writer *jw)
+{
+ int k;
+
+ for (k = 0; k < jw->open_stack.len; k++)
+ strbuf_addstr(&jw->json, " ");
+}
+
+/*
+ * Begin an object or array (either top-level or nested within the currently
+ * open object or array).
+ */
+static void begin(struct json_writer *jw, char ch_open, int pretty)
+{
+ jw->pretty = pretty;
+
+ strbuf_addch(&jw->json, ch_open);
+
+ strbuf_addch(&jw->open_stack, ch_open);
+ jw->need_comma = 0;
+}
+
+/*
+ * Assert that the top of the open-stack is an object.
+ */
+static void assert_in_object(const struct json_writer *jw, const char *key)
+{
+ if (!jw->open_stack.len)
+ BUG("json-writer: object: missing jw_object_begin(): '%s'", key);
+ if (jw->open_stack.buf[jw->open_stack.len - 1] != '{')
+ BUG("json-writer: object: not in object: '%s'", key);
+}
+
+/*
+ * Assert that the top of the open-stack is an array.
+ */
+static void assert_in_array(const struct json_writer *jw)
+{
+ if (!jw->open_stack.len)
+ BUG("json-writer: array: missing jw_array_begin()");
+ if (jw->open_stack.buf[jw->open_stack.len - 1] != '[')
+ BUG("json-writer: array: not in array");
+}
+
+/*
+ * Add comma if we have already seen a member at this level.
+ */
+static void maybe_add_comma(struct json_writer *jw)
+{
+ if (jw->need_comma)
+ strbuf_addch(&jw->json, ',');
+ else
+ jw->need_comma = 1;
+}
+
+static void fmt_double(struct json_writer *jw, int precision,
+ double value)
+{
+ if (precision < 0) {
+ strbuf_addf(&jw->json, "%f", value);
+ } else {
+ struct strbuf fmt = STRBUF_INIT;
+ strbuf_addf(&fmt, "%%.%df", precision);
+ strbuf_addf(&jw->json, fmt.buf, value);
+ strbuf_release(&fmt);
+ }
+}
+
+static void object_common(struct json_writer *jw, const char *key)
+{
+ assert_in_object(jw, key);
+ maybe_add_comma(jw);
+
+ if (jw->pretty) {
+ strbuf_addch(&jw->json, '\n');
+ indent_pretty(jw);
+ }
+
+ append_quoted_string(&jw->json, key);
+ strbuf_addch(&jw->json, ':');
+ if (jw->pretty)
+ strbuf_addch(&jw->json, ' ');
+}
+
+static void array_common(struct json_writer *jw)
+{
+ assert_in_array(jw);
+ maybe_add_comma(jw);
+
+ if (jw->pretty) {
+ strbuf_addch(&jw->json, '\n');
+ indent_pretty(jw);
+ }
+}
+
+/*
+ * Assert that the given JSON object or JSON array has been properly
+ * terminated. (Has closing bracket.)
+ */
+static void assert_is_terminated(const struct json_writer *jw)
+{
+ if (jw->open_stack.len)
+ BUG("json-writer: object: missing jw_end(): '%s'",
+ jw->json.buf);
+}
+
+void jw_object_begin(struct json_writer *jw, int pretty)
+{
+ begin(jw, '{', pretty);
+}
+
+void jw_object_string(struct json_writer *jw, const char *key, const char *value)
+{
+ object_common(jw, key);
+ append_quoted_string(&jw->json, value);
+}
+
+void jw_object_intmax(struct json_writer *jw, const char *key, intmax_t value)
+{
+ object_common(jw, key);
+ strbuf_addf(&jw->json, "%"PRIdMAX, value);
+}
+
+void jw_object_double(struct json_writer *jw, const char *key, int precision,
+ double value)
+{
+ object_common(jw, key);
+ fmt_double(jw, precision, value);
+}
+
+void jw_object_true(struct json_writer *jw, const char *key)
+{
+ object_common(jw, key);
+ strbuf_addstr(&jw->json, "true");
+}
+
+void jw_object_false(struct json_writer *jw, const char *key)
+{
+ object_common(jw, key);
+ strbuf_addstr(&jw->json, "false");
+}
+
+void jw_object_bool(struct json_writer *jw, const char *key, int value)
+{
+ if (value)
+ jw_object_true(jw, key);
+ else
+ jw_object_false(jw, key);
+}
+
+void jw_object_null(struct json_writer *jw, const char *key)
+{
+ object_common(jw, key);
+ strbuf_addstr(&jw->json, "null");
+}
+
+static void increase_indent(struct strbuf *sb,
+ const struct json_writer *jw,
+ int indent)
+{
+ int k;
+
+ strbuf_reset(sb);
+ for (k = 0; k < jw->json.len; k++) {
+ char ch = jw->json.buf[k];
+ strbuf_addch(sb, ch);
+ if (ch == '\n')
+ strbuf_addchars(sb, ' ', indent);
+ }
+}
+
+static void kill_indent(struct strbuf *sb,
+ const struct json_writer *jw)
+{
+ int k;
+ int eat_it = 0;
+
+ strbuf_reset(sb);
+ for (k = 0; k < jw->json.len; k++) {
+ char ch = jw->json.buf[k];
+ if (eat_it && ch == ' ')
+ continue;
+ if (ch == '\n') {
+ eat_it = 1;
+ continue;
+ }
+ eat_it = 0;
+ strbuf_addch(sb, ch);
+ }
+}
+
+static void append_sub_jw(struct json_writer *jw,
+ const struct json_writer *value)
+{
+ /*
+ * If both are pretty, increase the indentation of the sub_jw
+ * to better fit under the super.
+ *
+ * If the super is pretty, but the sub_jw is compact, leave the
+ * sub_jw compact. (We don't want to parse and rebuild the sub_jw
+ * for this debug-ish feature.)
+ *
+ * If the super is compact, and the sub_jw is pretty, convert
+ * the sub_jw to compact.
+ *
+ * If both are compact, keep the sub_jw compact.
+ */
+ if (jw->pretty && jw->open_stack.len && value->pretty) {
+ struct strbuf sb = STRBUF_INIT;
+ increase_indent(&sb, value, jw->open_stack.len * 2);
+ strbuf_addbuf(&jw->json, &sb);
+ strbuf_release(&sb);
+ return;
+ }
+ if (!jw->pretty && value->pretty) {
+ struct strbuf sb = STRBUF_INIT;
+ kill_indent(&sb, value);
+ strbuf_addbuf(&jw->json, &sb);
+ strbuf_release(&sb);
+ return;
+ }
+
+ strbuf_addbuf(&jw->json, &value->json);
+}
+
+/*
+ * Append existing (properly terminated) JSON sub-data (object or array)
+ * as-is onto the given JSON data.
+ */
+void jw_object_sub_jw(struct json_writer *jw, const char *key,
+ const struct json_writer *value)
+{
+ assert_is_terminated(value);
+
+ object_common(jw, key);
+ append_sub_jw(jw, value);
+}
+
+void jw_object_inline_begin_object(struct json_writer *jw, const char *key)
+{
+ object_common(jw, key);
+
+ jw_object_begin(jw, jw->pretty);
+}
+
+void jw_object_inline_begin_array(struct json_writer *jw, const char *key)
+{
+ object_common(jw, key);
+
+ jw_array_begin(jw, jw->pretty);
+}
+
+void jw_array_begin(struct json_writer *jw, int pretty)
+{
+ begin(jw, '[', pretty);
+}
+
+void jw_array_string(struct json_writer *jw, const char *value)
+{
+ array_common(jw);
+ append_quoted_string(&jw->json, value);
+}
+
+void jw_array_intmax(struct json_writer *jw, intmax_t value)
+{
+ array_common(jw);
+ strbuf_addf(&jw->json, "%"PRIdMAX, value);
+}
+
+void jw_array_double(struct json_writer *jw, int precision, double value)
+{
+ array_common(jw);
+ fmt_double(jw, precision, value);
+}
+
+void jw_array_true(struct json_writer *jw)
+{
+ array_common(jw);
+ strbuf_addstr(&jw->json, "true");
+}
+
+void jw_array_false(struct json_writer *jw)
+{
+ array_common(jw);
+ strbuf_addstr(&jw->json, "false");
+}
+
+void jw_array_bool(struct json_writer *jw, int value)
+{
+ if (value)
+ jw_array_true(jw);
+ else
+ jw_array_false(jw);
+}
+
+void jw_array_null(struct json_writer *jw)
+{
+ array_common(jw);
+ strbuf_addstr(&jw->json, "null");
+}
+
+void jw_array_sub_jw(struct json_writer *jw, const struct json_writer *value)
+{
+ assert_is_terminated(value);
+
+ array_common(jw);
+ append_sub_jw(jw, value);
+}
+
+void jw_array_argc_argv(struct json_writer *jw, int argc, const char **argv)
+{
+ int k;
+
+ for (k = 0; k < argc; k++)
+ jw_array_string(jw, argv[k]);
+}
+
+void jw_array_argv(struct json_writer *jw, const char **argv)
+{
+ while (*argv)
+ jw_array_string(jw, *argv++);
+}
+
+void jw_array_inline_begin_object(struct json_writer *jw)
+{
+ array_common(jw);
+
+ jw_object_begin(jw, jw->pretty);
+}
+
+void jw_array_inline_begin_array(struct json_writer *jw)
+{
+ array_common(jw);
+
+ jw_array_begin(jw, jw->pretty);
+}
+
+int jw_is_terminated(const struct json_writer *jw)
+{
+ return !jw->open_stack.len;
+}
+
+void jw_end(struct json_writer *jw)
+{
+ char ch_open;
+ int len;
+
+ if (!jw->open_stack.len)
+ BUG("json-writer: too many jw_end(): '%s'", jw->json.buf);
+
+ len = jw->open_stack.len - 1;
+ ch_open = jw->open_stack.buf[len];
+
+ strbuf_setlen(&jw->open_stack, len);
+ jw->need_comma = 1;
+
+ if (jw->pretty) {
+ strbuf_addch(&jw->json, '\n');
+ indent_pretty(jw);
+ }
+
+ if (ch_open == '{')
+ strbuf_addch(&jw->json, '}');
+ else
+ strbuf_addch(&jw->json, ']');
+}
diff --git a/json-writer.h b/json-writer.h
new file mode 100644
index 0000000..fc18acc
--- /dev/null
+++ b/json-writer.h
@@ -0,0 +1,105 @@
+#ifndef JSON_WRITER_H
+#define JSON_WRITER_H
+
+/*
+ * JSON data structures are defined at:
+ * [1] http://www.ietf.org/rfc/rfc7159.txt
+ * [2] http://json.org/
+ *
+ * The JSON-writer API allows one to build JSON data structures using a
+ * simple wrapper around a "struct strbuf" buffer. It is intended as a
+ * simple API to build output strings; it is not intended to be a general
+ * object model for JSON data. In particular, it does not re-order keys
+ * in an object (dictionary), it does not de-dup keys in an object, and
+ * it does not allow lookup or parsing of JSON data.
+ *
+ * All string values (both keys and string r-values) are properly quoted
+ * and escaped if they contain special characters.
+ *
+ * These routines create compact JSON data (with no unnecessary whitespace,
+ * newlines, or indenting). If you get an unexpected response, verify
+ * that you're not expecting a pretty JSON string.
+ *
+ * Both "JSON objects" (aka sets of k/v pairs) and "JSON array" can be
+ * constructed using a 'begin append* end' model.
+ *
+ * Nested objects and arrays can either be constructed bottom up (by
+ * creating sub object/arrays first and appending them to the super
+ * object/array) -or- by building them inline in one pass. This is a
+ * personal style and/or data shape choice.
+ *
+ * See t/helper/test-json-writer.c for various usage examples.
+ *
+ * LIMITATIONS:
+ * ============
+ *
+ * The JSON specification [1,2] defines string values as Unicode data
+ * and probably UTF-8 encoded. The current json-writer API does not
+ * enforce this and will write any string as received. However, it will
+ * properly quote and backslash-escape them as necessary. It is up to
+ * the caller to UTF-8 encode their strings *before* passing them to this
+ * API. This layer should not have to try to guess the encoding or locale
+ * of the given strings.
+ */
+
+struct json_writer
+{
+ /*
+ * Buffer of the in-progress JSON currently being composed.
+ */
+ struct strbuf json;
+
+ /*
+ * Simple stack of the currently open array and object forms.
+ * This is a string of '{' and '[' characters indicating the
+ * currently unterminated forms. This is used to ensure the
+ * properly closing character is used when popping a level and
+ * to know when the JSON is completely closed.
+ */
+ struct strbuf open_stack;
+
+ unsigned int need_comma:1;
+ unsigned int pretty:1;
+};
+
+#define JSON_WRITER_INIT { STRBUF_INIT, STRBUF_INIT, 0, 0 }
+
+void jw_init(struct json_writer *jw);
+void jw_release(struct json_writer *jw);
+
+void jw_object_begin(struct json_writer *jw, int pretty);
+void jw_array_begin(struct json_writer *jw, int pretty);
+
+void jw_object_string(struct json_writer *jw, const char *key,
+ const char *value);
+void jw_object_intmax(struct json_writer *jw, const char *key, intmax_t value);
+void jw_object_double(struct json_writer *jw, const char *key, int precision,
+ double value);
+void jw_object_true(struct json_writer *jw, const char *key);
+void jw_object_false(struct json_writer *jw, const char *key);
+void jw_object_bool(struct json_writer *jw, const char *key, int value);
+void jw_object_null(struct json_writer *jw, const char *key);
+void jw_object_sub_jw(struct json_writer *jw, const char *key,
+ const struct json_writer *value);
+
+void jw_object_inline_begin_object(struct json_writer *jw, const char *key);
+void jw_object_inline_begin_array(struct json_writer *jw, const char *key);
+
+void jw_array_string(struct json_writer *jw, const char *value);
+void jw_array_intmax(struct json_writer *jw, intmax_t value);
+void jw_array_double(struct json_writer *jw, int precision, double value);
+void jw_array_true(struct json_writer *jw);
+void jw_array_false(struct json_writer *jw);
+void jw_array_bool(struct json_writer *jw, int value);
+void jw_array_null(struct json_writer *jw);
+void jw_array_sub_jw(struct json_writer *jw, const struct json_writer *value);
+void jw_array_argc_argv(struct json_writer *jw, int argc, const char **argv);
+void jw_array_argv(struct json_writer *jw, const char **argv);
+
+void jw_array_inline_begin_object(struct json_writer *jw);
+void jw_array_inline_begin_array(struct json_writer *jw);
+
+int jw_is_terminated(const struct json_writer *jw);
+void jw_end(struct json_writer *jw);
+
+#endif /* JSON_WRITER_H */
diff --git a/line-log.c b/line-log.c
index fa9cfd5..72a5fed 100644
--- a/line-log.c
+++ b/line-log.c
@@ -479,7 +479,7 @@ static struct commit *check_single_commit(struct rev_info *revs)
struct object *obj = revs->pending.objects[i].item;
if (obj->flags & UNINTERESTING)
continue;
- obj = deref_tag(obj, NULL, 0);
+ obj = deref_tag(the_repository, obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (commit)
@@ -598,11 +598,11 @@ parse_lines(struct commit *commit, const char *prefix, struct string_list *args)
lines, anchor, &begin, &end,
full_name))
die("malformed -L argument '%s'", range_part);
- if (lines < end || ((lines || begin) && lines < begin))
+ if ((!lines && (begin || end)) || lines < begin)
die("file %s has only %lu lines", name_part, lines);
if (begin < 1)
begin = 1;
- if (end < 1)
+ if (end < 1 || lines < end)
end = lines;
begin--;
line_log_data_insert(&ranges, full_name, begin, end);
diff --git a/line-range.c b/line-range.c
index 323399d..232c390 100644
--- a/line-range.c
+++ b/line-range.c
@@ -47,7 +47,7 @@ static const char *parse_loc(const char *spec, nth_line_fn_t nth_line,
else if (!num)
*ret = begin;
else
- *ret = begin + num;
+ *ret = begin + num > 0 ? begin + num : 1;
return term;
}
return spec;
diff --git a/list-objects-filter.c b/list-objects-filter.c
index 5b14d27..a0ba78b 100644
--- a/list-objects-filter.c
+++ b/list-objects-filter.c
@@ -11,6 +11,7 @@
#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "oidset.h"
+#include "object-store.h"
/* Remember to update object flag allocation in object.h */
/*
diff --git a/list-objects.c b/list-objects.c
index 3eec510..c99c47a 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -10,6 +10,7 @@
#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "packfile.h"
+#include "object-store.h"
static void process_blob(struct rev_info *revs,
struct blob *blob,
@@ -47,7 +48,7 @@ static void process_blob(struct rev_info *revs,
pathlen = path->len;
strbuf_addstr(path, name);
- if (filter_fn)
+ if (!(obj->flags & USER_GIVEN) && filter_fn)
r = filter_fn(LOFS_BLOB, obj,
path->buf, &path->buf[pathlen],
filter_data);
@@ -132,7 +133,7 @@ static void process_tree(struct rev_info *revs,
}
strbuf_addstr(base, name);
- if (filter_fn)
+ if (!(obj->flags & USER_GIVEN) && filter_fn)
r = filter_fn(LOFS_BEGIN_TREE, obj,
base->buf, &base->buf[baselen],
filter_data);
@@ -157,7 +158,7 @@ static void process_tree(struct rev_info *revs,
if (S_ISDIR(entry.mode))
process_tree(revs,
- lookup_tree(entry.oid),
+ lookup_tree(the_repository, entry.oid),
show, base, entry.path,
cb_data, filter_fn, filter_data);
else if (S_ISGITLINK(entry.mode))
@@ -166,12 +167,12 @@ static void process_tree(struct rev_info *revs,
cb_data);
else
process_blob(revs,
- lookup_blob(entry.oid),
+ lookup_blob(the_repository, entry.oid),
show, base, entry.path,
cb_data, filter_fn, filter_data);
}
- if (filter_fn) {
+ if (!(obj->flags & USER_GIVEN) && filter_fn) {
r = filter_fn(LOFS_END_TREE, obj,
base->buf, &base->buf[baselen],
filter_data);
diff --git a/log-tree.c b/log-tree.c
index d3a43e2..7443e5f 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -1,6 +1,8 @@
#include "cache.h"
#include "config.h"
#include "diff.h"
+#include "object-store.h"
+#include "repository.h"
#include "commit.h"
#include "tag.h"
#include "graph.h"
@@ -90,20 +92,20 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
if (starts_with(refname, git_replace_ref_base)) {
struct object_id original_oid;
- if (!check_replace_refs)
+ if (!read_replace_refs)
return 0;
if (get_oid_hex(refname + strlen(git_replace_ref_base),
&original_oid)) {
warning("invalid replace ref %s", refname);
return 0;
}
- obj = parse_object(&original_oid);
+ obj = parse_object(the_repository, &original_oid);
if (obj)
add_name_decoration(DECORATION_GRAFTED, "replaced", obj);
return 0;
}
- obj = parse_object(oid);
+ obj = parse_object(the_repository, oid);
if (!obj)
return 0;
@@ -124,7 +126,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
if (!obj)
break;
if (!obj->parsed)
- parse_object(&obj->oid);
+ parse_object(the_repository, &obj->oid);
add_name_decoration(DECORATION_REF_TAG, refname, obj);
}
return 0;
@@ -132,7 +134,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
{
- struct commit *commit = lookup_commit(&graft->oid);
+ struct commit *commit = lookup_commit(the_repository, &graft->oid);
if (!commit)
return 0;
add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object);
@@ -496,12 +498,12 @@ static int show_one_mergetag(struct commit *commit,
size_t payload_size, gpg_message_offset;
hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &oid);
- tag = lookup_tag(&oid);
+ tag = lookup_tag(the_repository, &oid);
if (!tag)
return -1; /* error message already given */
strbuf_init(&verify_message, 256);
- if (parse_tag_buffer(tag, extra->value, extra->len))
+ if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
strbuf_addstr(&verify_message, "malformed mergetag\n");
else if (is_common_merge(commit) &&
!oidcmp(&tag->tagged->oid,
@@ -545,7 +547,7 @@ void show_log(struct rev_info *opt)
struct strbuf msgbuf = STRBUF_INIT;
struct log_info *log = opt->loginfo;
struct commit *commit = log->commit, *parent = log->parent;
- int abbrev_commit = opt->abbrev_commit ? opt->abbrev : GIT_SHA1_HEXSZ;
+ int abbrev_commit = opt->abbrev_commit ? opt->abbrev : the_hash_algo->hexsz;
const char *extra_headers = opt->extra_headers;
struct pretty_print_context ctx = {0};
diff --git a/mailmap.c b/mailmap.c
index 13f0d28..962fd86 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "string-list.h"
#include "mailmap.h"
+#include "object-store.h"
#define DEBUG_MAILMAP 0
#if DEBUG_MAILMAP
diff --git a/match-trees.c b/match-trees.c
index 72cc2ba..4cdeff5 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "tree.h"
#include "tree-walk.h"
+#include "object-store.h"
static int score_missing(unsigned mode, const char *path)
{
diff --git a/mem-pool.c b/mem-pool.c
index 389d7af..a2841a4 100644
--- a/mem-pool.c
+++ b/mem-pool.c
@@ -5,40 +5,88 @@
#include "cache.h"
#include "mem-pool.h"
-static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc)
+#define BLOCK_GROWTH_SIZE 1024*1024 - sizeof(struct mp_block);
+
+/*
+ * Allocate a new mp_block and insert it after the block specified in
+ * `insert_after`. If `insert_after` is NULL, then insert block at the
+ * head of the linked list.
+ */
+static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc, struct mp_block *insert_after)
{
struct mp_block *p;
mem_pool->pool_alloc += sizeof(struct mp_block) + block_alloc;
p = xmalloc(st_add(sizeof(struct mp_block), block_alloc));
- p->next_block = mem_pool->mp_block;
+
p->next_free = (char *)p->space;
p->end = p->next_free + block_alloc;
- mem_pool->mp_block = p;
+
+ if (insert_after) {
+ p->next_block = insert_after->next_block;
+ insert_after->next_block = p;
+ } else {
+ p->next_block = mem_pool->mp_block;
+ mem_pool->mp_block = p;
+ }
return p;
}
+void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)
+{
+ struct mem_pool *pool;
+
+ if (*mem_pool)
+ return;
+
+ pool = xcalloc(1, sizeof(*pool));
+
+ pool->block_alloc = BLOCK_GROWTH_SIZE;
+
+ if (initial_size > 0)
+ mem_pool_alloc_block(pool, initial_size, NULL);
+
+ *mem_pool = pool;
+}
+
+void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)
+{
+ struct mp_block *block, *block_to_free;
+
+ block = mem_pool->mp_block;
+ while (block)
+ {
+ block_to_free = block;
+ block = block->next_block;
+
+ if (invalidate_memory)
+ memset(block_to_free->space, 0xDD, ((char *)block_to_free->end) - ((char *)block_to_free->space));
+
+ free(block_to_free);
+ }
+
+ free(mem_pool);
+}
+
void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)
{
- struct mp_block *p;
+ struct mp_block *p = NULL;
void *r;
/* round up to a 'uintmax_t' alignment */
if (len & (sizeof(uintmax_t) - 1))
len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));
- for (p = mem_pool->mp_block; p; p = p->next_block)
- if (p->end - p->next_free >= len)
- break;
+ if (mem_pool->mp_block &&
+ mem_pool->mp_block->end - mem_pool->mp_block->next_free >= len)
+ p = mem_pool->mp_block;
if (!p) {
- if (len >= (mem_pool->block_alloc / 2)) {
- mem_pool->pool_alloc += len;
- return xmalloc(len);
- }
+ if (len >= (mem_pool->block_alloc / 2))
+ return mem_pool_alloc_block(mem_pool, len, mem_pool->mp_block);
- p = mem_pool_alloc_block(mem_pool, mem_pool->block_alloc);
+ p = mem_pool_alloc_block(mem_pool, mem_pool->block_alloc, NULL);
}
r = p->next_free;
@@ -53,3 +101,45 @@ void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)
memset(r, 0, len);
return r;
}
+
+int mem_pool_contains(struct mem_pool *mem_pool, void *mem)
+{
+ struct mp_block *p;
+
+ /* Check if memory is allocated in a block */
+ for (p = mem_pool->mp_block; p; p = p->next_block)
+ if ((mem >= ((void *)p->space)) &&
+ (mem < ((void *)p->end)))
+ return 1;
+
+ return 0;
+}
+
+void mem_pool_combine(struct mem_pool *dst, struct mem_pool *src)
+{
+ struct mp_block *p;
+
+ /* Append the blocks from src to dst */
+ if (dst->mp_block && src->mp_block) {
+ /*
+ * src and dst have blocks, append
+ * blocks from src to dst.
+ */
+ p = dst->mp_block;
+ while (p->next_block)
+ p = p->next_block;
+
+ p->next_block = src->mp_block;
+ } else if (src->mp_block) {
+ /*
+ * src has blocks, dst is empty.
+ */
+ dst->mp_block = src->mp_block;
+ } else {
+ /* src is empty, nothing to do. */
+ }
+
+ dst->pool_alloc += src->pool_alloc;
+ src->pool_alloc = 0;
+ src->mp_block = NULL;
+}
diff --git a/mem-pool.h b/mem-pool.h
index 829ad58..999d3c3 100644
--- a/mem-pool.h
+++ b/mem-pool.h
@@ -22,6 +22,16 @@ struct mem_pool {
};
/*
+ * Initialize mem_pool with specified initial size.
+ */
+void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size);
+
+/*
+ * Discard a memory pool and free all the memory it is responsible for.
+ */
+void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory);
+
+/*
* Alloc memory from the mem_pool.
*/
void *mem_pool_alloc(struct mem_pool *pool, size_t len);
@@ -31,4 +41,17 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len);
*/
void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size);
+/*
+ * Move the memory associated with the 'src' pool to the 'dst' pool. The 'src'
+ * pool will be empty and not contain any memory. It still needs to be free'd
+ * with a call to `mem_pool_discard`.
+ */
+void mem_pool_combine(struct mem_pool *dst, struct mem_pool *src);
+
+/*
+ * Check if a memory pointed at by 'mem' is part of the range of
+ * memory managed by the specified mem_pool.
+ */
+int mem_pool_contains(struct mem_pool *mem_pool, void *mem);
+
#endif
diff --git a/merge-blobs.c b/merge-blobs.c
index fa49c17..fabb8c1 100644
--- a/merge-blobs.c
+++ b/merge-blobs.c
@@ -4,6 +4,7 @@
#include "ll-merge.h"
#include "blob.h"
#include "merge-blobs.h"
+#include "object-store.h"
static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
{
diff --git a/merge-recursive.c b/merge-recursive.c
index bed4a5b..1446e92 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -8,6 +8,8 @@
#include "advice.h"
#include "lockfile.h"
#include "cache-tree.h"
+#include "object-store.h"
+#include "repository.h"
#include "commit.h"
#include "blob.h"
#include "builtin.h"
@@ -156,7 +158,7 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
}
if (!oidcmp(&two->object.oid, &shifted))
return two;
- return lookup_tree(&shifted);
+ return lookup_tree(the_repository, &shifted);
}
static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
@@ -182,7 +184,7 @@ static int oid_eq(const struct object_id *a, const struct object_id *b)
enum rename_type {
RENAME_NORMAL = 0,
- RENAME_DIR,
+ RENAME_VIA_DIR,
RENAME_DELETE,
RENAME_ONE_FILE_TO_ONE,
RENAME_ONE_FILE_TO_TWO,
@@ -312,13 +314,13 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
}
static int add_cacheinfo(struct merge_options *o,
- unsigned int mode, const struct object_id *oid,
- const char *path, int stage, int refresh, int options)
+ unsigned int mode, const struct object_id *oid,
+ const char *path, int stage, int refresh, int options)
{
struct cache_entry *ce;
int ret;
- ce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);
+ ce = make_cache_entry(&the_index, mode, oid ? oid : &null_oid, path, stage, 0);
if (!ce)
return err(o, _("add_cacheinfo failed for path '%s'; merge aborting."), path);
@@ -326,7 +328,7 @@ static int add_cacheinfo(struct merge_options *o,
if (refresh) {
struct cache_entry *nce;
- nce = refresh_cache_entry(ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
+ nce = refresh_cache_entry(&the_index, ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
if (!nce)
return err(o, _("add_cacheinfo failed to refresh for path '%s'; merge aborting."), path);
if (nce != ce)
@@ -414,14 +416,14 @@ struct tree *write_tree_from_memory(struct merge_options *o)
return NULL;
}
- result = lookup_tree(&active_cache_tree->oid);
+ result = lookup_tree(the_repository, &active_cache_tree->oid);
return result;
}
static int save_files_dirs(const struct object_id *oid,
- struct strbuf *base, const char *path,
- unsigned int mode, int stage, void *context)
+ struct strbuf *base, const char *path,
+ unsigned int mode, int stage, void *context)
{
struct path_hashmap_entry *entry;
int baselen = base->len;
@@ -542,7 +544,7 @@ static void record_df_conflict_files(struct merge_options *o,
struct string_list *entries)
{
/* If there is a D/F conflict and the file for such a conflict
- * currently exist in the working tree, we want to allow it to be
+ * currently exists in the working tree, we want to allow it to be
* removed to make room for the corresponding directory if needed.
* The files underneath the directories of such D/F conflicts will
* be processed before the corresponding file involved in the D/F
@@ -916,7 +918,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
*/
if (would_lose_untracked(path))
return err(o, _("refusing to lose untracked file at '%s'"),
- path);
+ path);
/* Successful unlink is good.. */
if (!unlink(path))
@@ -995,16 +997,16 @@ static int update_file_flags(struct merge_options *o,
unlink(path);
if (symlink(lnk, path))
ret = err(o, _("failed to symlink '%s': %s"),
- path, strerror(errno));
+ path, strerror(errno));
free(lnk);
} else
ret = err(o,
_("do not know what to do with %06o %s '%s'"),
mode, oid_to_hex(oid), path);
- free_buf:
+ free_buf:
free(buf);
}
- update_index:
+update_index:
if (!ret && update_cache)
if (add_cacheinfo(o, mode, oid, path, 0, update_wd,
ADD_CACHE_OK_TO_ADD))
@@ -1093,7 +1095,7 @@ static int merge_3way(struct merge_options *o,
}
static int find_first_merges(struct object_array *result, const char *path,
- struct commit *a, struct commit *b)
+ struct commit *a, struct commit *b)
{
int i, j;
struct object_array merges = OBJECT_ARRAY_INIT;
@@ -1111,7 +1113,7 @@ static int find_first_merges(struct object_array *result, const char *path,
/* get all revisions that merge commit a */
xsnprintf(merged_revision, sizeof(merged_revision), "^%s",
- oid_to_hex(&a->object.oid));
+ oid_to_hex(&a->object.oid));
init_revisions(&revs, NULL);
rev_opts.submodule = path;
/* FIXME: can't handle linked worktrees in submodules yet */
@@ -1190,9 +1192,9 @@ static int merge_submodule(struct merge_options *o,
return 0;
}
- if (!(commit_base = lookup_commit_reference(base)) ||
- !(commit_a = lookup_commit_reference(a)) ||
- !(commit_b = lookup_commit_reference(b))) {
+ if (!(commit_base = lookup_commit_reference(the_repository, base)) ||
+ !(commit_a = lookup_commit_reference(the_repository, a)) ||
+ !(commit_b = lookup_commit_reference(the_repository, b))) {
output(o, 1, _("Failed to merge submodule %s (commits not present)"), path);
return 0;
}
@@ -1253,12 +1255,12 @@ static int merge_submodule(struct merge_options *o,
output(o, 2, _("Found a possible merge resolution for the submodule:\n"));
print_commit((struct commit *) merges.objects[0].item);
output(o, 2, _(
- "If this is correct simply add it to the index "
- "for example\n"
- "by using:\n\n"
- " git update-index --cacheinfo 160000 %s \"%s\"\n\n"
- "which will accept this suggestion.\n"),
- oid_to_hex(&merges.objects[0].item->oid), path);
+ "If this is correct simply add it to the index "
+ "for example\n"
+ "by using:\n\n"
+ " git update-index --cacheinfo 160000 %s \"%s\"\n\n"
+ "which will accept this suggestion.\n"),
+ oid_to_hex(&merges.objects[0].item->oid), path);
break;
default:
@@ -1335,10 +1337,10 @@ static int merge_file_1(struct merge_options *o,
result->clean = (merge_status == 0);
} else if (S_ISGITLINK(a->mode)) {
result->clean = merge_submodule(o, &result->oid,
- one->path,
- &one->oid,
- &a->oid,
- &b->oid);
+ one->path,
+ &one->oid,
+ &a->oid,
+ &b->oid);
} else if (S_ISLNK(a->mode)) {
switch (o->recursive_variant) {
case MERGE_RECURSIVE_NORMAL:
@@ -1413,11 +1415,17 @@ static int merge_file_one(struct merge_options *o,
return merge_file_1(o, &one, &a, &b, path, branch1, branch2, mfi);
}
-static int conflict_rename_dir(struct merge_options *o,
- struct diff_filepair *pair,
- const char *rename_branch,
- const char *other_branch)
+static int handle_rename_via_dir(struct merge_options *o,
+ struct diff_filepair *pair,
+ const char *rename_branch,
+ const char *other_branch)
{
+ /*
+ * Handle file adds that need to be renamed due to directory rename
+ * detection. This differs from handle_rename_normal, because
+ * there is no content merge to do; just move the file into the
+ * desired final location.
+ */
const struct diff_filespec *dest = pair->two;
if (!o->call_depth && would_lose_untracked(dest->path)) {
@@ -1446,13 +1454,13 @@ static int conflict_rename_dir(struct merge_options *o,
}
static int handle_change_delete(struct merge_options *o,
- const char *path, const char *old_path,
- const struct object_id *o_oid, int o_mode,
- const struct object_id *changed_oid,
- int changed_mode,
- const char *change_branch,
- const char *delete_branch,
- const char *change, const char *change_past)
+ const char *path, const char *old_path,
+ const struct object_id *o_oid, int o_mode,
+ const struct object_id *changed_oid,
+ int changed_mode,
+ const char *change_branch,
+ const char *delete_branch,
+ const char *change, const char *change_past)
{
char *alt_path = NULL;
const char *update_path = path;
@@ -1473,6 +1481,21 @@ static int handle_change_delete(struct merge_options *o,
if (!ret)
ret = update_file(o, 0, o_oid, o_mode, update_path);
} else {
+ /*
+ * Despite the four nearly duplicate messages and argument
+ * lists below and the ugliness of the nested if-statements,
+ * having complete messages makes the job easier for
+ * translators.
+ *
+ * The slight variance among the cases is due to the fact
+ * that:
+ * 1) directory/file conflicts (in effect if
+ * !alt_path) could cause us to need to write the
+ * file to a different path.
+ * 2) renames (in effect if !old_path) could mean that
+ * there are two names for the path that the user
+ * may know the file by.
+ */
if (!alt_path) {
if (!old_path) {
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
@@ -1512,10 +1535,10 @@ static int handle_change_delete(struct merge_options *o,
return ret;
}
-static int conflict_rename_delete(struct merge_options *o,
- struct diff_filepair *pair,
- const char *rename_branch,
- const char *delete_branch)
+static int handle_rename_delete(struct merge_options *o,
+ struct diff_filepair *pair,
+ const char *rename_branch,
+ const char *delete_branch)
{
const struct diff_filespec *orig = pair->one;
const struct diff_filespec *dest = pair->two;
@@ -1617,8 +1640,8 @@ static int handle_file(struct merge_options *o,
return ret;
}
-static int conflict_rename_rename_1to2(struct merge_options *o,
- struct rename_conflict_info *ci)
+static int handle_rename_rename_1to2(struct merge_options *o,
+ struct rename_conflict_info *ci)
{
/* One file was renamed in both branches, but to different names. */
struct diff_filespec *one = ci->pair1->one;
@@ -1679,8 +1702,8 @@ static int conflict_rename_rename_1to2(struct merge_options *o,
return 0;
}
-static int conflict_rename_rename_2to1(struct merge_options *o,
- struct rename_conflict_info *ci)
+static int handle_rename_rename_2to1(struct merge_options *o,
+ struct rename_conflict_info *ci)
{
/* Two files, a & b, were renamed to the same thing, c. */
struct diff_filespec *a = ci->pair1->one;
@@ -2422,7 +2445,7 @@ static void apply_directory_rename_modifications(struct merge_options *o,
* "NOTE" in update_stages(), doing so will modify the current
* in-memory index which will break calls to would_lose_untracked()
* that we need to make. Instead, we need to just make sure that
- * the various conflict_rename_*() functions update the index
+ * the various handle_rename_*() functions update the index
* explicitly rather than relying on unpack_trees() to have done it.
*/
get_tree_entry(&tree->object.oid,
@@ -2695,7 +2718,7 @@ static int process_renames(struct merge_options *o,
if (oid_eq(&src_other.oid, &null_oid) &&
ren1->add_turned_into_rename) {
- setup_rename_conflict_info(RENAME_DIR,
+ setup_rename_conflict_info(RENAME_VIA_DIR,
ren1->pair,
NULL,
branch1,
@@ -2826,12 +2849,12 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs,
free(pairs);
}
-static int handle_renames(struct merge_options *o,
- struct tree *common,
- struct tree *head,
- struct tree *merge,
- struct string_list *entries,
- struct rename_info *ri)
+static int detect_and_process_renames(struct merge_options *o,
+ struct tree *common,
+ struct tree *head,
+ struct tree *merge,
+ struct string_list *entries,
+ struct rename_info *ri)
{
struct diff_queue_struct *head_pairs, *merge_pairs;
struct hashmap *dir_re_head, *dir_re_merge;
@@ -2907,7 +2930,8 @@ static struct object_id *stage_oid(const struct object_id *oid, unsigned mode)
}
static int read_oid_strbuf(struct merge_options *o,
- const struct object_id *oid, struct strbuf *dst)
+ const struct object_id *oid,
+ struct strbuf *dst)
{
void *buf;
enum object_type type;
@@ -2960,10 +2984,10 @@ error_return:
}
static int handle_modify_delete(struct merge_options *o,
- const char *path,
- struct object_id *o_oid, int o_mode,
- struct object_id *a_oid, int a_mode,
- struct object_id *b_oid, int b_mode)
+ const char *path,
+ struct object_id *o_oid, int o_mode,
+ struct object_id *a_oid, int a_mode,
+ struct object_id *b_oid, int b_mode)
{
const char *modify_branch, *delete_branch;
struct object_id *changed_oid;
@@ -3101,12 +3125,12 @@ static int merge_content(struct merge_options *o,
return !is_dirty && mfi.clean;
}
-static int conflict_rename_normal(struct merge_options *o,
- const char *path,
- struct object_id *o_oid, unsigned int o_mode,
- struct object_id *a_oid, unsigned int a_mode,
- struct object_id *b_oid, unsigned int b_mode,
- struct rename_conflict_info *ci)
+static int handle_rename_normal(struct merge_options *o,
+ const char *path,
+ struct object_id *o_oid, unsigned int o_mode,
+ struct object_id *a_oid, unsigned int a_mode,
+ struct object_id *b_oid, unsigned int b_mode,
+ struct rename_conflict_info *ci)
{
/* Merge the content and write it out */
return merge_content(o, path, was_dirty(o, path),
@@ -3133,37 +3157,37 @@ static int process_entry(struct merge_options *o,
switch (conflict_info->rename_type) {
case RENAME_NORMAL:
case RENAME_ONE_FILE_TO_ONE:
- clean_merge = conflict_rename_normal(o,
- path,
- o_oid, o_mode,
- a_oid, a_mode,
- b_oid, b_mode,
- conflict_info);
+ clean_merge = handle_rename_normal(o,
+ path,
+ o_oid, o_mode,
+ a_oid, a_mode,
+ b_oid, b_mode,
+ conflict_info);
break;
- case RENAME_DIR:
+ case RENAME_VIA_DIR:
clean_merge = 1;
- if (conflict_rename_dir(o,
- conflict_info->pair1,
- conflict_info->branch1,
- conflict_info->branch2))
+ if (handle_rename_via_dir(o,
+ conflict_info->pair1,
+ conflict_info->branch1,
+ conflict_info->branch2))
clean_merge = -1;
break;
case RENAME_DELETE:
clean_merge = 0;
- if (conflict_rename_delete(o,
- conflict_info->pair1,
- conflict_info->branch1,
- conflict_info->branch2))
+ if (handle_rename_delete(o,
+ conflict_info->pair1,
+ conflict_info->branch1,
+ conflict_info->branch2))
clean_merge = -1;
break;
case RENAME_ONE_FILE_TO_TWO:
clean_merge = 0;
- if (conflict_rename_rename_1to2(o, conflict_info))
+ if (handle_rename_rename_1to2(o, conflict_info))
clean_merge = -1;
break;
case RENAME_TWO_FILES_TO_ONE:
clean_merge = 0;
- if (conflict_rename_rename_2to1(o, conflict_info))
+ if (handle_rename_rename_2to1(o, conflict_info))
clean_merge = -1;
break;
default:
@@ -3257,6 +3281,13 @@ int merge_trees(struct merge_options *o,
struct tree **result)
{
int code, clean;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (!o->call_depth && index_has_changes(&the_index, head, &sb)) {
+ err(o, _("Your local changes to the following files would be overwritten by merge:\n %s"),
+ sb.buf);
+ return -1;
+ }
if (o->subtree_shift) {
merge = shift_tree_object(head, merge, o->subtree_shift);
@@ -3264,13 +3295,6 @@ int merge_trees(struct merge_options *o,
}
if (oid_eq(&common->object.oid, &merge->object.oid)) {
- struct strbuf sb = STRBUF_INIT;
-
- if (!o->call_depth && index_has_changes(&sb)) {
- err(o, _("Dirty index: cannot merge (dirty: %s)"),
- sb.buf);
- return 0;
- }
output(o, 0, _("Already up to date!"));
*result = head;
return 1;
@@ -3303,8 +3327,8 @@ int merge_trees(struct merge_options *o,
get_files_dirs(o, merge);
entries = get_unmerged();
- clean = handle_renames(o, common, head, merge, entries,
- &re_info);
+ clean = detect_and_process_renames(o, common, head, merge,
+ entries, &re_info);
record_df_conflict_files(o, entries);
if (clean < 0)
goto cleanup;
@@ -3328,7 +3352,7 @@ int merge_trees(struct merge_options *o,
entries->items[i].string);
}
-cleanup:
+ cleanup:
final_cleanup_renames(&re_info);
string_list_clear(entries, 1);
@@ -3403,7 +3427,7 @@ int merge_recursive(struct merge_options *o,
/* if there is no common ancestor, use an empty tree */
struct tree *tree;
- tree = lookup_tree(the_hash_algo->empty_tree);
+ tree = lookup_tree(the_repository, the_repository->hash_algo->empty_tree);
merged_common_ancestors = make_virtual_commit(tree, "ancestor");
}
@@ -3465,7 +3489,9 @@ static struct commit *get_ref(const struct object_id *oid, const char *name)
{
struct object *object;
- object = deref_tag(parse_object(oid), name, strlen(name));
+ object = deref_tag(the_repository, parse_object(the_repository, oid),
+ name,
+ strlen(name));
if (!object)
return NULL;
if (object->type == OBJ_TREE)
@@ -3496,14 +3522,14 @@ int merge_recursive_generic(struct merge_options *o,
struct commit *base;
if (!(base = get_ref(base_list[i], oid_to_hex(base_list[i]))))
return err(o, _("Could not parse object '%s'"),
- oid_to_hex(base_list[i]));
+ oid_to_hex(base_list[i]));
commit_list_insert(base, &ca);
}
}
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
clean = merge_recursive(o, head_commit, next_commit, ca,
- result);
+ result);
if (clean < 0) {
rollback_lock_file(&lock);
return clean;
diff --git a/merge.c b/merge.c
index 0783858..e30e03f 100644
--- a/merge.c
+++ b/merge.c
@@ -14,37 +14,6 @@ static const char *merge_argument(struct commit *commit)
return oid_to_hex(commit ? &commit->object.oid : the_hash_algo->empty_tree);
}
-int index_has_changes(struct strbuf *sb)
-{
- struct object_id head;
- int i;
-
- if (!get_oid_tree("HEAD", &head)) {
- struct diff_options opt;
-
- diff_setup(&opt);
- opt.flags.exit_with_status = 1;
- if (!sb)
- opt.flags.quick = 1;
- do_diff_cache(&head, &opt);
- diffcore_std(&opt);
- for (i = 0; sb && i < diff_queued_diff.nr; i++) {
- if (i)
- strbuf_addch(sb, ' ');
- strbuf_addstr(sb, diff_queued_diff.queue[i]->two->path);
- }
- diff_flush(&opt);
- return opt.flags.has_changes != 0;
- } else {
- for (i = 0; sb && i < active_nr; i++) {
- if (i)
- strbuf_addch(sb, ' ');
- strbuf_addstr(sb, active_cache[i]->name);
- }
- return !!active_nr;
- }
-}
-
int try_merge_command(const char *strategy, size_t xopts_nr,
const char **xopts, struct commit_list *common,
const char *head_arg, struct commit_list *remotes)
diff --git a/negotiator/default.c b/negotiator/default.c
new file mode 100644
index 0000000..4b78f6b
--- /dev/null
+++ b/negotiator/default.c
@@ -0,0 +1,176 @@
+#include "cache.h"
+#include "default.h"
+#include "../commit.h"
+#include "../fetch-negotiator.h"
+#include "../prio-queue.h"
+#include "../refs.h"
+#include "../tag.h"
+
+/* Remember to update object flag allocation in object.h */
+#define COMMON (1U << 2)
+#define COMMON_REF (1U << 3)
+#define SEEN (1U << 4)
+#define POPPED (1U << 5)
+
+static int marked;
+
+struct negotiation_state {
+ struct prio_queue rev_list;
+ int non_common_revs;
+};
+
+static void rev_list_push(struct negotiation_state *ns,
+ struct commit *commit, int mark)
+{
+ if (!(commit->object.flags & mark)) {
+ commit->object.flags |= mark;
+
+ if (parse_commit(commit))
+ return;
+
+ prio_queue_put(&ns->rev_list, commit);
+
+ if (!(commit->object.flags & COMMON))
+ ns->non_common_revs++;
+ }
+}
+
+static int clear_marks(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
+{
+ struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
+
+ if (o && o->type == OBJ_COMMIT)
+ clear_commit_marks((struct commit *)o,
+ COMMON | COMMON_REF | SEEN | POPPED);
+ return 0;
+}
+
+/*
+ * This function marks a rev and its ancestors as common.
+ * In some cases, it is desirable to mark only the ancestors (for example
+ * when only the server does not yet know that they are common).
+ */
+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;
+
+ if (!ancestors_only)
+ o->flags |= COMMON;
+
+ 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;
+
+ for (parents = commit->parents;
+ parents;
+ parents = parents->next)
+ mark_common(ns, parents->item, 0,
+ dont_parse);
+ }
+ }
+}
+
+/*
+ * Get the next rev to send, ignoring the common.
+ */
+static const struct object_id *get_rev(struct negotiation_state *ns)
+{
+ struct commit *commit = NULL;
+
+ while (commit == NULL) {
+ unsigned int mark;
+ struct commit_list *parents;
+
+ if (ns->rev_list.nr == 0 || ns->non_common_revs == 0)
+ return NULL;
+
+ commit = prio_queue_get(&ns->rev_list);
+ parse_commit(commit);
+ parents = commit->parents;
+
+ commit->object.flags |= POPPED;
+ if (!(commit->object.flags & COMMON))
+ ns->non_common_revs--;
+
+ if (commit->object.flags & COMMON) {
+ /* do not send "have", and ignore ancestors */
+ commit = NULL;
+ mark = COMMON | SEEN;
+ } else if (commit->object.flags & COMMON_REF)
+ /* send "have", and ignore ancestors */
+ mark = COMMON | SEEN;
+ else
+ /* send "have", also for its ancestors */
+ mark = SEEN;
+
+ while (parents) {
+ if (!(parents->item->object.flags & SEEN))
+ rev_list_push(ns, parents->item, mark);
+ if (mark & COMMON)
+ mark_common(ns, parents->item, 1, 0);
+ parents = parents->next;
+ }
+ }
+
+ return &commit->object.oid;
+}
+
+static void known_common(struct fetch_negotiator *n, struct commit *c)
+{
+ if (!(c->object.flags & SEEN)) {
+ rev_list_push(n->data, c, COMMON_REF | SEEN);
+ mark_common(n->data, c, 1, 1);
+ }
+}
+
+static void add_tip(struct fetch_negotiator *n, struct commit *c)
+{
+ n->known_common = NULL;
+ rev_list_push(n->data, c, SEEN);
+}
+
+static const struct object_id *next(struct fetch_negotiator *n)
+{
+ n->known_common = NULL;
+ n->add_tip = NULL;
+ return get_rev(n->data);
+}
+
+static int ack(struct fetch_negotiator *n, struct commit *c)
+{
+ int known_to_be_common = !!(c->object.flags & COMMON);
+ mark_common(n->data, c, 0, 1);
+ return known_to_be_common;
+}
+
+static void release(struct fetch_negotiator *n)
+{
+ clear_prio_queue(&((struct negotiation_state *)n->data)->rev_list);
+ FREE_AND_NULL(n->data);
+}
+
+void default_negotiator_init(struct fetch_negotiator *negotiator)
+{
+ struct negotiation_state *ns;
+ negotiator->known_common = known_common;
+ negotiator->add_tip = add_tip;
+ negotiator->next = next;
+ negotiator->ack = ack;
+ negotiator->release = release;
+ negotiator->data = ns = xcalloc(1, sizeof(*ns));
+ ns->rev_list.compare = compare_commits_by_commit_date;
+
+ if (marked)
+ for_each_ref(clear_marks, NULL);
+ marked = 1;
+}
diff --git a/negotiator/default.h b/negotiator/default.h
new file mode 100644
index 0000000..d23a8f2
--- /dev/null
+++ b/negotiator/default.h
@@ -0,0 +1,8 @@
+#ifndef NEGOTIATOR_DEFAULT_H
+#define NEGOTIATOR_DEFAULT_H
+
+struct fetch_negotiator;
+
+void default_negotiator_init(struct fetch_negotiator *negotiator);
+
+#endif
diff --git a/negotiator/skipping.c b/negotiator/skipping.c
new file mode 100644
index 0000000..dffbc76
--- /dev/null
+++ b/negotiator/skipping.c
@@ -0,0 +1,250 @@
+#include "cache.h"
+#include "skipping.h"
+#include "../commit.h"
+#include "../fetch-negotiator.h"
+#include "../prio-queue.h"
+#include "../refs.h"
+#include "../tag.h"
+
+/* Remember to update object flag allocation in object.h */
+/*
+ * Both us and the server know that both parties have this object.
+ */
+#define COMMON (1U << 2)
+/*
+ * The server has told us that it has this object. We still need to tell the
+ * server that we have this object (or one of its descendants), but since we are
+ * going to do that, we do not need to tell the server about its ancestors.
+ */
+#define ADVERTISED (1U << 3)
+/*
+ * This commit has entered the priority queue.
+ */
+#define SEEN (1U << 4)
+/*
+ * This commit has left the priority queue.
+ */
+#define POPPED (1U << 5)
+
+static int marked;
+
+/*
+ * An entry in the priority queue.
+ */
+struct entry {
+ struct commit *commit;
+
+ /*
+ * Used only if commit is not COMMON.
+ */
+ uint16_t original_ttl;
+ uint16_t ttl;
+};
+
+struct data {
+ struct prio_queue rev_list;
+
+ /*
+ * The number of non-COMMON commits in rev_list.
+ */
+ int non_common_revs;
+};
+
+static int compare(const void *a_, const void *b_, void *unused)
+{
+ const struct entry *a = a_;
+ const struct entry *b = b_;
+ return compare_commits_by_commit_date(a->commit, b->commit, NULL);
+}
+
+static struct entry *rev_list_push(struct data *data, struct commit *commit, int mark)
+{
+ struct entry *entry;
+ commit->object.flags |= mark | SEEN;
+
+ entry = xcalloc(1, sizeof(*entry));
+ entry->commit = commit;
+ prio_queue_put(&data->rev_list, entry);
+
+ if (!(mark & COMMON))
+ data->non_common_revs++;
+ return entry;
+}
+
+static int clear_marks(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
+{
+ struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
+
+ if (o && o->type == OBJ_COMMIT)
+ clear_commit_marks((struct commit *)o,
+ COMMON | ADVERTISED | SEEN | POPPED);
+ return 0;
+}
+
+/*
+ * Mark this SEEN commit and all its SEEN ancestors as COMMON.
+ */
+static void mark_common(struct data *data, struct commit *c)
+{
+ 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;
+ for (p = c->parents; p; p = p->next) {
+ if (p->item->object.flags & SEEN)
+ mark_common(data, p->item);
+ }
+}
+
+/*
+ * Ensure that the priority queue has an entry for to_push, and ensure that the
+ * entry has the correct flags and ttl.
+ *
+ * This function returns 1 if an entry was found or created, and 0 otherwise
+ * (because the entry for this commit had already been popped).
+ */
+static int push_parent(struct data *data, struct entry *entry,
+ struct commit *to_push)
+{
+ struct entry *parent_entry;
+
+ if (to_push->object.flags & SEEN) {
+ int i;
+ if (to_push->object.flags & POPPED)
+ /*
+ * The entry for this commit has already been popped,
+ * due to clock skew. Pretend that this parent does not
+ * exist.
+ */
+ return 0;
+ /*
+ * Find the existing entry and use it.
+ */
+ for (i = 0; i < data->rev_list.nr; i++) {
+ parent_entry = data->rev_list.array[i].data;
+ if (parent_entry->commit == to_push)
+ goto parent_found;
+ }
+ BUG("missing parent in priority queue");
+parent_found:
+ ;
+ } else {
+ parent_entry = rev_list_push(data, to_push, 0);
+ }
+
+ if (entry->commit->object.flags & (COMMON | ADVERTISED)) {
+ mark_common(data, to_push);
+ } else {
+ uint16_t new_original_ttl = entry->ttl
+ ? entry->original_ttl : entry->original_ttl * 3 / 2 + 1;
+ uint16_t new_ttl = entry->ttl
+ ? entry->ttl - 1 : new_original_ttl;
+ if (parent_entry->original_ttl < new_original_ttl) {
+ parent_entry->original_ttl = new_original_ttl;
+ parent_entry->ttl = new_ttl;
+ }
+ }
+
+ return 1;
+}
+
+static const struct object_id *get_rev(struct data *data)
+{
+ struct commit *to_send = NULL;
+
+ while (to_send == NULL) {
+ struct entry *entry;
+ s