diff options
| -rw-r--r-- | .gitlab-ci.yml | 3 | ||||
| -rw-r--r-- | .mailmap | 2 | ||||
| -rw-r--r-- | Documentation/BreakingChanges.adoc | 11 | ||||
| -rw-r--r-- | Documentation/CodingGuidelines | 6 | ||||
| -rw-r--r-- | Documentation/RelNotes/2.52.0.adoc | 120 | ||||
| -rw-r--r-- | Documentation/config.adoc | 9 | ||||
| -rw-r--r-- | Documentation/config/alias.adoc | 2 | ||||
| -rw-r--r-- | Documentation/config/core.adoc | 20 | ||||
| -rw-r--r-- | Documentation/config/promisor.adoc | 61 | ||||
| -rw-r--r-- | Documentation/config/sendemail.adoc | 2 | ||||
| -rw-r--r-- | Documentation/config/stash.adoc | 5 | ||||
| -rw-r--r-- | Documentation/config/worktree.adoc | 2 | ||||
| -rw-r--r-- | Documentation/fetch-options.adoc | 2 | ||||
| -rw-r--r-- | Documentation/git-add.adoc | 34 | ||||
| -rw-r--r-- | Documentation/git-checkout.adoc | 151 | ||||
| -rw-r--r-- | Documentation/git-fast-import.adoc | 10 | ||||
| -rw-r--r-- | Documentation/git-init.adoc | 12 | ||||
| -rw-r--r-- | Documentation/git-multi-pack-index.adoc | 2 | ||||
| -rw-r--r-- | Documentation/git-refs.adoc | 7 | ||||
| -rw-r--r-- | Documentation/git-repo.adoc | 9 | ||||
| -rw-r--r-- | Documentation/git-send-email.adoc | 34 | ||||
| -rw-r--r-- | Documentation/gitprotocol-v2.adoc | 64 | ||||
| -rw-r--r-- | add-interactive.c | 89 | ||||
| -rw-r--r-- | add-interactive.h | 7 | ||||
| -rw-r--r-- | add-patch.c | 12 | ||||
| -rw-r--r-- | advice.c | 2 | ||||
| -rw-r--r-- | advice.h | 2 | ||||
| -rw-r--r-- | alloc.c | 10 | ||||
| -rw-r--r-- | alloc.h | 4 | ||||
| -rw-r--r-- | bisect.c | 5 | ||||
| -rw-r--r-- | builtin/add.c | 2 | ||||
| -rw-r--r-- | builtin/am.c | 4 | ||||
| -rw-r--r-- | builtin/branch.c | 2 | ||||
| -rw-r--r-- | builtin/clean.c | 2 | ||||
| -rw-r--r-- | builtin/commit-graph.c | 4 | ||||
| -rw-r--r-- | builtin/commit.c | 11 | ||||
| -rw-r--r-- | builtin/config.c | 25 | ||||
| -rw-r--r-- | builtin/describe.c | 37 | ||||
| -rw-r--r-- | builtin/fetch.c | 21 | ||||
| -rw-r--r-- | builtin/grep.c | 2 | ||||
| -rw-r--r-- | builtin/last-modified.c | 1 | ||||
| -rw-r--r-- | builtin/log.c | 1 | ||||
| -rw-r--r-- | builtin/ls-tree.c | 7 | ||||
| -rw-r--r-- | builtin/merge.c | 3 | ||||
| -rw-r--r-- | builtin/multi-pack-index.c | 31 | ||||
| -rw-r--r-- | builtin/pack-objects.c | 8 | ||||
| -rw-r--r-- | builtin/push.c | 2 | ||||
| -rw-r--r-- | builtin/range-diff.c | 24 | ||||
| -rw-r--r-- | builtin/rebase.c | 6 | ||||
| -rw-r--r-- | builtin/refs.c | 48 | ||||
| -rw-r--r-- | builtin/repack.c | 7 | ||||
| -rw-r--r-- | builtin/repo.c | 45 | ||||
| -rw-r--r-- | builtin/rev-parse.c | 7 | ||||
| -rw-r--r-- | builtin/revert.c | 7 | ||||
| -rw-r--r-- | builtin/show-branch.c | 2 | ||||
| -rw-r--r-- | builtin/stash.c | 40 | ||||
| -rw-r--r-- | builtin/submodule--helper.c | 10 | ||||
| -rwxr-xr-x | ci/run-build-and-tests.sh | 1 | ||||
| -rw-r--r-- | color.c | 24 | ||||
| -rw-r--r-- | color.h | 14 | ||||
| -rw-r--r-- | combine-diff.c | 5 | ||||
| -rw-r--r-- | config.c | 297 | ||||
| -rw-r--r-- | contrib/diff-highlight/README | 8 | ||||
| -rwxr-xr-x | contrib/subtree/git-subtree.sh | 36 | ||||
| -rwxr-xr-x | contrib/subtree/t/t7900-subtree.sh | 71 | ||||
| -rw-r--r-- | diff.c | 48 | ||||
| -rw-r--r-- | diff.h | 12 | ||||
| -rw-r--r-- | environment.c | 15 | ||||
| -rw-r--r-- | environment.h | 3 | ||||
| -rw-r--r-- | git-curl-compat.h | 7 | ||||
| -rw-r--r-- | git-gui/Makefile | 2 | ||||
| -rwxr-xr-x | git-gui/git-gui--askyesno | 63 | ||||
| -rwxr-xr-x | git-gui/git-gui.sh | 42 | ||||
| -rw-r--r-- | git-gui/lib/index.tcl | 7 | ||||
| -rwxr-xr-x | git-send-email.perl | 43 | ||||
| -rw-r--r-- | gitk-git/README.md | 93 | ||||
| -rwxr-xr-x | gitk-git/gitk | 26 | ||||
| -rw-r--r-- | grep.c | 4 | ||||
| -rw-r--r-- | grep.h | 4 | ||||
| -rw-r--r-- | http-push.c | 2 | ||||
| -rw-r--r-- | http.c | 8 | ||||
| -rw-r--r-- | imap-send.c | 26 | ||||
| -rw-r--r-- | line-log.c | 15 | ||||
| -rw-r--r-- | list-objects-filter.c | 9 | ||||
| -rw-r--r-- | log-tree.c | 5 | ||||
| -rw-r--r-- | log-tree.h | 4 | ||||
| -rw-r--r-- | midx-write.c | 245 | ||||
| -rw-r--r-- | midx.c | 135 | ||||
| -rw-r--r-- | midx.h | 42 | ||||
| -rw-r--r-- | object-name.c | 37 | ||||
| -rw-r--r-- | object.c | 26 | ||||
| -rw-r--r-- | odb.c | 64 | ||||
| -rw-r--r-- | odb.h | 19 | ||||
| -rw-r--r-- | pack-bitmap.c | 15 | ||||
| -rw-r--r-- | pack-revindex.c | 14 | ||||
| -rw-r--r-- | packfile.c | 13 | ||||
| -rw-r--r-- | parse-options-cb.c | 4 | ||||
| -rw-r--r-- | pretty.c | 12 | ||||
| -rw-r--r-- | pretty.h | 3 | ||||
| -rw-r--r-- | promisor-remote.c | 424 | ||||
| -rw-r--r-- | range-diff.c | 20 | ||||
| -rw-r--r-- | range-diff.h | 5 | ||||
| -rw-r--r-- | ref-filter.h | 4 | ||||
| -rw-r--r-- | refs.c | 32 | ||||
| -rw-r--r-- | refs.h | 2 | ||||
| -rw-r--r-- | refs/files-backend.c | 78 | ||||
| -rw-r--r-- | remote.c | 5 | ||||
| -rw-r--r-- | repository.c | 2 | ||||
| -rw-r--r-- | repository.h | 3 | ||||
| -rw-r--r-- | revision.c | 49 | ||||
| -rw-r--r-- | revision.h | 2 | ||||
| -rw-r--r-- | sequencer.c | 19 | ||||
| -rw-r--r-- | sequencer.h | 4 | ||||
| -rw-r--r-- | shallow.c | 4 | ||||
| -rw-r--r-- | shallow.h | 5 | ||||
| -rw-r--r-- | sideband.c | 6 | ||||
| -rw-r--r-- | submodule.c | 2 | ||||
| -rw-r--r-- | t/helper/test-read-midx.c | 31 | ||||
| -rw-r--r-- | t/meson.build | 4 | ||||
| -rw-r--r-- | t/show-ref-exists-tests.sh | 77 | ||||
| -rwxr-xr-x | t/t0001-init.sh | 16 | ||||
| -rwxr-xr-x | t/t0450-txt-doc-vs-help.sh | 15 | ||||
| -rw-r--r-- | t/t0450/adoc-missing | 9 | ||||
| -rwxr-xr-x | t/t0613-reftable-write-options.sh | 24 | ||||
| -rwxr-xr-x | t/t1400-update-ref.sh | 53 | ||||
| -rwxr-xr-x | t/t1403-show-ref.sh | 65 | ||||
| -rwxr-xr-x | t/t1422-show-ref-exists.sh | 9 | ||||
| -rwxr-xr-x | t/t1462-refs-exists.sh | 10 | ||||
| -rwxr-xr-x | t/t1900-repo.sh | 18 | ||||
| -rwxr-xr-x | t/t3404-rebase-interactive.sh | 19 | ||||
| -rwxr-xr-x | t/t3415-rebase-autosquash.sh | 28 | ||||
| -rwxr-xr-x | t/t3418-rebase-continue.sh | 2 | ||||
| -rwxr-xr-x | t/t3701-add-interactive.sh | 53 | ||||
| -rwxr-xr-x | t/t3903-stash.sh | 49 | ||||
| -rwxr-xr-x | t/t3904-stash-patch.sh | 19 | ||||
| -rwxr-xr-x | t/t3905-stash-include-untracked.sh | 1 | ||||
| -rwxr-xr-x | t/t4013-diff-various.sh | 220 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_main (renamed from t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_--cc_--patch-with-stat_main (renamed from t/t4013/diff.diff-tree_--cc_--patch-with-stat_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_--cc_--shortstat_main (renamed from t/t4013/diff.diff-tree_--cc_--shortstat_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_--cc_--stat_--summary_main (renamed from t/t4013/diff.diff-tree_-c_--stat_--summary_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_--cc_--stat_main (renamed from t/t4013/diff.diff-tree_-c_--stat_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_--cc_main (renamed from t/t4013/diff.diff-tree_--cc_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_-c_--abbrev_main (renamed from t/t4013/diff.diff-tree_-c_--abbrev_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_-c_--stat_--summary_main (renamed from t/t4013/diff.diff-tree_--cc_--stat_--summary_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_-c_--stat_main (renamed from t/t4013/diff.diff-tree_--cc_--stat_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_-c_main (renamed from t/t4013/diff.diff-tree_-c_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_-m_main (renamed from t/t4013/diff.diff-tree_-m_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_-p_-m_main (renamed from t/t4013/diff.diff-tree_-p_-m_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_-p_main | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_-p_master | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_main | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff-tree_master | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff_--dirstat_--cc_main~1_main | 3 | ||||
| -rw-r--r-- | t/t4013/diff.diff_--dirstat_--cc_master~1_master | 3 | ||||
| -rw-r--r-- | t/t4013/diff.diff_--dirstat_main~1_main~2 | 3 | ||||
| -rw-r--r-- | t/t4013/diff.diff_--dirstat_master~1_master~2 | 3 | ||||
| -rw-r--r-- | t/t4013/diff.diff_--line-prefix=abc_main_main^_side (renamed from t/t4013/diff.diff_--line-prefix=abc_master_master^_side) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.diff_main_main^_side (renamed from t/t4013/diff.diff_master_master^_side) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--attach_--stdout_initial..main (renamed from t/t4013/diff.format-patch_--attach_--stdout_initial..master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--attach_--stdout_initial..main^ (renamed from t/t4013/diff.format-patch_--attach_--stdout_initial..master^) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..main (renamed from t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..main (renamed from t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--inline_--stdout_initial..main (renamed from t/t4013/diff.format-patch_--inline_--stdout_initial..master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--inline_--stdout_initial..main^ (renamed from t/t4013/diff.format-patch_--inline_--stdout_initial..master^) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--inline_--stdout_initial..main^^ (renamed from t/t4013/diff.format-patch_--inline_--stdout_initial..master^^) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..main^ (renamed from t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--stdout_--no-numbered_initial..main (renamed from t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--stdout_--numbered_initial..main (renamed from t/t4013/diff.format-patch_--stdout_--numbered_initial..master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--stdout_initial..main (renamed from t/t4013/diff.format-patch_--stdout_initial..master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.format-patch_--stdout_initial..main^ (renamed from t/t4013/diff.format-patch_--stdout_initial..master^) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--cc_-m_-p_main (renamed from t/t4013/diff.log_-c_-m_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--decorate=full_--all | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--decorate=full_--clear-decorations_--all | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--decorate=full_--decorate-all_--all | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--decorate_--all | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--decorate_--clear-decorations_--all | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--decorate_--decorate-all_--all | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--diff-merges=first-parent_main (renamed from t/t4013/diff.log_--diff-merges=first-parent_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--diff-merges=off_-p_--first-parent_main (renamed from t/t4013/diff.log_--no-diff-merges_-p_--first-parent_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--first-parent_--diff-merges=off_-p_main (renamed from t/t4013/diff.log_--first-parent_--diff-merges=off_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--no-diff-merges_-p_--first-parent_main (renamed from t/t4013/diff.log_--diff-merges=off_-p_--first-parent_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--patch-with-stat_--summary_main_--_dir_ (renamed from t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--patch-with-stat_main (renamed from t/t4013/diff.log_--patch-with-stat_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--patch-with-stat_main_--_dir_ (renamed from t/t4013/diff.log_--patch-with-stat_master_--_dir_) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_main (renamed from t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--root_--patch-with-stat_--summary_main (renamed from t/t4013/diff.log_--root_--patch-with-stat_--summary_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--root_--patch-with-stat_main (renamed from t/t4013/diff.log_--root_--patch-with-stat_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_main (renamed from t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--root_-p_main (renamed from t/t4013/diff.log_--root_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_--root_main (renamed from t/t4013/diff.log_--root_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-GF_-p_--pickaxe-all_main (renamed from t/t4013/diff.log_-GF_-p_--pickaxe-all_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-GF_-p_main (renamed from t/t4013/diff.log_-GF_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-GF_main (renamed from t/t4013/diff.log_-SF_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-IA_-IB_-I1_-I2_-p_main (renamed from t/t4013/diff.log_-IA_-IB_-I1_-I2_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-SF_-p_main (renamed from t/t4013/diff.log_-SF_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-SF_main (renamed from t/t4013/diff.log_-GF_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-SF_main_--max-count=0 | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-SF_main_--max-count=1 (renamed from t/t4013/diff.log_-SF_master_--max-count=2) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-SF_main_--max-count=2 | 7 | ||||
| -rw-r--r-- | t/t4013/diff.log_-SF_master_--max-count=0 | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-SF_master_--max-count=1 | 7 | ||||
| -rw-r--r-- | t/t4013/diff.log_-S_F_main (renamed from t/t4013/diff.log_-S_F_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-c_-m_-p_main (renamed from t/t4013/diff.log_--cc_-m_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-m_--raw_main (renamed from t/t4013/diff.log_-m_--raw_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-m_--stat_main (renamed from t/t4013/diff.log_-m_--stat_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-m_-p_--first-parent_main (renamed from t/t4013/diff.log_-m_-p_--first-parent_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-m_-p_main (renamed from t/t4013/diff.log_-m_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-p_--diff-merges=first-parent_main (renamed from t/t4013/diff.log_-p_--diff-merges=first-parent_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-p_--first-parent_main (renamed from t/t4013/diff.log_-p_--first-parent_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_-p_main (renamed from t/t4013/diff.log_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.log_main (renamed from t/t4013/diff.log_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.noellipses-diff-tree_-c_--abbrev_main (renamed from t/t4013/diff.noellipses-diff-tree_-c_--abbrev_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.noellipses-whatchanged_--root_main (renamed from t/t4013/diff.noellipses-whatchanged_--root_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.noellipses-whatchanged_-SF_main (renamed from t/t4013/diff.noellipses-whatchanged_-SF_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.noellipses-whatchanged_main (renamed from t/t4013/diff.noellipses-whatchanged_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.show_--first-parent_main (renamed from t/t4013/diff.show_--first-parent_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.show_-c_main (renamed from t/t4013/diff.show_-c_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.show_-m_main (renamed from t/t4013/diff.show_-m_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.show_main (renamed from t/t4013/diff.show_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_--patch-with-stat_--summary_main_--_dir_ (renamed from t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_--patch-with-stat_main (renamed from t/t4013/diff.whatchanged_--patch-with-stat_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_--patch-with-stat_main_--_dir_ (renamed from t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_main (renamed from t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_main (renamed from t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_--root_--patch-with-stat_main (renamed from t/t4013/diff.whatchanged_--root_--patch-with-stat_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_main (renamed from t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_--root_-p_main (renamed from t/t4013/diff.whatchanged_--root_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_--root_main (renamed from t/t4013/diff.whatchanged_--root_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_-SF_-p_main (renamed from t/t4013/diff.whatchanged_-SF_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_-SF_main (renamed from t/t4013/diff.whatchanged_-SF_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_-p_main (renamed from t/t4013/diff.whatchanged_-p_master) | 2 | ||||
| -rw-r--r-- | t/t4013/diff.whatchanged_main (renamed from t/t4013/diff.whatchanged_master) | 2 | ||||
| -rwxr-xr-x | t/t4211-line-log.sh | 2 | ||||
| -rw-r--r-- | t/t4211/sha1/expect.multiple | 6 | ||||
| -rw-r--r-- | t/t4211/sha1/expect.no-assertion-error | 90 | ||||
| -rw-r--r-- | t/t4211/sha1/expect.two-ranges | 6 | ||||
| -rw-r--r-- | t/t4211/sha256/expect.multiple | 6 | ||||
| -rw-r--r-- | t/t4211/sha256/expect.no-assertion-error | 90 | ||||
| -rw-r--r-- | t/t4211/sha256/expect.two-ranges | 6 | ||||
| -rwxr-xr-x | t/t5319-multi-pack-index.sh | 30 | ||||
| -rwxr-xr-x | t/t5510-fetch.sh | 114 | ||||
| -rwxr-xr-x | t/t5530-upload-pack-error.sh | 68 | ||||
| -rwxr-xr-x | t/t5564-http-proxy.sh | 4 | ||||
| -rwxr-xr-x | t/t5710-promisor-remote-capability.sh | 65 | ||||
| -rwxr-xr-x | t/t7502-commit-porcelain.sh | 52 | ||||
| -rwxr-xr-x | t/t8020-last-modified.sh | 16 | ||||
| -rwxr-xr-x | t/t9902-completion.sh | 6 | ||||
| -rw-r--r-- | t/test-lib.sh | 13 | ||||
| -rw-r--r-- | t/unit-tests/clar/.github/workflows/ci.yml | 37 | ||||
| -rw-r--r-- | t/unit-tests/clar/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | t/unit-tests/clar/README.md | 37 | ||||
| -rw-r--r-- | t/unit-tests/clar/clar.c | 154 | ||||
| -rw-r--r-- | t/unit-tests/clar/clar.h | 83 | ||||
| -rw-r--r-- | t/unit-tests/clar/clar/fixtures.h | 6 | ||||
| -rw-r--r-- | t/unit-tests/clar/clar/fs.h | 29 | ||||
| -rw-r--r-- | t/unit-tests/clar/clar/print.h | 71 | ||||
| -rw-r--r-- | t/unit-tests/clar/clar/sandbox.h | 226 | ||||
| -rw-r--r-- | t/unit-tests/clar/clar/summary.h | 5 | ||||
| -rw-r--r-- | t/unit-tests/clar/example/CMakeLists.txt | 28 | ||||
| -rw-r--r-- | t/unit-tests/clar/example/example.c | 6 | ||||
| -rw-r--r-- | t/unit-tests/clar/example/main.c (renamed from t/unit-tests/clar/test/main.c.sample) | 2 | ||||
| -rwxr-xr-x | t/unit-tests/clar/generate.py | 28 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/CMakeLists.txt | 34 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/clar_test.h | 16 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/help | 12 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/quiet | 44 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/specific_test | 9 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/stop_on_failure | 8 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/suite_names | 2 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/summary.xml | 41 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/summary_with_filename | 49 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/summary_without_filename | 49 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/tap | 92 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/expected/without_arguments | 48 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/main.c | 41 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/selftest.c | 370 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/selftest.h | 3 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/suites/CMakeLists.txt | 53 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/suites/combined.c (renamed from t/unit-tests/clar/test/sample.c) | 37 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/suites/main.c | 27 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/suites/pointer.c | 13 | ||||
| -rw-r--r-- | t/unit-tests/clar/test/suites/resources/test/file (renamed from t/unit-tests/clar/test/resources/test/file) | 0 | ||||
| -rw-r--r-- | transport.c | 2 | ||||
| -rw-r--r-- | upload-pack.c | 26 | ||||
| -rw-r--r-- | wt-status.c | 6 | ||||
| -rw-r--r-- | wt-status.h | 2 |
287 files changed, 4934 insertions, 1524 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index af10ebb59a..cf122e706f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -119,6 +119,7 @@ build:mingw64: variables: NO_PERL: 1 before_script: + - Set-MpPreference -DisableRealtimeMonitoring $true - ./ci/install-sdk.ps1 -directory "git-sdk" script: - git-sdk/usr/bin/bash.exe -l -c 'ci/make-test-artifacts.sh artifacts' @@ -135,6 +136,7 @@ test:mingw64: - job: "build:mingw64" artifacts: true before_script: + - Set-MpPreference -DisableRealtimeMonitoring $true - git-sdk/usr/bin/bash.exe -l -c 'tar xf artifacts/artifacts.tar.gz' - New-Item -Path .git/info -ItemType Directory - New-Item .git/info/exclude -ItemType File -Value "/git-sdk" @@ -148,6 +150,7 @@ test:mingw64: tags: - saas-windows-medium-amd64 before_script: + - Set-MpPreference -DisableRealtimeMonitoring $true - choco install -y git meson ninja openssl - Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 - refreshenv @@ -81,6 +81,8 @@ Fredrik Kuivinen <frekui@gmail.com> <freku045@student.liu.se> Frédéric Heitzmann <frederic.heitzmann@gmail.com> Garry Dolley <gdolley@ucla.edu> <gdolley@arpnetworks.com> Glen Choo <glencbz@gmail.com> <chooglen@google.com> +Greg Hurrell <greg@hurrell.net> <greg.hurrell@datadoghq.com> +Greg Hurrell <greg@hurrell.net> <win@wincent.com> Greg Price <price@mit.edu> <price@MIT.EDU> Greg Price <price@mit.edu> <price@ksplice.com> Heiko Voigt <hvoigt@hvoigt.net> <git-list@hvoigt.net> diff --git a/Documentation/BreakingChanges.adoc b/Documentation/BreakingChanges.adoc index f8d2eba061..0cba20fadb 100644 --- a/Documentation/BreakingChanges.adoc +++ b/Documentation/BreakingChanges.adoc @@ -165,6 +165,12 @@ A prerequisite for this change is that the ecosystem is ready to support the "reftable" format. Most importantly, alternative implementations of Git like JGit, libgit2 and Gitoxide need to support it. +* In new repositories, the default branch name will be `main`. We have been + warning that the default name will change since 675704c74dd (init: + provide useful advice about init.defaultBranch, 2020-12-11). The new name + matches the default branch name used in new repositories by many of the + big Git forges. + === Removals * Support for grafting commits has long been superseded by git-replace(1). @@ -239,6 +245,11 @@ These features will be removed. + The command will be removed. +* Support for `core.commentString=auto` has been deprecated and will + be removed in Git 3.0. ++ +cf. <xmqqa59i45wc.fsf@gitster.g> + == Superseded features that will not be deprecated Some features have gained newer replacements that aim to improve the design in diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 224f0978a8..df72fe0177 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -650,6 +650,12 @@ For C programs: cases. However, it is recommended to find a more descriptive name wherever possible to improve the readability and maintainability of the code. + - Bit fields should be defined without a space around the colon. E.g. + + unsigned my_field:1; + unsigned other_field:1; + unsigned field_with_longer_name:1; + For Perl programs: - Most of the C guidelines above apply. diff --git a/Documentation/RelNotes/2.52.0.adoc b/Documentation/RelNotes/2.52.0.adoc index 6066031491..1e5281188f 100644 --- a/Documentation/RelNotes/2.52.0.adoc +++ b/Documentation/RelNotes/2.52.0.adoc @@ -17,6 +17,33 @@ UI, Workflows & Features * A new command "git last-modified" has been added to show the closest ancestor commit that touched each path. + * "git refs exists" that works like "git show-ref --exists" has been + added. + + * "repo info" learns a short-hand option "-z" that is the same as + "--format=nul", and learns to report the objects format used in the + repository. + + * "core.commentChar=auto" that attempts to dynamically pick a + suitable comment character is non-workable, as it is too much + trouble to support for little benefit, and is marked as deprecated. + + * "git send-email" learned to drive "git imap-send" to store already + sent e-mails in an IMAP folder. + + * The "promisor-remote" capability mechanism has been updated to + allow the "partialCloneFilter" settings and the "token" value to be + communicated from the server side. + + * Declare that "git init" that is not otherwise configured uses + 'main' as the initial branch, not 'master', starting Git 3.0. + + * Keep giving hint about the default initial branch name for users + who may be surprised after Git 3.0 switch-over. + + * The stash.index configuration variable can be set to make "git stash + pop/apply" pretend that it was invoked with "--index". + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -47,6 +74,34 @@ Performance, Internal Implementation, Development Support etc. hash function implementation used to hash lines have been updated to the one used for ELF symbol lookup by Glibc. + * Instead of scanning for the remaining items to see if there are + still commits to be explored in the queue, use khash to remember + which items are still on the queue (an unacceptable alternative is + to reserve one object flag bits). + + * The bulk-checkin code used to depend on a file-scope static + singleton variable, which has been updated to pass an instance + throughout the callchain. + + * CodingGuidelines now spells out how bitfields are to be written. + + * Adjust to the way newer versions of cURL selectivel enables tracing + options, so that our tests can continue to work. + (merge 1b5a6bfff3 jk/curl-global-trace-components later to maint). + + * The clear_alloc_state() API function was not fully clearing the + structure for reuse, but since nobody reuses it, replace it with a + variant that frees the structure as well, making the callers simpler. + + * "git range-diff" learned a way to limit the memory consumed by + O(N*N) cost matrix. + + * Some places in the code confused a variable that is *not* a boolean + to enable color but is an enum that records what the user requested + to do about color. A couple of bugs of this sort have been fixed, + while the code has been cleaned up to prevent similar bugs in the + future. + Fixes since v2.51 ----------------- @@ -151,6 +206,59 @@ including security updates, are included in this release. this. (merge 681f26bccc ds/ls-files-lazy-unsparse later to maint). + * Windows "real-time monitoring" interferes with the execution of + tests and affects negatively in both correctness and performance, + which has been disabled in Gitlab CI. + (merge 608cf5b793 ps/gitlab-ci-disable-windows-monitoring later to maint). + + * A broken or malicious "git fetch" can say that it has the same + object for many many times, and the upload-pack serving it can + exhaust memory storing them redundantly, which has been corrected. + (merge 88a2dc68c8 ps/upload-pack-oom-protection later to maint). + + * A corner case bug in "git log -L..." has been corrected. + (merge e3106998ff sg/line-log-boundary-fixes later to maint). + + * "git rev-parse --short" and friends failed to disambiguate two + objects with object names that share common prefix longer than 32 + characters, which has been fixed. + (merge 8655908b9e jc/longer-disambiguation-fix later to maint). + + * Some among "git add -p" and friends ignored color.diff and/or + color.ui configuration variables, which is an old regression, which + has been corrected. + (merge 1092cd6435 jk/add-i-color later to maint). + + * "git subtree" (in contrib/) did not work correctly when splitting + squashed subtrees, which has been improved. + + * Import a newer version of the clar unit testing framework. + (merge 93dbb6b3c5 ps/clar-updates later to maint). + + * "git send-email --compose --reply-to=<address>" used to add + duplicated Reply-To: header, which made mailservers unhappy. This + has been corrected. + (merge f448f65719 nb/send-email-no-dup-reply-to later to maint). + + * "git rebase -i" failed to clean-up the commit log message when the + command commits the final one in a chain of "fixup" commands, which + has been corrected. + (merge 82a0a73e15 pw/rebase-i-cleanup-fix later to maint). + + * There are double frees and leaks around setup_revisions() API used + in "git stash show", which has been fixed, and setup_revisions() + API gained a wrapper to make it more ergonomic when using it with + strvec-manged argc/argv pairs. + (merge a04bc71725 jk/setup-revisions-freefix later to maint). + + * Deal more gracefully with directory / file conflicts when the files + backend is used for ref storage, by failing only the ones that are + involved in the conflict while allowing others. + (merge 948b2ab0d8 kn/refs-files-case-insensitive later to maint). + + * "git last-modified" operating in non-recursive mode used to trigger + a BUG(), which has been corrected. + * Other code cleanup, docfix, build fix, etc. (merge 823d537fa7 kh/doc-git-log-markup-fix later to maint). (merge cf7efa4f33 rj/t6137-cygwin-fix later to maint). @@ -164,3 +272,15 @@ including security updates, are included in this release. (merge 374579c6d4 kh/doc-interpret-trailers-markup-fix later to maint). (merge 44dce6541c kh/doc-config-typofix later to maint). (merge 785628b173 js/doc-sending-patch-via-thunderbird later to maint). + (merge e5c27bd3d8 je/doc-add later to maint). + (merge 13296ac909 ps/object-store-midx-dedup-info later to maint). + (merge 2f4bf83ffc km/alias-doc-markup-fix later to maint). + (merge b0d97aac19 kh/doc-markup-fixes later to maint). + (merge f9a6705d9a tc/t0450-harden later to maint). + (merge c25651aefd ds/midx-write-fixes later to maint). + (merge 069c15d256 rs/object-name-extend-abbrev-len-update later to maint). + (merge bf5c224537 mm/worktree-doc-typofix later to maint). + (merge 31397bc4f7 kh/doc-fast-import-markup-fix later to maint). + (merge ac7096723b jc/doc-includeif-hasconfig-remote-url-fix later to maint). + (merge fafc9b08b8 ag/doc-sendmail-gmail-example-update later to maint). + (merge a66fc22bf9 rs/get-oid-with-flags-cleanup later to maint). diff --git a/Documentation/config.adoc b/Documentation/config.adoc index cc769251be..05f1ca7293 100644 --- a/Documentation/config.adoc +++ b/Documentation/config.adoc @@ -114,8 +114,7 @@ whose format and meaning depends on the keyword. Supported keywords are: `gitdir`:: - - The data that follows the keyword `gitdir:` is used as a glob + The data that follows the keyword `gitdir` and a colon is used as a glob pattern. If the location of the .git directory matches the pattern, the include condition is met. + @@ -148,7 +147,7 @@ refer to linkgit:gitignore[5] for details. For convenience: case-insensitively (e.g. on case-insensitive file systems) `onbranch`:: - The data that follows the keyword `onbranch:` is taken to be a + The data that follows the keyword `onbranch` and a colon is taken to be a pattern with standard globbing wildcards and two additional ones, `**/` and `/**`, that can match multiple path components. If we are in a worktree where the name of the branch that is @@ -161,8 +160,8 @@ all branches that begin with `foo/`. This is useful if your branches are organized hierarchically and you would like to apply a configuration to all the branches in that hierarchy. -`hasconfig:remote.*.url:`:: - The data that follows this keyword is taken to +`hasconfig:remote.*.url`:: + The data that follows this keyword and a colon is taken to be a pattern with standard globbing wildcards and two additional ones, `**/` and `/**`, that can match multiple components. The first time this keyword is seen, the rest of diff --git a/Documentation/config/alias.adoc b/Documentation/config/alias.adoc index 2c5db0ad84..95825354bf 100644 --- a/Documentation/config/alias.adoc +++ b/Documentation/config/alias.adoc @@ -38,6 +38,6 @@ it will be treated as a shell command. For example, defining ** A convenient way to deal with this is to write your script operations in an inline function that is then called with any arguments from the command-line. For example `alias.cmd = "!c() { - echo $1 | grep $2 ; }; c" will correctly execute the prior example. + echo $1 | grep $2 ; }; c"` will correctly execute the prior example. ** Setting `GIT_TRACE=1` can help you debug the command being run for your alias. diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc index 3fbe83eef1..08739bb9d4 100644 --- a/Documentation/config/core.adoc +++ b/Documentation/config/core.adoc @@ -531,9 +531,25 @@ core.commentString:: commented, and removes them after the editor returns (default '#'). + -If set to "auto", `git-commit` would select a character that is not +ifndef::with-breaking-changes[] +If set to "auto", `git-commit` will select a character that is not the beginning character of any line in existing commit messages. -+ +Support for this value is deprecated and will be removed in Git 3.0 +due to the following limitations: ++ +-- +* It is incompatible with adding comments in a commit message + template. This includes the conflicts comments added to + the commit message by `cherry-pick`, `merge`, `rebase` and + `revert`. +* It is incompatible with adding comments to the commit message + in the `prepare-commit-msg` hook. +* It is incompatible with the `fixup` and `squash` commands when + rebasing, +* It is not respected by `git notes` +-- ++ +endif::with-breaking-changes[] Note that these two variables are aliases of each other, and in modern versions of Git you are free to use a string (e.g., `//` or `⁑⁕⁑`) with `commentChar`. Versions of Git prior to v2.45.0 will ignore diff --git a/Documentation/config/promisor.adoc b/Documentation/config/promisor.adoc index 2638b01f83..93e5e0d9b5 100644 --- a/Documentation/config/promisor.adoc +++ b/Documentation/config/promisor.adoc @@ -9,6 +9,28 @@ promisor.advertise:: "false", which means the "promisor-remote" capability is not advertised. +promisor.sendFields:: + A comma or space separated list of additional remote related + field names. A server sends these field names and the + associated field values from its configuration when + advertising its promisor remotes using the "promisor-remote" + capability, see linkgit:gitprotocol-v2[5]. Currently, only the + "partialCloneFilter" and "token" field names are supported. ++ +`partialCloneFilter`:: contains the partial clone filter +used for the remote. ++ +`token`:: contains an authentication token for the remote. ++ +When a field name is part of this list and a corresponding +"remote.foo.<field-name>" config variable is set on the server to a +non-empty value, then the field name and value are sent when +advertising the promisor remote "foo". ++ +This list has no effect unless the "promisor.advertise" config +variable is set to "true", and the "name" and "url" fields are always +advertised regardless of this setting. + promisor.acceptFromServer:: If set to "all", a client will accept all the promisor remotes a server might advertise using the "promisor-remote" @@ -28,3 +50,42 @@ promisor.acceptFromServer:: lazily fetchable from this promisor remote from its responses to "fetch" and "clone" requests from the client. Name and URL comparisons are case sensitive. See linkgit:gitprotocol-v2[5]. + +promisor.checkFields:: + A comma or space separated list of additional remote related + field names. A client checks if the values of these fields + transmitted by a server correspond to the values of these + fields in its own configuration before accepting a promisor + remote. Currently, "partialCloneFilter" and "token" are the + only supported field names. ++ +If one of these field names (e.g., "token") is being checked for an +advertised promisor remote (e.g., "foo"), three conditions must be met +for the check of this specific field to pass: ++ +1. The corresponding local configuration (e.g., `remote.foo.token`) + must be set. +2. The server must advertise the "token" field for remote "foo". +3. The value of the locally configured `remote.foo.token` must exactly + match the value advertised by the server for the "token" field. ++ +If any of these conditions is not met for any field name listed in +`promisor.checkFields`, the advertised remote "foo" is rejected. ++ +For the "partialCloneFilter" field, this allows the client to ensure +that the server's filter matches what it expects locally, preventing +inconsistencies in filtering behavior. For the "token" field, this can +be used to verify that authentication credentials match expected +values. ++ +Field values are compared case-sensitively. ++ +The "name" and "url" fields are always checked according to the +`promisor.acceptFromServer` policy, independently of this setting. ++ +The field names and values should be passed by the server through the +"promisor-remote" capability by using the `promisor.sendFields` config +variable. The fields are checked only if the +`promisor.acceptFromServer` config variable is not set to "None". If +set to "None", this config variable has no effect. See +linkgit:gitprotocol-v2[5]. diff --git a/Documentation/config/sendemail.adoc b/Documentation/config/sendemail.adoc index 4722334657..90164c734d 100644 --- a/Documentation/config/sendemail.adoc +++ b/Documentation/config/sendemail.adoc @@ -88,6 +88,8 @@ sendemail.smtpServer:: sendemail.smtpServerPort:: sendemail.smtpServerOption:: sendemail.smtpUser:: +sendemail.imapSentFolder:: +sendemail.useImapOnly:: sendemail.thread:: sendemail.transferEncoding:: sendemail.validate:: diff --git a/Documentation/config/stash.adoc b/Documentation/config/stash.adoc index ec1edaeba6..e556105a15 100644 --- a/Documentation/config/stash.adoc +++ b/Documentation/config/stash.adoc @@ -1,3 +1,8 @@ +stash.index:: + If this is set to true, `git stash apply` and `git stash pop` will + behave as if `--index` was supplied. Defaults to false. See the + descriptions in linkgit:git-stash[1]. + stash.showIncludeUntracked:: If this is set to true, the `git stash show` command will show the untracked files of a stash entry. Defaults to false. See diff --git a/Documentation/config/worktree.adoc b/Documentation/config/worktree.adoc index 5e35c7d018..9e3f84f748 100644 --- a/Documentation/config/worktree.adoc +++ b/Documentation/config/worktree.adoc @@ -15,5 +15,5 @@ worktree.useRelativePaths:: different locations or environments. Defaults to "false". + Note that setting `worktree.useRelativePaths` to "true" implies enabling the -`extension.relativeWorktrees` config (see linkgit:git-config[1]), +`extensions.relativeWorktrees` config (see linkgit:git-config[1]), thus making it incompatible with older versions of Git. diff --git a/Documentation/fetch-options.adoc b/Documentation/fetch-options.adoc index d3ac31f4e2..ad1e1f49be 100644 --- a/Documentation/fetch-options.adoc +++ b/Documentation/fetch-options.adoc @@ -2,7 +2,7 @@ --no-all:: Fetch all remotes, except for the ones that has the `remote.<name>.skipFetchAll` configuration variable set. - This overrides the configuration variable fetch.all`. + This overrides the configuration variable `fetch.all`. -a:: --append:: diff --git a/Documentation/git-add.adoc b/Documentation/git-add.adoc index b7a735824d..ad629c46c5 100644 --- a/Documentation/git-add.adoc +++ b/Documentation/git-add.adoc @@ -16,18 +16,18 @@ git add [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [- DESCRIPTION ----------- -This command updates the index using the current content found in -the working tree, to prepare the content staged for the next commit. -It typically adds the current content of existing paths as a whole, -but with some options it can also be used to add content with -only part of the changes made to the working tree files applied, or -remove paths that do not exist in the working tree anymore. - -The "index" holds a snapshot of the content of the working tree, and it -is this snapshot that is taken as the contents of the next commit. Thus -after making any changes to the working tree, and before running -the commit command, you must use the `add` command to add any new or -modified files to the index. +Add contents of new or changed files to the index. The "index" (also +known as the "staging area") is what you use to prepare the contents of +the next commit. + +When you run `git commit` without any other arguments, it will only +commit staged changes. For example, if you've edited `file.c` and want +to commit your changes to that file, you can run: + + git add file.c + git commit + +You can also add only part of your changes to a file with `git add -p`. This command can be performed multiple times before a commit. It only adds the content of the specified file(s) at the time the add command is @@ -37,12 +37,10 @@ you must run `git add` again to add the new content to the index. The `git status` command can be used to obtain a summary of which files have changes that are staged for the next commit. -The `git add` command will not add ignored files by default. If any -ignored files were explicitly specified on the command line, `git add` -will fail with a list of ignored files. Ignored files reached by -directory recursion or filename globbing performed by Git (quote your -globs before the shell) will be silently ignored. The `git add` command can -be used to add ignored files with the `-f` (force) option. +The `git add` command will not add ignored files by default. You can +use the `--force` option to add ignored files. If you specify the exact +filename of an ignored file, `git add` will fail with a list of ignored +files. Otherwise it will silently ignore the file. Please see linkgit:git-commit[1] for alternative ways to add content to a commit. diff --git a/Documentation/git-checkout.adoc b/Documentation/git-checkout.adoc index ff1cb29bc1..431185ca0b 100644 --- a/Documentation/git-checkout.adoc +++ b/Documentation/git-checkout.adoc @@ -12,25 +12,29 @@ git checkout [-q] [-f] [-m] [<branch>] git checkout [-q] [-f] [-m] --detach [<branch>] git checkout [-q] [-f] [-m] [--detach] <commit> git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new-branch>] [<start-point>] -git checkout [-f] <tree-ish> [--] <pathspec>... -git checkout [-f] <tree-ish> --pathspec-from-file=<file> [--pathspec-file-nul] +git checkout <tree-ish> [--] <pathspec>... +git checkout <tree-ish> --pathspec-from-file=<file> [--pathspec-file-nul] git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [--] <pathspec>... git checkout [-f|--ours|--theirs|-m|--conflict=<style>] --pathspec-from-file=<file> [--pathspec-file-nul] git checkout (-p|--patch) [<tree-ish>] [--] [<pathspec>...] DESCRIPTION ----------- -Updates files in the working tree to match the version in the index -or the specified tree. If no pathspec was given, `git checkout` will -also update `HEAD` to set the specified branch as the current -branch. + +`git checkout` has two main modes: + +1. **Switch branches**, with `git checkout <branch>` +2. **Restore a different version of a file**, for example with + `git checkout <commit> <filename>` or `git checkout <filename>` + +See ARGUMENT DISAMBIGUATION below for how Git decides which one to do. `git checkout [<branch>]`:: - To prepare for working on _<branch>_, switch to it by updating - the index and the files in the working tree, and by pointing - `HEAD` at the branch. Local modifications to the files in the - working tree are kept, so that they can be committed to the - _<branch>_. + Switch to _<branch>_. This sets the current branch to _<branch>_ and + updates the files in your working directory. The checkout will fail + if there are uncommitted changes to any files where _<branch>_ and + your current commit have different content. Uncommitted changes will + otherwise be kept. + If _<branch>_ is not found but there does exist a tracking branch in exactly one remote (call it _<remote>_) with a matching name and @@ -40,68 +44,63 @@ exactly one remote (call it _<remote>_) with a matching name and $ git checkout -b <branch> --track <remote>/<branch> ------------ + -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, -if it exists, for the current branch. - -`git checkout (-b|-B) <new-branch> [<start-point>]`:: - - Specifying `-b` causes a new branch to be created as if - linkgit:git-branch[1] were called and then checked out. In - this case you can use the `--track` or `--no-track` options, - which will be passed to `git branch`. As a convenience, - `--track` without `-b` implies branch creation; see the - description of `--track` below. -+ -If `-B` is given, _<new-branch>_ is created if it doesn't exist; otherwise, it -is reset. This is the transactional equivalent of -+ ------------- -$ git branch -f <branch> [<start-point>] -$ git checkout <branch> ------------- +Running `git checkout` without specifying a branch has no effect except +to print out the tracking information for the current branch. + +`git checkout -b <new-branch> [<start-point>]`:: + + Create a new branch named _<new-branch>_, start it at _<start-point>_ + (defaults to the current commit), and check out the new branch. + You can use the `--track` or `--no-track` options to set the branch's + upstream tracking information. + -that is to say, the branch is not reset/created unless "git checkout" is -successful (e.g., when the branch is in use in another worktree, not -just the current branch stays the same, but the branch is not reset to -the start-point, either). +This will fail if there's an error checking out _<new-branch>_, for +example if checking out the `<start-point>` commit would overwrite your +uncommitted changes. + +`git checkout -B <branch> [<start-point>]`:: + + The same as `-b`, except that if the branch already exists it + resets `_<branch>_` to the start point instead of failing. `git checkout --detach [<branch>]`:: `git checkout [--detach] <commit>`:: - Prepare to work on top of _<commit>_, by detaching `HEAD` at it - (see "DETACHED HEAD" section), and updating the index and the - files in the working tree. Local modifications to the files - in the working tree are kept, so that the resulting working - tree will be the state recorded in the commit plus the local - modifications. -+ -When the _<commit>_ argument is a branch name, the `--detach` option can -be used to detach `HEAD` at the tip of the branch (`git checkout -<branch>` would check out that branch without detaching `HEAD`). + The same as `git checkout <branch>`, except that instead of pointing + `HEAD` at the branch, it points `HEAD` at the commit ID. + See the "DETACHED HEAD" section below for more. + Omitting _<branch>_ detaches `HEAD` at the tip of the current branch. -`git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>...`:: -`git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul]`:: +`git checkout <tree-ish> [--] <pathspec>...`:: +`git checkout <tree-ish> --pathspec-from-file=<file> [--pathspec-file-nul]`:: - Overwrite the contents of the files that match the pathspec. - When the _<tree-ish>_ (most often a commit) is not given, - overwrite working tree with the contents in the index. - When the _<tree-ish>_ is given, overwrite both the index and - the working tree with the contents at the _<tree-ish>_. + Replace the specified files and/or directories with the version from + the given commit or tree and add them to the index + (also known as "staging area"). + -The index may contain unmerged entries because of a previous failed merge. -By default, if you try to check out such an entry from the index, the -checkout operation will fail and nothing will be checked out. -Using `-f` will ignore these unmerged entries. The contents from a -specific side of the merge can be checked out of the index by -using `--ours` or `--theirs`. With `-m`, changes made to the working tree -file can be discarded to re-create the original conflicted merge result. +For example, `git checkout main file.txt` will replace `file.txt` +with the version from `main`. + +`git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [--] <pathspec>...`:: +`git checkout [-f|--ours|--theirs|-m|--conflict=<style>] --pathspec-from-file=<file> [--pathspec-file-nul]`:: + + Replace the specified files and/or directories with the version from + the index. ++ +For example, if you check out a commit, edit `file.txt`, and then +decide those changes were a mistake, `git checkout file.txt` will +discard any unstaged changes to `file.txt`. ++ +This will fail if the file has a merge conflict and you haven't yet run +`git add file.txt` (or something equivalent) to mark it as resolved. +You can use `-f` to ignore the unmerged files instead of failing, use +`--ours` or `--theirs` to replace them with the version from a specific +side of the merge, or use `-m` to replace them with the original +conflicted merge result. `git checkout (-p|--patch) [<tree-ish>] [--] [<pathspec>...]`:: - This is similar to the previous mode, but lets you use the + This is similar to the previous two modes, but lets you use the interactive interface to show the "diff" output and choose which hunks to use in the result. See below for the description of `--patch` option. @@ -155,16 +154,14 @@ of it"). see linkgit:git-branch[1] for details. `-B <new-branch>`:: - Creates the branch _<new-branch>_, start it at _<start-point>_; - if it already exists, then reset it to _<start-point>_. And then - check the resulting branch out. This is equivalent to running - `git branch` with `-f` followed by `git checkout` of that branch; - see linkgit:git-branch[1] for details. + The same as `-b`, except that if the branch already exists it + resets `_<branch>_` to the start point instead of failing. `-t`:: `--track[=(direct|inherit)]`:: When creating a new branch, set up "upstream" configuration. See - `--track` in linkgit:git-branch[1] for details. + `--track` in linkgit:git-branch[1] for details. As a convenience, + --track without -b implies branch creation. + If no `-b` option is given, the name of the new branch will be derived from the remote-tracking branch, by looking at the local part of @@ -511,14 +508,18 @@ $ git log -g -2 HEAD ARGUMENT DISAMBIGUATION ----------------------- -When there is only one argument given and it is not `--` (e.g. `git -checkout abc`), and when the argument is both a valid _<tree-ish>_ -(e.g. a branch `abc` exists) and a valid _<pathspec>_ (e.g. a file -or a directory whose name is "abc" exists), Git would usually ask -you to disambiguate. Because checking out a branch is so common an -operation, however, `git checkout abc` takes "abc" as a _<tree-ish>_ -in such a situation. Use `git checkout -- <pathspec>` if you want -to checkout these paths out of the index. +When you run `git checkout <something>`, Git tries to guess whether +`<something>` is intended to be a branch, a commit, or a set of file(s), +and then either switches to that branch or commit, or restores the +specified files. + +If there's any ambiguity, Git will treat `<something>` as a branch or +commit, but you can use the double dash `--` to force Git to treat the +parameter as a list of files and/or directories, like this: + +---------- +git checkout -- file.txt +---------- EXAMPLES -------- diff --git a/Documentation/git-fast-import.adoc b/Documentation/git-fast-import.adoc index 3144ffcdb6..6e095b02a1 100644 --- a/Documentation/git-fast-import.adoc +++ b/Documentation/git-fast-import.adoc @@ -61,10 +61,10 @@ OPTIONS currently impacts only the `export-marks`, `import-marks`, and `import-marks-if-exists` feature commands. + - Only enable this option if you trust the program generating the - fast-import stream! This option is enabled automatically for - remote-helpers that use the `import` capability, as they are - already trusted to run their own code. +Only enable this option if you trust the program generating the +fast-import stream! This option is enabled automatically for +remote-helpers that use the `import` capability, as they are +already trusted to run their own code. Options for Frontends ~~~~~~~~~~~~~~~~~~~~~ @@ -647,7 +647,7 @@ External data format:: + Here usually `<dataref>` must be either a mark reference (`:<idnum>`) set by a prior `blob` command, or a full 40-byte SHA-1 of an -existing Git blob object. If `<mode>` is `040000`` then +existing Git blob object. If `<mode>` is `040000` then `<dataref>` must be the full 40-byte SHA-1 of an existing Git tree object or a mark reference set with `--import-marks`. diff --git a/Documentation/git-init.adoc b/Documentation/git-init.adoc index a0dffba665..bab99b9b47 100644 --- a/Documentation/git-init.adoc +++ b/Documentation/git-init.adoc @@ -77,9 +77,15 @@ If this is a reinitialization, the repository will be moved to the specified pat `-b <branch-name>`:: `--initial-branch=<branch-name>`:: Use _<branch-name>_ for the initial branch in the newly created -repository. If not specified, fall back to the default name (currently -`master`, but this is subject to change in the future; the name can be -customized via the `init.defaultBranch` configuration variable). +repository. If not specified, fall back to the default name +ifndef::with-breaking-changes[] +(currently `master`, but this will change to `main` when Git 3.0 is released). +endif::with-breaking-changes[] +ifdef::with-breaking-changes[] +`main`. +endif::with-breaking-changes[] +The default name can be customized via the `init.defaultBranch` configuration +variable. `--shared[=(false|true|umask|group|all|world|everybody|<perm>)]`:: diff --git a/Documentation/git-multi-pack-index.adoc b/Documentation/git-multi-pack-index.adoc index e8073bc272..2f642697e9 100644 --- a/Documentation/git-multi-pack-index.adoc +++ b/Documentation/git-multi-pack-index.adoc @@ -29,7 +29,7 @@ OPTIONS --no-progress:: Turn progress on/off explicitly. If neither is specified, progress is shown if standard error is connected to a terminal. Supported by - sub-commands `write`, `verify`, `expire`, and `repack. + sub-commands `write`, `verify`, `expire`, and `repack`. The following subcommands are available: diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc index d462953fb5..bfa9b3ea2d 100644 --- a/Documentation/git-refs.adoc +++ b/Documentation/git-refs.adoc @@ -18,6 +18,7 @@ git refs list [--count=<count>] [--shell|--perl|--python|--tcl] [--contains[=<object>]] [--no-contains[=<object>]] [(--exclude=<pattern>)...] [--start-after=<marker>] [ --stdin | (<pattern>...)] +git refs exists <ref> DESCRIPTION ----------- @@ -38,6 +39,12 @@ list:: formatting, and sorting. This subcommand is an alias for linkgit:git-for-each-ref[1] and offers identical functionality. +exists:: + Check whether the given reference exists. Returns an exit code of 0 if + it does, 2 if it is missing, and 1 in case looking up the reference + failed with an error other than the reference being missing. This does + not verify whether the reference resolves to an actual object. + OPTIONS ------- diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index 2870828d93..209afd1b61 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -8,7 +8,7 @@ git-repo - Retrieve information about the repository SYNOPSIS -------- [synopsis] -git repo info [--format=(keyvalue|nul)] [<key>...] +git repo info [--format=(keyvalue|nul)] [-z] [<key>...] DESCRIPTION ----------- @@ -18,7 +18,7 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE. COMMANDS -------- -`info [--format=(keyvalue|nul)] [<key>...]`:: +`info [--format=(keyvalue|nul)] [-z] [<key>...]`:: Retrieve metadata-related information about the current repository. Only the requested data will be returned based on their keys (see "INFO KEYS" section below). @@ -40,6 +40,8 @@ supported: between the key and the value and using a NUL character after each value. This format is better suited for being parsed by another applications than `keyvalue`. Unlike in the `keyvalue` format, the values are never quoted. ++ +`-z` is an alias for `--format=nul`. INFO KEYS --------- @@ -53,6 +55,9 @@ values that they return: `layout.shallow`:: `true` if this is a shallow repository, otherwise `false`. +`object.format`:: + The object format (hash algorithm) used in the repository. + `references.format`:: The reference storage format. The valid values are: + diff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc index 11b1ab1a07..263b977353 100644 --- a/Documentation/git-send-email.adoc +++ b/Documentation/git-send-email.adoc @@ -300,6 +300,32 @@ must be used for each option. commands and replies will be printed. Useful to debug TLS connection and authentication problems. +--imap-sent-folder=<folder>:: + Some email providers (e.g. iCloud) do not send a copy of the emails sent + using SMTP to the `Sent` folder or similar in your mailbox. Use this option + to use `git imap-send` to send a copy of the emails to the folder specified + using this option. You can run `git imap-send --list` to get a list of + valid folder names, including the correct name of the `Sent` folder in + your mailbox. You can also use this option to send emails to a dedicated + IMAP folder of your choice. ++ +This feature requires setting up `git imap-send`. See linkgit:git-imap-send[1] +for instructions. + +--use-imap-only:: +--no-use-imap-only:: + If this is set, all emails will only be copied to the IMAP folder specified + with `--imap-sent-folder` or `sendemail.imapSentFolder` and will not be sent + to the recipients. Useful if you just want to create a draft of the emails + and use another email client to send them. + If disabled with `--no-use-imap-only`, the emails will be sent like usual. + Disabled by default, but the `sendemail.useImapOnly` configuration + variable can be used to enable it. + ++ +This feature requires setting up `git imap-send`. See linkgit:git-imap-send[1] +for instructions. + --batch-size=<num>:: Some email servers (e.g. 'smtp.163.com') limit the number of emails to be sent per session (connection) and this will lead to a failure when @@ -531,10 +557,10 @@ edit `~/.gitconfig` to specify your account settings: ---- [sendemail] - smtpEncryption = tls + smtpEncryption = ssl smtpServer = smtp.gmail.com smtpUser = yourname@gmail.com - smtpServerPort = 587 + smtpServerPort = 465 ---- Gmail does not allow using your regular password for `git send-email`. @@ -552,10 +578,10 @@ if you want to use `OAUTHBEARER`, edit your `~/.gitconfig` file and add ---- [sendemail] - smtpEncryption = tls + smtpEncryption = ssl smtpServer = smtp.gmail.com smtpUser = yourname@gmail.com - smtpServerPort = 587 + smtpServerPort = 465 smtpAuth = OAUTHBEARER ---- diff --git a/Documentation/gitprotocol-v2.adoc b/Documentation/gitprotocol-v2.adoc index 9a57005d77..c7db103299 100644 --- a/Documentation/gitprotocol-v2.adoc +++ b/Documentation/gitprotocol-v2.adoc @@ -785,33 +785,64 @@ retrieving the header from a bundle at the indicated URI, and thus save themselves and the server(s) the request(s) needed to inspect the headers of that bundle or bundles. -promisor-remote=<pr-infos> -~~~~~~~~~~~~~~~~~~~~~~~~~~ +promisor-remote=<pr-info> +~~~~~~~~~~~~~~~~~~~~~~~~~ The server may advertise some promisor remotes it is using or knows about to a client which may want to use them as its promisor remotes, -instead of this repository. In this case <pr-infos> should be of the +instead of this repository. In this case <pr-info> should be of the form: - pr-infos = pr-info | pr-infos ";" pr-info + pr-info = pr-fields | pr-info ";" pr-fields - pr-info = "name=" pr-name | "name=" pr-name "," "url=" pr-url + pr-fields = pr-field | pr-fields "," pr-field -where `pr-name` is the urlencoded name of a promisor remote, and -`pr-url` the urlencoded URL of that promisor remote. + pr-field = field-name "=" field-value -In this case, if the client decides to use one or more promisor -remotes the server advertised, it can reply with -"promisor-remote=<pr-names>" where <pr-names> should be of the form: +where all the `field-name` and `field-value` in a given `pr-fields` +are field names and values related to a single promisor remote. A +given `field-name` MUST NOT appear more than once in given +`pr-fields`. + +The server MUST advertise at least the "name" and "url" field names +along with the associated field values, which are the name of a valid +remote and its URL, in each `pr-fields`. The "name" and "url" fields +MUST appear first in each pr-fields, in that order. + +After these mandatory fields, the server MAY advertise the following +optional fields in any order: + +`partialCloneFilter`:: The filter specification used by the remote. +Clients can use this to determine if the remote's filtering strategy +is compatible with their needs (e.g., checking if both use "blob:none"). +It corresponds to the "remote.<name>.partialCloneFilter" config setting. + +`token`:: An authentication token that clients can use when +connecting to the remote. It corresponds to the "remote.<name>.token" +config setting. + +No other fields are defined by the protocol at this time. Field names +are case-sensitive and MUST be transmitted exactly as specified +above. Clients MUST ignore fields they don't recognize to allow for +future protocol extensions. + +For now, the client can only use information transmitted through these +fields to decide if it accepts the advertised promisor remote. In the +future that information might be used for other purposes though. + +Field values MUST be urlencoded. + +If the client decides to use one or more promisor remotes the server +advertised, it can reply with "promisor-remote=<pr-names>" where +<pr-names> should be of the form: pr-names = pr-name | pr-names ";" pr-name where `pr-name` is the urlencoded name of a promisor remote the server advertised and the client accepts. -Note that, everywhere in this document, `pr-name` MUST be a valid -remote name, and the ';' and ',' characters MUST be encoded if they -appear in `pr-name` or `pr-url`. +Note that, everywhere in this document, the ';' and ',' characters +MUST be encoded if they appear in `pr-name` or `field-value`. If the server doesn't know any promisor remote that could be good for a client to use, or prefers a client not to use any promisor remote it @@ -822,9 +853,10 @@ In this case, or if the client doesn't want to use any promisor remote the server advertised, the client shouldn't advertise the "promisor-remote" capability at all in its reply. -The "promisor.advertise" and "promisor.acceptFromServer" configuration -options can be used on the server and client side to control what they -advertise or accept respectively. See the documentation of these +On the server side, the "promisor.advertise" and "promisor.sendFields" +configuration options can be used to control what it advertises. On +the client side, the "promisor.acceptFromServer" configuration option +can be used to control what it accepts. See the documentation of these configuration options for more information. Note that in the future it would be nice if the "promisor-remote" diff --git a/add-interactive.c b/add-interactive.c index 3e692b47ec..6ffe64c38d 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -20,14 +20,14 @@ #include "prompt.h" #include "tree.h" -static void init_color(struct repository *r, struct add_i_state *s, +static void init_color(struct repository *r, enum git_colorbool use_color, const char *section_and_slot, char *dst, const char *default_color) { char *key = xstrfmt("color.%s", section_and_slot); const char *value; - if (!s->use_color) + if (!want_color(use_color)) dst[0] = '\0'; else if (repo_config_get_value(r, key, &value) || color_parse(value, dst)) @@ -36,42 +36,64 @@ static void init_color(struct repository *r, struct add_i_state *s, free(key); } -void init_add_i_state(struct add_i_state *s, struct repository *r, - struct add_p_opt *add_p_opt) +static enum git_colorbool check_color_config(struct repository *r, const char *var) { const char *value; + enum git_colorbool ret; + + if (repo_config_get_value(r, var, &value)) + ret = GIT_COLOR_UNKNOWN; + else + ret = git_config_colorbool(var, value); + + /* + * Do not rely on want_color() to fall back to color.ui for us. It uses + * the value parsed by git_color_config(), which may not have been + * called by the main command. + */ + if (ret == GIT_COLOR_UNKNOWN && + !repo_config_get_value(r, "color.ui", &value)) + ret = git_config_colorbool("color.ui", value); + return ret; +} + +void init_add_i_state(struct add_i_state *s, struct repository *r, + struct add_p_opt *add_p_opt) +{ s->r = r; s->context = -1; s->interhunkcontext = -1; - if (repo_config_get_value(r, "color.interactive", &value)) - s->use_color = -1; - else - s->use_color = - git_config_colorbool("color.interactive", value); - s->use_color = want_color(s->use_color); - - init_color(r, s, "interactive.header", s->header_color, GIT_COLOR_BOLD); - init_color(r, s, "interactive.help", s->help_color, GIT_COLOR_BOLD_RED); - init_color(r, s, "interactive.prompt", s->prompt_color, - GIT_COLOR_BOLD_BLUE); - init_color(r, s, "interactive.error", s->error_color, - GIT_COLOR_BOLD_RED); - - init_color(r, s, "diff.frag", s->fraginfo_color, - diff_get_color(s->use_color, DIFF_FRAGINFO)); - init_color(r, s, "diff.context", s->context_color, "fall back"); + s->use_color_interactive = check_color_config(r, "color.interactive"); + + init_color(r, s->use_color_interactive, "interactive.header", + s->header_color, GIT_COLOR_BOLD); + init_color(r, s->use_color_interactive, "interactive.help", + s->help_color, GIT_COLOR_BOLD_RED); + init_color(r, s->use_color_interactive, "interactive.prompt", + s->prompt_color, GIT_COLOR_BOLD_BLUE); + init_color(r, s->use_color_interactive, "interactive.error", + s->error_color, GIT_COLOR_BOLD_RED); + strlcpy(s->reset_color_interactive, + want_color(s->use_color_interactive) ? GIT_COLOR_RESET : "", COLOR_MAXLEN); + + s->use_color_diff = check_color_config(r, "color.diff"); + + init_color(r, s->use_color_diff, "diff.frag", s->fraginfo_color, + diff_get_color(s->use_color_diff, DIFF_FRAGINFO)); + init_color(r, s->use_color_diff, "diff.context", s->context_color, + "fall back"); if (!strcmp(s->context_color, "fall back")) - init_color(r, s, "diff.plain", s->context_color, - diff_get_color(s->use_color, DIFF_CONTEXT)); - init_color(r, s, "diff.old", s->file_old_color, - diff_get_color(s->use_color, DIFF_FILE_OLD)); - init_color(r, s, "diff.new", s->file_new_color, - diff_get_color(s->use_color, DIFF_FILE_NEW)); - - strlcpy(s->reset_color, - s->use_color ? GIT_COLOR_RESET : "", COLOR_MAXLEN); + init_color(r, s->use_color_diff, "diff.plain", + s->context_color, + diff_get_color(s->use_color_diff, DIFF_CONTEXT)); + init_color(r, s->use_color_diff, "diff.old", s->file_old_color, + diff_get_color(s->use_color_diff, DIFF_FILE_OLD)); + init_color(r, s->use_color_diff, "diff.new", s->file_new_color, + diff_get_color(s->use_color_diff, DIFF_FILE_NEW)); + strlcpy(s->reset_color_diff, + want_color(s->use_color_diff) ? GIT_COLOR_RESET : "", COLOR_MAXLEN); FREE_AND_NULL(s->interactive_diff_filter); repo_config_get_string(r, "interactive.difffilter", @@ -109,7 +131,8 @@ void clear_add_i_state(struct add_i_state *s) FREE_AND_NULL(s->interactive_diff_filter); FREE_AND_NULL(s->interactive_diff_algorithm); memset(s, 0, sizeof(*s)); - s->use_color = -1; + s->use_color_interactive = GIT_COLOR_UNKNOWN; + s->use_color_diff = GIT_COLOR_UNKNOWN; } /* @@ -1188,9 +1211,9 @@ int run_add_i(struct repository *r, const struct pathspec *ps, * When color was asked for, use the prompt color for * highlighting, otherwise use square brackets. */ - if (s.use_color) { + if (want_color(s.use_color_interactive)) { data.color = s.prompt_color; - data.reset = s.reset_color; + data.reset = s.reset_color_interactive; } print_file_item_data.color = data.color; print_file_item_data.reset = data.reset; diff --git a/add-interactive.h b/add-interactive.h index 4213dcd67b..da49502b76 100644 --- a/add-interactive.h +++ b/add-interactive.h @@ -12,16 +12,19 @@ struct add_p_opt { struct add_i_state { struct repository *r; - int use_color; + enum git_colorbool use_color_interactive; + enum git_colorbool use_color_diff; char header_color[COLOR_MAXLEN]; char help_color[COLOR_MAXLEN]; char prompt_color[COLOR_MAXLEN]; char error_color[COLOR_MAXLEN]; - char reset_color[COLOR_MAXLEN]; + char reset_color_interactive[COLOR_MAXLEN]; + char fraginfo_color[COLOR_MAXLEN]; char context_color[COLOR_MAXLEN]; char file_old_color[COLOR_MAXLEN]; char file_new_color[COLOR_MAXLEN]; + char reset_color_diff[COLOR_MAXLEN]; int use_single_key; char *interactive_diff_filter, *interactive_diff_algorithm; diff --git a/add-patch.c b/add-patch.c index 302e6ba7d9..b0389c5d5b 100644 --- a/add-patch.c +++ b/add-patch.c @@ -300,7 +300,7 @@ static void err(struct add_p_state *s, const char *fmt, ...) va_start(args, fmt); fputs(s->s.error_color, stdout); vprintf(fmt, args); - puts(s->s.reset_color); + puts(s->s.reset_color_interactive); va_end(args); } @@ -457,7 +457,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) } strbuf_complete_line(plain); - if (want_color_fd(1, -1)) { + if (want_color_fd(1, s->s.use_color_diff)) { struct child_process colored_cp = CHILD_PROCESS_INIT; const char *diff_filter = s->s.interactive_diff_filter; @@ -714,7 +714,7 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk, if (len) strbuf_add(out, p, len); else if (colored) - strbuf_addf(out, "%s\n", s->s.reset_color); + strbuf_addf(out, "%s\n", s->s.reset_color_diff); else strbuf_addch(out, '\n'); } @@ -1107,7 +1107,7 @@ static void recolor_hunk(struct add_p_state *s, struct hunk *hunk) s->s.file_new_color : s->s.context_color); strbuf_add(&s->colored, plain + current, eol - current); - strbuf_addstr(&s->colored, s->s.reset_color); + strbuf_addstr(&s->colored, s->s.reset_color_diff); if (next > eol) strbuf_add(&s->colored, plain + eol, next - eol); current = next; @@ -1528,8 +1528,8 @@ static int patch_update_file(struct add_p_state *s, : 1)); printf(_(s->mode->prompt_mode[prompt_mode_type]), s->buf.buf); - if (*s->s.reset_color) - fputs(s->s.reset_color, stdout); + if (*s->s.reset_color_interactive) + fputs(s->s.reset_color_interactive, stdout); fflush(stdout); if (read_single_character(s) == EOF) break; @@ -7,7 +7,7 @@ #include "help.h" #include "string-list.h" -static int advice_use_color = -1; +static enum git_colorbool advice_use_color = GIT_COLOR_UNKNOWN; static char advice_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, GIT_COLOR_YELLOW, /* HINT */ @@ -18,7 +18,7 @@ enum advice_type { ADVICE_AM_WORK_DIR, ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME, ADVICE_COMMIT_BEFORE_MERGE, - ADVICE_DEFAULT_BRANCH_NAME, + ADVICE_DEFAULT_BRANCH_NAME, /* To be retired sometime after Git 3.0 */ ADVICE_DETACHED_HEAD, ADVICE_DIVERGING, ADVICE_FETCH_SET_HEAD_WARN, @@ -36,19 +36,25 @@ struct alloc_state { int slab_nr, slab_alloc; }; -struct alloc_state *allocate_alloc_state(void) +struct alloc_state *alloc_state_alloc(void) { return xcalloc(1, sizeof(struct alloc_state)); } -void clear_alloc_state(struct alloc_state *s) +void alloc_state_free_and_null(struct alloc_state **s_) { + struct alloc_state *s = *s_; + + if (!s) + return; + while (s->slab_nr > 0) { s->slab_nr--; free(s->slabs[s->slab_nr]); } FREE_AND_NULL(s->slabs); + FREE_AND_NULL(*s_); } static inline void *alloc_node(struct alloc_state *s, size_t node_size) @@ -14,7 +14,7 @@ void *alloc_commit_node(struct repository *r); void *alloc_tag_node(struct repository *r); void *alloc_object_node(struct repository *r); -struct alloc_state *allocate_alloc_state(void); -void clear_alloc_state(struct alloc_state *s); +struct alloc_state *alloc_state_alloc(void); +void alloc_state_free_and_null(struct alloc_state **s_); #endif @@ -674,9 +674,6 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs, const char *bad_format, const char *good_format, int read_paths) { - struct setup_revision_opt opt = { - .free_removed_argv_elements = 1, - }; int i; repo_init_revisions(r, revs, prefix); @@ -693,7 +690,7 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs, if (read_paths) read_bisect_paths(rev_argv); - setup_revisions(rev_argv->nr, rev_argv->v, revs, &opt); + setup_revisions_from_strvec(rev_argv, revs, NULL); } static void bisect_common(struct rev_info *revs) diff --git a/builtin/add.c b/builtin/add.c index bf312c40be..32709794b3 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -201,7 +201,7 @@ static int edit_patch(struct repository *repo, argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; - rev.diffopt.use_color = 0; + rev.diffopt.use_color = GIT_COLOR_NEVER; rev.diffopt.flags.ignore_dirty_submodules = 1; out = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666); rev.diffopt.file = xfdopen(out, "w"); diff --git a/builtin/am.c b/builtin/am.c index 6073d64ae9..277c2e7937 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -1408,7 +1408,7 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm rev_info.no_commit_id = 1; rev_info.diffopt.flags.binary = 1; rev_info.diffopt.flags.full_index = 1; - rev_info.diffopt.use_color = 0; + rev_info.diffopt.use_color = GIT_COLOR_NEVER; rev_info.diffopt.file = fp; rev_info.diffopt.close_file = 1; add_pending_object(&rev_info, &commit->object, ""); @@ -1441,7 +1441,7 @@ static void write_index_patch(const struct am_state *state) rev_info.disable_stdin = 1; rev_info.no_commit_id = 1; rev_info.diffopt.output_format = DIFF_FORMAT_PATCH; - rev_info.diffopt.use_color = 0; + rev_info.diffopt.use_color = GIT_COLOR_NEVER; rev_info.diffopt.file = fp; rev_info.diffopt.close_file = 1; add_pending_object(&rev_info, &tree->object, ""); diff --git a/builtin/branch.c b/builtin/branch.c index fa5ced452e..9fcf04bebb 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -46,7 +46,7 @@ static struct object_id head_oid; static int recurse_submodules = 0; static int submodule_propagate_branches = 0; -static int branch_use_color = -1; +static enum git_colorbool branch_use_color = GIT_COLOR_UNKNOWN; static char branch_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, GIT_COLOR_NORMAL, /* PLAIN */ diff --git a/builtin/clean.c b/builtin/clean.c index 38b67923a6..1d5e7e5366 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -64,7 +64,7 @@ static const char *color_interactive_slots[] = { [CLEAN_COLOR_RESET] = "reset", }; -static int clean_use_color = -1; +static enum git_colorbool clean_use_color = GIT_COLOR_UNKNOWN; static char clean_colors[][COLOR_MAXLEN] = { [CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED, [CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD, diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c index 6656187f90..fe3ebaadad 100644 --- a/builtin/commit-graph.c +++ b/builtin/commit-graph.c @@ -102,7 +102,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix, if (opts.progress) flags |= COMMIT_GRAPH_WRITE_PROGRESS; - source = odb_find_source(the_repository->objects, opts.obj_dir); + source = odb_find_source_or_die(the_repository->objects, opts.obj_dir); graph_name = get_commit_graph_filename(source); chain_name = get_commit_graph_chain_filename(source); if (open_commit_graph(graph_name, &fd, &st)) @@ -291,7 +291,7 @@ static int graph_write(int argc, const char **argv, const char *prefix, git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0)) flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS; - source = odb_find_source(the_repository->objects, opts.obj_dir); + source = odb_find_source_or_die(the_repository->objects, opts.obj_dir); if (opts.reachable) { if (write_commit_graph_reachable(source, flags, &write_opts)) diff --git a/builtin/commit.c b/builtin/commit.c index 8a5dee384d..0243f17d53 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -695,6 +695,7 @@ static int author_date_is_interesting(void) return author_message || force_date; } +#ifndef WITH_BREAKING_CHANGES static void adjust_comment_line_char(const struct strbuf *sb) { char candidates[] = "#;@!$%^&|:"; @@ -732,6 +733,7 @@ static void adjust_comment_line_char(const struct strbuf *sb) free(comment_line_str_to_free); comment_line_str = comment_line_str_to_free = xstrfmt("%c", *p); } +#endif /* !WITH_BREAKING_CHANGES */ static void prepare_amend_commit(struct commit *commit, struct strbuf *sb, struct pretty_print_context *ctx) @@ -928,15 +930,17 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) die_errno(_("could not write commit template")); +#ifndef WITH_BREAKING_CHANGES if (auto_comment_line_char) adjust_comment_line_char(&sb); +#endif /* !WITH_BREAKING_CHANGES */ strbuf_release(&sb); /* This checks if committer ident is explicitly given */ strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT)); if (use_editor && include_status) { int ident_shown = 0; - int saved_color_setting; + enum git_colorbool saved_color_setting; struct ident_split ci, ai; const char *hint_cleanup_all = allow_empty_message ? _("Please enter the commit message for your changes." @@ -1016,7 +1020,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, status_printf_ln(s, GIT_COLOR_NORMAL, "%s", ""); /* Add new line for clarity */ saved_color_setting = s->use_color; - s->use_color = 0; + s->use_color = GIT_COLOR_NEVER; committable = run_status(s->fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; string_list_clear_func(&s->change, change_data_free); @@ -1793,6 +1797,9 @@ int cmd_commit(int argc, show_usage_with_options_if_asked(argc, argv, builtin_commit_usage, builtin_commit_options); +#ifndef WITH_BREAKING_CHANGES + warn_on_auto_comment_char = true; +#endif /* !WITH_BREAKING_CHANGES */ prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/config.c b/builtin/config.c index 59fb113b07..2348a99dd4 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -568,9 +568,9 @@ static void get_color(const struct config_location_options *opts, } struct get_colorbool_config_data { - int get_colorbool_found; - int get_diff_color_found; - int get_color_ui_found; + enum git_colorbool get_colorbool_found; + enum git_colorbool get_diff_color_found; + enum git_colorbool get_color_ui_found; const char *get_colorbool_slot; }; @@ -594,33 +594,34 @@ static int get_colorbool(const struct config_location_options *opts, { struct get_colorbool_config_data data = { .get_colorbool_slot = var, - .get_colorbool_found = -1, - .get_diff_color_found = -1, - .get_color_ui_found = -1, + .get_colorbool_found = GIT_COLOR_UNKNOWN, + .get_diff_color_found = GIT_COLOR_UNKNOWN, + .get_color_ui_found = GIT_COLOR_UNKNOWN, }; + bool result; config_with_options(git_get_colorbool_config, &data, &opts->source, the_repository, &opts->options); - if (data.get_colorbool_found < 0) { + if (data.get_colorbool_found == GIT_COLOR_UNKNOWN) { if (!strcmp(data.get_colorbool_slot, "color.diff")) data.get_colorbool_found = data.get_diff_color_found; - if (data.get_colorbool_found < 0) + if (data.get_colorbool_found == GIT_COLOR_UNKNOWN) data.get_colorbool_found = data.get_color_ui_found; } - if (data.get_colorbool_found < 0) + if (data.get_colorbool_found == GIT_COLOR_UNKNOWN) /* default value if none found in config */ data.get_colorbool_found = GIT_COLOR_AUTO; - data.get_colorbool_found = want_color(data.get_colorbool_found); + result = want_color(data.get_colorbool_found); if (print) { - printf("%s\n", data.get_colorbool_found ? "true" : "false"); + printf("%s\n", result ? "true" : "false"); return 0; } else - return data.get_colorbool_found ? 0 : 1; + return result ? 0 : 1; } static void check_write(const struct git_config_source *source) diff --git a/builtin/describe.c b/builtin/describe.c index fbe78ace66..ffaf8d9f0a 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -24,6 +24,7 @@ #include "commit-slab.h" #include "wildmatch.h" #include "prio-queue.h" +#include "oidset.h" #define MAX_TAGS (FLAG_BITS - 1) #define DEFAULT_CANDIDATES 10 @@ -286,38 +287,47 @@ static void lazy_queue_clear(struct lazy_queue *queue) queue->get_pending = false; } -static bool all_have_flag(const struct lazy_queue *queue, unsigned flag) +static unsigned long finish_depth_computation(struct lazy_queue *queue, + struct possible_tag *best) { + unsigned long seen_commits = 0; + struct oidset unflagged = OIDSET_INIT; + for (size_t i = queue->get_pending ? 1 : 0; i < queue->queue.nr; i++) { struct commit *commit = queue->queue.array[i].data; - if (!(commit->object.flags & flag)) - return false; + if (!(commit->object.flags & best->flag_within)) + oidset_insert(&unflagged, &commit->object.oid); } - return true; -} -static unsigned long finish_depth_computation(struct lazy_queue *queue, - struct possible_tag *best) -{ - unsigned long seen_commits = 0; while (!lazy_queue_empty(queue)) { struct commit *c = lazy_queue_get(queue); struct commit_list *parents = c->parents; seen_commits++; if (c->object.flags & best->flag_within) { - if (all_have_flag(queue, best->flag_within)) + if (!oidset_size(&unflagged)) break; - } else + } else { + oidset_remove(&unflagged, &c->object.oid); best->depth++; + } while (parents) { + unsigned seen, flag_before, flag_after; struct commit *p = parents->item; repo_parse_commit(the_repository, p); - if (!(p->object.flags & SEEN)) + seen = p->object.flags & SEEN; + if (!seen) lazy_queue_put(queue, p); + flag_before = p->object.flags & best->flag_within; p->object.flags |= c->object.flags; + flag_after = p->object.flags & best->flag_within; + if (!seen && !flag_after) + oidset_insert(&unflagged, &p->object.oid); + if (seen && !flag_before && flag_after) + oidset_remove(&unflagged, &p->object.oid); parents = parents->next; } } + oidset_clear(&unflagged); return seen_commits; } @@ -570,7 +580,8 @@ static void describe_blob(const struct object_id *oid, struct strbuf *dst) NULL); repo_init_revisions(the_repository, &revs, NULL); - if (setup_revisions(args.nr, args.v, &revs, NULL) > 1) + setup_revisions_from_strvec(&args, &revs, NULL); + if (args.nr > 1) BUG("setup_revisions could not handle all args?"); if (prepare_revision_walk(&revs)) diff --git a/builtin/fetch.c b/builtin/fetch.c index 24645c4653..c7ff3480fb 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1643,7 +1643,8 @@ cleanup: struct ref_rejection_data { int *retcode; - int conflict_msg_shown; + bool conflict_msg_shown; + bool case_sensitive_msg_shown; const char *remote_name; }; @@ -1657,11 +1658,25 @@ static void ref_transaction_rejection_handler(const char *refname, { struct ref_rejection_data *data = cb_data; - if (err == REF_TRANSACTION_ERROR_NAME_CONFLICT && !data->conflict_msg_shown) { + if (err == REF_TRANSACTION_ERROR_CASE_CONFLICT && ignore_case && + !data->case_sensitive_msg_shown) { + error(_("You're on a case-insensitive filesystem, and the remote you are\n" + "trying to fetch from has references that only differ in casing. It\n" + "is impossible to store such references with the 'files' backend. You\n" + "can either accept this as-is, in which case you won't be able to\n" + "store all remote references on disk. Or you can alternatively\n" + "migrate your repository to use the 'reftable' backend with the\n" + "following command:\n\n git refs migrate --ref-format=reftable\n\n" + "Please keep in mind that not all implementations of Git support this\n" + "new format yet. So if you use tools other than Git to access this\n" + "repository it may not be an option to migrate to reftables.\n")); + data->case_sensitive_msg_shown = true; + } else if (err == REF_TRANSACTION_ERROR_NAME_CONFLICT && + !data->conflict_msg_shown) { error(_("some local refs could not be updated; try running\n" " 'git remote prune %s' to remove any old, conflicting " "branches"), data->remote_name); - data->conflict_msg_shown = 1; + data->conflict_msg_shown = true; } else { const char *reason = ref_transaction_error_msg(err); diff --git a/builtin/grep.c b/builtin/grep.c index 5df6537333..1d97eb2a2a 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1091,7 +1091,7 @@ int cmd_grep(int argc, if (show_in_pager == default_pager) show_in_pager = git_pager(the_repository, 1); if (show_in_pager) { - opt.color = 0; + opt.color = GIT_COLOR_NEVER; opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; diff --git a/builtin/last-modified.c b/builtin/last-modified.c index 886ba12cb5..ae8b36a2c3 100644 --- a/builtin/last-modified.c +++ b/builtin/last-modified.c @@ -265,6 +265,7 @@ static int last_modified_init(struct last_modified *lm, struct repository *r, lm->rev.boundary = 1; lm->rev.no_commit_id = 1; lm->rev.diff = 1; + lm->rev.diffopt.flags.no_recursive_diff_tree_combined = 1; lm->rev.diffopt.flags.recursive = lm->recursive; lm->rev.diffopt.flags.tree_in_recursive = lm->show_trees; diff --git a/builtin/log.c b/builtin/log.c index c2f8bbf863..5f552d14c0 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1404,6 +1404,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file, struct range_diff_options range_diff_opts = { .creation_factor = rev->creation_factor, .dual_color = 1, + .max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT, .diffopt = &opts, .other_arg = &other_arg }; diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 5d55731ca3..ec6940fc7c 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -373,7 +373,6 @@ int cmd_ls_tree(int argc, OPT_END() }; struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format; - struct object_context obj_context = {0}; int ret; repo_config(the_repository, git_default_config, NULL); @@ -405,9 +404,8 @@ int cmd_ls_tree(int argc, ls_tree_usage, ls_tree_options); if (argc < 1) usage_with_options(ls_tree_usage, ls_tree_options); - if (get_oid_with_context(the_repository, argv[0], - GET_OID_HASH_ANY, &oid, - &obj_context)) + if (repo_get_oid_with_flags(the_repository, argv[0], &oid, + GET_OID_HASH_ANY)) die("Not a valid object name %s", argv[0]); /* @@ -447,6 +445,5 @@ int cmd_ls_tree(int argc, ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options); clear_pathspec(&options.pathspec); - object_context_release(&obj_context); return ret; } diff --git a/builtin/merge.c b/builtin/merge.c index b235af730a..c421a11b0b 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -1379,6 +1379,9 @@ int cmd_merge(int argc, show_usage_with_options_if_asked(argc, argv, builtin_merge_usage, builtin_merge_options); +#ifndef WITH_BREAKING_CHANGES + warn_on_auto_comment_char = true; +#endif /* !WITH_BREAKING_CHANGES */ prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c index d3b9e98be3..5f364aa816 100644 --- a/builtin/multi-pack-index.c +++ b/builtin/multi-pack-index.c @@ -65,12 +65,20 @@ static int parse_object_dir(const struct option *opt, const char *arg, char **value = opt->value; free(*value); if (unset) - *value = xstrdup(repo_get_object_directory(the_repository)); + *value = xstrdup(the_repository->objects->sources->path); else *value = real_pathdup(arg, 1); return 0; } +static struct odb_source *handle_object_dir_option(struct repository *repo) +{ + struct odb_source *source = odb_find_source(repo->objects, opts.object_dir); + if (!source) + source = odb_add_to_alternates_memory(repo->objects, opts.object_dir); + return source; +} + static struct option common_opts[] = { OPT_CALLBACK(0, "object-dir", &opts.object_dir, N_("directory"), @@ -140,6 +148,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, N_("refs snapshot for selecting bitmap commits")), OPT_END(), }; + struct odb_source *source; int ret; opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE; @@ -158,6 +167,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, if (argc) usage_with_options(builtin_multi_pack_index_write_usage, options); + source = handle_object_dir_option(repo); FREE_AND_NULL(options); @@ -166,7 +176,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, read_packs_from_stdin(&packs); - ret = write_midx_file_only(repo, opts.object_dir, &packs, + ret = write_midx_file_only(source, &packs, opts.preferred_pack, opts.refs_snapshot, opts.flags); @@ -177,7 +187,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, } - ret = write_midx_file(repo, opts.object_dir, opts.preferred_pack, + ret = write_midx_file(source, opts.preferred_pack, opts.refs_snapshot, opts.flags); free(opts.refs_snapshot); @@ -194,6 +204,8 @@ static int cmd_multi_pack_index_verify(int argc, const char **argv, N_("force progress reporting"), MIDX_PROGRESS), OPT_END(), }; + struct odb_source *source; + options = add_common_options(builtin_multi_pack_index_verify_options); trace2_cmd_mode(argv[0]); @@ -206,10 +218,11 @@ static int cmd_multi_pack_index_verify(int argc, const char **argv, if (argc) usage_with_options(builtin_multi_pack_index_verify_usage, options); + source = handle_object_dir_option(the_repository); FREE_AND_NULL(options); - return verify_midx_file(the_repository, opts.object_dir, opts.flags); + return verify_midx_file(source, opts.flags); } static int cmd_multi_pack_index_expire(int argc, const char **argv, @@ -222,6 +235,8 @@ static int cmd_multi_pack_index_expire(int argc, const char **argv, N_("force progress reporting"), MIDX_PROGRESS), OPT_END(), }; + struct odb_source *source; + options = add_common_options(builtin_multi_pack_index_expire_options); trace2_cmd_mode(argv[0]); @@ -234,10 +249,11 @@ static int cmd_multi_pack_index_expire(int argc, const char **argv, if (argc) usage_with_options(builtin_multi_pack_index_expire_usage, options); + source = handle_object_dir_option(the_repository); FREE_AND_NULL(options); - return expire_midx_packs(the_repository, opts.object_dir, opts.flags); + return expire_midx_packs(source, opts.flags); } static int cmd_multi_pack_index_repack(int argc, const char **argv, @@ -252,6 +268,7 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv, N_("force progress reporting"), MIDX_PROGRESS), OPT_END(), }; + struct odb_source *source; options = add_common_options(builtin_multi_pack_index_repack_options); @@ -266,11 +283,11 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv, if (argc) usage_with_options(builtin_multi_pack_index_repack_usage, options); + source = handle_object_dir_option(the_repository); FREE_AND_NULL(options); - return midx_repack(the_repository, opts.object_dir, - (size_t)opts.batch_size, opts.flags); + return midx_repack(source, (size_t)opts.batch_size, opts.flags); } int cmd_multi_pack_index(int argc, diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 53a2256250..5856b5f6bf 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1741,7 +1741,7 @@ static int want_object_in_pack_mtime(const struct object_id *oid, struct multi_pack_index *m = get_multi_pack_index(source); struct pack_entry e; - if (m && fill_midx_entry(the_repository, oid, &e, m)) { + if (m && fill_midx_entry(m, oid, &e)) { want = want_object_in_pack_one(e.p, oid, exclude, found_pack, found_offset, found_mtime); if (want != -1) return want; @@ -4650,7 +4650,7 @@ static void get_object_list_path_walk(struct rev_info *revs) die(_("failed to pack objects via path-walk")); } -static void get_object_list(struct rev_info *revs, int ac, const char **av) +static void get_object_list(struct rev_info *revs, struct strvec *argv) { struct setup_revision_opt s_r_opt = { .allow_exclude_promisor_objects = 1, @@ -4660,7 +4660,7 @@ static void get_object_list(struct rev_info *revs, int ac, const char **av) int save_warning; save_commit_buffer = 0; - setup_revisions(ac, av, revs, &s_r_opt); + setup_revisions_from_strvec(argv, revs, &s_r_opt); /* make sure shallows are read */ is_repository_shallow(the_repository); @@ -5229,7 +5229,7 @@ int cmd_pack_objects(int argc, revs.include_check = is_not_in_promisor_pack; revs.include_check_obj = is_not_in_promisor_pack_obj; } - get_object_list(&revs, rp.nr, rp.v); + get_object_list(&revs, &rp); release_revisions(&revs); } cleanup_preferred_base(); diff --git a/builtin/push.c b/builtin/push.c index d0794b7b30..5b6cebbb85 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -27,7 +27,7 @@ static const char * const push_usage[] = { NULL, }; -static int push_use_color = -1; +static enum git_colorbool push_use_color = GIT_COLOR_UNKNOWN; static char push_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, GIT_COLOR_RED, /* ERROR */ diff --git a/builtin/range-diff.c b/builtin/range-diff.c index a563abff5f..1bc082a869 100644 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@ -6,6 +6,8 @@ #include "parse-options.h" #include "range-diff.h" #include "config.h" +#include "parse.h" +#include "color.h" static const char * const builtin_range_diff_usage[] = { @@ -15,6 +17,21 @@ N_("git range-diff [<options>] <base> <old-tip> <new-tip>"), NULL }; +static int parse_max_memory(const struct option *opt, const char *arg, int unset) +{ + size_t *max_memory = opt->value; + uintmax_t val; + + if (unset) + return 0; + + if (!git_parse_unsigned(arg, &val, SIZE_MAX)) + return error(_("invalid max-memory value: %s"), arg); + + *max_memory = (size_t)val; + return 0; +} + int cmd_range_diff(int argc, const char **argv, const char *prefix, @@ -25,6 +42,7 @@ int cmd_range_diff(int argc, struct strvec diff_merges_arg = STRVEC_INIT; struct range_diff_options range_diff_opts = { .creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT, + .max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT, .diffopt = &diffopt, .other_arg = &other_arg }; @@ -40,6 +58,10 @@ int cmd_range_diff(int argc, PARSE_OPT_OPTARG), OPT_PASSTHRU_ARGV(0, "diff-merges", &diff_merges_arg, N_("style"), N_("passed to 'git log'"), 0), + OPT_CALLBACK(0, "max-memory", &range_diff_opts.max_memory, + N_("size"), + N_("maximum memory for cost matrix (default 4G)"), + parse_max_memory), OPT_PASSTHRU_ARGV(0, "remerge-diff", &diff_merges_arg, NULL, N_("passed to 'git log'"), PARSE_OPT_NOARG), OPT_BOOL(0, "left-only", &left_only, @@ -66,7 +88,7 @@ int cmd_range_diff(int argc, /* force color when --dual-color was used */ if (!simple_color) - diffopt.use_color = 1; + diffopt.use_color = GIT_COLOR_ALWAYS; /* If `--diff-merges` was specified, imply `--merges` */ if (diff_merges_arg.nr) { diff --git a/builtin/rebase.c b/builtin/rebase.c index 3c85768d29..c468828189 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -299,8 +299,7 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) oid_to_hex(&opts->restrict_revision->object.oid)); ret = sequencer_make_script(the_repository, &todo_list.buf, - make_script_args.nr, make_script_args.v, - flags); + &make_script_args, flags); if (ret) { error(_("could not generate todo list")); goto cleanup; @@ -1242,6 +1241,9 @@ int cmd_rebase(int argc, builtin_rebase_usage, builtin_rebase_options); +#ifndef WITH_BREAKING_CHANGES + warn_on_auto_comment_char = true; +#endif /* !WITH_BREAKING_CHANGES */ prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/refs.c b/builtin/refs.c index 76224feba4..91548783b7 100644 --- a/builtin/refs.c +++ b/builtin/refs.c @@ -7,6 +7,7 @@ #include "strbuf.h" #include "worktree.h" #include "for-each-ref.h" +#include "refs/refs-internal.h" #define REFS_MIGRATE_USAGE \ N_("git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]") @@ -14,6 +15,9 @@ #define REFS_VERIFY_USAGE \ N_("git refs verify [--strict] [--verbose]") +#define REFS_EXISTS_USAGE \ + N_("git refs exists <ref>") + static int cmd_refs_migrate(int argc, const char **argv, const char *prefix, struct repository *repo UNUSED) { @@ -113,6 +117,48 @@ static int cmd_refs_list(int argc, const char **argv, const char *prefix, return for_each_ref_core(argc, argv, prefix, repo, refs_list_usage); } +static int cmd_refs_exists(int argc, const char **argv, const char *prefix, + struct repository *repo UNUSED) +{ + struct strbuf unused_referent = STRBUF_INIT; + struct object_id unused_oid; + unsigned int unused_type; + int failure_errno = 0; + const char *ref; + int ret = 0; + const char * const exists_usage[] = { + REFS_EXISTS_USAGE, + NULL, + }; + struct option options[] = { + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, options, exists_usage, 0); + if (argc != 1) + die(_("'git refs exists' requires a reference")); + + ref = *argv++; + if (refs_read_raw_ref(get_main_ref_store(the_repository), ref, + &unused_oid, &unused_referent, &unused_type, + &failure_errno)) { + if (failure_errno == ENOENT || failure_errno == EISDIR) { + error(_("reference does not exist")); + ret = 2; + } else { + errno = failure_errno; + error_errno(_("failed to look up reference")); + ret = 1; + } + + goto out; + } + +out: + strbuf_release(&unused_referent); + return ret; +} + int cmd_refs(int argc, const char **argv, const char *prefix, @@ -122,6 +168,7 @@ int cmd_refs(int argc, REFS_MIGRATE_USAGE, REFS_VERIFY_USAGE, "git refs list " COMMON_USAGE_FOR_EACH_REF, + REFS_EXISTS_USAGE, NULL, }; parse_opt_subcommand_fn *fn = NULL; @@ -129,6 +176,7 @@ int cmd_refs(int argc, OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate), OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify), OPT_SUBCOMMAND("list", &fn, cmd_refs_list), + OPT_SUBCOMMAND("exists", &fn, cmd_refs_exists), OPT_END(), }; diff --git a/builtin/repack.c b/builtin/repack.c index a4def39197..c490a51e91 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -223,9 +223,10 @@ static void mark_packs_for_deletion(struct existing_packs *existing, static void remove_redundant_pack(const char *dir_name, const char *base_name) { struct strbuf buf = STRBUF_INIT; - struct multi_pack_index *m = get_multi_pack_index(the_repository->objects->sources); + struct odb_source *source = the_repository->objects->sources; + struct multi_pack_index *m = get_multi_pack_index(source); strbuf_addf(&buf, "%s.pack", base_name); - if (m && m->local && midx_contains_pack(m, buf.buf)) + if (m && source->local && midx_contains_pack(m, buf.buf)) clear_midx_file(the_repository); strbuf_insertf(&buf, 0, "%s/", dir_name); unlink_pack_path(buf.buf, 1); @@ -1711,7 +1712,7 @@ int cmd_repack(int argc, unsigned flags = 0; if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0)) flags |= MIDX_WRITE_INCREMENTAL; - write_midx_file(the_repository, repo_get_object_directory(the_repository), + write_midx_file(the_repository->objects->sources, NULL, NULL, flags); } diff --git a/builtin/repo.c b/builtin/repo.c index 8c6e7f42ab..bbb0966f2d 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -9,7 +9,7 @@ #include "shallow.h" static const char *const repo_usage[] = { - "git repo info [--format=(keyvalue|nul)] [<key>...]", + "git repo info [--format=(keyvalue|nul)] [-z] [<key>...]", NULL }; @@ -38,6 +38,12 @@ static int get_layout_shallow(struct repository *repo, struct strbuf *buf) return 0; } +static int get_object_format(struct repository *repo, struct strbuf *buf) +{ + strbuf_addstr(buf, repo->hash_algo->name); + return 0; +} + static int get_references_format(struct repository *repo, struct strbuf *buf) { strbuf_addstr(buf, @@ -49,6 +55,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf) static const struct field repo_info_fields[] = { { "layout.bare", get_layout_bare }, { "layout.shallow", get_layout_shallow }, + { "object.format", get_object_format }, { "references.format", get_references_format }, }; @@ -112,26 +119,40 @@ static int print_fields(int argc, const char **argv, return ret; } +static int parse_format_cb(const struct option *opt, + const char *arg, int unset UNUSED) +{ + enum output_format *format = opt->value; + + if (opt->short_name == 'z') + *format = FORMAT_NUL_TERMINATED; + else if (!strcmp(arg, "nul")) + *format = FORMAT_NUL_TERMINATED; + else if (!strcmp(arg, "keyvalue")) + *format = FORMAT_KEYVALUE; + else + die(_("invalid format '%s'"), arg); + + return 0; +} + static int repo_info(int argc, const char **argv, const char *prefix, struct repository *repo) { - const char *format_str = "keyvalue"; - enum output_format format; + enum output_format format = FORMAT_KEYVALUE; struct option options[] = { - OPT_STRING(0, "format", &format_str, N_("format"), - N_("output format")), + OPT_CALLBACK_F(0, "format", &format, N_("format"), + N_("output format"), + PARSE_OPT_NONEG, parse_format_cb), + OPT_CALLBACK_F('z', NULL, &format, NULL, + N_("synonym for --format=nul"), + PARSE_OPT_NONEG | PARSE_OPT_NOARG, + parse_format_cb), OPT_END() }; argc = parse_options(argc, argv, prefix, options, repo_usage, 0); - if (!strcmp(format_str, "keyvalue")) - format = FORMAT_KEYVALUE; - else if (!strcmp(format_str, "nul")) - format = FORMAT_NUL_TERMINATED; - else - die(_("invalid format '%s'"), format_str); - return print_fields(argc, argv, repo, format); } diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 44ff1b8342..9da92b990d 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -708,7 +708,6 @@ int cmd_rev_parse(int argc, struct object_id oid; unsigned int flags = 0; const char *name = NULL; - struct object_context unused; struct strbuf buf = STRBUF_INIT; int seen_end_of_options = 0; enum format_type format = FORMAT_DEFAULT; @@ -1141,9 +1140,8 @@ int cmd_rev_parse(int argc, name++; type = REVERSED; } - if (!get_oid_with_context(the_repository, name, - flags, &oid, &unused)) { - object_context_release(&unused); + if (!repo_get_oid_with_flags(the_repository, name, &oid, + flags)) { if (output_algo) repo_oid_to_algop(the_repository, &oid, output_algo, &oid); @@ -1153,7 +1151,6 @@ int cmd_rev_parse(int argc, show_rev(type, &oid, name); continue; } - object_context_release(&unused); if (verify) die_no_single_rev(quiet); if (has_dashdash) diff --git a/builtin/revert.c b/builtin/revert.c index c3f92b585d..bedc40f368 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -4,6 +4,7 @@ #include "builtin.h" #include "parse-options.h" #include "diff.h" +#include "environment.h" #include "gettext.h" #include "revision.h" #include "rerere.h" @@ -285,6 +286,9 @@ int cmd_revert(int argc, struct replay_opts opts = REPLAY_OPTS_INIT; int res; +#ifndef WITH_BREAKING_CHANGES + warn_on_auto_comment_char = true; +#endif /* !WITH_BREAKING_CHANGES */ opts.action = REPLAY_REVERT; sequencer_init_config(&opts); res = run_sequencer(argc, argv, prefix, &opts); @@ -302,6 +306,9 @@ struct repository *repo UNUSED) struct replay_opts opts = REPLAY_OPTS_INIT; int res; +#ifndef WITH_BREAKING_CHANGES + warn_on_auto_comment_char = true; +#endif /* !WITH_BREAKING_CHANGES */ opts.action = REPLAY_PICK; sequencer_init_config(&opts); res = run_sequencer(argc, argv, prefix, &opts); diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 1ab7db9d2c..441babf2e3 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -29,7 +29,7 @@ static const char*const show_branch_usage[] = { NULL }; -static int showbranch_use_color = -1; +static enum git_colorbool showbranch_use_color = GIT_COLOR_UNKNOWN; static struct strvec default_args = STRVEC_INIT; diff --git a/builtin/stash.c b/builtin/stash.c index f5ddee5c7f..948eba06fb 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -146,6 +146,11 @@ static const char * const git_stash_import_usage[] = { static const char ref_stash[] = "refs/stash"; static struct strbuf stash_index_path = STRBUF_INIT; +static int show_stat = 1; +static int show_patch; +static int show_include_untracked; +static int use_index; + /* * w_commit is set to the commit containing the working tree * b_commit is set to the base commit @@ -377,7 +382,7 @@ static int diff_tree_binary(struct strbuf *out, struct object_id *w_commit) * however it should be done together with apply_cached. */ cp.git_cmd = 1; - strvec_pushl(&cp.args, "diff-tree", "--binary", NULL); + strvec_pushl(&cp.args, "diff-tree", "--binary", "--no-color", NULL); strvec_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex); return pipe_command(&cp, NULL, 0, out, 0, NULL, 0); @@ -717,7 +722,7 @@ static int apply_stash(int argc, const char **argv, const char *prefix, { int ret = -1; int quiet = 0; - int index = 0; + int index = use_index; struct stash_info info = STASH_INFO_INIT; struct option options[] = { OPT__QUIET(&quiet, N_("be quiet, only report errors")), @@ -815,7 +820,7 @@ static int pop_stash(int argc, const char **argv, const char *prefix, struct repository *repo UNUSED) { int ret = -1; - int index = 0; + int index = use_index; int quiet = 0; struct stash_info info = STASH_INFO_INIT; struct option options[] = { @@ -905,10 +910,6 @@ static int list_stash(int argc, const char **argv, const char *prefix, return run_command(&cp); } -static int show_stat = 1; -static int show_patch; -static int show_include_untracked; - static int git_stash_config(const char *var, const char *value, const struct config_context *ctx, void *cb) { @@ -924,6 +925,10 @@ static int git_stash_config(const char *var, const char *value, show_include_untracked = git_config_bool(var, value); return 0; } + if (!strcmp(var, "stash.index")) { + use_index = git_config_bool(var, value); + return 0; + } return git_diff_basic_config(var, value, ctx, cb); } @@ -1015,8 +1020,8 @@ static int show_stash(int argc, const char **argv, const char *prefix, } } - argc = setup_revisions(revision_args.nr, revision_args.v, &rev, NULL); - if (argc > 1) + setup_revisions_from_strvec(&revision_args, &rev, NULL); + if (revision_args.nr > 1) goto usage; if (!rev.diffopt.output_format) { rev.diffopt.output_format = DIFF_FORMAT_PATCH; @@ -1089,7 +1094,6 @@ static int store_stash(int argc, const char **argv, const char *prefix, int quiet = 0; const char *stash_msg = NULL; struct object_id obj; - struct object_context dummy = {0}; struct option options[] = { OPT__QUIET(&quiet, N_("be quiet")), OPT_STRING('m', "message", &stash_msg, "message", @@ -1109,9 +1113,8 @@ static int store_stash(int argc, const char **argv, const char *prefix, return -1; } - if (get_oid_with_context(the_repository, - argv[0], quiet ? GET_OID_QUIETLY : 0, &obj, - &dummy)) { + if (repo_get_oid_with_flags(the_repository, argv[0], &obj, + quiet ? GET_OID_QUIETLY : 0)) { if (!quiet) fprintf_ln(stderr, _("Cannot update %s with %s"), ref_stash, argv[0]); @@ -1122,7 +1125,6 @@ static int store_stash(int argc, const char **argv, const char *prefix, ret = do_store_stash(&obj, stash_msg, quiet); out: - object_context_release(&dummy); return ret; } @@ -1284,6 +1286,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch, cp_diff_tree.git_cmd = 1; strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "--binary", + "--no-color", "-U1", "HEAD", oid_to_hex(&info->w_tree), "--", NULL); if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) { ret = -1; @@ -1346,6 +1349,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps, cp_diff_tree.git_cmd = 1; strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "-U1", "HEAD", + "--no-color", oid_to_hex(&info->w_tree), "--", NULL); if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) { ret = -1; @@ -1720,6 +1724,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q cp_diff.git_cmd = 1; strvec_pushl(&cp_diff.args, "diff-index", "-p", + "--no-color", "--cached", "--binary", "HEAD", "--", NULL); add_pathspecs(&cp_diff.args, ps); @@ -2235,7 +2240,6 @@ static int do_export_stash(struct repository *r, const char **argv) { struct object_id base; - struct object_context unused; struct commit *prev; struct commit_list *items = NULL, **iter = &items, *cur; int res = 0; @@ -2269,9 +2273,9 @@ static int do_export_stash(struct repository *r, struct commit *stash; if (parse_stash_revision(&revision, argv[i], 1) || - get_oid_with_context(r, revision.buf, - GET_OID_QUIETLY | GET_OID_GENTLY, - &oid, &unused)) { + repo_get_oid_with_flags(r, revision.buf, &oid, + GET_OID_QUIETLY | + GET_OID_GENTLY)) { res = error(_("unable to find stash entry %s"), argv[i]); goto out; } diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 07a1935cbe..fcd73abe53 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -616,9 +616,6 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, struct rev_info rev = REV_INFO_INIT; struct strbuf buf = STRBUF_INIT; const char *git_dir; - struct setup_revision_opt opt = { - .free_removed_argv_elements = 1, - }; if (validate_submodule_path(path) < 0) die(NULL); @@ -655,7 +652,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, repo_init_revisions(the_repository, &rev, NULL); rev.abbrev = 0; - setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt); + setup_revisions_from_strvec(&diff_files_args, &rev, NULL); run_diff_files(&rev, 0); if (!diff_result_code(&rev)) { @@ -1094,9 +1091,6 @@ static int compute_summary_module_list(struct object_id *head_oid, { struct strvec diff_args = STRVEC_INIT; struct rev_info rev; - struct setup_revision_opt opt = { - .free_removed_argv_elements = 1, - }; struct module_cb_list list = MODULE_CB_LIST_INIT; int ret = 0; @@ -1114,7 +1108,7 @@ static int compute_summary_module_list(struct object_id *head_oid, repo_init_revisions(the_repository, &rev, info->prefix); rev.abbrev = 0; precompose_argv_prefix(diff_args.nr, diff_args.v, NULL); - setup_revisions(diff_args.nr, diff_args.v, &rev, &opt); + setup_revisions_from_strvec(&diff_args, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = submodule_summary_callback; rev.diffopt.format_callback_data = &list; diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh index 01823fd0f1..a21834043f 100755 --- a/ci/run-build-and-tests.sh +++ b/ci/run-build-and-tests.sh @@ -9,7 +9,6 @@ run_tests=t case "$jobname" in linux-breaking-changes) - export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export WITH_BREAKING_CHANGES=YesPlease ;; linux-TEST-vars) @@ -9,7 +9,7 @@ #include "pager.h" #include "strbuf.h" -static int git_use_color_default = GIT_COLOR_AUTO; +static enum git_colorbool git_use_color_default = GIT_COLOR_AUTO; int color_stdout_is_tty = -1; /* @@ -369,29 +369,29 @@ bad: #undef OUT } -int git_config_colorbool(const char *var, const char *value) +enum git_colorbool git_config_colorbool(const char *var, const char *value) { if (value) { if (!strcasecmp(value, "never")) - return 0; + return GIT_COLOR_NEVER; if (!strcasecmp(value, "always")) - return 1; + return GIT_COLOR_ALWAYS; if (!strcasecmp(value, "auto")) return GIT_COLOR_AUTO; } if (!var) - return -1; + return GIT_COLOR_UNKNOWN; /* Missing or explicit false to turn off colorization */ if (!git_config_bool(var, value)) - return 0; + return GIT_COLOR_NEVER; /* any normal truth value defaults to 'auto' */ return GIT_COLOR_AUTO; } -static int check_auto_color(int fd) +static bool check_auto_color(int fd) { static int color_stderr_is_tty = -1; int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty; @@ -399,12 +399,12 @@ static int check_auto_color(int fd) *is_tty_p = isatty(fd); if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) { if (!is_terminal_dumb()) - return 1; + return true; } - return 0; + return false; } -int want_color_fd(int fd, int var) +bool want_color_fd(int fd, enum git_colorbool var) { /* * NEEDSWORK: This function is sometimes used from multiple threads, and @@ -418,7 +418,7 @@ int want_color_fd(int fd, int var) if (fd < 1 || fd >= ARRAY_SIZE(want_auto)) BUG("file descriptor out of range: %d", fd); - if (var < 0) + if (var == GIT_COLOR_UNKNOWN) var = git_use_color_default; if (var == GIT_COLOR_AUTO) { @@ -426,7 +426,7 @@ int want_color_fd(int fd, int var) want_auto[fd] = check_auto_color(fd); return want_auto[fd]; } - return var; + return var == GIT_COLOR_ALWAYS; } int git_color_config(const char *var, const char *value, void *cb UNUSED) @@ -73,10 +73,12 @@ struct strbuf; * returned from git_config_colorbool. The "auto" value can be returned from * config_colorbool, and will be converted by want_color() into either 0 or 1. */ -#define GIT_COLOR_UNKNOWN -1 -#define GIT_COLOR_NEVER 0 -#define GIT_COLOR_ALWAYS 1 -#define GIT_COLOR_AUTO 2 +enum git_colorbool { + GIT_COLOR_UNKNOWN = -1, + GIT_COLOR_NEVER = 0, + GIT_COLOR_ALWAYS = 1, + GIT_COLOR_AUTO = 2, +}; /* A default list of colors to use for commit graphs and show-branch output */ extern const char *column_colors_ansi[]; @@ -98,13 +100,13 @@ int git_color_config(const char *var, const char *value, void *cb); * GIT_COLOR_ALWAYS for "always" or a positive boolean, * and GIT_COLOR_AUTO for "auto". */ -int git_config_colorbool(const char *var, const char *value); +enum git_colorbool git_config_colorbool(const char *var, const char *value); /* * Return a boolean whether to use color, where the argument 'var' is * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO. */ -int want_color_fd(int fd, int var); +bool want_color_fd(int fd, enum git_colorbool var); #define want_color(colorbool) want_color_fd(1, (colorbool)) #define want_color_stderr(colorbool) want_color_fd(2, (colorbool)) diff --git a/combine-diff.c b/combine-diff.c index 3878faabe7..b799862068 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -749,7 +749,7 @@ static void show_line_to_eol(const char *line, int len, const char *reset) static void dump_sline(struct sline *sline, const char *line_prefix, unsigned long cnt, int num_parent, - int use_color, int result_deleted) + enum git_colorbool use_color, int result_deleted) { unsigned long mark = (1UL<<num_parent); unsigned long no_pre_delete = (2UL<<num_parent); @@ -1515,8 +1515,9 @@ void diff_tree_combined(const struct object_id *oid, diffopts = *opt; copy_pathspec(&diffopts.pathspec, &opt->pathspec); - diffopts.flags.recursive = 1; diffopts.flags.allow_external = 0; + if (!opt->flags.no_recursive_diff_tree_combined) + diffopts.flags.recursive = 1; /* find set of paths that everybody touches * @@ -8,9 +8,11 @@ #include "git-compat-util.h" #include "abspath.h" +#include "advice.h" #include "date.h" #include "branch.h" #include "config.h" +#include "dir.h" #include "parse.h" #include "convert.h" #include "environment.h" @@ -1948,10 +1950,290 @@ int git_configset_get_pathname(struct config_set *set, const char *key, char **d return 1; } +struct comment_char_config { + unsigned last_key_id; + bool auto_set; + bool auto_set_in_file; + struct strintmap key_flags; + size_t alloc, nr; + struct comment_char_config_item { + unsigned key_id; + char *path; + enum config_scope scope; + } *item; +}; + +#define COMMENT_CHAR_CFG_INIT { \ + .key_flags = STRINTMAP_INIT, \ + } + +static void comment_char_config_release(struct comment_char_config *config) +{ + strintmap_clear(&config->key_flags); + for (size_t i = 0; i < config->nr; i++) + free(config->item[i].path); + free(config->item); +} + +/* Used to track whether the key occurs more than once in a given file */ +#define KEY_SEEN_ONCE 1u +#define KEY_SEEN_TWICE 2u +#define COMMENT_KEY_SHIFT(id) (2 * (id)) +#define COMMENT_KEY_MASK(id) (3u << COMMENT_KEY_SHIFT(id)) + +static void set_comment_key_flags(struct comment_char_config *config, + const char *path, unsigned id, unsigned value) +{ + unsigned old = strintmap_get(&config->key_flags, path); + unsigned new = (old & ~COMMENT_KEY_MASK(id)) | + value << COMMENT_KEY_SHIFT(id); + + strintmap_set(&config->key_flags, path, new); +} + +static unsigned get_comment_key_flags(struct comment_char_config *config, + const char *path, unsigned id) +{ + unsigned value = strintmap_get(&config->key_flags, path); + + return (value & COMMENT_KEY_MASK(id)) >> COMMENT_KEY_SHIFT(id); +} + +static const char *comment_key_name(unsigned id) +{ + static const char *name[] = { + "core.commentChar", + "core.commentString", + }; + + if (id >= ARRAY_SIZE(name)) + BUG("invalid comment key id"); + + return name[id]; +} + +static void comment_char_callback(const char *key, const char *value, + const struct config_context *ctx, void *data) +{ + struct comment_char_config *config = data; + const struct key_value_info *kvi = ctx->kvi; + unsigned key_id; + + if (!strcmp(key, "core.commentchar")) + key_id = 0; + else if (!strcmp(key, "core.commentstring")) + key_id = 1; + else + return; + + config->last_key_id = key_id; + config->auto_set = value && !strcmp(value, "auto"); + if (kvi->origin_type != CONFIG_ORIGIN_FILE) { + return; + } else if (get_comment_key_flags(config, kvi->filename, key_id)) { + set_comment_key_flags(config, kvi->filename, key_id, + KEY_SEEN_TWICE); + } else { + struct comment_char_config_item *item; + + ALLOC_GROW_BY(config->item, config->nr, 1, config->alloc); + item = &config->item[config->nr - 1]; + item->key_id = key_id; + item->scope = kvi->scope; + item->path = xstrdup(kvi->filename); + set_comment_key_flags(config, kvi->filename, key_id, + KEY_SEEN_ONCE); + } + config->auto_set_in_file = config->auto_set; +} + +static void add_config_scope_arg(struct repository *repo, struct strbuf *buf, + struct comment_char_config_item *item) +{ + char *global_config = git_global_config(); + char *system_config = git_system_config(); + + if (item->scope == CONFIG_SCOPE_SYSTEM && access(item->path, W_OK)) { + /* + * If the user cannot write to the system config recommend + * setting the global config instead. + */ + strbuf_addstr(buf, "--global "); + } else if (fspatheq(item->path, system_config)) { + strbuf_addstr(buf, "--system "); + } else if (fspatheq(item->path, global_config)) { + strbuf_addstr(buf, "--global "); + } else if (fspatheq(item->path, + mkpath("%s/config", + repo_get_git_dir(repo)))) { + ; /* --local is the default */ + } else if (fspatheq(item->path, + mkpath("%s/config.worktree", + repo_get_common_dir(repo)))) { + strbuf_addstr(buf, "--worktree "); + } else { + const char *path = item->path; + const char *home = getenv("HOME"); + + strbuf_addstr(buf, "--file "); + if (home && !fspathncmp(path, home, strlen(home))) { + path += strlen(home); + if (!fspathncmp(path, "/", 1)) + path++; + strbuf_addstr(buf, "~/"); + } + sq_quote_buf_pretty(buf, path); + strbuf_addch(buf, ' '); + } + + free(global_config); + free(system_config); +} + +static bool can_unset_comment_char_config(struct comment_char_config *config) +{ + for (size_t i = 0; i < config->nr; i++) { + struct comment_char_config_item *item = &config->item[i]; + + if (item->scope == CONFIG_SCOPE_SYSTEM && + access(item->path, W_OK)) + return false; + } + + return true; +} + +static void add_unset_auto_comment_char_advice(struct repository *repo, + struct comment_char_config *config) +{ + struct strbuf buf = STRBUF_INIT; + + if (!can_unset_comment_char_config(config)) + return; + + for (size_t i = 0; i < config->nr; i++) { + struct comment_char_config_item *item = &config->item[i]; + + strbuf_addstr(&buf, " git config unset "); + add_config_scope_arg(repo, &buf, item); + if (get_comment_key_flags(config, item->path, item->key_id) == KEY_SEEN_TWICE) + strbuf_addstr(&buf, "--all "); + strbuf_addf(&buf, "%s\n", comment_key_name(item->key_id)); + } + advise(_("\nTo use the default comment string (#) please run\n\n%s"), + buf.buf); + strbuf_release(&buf); +} + +static void add_comment_char_advice(struct repository *repo, + struct comment_char_config *config) +{ + struct strbuf buf = STRBUF_INIT; + struct comment_char_config_item *item; + /* TRANSLATORS this is a place holder for the value of core.commentString */ + const char *placeholder = _("<comment string>"); + + /* + * If auto is set in the last file that we saw advise the user how to + * update their config. + */ + if (!config->auto_set_in_file) + return; + + add_unset_auto_comment_char_advice(repo, config); + item = &config->item[config->nr - 1]; + strbuf_reset(&buf); + strbuf_addstr(&buf, " git config set "); + add_config_scope_arg(repo, &buf, item); + strbuf_addf(&buf, "%s %s\n", comment_key_name(item->key_id), + placeholder); + advise(_("\nTo set a custom comment string please run\n\n" + "%s\nwhere '%s' is the string you wish to use.\n"), + buf.buf, placeholder); + strbuf_release(&buf); +} + +#undef KEY_SEEN_ONCE +#undef KEY_SEEN_TWICE +#undef COMMENT_KEY_SHIFT +#undef COMMENT_KEY_MASK + +struct repo_config { + struct repository *repo; + struct comment_char_config comment_char_config; +}; + +#define REPO_CONFIG_INIT(repo_) { \ + .comment_char_config = COMMENT_CHAR_CFG_INIT, \ + .repo = repo_, \ + }; + +static void repo_config_release(struct repo_config *config) +{ + comment_char_config_release(&config->comment_char_config); +} + +#ifdef WITH_BREAKING_CHANGES +static void check_auto_comment_char_config(struct repository *repo, + struct comment_char_config *config) +{ + if (!config->auto_set) + return; + + die_message(_("Support for '%s=auto' has been removed in Git 3.0"), + comment_key_name(config->last_key_id)); + add_comment_char_advice(repo, config); + die(NULL); +} +#else +static void check_auto_comment_char_config(struct repository *repo, + struct comment_char_config *config) +{ + extern bool warn_on_auto_comment_char; + const char *DEPRECATED_CONFIG_ENV = + "GIT_AUTO_COMMENT_CHAR_CONFIG_WARNING_GIVEN"; + + if (!config->auto_set || !warn_on_auto_comment_char) + return; + + /* + * Use an environment variable to ensure that subprocesses do not repeat + * the warning. + */ + if (git_env_bool(DEPRECATED_CONFIG_ENV, false)) + return; + + setenv(DEPRECATED_CONFIG_ENV, "true", true); + + warning(_("Support for '%s=auto' is deprecated and will be removed in " + "Git 3.0"), comment_key_name(config->last_key_id)); + add_comment_char_advice(repo, config); +} +#endif /* WITH_BREAKING_CHANGES */ + +static void check_deprecated_config(struct repo_config *config) +{ + if (!config->repo->check_deprecated_config) + return; + + check_auto_comment_char_config(config->repo, + &config->comment_char_config); +} + +static int repo_config_callback(const char *key, const char *value, + const struct config_context *ctx, void *data) +{ + struct repo_config *config = data; + + comment_char_callback(key, value, ctx, &config->comment_char_config); + return config_set_callback(key, value, ctx, config->repo->config); +} + /* Functions use to read configuration from a repository */ static void repo_read_config(struct repository *repo) { struct config_options opts = { 0 }; + struct repo_config config = REPO_CONFIG_INIT(repo); opts.respect_includes = 1; opts.commondir = repo->commondir; @@ -1963,8 +2245,8 @@ static void repo_read_config(struct repository *repo) git_configset_clear(repo->config); git_configset_init(repo->config); - if (config_with_options(config_set_callback, repo->config, NULL, - repo, &opts) < 0) + if (config_with_options(repo_config_callback, &config, NULL, repo, + &opts) < 0) /* * config_with_options() normally returns only * zero, as most errors are fatal, and @@ -1977,6 +2259,8 @@ static void repo_read_config(struct repository *repo) * immediately. */ die(_("unknown error occurred while reading the configuration files")); + check_deprecated_config(&config); + repo_config_release(&config); } static void git_config_check_init(struct repository *repo) @@ -2664,6 +2948,14 @@ int repo_config_set_multivar_in_file_gently(struct repository *r, char *contents = NULL; size_t contents_sz; struct config_store_data store = CONFIG_STORE_INIT; + bool saved_check_deprecated_config = r->check_deprecated_config; + + /* + * Do not warn or die if there are deprecated config settings as + * we want the user to be able to change those settings by running + * "git config". + */ + r->check_deprecated_config = false; validate_comment_string(comment); @@ -2895,6 +3187,7 @@ out_free: if (in_fd >= 0) close(in_fd); config_store_data_clear(&store); + r->check_deprecated_config = saved_check_deprecated_config; return ret; write_err_out: diff --git a/contrib/diff-highlight/README b/contrib/diff-highlight/README index d4c2343175..1db4440e68 100644 --- a/contrib/diff-highlight/README +++ b/contrib/diff-highlight/README @@ -58,6 +58,14 @@ following in your git configuration: diff = diff-highlight | less --------------------------------------------- +If you use the interactive patch mode of `git add -p`, `git checkout +-p`, etc, you may also want to configure it to be used there: + +--------------------------------------------- +[interactive] + diffFilter = diff-highlight +--------------------------------------------- + Color Config ------------ diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index 3fddba797c..17106d1a72 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -785,20 +785,40 @@ ensure_valid_ref_format () { die "fatal: '$1' does not look like a ref" } -# Usage: check if a commit from another subtree should be +# Usage: should_ignore_subtree_split_commit REV +# +# Check if REV is a commit from another subtree and should be # ignored from processing for splits should_ignore_subtree_split_commit () { assert test $# = 1 - local rev="$1" - if test -n "$(git log -1 --grep="git-subtree-dir:" $rev)" + + git show \ + --no-patch \ + --no-show-signature \ + --format='%(trailers:key=git-subtree-dir,key=git-subtree-mainline)' \ + "$1" | + ( + have_mainline= + subtree_dir= + + while read -r trailer val + do + case "$trailer" in + git-subtree-dir:) + subtree_dir="${val%/}" ;; + git-subtree-mainline:) + have_mainline=y ;; + esac + done + + if test -n "${subtree_dir}" && + test -z "${have_mainline}" && + test "${subtree_dir}" != "$arg_prefix" then - if test -z "$(git log -1 --grep="git-subtree-mainline:" $rev)" && - test -z "$(git log -1 --grep="git-subtree-dir: $arg_prefix$" $rev)" - then - return 0 - fi + return 0 fi return 1 + ) } # Usage: process_split_commit REV PARENTS diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index 3edbb33af4..316dc5269e 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -9,6 +9,9 @@ This test verifies the basic operation of the add, merge, split, pull, and push subcommands of git subtree. ' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + TEST_DIRECTORY=$(pwd)/../../../t . "$TEST_DIRECTORY"/test-lib.sh . "$TEST_DIRECTORY"/lib-gpg.sh @@ -68,6 +71,33 @@ test_create_pre2_32_repo () { git -C "$1-clone" replace HEAD^2 $new_commit } +# test_create_subtree_add REPO ORPHAN PREFIX FILENAME ... +# +# Create a simple subtree on a new branch named ORPHAN in REPO. +# The subtree is then merged into the current branch of REPO, +# under PREFIX. The generated subtree has has one commit +# with subject and tag FILENAME with a single file "FILENAME.t" +# +# When this method returns: +# - the current branch of REPO will have file PREFIX/FILENAME.t +# - REPO will have a branch named ORPHAN with subtree history +# +# additional arguments are forwarded to "subtree add" +test_create_subtree_add () { + ( + cd "$1" && + orphan="$2" && + prefix="$3" && + filename="$4" && + shift 4 && + last="$(git branch --show-current)" && + git switch --orphan "$orphan" && + test_commit "$filename" && + git checkout "$last" && + git subtree add --prefix="$prefix" "$@" "$orphan" + ) +} + test_expect_success 'shows short help text for -h' ' test_expect_code 129 git subtree -h >out 2>err && test_must_be_empty err && @@ -426,6 +456,47 @@ test_expect_success 'split with multiple subtrees' ' --squash --rejoin -d -m "Sub B Split 1" 2>&1 | grep -w "\[1\]")" = "" ' +# When subtree split-ing a directory that has other subtree +# *merges* underneath it, the split must include those subtrees. +# This test creates a nested subtree, `subA/subB`, and tests +# that the tree is correct after a subtree split of `subA/`. +# The test covers: +# - An initial `subtree add`; and +# - A follow-up `subtree merge` +# both with and without `--squashed`. +for is_squashed in '' 'y' +do + test_expect_success "split keeps nested ${is_squashed:+--squash }subtrees that are part of the split" ' + subtree_test_create_repo "$test_count" && + ( + cd "$test_count" && + mkdir subA && + test_commit subA/file1 && + test_create_subtree_add \ + . mksubtree subA/subB file2 ${is_squashed:+--squash} && + test_path_is_file subA/file1.t && + test_path_is_file subA/subB/file2.t && + git subtree split --prefix=subA --branch=bsplit && + git checkout bsplit && + test_path_is_file file1.t && + test_path_is_file subB/file2.t && + git checkout mksubtree && + git branch -D bsplit && + test_commit file3 && + git checkout main && + git subtree merge \ + ${is_squashed:+--squash} \ + --prefix=subA/subB mksubtree && + test_path_is_file subA/subB/file3.t && + git subtree split --prefix=subA --branch=bsplit && + git checkout bsplit && + test_path_is_file file1.t && + test_path_is_file subB/file2.t && + test_path_is_file subB/file3.t + ) + ' +done + test_expect_success 'split sub dir/ with --rejoin from scratch' ' subtree_test_create_repo "$test_count" && test_create_commit "$test_count" main1 && @@ -57,7 +57,7 @@ static int diff_detect_rename_default; static int diff_indent_heuristic = 1; static int diff_rename_limit_default = 1000; static int diff_suppress_blank_empty; -static int diff_use_color_default = -1; +static enum git_colorbool diff_use_color_default = GIT_COLOR_UNKNOWN; static int diff_color_moved_default; static int diff_color_moved_ws_default; static int diff_context_default = 3; @@ -1672,7 +1672,7 @@ static void emit_hunk_header(struct emit_callback *ecbdata, const char *frag = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO); const char *func = diff_get_color(ecbdata->color_diff, DIFF_FUNCINFO); const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); - const char *reverse = ecbdata->color_diff ? GIT_COLOR_REVERSE : ""; + const char *reverse = want_color(ecbdata->color_diff) ? GIT_COLOR_REVERSE : ""; static const char atat[2] = { '@', '@' }; const char *cp, *ep; struct strbuf msgbuf = STRBUF_INIT; @@ -1826,7 +1826,7 @@ static void emit_rewrite_diff(const char *name_a, size_two = fill_textconv(o->repo, textconv_two, two, &data_two); memset(&ecbdata, 0, sizeof(ecbdata)); - ecbdata.color_diff = want_color(o->use_color); + ecbdata.color_diff = o->use_color; ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b); ecbdata.opt = o; if (ecbdata.ws_rule & WS_BLANK_AT_EOF) { @@ -2303,7 +2303,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata) } } -const char *diff_get_color(int diff_use_color, enum color_diff ix) +const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix) { if (want_color(diff_use_color)) return diff_colors[ix]; @@ -3732,7 +3732,7 @@ static void builtin_diff(const char *name_a, if (o->flags.suppress_diff_headers) lbl[0] = NULL; ecbdata.label_path = lbl; - ecbdata.color_diff = want_color(o->use_color); + ecbdata.color_diff = o->use_color; ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b); if (ecbdata.ws_rule & WS_BLANK_AT_EOF) check_blank_at_eof(&mf1, &mf2, &ecbdata); @@ -4497,7 +4497,7 @@ static void fill_metainfo(struct strbuf *msg, struct diff_options *o, struct diff_filepair *p, int *must_show_header, - int use_color) + enum git_colorbool use_color) { const char *set = diff_get_color(use_color, DIFF_METAINFO); const char *reset = diff_get_color(use_color, DIFF_RESET); @@ -4596,7 +4596,7 @@ static void run_diff_cmd(const struct external_diff *pgm, */ fill_metainfo(msg, name, other, one, two, o, p, &must_show_header, - want_color(o->use_color) && !pgm); + pgm ? GIT_COLOR_NEVER : o->use_color); xfrm_msg = msg->len ? msg->buf : NULL; } @@ -4995,8 +4995,7 @@ void diff_setup_done(struct diff_options *options) if (options->flags.follow_renames) diff_check_follow_pathspec(&options->pathspec, 1); - if (!options->use_color || - (options->flags.allow_external && external_diff())) + if (options->flags.allow_external && external_diff()) options->color_moved = 0; if (options->filter_not) { @@ -5278,7 +5277,7 @@ static int diff_opt_color_words(const struct option *opt, struct diff_options *options = opt->value; BUG_ON_OPT_NEG(unset); - options->use_color = 1; + options->use_color = GIT_COLOR_ALWAYS; options->word_diff = DIFF_WORDS_COLOR; options->word_regex = arg; return 0; @@ -5600,7 +5599,7 @@ static int diff_opt_word_diff(const struct option *opt, if (!strcmp(arg, "plain")) options->word_diff = DIFF_WORDS_PLAIN; else if (!strcmp(arg, "color")) { - options->use_color = 1; + options->use_color = GIT_COLOR_ALWAYS; options->word_diff = DIFF_WORDS_COLOR; } else if (!strcmp(arg, "porcelain")) @@ -6733,7 +6732,7 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o) if (WSEH_NEW & WS_RULE_MASK) BUG("WS rules bit mask overlaps with diff symbol flags"); - if (o->color_moved) + if (o->color_moved && want_color(o->use_color)) o->emitted_symbols = &esm; if (o->additional_path_headers) @@ -6746,20 +6745,17 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o) } if (o->emitted_symbols) { - if (o->color_moved) { - struct mem_pool entry_pool; - struct moved_entry_list *entry_list; - - mem_pool_init(&entry_pool, 1024 * 1024); - entry_list = add_lines_to_move_detection(o, - &entry_pool); - mark_color_as_moved(o, entry_list); - if (o->color_moved == COLOR_MOVED_ZEBRA_DIM) - dim_moved_lines(o); - - mem_pool_discard(&entry_pool, 0); - free(entry_list); - } + struct mem_pool entry_pool; + struct moved_entry_list *entry_list; + + mem_pool_init(&entry_pool, 1024 * 1024); + entry_list = add_lines_to_move_detection(o, &entry_pool); + mark_color_as_moved(o, entry_list); + if (o->color_moved == COLOR_MOVED_ZEBRA_DIM) + dim_moved_lines(o); + + mem_pool_discard(&entry_pool, 0); + free(entry_list); for (i = 0; i < esm.nr; i++) emit_diff_symbol_from_struct(o, &esm.buf[i]); @@ -7,6 +7,7 @@ #include "hash.h" #include "pathspec.h" #include "strbuf.h" +#include "color.h" struct oidset; @@ -126,6 +127,13 @@ struct diff_flags { unsigned recursive; unsigned tree_in_recursive; + /* + * Historically diff_tree_combined() overrides recursive to 1. To + * suppress this behavior, set the flag below. + * It has no effect if recursive is already set to 1. + */ + unsigned no_recursive_diff_tree_combined; + /* Affects the way how a file that is seemingly binary is treated. */ unsigned binary; unsigned text; @@ -283,7 +291,7 @@ struct diff_options { /* diff-filter bits */ unsigned int filter, filter_not; - int use_color; + enum git_colorbool use_color; /* Number of context lines to generate in patch output. */ int context; @@ -469,7 +477,7 @@ enum color_diff { DIFF_FILE_NEW_BOLD = 22, }; -const char *diff_get_color(int diff_use_color, enum color_diff ix); +const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix); #define diff_get_color_opt(o, ix) \ diff_get_color((o)->use_color, ix) diff --git a/environment.c b/environment.c index 0e72fdac85..a770b5921d 100644 --- a/environment.c +++ b/environment.c @@ -121,7 +121,10 @@ int protect_ntfs = PROTECT_NTFS_DEFAULT; */ const char *comment_line_str = "#"; char *comment_line_str_to_free; +#ifndef WITH_BREAKING_CHANGES int auto_comment_line_char; +bool warn_on_auto_comment_char; +#endif /* !WITH_BREAKING_CHANGES */ /* This is set by setup_git_directory_gently() and/or git_default_config() */ char *git_work_tree_cfg; @@ -463,16 +466,22 @@ static int git_default_core_config(const char *var, const char *value, if (!strcmp(var, "core.commentchar") || !strcmp(var, "core.commentstring")) { - if (!value) + if (!value) { return config_error_nonbool(var); - else if (!strcasecmp(value, "auto")) +#ifndef WITH_BREAKING_CHANGES + } else if (!strcasecmp(value, "auto")) { auto_comment_line_char = 1; - else if (value[0]) { + FREE_AND_NULL(comment_line_str_to_free); + comment_line_str = "#"; +#endif /* !WITH_BREAKING_CHANGES */ + } else if (value[0]) { if (strchr(value, '\n')) return error(_("%s cannot contain newline"), var); comment_line_str = value; FREE_AND_NULL(comment_line_str_to_free); +#ifndef WITH_BREAKING_CHANGES auto_comment_line_char = 0; +#endif /* !WITH_BREAKING_CHANGES */ } else return error(_("%s must have at least one character"), var); return 0; diff --git a/environment.h b/environment.h index 8cfce41015..51898c99cd 100644 --- a/environment.h +++ b/environment.h @@ -208,7 +208,10 @@ extern char *excludes_file; */ extern const char *comment_line_str; extern char *comment_line_str_to_free; +#ifndef WITH_BREAKING_CHANGES extern int auto_comment_line_char; +extern bool warn_on_auto_comment_char; +#endif /* !WITH_BREAKING_CHANGES */ # endif /* USE_THE_REPOSITORY_VARIABLE */ #endif /* ENVIRONMENT_H */ diff --git a/git-curl-compat.h b/git-curl-compat.h index aa8eed7ed2..659e5a3875 100644 --- a/git-curl-compat.h +++ b/git-curl-compat.h @@ -46,6 +46,13 @@ #endif /** + * curl_global_trace() was added in 8.3.0, released September 2023. + */ +#if LIBCURL_VERSION_NUM >= 0x080300 +#define GIT_CURL_HAVE_GLOBAL_TRACE 1 +#endif + +/** * CURLOPT_TCP_KEEPCNT was added in 8.9.0, released in July, 2024. */ #if LIBCURL_VERSION_NUM >= 0x080900 diff --git a/git-gui/Makefile b/git-gui/Makefile index 27bbe051de..69b0b84435 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -186,6 +186,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -200,6 +201,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..142d1bc3de --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,63 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. +# +# The window title, which defaults to "Question?", can be +# overridden via the optional `--title` command-line +# option. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +set title "Question?" +if {$argc < 1} { + puts stderr "Usage: $argv0 <question>" + exit 1 +} else { + if {$argc > 2 && [lindex $argv 0] == "--title"} { + set title [lindex $argv 1] + set argv [lreplace $argv 0 1] + } + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command {exit 0} +${NS}::button .b.no -text No -command {exit 1} + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . <Key-Return> {exit 0} +bind . <Key-Escape> {exit 1} + +if {$::tcl_platform(platform) eq {windows}} { + set icopath [file dirname [file normalize $argv0]] + if {[file tail $icopath] eq {git-core}} { + set icopath [file dirname $icopath] + } + set icopath [file dirname $icopath] + set icopath [file join $icopath share git git-for-windows.ico] + if {[file exists $icopath]} { + wm iconbitmap . -default $icopath + } +} + +wm title . $title +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index a931d7f7c9..d3d3aa14a9 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -103,7 +103,6 @@ if {[is_Windows]} { set _path_sep {:} } -set _search_path {} set _path_seen [dict create] foreach p [split $env(PATH) $_path_sep] { # Keep only absolute paths, getting rid of ., empty, etc. @@ -112,12 +111,9 @@ foreach p [split $env(PATH) $_path_sep] { } # Keep only the first occurence of any duplicates. set norm_p [file normalize $p] - if {[dict exists $_path_seen $norm_p]} { - continue - } dict set _path_seen $norm_p 1 - lappend _search_path $norm_p } +set _search_path [dict keys $_path_seen] unset _path_seen set env(PATH) [join $_search_path $_path_sep] @@ -583,21 +579,6 @@ proc open_cmd_pipe {cmd path} { return [open |$run r] } -proc _lappend_nice {cmd_var} { - global _nice - upvar $cmd_var cmd - - if {![info exists _nice]} { - set _nice [_which nice] - if {[catch {safe_exec [list $_nice git version]}]} { - set _nice {} - } - } - if {$_nice ne {}} { - lappend cmd $_nice - } -} - proc git {args} { git_redir $args {} } @@ -631,15 +612,14 @@ proc git_read {cmd {redir {}}} { return [safe_open_command $cmdp $redir] } -proc git_read_nice {cmd} { - global _git - set opt [list] - - _lappend_nice opt - - set cmdp [concat [list $_git] $cmd] +set _nice [list [_which nice]] +if {[catch {safe_exec [list {*}$_nice git version]}]} { + set _nice {} +} - return [safe_open_command [concat $opt $cmdp]] +proc git_read_nice {cmd} { + set cmdp [list {*}$::_nice $::_git {*}$cmd] + return [safe_open_command $cmdp] } proc git_write {cmd} { @@ -1130,6 +1110,12 @@ set argv0dir [file dirname [file normalize $::argv0]] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [file join $argv0dir git-gui--askpass] } +if {![info exists env(GIT_ASKPASS)]} { + set env(GIT_ASKPASS) [file join $argv0dir git-gui--askpass] +} +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [file join $argv0dir git-gui--askyesno] +} unset argv0dir ###################################################################### diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl index 7aa09c7728..e1d38e54be 100644 --- a/git-gui/lib/index.tcl +++ b/git-gui/lib/index.tcl @@ -425,6 +425,11 @@ proc revert_helper {txt paths} { if {![lock_index begin-update]} return + # Workaround for Tcl < 9.0: chord namespaces are not obeyed and + # operated in the global namespace. This clears an error that could + # have been left over from a previous operation. + set ::err {} + # Common "after" functionality that waits until multiple asynchronous # operations are complete (by waiting for them to activate their notes # on the chord). @@ -432,7 +437,7 @@ proc revert_helper {txt paths} { # The asynchronous operations are each indicated below by a comment # before the code block that starts the async operation. set after_chord [SimpleChord::new { - if {[string trim $err] != ""} { + if {[info exists err] && [string trim $err] ne ""} { rescan_on_error $err } else { unlock_index diff --git a/git-send-email.perl b/git-send-email.perl index 437f8ac46a..cd4b316ddc 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -62,7 +62,7 @@ git send-email --translate-aliases --smtp-user <str> * Username for SMTP-AUTH. --smtp-pass <str> * Password for SMTP-AUTH; not necessary. --smtp-encryption <str> * tls or ssl; anything else disables. - --smtp-ssl * Deprecated. Use '--smtp-encryption ssl'. + --smtp-ssl * Deprecated. Use `--smtp-encryption ssl`. --smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file). Pass an empty string to disable certificate verification. @@ -73,6 +73,10 @@ git send-email --translate-aliases --no-smtp-auth * Disable SMTP authentication. Shorthand for `--smtp-auth=none` --smtp-debug <0|1> * Disable, enable Net::SMTP debug. + --imap-sent-folder <str> * IMAP folder where a copy of the emails should be sent. + Make sure `git imap-send` is set up to use this feature. + --[no-]use-imap-only * Only copy emails to the IMAP folder specified by + `--imap-sent-folder` instead of actually sending them. --batch-size <int> * send max <int> message per connection. --relogin-delay <int> * delay <int> seconds between two successive login. @@ -200,7 +204,7 @@ my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/; # Variables we fill in automatically, or via prompting: my (@to,@cc,@xh,$envelope_sender, - $initial_in_reply_to,$reply_to,$initial_subject,@files, + $initial_in_reply_to,$reply_to,$initial_subject,@files,@imap_copy, $author,$sender,$smtp_authpass,$annotate,$compose,$time); # Things we either get from config, *or* are overridden on the # command-line. @@ -277,6 +281,7 @@ my ($smtp_server, $smtp_server_port, @smtp_server_options); my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path); my ($batch_size, $relogin_delay); my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth); +my ($imap_sent_folder); my ($confirm); my (@suppress_cc); my ($auto_8bit_encoding); @@ -293,6 +298,7 @@ my $mailmap = 0; my $target_xfer_encoding = 'auto'; my $forbid_sendmail_variables = 1; my $outlook_id_fix = 'auto'; +my $use_imap_only = 0; my %config_bool_settings = ( "thread" => \$thread, @@ -309,6 +315,7 @@ my %config_bool_settings = ( "forbidsendmailvariables" => \$forbid_sendmail_variables, "mailmap" => \$mailmap, "outlookidfix" => \$outlook_id_fix, + "useimaponly" => \$use_imap_only, ); my %config_settings = ( @@ -322,6 +329,7 @@ my %config_settings = ( "smtpauth" => \$smtp_auth, "smtpbatchsize" => \$batch_size, "smtprelogindelay" => \$relogin_delay, + "imapsentfolder" => \$imap_sent_folder, "to" => \@config_to, "tocmd" => \$to_cmd, "cc" => \@config_cc, @@ -527,6 +535,8 @@ my %options = ( "smtp-domain:s" => \$smtp_domain, "smtp-auth=s" => \$smtp_auth, "no-smtp-auth" => sub {$smtp_auth = 'none'}, + "imap-sent-folder=s" => \$imap_sent_folder, + "use-imap-only!" => \$use_imap_only, "annotate!" => \$annotate, "compose" => \$compose, "quiet" => \$quiet, @@ -1678,6 +1688,8 @@ EOF if ($dry_run) { # We don't want to send the email. + } elsif ($use_imap_only) { + die __("The destination IMAP folder is not properly defined.") if !defined $imap_sent_folder; } elsif (defined $sendmail_cmd || file_name_is_absolute($smtp_server)) { my $pid = open my $sm, '|-'; defined $pid or die $!; @@ -1829,6 +1841,17 @@ EOF print "\n"; } + if ($imap_sent_folder && !$dry_run) { + my $imap_header = $header; + if (@initial_bcc) { + # Bcc is not a part of $header, so we add it here. + # This is only for the IMAP copy, not for the actual email + # sent to the recipients. + $imap_header .= "Bcc: " . join(", ", @initial_bcc) . "\n"; + } + push @imap_copy, "From git-send-email\n$imap_header\n$message"; + } + return 1; } @@ -1931,6 +1954,9 @@ sub pre_process_file { $in_reply_to = $1; } } + elsif (/^Reply-To: (.*)/i) { + $reply_to = $1; + } elsif (/^References: (.*)/i) { if (!$initial_in_reply_to || $thread) { $references = $1; @@ -2223,6 +2249,19 @@ sub cleanup_compose_files { $smtp->quit if $smtp; +if ($imap_sent_folder && @imap_copy && !$dry_run) { + my $imap_input = join("\n", @imap_copy); + eval { + print "\nStarting git imap-send...\n"; + my ($fh, $ctx) = Git::command_input_pipe(['imap-send', '-f', $imap_sent_folder]); + print $fh $imap_input; + Git::command_close_pipe($fh, $ctx); + 1; + } or do { + warn "Warning: failed to send messages to IMAP folder $imap_sent_folder: $@"; + }; +} + sub apply_transfer_encoding { my $message = shift; my $from = shift; diff --git a/gitk-git/README.md b/gitk-git/README.md new file mode 100644 index 0000000000..2e307463c6 --- /dev/null +++ b/gitk-git/README.md @@ -0,0 +1,93 @@ +Gitk - The Git Repository Browser +================================= + +Gitk is a graphical Git repository browser. It displays the commit +history of a Git repository as a graph, showing the relationships +between commits, branches, and tags. + +Usage +===== + +To view the history of the current repository: +```bash +gitk +``` + +To view the history of specific files or directories: +```bash +gitk path/to/file +gitk path/to/directory +``` + +To view a specific branch or range of commits: +```bash +gitk branch-name +gitk v1.0..v2.0 +``` + +For more usage examples and options, see the [gitk manual](https://git-scm.com/docs/gitk). + +Building +======== + +Gitk is a Tcl/Tk application. It requires Tcl/Tk to be installed on +your system. + +Running directly +---------------- + +Gitk can be run from the source directory without installation: + +```bash +./gitk +``` + +This allows for quick testing of changes. + +Installation +------------ + +To install system-wide, you can use either `make` or `meson`: + +```bash +# Install to default location ($HOME/bin) +make install + +# Install to system-wide location +sudo make install prefix=/usr/local + +# Install to custom location +make install prefix=/opt/gitk + +# Using Meson +meson setup builddir +meson compile -C builddir +meson install -C builddir +``` + +Both build systems will handle setting the correct Tcl/Tk interpreter +path and installing translation files. + +Contributing +============ + +Contributions are welcome! The preferred method for submitting patches +is via email to the Git mailing list, as this allows for more thorough +review and broader community feedback. However, GitHub pull requests +are also accepted. + +All commits must be signed off (use `git commit --signoff`) and should +have commit messages prefixed with `gitk:`. + +Email Patches +------------- + +Send patches to git@vger.kernel.org and CC j6t@kdbg.org. See the Git +project's [patch submission guidelines](https://git-scm.com/docs/SubmittingPatches) +for detailed instructions on creating and sending patches. + +License +======= + +Gitk is distributed under the GNU General Public License, either +version 2, or (at your option) any later version. diff --git a/gitk-git/gitk b/gitk-git/gitk index 3b6acfc592..6e4d71d585 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2301,6 +2301,11 @@ proc scrollval {D {koff 0}} { return [expr int(-($D / $scroll_D0) * max(1, $kscroll-$koff))] } +proc precisescrollval {D {koff 0}} { + global kscroll + return [expr (-($D / 10.0) * max(1, $kscroll-$koff))] +} + proc bind_mousewheel {} { global canv cflist ctext bindall <MouseWheel> {allcanvs yview scroll [scrollval %D] units} @@ -2319,6 +2324,25 @@ proc bind_mousewheel {} { bind $cflist <Alt-MouseWheel> {$cflist yview scroll [scrollval 5*%D 2] units} bind $cflist <Alt-Shift-MouseWheel> break bind $canv <Alt-Shift-MouseWheel> {$canv xview scroll [scrollval 5*%D] units} + + bindall <TouchpadScroll> { + lassign [tk::PreciseScrollDeltas %D] deltaX deltaY + allcanvs yview scroll [precisescrollval $deltaY] units + } + bind $ctext <TouchpadScroll> { + lassign [tk::PreciseScrollDeltas %D] deltaX deltaY + $ctext yview scroll [precisescrollval $deltaY 2] units + $ctext xview scroll [precisescrollval $deltaX 2] units + } + bind $cflist <TouchpadScroll> { + lassign [tk::PreciseScrollDeltas %D] deltaX deltaY + $cflist yview scroll [precisescrollval $deltaY 2] units + } + bind $canv <TouchpadScroll> { + lassign [tk::PreciseScrollDeltas %D] deltaX deltaY + $canv xview scroll [precisescrollval $deltaX] units + allcanvs yview scroll [precisescrollval $deltaY] units + } } } @@ -12596,7 +12620,7 @@ set foundbgcolor yellow set currentsearchhitbgcolor orange # button for popping up context menus -if {[tk windowingsystem] eq "aqua"} { +if {[tk windowingsystem] eq "aqua" && [package vcompare $::tcl_version 8.7] < 0} { set ctxbut <Button-2> } else { set ctxbut <Button-3> @@ -1263,12 +1263,12 @@ static void show_line(struct grep_opt *opt, */ show_line_header(opt, name, lno, cno, sign); } - if (opt->color || opt->only_matching) { + if (want_color(opt->color) || opt->only_matching) { regmatch_t match; enum grep_context ctx = GREP_CONTEXT_BODY; int eflags = 0; - if (opt->color) { + if (want_color(opt->color)) { if (sign == ':') match_color = opt->colors[GREP_COLOR_MATCH_SELECTED]; else @@ -159,7 +159,7 @@ struct grep_opt { int pathname; int null_following_name; int only_matching; - int color; + enum git_colorbool color; int max_depth; int funcname; int funcbody; @@ -198,7 +198,7 @@ struct grep_opt { [GREP_COLOR_SEP] = GIT_COLOR_CYAN, \ }, \ .only_matching = 0, \ - .color = -1, \ + .color = GIT_COLOR_UNKNOWN, \ .output = std_output, \ } diff --git a/http-push.c b/http-push.c index 91a5465afb..4c43ba3bc7 100644 --- a/http-push.c +++ b/http-push.c @@ -1941,7 +1941,7 @@ int cmd_main(int argc, const char **argv) strvec_pushf(&commit_argv, "^%s", oid_to_hex(&ref->old_oid)); repo_init_revisions(the_repository, &revs, setup_git_directory()); - setup_revisions(commit_argv.nr, commit_argv.v, &revs, NULL); + setup_revisions_from_strvec(&commit_argv, &revs, NULL); revs.edge_hint = 0; /* just in case */ /* Generate a list of objects that need to be pushed */ @@ -1348,6 +1348,14 @@ void http_init(struct remote *remote, const char *url, int proactive_auth) if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) die("curl_global_init failed"); +#ifdef GIT_CURL_HAVE_GLOBAL_TRACE + { + const char *comp = getenv("GIT_TRACE_CURL_COMPONENTS"); + if (comp) + curl_global_trace(comp); + } +#endif + if (proactive_auth && http_proactive_auth == PROACTIVE_AUTH_NONE) http_proactive_auth = PROACTIVE_AUTH_IF_CREDENTIALS; diff --git a/imap-send.c b/imap-send.c index 254ec83ab7..4bd5b8aa0d 100644 --- a/imap-send.c +++ b/imap-send.c @@ -1442,14 +1442,24 @@ static int count_messages(struct strbuf *all_msgs) while (1) { if (starts_with(p, "From ")) { - p = strstr(p+5, "\nFrom: "); - if (!p) break; - p = strstr(p+7, "\nDate: "); - if (!p) break; - p = strstr(p+7, "\nSubject: "); - if (!p) break; - p += 10; - count++; + if (starts_with(p, "From git-send-email")) { + p = strstr(p+5, "\nFrom: "); + if (!p) break; + p += 7; + p = strstr(p, "\nTo: "); + if (!p) break; + p += 5; + count++; + } else { + p = strstr(p+5, "\nFrom: "); + if (!p) break; + p = strstr(p+7, "\nDate: "); + if (!p) break; + p = strstr(p+7, "\nSubject: "); + if (!p) break; + p += 10; + count++; + } } p = strstr(p+5, "\nFrom "); if (!p) diff --git a/line-log.c b/line-log.c index 188d387d40..8bd422148d 100644 --- a/line-log.c +++ b/line-log.c @@ -201,7 +201,7 @@ static void range_set_difference(struct range_set *out, * b: ------| */ j++; - if (j >= b->nr || end < b->ranges[j].start) { + if (j >= b->nr || end <= b->ranges[j].start) { /* * b exhausted, or * a: ----| @@ -408,7 +408,7 @@ static void diff_ranges_filter_touched(struct diff_ranges *out, assert(out->target.nr == 0); for (i = 0; i < diff->target.nr; i++) { - while (diff->target.ranges[i].start > rs->ranges[j].end) { + while (diff->target.ranges[i].start >= rs->ranges[j].end) { j++; if (j == rs->nr) return; @@ -939,9 +939,18 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang long t_cur = t_start; unsigned int j_last; + /* + * If a diff range touches multiple line ranges, then all + * those line ranges should be shown, so take a step back if + * the current line range is still in the previous diff range + * (even if only partially). + */ + if (j > 0 && diff->target.ranges[j-1].end > t_start) + j--; + while (j < diff->target.nr && diff->target.ranges[j].end < t_start) j++; - if (j == diff->target.nr || diff->target.ranges[j].start > t_end) + if (j == diff->target.nr || diff->target.ranges[j].start >= t_end) continue; /* Scan ahead to determine the last diff that falls in this range */ diff --git a/list-objects-filter.c b/list-objects-filter.c index 7ecd4d9ef5..acd65ebb73 100644 --- a/list-objects-filter.c +++ b/list-objects-filter.c @@ -524,12 +524,11 @@ static void filter_sparse_oid__init( struct filter *filter) { struct filter_sparse_data *d = xcalloc(1, sizeof(*d)); - struct object_context oc; struct object_id sparse_oid; - if (get_oid_with_context(the_repository, - filter_options->sparse_oid_name, - GET_OID_BLOB, &sparse_oid, &oc)) + if (repo_get_oid_with_flags(the_repository, + filter_options->sparse_oid_name, + &sparse_oid, GET_OID_BLOB)) die(_("unable to access sparse blob in '%s'"), filter_options->sparse_oid_name); if (add_patterns_from_blob_to_list(&sparse_oid, "", 0, &d->pl) < 0) @@ -544,8 +543,6 @@ static void filter_sparse_oid__init( filter->filter_data = d; filter->filter_object_fn = filter_sparse; filter->free_fn = filter_sparse_free; - - object_context_release(&oc); } /* diff --git a/log-tree.c b/log-tree.c index 233bf9f227..67d9ace596 100644 --- a/log-tree.c +++ b/log-tree.c @@ -57,7 +57,7 @@ static const char *color_decorate_slots[] = { [DECORATION_GRAFTED] = "grafted", }; -static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix) +static const char *decorate_get_color(enum git_colorbool decorate_use_color, enum decoration_type ix) { if (want_color(decorate_use_color)) return decoration_colors[ix]; @@ -341,7 +341,7 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio */ void format_decorations(struct strbuf *sb, const struct commit *commit, - int use_color, + enum git_colorbool use_color, const struct decoration_options *opts) { const struct name_decoration *decoration; @@ -717,6 +717,7 @@ static void show_diff_of_diff(struct rev_info *opt) struct range_diff_options range_diff_opts = { .creation_factor = opt->creation_factor, .dual_color = 1, + .max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT, .diffopt = &opts }; diff --git a/log-tree.h b/log-tree.h index ebe491c543..07924be8bc 100644 --- a/log-tree.h +++ b/log-tree.h @@ -1,6 +1,8 @@ #ifndef LOG_TREE_H #define LOG_TREE_H +#include "color.h" + struct rev_info; struct log_info { @@ -26,7 +28,7 @@ int log_tree_diff_flush(struct rev_info *); int log_tree_commit(struct rev_info *, struct commit *); void show_log(struct rev_info *opt); void format_decorations(struct strbuf *sb, const struct commit *commit, - int use_color, const struct decoration_options *opts); + enum git_colorbool use_color, const struct decoration_options *opts); void show_decorations(struct rev_info *opt, struct commit *commit); void log_write_email_headers(struct rev_info *opt, struct commit *commit, char **extra_headers_p, diff --git a/midx-write.c b/midx-write.c index a0aceab5e0..c73010df6d 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "abspath.h" #include "config.h" @@ -24,11 +22,12 @@ #define BITMAP_POS_UNKNOWN (~((uint32_t)0)) #define MIDX_CHUNK_FANOUT_SIZE (sizeof(uint32_t) * 256) #define MIDX_CHUNK_LARGE_OFFSET_WIDTH (sizeof(uint64_t)) +#define NO_PREFERRED_PACK (~((uint32_t)0)) extern int midx_checksum_valid(struct multi_pack_index *m); -extern void clear_midx_files_ext(const char *object_dir, const char *ext, +extern void clear_midx_files_ext(struct odb_source *source, const char *ext, const char *keep_hash); -extern void clear_incremental_midx_files_ext(const char *object_dir, +extern void clear_incremental_midx_files_ext(struct odb_source *source, const char *ext, const char **keep_hashes, uint32_t hashes_nr); @@ -104,7 +103,7 @@ struct write_midx_context { unsigned large_offsets_needed:1; uint32_t num_large_offsets; - int preferred_pack_idx; + uint32_t preferred_pack_idx; int incremental; uint32_t num_multi_pack_indexes_before; @@ -112,6 +111,7 @@ struct write_midx_context { struct string_list *to_include; struct repository *repo; + struct odb_source *source; }; static int should_include_pack(const struct write_midx_context *ctx, @@ -260,7 +260,7 @@ static void midx_fanout_sort(struct midx_fanout *fanout) static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout, struct multi_pack_index *m, uint32_t cur_fanout, - int preferred_pack) + uint32_t preferred_pack) { uint32_t start = m->num_objects_in_base, end; uint32_t cur_object; @@ -274,7 +274,7 @@ static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout, end = m->num_objects_in_base + ntohl(m->chunk_oid_fanout[cur_fanout]); for (cur_object = start; cur_object < end; cur_object++) { - if ((preferred_pack > -1) && + if ((preferred_pack != NO_PREFERRED_PACK) && (preferred_pack == nth_midxed_pack_int_id(m, cur_object))) { /* * Objects from preferred packs are added @@ -364,7 +364,8 @@ static void compute_sorted_entries(struct write_midx_context *ctx, preferred, cur_fanout); } - if (-1 < ctx->preferred_pack_idx && ctx->preferred_pack_idx < start_pack) + if (ctx->preferred_pack_idx != NO_PREFERRED_PACK && + ctx->preferred_pack_idx < start_pack) midx_fanout_add_pack_fanout(&fanout, ctx->info, ctx->preferred_pack_idx, 1, cur_fanout); @@ -648,7 +649,6 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx) } static void write_midx_reverse_index(struct write_midx_context *ctx, - const char *object_dir, unsigned char *midx_hash) { struct strbuf buf = STRBUF_INIT; @@ -657,11 +657,10 @@ static void write_midx_reverse_index(struct write_midx_context *ctx, trace2_region_enter("midx", "write_midx_reverse_index", ctx->repo); if (ctx->incremental) - get_split_midx_filename_ext(ctx->repo->hash_algo, &buf, - object_dir, midx_hash, - MIDX_EXT_REV); + get_split_midx_filename_ext(ctx->source, &buf, + midx_hash, MIDX_EXT_REV); else - get_midx_filename_ext(ctx->repo->hash_algo, &buf, object_dir, + get_midx_filename_ext(ctx->source, &buf, midx_hash, MIDX_EXT_REV); tmp_file = write_rev_file_order(ctx->repo, NULL, ctx->pack_order, @@ -836,14 +835,13 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr } static int write_midx_bitmap(struct write_midx_context *ctx, - const char *object_dir, const unsigned char *midx_hash, struct packing_data *pdata, struct commit **commits, uint32_t commits_nr, unsigned flags) { - int ret, i; + int ret; uint16_t options = 0; struct bitmap_writer writer; struct pack_idx_entry **index; @@ -852,12 +850,11 @@ static int write_midx_bitmap(struct write_midx_context *ctx, trace2_region_enter("midx", "write_midx_bitmap", ctx->repo); if (ctx->incremental) - get_split_midx_filename_ext(ctx->repo->hash_algo, &bitmap_name, - object_dir, midx_hash, - MIDX_EXT_BITMAP); + get_split_midx_filename_ext(ctx->source, &bitmap_name, + midx_hash, MIDX_EXT_BITMAP); else - get_midx_filename_ext(ctx->repo->hash_algo, &bitmap_name, - object_dir, midx_hash, MIDX_EXT_BITMAP); + get_midx_filename_ext(ctx->source, &bitmap_name, + midx_hash, MIDX_EXT_BITMAP); if (flags & MIDX_WRITE_BITMAP_HASH_CACHE) options |= BITMAP_OPT_HASH_CACHE; @@ -871,7 +868,7 @@ static int write_midx_bitmap(struct write_midx_context *ctx, * this order). */ ALLOC_ARRAY(index, pdata->nr_objects); - for (i = 0; i < pdata->nr_objects; i++) + for (uint32_t i = 0; i < pdata->nr_objects; i++) index[i] = &pdata->objects[i].idx; bitmap_writer_init(&writer, ctx->repo, pdata, @@ -892,7 +889,7 @@ static int write_midx_bitmap(struct write_midx_context *ctx, * happens between bitmap_writer_build_type_index() and * bitmap_writer_finish(). */ - for (i = 0; i < pdata->nr_objects; i++) + for (uint32_t i = 0; i < pdata->nr_objects; i++) index[ctx->pack_order[i]] = &pdata->objects[i].idx; bitmap_writer_select_commits(&writer, commits, commits_nr); @@ -913,15 +910,7 @@ cleanup: return ret; } -static struct multi_pack_index *lookup_multi_pack_index(struct repository *r, - const char *object_dir) -{ - struct odb_source *source = odb_find_source(r->objects, object_dir); - return get_multi_pack_index(source); -} - -static int fill_packs_from_midx(struct write_midx_context *ctx, - const char *preferred_pack_name, uint32_t flags) +static int fill_packs_from_midx(struct write_midx_context *ctx) { struct multi_pack_index *m; @@ -929,30 +918,10 @@ static int fill_packs_from_midx(struct write_midx_context *ctx, uint32_t i; for (i = 0; i < m->num_packs; i++) { - ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc); - - /* - * If generating a reverse index, need to have - * packed_git's loaded to compare their - * mtimes and object count. - * - * If a preferred pack is specified, need to - * have packed_git's loaded to ensure the chosen - * preferred pack has a non-zero object count. - */ - if (flags & MIDX_WRITE_REV_INDEX || - preferred_pack_name) { - if (prepare_midx_pack(ctx->repo, m, - m->num_packs_in_base + i)) { - error(_("could not load pack")); - return 1; - } - - if (open_pack_index(m->packs[i])) - die(_("could not open index for %s"), - m->packs[i]->pack_name); - } + if (prepare_midx_pack(m, m->num_packs_in_base + i)) + return error(_("could not load pack")); + ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc); fill_pack_info(&ctx->info[ctx->nr++], m->packs[i], m->pack_names[i], m->num_packs_in_base + i); @@ -989,10 +958,9 @@ static int link_midx_to_chain(struct multi_pack_index *m) for (i = 0; i < ARRAY_SIZE(midx_exts); i++) { const unsigned char *hash = get_midx_checksum(m); - get_midx_filename_ext(m->repo->hash_algo, &from, m->object_dir, + get_midx_filename_ext(m->source, &from, hash, midx_exts[i].non_split); - get_split_midx_filename_ext(m->repo->hash_algo, &to, - m->object_dir, hash, + get_split_midx_filename_ext(m->source, &to, hash, midx_exts[i].split); if (link(from.buf, to.buf) < 0 && errno != ENOENT) { @@ -1011,7 +979,7 @@ done: return ret; } -static void clear_midx_files(struct repository *r, const char *object_dir, +static void clear_midx_files(struct odb_source *source, const char **hashes, uint32_t hashes_nr, unsigned incremental) { @@ -1030,16 +998,16 @@ static void clear_midx_files(struct repository *r, const char *object_dir, uint32_t i, j; for (i = 0; i < ARRAY_SIZE(exts); i++) { - clear_incremental_midx_files_ext(object_dir, exts[i], + clear_incremental_midx_files_ext(source, exts[i], hashes, hashes_nr); for (j = 0; j < hashes_nr; j++) - clear_midx_files_ext(object_dir, exts[i], hashes[j]); + clear_midx_files_ext(source, exts[i], hashes[j]); } if (incremental) - get_midx_filename(r->hash_algo, &buf, object_dir); + get_midx_filename(source, &buf); else - get_midx_chain_filename(&buf, object_dir); + get_midx_chain_filename(source, &buf); if (unlink(buf.buf) && errno != ENOENT) die_errno(_("failed to clear multi-pack-index at %s"), buf.buf); @@ -1047,45 +1015,49 @@ static void clear_midx_files(struct repository *r, const char *object_dir, strbuf_release(&buf); } -static int write_midx_internal(struct repository *r, const char *object_dir, +static int write_midx_internal(struct odb_source *source, struct string_list *packs_to_include, struct string_list *packs_to_drop, const char *preferred_pack_name, const char *refs_snapshot, unsigned flags) { + struct repository *r = source->odb->repo; struct strbuf midx_name = STRBUF_INIT; unsigned char midx_hash[GIT_MAX_RAWSZ]; - uint32_t i, start_pack; + uint32_t start_pack; struct hashfile *f = NULL; struct lock_file lk; struct tempfile *incr; - struct write_midx_context ctx = { 0 }; + struct write_midx_context ctx = { + .preferred_pack_idx = NO_PREFERRED_PACK, + }; int bitmapped_packs_concat_len = 0; int pack_name_concat_len = 0; int dropped_packs = 0; - int result = 0; + int result = -1; const char **keep_hashes = NULL; struct chunkfile *cf; trace2_region_enter("midx", "write_midx_internal", r); ctx.repo = r; + ctx.source = source; ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL); if (ctx.incremental) strbuf_addf(&midx_name, "%s/pack/multi-pack-index.d/tmp_midx_XXXXXX", - object_dir); + source->path); else - get_midx_filename(r->hash_algo, &midx_name, object_dir); + get_midx_filename(source, &midx_name); if (safe_create_leading_directories(r, midx_name.buf)) die_errno(_("unable to create leading directories of %s"), midx_name.buf); if (!packs_to_include || ctx.incremental) { - struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir); + struct multi_pack_index *m = get_multi_pack_index(source); if (m && !midx_checksum_valid(m)) { warning(_("ignoring existing multi-pack-index; checksum mismatch")); m = NULL; @@ -1116,15 +1088,13 @@ static int write_midx_internal(struct repository *r, const char *object_dir, if (flags & MIDX_WRITE_BITMAP && load_midx_revindex(m)) { error(_("could not load reverse index for MIDX %s"), hash_to_hex_algop(get_midx_checksum(m), - m->repo->hash_algo)); - result = 1; + m->source->odb->repo->hash_algo)); goto cleanup; } ctx.num_multi_pack_indexes_before++; m = m->base_midx; } - } else if (ctx.m && fill_packs_from_midx(&ctx, preferred_pack_name, - flags) < 0) { + } else if (ctx.m && fill_packs_from_midx(&ctx)) { goto cleanup; } @@ -1139,7 +1109,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, ctx.to_include = packs_to_include; - for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx); + for_each_file_in_pack_dir(source->path, add_pack_to_midx, &ctx); stop_progress(&ctx.progress); if ((ctx.m && ctx.nr == ctx.m->num_packs + ctx.m->num_packs_in_base) && @@ -1159,18 +1129,21 @@ static int write_midx_internal(struct repository *r, const char *object_dir, * corresponding bitmap (or one wasn't requested). */ if (!want_bitmap) - clear_midx_files_ext(object_dir, "bitmap", NULL); + clear_midx_files_ext(source, "bitmap", NULL); + result = 0; goto cleanup; } } - if (ctx.incremental && !ctx.nr) + if (ctx.incremental && !ctx.nr) { + result = 0; goto cleanup; /* nothing to do */ + } if (preferred_pack_name) { - ctx.preferred_pack_idx = -1; + ctx.preferred_pack_idx = NO_PREFERRED_PACK; - for (i = 0; i < ctx.nr; i++) { + for (size_t i = 0; i < ctx.nr; i++) { if (!cmp_idx_or_pack_name(preferred_pack_name, ctx.info[i].pack_name)) { ctx.preferred_pack_idx = i; @@ -1178,14 +1151,21 @@ static int write_midx_internal(struct repository *r, const char *object_dir, } } - if (ctx.preferred_pack_idx == -1) + if (ctx.preferred_pack_idx == NO_PREFERRED_PACK) warning(_("unknown preferred pack: '%s'"), preferred_pack_name); } else if (ctx.nr && (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) { - struct packed_git *oldest = ctx.info[ctx.preferred_pack_idx].p; + struct packed_git *oldest = ctx.info[0].p; ctx.preferred_pack_idx = 0; + /* + * Attempt opening the pack index to populate num_objects. + * Ignore failiures as they can be expected and are not + * fatal during this selection time. + */ + open_pack_index(oldest); + if (packs_to_drop && packs_to_drop->nr) BUG("cannot write a MIDX bitmap during expiration"); @@ -1195,11 +1175,12 @@ static int write_midx_internal(struct repository *r, const char *object_dir, * pack-order has all of its objects selected from that pack * (and not another pack containing a duplicate) */ - for (i = 1; i < ctx.nr; i++) { + for (size_t i = 1; i < ctx.nr; i++) { struct packed_git *p = ctx.info[i].p; if (!oldest->num_objects || p->mtime < oldest->mtime) { oldest = p; + open_pack_index(oldest); ctx.preferred_pack_idx = i; } } @@ -1211,22 +1192,26 @@ static int write_midx_internal(struct repository *r, const char *object_dir, * objects to resolve, so the preferred value doesn't * matter. */ - ctx.preferred_pack_idx = -1; + ctx.preferred_pack_idx = NO_PREFERRED_PACK; } } else { /* * otherwise don't mark any pack as preferred to avoid * interfering with expiration logic below */ - ctx.preferred_pack_idx = -1; + ctx.preferred_pack_idx = NO_PREFERRED_PACK; } - if (ctx.preferred_pack_idx > -1) { + if (ctx.preferred_pack_idx != NO_PREFERRED_PACK) { struct packed_git *preferred = ctx.info[ctx.preferred_pack_idx].p; + + if (open_pack_index(preferred)) + die(_("failed to open preferred pack %s"), + ctx.info[ctx.preferred_pack_idx].pack_name); + if (!preferred->num_objects) { error(_("cannot select preferred pack %s with no objects"), preferred->pack_name); - result = 1; goto cleanup; } } @@ -1234,7 +1219,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, compute_sorted_entries(&ctx, start_pack); ctx.large_offsets_needed = 0; - for (i = 0; i < ctx.entries_nr; i++) { + for (size_t i = 0; i < ctx.entries_nr; i++) { if (ctx.entries[i].offset > 0x7fffffff) ctx.num_large_offsets++; if (ctx.entries[i].offset > 0xffffffff) @@ -1244,10 +1229,10 @@ static int write_midx_internal(struct repository *r, const char *object_dir, QSORT(ctx.info, ctx.nr, pack_info_compare); if (packs_to_drop && packs_to_drop->nr) { - int drop_index = 0; + size_t drop_index = 0; int missing_drops = 0; - for (i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) { + for (size_t i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) { int cmp = strcmp(ctx.info[i].pack_name, packs_to_drop->items[drop_index].string); @@ -1265,10 +1250,8 @@ static int write_midx_internal(struct repository *r, const char *object_dir, } } - if (missing_drops) { - result = 1; + if (missing_drops) goto cleanup; - } } /* @@ -1278,7 +1261,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, * pack_perm[old_id] = new_id */ ALLOC_ARRAY(ctx.pack_perm, ctx.nr); - for (i = 0; i < ctx.nr; i++) { + for (size_t i = 0; i < ctx.nr; i++) { if (ctx.info[i].expired) { dropped_packs++; ctx.pack_perm[ctx.info[i].orig_pack_int_id] = PACK_EXPIRED; @@ -1287,7 +1270,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, } } - for (i = 0; i < ctx.nr; i++) { + for (size_t i = 0; i < ctx.nr; i++) { if (ctx.info[i].expired) continue; pack_name_concat_len += strlen(ctx.info[i].pack_name) + 1; @@ -1314,7 +1297,6 @@ static int write_midx_internal(struct repository *r, const char *object_dir, if (ctx.nr - dropped_packs == 0) { error(_("no pack files to index.")); - result = 1; goto cleanup; } @@ -1327,20 +1309,20 @@ static int write_midx_internal(struct repository *r, const char *object_dir, if (ctx.incremental) { struct strbuf lock_name = STRBUF_INIT; - get_midx_chain_filename(&lock_name, object_dir); + get_midx_chain_filename(source, &lock_name); hold_lock_file_for_update(&lk, lock_name.buf, LOCK_DIE_ON_ERROR); strbuf_release(&lock_name); incr = mks_tempfile_m(midx_name.buf, 0444); if (!incr) { error(_("unable to create temporary MIDX layer")); - return -1; + goto cleanup; } if (adjust_shared_perm(r, get_tempfile_path(incr))) { error(_("unable to adjust shared permissions for '%s'"), get_tempfile_path(incr)); - return -1; + goto cleanup; } f = hashfd(r->hash_algo, get_tempfile_fd(incr), @@ -1390,7 +1372,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, if (flags & MIDX_WRITE_REV_INDEX && git_env_bool("GIT_TEST_MIDX_WRITE_REV", 0)) - write_midx_reverse_index(&ctx, object_dir, midx_hash); + write_midx_reverse_index(&ctx, midx_hash); if (flags & MIDX_WRITE_BITMAP) { struct packing_data pdata; @@ -1413,11 +1395,10 @@ static int write_midx_internal(struct repository *r, const char *object_dir, FREE_AND_NULL(ctx.entries); ctx.entries_nr = 0; - if (write_midx_bitmap(&ctx, object_dir, + if (write_midx_bitmap(&ctx, midx_hash, &pdata, commits, commits_nr, flags) < 0) { error(_("could not write multi-pack bitmap")); - result = 1; clear_packing_data(&pdata); free(commits); goto cleanup; @@ -1431,6 +1412,9 @@ static int write_midx_internal(struct repository *r, const char *object_dir, * have been freed in the previous if block. */ + if (ctx.num_multi_pack_indexes_before == UINT32_MAX) + die(_("too many multi-pack-indexes")); + CALLOC_ARRAY(keep_hashes, ctx.num_multi_pack_indexes_before + 1); if (ctx.incremental) { @@ -1440,18 +1424,18 @@ static int write_midx_internal(struct repository *r, const char *object_dir, if (!chainf) { error_errno(_("unable to open multi-pack-index chain file")); - return -1; + goto cleanup; } if (link_midx_to_chain(ctx.base_midx) < 0) - return -1; + goto cleanup; - get_split_midx_filename_ext(r->hash_algo, &final_midx_name, - object_dir, midx_hash, MIDX_EXT_MIDX); + get_split_midx_filename_ext(source, &final_midx_name, + midx_hash, MIDX_EXT_MIDX); if (rename_tempfile(&incr, final_midx_name.buf) < 0) { error_errno(_("unable to rename new multi-pack-index layer")); - return -1; + goto cleanup; } strbuf_release(&final_midx_name); @@ -1459,7 +1443,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, keep_hashes[ctx.num_multi_pack_indexes_before] = xstrdup(hash_to_hex_algop(midx_hash, r->hash_algo)); - for (i = 0; i < ctx.num_multi_pack_indexes_before; i++) { + for (uint32_t i = 0; i < ctx.num_multi_pack_indexes_before; i++) { uint32_t j = ctx.num_multi_pack_indexes_before - i - 1; keep_hashes[j] = xstrdup(hash_to_hex_algop(get_midx_checksum(m), @@ -1467,7 +1451,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, m = m->base_midx; } - for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++) + for (uint32_t i = 0; i <= ctx.num_multi_pack_indexes_before; i++) fprintf(get_lock_file_fp(&lk), "%s\n", keep_hashes[i]); } else { keep_hashes[ctx.num_multi_pack_indexes_before] = @@ -1480,12 +1464,13 @@ static int write_midx_internal(struct repository *r, const char *object_dir, if (commit_lock_file(&lk) < 0) die_errno(_("could not write multi-pack-index")); - clear_midx_files(r, object_dir, keep_hashes, + clear_midx_files(source, keep_hashes, ctx.num_multi_pack_indexes_before + 1, ctx.incremental); + result = 0; cleanup: - for (i = 0; i < ctx.nr; i++) { + for (size_t i = 0; i < ctx.nr; i++) { if (ctx.info[i].p) { close_pack(ctx.info[i].p); free(ctx.info[i].p); @@ -1498,7 +1483,7 @@ cleanup: free(ctx.pack_perm); free(ctx.pack_order); if (keep_hashes) { - for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++) + for (uint32_t i = 0; i <= ctx.num_multi_pack_indexes_before; i++) free((char *)keep_hashes[i]); free(keep_hashes); } @@ -1509,29 +1494,29 @@ cleanup: return result; } -int write_midx_file(struct repository *r, const char *object_dir, +int write_midx_file(struct odb_source *source, const char *preferred_pack_name, const char *refs_snapshot, unsigned flags) { - return write_midx_internal(r, object_dir, NULL, NULL, + return write_midx_internal(source, NULL, NULL, preferred_pack_name, refs_snapshot, flags); } -int write_midx_file_only(struct repository *r, const char *object_dir, +int write_midx_file_only(struct odb_source *source, struct string_list *packs_to_include, const char *preferred_pack_name, const char *refs_snapshot, unsigned flags) { - return write_midx_internal(r, object_dir, packs_to_include, NULL, + return write_midx_internal(source, packs_to_include, NULL, preferred_pack_name, refs_snapshot, flags); } -int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags) +int expire_midx_packs(struct odb_source *source, unsigned flags) { uint32_t i, *count, result = 0; struct string_list packs_to_drop = STRING_LIST_INIT_DUP; - struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir); + struct multi_pack_index *m = get_multi_pack_index(source); struct progress *progress = NULL; if (!m) @@ -1544,7 +1529,7 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla if (flags & MIDX_PROGRESS) progress = start_delayed_progress( - r, + source->odb->repo, _("Counting referenced objects"), m->num_objects); for (i = 0; i < m->num_objects; i++) { @@ -1556,7 +1541,7 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla if (flags & MIDX_PROGRESS) progress = start_delayed_progress( - r, + source->odb->repo, _("Finding and deleting unreferenced packfiles"), m->num_packs); for (i = 0; i < m->num_packs; i++) { @@ -1566,7 +1551,7 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla if (count[i]) continue; - if (prepare_midx_pack(r, m, i)) + if (prepare_midx_pack(m, i)) continue; if (m->packs[i]->pack_keep || m->packs[i]->is_cruft) @@ -1584,7 +1569,7 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla free(count); if (packs_to_drop.nr) - result = write_midx_internal(r, object_dir, NULL, + result = write_midx_internal(source, NULL, &packs_to_drop, NULL, NULL, flags); string_list_clear(&packs_to_drop, 0); @@ -1612,13 +1597,12 @@ static int compare_by_mtime(const void *a_, const void *b_) return 0; } -static int want_included_pack(struct repository *r, - struct multi_pack_index *m, +static int want_included_pack(struct multi_pack_index *m, int pack_kept_objects, uint32_t pack_int_id) { struct packed_git *p; - if (prepare_midx_pack(r, m, pack_int_id)) + if (prepare_midx_pack(m, pack_int_id)) return 0; p = m->packs[pack_int_id]; if (!pack_kept_objects && p->pack_keep) @@ -1640,7 +1624,7 @@ static void fill_included_packs_all(struct repository *r, repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects); for (i = 0; i < m->num_packs; i++) { - if (!want_included_pack(r, m, pack_kept_objects, i)) + if (!want_included_pack(m, pack_kept_objects, i)) continue; include_pack[i] = 1; @@ -1664,7 +1648,7 @@ static void fill_included_packs_batch(struct repository *r, for (i = 0; i < m->num_packs; i++) { pack_info[i].pack_int_id = i; - if (prepare_midx_pack(r, m, i)) + if (prepare_midx_pack(m, i)) continue; pack_info[i].mtime = m->packs[i]->mtime; @@ -1683,7 +1667,7 @@ static void fill_included_packs_batch(struct repository *r, struct packed_git *p = m->packs[pack_int_id]; uint64_t expected_size; - if (!want_included_pack(r, m, pack_kept_objects, pack_int_id)) + if (!want_included_pack(m, pack_kept_objects, pack_int_id)) continue; /* @@ -1710,14 +1694,15 @@ static void fill_included_packs_batch(struct repository *r, free(pack_info); } -int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, unsigned flags) +int midx_repack(struct odb_source *source, size_t batch_size, unsigned flags) { + struct repository *r = source->odb->repo; int result = 0; uint32_t i, packs_to_repack = 0; unsigned char *include_pack; struct child_process cmd = CHILD_PROCESS_INIT; FILE *cmd_in; - struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir); + struct multi_pack_index *m = get_multi_pack_index(source); /* * When updating the default for these configuration @@ -1751,7 +1736,7 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, strvec_push(&cmd.args, "pack-objects"); - strvec_pushf(&cmd.args, "%s/pack/pack", object_dir); + strvec_pushf(&cmd.args, "%s/pack/pack", source->path); if (delta_base_offset) strvec_push(&cmd.args, "--delta-base-offset"); @@ -1792,7 +1777,7 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, goto cleanup; } - result = write_midx_internal(r, object_dir, NULL, NULL, NULL, NULL, + result = write_midx_internal(source, NULL, NULL, NULL, NULL, flags); cleanup: @@ -16,9 +16,9 @@ #define MIDX_PACK_ERROR ((void *)(intptr_t)-1) int midx_checksum_valid(struct multi_pack_index *m); -void clear_midx_files_ext(const char *object_dir, const char *ext, +void clear_midx_files_ext(struct odb_source *source, const char *ext, const char *keep_hash); -void clear_incremental_midx_files_ext(const char *object_dir, const char *ext, +void clear_incremental_midx_files_ext(struct odb_source *source, const char *ext, char **keep_hashes, uint32_t hashes_nr); int cmp_idx_or_pack_name(const char *idx_or_pack_name, @@ -26,22 +26,20 @@ int cmp_idx_or_pack_name(const char *idx_or_pack_name, const unsigned char *get_midx_checksum(struct multi_pack_index *m) { - return m->data + m->data_len - m->repo->hash_algo->rawsz; + return m->data + m->data_len - m->source->odb->repo->hash_algo->rawsz; } -void get_midx_filename(const struct git_hash_algo *hash_algo, - struct strbuf *out, const char *object_dir) +void get_midx_filename(struct odb_source *source, struct strbuf *out) { - get_midx_filename_ext(hash_algo, out, object_dir, NULL, NULL); + get_midx_filename_ext(source, out, NULL, NULL); } -void get_midx_filename_ext(const struct git_hash_algo *hash_algo, - struct strbuf *out, const char *object_dir, +void get_midx_filename_ext(struct odb_source *source, struct strbuf *out, const unsigned char *hash, const char *ext) { - strbuf_addf(out, "%s/pack/multi-pack-index", object_dir); + strbuf_addf(out, "%s/pack/multi-pack-index", source->path); if (ext) - strbuf_addf(out, "-%s.%s", hash_to_hex_algop(hash, hash_algo), ext); + strbuf_addf(out, "-%s.%s", hash_to_hex_algop(hash, source->odb->repo->hash_algo), ext); } static int midx_read_oid_fanout(const unsigned char *chunk_start, @@ -95,11 +93,10 @@ static int midx_read_object_offsets(const unsigned char *chunk_start, return 0; } -static struct multi_pack_index *load_multi_pack_index_one(struct repository *r, - const char *object_dir, - const char *midx_name, - int local) +static struct multi_pack_index *load_multi_pack_index_one(struct odb_source *source, + const char *midx_name) { + struct repository *r = source->odb->repo; struct multi_pack_index *m = NULL; int fd; struct stat st; @@ -129,11 +126,10 @@ static struct multi_pack_index *load_multi_pack_index_one(struct repository *r, midx_map = xmmap(NULL, midx_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - FLEX_ALLOC_STR(m, object_dir, object_dir); + CALLOC_ARRAY(m, 1); m->data = midx_map; m->data_len = midx_size; - m->local = local; - m->repo = r; + m->source = source; m->signature = get_be32(m->data); if (m->signature != MIDX_SIGNATURE) @@ -224,24 +220,23 @@ cleanup_fail: return NULL; } -void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir) +void get_midx_chain_dirname(struct odb_source *source, struct strbuf *buf) { - strbuf_addf(buf, "%s/pack/multi-pack-index.d", object_dir); + strbuf_addf(buf, "%s/pack/multi-pack-index.d", source->path); } -void get_midx_chain_filename(struct strbuf *buf, const char *object_dir) +void get_midx_chain_filename(struct odb_source *source, struct strbuf *buf) { - get_midx_chain_dirname(buf, object_dir); + get_midx_chain_dirname(source, buf); strbuf_addstr(buf, "/multi-pack-index-chain"); } -void get_split_midx_filename_ext(const struct git_hash_algo *hash_algo, - struct strbuf *buf, const char *object_dir, +void get_split_midx_filename_ext(struct odb_source *source, struct strbuf *buf, const unsigned char *hash, const char *ext) { - get_midx_chain_dirname(buf, object_dir); + get_midx_chain_dirname(source, buf); strbuf_addf(buf, "/multi-pack-index-%s.%s", - hash_to_hex_algop(hash, hash_algo), ext); + hash_to_hex_algop(hash, source->odb->repo->hash_algo), ext); } static int open_multi_pack_index_chain(const struct git_hash_algo *hash_algo, @@ -297,19 +292,18 @@ static int add_midx_to_chain(struct multi_pack_index *midx, return 1; } -static struct multi_pack_index *load_midx_chain_fd_st(struct repository *r, - const char *object_dir, - int local, +static struct multi_pack_index *load_midx_chain_fd_st(struct odb_source *source, int fd, struct stat *st, int *incomplete_chain) { + const struct git_hash_algo *hash_algo = source->odb->repo->hash_algo; struct multi_pack_index *midx_chain = NULL; struct strbuf buf = STRBUF_INIT; int valid = 1; uint32_t i, count; FILE *fp = xfdopen(fd, "r"); - count = st->st_size / (r->hash_algo->hexsz + 1); + count = st->st_size / (hash_algo->hexsz + 1); for (i = 0; i < count; i++) { struct multi_pack_index *m; @@ -318,7 +312,7 @@ static struct multi_pack_index *load_midx_chain_fd_st(struct repository *r, if (strbuf_getline_lf(&buf, fp) == EOF) break; - if (get_oid_hex_algop(buf.buf, &layer, r->hash_algo)) { + if (get_oid_hex_algop(buf.buf, &layer, hash_algo)) { warning(_("invalid multi-pack-index chain: line '%s' " "not a hash"), buf.buf); @@ -329,9 +323,9 @@ static struct multi_pack_index *load_midx_chain_fd_st(struct repository *r, valid = 0; strbuf_reset(&buf); - get_split_midx_filename_ext(r->hash_algo, &buf, object_dir, + get_split_midx_filename_ext(source, &buf, layer.hash, MIDX_EXT_MIDX); - m = load_multi_pack_index_one(r, object_dir, buf.buf, local); + m = load_multi_pack_index_one(source, buf.buf); if (m) { if (add_midx_to_chain(m, midx_chain)) { @@ -354,40 +348,34 @@ static struct multi_pack_index *load_midx_chain_fd_st(struct repository *r, return midx_chain; } -static struct multi_pack_index *load_multi_pack_index_chain(struct repository *r, - const char *object_dir, - int local) +static struct multi_pack_index *load_multi_pack_index_chain(struct odb_source *source) { struct strbuf chain_file = STRBUF_INIT; struct stat st; int fd; struct multi_pack_index *m = NULL; - get_midx_chain_filename(&chain_file, object_dir); - if (open_multi_pack_index_chain(r->hash_algo, chain_file.buf, &fd, &st)) { + get_midx_chain_filename(source, &chain_file); + if (open_multi_pack_index_chain(source->odb->repo->hash_algo, chain_file.buf, &fd, &st)) { int incomplete; /* ownership of fd is taken over by load function */ - m = load_midx_chain_fd_st(r, object_dir, local, fd, &st, - &incomplete); + m = load_midx_chain_fd_st(source, fd, &st, &incomplete); } strbuf_release(&chain_file); return m; } -struct multi_pack_index *load_multi_pack_index(struct repository *r, - const char *object_dir, - int local) +struct multi_pack_index *load_multi_pack_index(struct odb_source *source) { struct strbuf midx_name = STRBUF_INIT; struct multi_pack_index *m; - get_midx_filename(r->hash_algo, &midx_name, object_dir); + get_midx_filename(source, &midx_name); - m = load_multi_pack_index_one(r, object_dir, - midx_name.buf, local); + m = load_multi_pack_index_one(source, midx_name.buf); if (!m) - m = load_multi_pack_index_chain(r, object_dir, local); + m = load_multi_pack_index_chain(source); strbuf_release(&midx_name); @@ -450,9 +438,10 @@ static uint32_t midx_for_pack(struct multi_pack_index **_m, return pack_int_id - m->num_packs_in_base; } -int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, +int prepare_midx_pack(struct multi_pack_index *m, uint32_t pack_int_id) { + struct repository *r = m->source->odb->repo; struct strbuf pack_name = STRBUF_INIT; struct strbuf key = STRBUF_INIT; struct packed_git *p; @@ -464,7 +453,7 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, if (m->packs[pack_int_id]) return 0; - strbuf_addf(&pack_name, "%s/pack/%s", m->object_dir, + strbuf_addf(&pack_name, "%s/pack/%s", m->source->path, m->pack_names[pack_int_id]); /* pack_map holds the ".pack" name, but we have the .idx */ @@ -475,7 +464,8 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, strhash(key.buf), key.buf, struct packed_git, packmap_ent); if (!p) { - p = add_packed_git(r, pack_name.buf, pack_name.len, m->local); + p = add_packed_git(r, pack_name.buf, pack_name.len, + m->source->local); if (p) { install_packed_git(r, p); list_add_tail(&p->mru, &r->objects->packed_git_mru); @@ -507,7 +497,7 @@ struct packed_git *nth_midxed_pack(struct multi_pack_index *m, #define MIDX_CHUNK_BITMAPPED_PACKS_WIDTH (2 * sizeof(uint32_t)) -int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m, +int nth_bitmapped_pack(struct multi_pack_index *m, struct bitmapped_pack *bp, uint32_t pack_int_id) { uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id); @@ -515,7 +505,7 @@ int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m, if (!m->chunk_bitmapped_packs) return error(_("MIDX does not contain the BTMP chunk")); - if (prepare_midx_pack(r, m, pack_int_id)) + if (prepare_midx_pack(m, pack_int_id)) return error(_("could not load bitmapped pack %"PRIu32), pack_int_id); bp->p = m->packs[local_pack_int_id]; @@ -534,7 +524,8 @@ int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result) { int ret = bsearch_hash(oid->hash, m->chunk_oid_fanout, - m->chunk_oid_lookup, m->repo->hash_algo->rawsz, + m->chunk_oid_lookup, + m->source->odb->repo->hash_algo->rawsz, result); if (result) *result += m->num_objects_in_base; @@ -565,7 +556,7 @@ struct object_id *nth_midxed_object_oid(struct object_id *oid, n = midx_for_object(&m, n); oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n), - m->repo->hash_algo); + m->source->odb->repo->hash_algo); return oid; } @@ -600,10 +591,9 @@ uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos) (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH); } -int fill_midx_entry(struct repository *r, +int fill_midx_entry(struct multi_pack_index *m, const struct object_id *oid, - struct pack_entry *e, - struct multi_pack_index *m) + struct pack_entry *e) { uint32_t pos; uint32_t pack_int_id; @@ -615,7 +605,7 @@ int fill_midx_entry(struct repository *r, midx_for_object(&m, pos); pack_int_id = nth_midxed_pack_int_id(m, pos); - if (prepare_midx_pack(r, m, pack_int_id)) + if (prepare_midx_pack(m, pack_int_id)) return 0; p = m->packs[pack_int_id - m->num_packs_in_base]; @@ -723,7 +713,7 @@ int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id) return 0; } -int prepare_multi_pack_index_one(struct odb_source *source, int local) +int prepare_multi_pack_index_one(struct odb_source *source) { struct repository *r = source->odb->repo; @@ -734,14 +724,14 @@ int prepare_multi_pack_index_one(struct odb_source *source, int local) if (source->midx) return 1; - source->midx = load_multi_pack_index(r, source->path, local); + source->midx = load_multi_pack_index(source); return !!source->midx; } int midx_checksum_valid(struct multi_pack_index *m) { - return hashfile_checksum_valid(m->repo->hash_algo, + return hashfile_checksum_valid(m->source->odb->repo->hash_algo, m->data, m->data_len); } @@ -768,7 +758,7 @@ static void clear_midx_file_ext(const char *full_path, size_t full_path_len UNUS die_errno(_("failed to remove %s"), full_path); } -void clear_midx_files_ext(const char *object_dir, const char *ext, +void clear_midx_files_ext(struct odb_source *source, const char *ext, const char *keep_hash) { struct clear_midx_data data; @@ -782,7 +772,7 @@ void clear_midx_files_ext(const char *object_dir, const char *ext, } data.ext = ext; - for_each_file_in_pack_dir(object_dir, + for_each_file_in_pack_dir(source->path, clear_midx_file_ext, &data); @@ -791,7 +781,7 @@ void clear_midx_files_ext(const char *object_dir, const char *ext, free(data.keep); } -void clear_incremental_midx_files_ext(const char *object_dir, const char *ext, +void clear_incremental_midx_files_ext(struct odb_source *source, const char *ext, char **keep_hashes, uint32_t hashes_nr) { @@ -807,7 +797,7 @@ void clear_incremental_midx_files_ext(const char *object_dir, const char *ext, data.keep_nr = hashes_nr; data.ext = ext; - for_each_file_in_pack_subdir(object_dir, "multi-pack-index.d", + for_each_file_in_pack_subdir(source->path, "multi-pack-index.d", clear_midx_file_ext, &data); for (i = 0; i < hashes_nr; i++) @@ -819,7 +809,7 @@ void clear_midx_file(struct repository *r) { struct strbuf midx = STRBUF_INIT; - get_midx_filename(r->hash_algo, &midx, r->objects->sources->path); + get_midx_filename(r->objects->sources, &midx); if (r->objects) { struct odb_source *source; @@ -834,8 +824,8 @@ void clear_midx_file(struct repository *r) if (remove_path(midx.buf)) die(_("failed to clear multi-pack-index at %s"), midx.buf); - clear_midx_files_ext(r->objects->sources->path, MIDX_EXT_BITMAP, NULL); - clear_midx_files_ext(r->objects->sources->path, MIDX_EXT_REV, NULL); + clear_midx_files_ext(r->objects->sources, MIDX_EXT_BITMAP, NULL); + clear_midx_files_ext(r->objects->sources, MIDX_EXT_REV, NULL); strbuf_release(&midx); } @@ -879,12 +869,13 @@ static int compare_pair_pos_vs_id(const void *_a, const void *_b) display_progress(progress, _n); \ } while (0) -int verify_midx_file(struct repository *r, const char *object_dir, unsigned flags) +int verify_midx_file(struct odb_source *source, unsigned flags) { + struct repository *r = source->odb->repo; struct pair_pos_vs_id *pairs = NULL; uint32_t i; struct progress *progress = NULL; - struct multi_pack_index *m = load_multi_pack_index(r, object_dir, 1); + struct multi_pack_index *m = load_multi_pack_index(source); struct multi_pack_index *curr; verify_midx_error = 0; @@ -893,7 +884,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag struct stat sb; struct strbuf filename = STRBUF_INIT; - get_midx_filename(r->hash_algo, &filename, object_dir); + get_midx_filename(source, &filename); if (!stat(filename.buf, &sb)) { error(_("multi-pack-index file exists, but failed to parse")); @@ -911,7 +902,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag _("Looking for referenced packfiles"), m->num_packs + m->num_packs_in_base); for (i = 0; i < m->num_packs + m->num_packs_in_base; i++) { - if (prepare_midx_pack(r, m, i)) + if (prepare_midx_pack(m, i)) midx_report("failed to load pack in position %d", i); display_progress(progress, i + 1); @@ -988,7 +979,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag nth_midxed_object_oid(&oid, m, pairs[i].pos); - if (!fill_midx_entry(r, &oid, &e, m)) { + if (!fill_midx_entry(m, &oid, &e)) { midx_report(_("failed to load pack entry for oid[%d] = %s"), pairs[i].pos, oid_to_hex(&oid)); continue; @@ -35,6 +35,8 @@ struct odb_source; "GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL" struct multi_pack_index { + struct odb_source *source; + const unsigned char *data; size_t data_len; @@ -50,7 +52,6 @@ struct multi_pack_index { uint32_t num_objects; int preferred_pack_idx; - int local; int has_chain; const unsigned char *chunk_pack_names; @@ -71,10 +72,6 @@ struct multi_pack_index { const char **pack_names; struct packed_git **packs; - - struct repository *repo; - - char object_dir[FLEX_ARRAY]; }; #define MIDX_PROGRESS (1 << 0) @@ -89,24 +86,19 @@ struct multi_pack_index { #define MIDX_EXT_MIDX "midx" const unsigned char *get_midx_checksum(struct multi_pack_index *m); -void get_midx_filename(const struct git_hash_algo *hash_algo, - struct strbuf *out, const char *object_dir); -void get_midx_filename_ext(const struct git_hash_algo *hash_algo, - struct strbuf *out, const char *object_dir, +void get_midx_filename(struct odb_source *source, struct strbuf *out); +void get_midx_filename_ext(struct odb_source *source, struct strbuf *out, const unsigned char *hash, const char *ext); -void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir); -void get_midx_chain_filename(struct strbuf *buf, const char *object_dir); -void get_split_midx_filename_ext(const struct git_hash_algo *hash_algo, - struct strbuf *buf, const char *object_dir, +void get_midx_chain_dirname(struct odb_source *source, struct strbuf *out); +void get_midx_chain_filename(struct odb_source *source, struct strbuf *out); +void get_split_midx_filename_ext(struct odb_source *source, struct strbuf *buf, const unsigned char *hash, const char *ext); -struct multi_pack_index *load_multi_pack_index(struct repository *r, - const char *object_dir, - int local); -int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id); +struct multi_pack_index *load_multi_pack_index(struct odb_source *source); +int prepare_midx_pack(struct multi_pack_index *m, uint32_t pack_int_id); struct packed_git *nth_midxed_pack(struct multi_pack_index *m, uint32_t pack_int_id); -int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m, +int nth_bitmapped_pack(struct multi_pack_index *m, struct bitmapped_pack *bp, uint32_t pack_int_id); int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result); @@ -118,27 +110,27 @@ uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos); struct object_id *nth_midxed_object_oid(struct object_id *oid, struct multi_pack_index *m, uint32_t n); -int fill_midx_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e, struct multi_pack_index *m); +int fill_midx_entry(struct multi_pack_index *m, const struct object_id *oid, struct pack_entry *e); int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name); int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id); -int prepare_multi_pack_index_one(struct odb_source *source, int local); +int prepare_multi_pack_index_one(struct odb_source *source); /* * Variant of write_midx_file which writes a MIDX containing only the packs * specified in packs_to_include. */ -int write_midx_file(struct repository *r, const char *object_dir, +int write_midx_file(struct odb_source *source, const char *preferred_pack_name, const char *refs_snapshot, unsigned flags); -int write_midx_file_only(struct repository *r, const char *object_dir, +int write_midx_file_only(struct odb_source *source, struct string_list *packs_to_include, const char *preferred_pack_name, const char *refs_snapshot, unsigned flags); void clear_midx_file(struct repository *r); -int verify_midx_file(struct repository *r, const char *object_dir, unsigned flags); -int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags); -int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, unsigned flags); +int verify_midx_file(struct odb_source *source, unsigned flags); +int expire_midx_packs(struct odb_source *source, unsigned flags); +int midx_repack(struct odb_source *source, size_t batch_size, unsigned flags); void close_midx(struct multi_pack_index *m); diff --git a/object-name.c b/object-name.c index 732056ff5e..7774991d28 100644 --- a/object-name.c +++ b/object-name.c @@ -696,15 +696,14 @@ static inline char get_hex_char_from_oid(const struct object_id *oid, return hex[oid->hash[pos >> 1] & 0xf]; } -static int extend_abbrev_len(const struct object_id *oid, void *cb_data) +static int extend_abbrev_len(const struct object_id *oid, + struct min_abbrev_data *mad) { - struct min_abbrev_data *mad = cb_data; - unsigned int i = mad->init_len; while (mad->hex[i] && mad->hex[i] == get_hex_char_from_oid(oid, i)) i++; - if (i < GIT_MAX_RAWSZ && i >= mad->cur_len) + if (mad->hex[i] && i >= mad->cur_len) mad->cur_len = i + 1; return 0; @@ -1858,55 +1857,35 @@ int repo_get_oid_committish(struct repository *r, const char *name, struct object_id *oid) { - struct object_context unused; - int ret = get_oid_with_context(r, name, GET_OID_COMMITTISH, - oid, &unused); - object_context_release(&unused); - return ret; + return repo_get_oid_with_flags(r, name, oid, GET_OID_COMMITTISH); } int repo_get_oid_treeish(struct repository *r, const char *name, struct object_id *oid) { - struct object_context unused; - int ret = get_oid_with_context(r, name, GET_OID_TREEISH, - oid, &unused); - object_context_release(&unused); - return ret; + return repo_get_oid_with_flags(r, name, oid, GET_OID_TREEISH); } int repo_get_oid_commit(struct repository *r, const char *name, struct object_id *oid) { - struct object_context unused; - int ret = get_oid_with_context(r, name, GET_OID_COMMIT, - oid, &unused); - object_context_release(&unused); - return ret; + return repo_get_oid_with_flags(r, name, oid, GET_OID_COMMIT); } int repo_get_oid_tree(struct repository *r, const char *name, struct object_id *oid) { - struct object_context unused; - int ret = get_oid_with_context(r, name, GET_OID_TREE, - oid, &unused); - object_context_release(&unused); - return ret; + return repo_get_oid_with_flags(r, name, oid, GET_OID_TREE); } int repo_get_oid_blob(struct repository *r, const char *name, struct object_id *oid) { - struct object_context unused; - int ret = get_oid_with_context(r, name, GET_OID_BLOB, - oid, &unused); - object_context_release(&unused); - return ret; + return repo_get_oid_with_flags(r, name, oid, GET_OID_BLOB); } /* Must be called only when object_name:filename doesn't exist. */ @@ -517,12 +517,11 @@ struct parsed_object_pool *parsed_object_pool_new(struct repository *repo) memset(o, 0, sizeof(*o)); o->repo = repo; - o->blob_state = allocate_alloc_state(); - o->tree_state = allocate_alloc_state(); - o->commit_state = allocate_alloc_state(); - o->tag_state = allocate_alloc_state(); - o->object_state = allocate_alloc_state(); - + o->blob_state = alloc_state_alloc(); + o->tree_state = alloc_state_alloc(); + o->commit_state = alloc_state_alloc(); + o->tag_state = alloc_state_alloc(); + o->object_state = alloc_state_alloc(); o->is_shallow = -1; CALLOC_ARRAY(o->shallow_stat, 1); @@ -573,16 +572,11 @@ void parsed_object_pool_clear(struct parsed_object_pool *o) o->buffer_slab = NULL; parsed_object_pool_reset_commit_grafts(o); - clear_alloc_state(o->blob_state); - clear_alloc_state(o->tree_state); - clear_alloc_state(o->commit_state); - clear_alloc_state(o->tag_state); - clear_alloc_state(o->object_state); + alloc_state_free_and_null(&o->blob_state); + alloc_state_free_and_null(&o->tree_state); + alloc_state_free_and_null(&o->commit_state); + alloc_state_free_and_null(&o->tag_state); + alloc_state_free_and_null(&o->object_state); stat_validity_clear(o->shallow_stat); - FREE_AND_NULL(o->blob_state); - FREE_AND_NULL(o->tree_state); - FREE_AND_NULL(o->commit_state); - FREE_AND_NULL(o->tag_state); - FREE_AND_NULL(o->object_state); FREE_AND_NULL(o->shallow_stat); } @@ -139,23 +139,21 @@ static void read_info_alternates(struct object_database *odb, const char *relative_base, int depth); -static int link_alt_odb_entry(struct object_database *odb, - const struct strbuf *entry, - const char *relative_base, - int depth, - const char *normalized_objdir) +static struct odb_source *link_alt_odb_entry(struct object_database *odb, + const char *dir, + const char *relative_base, + int depth) { - struct odb_source *alternate; + struct odb_source *alternate = NULL; struct strbuf pathbuf = STRBUF_INIT; struct strbuf tmp = STRBUF_INIT; khiter_t pos; - int ret = -1; - if (!is_absolute_path(entry->buf) && relative_base) { + if (!is_absolute_path(dir) && relative_base) { strbuf_realpath(&pathbuf, relative_base, 1); strbuf_addch(&pathbuf, '/'); } - strbuf_addbuf(&pathbuf, entry); + strbuf_addstr(&pathbuf, dir); if (!strbuf_realpath(&tmp, pathbuf.buf, 0)) { error(_("unable to normalize alternate object path: %s"), @@ -171,11 +169,15 @@ static int link_alt_odb_entry(struct object_database *odb, while (pathbuf.len && pathbuf.buf[pathbuf.len - 1] == '/') strbuf_setlen(&pathbuf, pathbuf.len - 1); - if (!alt_odb_usable(odb, &pathbuf, normalized_objdir, &pos)) + strbuf_reset(&tmp); + strbuf_realpath(&tmp, odb->sources->path, 1); + + if (!alt_odb_usable(odb, &pathbuf, tmp.buf, &pos)) goto error; CALLOC_ARRAY(alternate, 1); alternate->odb = odb; + alternate->local = false; /* pathbuf.buf is already in r->objects->source_by_path */ alternate->path = strbuf_detach(&pathbuf, NULL); @@ -188,11 +190,11 @@ static int link_alt_odb_entry(struct object_database *odb, /* recursively add alternates */ read_info_alternates(odb, alternate->path, depth + 1); - ret = 0; + error: strbuf_release(&tmp); strbuf_release(&pathbuf); - return ret; + return alternate; } static const char *parse_alt_odb_entry(const char *string, @@ -227,8 +229,7 @@ static const char *parse_alt_odb_entry(const char *string, static void link_alt_odb_entries(struct object_database *odb, const char *alt, int sep, const char *relative_base, int depth) { - struct strbuf objdirbuf = STRBUF_INIT; - struct strbuf entry = STRBUF_INIT; + struct strbuf dir = STRBUF_INIT; if (!alt || !*alt) return; @@ -239,17 +240,13 @@ static void link_alt_odb_entries(struct object_database *odb, const char *alt, return; } - strbuf_realpath(&objdirbuf, odb->sources->path, 1); - while (*alt) { - alt = parse_alt_odb_entry(alt, sep, &entry); - if (!entry.len) + alt = parse_alt_odb_entry(alt, sep, &dir); + if (!dir.len) continue; - link_alt_odb_entry(odb, &entry, - relative_base, depth, objdirbuf.buf); + link_alt_odb_entry(odb, dir.buf, relative_base, depth); } - strbuf_release(&entry); - strbuf_release(&objdirbuf); + strbuf_release(&dir); } static void read_info_alternates(struct object_database *odb, @@ -272,7 +269,7 @@ static void read_info_alternates(struct object_database *odb, } void odb_add_to_alternates_file(struct object_database *odb, - const char *reference) + const char *dir) { struct lock_file lock = LOCK_INIT; char *alts = repo_git_path(odb->repo, "objects/info/alternates"); @@ -289,7 +286,7 @@ void odb_add_to_alternates_file(struct object_database *odb, struct strbuf line = STRBUF_INIT; while (strbuf_getline(&line, in) != EOF) { - if (!strcmp(reference, line.buf)) { + if (!strcmp(dir, line.buf)) { found = 1; break; } @@ -305,27 +302,24 @@ void odb_add_to_alternates_file(struct object_database *odb, if (found) { rollback_lock_file(&lock); } else { - fprintf_or_die(out, "%s\n", reference); + fprintf_or_die(out, "%s\n", dir); if (commit_lock_file(&lock)) die_errno(_("unable to move new alternates file into place")); if (odb->loaded_alternates) - link_alt_odb_entries(odb, reference, - '\n', NULL, 0); + link_alt_odb_entries(odb, dir, '\n', NULL, 0); } free(alts); } -void odb_add_to_alternates_memory(struct object_database *odb, - const char *reference) +struct odb_source *odb_add_to_alternates_memory(struct object_database *odb, + const char *dir) { /* * Make sure alternates are initialized, or else our entry may be * overwritten when they are. */ odb_prepare_alternates(odb); - - link_alt_odb_entries(odb, reference, - '\n', NULL, 0); + return link_alt_odb_entry(odb, dir, NULL, 0); } struct odb_source *odb_set_temporary_primary_source(struct object_database *odb, @@ -463,6 +457,12 @@ struct odb_source *odb_find_source(struct object_database *odb, const char *obj_ free(obj_dir_real); strbuf_release(&odb_path_real); + return source; +} + +struct odb_source *odb_find_source_or_die(struct object_database *odb, const char *obj_dir) +{ + struct odb_source *source = odb_find_source(odb, obj_dir); if (!source) die(_("could not find object directory matching %s"), obj_dir); return source; @@ -64,6 +64,14 @@ struct odb_source { struct multi_pack_index *midx; /* + * Figure out whether this is the local source of the owning + * repository, which would typically be its ".git/objects" directory. + * This local object directory is usually where objects would be + * written to. + */ + bool local; + + /* * This is a temporary object store created by the tmp_objdir * facility. Disable ref updates since the objects in the store * might be discarded on rollback. @@ -199,11 +207,14 @@ struct odb_transaction *odb_transaction_begin(struct object_database *odb); void odb_transaction_commit(struct odb_transaction *transaction); /* - * Find source by its object directory path. Dies in case the source couldn't - * be found. + * Find source by its object directory path. Returns a `NULL` pointer in case + * the source could not be found. */ struct odb_source *odb_find_source(struct object_database *odb, const char *obj_dir); +/* Same as `odb_find_source()`, but dies in case the source doesn't exist. */ +struct odb_source *odb_find_source_or_die(struct object_database *odb, const char *obj_dir); + /* * Replace the current writable object directory with the specified temporary * object directory; returns the former primary source. @@ -278,8 +289,8 @@ void odb_add_to_alternates_file(struct object_database *odb, * recursive alternates it points to), but do not modify the on-disk alternates * file. */ -void odb_add_to_alternates_memory(struct object_database *odb, - const char *dir); +struct odb_source *odb_add_to_alternates_memory(struct object_database *odb, + const char *dir); /* * Read an object from the database. Returns the object data and assigns object diff --git a/pack-bitmap.c b/pack-bitmap.c index d14421ee20..058bdb5d7d 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -216,7 +216,7 @@ static uint32_t bitmap_num_objects(struct bitmap_index *index) static struct repository *bitmap_repo(struct bitmap_index *bitmap_git) { if (bitmap_is_midx(bitmap_git)) - return bitmap_git->midx->repo; + return bitmap_git->midx->source->odb->repo; return bitmap_git->pack->repo; } @@ -418,13 +418,12 @@ char *midx_bitmap_filename(struct multi_pack_index *midx) { struct strbuf buf = STRBUF_INIT; if (midx->has_chain) - get_split_midx_filename_ext(midx->repo->hash_algo, &buf, - midx->object_dir, + get_split_midx_filename_ext(midx->source, &buf, get_midx_checksum(midx), MIDX_EXT_BITMAP); else - get_midx_filename_ext(midx->repo->hash_algo, &buf, - midx->object_dir, get_midx_checksum(midx), + get_midx_filename_ext(midx->source, &buf, + get_midx_checksum(midx), MIDX_EXT_BITMAP); return strbuf_detach(&buf, NULL); @@ -463,7 +462,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, if (bitmap_git->pack || bitmap_git->midx) { struct strbuf buf = STRBUF_INIT; - get_midx_filename(midx->repo->hash_algo, &buf, midx->object_dir); + get_midx_filename(midx->source, &buf); trace2_data_string("bitmap", bitmap_repo(bitmap_git), "ignoring extra midx bitmap file", buf.buf); close(fd); @@ -493,7 +492,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, } for (i = 0; i < bitmap_git->midx->num_packs + bitmap_git->midx->num_packs_in_base; i++) { - if (prepare_midx_pack(bitmap_repo(bitmap_git), bitmap_git->midx, i)) { + if (prepare_midx_pack(bitmap_git->midx, i)) { warning(_("could not open pack %s"), bitmap_git->midx->pack_names[i]); goto cleanup; @@ -2466,7 +2465,7 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, struct multi_pack_index *m = bitmap_git->midx; for (i = 0; i < m->num_packs + m->num_packs_in_base; i++) { struct bitmapped_pack pack; - if (nth_bitmapped_pack(r, bitmap_git->midx, &pack, i) < 0) { + if (nth_bitmapped_pack(bitmap_git->midx, &pack, i) < 0) { warning(_("unable to load pack: '%s', disabling pack-reuse"), bitmap_git->midx->pack_names[i]); free(packs); diff --git a/pack-revindex.c b/pack-revindex.c index 0cc422a1e6..d0791cc493 100644 --- a/pack-revindex.c +++ b/pack-revindex.c @@ -379,25 +379,25 @@ int load_midx_revindex(struct multi_pack_index *m) * not want to accidentally call munmap() in the middle of the * MIDX. */ - trace2_data_string("load_midx_revindex", m->repo, + trace2_data_string("load_midx_revindex", m->source->odb->repo, "source", "midx"); m->revindex_data = (const uint32_t *)m->chunk_revindex; return 0; } - trace2_data_string("load_midx_revindex", m->repo, + trace2_data_string("load_midx_revindex", m->source->odb->repo, "source", "rev"); if (m->has_chain) - get_split_midx_filename_ext(m->repo->hash_algo, &revindex_name, - m->object_dir, get_midx_checksum(m), + get_split_midx_filename_ext(m->source, &revindex_name, + get_midx_checksum(m), MIDX_EXT_REV); else - get_midx_filename_ext(m->repo->hash_algo, &revindex_name, - m->object_dir, get_midx_checksum(m), + get_midx_filename_ext(m->source, &revindex_name, + get_midx_checksum(m), MIDX_EXT_REV); - ret = load_revindex_from_disk(m->repo->hash_algo, + ret = load_revindex_from_disk(m->source->odb->repo->hash_algo, revindex_name.buf, m->num_objects, &m->revindex_map, diff --git a/packfile.c b/packfile.c index 5d73932f50..acb680966d 100644 --- a/packfile.c +++ b/packfile.c @@ -935,14 +935,14 @@ static void prepare_pack(const char *full_name, size_t full_name_len, report_garbage(PACKDIR_FILE_GARBAGE, full_name); } -static void prepare_packed_git_one(struct odb_source *source, int local) +static void prepare_packed_git_one(struct odb_source *source) { struct string_list garbage = STRING_LIST_INIT_DUP; struct prepare_pack_data data = { .m = source->midx, .r = source->odb->repo, .garbage = &garbage, - .local = local, + .local = source->local, }; for_each_file_in_pack_dir(source->path, prepare_pack, &data); @@ -1037,9 +1037,8 @@ static void prepare_packed_git(struct repository *r) odb_prepare_alternates(r->objects); for (source = r->objects->sources; source; source = source->next) { - int local = (source == r->objects->sources); - prepare_multi_pack_index_one(source, local); - prepare_packed_git_one(source, local); + prepare_multi_pack_index_one(source); + prepare_packed_git_one(source); } rearrange_packed_git(r); @@ -1092,7 +1091,7 @@ struct packed_git *get_all_packs(struct repository *r) if (!m) continue; for (uint32_t i = 0; i < m->num_packs + m->num_packs_in_base; i++) - prepare_midx_pack(r, m, i); + prepare_midx_pack(m, i); } return r->objects->packed_git; @@ -2078,7 +2077,7 @@ int find_pack_entry(struct repository *r, const struct object_id *oid, struct pa prepare_packed_git(r); for (struct odb_source *source = r->objects->sources; source; source = source->next) - if (source->midx && fill_midx_entry(r, oid, e, source->midx)) + if (source->midx && fill_midx_entry(source->midx, oid, e)) return 1; if (!r->objects->packed_git) diff --git a/parse-options-cb.c b/parse-options-cb.c index 50c8afe412..976cc86385 100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@ -50,12 +50,12 @@ int parse_opt_expiry_date_cb(const struct option *opt, const char *arg, int parse_opt_color_flag_cb(const struct option *opt, const char *arg, int unset) { - int value; + enum git_colorbool value; if (!arg) arg = unset ? "never" : (const char *)opt->defval; value = git_config_colorbool(NULL, arg); - if (value < 0) + if (value == GIT_COLOR_UNKNOWN) return error(_("option `%s' expects \"always\", \"auto\", or \"never\""), opt->long_name); *(int *)opt->value = value; @@ -470,7 +470,7 @@ static inline void strbuf_add_with_color(struct strbuf *sb, const char *color, static void append_line_with_color(struct strbuf *sb, struct grep_opt *opt, const char *line, size_t linelen, - int color, enum grep_context ctx, + enum git_colorbool color, enum grep_context ctx, enum grep_header_field field) { const char *buf, *eol, *line_color, *match_color; @@ -899,7 +899,7 @@ struct format_commit_context { const char *message; char *commit_encoding; size_t width, indent1, indent2; - int auto_color; + enum git_colorbool auto_color; int padding; /* These offsets are relative to the start of the commit message. */ @@ -1455,14 +1455,14 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ switch (placeholder[0]) { case 'C': if (starts_with(placeholder + 1, "(auto)")) { - c->auto_color = want_color(c->pretty_ctx->color); - if (c->auto_color && sb->len) + c->auto_color = c->pretty_ctx->color; + if (want_color(c->auto_color) && sb->len) strbuf_addstr(sb, GIT_COLOR_RESET); return 7; /* consumed 7 bytes, "C(auto)" */ } else { int ret = parse_color(sb, placeholder, c); if (ret) - c->auto_color = 0; + c->auto_color = GIT_COLOR_NEVER; /* * Otherwise, we decided to treat %C<unknown> * as a literal string, and the previous @@ -2167,7 +2167,7 @@ static int pp_utf8_width(const char *start, const char *end) } static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt, - int color, int tabwidth, const char *line, + enum git_colorbool color, int tabwidth, const char *line, int linelen) { const char *tab; @@ -3,6 +3,7 @@ #include "date.h" #include "string-list.h" +#include "color.h" struct commit; struct repository; @@ -46,7 +47,7 @@ struct pretty_print_context { struct rev_info *rev; const char *output_encoding; struct string_list *mailmap; - int color; + enum git_colorbool color; struct ident_split *from_ident; unsigned encode_email_headers:1; struct pretty_print_describe_status *describe_status; diff --git a/promisor-remote.c b/promisor-remote.c index 08b0da8962..77ebf537e2 100644 --- a/promisor-remote.c +++ b/promisor-remote.c @@ -314,9 +314,162 @@ static int allow_unsanitized(char ch) return ch > 32 && ch < 127; } -static void promisor_info_vecs(struct repository *repo, - struct strvec *names, - struct strvec *urls) +/* + * All the fields used in "promisor-remote" protocol capability, + * including the mandatory "name" and "url" ones. + */ +static const char promisor_field_name[] = "name"; +static const char promisor_field_url[] = "url"; +static const char promisor_field_filter[] = "partialCloneFilter"; +static const char promisor_field_token[] = "token"; + +/* + * List of optional field names that can be used in the + * "promisor-remote" protocol capability (others must be + * ignored). Each field should correspond to a configurable property + * of a remote that can be relevant for the client. + */ +static const char *known_fields[] = { + promisor_field_filter, /* Filter used for partial clone */ + promisor_field_token, /* Authentication token for the remote */ + NULL +}; + +/* + * Check if 'field' is in the list of the known field names for the + * "promisor-remote" protocol capability. + */ +static int is_known_field(const char *field) +{ + const char **p; + + for (p = known_fields; *p; p++) + if (!strcasecmp(*p, field)) + return 1; + return 0; +} + +static int is_valid_field(struct string_list_item *item, void *cb_data) +{ + const char *field = item->string; + const char *config_key = (const char *)cb_data; + + if (!is_known_field(field)) { + warning(_("unsupported field '%s' in '%s' config"), field, config_key); + return 0; + } + return 1; +} + +static char *fields_from_config(struct string_list *fields_list, const char *config_key) +{ + char *fields = NULL; + + if (!repo_config_get_string(the_repository, config_key, &fields) && *fields) { + string_list_split_in_place_f(fields_list, fields, ",", -1, + STRING_LIST_SPLIT_TRIM | + STRING_LIST_SPLIT_NONEMPTY); + filter_string_list(fields_list, 0, is_valid_field, (void *)config_key); + } + + return fields; +} + +static struct string_list *fields_sent(void) +{ + static struct string_list fields_list = STRING_LIST_INIT_NODUP; + static int initialized; + + if (!initialized) { + fields_list.cmp = strcasecmp; + fields_from_config(&fields_list, "promisor.sendFields"); + initialized = 1; + } + + return &fields_list; +} + +static struct string_list *fields_checked(void) +{ + static struct string_list fields_list = STRING_LIST_INIT_NODUP; + static int initialized; + + if (!initialized) { + fields_list.cmp = strcasecmp; + fields_from_config(&fields_list, "promisor.checkFields"); + initialized = 1; + } + + return &fields_list; +} + +/* + * Struct for promisor remotes involved in the "promisor-remote" + * protocol capability. + * + * Except for "name", each <member> in this struct and its <value> + * should correspond (either on the client side or on the server side) + * to a "remote.<name>.<member>" config variable set to <value> where + * "<name>" is a promisor remote name. + */ +struct promisor_info { + const char *name; + const char *url; + const char *filter; + const char *token; +}; + +static void promisor_info_free(struct promisor_info *p) +{ + free((char *)p->name); + free((char *)p->url); + free((char *)p->filter); + free((char *)p->token); + free(p); +} + +static void promisor_info_list_clear(struct string_list *list) +{ + for (size_t i = 0; i < list->nr; i++) + promisor_info_free(list->items[i].util); + string_list_clear(list, 0); +} + +static void set_one_field(struct promisor_info *p, + const char *field, const char *value) +{ + if (!strcasecmp(field, promisor_field_filter)) + p->filter = xstrdup(value); + else if (!strcasecmp(field, promisor_field_token)) + p->token = xstrdup(value); + else + BUG("invalid field '%s'", field); +} + +static void set_fields(struct promisor_info *p, + struct string_list *field_names) +{ + struct string_list_item *item; + + for_each_string_list_item(item, field_names) { + char *key = xstrfmt("remote.%s.%s", p->name, item->string); + const char *val; + if (!repo_config_get_string_tmp(the_repository, key, &val) && *val) + set_one_field(p, item->string, val); + free(key); + } +} + +/* + * Populate 'list' with promisor remote information from the config. + * The 'util' pointer of each list item will hold a 'struct + * promisor_info'. Except "name" and "url", only members of that + * struct specified by the 'field_names' list are set (using values + * from the configuration). + */ +static void promisor_config_info_list(struct repository *repo, + struct string_list *list, + struct string_list *field_names) { struct promisor_remote *r; @@ -328,8 +481,17 @@ static void promisor_info_vecs(struct repository *repo, /* Only add remotes with a non empty URL */ if (!repo_config_get_string_tmp(the_repository, url_key, &url) && *url) { - strvec_push(names, r->name); - strvec_push(urls, url); + struct promisor_info *new_info = xcalloc(1, sizeof(*new_info)); + struct string_list_item *item; + + new_info->name = xstrdup(r->name); + new_info->url = xstrdup(url); + + if (field_names) + set_fields(new_info, field_names); + + item = string_list_append(list, new_info->name); + item->util = new_info; } free(url_key); @@ -340,47 +502,45 @@ char *promisor_remote_info(struct repository *repo) { struct strbuf sb = STRBUF_INIT; int advertise_promisors = 0; - struct strvec names = STRVEC_INIT; - struct strvec urls = STRVEC_INIT; + struct string_list config_info = STRING_LIST_INIT_NODUP; + struct string_list_item *item; repo_config_get_bool(the_repository, "promisor.advertise", &advertise_promisors); if (!advertise_promisors) return NULL; - promisor_info_vecs(repo, &names, &urls); + promisor_config_info_list(repo, &config_info, fields_sent()); - if (!names.nr) + if (!config_info.nr) return NULL; - for (size_t i = 0; i < names.nr; i++) { - if (i) + for_each_string_list_item(item, &config_info) { + struct promisor_info *p = item->util; + + if (item != config_info.items) strbuf_addch(&sb, ';'); - strbuf_addstr(&sb, "name="); - strbuf_addstr_urlencode(&sb, names.v[i], allow_unsanitized); - strbuf_addstr(&sb, ",url="); - strbuf_addstr_urlencode(&sb, urls.v[i], allow_unsanitized); + + strbuf_addf(&sb, "%s=", promisor_field_name); + strbuf_addstr_urlencode(&sb, p->name, allow_unsanitized); + strbuf_addf(&sb, ",%s=", promisor_field_url); + strbuf_addstr_urlencode(&sb, p->url, allow_unsanitized); + + if (p->filter) { + strbuf_addf(&sb, ",%s=", promisor_field_filter); + strbuf_addstr_urlencode(&sb, p->filter, allow_unsanitized); + } + if (p->token) { + strbuf_addf(&sb, ",%s=", promisor_field_token); + strbuf_addstr_urlencode(&sb, p->token, allow_unsanitized); + } } - strvec_clear(&names); - strvec_clear(&urls); + promisor_info_list_clear(&config_info); return strbuf_detach(&sb, NULL); } -/* - * Find first index of 'nicks' where there is 'nick'. 'nick' is - * compared case sensitively to the strings in 'nicks'. If not found - * 'nicks->nr' is returned. - */ -static size_t remote_nick_find(struct strvec *nicks, const char *nick) -{ - for (size_t i = 0; i < nicks->nr; i++) - if (!strcmp(nicks->v[i], nick)) - return i; - return nicks->nr; -} - enum accept_promisor { ACCEPT_NONE = 0, ACCEPT_KNOWN_URL, @@ -388,23 +548,84 @@ enum accept_promisor { ACCEPT_ALL }; +static int match_field_against_config(const char *field, const char *value, + struct promisor_info *config_info) +{ + if (config_info->filter && !strcasecmp(field, promisor_field_filter)) + return !strcmp(config_info->filter, value); + else if (config_info->token && !strcasecmp(field, promisor_field_token)) + return !strcmp(config_info->token, value); + + return 0; +} + +static int all_fields_match(struct promisor_info *advertised, + struct string_list *config_info, + int in_list) +{ + struct string_list *fields = fields_checked(); + struct string_list_item *item_checked; + + for_each_string_list_item(item_checked, fields) { + int match = 0; + const char *field = item_checked->string; + const char *value = NULL; + struct string_list_item *item; + + if (!strcasecmp(field, promisor_field_filter)) + value = advertised->filter; + else if (!strcasecmp(field, promisor_field_token)) + value = advertised->token; + + if (!value) + return 0; + + if (in_list) { + for_each_string_list_item(item, config_info) { + struct promisor_info *p = item->util; + if (match_field_against_config(field, value, p)) { + match = 1; + break; + } + } + } else { + item = string_list_lookup(config_info, advertised->name); + if (item) { + struct promisor_info *p = item->util; + match = match_field_against_config(field, value, p); + } + } + + if (!match) + return 0; + } + + return 1; +} + static int should_accept_remote(enum accept_promisor accept, - const char *remote_name, const char *remote_url, - struct strvec *names, struct strvec *urls) + struct promisor_info *advertised, + struct string_list *config_info) { - size_t i; + struct promisor_info *p; + struct string_list_item *item; + const char *remote_name = advertised->name; + const char *remote_url = advertised->url; if (accept == ACCEPT_ALL) - return 1; + return all_fields_match(advertised, config_info, 1); - i = remote_nick_find(names, remote_name); + /* Get config info for that promisor remote */ + item = string_list_lookup(config_info, remote_name); - if (i >= names->nr) + if (!item) /* We don't know about that remote */ return 0; + p = item->util; + if (accept == ACCEPT_KNOWN_NAME) - return 1; + return all_fields_match(advertised, config_info, 0); if (accept != ACCEPT_KNOWN_URL) BUG("Unhandled 'enum accept_promisor' value '%d'", accept); @@ -414,24 +635,72 @@ static int should_accept_remote(enum accept_promisor accept, return 0; } - if (!strcmp(urls->v[i], remote_url)) - return 1; + if (!strcmp(p->url, remote_url)) + return all_fields_match(advertised, config_info, 0); warning(_("known remote named '%s' but with URL '%s' instead of '%s'"), - remote_name, urls->v[i], remote_url); + remote_name, p->url, remote_url); return 0; } +static int skip_field_name_prefix(const char *elem, const char *field_name, const char **value) +{ + const char *p; + if (!skip_prefix(elem, field_name, &p) || *p != '=') + return 0; + *value = p + 1; + return 1; +} + +static struct promisor_info *parse_one_advertised_remote(const char *remote_info) +{ + struct promisor_info *info = xcalloc(1, sizeof(*info)); + struct string_list elem_list = STRING_LIST_INIT_DUP; + struct string_list_item *item; + + string_list_split(&elem_list, remote_info, ",", -1); + + for_each_string_list_item(item, &elem_list) { + const char *elem = item->string; + const char *p = strchr(elem, '='); + + if (!p) { + warning(_("invalid element '%s' from remote info"), elem); + continue; + } + + if (skip_field_name_prefix(elem, promisor_field_name, &p)) + info->name = url_percent_decode(p); + else if (skip_field_name_prefix(elem, promisor_field_url, &p)) + info->url = url_percent_decode(p); + else if (skip_field_name_prefix(elem, promisor_field_filter, &p)) + info->filter = url_percent_decode(p); + else if (skip_field_name_prefix(elem, promisor_field_token, &p)) + info->token = url_percent_decode(p); + } + + string_list_clear(&elem_list, 0); + + if (!info->name || !info->url) { + warning(_("server advertised a promisor remote without a name or URL: %s"), + remote_info); + promisor_info_free(info); + return NULL; + } + + return info; +} + static void filter_promisor_remote(struct repository *repo, struct strvec *accepted, const char *info) { - struct strbuf **remotes; const char *accept_str; enum accept_promisor accept = ACCEPT_NONE; - struct strvec names = STRVEC_INIT; - struct strvec urls = STRVEC_INIT; + struct string_list config_info = STRING_LIST_INIT_NODUP; + struct string_list remote_info = STRING_LIST_INIT_DUP; + struct string_list_item *item; if (!repo_config_get_string_tmp(the_repository, "promisor.acceptfromserver", &accept_str)) { if (!*accept_str || !strcasecmp("None", accept_str)) @@ -450,49 +719,31 @@ static void filter_promisor_remote(struct repository *repo, if (accept == ACCEPT_NONE) return; - if (accept != ACCEPT_ALL) - promisor_info_vecs(repo, &names, &urls); - /* Parse remote info received */ - remotes = strbuf_split_str(info, ';', 0); - - for (size_t i = 0; remotes[i]; i++) { - struct strbuf **elems; - const char *remote_name = NULL; - const char *remote_url = NULL; - char *decoded_name = NULL; - char *decoded_url = NULL; - - strbuf_strip_suffix(remotes[i], ";"); - elems = strbuf_split(remotes[i], ','); - - for (size_t j = 0; elems[j]; j++) { - int res; - strbuf_strip_suffix(elems[j], ","); - res = skip_prefix(elems[j]->buf, "name=", &remote_name) || - skip_prefix(elems[j]->buf, "url=", &remote_url); - if (!res) - warning(_("unknown element '%s' from remote info"), - elems[j]->buf); - } + string_list_split(&remote_info, info, ";", -1); + + for_each_string_list_item(item, &remote_info) { + struct promisor_info *advertised; - if (remote_name) - decoded_name = url_percent_decode(remote_name); - if (remote_url) - decoded_url = url_percent_decode(remote_url); + advertised = parse_one_advertised_remote(item->string); + + if (!advertised) + continue; + + if (!config_info.nr) { + promisor_config_info_list(repo, &config_info, fields_checked()); + string_list_sort(&config_info); + } - if (decoded_name && should_accept_remote(accept, decoded_name, decoded_url, &names, &urls)) - strvec_push(accepted, decoded_name); + if (should_accept_remote(accept, advertised, &config_info)) + strvec_push(accepted, advertised->name); - strbuf_list_free(elems); - free(decoded_name); - free(decoded_url); + promisor_info_free(advertised); } - strvec_clear(&names); - strvec_clear(&urls); - strbuf_list_free(remotes); + promisor_info_list_clear(&config_info); + string_list_clear(&remote_info, 0); } char *promisor_remote_reply(const char *info) @@ -518,16 +769,15 @@ char *promisor_remote_reply(const char *info) void mark_promisor_remotes_as_accepted(struct repository *r, const char *remotes) { - struct strbuf **accepted_remotes = strbuf_split_str(remotes, ';', 0); + struct string_list accepted_remotes = STRING_LIST_INIT_DUP; + struct string_list_item *item; - for (size_t i = 0; accepted_remotes[i]; i++) { - struct promisor_remote *p; - char *decoded_remote; + string_list_split(&accepted_remotes, remotes, ";", -1); - strbuf_strip_suffix(accepted_remotes[i], ";"); - decoded_remote = url_percent_decode(accepted_remotes[i]->buf); + for_each_string_list_item(item, &accepted_remotes) { + char *decoded_remote = url_percent_decode(item->string); + struct promisor_remote *p = repo_promisor_remote_find(r, decoded_remote); - p = repo_promisor_remote_find(r, decoded_remote); if (p) p->accepted = 1; else @@ -537,5 +787,5 @@ void mark_promisor_remotes_as_accepted(struct repository *r, const char *remotes free(decoded_remote); } - strbuf_list_free(accepted_remotes); + string_list_clear(&accepted_remotes, 0); } diff --git a/range-diff.c b/range-diff.c index 8a2dcbee32..ca449a0769 100644 --- a/range-diff.c +++ b/range-diff.c @@ -325,13 +325,24 @@ static int diffsize(const char *a, const char *b) } static void get_correspondences(struct string_list *a, struct string_list *b, - int creation_factor) + int creation_factor, size_t max_memory) { int n = a->nr + b->nr; int *cost, c, *a2b, *b2a; int i, j; - - ALLOC_ARRAY(cost, st_mult(n, n)); + size_t cost_size = st_mult(n, n); + size_t cost_bytes = st_mult(sizeof(int), cost_size); + if (cost_bytes >= max_memory) { + struct strbuf cost_str = STRBUF_INIT; + struct strbuf max_str = STRBUF_INIT; + strbuf_humanise_bytes(&cost_str, cost_bytes); + strbuf_humanise_bytes(&max_str, max_memory); + die(_("range-diff: unable to compute the range-diff, since it " + "exceeds the maximum memory for the cost matrix: %s " + "(%"PRIuMAX" bytes) needed, limited to %s (%"PRIuMAX" bytes)"), + cost_str.buf, (uintmax_t)cost_bytes, max_str.buf, (uintmax_t)max_memory); + } + ALLOC_ARRAY(cost, cost_size); ALLOC_ARRAY(a2b, n); ALLOC_ARRAY(b2a, n); @@ -591,7 +602,8 @@ int show_range_diff(const char *range1, const char *range2, if (!res) { find_exact_matches(&branch1, &branch2); get_correspondences(&branch1, &branch2, - range_diff_opts->creation_factor); + range_diff_opts->creation_factor, + range_diff_opts->max_memory); output(&branch1, &branch2, range_diff_opts); } diff --git a/range-diff.h b/range-diff.h index cd85000b5a..9d39818e34 100644 --- a/range-diff.h +++ b/range-diff.h @@ -5,6 +5,10 @@ #include "strvec.h" #define RANGE_DIFF_CREATION_FACTOR_DEFAULT 60 +#define RANGE_DIFF_MAX_MEMORY_DEFAULT \ + (sizeof(void*) >= 8 ? \ + ((size_t)(1024L * 1024L) * (size_t)(4L * 1024L)) : /* 4GB on 64-bit */ \ + ((size_t)(1024L * 1024L) * (size_t)(2L * 1024L))) /* 2GB on 32-bit */ /* * A much higher value than the default, when we KNOW we are comparing @@ -17,6 +21,7 @@ struct range_diff_options { unsigned dual_color:1; unsigned left_only:1, right_only:1; unsigned include_merges:1; + size_t max_memory; const struct diff_options *diffopt; /* may be NULL */ const struct strvec *other_arg; /* may be NULL */ }; diff --git a/ref-filter.h b/ref-filter.h index f22ca94b49..81f2c229a9 100644 --- a/ref-filter.h +++ b/ref-filter.h @@ -95,7 +95,7 @@ struct ref_format { const char *format; const char *rest; int quote_style; - int use_color; + enum git_colorbool use_color; /* Internal state to ref-filter */ int need_color_reset_at_eol; @@ -111,7 +111,7 @@ struct ref_format { .exclude = STRVEC_INIT, \ } #define REF_FORMAT_INIT { \ - .use_color = -1, \ + .use_color = GIT_COLOR_UNKNOWN, \ } /* Macros for checking --merged and --no-merged options */ @@ -627,10 +627,12 @@ void expand_ref_prefix(struct strvec *prefixes, const char *prefix) strvec_pushf(prefixes, *p, len, prefix); } +#ifndef WITH_BREAKING_CHANGES static const char default_branch_name_advice[] = N_( "Using '%s' as the name for the initial branch. This default branch name\n" -"is subject to change. To configure the initial branch name to use in all\n" -"of your new repositories, which will suppress this warning, call:\n" +"will change to \"main\" in Git 3.0. To configure the initial branch name\n" +"to use in all of your new repositories, which will suppress this warning,\n" +"call:\n" "\n" "\tgit config --global init.defaultBranch <name>\n" "\n" @@ -639,6 +641,15 @@ static const char default_branch_name_advice[] = N_( "\n" "\tgit branch -m <name>\n" ); +#else +static const char default_branch_name_advice[] = N_( +"Using '%s' as the name for the initial branch since Git 3.0.\n" +"If you expected Git to create 'master', the just-created\n" +"branch can be renamed via this command:\n" +"\n" +"\tgit branch -m master\n" +); +#endif /* WITH_BREAKING_CHANGES */ char *repo_default_branch_name(struct repository *r, int quiet) { @@ -649,11 +660,15 @@ char *repo_default_branch_name(struct repository *r, int quiet) if (env && *env) ret = xstrdup(env); - else if (repo_config_get_string(r, config_key, &ret) < 0) + if (!ret && repo_config_get_string(r, config_key, &ret) < 0) die(_("could not retrieve `%s`"), config_display_key); if (!ret) { +#ifdef WITH_BREAKING_CHANGES + ret = xstrdup("main"); +#else ret = xstrdup("master"); +#endif /* WITH_BREAKING_CHANGES */ if (!quiet) advise_if_enabled(ADVICE_DEFAULT_BRANCH_NAME, _(default_branch_name_advice), ret); @@ -1222,7 +1237,7 @@ int ref_transaction_maybe_set_rejected(struct ref_transaction *transaction, return 0; if (!transaction->rejections) - BUG("transaction not inititalized with failure support"); + BUG("transaction not initialized with failure support"); /* * Don't accept generic errors, since these errors are not user @@ -1231,6 +1246,13 @@ int ref_transaction_maybe_set_rejected(struct ref_transaction *transaction, if (err == REF_TRANSACTION_ERROR_GENERIC) return 0; + /* + * Rejected refnames shouldn't be considered in the availability + * checks, so remove them from the list. + */ + string_list_remove(&transaction->refnames, + transaction->updates[update_idx]->refname, 0); + transaction->updates[update_idx]->rejection_err = err; ALLOC_GROW(transaction->rejections->update_indices, transaction->rejections->nr + 1, @@ -3315,6 +3337,8 @@ const char *ref_transaction_error_msg(enum ref_transaction_error err) return "invalid new value provided"; case REF_TRANSACTION_ERROR_EXPECTED_SYMREF: return "expected symref but found regular ref"; + case REF_TRANSACTION_ERROR_CASE_CONFLICT: + return "reference conflict due to case-insensitive filesystem"; default: return "unknown failure"; } @@ -31,6 +31,8 @@ enum ref_transaction_error { REF_TRANSACTION_ERROR_INVALID_NEW_VALUE = -6, /* Expected ref to be symref, but is a regular ref */ REF_TRANSACTION_ERROR_EXPECTED_SYMREF = -7, + /* Cannot create ref due to case-insensitive filesystem */ + REF_TRANSACTION_ERROR_CASE_CONFLICT = -8, }; /* diff --git a/refs/files-backend.c b/refs/files-backend.c index 1b3bf26add..bc3347d18c 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -654,6 +654,26 @@ static void unlock_ref(struct ref_lock *lock) } /* + * Check if the transaction has another update with a case-insensitive refname + * match. + * + * If the update is part of the transaction, we only check up to that index. + * Further updates are expected to call this function to match previous indices. + */ +static bool transaction_has_case_conflicting_update(struct ref_transaction *transaction, + struct ref_update *update) +{ + for (size_t i = 0; i < transaction->nr; i++) { + if (transaction->updates[i] == update) + break; + + if (!strcasecmp(transaction->updates[i]->refname, update->refname)) + return true; + } + return false; +} + +/* * Lock refname, without following symrefs, and set *lock_p to point * at a newly-allocated lock object. Fill in lock->old_oid, referent, * and type similarly to read_raw_ref(). @@ -683,16 +703,17 @@ static void unlock_ref(struct ref_lock *lock) * - Generate informative error messages in the case of failure */ static enum ref_transaction_error lock_raw_ref(struct files_ref_store *refs, - struct ref_update *update, + struct ref_transaction *transaction, size_t update_idx, int mustexist, struct string_list *refnames_to_check, - const struct string_list *extras, struct ref_lock **lock_p, struct strbuf *referent, struct strbuf *err) { enum ref_transaction_error ret = REF_TRANSACTION_ERROR_GENERIC; + struct ref_update *update = transaction->updates[update_idx]; + const struct string_list *extras = &transaction->refnames; const char *refname = update->refname; unsigned int *type = &update->type; struct ref_lock *lock; @@ -782,6 +803,24 @@ retry: goto retry; } else { unable_to_lock_message(ref_file.buf, myerr, err); + if (myerr == EEXIST) { + if (ignore_case && + transaction_has_case_conflicting_update(transaction, update)) { + /* + * In case-insensitive filesystems, ensure that conflicts within a + * given transaction are handled. Pre-existing refs on a + * case-insensitive system will be overridden without any issue. + */ + ret = REF_TRANSACTION_ERROR_CASE_CONFLICT; + } else { + /* + * Pre-existing case-conflicting reference locks should also be + * specially categorized to avoid failing all batched updates. + */ + ret = REF_TRANSACTION_ERROR_CREATE_EXISTS; + } + } + goto error_return; } } @@ -837,6 +876,7 @@ retry: goto error_return; } else if (remove_dir_recursively(&ref_file, REMOVE_DIR_EMPTY_ONLY)) { + ret = REF_TRANSACTION_ERROR_NAME_CONFLICT; if (refs_verify_refname_available( &refs->base, refname, extras, NULL, 0, err)) { @@ -844,14 +884,14 @@ retry: * The error message set by * verify_refname_available() is OK. */ - ret = REF_TRANSACTION_ERROR_NAME_CONFLICT; goto error_return; } else { /* - * We can't delete the directory, - * but we also don't know of any - * references that it should - * contain. + * Directory conflicts can occur if there + * is an existing lock file in the directory + * or if the filesystem is case-insensitive + * and the directory contains a valid reference + * but conflicts with the update. */ strbuf_addf(err, "there is a non-empty directory '%s' " "blocking reference '%s'", @@ -873,8 +913,23 @@ retry: * If the ref did not exist and we are creating it, we have to * make sure there is no existing packed ref that conflicts * with refname. This check is deferred so that we can batch it. + * + * For case-insensitive filesystems, we should also check for F/D + * conflicts between 'foo' and 'Foo/bar'. So let's lowercase + * the refname. */ - item = string_list_append(refnames_to_check, refname); + if (ignore_case) { + struct strbuf lower = STRBUF_INIT; + + strbuf_addstr(&lower, refname); + strbuf_tolower(&lower); + + item = string_list_append_nodup(refnames_to_check, + strbuf_detach(&lower, NULL)); + } else { + item = string_list_append(refnames_to_check, refname); + } + item->util = xmalloc(sizeof(update_idx)); memcpy(item->util, &update_idx, sizeof(update_idx)); } @@ -2616,9 +2671,8 @@ static enum ref_transaction_error lock_ref_for_update(struct files_ref_store *re if (lock) { lock->count++; } else { - ret = lock_raw_ref(refs, update, update_idx, mustexist, - refnames_to_check, &transaction->refnames, - &lock, &referent, err); + ret = lock_raw_ref(refs, transaction, update_idx, mustexist, + refnames_to_check, &lock, &referent, err); if (ret) { char *reason; @@ -2858,7 +2912,7 @@ static int files_transaction_prepare(struct ref_store *ref_store, "ref_transaction_prepare"); size_t i; int ret = 0; - struct string_list refnames_to_check = STRING_LIST_INIT_NODUP; + struct string_list refnames_to_check = STRING_LIST_INIT_DUP; char *head_ref = NULL; int head_type; struct files_transaction_backend_data *backend_data; @@ -2143,9 +2143,6 @@ static int stat_branch_pair(const char *branch_name, const char *base, struct object_id oid; struct commit *ours, *theirs; struct rev_info revs; - struct setup_revision_opt opt = { - .free_removed_argv_elements = 1, - }; struct strvec argv = STRVEC_INIT; /* Cannot stat if what we used to build on no longer exists */ @@ -2180,7 +2177,7 @@ static int stat_branch_pair(const char *branch_name, const char *base, strvec_push(&argv, "--"); repo_init_revisions(the_repository, &revs, NULL); - setup_revisions(argv.nr, argv.v, &revs, &opt); + setup_revisions_from_strvec(&argv, &revs, NULL); if (prepare_revision_walk(&revs)) die(_("revision walk setup failed")); diff --git a/repository.c b/repository.c index ecd691181f..6faf5c7398 100644 --- a/repository.c +++ b/repository.c @@ -57,6 +57,7 @@ void initialize_repository(struct repository *repo) repo->parsed_objects = parsed_object_pool_new(repo); ALLOC_ARRAY(repo->index, 1); index_state_init(repo->index, repo); + repo->check_deprecated_config = true; /* * When a command runs inside a repository, it learns what @@ -168,6 +169,7 @@ void repo_set_gitdir(struct repository *repo, if (!repo->objects->sources) { CALLOC_ARRAY(repo->objects->sources, 1); repo->objects->sources->odb = repo->objects; + repo->objects->sources->local = true; repo->objects->sources_tail = &repo->objects->sources->next; } expand_base_dir(&repo->objects->sources->path, o->object_dir, diff --git a/repository.h b/repository.h index 042dc93f0f..5808a5d610 100644 --- a/repository.h +++ b/repository.h @@ -161,6 +161,9 @@ struct repository { /* Indicate if a repository has a different 'commondir' from 'gitdir' */ unsigned different_commondir:1; + + /* Should repo_config() check for deprecated settings */ + bool check_deprecated_config; }; #ifdef USE_THE_REPOSITORY_VARIABLE diff --git a/revision.c b/revision.c index 6ba8f67054..806a1c4c24 100644 --- a/revision.c +++ b/revision.c @@ -2321,6 +2321,24 @@ static timestamp_t parse_age(const char *arg) return num; } +static void overwrite_argv(int *argc, const char **argv, + const char **value, + const struct setup_revision_opt *opt) +{ + /* + * Detect the case when we are overwriting ourselves. The assignment + * itself would be a noop either way, but this lets us avoid corner + * cases around the free() and NULL operations. + */ + if (*value != argv[*argc]) { + if (opt && opt->free_removed_argv_elements) + free((char *)argv[*argc]); + argv[*argc] = *value; + *value = NULL; + } + (*argc)++; +} + static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv, int *unkc, const char **unkv, const struct setup_revision_opt* opt) @@ -2342,7 +2360,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg starts_with(arg, "--branches=") || starts_with(arg, "--tags=") || starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk=")) { - unkv[(*unkc)++] = arg; + overwrite_argv(unkc, unkv, &argv[0], opt); return 1; } @@ -2706,7 +2724,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else { int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix); if (!opts) - unkv[(*unkc)++] = arg; + overwrite_argv(unkc, unkv, &argv[0], opt); return opts; } @@ -3018,7 +3036,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (!strcmp(arg, "--stdin")) { if (revs->disable_stdin) { - argv[left++] = arg; + overwrite_argv(&left, argv, &argv[i], opt); continue; } if (revs->read_from_stdin++) @@ -3174,9 +3192,34 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s revs->show_notes_given = 1; } + if (argv) { + if (opt && opt->free_removed_argv_elements) + free((char *)argv[left]); + argv[left] = NULL; + } + return left; } +void setup_revisions_from_strvec(struct strvec *argv, struct rev_info *revs, + struct setup_revision_opt *opt) +{ + struct setup_revision_opt fallback_opt; + int ret; + + if (!opt) { + memset(&fallback_opt, 0, sizeof(fallback_opt)); + opt = &fallback_opt; + } + opt->free_removed_argv_elements = 1; + + ret = setup_revisions(argv->nr, argv->v, revs, opt); + + for (size_t i = ret; i < argv->nr; i++) + free((char *)argv->v[i]); + argv->nr = ret; +} + static void release_revisions_cmdline(struct rev_cmdline_info *cmdline) { unsigned int i; diff --git a/revision.h b/revision.h index 21e288c5ba..a28e349044 100644 --- a/revision.h +++ b/revision.h @@ -441,6 +441,8 @@ struct setup_revision_opt { }; int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *); +void setup_revisions_from_strvec(struct strvec *argv, struct rev_info *revs, + struct setup_revision_opt *); /** * Free data allocated in a "struct rev_info" after it's been diff --git a/sequencer.c b/sequencer.c index 9ae40a91b2..5476d39ba9 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1087,7 +1087,6 @@ N_("you have staged changes in your working tree\n" #define CLEANUP_MSG (1<<3) #define VERIFY_MSG (1<<4) #define CREATE_ROOT_COMMIT (1<<5) -#define VERBATIM_MSG (1<<6) static int run_command_silent_on_success(struct child_process *cmd) { @@ -1125,9 +1124,6 @@ static int run_git_commit(const char *defmsg, { struct child_process cmd = CHILD_PROCESS_INIT; - if ((flags & CLEANUP_MSG) && (flags & VERBATIM_MSG)) - BUG("CLEANUP_MSG and VERBATIM_MSG are mutually exclusive"); - cmd.git_cmd = 1; if (is_rebase_i(opts) && @@ -1166,8 +1162,6 @@ static int run_git_commit(const char *defmsg, strvec_pushl(&cmd.args, "-C", "HEAD", NULL); if ((flags & CLEANUP_MSG)) strvec_push(&cmd.args, "--cleanup=strip"); - if ((flags & VERBATIM_MSG)) - strvec_push(&cmd.args, "--cleanup=verbatim"); if ((flags & EDIT_MSG)) strvec_push(&cmd.args, "-e"); else if (!(flags & CLEANUP_MSG) && @@ -1540,9 +1534,6 @@ static int try_to_commit(struct repository *r, enum commit_msg_cleanup_mode cleanup; int res = 0; - if ((flags & CLEANUP_MSG) && (flags & VERBATIM_MSG)) - BUG("CLEANUP_MSG and VERBATIM_MSG are mutually exclusive"); - if (parse_head(r, ¤t_head)) return -1; @@ -1618,8 +1609,6 @@ static int try_to_commit(struct repository *r, if (flags & CLEANUP_MSG) cleanup = COMMIT_MSG_CLEANUP_ALL; - else if (flags & VERBATIM_MSG) - cleanup = COMMIT_MSG_CLEANUP_NONE; else if ((opts->signoff || opts->record_origin) && !opts->explicit_cleanup) cleanup = COMMIT_MSG_CLEANUP_SPACE; @@ -2436,7 +2425,6 @@ static int do_pick_commit(struct repository *r, if (!final_fixup) msg_file = rebase_path_squash_msg(); else if (file_exists(rebase_path_fixup_msg())) { - flags |= VERBATIM_MSG; msg_file = rebase_path_fixup_msg(); } else { const char *dest = git_path_squash_msg(r); @@ -6064,8 +6052,8 @@ static int make_script_with_merges(struct pretty_print_context *pp, return 0; } -int sequencer_make_script(struct repository *r, struct strbuf *out, int argc, - const char **argv, unsigned flags) +int sequencer_make_script(struct repository *r, struct strbuf *out, + struct strvec *argv, unsigned flags) { char *format = NULL; struct pretty_print_context pp = {0}; @@ -6106,7 +6094,8 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc, pp.fmt = revs.commit_format; pp.output_encoding = get_log_output_encoding(); - if (setup_revisions(argc, argv, &revs, NULL) > 1) { + setup_revisions_from_strvec(argv, &revs, NULL); + if (argv->nr > 1) { ret = error(_("make_script: unhandled options")); goto cleanup; } diff --git a/sequencer.h b/sequencer.h index 304ba4b4d3..719684c8a9 100644 --- a/sequencer.h +++ b/sequencer.h @@ -186,8 +186,8 @@ int sequencer_remove_state(struct replay_opts *opts); #define TODO_LIST_REAPPLY_CHERRY_PICKS (1U << 7) #define TODO_LIST_WARN_SKIPPED_CHERRY_PICKS (1U << 8) -int sequencer_make_script(struct repository *r, struct strbuf *out, int argc, - const char **argv, unsigned flags); +int sequencer_make_script(struct repository *r, struct strbuf *out, + struct strvec *argv, unsigned flags); int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags, const char *shortrevisions, const char *onto_name, @@ -213,7 +213,7 @@ static void show_commit(struct commit *commit, void *data) * are marked with shallow_flag. The list of border/shallow commits * are also returned. */ -struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av, +struct commit_list *get_shallow_commits_by_rev_list(struct strvec *argv, int shallow_flag, int not_shallow_flag) { @@ -232,7 +232,7 @@ struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av, repo_init_revisions(the_repository, &revs, NULL); save_commit_buffer = 0; - setup_revisions(ac, av, &revs, NULL); + setup_revisions_from_strvec(argv, &revs, NULL); if (prepare_revision_walk(&revs)) die("revision walk setup failed"); @@ -7,6 +7,7 @@ #include "strbuf.h" struct oid_array; +struct strvec; void set_alternate_shallow_file(struct repository *r, const char *path, int override); int register_shallow(struct repository *r, const struct object_id *oid); @@ -36,8 +37,8 @@ void rollback_shallow_file(struct repository *r, struct shallow_lock *lk); struct commit_list *get_shallow_commits(struct object_array *heads, int depth, int shallow_flag, int not_shallow_flag); -struct commit_list *get_shallow_commits_by_rev_list( - int ac, const char **av, int shallow_flag, int not_shallow_flag); +struct commit_list *get_shallow_commits_by_rev_list(struct strvec *argv, + int shallow_flag, int not_shallow_flag); int write_shallow_commits(struct strbuf *out, int use_pack_protocol, const struct oid_array *extra); diff --git a/sideband.c b/sideband.c index 8f15b98a65..ea7c25211e 100644 --- a/sideband.c +++ b/sideband.c @@ -27,16 +27,16 @@ static struct keyword_entry keywords[] = { }; /* Returns a color setting (GIT_COLOR_NEVER, etc). */ -static int use_sideband_colors(void) +static enum git_colorbool use_sideband_colors(void) { - static int use_sideband_colors_cached = -1; + static enum git_colorbool use_sideband_colors_cached = GIT_COLOR_UNKNOWN; const char *key = "color.remote"; struct strbuf sb = STRBUF_INIT; const char *value; int i; - if (use_sideband_colors_cached >= 0) + if (use_sideband_colors_cached != GIT_COLOR_UNKNOWN) return use_sideband_colors_cached; if (!repo_config_get_string_tmp(the_repository, key, &value)) diff --git a/submodule.c b/submodule.c index fff3c75570..35c55155f7 100644 --- a/submodule.c +++ b/submodule.c @@ -900,7 +900,7 @@ static void collect_changed_submodules(struct repository *r, save_warning = warn_on_object_refname_ambiguity; warn_on_object_refname_ambiguity = 0; repo_init_revisions(r, &rev, NULL); - setup_revisions(argv->nr, argv->v, &rev, &s_r_opt); + setup_revisions_from_strvec(argv, &rev, &s_r_opt); warn_on_object_refname_ambiguity = save_warning; if (prepare_revision_walk(&rev)) die(_("revision walk setup failed")); diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c index da2aa036b5..6de5d1665a 100644 --- a/t/helper/test-read-midx.c +++ b/t/helper/test-read-midx.c @@ -11,14 +11,24 @@ #include "gettext.h" #include "pack-revindex.h" +static struct multi_pack_index *setup_midx(const char *object_dir) +{ + struct odb_source *source; + setup_git_directory(); + source = odb_find_source(the_repository->objects, object_dir); + if (!source) + source = odb_add_to_alternates_memory(the_repository->objects, + object_dir); + return load_multi_pack_index(source); +} + static int read_midx_file(const char *object_dir, const char *checksum, int show_objects) { uint32_t i; struct multi_pack_index *m; - setup_git_directory(); - m = load_multi_pack_index(the_repository, object_dir, 1); + m = setup_midx(object_dir); if (!m) return 1; @@ -56,7 +66,7 @@ static int read_midx_file(const char *object_dir, const char *checksum, for (i = 0; i < m->num_packs; i++) printf("%s\n", m->pack_names[i]); - printf("object-dir: %s\n", m->object_dir); + printf("object-dir: %s\n", m->source->path); if (show_objects) { struct object_id oid; @@ -65,7 +75,7 @@ static int read_midx_file(const char *object_dir, const char *checksum, for (i = 0; i < m->num_objects; i++) { nth_midxed_object_oid(&oid, m, i + m->num_objects_in_base); - fill_midx_entry(the_repository, &oid, &e, m); + fill_midx_entry(m, &oid, &e); printf("%s %"PRIu64"\t%s\n", oid_to_hex(&oid), e.offset, e.p->pack_name); @@ -81,8 +91,7 @@ static int read_midx_checksum(const char *object_dir) { struct multi_pack_index *m; - setup_git_directory(); - m = load_multi_pack_index(the_repository, object_dir, 1); + m = setup_midx(object_dir); if (!m) return 1; printf("%s\n", hash_to_hex(get_midx_checksum(m))); @@ -96,9 +105,7 @@ static int read_midx_preferred_pack(const char *object_dir) struct multi_pack_index *midx = NULL; uint32_t preferred_pack; - setup_git_directory(); - - midx = load_multi_pack_index(the_repository, object_dir, 1); + midx = setup_midx(object_dir); if (!midx) return 1; @@ -119,14 +126,12 @@ static int read_midx_bitmapped_packs(const char *object_dir) struct bitmapped_pack pack; uint32_t i; - setup_git_directory(); - - midx = load_multi_pack_index(the_repository, object_dir, 1); + midx = setup_midx(object_dir); if (!midx) return 1; for (i = 0; i < midx->num_packs + midx->num_packs_in_base; i++) { - if (nth_bitmapped_pack(the_repository, midx, &pack, i) < 0) { + if (nth_bitmapped_pack(midx, &pack, i) < 0) { close_midx(midx); return 1; } diff --git a/t/meson.build b/t/meson.build index 82af229be3..7974795fe4 100644 --- a/t/meson.build +++ b/t/meson.build @@ -206,11 +206,13 @@ integration_tests = [ 't1419-exclude-refs.sh', 't1420-lost-found.sh', 't1421-reflog-write.sh', + 't1422-show-ref-exists.sh', 't1430-bad-ref-name.sh', 't1450-fsck.sh', 't1451-fsck-buffer.sh', 't1460-refs-migrate.sh', 't1461-refs-list.sh', + 't1462-refs-exists.sh', 't1500-rev-parse.sh', 't1501-work-tree.sh', 't1502-rev-parse-parseopt.sh', @@ -1221,4 +1223,4 @@ if perl.found() and time.found() timeout: 0, ) endforeach -endif
\ No newline at end of file +endif diff --git a/t/show-ref-exists-tests.sh b/t/show-ref-exists-tests.sh new file mode 100644 index 0000000000..36e8e9df33 --- /dev/null +++ b/t/show-ref-exists-tests.sh @@ -0,0 +1,77 @@ +git_show_ref_exists=${git_show_ref_exists:-git show-ref --exists} + +test_expect_success setup ' + test_commit --annotate A && + git checkout -b side && + test_commit --annotate B && + git checkout main && + test_commit C && + git branch B A^0 +' + +test_expect_success '--exists with existing reference' ' + ${git_show_ref_exists} refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +' + +test_expect_success '--exists with missing reference' ' + test_expect_code 2 ${git_show_ref_exists} refs/heads/does-not-exist +' + +test_expect_success '--exists does not use DWIM' ' + test_expect_code 2 ${git_show_ref_exists} $GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 2>err && + grep "reference does not exist" err +' + +test_expect_success '--exists with HEAD' ' + ${git_show_ref_exists} HEAD +' + +test_expect_success '--exists with bad reference name' ' + test_when_finished "git update-ref -d refs/heads/bad...name" && + new_oid=$(git rev-parse HEAD) && + test-tool ref-store main update-ref msg refs/heads/bad...name $new_oid $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + ${git_show_ref_exists} refs/heads/bad...name +' + +test_expect_success '--exists with arbitrary symref' ' + test_when_finished "git symbolic-ref -d refs/symref" && + git symbolic-ref refs/symref refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME && + ${git_show_ref_exists} refs/symref +' + +test_expect_success '--exists with dangling symref' ' + test_when_finished "git symbolic-ref -d refs/heads/dangling" && + git symbolic-ref refs/heads/dangling refs/heads/does-not-exist && + ${git_show_ref_exists} refs/heads/dangling +' + +test_expect_success '--exists with nonexistent object ID' ' + test-tool ref-store main update-ref msg refs/heads/missing-oid $(test_oid 001) $ZERO_OID REF_SKIP_OID_VERIFICATION && + ${git_show_ref_exists} refs/heads/missing-oid +' + +test_expect_success '--exists with non-commit object' ' + tree_oid=$(git rev-parse HEAD^{tree}) && + test-tool ref-store main update-ref msg refs/heads/tree ${tree_oid} $ZERO_OID REF_SKIP_OID_VERIFICATION && + ${git_show_ref_exists} refs/heads/tree +' + +test_expect_success '--exists with directory fails with generic error' ' + cat >expect <<-EOF && + error: reference does not exist + EOF + test_expect_code 2 ${git_show_ref_exists} refs/heads 2>err && + test_cmp expect err +' + +test_expect_success '--exists with non-existent special ref' ' + test_expect_code 2 ${git_show_ref_exists} FETCH_HEAD +' + +test_expect_success '--exists with existing special ref' ' + test_when_finished "rm .git/FETCH_HEAD" && + git rev-parse HEAD >.git/FETCH_HEAD && + ${git_show_ref_exists} FETCH_HEAD +' + +test_done diff --git a/t/t0001-init.sh b/t/t0001-init.sh index f593c53687..618da080dc 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -883,6 +883,22 @@ test_expect_success 'advice on unconfigured init.defaultBranch disabled' ' test_grep ! "hint: " err ' +test_expect_success 'default branch name' ' + if test_have_prereq WITH_BREAKING_CHANGES + then + expect=main + else + expect=master + fi && + echo "refs/heads/$expect" >expect && + ( + sane_unset GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME && + git init default-initial-branch-name + ) && + git -C default-initial-branch-name symbolic-ref HEAD >actual && + test_cmp expect actual +' + test_expect_success 'overridden default main branch name (env)' ' test_config_global init.defaultBranch nmb && GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env && diff --git a/t/t0450-txt-doc-vs-help.sh b/t/t0450-txt-doc-vs-help.sh index 2f7504ae7e..e12e18f97f 100755 --- a/t/t0450-txt-doc-vs-help.sh +++ b/t/t0450-txt-doc-vs-help.sh @@ -41,7 +41,7 @@ help_to_synopsis () { } builtin_to_adoc () { - echo "$GIT_BUILD_DIR/Documentation/git-$1.adoc" + echo "$GIT_SOURCE_DIR/Documentation/git-$1.adoc" } adoc_to_synopsis () { @@ -112,10 +112,19 @@ do adoc="$(builtin_to_adoc "$builtin")" && preq="$(echo BUILTIN_ADOC_$builtin | tr '[:lower:]-' '[:upper:]_')" && - if test -f "$adoc" + # If and only if *.adoc is missing, builtin shall be listed in t0450/adoc-missing. + if grep -q "^$builtin$" "$TEST_DIRECTORY"/t0450/adoc-missing then + test_expect_success "$builtin appropriately marked as not having .adoc" ' + ! test -f "$adoc" + ' + else test_set_prereq "$preq" - fi && + + test_expect_success "$builtin appropriately marked as having .adoc" ' + test -f "$adoc" + ' + fi # *.adoc output assertions test_expect_success "$preq" "$builtin *.adoc SYNOPSIS has dashed labels" ' diff --git a/t/t0450/adoc-missing b/t/t0450/adoc-missing new file mode 100644 index 0000000000..1ec9f8dcf3 --- /dev/null +++ b/t/t0450/adoc-missing @@ -0,0 +1,9 @@ +checkout--worker +merge-ours +merge-recursive +merge-recursive-ours +merge-recursive-theirs +merge-subtree +pickaxe +submodule--helper +upload-archive--writer diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh index d77e601111..e334751759 100755 --- a/t/t0613-reftable-write-options.sh +++ b/t/t0613-reftable-write-options.sh @@ -11,16 +11,18 @@ export GIT_TEST_REFTABLE_AUTOCOMPACTION # Block sizes depend on the hash function, so we force SHA1 here. GIT_TEST_DEFAULT_HASH=sha1 export GIT_TEST_DEFAULT_HASH -# Block sizes also depend on the actual refs we write, so we force "master" to -# be the default initial branch name. -GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master -export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh +# Block sizes depend on the actual refs we write, so, for tests +# that check block size, we force the initial branch name to be "master". +init_repo () { + git init --initial-branch master repo +} + test_expect_success 'default write options' ' test_when_finished "rm -rf repo" && - git init repo && + init_repo && ( cd repo && test_commit initial && @@ -43,7 +45,7 @@ test_expect_success 'default write options' ' test_expect_success 'disabled reflog writes no log blocks' ' test_config_global core.logAllRefUpdates false && test_when_finished "rm -rf repo" && - git init repo && + init_repo && ( cd repo && test_commit initial && @@ -62,7 +64,7 @@ test_expect_success 'disabled reflog writes no log blocks' ' test_expect_success 'many refs results in multiple blocks' ' test_when_finished "rm -rf repo" && - git init repo && + init_repo && ( cd repo && test_commit initial && @@ -115,7 +117,7 @@ test_expect_success 'tiny block size leads to error' ' test_expect_success 'small block size leads to multiple ref blocks' ' test_config_global core.logAllRefUpdates false && test_when_finished "rm -rf repo" && - git init repo && + init_repo && ( cd repo && test_commit A && @@ -172,7 +174,7 @@ test_expect_success 'block size exceeding maximum supported size' ' test_expect_success 'restart interval at every single record' ' test_when_finished "rm -rf repo" && - git init repo && + init_repo && ( cd repo && test_commit initial && @@ -212,7 +214,7 @@ test_expect_success 'restart interval exceeding maximum supported interval' ' test_expect_success 'object index gets written by default with ref index' ' test_config_global core.logAllRefUpdates false && test_when_finished "rm -rf repo" && - git init repo && + init_repo && ( cd repo && test_commit initial && @@ -247,7 +249,7 @@ test_expect_success 'object index gets written by default with ref index' ' test_expect_success 'object index can be disabled' ' test_config_global core.logAllRefUpdates false && test_when_finished "rm -rf repo" && - git init repo && + init_repo && ( cd repo && test_commit initial && diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index b7415ec9d5..db7f5444da 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -2294,6 +2294,59 @@ do ) ' + test_expect_success CASE_INSENSITIVE_FS,REFFILES "stdin $type batch-updates existing reference" ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + test_commit one && + old_head=$(git rev-parse HEAD) && + test_commit two && + head=$(git rev-parse HEAD) && + + { + format_command $type "create refs/heads/foo" "$head" && + format_command $type "create refs/heads/ref" "$old_head" && + format_command $type "create refs/heads/Foo" "$old_head" + } >stdin && + git update-ref $type --stdin --batch-updates <stdin >stdout && + + echo $head >expect && + git rev-parse refs/heads/foo >actual && + echo $old_head >expect && + git rev-parse refs/heads/ref >actual && + test_cmp expect actual && + test_grep -q "reference conflict due to case-insensitive filesystem" stdout + ) + ' + + test_expect_success CASE_INSENSITIVE_FS "stdin $type batch-updates existing reference" ' + git init --ref-format=reftable repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + test_commit one && + old_head=$(git rev-parse HEAD) && + test_commit two && + head=$(git rev-parse HEAD) && + + { + format_command $type "create refs/heads/foo" "$head" && + format_command $type "create refs/heads/ref" "$old_head" && + format_command $type "create refs/heads/Foo" "$old_head" + } >stdin && + git update-ref $type --stdin --batch-updates <stdin >stdout && + + echo $head >expect && + git rev-parse refs/heads/foo >actual && + echo $old_head >expect && + git rev-parse refs/heads/ref >actual && + test_cmp expect actual && + git rev-parse refs/heads/Foo >actual && + test_cmp expect actual + ) + ' + test_expect_success "stdin $type batch-updates delete incorrect symbolic ref" ' git init repo && test_when_finished "rm -fr repo" && diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh index 9da3650e91..36c903ca19 100755 --- a/t/t1403-show-ref.sh +++ b/t/t1403-show-ref.sh @@ -228,69 +228,4 @@ test_expect_success 'show-ref sub-modes are mutually exclusive' ' grep "cannot be used together" err ' -test_expect_success '--exists with existing reference' ' - git show-ref --exists refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME -' - -test_expect_success '--exists with missing reference' ' - test_expect_code 2 git show-ref --exists refs/heads/does-not-exist -' - -test_expect_success '--exists does not use DWIM' ' - test_expect_code 2 git show-ref --exists $GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 2>err && - grep "reference does not exist" err -' - -test_expect_success '--exists with HEAD' ' - git show-ref --exists HEAD -' - -test_expect_success '--exists with bad reference name' ' - test_when_finished "git update-ref -d refs/heads/bad...name" && - new_oid=$(git rev-parse HEAD) && - test-tool ref-store main update-ref msg refs/heads/bad...name $new_oid $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && - git show-ref --exists refs/heads/bad...name -' - -test_expect_success '--exists with arbitrary symref' ' - test_when_finished "git symbolic-ref -d refs/symref" && - git symbolic-ref refs/symref refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME && - git show-ref --exists refs/symref -' - -test_expect_success '--exists with dangling symref' ' - test_when_finished "git symbolic-ref -d refs/heads/dangling" && - git symbolic-ref refs/heads/dangling refs/heads/does-not-exist && - git show-ref --exists refs/heads/dangling -' - -test_expect_success '--exists with nonexistent object ID' ' - test-tool ref-store main update-ref msg refs/heads/missing-oid $(test_oid 001) $ZERO_OID REF_SKIP_OID_VERIFICATION && - git show-ref --exists refs/heads/missing-oid -' - -test_expect_success '--exists with non-commit object' ' - tree_oid=$(git rev-parse HEAD^{tree}) && - test-tool ref-store main update-ref msg refs/heads/tree ${tree_oid} $ZERO_OID REF_SKIP_OID_VERIFICATION && - git show-ref --exists refs/heads/tree -' - -test_expect_success '--exists with directory fails with generic error' ' - cat >expect <<-EOF && - error: reference does not exist - EOF - test_expect_code 2 git show-ref --exists refs/heads 2>err && - test_cmp expect err -' - -test_expect_success '--exists with non-existent special ref' ' - test_expect_code 2 git show-ref --exists FETCH_HEAD -' - -test_expect_success '--exists with existing special ref' ' - test_when_finished "rm .git/FETCH_HEAD" && - git rev-parse HEAD >.git/FETCH_HEAD && - git show-ref --exists FETCH_HEAD -' - test_done diff --git a/t/t1422-show-ref-exists.sh b/t/t1422-show-ref-exists.sh new file mode 100755 index 0000000000..fdca3f16c8 --- /dev/null +++ b/t/t1422-show-ref-exists.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +test_description='show-ref --exists' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +. "$TEST_DIRECTORY"/show-ref-exists-tests.sh diff --git a/t/t1462-refs-exists.sh b/t/t1462-refs-exists.sh new file mode 100755 index 0000000000..349453c4ca --- /dev/null +++ b/t/t1462-refs-exists.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +test_description='refs exists' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +git_show_ref_exists='git refs exists' +. "$TEST_DIRECTORY"/show-ref-exists-tests.sh diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh index a69c715357..2beba67889 100755 --- a/t/t1900-repo.sh +++ b/t/t1900-repo.sh @@ -63,6 +63,12 @@ test_expect_success 'setup remote' ' test_repo_info 'shallow repository = true is retrieved correctly' \ 'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true' +test_repo_info 'object.format = sha1 is retrieved correctly' \ + 'git init --object-format=sha1' 'sha1' 'object.format' 'sha1' + +test_repo_info 'object.format = sha256 is retrieved correctly' \ + 'git init --object-format=sha256' 'sha256' 'object.format' 'sha256' + test_expect_success 'values returned in order requested' ' cat >expect <<-\EOF && layout.bare=false @@ -92,4 +98,16 @@ test_expect_success 'git-repo-info aborts when requesting an invalid format' ' test_cmp expect actual ' +test_expect_success '-z uses nul-terminated format' ' + printf "layout.bare\nfalse\0layout.shallow\nfalse\0" >expected && + git repo info -z layout.bare layout.shallow >actual && + test_cmp expected actual +' + +test_expect_success 'git repo info uses the last requested format' ' + echo "layout.bare=false" >expected && + git repo info --format=nul -z --format=keyvalue layout.bare >actual && + test_cmp expected actual +' + test_done diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 34d6ad0770..e778dd8ae4 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -1176,7 +1176,7 @@ test_expect_success 'rebase -i respects core.commentchar' ' test B = $(git cat-file commit HEAD^ | sed -ne \$p) ' -test_expect_success 'rebase -i respects core.commentchar=auto' ' +test_expect_success !WITH_BREAKING_CHANGES 'rebase -i respects core.commentchar=auto' ' test_config core.commentchar auto && write_script copy-edit-script.sh <<-\EOF && cp "$1" edit-script @@ -1184,8 +1184,23 @@ test_expect_success 'rebase -i respects core.commentchar=auto' ' test_when_finished "git rebase --abort || :" && ( test_set_editor "$(pwd)/copy-edit-script.sh" && - git rebase -i HEAD^ + git rebase -i HEAD^ 2>err ) && + sed -n "s/^hint: *\$//p; s/^hint: //p; s/^warning: //p" err >actual && + cat >expect <<-EOF && + Support for ${SQ}core.commentChar=auto${SQ} is deprecated and will be removed in Git 3.0 + + To use the default comment string (#) please run + + git config unset core.commentChar + + To set a custom comment string please run + + git config set core.commentChar <comment string> + + where ${SQ}<comment string>${SQ} is the string you wish to use. + EOF + test_cmp expect actual && test -z "$(grep -ve "^#" -e "^\$" -e "^pick" edit-script)" ' diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index 5d093e3a7a..5033411a43 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -486,12 +486,28 @@ test_expect_success 'fixup a fixup' ' test XZWY = $(git show | tr -cd W-Z) ' -test_expect_success 'fixup does not clean up commit message' ' - oneline="#818" && - git commit --allow-empty -m "$oneline" && - git commit --fixup HEAD --allow-empty && - git -c commit.cleanup=strip rebase -ki --autosquash HEAD~2 && - test "$oneline" = "$(git show -s --format=%s)" +test_expect_success 'pick and fixup respect commit.cleanup' ' + git reset --hard base && + test_commit --no-tag "fixup! second commit" file1 fixup && + test_commit something && + write_script .git/hooks/prepare-commit-msg <<-\EOF && + printf "\n# Prepared\n" >> "$1" + EOF + git rebase -i --autosquash HEAD~3 && + test_commit_message HEAD~1 <<-\EOF && + second commit + + # Prepared + EOF + test_commit_message HEAD <<-\EOF && + something + + # Prepared + EOF + git reset --hard something && + git -c commit.cleanup=strip rebase -i --autosquash HEAD~3 && + test_commit_message HEAD~1 -m "second commit" && + test_commit_message HEAD -m "something" ' test_done diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index b8a8dd77e7..f9b8999db5 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -328,7 +328,7 @@ test_expect_success 'there is no --no-reschedule-failed-exec in an ongoing rebas test_expect_code 129 git rebase --edit-todo --no-reschedule-failed-exec ' -test_expect_success 'no change in comment character due to conflicts markers with core.commentChar=auto' ' +test_expect_success !WITH_BREAKING_CHANGES 'no change in comment character due to conflicts markers with core.commentChar=auto' ' git checkout -b branch-a && test_commit A F1 && git checkout -b branch-b HEAD^ && diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 04d2a19835..d9fe289a7a 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -866,6 +866,44 @@ test_expect_success 'colorized diffs respect diff.wsErrorHighlight' ' test_grep "old<" output ' +test_expect_success 'diff color respects color.diff' ' + git reset --hard && + + echo old >test && + git add test && + echo new >test && + + printf n >n && + force_color git \ + -c color.interactive=auto \ + -c color.interactive.prompt=blue \ + -c color.diff=false \ + -c color.diff.old=red \ + add -p >output.raw 2>&1 <n && + test_decode_color <output.raw >output && + test_grep "BLUE.*Stage this hunk" output && + test_grep ! "RED" output +' + +test_expect_success 're-coloring diff without color.interactive' ' + git reset --hard && + + test_write_lines 1 2 3 >test && + git add test && + test_write_lines one 2 three >test && + + test_write_lines s n n | + force_color git \ + -c color.interactive=false \ + -c color.interactive.prompt=blue \ + -c color.diff=true \ + -c color.diff.frag="bold magenta" \ + add -p >output.raw 2>&1 && + test_decode_color <output.raw >output && + test_grep "<BOLD;MAGENTA>@@" output && + test_grep ! "BLUE" output +' + test_expect_success 'diffFilter filters diff' ' git reset --hard && @@ -1283,6 +1321,12 @@ test_expect_success 'stash accepts -U and --inter-hunk-context' ' test_grep "@@ -2,20 +2,20 @@" actual ' +test_expect_success 'set up base for -p color tests' ' + echo commit >file && + git commit -am "commit state" && + git tag patch-base +' + for cmd in add checkout commit reset restore "stash save" "stash push" do test_expect_success "$cmd rejects invalid context options" ' @@ -1299,6 +1343,15 @@ do test_must_fail git $cmd --inter-hunk-context 2 2>actual && test_grep -E ".--inter-hunk-context. requires .(--interactive/)?--patch." actual ' + + test_expect_success "$cmd falls back to color.ui" ' + git reset --hard patch-base && + echo working-tree >file && + test_write_lines y | + force_color git -c color.ui=false $cmd -p >output.raw 2>&1 && + test_decode_color <output.raw >output && + test_cmp output.raw output + ' done test_done diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 0bb4648e36..70879941c2 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -902,6 +902,7 @@ test_expect_success 'branch: should not drop the stash if the apply fails' ' test_expect_success 'apply: show same status as git status (relative to ./)' ' git stash clear && + mkdir -p subdir && echo 1 >subdir/subfile1 && echo 2 >subdir/subfile2 && git add subdir/subfile1 && @@ -1356,6 +1357,7 @@ test_expect_success 'stash -k -- <pathspec> leaves unstaged files intact' ' test_expect_success 'stash -- <subdir> leaves untracked files in subdir intact' ' git reset && + mkdir -p subdir && >subdir/untracked && >subdir/tracked1 && >subdir/tracked2 && @@ -1372,6 +1374,7 @@ test_expect_success 'stash -- <subdir> leaves untracked files in subdir intact' test_expect_success 'stash -- <subdir> works with binary files' ' git reset && + mkdir -p subdir && >subdir/untracked && >subdir/tracked && cp "$TEST_DIRECTORY"/test-binary-1.png subdir/tracked-binary && @@ -1741,4 +1744,50 @@ test_expect_success 'submodules does not affect the branch recorded in stash mes ) ' +test_expect_success SANITIZE_LEAK 'stash show handles -- without leaking' ' + git stash show -- +' + +test_expect_success 'controlled error return on unrecognized option' ' + test_expect_code 129 git stash show -p --invalid 2>usage && + grep -e "^usage: git stash show" usage +' + +test_expect_success 'stash.index=true implies --index' ' + # setup for a few related tests + test_commit file base && + echo index >file && + git add file && + echo working >file && + git stash && + + test_when_finished "git reset --hard" && + git -c stash.index=true stash apply && + echo index >expect && + git show :0:file >actual && + test_cmp expect actual && + echo working >expect && + test_cmp expect file +' + +test_expect_success 'stash.index=true overridden by --no-index' ' + test_when_finished "git reset --hard" && + git -c stash.index=true stash apply --no-index && + echo base >expect && + git show :0:file >actual && + test_cmp expect actual && + echo working >expect && + test_cmp expect file +' + +test_expect_success 'stash.index=false overridden by --index' ' + test_when_finished "git reset --hard" && + git -c stash.index=false stash apply --index && + echo index >expect && + git show :0:file >actual && + test_cmp expect actual && + echo working >expect && + test_cmp expect file +' + test_done diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh index ae313e3c70..90a4ff2c10 100755 --- a/t/t3904-stash-patch.sh +++ b/t/t3904-stash-patch.sh @@ -107,4 +107,23 @@ test_expect_success 'stash -p with split hunk' ' ! grep "added line 2" test ' +test_expect_success 'stash -p not confused by GIT_PAGER_IN_USE' ' + echo to-stash >test && + # Set both GIT_PAGER_IN_USE and TERM. Our goal is to entice any + # diff subprocesses into thinking that they could output + # color, even though their stdout is not going into a tty. + echo y | + GIT_PAGER_IN_USE=1 TERM=vt100 git stash -p && + git diff --exit-code +' + +test_expect_success 'index push not confused by GIT_PAGER_IN_USE' ' + echo index >test && + git add test && + echo working-tree >test && + # As above, we try to entice the child diff into using color. + GIT_PAGER_IN_USE=1 TERM=vt100 git stash push test && + git diff --exit-code +' + test_done diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh index 1289ae3e07..7704709054 100755 --- a/t/t3905-stash-include-untracked.sh +++ b/t/t3905-stash-include-untracked.sh @@ -87,7 +87,6 @@ test_expect_success 'stash save --patch --all fails' ' test_expect_success 'clean up untracked/untracked file to prepare for next tests' ' git clean --force --quiet - ' test_expect_success 'stash pop after save --include-untracked leaves files untracked again' ' diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index cfeec239e0..55a06eadb3 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -5,7 +5,7 @@ test_description='Various diff formatting options' -GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh @@ -70,7 +70,7 @@ test_expect_success setup ' GIT_COMMITTER_DATE="2006-06-26 00:04:00 +0000" && export GIT_AUTHOR_DATE GIT_COMMITTER_DATE && - git checkout master && + git checkout main && git pull -s ours --no-rebase . side && GIT_AUTHOR_DATE="2006-06-26 00:05:00 +0000" && @@ -95,7 +95,7 @@ test_expect_success setup ' test_write_lines B A >dir/sub && git add dir/sub && git commit -m "Rearranged lines in dir/sub" && - git checkout master && + git checkout main && GIT_AUTHOR_DATE="2006-06-26 00:06:00 +0000" && GIT_COMMITTER_DATE="2006-06-26 00:06:00 +0000" && @@ -103,7 +103,7 @@ test_expect_success setup ' git checkout -b mode initial && git update-index --chmod=+x file0 && git commit -m "update mode" && - git checkout -f master && + git checkout -f main && GIT_AUTHOR_DATE="2006-06-26 00:06:00 +0000" && GIT_COMMITTER_DATE="2006-06-26 00:06:00 +0000" && @@ -112,12 +112,12 @@ test_expect_success setup ' git update-index --chmod=+x file2 && git commit -m "update mode (file2)" && git notes add -m "note" && - git checkout -f master && + git checkout -f main && - # Same merge as master, but with parents reversed. Hide it in a + # Same merge as main, but with parents reversed. Hide it in a # pseudo-ref to avoid impacting tests with --all. commit=$(echo reverse | - git commit-tree -p master^2 -p master^1 master^{tree}) && + git commit-tree -p main^2 -p main^1 main^{tree}) && git update-ref REVERSE $commit && git config diff.renames false && @@ -127,15 +127,15 @@ test_expect_success setup ' : <<\EOF ! [initial] Initial - * [master] Merge branch 'side' + * [main] Merge branch 'side' ! [rearrange] Rearranged lines in dir/sub ! [side] Side ---- + [rearrange] Rearranged lines in dir/sub - - [master] Merge branch 'side' + - [main] Merge branch 'side' * + [side] Side - * [master^] Third - * [master~2] Second + * [main^] Third + * [main~2] Second +*++ [initial] Initial EOF @@ -311,64 +311,64 @@ diff-tree initial mode diff-tree --stat initial mode diff-tree --summary initial mode -diff-tree master -diff-tree -m master -diff-tree -p master -diff-tree -p -m master -diff-tree -c master -diff-tree -c --abbrev master -:noellipses diff-tree -c --abbrev master -diff-tree --cc master +diff-tree main +diff-tree -m main +diff-tree -p main +diff-tree -p -m main +diff-tree -c main +diff-tree -c --abbrev main +:noellipses diff-tree -c --abbrev main +diff-tree --cc main # stat only should show the diffstat with the first parent -diff-tree -c --stat master -diff-tree --cc --stat master -diff-tree -c --stat --summary master -diff-tree --cc --stat --summary master +diff-tree -c --stat main +diff-tree --cc --stat main +diff-tree -c --stat --summary main +diff-tree --cc --stat --summary main # stat summary should show the diffstat and summary with the first parent diff-tree -c --stat --summary side diff-tree --cc --stat --summary side -diff-tree --cc --shortstat master +diff-tree --cc --shortstat main diff-tree --cc --summary REVERSE # improved by Timo's patch -diff-tree --cc --patch-with-stat master +diff-tree --cc --patch-with-stat main # improved by Timo's patch -diff-tree --cc --patch-with-stat --summary master +diff-tree --cc --patch-with-stat --summary main # this is correct diff-tree --cc --patch-with-stat --summary side -log master -log -p master -log --root master -log --root -p master -log --patch-with-stat master -log --root --patch-with-stat master -log --root --patch-with-stat --summary master +log main +log -p main +log --root main +log --root -p main +log --patch-with-stat main +log --root --patch-with-stat main +log --root --patch-with-stat --summary main # improved by Timo's patch -log --root -c --patch-with-stat --summary master +log --root -c --patch-with-stat --summary main # improved by Timo's patch -log --root --cc --patch-with-stat --summary master -log --no-diff-merges -p --first-parent master -log --diff-merges=off -p --first-parent master -log --first-parent --diff-merges=off -p master -log -p --first-parent master -log -p --diff-merges=first-parent master -log --diff-merges=first-parent master -log -m -p --first-parent master -log -m -p master -log --cc -m -p master -log -c -m -p master -log -m --raw master -log -m --stat master -log -SF master -log -S F master -log -SF -p master -log -SF master --max-count=0 -log -SF master --max-count=1 -log -SF master --max-count=2 -log -GF master -log -GF -p master -log -GF -p --pickaxe-all master -log -IA -IB -I1 -I2 -p master +log --root --cc --patch-with-stat --summary main +log --no-diff-merges -p --first-parent main +log --diff-merges=off -p --first-parent main +log --first-parent --diff-merges=off -p main +log -p --first-parent main +log -p --diff-merges=first-parent main +log --diff-merges=first-parent main +log -m -p --first-parent main +log -m -p main +log --cc -m -p main +log -c -m -p main +log -m --raw main +log -m --stat main +log -SF main +log -S F main +log -SF -p main +log -SF main --max-count=0 +log -SF main --max-count=1 +log -SF main --max-count=2 +log -GF main +log -GF -p main +log -GF -p --pickaxe-all main +log -IA -IB -I1 -I2 -p main log --decorate --all log --decorate=full --all log --decorate --clear-decorations --all @@ -377,35 +377,35 @@ log --decorate=full --clear-decorations --all rev-list --parents HEAD rev-list --children HEAD -whatchanged master -:noellipses whatchanged master -whatchanged -p master -whatchanged --root master -:noellipses whatchanged --root master -whatchanged --root -p master -whatchanged --patch-with-stat master -whatchanged --root --patch-with-stat master -whatchanged --root --patch-with-stat --summary master +whatchanged main +:noellipses whatchanged main +whatchanged -p main +whatchanged --root main +:noellipses whatchanged --root main +whatchanged --root -p main +whatchanged --patch-with-stat main +whatchanged --root --patch-with-stat main +whatchanged --root --patch-with-stat --summary main # improved by Timo's patch -whatchanged --root -c --patch-with-stat --summary master +whatchanged --root -c --patch-with-stat --summary main # improved by Timo's patch -whatchanged --root --cc --patch-with-stat --summary master -whatchanged -SF master -:noellipses whatchanged -SF master -whatchanged -SF -p master +whatchanged --root --cc --patch-with-stat --summary main +whatchanged -SF main +:noellipses whatchanged -SF main +whatchanged -SF -p main -log --patch-with-stat master -- dir/ -whatchanged --patch-with-stat master -- dir/ -log --patch-with-stat --summary master -- dir/ -whatchanged --patch-with-stat --summary master -- dir/ +log --patch-with-stat main -- dir/ +whatchanged --patch-with-stat main -- dir/ +log --patch-with-stat --summary main -- dir/ +whatchanged --patch-with-stat --summary main -- dir/ show initial show --root initial show side -show master -show -c master -show -m master -show --first-parent master +show main +show -c main +show -m main +show --first-parent main show --stat side show --stat --summary side show --patch-with-stat side @@ -414,22 +414,22 @@ show --patch-with-raw side show --patch-with-stat --summary side format-patch --stdout initial..side -format-patch --stdout initial..master^ -format-patch --stdout initial..master -format-patch --stdout --no-numbered initial..master -format-patch --stdout --numbered initial..master +format-patch --stdout initial..main^ +format-patch --stdout initial..main +format-patch --stdout --no-numbered initial..main +format-patch --stdout --numbered initial..main format-patch --attach --stdout initial..side format-patch --attach --stdout --suffix=.diff initial..side -format-patch --attach --stdout initial..master^ -format-patch --attach --stdout initial..master +format-patch --attach --stdout initial..main^ +format-patch --attach --stdout initial..main format-patch --inline --stdout initial..side -format-patch --inline --stdout initial..master^ -format-patch --inline --stdout --numbered-files initial..master -format-patch --inline --stdout initial..master -format-patch --inline --stdout --subject-prefix=TESTCASE initial..master +format-patch --inline --stdout initial..main^ +format-patch --inline --stdout --numbered-files initial..main +format-patch --inline --stdout initial..main +format-patch --inline --stdout --subject-prefix=TESTCASE initial..main config format.subjectprefix DIFFERENT_PREFIX -format-patch --inline --stdout initial..master^^ -format-patch --stdout --cover-letter -n initial..master^ +format-patch --inline --stdout initial..main^^ +format-patch --stdout --cover-letter -n initial..main^ diff --abbrev initial..side diff -U initial..side @@ -448,13 +448,13 @@ diff --name-status dir2 dir diff --no-index --name-status dir2 dir diff --no-index --name-status -- dir2 dir diff --no-index dir dir3 -diff master master^ side +diff main main^ side # Can't use spaces... -diff --line-prefix=abc master master^ side -diff --dirstat master~1 master~2 +diff --line-prefix=abc main main^ side +diff --dirstat main~1 main~2 diff --dirstat initial rearrange diff --dirstat-by-file initial rearrange -diff --dirstat --cc master~1 master +diff --dirstat --cc main~1 main # No-index --abbrev and --no-abbrev diff --raw initial :noellipses diff --raw initial @@ -482,7 +482,7 @@ test_expect_success !WITH_BREAKING_CHANGES 'whatchanged needs --i-still-use-this ' test_expect_success 'log -m matches pure log' ' - git log master >result && + git log main >result && process_diffs result >expected && git log -m >result && process_diffs result >actual && @@ -490,17 +490,17 @@ test_expect_success 'log -m matches pure log' ' ' test_expect_success 'log --diff-merges=on matches --diff-merges=separate' ' - git log -p --diff-merges=separate master >result && + git log -p --diff-merges=separate main >result && process_diffs result >expected && - git log -p --diff-merges=on master >result && + git log -p --diff-merges=on main >result && process_diffs result >actual && test_cmp expected actual ' test_expect_success 'log --dd matches --diff-merges=1 -p' ' - git log --diff-merges=1 -p master >result && + git log --diff-merges=1 -p main >result && process_diffs result >expected && - git log --dd master >result && + git log --dd main >result && process_diffs result >actual && test_cmp expected actual ' @@ -511,19 +511,19 @@ test_expect_success 'deny wrong log.diffMerges config' ' ' test_expect_success 'git config log.diffMerges first-parent' ' - git log -p --diff-merges=first-parent master >result && + git log -p --diff-merges=first-parent main >result && process_diffs result >expected && test_config log.diffMerges first-parent && - git log -p --diff-merges=on master >result && + git log -p --diff-merges=on main >result && process_diffs result >actual && test_cmp expected actual ' test_expect_success 'git config log.diffMerges first-parent vs -m' ' - git log -p --diff-merges=first-parent master >result && + git log -p --diff-merges=first-parent main >result && process_diffs result >expected && test_config log.diffMerges first-parent && - git log -p -m master >result && + git log -p -m main >result && process_diffs result >actual && test_cmp expected actual ' @@ -572,7 +572,7 @@ test_expect_success 'diff-tree --stdin with log formatting' ' Third Second EOF - git rev-list master | git diff-tree --stdin --format=%s -s >actual && + git rev-list main | git diff-tree --stdin --format=%s -s >actual && test_cmp expect actual ' @@ -585,16 +585,16 @@ test_expect_success 'diff-tree --stdin with pathspec' ' dir/sub EOF - git rev-list master^ | + git rev-list main^ | git diff-tree -r --stdin --name-only --format=%s dir >actual && test_cmp expect actual ' test_expect_success 'show A B ... -- <pathspec>' ' # side touches dir/sub, file0, and file3 - # master^ touches dir/sub, and file1 - # master^^ touches dir/sub, file0, and file2 - git show --name-only --format="<%s>" side master^ master^^ -- dir >actual && + # main^ touches dir/sub, and file1 + # main^^ touches dir/sub, file0, and file2 + git show --name-only --format="<%s>" side main^ main^^ -- dir >actual && cat >expect <<-\EOF && <Side> @@ -610,7 +610,7 @@ test_expect_success 'show A B ... -- <pathspec>' ' ' test_expect_success 'diff -I<regex>: setup' ' - git checkout master && + git checkout main && test_seq 50 >file0 && git commit -m "Set up -I<regex> test file" file0 && test_seq 50 | sed -e "s/13/ten and three/" -e "/7\$/d" >file0 && diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_main index 9951e3677d..af1cf20f4c 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_main @@ -1,4 +1,4 @@ -$ git diff-tree --cc --patch-with-stat --summary master +$ git diff-tree --cc --patch-with-stat --summary main 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_main index db3c0a7b2c..0ec6042097 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_main @@ -1,4 +1,4 @@ -$ git diff-tree --cc --patch-with-stat master +$ git diff-tree --cc --patch-with-stat main 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.diff-tree_--cc_--shortstat_master b/t/t4013/diff.diff-tree_--cc_--shortstat_main index a4ca42df2a..9a4ef03197 100644 --- a/t/t4013/diff.diff-tree_--cc_--shortstat_master +++ b/t/t4013/diff.diff-tree_--cc_--shortstat_main @@ -1,4 +1,4 @@ -$ git diff-tree --cc --shortstat master +$ git diff-tree --cc --shortstat main 59d314ad6f356dd08601a4cd5e530381da3e3c64 2 files changed, 5 insertions(+) $ diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--stat_--summary_main index 81c3021541..9db08a4aa9 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_main @@ -1,4 +1,4 @@ -$ git diff-tree -c --stat --summary master +$ git diff-tree --cc --stat --summary main 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.diff-tree_-c_--stat_master b/t/t4013/diff.diff-tree_--cc_--stat_main index 89d59b1548..7ecc67a524 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_main @@ -1,4 +1,4 @@ -$ git diff-tree -c --stat master +$ git diff-tree --cc --stat main 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.diff-tree_--cc_master b/t/t4013/diff.diff-tree_--cc_main index 5ecb4e14ae..1a962856ad 100644 --- a/t/t4013/diff.diff-tree_--cc_master +++ b/t/t4013/diff.diff-tree_--cc_main @@ -1,4 +1,4 @@ -$ git diff-tree --cc master +$ git diff-tree --cc main 59d314ad6f356dd08601a4cd5e530381da3e3c64 diff --cc dir/sub index cead32e,7289e35..992913c diff --git a/t/t4013/diff.diff-tree_-c_--abbrev_master b/t/t4013/diff.diff-tree_-c_--abbrev_main index b8e4aa2530..039d127cf2 100644 --- a/t/t4013/diff.diff-tree_-c_--abbrev_master +++ b/t/t4013/diff.diff-tree_-c_--abbrev_main @@ -1,4 +1,4 @@ -$ git diff-tree -c --abbrev master +$ git diff-tree -c --abbrev main 59d314ad6f356dd08601a4cd5e530381da3e3c64 ::100644 100644 100644 cead32e... 7289e35... 992913c... MM dir/sub ::100644 100644 100644 b414108... f4615da... 10a8a9f... MM file0 diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master b/t/t4013/diff.diff-tree_-c_--stat_--summary_main index d019867dd9..05a8d16ba7 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_main @@ -1,4 +1,4 @@ -$ git diff-tree --cc --stat --summary master +$ git diff-tree -c --stat --summary main 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.diff-tree_--cc_--stat_master b/t/t4013/diff.diff-tree_-c_--stat_main index 40b91796b3..61d9f450df 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_master +++ b/t/t4013/diff.diff-tree_-c_--stat_main @@ -1,4 +1,4 @@ -$ git diff-tree --cc --stat master +$ git diff-tree -c --stat main 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.diff-tree_-c_master b/t/t4013/diff.diff-tree_-c_main index e2d2bb2611..a84e1185cf 100644 --- a/t/t4013/diff.diff-tree_-c_master +++ b/t/t4013/diff.diff-tree_-c_main @@ -1,4 +1,4 @@ -$ git diff-tree -c master +$ git diff-tree -c main 59d314ad6f356dd08601a4cd5e530381da3e3c64 ::100644 100644 100644 cead32e925b1420c84c14cbf7cf755e7e45af8ad 7289e35bff32727c08dda207511bec138fdb9ea5 992913c5aa0a5476d10c49ed0f21fc0c6d1aedf3 MM dir/sub ::100644 100644 100644 b414108e81e5091fe0974a1858b4d0d22b107f70 f4615da674c09df322d6ba8d6b21ecfb1b1ba510 10a8a9f3657f91a156b9f0184ed79a20adef9f7f MM file0 diff --git a/t/t4013/diff.diff-tree_-m_master b/t/t4013/diff.diff-tree_-m_main index 6d0a2207fb..5da1f7f525 100644 --- a/t/t4013/diff.diff-tree_-m_master +++ b/t/t4013/diff.diff-tree_-m_main @@ -1,4 +1,4 @@ -$ git diff-tree -m master +$ git diff-tree -m main 59d314ad6f356dd08601a4cd5e530381da3e3c64 :040000 040000 65f5c9dd60ce3b2b3324b618ac7accf8d912c113 0564e026437809817a64fff393079714b6dd4628 M dir :100644 100644 b414108e81e5091fe0974a1858b4d0d22b107f70 10a8a9f3657f91a156b9f0184ed79a20adef9f7f M file0 diff --git a/t/t4013/diff.diff-tree_-p_-m_master b/t/t4013/diff.diff-tree_-p_-m_main index b60bea039d..29c9fc20b8 100644 --- a/t/t4013/diff.diff-tree_-p_-m_master +++ b/t/t4013/diff.diff-tree_-p_-m_main @@ -1,4 +1,4 @@ -$ git diff-tree -p -m master +$ git diff-tree -p -m main 59d314ad6f356dd08601a4cd5e530381da3e3c64 diff --git a/dir/sub b/dir/sub index cead32e..992913c 100644 diff --git a/t/t4013/diff.diff-tree_-p_main b/t/t4013/diff.diff-tree_-p_main new file mode 100644 index 0000000000..c658062422 --- /dev/null +++ b/t/t4013/diff.diff-tree_-p_main @@ -0,0 +1,2 @@ +$ git diff-tree -p main +$ diff --git a/t/t4013/diff.diff-tree_-p_master b/t/t4013/diff.diff-tree_-p_master deleted file mode 100644 index b182875fb2..0000000000 --- a/t/t4013/diff.diff-tree_-p_master +++ /dev/null @@ -1,2 +0,0 @@ -$ git diff-tree -p master -$ diff --git a/t/t4013/diff.diff-tree_main b/t/t4013/diff.diff-tree_main new file mode 100644 index 0000000000..dc5b9fdeb6 --- /dev/null +++ b/t/t4013/diff.diff-tree_main @@ -0,0 +1,2 @@ +$ git diff-tree main +$ diff --git a/t/t4013/diff.diff-tree_master b/t/t4013/diff.diff-tree_master deleted file mode 100644 index fe9226f8a1..0000000000 --- a/t/t4013/diff.diff-tree_master +++ /dev/null @@ -1,2 +0,0 @@ -$ git diff-tree master -$ diff --git a/t/t4013/diff.diff_--dirstat_--cc_main~1_main b/t/t4013/diff.diff_--dirstat_--cc_main~1_main new file mode 100644 index 0000000000..168a357a02 --- /dev/null +++ b/t/t4013/diff.diff_--dirstat_--cc_main~1_main @@ -0,0 +1,3 @@ +$ git diff --dirstat --cc main~1 main + 40.0% dir/ +$ diff --git a/t/t4013/diff.diff_--dirstat_--cc_master~1_master b/t/t4013/diff.diff_--dirstat_--cc_master~1_master deleted file mode 100644 index fba4e34175..0000000000 --- a/t/t4013/diff.diff_--dirstat_--cc_master~1_master +++ /dev/null @@ -1,3 +0,0 @@ -$ git diff --dirstat --cc master~1 master - 40.0% dir/ -$ diff --git a/t/t4013/diff.diff_--dirstat_main~1_main~2 b/t/t4013/diff.diff_--dirstat_main~1_main~2 new file mode 100644 index 0000000000..6809733708 --- /dev/null +++ b/t/t4013/diff.diff_--dirstat_main~1_main~2 @@ -0,0 +1,3 @@ +$ git diff --dirstat main~1 main~2 + 40.0% dir/ +$ diff --git a/t/t4013/diff.diff_--dirstat_master~1_master~2 b/t/t4013/diff.diff_--dirstat_master~1_master~2 deleted file mode 100644 index b672e1ca63..0000000000 --- a/t/t4013/diff.diff_--dirstat_master~1_master~2 +++ /dev/null @@ -1,3 +0,0 @@ -$ git diff --dirstat master~1 master~2 - 40.0% dir/ -$ diff --git a/t/t4013/diff.diff_--line-prefix=abc_master_master^_side b/t/t4013/diff.diff_--line-prefix=abc_main_main^_side index 99f91e7f0e..67a2145a36 100644 --- a/t/t4013/diff.diff_--line-prefix=abc_master_master^_side +++ b/t/t4013/diff.diff_--line-prefix=abc_main_main^_side @@ -1,4 +1,4 @@ -$ git diff --line-prefix=abc master master^ side +$ git diff --line-prefix=abc main main^ side abcdiff --cc dir/sub abcindex cead32e,7289e35..992913c abc--- a/dir/sub diff --git a/t/t4013/diff.diff_master_master^_side b/t/t4013/diff.diff_main_main^_side index 50ec9cadd6..ab81ec9e47 100644 --- a/t/t4013/diff.diff_master_master^_side +++ b/t/t4013/diff.diff_main_main^_side @@ -1,4 +1,4 @@ -$ git diff master master^ side +$ git diff main main^ side diff --cc dir/sub index cead32e,7289e35..992913c --- a/dir/sub diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..main index 52fedc179e..9f56380350 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..main @@ -1,4 +1,4 @@ -$ git format-patch --attach --stdout initial..master +$ git format-patch --attach --stdout initial..main From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..main^ index 1c3cde251b..80132ea99e 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..main^ @@ -1,4 +1,4 @@ -$ git format-patch --attach --stdout initial..master^ +$ git format-patch --attach --stdout initial..main^ From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..main index 02c4db7ec5..8e889090fb 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..main @@ -1,4 +1,4 @@ -$ git format-patch --inline --stdout --numbered-files initial..master +$ git format-patch --inline --stdout --numbered-files initial..main From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..main index c7677c5951..d7d2b12d15 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..main @@ -1,4 +1,4 @@ -$ git format-patch --inline --stdout --subject-prefix=TESTCASE initial..master +$ git format-patch --inline --stdout --subject-prefix=TESTCASE initial..main From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_initial..main index 5b3e34e2c0..c49c423f82 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..main @@ -1,4 +1,4 @@ -$ git format-patch --inline --stdout initial..master +$ git format-patch --inline --stdout initial..main From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..main^ index d13f8a8128..8669dbfe6c 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..main^ @@ -1,4 +1,4 @@ -$ git format-patch --inline --stdout initial..master^ +$ git format-patch --inline --stdout initial..main^ From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..main^^ index caec5537de..b749be58b0 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..main^^ @@ -1,4 +1,4 @@ -$ git format-patch --inline --stdout initial..master^^ +$ git format-patch --inline --stdout initial..main^^ From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..main^ index 244d964fc6..567f222198 100644 --- a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..main^ @@ -1,4 +1,4 @@ -$ git format-patch --stdout --cover-letter -n initial..master^ +$ git format-patch --stdout --cover-letter -n initial..main^ From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: C O Mitter <committer@example.com> Date: Mon, 26 Jun 2006 00:06:00 +0000 diff --git a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..main index bfc287a147..195b62ea4f 100644 --- a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master +++ b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..main @@ -1,4 +1,4 @@ -$ git format-patch --stdout --no-numbered initial..master +$ git format-patch --stdout --no-numbered initial..main From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--numbered_initial..main index 568f6f584e..0678a38515 100644 --- a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master +++ b/t/t4013/diff.format-patch_--stdout_--numbered_initial..main @@ -1,4 +1,4 @@ -$ git format-patch --stdout --numbered initial..master +$ git format-patch --stdout --numbered initial..main From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..main index 5f0352f9f7..b4a6302e7c 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--stdout_initial..main @@ -1,4 +1,4 @@ -$ git format-patch --stdout initial..master +$ git format-patch --stdout initial..main From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..main^ index 2ae454d807..36b3221582 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_initial..main^ @@ -1,4 +1,4 @@ -$ git format-patch --stdout initial..master^ +$ git format-patch --stdout initial..main^ From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 diff --git a/t/t4013/diff.log_-c_-m_-p_master b/t/t4013/diff.log_--cc_-m_-p_main index b660f3d5f2..f32746ea3e 100644 --- a/t/t4013/diff.log_-c_-m_-p_master +++ b/t/t4013/diff.log_--cc_-m_-p_main @@ -1,4 +1,4 @@ -$ git log -c -m -p master +$ git log --cc -m -p main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--decorate=full_--all b/t/t4013/diff.log_--decorate=full_--all index 6b0b334a5d..c099399525 100644 --- a/t/t4013/diff.log_--decorate=full_--all +++ b/t/t4013/diff.log_--decorate=full_--all @@ -26,7 +26,7 @@ Date: Mon Jun 26 00:06:00 2006 +0000 Notes added by 'git notes add' -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> refs/heads/master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> refs/heads/main) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.log_--decorate=full_--clear-decorations_--all b/t/t4013/diff.log_--decorate=full_--clear-decorations_--all index 1c030a6554..c43684e536 100644 --- a/t/t4013/diff.log_--decorate=full_--clear-decorations_--all +++ b/t/t4013/diff.log_--decorate=full_--clear-decorations_--all @@ -26,7 +26,7 @@ Date: Mon Jun 26 00:06:00 2006 +0000 Notes added by 'git notes add' -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> refs/heads/master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> refs/heads/main) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.log_--decorate=full_--decorate-all_--all b/t/t4013/diff.log_--decorate=full_--decorate-all_--all index d6e7928784..48dca61681 100644 --- a/t/t4013/diff.log_--decorate=full_--decorate-all_--all +++ b/t/t4013/diff.log_--decorate=full_--decorate-all_--all @@ -26,7 +26,7 @@ Date: Mon Jun 26 00:06:00 2006 +0000 Notes added by 'git notes add' -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> refs/heads/master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> refs/heads/main) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.log_--decorate_--all b/t/t4013/diff.log_--decorate_--all index c7df1f5814..8bbf891f65 100644 --- a/t/t4013/diff.log_--decorate_--all +++ b/t/t4013/diff.log_--decorate_--all @@ -26,7 +26,7 @@ Date: Mon Jun 26 00:06:00 2006 +0000 Notes added by 'git notes add' -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> main) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.log_--decorate_--clear-decorations_--all b/t/t4013/diff.log_--decorate_--clear-decorations_--all index 88be82cce3..86b1353f51 100644 --- a/t/t4013/diff.log_--decorate_--clear-decorations_--all +++ b/t/t4013/diff.log_--decorate_--clear-decorations_--all @@ -26,7 +26,7 @@ Date: Mon Jun 26 00:06:00 2006 +0000 Notes added by 'git notes add' -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> main) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.log_--decorate_--decorate-all_--all b/t/t4013/diff.log_--decorate_--decorate-all_--all index 5d22618bb6..59fb17bfc5 100644 --- a/t/t4013/diff.log_--decorate_--decorate-all_--all +++ b/t/t4013/diff.log_--decorate_--decorate-all_--all @@ -26,7 +26,7 @@ Date: Mon Jun 26 00:06:00 2006 +0000 Notes added by 'git notes add' -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> main) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.log_--diff-merges=first-parent_master b/t/t4013/diff.log_--diff-merges=first-parent_main index fa63a557dd..bacee621e5 100644 --- a/t/t4013/diff.log_--diff-merges=first-parent_master +++ b/t/t4013/diff.log_--diff-merges=first-parent_main @@ -1,4 +1,4 @@ -$ git log --diff-merges=first-parent master +$ git log --diff-merges=first-parent main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--no-diff-merges_-p_--first-parent_master b/t/t4013/diff.log_--diff-merges=off_-p_--first-parent_main index 597002232e..fe180fda3b 100644 --- a/t/t4013/diff.log_--no-diff-merges_-p_--first-parent_master +++ b/t/t4013/diff.log_--diff-merges=off_-p_--first-parent_main @@ -1,4 +1,4 @@ -$ git log --no-diff-merges -p --first-parent master +$ git log --diff-merges=off -p --first-parent main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--first-parent_--diff-merges=off_-p_master b/t/t4013/diff.log_--first-parent_--diff-merges=off_-p_main index 5d7461a167..dca62d4e60 100644 --- a/t/t4013/diff.log_--first-parent_--diff-merges=off_-p_master +++ b/t/t4013/diff.log_--first-parent_--diff-merges=off_-p_main @@ -1,4 +1,4 @@ -$ git log --first-parent --diff-merges=off -p master +$ git log --first-parent --diff-merges=off -p main commit 80e25ffa65bcdbe82ef654b4d06dbbde7945c37f Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--diff-merges=off_-p_--first-parent_master b/t/t4013/diff.log_--no-diff-merges_-p_--first-parent_main index 194e893c94..0b54118088 100644 --- a/t/t4013/diff.log_--diff-merges=off_-p_--first-parent_master +++ b/t/t4013/diff.log_--no-diff-merges_-p_--first-parent_main @@ -1,4 +1,4 @@ -$ git log --diff-merges=off -p --first-parent master +$ git log --no-diff-merges -p --first-parent main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_--summary_main_--_dir_ index a18f1472a9..3ed46cc867 100644 --- a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_--summary_main_--_dir_ @@ -1,4 +1,4 @@ -$ git log --patch-with-stat --summary master -- dir/ +$ git log --patch-with-stat --summary main -- dir/ commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--patch-with-stat_master b/t/t4013/diff.log_--patch-with-stat_main index ae425c4672..2e12b557cb 100644 --- a/t/t4013/diff.log_--patch-with-stat_master +++ b/t/t4013/diff.log_--patch-with-stat_main @@ -1,4 +1,4 @@ -$ git log --patch-with-stat master +$ git log --patch-with-stat main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_main_--_dir_ index d5207cadf4..d511ea7f6b 100644 --- a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_main_--_dir_ @@ -1,4 +1,4 @@ -$ git log --patch-with-stat master -- dir/ +$ git log --patch-with-stat main -- dir/ commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_main index 0fc1e8cd71..3cfd0e6422 100644 --- a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_main @@ -1,4 +1,4 @@ -$ git log --root --cc --patch-with-stat --summary master +$ git log --root --cc --patch-with-stat --summary main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--patch-with-stat_--summary_main index dffc09dde9..9f4d6dfa44 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_--summary_main @@ -1,4 +1,4 @@ -$ git log --root --patch-with-stat --summary master +$ git log --root --patch-with-stat --summary main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--root_--patch-with-stat_master b/t/t4013/diff.log_--root_--patch-with-stat_main index 55aa98012d..0d69ae2e11 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_main @@ -1,4 +1,4 @@ -$ git log --root --patch-with-stat master +$ git log --root --patch-with-stat main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_main index 019d85f7de..1b71add9de 100644 --- a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_main @@ -1,4 +1,4 @@ -$ git log --root -c --patch-with-stat --summary master +$ git log --root -c --patch-with-stat --summary main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--root_-p_master b/t/t4013/diff.log_--root_-p_main index b42c334439..04581296ed 100644 --- a/t/t4013/diff.log_--root_-p_master +++ b/t/t4013/diff.log_--root_-p_main @@ -1,4 +1,4 @@ -$ git log --root -p master +$ git log --root -p main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--root_master b/t/t4013/diff.log_--root_main index e8f46159da..d5e90fd6b4 100644 --- a/t/t4013/diff.log_--root_master +++ b/t/t4013/diff.log_--root_main @@ -1,4 +1,4 @@ -$ git log --root master +$ git log --root main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-GF_-p_--pickaxe-all_master b/t/t4013/diff.log_-GF_-p_--pickaxe-all_main index d36f88098b..1f7a497c2d 100644 --- a/t/t4013/diff.log_-GF_-p_--pickaxe-all_master +++ b/t/t4013/diff.log_-GF_-p_--pickaxe-all_main @@ -1,4 +1,4 @@ -$ git log -GF -p --pickaxe-all master +$ git log -GF -p --pickaxe-all main commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-GF_-p_master b/t/t4013/diff.log_-GF_-p_main index 9d93f2c23a..c80dda41e9 100644 --- a/t/t4013/diff.log_-GF_-p_master +++ b/t/t4013/diff.log_-GF_-p_main @@ -1,4 +1,4 @@ -$ git log -GF -p master +$ git log -GF -p main commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-SF_master b/t/t4013/diff.log_-GF_main index c1599f2f52..b94a7f7839 100644 --- a/t/t4013/diff.log_-SF_master +++ b/t/t4013/diff.log_-GF_main @@ -1,4 +1,4 @@ -$ git log -SF master +$ git log -GF main commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-IA_-IB_-I1_-I2_-p_master b/t/t4013/diff.log_-IA_-IB_-I1_-I2_-p_main index 929f35a05b..67e26b4e54 100644 --- a/t/t4013/diff.log_-IA_-IB_-I1_-I2_-p_master +++ b/t/t4013/diff.log_-IA_-IB_-I1_-I2_-p_main @@ -1,4 +1,4 @@ -$ git log -IA -IB -I1 -I2 -p master +$ git log -IA -IB -I1 -I2 -p main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-SF_-p_master b/t/t4013/diff.log_-SF_-p_main index 5e32438972..fa82ac1490 100644 --- a/t/t4013/diff.log_-SF_-p_master +++ b/t/t4013/diff.log_-SF_-p_main @@ -1,4 +1,4 @@ -$ git log -SF -p master +$ git log -SF -p main commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-GF_master b/t/t4013/diff.log_-SF_main index 4c6708d2d0..dbf770db49 100644 --- a/t/t4013/diff.log_-GF_master +++ b/t/t4013/diff.log_-SF_main @@ -1,4 +1,4 @@ -$ git log -GF master +$ git log -SF main commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-SF_main_--max-count=0 b/t/t4013/diff.log_-SF_main_--max-count=0 new file mode 100644 index 0000000000..683b17eb99 --- /dev/null +++ b/t/t4013/diff.log_-SF_main_--max-count=0 @@ -0,0 +1,2 @@ +$ git log -SF main --max-count=0 +$ diff --git a/t/t4013/diff.log_-SF_master_--max-count=2 b/t/t4013/diff.log_-SF_main_--max-count=1 index a6c55fd482..2102426f8c 100644 --- a/t/t4013/diff.log_-SF_master_--max-count=2 +++ b/t/t4013/diff.log_-SF_main_--max-count=1 @@ -1,4 +1,4 @@ -$ git log -SF master --max-count=2 +$ git log -SF main --max-count=1 commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-SF_main_--max-count=2 b/t/t4013/diff.log_-SF_main_--max-count=2 new file mode 100644 index 0000000000..23e12a4cbb --- /dev/null +++ b/t/t4013/diff.log_-SF_main_--max-count=2 @@ -0,0 +1,7 @@ +$ git log -SF main --max-count=2 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +$ diff --git a/t/t4013/diff.log_-SF_master_--max-count=0 b/t/t4013/diff.log_-SF_master_--max-count=0 deleted file mode 100644 index c1fc6c8731..0000000000 --- a/t/t4013/diff.log_-SF_master_--max-count=0 +++ /dev/null @@ -1,2 +0,0 @@ -$ git log -SF master --max-count=0 -$ diff --git a/t/t4013/diff.log_-SF_master_--max-count=1 b/t/t4013/diff.log_-SF_master_--max-count=1 deleted file mode 100644 index c981a03814..0000000000 --- a/t/t4013/diff.log_-SF_master_--max-count=1 +++ /dev/null @@ -1,7 +0,0 @@ -$ git log -SF master --max-count=1 -commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 -Author: A U Thor <author@example.com> -Date: Mon Jun 26 00:02:00 2006 +0000 - - Third -$ diff --git a/t/t4013/diff.log_-S_F_master b/t/t4013/diff.log_-S_F_main index 978d2b4118..a75a42e143 100644 --- a/t/t4013/diff.log_-S_F_master +++ b/t/t4013/diff.log_-S_F_main @@ -1,4 +1,4 @@ -$ git log -S F master +$ git log -S F main commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_--cc_-m_-p_master b/t/t4013/diff.log_-c_-m_-p_main index 7c217cf348..427f732456 100644 --- a/t/t4013/diff.log_--cc_-m_-p_master +++ b/t/t4013/diff.log_-c_-m_-p_main @@ -1,4 +1,4 @@ -$ git log --cc -m -p master +$ git log -c -m -p main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-m_--raw_master b/t/t4013/diff.log_-m_--raw_main index cd2ecc4628..31d9bc7707 100644 --- a/t/t4013/diff.log_-m_--raw_master +++ b/t/t4013/diff.log_-m_--raw_main @@ -1,4 +1,4 @@ -$ git log -m --raw master +$ git log -m --raw main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-m_--stat_master b/t/t4013/diff.log_-m_--stat_main index c7db084fd9..4c8909229b 100644 --- a/t/t4013/diff.log_-m_--stat_master +++ b/t/t4013/diff.log_-m_--stat_main @@ -1,4 +1,4 @@ -$ git log -m --stat master +$ git log -m --stat main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-m_-p_--first-parent_master b/t/t4013/diff.log_-m_-p_--first-parent_main index 7a0073f529..459e10786b 100644 --- a/t/t4013/diff.log_-m_-p_--first-parent_master +++ b/t/t4013/diff.log_-m_-p_--first-parent_main @@ -1,4 +1,4 @@ -$ git log -m -p --first-parent master +$ git log -m -p --first-parent main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-m_-p_master b/t/t4013/diff.log_-m_-p_main index 9ca62a01ed..07453c5698 100644 --- a/t/t4013/diff.log_-m_-p_master +++ b/t/t4013/diff.log_-m_-p_main @@ -1,4 +1,4 @@ -$ git log -m -p master +$ git log -m -p main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-p_--diff-merges=first-parent_master b/t/t4013/diff.log_-p_--diff-merges=first-parent_main index 9538a27511..264a2f373e 100644 --- a/t/t4013/diff.log_-p_--diff-merges=first-parent_master +++ b/t/t4013/diff.log_-p_--diff-merges=first-parent_main @@ -1,4 +1,4 @@ -$ git log -p --diff-merges=first-parent master +$ git log -p --diff-merges=first-parent main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-p_--first-parent_master b/t/t4013/diff.log_-p_--first-parent_main index 28840ebea1..247980817b 100644 --- a/t/t4013/diff.log_-p_--first-parent_master +++ b/t/t4013/diff.log_-p_--first-parent_main @@ -1,4 +1,4 @@ -$ git log -p --first-parent master +$ git log -p --first-parent main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-p_master b/t/t4013/diff.log_-p_main index bf1326dc36..c82b4dbf16 100644 --- a/t/t4013/diff.log_-p_master +++ b/t/t4013/diff.log_-p_main @@ -1,4 +1,4 @@ -$ git log -p master +$ git log -p main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_master b/t/t4013/diff.log_main index a8f6ce5abd..50401f73e6 100644 --- a/t/t4013/diff.log_master +++ b/t/t4013/diff.log_main @@ -1,4 +1,4 @@ -$ git log master +$ git log main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.noellipses-diff-tree_-c_--abbrev_master b/t/t4013/diff.noellipses-diff-tree_-c_--abbrev_main index bb80f013b3..3aa1f80af3 100644 --- a/t/t4013/diff.noellipses-diff-tree_-c_--abbrev_master +++ b/t/t4013/diff.noellipses-diff-tree_-c_--abbrev_main @@ -1,4 +1,4 @@ -$ git diff-tree -c --abbrev master +$ git diff-tree -c --abbrev main 59d314ad6f356dd08601a4cd5e530381da3e3c64 ::100644 100644 100644 cead32e 7289e35 992913c MM dir/sub ::100644 100644 100644 b414108 f4615da 10a8a9f MM file0 diff --git a/t/t4013/diff.noellipses-whatchanged_--root_master b/t/t4013/diff.noellipses-whatchanged_--root_main index c2cfd4e729..2bec055835 100644 --- a/t/t4013/diff.noellipses-whatchanged_--root_master +++ b/t/t4013/diff.noellipses-whatchanged_--root_main @@ -1,4 +1,4 @@ -$ git whatchanged --root master +$ git whatchanged --root main commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.noellipses-whatchanged_-SF_master b/t/t4013/diff.noellipses-whatchanged_-SF_main index b36ce5886e..0c1476d19e 100644 --- a/t/t4013/diff.noellipses-whatchanged_-SF_master +++ b/t/t4013/diff.noellipses-whatchanged_-SF_main @@ -1,4 +1,4 @@ -$ git whatchanged -SF master +$ git whatchanged -SF main commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.noellipses-whatchanged_master b/t/t4013/diff.noellipses-whatchanged_main index 55e500f2ed..c48d2851aa 100644 --- a/t/t4013/diff.noellipses-whatchanged_master +++ b/t/t4013/diff.noellipses-whatchanged_main @@ -1,4 +1,4 @@ -$ git whatchanged master +$ git whatchanged main commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.show_--first-parent_master b/t/t4013/diff.show_--first-parent_main index 3dcbe473a0..480502d65c 100644 --- a/t/t4013/diff.show_--first-parent_master +++ b/t/t4013/diff.show_--first-parent_main @@ -1,4 +1,4 @@ -$ git show --first-parent master +$ git show --first-parent main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.show_-c_master b/t/t4013/diff.show_-c_main index 81aba8da96..74ef8bc96b 100644 --- a/t/t4013/diff.show_-c_master +++ b/t/t4013/diff.show_-c_main @@ -1,4 +1,4 @@ -$ git show -c master +$ git show -c main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.show_-m_master b/t/t4013/diff.show_-m_main index 4ea2ee453d..8fd56736d9 100644 --- a/t/t4013/diff.show_-m_master +++ b/t/t4013/diff.show_-m_main @@ -1,4 +1,4 @@ -$ git show -m master +$ git show -m main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (from 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.show_master b/t/t4013/diff.show_main index fb08ce0e46..630b52a95e 100644 --- a/t/t4013/diff.show_master +++ b/t/t4013/diff.show_main @@ -1,4 +1,4 @@ -$ git show master +$ git show main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_main_--_dir_ index c8b6af2f43..ce0754d556 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_main_--_dir_ @@ -1,4 +1,4 @@ -$ git whatchanged --patch-with-stat --summary master -- dir/ +$ git whatchanged --patch-with-stat --summary main -- dir/ commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master b/t/t4013/diff.whatchanged_--patch-with-stat_main index 1ac431ba92..aabccf39a5 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--patch-with-stat_main @@ -1,4 +1,4 @@ -$ git whatchanged --patch-with-stat master +$ git whatchanged --patch-with-stat main commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_main_--_dir_ index b30c28588f..c05a0e8149 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_main_--_dir_ @@ -1,4 +1,4 @@ -$ git whatchanged --patch-with-stat master -- dir/ +$ git whatchanged --patch-with-stat main -- dir/ commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_main index 30aae7817b..1f74b1b548 100644 --- a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_main @@ -1,4 +1,4 @@ -$ git whatchanged --root --cc --patch-with-stat --summary master +$ git whatchanged --root --cc --patch-with-stat --summary main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_main index db90e51525..80d9812151 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_main @@ -1,4 +1,4 @@ -$ git whatchanged --root --patch-with-stat --summary master +$ git whatchanged --root --patch-with-stat --summary main commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_main index 9a6cc92ce7..c0b9082a2c 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_main @@ -1,4 +1,4 @@ -$ git whatchanged --root --patch-with-stat master +$ git whatchanged --root --patch-with-stat main commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_main index d1d32bd34c..0002c6912e 100644 --- a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_main @@ -1,4 +1,4 @@ -$ git whatchanged --root -c --patch-with-stat --summary master +$ git whatchanged --root -c --patch-with-stat --summary main commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.whatchanged_--root_-p_master b/t/t4013/diff.whatchanged_--root_-p_main index ebf1f0661e..39f3e2be74 100644 --- a/t/t4013/diff.whatchanged_--root_-p_master +++ b/t/t4013/diff.whatchanged_--root_-p_main @@ -1,4 +1,4 @@ -$ git whatchanged --root -p master +$ git whatchanged --root -p main commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_--root_master b/t/t4013/diff.whatchanged_--root_main index a405cb6138..36f4d6697f 100644 --- a/t/t4013/diff.whatchanged_--root_master +++ b/t/t4013/diff.whatchanged_--root_main @@ -1,4 +1,4 @@ -$ git whatchanged --root master +$ git whatchanged --root main commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_-SF_-p_master b/t/t4013/diff.whatchanged_-SF_-p_main index f39da84822..0e2e67c0df 100644 --- a/t/t4013/diff.whatchanged_-SF_-p_master +++ b/t/t4013/diff.whatchanged_-SF_-p_main @@ -1,4 +1,4 @@ -$ git whatchanged -SF -p master +$ git whatchanged -SF -p main commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_-SF_master b/t/t4013/diff.whatchanged_-SF_main index 0499321d0e..34c6bf6b95 100644 --- a/t/t4013/diff.whatchanged_-SF_master +++ b/t/t4013/diff.whatchanged_-SF_main @@ -1,4 +1,4 @@ -$ git whatchanged -SF master +$ git whatchanged -SF main commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_-p_master b/t/t4013/diff.whatchanged_-p_main index f18d43209c..18f3bdeef4 100644 --- a/t/t4013/diff.whatchanged_-p_master +++ b/t/t4013/diff.whatchanged_-p_main @@ -1,4 +1,4 @@ -$ git whatchanged -p master +$ git whatchanged -p main commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_master b/t/t4013/diff.whatchanged_main index cd3bcc2c72..d6c83ed8b0 100644 --- a/t/t4013/diff.whatchanged_master +++ b/t/t4013/diff.whatchanged_main @@ -1,4 +1,4 @@ -$ git whatchanged master +$ git whatchanged main commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Author: A U Thor <author@example.com> Date: Mon Jun 26 00:03:00 2006 +0000 diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh index 950451cf6a..0a7c3ca42f 100755 --- a/t/t4211-line-log.sh +++ b/t/t4211-line-log.sh @@ -78,6 +78,8 @@ canned_test "-L :main:a.c -L 4,18:a.c simple" multiple-overlapping canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset +canned_test "-L 10,16:b.c -L 18,26:b.c main" no-assertion-error + test_bad_opts "-L" "switch.*requires a value" test_bad_opts "-L b.c" "argument not .start,end:file" test_bad_opts "-L 1:" "argument not .start,end:file" diff --git a/t/t4211/sha1/expect.multiple b/t/t4211/sha1/expect.multiple index 76ad5b598c..1eee8a7801 100644 --- a/t/t4211/sha1/expect.multiple +++ b/t/t4211/sha1/expect.multiple @@ -102,3 +102,9 @@ diff --git a/a.c b/a.c + s++; + } +} +@@ -0,0 +16,5 @@ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/sha1/expect.no-assertion-error b/t/t4211/sha1/expect.no-assertion-error new file mode 100644 index 0000000000..994c37db1e --- /dev/null +++ b/t/t4211/sha1/expect.no-assertion-error @@ -0,0 +1,90 @@ +commit 0d8dcfc6b968e06a27d5215bad1fdde3de9d6235 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:50:24 2013 +0100 + + move within the file + +diff --git a/b.c b/b.c +--- a/b.c ++++ b/b.c +@@ -25,0 +18,9 @@ ++long f(long x) ++{ ++ int s = 0; ++ while (x) { ++ x /= 2; ++ s++; ++ } ++ return s; ++} + +commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,7 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} +\ No newline at end of file ++} ++ ++/* incomplete lines are bad! */ + +commit 100b61a6f2f720f812620a9d10afb3a960ccb73c +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,5 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} ++} +\ No newline at end of file + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -17,5 +17,5 @@ + int main () + { +- printf("%d\n", f(15)); ++ printf("%ld\n", f(15)); + return 0; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +16,5 @@ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/sha1/expect.two-ranges b/t/t4211/sha1/expect.two-ranges index 6109aa0dce..c5164f3be3 100644 --- a/t/t4211/sha1/expect.two-ranges +++ b/t/t4211/sha1/expect.two-ranges @@ -100,3 +100,9 @@ diff --git a/a.c b/a.c + s++; + } +} +@@ -0,0 +16,5 @@ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/sha256/expect.multiple b/t/t4211/sha256/expect.multiple index ca00409b9a..dbd987b74a 100644 --- a/t/t4211/sha256/expect.multiple +++ b/t/t4211/sha256/expect.multiple @@ -102,3 +102,9 @@ diff --git a/a.c b/a.c + s++; + } +} +@@ -0,0 +16,5 @@ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/sha256/expect.no-assertion-error b/t/t4211/sha256/expect.no-assertion-error new file mode 100644 index 0000000000..36ed12aa9c --- /dev/null +++ b/t/t4211/sha256/expect.no-assertion-error @@ -0,0 +1,90 @@ +commit eb871b8aa9aff323e484723039c9a92ab0266e060bc0ef2afb08fadda25c5ace +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:50:24 2013 +0100 + + move within the file + +diff --git a/b.c b/b.c +--- a/b.c ++++ b/b.c +@@ -25,0 +18,9 @@ ++long f(long x) ++{ ++ int s = 0; ++ while (x) { ++ x /= 2; ++ s++; ++ } ++ return s; ++} + +commit 5526ed05c2476b56af8b7be499e8f78bd50f490740733a9ca7e1f55878fa90a9 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,7 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} +\ No newline at end of file ++} ++ ++/* incomplete lines are bad! */ + +commit 29f32ac3141c48b22803e5c4127b719917b67d0f8ca8c5248bebfa2a19f7da10 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,5 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} ++} +\ No newline at end of file + +commit ccf97b9878189c40a981da50b15713bb80a35755326320ec80900caf22ced46f +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -17,5 +17,5 @@ + int main () + { +- printf("%d\n", f(15)); ++ printf("%ld\n", f(15)); + return 0; + } + +commit 1dd7e9b2b1699324b53b341e728653b913bc192a14dfea168c5b51f2b3d03592 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +16,5 @@ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/sha256/expect.two-ranges b/t/t4211/sha256/expect.two-ranges index af57c8b997..6a94d3b9cb 100644 --- a/t/t4211/sha256/expect.two-ranges +++ b/t/t4211/sha256/expect.two-ranges @@ -100,3 +100,9 @@ diff --git a/a.c b/a.c + s++; + } +} +@@ -0,0 +16,5 @@ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index bd75dea950..93f319a4b2 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -28,11 +28,11 @@ midx_read_expect () { EOF if test $NUM_PACKS -ge 1 then - ls $OBJECT_DIR/pack/ | grep idx | sort + ls "$OBJECT_DIR"/pack/ | grep idx | sort fi && printf "object-dir: $OBJECT_DIR\n" } >expect && - test-tool read-midx $OBJECT_DIR >actual && + test-tool read-midx "$OBJECT_DIR" >actual && test_cmp expect actual } @@ -305,7 +305,7 @@ test_expect_success 'midx picks objects from preferred pack' ' ofs=$(git show-index <objects/pack/test-BC-$bc.idx | grep $b | cut -d" " -f1) && - printf "%s %s\tobjects/pack/test-BC-%s.pack\n" \ + printf "%s %s\t./objects/pack/test-BC-%s.pack\n" \ "$b" "$ofs" "$bc" >expect && grep ^$b out >actual && @@ -639,7 +639,7 @@ test_expect_success 'force some 64-bit offsets with pack-objects' ' ( cd ../objects64 && pwd ) >.git/objects/info/alternates && midx64=$(git multi-pack-index --object-dir=../objects64 write) ) && - midx_read_expect 1 63 5 objects64 " large-offsets" + midx_read_expect 1 63 5 "$(pwd)/objects64" " large-offsets" ' test_expect_success 'verify multi-pack-index with 64-bit offsets' ' @@ -989,6 +989,23 @@ test_expect_success 'repack --batch-size=0 repacks everything' ' ) ' +test_expect_success EXPENSIVE 'repack/expire with many packs' ' + cp -r dup many && + ( + cd many && + + for i in $(test_seq 1 100) + do + test_commit extra$i && + git maintenance run --task=loose-objects || return 1 + done && + + git multi-pack-index write && + git multi-pack-index repack && + git multi-pack-index expire + ) +' + test_expect_success 'repack --batch-size=<large> repacks everything' ' ( cd dup2 && @@ -1083,7 +1100,10 @@ test_expect_success 'load reverse index when missing .idx, .pack' ' mv $idx.bak $idx && mv $pack $pack.bak && - git cat-file --batch-check="%(objectsize:disk)" <tip + git cat-file --batch-check="%(objectsize:disk)" <tip && + + test_must_fail git multi-pack-index write 2>err && + test_grep "could not load pack" err ) ' diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 83d1aadf9f..b7059cccaa 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -45,7 +45,25 @@ test_expect_success "clone and setup child repos" ' git config set branch.main.merge refs/heads/one ) && git clone . bundle && - git clone . seven + git clone . seven && + git clone --ref-format=reftable . case_sensitive && + ( + cd case_sensitive && + git branch branch1 && + git branch bRanch1 + ) && + git clone --ref-format=reftable . case_sensitive_fd && + ( + cd case_sensitive_fd && + git branch foo/bar && + git branch Foo + ) && + git clone --ref-format=reftable . case_sensitive_df && + ( + cd case_sensitive_df && + git branch Foo/bar && + git branch foo + ) ' test_expect_success "fetch test" ' @@ -1465,6 +1483,100 @@ test_expect_success SYMLINKS 'clone does not get confused by a D/F conflict' ' test_path_is_missing whoops ' +test_expect_success CASE_INSENSITIVE_FS,REFFILES 'existing references in a case insensitive filesystem' ' + test_when_finished rm -rf case_insensitive && + ( + git init --bare case_insensitive && + cd case_insensitive && + git remote add origin -- ../case_sensitive && + test_must_fail git fetch -f origin "refs/heads/*:refs/heads/*" 2>err && + test_grep "You${SQ}re on a case-insensitive filesystem" err && + git rev-parse refs/heads/main >expect && + git rev-parse refs/heads/branch1 >actual && + test_cmp expect actual + ) +' + +test_expect_success REFFILES 'existing reference lock in repo' ' + test_when_finished rm -rf base repo && + ( + git init --ref-format=reftable base && + cd base && + echo >file update && + git add . && + git commit -m "updated" && + git branch -M main && + + git update-ref refs/heads/foo @ && + git update-ref refs/heads/branch @ && + cd .. && + + git init --ref-format=files --bare repo && + cd repo && + git remote add origin ../base && + touch refs/heads/foo.lock && + test_must_fail git fetch -f origin "refs/heads/*:refs/heads/*" 2>err && + test_grep "error: fetching ref refs/heads/foo failed: reference already exists" err && + git rev-parse refs/heads/main >expect && + git rev-parse refs/heads/branch >actual && + test_cmp expect actual + ) +' + +test_expect_success CASE_INSENSITIVE_FS,REFFILES 'F/D conflict on case insensitive filesystem' ' + test_when_finished rm -rf case_insensitive && + ( + git init --bare case_insensitive && + cd case_insensitive && + git remote add origin -- ../case_sensitive_fd && + test_must_fail git fetch -f origin "refs/heads/*:refs/heads/*" 2>err && + test_grep "failed: refname conflict" err && + git rev-parse refs/heads/main >expect && + git rev-parse refs/heads/foo/bar >actual && + test_cmp expect actual + ) +' + +test_expect_success CASE_INSENSITIVE_FS,REFFILES 'D/F conflict on case insensitive filesystem' ' + test_when_finished rm -rf case_insensitive && + ( + git init --bare case_insensitive && + cd case_insensitive && + git remote add origin -- ../case_sensitive_df && + test_must_fail git fetch -f origin "refs/heads/*:refs/heads/*" 2>err && + test_grep "failed: refname conflict" err && + git rev-parse refs/heads/main >expect && + git rev-parse refs/heads/Foo/bar >actual && + test_cmp expect actual + ) +' + +test_expect_success REFFILES 'D/F conflict on case sensitive filesystem with lock' ' + ( + git init --ref-format=reftable base && + cd base && + echo >file update && + git add . && + git commit -m "updated" && + git branch -M main && + + git update-ref refs/heads/foo @ && + git update-ref refs/heads/branch @ && + cd .. && + + git init --ref-format=files --bare repo && + cd repo && + git remote add origin ../base && + mkdir refs/heads/foo && + touch refs/heads/foo/random.lock && + test_must_fail git fetch origin "refs/heads/*:refs/heads/*" 2>err && + test_grep "some local refs could not be updated; try running" err && + git rev-parse refs/heads/main >expect && + git rev-parse refs/heads/branch >actual && + test_cmp expect actual + ) +' + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh index 558eedf25a..d40292cfb7 100755 --- a/t/t5530-upload-pack-error.sh +++ b/t/t5530-upload-pack-error.sh @@ -4,8 +4,6 @@ test_description='errors in upload-pack' . ./test-lib.sh -D=$(pwd) - corrupt_repo () { object_sha1=$(git rev-parse "$1") && ob=$(expr "$object_sha1" : "\(..\)") && @@ -21,11 +19,7 @@ test_expect_success 'setup and corrupt repository' ' test_tick && echo changed >file && git commit -a -m changed && - corrupt_repo HEAD:file - -' - -test_expect_success 'fsck fails' ' + corrupt_repo HEAD:file && test_must_fail git fsck ' @@ -40,17 +34,12 @@ test_expect_success 'upload-pack fails due to error in pack-objects packing' ' ' test_expect_success 'corrupt repo differently' ' - git hash-object -w file && - corrupt_repo HEAD^^{tree} - -' - -test_expect_success 'fsck fails' ' + corrupt_repo HEAD^^{tree} && test_must_fail git fsck ' -test_expect_success 'upload-pack fails due to error in rev-list' ' +test_expect_success 'upload-pack fails due to error in rev-list' ' printf "%04xwant %s\n%04xshallow %s00000009done\n0000" \ $(($hexsz + 10)) $(git rev-parse HEAD) \ $(($hexsz + 12)) $(git rev-parse HEAD^) >input && @@ -59,7 +48,6 @@ test_expect_success 'upload-pack fails due to error in rev-list' ' ' test_expect_success 'upload-pack fails due to bad want (no object)' ' - printf "%04xwant %s multi_ack_detailed\n00000009done\n0000" \ $(($hexsz + 29)) $(test_oid deadbeef) >input && test_must_fail git upload-pack . <input >output 2>output.err && @@ -69,7 +57,6 @@ test_expect_success 'upload-pack fails due to bad want (no object)' ' ' test_expect_success 'upload-pack fails due to bad want (not tip)' ' - oid=$(echo an object we have | git hash-object -w --stdin) && printf "%04xwant %s multi_ack_detailed\n00000009done\n0000" \ $(($hexsz + 29)) "$oid" >input && @@ -80,7 +67,6 @@ test_expect_success 'upload-pack fails due to bad want (not tip)' ' ' test_expect_success 'upload-pack fails due to error in pack-objects enumeration' ' - printf "%04xwant %s\n00000009done\n0000" \ $((hexsz + 10)) $(git rev-parse HEAD) >input && test_must_fail git upload-pack . <input >/dev/null 2>output.err && @@ -105,18 +91,48 @@ test_expect_success 'upload-pack tolerates EOF just after stateless client wants test_cmp expect actual ' -test_expect_success 'create empty repository' ' - - mkdir foo && - cd foo && - git init - -' - test_expect_success 'fetch fails' ' + git init foo && + test_must_fail git -C foo fetch .. main +' - test_must_fail git fetch .. main +test_expect_success 'upload-pack ACKs repeated non-commit objects repeatedly (protocol v0)' ' + commit_id=$(git rev-parse HEAD) && + tree_id=$(git rev-parse HEAD^{tree}) && + test-tool pkt-line pack >request <<-EOF && + want $commit_id + 0000 + have $tree_id + have $tree_id + 0000 + EOF + git upload-pack --stateless-rpc . <request >actual && + depacketize <actual >actual.raw && + grep ^ACK actual.raw >actual.acks && + cat >expect <<-EOF && + ACK $tree_id + ACK $tree_id + EOF + test_cmp expect actual.acks +' +test_expect_success 'upload-pack ACKs repeated non-commit objects once only (protocol v2)' ' + commit_id=$(git rev-parse HEAD) && + tree_id=$(git rev-parse HEAD^{tree}) && + test-tool pkt-line pack >request <<-EOF && + command=fetch + object-format=$(test_oid algo) + 0001 + want $commit_id + have $tree_id + have $tree_id + 0000 + EOF + GIT_PROTOCOL=version=2 git upload-pack . <request >actual && + depacketize <actual >actual.raw && + grep ^ACK actual.raw >actual.acks && + echo "ACK $tree_id" >expect && + test_cmp expect actual.acks ' test_done diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh index b27e481f95..c3903faf2d 100755 --- a/t/t5564-http-proxy.sh +++ b/t/t5564-http-proxy.sh @@ -72,7 +72,9 @@ test_expect_success SOCKS_PROXY 'clone via Unix socket' ' test_when_finished "rm -rf clone" && test_config_global http.proxy "socks4://localhost$PWD/%2530.sock" && { { - GIT_TRACE_CURL=$PWD/trace git clone "$HTTPD_URL/smart/repo.git" clone 2>err && + GIT_TRACE_CURL=$PWD/trace \ + GIT_TRACE_CURL_COMPONENTS=socks \ + git clone "$HTTPD_URL/smart/repo.git" clone 2>err && grep -i "SOCKS4 request granted" trace } || old_libcurl_error err diff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh index cb061b1f35..023735d6a8 100755 --- a/t/t5710-promisor-remote-capability.sh +++ b/t/t5710-promisor-remote-capability.sh @@ -295,6 +295,71 @@ test_expect_success "clone with 'KnownUrl' and empty url, so not advertised" ' check_missing_objects server 1 "$oid" ' +test_expect_success "clone with promisor.sendFields" ' + git -C server config promisor.advertise true && + test_when_finished "rm -rf client" && + + git -C server remote add otherLop "https://invalid.invalid" && + git -C server config remote.otherLop.token "fooBar" && + git -C server config remote.otherLop.stuff "baz" && + git -C server config remote.otherLop.partialCloneFilter "blob:limit=10k" && + test_when_finished "git -C server remote remove otherLop" && + test_config -C server promisor.sendFields "partialCloneFilter, token" && + test_when_finished "rm trace" && + + # Clone from server to create a client + GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \ + -c remote.lop.promisor=true \ + -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ + -c remote.lop.url="file://$(pwd)/lop" \ + -c promisor.acceptfromserver=All \ + --no-local --filter="blob:limit=5k" server client && + + # Check that fields are properly transmitted + ENCODED_URL=$(echo "file://$(pwd)/lop" | sed -e "s/ /%20/g") && + PR1="name=lop,url=$ENCODED_URL,partialCloneFilter=blob:none" && + PR2="name=otherLop,url=https://invalid.invalid,partialCloneFilter=blob:limit=10k,token=fooBar" && + test_grep "clone< promisor-remote=$PR1;$PR2" trace && + test_grep "clone> promisor-remote=lop;otherLop" trace && + + # Check that the largest object is still missing on the server + check_missing_objects server 1 "$oid" +' + +test_expect_success "clone with promisor.checkFields" ' + git -C server config promisor.advertise true && + test_when_finished "rm -rf client" && + + git -C server remote add otherLop "https://invalid.invalid" && + git -C server config remote.otherLop.token "fooBar" && + git -C server config remote.otherLop.stuff "baz" && + git -C server config remote.otherLop.partialCloneFilter "blob:limit=10k" && + test_when_finished "git -C server remote remove otherLop" && + test_config -C server promisor.sendFields "partialCloneFilter, token" && + test_when_finished "rm trace" && + + # Clone from server to create a client + GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \ + -c remote.lop.promisor=true \ + -c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \ + -c remote.lop.url="file://$(pwd)/lop" \ + -c remote.lop.partialCloneFilter="blob:none" \ + -c promisor.acceptfromserver=All \ + -c promisor.checkFields=partialcloneFilter \ + --no-local --filter="blob:limit=5k" server client && + + # Check that fields are properly transmitted + ENCODED_URL=$(echo "file://$(pwd)/lop" | sed -e "s/ /%20/g") && + PR1="name=lop,url=$ENCODED_URL,partialCloneFilter=blob:none" && + PR2="name=otherLop,url=https://invalid.invalid,partialCloneFilter=blob:limit=10k,token=fooBar" && + test_grep "clone< promisor-remote=$PR1;$PR2" trace && + test_grep "clone> promisor-remote=lop" trace && + test_grep ! "clone> promisor-remote=lop;otherLop" trace && + + # Check that the largest object is still missing on the server + check_missing_objects server 1 "$oid" +' + test_expect_success "clone with promisor.advertise set to 'true' but don't delete the client" ' git -C server config promisor.advertise true && diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh index b37e2018a7..05f6da4ad9 100755 --- a/t/t7502-commit-porcelain.sh +++ b/t/t7502-commit-porcelain.sh @@ -956,13 +956,39 @@ test_expect_success 'commit --status with custom comment character' ' test_grep "^; Changes to be committed:" .git/COMMIT_EDITMSG ' -test_expect_success 'switch core.commentchar' ' +test_expect_success !WITH_BREAKING_CHANGES 'switch core.commentchar' ' test_commit "#foo" foo && - GIT_EDITOR=.git/FAKE_EDITOR git -c core.commentChar=auto commit --amend && + cat >config-include <<-\EOF && + [core] + commentString=: + commentString=% + commentChar=auto + EOF + test_when_finished "rm config-include" && + test_config include.path "$(pwd)/config-include" && + test_config core.commentChar ! && + GIT_EDITOR=.git/FAKE_EDITOR git commit --amend 2>err && + sed -n "s/^hint: *\$//p; s/^hint: //p; s/^warning: //p" err >actual && + cat >expect <<-EOF && + Support for ${SQ}core.commentChar=auto${SQ} is deprecated and will be removed in Git 3.0 + + To use the default comment string (#) please run + + git config unset core.commentChar + git config unset --file ~/config-include --all core.commentString + git config unset --file ~/config-include core.commentChar + + To set a custom comment string please run + + git config set --file ~/config-include core.commentChar <comment string> + + where ${SQ}<comment string>${SQ} is the string you wish to use. + EOF + test_cmp expect actual && test_grep "^; Changes to be committed:" .git/COMMIT_EDITMSG ' -test_expect_success 'switch core.commentchar but out of options' ' +test_expect_success !WITH_BREAKING_CHANGES 'switch core.commentchar but out of options' ' cat >text <<\EOF && # 1 ; 2 @@ -982,4 +1008,24 @@ EOF ) ' +test_expect_success WITH_BREAKING_CHANGES 'core.commentChar=auto is rejected' ' + test_config core.commentChar auto && + test_must_fail git rev-parse --git-dir 2>err && + sed -n "s/^hint: *\$//p; s/^hint: //p; s/^fatal: //p" err >actual && + cat >expect <<-EOF && + Support for ${SQ}core.commentChar=auto${SQ} has been removed in Git 3.0 + + To use the default comment string (#) please run + + git config unset core.commentChar + + To set a custom comment string please run + + git config set core.commentChar <comment string> + + where ${SQ}<comment string>${SQ} is the string you wish to use. + EOF + test_cmp expect actual +' + test_done diff --git a/t/t8020-last-modified.sh b/t/t8020-last-modified.sh index 5eb4cef035..e13aad1439 100755 --- a/t/t8020-last-modified.sh +++ b/t/t8020-last-modified.sh @@ -128,6 +128,22 @@ test_expect_success 'only last-modified files in the current tree' ' EOF ' +test_expect_success 'last-modified with subdir and criss-cross merge' ' + git checkout -b branch-k1 1 && + mkdir -p a k && + test_commit k1 a/file2 && + git checkout -b branch-k2 && + test_commit k2 k/file2 && + git checkout branch-k1 && + test_merge km2 branch-k2 && + test_merge km3 3 && + check_last_modified <<-\EOF + km3 a + k2 k + 1 file + EOF +' + test_expect_success 'cross merge boundaries in blaming' ' git checkout HEAD^0 && git rm -rf . && diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 6650d33fba..964e1f1569 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -11,9 +11,9 @@ test_description='test bash completion' # untraceable with such ancient Bash versions. test_untraceable=UnfortunatelyYes -# Override environment and always use master for the default initial branch +# Override environment and always use main for the default initial branch # name for these tests, so that rev completion candidates are as expected. -GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./lib-bash.sh @@ -1453,7 +1453,7 @@ test_expect_success 'git bisect - start subcommand arguments before double-dash HEAD Z final Z initial Z - master Z + main Z EOF ) ' diff --git a/t/test-lib.sh b/t/test-lib.sh index 621cd31ae1..562f950fb0 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -127,11 +127,18 @@ then export GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS fi -# Explicitly set the default branch name for testing, to avoid the -# transitory "git init" warning under --verbose. -: ${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME:=master} +# Explicitly set the default branch name for testing, to squelch hints +# from "git init" during the transition period. Should be removed +# after we decide to remove ADVICE_DEFAULT_BRANCH_NAME +if test -z "$WITH_BREAKING_CHANGES" +then + : ${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME:=master} +else + : ${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME:=main} +fi export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + ################################################################ # It appears that people try to run tests without building... GIT_BINARY="${GIT_TEST_INSTALLED:-$GIT_BUILD_DIR}/git$X" diff --git a/t/unit-tests/clar/.github/workflows/ci.yml b/t/unit-tests/clar/.github/workflows/ci.yml index 0065843d17..4d4724222c 100644 --- a/t/unit-tests/clar/.github/workflows/ci.yml +++ b/t/unit-tests/clar/.github/workflows/ci.yml @@ -13,23 +13,56 @@ jobs: platform: - os: ubuntu-latest generator: Unix Makefiles + env: + CFLAGS: "-Werror -Wall -Wextra" + - os: ubuntu-latest + generator: Unix Makefiles + env: + CC: "clang" + CFLAGS: "-Werror -Wall -Wextra -fsanitize=leak" + - os: ubuntu-latest + generator: Unix Makefiles + image: i386/debian:latest + env: + CFLAGS: "-Werror -Wall -Wextra" - os: macos-latest generator: Unix Makefiles + env: + CFLAGS: "-Werror -Wall -Wextra" - os: windows-latest generator: Visual Studio 17 2022 - os: windows-latest generator: MSYS Makefiles + env: + CFLAGS: "-Werror -Wall -Wextra" - os: windows-latest generator: MinGW Makefiles + env: + CFLAGS: "-Werror -Wall -Wextra" + fail-fast: false runs-on: ${{ matrix.platform.os }} + container: ${{matrix.platform.image}} + + env: + CC: ${{matrix.platform.env.CC}} + CFLAGS: ${{matrix.platform.env.CFLAGS}} steps: + - name: Prepare 32 bit container image + if: matrix.platform.image == 'i386/debian:latest' + run: apt -q update && apt -q -y install cmake gcc libc6-amd64 lib64stdc++6 make python3 - name: Check out - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Build + shell: bash run: | mkdir build cd build cmake .. -G "${{matrix.platform.generator}}" - cmake --build . + cmake --build . --verbose + - name: Test + shell: bash + run: | + cd build + CTEST_OUTPUT_ON_FAILURE=1 ctest --build-config Debug diff --git a/t/unit-tests/clar/CMakeLists.txt b/t/unit-tests/clar/CMakeLists.txt index 12d4af114f..125db05bc1 100644 --- a/t/unit-tests/clar/CMakeLists.txt +++ b/t/unit-tests/clar/CMakeLists.txt @@ -1,8 +1,15 @@ +include(CheckFunctionExists) + cmake_minimum_required(VERSION 3.16..3.29) project(clar LANGUAGES C) -option(BUILD_TESTS "Build test executable" ON) +option(BUILD_EXAMPLE "Build the example." ON) + +check_function_exists(realpath CLAR_HAS_REALPATH) +if(CLAR_HAS_REALPATH) + add_compile_definitions(-DCLAR_HAS_REALPATH) +endif() add_library(clar INTERFACE) target_sources(clar INTERFACE @@ -25,4 +32,8 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) if(BUILD_TESTING) add_subdirectory(test) endif() + + if(BUILD_EXAMPLE) + add_subdirectory(example) + endif() endif() diff --git a/t/unit-tests/clar/README.md b/t/unit-tests/clar/README.md index a8961c5f10..41595989ca 100644 --- a/t/unit-tests/clar/README.md +++ b/t/unit-tests/clar/README.md @@ -26,8 +26,7 @@ Can you count to funk? ~~~~ sh $ mkdir tests $ cp -r $CLAR_ROOT/clar* tests - $ cp $CLAR_ROOT/test/clar_test.h tests - $ cp $CLAR_ROOT/test/main.c.sample tests/main.c + $ cp $CLAR_ROOT/example/*.c tests ~~~~ - **One: Write some tests** @@ -147,7 +146,7 @@ To use Clar: 1. copy the Clar boilerplate to your test directory 2. copy (and probably modify) the sample `main.c` (from - `$CLAR_PATH/test/main.c.sample`) + `$CLAR_PATH/example/main.c`) 3. run the Clar mixer (a.k.a. `generate.py`) to scan your test directory and write out the test suite metadata. 4. compile your test files and the Clar boilerplate into a single test @@ -159,7 +158,7 @@ The Clar boilerplate gives you a set of useful test assertions and features the `clar.c` and `clar.h` files, plus the code in the `clar/` subdirectory. You should not need to edit these files. -The sample `main.c` (i.e. `$CLAR_PATH/test/main.c.sample`) file invokes +The sample `main.c` (i.e. `$CLAR_PATH/example/main.c`) file invokes `clar_test(argc, argv)` to run the tests. Usually, you will edit this file to perform any framework specific initialization and teardown that you need. @@ -251,11 +250,16 @@ suite. - `cl_fixture(const char *)`: Gets the full path to a fixture file. -Please do note that these methods are *always* available whilst running a -test, even when calling auxiliary/static functions inside the same file. +### Auxiliary / helper functions -It's strongly encouraged to perform test assertions in auxiliary methods, -instead of returning error values. This is considered good Clar style. +The clar API is always available while running a test, even when calling +"auxiliary" (helper) functions. + +You're encouraged to perform test assertions in those auxiliary +methods, instead of returning error values. This is considered good +Clar style. _However_, when you do this, you need to call `cl_invoke` +to preserve the current state; this ensures that failures are reported +as coming from the actual test, instead of the auxiliary method. Style Example: @@ -310,20 +314,19 @@ static void check_string(const char *str) void test_example__a_test_with_auxiliary_methods(void) { - check_string("foo"); - check_string("bar"); + cl_invoke(check_string("foo")); + cl_invoke(check_string("bar")); } ~~~~ About Clar ========== -Clar has been written from scratch by [Vicent Martí](https://github.com/vmg), -to replace the old testing framework in [libgit2][libgit2]. - -Do you know what languages are *in* on the SF startup scene? Node.js *and* -Latin. Follow [@vmg](https://www.twitter.com/vmg) on Twitter to -receive more lessons on word etymology. You can be hip too. - +Clar was originally written by [Vicent Martí](https://github.com/vmg), +to replace the old testing framework in [libgit2][libgit2]. It is +currently maintained by [Edward Thomson](https://github.com/ethomson), +and used by the [libgit2][libgit2] and [git][git] projects, amongst +others. [libgit2]: https://github.com/libgit2/libgit2 +[git]: https://github.com/git/git diff --git a/t/unit-tests/clar/clar.c b/t/unit-tests/clar/clar.c index 03a3aa8e87..d6176e50b2 100644 --- a/t/unit-tests/clar/clar.c +++ b/t/unit-tests/clar/clar.c @@ -79,6 +79,8 @@ # else # define p_snprintf snprintf # endif + +# define localtime_r(timer, buf) (localtime_s(buf, timer) == 0 ? buf : NULL) #else # include <sys/wait.h> /* waitpid(2) */ # include <unistd.h> @@ -150,7 +152,6 @@ static struct { enum cl_output_format output_format; - int report_errors_only; int exit_on_error; int verbosity; @@ -164,6 +165,10 @@ static struct { struct clar_report *reports; struct clar_report *last_report; + const char *invoke_file; + const char *invoke_func; + size_t invoke_line; + void (*local_cleanup)(void *); void *local_cleanup_payload; @@ -190,7 +195,7 @@ struct clar_suite { }; /* From clar_print_*.c */ -static void clar_print_init(int test_count, int suite_count, const char *suite_names); +static void clar_print_init(int test_count, int suite_count); static void clar_print_shutdown(int test_count, int suite_count, int error_count); static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error); static void clar_print_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status failed); @@ -199,8 +204,10 @@ static void clar_print_onabortv(const char *msg, va_list argp); static void clar_print_onabort(const char *msg, ...); /* From clar_sandbox.c */ -static void clar_unsandbox(void); -static void clar_sandbox(void); +static void clar_tempdir_init(void); +static void clar_tempdir_shutdown(void); +static int clar_sandbox_create(const char *suite_name, const char *test_name); +static int clar_sandbox_cleanup(void); /* From summary.h */ static struct clar_summary *clar_summary_init(const char *filename); @@ -304,6 +311,8 @@ clar_run_test( CL_TRACE(CL_TRACE__TEST__BEGIN); + clar_sandbox_create(suite->name, test->name); + _clar.last_report->start = time(NULL); clar_time_now(&start); @@ -328,9 +337,13 @@ clar_run_test( if (_clar.local_cleanup != NULL) _clar.local_cleanup(_clar.local_cleanup_payload); + clar__clear_invokepoint(); + if (cleanup->ptr != NULL) cleanup->ptr(); + clar_sandbox_cleanup(); + CL_TRACE(CL_TRACE__TEST__END); _clar.tests_ran++; @@ -339,11 +352,7 @@ clar_run_test( _clar.local_cleanup = NULL; _clar.local_cleanup_payload = NULL; - if (_clar.report_errors_only) { - clar_report_errors(_clar.last_report); - } else { - clar_print_ontest(suite->name, test->name, _clar.tests_ran, _clar.last_report->status); - } + clar_print_ontest(suite->name, test->name, _clar.tests_ran, _clar.last_report->status); } static void @@ -360,8 +369,7 @@ clar_run_suite(const struct clar_suite *suite, const char *filter) if (_clar.exit_on_error && _clar.total_errors) return; - if (!_clar.report_errors_only) - clar_print_onsuite(suite->name, ++_clar.suites_ran); + clar_print_onsuite(suite->name, ++_clar.suites_ran); _clar.active_suite = suite->name; _clar.active_test = NULL; @@ -428,12 +436,12 @@ clar_usage(const char *arg) printf(" -iname Include the suite with `name`\n"); printf(" -xname Exclude the suite with `name`\n"); printf(" -v Increase verbosity (show suite names)\n"); - printf(" -q Only report tests that had an error\n"); + printf(" -q Decrease verbosity, inverse to -v\n"); printf(" -Q Quit as soon as a test fails\n"); printf(" -t Display results in tap format\n"); printf(" -l Print suite names\n"); printf(" -r[filename] Write summary file (to the optional filename)\n"); - exit(-1); + exit(1); } static void @@ -441,18 +449,11 @@ clar_parse_args(int argc, char **argv) { int i; - /* Verify options before execute */ for (i = 1; i < argc; ++i) { char *argument = argv[i]; - if (argument[0] != '-' || argument[1] == '\0' - || strchr("sixvqQtlr", argument[1]) == NULL) { + if (argument[0] != '-' || argument[1] == '\0') clar_usage(argv[0]); - } - } - - for (i = 1; i < argc; ++i) { - char *argument = argv[i]; switch (argument[1]) { case 's': @@ -465,8 +466,13 @@ clar_parse_args(int argc, char **argv) argument += offset; arglen = strlen(argument); - if (arglen == 0) - clar_usage(argv[0]); + if (arglen == 0) { + if (i + 1 == argc) + clar_usage(argv[0]); + + argument = argv[++i]; + arglen = strlen(argument); + } for (j = 0; j < _clar_suite_count; ++j) { suitelen = strlen(_clar_suites[j].name); @@ -483,9 +489,6 @@ clar_parse_args(int argc, char **argv) ++found; - if (!exact) - _clar.verbosity = MAX(_clar.verbosity, 1); - switch (action) { case 's': { struct clar_explicit *explicit; @@ -517,23 +520,37 @@ clar_parse_args(int argc, char **argv) if (!found) clar_abort("No suite matching '%s' found.\n", argument); + break; } case 'q': - _clar.report_errors_only = 1; + if (argument[2] != '\0') + clar_usage(argv[0]); + + _clar.verbosity--; break; case 'Q': + if (argument[2] != '\0') + clar_usage(argv[0]); + _clar.exit_on_error = 1; break; case 't': + if (argument[2] != '\0') + clar_usage(argv[0]); + _clar.output_format = CL_OUTPUT_TAP; break; case 'l': { size_t j; + + if (argument[2] != '\0') + clar_usage(argv[0]); + printf("Test suites (use -s<name> to run just one):\n"); for (j = 0; j < _clar_suite_count; ++j) printf(" %3d: %s\n", (int)j, _clar_suites[j].name); @@ -542,23 +559,27 @@ clar_parse_args(int argc, char **argv) } case 'v': + if (argument[2] != '\0') + clar_usage(argv[0]); + _clar.verbosity++; break; case 'r': _clar.write_summary = 1; free(_clar.summary_filename); + if (*(argument + 2)) { if ((_clar.summary_filename = strdup(argument + 2)) == NULL) clar_abort("Failed to allocate summary filename.\n"); } else { _clar.summary_filename = NULL; } + break; default: - clar_abort("Unexpected commandline argument '%s'.\n", - argument[1]); + clar_usage(argv[0]); } } } @@ -571,11 +592,7 @@ clar_test_init(int argc, char **argv) if (argc > 1) clar_parse_args(argc, argv); - clar_print_init( - (int)_clar_callback_count, - (int)_clar_suite_count, - "" - ); + clar_print_init((int)_clar_callback_count, (int)_clar_suite_count); if (!_clar.summary_filename && (summary_env = getenv("CLAR_SUMMARY")) != NULL) { @@ -591,7 +608,7 @@ clar_test_init(int argc, char **argv) if (_clar.write_summary) _clar.summary = clar_summary_init(_clar.summary_filename); - clar_sandbox(); + clar_tempdir_init(); } int @@ -623,7 +640,7 @@ clar_test_shutdown(void) _clar.total_errors ); - clar_unsandbox(); + clar_tempdir_shutdown(); if (_clar.write_summary && clar_summary_shutdown(_clar.summary) < 0) clar_abort("Failed to write the summary file '%s: %s.\n", @@ -635,6 +652,14 @@ clar_test_shutdown(void) } for (report = _clar.reports; report; report = report_next) { + struct clar_error *error, *error_next; + + for (error = report->errors; error; error = error_next) { + free(error->description); + error_next = error->next; + free(error); + } + report_next = report->next; free(report); } @@ -660,7 +685,7 @@ static void abort_test(void) clar_print_onabort( "Fatal error: a cleanup method raised an exception.\n"); clar_report_errors(_clar.last_report); - exit(-1); + exit(1); } CL_TRACE(CL_TRACE__TEST__LONGJMP); @@ -695,9 +720,9 @@ void clar__fail( _clar.last_report->last_error = error; - error->file = file; - error->function = function; - error->line_number = line; + error->file = _clar.invoke_file ? _clar.invoke_file : file; + error->function = _clar.invoke_func ? _clar.invoke_func : function; + error->line_number = _clar.invoke_line ? _clar.invoke_line : line; error->error_msg = error_msg; if (description != NULL && @@ -754,7 +779,12 @@ void clar__assert_equal( p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)", s1, s2, pos); } else { - p_snprintf(buf, sizeof(buf), "'%s' != '%s'", s1, s2); + const char *q1 = s1 ? "'" : ""; + const char *q2 = s2 ? "'" : ""; + s1 = s1 ? s1 : "NULL"; + s2 = s2 ? s2 : "NULL"; + p_snprintf(buf, sizeof(buf), "%s%s%s != %s%s%s", + q1, s1, q1, q2, s2, q2); } } } @@ -767,12 +797,17 @@ void clar__assert_equal( if (!is_equal) { if (s1 && s2) { int pos; - for (pos = 0; s1[pos] == s2[pos] && pos < len; ++pos) + for (pos = 0; pos < len && s1[pos] == s2[pos]; ++pos) /* find differing byte offset */; p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)", len, s1, len, s2, pos); } else { - p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s'", len, s1, len, s2); + const char *q1 = s1 ? "'" : ""; + const char *q2 = s2 ? "'" : ""; + s1 = s1 ? s1 : "NULL"; + s2 = s2 ? s2 : "NULL"; + p_snprintf(buf, sizeof(buf), "%s%.*s%s != %s%.*s%s", + q1, len, s1, q1, q2, len, s2, q2); } } } @@ -790,7 +825,12 @@ void clar__assert_equal( p_snprintf(buf, sizeof(buf), "'%ls' != '%ls' (at byte %d)", wcs1, wcs2, pos); } else { - p_snprintf(buf, sizeof(buf), "'%ls' != '%ls'", wcs1, wcs2); + const char *q1 = wcs1 ? "'" : ""; + const char *q2 = wcs2 ? "'" : ""; + wcs1 = wcs1 ? wcs1 : L"NULL"; + wcs2 = wcs2 ? wcs2 : L"NULL"; + p_snprintf(buf, sizeof(buf), "%s%ls%s != %s%ls%s", + q1, wcs1, q1, q2, wcs2, q2); } } } @@ -803,12 +843,17 @@ void clar__assert_equal( if (!is_equal) { if (wcs1 && wcs2) { int pos; - for (pos = 0; wcs1[pos] == wcs2[pos] && pos < len; ++pos) + for (pos = 0; pos < len && wcs1[pos] == wcs2[pos]; ++pos) /* find differing byte offset */; p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls' (at byte %d)", len, wcs1, len, wcs2, pos); } else { - p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls'", len, wcs1, len, wcs2); + const char *q1 = wcs1 ? "'" : ""; + const char *q2 = wcs2 ? "'" : ""; + wcs1 = wcs1 ? wcs1 : L"NULL"; + wcs2 = wcs2 ? wcs2 : L"NULL"; + p_snprintf(buf, sizeof(buf), "%s%.*ls%s != %s%.*ls%s", + q1, len, wcs1, q1, q2, len, wcs2, q2); } } } @@ -850,6 +895,23 @@ void cl_set_cleanup(void (*cleanup)(void *), void *opaque) _clar.local_cleanup_payload = opaque; } +void clar__set_invokepoint( + const char *file, + const char *func, + size_t line) +{ + _clar.invoke_file = file; + _clar.invoke_func = func; + _clar.invoke_line = line; +} + +void clar__clear_invokepoint(void) +{ + _clar.invoke_file = NULL; + _clar.invoke_func = NULL; + _clar.invoke_line = 0; +} + #include "clar/sandbox.h" #include "clar/fixtures.h" #include "clar/fs.h" diff --git a/t/unit-tests/clar/clar.h b/t/unit-tests/clar/clar.h index 8c22382bd5..ca72292ae9 100644 --- a/t/unit-tests/clar/clar.h +++ b/t/unit-tests/clar/clar.h @@ -8,6 +8,25 @@ #define __CLAR_TEST_H__ #include <stdlib.h> +#include <limits.h> + +#if defined(_WIN32) && defined(CLAR_WIN32_LONGPATHS) +# define CLAR_MAX_PATH 4096 +#elif defined(_WIN32) +# define CLAR_MAX_PATH MAX_PATH +#else +# define CLAR_MAX_PATH PATH_MAX +#endif + +#ifndef CLAR_SELFTEST +# define CLAR_CURRENT_FILE __FILE__ +# define CLAR_CURRENT_LINE __LINE__ +# define CLAR_CURRENT_FUNC __func__ +#else +# define CLAR_CURRENT_FILE "file" +# define CLAR_CURRENT_LINE 42 +# define CLAR_CURRENT_FUNC "func" +#endif enum cl_test_status { CL_TEST_OK, @@ -30,6 +49,7 @@ void clar_test_shutdown(void); int clar_test(int argc, char *argv[]); const char *clar_sandbox_path(void); +const char *clar_tempdir_path(void); void cl_set_cleanup(void (*cleanup)(void *), void *opaque); void cl_fs_cleanup(void); @@ -84,18 +104,32 @@ const char *cl_fixture_basename(const char *fixture_name); #endif /** + * Invoke a helper function, which itself will use `cl_assert` + * constructs. This will preserve the stack information of the + * current call point, so that function name and line number + * information is shown from the line of the test, instead of + * the helper function. + */ +#define cl_invoke(expr) \ + do { \ + clar__set_invokepoint(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE); \ + expr; \ + clar__clear_invokepoint(); \ + } while(0) + +/** * Assertion macros with explicit error message */ -#define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 1) -#define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 1) -#define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 1) +#define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Function call failed: " #expr, desc, 1) +#define cl_must_fail_(expr, desc) clar__assert((expr) < 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Expected function call to fail: " #expr, desc, 1) +#define cl_assert_(expr, desc) clar__assert((expr) != 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Expression is not true: " #expr, desc, 1) /** * Check macros with explicit error message */ -#define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 0) -#define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 0) -#define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 0) +#define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Function call failed: " #expr, desc, 0) +#define cl_check_fail_(expr, desc) clar__assert((expr) < 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Expected function call to fail: " #expr, desc, 0) +#define cl_check_(expr, desc) clar__assert((expr) != 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Expression is not true: " #expr, desc, 0) /** * Assertion macros with no error message @@ -114,33 +148,33 @@ const char *cl_fixture_basename(const char *fixture_name); /** * Forced failure/warning */ -#define cl_fail(desc) clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1) -#define cl_warning(desc) clar__fail(__FILE__, __func__, __LINE__, "Warning during test execution:", desc, 0) +#define cl_fail(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Test failed.", desc, 1) +#define cl_warning(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Warning during test execution:", desc, 0) #define cl_skip() clar__skip() /** * Typed assertion macros */ -#define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2)) -#define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2)) +#define cl_assert_equal_s(s1,s2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2)) +#define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2)) -#define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2)) -#define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2)) +#define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2)) +#define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2)) -#define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len)) -#define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len)) +#define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len)) +#define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len)) -#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len)) -#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len)) +#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len)) +#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len)) -#define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2)) -#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2)) -#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2)) +#define cl_assert_equal_i(i1,i2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2)) +#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2)) +#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2)) -#define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__func__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0)) +#define cl_assert_equal_b(b1,b2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0)) -#define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__func__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2)) +#define cl_assert_equal_p(p1,p2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2)) void clar__skip(void); @@ -170,4 +204,11 @@ void clar__assert_equal( const char *fmt, ...); +void clar__set_invokepoint( + const char *file, + const char *func, + size_t line); + +void clar__clear_invokepoint(void); + #endif diff --git a/t/unit-tests/clar/clar/fixtures.h b/t/unit-tests/clar/clar/fixtures.h index 6ec6423484..9f1023df59 100644 --- a/t/unit-tests/clar/clar/fixtures.h +++ b/t/unit-tests/clar/clar/fixtures.h @@ -2,7 +2,7 @@ static const char * fixture_path(const char *base, const char *fixture_name) { - static char _path[4096]; + static char _path[CLAR_MAX_PATH]; size_t root_len; root_len = strlen(base); @@ -28,7 +28,7 @@ const char *cl_fixture(const char *fixture_name) void cl_fixture_sandbox(const char *fixture_name) { - fs_copy(cl_fixture(fixture_name), _clar_path); + fs_copy(cl_fixture(fixture_name), clar_sandbox_path()); } const char *cl_fixture_basename(const char *fixture_name) @@ -45,6 +45,6 @@ const char *cl_fixture_basename(const char *fixture_name) void cl_fixture_cleanup(const char *fixture_name) { - fs_rm(fixture_path(_clar_path, cl_fixture_basename(fixture_name))); + fs_rm(fixture_path(clar_sandbox_path(), cl_fixture_basename(fixture_name))); } #endif diff --git a/t/unit-tests/clar/clar/fs.h b/t/unit-tests/clar/clar/fs.h index 2203743fb4..f1311d91e8 100644 --- a/t/unit-tests/clar/clar/fs.h +++ b/t/unit-tests/clar/clar/fs.h @@ -8,12 +8,6 @@ #ifdef _WIN32 -#ifdef CLAR_WIN32_LONGPATHS -# define CLAR_MAX_PATH 4096 -#else -# define CLAR_MAX_PATH MAX_PATH -#endif - #define RM_RETRY_COUNT 5 #define RM_RETRY_DELAY 10 @@ -296,7 +290,7 @@ void cl_fs_cleanup(void) { #ifdef CLAR_FIXTURE_PATH - fs_rm(fixture_path(_clar_path, "*")); + fs_rm(fixture_path(clar_tempdir_path(), "*")); #else ((void)fs_copy); /* unused */ #endif @@ -371,17 +365,19 @@ static void fs_copydir_helper(const char *source, const char *dest, int dest_mode) { DIR *source_dir; - struct dirent *d; mkdir(dest, dest_mode); cl_assert_(source_dir = opendir(source), "Could not open source dir"); - for (;;) { + while (1) { + struct dirent *d; char *child; errno = 0; - if ((d = readdir(source_dir)) == NULL) + d = readdir(source_dir); + if (!d) break; + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; @@ -479,15 +475,18 @@ static void fs_rmdir_helper(const char *path) { DIR *dir; - struct dirent *d; cl_assert_(dir = opendir(path), "Could not open dir"); - for (;;) { + + while (1) { + struct dirent *d; char *child; errno = 0; - if ((d = readdir(dir)) == NULL) + d = readdir(dir); + if (!d) break; + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; @@ -524,7 +523,7 @@ fs_rm(const char *path) void cl_fs_cleanup(void) { - clar_unsandbox(); - clar_sandbox(); + clar_tempdir_shutdown(); + clar_tempdir_init(); } #endif diff --git a/t/unit-tests/clar/clar/print.h b/t/unit-tests/clar/clar/print.h index 69d0ee967e..89b66591d7 100644 --- a/t/unit-tests/clar/clar/print.h +++ b/t/unit-tests/clar/clar/print.h @@ -1,9 +1,13 @@ /* clap: clar protocol, the traditional clar output format */ -static void clar_print_clap_init(int test_count, int suite_count, const char *suite_names) +static void clar_print_clap_init(int test_count, int suite_count) { (void)test_count; - printf("Loaded %d suites: %s\n", (int)suite_count, suite_names); + + if (_clar.verbosity < 0) + return; + + printf("Loaded %d suites:\n", (int)suite_count); printf("Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')\n"); } @@ -13,10 +17,27 @@ static void clar_print_clap_shutdown(int test_count, int suite_count, int error_ (void)suite_count; (void)error_count; - printf("\n\n"); + if (_clar.verbosity >= 0) + printf("\n\n"); clar_report_all(); } + +static void clar_print_indented(const char *str, int indent) +{ + const char *bol, *eol; + + for (bol = str; *bol; bol = eol) { + eol = strchr(bol, '\n'); + if (eol) + eol++; + else + eol = bol + strlen(bol); + printf("%*s%.*s", indent, "", (int)(eol - bol), bol); + } + putc('\n', stdout); +} + static void clar_print_clap_error(int num, const struct clar_report *report, const struct clar_error *error) { printf(" %d) Failure:\n", num); @@ -27,10 +48,10 @@ static void clar_print_clap_error(int num, const struct clar_report *report, con error->file, error->line_number); - printf(" %s\n", error->error_msg); + clar_print_indented(error->error_msg, 2); if (error->description != NULL) - printf(" %s\n", error->description); + clar_print_indented(error->description, 2); printf("\n"); fflush(stdout); @@ -41,14 +62,17 @@ static void clar_print_clap_ontest(const char *suite_name, const char *test_name (void)test_name; (void)test_number; + if (_clar.verbosity < 0) + return; + if (_clar.verbosity > 1) { printf("%s::%s: ", suite_name, test_name); switch (status) { case CL_TEST_OK: printf("ok\n"); break; case CL_TEST_FAILURE: printf("fail\n"); break; - case CL_TEST_SKIP: printf("skipped"); break; - case CL_TEST_NOTRUN: printf("notrun"); break; + case CL_TEST_SKIP: printf("skipped\n"); break; + case CL_TEST_NOTRUN: printf("notrun\n"); break; } } else { switch (status) { @@ -64,6 +88,8 @@ static void clar_print_clap_ontest(const char *suite_name, const char *test_name static void clar_print_clap_onsuite(const char *suite_name, int suite_index) { + if (_clar.verbosity < 0) + return; if (_clar.verbosity == 1) printf("\n%s", suite_name); @@ -77,11 +103,10 @@ static void clar_print_clap_onabort(const char *fmt, va_list arg) /* tap: test anywhere protocol format */ -static void clar_print_tap_init(int test_count, int suite_count, const char *suite_names) +static void clar_print_tap_init(int test_count, int suite_count) { (void)test_count; (void)suite_count; - (void)suite_names; printf("TAP version 13\n"); } @@ -127,18 +152,20 @@ static void clar_print_tap_ontest(const char *suite_name, const char *test_name, case CL_TEST_FAILURE: printf("not ok %d - %s::%s\n", test_number, suite_name, test_name); - printf(" ---\n"); - printf(" reason: |\n"); - printf(" %s\n", error->error_msg); + if (_clar.verbosity >= 0) { + printf(" ---\n"); + printf(" reason: |\n"); + clar_print_indented(error->error_msg, 6); - if (error->description) - printf(" %s\n", error->description); + if (error->description) + clar_print_indented(error->description, 6); - printf(" at:\n"); - printf(" file: '"); print_escaped(error->file); printf("'\n"); - printf(" line: %" PRIuMAX "\n", error->line_number); - printf(" function: '%s'\n", error->function); - printf(" ---\n"); + printf(" at:\n"); + printf(" file: '"); print_escaped(error->file); printf("'\n"); + printf(" line: %" PRIuMAX "\n", error->line_number); + printf(" function: '%s'\n", error->function); + printf(" ---\n"); + } break; case CL_TEST_SKIP: @@ -152,6 +179,8 @@ static void clar_print_tap_ontest(const char *suite_name, const char *test_name, static void clar_print_tap_onsuite(const char *suite_name, int suite_index) { + if (_clar.verbosity < 0) + return; printf("# start of suite %d: %s\n", suite_index, suite_name); } @@ -177,9 +206,9 @@ static void clar_print_tap_onabort(const char *fmt, va_list arg) } \ } while (0) -static void clar_print_init(int test_count, int suite_count, const char *suite_names) +static void clar_print_init(int test_count, int suite_count) { - PRINT(init, test_count, suite_count, suite_names); + PRINT(init, test_count, suite_count); } static void clar_print_shutdown(int test_count, int suite_count, int error_count) diff --git a/t/unit-tests/clar/clar/sandbox.h b/t/unit-tests/clar/clar/sandbox.h index bc960f50e0..52add8aceb 100644 --- a/t/unit-tests/clar/clar/sandbox.h +++ b/t/unit-tests/clar/clar/sandbox.h @@ -2,7 +2,17 @@ #include <sys/syslimits.h> #endif -static char _clar_path[4096 + 1]; +/* + * The tempdir is the temporary directory for the entirety of the clar + * process execution. The sandbox is an individual temporary directory + * for the execution of an individual test. Sandboxes are deleted + * entirely after test execution to avoid pollution across tests. + */ + +static char _clar_tempdir[CLAR_MAX_PATH]; +static size_t _clar_tempdir_len; + +static char _clar_sandbox[CLAR_MAX_PATH]; static int is_valid_tmp_path(const char *path) @@ -15,7 +25,10 @@ is_valid_tmp_path(const char *path) if (!S_ISDIR(st.st_mode)) return 0; - return (access(path, W_OK) == 0); + if (access(path, W_OK) != 0) + return 0; + + return (strlen(path) < CLAR_MAX_PATH); } static int @@ -31,14 +44,11 @@ find_tmp_path(char *buffer, size_t length) for (i = 0; i < var_count; ++i) { const char *env = getenv(env_vars[i]); + if (!env) continue; if (is_valid_tmp_path(env)) { -#ifdef __APPLE__ - if (length >= PATH_MAX && realpath(env, buffer) != NULL) - return 0; -#endif strncpy(buffer, env, length - 1); buffer[length - 1] = '\0'; return 0; @@ -47,21 +57,18 @@ find_tmp_path(char *buffer, size_t length) /* If the environment doesn't say anything, try to use /tmp */ if (is_valid_tmp_path("/tmp")) { -#ifdef __APPLE__ - if (length >= PATH_MAX && realpath("/tmp", buffer) != NULL) - return 0; -#endif strncpy(buffer, "/tmp", length - 1); buffer[length - 1] = '\0'; return 0; } #else - DWORD env_len = GetEnvironmentVariable("CLAR_TMP", buffer, (DWORD)length); - if (env_len > 0 && env_len < (DWORD)length) + DWORD len = GetEnvironmentVariable("CLAR_TMP", buffer, (DWORD)length); + if (len > 0 && len < (DWORD)length) return 0; - if (GetTempPath((DWORD)length, buffer)) + len = GetTempPath((DWORD)length, buffer); + if (len > 0 && len < (DWORD)length) return 0; #endif @@ -75,17 +82,53 @@ find_tmp_path(char *buffer, size_t length) return -1; } -static void clar_unsandbox(void) +static int canonicalize_tmp_path(char *buffer) +{ +#ifdef _WIN32 + char tmp[CLAR_MAX_PATH], *p; + DWORD ret; + + ret = GetFullPathName(buffer, CLAR_MAX_PATH, tmp, NULL); + + if (ret == 0 || ret > CLAR_MAX_PATH) + return -1; + + ret = GetLongPathName(tmp, buffer, CLAR_MAX_PATH); + + if (ret == 0 || ret > CLAR_MAX_PATH) + return -1; + + /* normalize path to POSIX forward slashes */ + for (p = buffer; *p; p++) + if (*p == '\\') + *p = '/'; + + return 0; +#elif defined(CLAR_HAS_REALPATH) + char tmp[CLAR_MAX_PATH]; + + if (realpath(buffer, tmp) == NULL) + return -1; + + strcpy(buffer, tmp); + return 0; +#else + (void)buffer; + return 0; +#endif +} + +static void clar_tempdir_shutdown(void) { - if (_clar_path[0] == '\0') + if (_clar_tempdir[0] == '\0') return; cl_must_pass(chdir("..")); - fs_rm(_clar_path); + fs_rm(_clar_tempdir); } -static int build_sandbox_path(void) +static int build_tempdir_path(void) { #ifdef CLAR_TMPDIR const char path_tail[] = CLAR_TMPDIR "_XXXXXX"; @@ -95,64 +138,153 @@ static int build_sandbox_path(void) size_t len; - if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0) + if (find_tmp_path(_clar_tempdir, sizeof(_clar_tempdir)) < 0 || + canonicalize_tmp_path(_clar_tempdir) < 0) return -1; - len = strlen(_clar_path); + len = strlen(_clar_tempdir); -#ifdef _WIN32 - { /* normalize path to POSIX forward slashes */ - size_t i; - for (i = 0; i < len; ++i) { - if (_clar_path[i] == '\\') - _clar_path[i] = '/'; - } - } -#endif + if (len + strlen(path_tail) + 2 > CLAR_MAX_PATH) + return -1; - if (_clar_path[len - 1] != '/') { - _clar_path[len++] = '/'; - } + if (_clar_tempdir[len - 1] != '/') + _clar_tempdir[len++] = '/'; - strncpy(_clar_path + len, path_tail, sizeof(_clar_path) - len); + strncpy(_clar_tempdir + len, path_tail, sizeof(_clar_tempdir) - len); #if defined(__MINGW32__) - if (_mktemp(_clar_path) == NULL) + if (_mktemp(_clar_tempdir) == NULL) return -1; - if (mkdir(_clar_path, 0700) != 0) + if (mkdir(_clar_tempdir, 0700) != 0) return -1; #elif defined(_WIN32) - if (_mktemp_s(_clar_path, sizeof(_clar_path)) != 0) + if (_mktemp_s(_clar_tempdir, sizeof(_clar_tempdir)) != 0) return -1; - if (mkdir(_clar_path, 0700) != 0) + if (mkdir(_clar_tempdir, 0700) != 0) return -1; -#elif defined(__sun) || defined(__TANDEM) - if (mktemp(_clar_path) == NULL) +#elif defined(__sun) || defined(__TANDEM) || defined(__hpux) + if (mktemp(_clar_tempdir) == NULL) return -1; - if (mkdir(_clar_path, 0700) != 0) + if (mkdir(_clar_tempdir, 0700) != 0) return -1; #else - if (mkdtemp(_clar_path) == NULL) + if (mkdtemp(_clar_tempdir) == NULL) return -1; #endif + _clar_tempdir_len = strlen(_clar_tempdir); return 0; } -static void clar_sandbox(void) +static void clar_tempdir_init(void) { - if (_clar_path[0] == '\0' && build_sandbox_path() < 0) - clar_abort("Failed to build sandbox path.\n"); + if (_clar_tempdir[0] == '\0' && build_tempdir_path() < 0) + clar_abort("Failed to build tempdir path.\n"); - if (chdir(_clar_path) != 0) - clar_abort("Failed to change into sandbox directory '%s': %s.\n", - _clar_path, strerror(errno)); + if (chdir(_clar_tempdir) != 0) + clar_abort("Failed to change into tempdir '%s': %s.\n", + _clar_tempdir, strerror(errno)); + +#if !defined(CLAR_SANDBOX_TEST_NAMES) && defined(_WIN32) + srand(clock() ^ (unsigned int)time(NULL) ^ GetCurrentProcessId() ^ GetCurrentThreadId()); +#elif !defined(CLAR_SANDBOX_TEST_NAMES) + srand(clock() ^ time(NULL) ^ ((unsigned)getpid() << 16)); +#endif +} + +static void append(char *dst, const char *src) +{ + char *d; + const char *s; + + for (d = dst; *d; d++) + ; + + for (s = src; *s; d++, s++) + if (*s == ':') + *d = '_'; + else + *d = *s; + + *d = '\0'; +} + +static int clar_sandbox_create(const char *suite_name, const char *test_name) +{ +#ifndef CLAR_SANDBOX_TEST_NAMES + char alpha[] = "0123456789abcdef"; + int num = rand(); +#endif + + cl_assert(_clar_sandbox[0] == '\0'); + + /* + * We may want to use test names as sandbox directory names for + * readability, _however_ on platforms with restrictions for short + * file / folder names (eg, Windows), this may be too long. + */ +#ifdef CLAR_SANDBOX_TEST_NAMES + cl_assert(strlen(_clar_tempdir) + strlen(suite_name) + strlen(test_name) + 3 < CLAR_MAX_PATH); + + strcpy(_clar_sandbox, _clar_tempdir); + _clar_sandbox[_clar_tempdir_len] = '/'; + _clar_sandbox[_clar_tempdir_len + 1] = '\0'; + + append(_clar_sandbox, suite_name); + append(_clar_sandbox, "__"); + append(_clar_sandbox, test_name); +#else + ((void)suite_name); + ((void)test_name); + ((void)append); + + cl_assert(strlen(_clar_tempdir) + 9 < CLAR_MAX_PATH); + + strcpy(_clar_sandbox, _clar_tempdir); + _clar_sandbox[_clar_tempdir_len] = '/'; + + _clar_sandbox[_clar_tempdir_len + 1] = alpha[(num & 0xf0000000) >> 28]; + _clar_sandbox[_clar_tempdir_len + 2] = alpha[(num & 0x0f000000) >> 24]; + _clar_sandbox[_clar_tempdir_len + 3] = alpha[(num & 0x00f00000) >> 20]; + _clar_sandbox[_clar_tempdir_len + 4] = alpha[(num & 0x000f0000) >> 16]; + _clar_sandbox[_clar_tempdir_len + 5] = alpha[(num & 0x0000f000) >> 12]; + _clar_sandbox[_clar_tempdir_len + 6] = alpha[(num & 0x00000f00) >> 8]; + _clar_sandbox[_clar_tempdir_len + 7] = alpha[(num & 0x000000f0) >> 4]; + _clar_sandbox[_clar_tempdir_len + 8] = alpha[(num & 0x0000000f) >> 0]; + _clar_sandbox[_clar_tempdir_len + 9] = '\0'; +#endif + + if (mkdir(_clar_sandbox, 0700) != 0) + return -1; + + if (chdir(_clar_sandbox) != 0) + return -1; + + return 0; +} + +static int clar_sandbox_cleanup(void) +{ + cl_assert(_clar_sandbox[0] != '\0'); + + if (chdir(_clar_tempdir) != 0) + return -1; + + fs_rm(_clar_sandbox); + _clar_sandbox[0] = '\0'; + + return 0; +} + +const char *clar_tempdir_path(void) +{ + return _clar_tempdir; } const char *clar_sandbox_path(void) { - return _clar_path; + return _clar_sandbox; } diff --git a/t/unit-tests/clar/clar/summary.h b/t/unit-tests/clar/clar/summary.h index 0d0b646fe7..7b85f162d8 100644 --- a/t/unit-tests/clar/clar/summary.h +++ b/t/unit-tests/clar/clar/summary.h @@ -23,10 +23,11 @@ static int clar_summary_testsuite(struct clar_summary *summary, int idn, const char *name, time_t timestamp, int test_count, int fail_count, int error_count) { - struct tm *tm = localtime(×tamp); + struct tm tm; char iso_dt[20]; - if (strftime(iso_dt, sizeof(iso_dt), "%Y-%m-%dT%H:%M:%S", tm) == 0) + localtime_r(×tamp, &tm); + if (strftime(iso_dt, sizeof(iso_dt), "%Y-%m-%dT%H:%M:%S", &tm) == 0) return -1; return fprintf(summary->fp, "\t<testsuite" diff --git a/t/unit-tests/clar/example/CMakeLists.txt b/t/unit-tests/clar/example/CMakeLists.txt new file mode 100644 index 0000000000..b72f187523 --- /dev/null +++ b/t/unit-tests/clar/example/CMakeLists.txt @@ -0,0 +1,28 @@ +find_package(Python COMPONENTS Interpreter REQUIRED) + +add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" + COMMAND "${Python_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/generate.py" --output "${CMAKE_CURRENT_BINARY_DIR}" + DEPENDS main.c example.c + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +add_executable(example) +set_target_properties(example PROPERTIES + C_STANDARD 90 + C_STANDARD_REQUIRED ON + C_EXTENSIONS OFF +) +target_sources(example PRIVATE + main.c + example.c + "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" +) +target_compile_definitions(example PRIVATE) +target_compile_options(example PRIVATE + $<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall> +) +target_include_directories(example PRIVATE + "${CMAKE_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" +) +target_link_libraries(example clar) diff --git a/t/unit-tests/clar/example/example.c b/t/unit-tests/clar/example/example.c new file mode 100644 index 0000000000..c07d6bf68e --- /dev/null +++ b/t/unit-tests/clar/example/example.c @@ -0,0 +1,6 @@ +#include "clar.h" + +void test_example__simple_assert(void) +{ + cl_assert_equal_i(1, 1); +} diff --git a/t/unit-tests/clar/test/main.c.sample b/t/unit-tests/clar/example/main.c index a4d91b72fa..f8def7fa6e 100644 --- a/t/unit-tests/clar/test/main.c.sample +++ b/t/unit-tests/clar/example/main.c @@ -5,7 +5,7 @@ * For full terms see the included COPYING file. */ -#include "clar_test.h" +#include "clar.h" /* * Minimal main() for clar tests. diff --git a/t/unit-tests/clar/generate.py b/t/unit-tests/clar/generate.py index 80996ac3e7..fd2f0ee83b 100755 --- a/t/unit-tests/clar/generate.py +++ b/t/unit-tests/clar/generate.py @@ -158,17 +158,24 @@ class TestSuite(object): def find_modules(self): modules = [] - for root, _, files in os.walk(self.path): - module_root = root[len(self.path):] - module_root = [c for c in module_root.split(os.sep) if c] - tests_in_module = fnmatch.filter(files, "*.c") + if os.path.isfile(self.path): + full_path = os.path.abspath(self.path) + module_name = os.path.basename(self.path) + module_name = os.path.splitext(module_name)[0] + modules.append((full_path, module_name)) + else: + for root, _, files in os.walk(self.path): + module_root = root[len(self.path):] + module_root = [c for c in module_root.split(os.sep) if c] - for test_file in tests_in_module: - full_path = os.path.join(root, test_file) - module_name = "_".join(module_root + [test_file[:-2]]).replace("-", "_") + tests_in_module = fnmatch.filter(files, "*.c") - modules.append((full_path, module_name)) + for test_file in tests_in_module: + full_path = os.path.join(root, test_file) + module_name = "_".join(module_root + [test_file[:-2]]).replace("-", "_") + + modules.append((full_path, module_name)) return modules @@ -217,6 +224,7 @@ class TestSuite(object): def write(self): output = os.path.join(self.output, 'clar.suite') + os.makedirs(self.output, exist_ok=True) if not self.should_generate(output): return False @@ -258,7 +266,11 @@ if __name__ == '__main__': sys.exit(1) path = args.pop() if args else '.' + if os.path.isfile(path) and not options.output: + print("Must provide --output when specifying a file") + sys.exit(1) output = options.output or path + suite = TestSuite(path, output) suite.load(options.force) suite.disable(options.excluded) diff --git a/t/unit-tests/clar/test/CMakeLists.txt b/t/unit-tests/clar/test/CMakeLists.txt index 7f2c1dc17a..f240166439 100644 --- a/t/unit-tests/clar/test/CMakeLists.txt +++ b/t/unit-tests/clar/test/CMakeLists.txt @@ -2,12 +2,12 @@ find_package(Python COMPONENTS Interpreter REQUIRED) add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" COMMAND "${Python_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/generate.py" --output "${CMAKE_CURRENT_BINARY_DIR}" - DEPENDS main.c sample.c clar_test.h + DEPENDS main.c selftest.c WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) -add_executable(clar_test) -set_target_properties(clar_test PROPERTIES +add_executable(selftest) +set_target_properties(selftest PROPERTIES C_STANDARD 90 C_STANDARD_REQUIRED ON C_EXTENSIONS OFF @@ -15,25 +15,35 @@ set_target_properties(clar_test PROPERTIES # MSVC generates all kinds of warnings. We may want to fix these in the future # and then unconditionally treat warnings as errors. -if(NOT MSVC) - set_target_properties(clar_test PROPERTIES +if (NOT MSVC) + set_target_properties(selftest PROPERTIES COMPILE_WARNING_AS_ERROR ON ) endif() -target_sources(clar_test PRIVATE +target_sources(selftest PRIVATE main.c - sample.c + selftest.c "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" ) -target_compile_definitions(clar_test PRIVATE - CLAR_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/" +target_compile_definitions(selftest PRIVATE + CLAR_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/expected/" ) -target_compile_options(clar_test PRIVATE +target_compile_options(selftest PRIVATE $<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall> ) -target_include_directories(clar_test PRIVATE +target_include_directories(selftest PRIVATE "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" ) -target_link_libraries(clar_test clar) +target_link_libraries(selftest clar) + +add_test(NAME build_selftest + COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --target selftest +) +set_tests_properties(build_selftest PROPERTIES FIXTURES_SETUP clar_test_fixture) + +add_subdirectory(suites) + +add_test(NAME selftest COMMAND "${CMAKE_CURRENT_BINARY_DIR}/selftest" $<TARGET_FILE_DIR:combined_suite>) +set_tests_properties(selftest PROPERTIES FIXTURES_REQUIRED clar_test_fixture) diff --git a/t/unit-tests/clar/test/clar_test.h b/t/unit-tests/clar/test/clar_test.h deleted file mode 100644 index 0fcaa639aa..0000000000 --- a/t/unit-tests/clar/test/clar_test.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) Vicent Marti. All rights reserved. - * - * This file is part of clar, distributed under the ISC license. - * For full terms see the included COPYING file. - */ -#ifndef __CLAR_TEST__ -#define __CLAR_TEST__ - -/* Import the standard clar helper functions */ -#include "clar.h" - -/* Your custom shared includes / defines here */ -extern int global_test_counter; - -#endif diff --git a/t/unit-tests/clar/test/expected/help b/t/unit-tests/clar/test/expected/help new file mode 100644 index 0000000000..9428def2d7 --- /dev/null +++ b/t/unit-tests/clar/test/expected/help @@ -0,0 +1,12 @@ +Usage: combined [options] + +Options: + -sname Run only the suite with `name` (can go to individual test name) + -iname Include the suite with `name` + -xname Exclude the suite with `name` + -v Increase verbosity (show suite names) + -q Decrease verbosity, inverse to -v + -Q Quit as soon as a test fails + -t Display results in tap format + -l Print suite names + -r[filename] Write summary file (to the optional filename) diff --git a/t/unit-tests/clar/test/expected/quiet b/t/unit-tests/clar/test/expected/quiet new file mode 100644 index 0000000000..280c99d8ad --- /dev/null +++ b/t/unit-tests/clar/test/expected/quiet @@ -0,0 +1,44 @@ + 1) Failure: +combined::1 [file:42] + Function call failed: -1 + + 2) Failure: +combined::2 [file:42] + Expression is not true: 100 == 101 + + 3) Failure: +combined::strings [file:42] + String mismatch: "mismatched" != actual ("this one fails") + 'mismatched' != 'expected' (at byte 0) + + 4) Failure: +combined::strings_with_length [file:42] + String mismatch: "exactly" != actual ("this one fails") + 'exa' != 'exp' (at byte 2) + + 5) Failure: +combined::int [file:42] + 101 != value ("extra note on failing test") + 101 != 100 + + 6) Failure: +combined::int_fmt [file:42] + 022 != value + 0022 != 0144 + + 7) Failure: +combined::bool [file:42] + 0 != value + 0 != 1 + + 8) Failure: +combined::multiline_description [file:42] + Function call failed: -1 + description line 1 + description line 2 + + 9) Failure: +combined::null_string [file:42] + String mismatch: "expected" != actual ("this one fails") + 'expected' != NULL + diff --git a/t/unit-tests/clar/test/expected/specific_test b/t/unit-tests/clar/test/expected/specific_test new file mode 100644 index 0000000000..6c22e9f507 --- /dev/null +++ b/t/unit-tests/clar/test/expected/specific_test @@ -0,0 +1,9 @@ +Loaded 1 suites: +Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') +F + + 1) Failure: +combined::bool [file:42] + 0 != value + 0 != 1 + diff --git a/t/unit-tests/clar/test/expected/stop_on_failure b/t/unit-tests/clar/test/expected/stop_on_failure new file mode 100644 index 0000000000..c23610754f --- /dev/null +++ b/t/unit-tests/clar/test/expected/stop_on_failure @@ -0,0 +1,8 @@ +Loaded 1 suites: +Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') +F + + 1) Failure: +combined::1 [file:42] + Function call failed: -1 + diff --git a/t/unit-tests/clar/test/expected/suite_names b/t/unit-tests/clar/test/expected/suite_names new file mode 100644 index 0000000000..10d1538427 --- /dev/null +++ b/t/unit-tests/clar/test/expected/suite_names @@ -0,0 +1,2 @@ +Test suites (use -s<name> to run just one): + 0: combined diff --git a/t/unit-tests/clar/test/expected/summary.xml b/t/unit-tests/clar/test/expected/summary.xml new file mode 100644 index 0000000000..9a89d43a59 --- /dev/null +++ b/t/unit-tests/clar/test/expected/summary.xml @@ -0,0 +1,41 @@ +<testsuites> + <testsuite id="0" name="selftest" hostname="localhost" timestamp="2024-09-06T10:04:08" tests="8" failures="8" errors="0"> + <testcase name="1" classname="selftest" time="0.00"> + <failure type="assert"><![CDATA[Function call failed: -1 +(null)]]></failure> + </testcase> + <testcase name="2" classname="selftest" time="0.00"> + <failure type="assert"><![CDATA[Expression is not true: 100 == 101 +(null)]]></failure> + </testcase> + <testcase name="strings" classname="selftest" time="0.00"> + <failure type="assert"><![CDATA[String mismatch: "mismatched" != actual ("this one fails") +'mismatched' != 'expected' (at byte 0)]]></failure> + </testcase> + <testcase name="strings_with_length" classname="selftest" time="0.00"> + <failure type="assert"><![CDATA[String mismatch: "exactly" != actual ("this one fails") +'exa' != 'exp' (at byte 2)]]></failure> + </testcase> + <testcase name="int" classname="selftest" time="0.00"> + <failure type="assert"><![CDATA[101 != value ("extra note on failing test") +101 != 100]]></failure> + </testcase> + <testcase name="int_fmt" classname="selftest" time="0.00"> + <failure type="assert"><![CDATA[022 != value +0022 != 0144]]></failure> + </testcase> + <testcase name="bool" classname="selftest" time="0.00"> + <failure type="assert"><![CDATA[0 != value +0 != 1]]></failure> + </testcase> + <testcase name="multiline_description" classname="selftest" time="0.00"> + <failure type="assert"><![CDATA[Function call failed: −1 +description line 1 +description line 2]]></failure> + </testcase> + <testcase name="null_string" classname="selftest" time="0.00"> + <failure type="assert"><![CDATA[String mismatch: "expected" != actual ("this one fails") +'expected' != NULL]]></failure> + </testcase> + </testsuite> +</testsuites> diff --git a/t/unit-tests/clar/test/expected/summary_with_filename b/t/unit-tests/clar/test/expected/summary_with_filename new file mode 100644 index 0000000000..460160791d --- /dev/null +++ b/t/unit-tests/clar/test/expected/summary_with_filename @@ -0,0 +1,49 @@ +Loaded 1 suites: +Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') +FFFFFFFFF + + 1) Failure: +combined::1 [file:42] + Function call failed: -1 + + 2) Failure: +combined::2 [file:42] + Expression is not true: 100 == 101 + + 3) Failure: +combined::strings [file:42] + String mismatch: "mismatched" != actual ("this one fails") + 'mismatched' != 'expected' (at byte 0) + + 4) Failure: +combined::strings_with_length [file:42] + String mismatch: "exactly" != actual ("this one fails") + 'exa' != 'exp' (at byte 2) + + 5) Failure: +combined::int [file:42] + 101 != value ("extra note on failing test") + 101 != 100 + + 6) Failure: +combined::int_fmt [file:42] + 022 != value + 0022 != 0144 + + 7) Failure: +combined::bool [file:42] + 0 != value + 0 != 1 + + 8) Failure: +combined::multiline_description [file:42] + Function call failed: -1 + description line 1 + description line 2 + + 9) Failure: +combined::null_string [file:42] + String mismatch: "expected" != actual ("this one fails") + 'expected' != NULL + +written summary file to different.xml diff --git a/t/unit-tests/clar/test/expected/summary_without_filename b/t/unit-tests/clar/test/expected/summary_without_filename new file mode 100644 index 0000000000..7874c1d98b --- /dev/null +++ b/t/unit-tests/clar/test/expected/summary_without_filename @@ -0,0 +1,49 @@ +Loaded 1 suites: +Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') +FFFFFFFFF + + 1) Failure: +combined::1 [file:42] + Function call failed: -1 + + 2) Failure: +combined::2 [file:42] + Expression is not true: 100 == 101 + + 3) Failure: +combined::strings [file:42] + String mismatch: "mismatched" != actual ("this one fails") + 'mismatched' != 'expected' (at byte 0) + + 4) Failure: +combined::strings_with_length [file:42] + String mismatch: "exactly" != actual ("this one fails") + 'exa' != 'exp' (at byte 2) + + 5) Failure: +combined::int [file:42] + 101 != value ("extra note on failing test") + 101 != 100 + + 6) Failure: +combined::int_fmt [file:42] + 022 != value + 0022 != 0144 + + 7) Failure: +combined::bool [file:42] + 0 != value + 0 != 1 + + 8) Failure: +combined::multiline_description [file:42] + Function call failed: -1 + description line 1 + description line 2 + + 9) Failure: +combined::null_string [file:42] + String mismatch: "expected" != actual ("this one fails") + 'expected' != NULL + +written summary file to summary.xml diff --git a/t/unit-tests/clar/test/expected/tap b/t/unit-tests/clar/test/expected/tap new file mode 100644 index 0000000000..bddbd5dfe9 --- /dev/null +++ b/t/unit-tests/clar/test/expected/tap @@ -0,0 +1,92 @@ +TAP version 13 +# start of suite 1: combined +not ok 1 - combined::1 + --- + reason: | + Function call failed: -1 + at: + file: 'file' + line: 42 + function: 'func' + --- +not ok 2 - combined::2 + --- + reason: | + Expression is not true: 100 == 101 + at: + file: 'file' + line: 42 + function: 'func' + --- +not ok 3 - combined::strings + --- + reason: | + String mismatch: "mismatched" != actual ("this one fails") + 'mismatched' != 'expected' (at byte 0) + at: + file: 'file' + line: 42 + function: 'func' + --- +not ok 4 - combined::strings_with_length + --- + reason: | + String mismatch: "exactly" != actual ("this one fails") + 'exa' != 'exp' (at byte 2) + at: + file: 'file' + line: 42 + function: 'func' + --- +not ok 5 - combined::int + --- + reason: | + 101 != value ("extra note on failing test") + 101 != 100 + at: + file: 'file' + line: 42 + function: 'func' + --- +not ok 6 - combined::int_fmt + --- + reason: | + 022 != value + 0022 != 0144 + at: + file: 'file' + line: 42 + function: 'func' + --- +not ok 7 - combined::bool + --- + reason: | + 0 != value + 0 != 1 + at: + file: 'file' + line: 42 + function: 'func' + --- +not ok 8 - combined::multiline_description + --- + reason: | + Function call failed: -1 + description line 1 + description line 2 + at: + file: 'file' + line: 42 + function: 'func' + --- +not ok 9 - combined::null_string + --- + reason: | + String mismatch: "expected" != actual ("this one fails") + 'expected' != NULL + at: + file: 'file' + line: 42 + function: 'func' + --- +1..9 diff --git a/t/unit-tests/clar/test/expected/without_arguments b/t/unit-tests/clar/test/expected/without_arguments new file mode 100644 index 0000000000..1111d418a0 --- /dev/null +++ b/t/unit-tests/clar/test/expected/without_arguments @@ -0,0 +1,48 @@ +Loaded 1 suites: +Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') +FFFFFFFFF + + 1) Failure: +combined::1 [file:42] + Function call failed: -1 + + 2) Failure: +combined::2 [file:42] + Expression is not true: 100 == 101 + + 3) Failure: +combined::strings [file:42] + String mismatch: "mismatched" != actual ("this one fails") + 'mismatched' != 'expected' (at byte 0) + + 4) Failure: +combined::strings_with_length [file:42] + String mismatch: "exactly" != actual ("this one fails") + 'exa' != 'exp' (at byte 2) + + 5) Failure: +combined::int [file:42] + 101 != value ("extra note on failing test") + 101 != 100 + + 6) Failure: +combined::int_fmt [file:42] + 022 != value + 0022 != 0144 + + 7) Failure: +combined::bool [file:42] + 0 != value + 0 != 1 + + 8) Failure: +combined::multiline_description [file:42] + Function call failed: -1 + description line 1 + description line 2 + + 9) Failure: +combined::null_string [file:42] + String mismatch: "expected" != actual ("this one fails") + 'expected' != NULL + diff --git a/t/unit-tests/clar/test/main.c b/t/unit-tests/clar/test/main.c index 59e56ad255..94af440643 100644 --- a/t/unit-tests/clar/test/main.c +++ b/t/unit-tests/clar/test/main.c @@ -1,23 +1,9 @@ -/* - * Copyright (c) Vicent Marti. All rights reserved. - * - * This file is part of clar, distributed under the ISC license. - * For full terms see the included COPYING file. - */ +#include <stdio.h> +#include <string.h> -#include "clar_test.h" +#include "selftest.h" -/* - * Sample main() for clar tests. - * - * You should write your own main routine for clar tests that does specific - * setup and teardown as necessary for your application. The only required - * line is the call to `clar_test(argc, argv)`, which will execute the test - * suite. If you want to check the return value of the test application, - * your main() should return the same value returned by clar_test(). - */ - -int global_test_counter = 0; +const char *selftest_suite_directory; #ifdef _WIN32 int __cdecl main(int argc, char *argv[]) @@ -25,16 +11,15 @@ int __cdecl main(int argc, char *argv[]) int main(int argc, char *argv[]) #endif { - int ret; - - /* Your custom initialization here */ - global_test_counter = 0; - - /* Run the test suite */ - ret = clar_test(argc, argv); + if (argc < 2) { + fprintf(stderr, "usage: %s <selftest-suite-directory> <options>\n", + argv[0]); + exit(1); + } - /* Your custom cleanup here */ - cl_assert_equal_i(8, global_test_counter); + selftest_suite_directory = argv[1]; + memmove(argv + 1, argv + 2, argc - 1); + argc -= 1; - return ret; + return clar_test(argc, argv); } diff --git a/t/unit-tests/clar/test/selftest.c b/t/unit-tests/clar/test/selftest.c new file mode 100644 index 0000000000..eed83e4512 --- /dev/null +++ b/t/unit-tests/clar/test/selftest.c @@ -0,0 +1,370 @@ +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> + +#include "selftest.h" + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include <windows.h> + +static char *read_full(HANDLE h, int is_pipe) +{ + char *data = NULL; + size_t data_size = 0; + + while (1) { + CHAR buf[4096]; + DWORD bytes_read; + + if (!ReadFile(h, buf, sizeof(buf), &bytes_read, NULL)) { + if (!is_pipe) + cl_fail("Failed reading file handle."); + cl_assert_equal_i(GetLastError(), ERROR_BROKEN_PIPE); + break; + } + if (!bytes_read) + break; + + data = realloc(data, data_size + bytes_read); + cl_assert(data); + memcpy(data + data_size, buf, bytes_read); + data_size += bytes_read; + } + + data = realloc(data, data_size + 1); + cl_assert(data); + data[data_size] = '\0'; + + while (strstr(data, "\r\n")) { + char *ptr = strstr(data, "\r\n"); + memmove(ptr, ptr + 1, strlen(ptr)); + } + + return data; +} + +static char *read_file(const char *path) +{ + char *content; + HANDLE file; + + file = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + cl_assert(file != INVALID_HANDLE_VALUE); + content = read_full(file, 0); + cl_assert_equal_b(1, CloseHandle(file)); + + return content; +} + +static char *execute(const char *suite, int expected_error_code, const char **args, size_t nargs) +{ + SECURITY_ATTRIBUTES security_attributes = { 0 }; + PROCESS_INFORMATION process_info = { 0 }; + STARTUPINFO startup_info = { 0 }; + char binary_path[4096] = { 0 }; + char cmdline[4096] = { 0 }; + char *output = NULL; + HANDLE stdout_write; + HANDLE stdout_read; + DWORD exit_code; + size_t i; + + snprintf(binary_path, sizeof(binary_path), "%s/%s_suite.exe", + selftest_suite_directory, suite); + + /* + * Assemble command line arguments. In theory we'd have to properly + * quote them. In practice none of our tests actually care. + */ + snprintf(cmdline, sizeof(cmdline), suite); + for (i = 0; i < nargs; i++) { + size_t cmdline_len = strlen(cmdline); + const char *arg = args[i]; + cl_assert(cmdline_len + strlen(arg) < sizeof(cmdline)); + snprintf(cmdline + cmdline_len, sizeof(cmdline) - cmdline_len, + " %s", arg); + } + + /* + * Create a pipe that we will use to read data from the child process. + * The writing side needs to be inheritable such that the child can use + * it as stdout and stderr. The reading side should only be used by the + * parent. + */ + security_attributes.nLength = sizeof(security_attributes); + security_attributes.bInheritHandle = TRUE; + cl_assert_equal_b(1, CreatePipe(&stdout_read, &stdout_write, &security_attributes, 0)); + cl_assert_equal_b(1, SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)); + + /* + * Create the child process with our pipe. + */ + startup_info.cb = sizeof(startup_info); + startup_info.hStdError = stdout_write; + startup_info.hStdOutput = stdout_write; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + cl_assert_equal_b(1, CreateProcess(binary_path, cmdline, NULL, NULL, TRUE, + 0, NULL, NULL, &startup_info, &process_info)); + cl_assert_equal_b(1, CloseHandle(stdout_write)); + + output = read_full(stdout_read, 1); + cl_assert_equal_b(1, CloseHandle(stdout_read)); + cl_assert_equal_b(1, GetExitCodeProcess(process_info.hProcess, &exit_code)); + cl_assert_equal_i(exit_code, expected_error_code); + + return output; +} + +static void assert_output(const char *suite, const char *expected_output_file, int expected_error_code, ...) +{ + char *expected_output = NULL; + char *output = NULL; + const char *args[16]; + va_list ap; + size_t i; + + va_start(ap, expected_error_code); + for (i = 0; ; i++) { + const char *arg = va_arg(ap, const char *); + if (!arg) + break; + cl_assert(i < sizeof(args) / sizeof(*args)); + args[i] = arg; + } + va_end(ap); + + output = execute(suite, expected_error_code, args, i); + expected_output = read_file(cl_fixture(expected_output_file)); + cl_assert_equal_s(output, expected_output); + + free(expected_output); + free(output); +} + +#else +# include <errno.h> +# include <fcntl.h> +# include <limits.h> +# include <unistd.h> +# include <sys/wait.h> + +static char *read_full(int fd) +{ + size_t data_bytes = 0; + char *data = NULL; + + while (1) { + char buf[4096]; + ssize_t n; + + n = read(fd, buf, sizeof(buf)); + if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + cl_fail("Failed reading from child process."); + } + if (!n) + break; + + data = realloc(data, data_bytes + n); + cl_assert(data); + + memcpy(data + data_bytes, buf, n); + data_bytes += n; + } + + data = realloc(data, data_bytes + 1); + cl_assert(data); + data[data_bytes] = '\0'; + + return data; +} + +static char *read_file(const char *path) +{ + char *data; + int fd; + + fd = open(path, O_RDONLY); + if (fd < 0) + cl_fail("Failed reading expected file."); + + data = read_full(fd); + cl_must_pass(close(fd)); + + return data; +} + +static char *execute(const char *suite, int expected_error_code, const char **args, size_t nargs) +{ + int pipe_fds[2]; + pid_t pid; + + cl_must_pass(pipe(pipe_fds)); + + pid = fork(); + if (!pid) { + const char *final_args[17] = { NULL }; + char binary_path[4096]; + size_t len = 0; + size_t i; + + cl_assert(nargs < sizeof(final_args) / sizeof(*final_args)); + final_args[0] = suite; + for (i = 0; i < nargs; i++) + final_args[i + 1] = args[i]; + + if (dup2(pipe_fds[1], STDOUT_FILENO) < 0 || + dup2(pipe_fds[1], STDERR_FILENO) < 0 || + close(0) < 0 || + close(pipe_fds[0]) < 0 || + close(pipe_fds[1]) < 0) + exit(1); + + cl_assert(len + strlen(selftest_suite_directory) < sizeof(binary_path)); + strcpy(binary_path, selftest_suite_directory); + len += strlen(selftest_suite_directory); + + cl_assert(len + 1 < sizeof(binary_path)); + binary_path[len] = '/'; + len += 1; + + cl_assert(len + strlen(suite) < sizeof(binary_path)); + strcpy(binary_path + len, suite); + len += strlen(suite); + + cl_assert(len + strlen("_suite") < sizeof(binary_path)); + strcpy(binary_path + len, "_suite"); + len += strlen("_suite"); + + binary_path[len] = '\0'; + + execv(binary_path, (char **) final_args); + exit(1); + } else if (pid > 0) { + pid_t waited_pid; + char *output; + int stat; + + cl_must_pass(close(pipe_fds[1])); + + output = read_full(pipe_fds[0]); + + waited_pid = waitpid(pid, &stat, 0); + cl_assert_equal_i(pid, waited_pid); + cl_assert(WIFEXITED(stat)); + cl_assert_equal_i(WEXITSTATUS(stat), expected_error_code); + + return output; + } else { + cl_fail("Fork failed."); + } + + return NULL; +} + +static void assert_output(const char *suite, const char *expected_output_file, int expected_error_code, ...) +{ + char *expected_output, *output; + const char *args[16]; + va_list ap; + size_t i; + + va_start(ap, expected_error_code); + for (i = 0; ; i++) { + cl_assert(i < sizeof(args) / sizeof(*args)); + args[i] = va_arg(ap, const char *); + if (!args[i]) + break; + } + va_end(ap); + + output = execute(suite, expected_error_code, args, i); + expected_output = read_file(cl_fixture(expected_output_file)); + cl_assert_equal_s(output, expected_output); + + free(expected_output); + free(output); +} +#endif + +void test_selftest__help(void) +{ + cl_invoke(assert_output("combined", "help", 1, "-h", NULL)); +} + +void test_selftest__without_arguments(void) +{ + cl_invoke(assert_output("combined", "without_arguments", 9, NULL)); +} + +void test_selftest__specific_test(void) +{ + cl_invoke(assert_output("combined", "specific_test", 1, "-scombined::bool", NULL)); +} + +void test_selftest__stop_on_failure(void) +{ + cl_invoke(assert_output("combined", "stop_on_failure", 1, "-Q", NULL)); +} + +void test_selftest__quiet(void) +{ + cl_invoke(assert_output("combined", "quiet", 9, "-q", NULL)); +} + +void test_selftest__tap(void) +{ + cl_invoke(assert_output("combined", "tap", 9, "-t", NULL)); +} + +void test_selftest__suite_names(void) +{ + cl_invoke(assert_output("combined", "suite_names", 0, "-l", NULL)); +} + +void test_selftest__summary_without_filename(void) +{ + struct stat st; + cl_invoke(assert_output("combined", "summary_without_filename", 9, "-r", NULL)); + /* The summary contains timestamps, so we cannot verify its contents. */ + cl_must_pass(stat("summary.xml", &st)); +} + +void test_selftest__summary_with_filename(void) +{ + struct stat st; + cl_invoke(assert_output("combined", "summary_with_filename", 9, "-rdifferent.xml", NULL)); + /* The summary contains timestamps, so we cannot verify its contents. */ + cl_must_pass(stat("different.xml", &st)); +} + +void test_selftest__pointer_equal(void) +{ + const char *args[] = { + "-spointer::equal", + "-t" + }; + char *output = execute("pointer", 0, args, 2); + cl_assert_equal_s(output, + "TAP version 13\n" + "# start of suite 1: pointer\n" + "ok 1 - pointer::equal\n" + "1..1\n" + ); + free(output); +} + +void test_selftest__pointer_unequal(void) +{ + const char *args[] = { + "-spointer::unequal", + }; + char *output = execute("pointer", 1, args, 1); + cl_assert(output); + cl_assert(strstr(output, "Pointer mismatch: ")); + free(output); +} diff --git a/t/unit-tests/clar/test/selftest.h b/t/unit-tests/clar/test/selftest.h new file mode 100644 index 0000000000..c24e0c5af4 --- /dev/null +++ b/t/unit-tests/clar/test/selftest.h @@ -0,0 +1,3 @@ +#include "clar.h" + +extern const char *selftest_suite_directory; diff --git a/t/unit-tests/clar/test/suites/CMakeLists.txt b/t/unit-tests/clar/test/suites/CMakeLists.txt new file mode 100644 index 0000000000..fa8ab9416a --- /dev/null +++ b/t/unit-tests/clar/test/suites/CMakeLists.txt @@ -0,0 +1,53 @@ +list(APPEND suites + "combined" + "pointer" +) + +foreach(suite IN LISTS suites) + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${suite}/clar.suite" + COMMAND "${Python_EXECUTABLE}" + "${CMAKE_SOURCE_DIR}/generate.py" + "${CMAKE_CURRENT_SOURCE_DIR}/${suite}.c" + --output "${CMAKE_CURRENT_BINARY_DIR}/${suite}" + DEPENDS ${suite}.c + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + + add_executable(${suite}_suite) + set_target_properties(${suite}_suite PROPERTIES + C_STANDARD 90 + C_STANDARD_REQUIRED ON + C_EXTENSIONS OFF + ) + + # MSVC generates all kinds of warnings. We may want to fix these in the future + # and then unconditionally treat warnings as errors. + if(NOT MSVC) + set_target_properties(${suite}_suite PROPERTIES + COMPILE_WARNING_AS_ERROR ON + ) + endif() + + target_sources(${suite}_suite PRIVATE + main.c + ${suite}.c + "${CMAKE_CURRENT_BINARY_DIR}/${suite}/clar.suite" + ) + target_compile_definitions(${suite}_suite PRIVATE + CLAR_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/" + CLAR_SELFTEST + ) + target_compile_options(${suite}_suite PRIVATE + $<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall> + ) + target_include_directories(${suite}_suite PRIVATE + "${CMAKE_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}/${suite}" + ) + target_link_libraries(${suite}_suite clar) + + add_test(NAME build_${suite}_suite + COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --target selftest + ) + set_tests_properties(build_${suite}_suite PROPERTIES FIXTURES_SETUP clar_test_fixture) +endforeach() diff --git a/t/unit-tests/clar/test/sample.c b/t/unit-tests/clar/test/suites/combined.c index faa1209262..e8b41c98c3 100644 --- a/t/unit-tests/clar/test/sample.c +++ b/t/unit-tests/clar/test/suites/combined.c @@ -1,6 +1,7 @@ -#include "clar_test.h" #include <sys/stat.h> +#include "clar.h" + static int file_size(const char *filename) { struct stat st; @@ -10,19 +11,14 @@ static int file_size(const char *filename) return -1; } -void test_sample__initialize(void) -{ - global_test_counter++; -} - -void test_sample__cleanup(void) +void test_combined__cleanup(void) { cl_fixture_cleanup("test"); cl_assert(file_size("test/file") == -1); } -void test_sample__1(void) +void test_combined__1(void) { cl_assert(1); cl_must_pass(0); /* 0 == success */ @@ -30,7 +26,7 @@ void test_sample__1(void) cl_must_pass(-1); /* demonstrate a failing call */ } -void test_sample__2(void) +void test_combined__2(void) { cl_fixture_sandbox("test"); @@ -39,7 +35,7 @@ void test_sample__2(void) cl_assert(100 == 101); } -void test_sample__strings(void) +void test_combined__strings(void) { const char *actual = "expected"; cl_assert_equal_s("expected", actual); @@ -47,7 +43,7 @@ void test_sample__strings(void) cl_assert_equal_s_("mismatched", actual, "this one fails"); } -void test_sample__strings_with_length(void) +void test_combined__strings_with_length(void) { const char *actual = "expected"; cl_assert_equal_strn("expected_", actual, 8); @@ -56,29 +52,34 @@ void test_sample__strings_with_length(void) cl_assert_equal_strn_("exactly", actual, 3, "this one fails"); } -void test_sample__int(void) +void test_combined__int(void) { int value = 100; cl_assert_equal_i(100, value); cl_assert_equal_i_(101, value, "extra note on failing test"); } -void test_sample__int_fmt(void) +void test_combined__int_fmt(void) { int value = 100; cl_assert_equal_i_fmt(022, value, "%04o"); } -void test_sample__bool(void) +void test_combined__bool(void) { int value = 100; cl_assert_equal_b(1, value); /* test equality as booleans */ cl_assert_equal_b(0, value); } -void test_sample__ptr(void) +void test_combined__multiline_description(void) { - const char *actual = "expected"; - cl_assert_equal_p(actual, actual); /* pointers to same object */ - cl_assert_equal_p(&actual, actual); + cl_must_pass_(-1, "description line 1\ndescription line 2"); +} + +void test_combined__null_string(void) +{ + const char *actual = NULL; + cl_assert_equal_s(actual, actual); + cl_assert_equal_s_("expected", actual, "this one fails"); } diff --git a/t/unit-tests/clar/test/suites/main.c b/t/unit-tests/clar/test/suites/main.c new file mode 100644 index 0000000000..3ab581d390 --- /dev/null +++ b/t/unit-tests/clar/test/suites/main.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) Vicent Marti. All rights reserved. + * + * This file is part of clar, distributed under the ISC license. + * For full terms see the included COPYING file. + */ + +#include "clar.h" + +/* + * Selftest main() for clar tests. + * + * You should write your own main routine for clar tests that does specific + * setup and teardown as necessary for your application. The only required + * line is the call to `clar_test(argc, argv)`, which will execute the test + * suite. If you want to check the return value of the test application, + * your main() should return the same value returned by clar_test(). + */ + +#ifdef _WIN32 +int __cdecl main(int argc, char *argv[]) +#else +int main(int argc, char *argv[]) +#endif +{ + return clar_test(argc, argv); +} diff --git a/t/unit-tests/clar/test/suites/pointer.c b/t/unit-tests/clar/test/suites/pointer.c new file mode 100644 index 0000000000..20535b159e --- /dev/null +++ b/t/unit-tests/clar/test/suites/pointer.c @@ -0,0 +1,13 @@ +#include "clar.h" + +void test_pointer__equal(void) +{ + void *p1 = (void *)0x1; + cl_assert_equal_p(p1, p1); +} + +void test_pointer__unequal(void) +{ + void *p1 = (void *)0x1, *p2 = (void *)0x2; + cl_assert_equal_p(p1, p2); +} diff --git a/t/unit-tests/clar/test/resources/test/file b/t/unit-tests/clar/test/suites/resources/test/file index 220f4aa98a..220f4aa98a 100644 --- a/t/unit-tests/clar/test/resources/test/file +++ b/t/unit-tests/clar/test/suites/resources/test/file diff --git a/transport.c b/transport.c index 6ac8aa402b..c7f06a7382 100644 --- a/transport.c +++ b/transport.c @@ -30,7 +30,7 @@ #include "color.h" #include "bundle-uri.h" -static int transport_use_color = -1; +static enum git_colorbool transport_use_color = GIT_COLOR_UNKNOWN; static char transport_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, GIT_COLOR_RED /* REJECTED */ diff --git a/upload-pack.c b/upload-pack.c index 91fcdcad9b..1e87ae9559 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -476,20 +476,17 @@ static void create_pack_file(struct upload_pack_data *pack_data, static int do_got_oid(struct upload_pack_data *data, const struct object_id *oid) { - int we_knew_they_have = 0; struct object *o = parse_object_with_flags(the_repository, oid, PARSE_OBJECT_SKIP_HASH_CHECK | PARSE_OBJECT_DISCARD_TREE); if (!o) die("oops (%s)", oid_to_hex(oid)); + if (o->type == OBJ_COMMIT) { struct commit_list *parents; struct commit *commit = (struct commit *)o; - if (o->flags & THEY_HAVE) - we_knew_they_have = 1; - else - o->flags |= THEY_HAVE; + if (!data->oldest_have || (commit->date < data->oldest_have)) data->oldest_have = commit->date; for (parents = commit->parents; @@ -497,11 +494,13 @@ static int do_got_oid(struct upload_pack_data *data, const struct object_id *oid parents = parents->next) parents->item->object.flags |= THEY_HAVE; } - if (!we_knew_they_have) { - add_object_array(o, NULL, &data->have_obj); - return 1; - } - return 0; + + if (o->flags & THEY_HAVE) + return 0; + o->flags |= THEY_HAVE; + + add_object_array(o, NULL, &data->have_obj); + return 1; } static int got_oid(struct upload_pack_data *data, @@ -914,13 +913,12 @@ static void deepen(struct upload_pack_data *data, int depth) } static void deepen_by_rev_list(struct upload_pack_data *data, - int ac, - const char **av) + struct strvec *argv) { struct commit_list *result; disable_commit_graph(the_repository); - result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW); + result = get_shallow_commits_by_rev_list(argv, SHALLOW, NOT_SHALLOW); send_shallow(data, result); free_commit_list(result); send_unshallow(data); @@ -956,7 +954,7 @@ static int send_shallow_list(struct upload_pack_data *data) struct object *o = data->want_obj.objects[i].item; strvec_push(&av, oid_to_hex(&o->oid)); } - deepen_by_rev_list(data, av.nr, av.v); + deepen_by_rev_list(data, &av); strvec_clear(&av); ret = 1; } else { diff --git a/wt-status.c b/wt-status.c index 21dabab77d..8ffe6d3988 100644 --- a/wt-status.c +++ b/wt-status.c @@ -148,7 +148,7 @@ void wt_status_prepare(struct repository *r, struct wt_status *s) memcpy(s->color_palette, default_wt_status_colors, sizeof(default_wt_status_colors)); s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; - s->use_color = -1; + s->use_color = GIT_COLOR_UNKNOWN; s->relative_paths = 1; s->branch = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD", 0, NULL, NULL); @@ -1165,7 +1165,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s) * before. */ if (s->fp != stdout) { - rev.diffopt.use_color = 0; + rev.diffopt.use_color = GIT_COLOR_NEVER; wt_status_add_cut_line(s); } if (s->verbose > 1 && s->committable) { @@ -2155,7 +2155,7 @@ static void wt_shortstatus_print(struct wt_status *s) static void wt_porcelain_print(struct wt_status *s) { - s->use_color = 0; + s->use_color = GIT_COLOR_NEVER; s->relative_paths = 0; s->prefix = NULL; s->no_gettext = 1; diff --git a/wt-status.h b/wt-status.h index 4e377ce62b..e40a27214a 100644 --- a/wt-status.h +++ b/wt-status.h @@ -111,7 +111,7 @@ struct wt_status { int amend; enum commit_whence whence; int nowarn; - int use_color; + enum git_colorbool use_color; int no_gettext; int display_comment_prefix; int relative_paths; |
